{"version":3,"file":"index.cjs","sources":["../src/core/GPUContext.ts","../src/data/packDataPoints.ts","../src/data/createDataStore.ts","../src/data/lttbSample.ts","../src/data/cartesianData.ts","../src/data/sampleSeries.ts","../src/data/ohlcSample.ts","../src/core/renderCoordinator/utils/canvasUtils.ts","../src/core/renderCoordinator/data/computeVisibleSlice.ts","../src/utils/colors.ts","../src/core/renderCoordinator/utils/dataPointUtils.ts","../src/core/renderCoordinator/utils/axisUtils.ts","../src/core/renderCoordinator/utils/timeAxisUtils.ts","../src/core/renderCoordinator/axis/computeAxisTicks.ts","../src/utils/axisLabelStyling.ts","../src/core/renderCoordinator/render/renderAxisLabels.ts","../src/core/renderCoordinator/render/renderAnnotationLabels.ts","../src/interaction/findNearestPoint.ts","../src/core/renderCoordinator/render/renderOverlays.ts","../src/core/renderCoordinator/annotations/processAnnotations.ts","../src/core/renderCoordinator/animation/animationHelpers.ts","../src/core/renderCoordinator/render/renderSeries.ts","../src/shaders/grid.wgsl?raw","../src/renderers/rendererUtils.ts","../src/renderers/createAxisRenderer.ts","../src/renderers/createGridRenderer.ts","../src/shaders/area.wgsl?raw","../src/renderers/createAreaRenderer.ts","../src/shaders/line.wgsl?raw","../src/renderers/createLineRenderer.ts","../src/shaders/bar.wgsl?raw","../src/renderers/createBarRenderer.ts","../src/shaders/scatter.wgsl?raw","../src/renderers/createScatterRenderer.ts","../src/shaders/scatterDensityBinning.wgsl?raw","../src/shaders/scatterDensityColormap.wgsl?raw","../src/renderers/createScatterDensityRenderer.ts","../src/shaders/pie.wgsl?raw","../src/renderers/createPieRenderer.ts","../src/shaders/candlestick.wgsl?raw","../src/renderers/createCandlestickRenderer.ts","../src/shaders/crosshair.wgsl?raw","../src/data/createStreamBuffer.ts","../src/renderers/createCrosshairRenderer.ts","../src/shaders/highlight.wgsl?raw","../src/renderers/createHighlightRenderer.ts","../src/shaders/referenceLine.wgsl?raw","../src/renderers/createReferenceLineRenderer.ts","../src/shaders/annotationMarker.wgsl?raw","../src/renderers/createAnnotationMarkerRenderer.ts","../src/interaction/createEventManager.ts","../src/interaction/createInsideZoom.ts","../src/interaction/createZoomState.ts","../src/interaction/findPointsAtX.ts","../src/interaction/findCandlestick.ts","../src/interaction/findPieSlice.ts","../src/utils/scales.ts","../src/components/createTextOverlay.ts","../src/components/createLegend.ts","../src/components/createTooltip.ts","../src/components/formatTooltip.ts","../src/core/createAnimationController.ts","../src/utils/easing.ts","../src/core/createRenderCoordinator.ts","../src/config/defaults.ts","../src/themes/darkTheme.ts","../src/themes/lightTheme.ts","../src/themes/index.ts","../src/config/OptionResolver.ts","../src/components/createDataZoomSlider.ts","../src/utils/checkWebGPU.ts","../src/ChartGPU.ts","../src/interaction/createChartSync.ts","../src/interaction/createAnnotationHitTester.ts","../src/interaction/createAnnotationDragHandler.ts","../src/components/createAnnotationConfigDialog.ts","../src/interaction/createAnnotationAuthoring.ts","../src/core/RenderScheduler.ts","../src/index.ts"],"sourcesContent":["/**\n * GPUContext - WebGPU device and adapter management\n * \n * Handles WebGPU initialization, adapter selection, and device creation\n * following WebGPU best practices for resource management and error handling.\n * \n * This module provides both functional and class-based APIs for maximum flexibility.\n */\n\n/** Canvas types supported by GPUContext. */\nexport type SupportedCanvas = HTMLCanvasElement;\n\n/** Options for GPU context initialization. */\nexport interface GPUContextOptions {\n  /** DPR for high-DPI displays. Auto-detects on main thread, defaults to 1.0 in workers. */\n  readonly devicePixelRatio?: number;\n  /** Canvas alpha mode. Default: 'opaque' (faster, no transparency). */\n  readonly alphaMode?: 'opaque' | 'premultiplied';\n  /** GPU power preference for adapter selection. */\n  readonly powerPreference?: 'low-power' | 'high-performance';\n}\n\n/**\n * Represents the state of a GPU context.\n * All properties are readonly to ensure immutability.\n */\nexport interface GPUContextState {\n  readonly adapter: GPUAdapter | null;\n  readonly device: GPUDevice | null;\n  readonly initialized: boolean;\n  readonly canvas: HTMLCanvasElement | null;\n  readonly canvasContext: GPUCanvasContext | null;\n  readonly preferredFormat: GPUTextureFormat | null;\n  readonly devicePixelRatio: number;\n  readonly alphaMode: 'opaque' | 'premultiplied';\n  readonly powerPreference: 'low-power' | 'high-performance';\n}\n\n/** Reliable type guard - instanceof works in workers where HTMLCanvasElement is undefined. */\nexport function isHTMLCanvasElement(canvas: HTMLCanvasElement): canvas is HTMLCanvasElement {\n  return typeof HTMLCanvasElement !== 'undefined' && canvas instanceof HTMLCanvasElement;\n}\n\n/** Gets display dimensions - clientWidth/Height for HTMLCanvasElement */\nfunction getCanvasDimensions(canvas: HTMLCanvasElement): { width: number; height: number } {\n  // Prefer clientWidth/clientHeight (CSS pixels) for HTMLCanvasElement as they reflect actual display size\n  // Fall back to canvas.width/height (device pixels) if client dimensions are 0 or invalid\n  const width = canvas.clientWidth || canvas.width || 0;\n  const height = canvas.clientHeight || canvas.height || 0;\n  \n  // Validate dimensions are finite and non-negative\n  // Note: 0 dimensions are allowed here - they'll be clamped to 1 during GPUContext initialization\n  if (!Number.isFinite(width) || !Number.isFinite(height)) {\n    throw new Error(\n      `GPUContext: Invalid canvas dimensions detected: width=${canvas.clientWidth || canvas.width}, ` +\n      `height=${canvas.clientHeight || canvas.height}. ` +\n      `Canvas must have finite dimensions. Ensure canvas is properly sized before initialization.`\n    );\n  }\n  \n  return { width, height };\n\n}\n\n/**\n * Creates a new GPUContext state with initial values.\n * \n * @param canvas - Optional canvas element (HTMLCanvasElement) to configure for WebGPU rendering\n * @param options - Optional configuration for device pixel ratio, alpha mode, and power preference\n * @returns A new GPUContextState instance\n */\nexport function createGPUContext(\n  canvas?: HTMLCanvasElement,\n  options?: GPUContextOptions\n): GPUContextState {\n  // Auto-detect DPR on main thread, default to 1.0 in workers\n  const dprRaw =\n    options?.devicePixelRatio ?? (typeof window !== 'undefined' ? window.devicePixelRatio : 1.0);\n  // Be resilient: callers may pass 0/NaN/Infinity. Fall back to 1 instead of throwing.\n  const dpr = Number.isFinite(dprRaw) && dprRaw > 0 ? dprRaw : 1.0;\n  const alphaMode = options?.alphaMode ?? 'opaque';\n  const powerPreference = options?.powerPreference ?? 'high-performance';\n  \n  return {\n    adapter: null,\n    device: null,\n    initialized: false,\n    canvas: canvas || null,\n    canvasContext: null,\n    preferredFormat: null,\n    devicePixelRatio: dpr,\n    alphaMode,\n    powerPreference,\n  };\n}\n\n/**\n * Initializes the WebGPU context by requesting an adapter and device.\n * Returns a new state object with initialized values.\n * \n * @param context - The GPU context state to initialize\n * @returns A new GPUContextState with initialized adapter and device\n * @throws {Error} If WebGPU is not available in the browser\n * @throws {Error} If adapter request fails\n * @throws {Error} If device request fails\n * @throws {Error} If already initialized\n */\nexport async function initializeGPUContext(\n  context: GPUContextState\n): Promise<GPUContextState> {\n  if (context.initialized) {\n    throw new Error('GPUContext is already initialized. Call destroyGPUContext() before reinitializing.');\n  }\n\n  // Be resilient: callers may construct GPUContextState manually.\n  const sanitizedDevicePixelRatio =\n    Number.isFinite(context.devicePixelRatio) && context.devicePixelRatio > 0 ? context.devicePixelRatio : 1.0;\n\n  // Check for WebGPU support\n  if (!navigator.gpu) {\n    throw new Error(\n      'WebGPU is not available in this browser. ' +\n      'Please use a browser that supports WebGPU (Chrome 113+, Edge 113+, or Safari 18+). ' +\n      'Ensure WebGPU is enabled in browser flags if needed.'\n    );\n  }\n\n  let device: GPUDevice | null = null;\n\n  try {\n    // Request adapter with power preference from context\n    const adapter = await navigator.gpu.requestAdapter({\n      powerPreference: context.powerPreference,\n    });\n\n    if (!adapter) {\n      throw new Error(\n        'Failed to request WebGPU adapter. ' +\n        'No compatible adapter found. This may occur if no GPU is available or WebGPU is disabled.'\n      );\n    }\n\n    // Request device from adapter\n    device = await adapter.requestDevice();\n\n    if (!device) {\n      throw new Error('Failed to request WebGPU device from adapter.');\n    }\n\n    // Set up device lost handler for error recovery\n    device.addEventListener('uncapturederror', (event: GPUUncapturedErrorEvent) => {\n      console.error('WebGPU uncaptured error:', event.error);\n    });\n\n    let canvasContext: GPUCanvasContext | null = null;\n    let preferredFormat: GPUTextureFormat | null = null;\n\n    // Configure canvas if provided\n    if (context.canvas) {\n      const webgpuContext = context.canvas.getContext('webgpu') as GPUCanvasContext | null;\n      \n      if (!webgpuContext) {\n        // Clean up device before throwing\n        try {\n          device.destroy();\n        } catch (error) {\n          console.warn('Error destroying device during canvas setup failure:', error);\n        }\n        throw new Error('Failed to get WebGPU context from canvas.');\n      }\n\n      // Use DPR from context state (set at context creation)\n      const { width, height } = getCanvasDimensions(context.canvas);\n      const dpr = sanitizedDevicePixelRatio;\n      \n      // Calculate target dimensions in device pixels\n      // Note: width/height from getCanvasDimensions are in CSS pixels for HTMLCanvasElement,\n      // or device pixels (already set by main thread)\n      const targetWidth = Math.floor(width * dpr);\n      const targetHeight = Math.floor(height * dpr);\n\n      // Clamp to device limits (must happen after device creation)\n      const maxDim = device.limits.maxTextureDimension2D;\n      const finalWidth = Math.max(1, Math.min(targetWidth, maxDim));\n      const finalHeight = Math.max(1, Math.min(targetHeight, maxDim));\n      \n      context.canvas.width = finalWidth;\n      context.canvas.height = finalHeight;\n\n      // Get preferred format from navigator.gpu, fallback to bgra8unorm\n      preferredFormat = navigator.gpu.getPreferredCanvasFormat?.() || 'bgra8unorm';\n\n      // Configure the canvas context with alpha mode from context state\n      webgpuContext.configure({\n        device: device,\n        format: preferredFormat,\n        alphaMode: context.alphaMode,\n      });\n\n      canvasContext = webgpuContext;\n    }\n\n    return {\n      adapter,\n      device,\n      initialized: true,\n      canvas: context.canvas,\n      canvasContext,\n      preferredFormat,\n      devicePixelRatio: sanitizedDevicePixelRatio,\n      alphaMode: context.alphaMode,\n      powerPreference: context.powerPreference,\n    };\n  } catch (error) {\n    // If a device was created but initialization failed, destroy it to avoid leaks.\n    if (device) {\n      try {\n        device.destroy();\n      } catch (destroyError) {\n        console.warn('Error destroying device during initialization failure:', destroyError);\n      }\n    }\n    if (error instanceof Error) {\n      throw error;\n    }\n    throw new Error(`Failed to initialize GPUContext: ${String(error)}`);\n  }\n}\n\n/**\n * Gets the current texture from the canvas context.\n * \n * @param context - The GPU context state\n * @returns The current canvas texture\n * @throws {Error} If canvas is not configured or context is not initialized\n * \n * @example\n * ```typescript\n * const texture = getCanvasTexture(context);\n * // Use texture in render pass\n * ```\n */\nexport function getCanvasTexture(context: GPUContextState): GPUTexture {\n  if (!context.canvas) {\n    throw new Error('Canvas is not configured. Provide a canvas element when creating the context.');\n  }\n\n  if (!context.initialized || !context.canvasContext) {\n    throw new Error('GPUContext is not initialized. Call initializeGPUContext() first.');\n  }\n\n  return context.canvasContext.getCurrentTexture();\n}\n\n/**\n * Clears the canvas to a solid color.\n * Creates a command encoder, begins a render pass with the specified clear color,\n * ends the pass, and submits it to the queue.\n * \n * @param context - The GPU context state\n * @param r - Red component (0.0 to 1.0)\n * @param g - Green component (0.0 to 1.0)\n * @param b - Blue component (0.0 to 1.0)\n * @param a - Alpha component (0.0 to 1.0)\n * @throws {Error} If canvas is not configured or context is not initialized\n * @throws {Error} If device is not available\n * \n * @example\n * ```typescript\n * // Clear to dark purple (#1a1a2e)\n * clearScreen(context, 0x1a / 255, 0x1a / 255, 0x2e / 255, 1.0);\n * ```\n */\nexport function clearScreen(\n  context: GPUContextState,\n  r: number,\n  g: number,\n  b: number,\n  a: number\n): void {\n  // Validate color component ranges\n  if (r < 0 || r > 1 || g < 0 || g > 1 || b < 0 || b > 1 || a < 0 || a > 1) {\n    throw new Error('Color components must be in the range [0.0, 1.0]');\n  }\n\n  if (!context.canvas) {\n    throw new Error('Canvas is not configured. Provide a canvas element when creating the context.');\n  }\n\n  if (!context.initialized || !context.device || !context.canvasContext) {\n    throw new Error('GPUContext is not initialized. Call initializeGPUContext() first.');\n  }\n\n  // Get the current texture from the canvas\n  const texture = getCanvasTexture(context);\n\n  // Create command encoder\n  const encoder = context.device.createCommandEncoder();\n\n  // Begin render pass with clear color\n  const renderPass = encoder.beginRenderPass({\n    colorAttachments: [\n      {\n        view: texture.createView(),\n        clearValue: { r, g, b, a },\n        loadOp: 'clear',\n        storeOp: 'store',\n      },\n    ],\n  });\n\n  // End render pass\n  renderPass.end();\n\n  // Submit command buffer to queue\n  context.device.queue.submit([encoder.finish()]);\n}\n\n/**\n * Destroys the WebGPU device and cleans up resources.\n * Returns a new state object with reset values.\n * After calling this, the context must be reinitialized before use.\n * \n * @param context - The GPU context state to destroy\n * @returns A new GPUContextState with reset values\n */\nexport function destroyGPUContext(context: GPUContextState): GPUContextState {\n  if (context.device) {\n    try {\n      context.device.destroy();\n    } catch (error) {\n      console.warn('Error destroying GPU device:', error);\n    }\n  }\n\n  return {\n    adapter: null,\n    device: null,\n    initialized: false,\n    canvas: context.canvas,\n    canvasContext: null,\n    preferredFormat: null,\n    devicePixelRatio: context.devicePixelRatio,\n    alphaMode: context.alphaMode,\n    powerPreference: context.powerPreference,\n  };\n}\n\n/**\n * Convenience function that creates and initializes a GPU context in one step.\n * \n * @param canvas - Optional canvas element (HTMLCanvasElement) to configure for WebGPU rendering\n * @param options - Optional configuration for device pixel ratio, alpha mode, and power preference\n * @returns A fully initialized GPUContextState\n * @throws {Error} If initialization fails\n * \n * @example\n * ```typescript\n * const context = await createGPUContextAsync();\n * const device = context.device;\n * ```\n * \n * @example\n * ```typescript\n * const canvas = document.querySelector('canvas');\n * const context = await createGPUContextAsync(canvas);\n * const texture = getCanvasTexture(context);\n * ```\n */\nexport async function createGPUContextAsync(\n  canvas?: HTMLCanvasElement,\n  options?: GPUContextOptions\n): Promise<GPUContextState> {\n  const context = createGPUContext(canvas, options);\n  return initializeGPUContext(context);\n}\n\n/**\n * GPUContext class wrapper for backward compatibility.\n * \n * This class provides a class-based API that internally uses the functional implementation.\n * Use the functional API directly for better type safety and immutability.\n */\nexport class GPUContext {\n  private _state: GPUContextState;\n\n  /**\n   * Gets the WebGPU adapter, or null if not initialized.\n   */\n  get adapter(): GPUAdapter | null {\n    return this._state.adapter;\n  }\n\n  /**\n   * Gets the WebGPU device, or null if not initialized.\n   */\n  get device(): GPUDevice | null {\n    return this._state.device;\n  }\n\n  /**\n   * Checks if the context has been initialized.\n   */\n  get initialized(): boolean {\n    return this._state.initialized;\n  }\n\n  /**\n   * Gets the canvas element, or null if not provided.\n   */\n  get canvas(): SupportedCanvas | null {\n    return this._state.canvas;\n  }\n\n  /**\n   * Gets the WebGPU canvas context, or null if canvas is not configured.\n   */\n  get canvasContext(): GPUCanvasContext | null {\n    return this._state.canvasContext;\n  }\n\n  /**\n   * Gets the preferred canvas format, or null if canvas is not configured.\n   */\n  get preferredFormat(): GPUTextureFormat | null {\n    return this._state.preferredFormat;\n  }\n\n  /**\n   * Gets the device pixel ratio used for canvas sizing.\n   */\n  get devicePixelRatio(): number {\n    return this._state.devicePixelRatio;\n  }\n\n  /**\n   * Gets the canvas alpha mode.\n   */\n  get alphaMode(): 'opaque' | 'premultiplied' {\n    return this._state.alphaMode;\n  }\n\n  /**\n   * Gets the GPU power preference.\n   */\n  get powerPreference(): 'low-power' | 'high-performance' {\n    return this._state.powerPreference;\n  }\n\n  /**\n   * Creates a new GPUContext instance.\n   * \n   * @param canvas - Optional canvas element (HTMLCanvasElement) to configure for WebGPU rendering\n   * @param options - Optional configuration for device pixel ratio, alpha mode, and power preference\n   */\n  constructor(canvas?: HTMLCanvasElement, options?: GPUContextOptions) {\n    this._state = createGPUContext(canvas, options);\n  }\n\n  /**\n   * Initializes the WebGPU context by requesting an adapter and device.\n   * \n   * @throws {Error} If WebGPU is not available in the browser\n   * @throws {Error} If adapter request fails\n   * @throws {Error} If device request fails\n   * @throws {Error} If already initialized\n   */\n  async initialize(): Promise<void> {\n    this._state = await initializeGPUContext(this._state);\n  }\n\n  /**\n   * Static factory method to create and initialize a GPUContext instance.\n   * \n   * @param canvas - Optional canvas element (HTMLCanvasElement) to configure for WebGPU rendering\n   * @param options - Optional configuration for device pixel ratio, alpha mode, and power preference\n   * @returns A fully initialized GPUContext instance\n   * @throws {Error} If initialization fails\n   * \n   * @example\n   * ```typescript\n   * const context = await GPUContext.create();\n   * const device = context.device;\n   * ```\n   * \n   * @example\n   * ```typescript\n   * const canvas = document.querySelector('canvas');\n   * const context = await GPUContext.create(canvas);\n   * const texture = context.getCanvasTexture();\n   * ```\n   */\n  static async create(canvas?: HTMLCanvasElement, options?: GPUContextOptions): Promise<GPUContext> {\n    const context = new GPUContext(canvas, options);\n    await context.initialize();\n    return context;\n  }\n\n  /**\n   * Gets the current texture from the canvas context.\n   * \n   * @returns The current canvas texture\n   * @throws {Error} If canvas is not configured or context is not initialized\n   * \n   * @example\n   * ```typescript\n   * const texture = context.getCanvasTexture();\n   * // Use texture in render pass\n   * ```\n   */\n  getCanvasTexture(): GPUTexture {\n    return getCanvasTexture(this._state);\n  }\n\n  /**\n   * Clears the canvas to a solid color.\n   * Creates a command encoder, begins a render pass with the specified clear color,\n   * ends the pass, and submits it to the queue.\n   * \n   * @param r - Red component (0.0 to 1.0)\n   * @param g - Green component (0.0 to 1.0)\n   * @param b - Blue component (0.0 to 1.0)\n   * @param a - Alpha component (0.0 to 1.0)\n   * @throws {Error} If canvas is not configured or context is not initialized\n   * @throws {Error} If device is not available\n   * \n   * @example\n   * ```typescript\n   * // Clear to dark purple (#1a1a2e)\n   * context.clearScreen(0x1a / 255, 0x1a / 255, 0x2e / 255, 1.0);\n   * ```\n   */\n  clearScreen(r: number, g: number, b: number, a: number): void {\n    clearScreen(this._state, r, g, b, a);\n  }\n\n  /**\n   * Destroys the WebGPU device and cleans up resources.\n   * After calling destroy(), the context must be reinitialized before use.\n   */\n  destroy(): void {\n    this._state = destroyGPUContext(this._state);\n  }\n}\n","/**\n * Data point packing utilities for GPU buffer uploads.\n * \n * Internal utilities that convert high-level DataPoint/OHLCDataPoint arrays into\n * interleaved Float32Array buffers suitable for direct GPU buffer uploads via\n * `queue.writeBuffer()`.\n * \n * @module packDataPoints\n * @internal\n */\n\nimport type { DataPoint, OHLCDataPoint, DataPointTuple } from '../config/types';\nimport type { OHLCDataPointTuple, OHLCDataPointObject } from '../config/types';\n\n/**\n * Type guard to check if a DataPoint is in tuple form.\n */\nfunction isTupleDataPoint(point: DataPoint): point is DataPointTuple {\n  return Array.isArray(point);\n}\n\n/**\n * Type guard to check if an OHLCDataPoint is in tuple form.\n */\nfunction isOHLCTuple(point: OHLCDataPoint): point is OHLCDataPointTuple {\n  return Array.isArray(point);\n}\n\n/**\n * Packs DataPoint array into an interleaved Float32Array for GPU buffer uploads.\n * \n * **Internal utility** used by data store for efficient GPU buffer management.\n * \n * **Format**: `[x0, y0, x1, y1, x2, y2, ...]` (2 floats per point = 8 bytes stride)\n * \n * @param points - Array of data points (tuple or object form)\n * @returns Interleaved Float32Array [x0,y0,x1,y1,...] for GPU vertex buffer upload\n * @throws {TypeError} If points is null, undefined, or not an array\n * @throws {RangeError} If points array is empty or contains invalid values\n * @internal\n * \n * @example\n * ```typescript\n * const points = [{ x: 0, y: 10 }, { x: 1, y: 20 }];\n * const packed = packDataPoints(points);\n * // packed = Float32Array[0, 10, 1, 20]\n * \n * // Upload to GPU buffer:\n * device.queue.writeBuffer(vertexBuffer, 0, packed.buffer);\n * ```\n */\nexport function packDataPoints(points: ReadonlyArray<DataPoint>): Float32Array {\n  // Input validation\n  if (!points) {\n    throw new TypeError('packDataPoints: points parameter is required');\n  }\n  \n  if (!Array.isArray(points)) {\n    throw new TypeError('packDataPoints: points must be an array');\n  }\n  \n  if (points.length === 0) {\n    // Return empty array for empty input (valid case)\n    return new Float32Array(0);\n  }\n  \n  // Validate array length doesn't exceed safe limits\n  // Max safe array size: ~2GB / 8 bytes = 268M points\n  const MAX_POINTS = 268_435_456; // 2^28 points = 2GB buffer\n  if (points.length > MAX_POINTS) {\n    throw new RangeError(\n      `packDataPoints: points array too large (${points.length} points). ` +\n      `Maximum supported: ${MAX_POINTS.toLocaleString()} points (2GB buffer limit)`\n    );\n  }\n\n  // Allocate buffer: 2 floats per point × 4 bytes per float = 8 bytes per point\n  const buffer = new ArrayBuffer(points.length * 2 * 4);\n  const f32 = new Float32Array(buffer);\n\n  for (let i = 0; i < points.length; i++) {\n    const point = points[i];\n    \n    // Validate point is not null/undefined\n    if (point === null || point === undefined) {\n      throw new TypeError(\n        `packDataPoints: Invalid point at index ${i}. ` +\n        `Expected DataPoint (tuple or object), got ${point}`\n      );\n    }\n    \n    const x = isTupleDataPoint(point) ? point[0] : point.x;\n    const y = isTupleDataPoint(point) ? point[1] : point.y;\n    \n    // Validate numeric values (catches NaN, undefined properties)\n    if (typeof x !== 'number' || typeof y !== 'number') {\n      throw new TypeError(\n        `packDataPoints: Invalid coordinate values at index ${i}. ` +\n        `Expected numbers, got x=${typeof x}, y=${typeof y}`\n      );\n    }\n    \n    // Note: NaN and Infinity are valid Float32 values and will be preserved\n    // If you need to reject them, add additional checks here\n    \n    f32[i * 2 + 0] = x;\n    f32[i * 2 + 1] = y;\n  }\n\n  return f32;\n}\n\n/**\n * Packs OHLCDataPoint array into an interleaved Float32Array for GPU buffer uploads.\n * \n * **Internal utility** used by data store for efficient candlestick GPU buffer management.\n * \n * **Format**: `[t0, o0, h0, l0, c0, t1, o1, h1, l1, c1, ...]` (5 floats per point = 20 bytes stride)\n * \n * Order follows ECharts convention: timestamp, open, high, low, close (t, o, h, l, c).\n * \n * @param points - Array of OHLC data points (tuple or object form)\n * @returns Interleaved Float32Array [t0,o0,h0,l0,c0,t1,...] for GPU vertex buffer upload\n * @throws {TypeError} If points is null, undefined, or not an array\n * @throws {RangeError} If points array is empty or contains invalid values\n * @internal\n * \n * @example\n * ```typescript\n * const ohlcPoints = [\n *   { timestamp: 1000, open: 100, high: 110, low: 95, close: 105 },\n *   { timestamp: 2000, open: 105, high: 115, low: 100, close: 110 }\n * ];\n * const packed = packOHLCDataPoints(ohlcPoints);\n * // packed = Float32Array[1000, 100, 110, 95, 105, 2000, 105, 115, 100, 110]\n * \n * // Upload to GPU buffer:\n * device.queue.writeBuffer(vertexBuffer, 0, packed.buffer);\n * ```\n */\nexport function packOHLCDataPoints(points: ReadonlyArray<OHLCDataPoint>): Float32Array {\n  // Input validation\n  if (!points) {\n    throw new TypeError('packOHLCDataPoints: points parameter is required');\n  }\n  \n  if (!Array.isArray(points)) {\n    throw new TypeError('packOHLCDataPoints: points must be an array');\n  }\n  \n  if (points.length === 0) {\n    // Return empty array for empty input (valid case)\n    return new Float32Array(0);\n  }\n  \n  // Validate array length doesn't exceed safe limits\n  // Max safe array size: ~2GB / 20 bytes = 107M points\n  const MAX_POINTS = 107_374_182; // 2^30 / 10 points = ~2GB buffer\n  if (points.length > MAX_POINTS) {\n    throw new RangeError(\n      `packOHLCDataPoints: points array too large (${points.length} points). ` +\n      `Maximum supported: ${MAX_POINTS.toLocaleString()} points (2GB buffer limit)`\n    );\n  }\n\n  // Allocate buffer: 5 floats per point × 4 bytes per float = 20 bytes per point\n  const buffer = new ArrayBuffer(points.length * 5 * 4);\n  const f32 = new Float32Array(buffer);\n\n  for (let i = 0; i < points.length; i++) {\n    const point = points[i];\n    \n    // Validate point is not null/undefined\n    if (point === null || point === undefined) {\n      throw new TypeError(\n        `packOHLCDataPoints: Invalid point at index ${i}. ` +\n        `Expected OHLCDataPoint (tuple or object), got ${point}`\n      );\n    }\n    \n    if (isOHLCTuple(point)) {\n      // Tuple form: [timestamp, open, close, low, high]\n      // NOTE: ECharts convention is [t, o, c, l, h] but we store as [t, o, h, l, c]\n      \n      // Validate tuple has 5 elements\n      if (point.length !== 5) {\n        throw new TypeError(\n          `packOHLCDataPoints: Invalid OHLC tuple at index ${i}. ` +\n          `Expected 5 elements [timestamp, open, close, low, high], got ${point.length}`\n        );\n      }\n      \n      const timestamp = point[0];\n      const open = point[1];\n      const close = point[2];\n      const low = point[3];\n      const high = point[4];\n      \n      // Validate all values are numbers\n      if (typeof timestamp !== 'number' || typeof open !== 'number' || \n          typeof close !== 'number' || typeof low !== 'number' || typeof high !== 'number') {\n        throw new TypeError(\n          `packOHLCDataPoints: Invalid OHLC values at index ${i}. ` +\n          `All values must be numbers, got [${typeof timestamp}, ${typeof open}, ${typeof close}, ${typeof low}, ${typeof high}]`\n        );\n      }\n      \n      f32[i * 5 + 0] = timestamp;\n      f32[i * 5 + 1] = open;\n      f32[i * 5 + 2] = high; // Reorder: high comes from index 4\n      f32[i * 5 + 3] = low;  // Reorder: low from index 3\n      f32[i * 5 + 4] = close; // Reorder: close from index 2\n    } else {\n      // Object form: { timestamp, open, close, low, high }\n      const ohlcObj = point as OHLCDataPointObject;\n      \n      const { timestamp, open, high, low, close } = ohlcObj;\n      \n      // Validate all required properties exist and are numbers\n      if (typeof timestamp !== 'number' || typeof open !== 'number' || \n          typeof high !== 'number' || typeof low !== 'number' || typeof close !== 'number') {\n        throw new TypeError(\n          `packOHLCDataPoints: Invalid OHLC object at index ${i}. ` +\n          `All properties (timestamp, open, high, low, close) must be numbers, got ` +\n          `{timestamp: ${typeof timestamp}, open: ${typeof open}, high: ${typeof high}, low: ${typeof low}, close: ${typeof close}}`\n        );\n      }\n      \n      f32[i * 5 + 0] = timestamp;\n      f32[i * 5 + 1] = open;\n      f32[i * 5 + 2] = high;\n      f32[i * 5 + 3] = low;\n      f32[i * 5 + 4] = close;\n    }\n  }\n\n  return f32;\n}\n","import type { DataPoint, DataPointTuple } from '../config/types';\nimport { packDataPoints } from './packDataPoints';\n\nexport interface DataStore {\n  setSeries(\n    index: number,\n    data: ReadonlyArray<DataPoint>,\n    options?: Readonly<{ xOffset?: number }>\n  ): void;\n  /**\n   * Appends new points to an existing series without re-uploading the entire buffer when possible.\n   *\n   * - Reuses the same geometric growth policy as `setSeries`.\n   * - When no reallocation is needed, writes only the appended byte range via `queue.writeBuffer(...)`.\n   * - Maintains `pointCount` and a CPU-side combined data array so `getSeriesData(...)` remains correct.\n   *\n   * Throws if the series has not been set yet.\n   */\n  appendSeries(index: number, newPoints: ReadonlyArray<DataPoint>): void;\n  removeSeries(index: number): void;\n  getSeriesBuffer(index: number): GPUBuffer;\n  /**\n   * Returns the number of points last set for the given series index.\n   *\n   * Throws if the series has not been set yet.\n   */\n  getSeriesPointCount(index: number): number;\n  /**\n   * Returns the last CPU-side data set for the given series index.\n   *\n   * This is intended for internal metadata/hit-testing paths that need the same\n   * input array that was packed into the GPU buffer (without re-threading it\n   * through other state). Throws if the series has not been set yet.\n   */\n  getSeriesData(index: number): ReadonlyArray<DataPoint>;\n  dispose(): void;\n}\n\ntype SeriesEntry = {\n  readonly buffer: GPUBuffer;\n  readonly capacityBytes: number;\n  readonly pointCount: number;\n  readonly hash32: number;\n  /**\n   * X-origin subtracted during packing to preserve Float32 precision for large-magnitude domains\n   * (e.g. epoch-ms time axes). Stored so appendSeries can pack consistently.\n   */\n  readonly xOffset: number;\n  // Store a mutable array so streaming append can update in-place.\n  readonly data: DataPoint[];\n};\n\nconst MIN_BUFFER_BYTES = 4;\n\nfunction roundUpToMultipleOf4(bytes: number): number {\n  return (bytes + 3) & ~3;\n}\n\nfunction nextPow2(bytes: number): number {\n  if (!Number.isFinite(bytes) || bytes <= 0) return 1;\n  const n = Math.ceil(bytes);\n  return 2 ** Math.ceil(Math.log2(n));\n}\n\nfunction computeGrownCapacityBytes(currentCapacityBytes: number, requiredBytes: number): number {\n  // Grow geometrically to reduce buffer churn (power-of-two policy).\n  // Enforce 4-byte alignment via MIN_BUFFER_BYTES (>= 4) and power-of-two growth.\n  const required = Math.max(MIN_BUFFER_BYTES, roundUpToMultipleOf4(requiredBytes));\n  const grown = Math.max(MIN_BUFFER_BYTES, nextPow2(required));\n  return Math.max(currentCapacityBytes, grown);\n}\n\nfunction fnv1aUpdate(hash: number, words: Uint32Array): number {\n  let h = hash >>> 0;\n  for (let i = 0; i < words.length; i++) {\n    h ^= words[i]!;\n    h = Math.imul(h, 0x01000193) >>> 0; // FNV prime\n  }\n  return h >>> 0;\n}\n\n/**\n * Computes a stable 32-bit hash of the Float32 contents using their IEEE-754\n * bit patterns (not numeric equality), to cheaply detect changes.\n */\nfunction hashFloat32ArrayBits(data: Float32Array): number {\n  const u32 = new Uint32Array(data.buffer, data.byteOffset, data.byteLength / 4);\n  return fnv1aUpdate(0x811c9dc5, u32); // FNV-1a offset basis\n}\n\nexport function createDataStore(device: GPUDevice): DataStore {\n  const series = new Map<number, SeriesEntry>();\n  let disposed = false;\n\n  // Type guard (avoid relying on Array.isArray narrowing for readonly tuples in strict TS configs).\n  const isTupleDataPoint = (p: DataPoint): p is DataPointTuple => Array.isArray(p);\n\n  const packDataPointsWithXOffset = (points: ReadonlyArray<DataPoint>, xOffset: number): Float32Array => {\n    if (!points || points.length === 0) return new Float32Array(0);\n\n    const buffer = new ArrayBuffer(points.length * 2 * 4);\n    const f32 = new Float32Array(buffer);\n\n    // Hot path: keep logic minimal (validation happens elsewhere in option resolution).\n    for (let i = 0; i < points.length; i++) {\n      const p = points[i]!;\n      const x = isTupleDataPoint(p) ? p[0] : p.x;\n      const y = isTupleDataPoint(p) ? p[1] : p.y;\n\n      // Subtracting before the Float32 cast preserves sub-ULP deltas for large x magnitudes.\n      f32[i * 2 + 0] = x - xOffset;\n      f32[i * 2 + 1] = y;\n    }\n\n    return f32;\n  };\n\n  const assertNotDisposed = (): void => {\n    if (disposed) {\n      throw new Error('DataStore is disposed.');\n    }\n  };\n\n  const getSeriesEntry = (index: number): SeriesEntry => {\n    assertNotDisposed();\n    const entry = series.get(index);\n    if (!entry) {\n      throw new Error(`Series ${index} has no data. Call setSeries(${index}, data) first.`);\n    }\n    return entry;\n  };\n\n  const setSeries = (index: number, data: ReadonlyArray<DataPoint>, options?: Readonly<{ xOffset?: number }>): void => {\n    assertNotDisposed();\n\n    const xOffset = options?.xOffset ?? 0;\n    const packed = xOffset === 0 ? packDataPoints(data) : packDataPointsWithXOffset(data, xOffset);\n    const pointCount = data.length;\n    const hash32 = hashFloat32ArrayBits(packed);\n\n    const requiredBytes = roundUpToMultipleOf4(packed.byteLength);\n    const targetBytes = Math.max(MIN_BUFFER_BYTES, requiredBytes);\n\n    const existing = series.get(index);\n    const unchanged = existing && existing.pointCount === pointCount && existing.hash32 === hash32;\n    if (unchanged) return;\n\n    let buffer = existing?.buffer ?? null;\n    let capacityBytes = existing?.capacityBytes ?? 0;\n\n    if (!buffer || targetBytes > capacityBytes) {\n      const maxBufferSize = device.limits.maxBufferSize;\n      if (targetBytes > maxBufferSize) {\n        throw new Error(\n          `DataStore.setSeries(${index}): required buffer size ${targetBytes} exceeds device.limits.maxBufferSize (${maxBufferSize}).`\n        );\n      }\n\n      if (buffer) {\n        try {\n          buffer.destroy();\n        } catch {\n          // Ignore destroy errors; we are replacing the buffer anyway.\n        }\n      }\n\n      const grownCapacityBytes = computeGrownCapacityBytes(capacityBytes, targetBytes);\n      if (grownCapacityBytes > maxBufferSize) {\n        // If geometric growth would exceed the limit, fall back to the exact required size.\n        // (Still no shrink: if current capacity was already larger, we'd keep it above.)\n        // NOTE: targetBytes is already checked against maxBufferSize above.\n        capacityBytes = targetBytes;\n      } else {\n        capacityBytes = grownCapacityBytes;\n      }\n\n      buffer = device.createBuffer({\n        size: capacityBytes,\n        usage: GPUBufferUsage.VERTEX | GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_DST,\n      });\n    }\n\n    // Avoid 0-byte writes (empty series). The buffer is still valid for binding.\n    if (packed.byteLength > 0) {\n      device.queue.writeBuffer(buffer, 0, packed.buffer);\n    }\n\n    series.set(index, {\n      buffer,\n      capacityBytes,\n      pointCount,\n      hash32,\n      xOffset,\n      data: data.length === 0 ? [] : data.slice(),\n    });\n  };\n\n  const appendSeries = (index: number, newPoints: ReadonlyArray<DataPoint>): void => {\n    assertNotDisposed();\n    if (!newPoints || newPoints.length === 0) return;\n\n    const existing = getSeriesEntry(index);\n    const prevPointCount = existing.pointCount;\n    const nextPointCount = prevPointCount + newPoints.length;\n\n    const appendPacked =\n      existing.xOffset === 0 ? packDataPoints(newPoints) : packDataPointsWithXOffset(newPoints, existing.xOffset);\n    const appendBytes = appendPacked.byteLength;\n\n    // Each point is 2 floats (x, y) = 8 bytes.\n    const requiredBytes = roundUpToMultipleOf4(nextPointCount * 2 * 4);\n    const targetBytes = Math.max(MIN_BUFFER_BYTES, requiredBytes);\n\n    let buffer = existing.buffer;\n    let capacityBytes = existing.capacityBytes;\n\n    // Ensure the CPU-side store is updated regardless of GPU growth path.\n    const nextData = existing.data;\n    nextData.push(...newPoints);\n\n    const maxBufferSize = device.limits.maxBufferSize;\n\n    if (targetBytes > capacityBytes) {\n      if (targetBytes > maxBufferSize) {\n        throw new Error(\n          `DataStore.appendSeries(${index}): required buffer size ${targetBytes} exceeds device.limits.maxBufferSize (${maxBufferSize}).`\n        );\n      }\n\n      // Replace buffer (no shrink). This is the slow path; we re-upload the full series.\n      try {\n        buffer.destroy();\n      } catch {\n        // Ignore destroy errors; we are replacing the buffer anyway.\n      }\n\n      const grownCapacityBytes = computeGrownCapacityBytes(capacityBytes, targetBytes);\n      capacityBytes = grownCapacityBytes > maxBufferSize ? targetBytes : grownCapacityBytes;\n\n      buffer = device.createBuffer({\n        size: capacityBytes,\n        usage: GPUBufferUsage.VERTEX | GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_DST,\n      });\n\n      const fullPacked =\n        existing.xOffset === 0 ? packDataPoints(nextData) : packDataPointsWithXOffset(nextData, existing.xOffset);\n      if (fullPacked.byteLength > 0) {\n        device.queue.writeBuffer(buffer, 0, fullPacked.buffer);\n      }\n\n      series.set(index, {\n        buffer,\n        capacityBytes,\n        pointCount: nextPointCount,\n        hash32: hashFloat32ArrayBits(fullPacked),\n        xOffset: existing.xOffset,\n        data: nextData,\n      });\n      return;\n    }\n\n    // Fast path: write only the appended range into the existing buffer.\n    if (appendBytes > 0) {\n      const byteOffset = prevPointCount * 2 * 4;\n      device.queue.writeBuffer(buffer, byteOffset, appendPacked.buffer);\n    }\n\n    // Incremental FNV-1a update over the appended IEEE-754 bit patterns.\n    const appendWords = new Uint32Array(appendPacked.buffer, appendPacked.byteOffset, appendPacked.byteLength / 4);\n    const nextHash32 = fnv1aUpdate(existing.hash32, appendWords);\n\n    series.set(index, {\n      buffer,\n      capacityBytes,\n      pointCount: nextPointCount,\n      hash32: nextHash32,\n      xOffset: existing.xOffset,\n      data: nextData,\n    });\n  };\n\n  const removeSeries = (index: number): void => {\n    assertNotDisposed();\n\n    const entry = series.get(index);\n    if (!entry) return;\n\n    try {\n      entry.buffer.destroy();\n    } catch {\n      // Ignore destroy errors; removal should be best-effort.\n    }\n    series.delete(index);\n  };\n\n  const getSeriesBuffer = (index: number): GPUBuffer => {\n    return getSeriesEntry(index).buffer;\n  };\n\n  const getSeriesPointCount = (index: number): number => {\n    return getSeriesEntry(index).pointCount;\n  };\n\n  const getSeriesData = (index: number): ReadonlyArray<DataPoint> => {\n    return getSeriesEntry(index).data;\n  };\n\n  const dispose = (): void => {\n    if (disposed) return;\n    disposed = true;\n\n    for (const entry of series.values()) {\n      try {\n        entry.buffer.destroy();\n      } catch {\n        // Ignore destroy errors; disposal should be best-effort.\n      }\n    }\n    series.clear();\n  };\n\n  return {\n    setSeries,\n    appendSeries,\n    removeSeries,\n    getSeriesBuffer,\n    getSeriesPointCount,\n    getSeriesData,\n    dispose,\n  };\n}\n\n","import type { DataPoint, DataPointTuple } from '../config/types';\n\nfunction isTupleDataPoint(point: DataPoint): point is DataPointTuple {\n  // `DataPoint` uses a readonly tuple; `Array.isArray` doesn't narrow it well without a predicate.\n  return Array.isArray(point);\n}\n\nfunction lttbIndicesForInterleavedXY(data: Float32Array, targetPoints: number): Int32Array {\n  const n = data.length >>> 1; // floor(length / 2)\n  const lastIndex = n - 1;\n\n  if (targetPoints <= 0 || n === 0) return new Int32Array(0);\n  if (targetPoints === 1) return new Int32Array([0]);\n  if (targetPoints === 2) return n >= 2 ? new Int32Array([0, lastIndex]) : new Int32Array([0]);\n  if (n <= targetPoints) {\n    const indices = new Int32Array(n);\n    for (let i = 0; i < n; i++) indices[i] = i;\n    return indices;\n  }\n\n  const indices = new Int32Array(targetPoints);\n  indices[0] = 0;\n  indices[targetPoints - 1] = lastIndex;\n\n  const bucketSize = (n - 2) / (targetPoints - 2);\n\n  let a = 0;\n  let out = 1;\n\n  const lastX = data[lastIndex * 2 + 0];\n  const lastY = data[lastIndex * 2 + 1];\n\n  for (let bucket = 0; bucket < targetPoints - 2; bucket++) {\n    // Current bucket: candidate points are [rangeStart, rangeEndExclusive) and never include lastIndex.\n    let rangeStart = Math.floor(bucketSize * bucket) + 1;\n    let rangeEndExclusive = Math.min(Math.floor(bucketSize * (bucket + 1)) + 1, lastIndex);\n    if (rangeStart >= rangeEndExclusive) {\n      // Defensive: ensure at least one candidate point.\n      rangeStart = Math.min(rangeStart, lastIndex - 1);\n      rangeEndExclusive = Math.min(rangeStart + 1, lastIndex);\n    }\n\n    // Next bucket for average: [nextRangeStart, nextRangeEndExclusive)\n    const nextRangeStart = Math.floor(bucketSize * (bucket + 1)) + 1;\n    const nextRangeEndExclusive = Math.min(Math.floor(bucketSize * (bucket + 2)) + 1, lastIndex);\n\n    // If there are no points in the next bucket, use the last point as the average.\n    let avgX = lastX;\n    let avgY = lastY;\n    if (nextRangeStart < nextRangeEndExclusive) {\n      let sumX = 0;\n      let sumY = 0;\n      let avgCount = 0;\n      for (let i = nextRangeStart; i < nextRangeEndExclusive; i++) {\n        sumX += data[i * 2 + 0];\n        sumY += data[i * 2 + 1];\n        avgCount++;\n      }\n      if (avgCount > 0) {\n        avgX = sumX / avgCount;\n        avgY = sumY / avgCount;\n      }\n    }\n\n    const ax = data[a * 2 + 0];\n    const ay = data[a * 2 + 1];\n\n    let maxArea = -1;\n    let maxIndex = rangeStart;\n    for (let i = rangeStart; i < rangeEndExclusive; i++) {\n      const bx = data[i * 2 + 0];\n      const by = data[i * 2 + 1];\n      const area2 = (ax - avgX) * (by - ay) - (ax - bx) * (avgY - ay);\n      const absArea2 = area2 < 0 ? -area2 : area2;\n      if (absArea2 > maxArea) {\n        maxArea = absArea2;\n        maxIndex = i;\n      }\n    }\n\n    indices[out++] = maxIndex;\n    a = maxIndex;\n  }\n\n  return indices;\n}\n\nfunction lttbIndicesForDataPoints(data: ReadonlyArray<DataPoint>, targetPoints: number): Int32Array {\n  const n = data.length;\n  const lastIndex = n - 1;\n\n  if (targetPoints <= 0 || n === 0) return new Int32Array(0);\n  if (targetPoints === 1) return new Int32Array([0]);\n  if (targetPoints === 2) return n >= 2 ? new Int32Array([0, lastIndex]) : new Int32Array([0]);\n  if (n <= targetPoints) {\n    const indices = new Int32Array(n);\n    for (let i = 0; i < n; i++) indices[i] = i;\n    return indices;\n  }\n\n  const indices = new Int32Array(targetPoints);\n  indices[0] = 0;\n  indices[targetPoints - 1] = lastIndex;\n\n  const bucketSize = (n - 2) / (targetPoints - 2);\n\n  let a = 0;\n  let out = 1;\n\n  const pLast = data[lastIndex]!;\n  const lastX = isTupleDataPoint(pLast) ? pLast[0] : pLast.x;\n  const lastY = isTupleDataPoint(pLast) ? pLast[1] : pLast.y;\n\n  for (let bucket = 0; bucket < targetPoints - 2; bucket++) {\n    // Current bucket: candidate points are [rangeStart, rangeEndExclusive) and never include lastIndex.\n    let rangeStart = Math.floor(bucketSize * bucket) + 1;\n    let rangeEndExclusive = Math.min(Math.floor(bucketSize * (bucket + 1)) + 1, lastIndex);\n    if (rangeStart >= rangeEndExclusive) {\n      // Defensive: ensure at least one candidate point.\n      rangeStart = Math.min(rangeStart, lastIndex - 1);\n      rangeEndExclusive = Math.min(rangeStart + 1, lastIndex);\n    }\n\n    // Next bucket for average: [nextRangeStart, nextRangeEndExclusive)\n    const nextRangeStart = Math.floor(bucketSize * (bucket + 1)) + 1;\n    const nextRangeEndExclusive = Math.min(Math.floor(bucketSize * (bucket + 2)) + 1, lastIndex);\n\n    // If there are no points in the next bucket, use the last point as the average.\n    let avgX = lastX;\n    let avgY = lastY;\n    if (nextRangeStart < nextRangeEndExclusive) {\n      let sumX = 0;\n      let sumY = 0;\n      let avgCount = 0;\n      for (let i = nextRangeStart; i < nextRangeEndExclusive; i++) {\n        const p = data[i]!;\n        const x = isTupleDataPoint(p) ? p[0] : p.x;\n        const y = isTupleDataPoint(p) ? p[1] : p.y;\n        sumX += x;\n        sumY += y;\n        avgCount++;\n      }\n      if (avgCount > 0) {\n        avgX = sumX / avgCount;\n        avgY = sumY / avgCount;\n      }\n    }\n\n    const pa = data[a]!;\n    const ax = isTupleDataPoint(pa) ? pa[0] : pa.x;\n    const ay = isTupleDataPoint(pa) ? pa[1] : pa.y;\n\n    let maxArea = -1;\n    let maxIndex = rangeStart;\n    for (let i = rangeStart; i < rangeEndExclusive; i++) {\n      const pb = data[i]!;\n      const bx = isTupleDataPoint(pb) ? pb[0] : pb.x;\n      const by = isTupleDataPoint(pb) ? pb[1] : pb.y;\n      const area2 = (ax - avgX) * (by - ay) - (ax - bx) * (avgY - ay);\n      const absArea2 = area2 < 0 ? -area2 : area2;\n      if (absArea2 > maxArea) {\n        maxArea = absArea2;\n        maxIndex = i;\n      }\n    }\n\n    indices[out++] = maxIndex;\n    a = maxIndex;\n  }\n\n  return indices;\n}\n\nexport function lttbSample(data: Float32Array, targetPoints: number): Float32Array;\nexport function lttbSample(data: DataPoint[], targetPoints: number): DataPoint[];\nexport function lttbSample(data: ReadonlyArray<DataPoint>, targetPoints: number): ReadonlyArray<DataPoint>;\nexport function lttbSample(\n  data: ReadonlyArray<DataPoint> | Float32Array,\n  targetPoints: number\n): ReadonlyArray<DataPoint> | Float32Array {\n  const threshold = Math.floor(targetPoints);\n\n  if (data instanceof Float32Array) {\n    const n = data.length >>> 1;\n    if (threshold <= 0 || n === 0) return new Float32Array(0);\n\n    // If we're already under the target, avoid copying.\n    if (n <= threshold) return data;\n\n    const indices = lttbIndicesForInterleavedXY(data, threshold);\n    const out = new Float32Array(indices.length * 2);\n    for (let i = 0; i < indices.length; i++) {\n      const idx = indices[i]!;\n      out[i * 2 + 0] = data[idx * 2 + 0];\n      out[i * 2 + 1] = data[idx * 2 + 1];\n    }\n    return out;\n  }\n\n  const n = data.length;\n  if (threshold <= 0 || n === 0) return [];\n\n  // Story requirement: when data is shorter than the target, return original.\n  if (n <= threshold) return data;\n\n  const indices = lttbIndicesForDataPoints(data, threshold);\n  const out = new Array<DataPoint>(indices.length);\n  for (let i = 0; i < indices.length; i++) {\n    out[i] = data[indices[i]!]!;\n  }\n  return out;\n}\n\n","/**\n * Internal cartesian data abstraction for CartesianSeriesData.\n *\n * Provides high-performance, allocation-minimizing primitives to support all three cartesian formats:\n * - ReadonlyArray<DataPoint> (tuple or object)\n * - XYArraysData (separate x/y/size arrays)\n * - InterleavedXYData (typed array view with [x0,y0,x1,y1,...] layout)\n *\n * DO NOT export from public entrypoint (src/index.ts). This is internal-only.\n *\n * @module cartesianData\n * @internal\n */\n\nimport type { CartesianSeriesData, DataPoint, XYArraysData, InterleavedXYData } from '../config/types';\n\n/**\n * Bounds type for min/max x and y values.\n */\nexport type Bounds = Readonly<{ xMin: number; xMax: number; yMin: number; yMax: number }>;\n\n/**\n * Type for typed arrays with numeric indexing (excluding DataView and BigInt arrays).\n * BigInt arrays are excluded because coordinates must be numbers, not bigints.\n */\ntype TypedArray = \n  | Int8Array\n  | Uint8Array\n  | Uint8ClampedArray\n  | Int16Array\n  | Uint16Array\n  | Int32Array\n  | Uint32Array\n  | Float32Array\n  | Float64Array;\n\n/**\n * Type guard for XYArraysData format.\n */\nfunction isXYArraysData(data: CartesianSeriesData): data is XYArraysData {\n  return (\n    typeof data === 'object' &&\n    data !== null &&\n    !Array.isArray(data) &&\n    'x' in data &&\n    'y' in data &&\n    typeof (data as any).x === 'object' &&\n    typeof (data as any).y === 'object' &&\n    'length' in (data as any).x &&\n    'length' in (data as any).y\n  );\n}\n\n/**\n * Type guard for InterleavedXYData format (ArrayBufferView).\n */\nfunction isInterleavedXYData(data: CartesianSeriesData): data is InterleavedXYData {\n  return (\n    typeof data === 'object' &&\n    data !== null &&\n    !Array.isArray(data) &&\n    ArrayBuffer.isView(data)\n  );\n}\n\n/**\n * Type guard for tuple DataPoint format.\n */\nfunction isTupleDataPoint(p: DataPoint): p is readonly [number, number, number?] {\n  return Array.isArray(p);\n}\n\n/**\n * Returns the number of points in the CartesianSeriesData.\n */\nexport function getPointCount(data: CartesianSeriesData): number {\n  if (isXYArraysData(data)) {\n    // Use minimum of x and y array lengths for safety\n    return Math.min(data.x.length, data.y.length);\n  }\n  \n  if (isInterleavedXYData(data)) {\n    // DataView is unsupported - throw clear error\n    if (data instanceof DataView) {\n      throw new Error('DataView is not supported for InterleavedXYData. Use typed arrays (Float32Array, Float64Array, etc.).');\n    }\n    // Interpret pointCount as floor(length/2), tolerant of odd length\n    // Cast to typed array with numeric indexing after DataView check\n    const arr = data as TypedArray;\n    return Math.floor(arr.length / 2);\n  }\n  \n  // ReadonlyArray<DataPoint>\n  return data.length;\n}\n\n/**\n * Returns the x-coordinate of the point at index i.\n */\nexport function getX(data: CartesianSeriesData, i: number): number {\n  if (isXYArraysData(data)) {\n    return data.x[i]!;\n  }\n  \n  if (isInterleavedXYData(data)) {\n    if (data instanceof DataView) {\n      throw new Error('DataView is not supported for InterleavedXYData. Use typed arrays (Float32Array, Float64Array, etc.).');\n    }\n    const arr = data as TypedArray;\n    return arr[i * 2]!;\n  }\n  \n  // ReadonlyArray<DataPoint>\n  const p = data[i]!;\n  return isTupleDataPoint(p) ? p[0] : p.x;\n}\n\n/**\n * Returns the y-coordinate of the point at index i.\n */\nexport function getY(data: CartesianSeriesData, i: number): number {\n  if (isXYArraysData(data)) {\n    return data.y[i]!;\n  }\n  \n  if (isInterleavedXYData(data)) {\n    if (data instanceof DataView) {\n      throw new Error('DataView is not supported for InterleavedXYData. Use typed arrays (Float32Array, Float64Array, etc.).');\n    }\n    const arr = data as TypedArray;\n    return arr[i * 2 + 1]!;\n  }\n  \n  // ReadonlyArray<DataPoint>\n  const p = data[i]!;\n  return isTupleDataPoint(p) ? p[1] : p.y;\n}\n\n/**\n * Returns the size value of the point at index i, or undefined if not available.\n * Note: InterleavedXYData does NOT support interleaved size (use XYArraysData.size if needed).\n */\nexport function getSize(data: CartesianSeriesData, i: number): number | undefined {\n  if (isXYArraysData(data)) {\n    return data.size?.[i];\n  }\n  \n  if (isInterleavedXYData(data)) {\n    // Size is not interleaved in InterleavedXYData format\n    return undefined;\n  }\n  \n  // ReadonlyArray<DataPoint>\n  const p = data[i]!;\n  return isTupleDataPoint(p) ? p[2] : p.size;\n}\n\n/**\n * Packs XY coordinates from CartesianSeriesData into a Float32Array in interleaved layout.\n * \n * Writes `pointCount` points starting at `srcPointOffset` in the source data\n * into `out` starting at `outFloatOffset` (measured in float32 elements, not bytes).\n * \n * Each point writes 2 floats: [x - xOffset, y].\n * Size dimension is NOT packed (use getSize() separately if needed).\n * \n * @param out - Target Float32Array to write into\n * @param outFloatOffset - Starting offset in `out` (in float32 elements)\n * @param src - Source CartesianSeriesData\n * @param srcPointOffset - Starting point index in source\n * @param pointCount - Number of points to pack\n * @param xOffset - Value to subtract from x coordinates (for Float32 precision preservation)\n */\nexport function packXYInto(\n  out: Float32Array,\n  outFloatOffset: number,\n  src: CartesianSeriesData,\n  srcPointOffset: number,\n  pointCount: number,\n  xOffset: number\n): void {\n  const availablePoints = getPointCount(src) - srcPointOffset;\n  const actualPointCount = Math.min(pointCount, availablePoints);\n  \n  if (actualPointCount <= 0) return;\n  \n  // Validate output buffer capacity\n  const requiredOutLength = outFloatOffset + actualPointCount * 2;\n  if (requiredOutLength > out.length) {\n    throw new Error(\n      `packXYInto: output buffer too small (need ${requiredOutLength} floats, have ${out.length})`\n    );\n  }\n  \n  if (isXYArraysData(src)) {\n    // Fast path: bulk copy with xOffset adjustment\n    for (let i = 0; i < actualPointCount; i++) {\n      const srcIdx = srcPointOffset + i;\n      const outIdx = outFloatOffset + i * 2;\n      out[outIdx] = src.x[srcIdx]! - xOffset;\n      out[outIdx + 1] = src.y[srcIdx]!;\n    }\n    return;\n  }\n  \n  if (isInterleavedXYData(src)) {\n    if (src instanceof DataView) {\n      throw new Error('DataView is not supported for InterleavedXYData. Use typed arrays (Float32Array, Float64Array, etc.).');\n    }\n    \n    const arr = src as TypedArray;\n    \n    // Fast path: bulk copy with xOffset adjustment\n    for (let i = 0; i < actualPointCount; i++) {\n      const srcIdx = (srcPointOffset + i) * 2;\n      const outIdx = outFloatOffset + i * 2;\n      out[outIdx] = arr[srcIdx]! - xOffset;\n      out[outIdx + 1] = arr[srcIdx + 1]!;\n    }\n    return;\n  }\n  \n  // ReadonlyArray<DataPoint> path\n  for (let i = 0; i < actualPointCount; i++) {\n    const srcIdx = srcPointOffset + i;\n    const outIdx = outFloatOffset + i * 2;\n    const p = src[srcIdx]!;\n    \n    const x = isTupleDataPoint(p) ? p[0] : p.x;\n    const y = isTupleDataPoint(p) ? p[1] : p.y;\n    \n    out[outIdx] = x - xOffset;\n    out[outIdx + 1] = y;\n  }\n}\n\n/**\n * Computes xMin/xMax/yMin/yMax bounds from CartesianSeriesData.\n * Skips non-finite x or y values. Returns null if no finite points found.\n * Ensures xMin !== xMax and yMin !== yMax for scale derivation (expands max by +1 if needed).\n *\n * @param data - CartesianSeriesData in any supported format\n * @returns Bounds object or null if no finite points\n */\nexport function computeRawBoundsFromCartesianData(data: CartesianSeriesData): Bounds | null {\n  let xMin = Number.POSITIVE_INFINITY;\n  let xMax = Number.NEGATIVE_INFINITY;\n  let yMin = Number.POSITIVE_INFINITY;\n  let yMax = Number.NEGATIVE_INFINITY;\n  \n  const count = getPointCount(data);\n  \n  for (let i = 0; i < count; i++) {\n    const x = getX(data, i);\n    const y = getY(data, i);\n    \n    if (!Number.isFinite(x) || !Number.isFinite(y)) continue;\n    \n    if (x < xMin) xMin = x;\n    if (x > xMax) xMax = x;\n    if (y < yMin) yMin = y;\n    if (y > yMax) yMax = y;\n  }\n  \n  if (!Number.isFinite(xMin) || !Number.isFinite(xMax) || !Number.isFinite(yMin) || !Number.isFinite(yMax)) {\n    return null;\n  }\n  \n  // Preserve existing behavior: if min==max, expand max by +1 for usability\n  if (xMin === xMax) xMax = xMin + 1;\n  if (yMin === yMax) yMax = yMin + 1;\n  \n  return { xMin, xMax, yMin, yMax };\n}\n","import type { CartesianSeriesData, DataPointTuple, SeriesSampling } from '../config/types';\nimport { lttbSample } from './lttbSample';\nimport { getPointCount, getX, getY, getSize as getPointSize } from './cartesianData';\n\n\nfunction clampTargetPoints(targetPoints: number): number {\n  const t = Math.floor(targetPoints);\n  return Number.isFinite(t) ? t : 0;\n}\n\n/**\n * Type guard for XYArraysData format.\n */\nfunction isXYArraysData(data: CartesianSeriesData): data is import('../config/types').XYArraysData {\n  return (\n    typeof data === 'object' &&\n    data !== null &&\n    !Array.isArray(data) &&\n    'x' in data &&\n    'y' in data &&\n    typeof (data as any).x === 'object' &&\n    typeof (data as any).y === 'object' &&\n    'length' in (data as any).x &&\n    'length' in (data as any).y\n  );\n}\n\n/**\n * Type guard for InterleavedXYData format (ArrayBufferView).\n */\nfunction isInterleavedXYData(data: CartesianSeriesData): data is import('../config/types').InterleavedXYData {\n  return (\n    typeof data === 'object' &&\n    data !== null &&\n    !Array.isArray(data) &&\n    ArrayBuffer.isView(data)\n  );\n}\n\n/**\n * Packs CartesianSeriesData into a Float32Array for LTTB sampling.\n * Returns the packed Float32Array.\n */\nfunction packToFloat32Array(data: CartesianSeriesData): Float32Array {\n  const count = getPointCount(data);\n  const out = new Float32Array(count * 2);\n  \n  for (let i = 0; i < count; i++) {\n    out[i * 2] = getX(data, i);\n    out[i * 2 + 1] = getY(data, i);\n  }\n  \n  return out;\n}\n\ntype BucketMode = 'average' | 'max' | 'min';\n\n/**\n * Samples CartesianSeriesData using bucket-based strategies (average, max, min).\n * Always returns DataPointTuple[] for newly allocated data.\n * Preserves size semantics when available.\n */\nfunction sampleByBucketsFromCartesian(\n  data: CartesianSeriesData,\n  targetPoints: number,\n  mode: BucketMode\n): DataPointTuple[] {\n  const n = getPointCount(data);\n  const threshold = clampTargetPoints(targetPoints);\n\n  if (threshold <= 0 || n === 0) return [];\n  if (threshold === 1) {\n    const x = getX(data, 0);\n    const y = getY(data, 0);\n    const size = getPointSize(data, 0);\n    return size !== undefined ? [[x, y, size]] : [[x, y]];\n  }\n  if (threshold === 2) {\n    if (n >= 2) {\n      const x0 = getX(data, 0);\n      const y0 = getY(data, 0);\n      const size0 = getPointSize(data, 0);\n      const xLast = getX(data, n - 1);\n      const yLast = getY(data, n - 1);\n      const sizeLast = getPointSize(data, n - 1);\n      return [\n        size0 !== undefined ? [x0, y0, size0] : [x0, y0],\n        sizeLast !== undefined ? [xLast, yLast, sizeLast] : [xLast, yLast],\n      ];\n    } else {\n      const x = getX(data, 0);\n      const y = getY(data, 0);\n      const size = getPointSize(data, 0);\n      return size !== undefined ? [[x, y, size]] : [[x, y]];\n    }\n  }\n\n  const lastIndex = n - 1;\n  const out: DataPointTuple[] = new Array(threshold);\n  \n  // First and last points\n  {\n    const x0 = getX(data, 0);\n    const y0 = getY(data, 0);\n    const size0 = getPointSize(data, 0);\n    out[0] = size0 !== undefined ? [x0, y0, size0] : [x0, y0];\n    \n    const xLast = getX(data, lastIndex);\n    const yLast = getY(data, lastIndex);\n    const sizeLast = getPointSize(data, lastIndex);\n    out[threshold - 1] = sizeLast !== undefined ? [xLast, yLast, sizeLast] : [xLast, yLast];\n  }\n\n  const bucketSize = (n - 2) / (threshold - 2);\n\n  for (let bucket = 0; bucket < threshold - 2; bucket++) {\n    let rangeStart = Math.floor(bucketSize * bucket) + 1;\n    let rangeEndExclusive = Math.min(Math.floor(bucketSize * (bucket + 1)) + 1, lastIndex);\n\n    if (rangeStart >= rangeEndExclusive) {\n      rangeStart = Math.min(rangeStart, lastIndex - 1);\n      rangeEndExclusive = Math.min(rangeStart + 1, lastIndex);\n    }\n\n    let chosen: DataPointTuple | null = null;\n\n    if (mode === 'average') {\n      let sumX = 0;\n      let sumY = 0;\n      let sumSize = 0;\n      let count = 0;\n      let sizeCount = 0;\n      for (let i = rangeStart; i < rangeEndExclusive; i++) {\n        const x = getX(data, i);\n        const y = getY(data, i);\n        if (!Number.isFinite(x) || !Number.isFinite(y)) continue;\n        sumX += x;\n        sumY += y;\n        count++;\n\n        const size = getPointSize(data, i);\n        if (typeof size === 'number' && Number.isFinite(size)) {\n          sumSize += size;\n          sizeCount++;\n        }\n      }\n\n      if (count > 0) {\n        const avgX = sumX / count;\n        const avgY = sumY / count;\n        if (sizeCount > 0) {\n          chosen = [avgX, avgY, sumSize / sizeCount];\n        } else {\n          chosen = [avgX, avgY];\n        }\n      }\n    } else {\n      let bestY = mode === 'max' ? Number.NEGATIVE_INFINITY : Number.POSITIVE_INFINITY;\n      let bestIndex = rangeStart;\n      for (let i = rangeStart; i < rangeEndExclusive; i++) {\n        const y = getY(data, i);\n        if (!Number.isFinite(y)) continue;\n        if (mode === 'max') {\n          if (y > bestY) {\n            bestY = y;\n            bestIndex = i;\n          }\n        } else {\n          if (y < bestY) {\n            bestY = y;\n            bestIndex = i;\n          }\n        }\n      }\n      // Return the best point found\n      const x = getX(data, bestIndex);\n      const y = getY(data, bestIndex);\n      const size = getPointSize(data, bestIndex);\n      chosen = size !== undefined ? [x, y, size] : [x, y];\n    }\n\n    if (chosen === null) {\n      // Fallback to first point in range\n      const x = getX(data, rangeStart);\n      const y = getY(data, rangeStart);\n      const size = getPointSize(data, rangeStart);\n      chosen = size !== undefined ? [x, y, size] : [x, y];\n    }\n\n    out[bucket + 1] = chosen;\n  }\n\n  return out;\n}\n\n\n/**\n * Samples CartesianSeriesData using the specified sampling strategy.\n * \n * Returns the ORIGINAL data reference when:\n * - `sampling === 'none'`\n * - `samplingThreshold` is invalid/non-positive\n * - Point count <= threshold\n * \n * When sampling occurs:\n * - For `lttb`:\n *   - Float32Array interleaved → returns sampled Float32Array\n *   - Other interleaved typed array → packs to Float32Array, returns sampled Float32Array\n *   - DataPoint[] → returns sampled DataPoint[]\n *   - XYArraysData → packs to Float32Array, returns sampled Float32Array\n * - For `average`/`max`/`min`:\n *   - Returns DataPointTuple[] for all input formats\n */\nexport function sampleSeriesDataPoints(\n  data: CartesianSeriesData,\n  sampling: SeriesSampling,\n  samplingThreshold: number\n): CartesianSeriesData {\n  const threshold = clampTargetPoints(samplingThreshold);\n  const pointCount = getPointCount(data);\n\n  // Disabled or already under threshold: keep original reference (avoid extra allocations).\n  if (sampling === 'none') return data;\n  if (!(threshold > 0)) return data;\n  if (pointCount <= threshold) return data;\n\n  switch (sampling) {\n    case 'lttb': {\n      // Float32Array fast path\n      if (data instanceof Float32Array) {\n        return lttbSample(data, threshold);\n      }\n      \n      // Other interleaved typed arrays: pack to Float32Array and sample\n      if (isInterleavedXYData(data)) {\n        const packed = packToFloat32Array(data);\n        return lttbSample(packed, threshold);\n      }\n      \n      // XYArraysData: pack to Float32Array and sample\n      if (isXYArraysData(data)) {\n        const packed = packToFloat32Array(data);\n        return lttbSample(packed, threshold);\n      }\n      \n      // DataPoint[] path (existing behavior)\n      return lttbSample(data, threshold);\n    }\n    \n    case 'average':\n      return sampleByBucketsFromCartesian(data, threshold, 'average');\n    \n    case 'max':\n      return sampleByBucketsFromCartesian(data, threshold, 'max');\n    \n    case 'min':\n      return sampleByBucketsFromCartesian(data, threshold, 'min');\n    \n    default: {\n      // Defensive for JS callers / widened types.\n      return data;\n    }\n  }\n}\n\n","import type { OHLCDataPoint, OHLCDataPointTuple } from '../config/types';\n\nfunction isTupleOHLCDataPoint(point: OHLCDataPoint): point is OHLCDataPointTuple {\n  return Array.isArray(point);\n}\n\n/**\n * Downsamples OHLC (candlestick) data to a target number of points using bucket aggregation.\n *\n * Each bucket aggregates candles preserving OHLC semantics:\n * - timestamp and open from the first candle in the bucket\n * - close from the last candle in the bucket\n * - high as the maximum of all highs in the bucket\n * - low as the minimum of all lows in the bucket\n *\n * @param data - Array of OHLC data points (tuples or objects)\n * @param targetPoints - Desired number of output points\n * @returns Downsampled array; same reference if no sampling needed\n *\n * Edge cases:\n * - If `data.length <= targetPoints` or `targetPoints < 2`, returns the original array (same reference)\n * - First and last candles are always preserved exactly (same element references)\n * - Output shape matches input shape (tuples → tuples, objects → objects)\n */\nexport function ohlcSample(\n  data: ReadonlyArray<OHLCDataPoint>,\n  targetPoints: number,\n): ReadonlyArray<OHLCDataPoint> {\n  const threshold = Math.floor(targetPoints);\n  const n = data.length;\n\n  // Return original if already under target or insufficient target.\n  if (threshold < 2 || n <= threshold) return data;\n\n  const out = new Array<OHLCDataPoint>(threshold);\n\n  // Preserve first and last candles exactly.\n  out[0] = data[0]!;\n  out[threshold - 1] = data[n - 1]!;\n\n  if (threshold === 2) return out;\n\n  // Hoist tuple-vs-object detection once (assume homogeneous arrays).\n  const isTuple = isTupleOHLCDataPoint(data[0]!);\n\n  // Bucket size for interior points: (n - 2) interior input points → (threshold - 2) interior output points.\n  const bucketSize = (n - 2) / (threshold - 2);\n\n  if (isTuple) {\n    // Tuple format path: [timestamp, open, close, low, high]\n    const dataAsTuples = data as ReadonlyArray<OHLCDataPointTuple>;\n\n    for (let bucket = 0; bucket < threshold - 2; bucket++) {\n      // Bucket range: [rangeStart, rangeEndExclusive)\n      let rangeStart = Math.floor(bucketSize * bucket) + 1;\n      let rangeEndExclusive = Math.min(Math.floor(bucketSize * (bucket + 1)) + 1, n - 1);\n\n      // Defensive: ensure at least one candidate point.\n      if (rangeStart >= rangeEndExclusive) {\n        rangeStart = Math.min(rangeStart, n - 2);\n        rangeEndExclusive = Math.min(rangeStart + 1, n - 1);\n      }\n\n      // Extract first and last candles in bucket.\n      const firstCandle = dataAsTuples[rangeStart]!;\n      const lastCandle = dataAsTuples[rangeEndExclusive - 1]!;\n\n      const timestamp = firstCandle[0];\n      const open = firstCandle[1];\n      const close = lastCandle[2];\n\n      // Aggregate high and low across the bucket.\n      let high = -Infinity;\n      let low = Infinity;\n      for (let i = rangeStart; i < rangeEndExclusive; i++) {\n        const candle = dataAsTuples[i]!;\n        const candleLow = candle[3];\n        const candleHigh = candle[4];\n        if (candleHigh > high) high = candleHigh;\n        if (candleLow < low) low = candleLow;\n      }\n\n      out[bucket + 1] = [timestamp, open, close, low, high];\n    }\n  } else {\n    // Object format path: { timestamp, open, close, low, high }\n    const dataAsObjects = data as ReadonlyArray<Exclude<OHLCDataPoint, OHLCDataPointTuple>>;\n\n    for (let bucket = 0; bucket < threshold - 2; bucket++) {\n      // Bucket range: [rangeStart, rangeEndExclusive)\n      let rangeStart = Math.floor(bucketSize * bucket) + 1;\n      let rangeEndExclusive = Math.min(Math.floor(bucketSize * (bucket + 1)) + 1, n - 1);\n\n      // Defensive: ensure at least one candidate point.\n      if (rangeStart >= rangeEndExclusive) {\n        rangeStart = Math.min(rangeStart, n - 2);\n        rangeEndExclusive = Math.min(rangeStart + 1, n - 1);\n      }\n\n      // Extract first and last candles in bucket.\n      const firstCandle = dataAsObjects[rangeStart]!;\n      const lastCandle = dataAsObjects[rangeEndExclusive - 1]!;\n\n      const timestamp = firstCandle.timestamp;\n      const open = firstCandle.open;\n      const close = lastCandle.close;\n\n      // Aggregate high and low across the bucket.\n      let high = -Infinity;\n      let low = Infinity;\n      for (let i = rangeStart; i < rangeEndExclusive; i++) {\n        const candle = dataAsObjects[i]!;\n        const candleHigh = candle.high;\n        const candleLow = candle.low;\n        if (candleHigh > high) high = candleHigh;\n        if (candleLow < low) low = candleLow;\n      }\n\n      out[bucket + 1] = { timestamp, open, close, low, high };\n    }\n  }\n\n  return out;\n}\n","/**\n * Canvas sizing and measurement utilities for the RenderCoordinator.\n *\n * These pure functions handle canvas dimension retrieval with special handling\n * for device pixel ratio and GPU overlay coordinate conversions.\n *\n * @module canvasUtils\n */\n\n/**\n * Gets canvas CSS width - clientWidth for HTMLCanvasElement.\n *\n * @param canvas - The canvas element to measure, or null\n * @returns CSS width in pixels, or 0 if canvas is null\n */\nexport function getCanvasCssWidth(canvas: HTMLCanvasElement | null): number {\n  if (!canvas) {\n    return 0;\n  }\n\n  return canvas.clientWidth;\n}\n\n/**\n * Gets canvas CSS height - clientHeight for HTMLCanvasElement.\n *\n * @param canvas - The canvas element to measure, or null\n * @returns CSS height in pixels, or 0 if canvas is null\n */\nexport function getCanvasCssHeight(canvas: HTMLCanvasElement | null): number {\n  if (!canvas) {\n    return 0;\n  }\n\n  return canvas.clientHeight;\n}\n\n/**\n * Gets canvas CSS size derived strictly from device-pixel dimensions and DPR.\n *\n * This is intentionally different from `getCanvasCssWidth/Height(...)`:\n * - HTMLCanvasElement: `clientWidth/clientHeight` reflect DOM layout and can diverge (rounding, zoom, async resize)\n *   from the WebGPU render target size (`canvas.width/height` in device pixels).\n * - For GPU overlays that round-trip CSS↔device pixels in-shader, we must derive CSS size from\n *   `canvas.width/height` + DPR to keep transforms consistent with the render target.\n *\n * NOTE: Use this for GPU overlay coordinate conversion only (reference lines, markers).\n * Keep DOM overlays (labels/tooltips) using `clientWidth/clientHeight` for layout correctness.\n *\n * @param canvas - The canvas element to measure, or null\n * @param devicePixelRatio - The device pixel ratio (defaults to window.devicePixelRatio or 1)\n * @returns Object with width and height in CSS pixels derived from device pixels\n */\nexport function getCanvasCssSizeFromDevicePixels(\n  canvas: HTMLCanvasElement | null,\n  devicePixelRatio: number = typeof window !== 'undefined' ? window.devicePixelRatio : 1,\n): Readonly<{ width: number; height: number }> {\n  if (!canvas) return { width: 0, height: 0 };\n  const dpr = Number.isFinite(devicePixelRatio) && devicePixelRatio > 0 ? devicePixelRatio : 1;\n  // HTMLCanvasElement exposes `.width/.height` in device pixels.\n  return { width: canvas.width / dpr, height: canvas.height / dpr };\n}\n\n/**\n * Clamps a value to an integer within [lo, hi] range.\n *\n * @param v - Value to clamp\n * @param lo - Lower bound (inclusive)\n * @param hi - Upper bound (inclusive)\n * @returns Clamped integer value\n */\nexport function clampInt(v: number, lo: number, hi: number): number {\n  return Math.min(hi, Math.max(lo, v | 0));\n}\n","/**\n * Visible Slice Computation Utilities\n *\n * Provides efficient data slicing for zoom operations using binary search\n * when data is monotonic, with fallback to linear filtering.\n *\n * Key features:\n * - Binary search slicing for O(log n) performance on sorted data\n * - WeakMap caching of monotonicity checks to avoid O(n) scans\n * - Separate implementations for cartesian (x-based) and OHLC (timestamp-based) data\n * - Support for DataPoint[], XYArraysData, and InterleavedXYData formats\n */\n\nimport type {\n  CartesianSeriesData,\n  DataPoint,\n  OHLCDataPoint,\n  OHLCDataPointTuple,\n  OHLCDataPointObject,\n  XYArraysData,\n  InterleavedXYData,\n} from '../../../config/types';\nimport { getPointCount, getX, getY } from '../../../data/cartesianData';\nimport { clampInt } from '../utils/canvasUtils';\n\n// Type guards for OHLC data\nexport function isTupleOHLCDataPoint(p: OHLCDataPoint): p is OHLCDataPointTuple {\n  return Array.isArray(p);\n}\n\n// Cache monotonicity checks to avoid O(n) scans on every zoom operation\n// WeakMap works for arrays, typed arrays, and object references (XYArraysData)\nconst monotonicXCache = new WeakMap<object, boolean>();\nconst monotonicTimestampCache = new WeakMap<ReadonlyArray<OHLCDataPoint>, boolean>();\n\n/**\n * Checks if cartesian data is monotonic non-decreasing by X coordinate with all finite values.\n * Results are cached in a WeakMap to avoid repeated O(n) scans.\n * \n * Supports all CartesianSeriesData formats: DataPoint[], XYArraysData, InterleavedXYData.\n */\nexport function isMonotonicNonDecreasingFiniteX(data: CartesianSeriesData): boolean {\n  // For primitive arrays and typed arrays, we can cache by object reference\n  // For XYArraysData, we cache by the object itself\n  const cacheKey = typeof data === 'object' && data !== null ? data : null;\n  if (cacheKey) {\n    const cached = monotonicXCache.get(cacheKey);\n    if (cached !== undefined) return cached;\n  }\n\n  let prevX = Number.NEGATIVE_INFINITY;\n  const n = getPointCount(data);\n\n  for (let i = 0; i < n; i++) {\n    const x = getX(data, i);\n    if (!Number.isFinite(x)) {\n      if (cacheKey) monotonicXCache.set(cacheKey, false);\n      return false;\n    }\n    if (x < prevX) {\n      if (cacheKey) monotonicXCache.set(cacheKey, false);\n      return false;\n    }\n    prevX = x;\n  }\n\n  if (cacheKey) monotonicXCache.set(cacheKey, true);\n  return true;\n}\n\n/**\n * Checks if OHLC data is monotonic non-decreasing by timestamp with all finite values.\n * Results are cached in a WeakMap to avoid repeated O(n) scans.\n */\nexport function isMonotonicNonDecreasingFiniteTimestamp(data: ReadonlyArray<OHLCDataPoint>): boolean {\n  const cached = monotonicTimestampCache.get(data);\n  if (cached !== undefined) return cached;\n\n  let prevTimestamp = Number.NEGATIVE_INFINITY;\n\n  for (let i = 0; i < data.length; i++) {\n    const p = data[i]!;\n    const timestamp = isTupleOHLCDataPoint(p) ? p[0] : p.timestamp;\n    if (!Number.isFinite(timestamp)) {\n      monotonicTimestampCache.set(data, false);\n      return false;\n    }\n    if (timestamp < prevTimestamp) {\n      monotonicTimestampCache.set(data, false);\n      return false;\n    }\n    prevTimestamp = timestamp;\n  }\n  monotonicTimestampCache.set(data, true);\n  return true;\n}\n\n// Binary search: lower bound (first element >= target) for CartesianSeriesData\nfunction lowerBoundX(data: CartesianSeriesData, xTarget: number): number {\n  let lo = 0;\n  let hi = getPointCount(data);\n  while (lo < hi) {\n    const mid = (lo + hi) >>> 1;\n    const x = getX(data, mid);\n    if (x < xTarget) lo = mid + 1;\n    else hi = mid;\n  }\n  return lo;\n}\n\n// Binary search: upper bound (first element > target) for CartesianSeriesData\nfunction upperBoundX(data: CartesianSeriesData, xTarget: number): number {\n  let lo = 0;\n  let hi = getPointCount(data);\n  while (lo < hi) {\n    const mid = (lo + hi) >>> 1;\n    const x = getX(data, mid);\n    if (x <= xTarget) lo = mid + 1;\n    else hi = mid;\n  }\n  return lo;\n}\n\nfunction lowerBoundTimestampTuple(data: ReadonlyArray<OHLCDataPointTuple>, timestampTarget: number): number {\n  let lo = 0;\n  let hi = data.length;\n  while (lo < hi) {\n    const mid = (lo + hi) >>> 1;\n    const timestamp = data[mid][0];\n    if (timestamp < timestampTarget) lo = mid + 1;\n    else hi = mid;\n  }\n  return lo;\n}\n\nfunction upperBoundTimestampTuple(data: ReadonlyArray<OHLCDataPointTuple>, timestampTarget: number): number {\n  let lo = 0;\n  let hi = data.length;\n  while (lo < hi) {\n    const mid = (lo + hi) >>> 1;\n    const timestamp = data[mid][0];\n    if (timestamp <= timestampTarget) lo = mid + 1;\n    else hi = mid;\n  }\n  return lo;\n}\n\nfunction lowerBoundTimestampObject(data: ReadonlyArray<OHLCDataPointObject>, timestampTarget: number): number {\n  let lo = 0;\n  let hi = data.length;\n  while (lo < hi) {\n    const mid = (lo + hi) >>> 1;\n    const timestamp = data[mid].timestamp;\n    if (timestamp < timestampTarget) lo = mid + 1;\n    else hi = mid;\n  }\n  return lo;\n}\n\nfunction upperBoundTimestampObject(data: ReadonlyArray<OHLCDataPointObject>, timestampTarget: number): number {\n  let lo = 0;\n  let hi = data.length;\n  while (lo < hi) {\n    const mid = (lo + hi) >>> 1;\n    const timestamp = data[mid].timestamp;\n    if (timestamp <= timestampTarget) lo = mid + 1;\n    else hi = mid;\n  }\n  return lo;\n}\n\n/**\n * Helper: Check if data is XYArraysData format.\n */\nfunction isXYArraysData(data: CartesianSeriesData): data is XYArraysData {\n  return (\n    typeof data === 'object' &&\n    data !== null &&\n    !Array.isArray(data) &&\n    'x' in data &&\n    'y' in data &&\n    typeof (data as any).x === 'object' &&\n    typeof (data as any).y === 'object' &&\n    'length' in (data as any).x &&\n    'length' in (data as any).y\n  );\n}\n\n/**\n * Helper: Check if data is InterleavedXYData format (ArrayBufferView).\n */\nfunction isInterleavedXYData(data: CartesianSeriesData): data is InterleavedXYData {\n  return (\n    typeof data === 'object' &&\n    data !== null &&\n    !Array.isArray(data) &&\n    ArrayBuffer.isView(data)\n  );\n}\n\n/**\n * Helper: Slice CartesianSeriesData to index range [start, end).\n * Returns appropriate view/slice for each format.\n */\nfunction sliceCartesianData(\n  data: CartesianSeriesData,\n  start: number,\n  end: number\n): CartesianSeriesData {\n  // Clamp indices\n  const n = getPointCount(data);\n  const s = Math.max(0, Math.min(start, n));\n  const e = Math.max(s, Math.min(end, n));\n\n  if (s === 0 && e === n) return data;\n  if (e <= s) {\n    // Return empty data in appropriate format\n    if (isXYArraysData(data)) {\n      return { x: [], y: [], ...(data.size ? { size: [] } : {}) };\n    }\n    if (isInterleavedXYData(data)) {\n      // Return empty view of same type\n      if (data instanceof DataView) {\n        throw new Error('DataView is not supported for InterleavedXYData');\n      }\n      const TypedArrayConstructor = (data as any).constructor;\n      return new TypedArrayConstructor(0);\n    }\n    return [];\n  }\n\n  // XYArraysData: slice x, y, and optional size arrays\n  if (isXYArraysData(data)) {\n    const xSliced = Array.isArray(data.x)\n      ? data.x.slice(s, e)\n      : 'subarray' in data.x\n      ? (data.x as any).subarray(s, e)\n      : Array.from(data.x).slice(s, e);\n\n    const ySliced = Array.isArray(data.y)\n      ? data.y.slice(s, e)\n      : 'subarray' in data.y\n      ? (data.y as any).subarray(s, e)\n      : Array.from(data.y).slice(s, e);\n\n    const result: XYArraysData = { x: xSliced, y: ySliced };\n\n    if (data.size) {\n      const sizeSliced = Array.isArray(data.size)\n        ? data.size.slice(s, e)\n        : 'subarray' in data.size\n        ? (data.size as any).subarray(s, e)\n        : Array.from(data.size).slice(s, e);\n      (result as any).size = sizeSliced;\n    }\n\n    return result;\n  }\n\n  // InterleavedXYData: return subarray view (start*2, end*2)\n  if (isInterleavedXYData(data)) {\n    if (data instanceof DataView) {\n      throw new Error('DataView is not supported for InterleavedXYData');\n    }\n    return (data as any).subarray(s * 2, e * 2);\n  }\n\n  // ReadonlyArray<DataPoint>: standard slice\n  return (data as ReadonlyArray<DataPoint>).slice(s, e);\n}\n\n/**\n * Slices cartesian data to the visible X range [xMin, xMax].\n *\n * Uses binary search (O(log n)) when data is monotonic by X;\n * otherwise falls back to linear filtering (O(n)).\n *\n * @param data - Cartesian data in any supported format\n * @param xMin - Minimum X value (inclusive)\n * @param xMax - Maximum X value (inclusive)\n * @returns Sliced data in the same format as input\n */\nexport function sliceVisibleRangeByX(\n  data: CartesianSeriesData,\n  xMin: number,\n  xMax: number\n): CartesianSeriesData {\n  const n = getPointCount(data);\n  if (n === 0) return data;\n  if (!Number.isFinite(xMin) || !Number.isFinite(xMax)) return data;\n\n  const canBinarySearch = isMonotonicNonDecreasingFiniteX(data);\n\n  if (canBinarySearch) {\n    const lo = lowerBoundX(data, xMin);\n    const hi = upperBoundX(data, xMax);\n\n    if (lo <= 0 && hi >= n) return data;\n    return sliceCartesianData(data, lo, hi);\n  }\n\n  // Safe fallback: linear filter (preserves order, ignores non-finite x)\n  // For non-monotonic data, we must return a filtered array\n  const out: DataPoint[] = [];\n  for (let i = 0; i < n; i++) {\n    const x = getX(data, i);\n    if (!Number.isFinite(x)) continue;\n    if (x >= xMin && x <= xMax) {\n      const y = getY(data, i);\n      out.push([x, y]);\n    }\n  }\n  return out;\n}\n\n/**\n * Finds the index range of visible points in cartesian data.\n *\n * Returns { start, end } indices suitable for slicing or iteration.\n * Only works correctly when data is monotonic; returns full range otherwise.\n *\n * @param data - Cartesian data in any supported format\n * @param xMin - Minimum X value (inclusive)\n * @param xMax - Maximum X value (inclusive)\n * @returns Index range { start, end } for visible data\n */\nexport function findVisibleRangeIndicesByX(\n  data: CartesianSeriesData,\n  xMin: number,\n  xMax: number\n): { readonly start: number; readonly end: number } {\n  const n = getPointCount(data);\n  if (n === 0) return { start: 0, end: 0 };\n  if (!Number.isFinite(xMin) || !Number.isFinite(xMax)) return { start: 0, end: n };\n\n  const canBinarySearch = isMonotonicNonDecreasingFiniteX(data);\n  if (!canBinarySearch) {\n    // Data is not monotonic by x; we can't represent the visible set as a contiguous index range\n    // Fall back to processing the full series for correctness\n    return { start: 0, end: n };\n  }\n\n  const start = lowerBoundX(data, xMin);\n  const end = upperBoundX(data, xMax);\n\n  const s = clampInt(start, 0, n);\n  const e = clampInt(end, 0, n);\n  return e <= s ? { start: s, end: s } : { start: s, end: e };\n}\n\n/**\n * Slices OHLC/candlestick data to the visible timestamp range [xMin, xMax].\n *\n * Uses binary search (O(log n)) when timestamps are monotonic;\n * otherwise falls back to linear filtering (O(n)).\n *\n * @param data - OHLC data points (tuple or object format)\n * @param xMin - Minimum timestamp (inclusive)\n * @param xMax - Maximum timestamp (inclusive)\n * @returns Sliced data array containing only points within [xMin, xMax]\n */\nexport function sliceVisibleRangeByOHLC(\n  data: ReadonlyArray<OHLCDataPoint>,\n  xMin: number,\n  xMax: number\n): ReadonlyArray<OHLCDataPoint> {\n  const n = data.length;\n  if (n === 0) return data;\n  if (!Number.isFinite(xMin) || !Number.isFinite(xMax)) return data;\n\n  const canBinarySearch = isMonotonicNonDecreasingFiniteTimestamp(data);\n  const isTuple = n > 0 && isTupleOHLCDataPoint(data[0]!);\n\n  if (canBinarySearch) {\n    const lo = isTuple\n      ? lowerBoundTimestampTuple(data as ReadonlyArray<OHLCDataPointTuple>, xMin)\n      : lowerBoundTimestampObject(data as ReadonlyArray<OHLCDataPointObject>, xMin);\n    const hi = isTuple\n      ? upperBoundTimestampTuple(data as ReadonlyArray<OHLCDataPointTuple>, xMax)\n      : upperBoundTimestampObject(data as ReadonlyArray<OHLCDataPointObject>, xMax);\n\n    if (lo <= 0 && hi >= n) return data;\n    if (hi <= lo) return [];\n    return data.slice(lo, hi);\n  }\n\n  // Safe fallback: linear filter (preserves order, ignores non-finite timestamp)\n  const out: OHLCDataPoint[] = [];\n  for (let i = 0; i < n; i++) {\n    const p = data[i]!;\n    const timestamp = isTupleOHLCDataPoint(p) ? p[0] : p.timestamp;\n    if (!Number.isFinite(timestamp)) continue;\n    if (timestamp >= xMin && timestamp <= xMax) out.push(p);\n  }\n  return out;\n}\n","export type Rgba01 = readonly [r: number, g: number, b: number, a: number];\n\nconst clamp01 = (v: number): number => Math.min(1, Math.max(0, v));\nconst clamp255 = (v: number): number => Math.min(255, Math.max(0, v));\n\nconst parseHexNibble = (hex: string): number => {\n  const n = Number.parseInt(hex, 16);\n  return Number.isFinite(n) ? n : 0;\n};\n\nconst parseHexByte = (hex: string): number => {\n  const n = Number.parseInt(hex, 16);\n  return Number.isFinite(n) ? n : 0;\n};\n\nconst parseHexColorToRgba01 = (color: string): Rgba01 | null => {\n  const c = color.trim();\n  if (!c.startsWith('#')) return null;\n\n  const hex = c.slice(1);\n\n  // #rgb\n  if (hex.length === 3) {\n    const r = parseHexNibble(hex[0]);\n    const g = parseHexNibble(hex[1]);\n    const b = parseHexNibble(hex[2]);\n    return [(r * 17) / 255, (g * 17) / 255, (b * 17) / 255, 1];\n  }\n\n  // #rgba\n  if (hex.length === 4) {\n    const r = parseHexNibble(hex[0]);\n    const g = parseHexNibble(hex[1]);\n    const b = parseHexNibble(hex[2]);\n    const a = parseHexNibble(hex[3]);\n    return [(r * 17) / 255, (g * 17) / 255, (b * 17) / 255, (a * 17) / 255];\n  }\n\n  // #rrggbb\n  if (hex.length === 6) {\n    const r = parseHexByte(hex.slice(0, 2));\n    const g = parseHexByte(hex.slice(2, 4));\n    const b = parseHexByte(hex.slice(4, 6));\n    return [r / 255, g / 255, b / 255, 1];\n  }\n\n  // #rrggbbaa\n  if (hex.length === 8) {\n    const r = parseHexByte(hex.slice(0, 2));\n    const g = parseHexByte(hex.slice(2, 4));\n    const b = parseHexByte(hex.slice(4, 6));\n    const a = parseHexByte(hex.slice(6, 8));\n    return [r / 255, g / 255, b / 255, a / 255];\n  }\n\n  return null;\n};\n\nconst parseRgbNumberOrPercent = (token: string): number | null => {\n  const t = token.trim();\n  if (t.length === 0) return null;\n\n  if (t.endsWith('%')) {\n    const n = Number.parseFloat(t.slice(0, -1));\n    if (!Number.isFinite(n)) return null;\n    return clamp255((n / 100) * 255);\n  }\n\n  const n = Number.parseFloat(t);\n  if (!Number.isFinite(n)) return null;\n  return clamp255(n);\n};\n\nconst parseAlphaNumberOrPercent = (token: string): number | null => {\n  const t = token.trim();\n  if (t.length === 0) return null;\n\n  if (t.endsWith('%')) {\n    const n = Number.parseFloat(t.slice(0, -1));\n    if (!Number.isFinite(n)) return null;\n    return clamp01(n / 100);\n  }\n\n  const n = Number.parseFloat(t);\n  if (!Number.isFinite(n)) return null;\n  return clamp01(n);\n};\n\nconst parseRgbFuncToRgba01 = (color: string): Rgba01 | null => {\n  const c = color.trim();\n  const m = /^(rgba?|RGBA?)\\(\\s*([^\\)]*)\\s*\\)$/.exec(c);\n  if (!m) return null;\n\n  const fn = m[1].toLowerCase();\n  const argsRaw = m[2];\n\n  // Requirement scope: support comma-separated rgb()/rgba().\n  // (We intentionally do not attempt full CSS Color 4 space-separated syntax here.)\n  const parts = argsRaw.split(',').map((p) => p.trim());\n  if (fn === 'rgb') {\n    if (parts.length !== 3) return null;\n    const r = parseRgbNumberOrPercent(parts[0]);\n    const g = parseRgbNumberOrPercent(parts[1]);\n    const b = parseRgbNumberOrPercent(parts[2]);\n    if (r == null || g == null || b == null) return null;\n    return [r / 255, g / 255, b / 255, 1];\n  }\n\n  if (fn === 'rgba') {\n    if (parts.length !== 4) return null;\n    const r = parseRgbNumberOrPercent(parts[0]);\n    const g = parseRgbNumberOrPercent(parts[1]);\n    const b = parseRgbNumberOrPercent(parts[2]);\n    const a = parseAlphaNumberOrPercent(parts[3]);\n    if (r == null || g == null || b == null || a == null) return null;\n    return [r / 255, g / 255, b / 255, a];\n  }\n\n  return null;\n};\n\n/**\n * Parse a CSS color string into RGBA floats in [0..1].\n *\n * Supported:\n * - #rgb / #rgba / #rrggbb / #rrggbbaa\n * - rgb(r,g,b)\n * - rgba(r,g,b,a)\n *\n * Returns null when parsing fails.\n */\nexport const parseCssColorToRgba01 = (color: string): Rgba01 | null => {\n  if (typeof color !== 'string') return null;\n  const c = color.trim();\n  if (c.length === 0) return null;\n\n  const hex = parseHexColorToRgba01(c);\n  if (hex) return hex;\n\n  const rgb = parseRgbFuncToRgba01(c);\n  if (rgb) return rgb;\n\n  return null;\n};\n\nexport const parseCssColorToGPUColor = (\n  color: string,\n  fallback: GPUColor = { r: 0, g: 0, b: 0, a: 1 }\n): GPUColor => {\n  const rgba = parseCssColorToRgba01(color);\n  if (!rgba) return fallback;\n  const [r, g, b, a] = rgba;\n  return { r, g, b, a };\n};\n\n","/**\n * Data point type guards and utilities for the RenderCoordinator.\n *\n * These pure functions handle the dual data format system (tuple vs object)\n * and provide type-safe access to point coordinates.\n *\n * @module dataPointUtils\n */\n\nimport type { DataPoint, DataPointTuple, OHLCDataPoint, OHLCDataPointTuple } from '../../../config/types';\n\n/**\n * Validates that a number is finite, returning the number or null.\n *\n * @param v - Value to validate\n * @returns The number if finite, otherwise null\n */\nexport const finiteOrNull = (v: number | null | undefined): number | null =>\n  typeof v === 'number' && Number.isFinite(v) ? v : null;\n\n/**\n * Validates that a number is finite, returning the number or undefined.\n *\n * @param v - Value to validate\n * @returns The number if finite, otherwise undefined\n */\nexport const finiteOrUndefined = (v: number | undefined): number | undefined =>\n  typeof v === 'number' && Number.isFinite(v) ? v : undefined;\n\n/**\n * Compile-time exhaustiveness check for error handling.\n * Used in switch statements to ensure all cases are handled.\n *\n * @param value - The value that should be of type `never` if all cases are handled\n * @throws Always throws an error if called\n */\nexport const assertUnreachable = (value: never): never => {\n  // Intentionally minimal message: this is used for compile-time exhaustiveness.\n  throw new Error(`RenderCoordinator: unreachable value: ${String(value)}`);\n};\n\n/**\n * Type guard: checks if a DataPoint is in tuple form `[x, y]`.\n *\n * @param p - The data point to check\n * @returns True if the point is a tuple, false if it's an object\n */\nexport const isTupleDataPoint = (p: DataPoint): p is DataPointTuple => Array.isArray(p);\n\n/**\n * Extracts x,y coordinates from either tuple or object point format.\n *\n * @param p - The data point (either tuple or object format)\n * @returns Object with x and y properties\n */\nexport const getPointXY = (p: DataPoint): { readonly x: number; readonly y: number } => {\n  if (isTupleDataPoint(p)) return { x: p[0], y: p[1] };\n  return { x: p.x, y: p.y };\n};\n\n/**\n * Type guard: checks if a data point is in tuple OHLC form `[timestamp, open, high, low, close]`.\n *\n * @param p - The OHLC data point to check\n * @returns True if the point is a tuple, false if it's an object\n */\nexport const isTupleOHLCDataPoint = (p: OHLCDataPoint): p is OHLCDataPointTuple => Array.isArray(p);\n\n/**\n * Type guard: checks if a data point is in tuple form `[x, y]` (for individual points).\n *\n * @param p - The point to check\n * @returns True if the point is a tuple array\n */\nexport const isTuplePoint = (p: unknown): p is readonly [number, number] => Array.isArray(p);\n\n/**\n * Type guard: checks if entire data array is in tuple format.\n * Only checks the first element for performance.\n *\n * @param data - Array of data points to check\n * @returns True if first element (and therefore likely all) is a tuple\n */\nexport const isTupleDataArray = (data: ReadonlyArray<DataPoint>): data is ReadonlyArray<DataPointTuple> =>\n  data.length > 0 && isTupleDataPoint(data[0]);\n","/**\n * Axis and grid utilities for the RenderCoordinator.\n *\n * These pure functions handle coordinate transformations between different spaces:\n * - CSS pixels (DOM layout)\n * - Device pixels (canvas.width/height)\n * - Normalized device coordinates / clip space (WebGPU [-1, 1])\n *\n * @module axisUtils\n */\n\nimport type { GPUContextLike } from '../types';\nimport type { ResolvedChartGPUOptions } from '../../../config/OptionResolver';\nimport type { GridArea } from '../../../renderers/createGridRenderer';\nimport { parseCssColorToRgba01 } from '../../../utils/colors';\nimport { normalizeDomain } from './boundsComputation';\nimport { clampInt } from './canvasUtils';\n\n/**\n * Computes grid area with margins and canvas dimensions for rendering layout.\n * GridArea uses:\n * - Margins (left, right, top, bottom) in CSS pixels\n * - Canvas dimensions (canvasWidth, canvasHeight) in DEVICE pixels\n * - devicePixelRatio for CSS-to-device conversion (worker-compatible)\n *\n * @param gpuContext - GPU context with canvas and device pixel ratio\n * @param options - Resolved chart options with grid margins\n * @returns GridArea object with margins, canvas dimensions, and DPR\n * @throws If canvas is null or has invalid dimensions\n */\nexport const computeGridArea = (gpuContext: GPUContextLike, options: ResolvedChartGPUOptions): GridArea => {\n  const canvas = gpuContext.canvas;\n  if (!canvas) throw new Error('RenderCoordinator: gpuContext.canvas is required.');\n\n  const dpr = gpuContext.devicePixelRatio ?? 1;\n  const devicePixelRatio = (Number.isFinite(dpr) && dpr > 0) ? dpr : 1;\n\n  // Validate and sanitize canvas dimensions (device pixels)\n  const rawCanvasWidth = canvas.width;\n  const rawCanvasHeight = canvas.height;\n\n  if (!Number.isFinite(rawCanvasWidth) || !Number.isFinite(rawCanvasHeight)) {\n    throw new Error(\n      `RenderCoordinator: Invalid canvas dimensions: width=${rawCanvasWidth}, height=${rawCanvasHeight}. ` +\n      `Canvas must be initialized with finite dimensions before rendering.`\n    );\n  }\n\n  // Be resilient: charts may be mounted into 0-sized containers (e.g. display:none during init).\n  // Renderers guard internally; clamping avoids hard crashes and allows future resize to recover.\n  const canvasWidth = Math.max(1, Math.floor(rawCanvasWidth));\n  const canvasHeight = Math.max(1, Math.floor(rawCanvasHeight));\n\n  // Validate and sanitize grid margins (CSS pixels)\n  const left = Number.isFinite(options.grid.left) ? options.grid.left : 0;\n  const right = Number.isFinite(options.grid.right) ? options.grid.right : 0;\n  const top = Number.isFinite(options.grid.top) ? options.grid.top : 0;\n  const bottom = Number.isFinite(options.grid.bottom) ? options.grid.bottom : 0;\n\n  // Ensure margins are non-negative (negative margins could cause rendering issues)\n  const sanitizedLeft = Math.max(0, left);\n  const sanitizedRight = Math.max(0, right);\n  const sanitizedTop = Math.max(0, top);\n  const sanitizedBottom = Math.max(0, bottom);\n\n  return {\n    left: sanitizedLeft,\n    right: sanitizedRight,\n    top: sanitizedTop,\n    bottom: sanitizedBottom,\n    canvasWidth,                      // Device pixels (clamped above)\n    canvasHeight,                     // Device pixels (clamped above)\n    devicePixelRatio,                 // Explicit DPR for worker compatibility (validated above)\n  };\n};\n\n/**\n * Converts RGBA normalized [0-1] values to CSS rgba() string.\n *\n * @param rgba - Array of [r, g, b, a] in range [0, 1]\n * @returns CSS rgba() string\n */\nexport const rgba01ToCssRgba = (rgba: readonly [number, number, number, number]): string => {\n  const r = Math.max(0, Math.min(255, Math.round(rgba[0] * 255)));\n  const g = Math.max(0, Math.min(255, Math.round(rgba[1] * 255)));\n  const b = Math.max(0, Math.min(255, Math.round(rgba[2] * 255)));\n  const a = Math.max(0, Math.min(1, rgba[3]));\n  return `rgba(${r},${g},${b},${a})`;\n};\n\n/**\n * Applies alpha multiplier to CSS color.\n * Parses color, multiplies alpha channel, and returns new CSS rgba() string.\n *\n * @param cssColor - CSS color string\n * @param alphaMultiplier - Alpha multiplier in range [0, 1]\n * @returns CSS rgba() string with modified alpha, or original color if parse fails\n */\nexport const withAlpha = (cssColor: string, alphaMultiplier: number): string => {\n  const parsed = parseCssColorToRgba01(cssColor);\n  if (!parsed) return cssColor;\n  const a = Math.max(0, Math.min(1, parsed[3] * alphaMultiplier));\n  return rgba01ToCssRgba([parsed[0], parsed[1], parsed[2], a]);\n};\n\n/**\n * Converts grid margins to normalized device clip coordinates for WebGPU.\n * Output is in WebGPU clip space: [-1, 1] for both x and y.\n * Y-axis is flipped (top is positive, bottom is negative).\n *\n * @param gridArea - Grid area with margins and canvas dimensions\n * @returns Clip rect with left, right, top, bottom in range [-1, 1]\n */\nexport const computePlotClipRect = (\n  gridArea: GridArea\n): { readonly left: number; readonly right: number; readonly top: number; readonly bottom: number } => {\n  const { left, right, top, bottom, canvasWidth, canvasHeight, devicePixelRatio } = gridArea;\n\n  const plotLeft = left * devicePixelRatio;\n  const plotRight = canvasWidth - right * devicePixelRatio;\n  const plotTop = top * devicePixelRatio;\n  const plotBottom = canvasHeight - bottom * devicePixelRatio;\n\n  const plotLeftClip = (plotLeft / canvasWidth) * 2.0 - 1.0;\n  const plotRightClip = (plotRight / canvasWidth) * 2.0 - 1.0;\n  const plotTopClip = 1.0 - (plotTop / canvasHeight) * 2.0; // flip Y\n  const plotBottomClip = 1.0 - (plotBottom / canvasHeight) * 2.0; // flip Y\n\n  return {\n    left: plotLeftClip,\n    right: plotRightClip,\n    top: plotTopClip,\n    bottom: plotBottomClip,\n  };\n};\n\n/**\n * Clamps value to [0, 1] range.\n *\n * @param v - Value to clamp\n * @returns Clamped value\n */\nexport const clamp01 = (v: number): number => Math.min(1, Math.max(0, v));\n\n/**\n * Linear interpolation between two values with clamped t.\n *\n * @param a - Start value\n * @param b - End value\n * @param t01 - Interpolation parameter in range [0, 1]\n * @returns Interpolated value\n */\nexport const lerp = (a: number, b: number, t01: number): number => a + (b - a) * clamp01(t01);\n\n/**\n * Interpolates between two domains (min/max pairs).\n * Ensures result is a valid domain (min ≤ max, both finite).\n *\n * @param from - Start domain\n * @param to - End domain\n * @param t01 - Interpolation parameter in range [0, 1]\n * @returns Interpolated domain\n */\nexport const lerpDomain = (\n  from: { readonly min: number; readonly max: number },\n  to: { readonly min: number; readonly max: number },\n  t01: number\n): { readonly min: number; readonly max: number } => {\n  return normalizeDomain(lerp(from.min, to.min, t01), lerp(from.max, to.max, t01));\n};\n\n/**\n * Computes scissor rect in device pixels from grid margins.\n * Used for WebGPU scissor testing to clip rendering to plot area.\n *\n * @param gridArea - Grid area with margins and canvas dimensions\n * @returns Scissor rect with x, y, w, h in device pixels\n */\nexport const computePlotScissorDevicePx = (\n  gridArea: GridArea\n): { readonly x: number; readonly y: number; readonly w: number; readonly h: number } => {\n  const { canvasWidth, canvasHeight, devicePixelRatio } = gridArea;\n\n  const plotLeftDevice = gridArea.left * devicePixelRatio;\n  const plotRightDevice = canvasWidth - gridArea.right * devicePixelRatio;\n  const plotTopDevice = gridArea.top * devicePixelRatio;\n  const plotBottomDevice = canvasHeight - gridArea.bottom * devicePixelRatio;\n\n  const scissorX = clampInt(Math.floor(plotLeftDevice), 0, Math.max(0, canvasWidth));\n  const scissorY = clampInt(Math.floor(plotTopDevice), 0, Math.max(0, canvasHeight));\n  const scissorR = clampInt(Math.ceil(plotRightDevice), 0, Math.max(0, canvasWidth));\n  const scissorB = clampInt(Math.ceil(plotBottomDevice), 0, Math.max(0, canvasHeight));\n  const scissorW = Math.max(0, scissorR - scissorX);\n  const scissorH = Math.max(0, scissorB - scissorY);\n\n  return { x: scissorX, y: scissorY, w: scissorW, h: scissorH };\n};\n\n/**\n * Converts clip-space X to canvas CSS pixels (from normalized [-1, 1]).\n *\n * @param xClip - X coordinate in clip space [-1, 1]\n * @param canvasCssWidth - Canvas width in CSS pixels\n * @returns X coordinate in canvas CSS pixels\n */\nexport const clipXToCanvasCssPx = (xClip: number, canvasCssWidth: number): number => ((xClip + 1) / 2) * canvasCssWidth;\n\n/**\n * Converts clip-space Y to canvas CSS pixels (from normalized [-1, 1]).\n * Y-axis is flipped (1 is top, -1 is bottom).\n *\n * @param yClip - Y coordinate in clip space [-1, 1]\n * @param canvasCssHeight - Canvas height in CSS pixels\n * @returns Y coordinate in canvas CSS pixels\n */\nexport const clipYToCanvasCssPx = (yClip: number, canvasCssHeight: number): number => ((1 - yClip) / 2) * canvasCssHeight;\n","/**\n * Time axis and formatting utilities for the RenderCoordinator.\n *\n * These pure functions handle time-based tick generation, adaptive label formatting,\n * and number/percentage parsing for pie chart configuration.\n *\n * @module timeAxisUtils\n */\n\nimport type { LinearScale } from '../../../utils/scales';\nimport type { TextOverlayAnchor } from '../../../components/createTextOverlay';\nimport type { PieCenter, PieRadius } from '../../../config/types';\nimport { clipXToCanvasCssPx } from './axisUtils';\nimport { finiteOrNull } from './dataPointUtils';\n\n/**\n * Time constants for axis formatting decisions.\n */\nexport const MS_PER_DAY = 24 * 60 * 60 * 1000;\nexport const MS_PER_MONTH_APPROX = 30 * MS_PER_DAY;\nexport const MS_PER_YEAR_APPROX = 365 * MS_PER_DAY;\n\n/**\n * Tick configuration constants.\n */\nexport const MAX_TIME_X_TICK_COUNT = 9;\nexport const MIN_TIME_X_TICK_COUNT = 1;\nexport const MIN_X_LABEL_GAP_CSS_PX = 6;\nexport const DEFAULT_MAX_TICK_FRACTION_DIGITS = 6;\nexport const DEFAULT_TICK_COUNT = 5;\n\n/**\n * English month abbreviations for time axis labels.\n */\nexport const MONTH_SHORT_EN: readonly string[] = [\n  'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun',\n  'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec',\n];\n\n/**\n * Parses value as number or percentage string, returns null if invalid.\n * Used for pie chart center and radius configuration.\n *\n * @param value - Number or percentage string (e.g. \"50%\", \"120\", 120)\n * @param basis - Basis value for percentage calculation\n * @returns Parsed number or null if invalid\n */\nexport const parseNumberOrPercent = (value: number | string, basis: number): number | null => {\n  if (typeof value === 'number') return Number.isFinite(value) ? value : null;\n  if (typeof value !== 'string') return null;\n\n  const s = value.trim();\n  if (s.length === 0) return null;\n\n  if (s.endsWith('%')) {\n    const pct = Number.parseFloat(s.slice(0, -1));\n    if (!Number.isFinite(pct)) return null;\n    return (pct / 100) * basis;\n  }\n\n  // Be permissive: allow numeric strings like \"120\".\n  const n = Number.parseFloat(s);\n  return Number.isFinite(n) ? n : null;\n};\n\n/**\n * Resolves pie center from mixed number/string/percent format.\n * Defaults to center of plot area (50%, 50%).\n *\n * @param center - Pie center configuration or undefined\n * @param plotWidthCss - Plot area width in CSS pixels\n * @param plotHeightCss - Plot area height in CSS pixels\n * @returns Resolved center coordinates in CSS pixels\n */\nexport const resolvePieCenterPlotCss = (\n  center: PieCenter | undefined,\n  plotWidthCss: number,\n  plotHeightCss: number\n): { readonly x: number; readonly y: number } => {\n  const xRaw = center?.[0] ?? '50%';\n  const yRaw = center?.[1] ?? '50%';\n\n  const x = parseNumberOrPercent(xRaw, plotWidthCss);\n  const y = parseNumberOrPercent(yRaw, plotHeightCss);\n\n  return {\n    x: Number.isFinite(x) ? x! : plotWidthCss * 0.5,\n    y: Number.isFinite(y) ? y! : plotHeightCss * 0.5,\n  };\n};\n\n/**\n * Type guard for pie radius tuple format `[inner, outer]`.\n *\n * @param radius - Pie radius configuration\n * @returns True if radius is a tuple\n */\nexport const isPieRadiusTuple = (\n  radius: PieRadius\n): radius is readonly [inner: number | string, outer: number | string] => Array.isArray(radius);\n\n/**\n * Resolves pie inner/outer radii with defaults, bounds checking.\n * Default outer radius is 70% of max, inner radius is 0 (full pie).\n *\n * @param radius - Pie radius configuration or undefined\n * @param maxRadiusCss - Maximum radius in CSS pixels\n * @returns Resolved inner and outer radii in CSS pixels\n */\nexport const resolvePieRadiiCss = (\n  radius: PieRadius | undefined,\n  maxRadiusCss: number\n): { readonly inner: number; readonly outer: number } => {\n  // Default similar to common chart libs (mirrors `createPieRenderer.ts`).\n  if (radius == null) return { inner: 0, outer: maxRadiusCss * 0.7 };\n\n  if (isPieRadiusTuple(radius)) {\n    const inner = parseNumberOrPercent(radius[0], maxRadiusCss);\n    const outer = parseNumberOrPercent(radius[1], maxRadiusCss);\n    const innerCss = Math.max(0, Number.isFinite(inner) ? inner! : 0);\n    const outerCss = Math.max(innerCss, Number.isFinite(outer) ? outer! : maxRadiusCss * 0.7);\n    return { inner: innerCss, outer: Math.min(maxRadiusCss, outerCss) };\n  }\n\n  const outer = parseNumberOrPercent(radius, maxRadiusCss);\n  const outerCss = Math.max(0, Number.isFinite(outer) ? outer! : maxRadiusCss * 0.7);\n  return { inner: 0, outer: Math.min(maxRadiusCss, outerCss) };\n};\n\n/**\n * Calculates decimal precision needed for clean tick formatting from tick step.\n * Prefers \"clean\" decimal representations (e.g. 2.5, 0.25, 0.125) without relying on magnitude alone.\n *\n * @param tickStep - Step size between ticks\n * @param cap - Maximum fraction digits to return (default 6)\n * @returns Number of fraction digits for formatting\n */\nexport const computeMaxFractionDigitsFromStep = (tickStep: number, cap: number = DEFAULT_MAX_TICK_FRACTION_DIGITS): number => {\n  const stepAbs = Math.abs(tickStep);\n  if (!Number.isFinite(stepAbs) || stepAbs === 0) return 0;\n\n  // Prefer \"clean\" decimal representations (e.g. 2.5, 0.25, 0.125) without relying on magnitude alone.\n  // We accept floating-point noise and cap the search to keep formatting reasonable.\n  for (let d = 0; d <= cap; d++) {\n    const scaled = stepAbs * 10 ** d;\n    const rounded = Math.round(scaled);\n    const err = Math.abs(scaled - rounded);\n    const tol = 1e-9 * Math.max(1, Math.abs(scaled));\n    if (err <= tol) return d;\n  }\n\n  // Fallback for repeating decimals (e.g. 1/3): show a small number of digits based on magnitude.\n  // The +1 nudges values like 0.333.. towards 2 decimals rather than 1.\n  return Math.max(0, Math.min(cap, Math.ceil(-Math.log10(stepAbs)) + 1));\n};\n\n/**\n * Creates Intl.NumberFormat instance for consistent tick formatting.\n * Automatically computes appropriate fraction digits from tick step.\n *\n * @param tickStep - Step size between ticks\n * @returns NumberFormat instance\n */\nexport const createTickFormatter = (tickStep: number): Intl.NumberFormat => {\n  const maximumFractionDigits = computeMaxFractionDigitsFromStep(tickStep);\n  return new Intl.NumberFormat(undefined, { maximumFractionDigits });\n};\n\n/**\n * Formats numeric value using NumberFormat, handles -0 and NaN edge cases.\n *\n * @param nf - NumberFormat instance\n * @param v - Value to format\n * @returns Formatted string or null if invalid\n */\nexport const formatTickValue = (nf: Intl.NumberFormat, v: number): string | null => {\n  if (!Number.isFinite(v)) return null;\n  // Avoid displaying \"-0\" from floating-point artifacts.\n  const normalized = Math.abs(v) < 1e-12 ? 0 : v;\n  const formatted = nf.format(normalized);\n  // Guard against unexpected output like \"NaN\" even after the finite check (defensive).\n  return formatted === 'NaN' ? null : formatted;\n};\n\n/**\n * Pads single-digit numbers with leading zero (used by time formatting).\n *\n * @param n - Number to pad\n * @returns Zero-padded string (minimum 2 digits)\n */\nexport const pad2 = (n: number): string => String(Math.trunc(n)).padStart(2, '0');\n\n/**\n * Formats millisecond timestamps with adaptive precision based on visible range.\n * Format tiers:\n * - < 1 day: HH:mm\n * - 1-7 days: MM/DD HH:mm\n * - 1-12 weeks (up to ~3 months): MM/DD\n * - 3-12 months: MMM DD\n * - > 1 year: YYYY/MM\n *\n * @param timestampMs - Timestamp in milliseconds\n * @param visibleRangeMs - Visible range width in milliseconds\n * @returns Formatted time string or null if invalid\n */\nexport const formatTimeTickValue = (timestampMs: number, visibleRangeMs: number): string | null => {\n  if (!Number.isFinite(timestampMs)) return null;\n  if (!Number.isFinite(visibleRangeMs) || visibleRangeMs < 0) visibleRangeMs = 0;\n\n  const d = new Date(timestampMs);\n  // Guard against out-of-range timestamps that produce an invalid Date.\n  if (!Number.isFinite(d.getTime())) return null;\n  const yyyy = d.getFullYear();\n  const mm = d.getMonth() + 1; // 1-12\n  const dd = d.getDate();\n  const hh = d.getHours();\n  const min = d.getMinutes();\n\n  if (visibleRangeMs < MS_PER_DAY) {\n    return `${pad2(hh)}:${pad2(min)}`;\n  }\n  // Treat the 7-day boundary as inclusive for the \"1–7 days\" tier.\n  if (visibleRangeMs <= 7 * MS_PER_DAY) {\n    return `${pad2(mm)}/${pad2(dd)} ${pad2(hh)}:${pad2(min)}`;\n  }\n  // Keep short calendar dates until the visible range reaches ~3 months.\n  if (visibleRangeMs < 3 * MS_PER_MONTH_APPROX) {\n    return `${pad2(mm)}/${pad2(dd)}`;\n  }\n  if (visibleRangeMs <= MS_PER_YEAR_APPROX) {\n    const mmm = MONTH_SHORT_EN[d.getMonth()] ?? pad2(mm);\n    return `${mmm} ${pad2(dd)}`;\n  }\n  return `${yyyy}/${pad2(mm)}`;\n};\n\n/**\n * Generates evenly-spaced tick values across domain.\n *\n * @param domainMin - Domain minimum value\n * @param domainMax - Domain maximum value\n * @param tickCount - Number of ticks to generate\n * @returns Array of tick values\n */\nexport const generateLinearTicks = (domainMin: number, domainMax: number, tickCount: number): number[] => {\n  const count = Math.max(1, Math.floor(tickCount));\n  const ticks: number[] = new Array(count);\n  for (let i = 0; i < count; i++) {\n    const t = count === 1 ? 0.5 : i / (count - 1);\n    ticks[i] = domainMin + t * (domainMax - domainMin);\n  }\n  return ticks;\n};\n\n/**\n * Computes optimal tick count + values to avoid label overlap on time x-axis.\n * Uses text measurement context to test label widths.\n * Tries tick counts from MAX (9) down to MIN (1) until labels fit without overlap.\n *\n * @param params - Configuration object with axis, scale, canvas, and measurement settings\n * @returns Object with tickCount and tickValues\n */\nexport const computeAdaptiveTimeXAxisTicks = (params: {\n  readonly axisMin: number | null;\n  readonly axisMax: number | null;\n  readonly xScale: LinearScale;\n  readonly plotClipLeft: number;\n  readonly plotClipRight: number;\n  readonly canvasCssWidth: number;\n  readonly visibleRangeMs: number;\n  readonly measureCtx: CanvasRenderingContext2D | null;\n  readonly measureCache?: Map<string, number>;\n  readonly fontSize: number;\n  readonly fontFamily: string;\n}): { readonly tickCount: number; readonly tickValues: readonly number[] } => {\n  const {\n    axisMin,\n    axisMax,\n    xScale,\n    plotClipLeft,\n    plotClipRight,\n    canvasCssWidth,\n    visibleRangeMs,\n    measureCtx,\n    measureCache,\n    fontSize,\n    fontFamily,\n  } = params;\n\n  // Domain fallback matches `createAxisRenderer` (use explicit min/max when provided).\n  const domainMin = finiteOrNull(axisMin) ?? xScale.invert(plotClipLeft);\n  const domainMax = finiteOrNull(axisMax) ?? xScale.invert(plotClipRight);\n\n  if (!measureCtx || canvasCssWidth <= 0) {\n    return { tickCount: DEFAULT_TICK_COUNT, tickValues: generateLinearTicks(domainMin, domainMax, DEFAULT_TICK_COUNT) };\n  }\n\n  // Ensure the measurement font matches the overlay labels.\n  measureCtx.font = `${fontSize}px ${fontFamily}`;\n  if (measureCache && measureCache.size > 2000) measureCache.clear();\n\n  // Pre-construct the font part of the cache key to avoid repeated concatenation.\n  const cacheKeyPrefix = measureCache ? `${fontSize}px ${fontFamily}@@` : null;\n\n  for (let tickCount = MAX_TIME_X_TICK_COUNT; tickCount >= MIN_TIME_X_TICK_COUNT; tickCount--) {\n    const tickValues = generateLinearTicks(domainMin, domainMax, tickCount);\n\n    // Compute label extents in *canvas-local CSS px* and ensure adjacent labels don't overlap.\n    let prevRight = Number.NEGATIVE_INFINITY;\n    let ok = true;\n\n    for (let i = 0; i < tickValues.length; i++) {\n      const v = tickValues[i]!;\n      const label = formatTimeTickValue(v, visibleRangeMs);\n      if (label == null) continue;\n\n      const w = (() => {\n        if (!cacheKeyPrefix) return measureCtx.measureText(label).width;\n        const key = cacheKeyPrefix + label;\n        const cached = measureCache!.get(key);\n        if (cached != null) return cached;\n        const measured = measureCtx.measureText(label).width;\n        measureCache!.set(key, measured);\n        return measured;\n      })();\n      const xClip = xScale.scale(v);\n      const xCss = clipXToCanvasCssPx(xClip, canvasCssWidth);\n\n      const anchor: TextOverlayAnchor =\n        tickCount === 1 ? 'middle' : i === 0 ? 'start' : i === tickValues.length - 1 ? 'end' : 'middle';\n\n      const left = anchor === 'start' ? xCss : anchor === 'end' ? xCss - w : xCss - w * 0.5;\n      const right = anchor === 'start' ? xCss + w : anchor === 'end' ? xCss : xCss + w * 0.5;\n\n      if (left < prevRight + MIN_X_LABEL_GAP_CSS_PX) {\n        ok = false;\n        break;\n      }\n      prevRight = right;\n    }\n\n    if (ok) {\n      return { tickCount, tickValues };\n    }\n  }\n\n  return { tickCount: MIN_TIME_X_TICK_COUNT, tickValues: generateLinearTicks(domainMin, domainMax, MIN_TIME_X_TICK_COUNT) };\n};\n","/**\n * Axis tick computation and formatting.\n *\n * Generates tick values and formatting for linear axes. Handles decimal precision\n * determination based on tick step size and provides number formatting utilities.\n *\n * @module computeAxisTicks\n */\n\n/**\n * Default maximum fraction digits for tick formatting.\n */\nconst DEFAULT_MAX_TICK_FRACTION_DIGITS = 8;\n\n/**\n * Generates evenly-spaced tick values between domain min and max.\n *\n * @param domainMin - Minimum value of the domain\n * @param domainMax - Maximum value of the domain\n * @param tickCount - Number of ticks to generate (must be >= 1)\n * @returns Array of tick values\n */\nexport function generateLinearTicks(domainMin: number, domainMax: number, tickCount: number): number[] {\n  const count = Math.max(1, Math.floor(tickCount));\n  const ticks: number[] = new Array(count);\n  for (let i = 0; i < count; i++) {\n    const t = count === 1 ? 0.5 : i / (count - 1);\n    const v = domainMin + t * (domainMax - domainMin);\n    ticks[i] = v;\n  }\n  return ticks;\n}\n\n/**\n * Computes the maximum number of decimal places needed to display a tick step cleanly.\n *\n * Prefers \"clean\" decimal representations (e.g., 2.5, 0.25, 0.125) without relying on\n * magnitude alone. Accepts floating-point noise and caps the search to keep formatting\n * reasonable.\n *\n * @param tickStep - The step size between ticks\n * @param cap - Maximum number of decimal places to consider (default: 8)\n * @returns Number of decimal places (0 to cap)\n */\nexport function computeMaxFractionDigitsFromStep(tickStep: number, cap: number = DEFAULT_MAX_TICK_FRACTION_DIGITS): number {\n  const stepAbs = Math.abs(tickStep);\n  if (!Number.isFinite(stepAbs) || stepAbs === 0) return 0;\n\n  // Prefer \"clean\" decimal representations (e.g. 2.5, 0.25, 0.125) without relying on magnitude alone.\n  // We accept floating-point noise and cap the search to keep formatting reasonable.\n  for (let d = 0; d <= cap; d++) {\n    const scaled = stepAbs * 10 ** d;\n    const rounded = Math.round(scaled);\n    const err = Math.abs(scaled - rounded);\n    const tol = 1e-9 * Math.max(1, Math.abs(scaled));\n    if (err <= tol) return d;\n  }\n\n  // Fallback for repeating decimals (e.g. 1/3): show a small number of digits based on magnitude.\n  // The +1 nudges values like 0.333.. towards 2 decimals rather than 1.\n  return Math.max(0, Math.min(cap, 1 - Math.floor(Math.log10(stepAbs)) + 1));\n}\n\n/**\n * Creates an Intl.NumberFormat for tick value formatting.\n *\n * Automatically determines the appropriate number of decimal places based on the\n * tick step size using `computeMaxFractionDigitsFromStep()`.\n *\n * @param tickStep - The step size between ticks\n * @returns Intl.NumberFormat configured for tick formatting\n */\nexport function createTickFormatter(tickStep: number): Intl.NumberFormat {\n  const maximumFractionDigits = computeMaxFractionDigitsFromStep(tickStep);\n  return new Intl.NumberFormat(undefined, { maximumFractionDigits });\n}\n\n/**\n * Formats a numeric tick value using the provided number formatter.\n *\n * Handles edge cases:\n * - Non-finite values return null\n * - Values near zero (< 1e-12) are normalized to 0 to avoid \"-0\" display\n * - Unexpected \"NaN\" output from formatter is guarded against\n *\n * @param nf - Intl.NumberFormat to use for formatting\n * @param v - Numeric value to format\n * @returns Formatted string or null if value cannot be formatted\n */\nexport function formatTickValue(nf: Intl.NumberFormat, v: number): string | null {\n  if (!Number.isFinite(v)) return null;\n  // Avoid displaying \"-0\" from floating-point artifacts.\n  const normalized = Math.abs(v) < 1e-12 ? 0 : v;\n  const formatted = nf.format(normalized);\n  // Guard against unexpected output like \"NaN\" even after the finite check (defensive).\n  return formatted === 'NaN' ? null : formatted;\n}\n","/**\n * Shared axis label styling utilities.\n */\n\n/**\n * Theme configuration for axis labels.\n */\nexport interface AxisLabelThemeConfig {\n  readonly fontSize: number;\n  readonly fontFamily: string;\n  readonly textColor: string;\n}\n\n/**\n * Calculates the font size for axis titles (larger than regular tick labels).\n */\nexport function getAxisTitleFontSize(baseFontSize: number): number {\n  return Math.max(\n    baseFontSize + 1,\n    Math.round(baseFontSize * 1.15)\n  );\n}\n\n/**\n * Applies consistent styling to an axis label span element.\n */\nexport function styleAxisLabelSpan(\n  span: HTMLSpanElement,\n  isTitle: boolean,\n  theme: AxisLabelThemeConfig\n): void {\n  // Set inline styles\n  span.dir = 'auto';\n  span.style.fontFamily = theme.fontFamily;\n\n  // Axis titles are bold\n  if (isTitle) {\n    span.style.fontWeight = '600';\n  }\n}\n\n","/**\n * Axis Label Rendering Utilities\n *\n * Generates DOM-based axis labels and titles for cartesian charts.\n * Labels are positioned using canvas-local CSS coordinates and rendered\n * into a text overlay element.\n *\n * @module renderAxisLabels\n */\n\nimport type { ResolvedChartGPUOptions } from '../../../config/OptionResolver';\nimport type { LinearScale } from '../../../utils/scales';\nimport type { TextOverlay, TextOverlayAnchor } from '../../../components/createTextOverlay';\nimport { getCanvasCssWidth, getCanvasCssHeight } from '../utils/canvasUtils';\nimport { formatTimeTickValue } from '../utils/timeAxisUtils';\nimport { formatTickValue, createTickFormatter } from '../axis/computeAxisTicks';\nimport { finiteOrUndefined } from '../utils/dataPointUtils';\nimport { getAxisTitleFontSize } from '../../../utils/axisLabelStyling';\n\nconst DEFAULT_TICK_LENGTH_CSS_PX = 6;\nconst LABEL_PADDING_CSS_PX = 4;\nconst DEFAULT_TICK_COUNT = 5;\n\nexport interface AxisLabelRenderContext {\n  gpuContext: {\n    canvas: HTMLCanvasElement | OffscreenCanvas | null;\n  };\n  currentOptions: ResolvedChartGPUOptions;\n  xScale: LinearScale;\n  yScale: LinearScale;\n  xTickValues: ReadonlyArray<number>;\n  plotClipRect: {\n    left: number;\n    right: number;\n    top: number;\n    bottom: number;\n  };\n  visibleXRangeMs: number;\n}\n\nfunction clipXToCanvasCssPx(xClip: number, canvasCssWidth: number): number {\n  return ((xClip + 1) / 2) * canvasCssWidth;\n}\n\nfunction clipYToCanvasCssPx(yClip: number, canvasCssHeight: number): number {\n  return ((1 - yClip) / 2) * canvasCssHeight;\n}\n\nfunction styleAxisLabelSpan(span: HTMLSpanElement, isTitle: boolean, theme: ResolvedChartGPUOptions['theme']): void {\n  span.style.fontFamily = theme.fontFamily;\n  span.style.fontWeight = isTitle ? '500' : '400';\n  span.style.userSelect = 'none';\n  span.style.pointerEvents = 'none';\n}\n\n/**\n * Renders axis labels and titles to the text overlay.\n *\n * Generates X and Y axis tick labels with appropriate formatting,\n * and renders axis titles if configured.\n *\n * @param axisLabelOverlay - Text overlay for rendering labels\n * @param overlayContainer - DOM container for overlay positioning\n * @param context - Rendering context with scales, options, and layout\n */\nexport function renderAxisLabels(\n  axisLabelOverlay: TextOverlay | null,\n  overlayContainer: HTMLElement | null,\n  context: AxisLabelRenderContext\n): void {\n  const { gpuContext, currentOptions, xScale, yScale, xTickValues, plotClipRect, visibleXRangeMs } = context;\n\n  const hasCartesianSeries = currentOptions.series.some((s) => s.type !== 'pie');\n  if (!hasCartesianSeries || !axisLabelOverlay || !overlayContainer) {\n    return;\n  }\n\n  const canvas = gpuContext.canvas;\n  if (!canvas) return;\n\n  // Get canvas dimensions\n  const canvasCssWidth = getCanvasCssWidth(canvas as HTMLCanvasElement);\n  const canvasCssHeight = getCanvasCssHeight(canvas as HTMLCanvasElement);\n  if (canvasCssWidth <= 0 || canvasCssHeight <= 0) return;\n\n  // Calculate offsets (only for HTMLCanvasElement with DOM)\n  const offsetX = (canvas as HTMLCanvasElement).offsetLeft || 0;\n  const offsetY = (canvas as HTMLCanvasElement).offsetTop || 0;\n\n  const plotLeftCss = clipXToCanvasCssPx(plotClipRect.left, canvasCssWidth);\n  const plotRightCss = clipXToCanvasCssPx(plotClipRect.right, canvasCssWidth);\n  const plotTopCss = clipYToCanvasCssPx(plotClipRect.top, canvasCssHeight);\n  const plotBottomCss = clipYToCanvasCssPx(plotClipRect.bottom, canvasCssHeight);\n\n  // Clear axis label overlay\n  axisLabelOverlay.clear();\n\n  // X-axis tick labels\n  const xTickLengthCssPx = currentOptions.xAxis.tickLength ?? DEFAULT_TICK_LENGTH_CSS_PX;\n  const xLabelY = plotBottomCss + xTickLengthCssPx + LABEL_PADDING_CSS_PX + currentOptions.theme.fontSize * 0.5;\n  const isTimeXAxis = currentOptions.xAxis.type === 'time';\n  const xFormatter = (() => {\n    if (isTimeXAxis) return null;\n    const xDomainMin = finiteOrUndefined(currentOptions.xAxis.min) ?? xScale.invert(plotClipRect.left);\n    const xDomainMax = finiteOrUndefined(currentOptions.xAxis.max) ?? xScale.invert(plotClipRect.right);\n    const xTickCount = xTickValues.length;\n    const xTickStep = xTickCount === 1 ? 0 : (xDomainMax - xDomainMin) / (xTickCount - 1);\n    return createTickFormatter(xTickStep);\n  })();\n\n  for (let i = 0; i < xTickValues.length; i++) {\n    const v = xTickValues[i]!;\n    const xClip = xScale.scale(v);\n    const xCss = clipXToCanvasCssPx(xClip, canvasCssWidth);\n\n    const anchor: TextOverlayAnchor =\n      xTickValues.length === 1 ? 'middle' : i === 0 ? 'start' : i === xTickValues.length - 1 ? 'end' : 'middle';\n    const label = isTimeXAxis ? formatTimeTickValue(v, visibleXRangeMs) : formatTickValue(xFormatter!, v);\n    if (label == null) continue;\n\n    const span = axisLabelOverlay.addLabel(label, offsetX + xCss, offsetY + xLabelY, {\n      fontSize: currentOptions.theme.fontSize,\n      color: currentOptions.theme.textColor,\n      anchor,\n    });\n    styleAxisLabelSpan(span, false, currentOptions.theme);\n  }\n\n  // Y-axis tick labels\n  const yTickCount = DEFAULT_TICK_COUNT;\n  const yTickLengthCssPx = currentOptions.yAxis.tickLength ?? DEFAULT_TICK_LENGTH_CSS_PX;\n  const yDomainMin = finiteOrUndefined(currentOptions.yAxis.min) ?? yScale.invert(plotClipRect.bottom);\n  const yDomainMax = finiteOrUndefined(currentOptions.yAxis.max) ?? yScale.invert(plotClipRect.top);\n  const yTickStep = yTickCount <= 1 ? 0 : (yDomainMax - yDomainMin) / (yTickCount - 1);\n  const yFormatter = createTickFormatter(yTickStep);\n  const yLabelX = plotLeftCss - yTickLengthCssPx - LABEL_PADDING_CSS_PX;\n  const ySpans: HTMLSpanElement[] = [];\n\n  for (let i = 0; i < yTickCount; i++) {\n    const t = yTickCount <= 1 ? 0.5 : i / (yTickCount - 1);\n    const v = yDomainMin + t * (yDomainMax - yDomainMin);\n    const yClip = yScale.scale(v);\n    const yCss = clipYToCanvasCssPx(yClip, canvasCssHeight);\n\n    const label = formatTickValue(yFormatter, v);\n    if (label == null) continue;\n\n    const span = axisLabelOverlay.addLabel(label, offsetX + yLabelX, offsetY + yCss, {\n      fontSize: currentOptions.theme.fontSize,\n      color: currentOptions.theme.textColor,\n      anchor: 'end',\n    });\n    styleAxisLabelSpan(span, false, currentOptions.theme);\n    ySpans.push(span);\n  }\n\n  // X-axis title\n  const axisNameFontSize = getAxisTitleFontSize(currentOptions.theme.fontSize);\n  const xAxisName = currentOptions.xAxis.name?.trim() ?? '';\n  if (xAxisName.length > 0) {\n    const xCenter = (plotLeftCss + plotRightCss) / 2;\n    const xTickLabelsBottom = xLabelY + currentOptions.theme.fontSize * 0.5;\n    const hasSliderZoom = currentOptions.dataZoom?.some((z) => z?.type === 'slider') ?? false;\n    const sliderTrackHeightCssPx = 32;\n    const bottomLimitCss = hasSliderZoom ? canvasCssHeight - sliderTrackHeightCssPx : canvasCssHeight;\n    const xTitleY = (xTickLabelsBottom + bottomLimitCss) / 2;\n\n    const span = axisLabelOverlay.addLabel(xAxisName, offsetX + xCenter, offsetY + xTitleY, {\n      fontSize: axisNameFontSize,\n      color: currentOptions.theme.textColor,\n      anchor: 'middle',\n    });\n    styleAxisLabelSpan(span, true, currentOptions.theme);\n  }\n\n  // Y-axis title\n  const yAxisName = currentOptions.yAxis.name?.trim() ?? '';\n  if (yAxisName.length > 0) {\n    // Measure actual rendered label widths from DOM\n    const maxTickLabelWidth =\n      ySpans.length === 0 ? 0 : ySpans.reduce((max, s) => Math.max(max, s.getBoundingClientRect().width), 0);\n\n    const yCenter = (plotTopCss + plotBottomCss) / 2;\n    const yTickLabelLeft = yLabelX - maxTickLabelWidth;\n    const yTitleX = yTickLabelLeft - LABEL_PADDING_CSS_PX - axisNameFontSize * 0.5;\n\n    const span = axisLabelOverlay.addLabel(yAxisName, offsetX + yTitleX, offsetY + yCenter, {\n      fontSize: axisNameFontSize,\n      color: currentOptions.theme.textColor,\n      anchor: 'middle',\n      rotation: -90,\n    });\n    styleAxisLabelSpan(span, true, currentOptions.theme);\n  }\n}\n","/**\n * Annotation Label Rendering Utilities\n *\n * Generates DOM-based annotation labels for cartesian charts.\n * Handles template rendering, coordinate transformations, and styling\n * for lineX, lineY, point, and text annotations.\n *\n * @module renderAnnotationLabels\n */\n\nimport type { ResolvedChartGPUOptions } from '../../../config/OptionResolver';\nimport type { LinearScale } from '../../../utils/scales';\nimport type { TextOverlay, TextOverlayAnchor } from '../../../components/createTextOverlay';\nimport { parseCssColorToRgba01 } from '../../../utils/colors';\nimport { clamp01 } from '../utils/axisUtils';\nimport { assertUnreachable } from '../utils/dataPointUtils';\n\nexport interface AnnotationLabelRenderContext {\n  currentOptions: ResolvedChartGPUOptions;\n  xScale: LinearScale;\n  yScale: LinearScale;\n  canvasCssWidthForAnnotations: number;\n  canvasCssHeightForAnnotations: number;\n  plotLeftCss: number;\n  plotTopCss: number;\n  plotWidthCss: number;\n  plotHeightCss: number;\n  canvas: HTMLCanvasElement | OffscreenCanvas;\n}\n\ninterface AnnotationLabelData {\n  text: string;\n  x: number;\n  y: number;\n  anchor: TextOverlayAnchor;\n  color: string;\n  fontSize: number;\n  background?: {\n    backgroundColor: string;\n    padding?: readonly [number, number, number, number];\n    borderRadius?: number;\n  };\n}\n\nfunction isHTMLCanvasElement(canvas: HTMLCanvasElement | OffscreenCanvas): canvas is HTMLCanvasElement {\n  return 'offsetLeft' in canvas;\n}\n\nfunction clipXToCanvasCssPx(xClip: number, canvasCssWidth: number): number {\n  return ((xClip + 1) / 2) * canvasCssWidth;\n}\n\nfunction clipYToCanvasCssPx(yClip: number, canvasCssHeight: number): number {\n  return ((1 - yClip) / 2) * canvasCssHeight;\n}\n\nfunction toCssRgba(color: string, opacity01: number): string {\n  const base = parseCssColorToRgba01(color) ?? ([0, 0, 0, 1] as const);\n  const a = clamp01(base[3] * clamp01(opacity01));\n  const r = Math.round(clamp01(base[0]) * 255);\n  const g = Math.round(clamp01(base[1]) * 255);\n  const b = Math.round(clamp01(base[2]) * 255);\n  return `rgba(${r}, ${g}, ${b}, ${a})`;\n}\n\nfunction formatNumber(n: number, decimals?: number): string {\n  if (!Number.isFinite(n)) return '';\n  if (decimals == null) return String(n);\n  const d = Math.min(20, Math.max(0, Math.floor(decimals)));\n  return n.toFixed(d);\n}\n\n// PERFORMANCE: Cache regex pattern (compiled once per render, reused for all templates)\nconst templateRegex = /\\{(x|y|value|name)\\}/g;\n\nfunction renderTemplate(\n  template: string,\n  values: Readonly<{ x?: number; y?: number; value?: number; name?: string }>,\n  decimals?: number\n): string {\n  // PERFORMANCE: Reset regex lastIndex to ensure consistent behavior\n  templateRegex.lastIndex = 0;\n  return template.replace(templateRegex, (_m, key) => {\n    if (key === 'name') return values.name ?? '';\n    const v = (values as any)[key] as number | undefined;\n    return v == null ? '' : formatNumber(v, decimals);\n  });\n}\n\nfunction mapAnchor(anchor: 'start' | 'center' | 'end' | undefined): TextOverlayAnchor {\n  switch (anchor) {\n    case 'center':\n      return 'middle';\n    case 'end':\n      return 'end';\n    case 'start':\n    default:\n      return 'start';\n  }\n}\n\n/**\n * Renders annotation labels to the text overlay.\n *\n * Processes annotations and generates DOM labels with template support,\n * coordinate transformations, and background styling.\n *\n * @param annotationOverlay - Text overlay for rendering labels\n * @param overlayContainer - DOM container for overlay positioning\n * @param context - Rendering context with scales, options, and layout\n */\nexport function renderAnnotationLabels(\n  annotationOverlay: TextOverlay | null,\n  overlayContainer: HTMLElement | null,\n  context: AnnotationLabelRenderContext\n): void {\n  const {\n    currentOptions,\n    xScale,\n    yScale,\n    canvasCssWidthForAnnotations,\n    canvasCssHeightForAnnotations,\n    plotLeftCss,\n    plotTopCss,\n    plotWidthCss,\n    plotHeightCss,\n    canvas,\n  } = context;\n\n  const hasCartesianSeries = currentOptions.series.some((s) => s.type !== 'pie');\n  if (!hasCartesianSeries || !annotationOverlay || !overlayContainer) {\n    return;\n  }\n\n  // Validate canvas dimensions\n  if (\n    !canvas ||\n    canvasCssWidthForAnnotations <= 0 ||\n    canvasCssHeightForAnnotations <= 0 ||\n    plotWidthCss <= 0 ||\n    plotHeightCss <= 0\n  ) {\n    annotationOverlay.clear();\n    return;\n  }\n\n  const offsetX = isHTMLCanvasElement(canvas) ? canvas.offsetLeft : 0;\n  const offsetY = isHTMLCanvasElement(canvas) ? canvas.offsetTop : 0;\n\n  annotationOverlay.clear();\n\n  const annotations = currentOptions.annotations ?? [];\n  if (annotations.length === 0) {\n    return;\n  }\n\n  const labelsOut: AnnotationLabelData[] = [];\n\n  for (let i = 0; i < annotations.length; i++) {\n    const a = annotations[i]!;\n\n    const labelCfg = a.label;\n    const wantsLabel = labelCfg != null || a.type === 'text';\n    if (!wantsLabel) continue;\n\n    // Compute anchor point (canvas-local CSS px)\n    let anchorXCss: number | null = null;\n    let anchorYCss: number | null = null;\n    let values: { x?: number; y?: number; value?: number; name?: string } = { name: a.id ?? '' };\n\n    switch (a.type) {\n      case 'lineX': {\n        const xClip = xScale.scale(a.x);\n        const xCss = clipXToCanvasCssPx(xClip, canvasCssWidthForAnnotations);\n        anchorXCss = xCss;\n        anchorYCss = plotTopCss;\n        values = { ...values, x: a.x, value: a.x };\n        break;\n      }\n      case 'lineY': {\n        const yClip = yScale.scale(a.y);\n        const yCss = clipYToCanvasCssPx(yClip, canvasCssHeightForAnnotations);\n        anchorXCss = plotLeftCss;\n        // Offset label 8px above the horizontal line (negative Y = upward)\n        anchorYCss = yCss - 8;\n        values = { ...values, y: a.y, value: a.y };\n        break;\n      }\n      case 'point': {\n        const xClip = xScale.scale(a.x);\n        const yClip = yScale.scale(a.y);\n        const xCss = clipXToCanvasCssPx(xClip, canvasCssWidthForAnnotations);\n        const yCss = clipYToCanvasCssPx(yClip, canvasCssHeightForAnnotations);\n        anchorXCss = xCss;\n        anchorYCss = yCss;\n        values = { ...values, x: a.x, y: a.y, value: a.y };\n        break;\n      }\n      case 'text': {\n        if (a.position.space === 'data') {\n          const xClip = xScale.scale(a.position.x);\n          const yClip = yScale.scale(a.position.y);\n          const xCss = clipXToCanvasCssPx(xClip, canvasCssWidthForAnnotations);\n          const yCss = clipYToCanvasCssPx(yClip, canvasCssHeightForAnnotations);\n          anchorXCss = xCss;\n          anchorYCss = yCss;\n          values = { ...values, x: a.position.x, y: a.position.y, value: a.position.y };\n        } else {\n          const xCss = plotLeftCss + a.position.x * plotWidthCss;\n          const yCss = plotTopCss + a.position.y * plotHeightCss;\n          anchorXCss = xCss;\n          anchorYCss = yCss;\n          values = { ...values, x: a.position.x, y: a.position.y, value: a.position.y };\n        }\n        break;\n      }\n      default:\n        assertUnreachable(a);\n    }\n\n    if (anchorXCss == null || anchorYCss == null || !Number.isFinite(anchorXCss) || !Number.isFinite(anchorYCss)) {\n      continue;\n    }\n\n    const dx = labelCfg?.offset?.[0] ?? 0;\n    const dy = labelCfg?.offset?.[1] ?? 0;\n    const x = anchorXCss + dx;\n    const y = anchorYCss + dy;\n\n    // Label text selection (explicit > template > defaults)\n    const text =\n      labelCfg?.text ??\n      (labelCfg?.template\n        ? renderTemplate(labelCfg.template, values, labelCfg.decimals)\n        : labelCfg\n          ? (() => {\n              const defaultTemplate =\n                a.type === 'lineX'\n                  ? 'x={x}'\n                  : a.type === 'lineY'\n                    ? 'y={y}'\n                    : a.type === 'point'\n                      ? '({x}, {y})'\n                      : a.type === 'text'\n                        ? a.text\n                        : '';\n              return defaultTemplate.includes('{')\n                ? renderTemplate(defaultTemplate, values, labelCfg.decimals)\n                : defaultTemplate;\n            })()\n          : a.type === 'text'\n            ? a.text\n            : '');\n\n    const trimmed = typeof text === 'string' ? text.trim() : '';\n    if (trimmed.length === 0) continue;\n\n    const anchor = mapAnchor(labelCfg?.anchor);\n    const color = a.style?.color ?? currentOptions.theme.textColor;\n    const fontSize = currentOptions.theme.fontSize;\n\n    const bg = labelCfg?.background;\n    const bgColor = bg?.color != null ? toCssRgba(bg.color, bg.opacity ?? 1) : undefined;\n    const padding = (() => {\n      const p = bg?.padding;\n      if (typeof p === 'number' && Number.isFinite(p)) return [p, p, p, p] as const;\n      if (Array.isArray(p) && p.length === 4 && p.every((n) => typeof n === 'number' && Number.isFinite(n))) {\n        return [p[0], p[1], p[2], p[3]] as const;\n      }\n      return bg ? ([2, 4, 2, 4] as const) : undefined;\n    })();\n    const borderRadius =\n      typeof bg?.borderRadius === 'number' && Number.isFinite(bg.borderRadius) ? bg.borderRadius : undefined;\n\n    const labelData: AnnotationLabelData = {\n      text: trimmed,\n      x: offsetX + x,\n      y: offsetY + y,\n      anchor,\n      color,\n      fontSize,\n      ...(bgColor\n        ? {\n            background: {\n              backgroundColor: bgColor,\n              ...(padding ? { padding } : {}),\n              ...(borderRadius != null ? { borderRadius } : {}),\n            },\n          }\n        : {}),\n    };\n\n    labelsOut.push(labelData);\n\n    // Render label to DOM\n    const span = annotationOverlay.addLabel(trimmed, labelData.x, labelData.y, {\n      fontSize,\n      color,\n      anchor,\n    });\n\n    if (labelData.background) {\n      span.style.backgroundColor = labelData.background.backgroundColor;\n      span.style.display = 'inline-block';\n      span.style.boxSizing = 'border-box';\n      if (labelData.background.padding) {\n        const [t, r, b, l] = labelData.background.padding;\n        span.style.padding = `${t}px ${r}px ${b}px ${l}px`;\n      }\n      if (labelData.background.borderRadius != null) {\n        span.style.borderRadius = `${labelData.background.borderRadius}px`;\n      }\n    }\n  }\n}\n","import type { DataPoint, CartesianSeriesData, DataPointTuple, ScatterPointTuple } from '../config/types';\nimport type {\n  ResolvedBarSeriesConfig,\n  ResolvedScatterSeriesConfig,\n  ResolvedSeriesConfig,\n} from '../config/OptionResolver';\nimport type { LinearScale } from '../utils/scales';\nimport { getPointCount, getX, getY, getSize } from '../data/cartesianData';\nimport { isMonotonicNonDecreasingFiniteX } from '../core/renderCoordinator/data/computeVisibleSlice';\n\nconst DEFAULT_MAX_DISTANCE_PX = 20;\nconst DEFAULT_BAR_GAP = 0.01; // Minimal gap between bars within a group (was 0.1)\nconst DEFAULT_BAR_CATEGORY_GAP = 0.2;\nconst DEFAULT_SCATTER_RADIUS_CSS_PX = 4;\n\n/**\n * Binary search: finds the lower bound index (first element >= target) in monotonic cartesian data.\n * Returns index in range [0, n] where n = point count.\n */\nfunction lowerBoundX(data: CartesianSeriesData, xTarget: number): number {\n  let lo = 0;\n  let hi = getPointCount(data);\n  while (lo < hi) {\n    const mid = (lo + hi) >>> 1;\n    const x = getX(data, mid);\n    if (x < xTarget) lo = mid + 1;\n    else hi = mid;\n  }\n  return lo;\n}\n\nexport type NearestPointMatch = Readonly<{\n  seriesIndex: number;\n  dataIndex: number;\n  point: DataPoint;\n  /** Euclidean distance in range units. */\n  distance: number;\n}>;\n\nexport type BarBounds = { left: number; right: number; top: number; bottom: number };\n\nexport function isPointInBar(x: number, y: number, barBounds: BarBounds): boolean {\n  // Inclusive bounds.\n  // Note: stacked bar segments can share edges; tie-breaking is handled by the caller.\n  return (\n    x >= barBounds.left &&\n    x <= barBounds.right &&\n    y >= barBounds.top &&\n    y <= barBounds.bottom\n  );\n}\n\nconst clamp01 = (v: number): number => Math.min(1, Math.max(0, v));\n\nconst parsePercent = (value: string): number | null => {\n  const m = value.trim().match(/^(\\d+(?:\\.\\d+)?)%$/);\n  if (!m) return null;\n  const p = Number(m[1]) / 100;\n  return Number.isFinite(p) ? p : null;\n};\n\nconst normalizeStackId = (stack: unknown): string => {\n  if (typeof stack !== 'string') return '';\n  const trimmed = stack.trim();\n  return trimmed.length > 0 ? trimmed : '';\n};\n\nconst isTupleDataPoint = (p: DataPoint): p is DataPointTuple => Array.isArray(p);\n\nconst getPointSizeCssPx = (p: DataPoint): number | null => {\n  if (isTupleDataPoint(p)) {\n    const s = p[2];\n    return typeof s === 'number' && Number.isFinite(s) ? s : null;\n  }\n  const s = p.size;\n  return typeof s === 'number' && Number.isFinite(s) ? s : null;\n};\n\nconst toScatterTuple = (p: DataPoint): ScatterPointTuple => {\n  if (isTupleDataPoint(p)) return p;\n  return [p.x, p.y, p.size] as const;\n};\n\nconst safeCallSymbolSize = (\n  fn: (value: ScatterPointTuple) => number,\n  value: ScatterPointTuple,\n): number | null => {\n  try {\n    const v = fn(value);\n    return typeof v === 'number' && Number.isFinite(v) ? v : null;\n  } catch {\n    return null;\n  }\n};\n\nconst getScatterRadiusCssPx = (seriesCfg: ResolvedScatterSeriesConfig, p: DataPoint): number => {\n  // Mirrors `createScatterRenderer.ts` size semantics (but stays in CSS px):\n  // point.size -> series.symbolSize -> default 4px.\n  const perPoint = getPointSizeCssPx(p);\n  if (perPoint != null) return Math.max(0, perPoint);\n\n  const seriesSymbolSize = seriesCfg.symbolSize;\n  if (typeof seriesSymbolSize === 'number') {\n    return Number.isFinite(seriesSymbolSize)\n      ? Math.max(0, seriesSymbolSize)\n      : DEFAULT_SCATTER_RADIUS_CSS_PX;\n  }\n  if (typeof seriesSymbolSize === 'function') {\n    const v = safeCallSymbolSize(seriesSymbolSize, toScatterTuple(p));\n    return v == null ? DEFAULT_SCATTER_RADIUS_CSS_PX : Math.max(0, v);\n  }\n\n  return DEFAULT_SCATTER_RADIUS_CSS_PX;\n};\n\n\n// Note: we intentionally do NOT compute “nearest bar by distance”.\n// Bars are only considered a match when the cursor is inside their rect bounds.\n\nexport type BarClusterSlots = Readonly<{\n  clusterIndexBySeries: ReadonlyArray<number>;\n  clusterCount: number;\n  stackIdBySeries: ReadonlyArray<string>;\n}>;\n\nexport function computeBarClusterSlots(\n  seriesConfigs: ReadonlyArray<ResolvedBarSeriesConfig>,\n): BarClusterSlots {\n  // Cluster slots (mirrors `createBarRenderer.ts`):\n  // - Each unique non-empty stackId gets a single cluster slot.\n  // - Each unstacked series gets its own cluster slot.\n  const stackIdToClusterIndex = new Map<string, number>();\n  const clusterIndexBySeries: number[] = new Array(seriesConfigs.length);\n  const stackIdBySeries: string[] = new Array(seriesConfigs.length);\n\n  let clusterCount = 0;\n  for (let i = 0; i < seriesConfigs.length; i++) {\n    const stackId = normalizeStackId(seriesConfigs[i].stack);\n    stackIdBySeries[i] = stackId;\n\n    if (stackId !== '') {\n      const existing = stackIdToClusterIndex.get(stackId);\n      if (existing !== undefined) {\n        clusterIndexBySeries[i] = existing;\n      } else {\n        const idx = clusterCount++;\n        stackIdToClusterIndex.set(stackId, idx);\n        clusterIndexBySeries[i] = idx;\n      }\n    } else {\n      clusterIndexBySeries[i] = clusterCount++;\n    }\n  }\n\n  return {\n    clusterIndexBySeries,\n    clusterCount: Math.max(1, clusterCount),\n    stackIdBySeries,\n  };\n}\n\nexport function computeBarCategoryStep(seriesConfigs: ReadonlyArray<ResolvedBarSeriesConfig>): number {\n  const xs: number[] = [];\n  for (let s = 0; s < seriesConfigs.length; s++) {\n    const data = seriesConfigs[s].data as CartesianSeriesData;\n    const n = getPointCount(data);\n    for (let i = 0; i < n; i++) {\n      const x = getX(data, i);\n      if (Number.isFinite(x)) xs.push(x);\n    }\n  }\n\n  if (xs.length < 2) return 1;\n  xs.sort((a, b) => a - b);\n\n  let minStep = Number.POSITIVE_INFINITY;\n  for (let i = 1; i < xs.length; i++) {\n    const d = xs[i] - xs[i - 1];\n    if (d > 0 && d < minStep) minStep = d;\n  }\n  return Number.isFinite(minStep) && minStep > 0 ? minStep : 1;\n}\n\nexport function computeCategoryWidthPx(\n  seriesConfigs: ReadonlyArray<ResolvedBarSeriesConfig>,\n  xScale: LinearScale,\n  categoryStep: number,\n): number {\n  // Primary path (mirrors renderer): derive width from domain step via scale().\n  if (Number.isFinite(categoryStep) && categoryStep > 0) {\n    const x0 = 0;\n    const p0 = xScale.scale(x0);\n    const p1 = xScale.scale(x0 + categoryStep);\n    const w = Math.abs(p1 - p0);\n    if (Number.isFinite(w) && w > 0) return w;\n  }\n\n  // Fallback: compute min positive delta in *scaled* x positions.\n  const sx: number[] = [];\n  for (let s = 0; s < seriesConfigs.length; s++) {\n    const data = seriesConfigs[s].data as CartesianSeriesData;\n    const n = getPointCount(data);\n    for (let i = 0; i < n; i++) {\n      const x = getX(data, i);\n      if (!Number.isFinite(x)) continue;\n      const px = xScale.scale(x);\n      if (Number.isFinite(px)) sx.push(px);\n    }\n  }\n  if (sx.length < 2) return 0;\n  sx.sort((a, b) => a - b);\n\n  let minDx = Number.POSITIVE_INFINITY;\n  for (let i = 1; i < sx.length; i++) {\n    const d = sx[i] - sx[i - 1];\n    if (d > 0 && d < minDx) minDx = d;\n  }\n\n  return Number.isFinite(minDx) && minDx > 0 ? minDx : 0;\n}\n\ntype BarSharedLayout = Readonly<{\n  barWidth?: number | string;\n  barGap?: number;\n  barCategoryGap?: number;\n}>;\n\nconst computeSharedBarLayout = (\n  seriesConfigs: ReadonlyArray<ResolvedBarSeriesConfig>,\n): BarSharedLayout => {\n  let barWidth: number | string | undefined = undefined;\n  let barGap: number | undefined = undefined;\n  let barCategoryGap: number | undefined = undefined;\n\n  for (let i = 0; i < seriesConfigs.length; i++) {\n    const s = seriesConfigs[i];\n    if (barWidth === undefined && s.barWidth !== undefined) barWidth = s.barWidth;\n    if (barGap === undefined && s.barGap !== undefined) barGap = s.barGap;\n    if (barCategoryGap === undefined && s.barCategoryGap !== undefined) barCategoryGap = s.barCategoryGap;\n  }\n\n  return { barWidth, barGap, barCategoryGap };\n};\n\nexport type BarLayoutPx = Readonly<{\n  categoryStep: number;\n  categoryWidthPx: number;\n  barWidthPx: number;\n  gapPx: number;\n  clusterWidthPx: number;\n  clusterSlots: BarClusterSlots;\n}>;\n\nexport function computeBarLayoutPx(\n  seriesConfigs: ReadonlyArray<ResolvedBarSeriesConfig>,\n  xScale: LinearScale,\n): BarLayoutPx {\n  const clusterSlots = computeBarClusterSlots(seriesConfigs);\n  const clusterCount = clusterSlots.clusterCount;\n\n  const categoryStep = computeBarCategoryStep(seriesConfigs);\n  const categoryWidthPx = computeCategoryWidthPx(seriesConfigs, xScale, categoryStep);\n\n  const layout = computeSharedBarLayout(seriesConfigs);\n  const barGap = clamp01(layout.barGap ?? DEFAULT_BAR_GAP);\n  const barCategoryGap = clamp01(layout.barCategoryGap ?? DEFAULT_BAR_CATEGORY_GAP);\n\n  const categoryInnerWidthPx = Math.max(0, categoryWidthPx * (1 - barCategoryGap));\n  const denom = clusterCount + Math.max(0, clusterCount - 1) * barGap;\n  const maxBarWidthPx = denom > 0 ? categoryInnerWidthPx / denom : 0;\n\n  let barWidthPx = 0;\n  const rawBarWidth = layout.barWidth;\n  if (typeof rawBarWidth === 'number') {\n    barWidthPx = Math.max(0, rawBarWidth);\n    barWidthPx = Math.min(barWidthPx, maxBarWidthPx);\n  } else if (typeof rawBarWidth === 'string') {\n    const p = parsePercent(rawBarWidth);\n    barWidthPx = p == null ? 0 : maxBarWidthPx * clamp01(p);\n  }\n\n  if (!(barWidthPx > 0)) {\n    // Auto-width: max per-bar width that still avoids overlap (given clusterCount and barGap).\n    barWidthPx = maxBarWidthPx;\n  }\n\n  const gapPx = barWidthPx * barGap;\n  const clusterWidthPx = clusterCount * barWidthPx + Math.max(0, clusterCount - 1) * gapPx;\n\n  return {\n    categoryStep,\n    categoryWidthPx,\n    barWidthPx,\n    gapPx,\n    clusterWidthPx,\n    clusterSlots,\n  };\n}\n\nconst computeBaselineForBarsFromData = (seriesConfigs: ReadonlyArray<ResolvedBarSeriesConfig>): number => {\n  let yMin = Number.POSITIVE_INFINITY;\n  let yMax = Number.NEGATIVE_INFINITY;\n\n  for (let s = 0; s < seriesConfigs.length; s++) {\n    const data = seriesConfigs[s].data as CartesianSeriesData;\n    const n = getPointCount(data);\n    for (let i = 0; i < n; i++) {\n      const y = getY(data, i);\n      if (!Number.isFinite(y)) continue;\n      if (y < yMin) yMin = y;\n      if (y > yMax) yMax = y;\n    }\n  }\n\n  if (!Number.isFinite(yMin) || !Number.isFinite(yMax)) return 0;\n  if (yMin <= 0 && 0 <= yMax) return 0;\n  return Math.abs(yMin) < Math.abs(yMax) ? yMin : yMax;\n};\n\nexport function inferPlotHeightPxForBarHitTesting(\n  seriesConfigs: ReadonlyArray<ResolvedBarSeriesConfig>,\n  yScale: LinearScale,\n): number {\n  // We don't have direct access to the scale range endpoints, so infer the plot height in range-space.\n  // In the common ChartGPU interaction setup, yScale.range(plotHeightCss, 0), so max(scaledY) should\n  // approximate plotHeightCss (or be <= plotHeightCss if axis min/max are overridden).\n  let maxY = 0;\n  for (let s = 0; s < seriesConfigs.length; s++) {\n    const data = seriesConfigs[s].data as CartesianSeriesData;\n    const n = getPointCount(data);\n    for (let i = 0; i < n; i++) {\n      const y = getY(data, i);\n      if (!Number.isFinite(y)) continue;\n      const py = yScale.scale(y);\n      if (Number.isFinite(py) && py > maxY) maxY = py;\n    }\n  }\n  return Math.max(0, maxY);\n}\n\nexport function computeBaselineDomainAndPx(\n  seriesConfigs: ReadonlyArray<ResolvedBarSeriesConfig>,\n  yScale: LinearScale,\n  plotHeightPx: number,\n): Readonly<{ baselineDomain: number; baselinePx: number }> {\n  // Axis-aware baseline logic (mirrors `createBarRenderer.ts`, but in px-space):\n  // Determine visible y-domain from yScale via invert(bottom/top) where top=0 and bottom=plotHeightPx.\n  const yDomainA = yScale.invert(plotHeightPx);\n  const yDomainB = yScale.invert(0);\n  const yMin = Math.min(yDomainA, yDomainB);\n  const yMax = Math.max(yDomainA, yDomainB);\n\n  let baselineDomain: number;\n  if (!Number.isFinite(yMin) || !Number.isFinite(yMax)) {\n    baselineDomain = computeBaselineForBarsFromData(seriesConfigs);\n  } else if (yMin <= 0 && 0 <= yMax) {\n    baselineDomain = 0;\n  } else if (yMin > 0) {\n    baselineDomain = yMin;\n  } else if (yMax < 0) {\n    baselineDomain = yMax;\n  } else {\n    baselineDomain = computeBaselineForBarsFromData(seriesConfigs);\n  }\n\n  let baselinePx = yScale.scale(baselineDomain);\n  if (!Number.isFinite(baselinePx)) {\n    baselineDomain = computeBaselineForBarsFromData(seriesConfigs);\n    baselinePx = yScale.scale(baselineDomain);\n  }\n  if (!Number.isFinite(baselinePx)) {\n    baselineDomain = 0;\n    baselinePx = yScale.scale(0);\n  }\n\n  return { baselineDomain, baselinePx };\n}\n\nexport function bucketStackedXKey(\n  xCenterPx: number,\n  categoryWidthPx: number,\n  xDomain: number,\n  categoryStep: number,\n): number {\n  // Match renderer intent:\n  // - Prefer bucketing in *range-space* to avoid float-equality issues in domain-x.\n  // - Requirement: Math.round(xCenterPx / categoryWidthPx) (grid-local).\n  if (Number.isFinite(categoryWidthPx) && categoryWidthPx > 0 && Number.isFinite(xCenterPx)) {\n    return Math.round(xCenterPx / categoryWidthPx);\n  }\n  if (Number.isFinite(categoryStep) && categoryStep > 0 && Number.isFinite(xDomain)) {\n    return Math.round(xDomain / categoryStep);\n  }\n  return Math.round(xDomain * 1e6);\n}\n\n/**\n * Finds the nearest data point to the given cursor position across all series.\n *\n * Coordinate system contract:\n * - `x`/`y` MUST be in the same units as `xScale`/`yScale` **range**.\n * - If you pass **grid-local CSS pixels** (e.g. `payload.gridX` / `payload.gridY` from `createEventManager`),\n *   then `xScale.range()` / `yScale.range()` must also be in **CSS pixels**.\n * - If your scales are in **clip space** (e.g. \\([-1, 1]\\)), pass cursor coordinates in clip space too.\n *\n * DPR/WebGPU note:\n * - Pointer events are naturally in CSS pixels; WebGPU rendering often uses device pixels or clip space.\n *   This helper stays agnostic and only computes Euclidean distance in the provided **range-space**.\n *\n * Performance notes:\n * - Assumes each series is sorted by increasing x in domain space.\n * - Uses per-series lower-bound binary search on x, then expands outward while x-distance alone can still win.\n * - Uses squared distance comparisons and computes `sqrt` only for the final match.\n * - Skips non-finite points and any points whose scaled coordinates are NaN.\n */\nexport function findNearestPoint(\n  series: ReadonlyArray<ResolvedSeriesConfig>,\n  x: number,\n  y: number,\n  xScale: LinearScale,\n  yScale: LinearScale,\n  maxDistance: number = DEFAULT_MAX_DISTANCE_PX,\n): NearestPointMatch | null {\n  if (!Number.isFinite(x) || !Number.isFinite(y)) return null;\n\n  const md = Number.isFinite(maxDistance)\n    ? Math.max(0, maxDistance)\n    : DEFAULT_MAX_DISTANCE_PX;\n  const maxDistSq = md * md;\n\n  const xTarget = xScale.invert(x);\n  if (!Number.isFinite(xTarget)) return null;\n\n  let bestSeriesIndex = -1;\n  let bestDataIndex = -1;\n  let bestPoint: DataPoint | null = null;\n  let bestDistSq = Number.POSITIVE_INFINITY;\n\n  // Story 4.6: Bar hit-testing (range-space bounds).\n  // - Only counts as a match when cursor is inside a bar rect.\n  // - For stacked bars, uses the same stacking bucket logic as the bar renderer (xKey bucketing).\n  // - If multiple segments match (shared edges), prefer visually topmost (smallest `top` in CSS px).\n  //   If still tied, prefer larger `seriesIndex` for determinism.\n  const barSeriesConfigs: ResolvedBarSeriesConfig[] = [];\n  const barSeriesIndexByBar: number[] = [];\n  for (let s = 0; s < series.length; s++) {\n    const cfg = series[s];\n    if (cfg?.type === 'bar' && cfg.visible !== false) {\n      barSeriesConfigs.push(cfg);\n      barSeriesIndexByBar.push(s);\n    }\n  }\n\n  if (barSeriesConfigs.length > 0) {\n    const layoutPx = computeBarLayoutPx(barSeriesConfigs, xScale);\n    if (layoutPx.barWidthPx > 0 && layoutPx.clusterWidthPx >= 0) {\n      const plotHeightPx = inferPlotHeightPxForBarHitTesting(barSeriesConfigs, yScale);\n      const { baselineDomain, baselinePx } = computeBaselineDomainAndPx(barSeriesConfigs, yScale, plotHeightPx);\n\n      const { clusterSlots, barWidthPx, gapPx, clusterWidthPx, categoryWidthPx, categoryStep } = layoutPx;\n      const stackSumsByStackId = new Map<string, Map<number, { posSum: number; negSum: number }>>();\n\n      let bestBarHit:\n        | {\n            readonly seriesIndex: number;\n            readonly dataIndex: number;\n            readonly top: number;\n          }\n        | null = null;\n\n      for (let b = 0; b < barSeriesConfigs.length; b++) {\n        const seriesCfg = barSeriesConfigs[b];\n        const originalSeriesIndex = barSeriesIndexByBar[b] ?? -1;\n        if (originalSeriesIndex < 0) continue;\n\n        const data = seriesCfg.data as CartesianSeriesData;\n        const n = getPointCount(data);\n        const clusterIndex = clusterSlots.clusterIndexBySeries[b] ?? 0;\n        const stackId = clusterSlots.stackIdBySeries[b] ?? '';\n\n        for (let i = 0; i < n; i++) {\n          const xDomain = getX(data, i);\n          const yDomain = getY(data, i);\n          if (!Number.isFinite(xDomain) || !Number.isFinite(yDomain)) continue;\n\n          const xCenterPx = xScale.scale(xDomain);\n          if (!Number.isFinite(xCenterPx)) continue;\n\n          const left = xCenterPx - clusterWidthPx / 2 + clusterIndex * (barWidthPx + gapPx);\n          const right = left + barWidthPx;\n\n          let baseDomain = baselineDomain;\n          let topDomain = yDomain;\n\n          if (stackId !== '') {\n            let sumsForX = stackSumsByStackId.get(stackId);\n            if (!sumsForX) {\n              sumsForX = new Map<number, { posSum: number; negSum: number }>();\n              stackSumsByStackId.set(stackId, sumsForX);\n            }\n\n            const xKey = bucketStackedXKey(xCenterPx, categoryWidthPx, xDomain, categoryStep);\n            let sums = sumsForX.get(xKey);\n            if (!sums) {\n              sums = { posSum: baselineDomain, negSum: baselineDomain };\n              sumsForX.set(xKey, sums);\n            }\n\n            if (yDomain >= 0) {\n              baseDomain = sums.posSum;\n              topDomain = baseDomain + yDomain;\n              sums.posSum = topDomain;\n            } else {\n              baseDomain = sums.negSum;\n              topDomain = baseDomain + yDomain;\n              sums.negSum = topDomain;\n            }\n          } else {\n            baseDomain = baselineDomain;\n            topDomain = yDomain;\n          }\n\n          const basePx = stackId !== '' ? yScale.scale(baseDomain) : baselinePx;\n          const topPx = yScale.scale(topDomain);\n          if (!Number.isFinite(basePx) || !Number.isFinite(topPx)) continue;\n\n          const bounds: BarBounds = {\n            left,\n            right,\n            top: Math.min(basePx, topPx),\n            bottom: Math.max(basePx, topPx),\n          };\n\n          if (!isPointInBar(x, y, bounds)) continue;\n\n          const isBetter =\n            bestBarHit === null ||\n            bounds.top < bestBarHit.top ||\n            (bounds.top === bestBarHit.top && originalSeriesIndex > bestBarHit.seriesIndex);\n\n          if (isBetter) {\n            bestBarHit = { seriesIndex: originalSeriesIndex, dataIndex: i, top: bounds.top };\n          }\n        }\n      }\n\n      if (bestBarHit) {\n        const seriesData = series[bestBarHit.seriesIndex]?.data as CartesianSeriesData | undefined;\n        if (seriesData) {\n          const x = getX(seriesData, bestBarHit.dataIndex);\n          const y = getY(seriesData, bestBarHit.dataIndex);\n          const size = getSize(seriesData, bestBarHit.dataIndex);\n          const point: DataPoint = size !== undefined ? [x, y, size] : [x, y];\n          return {\n            seriesIndex: bestBarHit.seriesIndex,\n            dataIndex: bestBarHit.dataIndex,\n            point,\n            distance: 0,\n          };\n        }\n      }\n    }\n  }\n\n  // Build index mapping for non-bar cartesian series (scatter, line, area) to preserve original series indices\n  // after filtering for visibility, matching the pattern used for bar series above.\n  const cartesianSeriesConfigs: ResolvedSeriesConfig[] = [];\n  const cartesianSeriesIndexMap: number[] = [];\n  for (let s = 0; s < series.length; s++) {\n    const seriesCfg = series[s];\n    // Pie and candlestick series are non-cartesian (or not yet implemented); they don't participate in x/y nearest-point hit-testing.\n    if (seriesCfg.type === 'pie' || seriesCfg.type === 'candlestick') continue;\n\n    // Skip invisible series (matches bar series visibility check above).\n    if (seriesCfg.visible === false) continue;\n\n    cartesianSeriesConfigs.push(seriesCfg);\n    cartesianSeriesIndexMap.push(s);\n  }\n\n  for (let s = 0; s < cartesianSeriesConfigs.length; s++) {\n    const seriesCfg = cartesianSeriesConfigs[s];\n    const originalSeriesIndex = cartesianSeriesIndexMap[s] ?? -1;\n    if (originalSeriesIndex < 0) continue;\n\n    const data = seriesCfg.data as CartesianSeriesData;\n    const n = getPointCount(data);\n    if (n === 0) continue;\n\n    const isScatter = seriesCfg.type === 'scatter';\n    const scatterCfg = isScatter ? (seriesCfg as ResolvedScatterSeriesConfig) : null;\n\n    // Check if data is monotonic for O(log n) fast path\n    const canBinarySearch = isMonotonicNonDecreasingFiniteX(data);\n\n    if (canBinarySearch) {\n      // Fast path: binary search + expand outward\n      // Find the index where data[i].x >= xTarget (lower bound)\n      const startIdx = lowerBoundX(data, xTarget);\n\n      // Expand outward from startIdx while points could still be closer\n      // Check right side first (startIdx onwards)\n      for (let i = startIdx; i < n; i++) {\n        const px = getX(data, i);\n        const py = getY(data, i);\n        if (!Number.isFinite(px) || !Number.isFinite(py)) continue;\n\n        const sx = xScale.scale(px);\n        const sy = yScale.scale(py);\n        if (!Number.isFinite(sx) || !Number.isFinite(sy)) continue;\n\n        const dx = sx - x;\n        const dy = sy - y;\n        const distSq = dx * dx + dy * dy;\n\n        // Early exit: if x-distance alone exceeds current best, no point can be closer (monotonic x)\n        const dxSq = dx * dx;\n        if (dxSq > bestDistSq) break;\n\n        // Check scatter radius if applicable\n        let allowedSq = maxDistSq;\n        if (scatterCfg) {\n          const size = getSize(data, i);\n          const p: DataPoint = size !== undefined ? [px, py, size] : [px, py];\n          const r = getScatterRadiusCssPx(scatterCfg, p);\n          const allowed = md + r;\n          allowedSq = allowed * allowed;\n        }\n\n        if (distSq > allowedSq) continue;\n\n        const isBetter =\n          distSq < bestDistSq ||\n          (distSq === bestDistSq &&\n            (bestPoint === null ||\n              originalSeriesIndex < bestSeriesIndex ||\n              (originalSeriesIndex === bestSeriesIndex && i < bestDataIndex)));\n\n        if (isBetter) {\n          bestDistSq = distSq;\n          bestSeriesIndex = originalSeriesIndex;\n          bestDataIndex = i;\n          const size = getSize(data, i);\n          bestPoint = size !== undefined ? [px, py, size] : [px, py];\n        }\n      }\n\n      // Check left side (before startIdx)\n      for (let i = startIdx - 1; i >= 0; i--) {\n        const px = getX(data, i);\n        const py = getY(data, i);\n        if (!Number.isFinite(px) || !Number.isFinite(py)) continue;\n\n        const sx = xScale.scale(px);\n        const sy = yScale.scale(py);\n        if (!Number.isFinite(sx) || !Number.isFinite(sy)) continue;\n\n        const dx = sx - x;\n        const dy = sy - y;\n        const distSq = dx * dx + dy * dy;\n\n        // Early exit: if x-distance alone exceeds current best, no point can be closer\n        const dxSq = dx * dx;\n        if (dxSq > bestDistSq) break;\n\n        // Check scatter radius if applicable\n        let allowedSq = maxDistSq;\n        if (scatterCfg) {\n          const size = getSize(data, i);\n          const p: DataPoint = size !== undefined ? [px, py, size] : [px, py];\n          const r = getScatterRadiusCssPx(scatterCfg, p);\n          const allowed = md + r;\n          allowedSq = allowed * allowed;\n        }\n\n        if (distSq > allowedSq) continue;\n\n        const isBetter =\n          distSq < bestDistSq ||\n          (distSq === bestDistSq &&\n            (bestPoint === null ||\n              originalSeriesIndex < bestSeriesIndex ||\n              (originalSeriesIndex === bestSeriesIndex && i < bestDataIndex)));\n\n        if (isBetter) {\n          bestDistSq = distSq;\n          bestSeriesIndex = originalSeriesIndex;\n          bestDataIndex = i;\n          const size = getSize(data, i);\n          bestPoint = size !== undefined ? [px, py, size] : [px, py];\n        }\n      }\n    } else {\n      // Fallback: linear scan for non-monotonic data\n      for (let i = 0; i < n; i++) {\n        const px = getX(data, i);\n        const py = getY(data, i);\n        if (!Number.isFinite(px) || !Number.isFinite(py)) continue;\n\n        const sx = xScale.scale(px);\n        const sy = yScale.scale(py);\n        if (!Number.isFinite(sx) || !Number.isFinite(sy)) continue;\n\n        const dx = sx - x;\n        const dy = sy - y;\n        const distSq = dx * dx + dy * dy;\n\n        // Check scatter radius if applicable\n        let allowedSq = maxDistSq;\n        if (scatterCfg) {\n          const size = getSize(data, i);\n          const p: DataPoint = size !== undefined ? [px, py, size] : [px, py];\n          const r = getScatterRadiusCssPx(scatterCfg, p);\n          const allowed = md + r;\n          allowedSq = allowed * allowed;\n        }\n\n        if (distSq > allowedSq) continue;\n\n        const isBetter =\n          distSq < bestDistSq ||\n          (distSq === bestDistSq &&\n            (bestPoint === null ||\n              originalSeriesIndex < bestSeriesIndex ||\n              (originalSeriesIndex === bestSeriesIndex && i < bestDataIndex)));\n\n        if (isBetter) {\n          bestDistSq = distSq;\n          bestSeriesIndex = originalSeriesIndex;\n          bestDataIndex = i;\n          const size = getSize(data, i);\n          bestPoint = size !== undefined ? [px, py, size] : [px, py];\n        }\n      }\n    }\n  }\n\n  if (bestPoint === null) return null;\n  if (!Number.isFinite(bestDistSq)) return null;\n\n  return {\n    seriesIndex: bestSeriesIndex,\n    dataIndex: bestDataIndex,\n    point: bestPoint,\n    distance: Math.sqrt(bestDistSq),\n  };\n}\n\n","/**\n * Overlay Rendering Utilities\n *\n * Prepares and renders GPU-based chart overlays (grid, axes, crosshair, highlight).\n * These overlays are rendered on top of the main chart series.\n *\n * @module renderOverlays\n */\n\nimport type { ResolvedChartGPUOptions } from '../../../config/OptionResolver';\nimport type { LinearScale } from '../../../utils/scales';\nimport type { GridRenderer } from '../../../renderers/createGridRenderer';\nimport type { AxisRenderer } from '../../../renderers/createAxisRenderer';\nimport type { CrosshairRenderer, CrosshairRenderOptions } from '../../../renderers/createCrosshairRenderer';\nimport type { HighlightRenderer, HighlightPoint } from '../../../renderers/createHighlightRenderer';\nimport type { GridArea } from '../../../renderers/createGridRenderer';\nimport { findNearestPoint } from '../../../interaction/findNearestPoint';\nimport { getPointXY } from '../utils/dataPointUtils';\nimport { computePlotScissorDevicePx } from '../utils/axisUtils';\n\nconst DEFAULT_TICK_COUNT = 5;\nconst DEFAULT_CROSSHAIR_LINE_WIDTH_CSS_PX = 1;\nconst DEFAULT_HIGHLIGHT_SIZE_CSS_PX = 4;\n\nexport interface OverlayRenderers {\n  gridRenderer: GridRenderer;\n  xAxisRenderer: AxisRenderer;\n  yAxisRenderer: AxisRenderer;\n  crosshairRenderer: CrosshairRenderer;\n  highlightRenderer: HighlightRenderer;\n}\n\nexport interface OverlayPrepareContext {\n  currentOptions: ResolvedChartGPUOptions;\n  xScale: LinearScale;\n  yScale: LinearScale;\n  gridArea: GridArea;\n  xTickCount: number;\n  hasCartesianSeries: boolean;\n  effectivePointer: {\n    hasPointer: boolean;\n    isInGrid: boolean;\n    source: 'mouse' | 'sync';\n    x: number;\n    y: number;\n    gridX: number;\n    gridY: number;\n  };\n  interactionScales: {\n    xScale: LinearScale;\n    yScale: LinearScale;\n  } | null;\n  seriesForRender: ReadonlyArray<any>;\n  withAlpha: (color: string, alpha: number) => string;\n}\n\nexport interface OverlayRenderContext {\n  mainPass: GPURenderPassEncoder;\n  topOverlayPass: GPURenderPassEncoder;\n  hasCartesianSeries: boolean;\n}\n\n/**\n * Prepares all overlay renderers with current frame data.\n *\n * This includes grid lines, axes, crosshair, and point highlights.\n *\n * @param renderers - Overlay renderer instances\n * @param context - Rendering context with scales, options, and pointer state\n */\nexport function prepareOverlays(renderers: OverlayRenderers, context: OverlayPrepareContext): void {\n  const {\n    currentOptions,\n    xScale,\n    yScale,\n    gridArea,\n    xTickCount,\n    hasCartesianSeries,\n    effectivePointer,\n    interactionScales,\n    seriesForRender,\n    withAlpha,\n  } = context;\n\n  // Grid preparation\n  renderers.gridRenderer.prepare(gridArea, { color: currentOptions.theme.gridLineColor });\n\n  // Axes preparation (cartesian only)\n  if (hasCartesianSeries) {\n    renderers.xAxisRenderer.prepare(\n      currentOptions.xAxis,\n      xScale,\n      'x',\n      gridArea,\n      currentOptions.theme.axisLineColor,\n      currentOptions.theme.axisTickColor,\n      xTickCount\n    );\n    renderers.yAxisRenderer.prepare(\n      currentOptions.yAxis,\n      yScale,\n      'y',\n      gridArea,\n      currentOptions.theme.axisLineColor,\n      currentOptions.theme.axisTickColor,\n      DEFAULT_TICK_COUNT\n    );\n  }\n\n  // Crosshair preparation (when pointer is in grid)\n  if (effectivePointer.hasPointer && effectivePointer.isInGrid) {\n    const crosshairOptions: CrosshairRenderOptions = {\n      showX: true,\n      // Sync has no meaningful y, so avoid horizontal line.\n      showY: effectivePointer.source !== 'sync',\n      color: withAlpha(currentOptions.theme.axisLineColor, 0.6),\n      lineWidth: DEFAULT_CROSSHAIR_LINE_WIDTH_CSS_PX,\n    };\n    renderers.crosshairRenderer.prepare(effectivePointer.x, effectivePointer.y, gridArea, crosshairOptions);\n    renderers.crosshairRenderer.setVisible(true);\n  } else {\n    renderers.crosshairRenderer.setVisible(false);\n  }\n\n  // Highlight preparation (on hover, find nearest point)\n  if (effectivePointer.source === 'mouse' && effectivePointer.hasPointer && effectivePointer.isInGrid) {\n    if (interactionScales) {\n      // findNearestPoint handles visibility filtering internally\n      const match = findNearestPoint(\n        seriesForRender,\n        effectivePointer.gridX,\n        effectivePointer.gridY,\n        interactionScales.xScale,\n        interactionScales.yScale\n      );\n\n      if (match) {\n        const { x, y } = getPointXY(match.point);\n        const xGridCss = interactionScales.xScale.scale(x);\n        const yGridCss = interactionScales.yScale.scale(y);\n\n        if (Number.isFinite(xGridCss) && Number.isFinite(yGridCss)) {\n          const centerCssX = gridArea.left + xGridCss;\n          const centerCssY = gridArea.top + yGridCss;\n\n          const plotScissor = computePlotScissorDevicePx(gridArea);\n          const point: HighlightPoint = {\n            centerDeviceX: centerCssX * gridArea.devicePixelRatio,\n            centerDeviceY: centerCssY * gridArea.devicePixelRatio,\n            devicePixelRatio: gridArea.devicePixelRatio,\n            canvasWidth: gridArea.canvasWidth,\n            canvasHeight: gridArea.canvasHeight,\n            scissor: plotScissor,\n          };\n\n          const seriesColor = currentOptions.series[match.seriesIndex]?.color ?? '#888';\n          renderers.highlightRenderer.prepare(point, seriesColor, DEFAULT_HIGHLIGHT_SIZE_CSS_PX);\n          renderers.highlightRenderer.setVisible(true);\n        } else {\n          renderers.highlightRenderer.setVisible(false);\n        }\n      } else {\n        renderers.highlightRenderer.setVisible(false);\n      }\n    } else {\n      renderers.highlightRenderer.setVisible(false);\n    }\n  } else {\n    renderers.highlightRenderer.setVisible(false);\n  }\n}\n\n/**\n * Renders all overlay elements to the appropriate render passes.\n *\n * Grid is rendered in the main pass (background).\n * Highlight, axes, and crosshair are rendered in the top overlay pass (foreground).\n *\n * @param renderers - Overlay renderer instances\n * @param context - Render pass context\n */\nexport function renderOverlays(renderers: OverlayRenderers, context: OverlayRenderContext): void {\n  const { mainPass, topOverlayPass, hasCartesianSeries } = context;\n\n  // Grid renders in main pass (background)\n  if (renderers.gridRenderer) {\n    renderers.gridRenderer.render(mainPass);\n  }\n\n  // Highlight, axes, crosshair render in top overlay pass (foreground)\n  renderers.highlightRenderer.render(topOverlayPass);\n  if (hasCartesianSeries) {\n    renderers.xAxisRenderer.render(topOverlayPass);\n    renderers.yAxisRenderer.render(topOverlayPass);\n  }\n  renderers.crosshairRenderer.render(topOverlayPass);\n}\n","/**\n * Annotation processing for the RenderCoordinator.\n *\n * Processes annotation configurations into GPU-renderable instances (reference lines,\n * markers) and DOM label data. Supports layering (above/below series) and multiple\n * annotation types (lineX, lineY, point, text).\n *\n * @module processAnnotations\n */\n\nimport type { AnnotationConfig } from '../../../config/types';\nimport type { LinearScale } from '../../../utils/scales';\nimport type { ThemeConfig } from '../../../themes/types';\nimport type { ReferenceLineInstance } from '../../../renderers/createReferenceLineRenderer';\nimport type { AnnotationMarkerInstance } from '../../../renderers/createAnnotationMarkerRenderer';\nimport type { TextOverlayAnchor } from '../../../components/createTextOverlay';\nimport { parseCssColorToRgba01 } from '../../../utils/colors';\nimport { clipXToCanvasCssPx, clipYToCanvasCssPx, clamp01 } from '../utils/axisUtils';\nimport { assertUnreachable } from '../utils/dataPointUtils';\n\n/**\n * Internal type for annotation label data (DOM overlay).\n */\nexport interface AnnotationLabelData {\n  readonly text: string;\n  readonly x: number;\n  readonly y: number;\n  readonly anchor?: 'start' | 'middle' | 'end';\n  readonly color?: string;\n  readonly fontSize?: number;\n  readonly background?: Readonly<{\n    readonly backgroundColor: string;\n    readonly padding?: readonly [number, number, number, number];\n    readonly borderRadius?: number;\n  }>;\n}\n\n/**\n * Plot bounds in CSS pixels.\n */\nexport interface PlotBounds {\n  readonly leftCss: number;\n  readonly rightCss: number;\n  readonly topCss: number;\n  readonly bottomCss: number;\n  readonly widthCss: number;\n  readonly heightCss: number;\n}\n\n/**\n * Context for annotation processing.\n */\nexport interface AnnotationContext {\n  readonly annotations: ReadonlyArray<AnnotationConfig>;\n  readonly xScale: LinearScale;\n  readonly yScale: LinearScale;\n  readonly plotBounds: PlotBounds;\n  readonly canvasCssWidth: number;\n  readonly canvasCssHeight: number;\n  readonly theme: ThemeConfig;\n  readonly offsetX?: number;\n  readonly offsetY?: number;\n}\n\n/**\n * Result of annotation processing.\n */\nexport interface AnnotationResult {\n  readonly linesBelow: ReferenceLineInstance[];\n  readonly linesAbove: ReferenceLineInstance[];\n  readonly markersBelow: AnnotationMarkerInstance[];\n  readonly markersAbove: AnnotationMarkerInstance[];\n  readonly labels: AnnotationLabelData[];\n}\n\n/**\n * Resolves annotation RGBA color with opacity.\n *\n * @param color - CSS color string or undefined\n * @param opacity - Opacity value [0, 1] or undefined\n * @param defaultColor - Default color (typically theme text color)\n * @returns RGBA tuple [r, g, b, a] in range [0, 1]\n */\nfunction resolveAnnotationRgba(\n  color: string | undefined,\n  opacity: number | undefined,\n  defaultColor: string\n): readonly [number, number, number, number] {\n  const base =\n    parseCssColorToRgba01(color ?? defaultColor) ??\n    parseCssColorToRgba01(defaultColor) ??\n    ([1, 1, 1, 1] as const);\n  const o = opacity == null ? 1 : clamp01(opacity);\n  return [clamp01(base[0]), clamp01(base[1]), clamp01(base[2]), clamp01(base[3] * o)] as const;\n}\n\n/**\n * Converts color and opacity to CSS rgba() string.\n *\n * @param color - CSS color string\n * @param opacity01 - Opacity in range [0, 1]\n * @returns CSS rgba() string\n */\nfunction toCssRgba(color: string, opacity01: number): string {\n  const base = parseCssColorToRgba01(color) ?? ([0, 0, 0, 1] as const);\n  const a = clamp01(base[3] * clamp01(opacity01));\n  const r = Math.round(clamp01(base[0]) * 255);\n  const g = Math.round(clamp01(base[1]) * 255);\n  const b = Math.round(clamp01(base[2]) * 255);\n  return `rgba(${r}, ${g}, ${b}, ${a})`;\n}\n\n/**\n * Formats number with optional decimal precision.\n *\n * @param n - Number to format\n * @param decimals - Number of decimal places (optional)\n * @returns Formatted string\n */\nfunction formatNumber(n: number, decimals?: number): string {\n  if (!Number.isFinite(n)) return '';\n  if (decimals == null) return String(n);\n  const d = Math.min(20, Math.max(0, Math.floor(decimals)));\n  return n.toFixed(d);\n}\n\n/**\n * Renders template string with value substitution.\n * Supports {x}, {y}, {value}, and {name} placeholders.\n *\n * @param template - Template string with placeholders\n * @param values - Values for substitution\n * @param decimals - Decimal precision for numbers\n * @returns Rendered string\n */\nfunction renderTemplate(\n  template: string,\n  values: Readonly<{ x?: number; y?: number; value?: number; name?: string }>,\n  decimals?: number\n): string {\n  // PERFORMANCE: Create regex per call (cached by engine in hot path)\n  const templateRegex = /\\{(x|y|value|name)\\}/g;\n  return template.replace(templateRegex, (_m, key) => {\n    if (key === 'name') return values.name ?? '';\n    const v = (values as any)[key] as number | undefined;\n    return v == null ? '' : formatNumber(v, decimals);\n  });\n}\n\n/**\n * Maps annotation anchor to text overlay anchor.\n *\n * @param anchor - Annotation anchor or undefined\n * @returns Text overlay anchor\n */\nfunction mapAnchor(anchor: 'start' | 'center' | 'end' | undefined): TextOverlayAnchor {\n  switch (anchor) {\n    case 'center':\n      return 'middle';\n    case 'end':\n      return 'end';\n    case 'start':\n    default:\n      return 'start';\n  }\n}\n\n/**\n * Processes annotations into GPU-renderable instances and DOM labels.\n *\n * **Annotation Types:**\n * - `lineX`: Vertical reference line at x coordinate\n * - `lineY`: Horizontal reference line at y coordinate\n * - `point`: Marker at (x, y) coordinate\n * - `text`: Text annotation with flexible positioning\n *\n * **Layering:**\n * - `belowSeries`: Rendered before series (occluded by data)\n * - `aboveSeries`: Rendered after series (always visible, default)\n *\n * **Labels:**\n * - Optional text labels for all annotation types\n * - Template support with {x}, {y}, {value}, {name} placeholders\n * - Background styling with padding and border radius\n *\n * @param context - Annotation processing context\n * @returns Annotation result with lines, markers, and labels\n */\nexport function processAnnotations(context: AnnotationContext): AnnotationResult {\n  const {\n    annotations,\n    xScale,\n    yScale,\n    plotBounds,\n    canvasCssWidth,\n    canvasCssHeight,\n    theme,\n    offsetX = 0,\n    offsetY = 0,\n  } = context;\n\n  const { leftCss: plotLeftCss, topCss: plotTopCss, widthCss: plotWidthCss, heightCss: plotHeightCss } = plotBounds;\n\n  // Output arrays (reused across calls for performance)\n  const linesBelow: ReferenceLineInstance[] = [];\n  const linesAbove: ReferenceLineInstance[] = [];\n  const markersBelow: AnnotationMarkerInstance[] = [];\n  const markersAbove: AnnotationMarkerInstance[] = [];\n  const labels: AnnotationLabelData[] = [];\n\n  // PERFORMANCE: Early exit if no annotations or invalid canvas dimensions\n  if (annotations.length === 0 || canvasCssWidth <= 0 || canvasCssHeight <= 0 || plotWidthCss <= 0 || plotHeightCss <= 0) {\n    return { linesBelow, linesAbove, markersBelow, markersAbove, labels };\n  }\n\n  // Process each annotation\n  for (let i = 0; i < annotations.length; i++) {\n    const a = annotations[i]!;\n    const layer = a.layer ?? 'aboveSeries';\n    const targetLines = layer === 'belowSeries' ? linesBelow : linesAbove;\n    const targetMarkers = layer === 'belowSeries' ? markersBelow : markersAbove;\n\n    // Resolve annotation styling\n    const styleColor = a.style?.color;\n    const styleOpacity = a.style?.opacity;\n    const lineWidth = typeof a.style?.lineWidth === 'number' && Number.isFinite(a.style.lineWidth) ? Math.max(0, a.style.lineWidth) : 1;\n    const lineDash = a.style?.lineDash;\n    const rgba = resolveAnnotationRgba(styleColor, styleOpacity, theme.textColor);\n\n    // Process annotation by type (GPU rendering)\n    switch (a.type) {\n      case 'lineX': {\n        const xClip = xScale.scale(a.x);\n        const xCss = clipXToCanvasCssPx(xClip, canvasCssWidth);\n        if (!Number.isFinite(xCss)) break;\n        targetLines.push({\n          axis: 'vertical',\n          positionCssPx: xCss,\n          lineWidth,\n          lineDash,\n          rgba,\n        });\n        break;\n      }\n      case 'lineY': {\n        const yClip = yScale.scale(a.y);\n        const yCss = clipYToCanvasCssPx(yClip, canvasCssHeight);\n        if (!Number.isFinite(yCss)) break;\n        targetLines.push({\n          axis: 'horizontal',\n          positionCssPx: yCss,\n          lineWidth,\n          lineDash,\n          rgba,\n        });\n        break;\n      }\n      case 'point': {\n        const xClip = xScale.scale(a.x);\n        const yClip = yScale.scale(a.y);\n        const xCss = clipXToCanvasCssPx(xClip, canvasCssWidth);\n        const yCss = clipYToCanvasCssPx(yClip, canvasCssHeight);\n        if (!Number.isFinite(xCss) || !Number.isFinite(yCss)) break;\n\n        const markerSize =\n          typeof a.marker?.size === 'number' && Number.isFinite(a.marker.size) ? Math.max(1, a.marker.size) : 6;\n        const markerColor = a.marker?.style?.color ?? a.style?.color;\n        const markerOpacity = a.marker?.style?.opacity ?? a.style?.opacity;\n        const fillRgba = resolveAnnotationRgba(markerColor, markerOpacity, theme.textColor);\n\n        targetMarkers.push({\n          xCssPx: xCss,\n          yCssPx: yCss,\n          sizeCssPx: markerSize,\n          fillRgba,\n        });\n        break;\n      }\n      case 'text': {\n        // Text annotations are handled via DOM overlays (labels), not GPU\n        break;\n      }\n      default:\n        assertUnreachable(a);\n    }\n\n    // Process annotation label (DOM overlay)\n    const labelCfg = a.label;\n    const wantsLabel = labelCfg != null || a.type === 'text';\n    if (!wantsLabel) continue;\n\n    // Compute anchor point (canvas-local CSS px)\n    let anchorXCss: number | null = null;\n    let anchorYCss: number | null = null;\n    let values: { x?: number; y?: number; value?: number; name?: string } = { name: a.id ?? '' };\n\n    switch (a.type) {\n      case 'lineX': {\n        const xClip = xScale.scale(a.x);\n        const xCss = clipXToCanvasCssPx(xClip, canvasCssWidth);\n        anchorXCss = xCss;\n        anchorYCss = plotTopCss;\n        values = { ...values, x: a.x, value: a.x };\n        break;\n      }\n      case 'lineY': {\n        const yClip = yScale.scale(a.y);\n        const yCss = clipYToCanvasCssPx(yClip, canvasCssHeight);\n        anchorXCss = plotLeftCss;\n        // Offset label 8px above the horizontal line (negative Y = upward)\n        anchorYCss = yCss - 8;\n        values = { ...values, y: a.y, value: a.y };\n        break;\n      }\n      case 'point': {\n        const xClip = xScale.scale(a.x);\n        const yClip = yScale.scale(a.y);\n        const xCss = clipXToCanvasCssPx(xClip, canvasCssWidth);\n        const yCss = clipYToCanvasCssPx(yClip, canvasCssHeight);\n        anchorXCss = xCss;\n        anchorYCss = yCss;\n        values = { ...values, x: a.x, y: a.y, value: a.y };\n        break;\n      }\n      case 'text': {\n        if (a.position.space === 'data') {\n          const xClip = xScale.scale(a.position.x);\n          const yClip = yScale.scale(a.position.y);\n          const xCss = clipXToCanvasCssPx(xClip, canvasCssWidth);\n          const yCss = clipYToCanvasCssPx(yClip, canvasCssHeight);\n          anchorXCss = xCss;\n          anchorYCss = yCss;\n          values = { ...values, x: a.position.x, y: a.position.y, value: a.position.y };\n        } else {\n          const xCss = plotLeftCss + a.position.x * plotWidthCss;\n          const yCss = plotTopCss + a.position.y * plotHeightCss;\n          anchorXCss = xCss;\n          anchorYCss = yCss;\n          values = { ...values, x: a.position.x, y: a.position.y, value: a.position.y };\n        }\n        break;\n      }\n      default:\n        assertUnreachable(a);\n    }\n\n    if (anchorXCss == null || anchorYCss == null || !Number.isFinite(anchorXCss) || !Number.isFinite(anchorYCss)) {\n      continue;\n    }\n\n    // Apply label offset\n    const dx = labelCfg?.offset?.[0] ?? 0;\n    const dy = labelCfg?.offset?.[1] ?? 0;\n    const x = anchorXCss + dx;\n    const y = anchorYCss + dy;\n\n    // Label text selection (explicit > template > defaults)\n    const text =\n      labelCfg?.text ??\n      (labelCfg?.template\n        ? renderTemplate(labelCfg.template, values, labelCfg.decimals)\n        : labelCfg\n          ? (() => {\n              const defaultTemplate =\n                a.type === 'lineX'\n                  ? 'x={x}'\n                  : a.type === 'lineY'\n                    ? 'y={y}'\n                    : a.type === 'point'\n                      ? '({x}, {y})'\n                      : a.type === 'text'\n                        ? a.text\n                        : '';\n              return defaultTemplate.includes('{')\n                ? renderTemplate(defaultTemplate, values, labelCfg.decimals)\n                : defaultTemplate;\n            })()\n          : a.type === 'text'\n            ? a.text\n            : '');\n\n    const trimmed = typeof text === 'string' ? text.trim() : '';\n    if (trimmed.length === 0) continue;\n\n    // Label styling\n    const anchor = mapAnchor(labelCfg?.anchor);\n    const color = a.style?.color ?? theme.textColor;\n    const fontSize = theme.fontSize;\n\n    // Background styling\n    const bg = labelCfg?.background;\n    const bgColor = bg?.color != null ? toCssRgba(bg.color, bg.opacity ?? 1) : undefined;\n    const padding = (() => {\n      const p = bg?.padding;\n      if (typeof p === 'number' && Number.isFinite(p)) return [p, p, p, p] as const;\n      if (Array.isArray(p) && p.length === 4 && p.every((n) => typeof n === 'number' && Number.isFinite(n))) {\n        return [p[0], p[1], p[2], p[3]] as const;\n      }\n      return bg ? ([2, 4, 2, 4] as const) : undefined;\n    })();\n    const borderRadius =\n      typeof bg?.borderRadius === 'number' && Number.isFinite(bg.borderRadius) ? bg.borderRadius : undefined;\n\n    // Create label data\n    const labelData: AnnotationLabelData = {\n      text: trimmed,\n      x: offsetX + x,\n      y: offsetY + y,\n      anchor,\n      color,\n      fontSize,\n      ...(bgColor\n        ? {\n            background: {\n              backgroundColor: bgColor,\n              ...(padding ? { padding } : {}),\n              ...(borderRadius != null ? { borderRadius } : {}),\n            },\n          }\n        : {}),\n    };\n\n    labels.push(labelData);\n  }\n\n  return {\n    linesBelow,\n    linesAbove,\n    markersBelow,\n    markersAbove,\n    labels,\n  };\n}\n","/**\n * Animation helper utilities for intro and update animations.\n *\n * Provides pure functions for animation config resolution, easing transformations,\n * series interpolation, and animation state management. These utilities support\n * both intro animations (initial reveal) and update animations (smooth transitions).\n *\n * @module animationHelpers\n */\n\nimport type { AnimationConfig, DataPoint } from '../../../config/types';\nimport type { ResolvedPieSeriesConfig } from '../../../config/OptionResolver';\nimport type { EasingFunction } from '../../../utils/easing';\nimport { getPointXY, isTupleDataPoint } from '../utils/dataPointUtils';\n\n/**\n * Intro animation phase state machine.\n */\nexport type IntroPhase = 'pending' | 'running' | 'done';\n\n/**\n * Domain boundaries with min and max values.\n */\nexport interface DomainBounds {\n  readonly min: number;\n  readonly max: number;\n}\n\n/**\n * Resolved animation configuration with timing and easing.\n */\nexport interface ResolvedAnimationConfig {\n  readonly delayMs: number;\n  readonly durationMs: number;\n  readonly easing: EasingFunction;\n}\n\n/**\n * Series configuration type that supports all series types.\n */\nexport type AnySeriesConfig =\n  | { readonly type: 'line'; readonly data: ReadonlyArray<DataPoint> }\n  | { readonly type: 'area'; readonly data: ReadonlyArray<DataPoint> }\n  | { readonly type: 'bar'; readonly data: ReadonlyArray<DataPoint> }\n  | { readonly type: 'scatter'; readonly data: ReadonlyArray<DataPoint> }\n  | { readonly type: 'candlestick'; readonly data: ReadonlyArray<any> }\n  | ResolvedPieSeriesConfig;\n\n/**\n * Clamps a value between 0 and 1.\n *\n * @param value - Value to clamp\n * @returns Clamped value in [0, 1]\n */\nexport function clamp01(value: number): number {\n  return Math.max(0, Math.min(1, value));\n}\n\n/**\n * Resolves animation configuration from options.\n *\n * Returns null if animation is disabled (false or null).\n * Returns default config if animation is true or an empty object.\n * Converts duration/delay from user config to milliseconds.\n *\n * @param animation - Animation options from chart config\n * @param getEasingFn - Function to resolve easing by name (to avoid circular deps)\n * @returns Resolved animation config or null if disabled\n */\nexport function resolveAnimationConfig(\n  animation: boolean | AnimationConfig | null | undefined,\n  getEasingFn: (name: string) => EasingFunction\n): ResolvedAnimationConfig | null {\n  if (animation === false || animation == null) return null;\n\n  const cfg: AnimationConfig | null = animation === true ? {} : animation;\n  if (!cfg) return null;\n\n  // Extract duration and delay with defaults\n  const durationMsRaw = cfg.duration ?? 300;\n  const delayMsRaw = cfg.delay ?? 0;\n\n  const durationMs = Number.isFinite(durationMsRaw) ? Math.max(0, durationMsRaw) : 300;\n  const delayMs = Number.isFinite(delayMsRaw) ? Math.max(0, delayMsRaw) : 0;\n\n  // Resolve easing (string name or function)\n  const easingConfig = cfg.easing ?? 'cubicOut';\n  const easing =\n    typeof easingConfig === 'string' ? getEasingFn(easingConfig) : easingConfig;\n\n  return {\n    durationMs,\n    delayMs,\n    easing,\n  };\n}\n\n/**\n * Creates an easing function that incorporates delay.\n *\n * The returned function maps t ∈ [0, 1] to an output considering both delay\n * and duration:\n * - t in [0, delay]: output = 0 (delay phase)\n * - t in [delay, delay+duration]: output = easing((t-delay)/duration)\n * - t > delay+duration: output = 1 (complete)\n *\n * @param delayMs - Delay before animation starts (milliseconds)\n * @param durationMs - Animation duration after delay (milliseconds)\n * @param easing - Base easing function to apply after delay\n * @returns Easing function with delay incorporated\n */\nexport function createEasingWithDelay(\n  delayMs: number,\n  durationMs: number,\n  easing: EasingFunction\n): EasingFunction {\n  return (t01: number): number => {\n    const t = clamp01(t01);\n    const totalMs = delayMs + durationMs;\n\n    if (!(totalMs > 0)) return 1;\n\n    const elapsedMs = t * totalMs;\n    if (elapsedMs < delayMs) return 0;\n\n    if (!(durationMs > 0)) return 1;\n    const innerT = (elapsedMs - delayMs) / durationMs;\n    return easing(innerT);\n  };\n}\n\n/**\n * Checks if a series configuration has drawable marks.\n *\n * Returns true if the series has data that will produce visible marks:\n * - Pie: at least one slice with value > 0\n * - Cartesian (line/area/bar/scatter/candlestick): at least one data point\n *\n * @param series - Series configuration to check\n * @returns True if series has drawable content\n */\nexport function hasDrawableMarks(series: AnySeriesConfig): boolean {\n  switch (series.type) {\n    case 'pie': {\n      return series.data.some(\n        (it: any) => typeof it?.value === 'number' && Number.isFinite(it.value) && it.value > 0\n      );\n    }\n    case 'line':\n    case 'area':\n    case 'bar':\n    case 'scatter':\n    case 'candlestick': {\n      return series.data.length > 0;\n    }\n    default: {\n      return false;\n    }\n  }\n}\n\n/**\n * Checks if any series in the list has drawable marks.\n *\n * @param seriesList - Array of series configurations\n * @returns True if at least one series has drawable marks\n */\nexport function hasAnyDrawableMarks(seriesList: ReadonlyArray<AnySeriesConfig>): boolean {\n  for (let i = 0; i < seriesList.length; i++) {\n    if (hasDrawableMarks(seriesList[i]!)) {\n      return true;\n    }\n  }\n  return false;\n}\n\n/**\n * Linearly interpolates between two domain bounds.\n *\n * @param from - Starting domain\n * @param to - Ending domain\n * @param t - Interpolation progress [0, 1]\n * @returns Interpolated domain\n */\nexport function lerpDomain(from: DomainBounds, to: DomainBounds, t: number): DomainBounds {\n  const t01 = clamp01(t);\n  return {\n    min: from.min + (to.min - from.min) * t01,\n    max: from.max + (to.max - from.max) * t01,\n  };\n}\n\n/**\n * Linearly interpolates between two numbers.\n *\n * @param from - Starting value\n * @param to - Ending value\n * @param t - Interpolation progress [0, 1]\n * @returns Interpolated value\n */\nexport function lerp(from: number, to: number, t: number): number {\n  return from + (to - from) * clamp01(t);\n}\n\n/**\n * Interpolates cartesian series data between from and to states.\n *\n * Returns null if array lengths don't match (can't interpolate mismatched arrays).\n * Reuses cache array if provided and same length.\n *\n * @param fromData - Starting data points\n * @param toData - Ending data points\n * @param t - Interpolation progress [0, 1]\n * @param cache - Optional cache array to reuse\n * @returns Interpolated data points or null if lengths mismatch\n */\nexport function interpolateCartesianData(\n  fromData: ReadonlyArray<DataPoint>,\n  toData: ReadonlyArray<DataPoint>,\n  t: number,\n  cache: DataPoint[] | null\n): DataPoint[] | null {\n  if (fromData.length !== toData.length) return null;\n\n  const n = toData.length;\n  if (n === 0) return cache ?? [];\n\n  const out = cache && cache.length === n ? cache : new Array<DataPoint>(n);\n  const t01 = clamp01(t);\n\n  // Determine format from first element\n  const isTuple = isTupleDataPoint(toData[0]!);\n\n  for (let i = 0; i < n; i++) {\n    const fromPt = fromData[i]!;\n    const toPt = toData[i]!;\n\n    const fromXY = getPointXY(fromPt);\n    const toXY = getPointXY(toPt);\n\n    const x = lerp(fromXY.x, toXY.x, t01);\n    const y = lerp(fromXY.y, toXY.y, t01);\n\n    if (isTuple) {\n      out[i] = [x, y] as DataPoint;\n    } else {\n      out[i] = { x, y } as DataPoint;\n    }\n  }\n\n  return out;\n}\n\n/**\n * Interpolates pie series data between from and to states.\n *\n * Returns the toSeries unchanged if data array lengths don't match.\n * Only interpolates the value property; angles are recomputed by the renderer.\n *\n * @param fromSeries - Starting pie series\n * @param toSeries - Ending pie series\n * @param t - Interpolation progress [0, 1]\n * @param cache - Optional cache array to reuse\n * @returns Interpolated pie series\n */\nexport function interpolatePieData(\n  fromSeries: ResolvedPieSeriesConfig,\n  toSeries: ResolvedPieSeriesConfig,\n  t: number,\n  cache: ResolvedPieSeriesConfig['data'] | null\n): ResolvedPieSeriesConfig {\n  const fromData = fromSeries.data;\n  const toData = toSeries.data;\n\n  if (fromData.length !== toData.length) return toSeries;\n\n  const n = toData.length;\n  if (n === 0) return toSeries;\n\n  // Create or reuse cache array\n  const out =\n    cache && cache.length === n\n      ? cache\n      : (() => {\n          const created: any[] = new Array(n);\n          for (let i = 0; i < n; i++) {\n            // Preserve name/color from \"to\"; patch value per frame\n            created[i] = { ...toData[i]!, value: 0 };\n          }\n          return created as ResolvedPieSeriesConfig['data'];\n        })();\n\n  const t01 = clamp01(t);\n\n  for (let i = 0; i < n; i++) {\n    const vFrom = (fromData[i] as any)?.value;\n    const vTo = (toData[i] as any)?.value;\n\n    // Interpolate value if both are valid numbers\n    const nextValue =\n      typeof vFrom === 'number' && typeof vTo === 'number' && Number.isFinite(vFrom) && Number.isFinite(vTo)\n        ? Math.max(0, lerp(vFrom, vTo, t01))\n        : typeof vTo === 'number' && Number.isFinite(vTo)\n          ? vTo\n          : 0;\n\n    (out[i] as any).value = nextValue;\n  }\n\n  return { ...toSeries, data: out };\n}\n\n/**\n * Checks if two domain bounds are equal.\n *\n * @param a - First domain\n * @param b - Second domain\n * @returns True if domains have identical min and max\n */\nexport function isDomainEqual(a: DomainBounds, b: DomainBounds): boolean {\n  return a.min === b.min && a.max === b.max;\n}\n\n/**\n * Determines the next intro phase based on current state and conditions.\n *\n * State machine transitions:\n * - pending → running: when has drawable marks and animation enabled\n * - running → done: when animation completes\n * - done → pending: when retriggering (e.g., visibility change)\n *\n * @param currentPhase - Current intro phase\n * @param hasDrawable - Whether series have drawable marks\n * @param animationEnabled - Whether animation is enabled\n * @param retrigger - Whether to retrigger from done state\n * @returns Next intro phase\n */\nexport function computeNextIntroPhase(\n  currentPhase: IntroPhase,\n  hasDrawable: boolean,\n  animationEnabled: boolean,\n  retrigger: boolean = false\n): IntroPhase {\n  if (retrigger && currentPhase === 'done') {\n    return 'pending';\n  }\n\n  if (currentPhase === 'pending' && hasDrawable && animationEnabled) {\n    return 'running';\n  }\n\n  return currentPhase;\n}\n\n/**\n * Applies intro animation progress to create an animated bar Y scale.\n *\n * During intro, bars grow from the zero line (or domain min if no zero).\n * This creates a scale that compresses bars based on progress.\n *\n * @param baseYScale - Original Y scale\n * @param yMin - Domain minimum\n * @param yMax - Domain maximum\n * @param progress - Animation progress [0, 1]\n * @returns Y coordinate adjusted for intro animation\n */\nexport function applyBarIntroProgress(\n  baseY: number,\n  yMin: number,\n  yMax: number,\n  progress: number\n): number {\n  const p = clamp01(progress);\n\n  // Find zero line or use domain min as anchor\n  const zeroLine = yMin <= 0 && yMax >= 0 ? 0 : yMin;\n\n  // Interpolate from zero line to actual value\n  return lerp(zeroLine, baseY, p);\n}\n","/**\n * Series Rendering Utilities\n *\n * Prepares and renders all chart series types (area, line, bar, scatter, candlestick, pie).\n * Handles intro animations, GPU buffer management, and multi-pass rendering with proper layering.\n *\n * @module renderSeries\n */\n\nimport type { ResolvedChartGPUOptions, ResolvedSeriesConfig, ResolvedBarSeriesConfig, ResolvedAreaSeriesConfig, ResolvedPieSeriesConfig } from '../../../config/OptionResolver';\nimport type { DataPoint } from '../../../config/types';\nimport type { LinearScale } from '../../../utils/scales';\nimport type { GridArea } from '../../../renderers/createGridRenderer';\nimport type { LineRenderer } from '../../../renderers/createLineRenderer';\nimport type { AreaRenderer } from '../../../renderers/createAreaRenderer';\nimport type { BarRenderer } from '../../../renderers/createBarRenderer';\nimport type { ScatterRenderer } from '../../../renderers/createScatterRenderer';\nimport type { ScatterDensityRenderer } from '../../../renderers/createScatterDensityRenderer';\nimport type { PieRenderer } from '../../../renderers/createPieRenderer';\nimport type { CandlestickRenderer } from '../../../renderers/createCandlestickRenderer';\nimport type { ReferenceLineRenderer } from '../../../renderers/createReferenceLineRenderer';\nimport type { AnnotationMarkerRenderer } from '../../../renderers/createAnnotationMarkerRenderer';\nimport type { DataStore } from '../../../data/createDataStore';\nimport { isTupleDataPoint } from '../utils/dataPointUtils';\nimport { clampInt } from '../utils/canvasUtils';\nimport { clamp01 } from '../animation/animationHelpers';\nimport { findVisibleRangeIndicesByX } from '../data/computeVisibleSlice';\nimport { resolvePieRadiiCss } from '../utils/timeAxisUtils';\n\nexport interface SeriesRenderers {\n  lineRenderers: LineRenderer[];\n  areaRenderers: AreaRenderer[];\n  barRenderer: BarRenderer;\n  scatterRenderers: ScatterRenderer[];\n  scatterDensityRenderers: ScatterDensityRenderer[];\n  pieRenderers: PieRenderer[];\n  candlestickRenderers: CandlestickRenderer[];\n}\n\nexport interface AnnotationRenderers {\n  referenceLineRenderer: ReferenceLineRenderer;\n  referenceLineRendererMsaa: ReferenceLineRenderer;\n  annotationMarkerRenderer: AnnotationMarkerRenderer;\n  annotationMarkerRendererMsaa: AnnotationMarkerRenderer;\n}\n\nexport interface SeriesPrepareContext {\n  currentOptions: ResolvedChartGPUOptions;\n  seriesForRender: ReadonlyArray<ResolvedSeriesConfig>;\n  xScale: LinearScale;\n  yScale: LinearScale;\n  gridArea: GridArea;\n  dataStore: DataStore;\n  appendedGpuThisFrame: Set<number>;\n  gpuSeriesKindByIndex: Array<'fullRawLine' | 'other' | 'unknown'>;\n  zoomState: { getRange(): { start: number; end: number } | null } | null;\n  visibleXDomain: { min: number; max: number };\n  introPhase: 'pending' | 'running' | 'done';\n  introProgress01: number;\n  withAlpha: (color: string, alpha: number) => string;\n  maxRadiusCss: number;\n}\n\nexport interface SeriesRenderContext {\n  hasCartesianSeries: boolean;\n  gridArea: GridArea;\n  mainPass: GPURenderPassEncoder;\n  plotScissor: { x: number; y: number; w: number; h: number };\n  introPhase: 'pending' | 'running' | 'done';\n  introProgress01: number;\n  referenceLineBelowCount: number;\n  markerBelowCount: number;\n}\n\nexport interface AboveSeriesAnnotationContext {\n  hasCartesianSeries: boolean;\n  gridArea: GridArea;\n  overlayPass: GPURenderPassEncoder;\n  plotScissor: { x: number; y: number; w: number; h: number };\n  referenceLineBelowCount: number;\n  referenceLineAboveCount: number;\n  markerBelowCount: number;\n  markerAboveCount: number;\n}\n\nexport interface SeriesPreparationResult {\n  visibleSeriesForRender: ReadonlyArray<{ series: ResolvedSeriesConfig; originalIndex: number }>;\n  barSeriesConfigs: ResolvedBarSeriesConfig[];\n  visibleBarSeriesConfigs: ResolvedBarSeriesConfig[];\n}\n\n/**\n * Helper: determines if an area should be rendered for a series.\n * Line series with areaStyle should render as area.\n */\nfunction shouldRenderArea(series: ResolvedSeriesConfig): boolean {\n  return series.type === 'area' || (series.type === 'line' && !!series.areaStyle);\n}\n\n/**\n * Prepares all series renderers with current frame data.\n *\n * This loop prepares ALL series (including hidden) to maintain correct renderer indices.\n * Visibility filtering happens after preparation for rendering.\n *\n * @param renderers - Series renderer instances\n * @param context - Preparation context with scales, options, and state\n * @returns Preparation result with visibility-filtered series arrays\n */\nexport function prepareSeries(\n  renderers: SeriesRenderers,\n  context: SeriesPrepareContext\n): SeriesPreparationResult {\n  const {\n    currentOptions,\n    seriesForRender,\n    xScale,\n    yScale,\n    gridArea,\n    dataStore,\n    appendedGpuThisFrame,\n    gpuSeriesKindByIndex,\n    zoomState,\n    visibleXDomain,\n    introPhase,\n    introProgress01,\n    withAlpha,\n    maxRadiusCss,\n  } = context;\n\n  const defaultBaseline = currentOptions.yAxis.min ?? (currentOptions.yAxis.min ?? 0);\n  const barSeriesConfigs: ResolvedBarSeriesConfig[] = [];\n\n  const introP = introPhase === 'running' ? clamp01(introProgress01) : 1;\n\n  // Preparation loop: prepare ALL series (including hidden) to maintain correct indices\n  for (let i = 0; i < seriesForRender.length; i++) {\n    const s = seriesForRender[i];\n    switch (s.type) {\n      case 'area': {\n        const baseline = s.baseline ?? defaultBaseline;\n        // TODO(step 2): normalize CartesianSeriesData to ReadonlyArray<DataPoint>\n        renderers.areaRenderers[i].prepare(s, s.data as ReadonlyArray<DataPoint>, xScale, yScale, baseline);\n        break;\n      }\n      case 'line': {\n        // Always prepare the line stroke.\n        // If we already appended into the DataStore this frame (fast-path), avoid a full re-upload.\n        // For time axes (epoch-ms), subtract an x-origin before packing to Float32 to avoid precision loss\n        // (Float32 ulp at ~1e12 is ~2e5), which can manifest as stroke shimmer during zoom.\n        const xOffset = (() => {\n          if (currentOptions.xAxis.type !== 'time') return 0;\n          // TODO(step 2): normalize CartesianSeriesData to ReadonlyArray<DataPoint>\n          const d = s.data as ReadonlyArray<DataPoint>;\n          for (let k = 0; k < d.length; k++) {\n            const p = d[k]!\n            const x = isTupleDataPoint(p) ? p[0] : p.x;\n            if (Number.isFinite(x)) return x;\n          }\n          return 0;\n        })();\n        if (!appendedGpuThisFrame.has(i)) {\n          // TODO(step 2): normalize CartesianSeriesData to ReadonlyArray<DataPoint>\n          dataStore.setSeries(i, s.data as ReadonlyArray<DataPoint>, { xOffset });\n        }\n        const buffer = dataStore.getSeriesBuffer(i);\n        renderers.lineRenderers[i].prepare(s, buffer, xScale, yScale, xOffset);\n\n        // Track the GPU buffer kind for future append fast-path decisions.\n        const zoomRange = zoomState?.getRange() ?? null;\n        const isFullSpanZoom =\n          zoomRange == null ||\n          (Number.isFinite(zoomRange.start) &&\n            Number.isFinite(zoomRange.end) &&\n            zoomRange.start <= 0 &&\n            zoomRange.end >= 100);\n        if (isFullSpanZoom && s.sampling === 'none') {\n          gpuSeriesKindByIndex[i] = 'fullRawLine';\n        } else {\n          gpuSeriesKindByIndex[i] = 'other';\n        }\n\n        // If `areaStyle` is provided on a line series, render a fill behind it.\n        if (s.areaStyle) {\n          const areaLike: ResolvedAreaSeriesConfig = {\n            type: 'area',\n            name: s.name,\n            rawData: s.data,\n            data: s.data,\n            color: s.areaStyle.color,\n            areaStyle: s.areaStyle,\n            sampling: s.sampling,\n            samplingThreshold: s.samplingThreshold,\n          };\n\n          // TODO(step 2): normalize CartesianSeriesData to ReadonlyArray<DataPoint>\n          renderers.areaRenderers[i].prepare(areaLike, areaLike.data as ReadonlyArray<DataPoint>, xScale, yScale, defaultBaseline);\n        }\n\n        break;\n      }\n      case 'bar': {\n        barSeriesConfigs.push(s);\n        break;\n      }\n      case 'scatter': {\n        // Scatter renderer sets/resets its own scissor. Animate intro via alpha fade.\n        if (s.mode === 'density') {\n          // Density mode bins raw (unsampled) data for correctness, but limits compute to the visible\n          // range when x is monotonic.\n          // TODO(step 2): normalize CartesianSeriesData to ReadonlyArray<DataPoint>\n          const rawData = (s.rawData ?? s.data) as ReadonlyArray<DataPoint>;\n          const visible = findVisibleRangeIndicesByX(rawData, visibleXDomain.min, visibleXDomain.max);\n\n          // Upload full raw data for compute. DataStore hashing makes this a cheap no-op when unchanged.\n          if (!appendedGpuThisFrame.has(i)) {\n            dataStore.setSeries(i, rawData);\n          }\n          const buffer = dataStore.getSeriesBuffer(i);\n          const pointCount = dataStore.getSeriesPointCount(i);\n\n          renderers.scatterDensityRenderers[i].prepare(\n            s,\n            buffer,\n            pointCount,\n            visible.start,\n            visible.end,\n            xScale,\n            yScale,\n            gridArea,\n            s.rawBounds\n          );\n          // Density mode keeps its own compute path; treat as non-fast-path for append heuristics.\n          gpuSeriesKindByIndex[i] = 'other';\n        } else {\n          const animated = introP < 1 ? ({ ...s, color: withAlpha(s.color, introP) } as const) : s;\n          // TODO(step 2): normalize CartesianSeriesData to ReadonlyArray<DataPoint>\n          renderers.scatterRenderers[i].prepare(animated, s.data as ReadonlyArray<DataPoint>, xScale, yScale, gridArea);\n        }\n        break;\n      }\n      case 'pie': {\n        // Pie renderer sets/resets its own scissor. Animate intro via radius scale (CSS px).\n        if (introP < 1 && maxRadiusCss > 0) {\n          const radiiCss = resolvePieRadiiCss(s.radius, maxRadiusCss);\n          const inner = Math.max(0, radiiCss.inner) * introP;\n          const outer = Math.max(inner, radiiCss.outer) * introP;\n          const animated: ResolvedPieSeriesConfig = { ...s, radius: [inner, outer] as const };\n          renderers.pieRenderers[i].prepare(animated, gridArea);\n          break;\n        }\n        renderers.pieRenderers[i].prepare(s, gridArea);\n        break;\n      }\n      case 'candlestick': {\n        // Candlestick renderer handles clipping internally, no intro animation for now.\n        renderers.candlestickRenderers[i].prepare(s, s.data, xScale, yScale, gridArea, currentOptions.theme.backgroundColor);\n        break;\n      }\n      default: {\n        // Exhaustive check for unhandled series types\n        const _exhaustive: never = s;\n        throw new Error(`Unhandled series type: ${(_exhaustive as any).type}`);\n      }\n    }\n  }\n\n  // Filter series by visibility for rendering (after preparation)\n  const visibleSeriesForRender = seriesForRender\n    .map((s, i) => ({ series: s, originalIndex: i }))\n    .filter(({ series }) => series.visible !== false);\n\n  // Bars are collected but prepared separately by coordinator (needs yScaleForBars which depends on visibleBarSeriesConfigs)\n  const visibleBarSeriesConfigs = barSeriesConfigs.filter(s => s.visible !== false);\n\n  return {\n    visibleSeriesForRender,\n    barSeriesConfigs,\n    visibleBarSeriesConfigs,\n  };\n}\n\n/**\n * Encodes scatter density compute passes before rendering.\n *\n * Must be called before beginRenderPass() for the main pass.\n *\n * @param renderers - Series renderer instances\n * @param seriesForRender - All series configurations\n * @param encoder - Command encoder for compute passes\n */\nexport function encodeScatterDensityCompute(\n  renderers: SeriesRenderers,\n  seriesForRender: ReadonlyArray<ResolvedSeriesConfig>,\n  encoder: GPUCommandEncoder\n): void {\n  for (let i = 0; i < seriesForRender.length; i++) {\n    const s = seriesForRender[i];\n    if (s.visible !== false && s.type === 'scatter' && s.mode === 'density') {\n      renderers.scatterDensityRenderers[i].encodeCompute(encoder);\n    }\n  }\n}\n\n/**\n * Renders all series to the main render pass with proper layering.\n *\n * Render order (from back to front):\n * 1. Pies (non-cartesian, behind cartesian series)\n * 2. Annotations below series (reference lines, markers)\n * 3. Area fills\n * 4. Bars\n * 5. Candlesticks\n * 6. Scatter points\n * 7. Line strokes\n *\n * @param renderers - Series renderer instances\n * @param annotationRenderers - Annotation renderer instances\n * @param context - Render pass context with pass encoders and state\n */\nexport function renderSeries(\n  renderers: SeriesRenderers,\n  annotationRenderers: AnnotationRenderers,\n  context: SeriesRenderContext,\n  prepResult: SeriesPreparationResult\n): void {\n  const {\n    hasCartesianSeries,\n    gridArea,\n    mainPass,\n    plotScissor,\n    introPhase,\n    introProgress01,\n    referenceLineBelowCount,\n    markerBelowCount,\n  } = context;\n\n  const { visibleSeriesForRender } = prepResult;\n  const introP = introPhase === 'running' ? clamp01(introProgress01) : 1;\n\n  // Render pies first (non-cartesian, visible behind cartesian series)\n  for (let idx = 0; idx < visibleSeriesForRender.length; idx++) {\n    const { series, originalIndex } = visibleSeriesForRender[idx];\n    if (series.type === 'pie') {\n      renderers.pieRenderers[originalIndex].render(mainPass);\n    }\n  }\n\n  // Annotations (below series): clipped to plot scissor.\n  if (hasCartesianSeries && plotScissor.w > 0 && plotScissor.h > 0) {\n    const hasBelow = referenceLineBelowCount > 0 || markerBelowCount > 0;\n    if (hasBelow) {\n      mainPass.setScissorRect(plotScissor.x, plotScissor.y, plotScissor.w, plotScissor.h);\n      if (referenceLineBelowCount > 0) {\n        annotationRenderers.referenceLineRenderer.render(mainPass, 0, referenceLineBelowCount);\n      }\n      if (markerBelowCount > 0) {\n        annotationRenderers.annotationMarkerRenderer.render(mainPass, 0, markerBelowCount);\n      }\n      mainPass.setScissorRect(0, 0, gridArea.canvasWidth, gridArea.canvasHeight);\n    }\n  }\n\n  // Render area fills\n  for (let idx = 0; idx < visibleSeriesForRender.length; idx++) {\n    const { series, originalIndex } = visibleSeriesForRender[idx];\n    if (shouldRenderArea(series)) {\n      // Line/area intro reveal: left-to-right plot scissor.\n      if (introP < 1) {\n        const w = clampInt(Math.floor(plotScissor.w * introP), 0, plotScissor.w);\n        if (w > 0 && plotScissor.h > 0) {\n          mainPass.setScissorRect(plotScissor.x, plotScissor.y, w, plotScissor.h);\n          renderers.areaRenderers[originalIndex].render(mainPass);\n          mainPass.setScissorRect(0, 0, gridArea.canvasWidth, gridArea.canvasHeight);\n        }\n      } else {\n        mainPass.setScissorRect(plotScissor.x, plotScissor.y, plotScissor.w, plotScissor.h);\n        renderers.areaRenderers[originalIndex].render(mainPass);\n        mainPass.setScissorRect(0, 0, gridArea.canvasWidth, gridArea.canvasHeight);\n      }\n    }\n  }\n\n  // Clip bars to the plot grid (mirrors area/line scissor usage).\n  if (plotScissor.w > 0 && plotScissor.h > 0) {\n    mainPass.setScissorRect(plotScissor.x, plotScissor.y, plotScissor.w, plotScissor.h);\n    renderers.barRenderer.render(mainPass);\n    mainPass.setScissorRect(0, 0, gridArea.canvasWidth, gridArea.canvasHeight);\n  }\n\n  // Render candlesticks\n  for (let idx = 0; idx < visibleSeriesForRender.length; idx++) {\n    const { series, originalIndex } = visibleSeriesForRender[idx];\n    if (series.type === 'candlestick') {\n      renderers.candlestickRenderers[originalIndex].render(mainPass);\n    }\n  }\n\n  // Render scatter points\n  for (let idx = 0; idx < visibleSeriesForRender.length; idx++) {\n    const { series, originalIndex } = visibleSeriesForRender[idx];\n    if (series.type !== 'scatter') continue;\n    if (series.mode === 'density') {\n      renderers.scatterDensityRenderers[originalIndex].render(mainPass);\n    } else {\n      renderers.scatterRenderers[originalIndex].render(mainPass);\n    }\n  }\n\n  // Render line strokes\n  for (let idx = 0; idx < visibleSeriesForRender.length; idx++) {\n    const { series, originalIndex } = visibleSeriesForRender[idx];\n    if (series.type === 'line') {\n      // Line intro reveal: left-to-right plot scissor.\n      if (introP < 1) {\n        const w = clampInt(Math.floor(plotScissor.w * introP), 0, plotScissor.w);\n        if (w > 0 && plotScissor.h > 0) {\n          mainPass.setScissorRect(plotScissor.x, plotScissor.y, w, plotScissor.h);\n          renderers.lineRenderers[originalIndex].render(mainPass);\n          mainPass.setScissorRect(0, 0, gridArea.canvasWidth, gridArea.canvasHeight);\n        }\n      } else {\n        mainPass.setScissorRect(plotScissor.x, plotScissor.y, plotScissor.w, plotScissor.h);\n        renderers.lineRenderers[originalIndex].render(mainPass);\n        mainPass.setScissorRect(0, 0, gridArea.canvasWidth, gridArea.canvasHeight);\n      }\n    }\n  }\n}\n\n/**\n * Renders above-series annotations to the MSAA overlay pass.\n *\n * Must be called during the MSAA overlay pass (after blit).\n *\n * @param annotationRenderers - Annotation renderer instances\n * @param context - Render pass context with overlay pass and state\n */\nexport function renderAboveSeriesAnnotations(\n  annotationRenderers: AnnotationRenderers,\n  context: AboveSeriesAnnotationContext\n): void {\n  const {\n    hasCartesianSeries,\n    gridArea,\n    overlayPass,\n    plotScissor,\n    referenceLineBelowCount,\n    referenceLineAboveCount,\n    markerBelowCount,\n    markerAboveCount,\n  } = context;\n\n  // Annotations (above series): reference lines then markers, clipped to plot scissor.\n  if (hasCartesianSeries && plotScissor.w > 0 && plotScissor.h > 0) {\n    const hasAbove = referenceLineAboveCount > 0 || markerAboveCount > 0;\n    if (hasAbove) {\n      const firstLine = referenceLineBelowCount;\n      const firstMarker = markerBelowCount;\n      overlayPass.setScissorRect(plotScissor.x, plotScissor.y, plotScissor.w, plotScissor.h);\n      if (referenceLineAboveCount > 0) {\n        annotationRenderers.referenceLineRendererMsaa.render(overlayPass, firstLine, referenceLineAboveCount);\n      }\n      if (markerAboveCount > 0) {\n        annotationRenderers.annotationMarkerRendererMsaa.render(overlayPass, firstMarker, markerAboveCount);\n      }\n      overlayPass.setScissorRect(0, 0, gridArea.canvasWidth, gridArea.canvasHeight);\n    }\n  }\n}\n","export default \"// grid.wgsl\\n// Minimal grid line shader:\\n// - Vertex input: vec2<f32> position in clip-space coordinates\\n// - Uniforms: identity transform + solid RGBA color\\n\\nstruct VSUniforms {\\n  transform: mat4x4<f32>,\\n};\\n\\n@group(0) @binding(0) var<uniform> vsUniforms: VSUniforms;\\n\\nstruct FSUniforms {\\n  color: vec4<f32>,\\n};\\n\\n@group(0) @binding(1) var<uniform> fsUniforms: FSUniforms;\\n\\nstruct VSIn {\\n  @location(0) position: vec2<f32>,\\n};\\n\\nstruct VSOut {\\n  @builtin(position) clipPosition: vec4<f32>,\\n};\\n\\n@vertex\\nfn vsMain(in: VSIn) -> VSOut {\\n  var out: VSOut;\\n  out.clipPosition = vsUniforms.transform * vec4<f32>(in.position, 0.0, 1.0);\\n  return out;\\n}\\n\\n@fragment\\nfn fsMain() -> @location(0) vec4<f32> {\\n  return fsUniforms.color;\\n}\\n\"","/**\n * Shared renderer utilities.\n *\n * Minimal, library-friendly helpers for common WebGPU boilerplate:\n * - shader module creation\n * - render pipeline creation (ergonomic config + sensible defaults)\n * - uniform buffer creation + updates\n *\n * Notes:\n * - All helpers are pure functions; they create resources but do not mutate external state.\n * - First argument is always `device: GPUDevice`.\n */\n\nexport type ShaderStageModuleSource =\n  | {\n      /** Use an existing module. */\n      readonly module: GPUShaderModule;\n      readonly entryPoint?: string;\n      readonly constants?: Record<string, GPUPipelineConstantValue>;\n    }\n  | {\n      /** Provide WGSL code to compile. */\n      readonly code: string;\n      readonly label?: string;\n      readonly entryPoint?: string;\n      readonly constants?: Record<string, GPUPipelineConstantValue>;\n    };\n\nexport type VertexStageConfig = ShaderStageModuleSource & {\n  readonly buffers?: readonly GPUVertexBufferLayout[];\n};\n\nexport type FragmentStageConfig = ShaderStageModuleSource & {\n  /**\n   * Provide full color target states directly (most flexible).\n   * If omitted, `formats` must be provided.\n   */\n  readonly targets?: readonly GPUColorTargetState[];\n  /**\n   * Convenience: provide one or more target formats and optionally a shared blend/writeMask.\n   * Ignored if `targets` is provided.\n   */\n  readonly formats?: GPUTextureFormat | readonly GPUTextureFormat[];\n  readonly blend?: GPUBlendState;\n  readonly writeMask?: GPUColorWriteFlags;\n};\n\nexport type RenderPipelineConfig =\n  | (RenderPipelineConfigBase & { readonly fragment: FragmentStageConfig })\n  | (RenderPipelineConfigBase & { readonly fragment?: undefined });\n\nexport interface RenderPipelineConfigBase {\n  readonly label?: string;\n\n  /**\n   * Defaults to `'auto'`.\n   *\n   * If you provide `bindGroupLayouts`, a pipeline layout will be created for you.\n   * If both are provided, `layout` wins.\n   */\n  readonly layout?: GPUPipelineLayout | 'auto';\n  readonly bindGroupLayouts?: readonly GPUBindGroupLayout[];\n\n  readonly vertex: VertexStageConfig;\n\n  readonly primitive?: GPUPrimitiveState;\n  readonly depthStencil?: GPUDepthStencilState;\n  readonly multisample?: GPUMultisampleState;\n}\n\nconst DEFAULT_VERTEX_ENTRY = 'vsMain';\nconst DEFAULT_FRAGMENT_ENTRY = 'fsMain';\n\nconst isPowerOfTwo = (n: number): boolean => Number.isInteger(n) && n > 0 && (n & (n - 1)) === 0;\n\nconst alignTo = (value: number, alignment: number): number => {\n  if (!Number.isFinite(value) || value < 0) {\n    throw new Error(`alignTo(value): value must be a finite non-negative number. Received: ${String(value)}`);\n  }\n  if (!isPowerOfTwo(alignment)) {\n    throw new Error(`alignTo(alignment): alignment must be a positive power of two. Received: ${String(alignment)}`);\n  }\n  const v = Math.floor(value);\n  return (v + alignment - 1) & ~(alignment - 1);\n};\n\nconst getStageModule = (\n  device: GPUDevice,\n  stage: ShaderStageModuleSource\n): { readonly module: GPUShaderModule; readonly entryPoint: string; readonly constants?: Record<string, GPUPipelineConstantValue> } => {\n  if ('module' in stage) {\n    return {\n      module: stage.module,\n      entryPoint: stage.entryPoint || '',\n      constants: stage.constants,\n    };\n  }\n\n  return {\n    module: createShaderModule(device, stage.code, stage.label),\n    entryPoint: stage.entryPoint || '',\n    constants: stage.constants,\n  };\n};\n\n/**\n * Creates a shader module from WGSL source.\n */\nexport function createShaderModule(device: GPUDevice, code: string, label?: string): GPUShaderModule {\n  if (typeof code !== 'string' || code.length === 0) {\n    throw new Error('createShaderModule(code): WGSL code must be a non-empty string.');\n  }\n  return device.createShaderModule({ code, label });\n}\n\n/**\n * Creates a render pipeline with reduced boilerplate and sensible defaults.\n *\n * Defaults:\n * - `layout: 'auto'`\n * - `vertex.entryPoint: 'vsMain'`\n * - `fragment.entryPoint: 'fsMain'` (if fragment present)\n * - `primitive.topology: 'triangle-list'`\n * - `multisample.count: 1`\n */\nexport function createRenderPipeline(device: GPUDevice, config: RenderPipelineConfig): GPURenderPipeline {\n  const layout: GPUPipelineLayout | 'auto' =\n    config.layout ??\n    (config.bindGroupLayouts ? device.createPipelineLayout({ bindGroupLayouts: [...config.bindGroupLayouts] }) : 'auto');\n\n  const vertexStage = getStageModule(device, config.vertex);\n  const vertexEntryPoint = vertexStage.entryPoint || DEFAULT_VERTEX_ENTRY;\n\n  let fragment: GPUFragmentState | undefined = undefined;\n  if (config.fragment) {\n    const fragmentStage = getStageModule(device, config.fragment);\n    const fragmentEntryPoint = fragmentStage.entryPoint || DEFAULT_FRAGMENT_ENTRY;\n\n    let targets: readonly GPUColorTargetState[] | undefined = config.fragment.targets;\n    if (!targets) {\n      const formats = config.fragment.formats;\n      if (!formats) {\n        throw new Error(\n          \"createRenderPipeline(fragment): provide either `fragment.targets` or `fragment.formats` when a fragment stage is present.\"\n        );\n      }\n      const formatList = Array.isArray(formats) ? formats : [formats];\n      targets = formatList.map((format) => ({\n        format,\n        blend: config.fragment!.blend,\n        writeMask: config.fragment!.writeMask,\n      }));\n    }\n\n    fragment = {\n      module: fragmentStage.module,\n      entryPoint: fragmentEntryPoint,\n      targets: [...targets],\n      constants: fragmentStage.constants,\n    };\n  }\n\n  const primitive: GPUPrimitiveState = config.primitive ?? { topology: 'triangle-list' };\n  const multisample: GPUMultisampleState = config.multisample ?? { count: 1 };\n\n  return device.createRenderPipeline({\n    label: config.label,\n    layout,\n    vertex: {\n      module: vertexStage.module,\n      entryPoint: vertexEntryPoint,\n      buffers: config.vertex.buffers ? [...config.vertex.buffers] : [],\n      constants: vertexStage.constants,\n    },\n    fragment,\n    primitive,\n    depthStencil: config.depthStencil,\n    multisample,\n  });\n}\n\n/**\n * Creates a uniform buffer suitable for `@group/@binding` uniform bindings.\n *\n * Notes:\n * - WebGPU's `queue.writeBuffer()` requires `byteLength` and offsets to be multiples of 4.\n * - Uniform data layout in WGSL is typically aligned to 16 bytes; we default to a 16-byte size alignment.\n * - If you plan to use this buffer with *dynamic offsets*, you must additionally align offsets to\n *   `device.limits.minUniformBufferOffsetAlignment` (commonly 256). This helper does not enforce that.\n */\nexport function createUniformBuffer(\n  device: GPUDevice,\n  size: number,\n  options?: { readonly label?: string; readonly alignment?: number }\n): GPUBuffer {\n  if (!Number.isFinite(size) || size <= 0) {\n    throw new Error(`createUniformBuffer(size): size must be a positive number. Received: ${String(size)}`);\n  }\n\n  const alignment = options?.alignment ?? 16;\n  const alignedSize = alignTo(size, Math.max(4, alignment));\n\n  const maxSize = device.limits.maxUniformBufferBindingSize;\n  if (alignedSize > maxSize) {\n    throw new Error(\n      `createUniformBuffer(size): requested size ${alignedSize} exceeds device.limits.maxUniformBufferBindingSize (${maxSize}).`\n    );\n  }\n\n  return device.createBuffer({\n    label: options?.label,\n    size: alignedSize,\n    usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST,\n  });\n}\n\n/**\n * Writes CPU data into a uniform buffer (default offset 0).\n *\n * `data` must be a `BufferSource`:\n * - `ArrayBuffer` or `ArrayBufferView` (TypedArray/DataView)\n *\n * Important WebGPU constraint:\n * - `queue.writeBuffer()` requires write size (and offsets) to be multiples of 4 bytes.\n */\nexport function writeUniformBuffer(device: GPUDevice, buffer: GPUBuffer, data: BufferSource): void {\n  const src =\n    data instanceof ArrayBuffer\n      ? { arrayBuffer: data, offset: 0, size: data.byteLength }\n      : { arrayBuffer: data.buffer, offset: data.byteOffset, size: data.byteLength };\n\n  if (src.size === 0) return;\n\n  if ((src.offset & 3) !== 0 || (src.size & 3) !== 0) {\n    throw new Error(\n      `writeUniformBuffer(data): data byteOffset (${src.offset}) and byteLength (${src.size}) must be multiples of 4 for queue.writeBuffer().`\n    );\n  }\n\n  if (src.size > buffer.size) {\n    throw new Error(`writeUniformBuffer(data): data byteLength (${src.size}) exceeds buffer.size (${buffer.size}).`);\n  }\n\n  device.queue.writeBuffer(buffer, 0, src.arrayBuffer, src.offset, src.size);\n}\n","import gridWgsl from '../shaders/grid.wgsl?raw';\nimport type { AxisConfig } from '../config/types';\nimport type { LinearScale } from '../utils/scales';\nimport { createRenderPipeline, createUniformBuffer, writeUniformBuffer } from './rendererUtils';\nimport type { GridArea } from './createGridRenderer';\nimport { parseCssColorToRgba01 } from '../utils/colors';\n\nexport interface AxisRenderer {\n  prepare(\n    axisConfig: AxisConfig,\n    scale: LinearScale,\n    orientation: 'x' | 'y',\n    gridArea: GridArea,\n    axisLineColor?: string,\n    axisTickColor?: string,\n    tickCount?: number\n  ): void;\n  render(passEncoder: GPURenderPassEncoder): void;\n  dispose(): void;\n}\n\nexport interface AxisRendererOptions {\n  /**\n   * Must match the canvas context format used for the render pass color attachment.\n   * Usually this is `gpuContext.preferredFormat`.\n   *\n   * Defaults to `'bgra8unorm'` for backward compatibility.\n   */\n  readonly targetFormat?: GPUTextureFormat;\n}\n\nconst DEFAULT_TARGET_FORMAT: GPUTextureFormat = 'bgra8unorm';\nconst DEFAULT_TICK_COUNT = 5;\nconst DEFAULT_TICK_LENGTH_CSS_PX = 6;\nconst DEFAULT_AXIS_RGBA: readonly [number, number, number, number] = [1, 1, 1, 0.8];\n\nconst createIdentityMat4Buffer = (): ArrayBuffer => {\n  // Column-major identity mat4x4\n  const buffer = new ArrayBuffer(16 * 4);\n  new Float32Array(buffer).set([\n    1, 0, 0, 0, // col0\n    0, 1, 0, 0, // col1\n    0, 0, 1, 0, // col2\n    0, 0, 0, 1, // col3\n  ]);\n  return buffer;\n};\n\nconst isFiniteGridArea = (gridArea: GridArea): boolean =>\n  Number.isFinite(gridArea.left) &&\n  Number.isFinite(gridArea.right) &&\n  Number.isFinite(gridArea.top) &&\n  Number.isFinite(gridArea.bottom) &&\n  Number.isFinite(gridArea.canvasWidth) &&\n  Number.isFinite(gridArea.canvasHeight);\n\nconst finiteOrUndefined = (v: number | undefined): number | undefined => (typeof v === 'number' && Number.isFinite(v) ? v : undefined);\n\nconst normalizeDomain = (minCandidate: number, maxCandidate: number): { readonly min: number; readonly max: number } => {\n  let min = minCandidate;\n  let max = maxCandidate;\n\n  if (!Number.isFinite(min) || !Number.isFinite(max)) {\n    min = 0;\n    max = 1;\n  }\n\n  if (min === max) {\n    max = min + 1;\n  } else if (min > max) {\n    const t = min;\n    min = max;\n    max = t;\n  }\n\n  return { min, max };\n};\n\nconst generateAxisVertices = (\n  axisConfig: AxisConfig,\n  scale: LinearScale,\n  orientation: 'x' | 'y',\n  gridArea: GridArea,\n  tickCountOverride?: number\n): Float32Array => {\n  const { left, right, top, bottom, canvasWidth, canvasHeight } = gridArea;\n  // Be resilient: older call sites may omit/incorrectly pass DPR. Defaulting avoids hard crashes.\n  const devicePixelRatio =\n    Number.isFinite(gridArea.devicePixelRatio) && gridArea.devicePixelRatio > 0 ? gridArea.devicePixelRatio : 1;\n\n  if (!isFiniteGridArea(gridArea)) {\n    throw new Error('AxisRenderer.prepare: gridArea dimensions must be finite numbers.');\n  }\n  if (canvasWidth <= 0 || canvasHeight <= 0) {\n    throw new Error('AxisRenderer.prepare: canvas dimensions must be positive.');\n  }\n  if (left < 0 || right < 0 || top < 0 || bottom < 0) {\n    throw new Error('AxisRenderer.prepare: gridArea margins must be non-negative.');\n  }\n\n  const plotLeft = left * devicePixelRatio;\n  const plotRight = canvasWidth - right * devicePixelRatio;\n  const plotTop = top * devicePixelRatio;\n  const plotBottom = canvasHeight - bottom * devicePixelRatio;\n\n  const plotLeftClip = (plotLeft / canvasWidth) * 2.0 - 1.0;\n  const plotRightClip = (plotRight / canvasWidth) * 2.0 - 1.0;\n  const plotTopClip = 1.0 - (plotTop / canvasHeight) * 2.0; // flip Y\n  const plotBottomClip = 1.0 - (plotBottom / canvasHeight) * 2.0; // flip Y\n\n  const tickLengthCssPx = axisConfig.tickLength ?? DEFAULT_TICK_LENGTH_CSS_PX;\n  if (!Number.isFinite(tickLengthCssPx) || tickLengthCssPx < 0) {\n    throw new Error('AxisRenderer.prepare: tickLength must be a finite non-negative number.');\n  }\n\n  const tickCountRaw = tickCountOverride ?? DEFAULT_TICK_COUNT;\n  const tickCount = Math.max(1, Math.floor(tickCountRaw));\n  if (!Number.isFinite(tickCountRaw) || tickCount < 1) {\n    throw new Error('AxisRenderer.prepare: tickCount must be a finite number >= 1.');\n  }\n  const tickLengthDevicePx = tickLengthCssPx * devicePixelRatio;\n  const tickDeltaClipX = (tickLengthDevicePx / canvasWidth) * 2.0;\n  const tickDeltaClipY = (tickLengthDevicePx / canvasHeight) * 2.0;\n\n  // IMPORTANT: ignore non-finite overrides to keep GPU ticks consistent with the render coordinator\n  // (which also treats min/max as “unset” when non-finite).\n  const domainMinRaw =\n    finiteOrUndefined(axisConfig.min) ??\n    (orientation === 'x' ? scale.invert(plotLeftClip) : scale.invert(plotBottomClip));\n  const domainMaxRaw =\n    finiteOrUndefined(axisConfig.max) ??\n    (orientation === 'x' ? scale.invert(plotRightClip) : scale.invert(plotTopClip));\n  const domain = normalizeDomain(domainMinRaw, domainMaxRaw);\n  const domainMin = domain.min;\n  const domainMax = domain.max;\n\n  // Line-list segments:\n  // - 1 baseline segment\n  // - tickCount tick segments\n  const totalSegments = 1 + tickCount;\n  const vertices = new Float32Array(totalSegments * 2 * 2); // segments * 2 vertices * vec2<f32>\n\n  let idx = 0;\n\n  if (orientation === 'x') {\n    // Baseline along bottom edge of plot rect.\n    vertices[idx++] = plotLeftClip;\n    vertices[idx++] = plotBottomClip;\n    vertices[idx++] = plotRightClip;\n    vertices[idx++] = plotBottomClip;\n\n    // Ticks extend downward (outside plot).\n    const y0 = plotBottomClip;\n    const y1 = y0 - tickDeltaClipY;\n\n    for (let i = 0; i < tickCount; i++) {\n      const t = tickCount === 1 ? 0.5 : i / (tickCount - 1);\n      const v = domainMin + t * (domainMax - domainMin);\n      const x = scale.scale(v);\n\n      vertices[idx++] = x;\n      vertices[idx++] = y0;\n      vertices[idx++] = x;\n      vertices[idx++] = y1;\n    }\n  } else {\n    // Baseline along left edge of plot rect.\n    vertices[idx++] = plotLeftClip;\n    vertices[idx++] = plotBottomClip;\n    vertices[idx++] = plotLeftClip;\n    vertices[idx++] = plotTopClip;\n\n    // Ticks extend left (outside plot).\n    const x0 = plotLeftClip;\n    const x1 = x0 - tickDeltaClipX;\n\n    for (let i = 0; i < tickCount; i++) {\n      const t = tickCount === 1 ? 0.5 : i / (tickCount - 1);\n      const v = domainMin + t * (domainMax - domainMin);\n      const y = scale.scale(v);\n\n      vertices[idx++] = x0;\n      vertices[idx++] = y;\n      vertices[idx++] = x1;\n      vertices[idx++] = y;\n    }\n  }\n\n  return vertices;\n};\n\nexport function createAxisRenderer(device: GPUDevice, options?: AxisRendererOptions): AxisRenderer {\n  let disposed = false;\n  const targetFormat = options?.targetFormat ?? DEFAULT_TARGET_FORMAT;\n\n  const bindGroupLayout = device.createBindGroupLayout({\n    entries: [\n      { binding: 0, visibility: GPUShaderStage.VERTEX, buffer: { type: 'uniform' } },\n      { binding: 1, visibility: GPUShaderStage.FRAGMENT, buffer: { type: 'uniform' } },\n    ],\n  });\n\n  const vsUniformBuffer = createUniformBuffer(device, 64, { label: 'axisRenderer/vsUniforms' });\n  const fsUniformBufferLine = createUniformBuffer(device, 16, { label: 'axisRenderer/fsUniformsLine' });\n  const fsUniformBufferTick = createUniformBuffer(device, 16, { label: 'axisRenderer/fsUniformsTick' });\n\n  const bindGroupLine = device.createBindGroup({\n    layout: bindGroupLayout,\n    entries: [\n      { binding: 0, resource: { buffer: vsUniformBuffer } },\n      { binding: 1, resource: { buffer: fsUniformBufferLine } },\n    ],\n  });\n\n  const bindGroupTick = device.createBindGroup({\n    layout: bindGroupLayout,\n    entries: [\n      { binding: 0, resource: { buffer: vsUniformBuffer } },\n      { binding: 1, resource: { buffer: fsUniformBufferTick } },\n    ],\n  });\n\n  const pipeline = createRenderPipeline(device, {\n    label: 'axisRenderer/pipeline',\n    bindGroupLayouts: [bindGroupLayout],\n    vertex: {\n      code: gridWgsl,\n      label: 'grid.wgsl',\n      buffers: [\n        {\n          arrayStride: 8,\n          stepMode: 'vertex',\n          attributes: [{ shaderLocation: 0, format: 'float32x2', offset: 0 }],\n        },\n      ],\n    },\n    fragment: {\n      code: gridWgsl,\n      label: 'grid.wgsl',\n      formats: targetFormat,\n      blend: {\n        color: { operation: 'add', srcFactor: 'src-alpha', dstFactor: 'one-minus-src-alpha' },\n        alpha: { operation: 'add', srcFactor: 'one', dstFactor: 'one-minus-src-alpha' },\n      },\n    },\n    primitive: { topology: 'line-list', cullMode: 'none' },\n    multisample: { count: 1 },\n  });\n\n  let vertexBuffer: GPUBuffer | null = null;\n  let vertexCount = 0;\n\n  const assertNotDisposed = (): void => {\n    if (disposed) throw new Error('AxisRenderer is disposed.');\n  };\n\n  const prepare: AxisRenderer['prepare'] = (\n    axisConfig,\n    scale,\n    orientation,\n    gridArea,\n    axisLineColor,\n    axisTickColor,\n    tickCount\n  ) => {\n    assertNotDisposed();\n\n    if (orientation !== 'x' && orientation !== 'y') {\n      throw new Error(\"AxisRenderer.prepare: orientation must be 'x' or 'y'.\");\n    }\n\n    const vertices = generateAxisVertices(axisConfig, scale, orientation, gridArea, tickCount);\n    const requiredSize = vertices.byteLength;\n    const bufferSize = Math.max(4, requiredSize);\n\n    if (!vertexBuffer || vertexBuffer.size < bufferSize) {\n      if (vertexBuffer) {\n        try {\n          vertexBuffer.destroy();\n        } catch {\n          // best-effort\n        }\n      }\n      vertexBuffer = device.createBuffer({\n        label: 'axisRenderer/vertexBuffer',\n        size: bufferSize,\n        usage: GPUBufferUsage.VERTEX | GPUBufferUsage.COPY_DST,\n      });\n    }\n\n    device.queue.writeBuffer(vertexBuffer, 0, vertices.buffer, 0, vertices.byteLength);\n    vertexCount = vertices.length / 2;\n\n    // Identity transform (vertices already in clip-space).\n    writeUniformBuffer(device, vsUniformBuffer, createIdentityMat4Buffer());\n\n    // Separate colors for baseline vs ticks.\n    // Gracefully fall back to legacy (slightly brighter than grid) when parsing fails.\n    const axisLineColorString = axisLineColor ?? 'rgba(255,255,255,0.8)';\n    const axisTickColorString = axisTickColor ?? axisLineColorString;\n\n    const axisLineRgba = parseCssColorToRgba01(axisLineColorString) ?? DEFAULT_AXIS_RGBA;\n    const axisTickRgba = parseCssColorToRgba01(axisTickColorString) ?? axisLineRgba;\n\n    const lineColorBuffer = new ArrayBuffer(4 * 4);\n    new Float32Array(lineColorBuffer).set([\n      axisLineRgba[0],\n      axisLineRgba[1],\n      axisLineRgba[2],\n      axisLineRgba[3],\n    ]);\n    writeUniformBuffer(device, fsUniformBufferLine, lineColorBuffer);\n\n    const tickColorBuffer = new ArrayBuffer(4 * 4);\n    new Float32Array(tickColorBuffer).set([\n      axisTickRgba[0],\n      axisTickRgba[1],\n      axisTickRgba[2],\n      axisTickRgba[3],\n    ]);\n    writeUniformBuffer(device, fsUniformBufferTick, tickColorBuffer);\n  };\n\n  const render: AxisRenderer['render'] = (passEncoder) => {\n    assertNotDisposed();\n    if (vertexCount === 0 || !vertexBuffer) return;\n\n    passEncoder.setPipeline(pipeline);\n    passEncoder.setVertexBuffer(0, vertexBuffer);\n\n    // Baseline: first 2 vertices.\n    passEncoder.setBindGroup(0, bindGroupLine);\n    passEncoder.draw(Math.min(2, vertexCount));\n\n    // Ticks: remaining vertices.\n    if (vertexCount > 2) {\n      passEncoder.setBindGroup(0, bindGroupTick);\n      passEncoder.draw(vertexCount - 2, 1, 2, 0);\n    }\n  };\n\n  const dispose: AxisRenderer['dispose'] = () => {\n    if (disposed) return;\n    disposed = true;\n\n    try {\n      vsUniformBuffer.destroy();\n    } catch {\n      // best-effort\n    }\n    try {\n      fsUniformBufferLine.destroy();\n    } catch {\n      // best-effort\n    }\n    try {\n      fsUniformBufferTick.destroy();\n    } catch {\n      // best-effort\n    }\n    if (vertexBuffer) {\n      try {\n        vertexBuffer.destroy();\n      } catch {\n        // best-effort\n      }\n    }\n\n    vertexBuffer = null;\n    vertexCount = 0;\n  };\n\n  return { prepare, render, dispose };\n}\n\n","import gridWgsl from '../shaders/grid.wgsl?raw';\nimport { createRenderPipeline, createUniformBuffer, writeUniformBuffer } from './rendererUtils';\nimport { parseCssColorToRgba01 } from '../utils/colors';\n\nexport interface GridRenderer {\n  /**\n   * Backward compatible:\n   * - `prepare(gridArea, lineCount)` where `lineCount` is `{ horizontal?, vertical? }`\n   *\n   * Preferred:\n   * - `prepare(gridArea, { lineCount, color })`\n   */\n  prepare(gridArea: GridArea, lineCountOrOptions?: GridLineCount | GridPrepareOptions): void;\n  render(passEncoder: GPURenderPassEncoder): void;\n  dispose(): void;\n}\n\nexport interface GridArea {\n  readonly left: number;        // Left margin in CSS pixels\n  readonly right: number;       // Right margin in CSS pixels\n  readonly top: number;         // Top margin in CSS pixels\n  readonly bottom: number;      // Bottom margin in CSS pixels\n  readonly canvasWidth: number;  // Canvas width in device pixels (canvas.width)\n  readonly canvasHeight: number; // Canvas height in device pixels (canvas.height)\n  readonly devicePixelRatio: number; // Device pixel ratio for CSS-to-device conversion\n}\n\nexport interface GridLineCount {\n  readonly horizontal?: number;  // Default: 5\n  readonly vertical?: number;    // Default: 6\n}\n\nexport interface GridPrepareOptions {\n  readonly lineCount?: GridLineCount;\n  /**\n   * CSS color string used for grid lines.\n   *\n   * Expected formats: `#rgb`, `#rrggbb`, `#rrggbbaa`, `rgb(r,g,b)`, `rgba(r,g,b,a)`.\n   */\n  readonly color?: string;\n}\n\nexport interface GridRendererOptions {\n  /**\n   * Must match the canvas context format used for the render pass color attachment.\n   * Usually this is `gpuContext.preferredFormat`.\n   *\n   * Defaults to `'bgra8unorm'` for backward compatibility.\n   */\n  readonly targetFormat?: GPUTextureFormat;\n}\n\nconst DEFAULT_TARGET_FORMAT: GPUTextureFormat = 'bgra8unorm';\nconst DEFAULT_HORIZONTAL_LINES = 5;\nconst DEFAULT_VERTICAL_LINES = 6;\nconst DEFAULT_GRID_COLOR = 'rgba(255,255,255,0.15)';\nconst DEFAULT_GRID_RGBA: readonly [number, number, number, number] = [1, 1, 1, 0.15];\n\nconst createIdentityMat4Buffer = (): ArrayBuffer => {\n  // Column-major identity mat4x4\n  const buffer = new ArrayBuffer(16 * 4);\n  new Float32Array(buffer).set([\n    1, 0, 0, 0, // col0\n    0, 1, 0, 0, // col1\n    0, 0, 1, 0, // col2\n    0, 0, 0, 1, // col3\n  ]);\n  return buffer;\n};\n\nconst generateGridVertices = (gridArea: GridArea, horizontal: number, vertical: number): Float32Array => {\n  const { left, right, top, bottom, canvasWidth, canvasHeight } = gridArea;\n  // Be resilient: older call sites may omit/incorrectly pass DPR. Defaulting avoids hard crashes.\n  const devicePixelRatio =\n    Number.isFinite(gridArea.devicePixelRatio) && gridArea.devicePixelRatio > 0 ? gridArea.devicePixelRatio : 1;\n\n  // Calculate plot area in device pixels using explicit DPR\n  const plotLeft = left * devicePixelRatio;\n  const plotRight = canvasWidth - right * devicePixelRatio;\n  const plotTop = top * devicePixelRatio;\n  const plotBottom = canvasHeight - bottom * devicePixelRatio;\n\n  const plotWidth = plotRight - plotLeft;\n  const plotHeight = plotBottom - plotTop;\n\n  // Total vertices: (horizontal + vertical) * 2 vertices per line\n  const totalLines = horizontal + vertical;\n  const vertices = new Float32Array(totalLines * 2 * 2); // 2 vertices * 2 floats per vertex\n\n  let idx = 0;\n\n  // Generate horizontal lines (constant Y, varying X)\n  for (let i = 0; i < horizontal; i++) {\n    // Calculate t parameter for even spacing\n    const t = horizontal === 1 ? 0.5 : i / (horizontal - 1);\n    const yDevice = plotTop + t * plotHeight;\n\n    // Convert to clip space\n    const xClipLeft = (plotLeft / canvasWidth) * 2.0 - 1.0;\n    const xClipRight = (plotRight / canvasWidth) * 2.0 - 1.0;\n    const yClip = 1.0 - (yDevice / canvasHeight) * 2.0; // Flip Y-axis\n\n    // First vertex (left edge)\n    vertices[idx++] = xClipLeft;\n    vertices[idx++] = yClip;\n\n    // Second vertex (right edge)\n    vertices[idx++] = xClipRight;\n    vertices[idx++] = yClip;\n  }\n\n  // Generate vertical lines (constant X, varying Y)\n  for (let i = 0; i < vertical; i++) {\n    // Calculate t parameter for even spacing\n    const t = vertical === 1 ? 0.5 : i / (vertical - 1);\n    const xDevice = plotLeft + t * plotWidth;\n\n    // Convert to clip space\n    const xClip = (xDevice / canvasWidth) * 2.0 - 1.0;\n    const yClipTop = 1.0 - (plotTop / canvasHeight) * 2.0; // Flip Y-axis\n    const yClipBottom = 1.0 - (plotBottom / canvasHeight) * 2.0; // Flip Y-axis\n\n    // First vertex (top edge)\n    vertices[idx++] = xClip;\n    vertices[idx++] = yClipTop;\n\n    // Second vertex (bottom edge)\n    vertices[idx++] = xClip;\n    vertices[idx++] = yClipBottom;\n  }\n\n  return vertices;\n};\n\nexport function createGridRenderer(device: GPUDevice, options?: GridRendererOptions): GridRenderer {\n  let disposed = false;\n  const targetFormat = options?.targetFormat ?? DEFAULT_TARGET_FORMAT;\n\n  const bindGroupLayout = device.createBindGroupLayout({\n    entries: [\n      { binding: 0, visibility: GPUShaderStage.VERTEX, buffer: { type: 'uniform' } },\n      { binding: 1, visibility: GPUShaderStage.FRAGMENT, buffer: { type: 'uniform' } },\n    ],\n  });\n\n  const vsUniformBuffer = createUniformBuffer(device, 64, { label: 'gridRenderer/vsUniforms' });\n  const fsUniformBuffer = createUniformBuffer(device, 16, { label: 'gridRenderer/fsUniforms' });\n\n  const bindGroup = device.createBindGroup({\n    layout: bindGroupLayout,\n    entries: [\n      { binding: 0, resource: { buffer: vsUniformBuffer } },\n      { binding: 1, resource: { buffer: fsUniformBuffer } },\n    ],\n  });\n\n  const pipeline = createRenderPipeline(device, {\n    label: 'gridRenderer/pipeline',\n    bindGroupLayouts: [bindGroupLayout],\n    vertex: {\n      code: gridWgsl,\n      label: 'grid.wgsl',\n      buffers: [\n        {\n          arrayStride: 8, // vec2<f32> = 2 * 4 bytes\n          stepMode: 'vertex',\n          attributes: [{ shaderLocation: 0, format: 'float32x2', offset: 0 }],\n        },\n      ],\n    },\n    fragment: {\n      code: gridWgsl,\n      label: 'grid.wgsl',\n      formats: targetFormat,\n      // Enable standard alpha blending so `fsUniforms.color.a` behaves as expected\n      // (blends into the cleared background instead of making the canvas pixels transparent).\n      blend: {\n        color: { operation: 'add', srcFactor: 'src-alpha', dstFactor: 'one-minus-src-alpha' },\n        alpha: { operation: 'add', srcFactor: 'one', dstFactor: 'one-minus-src-alpha' },\n      },\n    },\n    primitive: { topology: 'line-list', cullMode: 'none' },\n    multisample: { count: 1 },\n  });\n\n  let vertexBuffer: GPUBuffer | null = null;\n  let vertexCount = 0;\n\n  const assertNotDisposed = (): void => {\n    if (disposed) throw new Error('GridRenderer is disposed.');\n  };\n\n  const prepare: GridRenderer['prepare'] = (gridArea, lineCountOrOptions) => {\n    assertNotDisposed();\n\n    const isOptionsObject =\n      lineCountOrOptions != null &&\n      typeof lineCountOrOptions === 'object' &&\n      ('lineCount' in lineCountOrOptions || 'color' in lineCountOrOptions);\n\n    const options: GridPrepareOptions | undefined = isOptionsObject\n      ? (lineCountOrOptions as GridPrepareOptions)\n      : undefined;\n\n    const lineCount: GridLineCount | undefined = isOptionsObject\n      ? options?.lineCount\n      : (lineCountOrOptions as GridLineCount | undefined);\n\n    const horizontal = lineCount?.horizontal ?? DEFAULT_HORIZONTAL_LINES;\n    const vertical = lineCount?.vertical ?? DEFAULT_VERTICAL_LINES;\n    const colorString = options?.color ?? DEFAULT_GRID_COLOR;\n\n    // Validate inputs\n    if (horizontal < 0 || vertical < 0) {\n      throw new Error('GridRenderer.prepare: line counts must be non-negative.');\n    }\n    if (\n      !Number.isFinite(gridArea.left) ||\n      !Number.isFinite(gridArea.right) ||\n      !Number.isFinite(gridArea.top) ||\n      !Number.isFinite(gridArea.bottom) ||\n      !Number.isFinite(gridArea.canvasWidth) ||\n      !Number.isFinite(gridArea.canvasHeight)\n    ) {\n      throw new Error('GridRenderer.prepare: gridArea dimensions must be finite numbers.');\n    }\n    if (gridArea.canvasWidth <= 0 || gridArea.canvasHeight <= 0) {\n      throw new Error('GridRenderer.prepare: canvas dimensions must be positive.');\n    }\n\n    // Early return if no lines to draw\n    if (horizontal === 0 && vertical === 0) {\n      vertexCount = 0;\n      return;\n    }\n\n    // Generate vertices\n    const vertices = generateGridVertices(gridArea, horizontal, vertical);\n    const requiredSize = vertices.byteLength;\n\n    // Ensure minimum buffer size of 4 bytes\n    const bufferSize = Math.max(4, requiredSize);\n\n    // Create or recreate vertex buffer if needed\n    if (!vertexBuffer || vertexBuffer.size < bufferSize) {\n      if (vertexBuffer) {\n        try {\n          vertexBuffer.destroy();\n        } catch {\n          // best-effort\n        }\n      }\n\n      vertexBuffer = device.createBuffer({\n        label: 'gridRenderer/vertexBuffer',\n        size: bufferSize,\n        usage: GPUBufferUsage.VERTEX | GPUBufferUsage.COPY_DST,\n      });\n    }\n\n    // Write vertex data\n    device.queue.writeBuffer(vertexBuffer, 0, vertices.buffer, 0, vertices.byteLength);\n    vertexCount = (horizontal + vertical) * 2;\n\n    // Write uniforms\n    // VS uniform: identity transform (vertices already in clip space)\n    const transformBuffer = createIdentityMat4Buffer();\n    writeUniformBuffer(device, vsUniformBuffer, transformBuffer);\n\n    // FS uniform: theme-driven (grid lines)\n    const rgba = parseCssColorToRgba01(colorString) ?? DEFAULT_GRID_RGBA;\n    const colorBuffer = new ArrayBuffer(4 * 4);\n    new Float32Array(colorBuffer).set([rgba[0], rgba[1], rgba[2], rgba[3]]);\n    writeUniformBuffer(device, fsUniformBuffer, colorBuffer);\n  };\n\n  const render: GridRenderer['render'] = (passEncoder) => {\n    assertNotDisposed();\n    if (vertexCount === 0 || !vertexBuffer) return;\n\n    passEncoder.setPipeline(pipeline);\n    passEncoder.setBindGroup(0, bindGroup);\n    passEncoder.setVertexBuffer(0, vertexBuffer);\n    passEncoder.draw(vertexCount);\n  };\n\n  const dispose: GridRenderer['dispose'] = () => {\n    if (disposed) return;\n    disposed = true;\n\n    try {\n      vsUniformBuffer.destroy();\n    } catch {\n      // best-effort\n    }\n    try {\n      fsUniformBuffer.destroy();\n    } catch {\n      // best-effort\n    }\n    if (vertexBuffer) {\n      try {\n        vertexBuffer.destroy();\n      } catch {\n        // best-effort\n      }\n    }\n\n    vertexBuffer = null;\n    vertexCount = 0;\n  };\n\n  return { prepare, render, dispose };\n}\n","export default \"// area.wgsl\\n// Minimal area-fill shader (triangle-strip):\\n// - Vertex input: vec2<f32> position in data coords\\n// - Uniforms: clip-space transform + baseline value + solid RGBA color\\n// - Topology: triangle-strip\\n// - CPU duplicates vertices as p0,p0,p1,p1,... and we use vertex_index parity:\\n//   even index -> \\\"top\\\" vertex (original y)\\n//   odd index  -> \\\"baseline\\\" vertex (uniform baseline)\\n\\nstruct VSUniforms {\\n  transform: mat4x4<f32>,\\n  baseline: f32,\\n  // Pad to 16-byte multiple (uniform buffer layout requirements).\\n  _pad0: vec3<f32>,\\n};\\n\\n@group(0) @binding(0) var<uniform> vsUniforms: VSUniforms;\\n\\nstruct FSUniforms {\\n  color: vec4<f32>,\\n};\\n\\n@group(0) @binding(1) var<uniform> fsUniforms: FSUniforms;\\n\\nstruct VSIn {\\n  @location(0) position: vec2<f32>,\\n};\\n\\nstruct VSOut {\\n  @builtin(position) clipPosition: vec4<f32>,\\n};\\n\\n@vertex\\nfn vsMain(in: VSIn, @builtin(vertex_index) vertexIndex: u32) -> VSOut {\\n  var out: VSOut;\\n  let useBaseline = (vertexIndex & 1u) == 1u;\\n  let y = select(in.position.y, vsUniforms.baseline, useBaseline);\\n  let pos = vec2<f32>(in.position.x, y);\\n  out.clipPosition = vsUniforms.transform * vec4<f32>(pos, 0.0, 1.0);\\n  return out;\\n}\\n\\n@fragment\\nfn fsMain() -> @location(0) vec4<f32> {\\n  return fsUniforms.color;\\n}\\n\\n\"","import areaWgsl from '../shaders/area.wgsl?raw';\nimport type { ResolvedAreaSeriesConfig } from '../config/OptionResolver';\nimport type { DataPoint, DataPointTuple } from '../config/types';\nimport type { LinearScale } from '../utils/scales';\nimport { parseCssColorToRgba01 } from '../utils/colors';\nimport { createRenderPipeline, createUniformBuffer, writeUniformBuffer } from './rendererUtils';\n\nexport interface AreaRenderer {\n  prepare(\n    seriesConfig: ResolvedAreaSeriesConfig,\n    // TODO(step 2): This will accept normalized ReadonlyArray<DataPoint>\n    data: ReadonlyArray<DataPoint>,\n    xScale: LinearScale,\n    yScale: LinearScale,\n    baseline?: number\n  ): void;\n  render(passEncoder: GPURenderPassEncoder): void;\n  dispose(): void;\n}\n\nexport interface AreaRendererOptions {\n  /**\n   * Must match the canvas context format used for the render pass color attachment.\n   * Usually this is `gpuContext.preferredFormat`.\n   *\n   * Defaults to `'bgra8unorm'` for backward compatibility.\n   */\n  readonly targetFormat?: GPUTextureFormat;\n}\n\ntype Rgba = readonly [r: number, g: number, b: number, a: number];\n\nconst DEFAULT_TARGET_FORMAT: GPUTextureFormat = 'bgra8unorm';\n\nconst clamp01 = (v: number): number => Math.min(1, Math.max(0, v));\nconst parseSeriesColorToRgba01 = (color: string): Rgba =>\n  parseCssColorToRgba01(color) ?? ([0, 0, 0, 1] as const);\n\nconst isTupleDataPoint = (point: DataPoint): point is DataPointTuple => Array.isArray(point);\n\nconst getPointXY = (\n  point: DataPoint\n): { readonly x: number; readonly y: number } => {\n  if (isTupleDataPoint(point)) return { x: point[0], y: point[1] };\n  return { x: point.x, y: point.y };\n};\n\nconst computeDataBounds = (\n  data: ReadonlyArray<DataPoint>\n): { readonly xMin: number; readonly xMax: number; readonly yMin: number; readonly yMax: number } => {\n  let xMin = Number.POSITIVE_INFINITY;\n  let xMax = Number.NEGATIVE_INFINITY;\n  let yMin = Number.POSITIVE_INFINITY;\n  let yMax = Number.NEGATIVE_INFINITY;\n\n  for (let i = 0; i < data.length; i++) {\n    const { x, y } = getPointXY(data[i]);\n    if (!Number.isFinite(x) || !Number.isFinite(y)) continue;\n    if (x < xMin) xMin = x;\n    if (x > xMax) xMax = x;\n    if (y < yMin) yMin = y;\n    if (y > yMax) yMax = y;\n  }\n\n  if (!Number.isFinite(xMin) || !Number.isFinite(xMax) || !Number.isFinite(yMin) || !Number.isFinite(yMax)) {\n    return { xMin: 0, xMax: 1, yMin: 0, yMax: 1 };\n  }\n\n  // Avoid degenerate domains for affine derivation (handled later too, but keep stable samples).\n  if (xMin === xMax) xMax = xMin + 1;\n  if (yMin === yMax) yMax = yMin + 1;\n\n  return { xMin, xMax, yMin, yMax };\n};\n\nconst computeClipAffineFromScale = (\n  scale: LinearScale,\n  v0: number,\n  v1: number\n): { readonly a: number; readonly b: number } => {\n  const p0 = scale.scale(v0);\n  const p1 = scale.scale(v1);\n\n  // If the domain sample is degenerate or non-finite, fall back to constant output.\n  if (!Number.isFinite(v0) || !Number.isFinite(v1) || v0 === v1 || !Number.isFinite(p0) || !Number.isFinite(p1)) {\n    return { a: 0, b: Number.isFinite(p0) ? p0 : 0 };\n  }\n\n  const a = (p1 - p0) / (v1 - v0);\n  const b = p0 - a * v0;\n  return { a: Number.isFinite(a) ? a : 0, b: Number.isFinite(b) ? b : 0 };\n};\n\nconst writeTransformMat4F32 = (out: Float32Array, ax: number, bx: number, ay: number, by: number): void => {\n  // Column-major mat4x4 for: clip = M * vec4(x, y, 0, 1)\n  out[0] = ax;\n  out[1] = 0;\n  out[2] = 0;\n  out[3] = 0; // col0\n  out[4] = 0;\n  out[5] = ay;\n  out[6] = 0;\n  out[7] = 0; // col1\n  out[8] = 0;\n  out[9] = 0;\n  out[10] = 1;\n  out[11] = 0; // col2\n  out[12] = bx;\n  out[13] = by;\n  out[14] = 0;\n  out[15] = 1; // col3\n};\n\nconst createAreaVertices = (data: ReadonlyArray<DataPoint>): Float32Array => {\n  // Triangle-strip expects duplicated vertices:\n  // p0,p0,p1,p1,... and WGSL uses vertex_index parity to swap y to baseline for odd indices.\n  const n = data.length;\n  const out = new Float32Array(n * 2 * 2); // n * 2 vertices * vec2<f32>\n\n  let idx = 0;\n  for (let i = 0; i < n; i++) {\n    const { x, y } = getPointXY(data[i]);\n    out[idx++] = x;\n    out[idx++] = y;\n    out[idx++] = x;\n    out[idx++] = y;\n  }\n\n  return out;\n};\n\nexport function createAreaRenderer(device: GPUDevice, options?: AreaRendererOptions): AreaRenderer {\n  let disposed = false;\n  const targetFormat = options?.targetFormat ?? DEFAULT_TARGET_FORMAT;\n\n  const bindGroupLayout = device.createBindGroupLayout({\n    entries: [\n      { binding: 0, visibility: GPUShaderStage.VERTEX, buffer: { type: 'uniform' } },\n      { binding: 1, visibility: GPUShaderStage.FRAGMENT, buffer: { type: 'uniform' } },\n    ],\n  });\n\n  const vsUniformBuffer = createUniformBuffer(device, 96, { label: 'areaRenderer/vsUniforms' });\n  const fsUniformBuffer = createUniformBuffer(device, 16, { label: 'areaRenderer/fsUniforms' });\n\n  // Reused CPU-side staging for uniform writes (avoid per-frame allocations).\n  const vsUniformScratchBuffer = new ArrayBuffer(96);\n  const vsUniformScratchF32 = new Float32Array(vsUniformScratchBuffer);\n  const fsUniformScratchF32 = new Float32Array(4);\n\n  const bindGroup = device.createBindGroup({\n    layout: bindGroupLayout,\n    entries: [\n      { binding: 0, resource: { buffer: vsUniformBuffer } },\n      { binding: 1, resource: { buffer: fsUniformBuffer } },\n    ],\n  });\n\n  const pipeline = createRenderPipeline(device, {\n    label: 'areaRenderer/pipeline',\n    bindGroupLayouts: [bindGroupLayout],\n    vertex: {\n      code: areaWgsl,\n      label: 'area.wgsl',\n      buffers: [\n        {\n          arrayStride: 8,\n          stepMode: 'vertex',\n          attributes: [{ shaderLocation: 0, format: 'float32x2', offset: 0 }],\n        },\n      ],\n    },\n    fragment: {\n      code: areaWgsl,\n      label: 'area.wgsl',\n      formats: targetFormat,\n      // Enable standard alpha blending so `areaStyle.opacity` behaves correctly.\n      blend: {\n        color: { operation: 'add', srcFactor: 'src-alpha', dstFactor: 'one-minus-src-alpha' },\n        alpha: { operation: 'add', srcFactor: 'one', dstFactor: 'one-minus-src-alpha' },\n      },\n    },\n    primitive: { topology: 'triangle-strip', cullMode: 'none' },\n    multisample: { count: 1 },\n  });\n\n  let vertexBuffer: GPUBuffer | null = null;\n  let vertexCount = 0;\n\n  const assertNotDisposed = (): void => {\n    if (disposed) throw new Error('AreaRenderer is disposed.');\n  };\n\n  const writeVsUniforms = (ax: number, bx: number, ay: number, by: number, baseline: number): void => {\n    // VSUniforms:\n    // - mat4x4<f32> (64 bytes)\n    // - baseline: f32 (4 bytes)\n    // - (implicit padding to next 16B boundary) (12 bytes)\n    // - _pad0: vec3<f32> (occupies 16 bytes in a uniform buffer)\n    // Total: 96 bytes.\n    //\n    // Layout details (uniform address space):\n    // - transform at byte offset 0\n    // - baseline at byte offset 64 (f32[16])\n    // - _pad0 at byte offset 80 (f32[20..22]) with trailing 4B padding\n    writeTransformMat4F32(vsUniformScratchF32, ax, bx, ay, by);\n    vsUniformScratchF32[16] = baseline;\n    vsUniformScratchF32[17] = 0;\n    vsUniformScratchF32[18] = 0;\n    vsUniformScratchF32[19] = 0;\n    vsUniformScratchF32[20] = 0;\n    vsUniformScratchF32[21] = 0;\n    vsUniformScratchF32[22] = 0;\n    vsUniformScratchF32[23] = 0;\n    writeUniformBuffer(device, vsUniformBuffer, vsUniformScratchBuffer);\n  };\n\n  const prepare: AreaRenderer['prepare'] = (seriesConfig, data, xScale, yScale, baseline) => {\n    assertNotDisposed();\n\n    const vertices = createAreaVertices(data);\n    const requiredSize = vertices.byteLength;\n    const bufferSize = Math.max(4, requiredSize);\n\n    if (!vertexBuffer || vertexBuffer.size < bufferSize) {\n      if (vertexBuffer) {\n        try {\n          vertexBuffer.destroy();\n        } catch {\n          // best-effort\n        }\n      }\n      vertexBuffer = device.createBuffer({\n        label: 'areaRenderer/vertexBuffer',\n        size: bufferSize,\n        usage: GPUBufferUsage.VERTEX | GPUBufferUsage.COPY_DST,\n      });\n    }\n\n    if (vertices.byteLength > 0) {\n      device.queue.writeBuffer(vertexBuffer, 0, vertices.buffer, 0, vertices.byteLength);\n    }\n    vertexCount = vertices.length / 2;\n\n    const { xMin, xMax, yMin, yMax } = computeDataBounds(data);\n    const { a: ax, b: bx } = computeClipAffineFromScale(xScale, xMin, xMax);\n    const { a: ay, b: by } = computeClipAffineFromScale(yScale, yMin, yMax);\n\n    const baselineValue =\n      Number.isFinite(baseline ?? Number.NaN) ? (baseline as number) : Number.isFinite(yMin) ? yMin : 0;\n\n    writeVsUniforms(ax, bx, ay, by, baselineValue);\n\n    // Use the resolved fill color from areaStyle.color (not seriesConfig.color).\n    const [r, g, b, a] = parseSeriesColorToRgba01(seriesConfig.areaStyle.color);\n    const opacity = clamp01(seriesConfig.areaStyle.opacity);\n    fsUniformScratchF32[0] = r;\n    fsUniformScratchF32[1] = g;\n    fsUniformScratchF32[2] = b;\n    fsUniformScratchF32[3] = clamp01(a * opacity);\n    writeUniformBuffer(device, fsUniformBuffer, fsUniformScratchF32);\n  };\n\n  const render: AreaRenderer['render'] = (passEncoder) => {\n    assertNotDisposed();\n    if (!vertexBuffer || vertexCount < 4) return;\n\n    passEncoder.setPipeline(pipeline);\n    passEncoder.setBindGroup(0, bindGroup);\n    passEncoder.setVertexBuffer(0, vertexBuffer);\n    passEncoder.draw(vertexCount);\n  };\n\n  const dispose: AreaRenderer['dispose'] = () => {\n    if (disposed) return;\n    disposed = true;\n\n    if (vertexBuffer) {\n      try {\n        vertexBuffer.destroy();\n      } catch {\n        // best-effort\n      }\n    }\n    vertexBuffer = null;\n    vertexCount = 0;\n\n    try {\n      vsUniformBuffer.destroy();\n    } catch {\n      // best-effort\n    }\n    try {\n      fsUniformBuffer.destroy();\n    } catch {\n      // best-effort\n    }\n  };\n\n  return { prepare, render, dispose };\n}\n\n","export default \"// line.wgsl\\n// Minimal line-strip shader:\\n// - Vertex input: vec2<f32> position in data coords\\n// - Uniforms: clip-space transform + solid RGBA color\\n\\nstruct VSUniforms {\\n  transform: mat4x4<f32>,\\n};\\n\\n@group(0) @binding(0) var<uniform> vsUniforms: VSUniforms;\\n\\nstruct FSUniforms {\\n  color: vec4<f32>,\\n};\\n\\n@group(0) @binding(1) var<uniform> fsUniforms: FSUniforms;\\n\\nstruct VSIn {\\n  @location(0) position: vec2<f32>,\\n};\\n\\nstruct VSOut {\\n  @builtin(position) clipPosition: vec4<f32>,\\n};\\n\\n@vertex\\nfn vsMain(in: VSIn) -> VSOut {\\n  var out: VSOut;\\n  out.clipPosition = vsUniforms.transform * vec4<f32>(in.position, 0.0, 1.0);\\n  return out;\\n}\\n\\n@fragment\\nfn fsMain() -> @location(0) vec4<f32> {\\n  return fsUniforms.color;\\n}\\n\\n\"","import lineWgsl from '../shaders/line.wgsl?raw';\nimport type { ResolvedLineSeriesConfig } from '../config/OptionResolver';\nimport type { DataPoint, DataPointTuple } from '../config/types';\nimport type { LinearScale } from '../utils/scales';\nimport { parseCssColorToRgba01 } from '../utils/colors';\nimport { createRenderPipeline, createUniformBuffer, writeUniformBuffer } from './rendererUtils';\n\nexport interface LineRenderer {\n  prepare(\n    seriesConfig: ResolvedLineSeriesConfig,\n    dataBuffer: GPUBuffer,\n    xScale: LinearScale,\n    yScale: LinearScale,\n    xOffset?: number\n  ): void;\n  render(passEncoder: GPURenderPassEncoder): void;\n  dispose(): void;\n}\n\nexport interface LineRendererOptions {\n  /**\n   * Must match the canvas context format used for the render pass color attachment.\n   * Usually this is `gpuContext.preferredFormat`.\n   *\n   * Defaults to `'bgra8unorm'` for backward compatibility.\n   */\n  readonly targetFormat?: GPUTextureFormat;\n}\n\ntype Rgba = readonly [r: number, g: number, b: number, a: number];\n\nconst DEFAULT_TARGET_FORMAT: GPUTextureFormat = 'bgra8unorm';\n\nconst clamp01 = (v: number): number => Math.min(1, Math.max(0, v));\nconst parseSeriesColorToRgba01 = (color: string): Rgba =>\n  parseCssColorToRgba01(color) ?? ([0, 0, 0, 1] as const);\n\nconst isTupleDataPoint = (\n  point: DataPoint\n): point is DataPointTuple => Array.isArray(point);\n\nconst getPointXY = (point: DataPoint): { readonly x: number; readonly y: number } => {\n  if (isTupleDataPoint(point)) return { x: point[0], y: point[1] };\n  return { x: point.x, y: point.y };\n};\n\nconst computeDataBounds = (\n  data: ReadonlyArray<DataPoint>\n): { readonly xMin: number; readonly xMax: number; readonly yMin: number; readonly yMax: number } => {\n  let xMin = Number.POSITIVE_INFINITY;\n  let xMax = Number.NEGATIVE_INFINITY;\n  let yMin = Number.POSITIVE_INFINITY;\n  let yMax = Number.NEGATIVE_INFINITY;\n\n  for (let i = 0; i < data.length; i++) {\n    const { x, y } = getPointXY(data[i]);\n    if (!Number.isFinite(x) || !Number.isFinite(y)) continue;\n    if (x < xMin) xMin = x;\n    if (x > xMax) xMax = x;\n    if (y < yMin) yMin = y;\n    if (y > yMax) yMax = y;\n  }\n\n  if (!Number.isFinite(xMin) || !Number.isFinite(xMax) || !Number.isFinite(yMin) || !Number.isFinite(yMax)) {\n    return { xMin: 0, xMax: 1, yMin: 0, yMax: 1 };\n  }\n\n  // Avoid degenerate domains for affine derivation (handled later too, but keep stable samples).\n  if (xMin === xMax) xMax = xMin + 1;\n  if (yMin === yMax) yMax = yMin + 1;\n\n  return { xMin, xMax, yMin, yMax };\n};\n\nconst computeClipAffineFromScale = (\n  scale: LinearScale,\n  v0: number,\n  v1: number\n): { readonly a: number; readonly b: number } => {\n  const p0 = scale.scale(v0);\n  const p1 = scale.scale(v1);\n\n  // If the domain sample is degenerate or non-finite, fall back to constant output.\n  if (!Number.isFinite(v0) || !Number.isFinite(v1) || v0 === v1 || !Number.isFinite(p0) || !Number.isFinite(p1)) {\n    return { a: 0, b: Number.isFinite(p0) ? p0 : 0 };\n  }\n\n  const a = (p1 - p0) / (v1 - v0);\n  const b = p0 - a * v0;\n  return { a: Number.isFinite(a) ? a : 0, b: Number.isFinite(b) ? b : 0 };\n};\n\nconst writeTransformMat4F32 = (out: Float32Array, ax: number, bx: number, ay: number, by: number): void => {\n  // Column-major mat4x4 for: clip = M * vec4(x, y, 0, 1)\n  out[0] = ax;\n  out[1] = 0;\n  out[2] = 0;\n  out[3] = 0; // col0\n  out[4] = 0;\n  out[5] = ay;\n  out[6] = 0;\n  out[7] = 0; // col1\n  out[8] = 0;\n  out[9] = 0;\n  out[10] = 1;\n  out[11] = 0; // col2\n  out[12] = bx;\n  out[13] = by;\n  out[14] = 0;\n  out[15] = 1; // col3\n};\n\nexport function createLineRenderer(device: GPUDevice, options?: LineRendererOptions): LineRenderer {\n  let disposed = false;\n  const targetFormat = options?.targetFormat ?? DEFAULT_TARGET_FORMAT;\n\n  const bindGroupLayout = device.createBindGroupLayout({\n    entries: [\n      { binding: 0, visibility: GPUShaderStage.VERTEX, buffer: { type: 'uniform' } },\n      { binding: 1, visibility: GPUShaderStage.FRAGMENT, buffer: { type: 'uniform' } },\n    ],\n  });\n\n  const vsUniformBuffer = createUniformBuffer(device, 64, { label: 'lineRenderer/vsUniforms' });\n  const fsUniformBuffer = createUniformBuffer(device, 16, { label: 'lineRenderer/fsUniforms' });\n\n  // Reused CPU-side staging for uniform writes (avoid per-frame allocations).\n  const vsUniformScratchBuffer = new ArrayBuffer(64);\n  const vsUniformScratchF32 = new Float32Array(vsUniformScratchBuffer);\n  const fsUniformScratchF32 = new Float32Array(4);\n\n  const bindGroup = device.createBindGroup({\n    layout: bindGroupLayout,\n    entries: [\n      { binding: 0, resource: { buffer: vsUniformBuffer } },\n      { binding: 1, resource: { buffer: fsUniformBuffer } },\n    ],\n  });\n\n  const pipeline = createRenderPipeline(device, {\n    label: 'lineRenderer/pipeline',\n    bindGroupLayouts: [bindGroupLayout],\n    vertex: {\n      code: lineWgsl,\n      label: 'line.wgsl',\n      buffers: [\n        {\n          arrayStride: 8,\n          stepMode: 'vertex',\n          attributes: [{ shaderLocation: 0, format: 'float32x2', offset: 0 }],\n        },\n      ],\n    },\n    fragment: {\n      code: lineWgsl,\n      label: 'line.wgsl',\n      formats: targetFormat,\n      // Enable standard alpha blending so per-series `lineStyle.opacity` behaves\n      // correctly against an opaque cleared background.\n      blend: {\n        color: { operation: 'add', srcFactor: 'src-alpha', dstFactor: 'one-minus-src-alpha' },\n        alpha: { operation: 'add', srcFactor: 'one', dstFactor: 'one-minus-src-alpha' },\n      },\n    },\n    primitive: { topology: 'line-strip', cullMode: 'none' },\n    multisample: { count: 1 },\n  });\n\n  let currentVertexBuffer: GPUBuffer | null = null;\n  let currentVertexCount = 0;\n\n  const assertNotDisposed = (): void => {\n    if (disposed) throw new Error('LineRenderer is disposed.');\n  };\n\n  const prepare: LineRenderer['prepare'] = (seriesConfig, dataBuffer, xScale, yScale, xOffset = 0) => {\n    assertNotDisposed();\n\n    currentVertexBuffer = dataBuffer;\n    // TODO(step 2): data will already be normalized to ReadonlyArray<DataPoint>\n    const dataArray = seriesConfig.data as ReadonlyArray<DataPoint>;\n    currentVertexCount = dataArray.length;\n\n    const { xMin, xMax, yMin, yMax } = computeDataBounds(dataArray);\n    const { a: ax, b: bx } = computeClipAffineFromScale(xScale, xMin, xMax);\n    const { a: ay, b: by } = computeClipAffineFromScale(yScale, yMin, yMax);\n\n    // When the vertex buffer packs x as (x - xOffset) (to preserve Float32 precision for large\n    // domains like epoch-ms), fold the offset back into the affine's intercept in f64 on CPU:\n    // clipX = ax * (x - xOffset) + (bx + ax * xOffset)\n    const bxAdjusted = bx + ax * xOffset;\n    writeTransformMat4F32(vsUniformScratchF32, ax, bxAdjusted, ay, by);\n    writeUniformBuffer(device, vsUniformBuffer, vsUniformScratchBuffer);\n\n    const [r, g, b, a] = parseSeriesColorToRgba01(seriesConfig.color);\n    const opacity = clamp01(seriesConfig.lineStyle.opacity);\n    fsUniformScratchF32[0] = r;\n    fsUniformScratchF32[1] = g;\n    fsUniformScratchF32[2] = b;\n    fsUniformScratchF32[3] = clamp01(a * opacity);\n    writeUniformBuffer(device, fsUniformBuffer, fsUniformScratchF32);\n  };\n\n  const render: LineRenderer['render'] = (passEncoder) => {\n    assertNotDisposed();\n    if (!currentVertexBuffer || currentVertexCount < 2) return;\n\n    passEncoder.setPipeline(pipeline);\n    passEncoder.setBindGroup(0, bindGroup);\n    passEncoder.setVertexBuffer(0, currentVertexBuffer);\n    passEncoder.draw(currentVertexCount);\n  };\n\n  const dispose: LineRenderer['dispose'] = () => {\n    if (disposed) return;\n    disposed = true;\n\n    currentVertexBuffer = null;\n    currentVertexCount = 0;\n\n    try {\n      vsUniformBuffer.destroy();\n    } catch {\n      // best-effort\n    }\n    try {\n      fsUniformBuffer.destroy();\n    } catch {\n      // best-effort\n    }\n  };\n\n  return { prepare, render, dispose };\n}\n","export default \"// bar.wgsl\\n// Instanced bar/rect shader:\\n// - Per-instance vertex input:\\n//   - rect  = vec4<f32>(x, y, width, height) in CLIP space\\n//   - color = vec4<f32>(r, g, b, a) in [0..1]\\n// - Draw call: draw(6, instanceCount) using triangle-list expansion in VS\\n// - Uniforms:\\n//   - @group(0) @binding(0): VSUniforms { transform }\\n\\nstruct VSUniforms {\\n  transform: mat4x4<f32>,\\n};\\n\\n@group(0) @binding(0) var<uniform> vsUniforms: VSUniforms;\\n\\nstruct VSIn {\\n  // rect.xy = origin, rect.zw = size (width, height)\\n  @location(0) rect: vec4<f32>,\\n  @location(1) color: vec4<f32>,\\n};\\n\\nstruct VSOut {\\n  @builtin(position) clipPosition: vec4<f32>,\\n  @location(0) color: vec4<f32>,\\n};\\n\\n@vertex\\nfn vsMain(in: VSIn, @builtin(vertex_index) vertexIndex: u32) -> VSOut {\\n  // Fixed local corners for 2 triangles (triangle-list).\\n  let corners = array<vec2<f32>, 6>(\\n    vec2<f32>(0.0, 0.0),\\n    vec2<f32>(1.0, 0.0),\\n    vec2<f32>(0.0, 1.0),\\n    vec2<f32>(0.0, 1.0),\\n    vec2<f32>(1.0, 0.0),\\n    vec2<f32>(1.0, 1.0)\\n  );\\n\\n  // Normalize negative width/height by computing min/max extents.\\n  let p0 = in.rect.xy;\\n  let p1 = in.rect.xy + in.rect.zw;\\n  let rectMin = min(p0, p1);\\n  let rectMax = max(p0, p1);\\n  let rectSize = rectMax - rectMin;\\n\\n  let corner = corners[vertexIndex];\\n  let pos = rectMin + corner * rectSize;\\n\\n  var out: VSOut;\\n  out.clipPosition = vsUniforms.transform * vec4<f32>(pos, 0.0, 1.0);\\n  out.color = in.color;\\n  return out;\\n}\\n\\n@fragment\\nfn fsMain(in: VSOut) -> @location(0) vec4<f32> {\\n  return in.color;\\n}\\n\\n\"","import barWgsl from '../shaders/bar.wgsl?raw';\nimport type { ResolvedBarSeriesConfig } from '../config/OptionResolver';\nimport type { DataPoint, DataPointTuple } from '../config/types';\nimport type { LinearScale } from '../utils/scales';\nimport type { GridArea } from './createGridRenderer';\nimport { parseCssColorToRgba01 } from '../utils/colors';\nimport type { DataStore } from '../data/createDataStore';\nimport { createRenderPipeline, createUniformBuffer, writeUniformBuffer } from './rendererUtils';\n\nexport interface BarRenderer {\n  prepare(\n    seriesConfigs: ReadonlyArray<ResolvedBarSeriesConfig>,\n    dataStore: DataStore,\n    xScale: LinearScale,\n    yScale: LinearScale,\n    gridArea: GridArea\n  ): void;\n  render(passEncoder: GPURenderPassEncoder): void;\n  dispose(): void;\n}\n\nexport interface BarRendererOptions {\n  /**\n   * Must match the canvas context format used for the render pass color attachment.\n   * Usually this is `gpuContext.preferredFormat`.\n   *\n   * Defaults to `'bgra8unorm'` for backward compatibility.\n   */\n  readonly targetFormat?: GPUTextureFormat;\n}\n\ntype Rgba = readonly [r: number, g: number, b: number, a: number];\n\nconst DEFAULT_TARGET_FORMAT: GPUTextureFormat = 'bgra8unorm';\nconst DEFAULT_BAR_GAP = 0.01; // Minimal gap between bars within a group (was 0.1)\nconst DEFAULT_BAR_CATEGORY_GAP = 0.2;\nconst INSTANCE_STRIDE_BYTES = 32; // rect vec4 + color vec4\nconst INSTANCE_STRIDE_FLOATS = INSTANCE_STRIDE_BYTES / 4;\n\nconst clamp01 = (v: number): number => Math.min(1, Math.max(0, v));\nconst parseSeriesColorToRgba01 = (color: string): Rgba =>\n  parseCssColorToRgba01(color) ?? ([0, 0, 0, 1] as const);\n\nconst nextPow2 = (v: number): number => {\n  if (!Number.isFinite(v) || v <= 0) return 1;\n  const n = Math.ceil(v);\n  return 2 ** Math.ceil(Math.log2(n));\n};\n\nconst createIdentityMat4Buffer = (): ArrayBuffer => {\n  // Column-major identity mat4x4\n  const buffer = new ArrayBuffer(16 * 4);\n  new Float32Array(buffer).set([\n    1, 0, 0, 0, // col0\n    0, 1, 0, 0, // col1\n    0, 0, 1, 0, // col2\n    0, 0, 0, 1, // col3\n  ]);\n  return buffer;\n};\n\nconst parsePercent = (value: string): number | null => {\n  const m = value.trim().match(/^(\\d+(?:\\.\\d+)?)%$/);\n  if (!m) return null;\n  const p = Number(m[1]) / 100;\n  return Number.isFinite(p) ? p : null;\n};\n\nconst normalizeStackId = (stack: unknown): string => {\n  if (typeof stack !== 'string') return '';\n  const trimmed = stack.trim();\n  return trimmed.length > 0 ? trimmed : '';\n};\n\nconst isTupleDataPoint = (p: DataPoint): p is DataPointTuple => Array.isArray(p);\n\nconst getPointXY = (p: DataPoint): { readonly x: number; readonly y: number } => {\n  if (isTupleDataPoint(p)) return { x: p[0], y: p[1] };\n  return { x: p.x, y: p.y };\n};\n\nconst computePlotSizeCssPx = (gridArea: GridArea): { readonly plotWidthCss: number; readonly plotHeightCss: number } | null => {\n  const dpr = gridArea.devicePixelRatio;\n  if (!(dpr > 0)) return null;\n  const canvasCssWidth = gridArea.canvasWidth / dpr;\n  const canvasCssHeight = gridArea.canvasHeight / dpr;\n  const plotWidthCss = canvasCssWidth - gridArea.left - gridArea.right;\n  const plotHeightCss = canvasCssHeight - gridArea.top - gridArea.bottom;\n  if (!(plotWidthCss > 0) || !(plotHeightCss > 0)) return null;\n  return { plotWidthCss, plotHeightCss };\n};\n\nconst computePlotClipRect = (\n  gridArea: GridArea\n): { readonly left: number; readonly right: number; readonly top: number; readonly bottom: number } => {\n  const { left, right, top, bottom, canvasWidth, canvasHeight, devicePixelRatio } = gridArea;\n\n  const plotLeft = left * devicePixelRatio;\n  const plotRight = canvasWidth - right * devicePixelRatio;\n  const plotTop = top * devicePixelRatio;\n  const plotBottom = canvasHeight - bottom * devicePixelRatio;\n\n  const plotLeftClip = (plotLeft / canvasWidth) * 2.0 - 1.0;\n  const plotRightClip = (plotRight / canvasWidth) * 2.0 - 1.0;\n  const plotTopClip = 1.0 - (plotTop / canvasHeight) * 2.0; // flip Y\n  const plotBottomClip = 1.0 - (plotBottom / canvasHeight) * 2.0; // flip Y\n\n  return { left: plotLeftClip, right: plotRightClip, top: plotTopClip, bottom: plotBottomClip };\n};\n\nconst computeCategoryWidthClip = (\n  xScale: LinearScale,\n  categoryStep: number,\n  plotClipRect: Readonly<{ left: number; right: number }>,\n  fallbackCategoryCount: number\n): number => {\n  if (Number.isFinite(categoryStep) && categoryStep > 0) {\n    const x0 = 0;\n    const p0 = xScale.scale(x0);\n    const p1 = xScale.scale(x0 + categoryStep);\n    const w = Math.abs(p1 - p0);\n    if (Number.isFinite(w) && w > 0) return w;\n  }\n\n  const clipWidth = Math.abs(plotClipRect.right - plotClipRect.left);\n  if (!(clipWidth > 0)) return 0;\n  const n = Math.max(1, Math.floor(fallbackCategoryCount));\n  return clipWidth / n;\n};\n\nexport function createBarRenderer(device: GPUDevice, options?: BarRendererOptions): BarRenderer {\n  let disposed = false;\n  const targetFormat = options?.targetFormat ?? DEFAULT_TARGET_FORMAT;\n\n  const bindGroupLayout = device.createBindGroupLayout({\n    entries: [\n      { binding: 0, visibility: GPUShaderStage.VERTEX, buffer: { type: 'uniform' } },\n    ],\n  });\n\n  const vsUniformBuffer = createUniformBuffer(device, 64, { label: 'barRenderer/vsUniforms' });\n  // Default to identity: we upload rects in clip-space.\n  writeUniformBuffer(device, vsUniformBuffer, createIdentityMat4Buffer());\n\n  const bindGroup = device.createBindGroup({\n    layout: bindGroupLayout,\n    entries: [\n      { binding: 0, resource: { buffer: vsUniformBuffer } },\n    ],\n  });\n\n  const pipeline = createRenderPipeline(device, {\n    label: 'barRenderer/pipeline',\n    bindGroupLayouts: [bindGroupLayout],\n    vertex: {\n      code: barWgsl,\n      label: 'bar.wgsl',\n      buffers: [\n        {\n          arrayStride: INSTANCE_STRIDE_BYTES, // rect vec4 + color vec4\n          stepMode: 'instance',\n          attributes: [\n            { shaderLocation: 0, format: 'float32x4', offset: 0 },\n            { shaderLocation: 1, format: 'float32x4', offset: 16 },\n          ],\n        },\n      ],\n    },\n    fragment: {\n      code: barWgsl,\n      label: 'bar.wgsl',\n      formats: targetFormat,\n      blend: {\n        color: { operation: 'add', srcFactor: 'src-alpha', dstFactor: 'one-minus-src-alpha' },\n        alpha: { operation: 'add', srcFactor: 'one', dstFactor: 'one-minus-src-alpha' },\n      },\n    },\n    primitive: { topology: 'triangle-list', cullMode: 'none' },\n    multisample: { count: 1 },\n  });\n\n  let instanceBuffer: GPUBuffer | null = null;\n  let instanceCount = 0;\n  let cpuInstanceStagingBuffer = new ArrayBuffer(0);\n  let cpuInstanceStagingF32 = new Float32Array(cpuInstanceStagingBuffer);\n  const categoryXScratch: number[] = [];\n\n  const assertNotDisposed = (): void => {\n    if (disposed) throw new Error('BarRenderer is disposed.');\n  };\n\n  const ensureCpuInstanceCapacityFloats = (requiredFloats: number): void => {\n    if (requiredFloats <= cpuInstanceStagingF32.length) return;\n    // Grow geometrically (power-of-two) to reduce churn.\n    const nextFloats = Math.max(8, nextPow2(requiredFloats));\n    cpuInstanceStagingBuffer = new ArrayBuffer(nextFloats * 4);\n    cpuInstanceStagingF32 = new Float32Array(cpuInstanceStagingBuffer);\n  };\n\n  const computeBarCategoryStep = (seriesConfigs: ReadonlyArray<ResolvedBarSeriesConfig>): number => {\n    categoryXScratch.length = 0;\n    for (let s = 0; s < seriesConfigs.length; s++) {\n      // TODO(step 2): normalize CartesianSeriesData to ReadonlyArray<DataPoint>\n      const data = seriesConfigs[s].data as ReadonlyArray<DataPoint>;\n      for (let i = 0; i < data.length; i++) {\n        const { x } = getPointXY(data[i]);\n        if (Number.isFinite(x)) categoryXScratch.push(x);\n      }\n    }\n\n    if (categoryXScratch.length < 2) return 1;\n    categoryXScratch.sort((a, b) => a - b);\n\n    let minStep = Number.POSITIVE_INFINITY;\n    for (let i = 1; i < categoryXScratch.length; i++) {\n      const d = categoryXScratch[i] - categoryXScratch[i - 1];\n      if (d > 0 && d < minStep) minStep = d;\n    }\n    return Number.isFinite(minStep) && minStep > 0 ? minStep : 1;\n  };\n\n  const computeSharedBarLayout = (\n    seriesConfigs: ReadonlyArray<ResolvedBarSeriesConfig>\n  ): { readonly barWidth?: number | string; readonly barGap?: number; readonly barCategoryGap?: number } => {\n    let barWidth: number | string | undefined = undefined;\n    let barGap: number | undefined = undefined;\n    let barCategoryGap: number | undefined = undefined;\n\n    for (let i = 0; i < seriesConfigs.length; i++) {\n      const s = seriesConfigs[i];\n      if (barWidth === undefined && s.barWidth !== undefined) barWidth = s.barWidth;\n      if (barGap === undefined && s.barGap !== undefined) barGap = s.barGap;\n      if (barCategoryGap === undefined && s.barCategoryGap !== undefined) barCategoryGap = s.barCategoryGap;\n    }\n\n    return { barWidth, barGap, barCategoryGap };\n  };\n\n  const computeBaselineForBarsFromData = (seriesConfigs: ReadonlyArray<ResolvedBarSeriesConfig>): number => {\n    let yMin = Number.POSITIVE_INFINITY;\n    let yMax = Number.NEGATIVE_INFINITY;\n\n    for (let s = 0; s < seriesConfigs.length; s++) {\n      // TODO(step 2): normalize CartesianSeriesData to ReadonlyArray<DataPoint>\n      const data = seriesConfigs[s].data as ReadonlyArray<DataPoint>;\n      for (let i = 0; i < data.length; i++) {\n        const { y } = getPointXY(data[i]);\n        if (!Number.isFinite(y)) continue;\n        if (y < yMin) yMin = y;\n        if (y > yMax) yMax = y;\n      }\n    }\n\n    if (!Number.isFinite(yMin) || !Number.isFinite(yMax)) return 0;\n    if (yMin <= 0 && 0 <= yMax) return 0;\n    return Math.abs(yMin) < Math.abs(yMax) ? yMin : yMax;\n  };\n\n  const computeBaselineForBarsFromAxis = (\n    seriesConfigs: ReadonlyArray<ResolvedBarSeriesConfig>,\n    yScale: LinearScale,\n    plotClipRect: Readonly<{ top: number; bottom: number }>\n  ): number => {\n    // Determine the visible y-domain from the yScale + plot clip rect (clip-space).\n    const yDomainA = yScale.invert(plotClipRect.bottom);\n    const yDomainB = yScale.invert(plotClipRect.top);\n    const yMin = Math.min(yDomainA, yDomainB);\n    const yMax = Math.max(yDomainA, yDomainB);\n\n    // If scale/range is degenerate, fall back.\n    if (!Number.isFinite(yMin) || !Number.isFinite(yMax)) {\n      return computeBaselineForBarsFromData(seriesConfigs);\n    }\n\n    if (yMin <= 0 && 0 <= yMax) return 0;\n    if (yMin > 0) return yMin;\n    if (yMax < 0) return yMax;\n\n    // Should be unreachable with finite min/max, but keep a safe fallback.\n    return computeBaselineForBarsFromData(seriesConfigs);\n  };\n\n  const prepare: BarRenderer['prepare'] = (seriesConfigs, dataStore, xScale, yScale, gridArea) => {\n    assertNotDisposed();\n    void dataStore;\n\n    if (seriesConfigs.length === 0) {\n      instanceCount = 0;\n      return;\n    }\n\n    const plotSize = computePlotSizeCssPx(gridArea);\n    if (!plotSize) {\n      instanceCount = 0;\n      return;\n    }\n\n    const plotClipRect = computePlotClipRect(gridArea);\n    const plotClipWidth = plotClipRect.right - plotClipRect.left;\n    const plotClipHeight = plotClipRect.top - plotClipRect.bottom;\n    const clipPerCssX = plotSize.plotWidthCss > 0 ? plotClipWidth / plotSize.plotWidthCss : 0;\n    void plotClipHeight; // reserved for future y-size conversions (e.g. border radius)\n\n    // Cluster slots:\n    // - Each unique non-empty stackId gets a single cluster slot.\n    // - Each unstacked series gets its own cluster slot.\n    const stackIdToClusterIndex = new Map<string, number>();\n    const clusterIndexBySeries: number[] = new Array(seriesConfigs.length);\n    let clusterCount = 0;\n    for (let i = 0; i < seriesConfigs.length; i++) {\n      const stackId = normalizeStackId(seriesConfigs[i].stack);\n      if (stackId !== '') {\n        const existing = stackIdToClusterIndex.get(stackId);\n        if (existing !== undefined) {\n          clusterIndexBySeries[i] = existing;\n        } else {\n          const idx = clusterCount++;\n          stackIdToClusterIndex.set(stackId, idx);\n          clusterIndexBySeries[i] = idx;\n        }\n      } else {\n        clusterIndexBySeries[i] = clusterCount++;\n      }\n    }\n    clusterCount = Math.max(1, clusterCount);\n\n    const categoryStep = computeBarCategoryStep(seriesConfigs);\n    const layout = computeSharedBarLayout(seriesConfigs);\n    const barGap = clamp01(layout.barGap ?? DEFAULT_BAR_GAP);\n    const barCategoryGap = clamp01(layout.barCategoryGap ?? DEFAULT_BAR_CATEGORY_GAP);\n\n    let fallbackCategoryCount = 1;\n    for (let s = 0; s < seriesConfigs.length; s++) {\n      // TODO(step 2): normalize CartesianSeriesData to ReadonlyArray<DataPoint>\n      const dataLength = (seriesConfigs[s].data as ReadonlyArray<DataPoint>).length;\n      fallbackCategoryCount = Math.max(fallbackCategoryCount, Math.floor(dataLength));\n    }\n\n    const categoryWidthClip = computeCategoryWidthClip(xScale, categoryStep, plotClipRect, fallbackCategoryCount);\n    const categoryInnerWidthClip = Math.max(0, categoryWidthClip * (1 - barCategoryGap));\n\n    const denom = clusterCount + Math.max(0, clusterCount - 1) * barGap;\n    const maxBarWidthClip = denom > 0 ? categoryInnerWidthClip / denom : 0;\n\n    let barWidthClip = 0;\n    const rawBarWidth = layout.barWidth;\n    if (typeof rawBarWidth === 'number') {\n      barWidthClip = Math.max(0, rawBarWidth) * clipPerCssX;\n      barWidthClip = Math.min(barWidthClip, maxBarWidthClip);\n    } else if (typeof rawBarWidth === 'string') {\n      const p = parsePercent(rawBarWidth);\n      barWidthClip = p == null ? 0 : maxBarWidthClip * clamp01(p);\n    }\n\n    if (!(barWidthClip > 0)) {\n      // Auto-width: max per-bar width that still avoids overlap (given clusterCount and barGap).\n      barWidthClip = maxBarWidthClip;\n    }\n\n    const gapClip = barWidthClip * barGap;\n    const clusterWidthClip = clusterCount * barWidthClip + Math.max(0, clusterCount - 1) * gapClip;\n\n    let baselineDomain = computeBaselineForBarsFromAxis(seriesConfigs, yScale, plotClipRect);\n    let baselineClip = yScale.scale(baselineDomain);\n    if (!Number.isFinite(baselineClip)) {\n      // Fallback for pathological scales: revert to data-derived baseline, then 0.\n      const fallbackBaselineDomain = computeBaselineForBarsFromData(seriesConfigs);\n      baselineDomain = fallbackBaselineDomain;\n      baselineClip = yScale.scale(fallbackBaselineDomain);\n      if (!Number.isFinite(baselineClip)) {\n        baselineDomain = 0;\n        baselineClip = yScale.scale(0);\n      }\n      if (!Number.isFinite(baselineClip)) {\n        instanceCount = 0;\n        return;\n      }\n    }\n\n    let maxBars = 0;\n    for (let s = 0; s < seriesConfigs.length; s++) {\n      // TODO(step 2): normalize CartesianSeriesData to ReadonlyArray<DataPoint>\n      maxBars += Math.max(0, (seriesConfigs[s].data as ReadonlyArray<DataPoint>).length);\n    }\n\n    ensureCpuInstanceCapacityFloats(maxBars * INSTANCE_STRIDE_FLOATS);\n    const f32 = cpuInstanceStagingF32;\n    let outFloats = 0;\n\n    // Per-stack, per-x running sums in domain units (supports negative stacking too).\n    const stackSumsByStackId = new Map<string, Map<number, { posSum: number; negSum: number }>>();\n\n    for (let seriesIndex = 0; seriesIndex < seriesConfigs.length; seriesIndex++) {\n      const series = seriesConfigs[seriesIndex];\n      // TODO(step 2): normalize CartesianSeriesData to ReadonlyArray<DataPoint>\n      const data = series.data as ReadonlyArray<DataPoint>;\n      const [r, g, b, a] = parseSeriesColorToRgba01(series.color);\n      const stackId = normalizeStackId(series.stack);\n      const clusterIndex = clusterIndexBySeries[seriesIndex] ?? 0;\n\n      for (let i = 0; i < data.length; i++) {\n        const { x, y } = getPointXY(data[i]);\n        const xClipCenter = xScale.scale(x);\n        if (!Number.isFinite(xClipCenter) || !Number.isFinite(y)) continue;\n\n        const left = xClipCenter - clusterWidthClip / 2 + clusterIndex * (barWidthClip + gapClip);\n\n        let baseClip = baselineClip;\n        let height = 0;\n\n        if (stackId !== '') {\n          let sumsForX = stackSumsByStackId.get(stackId);\n          if (!sumsForX) {\n            sumsForX = new Map<number, { posSum: number; negSum: number }>();\n            stackSumsByStackId.set(stackId, sumsForX);\n          }\n\n          // NOTE: Never key stacks by raw `x` (float equality is fragile). Instead, compute a stable\n          // integer \"category\" key so visually-equivalent bars stack together even with tiny noise.\n          let xKey: number;\n          if (Number.isFinite(categoryWidthClip) && categoryWidthClip > 0 && Number.isFinite(xClipCenter)) {\n            xKey = Math.round((xClipCenter - plotClipRect.left) / categoryWidthClip);\n          } else if (Number.isFinite(categoryStep) && categoryStep > 0) {\n            xKey = Math.round(x / categoryStep);\n          } else {\n            // Last-resort: stable-ish quantization in domain space.\n            xKey = Math.round(x * 1e6);\n          }\n\n          let sums = sumsForX.get(xKey);\n          if (!sums) {\n            sums = { posSum: baselineDomain, negSum: baselineDomain };\n            sumsForX.set(xKey, sums);\n          }\n\n          // Stack upward for y>=0, downward for y<0 (domain units).\n          let baseDomain: number;\n          let topDomain: number;\n          if (y >= 0) {\n            baseDomain = sums.posSum;\n            topDomain = baseDomain + y;\n            sums.posSum = topDomain;\n          } else {\n            baseDomain = sums.negSum;\n            topDomain = baseDomain + y;\n            sums.negSum = topDomain;\n          }\n\n          const bClip = yScale.scale(baseDomain);\n          const tClip = yScale.scale(topDomain);\n          if (!Number.isFinite(bClip) || !Number.isFinite(tClip)) continue;\n          baseClip = bClip;\n          height = tClip - bClip;\n        } else {\n          const yClip = yScale.scale(y);\n          if (!Number.isFinite(yClip)) continue;\n          height = yClip - baselineClip;\n        }\n\n        f32[outFloats + 0] = left;\n        f32[outFloats + 1] = baseClip;\n        f32[outFloats + 2] = barWidthClip;\n        f32[outFloats + 3] = height;\n        f32[outFloats + 4] = r;\n        f32[outFloats + 5] = g;\n        f32[outFloats + 6] = b;\n        f32[outFloats + 7] = a;\n        outFloats += INSTANCE_STRIDE_FLOATS;\n      }\n    }\n\n    // If we skipped invalid points, resize the effective instance count.\n    instanceCount = outFloats / INSTANCE_STRIDE_FLOATS;\n    const requiredBytes = Math.max(4, instanceCount * INSTANCE_STRIDE_BYTES);\n\n    if (!instanceBuffer || instanceBuffer.size < requiredBytes) {\n      const grownBytes = Math.max(Math.max(4, nextPow2(requiredBytes)), instanceBuffer ? instanceBuffer.size : 0);\n      if (instanceBuffer) {\n        try {\n          instanceBuffer.destroy();\n        } catch {\n          // best-effort\n        }\n      }\n      instanceBuffer = device.createBuffer({\n        label: 'barRenderer/instanceBuffer',\n        size: grownBytes,\n        usage: GPUBufferUsage.VERTEX | GPUBufferUsage.COPY_DST,\n      });\n    }\n\n    if (instanceCount > 0) {\n      device.queue.writeBuffer(instanceBuffer, 0, cpuInstanceStagingBuffer, 0, instanceCount * INSTANCE_STRIDE_BYTES);\n    }\n  };\n\n  const render: BarRenderer['render'] = (passEncoder) => {\n    assertNotDisposed();\n    if (!instanceBuffer || instanceCount === 0) return;\n\n    passEncoder.setPipeline(pipeline);\n    passEncoder.setBindGroup(0, bindGroup);\n    passEncoder.setVertexBuffer(0, instanceBuffer);\n    passEncoder.draw(6, instanceCount);\n  };\n\n  const dispose: BarRenderer['dispose'] = () => {\n    if (disposed) return;\n    disposed = true;\n\n    if (instanceBuffer) {\n      try {\n        instanceBuffer.destroy();\n      } catch {\n        // best-effort\n      }\n    }\n    instanceBuffer = null;\n    instanceCount = 0;\n\n    try {\n      vsUniformBuffer.destroy();\n    } catch {\n      // best-effort\n    }\n  };\n\n  return { prepare, render, dispose };\n}\n\n","export default \"// scatter.wgsl\\n// Instanced anti-aliased circle shader (SDF):\\n// - Per-instance vertex input:\\n//   - center   = vec2<f32> point center (transformed by VSUniforms.transform)\\n//   - radiusPx = f32 circle radius in pixels\\n// - Draw call: draw(6, instanceCount) using triangle-list expansion in VS\\n// - Uniforms:\\n//   - @group(0) @binding(0): VSUniforms { transform, viewportPx }\\n//   - @group(0) @binding(1): FSUniforms { color }\\n//\\n// Notes:\\n// - `viewportPx` is the current render target size in pixels (width, height).\\n// - The quad is expanded in clip space using `radiusPx` and `viewportPx`.\\n\\nstruct VSUniforms {\\n  transform: mat4x4<f32>,\\n  viewportPx: vec2<f32>,\\n  // Pad to 16-byte alignment (mat4x4 is 64B; vec2 adds 8B; pad to 80B).\\n  _pad0: vec2<f32>,\\n};\\n\\n@group(0) @binding(0) var<uniform> vsUniforms: VSUniforms;\\n\\nstruct FSUniforms {\\n  color: vec4<f32>,\\n};\\n\\n@group(0) @binding(1) var<uniform> fsUniforms: FSUniforms;\\n\\nstruct VSIn {\\n  @location(0) center: vec2<f32>,\\n  @location(1) radiusPx: f32,\\n};\\n\\nstruct VSOut {\\n  @builtin(position) clipPosition: vec4<f32>,\\n  @location(0) localPx: vec2<f32>,\\n  @location(1) radiusPx: f32,\\n};\\n\\n@vertex\\nfn vsMain(in: VSIn, @builtin(vertex_index) vertexIndex: u32) -> VSOut {\\n  // Fixed local corners for 2 triangles (triangle-list).\\n  // `localNdc` is a quad in [-1, 1]^2; we convert it to pixel offsets via radiusPx.\\n  let localNdc = array<vec2<f32>, 6>(\\n    vec2<f32>(-1.0, -1.0),\\n    vec2<f32>( 1.0, -1.0),\\n    vec2<f32>(-1.0,  1.0),\\n    vec2<f32>(-1.0,  1.0),\\n    vec2<f32>( 1.0, -1.0),\\n    vec2<f32>( 1.0,  1.0)\\n  );\\n\\n  let corner = localNdc[vertexIndex];\\n  let localPx = corner * in.radiusPx;\\n\\n  // Convert pixel offset to clip-space offset.\\n  // Clip space spans [-1, 1] across the viewport, so px -> clip is (2 / viewportPx).\\n  let localClip = localPx * (2.0 / vsUniforms.viewportPx);\\n\\n  let centerClip = (vsUniforms.transform * vec4<f32>(in.center, 0.0, 1.0)).xy;\\n\\n  var out: VSOut;\\n  out.clipPosition = vec4<f32>(centerClip + localClip, 0.0, 1.0);\\n  out.localPx = localPx;\\n  out.radiusPx = in.radiusPx;\\n  return out;\\n}\\n\\n@fragment\\nfn fsMain(in: VSOut) -> @location(0) vec4<f32> {\\n  // Signed distance to the circle boundary (negative inside).\\n  let dist = length(in.localPx) - in.radiusPx;\\n\\n  // Analytic-ish AA: smooth edge based on derivative of dist in screen space.\\n  let w = fwidth(dist);\\n  let a = 1.0 - smoothstep(0.0, w, dist);\\n\\n  // Discard fully outside to avoid unnecessary blending work.\\n  if (a <= 0.0) {\\n    discard;\\n  }\\n\\n  return vec4<f32>(fsUniforms.color.rgb, fsUniforms.color.a * a);\\n}\\n\\n\"","import scatterWgsl from '../shaders/scatter.wgsl?raw';\nimport type { ResolvedScatterSeriesConfig } from '../config/OptionResolver';\nimport type { DataPoint, DataPointTuple, ScatterPointTuple } from '../config/types';\nimport type { LinearScale } from '../utils/scales';\nimport { parseCssColorToRgba01 } from '../utils/colors';\nimport type { GridArea } from './createGridRenderer';\nimport { createRenderPipeline, createUniformBuffer, writeUniformBuffer } from './rendererUtils';\n\nexport interface ScatterRenderer {\n  prepare(\n    seriesConfig: ResolvedScatterSeriesConfig,\n    // TODO(step 2): This will accept normalized ReadonlyArray<DataPoint>\n    data: ReadonlyArray<DataPoint>,\n    xScale: LinearScale,\n    yScale: LinearScale,\n    gridArea?: GridArea\n  ): void;\n  render(passEncoder: GPURenderPassEncoder): void;\n  dispose(): void;\n}\n\nexport interface ScatterRendererOptions {\n  /**\n   * Must match the canvas context format used for the render pass color attachment.\n   * Usually this is `gpuContext.preferredFormat`.\n   *\n   * Defaults to `'bgra8unorm'` for backward compatibility.\n   */\n  readonly targetFormat?: GPUTextureFormat;\n}\n\ntype Rgba = readonly [r: number, g: number, b: number, a: number];\n\nconst DEFAULT_TARGET_FORMAT: GPUTextureFormat = 'bgra8unorm';\nconst DEFAULT_SCATTER_RADIUS_CSS_PX = 4;\nconst INSTANCE_STRIDE_BYTES = 16; // center.xy, radiusPx, pad\nconst INSTANCE_STRIDE_FLOATS = INSTANCE_STRIDE_BYTES / 4;\n\nconst clamp01 = (v: number): number => Math.min(1, Math.max(0, v));\nconst clampInt = (v: number, lo: number, hi: number): number => Math.min(hi, Math.max(lo, v | 0));\n\nconst parseSeriesColorToRgba01 = (color: string): Rgba =>\n  parseCssColorToRgba01(color) ?? ([0, 0, 0, 1] as const);\n\nconst nextPow2 = (v: number): number => {\n  if (!Number.isFinite(v) || v <= 0) return 1;\n  const n = Math.ceil(v);\n  return 2 ** Math.ceil(Math.log2(n));\n};\n\nconst isTupleDataPoint = (point: DataPoint): point is DataPointTuple => Array.isArray(point);\n\nconst getPointXY = (point: DataPoint): { readonly x: number; readonly y: number } => {\n  if (isTupleDataPoint(point)) return { x: point[0], y: point[1] };\n  return { x: point.x, y: point.y };\n};\n\nconst getPointSizeCssPx = (point: DataPoint): number | null => {\n  if (isTupleDataPoint(point)) {\n    const s = point[2];\n    return typeof s === 'number' && Number.isFinite(s) ? s : null;\n  }\n  const s = point.size;\n  return typeof s === 'number' && Number.isFinite(s) ? s : null;\n};\n\nconst toScatterTuple = (point: DataPoint): ScatterPointTuple => {\n  if (isTupleDataPoint(point)) return point;\n  return [point.x, point.y, point.size] as const;\n};\n\nconst computeDataBounds = (\n  data: ReadonlyArray<DataPoint>\n): { readonly xMin: number; readonly xMax: number; readonly yMin: number; readonly yMax: number } => {\n  let xMin = Number.POSITIVE_INFINITY;\n  let xMax = Number.NEGATIVE_INFINITY;\n  let yMin = Number.POSITIVE_INFINITY;\n  let yMax = Number.NEGATIVE_INFINITY;\n\n  for (let i = 0; i < data.length; i++) {\n    const { x, y } = getPointXY(data[i]);\n    if (!Number.isFinite(x) || !Number.isFinite(y)) continue;\n    if (x < xMin) xMin = x;\n    if (x > xMax) xMax = x;\n    if (y < yMin) yMin = y;\n    if (y > yMax) yMax = y;\n  }\n\n  if (!Number.isFinite(xMin) || !Number.isFinite(xMax) || !Number.isFinite(yMin) || !Number.isFinite(yMax)) {\n    return { xMin: 0, xMax: 1, yMin: 0, yMax: 1 };\n  }\n\n  // Avoid degenerate domains for affine derivation (handled later too, but keep stable samples).\n  if (xMin === xMax) xMax = xMin + 1;\n  if (yMin === yMax) yMax = yMin + 1;\n\n  return { xMin, xMax, yMin, yMax };\n};\n\nconst computeClipAffineFromScale = (\n  scale: LinearScale,\n  v0: number,\n  v1: number\n): { readonly a: number; readonly b: number } => {\n  const p0 = scale.scale(v0);\n  const p1 = scale.scale(v1);\n\n  // If the domain sample is degenerate or non-finite, fall back to constant output.\n  if (!Number.isFinite(v0) || !Number.isFinite(v1) || v0 === v1 || !Number.isFinite(p0) || !Number.isFinite(p1)) {\n    return { a: 0, b: Number.isFinite(p0) ? p0 : 0 };\n  }\n\n  const a = (p1 - p0) / (v1 - v0);\n  const b = p0 - a * v0;\n  return { a: Number.isFinite(a) ? a : 0, b: Number.isFinite(b) ? b : 0 };\n};\n\nconst writeTransformMat4F32 = (out: Float32Array, ax: number, bx: number, ay: number, by: number): void => {\n  // Column-major mat4x4 for: clip = M * vec4(x, y, 0, 1)\n  out[0] = ax;\n  out[1] = 0;\n  out[2] = 0;\n  out[3] = 0; // col0\n  out[4] = 0;\n  out[5] = ay;\n  out[6] = 0;\n  out[7] = 0; // col1\n  out[8] = 0;\n  out[9] = 0;\n  out[10] = 1;\n  out[11] = 0; // col2\n  out[12] = bx;\n  out[13] = by;\n  out[14] = 0;\n  out[15] = 1; // col3\n};\n\nconst computePlotScissorDevicePx = (\n  gridArea: GridArea\n): { readonly x: number; readonly y: number; readonly w: number; readonly h: number } => {\n  const { canvasWidth, canvasHeight, devicePixelRatio } = gridArea;\n\n  const plotLeftDevice = gridArea.left * devicePixelRatio;\n  const plotRightDevice = canvasWidth - gridArea.right * devicePixelRatio;\n  const plotTopDevice = gridArea.top * devicePixelRatio;\n  const plotBottomDevice = canvasHeight - gridArea.bottom * devicePixelRatio;\n\n  const scissorX = clampInt(Math.floor(plotLeftDevice), 0, Math.max(0, canvasWidth));\n  const scissorY = clampInt(Math.floor(plotTopDevice), 0, Math.max(0, canvasHeight));\n  const scissorR = clampInt(Math.ceil(plotRightDevice), 0, Math.max(0, canvasWidth));\n  const scissorB = clampInt(Math.ceil(plotBottomDevice), 0, Math.max(0, canvasHeight));\n  const scissorW = Math.max(0, scissorR - scissorX);\n  const scissorH = Math.max(0, scissorB - scissorY);\n\n  return { x: scissorX, y: scissorY, w: scissorW, h: scissorH };\n};\n\nexport function createScatterRenderer(device: GPUDevice, options?: ScatterRendererOptions): ScatterRenderer {\n  let disposed = false;\n  const targetFormat = options?.targetFormat ?? DEFAULT_TARGET_FORMAT;\n\n  const bindGroupLayout = device.createBindGroupLayout({\n    entries: [\n      { binding: 0, visibility: GPUShaderStage.VERTEX, buffer: { type: 'uniform' } },\n      { binding: 1, visibility: GPUShaderStage.FRAGMENT, buffer: { type: 'uniform' } },\n    ],\n  });\n\n  // VSUniforms: mat4x4 (64) + viewportPx vec2 (8) + pad vec2 (8) = 80 bytes.\n  const vsUniformBuffer = createUniformBuffer(device, 80, { label: 'scatterRenderer/vsUniforms' });\n  const fsUniformBuffer = createUniformBuffer(device, 16, { label: 'scatterRenderer/fsUniforms' });\n\n  // Reused CPU-side staging for uniform writes (avoid per-frame allocations).\n  const vsUniformScratchBuffer = new ArrayBuffer(80);\n  const vsUniformScratchF32 = new Float32Array(vsUniformScratchBuffer);\n  const fsUniformScratchF32 = new Float32Array(4);\n\n  const bindGroup = device.createBindGroup({\n    layout: bindGroupLayout,\n    entries: [\n      { binding: 0, resource: { buffer: vsUniformBuffer } },\n      { binding: 1, resource: { buffer: fsUniformBuffer } },\n    ],\n  });\n\n  const pipeline = createRenderPipeline(device, {\n    label: 'scatterRenderer/pipeline',\n    bindGroupLayouts: [bindGroupLayout],\n    vertex: {\n      code: scatterWgsl,\n      label: 'scatter.wgsl',\n      buffers: [\n        {\n          arrayStride: INSTANCE_STRIDE_BYTES,\n          stepMode: 'instance',\n          attributes: [\n            { shaderLocation: 0, format: 'float32x2', offset: 0 },\n            { shaderLocation: 1, format: 'float32', offset: 8 },\n          ],\n        },\n      ],\n    },\n    fragment: {\n      code: scatterWgsl,\n      label: 'scatter.wgsl',\n      formats: targetFormat,\n      // Standard alpha blending (circle AA uses alpha, and series color may be translucent).\n      blend: {\n        color: { operation: 'add', srcFactor: 'src-alpha', dstFactor: 'one-minus-src-alpha' },\n        alpha: { operation: 'add', srcFactor: 'one', dstFactor: 'one-minus-src-alpha' },\n      },\n    },\n    primitive: { topology: 'triangle-list', cullMode: 'none' },\n    multisample: { count: 1 },\n  });\n\n  let instanceBuffer: GPUBuffer | null = null;\n  let instanceCount = 0;\n  let cpuInstanceStagingBuffer = new ArrayBuffer(0);\n  let cpuInstanceStagingF32 = new Float32Array(cpuInstanceStagingBuffer);\n\n  let lastCanvasWidth = 0;\n  let lastCanvasHeight = 0;\n  let lastViewportPx: readonly [number, number] = [1, 1];\n  let lastScissor: { readonly x: number; readonly y: number; readonly w: number; readonly h: number } | null = null;\n\n  const assertNotDisposed = (): void => {\n    if (disposed) throw new Error('ScatterRenderer is disposed.');\n  };\n\n  const ensureCpuInstanceCapacityFloats = (requiredFloats: number): void => {\n    if (requiredFloats <= cpuInstanceStagingF32.length) return;\n    const nextFloats = Math.max(8, nextPow2(requiredFloats));\n    cpuInstanceStagingBuffer = new ArrayBuffer(nextFloats * 4);\n    cpuInstanceStagingF32 = new Float32Array(cpuInstanceStagingBuffer);\n  };\n\n  const writeVsUniforms = (\n    ax: number,\n    bx: number,\n    ay: number,\n    by: number,\n    viewportW: number,\n    viewportH: number\n  ): void => {\n    const w = Number.isFinite(viewportW) && viewportW > 0 ? viewportW : 1;\n    const h = Number.isFinite(viewportH) && viewportH > 0 ? viewportH : 1;\n\n    writeTransformMat4F32(vsUniformScratchF32, ax, bx, ay, by);\n    vsUniformScratchF32[16] = w;\n    vsUniformScratchF32[17] = h;\n    vsUniformScratchF32[18] = 0;\n    vsUniformScratchF32[19] = 0;\n    writeUniformBuffer(device, vsUniformBuffer, vsUniformScratchBuffer);\n\n    lastViewportPx = [w, h];\n  };\n\n  const prepare: ScatterRenderer['prepare'] = (seriesConfig, data, xScale, yScale, gridArea) => {\n    assertNotDisposed();\n\n    const { xMin, xMax, yMin, yMax } = computeDataBounds(data);\n    const { a: ax, b: bx } = computeClipAffineFromScale(xScale, xMin, xMax);\n    const { a: ay, b: by } = computeClipAffineFromScale(yScale, yMin, yMax);\n\n    if (gridArea) {\n      lastCanvasWidth = gridArea.canvasWidth;\n      lastCanvasHeight = gridArea.canvasHeight;\n      writeVsUniforms(ax, bx, ay, by, gridArea.canvasWidth, gridArea.canvasHeight);\n      lastScissor = computePlotScissorDevicePx(gridArea);\n    } else {\n      // Backward-compatible: keep rendering with the last known viewport (or safe default).\n      writeVsUniforms(ax, bx, ay, by, lastViewportPx[0], lastViewportPx[1]);\n      lastScissor = null;\n    }\n\n    const [r, g, b, a] = parseSeriesColorToRgba01(seriesConfig.color);\n    fsUniformScratchF32[0] = r;\n    fsUniformScratchF32[1] = g;\n    fsUniformScratchF32[2] = b;\n    fsUniformScratchF32[3] = clamp01(a);\n    writeUniformBuffer(device, fsUniformBuffer, fsUniformScratchF32);\n\n    const dpr = gridArea?.devicePixelRatio ?? 1;\n    const hasValidDpr = dpr > 0 && Number.isFinite(dpr);\n\n    const seriesSymbolSize = seriesConfig.symbolSize;\n    const getSeriesSizeCssPx =\n      typeof seriesSymbolSize === 'function'\n        ? (point: DataPoint): number => {\n            const v = seriesSymbolSize(toScatterTuple(point));\n            return typeof v === 'number' && Number.isFinite(v) ? v : DEFAULT_SCATTER_RADIUS_CSS_PX;\n          }\n        : typeof seriesSymbolSize === 'number' && Number.isFinite(seriesSymbolSize)\n          ? (): number => seriesSymbolSize\n          : (): number => DEFAULT_SCATTER_RADIUS_CSS_PX;\n\n    ensureCpuInstanceCapacityFloats(data.length * INSTANCE_STRIDE_FLOATS);\n    const f32 = cpuInstanceStagingF32;\n    let outFloats = 0;\n\n    for (let i = 0; i < data.length; i++) {\n      const p = data[i];\n      const { x, y } = getPointXY(p);\n      if (!Number.isFinite(x) || !Number.isFinite(y)) continue;\n\n      const sizeCss = getPointSizeCssPx(p) ?? getSeriesSizeCssPx(p);\n      const radiusCss = Number.isFinite(sizeCss) ? Math.max(0, sizeCss) : DEFAULT_SCATTER_RADIUS_CSS_PX;\n      const radiusDevicePx = hasValidDpr ? radiusCss * dpr : radiusCss;\n      if (!(radiusDevicePx > 0)) continue;\n\n      f32[outFloats + 0] = x;\n      f32[outFloats + 1] = y;\n      f32[outFloats + 2] = radiusDevicePx;\n      f32[outFloats + 3] = 0; // pad\n      outFloats += INSTANCE_STRIDE_FLOATS;\n    }\n\n    instanceCount = outFloats / INSTANCE_STRIDE_FLOATS;\n    const requiredBytes = Math.max(4, instanceCount * INSTANCE_STRIDE_BYTES);\n\n    if (!instanceBuffer || instanceBuffer.size < requiredBytes) {\n      const grownBytes = Math.max(Math.max(4, nextPow2(requiredBytes)), instanceBuffer ? instanceBuffer.size : 0);\n      if (instanceBuffer) {\n        try {\n          instanceBuffer.destroy();\n        } catch {\n          // best-effort\n        }\n      }\n      instanceBuffer = device.createBuffer({\n        label: 'scatterRenderer/instanceBuffer',\n        size: grownBytes,\n        usage: GPUBufferUsage.VERTEX | GPUBufferUsage.COPY_DST,\n      });\n    }\n\n    if (instanceBuffer && instanceCount > 0) {\n      device.queue.writeBuffer(instanceBuffer, 0, cpuInstanceStagingBuffer, 0, instanceCount * INSTANCE_STRIDE_BYTES);\n    }\n  };\n\n  const render: ScatterRenderer['render'] = (passEncoder) => {\n    assertNotDisposed();\n    if (!instanceBuffer || instanceCount === 0) return;\n\n    // Clip to plot area when available.\n    if (lastScissor && lastCanvasWidth > 0 && lastCanvasHeight > 0) {\n      passEncoder.setScissorRect(lastScissor.x, lastScissor.y, lastScissor.w, lastScissor.h);\n    }\n\n    passEncoder.setPipeline(pipeline);\n    passEncoder.setBindGroup(0, bindGroup);\n    passEncoder.setVertexBuffer(0, instanceBuffer);\n    passEncoder.draw(6, instanceCount);\n\n    // Reset scissor to full canvas to avoid impacting later renderers.\n    if (lastScissor && lastCanvasWidth > 0 && lastCanvasHeight > 0) {\n      passEncoder.setScissorRect(0, 0, lastCanvasWidth, lastCanvasHeight);\n    }\n  };\n\n  const dispose: ScatterRenderer['dispose'] = () => {\n    if (disposed) return;\n    disposed = true;\n\n    if (instanceBuffer) {\n      try {\n        instanceBuffer.destroy();\n      } catch {\n        // best-effort\n      }\n    }\n    instanceBuffer = null;\n    instanceCount = 0;\n\n    try {\n      vsUniformBuffer.destroy();\n    } catch {\n      // best-effort\n    }\n    try {\n      fsUniformBuffer.destroy();\n    } catch {\n      // best-effort\n    }\n\n    lastCanvasWidth = 0;\n    lastCanvasHeight = 0;\n    lastViewportPx = [1, 1];\n    lastScissor = null;\n  };\n\n  return { prepare, render, dispose };\n}\n\n","export default \"struct ComputeUniforms {\\n  transform: mat4x4<f32>,\\n  viewportPx: vec2f,\\n  _pad0: vec2f,\\n  plotOriginPx: vec2<u32>,\\n  plotSizePx: vec2<u32>,\\n  binSizePx: u32,\\n  binCountX: u32,\\n  binCountY: u32,\\n  visibleStart: u32,\\n  visibleEnd: u32,\\n  normalization: u32,\\n  _pad1: vec2<u32>,\\n};\\n\\n@group(0) @binding(0) var<uniform> u: ComputeUniforms;\\n@group(0) @binding(1) var<storage, read> points: array<vec2f>;\\n@group(0) @binding(2) var<storage, read_write> bins: array<atomic<u32>>;\\n\\nstruct MaxBuffer {\\n  value: atomic<u32>,\\n};\\n@group(0) @binding(3) var<storage, read_write> maxBuf: MaxBuffer;\\n\\nfn clipToDevicePx(clip: vec2f) -> vec2f {\\n  // clip in [-1,1] -> device pixel in [0, viewport]\\n  return vec2f(\\n    (clip.x * 0.5 + 0.5) * u.viewportPx.x,\\n    (-clip.y * 0.5 + 0.5) * u.viewportPx.y\\n  );\\n}\\n\\n@compute @workgroup_size(256)\\nfn binPoints(@builtin(global_invocation_id) gid: vec3<u32>) {\\n  let idx = u.visibleStart + gid.x;\\n  if (idx >= u.visibleEnd) {\\n    return;\\n  }\\n\\n  let p = points[idx];\\n  let clip4 = u.transform * vec4f(p.x, p.y, 0.0, 1.0);\\n  let clip = clip4.xy / max(1e-9, clip4.w);\\n  let px = clipToDevicePx(clip);\\n\\n  // Scissor bounds in device px\\n  let left = f32(u.plotOriginPx.x);\\n  let top = f32(u.plotOriginPx.y);\\n  let right = left + f32(u.plotSizePx.x);\\n  let bottom = top + f32(u.plotSizePx.y);\\n\\n  if (px.x < left || px.x >= right || px.y < top || px.y >= bottom) {\\n    return;\\n  }\\n\\n  let localX = u32((px.x - left) / f32(u.binSizePx));\\n  let localY = u32((px.y - top) / f32(u.binSizePx));\\n  if (localX >= u.binCountX || localY >= u.binCountY) {\\n    return;\\n  }\\n\\n  let binIndex = localY * u.binCountX + localX;\\n  atomicAdd(&bins[binIndex], 1u);\\n}\\n\\n@compute @workgroup_size(256)\\nfn reduceMax(@builtin(global_invocation_id) gid: vec3<u32>) {\\n  let binTotal = u.binCountX * u.binCountY;\\n  let i = gid.x;\\n  if (i >= binTotal) {\\n    return;\\n  }\\n\\n  let v = atomicLoad(&bins[i]);\\n  atomicMax(&maxBuf.value, v);\\n}\\n\\n\"","export default \"struct RenderUniforms {\\n  plotOriginPx: vec2<u32>,\\n  plotSizePx: vec2<u32>,\\n  binSizePx: u32,\\n  binCountX: u32,\\n  binCountY: u32,\\n  normalization: u32,\\n  _pad: vec2<u32>,\\n};\\n\\n@group(0) @binding(0) var<uniform> u: RenderUniforms;\\n@group(0) @binding(1) var<storage, read> bins: array<u32>;\\n@group(0) @binding(2) var<storage, read> maxBuf: array<u32>;\\n@group(0) @binding(3) var lutTex: texture_2d<f32>;\\n\\nstruct VsOut {\\n  @builtin(position) position: vec4f,\\n};\\n\\n@vertex\\nfn vsMain(@builtin(vertex_index) vid: u32) -> VsOut {\\n  // Fullscreen triangle (covers clip space).\\n  // (0,0)->(-1,-1), (2,0)->(3,-1), (0,2)->(-1,3)\\n  var pos = array<vec2f, 3>(\\n    vec2f(-1.0, -1.0),\\n    vec2f(3.0, -1.0),\\n    vec2f(-1.0, 3.0)\\n  );\\n  var out: VsOut;\\n  out.position = vec4f(pos[vid], 0.0, 1.0);\\n  return out;\\n}\\n\\nfn applyNormalization(count: f32, maxCount: f32, mode: u32) -> f32 {\\n  if (maxCount <= 0.0) {\\n    return 0.0;\\n  }\\n  let t = clamp(count / maxCount, 0.0, 1.0);\\n  if (mode == 1u) { // sqrt\\n    return sqrt(t);\\n  }\\n  if (mode == 2u) { // log\\n    // log1p(count) / log1p(max)\\n    return clamp(log(1.0 + count) / max(1e-9, log(1.0 + maxCount)), 0.0, 1.0);\\n  }\\n  return t; // linear\\n}\\n\\n@fragment\\nfn fsMain(@builtin(position) pos: vec4f) -> @location(0) vec4f {\\n  // pos.xy is framebuffer pixel coords (device px) with origin top-left.\\n  let x = pos.x;\\n  let y = pos.y;\\n\\n  let left = f32(u.plotOriginPx.x);\\n  let top = f32(u.plotOriginPx.y);\\n  // plot scissor also applied on CPU; keep a guard anyway.\\n  if (x < left || y < top) {\\n    return vec4f(0.0);\\n  }\\n\\n  let localX = u32((x - left) / f32(u.binSizePx));\\n  let localY = u32((y - top) / f32(u.binSizePx));\\n  if (localX >= u.binCountX || localY >= u.binCountY) {\\n    return vec4f(0.0);\\n  }\\n\\n  let idx = localY * u.binCountX + localX;\\n  let c = f32(bins[idx]);\\n  let maxC = f32(maxBuf[0]);\\n\\n  let t = applyNormalization(c, maxC, u.normalization);\\n  let lutX = i32(round(t * 255.0));\\n  let lut = textureLoad(lutTex, vec2<i32>(lutX, 0), 0);\\n  return vec4f(lut.rgb, 1.0);\\n}\\n\\n\"","import scatterDensityBinningWgsl from '../shaders/scatterDensityBinning.wgsl?raw';\nimport scatterDensityColormapWgsl from '../shaders/scatterDensityColormap.wgsl?raw';\nimport type { RawBounds, ResolvedScatterSeriesConfig } from '../config/OptionResolver';\nimport type { LinearScale } from '../utils/scales';\nimport { parseCssColorToRgba01 } from '../utils/colors';\nimport type { GridArea } from './createGridRenderer';\nimport { createRenderPipeline, createShaderModule, createUniformBuffer, writeUniformBuffer } from './rendererUtils';\n\nexport interface ScatterDensityRenderer {\n  prepare(\n    seriesConfig: ResolvedScatterSeriesConfig,\n    pointBuffer: GPUBuffer,\n    pointCount: number,\n    visibleStartIndex: number,\n    visibleEndIndex: number,\n    xScale: LinearScale,\n    yScale: LinearScale,\n    gridArea: GridArea,\n    rawBounds?: RawBounds\n  ): void;\n  encodeCompute(encoder: GPUCommandEncoder): void;\n  render(passEncoder: GPURenderPassEncoder): void;\n  dispose(): void;\n}\n\nexport interface ScatterDensityRendererOptions {\n  readonly targetFormat?: GPUTextureFormat;\n}\n\nconst DEFAULT_TARGET_FORMAT: GPUTextureFormat = 'bgra8unorm';\n\nconst clamp01 = (v: number): number => Math.min(1, Math.max(0, v));\nconst clampInt = (v: number, lo: number, hi: number): number => Math.min(hi, Math.max(lo, v | 0));\n\nconst nextPow2 = (v: number): number => {\n  if (!Number.isFinite(v) || v <= 0) return 1;\n  const n = Math.ceil(v);\n  return 2 ** Math.ceil(Math.log2(n));\n};\n\nconst computeClipAffineFromScale = (\n  scale: LinearScale,\n  v0: number,\n  v1: number\n): { readonly a: number; readonly b: number } => {\n  const p0 = scale.scale(v0);\n  const p1 = scale.scale(v1);\n\n  if (!Number.isFinite(v0) || !Number.isFinite(v1) || v0 === v1 || !Number.isFinite(p0) || !Number.isFinite(p1)) {\n    return { a: 0, b: Number.isFinite(p0) ? p0 : 0 };\n  }\n\n  const a = (p1 - p0) / (v1 - v0);\n  const b = p0 - a * v0;\n  return { a: Number.isFinite(a) ? a : 0, b: Number.isFinite(b) ? b : 0 };\n};\n\nconst writeTransformMat4F32 = (out: Float32Array, ax: number, bx: number, ay: number, by: number): void => {\n  // Column-major mat4x4 for: clip = M * vec4(x, y, 0, 1)\n  out[0] = ax;\n  out[1] = 0;\n  out[2] = 0;\n  out[3] = 0;\n  out[4] = 0;\n  out[5] = ay;\n  out[6] = 0;\n  out[7] = 0;\n  out[8] = 0;\n  out[9] = 0;\n  out[10] = 1;\n  out[11] = 0;\n  out[12] = bx;\n  out[13] = by;\n  out[14] = 0;\n  out[15] = 1;\n};\n\nconst computePlotScissorDevicePx = (\n  gridArea: GridArea\n): { readonly x: number; readonly y: number; readonly w: number; readonly h: number } => {\n  const { canvasWidth, canvasHeight, devicePixelRatio } = gridArea;\n\n  const plotLeftDevice = gridArea.left * devicePixelRatio;\n  const plotRightDevice = canvasWidth - gridArea.right * devicePixelRatio;\n  const plotTopDevice = gridArea.top * devicePixelRatio;\n  const plotBottomDevice = canvasHeight - gridArea.bottom * devicePixelRatio;\n\n  const scissorX = clampInt(Math.floor(plotLeftDevice), 0, Math.max(0, canvasWidth));\n  const scissorY = clampInt(Math.floor(plotTopDevice), 0, Math.max(0, canvasHeight));\n  const scissorR = clampInt(Math.ceil(plotRightDevice), 0, Math.max(0, canvasWidth));\n  const scissorB = clampInt(Math.ceil(plotBottomDevice), 0, Math.max(0, canvasHeight));\n  const scissorW = Math.max(0, scissorR - scissorX);\n  const scissorH = Math.max(0, scissorB - scissorY);\n\n  return { x: scissorX, y: scissorY, w: scissorW, h: scissorH };\n};\n\ntype Rgba01 = readonly [r: number, g: number, b: number, a: number];\n\nconst lerp = (a: number, b: number, t: number): number => a + (b - a) * t;\nconst lerpRgba = (a: Rgba01, b: Rgba01, t: number): Rgba01 =>\n  [lerp(a[0], b[0], t), lerp(a[1], b[1], t), lerp(a[2], b[2], t), lerp(a[3], b[3], t)] as const;\n\nconst parseColorStop = (css: string): Rgba01 => parseCssColorToRgba01(css) ?? ([0, 0, 0, 1] as const);\n\nconst getNamedStops = (name: 'viridis' | 'plasma' | 'inferno'): readonly string[] => {\n  // Compact stop lists (interpolated to 256 entries). These are standard-ish anchors.\n  if (name === 'plasma') {\n    return ['#0d0887', '#6a00a8', '#b12a90', '#e16462', '#fca636', '#f0f921'] as const;\n  }\n  if (name === 'inferno') {\n    return ['#000004', '#420a68', '#932667', '#dd513a', '#fca50a', '#fcffa4'] as const;\n  }\n  // viridis\n  return ['#440154', '#3b528b', '#21918c', '#5ec962', '#fde725'] as const;\n};\n\nconst buildLutRGBA8 = (colormap: ResolvedScatterSeriesConfig['densityColormap']): Uint8Array<ArrayBuffer> => {\n  const stopsCss =\n    typeof colormap === 'string'\n      ? getNamedStops(colormap)\n      : Array.isArray(colormap) && colormap.length > 0\n        ? colormap\n        : (getNamedStops('viridis') as readonly string[]);\n\n  const stops = stopsCss.map(parseColorStop);\n  const n = Math.max(2, stops.length);\n\n  // Ensure the underlying buffer is a plain ArrayBuffer (not SharedArrayBuffer) for WebGPU typings.\n  const out: Uint8Array<ArrayBuffer> = new Uint8Array(new ArrayBuffer(256 * 4));\n  for (let i = 0; i < 256; i++) {\n    const t = i / 255;\n    const x = t * (n - 1);\n    const seg = Math.min(n - 2, Math.max(0, Math.floor(x)));\n    const localT = x - seg;\n    const c = lerpRgba(stops[seg]!, stops[seg + 1]!, localT);\n\n    out[i * 4 + 0] = clampInt(Math.round(clamp01(c[0]) * 255), 0, 255);\n    out[i * 4 + 1] = clampInt(Math.round(clamp01(c[1]) * 255), 0, 255);\n    out[i * 4 + 2] = clampInt(Math.round(clamp01(c[2]) * 255), 0, 255);\n    out[i * 4 + 3] = clampInt(Math.round(clamp01(c[3]) * 255), 0, 255);\n  }\n  return out;\n};\n\nconst colormapKey = (colormap: ResolvedScatterSeriesConfig['densityColormap']): string => {\n  if (typeof colormap === 'string') return colormap;\n  try {\n    return JSON.stringify(colormap);\n  } catch {\n    return 'custom';\n  }\n};\n\nconst normalizationToU32 = (n: ResolvedScatterSeriesConfig['densityNormalization']): number => {\n  // Must match shader:\n  // 0: linear, 1: sqrt, 2: log\n  if (n === 'sqrt') return 1;\n  if (n === 'log') return 2;\n  return 0;\n};\n\nexport function createScatterDensityRenderer(\n  device: GPUDevice,\n  options?: ScatterDensityRendererOptions\n): ScatterDensityRenderer {\n  let disposed = false;\n  const targetFormat = options?.targetFormat ?? DEFAULT_TARGET_FORMAT;\n\n  const computeBindGroupLayout = device.createBindGroupLayout({\n    entries: [\n      { binding: 0, visibility: GPUShaderStage.COMPUTE, buffer: { type: 'uniform' } },\n      { binding: 1, visibility: GPUShaderStage.COMPUTE, buffer: { type: 'read-only-storage' } },\n      { binding: 2, visibility: GPUShaderStage.COMPUTE, buffer: { type: 'storage' } },\n      { binding: 3, visibility: GPUShaderStage.COMPUTE, buffer: { type: 'storage' } },\n    ],\n  });\n\n  const renderBindGroupLayout = device.createBindGroupLayout({\n    entries: [\n      { binding: 0, visibility: GPUShaderStage.FRAGMENT, buffer: { type: 'uniform' } },\n      // `scatterDensityColormap.wgsl` declares these as `var<storage, read>`, so they must be read-only-storage.\n      { binding: 1, visibility: GPUShaderStage.FRAGMENT, buffer: { type: 'read-only-storage' } },\n      { binding: 2, visibility: GPUShaderStage.FRAGMENT, buffer: { type: 'read-only-storage' } },\n      { binding: 3, visibility: GPUShaderStage.FRAGMENT, texture: { sampleType: 'unfilterable-float' } },\n    ],\n  });\n\n  // Compute uniforms:\n  // transform(64) + viewportPx(8)+pad(8)=80\n  // plotOriginPx u32x2(8) + plotSizePx u32x2(8) = 16 => 96\n  // binSize/binCountX/binCountY/start/end/norm u32*6 (24) + pad u32x2 (8) => 128\n  const computeUniformBuffer = createUniformBuffer(device, 128, { label: 'scatterDensity/computeUniforms' });\n  const computeUniformScratch = new ArrayBuffer(128);\n  const computeUniformF32 = new Float32Array(computeUniformScratch, 0, 20); // first 80 bytes (20 f32)\n  const computeUniformU32 = new Uint32Array(computeUniformScratch);\n\n  // Render uniforms: plotOriginPx(8)+plotSizePx(8)=16; u32*4 (16) + padding to 48.\n  const renderUniformBuffer = createUniformBuffer(device, 48, { label: 'scatterDensity/renderUniforms' });\n  const renderUniformScratch = new ArrayBuffer(48);\n  const renderUniformU32 = new Uint32Array(renderUniformScratch);\n\n  const binningModule = createShaderModule(device, scatterDensityBinningWgsl, 'scatterDensityBinning.wgsl');\n  const binPointsPipeline = device.createComputePipeline({\n    label: 'scatterDensity/binPointsPipeline',\n    layout: device.createPipelineLayout({ bindGroupLayouts: [computeBindGroupLayout] }),\n    compute: { module: binningModule, entryPoint: 'binPoints' },\n  });\n  const reduceMaxPipeline = device.createComputePipeline({\n    label: 'scatterDensity/reduceMaxPipeline',\n    layout: device.createPipelineLayout({ bindGroupLayouts: [computeBindGroupLayout] }),\n    compute: { module: binningModule, entryPoint: 'reduceMax' },\n  });\n\n  const renderPipeline = createRenderPipeline(device, {\n    label: 'scatterDensity/renderPipeline',\n    bindGroupLayouts: [renderBindGroupLayout],\n    vertex: { code: scatterDensityColormapWgsl, label: 'scatterDensityColormap.wgsl' },\n    fragment: {\n      code: scatterDensityColormapWgsl,\n      label: 'scatterDensityColormap.wgsl',\n      formats: targetFormat,\n      blend: undefined,\n    },\n    primitive: { topology: 'triangle-list', cullMode: 'none' },\n    multisample: { count: 1 },\n  });\n\n  let binsBuffer: GPUBuffer | null = null;\n  let maxBuffer: GPUBuffer | null = null;\n  let binsCapacityU32 = 0;\n\n  let lutTexture: GPUTexture | null = null;\n  let lutView: GPUTextureView | null = null;\n  let lastColormapKey = '';\n\n  let computeBindGroup: GPUBindGroup | null = null;\n  let renderBindGroup: GPUBindGroup | null = null;\n\n  // Cached state to decide when to recompute.\n  let lastPointBuffer: GPUBuffer | null = null;\n  let lastPointCount = -1;\n  let lastVisibleStart = 0;\n  let lastVisibleEnd = 0;\n  let lastBinSizePx = 0;\n  let lastBinCountX = 0;\n  let lastBinCountY = 0;\n  let lastPlotScissor: { readonly x: number; readonly y: number; readonly w: number; readonly h: number } | null = null;\n  let lastCanvasWidth = 0;\n  let lastCanvasHeight = 0;\n  let lastNormalizationU32 = 2; // default 'log'\n\n  let computeDirty = true;\n  let hasPrepared = false;\n\n  // Zero staging for fast clear (reallocated to match bins size).\n  let zeroBinsStaging = new Uint32Array(0);\n\n  const assertNotDisposed = (): void => {\n    if (disposed) throw new Error('ScatterDensityRenderer is disposed.');\n  };\n\n  const ensureLut = (seriesConfig: ResolvedScatterSeriesConfig): void => {\n    const key = colormapKey(seriesConfig.densityColormap);\n    if (!lutTexture) {\n      lutTexture = device.createTexture({\n        label: 'scatterDensity/lutTexture',\n        size: { width: 256, height: 1, depthOrArrayLayers: 1 },\n        format: 'rgba8unorm',\n        usage: GPUTextureUsage.TEXTURE_BINDING | GPUTextureUsage.COPY_DST,\n      });\n      lutView = lutTexture.createView();\n      lastColormapKey = '';\n    }\n    if (key === lastColormapKey) return;\n\n    const data = buildLutRGBA8(seriesConfig.densityColormap);\n    device.queue.writeTexture(\n      { texture: lutTexture! },\n      data,\n      { bytesPerRow: 256 * 4, rowsPerImage: 1 },\n      { width: 256, height: 1, depthOrArrayLayers: 1 }\n    );\n    lastColormapKey = key;\n  };\n\n  const ensureBins = (binCountX: number, binCountY: number): void => {\n    const n = Math.max(1, binCountX | 0) * Math.max(1, binCountY | 0);\n    if (binsBuffer && maxBuffer && n <= binsCapacityU32) return;\n\n    const requiredU32 = Math.max(1, n);\n    const grownU32 = Math.max(256, nextPow2(requiredU32));\n    binsCapacityU32 = grownU32;\n\n    if (binsBuffer) {\n      try {\n        binsBuffer.destroy();\n      } catch {\n        // best-effort\n      }\n      binsBuffer = null;\n    }\n    if (maxBuffer) {\n      try {\n        maxBuffer.destroy();\n      } catch {\n        // best-effort\n      }\n      maxBuffer = null;\n    }\n\n    binsBuffer = device.createBuffer({\n      label: 'scatterDensity/binsBuffer',\n      size: binsCapacityU32 * 4,\n      usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_DST,\n    });\n    maxBuffer = device.createBuffer({\n      label: 'scatterDensity/maxBuffer',\n      size: 4,\n      usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_DST,\n    });\n\n    // Refresh clear staging.\n    zeroBinsStaging = new Uint32Array(binsCapacityU32);\n\n    // Bind groups depend on buffers, so force re-create.\n    computeBindGroup = null;\n    renderBindGroup = null;\n    computeDirty = true;\n  };\n\n  const ensureBindGroups = (): void => {\n    if (!binsBuffer || !maxBuffer || !lutView || !lastPointBuffer) return;\n    if (!computeBindGroup) {\n      computeBindGroup = device.createBindGroup({\n        label: 'scatterDensity/computeBindGroup',\n        layout: computeBindGroupLayout,\n        entries: [\n          { binding: 0, resource: { buffer: computeUniformBuffer } },\n          { binding: 1, resource: { buffer: lastPointBuffer } },\n          { binding: 2, resource: { buffer: binsBuffer } },\n          { binding: 3, resource: { buffer: maxBuffer } },\n        ],\n      });\n    }\n    if (!renderBindGroup) {\n      renderBindGroup = device.createBindGroup({\n        label: 'scatterDensity/renderBindGroup',\n        layout: renderBindGroupLayout,\n        entries: [\n          { binding: 0, resource: { buffer: renderUniformBuffer } },\n          { binding: 1, resource: { buffer: binsBuffer } },\n          { binding: 2, resource: { buffer: maxBuffer } },\n          { binding: 3, resource: lutView },\n        ],\n      });\n    }\n  };\n\n  const prepare: ScatterDensityRenderer['prepare'] = (\n    seriesConfig,\n    pointBuffer,\n    pointCount,\n    visibleStartIndex,\n    visibleEndIndex,\n    xScale,\n    yScale,\n    gridArea,\n    rawBounds\n  ) => {\n    assertNotDisposed();\n    hasPrepared = true;\n\n    const plotScissor = computePlotScissorDevicePx(gridArea);\n    const dpr = gridArea.devicePixelRatio;\n    const binSizeCss = Number.isFinite(seriesConfig.binSize) ? Math.max(1e-6, seriesConfig.binSize) : 2;\n    const binSizePx = Math.max(1, Math.round(binSizeCss * (Number.isFinite(dpr) && dpr > 0 ? dpr : 1)));\n\n    const binCountX = Math.max(1, Math.ceil(plotScissor.w / binSizePx));\n    const binCountY = Math.max(1, Math.ceil(plotScissor.h / binSizePx));\n\n    ensureBins(binCountX, binCountY);\n    ensureLut(seriesConfig);\n\n    const normU32 = normalizationToU32(seriesConfig.densityNormalization);\n\n    // Dirty detection.\n    if (lastPointBuffer !== pointBuffer) {\n      lastPointBuffer = pointBuffer;\n      computeBindGroup = null;\n      renderBindGroup = null;\n      computeDirty = true;\n    }\n    if (lastPointCount !== pointCount) {\n      lastPointCount = pointCount;\n      computeDirty = true;\n    }\n    if (lastVisibleStart !== visibleStartIndex || lastVisibleEnd !== visibleEndIndex) {\n      lastVisibleStart = visibleStartIndex;\n      lastVisibleEnd = visibleEndIndex;\n      computeDirty = true;\n    }\n    if (lastBinSizePx !== binSizePx || lastBinCountX !== binCountX || lastBinCountY !== binCountY) {\n      lastBinSizePx = binSizePx;\n      lastBinCountX = binCountX;\n      lastBinCountY = binCountY;\n      computeDirty = true;\n    }\n    if (\n      !lastPlotScissor ||\n      lastPlotScissor.x !== plotScissor.x ||\n      lastPlotScissor.y !== plotScissor.y ||\n      lastPlotScissor.w !== plotScissor.w ||\n      lastPlotScissor.h !== plotScissor.h\n    ) {\n      lastPlotScissor = plotScissor;\n      computeDirty = true;\n    }\n    if (lastCanvasWidth !== gridArea.canvasWidth || lastCanvasHeight !== gridArea.canvasHeight) {\n      lastCanvasWidth = gridArea.canvasWidth;\n      lastCanvasHeight = gridArea.canvasHeight;\n      computeDirty = true;\n    }\n    if (lastNormalizationU32 !== normU32) {\n      lastNormalizationU32 = normU32;\n      computeDirty = true;\n    }\n\n    // Write uniforms.\n    const rb = rawBounds;\n    const xMin = rb?.xMin ?? 0;\n    const xMax = rb?.xMax ?? 1;\n    const yMin = rb?.yMin ?? 0;\n    const yMax = rb?.yMax ?? 1;\n\n    const { a: ax, b: bx } = computeClipAffineFromScale(xScale, xMin, xMax);\n    const { a: ay, b: by } = computeClipAffineFromScale(yScale, yMin, yMax);\n\n    writeTransformMat4F32(computeUniformF32, ax, bx, ay, by);\n    computeUniformF32[16] = gridArea.canvasWidth > 0 ? gridArea.canvasWidth : 1;\n    computeUniformF32[17] = gridArea.canvasHeight > 0 ? gridArea.canvasHeight : 1;\n    computeUniformF32[18] = 0;\n    computeUniformF32[19] = 0;\n\n    computeUniformU32[20] = plotScissor.x >>> 0;\n    computeUniformU32[21] = plotScissor.y >>> 0;\n    computeUniformU32[22] = plotScissor.w >>> 0;\n    computeUniformU32[23] = plotScissor.h >>> 0;\n    computeUniformU32[24] = binSizePx >>> 0;\n    computeUniformU32[25] = binCountX >>> 0;\n    computeUniformU32[26] = binCountY >>> 0;\n    computeUniformU32[27] = (Math.max(0, visibleStartIndex) | 0) >>> 0;\n    computeUniformU32[28] = (Math.max(0, visibleEndIndex) | 0) >>> 0;\n    computeUniformU32[29] = normU32 >>> 0;\n\n    writeUniformBuffer(device, computeUniformBuffer, computeUniformScratch);\n\n    renderUniformU32[0] = plotScissor.x >>> 0;\n    renderUniformU32[1] = plotScissor.y >>> 0;\n    renderUniformU32[2] = plotScissor.w >>> 0;\n    renderUniformU32[3] = plotScissor.h >>> 0;\n    renderUniformU32[4] = binSizePx >>> 0;\n    renderUniformU32[5] = binCountX >>> 0;\n    renderUniformU32[6] = binCountY >>> 0;\n    renderUniformU32[7] = normU32 >>> 0;\n    writeUniformBuffer(device, renderUniformBuffer, renderUniformScratch);\n\n    ensureBindGroups();\n  };\n\n  const encodeCompute: ScatterDensityRenderer['encodeCompute'] = (encoder) => {\n    assertNotDisposed();\n    if (!hasPrepared) return;\n    if (!computeDirty) return;\n    if (!binsBuffer || !maxBuffer || !computeBindGroup || lastPointCount <= 0) {\n      computeDirty = false;\n      return;\n    }\n    if (!lastPlotScissor || lastPlotScissor.w <= 0 || lastPlotScissor.h <= 0) {\n      computeDirty = false;\n      return;\n    }\n\n    // Clear bins + max.\n    device.queue.writeBuffer(binsBuffer, 0, zeroBinsStaging.buffer, 0, binsCapacityU32 * 4);\n    device.queue.writeBuffer(maxBuffer, 0, new Uint32Array([0]).buffer);\n\n    const binTotal = (lastBinCountX * lastBinCountY) | 0;\n    const visibleCount = Math.max(0, (lastVisibleEnd - lastVisibleStart) | 0);\n\n    const pass = encoder.beginComputePass({ label: 'scatterDensity/computePass' });\n    pass.setBindGroup(0, computeBindGroup);\n\n    pass.setPipeline(binPointsPipeline);\n    const wg = 256;\n    const groupsPoints = Math.ceil(visibleCount / wg);\n    if (groupsPoints > 0) pass.dispatchWorkgroups(groupsPoints);\n\n    pass.setPipeline(reduceMaxPipeline);\n    const groupsBins = Math.ceil(binTotal / wg);\n    if (groupsBins > 0) pass.dispatchWorkgroups(groupsBins);\n\n    pass.end();\n    computeDirty = false;\n  };\n\n  const render: ScatterDensityRenderer['render'] = (passEncoder) => {\n    assertNotDisposed();\n    if (!hasPrepared) return;\n    if (!renderBindGroup || !lastPlotScissor || !lutView) return;\n    if (lastPlotScissor.w <= 0 || lastPlotScissor.h <= 0) return;\n\n    passEncoder.setScissorRect(lastPlotScissor.x, lastPlotScissor.y, lastPlotScissor.w, lastPlotScissor.h);\n    passEncoder.setPipeline(renderPipeline);\n    passEncoder.setBindGroup(0, renderBindGroup);\n    passEncoder.draw(3);\n\n    if (lastCanvasWidth > 0 && lastCanvasHeight > 0) {\n      passEncoder.setScissorRect(0, 0, lastCanvasWidth, lastCanvasHeight);\n    }\n  };\n\n  const dispose: ScatterDensityRenderer['dispose'] = () => {\n    if (disposed) return;\n    disposed = true;\n\n    try {\n      computeUniformBuffer.destroy();\n    } catch {\n      // best-effort\n    }\n    try {\n      renderUniformBuffer.destroy();\n    } catch {\n      // best-effort\n    }\n\n    if (binsBuffer) {\n      try {\n        binsBuffer.destroy();\n      } catch {\n        // best-effort\n      }\n    }\n    if (maxBuffer) {\n      try {\n        maxBuffer.destroy();\n      } catch {\n        // best-effort\n      }\n    }\n    binsBuffer = null;\n    maxBuffer = null;\n    binsCapacityU32 = 0;\n\n    if (lutTexture) {\n      try {\n        lutTexture.destroy();\n      } catch {\n        // best-effort\n      }\n    }\n    lutTexture = null;\n    lutView = null;\n\n    computeBindGroup = null;\n    renderBindGroup = null;\n    lastPointBuffer = null;\n  };\n\n  return { prepare, encodeCompute, render, dispose };\n}\n\n","export default \"// pie.wgsl\\n// Instanced anti-aliased pie-slice shader (instanced quad + SDF mask).\\n//\\n// - Per-instance vertex input:\\n//   - center        = vec2<f32> slice center (transformed by VSUniforms.transform)\\n//   - startAngleRad = f32 start angle in radians\\n//   - endAngleRad   = f32 end angle in radians\\n//   - radiiPx       = vec2<f32>(innerRadiusPx, outerRadiusPx) in *device pixels*\\n//   - color         = vec4<f32> RGBA color in [0..1]\\n//\\n// - Draw call: draw(6, instanceCount) using triangle-list expansion in VS\\n//\\n// - Uniforms:\\n//   - @group(0) @binding(0): VSUniforms { transform, viewportPx }\\n//\\n// Notes:\\n// - The quad is expanded in clip space using `radiusPx` and `viewportPx`.\\n// - Fragment uses an SDF mask for the circle boundary + an angular wedge mask.\\n// - Fully outside fragments are discarded to avoid unnecessary blending work.\\n//\\n// Conventions: matches other shaders in this repo (vsMain/fsMain, group 0 bindings,\\n// and explicit uniform padding/alignment where needed).\\n\\nconst PI: f32 = 3.141592653589793;\\nconst TAU: f32 = 6.283185307179586; // 2*pi\\n\\nstruct VSUniforms {\\n  transform: mat4x4<f32>,\\n  viewportPx: vec2<f32>,\\n  // Pad to 16-byte alignment (mat4x4 is 64B; vec2 adds 8B; pad to 80B).\\n  _pad0: vec2<f32>,\\n};\\n\\n@group(0) @binding(0) var<uniform> vsUniforms: VSUniforms;\\n\\nstruct VSIn {\\n  @location(0) center: vec2<f32>,\\n  @location(1) startAngleRad: f32,\\n  @location(2) endAngleRad: f32,\\n  @location(3) radiiPx: vec2<f32>, // (innerPx, outerPx)\\n  @location(4) color: vec4<f32>,\\n};\\n\\nstruct VSOut {\\n  @builtin(position) clipPosition: vec4<f32>,\\n  @location(0) localPx: vec2<f32>,\\n  @location(1) startAngleRad: f32,\\n  @location(2) endAngleRad: f32,\\n  @location(3) radiiPx: vec2<f32>,\\n  @location(4) color: vec4<f32>,\\n};\\n\\n@vertex\\nfn vsMain(in: VSIn, @builtin(vertex_index) vertexIndex: u32) -> VSOut {\\n  // Fixed local corners for 2 triangles (triangle-list).\\n  // `localNdc` is a quad in [-1, 1]^2; we convert it to pixel offsets via radiusPx.\\n  let localNdc = array<vec2<f32>, 6>(\\n    vec2<f32>(-1.0, -1.0),\\n    vec2<f32>( 1.0, -1.0),\\n    vec2<f32>(-1.0,  1.0),\\n    vec2<f32>(-1.0,  1.0),\\n    vec2<f32>( 1.0, -1.0),\\n    vec2<f32>( 1.0,  1.0)\\n  );\\n\\n  let corner = localNdc[vertexIndex];\\n  let outerPx = in.radiiPx.y;\\n  let localPx = corner * outerPx;\\n\\n  // Convert pixel offset to clip-space offset.\\n  // Clip space spans [-1, 1] across the viewport, so px -> clip is (2 / viewportPx).\\n  let localClip = localPx * (2.0 / vsUniforms.viewportPx);\\n\\n  let centerClip = (vsUniforms.transform * vec4<f32>(in.center, 0.0, 1.0)).xy;\\n\\n  var out: VSOut;\\n  out.clipPosition = vec4<f32>(centerClip + localClip, 0.0, 1.0);\\n  out.localPx = localPx;\\n  out.startAngleRad = in.startAngleRad;\\n  out.endAngleRad = in.endAngleRad;\\n  out.radiiPx = in.radiiPx;\\n  out.color = in.color;\\n  return out;\\n}\\n\\nfn wrapToTau(theta: f32) -> f32 {\\n  // Maps theta to [0, TAU). (Input often comes from atan2 in [-PI, PI].)\\n  return select(theta, theta + TAU, theta < 0.0);\\n}\\n\\n@fragment\\nfn fsMain(in: VSOut) -> @location(0) vec4<f32> {\\n  let p = in.localPx;\\n  let r = length(p);\\n\\n  let innerPx = in.radiiPx.x;\\n  let outerPx = in.radiiPx.y;\\n\\n  // --- Radial mask: ring between inner and outer radii (inner==0 => pie) ---\\n  // Positive inside the ring, negative outside.\\n  let radialDist = min(r - innerPx, outerPx - r);\\n  let radialW = fwidth(radialDist);\\n  let radialA = smoothstep(-radialW, radialW, radialDist);\\n\\n  if (radialA <= 0.0) {\\n    discard;\\n  }\\n\\n  // Compute fragment angle in [0, TAU).\\n  let angle = wrapToTau(atan2(p.y, p.x));\\n\\n  // --- Angular mask: wedge between start/end angles with wrap ---\\n  let start = in.startAngleRad;\\n  let end = in.endAngleRad;\\n\\n  // Compute span in [0, 2π) with wrap.\\n  var span = end - start;\\n  span = span + select(0.0, TAU, span < 0.0);\\n\\n  // Compute rel in [0, 2π) with wrap.\\n  var rel = angle - start;\\n  rel = rel + select(0.0, TAU, rel < 0.0);\\n\\n  let inside = rel <= span;\\n\\n  // Signed angular distance (in radians) to nearest boundary.\\n  // - Inside: +min(rel, span-rel)\\n  // - Outside: -min(rel-span, 2π-rel)\\n  let dIn = min(rel, max(span - rel, 0.0));\\n  let dOutA = max(rel - span, 0.0);\\n  let dOutB = max(TAU - rel, 0.0);\\n  let dOut = min(dOutA, dOutB);\\n\\n  let signedAngleDist = select(-dOut, dIn, inside);\\n\\n  // Convert to approximate pixel distance to the boundary ray.\\n  // (For small angles, perpendicular distance to a ray ≈ r * angle.)\\n  let angleDistPx = signedAngleDist * max(r, 1.0);\\n\\n  let angW = fwidth(angleDistPx);\\n  let angularA = smoothstep(-angW, angW, angleDistPx);\\n\\n  let aOut = radialA * angularA;\\n  if (aOut <= 0.0) {\\n    discard;\\n  }\\n\\n  return vec4<f32>(in.color.rgb, in.color.a * aOut);\\n}\\n\\n\"","import pieWgsl from '../shaders/pie.wgsl?raw';\nimport type { ResolvedPieSeriesConfig } from '../config/OptionResolver';\nimport type { PieCenter, PieRadius } from '../config/types';\nimport { parseCssColorToRgba01 } from '../utils/colors';\nimport type { GridArea } from './createGridRenderer';\nimport { createRenderPipeline, createUniformBuffer, writeUniformBuffer } from './rendererUtils';\n\nexport interface PieRenderer {\n  prepare(seriesConfig: ResolvedPieSeriesConfig, gridArea: GridArea): void;\n  render(passEncoder: GPURenderPassEncoder): void;\n  dispose(): void;\n}\n\nexport interface PieRendererOptions {\n  /**\n   * Must match the canvas context format used for the render pass color attachment.\n   * Usually this is `gpuContext.preferredFormat`.\n   *\n   * Defaults to `'bgra8unorm'` for backward compatibility.\n   */\n  readonly targetFormat?: GPUTextureFormat;\n}\n\ntype Rgba = readonly [r: number, g: number, b: number, a: number];\n\nconst DEFAULT_TARGET_FORMAT: GPUTextureFormat = 'bgra8unorm';\n\n// Instance layout (must match `pie.wgsl` locations):\n// @location(0) center: vec2<f32>\n// @location(1) startAngleRad: f32\n// @location(2) endAngleRad: f32\n// @location(3) radiiPx: vec2<f32> (innerPx, outerPx) in device pixels\n// @location(4) color: vec4<f32>\nconst INSTANCE_STRIDE_BYTES = 40;\nconst INSTANCE_STRIDE_FLOATS = INSTANCE_STRIDE_BYTES / 4;\n\nconst TAU = Math.PI * 2;\n\nconst clamp01 = (v: number): number => Math.min(1, Math.max(0, v));\nconst clampInt = (v: number, lo: number, hi: number): number => Math.min(hi, Math.max(lo, v | 0));\n\nconst nextPow2 = (v: number): number => {\n  if (!Number.isFinite(v) || v <= 0) return 1;\n  const n = Math.ceil(v);\n  return 2 ** Math.ceil(Math.log2(n));\n};\n\nconst wrapToTau = (thetaRad: number): number => {\n  if (!Number.isFinite(thetaRad)) return 0;\n  const t = thetaRad % TAU;\n  return t < 0 ? t + TAU : t;\n};\n\nconst parseColor = (cssColor: string, fallbackCssColor: string): Rgba => {\n  const parsed = parseCssColorToRgba01(cssColor);\n  if (parsed) return [parsed[0], parsed[1], parsed[2], clamp01(parsed[3])] as const;\n\n  const fb = parseCssColorToRgba01(fallbackCssColor);\n  if (fb) return [fb[0], fb[1], fb[2], clamp01(fb[3])] as const;\n\n  return [0, 0, 0, 1] as const;\n};\n\nconst parseNumberOrPercent = (value: number | string, basis: number): number | null => {\n  if (typeof value === 'number') return Number.isFinite(value) ? value : null;\n  if (typeof value !== 'string') return null;\n\n  const s = value.trim();\n  if (s.length === 0) return null;\n\n  if (s.endsWith('%')) {\n    const pct = Number.parseFloat(s.slice(0, -1));\n    if (!Number.isFinite(pct)) return null;\n    return (pct / 100) * basis;\n  }\n\n  // Be permissive: allow numeric strings like \"120\" even though the public type primarily documents percent strings.\n  const n = Number.parseFloat(s);\n  return Number.isFinite(n) ? n : null;\n};\n\nconst resolveCenterPlotCss = (\n  center: PieCenter | undefined,\n  plotWidthCss: number,\n  plotHeightCss: number\n): { readonly x: number; readonly y: number } => {\n  const xRaw = center?.[0] ?? '50%';\n  const yRaw = center?.[1] ?? '50%';\n\n  const x = parseNumberOrPercent(xRaw, plotWidthCss);\n  const y = parseNumberOrPercent(yRaw, plotHeightCss);\n\n  return {\n    x: Number.isFinite(x) ? x! : plotWidthCss * 0.5,\n    y: Number.isFinite(y) ? y! : plotHeightCss * 0.5,\n  };\n};\n\nconst isRadiusTuple = (\n  radius: PieRadius\n): radius is readonly [inner: number | string, outer: number | string] => Array.isArray(radius);\n\nconst resolveRadiiCss = (\n  radius: PieRadius | undefined,\n  maxRadiusCss: number\n): { readonly inner: number; readonly outer: number } => {\n  // Default similar to common chart libs.\n  if (radius == null) return { inner: 0, outer: maxRadiusCss * 0.7 };\n\n  if (isRadiusTuple(radius)) {\n    const inner = parseNumberOrPercent(radius[0], maxRadiusCss);\n    const outer = parseNumberOrPercent(radius[1], maxRadiusCss);\n    const innerCss = Math.max(0, Number.isFinite(inner) ? inner! : 0);\n    const outerCss = Math.max(innerCss, Number.isFinite(outer) ? outer! : maxRadiusCss * 0.7);\n    return { inner: innerCss, outer: Math.min(maxRadiusCss, outerCss) };\n  }\n\n  const outer = parseNumberOrPercent(radius, maxRadiusCss);\n  const outerCss = Math.max(0, Number.isFinite(outer) ? outer! : maxRadiusCss * 0.7);\n  return { inner: 0, outer: Math.min(maxRadiusCss, outerCss) };\n};\n\nconst computePlotScissorDevicePx = (\n  gridArea: GridArea\n): { readonly x: number; readonly y: number; readonly w: number; readonly h: number } => {\n  const { canvasWidth, canvasHeight, devicePixelRatio } = gridArea;\n\n  const plotLeftDevice = gridArea.left * devicePixelRatio;\n  const plotRightDevice = canvasWidth - gridArea.right * devicePixelRatio;\n  const plotTopDevice = gridArea.top * devicePixelRatio;\n  const plotBottomDevice = canvasHeight - gridArea.bottom * devicePixelRatio;\n\n  const scissorX = clampInt(Math.floor(plotLeftDevice), 0, Math.max(0, canvasWidth));\n  const scissorY = clampInt(Math.floor(plotTopDevice), 0, Math.max(0, canvasHeight));\n  const scissorR = clampInt(Math.ceil(plotRightDevice), 0, Math.max(0, canvasWidth));\n  const scissorB = clampInt(Math.ceil(plotBottomDevice), 0, Math.max(0, canvasHeight));\n  const scissorW = Math.max(0, scissorR - scissorX);\n  const scissorH = Math.max(0, scissorB - scissorY);\n\n  return { x: scissorX, y: scissorY, w: scissorW, h: scissorH };\n};\n\nconst IDENTITY_MAT4_F32 = new Float32Array([\n  1, 0, 0, 0, // col0\n  0, 1, 0, 0, // col1\n  0, 0, 1, 0, // col2\n  0, 0, 0, 1, // col3\n]);\n\nexport function createPieRenderer(device: GPUDevice, options?: PieRendererOptions): PieRenderer {\n  let disposed = false;\n  const targetFormat = options?.targetFormat ?? DEFAULT_TARGET_FORMAT;\n\n  const bindGroupLayout = device.createBindGroupLayout({\n    entries: [{ binding: 0, visibility: GPUShaderStage.VERTEX, buffer: { type: 'uniform' } }],\n  });\n\n  // VSUniforms in `pie.wgsl`: mat4x4 (64) + viewportPx vec2 (8) + pad vec2 (8) = 80 bytes.\n  const vsUniformBuffer = createUniformBuffer(device, 80, { label: 'pieRenderer/vsUniforms' });\n\n  // Reused CPU-side staging for uniform writes (avoid per-frame allocations).\n  const vsUniformScratchBuffer = new ArrayBuffer(80);\n  const vsUniformScratchF32 = new Float32Array(vsUniformScratchBuffer);\n\n  const bindGroup = device.createBindGroup({\n    layout: bindGroupLayout,\n    entries: [{ binding: 0, resource: { buffer: vsUniformBuffer } }],\n  });\n\n  const pipeline = createRenderPipeline(device, {\n    label: 'pieRenderer/pipeline',\n    bindGroupLayouts: [bindGroupLayout],\n    vertex: {\n      code: pieWgsl,\n      label: 'pie.wgsl',\n      buffers: [\n        {\n          arrayStride: INSTANCE_STRIDE_BYTES,\n          stepMode: 'instance',\n          attributes: [\n            { shaderLocation: 0, format: 'float32x2', offset: 0 }, // center\n            { shaderLocation: 1, format: 'float32', offset: 8 }, // startAngleRad\n            { shaderLocation: 2, format: 'float32', offset: 12 }, // endAngleRad\n            { shaderLocation: 3, format: 'float32x2', offset: 16 }, // radiiPx\n            { shaderLocation: 4, format: 'float32x4', offset: 24 }, // color\n          ],\n        },\n      ],\n    },\n    fragment: {\n      code: pieWgsl,\n      label: 'pie.wgsl',\n      formats: targetFormat,\n      // Standard alpha blending for AA edges and translucent slice colors.\n      blend: {\n        color: { operation: 'add', srcFactor: 'src-alpha', dstFactor: 'one-minus-src-alpha' },\n        alpha: { operation: 'add', srcFactor: 'one', dstFactor: 'one-minus-src-alpha' },\n      },\n    },\n    primitive: { topology: 'triangle-list', cullMode: 'none' },\n    multisample: { count: 1 },\n  });\n\n  let instanceBuffer: GPUBuffer | null = null;\n  let instanceCount = 0;\n  let cpuInstanceStagingBuffer = new ArrayBuffer(0);\n  let cpuInstanceStagingF32 = new Float32Array(cpuInstanceStagingBuffer);\n\n  let lastCanvasWidth = 0;\n  let lastCanvasHeight = 0;\n  let lastScissor: { readonly x: number; readonly y: number; readonly w: number; readonly h: number } | null = null;\n\n  const assertNotDisposed = (): void => {\n    if (disposed) throw new Error('PieRenderer is disposed.');\n  };\n\n  const ensureCpuInstanceCapacityFloats = (requiredFloats: number): void => {\n    if (requiredFloats <= cpuInstanceStagingF32.length) return;\n    const nextFloats = Math.max(8, nextPow2(requiredFloats));\n    cpuInstanceStagingBuffer = new ArrayBuffer(nextFloats * 4);\n    cpuInstanceStagingF32 = new Float32Array(cpuInstanceStagingBuffer);\n  };\n\n  const writeVsUniforms = (viewportWDevicePx: number, viewportHDevicePx: number): void => {\n    const w = Number.isFinite(viewportWDevicePx) && viewportWDevicePx > 0 ? viewportWDevicePx : 1;\n    const h = Number.isFinite(viewportHDevicePx) && viewportHDevicePx > 0 ? viewportHDevicePx : 1;\n\n    vsUniformScratchF32.set(IDENTITY_MAT4_F32, 0);\n    vsUniformScratchF32[16] = w;\n    vsUniformScratchF32[17] = h;\n    vsUniformScratchF32[18] = 0;\n    vsUniformScratchF32[19] = 0;\n    writeUniformBuffer(device, vsUniformBuffer, vsUniformScratchBuffer);\n  };\n\n  const prepare: PieRenderer['prepare'] = (seriesConfig, gridArea) => {\n    assertNotDisposed();\n\n    const dprRaw = gridArea.devicePixelRatio;\n    const dpr = dprRaw > 0 && Number.isFinite(dprRaw) ? dprRaw : 1;\n\n    lastCanvasWidth = gridArea.canvasWidth;\n    lastCanvasHeight = gridArea.canvasHeight;\n    writeVsUniforms(gridArea.canvasWidth, gridArea.canvasHeight);\n    lastScissor = computePlotScissorDevicePx(gridArea);\n\n    const canvasCssWidth = gridArea.canvasWidth / dpr;\n    const canvasCssHeight = gridArea.canvasHeight / dpr;\n    if (!(canvasCssWidth > 0) || !(canvasCssHeight > 0)) {\n      instanceCount = 0;\n      return;\n    }\n\n    const plotWidthCss = canvasCssWidth - gridArea.left - gridArea.right;\n    const plotHeightCss = canvasCssHeight - gridArea.top - gridArea.bottom;\n    if (!(plotWidthCss > 0) || !(plotHeightCss > 0)) {\n      instanceCount = 0;\n      return;\n    }\n\n    const maxRadiusCss = 0.5 * Math.min(plotWidthCss, plotHeightCss);\n    if (!(maxRadiusCss > 0)) {\n      instanceCount = 0;\n      return;\n    }\n\n    // Center specified in plot-local CSS px (or %), then shifted by GridArea CSS margins.\n    const centerPlotCss = resolveCenterPlotCss(seriesConfig.center, plotWidthCss, plotHeightCss);\n    const centerCanvasCssX = gridArea.left + centerPlotCss.x;\n    const centerCanvasCssY = gridArea.top + centerPlotCss.y;\n\n    // Instance center is in clip space; VS transform is identity.\n    const centerClipX = (centerCanvasCssX / canvasCssWidth) * 2 - 1;\n    const centerClipY = 1 - (centerCanvasCssY / canvasCssHeight) * 2;\n    if (!Number.isFinite(centerClipX) || !Number.isFinite(centerClipY)) {\n      instanceCount = 0;\n      return;\n    }\n\n    // Radii specified in CSS px (or % of max radius), converted to device px for the shader.\n    const radiiCss = resolveRadiiCss(seriesConfig.radius, maxRadiusCss);\n    const innerCss = Math.max(0, Math.min(radiiCss.inner, radiiCss.outer));\n    const outerCss = Math.max(innerCss, radiiCss.outer);\n    const innerPx = innerCss * dpr;\n    const outerPx = outerCss * dpr;\n    if (!(outerPx > 0)) {\n      instanceCount = 0;\n      return;\n    }\n\n    // Total positive value for angle allocation (exclude hidden slices).\n    let total = 0;\n    let validCount = 0;\n    for (let i = 0; i < seriesConfig.data.length; i++) {\n      const item = seriesConfig.data[i];\n      const v = item?.value;\n      if (typeof v === 'number' && Number.isFinite(v) && v > 0 && item.visible !== false) {\n        total += v;\n        validCount++;\n      }\n    }\n    if (!(total > 0) || validCount === 0) {\n      instanceCount = 0;\n      return;\n    }\n\n    ensureCpuInstanceCapacityFloats(validCount * INSTANCE_STRIDE_FLOATS);\n    const f32 = cpuInstanceStagingF32;\n\n    // IMPORTANT: shader assumes start/end are already wrapped to [0, 2π) (it only adds TAU once).\n    const startDeg =\n      typeof seriesConfig.startAngle === 'number' && Number.isFinite(seriesConfig.startAngle) ? seriesConfig.startAngle : 90;\n    let current = wrapToTau((startDeg * Math.PI) / 180);\n\n    // Make the last slice close the circle (reduces float drift).\n    let accumulated = 0;\n    let outFloats = 0;\n    let emitted = 0;\n\n    for (let i = 0; i < seriesConfig.data.length; i++) {\n      const item = seriesConfig.data[i];\n      const v = item?.value;\n      if (typeof v !== 'number' || !Number.isFinite(v) || v <= 0) continue;\n      // Skip hidden slices\n      if (item.visible === false) continue;\n\n      emitted++;\n      const isLast = emitted === validCount;\n\n      const frac = v / total;\n      let span = frac * TAU;\n      if (isLast) {\n        span = Math.max(0, TAU - accumulated);\n      } else {\n        // Keep accumulated stable and avoid pathological spans from weird inputs.\n        span = Math.max(0, Math.min(TAU, span));\n      }\n      accumulated += span;\n      if (!(span > 0)) continue;\n\n      const startRad = current;\n      // When there's only one visible slice, it should span the full circle (0 to TAU).\n      // Don't wrap the end angle in this case, as wrapping (start + TAU) gives start again.\n      const endRad = validCount === 1 ? current + TAU : wrapToTau(current + span);\n      current = wrapToTau(current + span);\n\n      const [r, g, b, a] = parseColor(item.color, seriesConfig.color);\n\n      f32[outFloats + 0] = centerClipX;\n      f32[outFloats + 1] = centerClipY;\n      f32[outFloats + 2] = startRad;\n      f32[outFloats + 3] = endRad;\n      f32[outFloats + 4] = innerPx;\n      f32[outFloats + 5] = outerPx;\n      f32[outFloats + 6] = r;\n      f32[outFloats + 7] = g;\n      f32[outFloats + 8] = b;\n      f32[outFloats + 9] = a;\n      outFloats += INSTANCE_STRIDE_FLOATS;\n    }\n\n    instanceCount = outFloats / INSTANCE_STRIDE_FLOATS;\n    const requiredBytes = Math.max(4, instanceCount * INSTANCE_STRIDE_BYTES);\n\n    if (!instanceBuffer || instanceBuffer.size < requiredBytes) {\n      const grownBytes = Math.max(Math.max(4, nextPow2(requiredBytes)), instanceBuffer ? instanceBuffer.size : 0);\n      if (instanceBuffer) {\n        try {\n          instanceBuffer.destroy();\n        } catch {\n          // best-effort\n        }\n      }\n      instanceBuffer = device.createBuffer({\n        label: 'pieRenderer/instanceBuffer',\n        size: grownBytes,\n        usage: GPUBufferUsage.VERTEX | GPUBufferUsage.COPY_DST,\n      });\n    }\n\n    if (instanceBuffer && instanceCount > 0) {\n      device.queue.writeBuffer(instanceBuffer, 0, cpuInstanceStagingBuffer, 0, instanceCount * INSTANCE_STRIDE_BYTES);\n    }\n  };\n\n  const render: PieRenderer['render'] = (passEncoder) => {\n    assertNotDisposed();\n    if (!instanceBuffer || instanceCount === 0) return;\n\n    // Clip to plot area (scissor is in device pixels).\n    if (lastScissor && lastCanvasWidth > 0 && lastCanvasHeight > 0) {\n      passEncoder.setScissorRect(lastScissor.x, lastScissor.y, lastScissor.w, lastScissor.h);\n    }\n\n    passEncoder.setPipeline(pipeline);\n    passEncoder.setBindGroup(0, bindGroup);\n    passEncoder.setVertexBuffer(0, instanceBuffer);\n    passEncoder.draw(6, instanceCount);\n\n    // Reset scissor to full canvas to avoid impacting later renderers.\n    if (lastScissor && lastCanvasWidth > 0 && lastCanvasHeight > 0) {\n      passEncoder.setScissorRect(0, 0, lastCanvasWidth, lastCanvasHeight);\n    }\n  };\n\n  const dispose: PieRenderer['dispose'] = () => {\n    if (disposed) return;\n    disposed = true;\n\n    if (instanceBuffer) {\n      try {\n        instanceBuffer.destroy();\n      } catch {\n        // best-effort\n      }\n    }\n    instanceBuffer = null;\n    instanceCount = 0;\n\n    try {\n      vsUniformBuffer.destroy();\n    } catch {\n      // best-effort\n    }\n\n    lastCanvasWidth = 0;\n    lastCanvasHeight = 0;\n    lastScissor = null;\n  };\n\n  return { prepare, render, dispose };\n}\n\n","export default \"// candlestick.wgsl\\n// Instanced candlestick shader (bodies + wicks):\\n// - Per-instance vertex input:\\n//   - xClip, openClip, closeClip, lowClip, highClip, bodyWidthClip (6 floats)\\n//   - bodyColor rgba (4 floats)\\n// - Draw call: draw(18, instanceCount) using triangle-list expansion in VS\\n//   - vertices 0-5: body quad (2 triangles)\\n//   - vertices 6-11: upper wick (2 triangles)\\n//   - vertices 12-17: lower wick (2 triangles)\\n// - Uniforms:\\n//   - @group(0) @binding(0): VSUniforms { transform, wickWidthClip }\\n\\nstruct VSUniforms {\\n  transform: mat4x4<f32>,\\n  wickWidthClip: f32,\\n  _pad0: f32,\\n  _pad1: f32,\\n  _pad2: f32,\\n};\\n\\n@group(0) @binding(0) var<uniform> vsUniforms: VSUniforms;\\n\\nstruct VSIn {\\n  @location(0) xClip: f32,\\n  @location(1) openClip: f32,\\n  @location(2) closeClip: f32,\\n  @location(3) lowClip: f32,\\n  @location(4) highClip: f32,\\n  @location(5) bodyWidthClip: f32,\\n  @location(6) bodyColor: vec4<f32>,\\n};\\n\\nstruct VSOut {\\n  @builtin(position) clipPosition: vec4<f32>,\\n  @location(0) color: vec4<f32>,\\n};\\n\\n@vertex\\nfn vsMain(in: VSIn, @builtin(vertex_index) vertexIndex: u32) -> VSOut {\\n  // Compute body bounds\\n  let bodyTop = max(in.openClip, in.closeClip);\\n  let bodyBottom = min(in.openClip, in.closeClip);\\n  let bodyLeft = in.xClip - in.bodyWidthClip * 0.5;\\n  let bodyRight = in.xClip + in.bodyWidthClip * 0.5;\\n\\n  // Wick bounds\\n  let wickLeft = in.xClip - vsUniforms.wickWidthClip * 0.5;\\n  let wickRight = in.xClip + vsUniforms.wickWidthClip * 0.5;\\n\\n  var pos: vec2<f32>;\\n\\n  if (vertexIndex < 6u) {\\n    // Body quad (vertices 0-5)\\n    let corners = array<vec2<f32>, 6>(\\n      vec2<f32>(0.0, 0.0),\\n      vec2<f32>(1.0, 0.0),\\n      vec2<f32>(0.0, 1.0),\\n      vec2<f32>(0.0, 1.0),\\n      vec2<f32>(1.0, 0.0),\\n      vec2<f32>(1.0, 1.0)\\n    );\\n    let corner = corners[vertexIndex];\\n    let bodyMin = vec2<f32>(bodyLeft, bodyBottom);\\n    let bodyMax = vec2<f32>(bodyRight, bodyTop);\\n    pos = bodyMin + corner * (bodyMax - bodyMin);\\n  } else if (vertexIndex < 12u) {\\n    // Upper wick (vertices 6-11): from bodyTop to highClip\\n    let idx = vertexIndex - 6u;\\n    let corners = array<vec2<f32>, 6>(\\n      vec2<f32>(0.0, 0.0),\\n      vec2<f32>(1.0, 0.0),\\n      vec2<f32>(0.0, 1.0),\\n      vec2<f32>(0.0, 1.0),\\n      vec2<f32>(1.0, 0.0),\\n      vec2<f32>(1.0, 1.0)\\n    );\\n    let corner = corners[idx];\\n    let wickMin = vec2<f32>(wickLeft, bodyTop);\\n    let wickMax = vec2<f32>(wickRight, in.highClip);\\n    pos = wickMin + corner * (wickMax - wickMin);\\n  } else {\\n    // Lower wick (vertices 12-17): from lowClip to bodyBottom\\n    let idx = vertexIndex - 12u;\\n    let corners = array<vec2<f32>, 6>(\\n      vec2<f32>(0.0, 0.0),\\n      vec2<f32>(1.0, 0.0),\\n      vec2<f32>(0.0, 1.0),\\n      vec2<f32>(0.0, 1.0),\\n      vec2<f32>(1.0, 0.0),\\n      vec2<f32>(1.0, 1.0)\\n    );\\n    let corner = corners[idx];\\n    let wickMin = vec2<f32>(wickLeft, in.lowClip);\\n    let wickMax = vec2<f32>(wickRight, bodyBottom);\\n    pos = wickMin + corner * (wickMax - wickMin);\\n  }\\n\\n  var out: VSOut;\\n  out.clipPosition = vsUniforms.transform * vec4<f32>(pos, 0.0, 1.0);\\n  out.color = in.bodyColor;\\n  return out;\\n}\\n\\n@fragment\\nfn fsMain(in: VSOut) -> @location(0) vec4<f32> {\\n  return in.color;\\n}\\n\"","import candlestickWgsl from '../shaders/candlestick.wgsl?raw';\nimport type { ResolvedCandlestickSeriesConfig } from '../config/OptionResolver';\nimport type { OHLCDataPoint, OHLCDataPointTuple } from '../config/types';\nimport type { LinearScale } from '../utils/scales';\nimport type { GridArea } from './createGridRenderer';\nimport { parseCssColorToRgba01 } from '../utils/colors';\nimport { createRenderPipeline, createUniformBuffer, writeUniformBuffer } from './rendererUtils';\n\nexport interface CandlestickRenderer {\n  prepare(\n    series: ResolvedCandlestickSeriesConfig,\n    data: ResolvedCandlestickSeriesConfig['data'],\n    xScale: LinearScale,\n    yScale: LinearScale,\n    gridArea: GridArea,\n    backgroundColor?: string\n  ): void;\n  render(passEncoder: GPURenderPassEncoder): void;\n  dispose(): void;\n}\n\nexport interface CandlestickRendererOptions {\n  /**\n   * Must match the canvas context format used for the render pass color attachment.\n   * Usually this is `gpuContext.preferredFormat`.\n   *\n   * Defaults to `'bgra8unorm'` for backward compatibility.\n   */\n  readonly targetFormat?: GPUTextureFormat;\n}\n\ntype Rgba = readonly [r: number, g: number, b: number, a: number];\n\nconst DEFAULT_TARGET_FORMAT: GPUTextureFormat = 'bgra8unorm';\nconst DEFAULT_WICK_WIDTH_CSS_PX = 1;\nconst INSTANCE_STRIDE_BYTES = 40; // 6 floats + vec4 color\nconst INSTANCE_STRIDE_FLOATS = INSTANCE_STRIDE_BYTES / 4;\n\nconst clamp01 = (v: number): number => Math.min(1, Math.max(0, v));\nconst clampInt = (v: number, lo: number, hi: number): number => Math.min(hi, Math.max(lo, v | 0));\n\nconst parseSeriesColorToRgba01 = (color: string): Rgba =>\n  parseCssColorToRgba01(color) ?? ([0, 0, 0, 1] as const);\n\nconst nextPow2 = (v: number): number => {\n  if (!Number.isFinite(v) || v <= 0) return 1;\n  const n = Math.ceil(v);\n  return 2 ** Math.ceil(Math.log2(n));\n};\n\nconst parsePercent = (value: string): number | null => {\n  const m = value.trim().match(/^(\\d+(?:\\.\\d+)?)%$/);\n  if (!m) return null;\n  const p = Number(m[1]) / 100;\n  return Number.isFinite(p) ? p : null;\n};\n\nconst isTupleDataPoint = (p: OHLCDataPoint): p is OHLCDataPointTuple => Array.isArray(p);\n\nconst getOHLC = (\n  p: OHLCDataPoint\n): { readonly timestamp: number; readonly open: number; readonly close: number; readonly low: number; readonly high: number } => {\n  if (isTupleDataPoint(p)) {\n    return { timestamp: p[0], open: p[1], close: p[2], low: p[3], high: p[4] };\n  }\n  return { timestamp: p.timestamp, open: p.open, close: p.close, low: p.low, high: p.high };\n};\n\nconst computePlotSizeCssPx = (gridArea: GridArea): { readonly plotWidthCss: number; readonly plotHeightCss: number } | null => {\n  const dpr = gridArea.devicePixelRatio;\n  if (!(dpr > 0)) return null;\n  const canvasCssWidth = gridArea.canvasWidth / dpr;\n  const canvasCssHeight = gridArea.canvasHeight / dpr;\n  const plotWidthCss = canvasCssWidth - gridArea.left - gridArea.right;\n  const plotHeightCss = canvasCssHeight - gridArea.top - gridArea.bottom;\n  if (!(plotWidthCss > 0) || !(plotHeightCss > 0)) return null;\n  return { plotWidthCss, plotHeightCss };\n};\n\nconst computePlotClipRect = (\n  gridArea: GridArea\n): { readonly left: number; readonly right: number; readonly top: number; readonly bottom: number; readonly width: number; readonly height: number } => {\n  const { left, right, top, bottom, canvasWidth, canvasHeight, devicePixelRatio } = gridArea;\n\n  const plotLeft = left * devicePixelRatio;\n  const plotRight = canvasWidth - right * devicePixelRatio;\n  const plotTop = top * devicePixelRatio;\n  const plotBottom = canvasHeight - bottom * devicePixelRatio;\n\n  const plotLeftClip = (plotLeft / canvasWidth) * 2.0 - 1.0;\n  const plotRightClip = (plotRight / canvasWidth) * 2.0 - 1.0;\n  const plotTopClip = 1.0 - (plotTop / canvasHeight) * 2.0; // flip Y\n  const plotBottomClip = 1.0 - (plotBottom / canvasHeight) * 2.0; // flip Y\n\n  return {\n    left: plotLeftClip,\n    right: plotRightClip,\n    top: plotTopClip,\n    bottom: plotBottomClip,\n    width: plotRightClip - plotLeftClip,\n    height: plotTopClip - plotBottomClip,\n  };\n};\n\nconst computePlotScissorDevicePx = (\n  gridArea: GridArea\n): { readonly x: number; readonly y: number; readonly w: number; readonly h: number } => {\n  const { canvasWidth, canvasHeight, devicePixelRatio } = gridArea;\n\n  const plotLeftDevice = gridArea.left * devicePixelRatio;\n  const plotRightDevice = canvasWidth - gridArea.right * devicePixelRatio;\n  const plotTopDevice = gridArea.top * devicePixelRatio;\n  const plotBottomDevice = canvasHeight - gridArea.bottom * devicePixelRatio;\n\n  const scissorX = clampInt(Math.floor(plotLeftDevice), 0, Math.max(0, canvasWidth));\n  const scissorY = clampInt(Math.floor(plotTopDevice), 0, Math.max(0, canvasHeight));\n  const scissorR = clampInt(Math.ceil(plotRightDevice), 0, Math.max(0, canvasWidth));\n  const scissorB = clampInt(Math.ceil(plotBottomDevice), 0, Math.max(0, canvasHeight));\n  const scissorW = Math.max(0, scissorR - scissorX);\n  const scissorH = Math.max(0, scissorB - scissorY);\n\n  return { x: scissorX, y: scissorY, w: scissorW, h: scissorH };\n};\n\nconst computeCategoryStep = (data: ReadonlyArray<OHLCDataPoint>): number => {\n  const timestamps: number[] = [];\n  for (let i = 0; i < data.length; i++) {\n    const { timestamp } = getOHLC(data[i]);\n    if (Number.isFinite(timestamp)) timestamps.push(timestamp);\n  }\n\n  if (timestamps.length < 2) return 1;\n  timestamps.sort((a, b) => a - b);\n\n  let minStep = Number.POSITIVE_INFINITY;\n  for (let i = 1; i < timestamps.length; i++) {\n    const d = timestamps[i] - timestamps[i - 1];\n    if (d > 0 && d < minStep) minStep = d;\n  }\n  return Number.isFinite(minStep) && minStep > 0 ? minStep : 1;\n};\n\nconst computeCategoryWidthClip = (\n  xScale: LinearScale,\n  categoryStep: number,\n  plotClipRect: Readonly<{ width: number }>,\n  fallbackCategoryCount: number\n): number => {\n  if (Number.isFinite(categoryStep) && categoryStep > 0) {\n    const x0 = 0;\n    const p0 = xScale.scale(x0);\n    const p1 = xScale.scale(x0 + categoryStep);\n    const w = Math.abs(p1 - p0);\n    if (Number.isFinite(w) && w > 0) return w;\n  }\n\n  const clipWidth = Math.abs(plotClipRect.width);\n  if (!(clipWidth > 0)) return 0;\n  const n = Math.max(1, Math.floor(fallbackCategoryCount));\n  return clipWidth / n;\n};\n\nconst createIdentityMat4Buffer = (): ArrayBuffer => {\n  // Column-major identity mat4x4\n  const buffer = new ArrayBuffer(16 * 4);\n  new Float32Array(buffer).set([\n    1, 0, 0, 0, // col0\n    0, 1, 0, 0, // col1\n    0, 0, 1, 0, // col2\n    0, 0, 0, 1, // col3\n  ]);\n  return buffer;\n};\n\nexport function createCandlestickRenderer(device: GPUDevice, options?: CandlestickRendererOptions): CandlestickRenderer {\n  let disposed = false;\n  const targetFormat = options?.targetFormat ?? DEFAULT_TARGET_FORMAT;\n\n  const bindGroupLayout = device.createBindGroupLayout({\n    entries: [{ binding: 0, visibility: GPUShaderStage.VERTEX, buffer: { type: 'uniform' } }],\n  });\n\n  // VSUniforms: mat4x4 (64 bytes) + wickWidthClip f32 (4 bytes) + pad (12 bytes) = 80 bytes\n  const vsUniformBuffer = createUniformBuffer(device, 80, { label: 'candlestickRenderer/vsUniforms' });\n  writeUniformBuffer(device, vsUniformBuffer, createIdentityMat4Buffer()); // Default to identity\n\n  const vsUniformScratchBuffer = new ArrayBuffer(80);\n  const vsUniformScratchF32 = new Float32Array(vsUniformScratchBuffer);\n\n  const bindGroup = device.createBindGroup({\n    layout: bindGroupLayout,\n    entries: [{ binding: 0, resource: { buffer: vsUniformBuffer } }],\n  });\n\n  const pipeline = createRenderPipeline(device, {\n    label: 'candlestickRenderer/pipeline',\n    bindGroupLayouts: [bindGroupLayout],\n    vertex: {\n      code: candlestickWgsl,\n      label: 'candlestick.wgsl',\n      buffers: [\n        {\n          arrayStride: INSTANCE_STRIDE_BYTES,\n          stepMode: 'instance',\n          attributes: [\n            { shaderLocation: 0, format: 'float32', offset: 0 },\n            { shaderLocation: 1, format: 'float32', offset: 4 },\n            { shaderLocation: 2, format: 'float32', offset: 8 },\n            { shaderLocation: 3, format: 'float32', offset: 12 },\n            { shaderLocation: 4, format: 'float32', offset: 16 },\n            { shaderLocation: 5, format: 'float32', offset: 20 },\n            { shaderLocation: 6, format: 'float32x4', offset: 24 },\n          ],\n        },\n      ],\n    },\n    fragment: {\n      code: candlestickWgsl,\n      label: 'candlestick.wgsl',\n      formats: targetFormat,\n      blend: {\n        color: { operation: 'add', srcFactor: 'src-alpha', dstFactor: 'one-minus-src-alpha' },\n        alpha: { operation: 'add', srcFactor: 'one', dstFactor: 'one-minus-src-alpha' },\n      },\n    },\n    primitive: { topology: 'triangle-list', cullMode: 'none' },\n    multisample: { count: 1 },\n  });\n\n  let instanceBuffer: GPUBuffer | null = null;\n  let instanceCount = 0;\n  let cpuInstanceStagingBuffer = new ArrayBuffer(0);\n  let cpuInstanceStagingF32 = new Float32Array(cpuInstanceStagingBuffer);\n\n  let lastCanvasWidth = 0;\n  let lastCanvasHeight = 0;\n  let lastScissor: { readonly x: number; readonly y: number; readonly w: number; readonly h: number } | null = null;\n\n  // Hollow mode state\n  let hollowMode = false;\n  let hollowInstanceBuffer: GPUBuffer | null = null;\n  let hollowInstanceCount = 0;\n  let cpuHollowStagingBuffer = new ArrayBuffer(0);\n  let cpuHollowStagingF32 = new Float32Array(cpuHollowStagingBuffer);\n\n  const assertNotDisposed = (): void => {\n    if (disposed) throw new Error('CandlestickRenderer is disposed.');\n  };\n\n  const ensureCpuInstanceCapacityFloats = (requiredFloats: number): void => {\n    if (requiredFloats <= cpuInstanceStagingF32.length) return;\n    const nextFloats = Math.max(8, nextPow2(requiredFloats));\n    cpuInstanceStagingBuffer = new ArrayBuffer(nextFloats * 4);\n    cpuInstanceStagingF32 = new Float32Array(cpuInstanceStagingBuffer);\n  };\n\n  const ensureCpuHollowCapacityFloats = (requiredFloats: number): void => {\n    if (requiredFloats <= cpuHollowStagingF32.length) return;\n    const nextFloats = Math.max(8, nextPow2(requiredFloats));\n    cpuHollowStagingBuffer = new ArrayBuffer(nextFloats * 4);\n    cpuHollowStagingF32 = new Float32Array(cpuHollowStagingBuffer);\n  };\n\n  const prepare: CandlestickRenderer['prepare'] = (series, data, xScale, yScale, gridArea, backgroundColor) => {\n    assertNotDisposed();\n\n    if (data.length === 0) {\n      instanceCount = 0;\n      hollowInstanceCount = 0;\n      return;\n    }\n\n    const plotSize = computePlotSizeCssPx(gridArea);\n    if (!plotSize) {\n      instanceCount = 0;\n      hollowInstanceCount = 0;\n      return;\n    }\n\n    const plotClipRect = computePlotClipRect(gridArea);\n    const clipPerCssX = plotSize.plotWidthCss > 0 ? plotClipRect.width / plotSize.plotWidthCss : 0;\n\n    lastCanvasWidth = gridArea.canvasWidth;\n    lastCanvasHeight = gridArea.canvasHeight;\n    lastScissor = computePlotScissorDevicePx(gridArea);\n\n    // Compute category step and width\n    const categoryStep = computeCategoryStep(data);\n    const categoryWidthClip = computeCategoryWidthClip(xScale, categoryStep, plotClipRect, data.length);\n\n    // Compute body width in clip space\n    let bodyWidthClip = 0;\n    const rawBarWidth = series.barWidth;\n    if (typeof rawBarWidth === 'number') {\n      bodyWidthClip = Math.max(0, rawBarWidth) * clipPerCssX;\n    } else if (typeof rawBarWidth === 'string') {\n      const p = parsePercent(rawBarWidth);\n      bodyWidthClip = p == null ? 0 : categoryWidthClip * clamp01(p);\n    }\n\n    // Apply min/max width constraints (CSS pixels converted to clip space)\n    const minWidthClip = series.barMinWidth * clipPerCssX;\n    const maxWidthClip = series.barMaxWidth * clipPerCssX;\n    bodyWidthClip = Math.min(Math.max(bodyWidthClip, minWidthClip), maxWidthClip);\n\n    // Compute wick width in clip space (default 1px CSS)\n    const wickWidthCssPx = series.itemStyle.borderWidth ?? DEFAULT_WICK_WIDTH_CSS_PX;\n    const wickWidthClip = Math.max(0, wickWidthCssPx) * clipPerCssX;\n\n    // Write VS uniforms (identity transform + wick width)\n    vsUniformScratchF32.set([\n      1, 0, 0, 0, // col0\n      0, 1, 0, 0, // col1\n      0, 0, 1, 0, // col2\n      0, 0, 0, 1, // col3\n      wickWidthClip,\n      0,\n      0,\n      0,\n    ]);\n    writeUniformBuffer(device, vsUniformBuffer, vsUniformScratchBuffer);\n\n    // Parse colors\n    const upColor = parseSeriesColorToRgba01(series.itemStyle.upColor);\n    const downColor = parseSeriesColorToRgba01(series.itemStyle.downColor);\n    const upBorderColor = parseSeriesColorToRgba01(series.itemStyle.upBorderColor);\n    const downBorderColor = parseSeriesColorToRgba01(series.itemStyle.downBorderColor);\n    const bgColor = backgroundColor ? parseSeriesColorToRgba01(backgroundColor) : ([0, 0, 0, 1] as const);\n\n    hollowMode = series.style === 'hollow';\n\n    ensureCpuInstanceCapacityFloats(data.length * INSTANCE_STRIDE_FLOATS);\n    const f32 = cpuInstanceStagingF32;\n    let outFloats = 0;\n\n    if (hollowMode) {\n      ensureCpuHollowCapacityFloats(data.length * INSTANCE_STRIDE_FLOATS);\n    }\n    const hollowF32 = cpuHollowStagingF32;\n    let hollowOutFloats = 0;\n\n    for (let i = 0; i < data.length; i++) {\n      const { timestamp, open, close, low, high } = getOHLC(data[i]);\n      if (!Number.isFinite(timestamp) || !Number.isFinite(open) || !Number.isFinite(close) || !Number.isFinite(low) || !Number.isFinite(high)) {\n        continue;\n      }\n\n      const xClip = xScale.scale(timestamp);\n      const openClip = yScale.scale(open);\n      const closeClip = yScale.scale(close);\n      const lowClip = yScale.scale(low);\n      const highClip = yScale.scale(high);\n\n      if (!Number.isFinite(xClip) || !Number.isFinite(openClip) || !Number.isFinite(closeClip) || !Number.isFinite(lowClip) || !Number.isFinite(highClip)) {\n        continue;\n      }\n\n      const isUp = close > open;\n\n      if (hollowMode) {\n        // Pass 1: Draw all candles with border colors (body + wicks)\n        const borderColor = isUp ? upBorderColor : downBorderColor;\n        f32[outFloats + 0] = xClip;\n        f32[outFloats + 1] = openClip;\n        f32[outFloats + 2] = closeClip;\n        f32[outFloats + 3] = lowClip;\n        f32[outFloats + 4] = highClip;\n        f32[outFloats + 5] = bodyWidthClip;\n        f32[outFloats + 6] = borderColor[0];\n        f32[outFloats + 7] = borderColor[1];\n        f32[outFloats + 8] = borderColor[2];\n        f32[outFloats + 9] = borderColor[3];\n        outFloats += INSTANCE_STRIDE_FLOATS;\n\n        // Pass 2: For UP candles only, draw body inset with background color to punch out interior\n        if (isUp) {\n          const borderWidthClip = series.itemStyle.borderWidth * clipPerCssX;\n          const insetBodyWidthClip = Math.max(0, bodyWidthClip - 2 * borderWidthClip);\n\n          hollowF32[hollowOutFloats + 0] = xClip;\n          hollowF32[hollowOutFloats + 1] = openClip;\n          hollowF32[hollowOutFloats + 2] = closeClip;\n          hollowF32[hollowOutFloats + 3] = lowClip; // Not used for body-only draw, but keep for consistency\n          hollowF32[hollowOutFloats + 4] = highClip; // Not used for body-only draw\n          hollowF32[hollowOutFloats + 5] = insetBodyWidthClip;\n          hollowF32[hollowOutFloats + 6] = bgColor[0];\n          hollowF32[hollowOutFloats + 7] = bgColor[1];\n          hollowF32[hollowOutFloats + 8] = bgColor[2];\n          hollowF32[hollowOutFloats + 9] = bgColor[3];\n          hollowOutFloats += INSTANCE_STRIDE_FLOATS;\n        }\n      } else {\n        // Classic mode: draw candles with fill colors\n        const fillColor = isUp ? upColor : downColor;\n        f32[outFloats + 0] = xClip;\n        f32[outFloats + 1] = openClip;\n        f32[outFloats + 2] = closeClip;\n        f32[outFloats + 3] = lowClip;\n        f32[outFloats + 4] = highClip;\n        f32[outFloats + 5] = bodyWidthClip;\n        f32[outFloats + 6] = fillColor[0];\n        f32[outFloats + 7] = fillColor[1];\n        f32[outFloats + 8] = fillColor[2];\n        f32[outFloats + 9] = fillColor[3];\n        outFloats += INSTANCE_STRIDE_FLOATS;\n      }\n    }\n\n    instanceCount = outFloats / INSTANCE_STRIDE_FLOATS;\n    hollowInstanceCount = hollowOutFloats / INSTANCE_STRIDE_FLOATS;\n\n    // Upload primary instance buffer\n    const requiredBytes = Math.max(4, instanceCount * INSTANCE_STRIDE_BYTES);\n    if (!instanceBuffer || instanceBuffer.size < requiredBytes) {\n      const grownBytes = Math.max(Math.max(4, nextPow2(requiredBytes)), instanceBuffer ? instanceBuffer.size : 0);\n      if (instanceBuffer) {\n        try {\n          instanceBuffer.destroy();\n        } catch {\n          // best-effort\n        }\n      }\n      instanceBuffer = device.createBuffer({\n        label: 'candlestickRenderer/instanceBuffer',\n        size: grownBytes,\n        usage: GPUBufferUsage.VERTEX | GPUBufferUsage.COPY_DST,\n      });\n    }\n\n    if (instanceCount > 0) {\n      device.queue.writeBuffer(instanceBuffer, 0, cpuInstanceStagingBuffer, 0, instanceCount * INSTANCE_STRIDE_BYTES);\n    }\n\n    // Upload hollow mode buffer (second pass)\n    if (hollowMode && hollowInstanceCount > 0) {\n      const hollowRequiredBytes = Math.max(4, hollowInstanceCount * INSTANCE_STRIDE_BYTES);\n      if (!hollowInstanceBuffer || hollowInstanceBuffer.size < hollowRequiredBytes) {\n        const grownBytes = Math.max(Math.max(4, nextPow2(hollowRequiredBytes)), hollowInstanceBuffer ? hollowInstanceBuffer.size : 0);\n        if (hollowInstanceBuffer) {\n          try {\n            hollowInstanceBuffer.destroy();\n          } catch {\n            // best-effort\n          }\n        }\n        hollowInstanceBuffer = device.createBuffer({\n          label: 'candlestickRenderer/hollowInstanceBuffer',\n          size: grownBytes,\n          usage: GPUBufferUsage.VERTEX | GPUBufferUsage.COPY_DST,\n        });\n      }\n      device.queue.writeBuffer(hollowInstanceBuffer, 0, cpuHollowStagingBuffer, 0, hollowInstanceCount * INSTANCE_STRIDE_BYTES);\n    }\n  };\n\n  const render: CandlestickRenderer['render'] = (passEncoder) => {\n    assertNotDisposed();\n\n    if (!instanceBuffer || instanceCount === 0) return;\n\n    // Apply scissor rect to clip to plot area\n    if (lastScissor && lastCanvasWidth > 0 && lastCanvasHeight > 0) {\n      passEncoder.setScissorRect(lastScissor.x, lastScissor.y, lastScissor.w, lastScissor.h);\n    }\n\n    passEncoder.setPipeline(pipeline);\n    passEncoder.setBindGroup(0, bindGroup);\n\n    // Pass 1: Draw all candles (18 vertices per instance)\n    passEncoder.setVertexBuffer(0, instanceBuffer);\n    passEncoder.draw(18, instanceCount);\n\n    // Pass 2: For hollow mode, draw body-only punch-out for UP candles\n    if (hollowMode && hollowInstanceBuffer && hollowInstanceCount > 0) {\n      passEncoder.setVertexBuffer(0, hollowInstanceBuffer);\n      // Draw only body vertices (0-5) by drawing 6 vertices per instance\n      passEncoder.draw(6, hollowInstanceCount);\n    }\n\n    // Reset scissor to full canvas\n    if (lastScissor && lastCanvasWidth > 0 && lastCanvasHeight > 0) {\n      passEncoder.setScissorRect(0, 0, lastCanvasWidth, lastCanvasHeight);\n    }\n  };\n\n  const dispose: CandlestickRenderer['dispose'] = () => {\n    if (disposed) return;\n    disposed = true;\n\n    if (instanceBuffer) {\n      try {\n        instanceBuffer.destroy();\n      } catch {\n        // best-effort\n      }\n    }\n    instanceBuffer = null;\n    instanceCount = 0;\n\n    if (hollowInstanceBuffer) {\n      try {\n        hollowInstanceBuffer.destroy();\n      } catch {\n        // best-effort\n      }\n    }\n    hollowInstanceBuffer = null;\n    hollowInstanceCount = 0;\n\n    try {\n      vsUniformBuffer.destroy();\n    } catch {\n      // best-effort\n    }\n\n    lastCanvasWidth = 0;\n    lastCanvasHeight = 0;\n    lastScissor = null;\n  };\n\n  return { prepare, render, dispose };\n}\n","export default \"// crosshair.wgsl\\n// Minimal crosshair line shader:\\n// - Vertex input: vec2<f32> position in clip-space coordinates\\n// - VS uniform: transform mat4 (identity)\\n// - FS uniform: solid RGBA color\\n\\nstruct VSUniforms {\\n  transform: mat4x4<f32>,\\n};\\n\\n@group(0) @binding(0) var<uniform> vsUniforms: VSUniforms;\\n\\nstruct FSUniforms {\\n  color: vec4<f32>,\\n};\\n\\n@group(0) @binding(1) var<uniform> fsUniforms: FSUniforms;\\n\\nstruct VSIn {\\n  @location(0) position: vec2<f32>,\\n};\\n\\nstruct VSOut {\\n  @builtin(position) clipPosition: vec4<f32>,\\n};\\n\\n@vertex\\nfn vsMain(in: VSIn) -> VSOut {\\n  var out: VSOut;\\n  out.clipPosition = vsUniforms.transform * vec4<f32>(in.position, 0.0, 1.0);\\n  return out;\\n}\\n\\n@fragment\\nfn fsMain() -> @location(0) vec4<f32> {\\n  return fsUniforms.color;\\n}\\n\\n\"","export interface StreamBuffer {\n  /**\n   * Writes a new vertex payload into the streaming buffer.\n   *\n   * Notes:\n   * - `data` is interpreted as interleaved `vec2<f32>` vertices: `[x0, y0, x1, y1, ...]`.\n   * - Uses double buffering (alternates GPU buffers each write) to avoid writing into the same\n   *   buffer the GPU might still be reading from the prior frame.\n   * - Uses a per-buffer CPU mirror (Uint32 bit patterns) to compute partial updates.\n   */\n  write(data: Float32Array): void;\n  /** Returns the GPUBuffer that contains the most recently written data. */\n  getBuffer(): GPUBuffer;\n  /** Returns the vertex count for the most recently written data. */\n  getVertexCount(): number;\n  /** Destroys GPU resources (best-effort). Safe to call multiple times. */\n  dispose(): void;\n}\n\nconst align4 = (n: number): number => (n + 3) & ~3;\n\n// Small payloads are cheaper to just full-write (avoid diff overhead).\nconst SMALL_FULL_WRITE_MAX_BYTES = 1024;\n\n// Heuristic guard against pathological alternating-word diffs which would produce many tiny ranges.\n// If exceeded, we do a single full-range write for the used bytes.\nconst MAX_DIFF_RANGES_BEFORE_FULL_WRITE = 128;\nconst MAX_CHANGED_WORDS_BEFORE_FULL_WRITE = 16_384;\n\nconst toU32View = (data: Float32Array): Uint32Array => {\n  if ((data.byteOffset & 3) !== 0) {\n    // This should never happen for Float32Array, but keep it explicit for correctness.\n    throw new Error('createStreamBuffer.write: data.byteOffset must be 4-byte aligned.');\n  }\n  return new Uint32Array(data.buffer, data.byteOffset, data.byteLength >>> 2);\n};\n\nexport function createStreamBuffer(device: GPUDevice, maxSize: number): StreamBuffer {\n  if (!Number.isFinite(maxSize) || maxSize <= 0) {\n    throw new Error(`createStreamBuffer(maxSize): maxSize (bytes) must be a positive number. Received: ${String(maxSize)}`);\n  }\n\n  const clamped = Math.max(4, Math.floor(maxSize));\n  const capacityBytes = align4(clamped);\n\n  const limit = device.limits.maxBufferSize;\n  if (capacityBytes > limit) {\n    throw new Error(\n      `createStreamBuffer(maxSize): requested size ${capacityBytes} bytes exceeds device.limits.maxBufferSize (${limit}).`\n    );\n  }\n\n  const capacityWords = capacityBytes >>> 2;\n\n  const createSlot = (label: string): { readonly buffer: GPUBuffer; readonly mirror: Uint32Array } => ({\n    buffer: device.createBuffer({\n      label,\n      size: capacityBytes,\n      usage: GPUBufferUsage.VERTEX | GPUBufferUsage.COPY_DST,\n    }),\n    mirror: new Uint32Array(capacityWords),\n  });\n\n  const slots = [createSlot('streamBuffer/a'), createSlot('streamBuffer/b')] as const;\n\n  let disposed = false;\n  let currentIndex = 0; // getBuffer() returns slots[currentIndex]\n  let vertexCount = 0;\n\n  const assertNotDisposed = (): void => {\n    if (disposed) throw new Error('createStreamBuffer: StreamBuffer is disposed.');\n  };\n\n  const writeFull = (slotIndex: number, newWords: Uint32Array, usedWords: number): void => {\n    const slot = slots[slotIndex];\n    const mirror = slot.mirror;\n\n    if (usedWords < 0 || usedWords > newWords.length) {\n      throw new Error('createStreamBuffer.write: internal error (invalid usedWords).');\n    }\n    if (usedWords === 0) return;\n\n    const usedBytes = usedWords << 2;\n    device.queue.writeBuffer(slot.buffer, 0, newWords.buffer, newWords.byteOffset, usedBytes);\n    mirror.set(newWords.subarray(0, usedWords), 0);\n  };\n\n  const writeRangesByDiff = (slotIndex: number, newWords: Uint32Array, usedWords: number): void => {\n    const slot = slots[slotIndex];\n    const mirror = slot.mirror;\n\n    // Guard against programming errors.\n    if (usedWords < 0 || usedWords > newWords.length) {\n      throw new Error('createStreamBuffer.write: internal error (invalid usedWords).');\n    }\n\n    // Small-buffer fast path: diffing overhead dominates.\n    const usedBytes = usedWords << 2;\n    if (usedBytes > 0 && usedBytes <= SMALL_FULL_WRITE_MAX_BYTES) {\n      writeFull(slotIndex, newWords, usedWords);\n      return;\n    }\n\n    // First pass: collect ranges and decide whether we should fall back to a full write.\n    const ranges: Array<[start: number, end: number]> = [];\n    let rangeCount = 0;\n    let changedWords = 0;\n\n    let i = 0;\n    while (i < usedWords) {\n      // Find first differing word.\n      while (i < usedWords && mirror[i] === newWords[i]) i++;\n      if (i >= usedWords) break;\n\n      const start = i;\n      i++;\n      // Extend to contiguous run of differing words.\n      while (i < usedWords && mirror[i] !== newWords[i]) i++;\n      const end = i;\n\n      ranges.push([start, end]);\n      rangeCount++;\n      changedWords += end - start;\n\n      // Pathological case guard: alternating changes can create many tiny ranges.\n      if (rangeCount > MAX_DIFF_RANGES_BEFORE_FULL_WRITE || changedWords > MAX_CHANGED_WORDS_BEFORE_FULL_WRITE) {\n        writeFull(slotIndex, newWords, usedWords);\n        return;\n      }\n    }\n\n    // Second pass: apply range writes.\n    for (let r = 0; r < ranges.length; r++) {\n      const [start, end] = ranges[r];\n      const byteOffset = start << 2;\n      const byteSize = (end - start) << 2;\n\n      // WebGPU requires offsets/sizes to be multiples of 4 bytes (satisfied by word addressing).\n      device.queue.writeBuffer(slot.buffer, byteOffset, newWords.buffer, newWords.byteOffset + byteOffset, byteSize);\n      mirror.set(newWords.subarray(start, end), start);\n    }\n  };\n\n  const write: StreamBuffer['write'] = (data) => {\n    assertNotDisposed();\n\n    if (data.length & 1) {\n      throw new Error('createStreamBuffer.write: data length must be even (vec2<f32> vertices).');\n    }\n\n    const bytes = data.byteLength;\n    if (bytes > capacityBytes) {\n      throw new Error(\n        `createStreamBuffer.write: data.byteLength (${bytes}) exceeds capacity (${capacityBytes}). Increase maxSize.`\n      );\n    }\n\n    const nextVertexCount = data.length >>> 1;\n    if (bytes === 0) {\n      // Avoid swapping buffers for empty payloads.\n      vertexCount = nextVertexCount;\n      return;\n    }\n\n    const words = toU32View(data);\n    const nextIndex = 1 - currentIndex;\n\n    // Only swap after the write succeeds so we never expose a partially-updated \"current\" buffer.\n    writeRangesByDiff(nextIndex, words, words.length);\n    currentIndex = nextIndex;\n    vertexCount = nextVertexCount;\n  };\n\n  const getBuffer: StreamBuffer['getBuffer'] = () => {\n    assertNotDisposed();\n    return slots[currentIndex].buffer;\n  };\n\n  const getVertexCount: StreamBuffer['getVertexCount'] = () => {\n    assertNotDisposed();\n    return vertexCount;\n  };\n\n  const dispose: StreamBuffer['dispose'] = () => {\n    if (disposed) return;\n    disposed = true;\n    vertexCount = 0;\n\n    for (const slot of slots) {\n      try {\n        slot.buffer.destroy();\n      } catch {\n        // best-effort\n      }\n    }\n  };\n\n  return { write, getBuffer, getVertexCount, dispose };\n}\n\n","import crosshairWgsl from '../shaders/crosshair.wgsl?raw';\nimport { createStreamBuffer } from '../data/createStreamBuffer';\nimport { parseCssColorToRgba01 } from '../utils/colors';\nimport { createRenderPipeline, createUniformBuffer, writeUniformBuffer } from './rendererUtils';\nimport type { GridArea } from './createGridRenderer';\n\nexport interface CrosshairRenderOptions {\n  /** Whether to render the vertical crosshair line. */\n  readonly showX: boolean;\n  /** Whether to render the horizontal crosshair line. */\n  readonly showY: boolean;\n  /** CSS color string for the crosshair lines. */\n  readonly color: string;\n  /**\n   * Desired line width in CSS pixels.\n   *\n   * Note: WebGPU wide lines are not reliably supported; the renderer emulates thickness by\n   * drawing multiple 1px lines in device-pixel offsets (best-effort, deterministic).\n   */\n  readonly lineWidth: number;\n}\n\nexport interface CrosshairRenderer {\n  /**\n   * Positions the crosshair for rendering.\n   *\n   * Coordinate contract:\n   * - `x`, `y` are CANVAS-LOCAL CSS pixels (e.g. eventManager payload x/y)\n   * - `gridArea` margins are CSS pixels; `gridArea.canvasWidth/Height` are device pixels\n   */\n  prepare(x: number, y: number, gridArea: GridArea, options: CrosshairRenderOptions): void;\n  /** Draws the crosshair (if visible) clipped to the plot rect. */\n  render(passEncoder: GPURenderPassEncoder): void;\n  /** Shows/hides the crosshair without destroying GPU resources. */\n  setVisible(visible: boolean): void;\n  /** Cleans up GPU resources (best-effort). */\n  dispose(): void;\n}\n\nexport interface CrosshairRendererOptions {\n  /**\n   * Must match the canvas context format used for the render pass color attachment.\n   * Usually this is `gpuContext.preferredFormat`.\n   *\n   * Defaults to `'bgra8unorm'` for backward compatibility.\n   */\n  readonly targetFormat?: GPUTextureFormat;\n}\n\nconst DEFAULT_TARGET_FORMAT: GPUTextureFormat = 'bgra8unorm';\nconst DEFAULT_CROSSHAIR_RGBA: readonly [number, number, number, number] = [1, 1, 1, 0.8];\n\nconst MAX_THICKNESS_DEVICE_PX = 8;\nconst DASH_ON_DEVICE_PX = 6;\nconst DASH_OFF_DEVICE_PX = 4;\n\n// Hard cap to keep CPU-side dash segmentation inexpensive/deterministic.\nconst MAX_VERTICES = 8192; // vec2<f32> vertices, i.e. floats/2.\n\nconst createIdentityMat4Buffer = (): ArrayBuffer => {\n  // Column-major identity mat4x4\n  const buffer = new ArrayBuffer(16 * 4);\n  new Float32Array(buffer).set([\n    1, 0, 0, 0, // col0\n    0, 1, 0, 0, // col1\n    0, 0, 1, 0, // col2\n    0, 0, 0, 1, // col3\n  ]);\n  return buffer;\n};\n\nconst isFiniteGridArea = (gridArea: GridArea): boolean =>\n  Number.isFinite(gridArea.left) &&\n  Number.isFinite(gridArea.right) &&\n  Number.isFinite(gridArea.top) &&\n  Number.isFinite(gridArea.bottom) &&\n  Number.isFinite(gridArea.canvasWidth) &&\n  Number.isFinite(gridArea.canvasHeight);\n\nconst clampInt = (v: number, lo: number, hi: number): number => Math.min(hi, Math.max(lo, v | 0));\n\nconst computeThicknessOffsetsDevicePx = (lineWidthCssPx: number, dpr: number): readonly number[] => {\n  if (!Number.isFinite(lineWidthCssPx) || lineWidthCssPx < 0) {\n    throw new Error('CrosshairRenderer.prepare: lineWidth must be a finite non-negative number.');\n  }\n  if (lineWidthCssPx === 0) return [];\n\n  // Convert to device px, then clamp to a small deterministic maximum.\n  const widthDevicePx = lineWidthCssPx * dpr;\n  const thickness = Math.max(1, Math.min(MAX_THICKNESS_DEVICE_PX, Math.round(widthDevicePx)));\n\n  // Symmetric offsets around center (even thickness yields ±0.5 style offsets).\n  const mid = (thickness - 1) / 2;\n  const out: number[] = [];\n  for (let i = 0; i < thickness; i++) out.push(i - mid);\n  return out;\n};\n\nconst devicePxToClipX = (xDevicePx: number, canvasWidthDevicePx: number): number =>\n  (xDevicePx / canvasWidthDevicePx) * 2.0 - 1.0;\nconst devicePxToClipY = (yDevicePx: number, canvasHeightDevicePx: number): number =>\n  1.0 - (yDevicePx / canvasHeightDevicePx) * 2.0;\n\ntype Segment2D = readonly [x0: number, y0: number, x1: number, y1: number];\n\nconst appendSegmentVerticesClip = (out: number[], seg: Segment2D): void => {\n  out.push(seg[0], seg[1], seg[2], seg[3]);\n};\n\nconst generateDashedSegmentsAxisAligned = (start: number, end: number): readonly [number, number][] => {\n  // Returns a list of [a,b] segments in *device* space along a single axis.\n  if (!Number.isFinite(start) || !Number.isFinite(end)) return [];\n\n  const a0 = Math.min(start, end);\n  const a1 = Math.max(start, end);\n  if (a1 <= a0) return [];\n\n  const on = DASH_ON_DEVICE_PX;\n  const off = DASH_OFF_DEVICE_PX;\n  const period = on + off;\n  if (period <= 0 || !Number.isFinite(period)) return [];\n\n  // Conservative cap: if this many segments would exceed MAX_VERTICES after thickness expansion,\n  // the caller will fall back to a single solid segment.\n  const approxSegments = Math.ceil((a1 - a0) / period);\n  if (!Number.isFinite(approxSegments) || approxSegments <= 0) return [];\n\n  const segments: Array<[number, number]> = [];\n  let t = a0;\n  while (t < a1) {\n    const s0 = t;\n    const s1 = Math.min(t + on, a1);\n    if (s1 > s0) segments.push([s0, s1]);\n    t += period;\n  }\n  return segments;\n};\n\nconst generateCrosshairVertices = (\n  xCssPx: number,\n  yCssPx: number,\n  gridArea: GridArea,\n  options: CrosshairRenderOptions\n): {\n  readonly vertices: Float32Array;\n  readonly scissor: { readonly x: number; readonly y: number; readonly w: number; readonly h: number };\n} => {\n  if (!Number.isFinite(xCssPx) || !Number.isFinite(yCssPx)) {\n    throw new Error('CrosshairRenderer.prepare: x and y must be finite numbers.');\n  }\n  if (!isFiniteGridArea(gridArea)) {\n    throw new Error('CrosshairRenderer.prepare: gridArea dimensions must be finite numbers.');\n  }\n  if (gridArea.canvasWidth <= 0 || gridArea.canvasHeight <= 0) {\n    throw new Error('CrosshairRenderer.prepare: canvas dimensions must be positive.');\n  }\n  if (gridArea.left < 0 || gridArea.right < 0 || gridArea.top < 0 || gridArea.bottom < 0) {\n    throw new Error('CrosshairRenderer.prepare: gridArea margins must be non-negative.');\n  }\n\n  const { canvasWidth, canvasHeight } = gridArea;\n  // Be resilient: older call sites may omit/incorrectly pass DPR. Defaulting avoids hard crashes.\n  const devicePixelRatio =\n    Number.isFinite(gridArea.devicePixelRatio) && gridArea.devicePixelRatio > 0 ? gridArea.devicePixelRatio : 1;\n\n  const plotLeftDevice = gridArea.left * devicePixelRatio;\n  const plotRightDevice = canvasWidth - gridArea.right * devicePixelRatio;\n  const plotTopDevice = gridArea.top * devicePixelRatio;\n  const plotBottomDevice = canvasHeight - gridArea.bottom * devicePixelRatio;\n\n  const scissorX = clampInt(Math.floor(plotLeftDevice), 0, Math.max(0, canvasWidth));\n  const scissorY = clampInt(Math.floor(plotTopDevice), 0, Math.max(0, canvasHeight));\n  const scissorR = clampInt(Math.ceil(plotRightDevice), 0, Math.max(0, canvasWidth));\n  const scissorB = clampInt(Math.ceil(plotBottomDevice), 0, Math.max(0, canvasHeight));\n  const scissorW = Math.max(0, scissorR - scissorX);\n  const scissorH = Math.max(0, scissorB - scissorY);\n\n  // Convert the requested position from CSS px (canvas-local) to device px.\n  const xDevice = xCssPx * devicePixelRatio;\n  const yDevice = yCssPx * devicePixelRatio;\n\n  const thicknessOffsets = computeThicknessOffsetsDevicePx(options.lineWidth, devicePixelRatio);\n  if (thicknessOffsets.length === 0 || (!options.showX && !options.showY)) {\n    return {\n      vertices: new Float32Array(0),\n      scissor: { x: scissorX, y: scissorY, w: scissorW, h: scissorH },\n    };\n  }\n\n  const floats: number[] = [];\n\n  // Compute how many dashed segments we *might* generate and fall back to solid if too many.\n  const dashSegmentsY = options.showX ? generateDashedSegmentsAxisAligned(plotTopDevice, plotBottomDevice) : [];\n  const dashSegmentsX = options.showY ? generateDashedSegmentsAxisAligned(plotLeftDevice, plotRightDevice) : [];\n\n  const segmentsPerThickness =\n    (options.showX ? dashSegmentsY.length : 0) + (options.showY ? dashSegmentsX.length : 0);\n  const projectedVertexCount = segmentsPerThickness * thicknessOffsets.length * 2; // 2 vertices per segment\n\n  const useDashed = projectedVertexCount > 0 && projectedVertexCount <= MAX_VERTICES;\n\n  const addVerticalSolid = (xDevicePx: number): void => {\n    const xClip = devicePxToClipX(xDevicePx, canvasWidth);\n    const y0 = devicePxToClipY(plotTopDevice, canvasHeight);\n    const y1 = devicePxToClipY(plotBottomDevice, canvasHeight);\n    appendSegmentVerticesClip(floats, [xClip, y0, xClip, y1]);\n  };\n\n  const addHorizontalSolid = (yDevicePx: number): void => {\n    const yClip = devicePxToClipY(yDevicePx, canvasHeight);\n    const x0 = devicePxToClipX(plotLeftDevice, canvasWidth);\n    const x1 = devicePxToClipX(plotRightDevice, canvasWidth);\n    appendSegmentVerticesClip(floats, [x0, yClip, x1, yClip]);\n  };\n\n  if (options.showX) {\n    for (let i = 0; i < thicknessOffsets.length; i++) {\n      const xd = xDevice + thicknessOffsets[i];\n      if (!useDashed) {\n        addVerticalSolid(xd);\n        continue;\n      }\n\n      const xClip = devicePxToClipX(xd, canvasWidth);\n      for (let s = 0; s < dashSegmentsY.length; s++) {\n        const [ya, yb] = dashSegmentsY[s];\n        const y0 = devicePxToClipY(ya, canvasHeight);\n        const y1 = devicePxToClipY(yb, canvasHeight);\n        appendSegmentVerticesClip(floats, [xClip, y0, xClip, y1]);\n      }\n    }\n  }\n\n  if (options.showY) {\n    for (let i = 0; i < thicknessOffsets.length; i++) {\n      const yd = yDevice + thicknessOffsets[i];\n      if (!useDashed) {\n        addHorizontalSolid(yd);\n        continue;\n      }\n\n      const yClip = devicePxToClipY(yd, canvasHeight);\n      for (let s = 0; s < dashSegmentsX.length; s++) {\n        const [xa, xb] = dashSegmentsX[s];\n        const x0 = devicePxToClipX(xa, canvasWidth);\n        const x1 = devicePxToClipX(xb, canvasWidth);\n        appendSegmentVerticesClip(floats, [x0, yClip, x1, yClip]);\n      }\n    }\n  }\n\n  const vertices = new Float32Array(floats);\n  return { vertices, scissor: { x: scissorX, y: scissorY, w: scissorW, h: scissorH } };\n};\n\nexport function createCrosshairRenderer(device: GPUDevice, options?: CrosshairRendererOptions): CrosshairRenderer {\n  let disposed = false;\n  let visible = true;\n\n  const targetFormat = options?.targetFormat ?? DEFAULT_TARGET_FORMAT;\n\n  const bindGroupLayout = device.createBindGroupLayout({\n    entries: [\n      { binding: 0, visibility: GPUShaderStage.VERTEX, buffer: { type: 'uniform' } },\n      { binding: 1, visibility: GPUShaderStage.FRAGMENT, buffer: { type: 'uniform' } },\n    ],\n  });\n\n  const vsUniformBuffer = createUniformBuffer(device, 64, { label: 'crosshairRenderer/vsUniforms' });\n  const fsUniformBuffer = createUniformBuffer(device, 16, { label: 'crosshairRenderer/fsUniforms' });\n\n  const bindGroup = device.createBindGroup({\n    layout: bindGroupLayout,\n    entries: [\n      { binding: 0, resource: { buffer: vsUniformBuffer } },\n      { binding: 1, resource: { buffer: fsUniformBuffer } },\n    ],\n  });\n\n  const pipeline = createRenderPipeline(device, {\n    label: 'crosshairRenderer/pipeline',\n    bindGroupLayouts: [bindGroupLayout],\n    vertex: {\n      code: crosshairWgsl,\n      label: 'crosshair.wgsl',\n      buffers: [\n        {\n          arrayStride: 8,\n          stepMode: 'vertex',\n          attributes: [{ shaderLocation: 0, format: 'float32x2', offset: 0 }],\n        },\n      ],\n    },\n    fragment: {\n      code: crosshairWgsl,\n      label: 'crosshair.wgsl',\n      formats: targetFormat,\n      blend: {\n        color: { operation: 'add', srcFactor: 'src-alpha', dstFactor: 'one-minus-src-alpha' },\n        alpha: { operation: 'add', srcFactor: 'one', dstFactor: 'one-minus-src-alpha' },\n      },\n    },\n    primitive: { topology: 'line-list', cullMode: 'none' },\n    multisample: { count: 1 },\n  });\n\n  const stream = createStreamBuffer(device, MAX_VERTICES * 8);\n  let vertexCount = 0;\n  let lastCanvasWidth = 0;\n  let lastCanvasHeight = 0;\n  let lastScissor = { x: 0, y: 0, w: 0, h: 0 };\n\n  const assertNotDisposed = (): void => {\n    if (disposed) throw new Error('CrosshairRenderer is disposed.');\n  };\n\n  const prepare: CrosshairRenderer['prepare'] = (x, y, gridArea, renderOptions) => {\n    assertNotDisposed();\n\n    // Validate options up-front for deterministic behavior.\n    if (typeof renderOptions.showX !== 'boolean' || typeof renderOptions.showY !== 'boolean') {\n      throw new Error('CrosshairRenderer.prepare: showX/showY must be boolean.');\n    }\n    if (typeof renderOptions.color !== 'string') {\n      throw new Error('CrosshairRenderer.prepare: color must be a string.');\n    }\n    if (!Number.isFinite(renderOptions.lineWidth) || renderOptions.lineWidth < 0) {\n      throw new Error('CrosshairRenderer.prepare: lineWidth must be a finite non-negative number.');\n    }\n\n    const { vertices, scissor } = generateCrosshairVertices(x, y, gridArea, renderOptions);\n    if (vertices.byteLength === 0) {\n      vertexCount = 0;\n    } else {\n      stream.write(vertices);\n      vertexCount = stream.getVertexCount();\n    }\n\n    // Identity transform (vertices are already in clip-space).\n    writeUniformBuffer(device, vsUniformBuffer, createIdentityMat4Buffer());\n\n    // Color.\n    const rgba = parseCssColorToRgba01(renderOptions.color) ?? DEFAULT_CROSSHAIR_RGBA;\n    const colorBuffer = new ArrayBuffer(4 * 4);\n    new Float32Array(colorBuffer).set([rgba[0], rgba[1], rgba[2], rgba[3]]);\n    writeUniformBuffer(device, fsUniformBuffer, colorBuffer);\n\n    lastCanvasWidth = gridArea.canvasWidth;\n    lastCanvasHeight = gridArea.canvasHeight;\n    lastScissor = scissor;\n  };\n\n  const render: CrosshairRenderer['render'] = (passEncoder) => {\n    assertNotDisposed();\n    if (!visible) return;\n    if (vertexCount === 0) return;\n    if (lastCanvasWidth <= 0 || lastCanvasHeight <= 0) return;\n\n    // Clip to plot area (device pixels).\n    passEncoder.setScissorRect(lastScissor.x, lastScissor.y, lastScissor.w, lastScissor.h);\n\n    passEncoder.setPipeline(pipeline);\n    passEncoder.setBindGroup(0, bindGroup);\n    passEncoder.setVertexBuffer(0, stream.getBuffer());\n    passEncoder.draw(vertexCount);\n\n    // Reset scissor to full canvas (avoid affecting subsequent renderers).\n    passEncoder.setScissorRect(0, 0, lastCanvasWidth, lastCanvasHeight);\n  };\n\n  const setVisible: CrosshairRenderer['setVisible'] = (v) => {\n    assertNotDisposed();\n    visible = Boolean(v);\n  };\n\n  const dispose: CrosshairRenderer['dispose'] = () => {\n    if (disposed) return;\n    disposed = true;\n\n    try {\n      vsUniformBuffer.destroy();\n    } catch {\n      // best-effort\n    }\n    try {\n      fsUniformBuffer.destroy();\n    } catch {\n      // best-effort\n    }\n    stream.dispose();\n\n    vertexCount = 0;\n    lastCanvasWidth = 0;\n    lastCanvasHeight = 0;\n    lastScissor = { x: 0, y: 0, w: 0, h: 0 };\n  };\n\n  return { prepare, render, setVisible, dispose };\n}\n\n","export default \"// highlight.wgsl\\n// Draws an anti-aliased ring highlight around a point.\\n//\\n// Contract:\\n// - `@builtin(position)` in the fragment stage is framebuffer-space pixels.\\n// - The renderer supplies `center` and ring sizes in *device pixels*.\\n\\nstruct Uniforms {\\n  center: vec2<f32>,\\n  radius: f32,\\n  thickness: f32,\\n  color: vec4<f32>,\\n  outlineColor: vec4<f32>,\\n};\\n\\n@group(0) @binding(0) var<uniform> u: Uniforms;\\n\\nstruct VSOut {\\n  @builtin(position) position: vec4<f32>,\\n};\\n\\n@vertex\\nfn vsMain(@builtin(vertex_index) vertexIndex: u32) -> VSOut {\\n  // Fullscreen triangle.\\n  // Covers clip-space [-1,1] with 3 verts: (-1,-1), (3,-1), (-1,3)\\n  let positions = array<vec2<f32>, 3>(\\n    vec2<f32>(-1.0, -1.0),\\n    vec2<f32>(3.0, -1.0),\\n    vec2<f32>(-1.0, 3.0)\\n  );\\n\\n  var out: VSOut;\\n  out.position = vec4<f32>(positions[vertexIndex], 0.0, 1.0);\\n  return out;\\n}\\n\\nfn ringCoverage(distancePx: f32, radiusPx: f32, thicknessPx: f32) -> f32 {\\n  let aa = 1.0; // ~1px antialias band (device pixels)\\n  let halfT = max(0.5, thicknessPx * 0.5);\\n  let a0 = smoothstep(radiusPx - halfT - aa, radiusPx - halfT + aa, distancePx);\\n  let a1 = smoothstep(radiusPx + halfT - aa, radiusPx + halfT + aa, distancePx);\\n  return clamp(a0 - a1, 0.0, 1.0);\\n}\\n\\n@fragment\\nfn fsMain(@builtin(position) fragPos: vec4<f32>) -> @location(0) vec4<f32> {\\n  let d = distance(fragPos.xy, u.center);\\n\\n  let ring = ringCoverage(d, u.radius, u.thickness);\\n  let outline = ringCoverage(d, u.radius, u.thickness + 2.0);\\n\\n  let cover = max(ring, outline);\\n  if (cover <= 0.0) {\\n    discard;\\n  }\\n\\n  // Blend between outline and ring color based on relative coverage,\\n  // then apply total coverage as alpha.\\n  let t = clamp(select(0.0, ring / cover, cover > 0.0), 0.0, 1.0);\\n  let rgb = mix(u.outlineColor.rgb, u.color.rgb, t);\\n  let a = mix(u.outlineColor.a, u.color.a, t) * cover;\\n  return vec4<f32>(rgb, a);\\n}\\n\\n\"","import highlightWgsl from '../shaders/highlight.wgsl?raw';\nimport { parseCssColorToRgba01 } from '../utils/colors';\nimport { createRenderPipeline, createUniformBuffer, writeUniformBuffer } from './rendererUtils';\n\nexport type HighlightPoint = Readonly<{\n  /** Center in *device pixels* (same coordinate space as fragment `@builtin(position)`). */\n  centerDeviceX: number;\n  centerDeviceY: number;\n\n  /** Device pixel ratio used for CSS→device conversion (worker-safe). */\n  devicePixelRatio: number;\n\n  /** Canvas dimensions in *device pixels* (used to reset scissor). */\n  canvasWidth: number;\n  canvasHeight: number;\n\n  /** Plot scissor rect in *device pixels*. */\n  scissor: Readonly<{ x: number; y: number; w: number; h: number }>;\n}>;\n\nexport interface HighlightRenderer {\n  /**\n   * Prepares the highlight ring.\n   *\n   * Coordinate contract:\n   * - `point.centerDeviceX/Y` are device pixels in the same space as fragment `@builtin(position)`.\n   * - `size` is specified in CSS pixels; the renderer will scale it by `point.devicePixelRatio`.\n   */\n  prepare(point: HighlightPoint, color: string, size: number): void;\n  render(passEncoder: GPURenderPassEncoder): void;\n  setVisible(visible: boolean): void;\n  dispose(): void;\n}\n\nexport interface HighlightRendererOptions {\n  /**\n   * Must match the canvas context format used for the render pass color attachment.\n   * Usually this is `gpuContext.preferredFormat`.\n   *\n   * Defaults to `'bgra8unorm'` for backward compatibility.\n   */\n  readonly targetFormat?: GPUTextureFormat;\n}\n\nconst DEFAULT_TARGET_FORMAT: GPUTextureFormat = 'bgra8unorm';\nconst DEFAULT_RGBA: readonly [number, number, number, number] = [1, 1, 1, 1];\n\nconst clamp01 = (v: number): number => Math.min(1, Math.max(0, v));\nconst clampInt = (v: number, lo: number, hi: number): number => Math.min(hi, Math.max(lo, v | 0));\n\nconst isFiniteScissor = (s: HighlightPoint['scissor']): boolean =>\n  Number.isFinite(s.x) && Number.isFinite(s.y) && Number.isFinite(s.w) && Number.isFinite(s.h);\n\nconst brighten = (rgba: readonly [number, number, number, number], factor: number): readonly [number, number, number, number] => {\n  const f = Number.isFinite(factor) ? factor : 1;\n  return [clamp01(rgba[0] * f), clamp01(rgba[1] * f), clamp01(rgba[2] * f), clamp01(rgba[3])] as const;\n};\n\nconst luminance = (rgba: readonly [number, number, number, number]): number =>\n  0.2126 * rgba[0] + 0.7152 * rgba[1] + 0.0722 * rgba[2];\n\nexport function createHighlightRenderer(device: GPUDevice, options?: HighlightRendererOptions): HighlightRenderer {\n  let disposed = false;\n  let visible = true;\n\n  const targetFormat = options?.targetFormat ?? DEFAULT_TARGET_FORMAT;\n\n  const bindGroupLayout = device.createBindGroupLayout({\n    entries: [{ binding: 0, visibility: GPUShaderStage.FRAGMENT, buffer: { type: 'uniform' } }],\n  });\n\n  // Uniform layout (WGSL):\n  // center.xy, radius, thickness, color.rgba, outlineColor.rgba\n  // = 12 floats = 48 bytes\n  const uniformBuffer = createUniformBuffer(device, 48, { label: 'highlightRenderer/uniforms' });\n\n  const bindGroup = device.createBindGroup({\n    layout: bindGroupLayout,\n    entries: [{ binding: 0, resource: { buffer: uniformBuffer } }],\n  });\n\n  const pipeline = createRenderPipeline(device, {\n    label: 'highlightRenderer/pipeline',\n    bindGroupLayouts: [bindGroupLayout],\n    vertex: { code: highlightWgsl, label: 'highlight.wgsl' },\n    fragment: {\n      code: highlightWgsl,\n      label: 'highlight.wgsl',\n      formats: targetFormat,\n      blend: {\n        color: { operation: 'add', srcFactor: 'src-alpha', dstFactor: 'one-minus-src-alpha' },\n        alpha: { operation: 'add', srcFactor: 'one', dstFactor: 'one-minus-src-alpha' },\n      },\n    },\n    primitive: { topology: 'triangle-list', cullMode: 'none' },\n    multisample: { count: 1 },\n  });\n\n  let lastCanvasWidth = 0;\n  let lastCanvasHeight = 0;\n  let lastScissor = { x: 0, y: 0, w: 0, h: 0 };\n  let hasPrepared = false;\n\n  const assertNotDisposed = (): void => {\n    if (disposed) throw new Error('HighlightRenderer is disposed.');\n  };\n\n  const prepare: HighlightRenderer['prepare'] = (point, cssColor, sizeCssPx) => {\n    assertNotDisposed();\n\n    if (!Number.isFinite(point.centerDeviceX) || !Number.isFinite(point.centerDeviceY)) {\n      throw new Error('HighlightRenderer.prepare: point center must be finite.');\n    }\n    if (!Number.isFinite(point.canvasWidth) || !Number.isFinite(point.canvasHeight) || point.canvasWidth <= 0 || point.canvasHeight <= 0) {\n      throw new Error('HighlightRenderer.prepare: canvasWidth/canvasHeight must be positive finite numbers.');\n    }\n    if (!isFiniteScissor(point.scissor)) {\n      throw new Error('HighlightRenderer.prepare: scissor must be finite.');\n    }\n    if (!Number.isFinite(sizeCssPx) || sizeCssPx < 0) {\n      throw new Error('HighlightRenderer.prepare: size must be a finite non-negative number.');\n    }\n\n    const dprRaw = point.devicePixelRatio;\n    const dpr = Number.isFinite(dprRaw) && dprRaw > 0 ? dprRaw : 1;\n    const baseRadiusDevicePx = sizeCssPx * dpr;\n\n    // Slightly larger than the implied \"normal\" point size.\n    const radius = Math.max(1, baseRadiusDevicePx * 1.5);\n    const thickness = Math.max(1, Math.round(Math.max(2, radius * 0.25)));\n\n    const seriesRgba = parseCssColorToRgba01(cssColor) ?? DEFAULT_RGBA;\n    const ringRgba = brighten(seriesRgba, 1.25);\n    const useDarkOutline = luminance(seriesRgba) > 0.7;\n    const outlineRgba: readonly [number, number, number, number] = useDarkOutline ? [0, 0, 0, 0.9] : [1, 1, 1, 0.9];\n\n    const buf = new ArrayBuffer(12 * 4);\n    new Float32Array(buf).set([\n      point.centerDeviceX,\n      point.centerDeviceY,\n      radius,\n      thickness,\n      ringRgba[0],\n      ringRgba[1],\n      ringRgba[2],\n      1.0,\n      outlineRgba[0],\n      outlineRgba[1],\n      outlineRgba[2],\n      outlineRgba[3],\n    ]);\n    writeUniformBuffer(device, uniformBuffer, buf);\n\n    lastCanvasWidth = point.canvasWidth;\n    lastCanvasHeight = point.canvasHeight;\n\n    // Clamp scissor to valid canvas bounds (defensive).\n    const x0 = clampInt(Math.floor(point.scissor.x), 0, Math.max(0, point.canvasWidth));\n    const y0 = clampInt(Math.floor(point.scissor.y), 0, Math.max(0, point.canvasHeight));\n    const x1 = clampInt(Math.ceil(point.scissor.x + point.scissor.w), 0, Math.max(0, point.canvasWidth));\n    const y1 = clampInt(Math.ceil(point.scissor.y + point.scissor.h), 0, Math.max(0, point.canvasHeight));\n    lastScissor = { x: x0, y: y0, w: Math.max(0, x1 - x0), h: Math.max(0, y1 - y0) };\n\n    hasPrepared = true;\n  };\n\n  const render: HighlightRenderer['render'] = (passEncoder) => {\n    assertNotDisposed();\n    if (!visible) return;\n    if (!hasPrepared) return;\n    if (lastCanvasWidth <= 0 || lastCanvasHeight <= 0) return;\n    if (lastScissor.w === 0 || lastScissor.h === 0) return;\n\n    passEncoder.setScissorRect(lastScissor.x, lastScissor.y, lastScissor.w, lastScissor.h);\n    passEncoder.setPipeline(pipeline);\n    passEncoder.setBindGroup(0, bindGroup);\n    passEncoder.draw(3);\n    passEncoder.setScissorRect(0, 0, lastCanvasWidth, lastCanvasHeight);\n  };\n\n  const setVisible: HighlightRenderer['setVisible'] = (v) => {\n    assertNotDisposed();\n    visible = Boolean(v);\n  };\n\n  const dispose: HighlightRenderer['dispose'] = () => {\n    if (disposed) return;\n    disposed = true;\n\n    try {\n      uniformBuffer.destroy();\n    } catch {\n      // best-effort\n    }\n\n    lastCanvasWidth = 0;\n    lastCanvasHeight = 0;\n    lastScissor = { x: 0, y: 0, w: 0, h: 0 };\n    hasPrepared = false;\n  };\n\n  return { prepare, render, setVisible, dispose };\n}\n\n","export default \"// Reference line renderer (axis-aligned, instanced quads).\\n//\\n// Coordinate conventions:\\n// - Instance position is provided in CANVAS-LOCAL CSS pixels (same coordinate space as pointer events).\\n// - Plot rect is provided in DEVICE pixels (computed from grid margins + DPR).\\n// - Line width and dash lengths are provided in CSS pixels and converted in-shader using DPR.\\n//\\n// Scissoring/clipping:\\n// - The render coordinator is expected to set a scissor rect for the plot area before drawing.\\n// - This shader simply draws full-height/full-width quads; clipping is handled by scissor.\\n//\\n// Dash semantics:\\n// - lineDash is a repeating on/off sequence in CSS pixels, starting with \\\"on\\\" at t=0.\\n// - Up to 8 dash entries are supported per line (truncated on CPU).\\n//\\n// Performance:\\n// - Vertex stage expands each instance into a quad (2 triangles, 6 vertices).\\n// - We intentionally avoid snapping to integer device pixels to prevent visible stepping/jiggle\\n//   while zooming; edge AA is handled in the fragment stage.\\n\\nstruct VSUniforms {\\n  canvasSize : vec2<f32>,     // device pixels (canvas.width, canvas.height)\\n  plotOrigin : vec2<f32>,     // device pixels (plotLeft, plotTop)\\n  plotSize : vec2<f32>,       // device pixels (plotWidth, plotHeight)\\n  devicePixelRatio : f32,\\n  _pad0 : f32,\\n};\\n\\n@group(0) @binding(0) var<uniform> u : VSUniforms;\\n\\nstruct VSIn {\\n  // axisPos.x = axis (0 = vertical, 1 = horizontal)\\n  // axisPos.y = position in CANVAS-LOCAL CSS pixels (x for vertical, y for horizontal)\\n  @location(0) axisPos : vec2<f32>,\\n\\n  // widthDashCount.x = lineWidth in CSS px\\n  // widthDashCount.y = dashCount (float, cast to u32)\\n  @location(1) widthDashCount : vec2<f32>,\\n\\n  // dashMeta.x = dashTotal (CSS px)\\n  // dashMeta.y = reserved (unused)\\n  @location(2) dashMeta : vec2<f32>,\\n\\n  @location(3) dash0_3 : vec4<f32>,\\n  @location(4) dash4_7 : vec4<f32>,\\n\\n  // Premultiplied or straight alpha is fine; blending is handled by pipeline state.\\n  @location(5) color : vec4<f32>,\\n};\\n\\nstruct VSOut {\\n  @builtin(position) position : vec4<f32>,\\n\\n  // Distance along the line in CSS pixels (0..plotLengthCss).\\n  @location(0) alongCss : f32,\\n\\n  // Packed dash metadata to avoid extra varyings.\\n  // dashInfo.x = dashCount (float, cast to u32)\\n  // dashInfo.y = dashTotal (CSS px)\\n  @location(1) @interpolate(flat) dashInfo : vec2<f32>,\\n\\n  @location(2) @interpolate(flat) dash0_3 : vec4<f32>,\\n  @location(3) @interpolate(flat) dash4_7 : vec4<f32>,\\n  @location(4) @interpolate(flat) color : vec4<f32>,\\n\\n  // Axis-aligned quad anti-aliasing (device pixels).\\n  // acrossDevice ranges [0..widthDevice] across the stroke thickness.\\n  @location(5) acrossDevice : f32,\\n  @location(6) @interpolate(flat) widthDevice : f32,\\n};\\n\\nfn quadUv(vid : u32) -> vec2<f32> {\\n  // Two triangles covering [0,1]x[0,1].\\n  // 0: (0,0) 1:(1,0) 2:(0,1) 3:(0,1) 4:(1,0) 5:(1,1)\\n  switch (vid) {\\n    case 0u: { return vec2<f32>(0.0, 0.0); }\\n    case 1u: { return vec2<f32>(1.0, 0.0); }\\n    case 2u: { return vec2<f32>(0.0, 1.0); }\\n    case 3u: { return vec2<f32>(0.0, 1.0); }\\n    case 4u: { return vec2<f32>(1.0, 0.0); }\\n    default: { return vec2<f32>(1.0, 1.0); }\\n  }\\n}\\n\\n@vertex\\nfn vsMain(in : VSIn, @builtin(vertex_index) vid : u32) -> VSOut {\\n  let uv = quadUv(vid);\\n  let dpr = max(1e-6, u.devicePixelRatio);\\n  // IMPORTANT: Do NOT snap reference lines to integer device pixels.\\n  // Snapping looks crisp at rest but causes visible \\\"jiggle\\\" / stepping while zooming because\\n  // the line position is continuously changing (data-space → screen-space), and rounding\\n  // quantizes that motion to adjacent pixels. We rely on analytic AA in the fragment stage\\n  // to keep strokes stable and reasonably crisp across DPRs.\\n\\n  let axis = in.axisPos.x;\\n  let posCss = in.axisPos.y;\\n  let widthCss = max(0.0, in.widthDashCount.x);\\n  let widthDevice = max(1.0, widthCss * dpr);\\n\\n  var xDevice : f32;\\n  var yDevice : f32;\\n  var alongCss : f32;\\n  var acrossDevice : f32;\\n\\n  if (axis < 0.5) {\\n    // Vertical line at x = posCss (canvas-local CSS px), spanning plot height.\\n    let centerX = posCss * dpr;\\n    let startX = centerX - 0.5 * widthDevice;\\n    xDevice = startX + uv.x * widthDevice;\\n    yDevice = u.plotOrigin.y + uv.y * u.plotSize.y;\\n    alongCss = (uv.y * u.plotSize.y) / dpr;\\n    acrossDevice = uv.x * widthDevice;\\n  } else {\\n    // Horizontal line at y = posCss (canvas-local CSS px), spanning plot width.\\n    let centerY = posCss * dpr;\\n    let startY = centerY - 0.5 * widthDevice;\\n    xDevice = u.plotOrigin.x + uv.x * u.plotSize.x;\\n    yDevice = startY + uv.y * widthDevice;\\n    alongCss = (uv.x * u.plotSize.x) / dpr;\\n    acrossDevice = uv.y * widthDevice;\\n  }\\n\\n  let clipX = (xDevice / u.canvasSize.x) * 2.0 - 1.0;\\n  let clipY = 1.0 - (yDevice / u.canvasSize.y) * 2.0;\\n\\n  var out : VSOut;\\n  out.position = vec4<f32>(clipX, clipY, 0.0, 1.0);\\n  out.alongCss = alongCss;\\n  out.dashInfo = vec2<f32>(in.widthDashCount.y, in.dashMeta.x);\\n  out.dash0_3 = in.dash0_3;\\n  out.dash4_7 = in.dash4_7;\\n  out.color = in.color;\\n  out.acrossDevice = acrossDevice;\\n  out.widthDevice = widthDevice;\\n  return out;\\n}\\n\\nfn dashValue(i : u32, d0 : vec4<f32>, d1 : vec4<f32>) -> f32 {\\n  switch (i) {\\n    case 0u: { return d0.x; }\\n    case 1u: { return d0.y; }\\n    case 2u: { return d0.z; }\\n    case 3u: { return d0.w; }\\n    case 4u: { return d1.x; }\\n    case 5u: { return d1.y; }\\n    case 6u: { return d1.z; }\\n    default: { return d1.w; }\\n  }\\n}\\n\\n@fragment\\nfn fsMain(in : VSOut) -> @location(0) vec4<f32> {\\n  // Analytic edge anti-aliasing for axis-aligned quads (reduces shimmering during zoom).\\n  // This is a lightweight alternative to full MSAA for thin strokes.\\n  let edgeDist = min(in.acrossDevice, in.widthDevice - in.acrossDevice);\\n  // Slightly widen AA to reduce temporal shimmer on moving 1-2px strokes.\\n  // Keep conservative so lines remain reasonably crisp.\\n  let aa = max(fwidth(in.acrossDevice), 1e-3) * 1.25;\\n  let edgeCoverage = smoothstep(0.0, aa, edgeDist);\\n  var color = in.color;\\n  color.a = color.a * edgeCoverage;\\n\\n  let dashCount = u32(round(in.dashInfo.x));\\n  let dashTotal = in.dashInfo.y;\\n\\n  // IMPORTANT: derivative ops (fwidth) must execute in uniform control flow.\\n  // So compute the dash parameterization unconditionally (using a safe total) BEFORE any early-return.\\n  let dashTotalSafe = max(dashTotal, 1.0);\\n  let t = in.alongCss - floor(in.alongCss / dashTotalSafe) * dashTotalSafe;\\n  // Anti-alias dash edges along the line axis (CSS pixels).\\n  // This reduces shimmer during zoom for dashed reference lines without requiring MSAA.\\n  let dashAa = max(fwidth(t), 1e-3);\\n\\n  // Solid line (no dash pattern).\\n  if (dashCount == 0u || dashTotal <= 0.0) {\\n    return color;\\n  }\\n\\n  var acc = 0.0;\\n  var on = true;\\n\\n  for (var i : u32 = 0u; i < 8u; i = i + 1u) {\\n    if (i >= dashCount) { break; }\\n    let seg = dashValue(i, in.dash0_3, in.dash4_7);\\n    if (seg <= 0.0) { continue; }\\n\\n    if (t < acc + seg) {\\n      // IMPORTANT: Avoid `discard` for off segments.\\n      // Discard can cause temporal popping on moving dashed edges; prefer a smooth alpha mask.\\n      //\\n      // Fade in/out near dash boundaries for smooth edges. This produces coverage in [0..1]\\n      // within the current segment, going to 0 at segment boundaries.\\n      let inFromStart = smoothstep(0.0, dashAa, t - acc);\\n      let inFromEnd = smoothstep(0.0, dashAa, (acc + seg) - t);\\n      let segCoverage = min(inFromStart, inFromEnd);\\n\\n      // On segments contribute alpha; off segments contribute 0 alpha (no discard).\\n      let dashMask = select(0.0, segCoverage, on);\\n      color.a = color.a * dashMask;\\n      return color;\\n    }\\n\\n    acc = acc + seg;\\n    on = !on;\\n  }\\n\\n  // Defensive fallback if the dash list is degenerate.\\n  // If we didn't find a segment (shouldn't happen), default to transparent (safer than solid).\\n  color.a = 0.0;\\n  return color;\\n}\\n\"","import referenceLineWgsl from '../shaders/referenceLine.wgsl?raw';\nimport { createRenderPipeline, createUniformBuffer, writeUniformBuffer } from './rendererUtils';\nimport type { GridArea } from './createGridRenderer';\n\n/**\n * Maximum dash entries supported per line instance.\n *\n * WGSL requires fixed-size arrays/varyings; we cap and truncate for deterministic perf.\n * If you need more, increase this (and update the shader accordingly).\n */\nconst MAX_DASH_VALUES = 8;\n\nconst DEFAULT_TARGET_FORMAT: GPUTextureFormat = 'bgra8unorm';\n\nexport type ReferenceLineAxis = 'vertical' | 'horizontal';\n\nexport interface ReferenceLineInstance {\n  /**\n   * Axis alignment.\n   * - `'vertical'`: a line spanning the plot height at a fixed X position\n   * - `'horizontal'`: a line spanning the plot width at a fixed Y position\n   */\n  readonly axis: ReferenceLineAxis;\n\n  /**\n   * Position in **CANVAS-LOCAL CSS pixels**.\n   *\n   * This is the same coordinate space as pointer event payloads:\n   * - For vertical lines: canvas-local X in CSS px\n   * - For horizontal lines: canvas-local Y in CSS px\n   *\n   * The shader converts CSS px → device px using DPR and relies on analytic AA for stable\n   * strokes during zoom (no integer device-pixel snapping).\n   */\n  readonly positionCssPx: number;\n\n  /**\n   * Desired line width in **CSS pixels**.\n   *\n   * The renderer emulates thickness using a quad (two triangles) and converts CSS px to\n   * device px using `gridArea.devicePixelRatio`.\n   */\n  readonly lineWidth: number;\n\n  /**\n   * Dash pattern in **CSS pixels**, matching the semantics of Canvas2D/SVG:\n   * `[dash, gap, dash, gap, ...]`, repeating, starting with an \"on\" dash.\n   *\n   * - `undefined` / `[]` renders a solid line.\n   * - Non-finite / non-positive entries are ignored.\n   * - If the list length is odd, it is duplicated (CSS behavior) before truncation.\n   * - The pattern is truncated to `MAX_DASH_VALUES`.\n   */\n  readonly lineDash?: ReadonlyArray<number>;\n\n  /**\n   * Line color as RGBA in 0..1.\n   *\n   * `rgba[3]` is the final opacity (i.e. you can pre-multiply any \"opacity\" control into alpha).\n   */\n  readonly rgba: readonly [number, number, number, number];\n}\n\nexport interface ReferenceLineRendererOptions {\n  /**\n   * Must match the canvas context format used for the render pass color attachment.\n   * Usually this is `gpuContext.preferredFormat`.\n   *\n   * Defaults to `'bgra8unorm'` for backward compatibility.\n   */\n  readonly targetFormat?: GPUTextureFormat;\n\n  /**\n   * Multisample count for the render pipeline.\n   *\n   * Must match the render pass color attachment sampleCount.\n   * Defaults to 1 (no MSAA).\n   */\n  readonly sampleCount?: number;\n}\n\nexport interface ReferenceLineRenderer {\n  /**\n   * Prepares GPU buffers and uniforms for drawing.\n   *\n   * Coordinate contract:\n   * - Line positions are CANVAS-LOCAL CSS pixels.\n   * - `gridArea` margins are CSS pixels; `gridArea.canvasWidth/Height` are device pixels.\n   */\n  prepare(gridArea: GridArea, lines: ReadonlyArray<ReferenceLineInstance>): void;\n  /**\n   * Draws all prepared reference lines.\n   *\n   * Important: This renderer does NOT set scissor state. The render coordinator is expected\n   * to set a scissor rect for the plot area before calling `render()`.\n   */\n  render(passEncoder: GPURenderPassEncoder, firstInstance?: number, instanceCount?: number): void;\n  /** Cleans up GPU resources (best-effort). */\n  dispose(): void;\n}\n\nconst isFiniteGridArea = (gridArea: GridArea): boolean =>\n  Number.isFinite(gridArea.left) &&\n  Number.isFinite(gridArea.right) &&\n  Number.isFinite(gridArea.top) &&\n  Number.isFinite(gridArea.bottom) &&\n  Number.isFinite(gridArea.canvasWidth) &&\n  Number.isFinite(gridArea.canvasHeight);\n\ntype PackedDash = {\n  readonly dashCount: number;\n  readonly dashTotal: number;\n  readonly values: readonly number[]; // length MAX_DASH_VALUES\n};\n\nconst normalizeDash = (lineDash?: ReadonlyArray<number>): PackedDash => {\n  if (!lineDash || lineDash.length === 0) {\n    return { dashCount: 0, dashTotal: 0, values: new Array<number>(MAX_DASH_VALUES).fill(0) };\n  }\n\n  const cleaned: number[] = [];\n  for (let i = 0; i < lineDash.length; i++) {\n    const v = lineDash[i];\n    if (typeof v === 'number' && Number.isFinite(v) && v > 0) cleaned.push(v);\n  }\n\n  if (cleaned.length === 0) {\n    return { dashCount: 0, dashTotal: 0, values: new Array<number>(MAX_DASH_VALUES).fill(0) };\n  }\n\n  // CSS behavior: odd-length dash arrays are repeated to make even length.\n  const normalized = cleaned.length % 2 === 1 ? cleaned.concat(cleaned) : cleaned;\n\n  const dashCount = Math.min(MAX_DASH_VALUES, normalized.length);\n  const values = new Array<number>(MAX_DASH_VALUES).fill(0);\n  let dashTotal = 0;\n  for (let i = 0; i < dashCount; i++) {\n    values[i] = normalized[i];\n    dashTotal += normalized[i];\n  }\n\n  if (!Number.isFinite(dashTotal) || dashTotal <= 0) {\n    return { dashCount: 0, dashTotal: 0, values: new Array<number>(MAX_DASH_VALUES).fill(0) };\n  }\n\n  return { dashCount, dashTotal, values };\n};\n\nexport function createReferenceLineRenderer(device: GPUDevice, options?: ReferenceLineRendererOptions): ReferenceLineRenderer {\n  let disposed = false;\n  const targetFormat = options?.targetFormat ?? DEFAULT_TARGET_FORMAT;\n  // Be resilient: coerce invalid values to 1 (no MSAA).\n  const sampleCountRaw = options?.sampleCount ?? 1;\n  const sampleCount = Number.isFinite(sampleCountRaw) ? Math.max(1, Math.floor(sampleCountRaw)) : 1;\n\n  const bindGroupLayout = device.createBindGroupLayout({\n    entries: [{ binding: 0, visibility: GPUShaderStage.VERTEX, buffer: { type: 'uniform' } }],\n  });\n\n  // VSUniforms:\n  // - canvasSize (vec2f)\n  // - plotOrigin (vec2f)\n  // - plotSize (vec2f)\n  // - devicePixelRatio (f32)\n  // - pad (f32)\n  const vsUniformBuffer = createUniformBuffer(device, 32, { label: 'referenceLineRenderer/vsUniforms' });\n\n  const bindGroup = device.createBindGroup({\n    layout: bindGroupLayout,\n    entries: [{ binding: 0, resource: { buffer: vsUniformBuffer } }],\n  });\n\n  const INSTANCE_STRIDE_BYTES = 72;\n  const INSTANCE_STRIDE_FLOATS = INSTANCE_STRIDE_BYTES / 4;\n\n  const pipeline = createRenderPipeline(device, {\n    label: 'referenceLineRenderer/pipeline',\n    bindGroupLayouts: [bindGroupLayout],\n    vertex: {\n      code: referenceLineWgsl,\n      label: 'referenceLine.wgsl',\n      buffers: [\n        {\n          arrayStride: INSTANCE_STRIDE_BYTES,\n          stepMode: 'instance',\n          attributes: [\n            { shaderLocation: 0, format: 'float32x2', offset: 0 },  // axisPos\n            { shaderLocation: 1, format: 'float32x2', offset: 8 },  // widthDashCount\n            { shaderLocation: 2, format: 'float32x2', offset: 16 }, // dashMeta\n            { shaderLocation: 3, format: 'float32x4', offset: 24 }, // dash0_3\n            { shaderLocation: 4, format: 'float32x4', offset: 40 }, // dash4_7\n            { shaderLocation: 5, format: 'float32x4', offset: 56 }, // color\n          ],\n        },\n      ],\n    },\n    fragment: {\n      code: referenceLineWgsl,\n      label: 'referenceLine.wgsl',\n      formats: targetFormat,\n      blend: {\n        color: { operation: 'add', srcFactor: 'src-alpha', dstFactor: 'one-minus-src-alpha' },\n        alpha: { operation: 'add', srcFactor: 'one', dstFactor: 'one-minus-src-alpha' },\n      },\n    },\n    primitive: { topology: 'triangle-list', cullMode: 'none' },\n    multisample: { count: sampleCount },\n  });\n\n  let instanceBuffer: GPUBuffer | null = null;\n  let instanceCapacity = 0;\n  let instanceCount = 0;\n\n  const assertNotDisposed = (): void => {\n    if (disposed) throw new Error('ReferenceLineRenderer is disposed.');\n  };\n\n  const prepare: ReferenceLineRenderer['prepare'] = (gridArea, lines) => {\n    assertNotDisposed();\n\n    if (!Array.isArray(lines)) {\n      throw new Error('ReferenceLineRenderer.prepare: lines must be an array.');\n    }\n    if (!isFiniteGridArea(gridArea)) {\n      throw new Error('ReferenceLineRenderer.prepare: gridArea dimensions must be finite numbers.');\n    }\n    if (gridArea.canvasWidth <= 0 || gridArea.canvasHeight <= 0) {\n      throw new Error('ReferenceLineRenderer.prepare: canvas dimensions must be positive.');\n    }\n    if (gridArea.left < 0 || gridArea.right < 0 || gridArea.top < 0 || gridArea.bottom < 0) {\n      throw new Error('ReferenceLineRenderer.prepare: gridArea margins must be non-negative.');\n    }\n\n    // Be resilient: older call sites may omit/incorrectly pass DPR. Defaulting avoids hard crashes.\n    const dpr =\n      Number.isFinite(gridArea.devicePixelRatio) && gridArea.devicePixelRatio > 0 ? gridArea.devicePixelRatio : 1;\n\n    const plotLeftDevice = gridArea.left * dpr;\n    const plotTopDevice = gridArea.top * dpr;\n    const plotRightDevice = gridArea.canvasWidth - gridArea.right * dpr;\n    const plotBottomDevice = gridArea.canvasHeight - gridArea.bottom * dpr;\n    const plotWidthDevice = plotRightDevice - plotLeftDevice;\n    const plotHeightDevice = plotBottomDevice - plotTopDevice;\n\n    if (!(plotWidthDevice > 0) || !(plotHeightDevice > 0)) {\n      instanceCount = 0;\n      return;\n    }\n\n    // Write uniforms.\n    const uniforms = new Float32Array(8);\n    uniforms[0] = gridArea.canvasWidth;\n    uniforms[1] = gridArea.canvasHeight;\n    uniforms[2] = plotLeftDevice;\n    uniforms[3] = plotTopDevice;\n    uniforms[4] = plotWidthDevice;\n    uniforms[5] = plotHeightDevice;\n    uniforms[6] = dpr;\n    uniforms[7] = 0;\n    writeUniformBuffer(device, vsUniformBuffer, uniforms);\n\n    // Early out: no instances.\n    if (lines.length === 0) {\n      instanceCount = 0;\n      return;\n    }\n\n    // Ensure instance buffer capacity.\n    if (!instanceBuffer || instanceCapacity < lines.length) {\n      const nextCapacity = Math.max(1, Math.ceil(lines.length * 1.5));\n      const size = Math.max(4, nextCapacity * INSTANCE_STRIDE_BYTES);\n\n      if (instanceBuffer) {\n        try {\n          instanceBuffer.destroy();\n        } catch {\n          // best-effort\n        }\n      }\n\n      instanceBuffer = device.createBuffer({\n        label: 'referenceLineRenderer/instanceBuffer',\n        size,\n        usage: GPUBufferUsage.VERTEX | GPUBufferUsage.COPY_DST,\n      });\n      instanceCapacity = nextCapacity;\n    }\n\n    const data = new Float32Array(lines.length * INSTANCE_STRIDE_FLOATS);\n\n    for (let i = 0; i < lines.length; i++) {\n      const line = lines[i];\n      const base = i * INSTANCE_STRIDE_FLOATS;\n\n      if (line.axis !== 'vertical' && line.axis !== 'horizontal') {\n        throw new Error(\"ReferenceLineRenderer.prepare: line.axis must be 'vertical' or 'horizontal'.\");\n      }\n      if (!Number.isFinite(line.positionCssPx)) {\n        throw new Error('ReferenceLineRenderer.prepare: line.positionCssPx must be a finite number.');\n      }\n      if (!Number.isFinite(line.lineWidth) || line.lineWidth < 0) {\n        throw new Error('ReferenceLineRenderer.prepare: line.lineWidth must be a finite non-negative number.');\n      }\n\n      const rgba = line.rgba;\n      if (!Array.isArray(rgba) || rgba.length !== 4) {\n        throw new Error('ReferenceLineRenderer.prepare: line.rgba must be a tuple [r,g,b,a].');\n      }\n\n      const dash = normalizeDash(line.lineDash);\n\n      // axisPos\n      data[base + 0] = line.axis === 'vertical' ? 0 : 1;\n      data[base + 1] = line.positionCssPx;\n\n      // widthDashCount\n      data[base + 2] = line.lineWidth;\n      data[base + 3] = dash.dashCount;\n\n      // dashMeta\n      data[base + 4] = dash.dashTotal;\n      data[base + 5] = 0;\n\n      // dash0_3 + dash4_7\n      for (let d = 0; d < MAX_DASH_VALUES; d++) {\n        data[base + 6 + d] = dash.values[d];\n      }\n\n      // color\n      data[base + 14] = rgba[0];\n      data[base + 15] = rgba[1];\n      data[base + 16] = rgba[2];\n      data[base + 17] = rgba[3];\n    }\n\n    device.queue.writeBuffer(instanceBuffer, 0, data.buffer, data.byteOffset, data.byteLength);\n    instanceCount = lines.length;\n  };\n\n  const render: ReferenceLineRenderer['render'] = (passEncoder, firstInstance = 0, requestedCount) => {\n    assertNotDisposed();\n    if (instanceCount === 0 || !instanceBuffer) return;\n\n    const first = Number.isFinite(firstInstance) ? Math.max(0, Math.floor(firstInstance)) : 0;\n    const available = Math.max(0, instanceCount - first);\n    const count =\n      requestedCount == null\n        ? available\n        : Number.isFinite(requestedCount)\n          ? Math.max(0, Math.min(available, Math.floor(requestedCount)))\n          : available;\n    if (count === 0) return;\n\n    passEncoder.setPipeline(pipeline);\n    passEncoder.setBindGroup(0, bindGroup);\n    passEncoder.setVertexBuffer(0, instanceBuffer);\n    passEncoder.draw(6, count, 0, first);\n  };\n\n  const dispose: ReferenceLineRenderer['dispose'] = () => {\n    if (disposed) return;\n    disposed = true;\n\n    try {\n      vsUniformBuffer.destroy();\n    } catch {\n      // best-effort\n    }\n    if (instanceBuffer) {\n      try {\n        instanceBuffer.destroy();\n      } catch {\n        // best-effort\n      }\n    }\n\n    instanceBuffer = null;\n    instanceCapacity = 0;\n    instanceCount = 0;\n  };\n\n  return { prepare, render, dispose };\n}\n\n","export default \"// annotationMarker.wgsl\\n// Instanced annotation marker shader (circle SDF with optional stroke).\\n//\\n// Coordinate contract:\\n// - Instance center is CANVAS-LOCAL CSS pixels (xCssPx, yCssPx)\\n// - Instance size is diameter in CSS pixels (sizeCssPx)\\n// - Uniform provides render target size in *device* pixels and DPR for CSS→device conversion.\\n//\\n// Draw call: draw(6, instanceCount) using triangle-list quad expansion in VS.\\n\\nstruct VSUniforms {\\n  viewportPx: vec2<f32>, // render target size in device pixels (width, height)\\n  dpr: f32,              // device pixel ratio (CSS px -> device px)\\n  _pad0: f32,\\n};\\n\\n@group(0) @binding(0) var<uniform> vsUniforms: VSUniforms;\\n\\nstruct VSIn {\\n  // Center in CANVAS-LOCAL CSS pixels.\\n  @location(0) centerCssPx: vec2<f32>,\\n  // Marker diameter in CSS pixels.\\n  @location(1) sizeCssPx: f32,\\n  // Stroke width in CSS pixels (0 disables stroke).\\n  @location(2) strokeWidthCssPx: f32,\\n  // Colors are straight-alpha RGBA in 0..1.\\n  @location(3) fillRgba: vec4<f32>,\\n  @location(4) strokeRgba: vec4<f32>,\\n};\\n\\nstruct VSOut {\\n  @builtin(position) clipPosition: vec4<f32>,\\n  // Local quad coordinates in [-1, 1]^2 (used for circle SDF).\\n  @location(0) local: vec2<f32>,\\n  // Half-size in device pixels (radius in screen space).\\n  @location(1) halfSizePx: f32,\\n  @location(2) strokeWidthPx: f32,\\n  @location(3) fillRgba: vec4<f32>,\\n  @location(4) strokeRgba: vec4<f32>,\\n};\\n\\n@vertex\\nfn vsMain(in: VSIn, @builtin(vertex_index) vertexIndex: u32) -> VSOut {\\n  // Fixed local corners for 2 triangles (triangle-list).\\n  let localCorners = array<vec2<f32>, 6>(\\n    vec2<f32>(-1.0, -1.0),\\n    vec2<f32>( 1.0, -1.0),\\n    vec2<f32>(-1.0,  1.0),\\n    vec2<f32>(-1.0,  1.0),\\n    vec2<f32>( 1.0, -1.0),\\n    vec2<f32>( 1.0,  1.0)\\n  );\\n\\n  let corner = localCorners[vertexIndex];\\n\\n  let dpr = select(1.0, vsUniforms.dpr, vsUniforms.dpr > 0.0);\\n  let centerPx = in.centerCssPx * dpr;\\n  let halfSizePx = 0.5 * max(0.0, in.sizeCssPx) * dpr;\\n  let strokeWidthPx = max(0.0, in.strokeWidthCssPx) * dpr;\\n\\n  let posPx = centerPx + corner * halfSizePx;\\n\\n  // Convert device pixels to clip-space with origin at top-left:\\n  // x: [0..w] -> [-1..1], y: [0..h] -> [1..-1]\\n  let clipX = (posPx.x / vsUniforms.viewportPx.x) * 2.0 - 1.0;\\n  let clipY = 1.0 - (posPx.y / vsUniforms.viewportPx.y) * 2.0;\\n\\n  var out: VSOut;\\n  out.clipPosition = vec4<f32>(clipX, clipY, 0.0, 1.0);\\n  out.local = corner;\\n  out.halfSizePx = halfSizePx;\\n  out.strokeWidthPx = strokeWidthPx;\\n  out.fillRgba = in.fillRgba;\\n  out.strokeRgba = in.strokeRgba;\\n  return out;\\n}\\n\\n@fragment\\nfn fsMain(in: VSOut) -> @location(0) vec4<f32> {\\n  if (in.halfSizePx <= 0.0) {\\n    discard;\\n  }\\n\\n  // Circle SDF in normalized space: dist == 1 at the circle boundary.\\n  let dist = length(in.local);\\n  let aa = max(1e-6, fwidth(dist));\\n\\n  // Coverage inside the circle.\\n  let outerCoverage = 1.0 - smoothstep(1.0 - aa, 1.0 + aa, dist);\\n  if (outerCoverage <= 0.0) {\\n    discard;\\n  }\\n\\n  // Optional stroke: compute inner radius in normalized units.\\n  let strokeNorm = clamp(in.strokeWidthPx / max(1e-6, in.halfSizePx), 0.0, 1.0);\\n  let inner = max(0.0, 1.0 - strokeNorm);\\n  let innerCoverage = 1.0 - smoothstep(inner - aa, inner + aa, dist);\\n\\n  let fillCoverage = clamp(innerCoverage, 0.0, 1.0);\\n  let strokeCoverage = clamp(outerCoverage - innerCoverage, 0.0, 1.0);\\n\\n  let fillA = clamp(in.fillRgba.a, 0.0, 1.0) * fillCoverage;\\n  let strokeA = clamp(in.strokeRgba.a, 0.0, 1.0) * strokeCoverage;\\n  let outA = fillA + strokeA;\\n  if (outA <= 0.0) {\\n    discard;\\n  }\\n\\n  // Straight-alpha output: compute a weighted average RGB for correct blending.\\n  let rgb = (in.fillRgba.rgb * fillA + in.strokeRgba.rgb * strokeA) / outA;\\n  return vec4<f32>(rgb, outA);\\n}\\n\\n\"","import annotationMarkerWgsl from '../shaders/annotationMarker.wgsl?raw';\nimport { createRenderPipeline, createUniformBuffer, writeUniformBuffer } from './rendererUtils';\n\nexport type AnnotationMarkerInstance = Readonly<{\n  /**\n   * Center in CANVAS-LOCAL CSS pixels.\n   * (0,0) is the canvas top-left in CSS pixel coordinates.\n   */\n  xCssPx: number;\n  yCssPx: number;\n\n  /** Marker diameter in CSS pixels. */\n  sizeCssPx: number;\n\n  /** Fill color RGBA in 0..1 (straight alpha). */\n  fillRgba: readonly [r: number, g: number, b: number, a: number];\n\n  /** Optional stroke width in CSS pixels (0 disables stroke). */\n  strokeWidthCssPx?: number;\n\n  /** Optional stroke color RGBA in 0..1 (straight alpha). */\n  strokeRgba?: readonly [r: number, g: number, b: number, a: number];\n}>;\n\nexport interface AnnotationMarkerRenderer {\n  /**\n   * Uploads marker instances and prepares uniforms for rendering.\n   *\n   * Coordinate contract:\n   * - `instances[*].xCssPx/yCssPx` are CANVAS-LOCAL CSS pixels.\n   * - `canvasWidth/canvasHeight` are in *device pixels* (same as render target size).\n   * - `devicePixelRatio` is used to convert CSS px to device px inside the shader.\n   *\n   * Scissor contract:\n   * - This renderer intentionally does NOT set or reset scissor state.\n   *   The caller must set scissor for plot clipping before invoking `render()`.\n   */\n  prepare(params: Readonly<{\n    canvasWidth: number;\n    canvasHeight: number;\n    devicePixelRatio: number;\n    instances: readonly AnnotationMarkerInstance[];\n  }>): void;\n\n  /** Draws all prepared instances (if any). */\n  render(passEncoder: GPURenderPassEncoder, firstInstance?: number, instanceCount?: number): void;\n\n  /** Cleans up GPU resources (best-effort). */\n  dispose(): void;\n}\n\nexport interface AnnotationMarkerRendererOptions {\n  /**\n   * Must match the canvas context format used for the render pass color attachment.\n   * Usually this is `gpuContext.preferredFormat`.\n   *\n   * Defaults to `'bgra8unorm'` for backward compatibility.\n   */\n  readonly targetFormat?: GPUTextureFormat;\n\n  /**\n   * Multisample count for the render pipeline.\n   *\n   * Must match the render pass color attachment sampleCount.\n   * Defaults to 1 (no MSAA).\n   */\n  readonly sampleCount?: number;\n}\n\nconst DEFAULT_TARGET_FORMAT: GPUTextureFormat = 'bgra8unorm';\n\n// Instance layout (WGSL VSIn):\n// centerCssPx.xy, sizeCssPx, strokeWidthCssPx, fillRgba.rgba, strokeRgba.rgba\nconst INSTANCE_STRIDE_FLOATS = 12;\nconst INSTANCE_STRIDE_BYTES = INSTANCE_STRIDE_FLOATS * 4;\n\nconst clamp01 = (v: number): number => Math.min(1, Math.max(0, v));\n\nconst nextPow2 = (v: number): number => {\n  if (!Number.isFinite(v) || v <= 0) return 1;\n  const n = Math.ceil(v);\n  return 2 ** Math.ceil(Math.log2(n));\n};\n\nexport function createAnnotationMarkerRenderer(device: GPUDevice, options?: AnnotationMarkerRendererOptions): AnnotationMarkerRenderer {\n  let disposed = false;\n  const targetFormat = options?.targetFormat ?? DEFAULT_TARGET_FORMAT;\n  // Be resilient: coerce invalid values to 1 (no MSAA).\n  const sampleCountRaw = options?.sampleCount ?? 1;\n  const sampleCount = Number.isFinite(sampleCountRaw) ? Math.max(1, Math.floor(sampleCountRaw)) : 1;\n\n  const bindGroupLayout = device.createBindGroupLayout({\n    entries: [{ binding: 0, visibility: GPUShaderStage.VERTEX, buffer: { type: 'uniform' } }],\n  });\n\n  // VSUniforms (WGSL):\n  // viewportPx vec2 + dpr f32 + pad f32 = 16 bytes\n  const vsUniformBuffer = createUniformBuffer(device, 16, { label: 'annotationMarkerRenderer/vsUniforms' });\n  const vsUniformScratchF32 = new Float32Array(4);\n\n  const bindGroup = device.createBindGroup({\n    layout: bindGroupLayout,\n    entries: [{ binding: 0, resource: { buffer: vsUniformBuffer } }],\n  });\n\n  const pipeline = createRenderPipeline(device, {\n    label: 'annotationMarkerRenderer/pipeline',\n    bindGroupLayouts: [bindGroupLayout],\n    vertex: {\n      code: annotationMarkerWgsl,\n      label: 'annotationMarker.wgsl',\n      buffers: [\n        {\n          arrayStride: INSTANCE_STRIDE_BYTES,\n          stepMode: 'instance',\n          attributes: [\n            { shaderLocation: 0, format: 'float32x2', offset: 0 }, // centerCssPx\n            { shaderLocation: 1, format: 'float32', offset: 8 }, // sizeCssPx\n            { shaderLocation: 2, format: 'float32', offset: 12 }, // strokeWidthCssPx\n            { shaderLocation: 3, format: 'float32x4', offset: 16 }, // fillRgba\n            { shaderLocation: 4, format: 'float32x4', offset: 32 }, // strokeRgba\n          ],\n        },\n      ],\n    },\n    fragment: {\n      code: annotationMarkerWgsl,\n      label: 'annotationMarker.wgsl',\n      formats: targetFormat,\n      blend: {\n        color: { operation: 'add', srcFactor: 'src-alpha', dstFactor: 'one-minus-src-alpha' },\n        alpha: { operation: 'add', srcFactor: 'one', dstFactor: 'one-minus-src-alpha' },\n      },\n    },\n    primitive: { topology: 'triangle-list', cullMode: 'none' },\n    multisample: { count: sampleCount },\n  });\n\n  let instanceBuffer: GPUBuffer | null = null;\n  let instanceCount = 0;\n  let cpuInstanceStagingBuffer = new ArrayBuffer(0);\n  let cpuInstanceStagingF32 = new Float32Array(cpuInstanceStagingBuffer);\n\n  const assertNotDisposed = (): void => {\n    if (disposed) throw new Error('AnnotationMarkerRenderer is disposed.');\n  };\n\n  const ensureCpuInstanceCapacityFloats = (requiredFloats: number): void => {\n    if (requiredFloats <= cpuInstanceStagingF32.length) return;\n    const nextFloats = Math.max(32, nextPow2(requiredFloats));\n    cpuInstanceStagingBuffer = new ArrayBuffer(nextFloats * 4);\n    cpuInstanceStagingF32 = new Float32Array(cpuInstanceStagingBuffer);\n  };\n\n  const writeVsUniforms = (canvasWidthDevicePx: number, canvasHeightDevicePx: number, devicePixelRatio: number): void => {\n    const w = Number.isFinite(canvasWidthDevicePx) && canvasWidthDevicePx > 0 ? canvasWidthDevicePx : 1;\n    const h = Number.isFinite(canvasHeightDevicePx) && canvasHeightDevicePx > 0 ? canvasHeightDevicePx : 1;\n    const dpr = Number.isFinite(devicePixelRatio) && devicePixelRatio > 0 ? devicePixelRatio : 1;\n\n    vsUniformScratchF32[0] = w;\n    vsUniformScratchF32[1] = h;\n    vsUniformScratchF32[2] = dpr;\n    vsUniformScratchF32[3] = 0;\n    writeUniformBuffer(device, vsUniformBuffer, vsUniformScratchF32);\n  };\n\n  const prepare: AnnotationMarkerRenderer['prepare'] = ({ canvasWidth, canvasHeight, devicePixelRatio, instances }) => {\n    assertNotDisposed();\n\n    if (!Number.isFinite(canvasWidth) || !Number.isFinite(canvasHeight) || canvasWidth <= 0 || canvasHeight <= 0) {\n      throw new Error('AnnotationMarkerRenderer.prepare: canvasWidth/canvasHeight must be positive finite numbers.');\n    }\n    if (!Array.isArray(instances)) {\n      throw new Error('AnnotationMarkerRenderer.prepare: instances must be an array.');\n    }\n\n    writeVsUniforms(canvasWidth, canvasHeight, devicePixelRatio);\n\n    ensureCpuInstanceCapacityFloats(instances.length * INSTANCE_STRIDE_FLOATS);\n    const f32 = cpuInstanceStagingF32;\n    let outFloats = 0;\n\n    for (let i = 0; i < instances.length; i++) {\n      const m = instances[i];\n      if (!Number.isFinite(m.xCssPx) || !Number.isFinite(m.yCssPx)) continue;\n      if (!Number.isFinite(m.sizeCssPx) || m.sizeCssPx <= 0) continue;\n\n      const strokeWidthCss = m.strokeWidthCssPx ?? 0;\n      const strokeRgba = m.strokeRgba ?? ([0, 0, 0, 0] as const);\n\n      // Clamp colors to [0,1] for deterministic output.\n      const fr = clamp01(m.fillRgba[0]);\n      const fg = clamp01(m.fillRgba[1]);\n      const fb = clamp01(m.fillRgba[2]);\n      const fa = clamp01(m.fillRgba[3]);\n\n      const sr = clamp01(strokeRgba[0]);\n      const sg = clamp01(strokeRgba[1]);\n      const sb = clamp01(strokeRgba[2]);\n      const sa = clamp01(strokeRgba[3]);\n\n      f32[outFloats + 0] = m.xCssPx;\n      f32[outFloats + 1] = m.yCssPx;\n      f32[outFloats + 2] = m.sizeCssPx;\n      f32[outFloats + 3] = Number.isFinite(strokeWidthCss) ? Math.max(0, strokeWidthCss) : 0;\n\n      f32[outFloats + 4] = fr;\n      f32[outFloats + 5] = fg;\n      f32[outFloats + 6] = fb;\n      f32[outFloats + 7] = fa;\n\n      f32[outFloats + 8] = sr;\n      f32[outFloats + 9] = sg;\n      f32[outFloats + 10] = sb;\n      f32[outFloats + 11] = sa;\n\n      outFloats += INSTANCE_STRIDE_FLOATS;\n    }\n\n    instanceCount = outFloats / INSTANCE_STRIDE_FLOATS;\n\n    // PERFORMANCE: Early exit if no valid instances (skip buffer allocation/write)\n    if (instanceCount === 0) {\n      return;\n    }\n\n    const requiredBytes = Math.max(4, instanceCount * INSTANCE_STRIDE_BYTES);\n\n    if (!instanceBuffer || instanceBuffer.size < requiredBytes) {\n      const grownBytes = Math.max(Math.max(4, nextPow2(requiredBytes)), instanceBuffer ? instanceBuffer.size : 0);\n      if (instanceBuffer) {\n        try {\n          instanceBuffer.destroy();\n        } catch {\n          // best-effort\n        }\n      }\n      instanceBuffer = device.createBuffer({\n        label: 'annotationMarkerRenderer/instanceBuffer',\n        size: grownBytes,\n        usage: GPUBufferUsage.VERTEX | GPUBufferUsage.COPY_DST,\n      });\n    }\n\n    // PERFORMANCE: Only write buffer when we have instances (instanceCount > 0 already checked above)\n    device.queue.writeBuffer(instanceBuffer, 0, cpuInstanceStagingBuffer, 0, instanceCount * INSTANCE_STRIDE_BYTES);\n  };\n\n  const render: AnnotationMarkerRenderer['render'] = (passEncoder, firstInstance = 0, requestedCount) => {\n    assertNotDisposed();\n    if (!instanceBuffer || instanceCount === 0) return;\n\n    const first = Number.isFinite(firstInstance) ? Math.max(0, Math.floor(firstInstance)) : 0;\n    const available = Math.max(0, instanceCount - first);\n    const count =\n      requestedCount == null\n        ? available\n        : Number.isFinite(requestedCount)\n          ? Math.max(0, Math.min(available, Math.floor(requestedCount)))\n          : available;\n    if (count === 0) return;\n\n    passEncoder.setPipeline(pipeline);\n    passEncoder.setBindGroup(0, bindGroup);\n    passEncoder.setVertexBuffer(0, instanceBuffer);\n    passEncoder.draw(6, count, 0, first);\n  };\n\n  const dispose: AnnotationMarkerRenderer['dispose'] = () => {\n    if (disposed) return;\n    disposed = true;\n\n    if (instanceBuffer) {\n      try {\n        instanceBuffer.destroy();\n      } catch {\n        // best-effort\n      }\n    }\n    instanceBuffer = null;\n    instanceCount = 0;\n\n    try {\n      vsUniformBuffer.destroy();\n    } catch {\n      // best-effort\n    }\n  };\n\n  return { prepare, render, dispose };\n}\n\n","import type { GridArea } from '../renderers/createGridRenderer';\n\nexport type ChartGPUEventName = 'mousemove' | 'click' | 'mouseleave';\n\nexport type ChartGPUEventPayload = {\n  readonly x: number;\n  readonly y: number;\n  readonly gridX: number;\n  readonly gridY: number;\n  /** Plot (grid) width in CSS pixels. */\n  readonly plotWidthCss: number;\n  /** Plot (grid) height in CSS pixels. */\n  readonly plotHeightCss: number;\n  readonly isInGrid: boolean;\n  readonly originalEvent: PointerEvent;\n};\n\nexport type ChartGPUEventCallback = (payload: ChartGPUEventPayload) => void;\n\nexport interface EventManager {\n  readonly canvas: HTMLCanvasElement;\n  on(event: ChartGPUEventName, callback: ChartGPUEventCallback): void;\n  off(event: ChartGPUEventName, callback: ChartGPUEventCallback): void;\n  updateGridArea(gridArea: GridArea): void;\n  dispose(): void;\n}\n\ntype ListenerRegistry = Readonly<Record<ChartGPUEventName, Set<ChartGPUEventCallback>>>;\n\ntype TapCandidate = {\n  readonly pointerId: number;\n  readonly startClientX: number;\n  readonly startClientY: number;\n  readonly startTimeMs: number;\n};\n\nconst DEFAULT_TAP_MAX_DISTANCE_CSS_PX = 6;\nconst DEFAULT_TAP_MAX_TIME_MS = 500;\n\nexport function createEventManager(canvas: HTMLCanvasElement, initialGridArea: GridArea): EventManager {\n  let disposed = false;\n  let gridArea = initialGridArea;\n\n  const listeners: ListenerRegistry = {\n    mousemove: new Set<ChartGPUEventCallback>(),\n    click: new Set<ChartGPUEventCallback>(),\n    mouseleave: new Set<ChartGPUEventCallback>(),\n  };\n\n  let tapCandidate: TapCandidate | null = null;\n  let suppressNextLostPointerCaptureId: number | null = null;\n\n  const toPayload = (e: PointerEvent): ChartGPUEventPayload | null => {\n    const rect = canvas.getBoundingClientRect();\n    if (rect.width === 0 || rect.height === 0) return null;\n\n    const x = e.clientX - rect.left;\n    const y = e.clientY - rect.top;\n\n    const plotLeftCss = gridArea.left;\n    const plotTopCss = gridArea.top;\n    const plotWidthCss = rect.width - gridArea.left - gridArea.right;\n    const plotHeightCss = rect.height - gridArea.top - gridArea.bottom;\n\n    const gridX = x - plotLeftCss;\n    const gridY = y - plotTopCss;\n\n    const isInGrid =\n      gridX >= 0 &&\n      gridX <= plotWidthCss &&\n      gridY >= 0 &&\n      gridY <= plotHeightCss;\n\n    return { x, y, gridX, gridY, plotWidthCss, plotHeightCss, isInGrid, originalEvent: e };\n  };\n\n  const emit = (eventName: ChartGPUEventName, e: PointerEvent): void => {\n    const payload = toPayload(e);\n    if (!payload) return;\n\n    for (const cb of listeners[eventName]) cb(payload);\n  };\n\n  const clearTapCandidateIfMatches = (e: PointerEvent): void => {\n    if (!tapCandidate) return;\n    if (!e.isPrimary) return;\n    if (e.pointerId !== tapCandidate.pointerId) return;\n    tapCandidate = null;\n  };\n\n  const onPointerMove = (e: PointerEvent): void => {\n    if (disposed) return;\n    emit('mousemove', e);\n  };\n\n  const onPointerLeave = (e: PointerEvent): void => {\n    if (disposed) return;\n    clearTapCandidateIfMatches(e);\n    emit('mouseleave', e);\n  };\n\n  const onPointerCancel = (e: PointerEvent): void => {\n    if (disposed) return;\n    clearTapCandidateIfMatches(e);\n    emit('mouseleave', e);\n  };\n\n  const onLostPointerCapture = (e: PointerEvent): void => {\n    if (disposed) return;\n    if (suppressNextLostPointerCaptureId === e.pointerId) {\n      suppressNextLostPointerCaptureId = null;\n      return;\n    }\n    clearTapCandidateIfMatches(e);\n    emit('mouseleave', e);\n  };\n\n  const onPointerDown = (e: PointerEvent): void => {\n    if (disposed) return;\n    if (!e.isPrimary) return;\n\n    // For mouse, only allow left button.\n    if (e.pointerType === 'mouse' && e.button !== 0) return;\n\n    // If canvas has no size, treat as non-interactive (and avoid tap tracking).\n    const rect = canvas.getBoundingClientRect();\n    if (rect.width === 0 || rect.height === 0) return;\n\n    tapCandidate = {\n      pointerId: e.pointerId,\n      startClientX: e.clientX,\n      startClientY: e.clientY,\n      startTimeMs: e.timeStamp,\n    };\n\n    // Optional pointer capture improves reliability for touch/pen.\n    try {\n      canvas.setPointerCapture(e.pointerId);\n    } catch {\n      // best-effort\n    }\n  };\n\n  const onPointerUp = (e: PointerEvent): void => {\n    if (disposed) return;\n    if (!e.isPrimary) return;\n    if (!tapCandidate || e.pointerId !== tapCandidate.pointerId) return;\n\n    const dt = e.timeStamp - tapCandidate.startTimeMs;\n    const dx = e.clientX - tapCandidate.startClientX;\n    const dy = e.clientY - tapCandidate.startClientY;\n    const distSq = dx * dx + dy * dy;\n\n    tapCandidate = null;\n\n    // Release capture if we have it; suppress the resulting lostpointercapture.\n    try {\n      if (canvas.hasPointerCapture(e.pointerId)) {\n        suppressNextLostPointerCaptureId = e.pointerId;\n        canvas.releasePointerCapture(e.pointerId);\n      }\n    } catch {\n      // best-effort\n    }\n\n    const maxDist = DEFAULT_TAP_MAX_DISTANCE_CSS_PX;\n    const isTap =\n      dt <= DEFAULT_TAP_MAX_TIME_MS && distSq <= maxDist * maxDist;\n\n    if (isTap) emit('click', e);\n  };\n\n  canvas.addEventListener('pointermove', onPointerMove, { passive: true });\n  canvas.addEventListener('pointerleave', onPointerLeave, { passive: true });\n  canvas.addEventListener('pointercancel', onPointerCancel, { passive: true });\n  canvas.addEventListener('lostpointercapture', onLostPointerCapture, { passive: true });\n  canvas.addEventListener('pointerdown', onPointerDown, { passive: true });\n  canvas.addEventListener('pointerup', onPointerUp, { passive: true });\n\n  const on: EventManager['on'] = (event, callback) => {\n    if (disposed) return;\n    listeners[event].add(callback);\n  };\n\n  const off: EventManager['off'] = (event, callback) => {\n    listeners[event].delete(callback);\n  };\n\n  const updateGridArea: EventManager['updateGridArea'] = (nextGridArea) => {\n    gridArea = nextGridArea;\n  };\n\n  const dispose: EventManager['dispose'] = () => {\n    if (disposed) return;\n    disposed = true;\n\n    tapCandidate = null;\n    suppressNextLostPointerCaptureId = null;\n\n    canvas.removeEventListener('pointermove', onPointerMove);\n    canvas.removeEventListener('pointerleave', onPointerLeave);\n    canvas.removeEventListener('pointercancel', onPointerCancel);\n    canvas.removeEventListener('lostpointercapture', onLostPointerCapture);\n    canvas.removeEventListener('pointerdown', onPointerDown);\n    canvas.removeEventListener('pointerup', onPointerUp);\n\n    listeners.mousemove.clear();\n    listeners.click.clear();\n    listeners.mouseleave.clear();\n  };\n\n  return { canvas, on, off, updateGridArea, dispose };\n}\n","import type { EventManager, ChartGPUEventPayload } from './createEventManager';\nimport type { ZoomState } from './createZoomState';\n\nexport type InsideZoom = Readonly<{\n  enable(): void;\n  disable(): void;\n  dispose(): void;\n}>;\n\nconst clamp = (v: number, lo: number, hi: number): number => Math.min(hi, Math.max(lo, v));\n\nconst normalizeWheelDelta = (e: WheelEvent, basisCssPx: number): number => {\n  const raw = e.deltaY;\n  if (!Number.isFinite(raw) || raw === 0) return 0;\n\n  // Normalize to CSS pixels-ish so sensitivity is stable across deltaMode.\n  switch (e.deltaMode) {\n    case WheelEvent.DOM_DELTA_PIXEL:\n      return raw;\n    case WheelEvent.DOM_DELTA_LINE:\n      return raw * 16;\n    case WheelEvent.DOM_DELTA_PAGE:\n      return raw * (Number.isFinite(basisCssPx) && basisCssPx > 0 ? basisCssPx : 800);\n    default:\n      return raw;\n  }\n};\n\nconst normalizeWheelDeltaX = (e: WheelEvent, basisCssPx: number): number => {\n  const raw = e.deltaX;\n  if (!Number.isFinite(raw) || raw === 0) return 0;\n\n  // Normalize to CSS pixels-ish so sensitivity is stable across deltaMode.\n  switch (e.deltaMode) {\n    case WheelEvent.DOM_DELTA_PIXEL:\n      return raw;\n    case WheelEvent.DOM_DELTA_LINE:\n      return raw * 16;\n    case WheelEvent.DOM_DELTA_PAGE:\n      return raw * (Number.isFinite(basisCssPx) && basisCssPx > 0 ? basisCssPx : 800);\n    default:\n      return raw;\n  }\n};\n\nconst wheelDeltaToZoomFactor = (deltaCssPx: number): number => {\n  // Positive delta = scroll down = zoom out; negative = zoom in.\n  const abs = Math.abs(deltaCssPx);\n  if (!Number.isFinite(abs) || abs === 0) return 1;\n\n  // Cap extreme deltas (some devices can emit huge values).\n  const capped = Math.min(abs, 200);\n  const sensitivity = 0.002;\n  return Math.exp(capped * sensitivity);\n};\n\nconst isMiddleButtonDrag = (e: PointerEvent): boolean =>\n  e.pointerType === 'mouse' && (e.buttons & 4) !== 0;\n\nconst isShiftLeftDrag = (e: PointerEvent): boolean =>\n  e.pointerType === 'mouse' && e.shiftKey && (e.buttons & 1) !== 0;\n\n/**\n * Internal “inside” zoom interaction:\n * - wheel zoom centered at cursor-x (only when inside grid)\n * - shift+left drag OR middle-mouse drag pans left/right (only when inside grid)\n */\nexport function createInsideZoom(eventManager: EventManager, zoomState: ZoomState): InsideZoom {\n  let disposed = false;\n  let enabled = false;\n\n  let lastPointer: ChartGPUEventPayload | null = null;\n  let isPanning = false;\n  let lastPanGridX = 0;\n\n  const clearPan = (): void => {\n    isPanning = false;\n    lastPanGridX = 0;\n  };\n\n  const onMouseMove = (payload: ChartGPUEventPayload): void => {\n    lastPointer = payload;\n    if (!enabled) return;\n\n    // Pan only for mouse drags, only when inside grid.\n    const e = payload.originalEvent;\n    const shouldPan = payload.isInGrid && (isShiftLeftDrag(e) || isMiddleButtonDrag(e));\n\n    if (!shouldPan) {\n      clearPan();\n      return;\n    }\n\n    const plotWidthCss = payload.plotWidthCss;\n    if (!(plotWidthCss > 0) || !Number.isFinite(plotWidthCss)) {\n      clearPan();\n      return;\n    }\n\n    if (!isPanning) {\n      isPanning = true;\n      lastPanGridX = payload.gridX;\n      return;\n    }\n\n    const dxCss = payload.gridX - lastPanGridX;\n    lastPanGridX = payload.gridX;\n    if (!Number.isFinite(dxCss) || dxCss === 0) return;\n\n    const { start, end } = zoomState.getRange();\n    const span = end - start;\n    if (!Number.isFinite(span) || span === 0) return;\n\n    // Convert grid-local px to percent points *within the current window*.\n    // “Grab to pan” behavior: dragging right should move the window left (show earlier data).\n    const deltaPct = -(dxCss / plotWidthCss) * span;\n    if (!Number.isFinite(deltaPct) || deltaPct === 0) return;\n    zoomState.pan(deltaPct);\n  };\n\n  const onMouseLeave = (_payload: ChartGPUEventPayload): void => {\n    lastPointer = null;\n    clearPan();\n  };\n\n  const onWheel = (e: WheelEvent): void => {\n    if (!enabled || disposed) return;\n\n    const p = lastPointer;\n    if (!p || !p.isInGrid) return;\n\n    const plotWidthCss = p.plotWidthCss;\n    const plotHeightCss = p.plotHeightCss;\n    if (!(plotWidthCss > 0) || !(plotHeightCss > 0)) return;\n\n    const deltaYCss = normalizeWheelDelta(e, plotHeightCss);\n    const deltaXCss = normalizeWheelDeltaX(e, plotWidthCss);\n\n    // Check if horizontal scroll is dominant (pan operation).\n    if (Math.abs(deltaXCss) > Math.abs(deltaYCss) && deltaXCss !== 0) {\n      const { start, end } = zoomState.getRange();\n      const span = end - start;\n      if (!Number.isFinite(span) || span === 0) return;\n\n      // Convert horizontal scroll delta to percent pan.\n      // Positive deltaX = scroll right = pan right (show earlier data).\n      const deltaPct = (deltaXCss / plotWidthCss) * span;\n      if (!Number.isFinite(deltaPct) || deltaPct === 0) return;\n\n      e.preventDefault();\n      zoomState.pan(deltaPct);\n      return;\n    }\n\n    // Otherwise, proceed with vertical scroll zoom logic.\n    if (deltaYCss === 0) return;\n\n    const factor = wheelDeltaToZoomFactor(deltaYCss);\n    if (!(factor > 1)) return;\n\n    const { start, end } = zoomState.getRange();\n    const span = end - start;\n    if (!Number.isFinite(span) || span === 0) return;\n    const r = clamp(p.gridX / plotWidthCss, 0, 1);\n    const centerPct = clamp(start + r * span, 0, 100);\n\n    // Only prevent default when we are actually consuming the wheel to zoom.\n    e.preventDefault();\n\n    if (deltaYCss < 0) zoomState.zoomIn(centerPct, factor);\n    else zoomState.zoomOut(centerPct, factor);\n  };\n\n  const enable: InsideZoom['enable'] = () => {\n    if (disposed || enabled) return;\n    enabled = true;\n    eventManager.on('mousemove', onMouseMove);\n    eventManager.on('mouseleave', onMouseLeave);\n    eventManager.canvas.addEventListener('wheel', onWheel, { passive: false });\n  };\n\n  const disable: InsideZoom['disable'] = () => {\n    if (disposed || !enabled) return;\n    enabled = false;\n    eventManager.off('mousemove', onMouseMove);\n    eventManager.off('mouseleave', onMouseLeave);\n    eventManager.canvas.removeEventListener('wheel', onWheel);\n    lastPointer = null;\n    clearPan();\n  };\n\n  const dispose: InsideZoom['dispose'] = () => {\n    if (disposed) return;\n    disable();\n    disposed = true;\n  };\n\n  return { enable, disable, dispose };\n}\n\n","export type ZoomRange = Readonly<{ start: number; end: number }>;\n\nexport type ZoomRangeChangeCallback = (range: ZoomRange) => void;\n\nexport interface ZoomState {\n  /**\n   * Returns the current zoom window in percent space, clamped to [0, 100].\n   */\n  getRange(): ZoomRange;\n  /**\n   * Sets the zoom window in percent space.\n   */\n  setRange(start: number, end: number): void;\n  /**\n   * Zooms in around `center` by shrinking the span by `factor`.\n   *\n   * `factor <= 1` is treated as a no-op.\n   */\n  zoomIn(center: number, factor: number): void;\n  /**\n   * Zooms out around `center` by growing the span by `factor`.\n   *\n   * `factor <= 1` is treated as a no-op.\n   */\n  zoomOut(center: number, factor: number): void;\n  /**\n   * Pans the zoom window by `delta` percent points (preserving span).\n   */\n  pan(delta: number): void;\n  /**\n   * Subscribes to changes. Returns an unsubscribe function.\n   */\n  onChange(callback: ZoomRangeChangeCallback): () => void;\n}\n\nexport type ZoomSpanConstraints = Readonly<{\n  /**\n   * Minimum allowed span (percent points in [0, 100]).\n   */\n  readonly minSpan?: number;\n  /**\n   * Maximum allowed span (percent points in [0, 100]).\n   */\n  readonly maxSpan?: number;\n}>;\n\nexport type ZoomRangeAnchor =\n  | 'start'\n  | 'end'\n  | 'center'\n  | Readonly<{ center: number; ratio: number }>;\n\nexport interface ZoomStateWithConstraints extends ZoomState {\n  /**\n   * Updates span constraints at runtime (used by coordinator on setOption/appendData).\n   *\n   * Passing `undefined` leaves that constraint unchanged.\n   */\n  setSpanConstraints(minSpan?: number, maxSpan?: number): void;\n  /**\n   * Sets a range with an explicit anchor for clamping (used by slider handles).\n   */\n  setRangeAnchored(start: number, end: number, anchor: ZoomRangeAnchor): void;\n}\n\n// Minimum span of 0.5% prevents zooming beyond what can be reasonably visualized\n// and prevents the slider UI from becoming unusably collapsed.\n// At 0.5% span, a 500px track shows a 2.5px window, which with 10px handles\n// is still somewhat distinguishable. Below 0.5% the UI becomes meaningless.\nconst DEFAULT_MIN_SPAN = 0.5;\nconst DEFAULT_MAX_SPAN = 100;\n\nconst clamp = (v: number, lo: number, hi: number): number => Math.min(hi, Math.max(lo, v));\nconst clamp01 = (v: number): number => clamp(v, 0, 1);\n\nconst normalizeZero = (v: number): number => (Object.is(v, -0) ? 0 : v);\n\nconst copyRange = (r: ZoomRange): ZoomRange => ({ start: r.start, end: r.end });\n\nexport function createZoomState(\n  initialStart: number,\n  initialEnd: number,\n  constraints?: ZoomSpanConstraints,\n): ZoomStateWithConstraints {\n  let start = 0;\n  let end = 100;\n  let lastEmitted: ZoomRange | null = null;\n\n  const listeners = new Set<ZoomRangeChangeCallback>();\n\n  let minSpan = (() => {\n    const v = Number.isFinite(constraints?.minSpan) ? (constraints!.minSpan as number) : DEFAULT_MIN_SPAN;\n    return clamp(Number.isFinite(v) ? v : 0, 0, 100);\n  })();\n\n  let maxSpan = (() => {\n    const v = Number.isFinite(constraints?.maxSpan) ? (constraints!.maxSpan as number) : DEFAULT_MAX_SPAN;\n    return clamp(Number.isFinite(v) ? v : 100, 0, 100);\n  })();\n\n  let normalizedMinSpan = Math.min(minSpan, maxSpan);\n  let normalizedMaxSpan = Math.max(minSpan, maxSpan);\n\n  const emit = (): void => {\n    const next: ZoomRange = { start, end };\n    if (\n      lastEmitted !== null &&\n      lastEmitted.start === next.start &&\n      lastEmitted.end === next.end\n    ) {\n      return;\n    }\n\n    lastEmitted = copyRange(next);\n\n    // Emit to a snapshot so additions/removals during emit don't affect this flush.\n    const snapshot = Array.from(listeners);\n    for (const cb of snapshot) cb({ start, end });\n  };\n\n  const toAnchor = (nextStart: number, nextEnd: number, spec?: ZoomRangeAnchor): { readonly center: number; readonly ratio: number } | undefined => {\n    if (!spec) return undefined;\n    if (typeof spec === 'string') {\n      switch (spec) {\n        case 'start':\n          return { center: nextStart, ratio: 0 };\n        case 'end':\n          return { center: nextEnd, ratio: 1 };\n        case 'center':\n          return { center: (nextStart + nextEnd) * 0.5, ratio: 0.5 };\n      }\n    }\n    if (spec && Number.isFinite(spec.center) && Number.isFinite(spec.ratio)) {\n      return { center: spec.center, ratio: spec.ratio };\n    }\n    return undefined;\n  };\n\n  const applyNextRange = (\n    nextStart: number,\n    nextEnd: number,\n    options?: { readonly emit?: boolean; readonly anchor?: { readonly center: number; readonly ratio: number } },\n  ): void => {\n    if (!Number.isFinite(nextStart) || !Number.isFinite(nextEnd)) return;\n\n    let s = nextStart;\n    let e = nextEnd;\n\n    if (s > e) {\n      const t = s;\n      s = e;\n      e = t;\n    }\n\n    // Enforce span constraints by resizing around the proposed midpoint.\n    let span = e - s;\n    if (!Number.isFinite(span) || span < 0) return;\n\n    const targetSpan = clamp(span, normalizedMinSpan, normalizedMaxSpan);\n    if (targetSpan !== span) {\n      const anchorCenter =\n        options?.anchor && Number.isFinite(options.anchor.center)\n          ? clamp(options.anchor.center, 0, 100)\n          : (s + e) * 0.5;\n      const anchorRatio =\n        options?.anchor && Number.isFinite(options.anchor.ratio)\n          ? clamp01(options.anchor.ratio)\n          : 0.5;\n\n      // Resize around the anchor so zoom operations preserve the cursor location.\n      s = anchorCenter - anchorRatio * targetSpan;\n      e = s + targetSpan;\n      span = targetSpan;\n    }\n\n    // If span exceeds bounds (shouldn't happen with normalizedMaxSpan <= 100), clamp to full extent.\n    if (span > 100) {\n      s = 0;\n      e = 100;\n      span = 100;\n    }\n\n    // Shift into bounds without changing span.\n    if (s < 0) {\n      const shift = -s;\n      s += shift;\n      e += shift;\n    }\n    if (e > 100) {\n      const shift = e - 100;\n      s -= shift;\n      e -= shift;\n    }\n\n    // Final clamp for tiny floating point drift.\n    s = clamp(s, 0, 100);\n    e = clamp(e, 0, 100);\n\n    s = normalizeZero(s);\n    e = normalizeZero(e);\n\n    if (s === start && e === end) return;\n    start = s;\n    end = e;\n\n    if (options?.emit === false) return;\n    emit();\n  };\n\n  // Initialize state (no emit by default).\n  applyNextRange(initialStart, initialEnd, { emit: false });\n\n  const getRange: ZoomState['getRange'] = () => ({ start, end });\n\n  const setRange: ZoomState['setRange'] = (nextStart, nextEnd) => {\n    applyNextRange(nextStart, nextEnd);\n  };\n\n  const setRangeAnchored: ZoomStateWithConstraints['setRangeAnchored'] = (nextStart, nextEnd, anchor) => {\n    applyNextRange(nextStart, nextEnd, { anchor: toAnchor(nextStart, nextEnd, anchor) });\n  };\n\n  const setSpanConstraints: ZoomStateWithConstraints['setSpanConstraints'] = (nextMinSpan, nextMaxSpan) => {\n    // Undefined => leave unchanged (lets coordinator reapply dynamically computed values explicitly).\n    const nextMin =\n      typeof nextMinSpan === 'number' && Number.isFinite(nextMinSpan) ? clamp(nextMinSpan, 0, 100) : minSpan;\n    const nextMax =\n      typeof nextMaxSpan === 'number' && Number.isFinite(nextMaxSpan) ? clamp(nextMaxSpan, 0, 100) : maxSpan;\n\n    if (nextMin === minSpan && nextMax === maxSpan) return;\n\n    minSpan = nextMin;\n    maxSpan = nextMax;\n    normalizedMinSpan = Math.min(minSpan, maxSpan);\n    normalizedMaxSpan = Math.max(minSpan, maxSpan);\n\n    // If the current range violates the new constraints, clamp it.\n    // Heuristic anchors keep \"pinned to start/end\" views stable (auto-scroll and common UX).\n    const s = start;\n    const e = end;\n    const eps = 1e-6;\n    const anchor: ZoomRangeAnchor =\n      e >= 100 - eps ? 'end' : s <= 0 + eps ? 'start' : 'center';\n    applyNextRange(s, e, { anchor: toAnchor(s, e, anchor) });\n  };\n\n  const zoomIn: ZoomState['zoomIn'] = (center, factor) => {\n    if (!Number.isFinite(center) || !Number.isFinite(factor)) return;\n    if (factor <= 1) return;\n\n    const c = clamp(center, 0, 100);\n    const span = end - start;\n    const r = span === 0 ? 0.5 : clamp01((c - start) / span);\n    const nextSpan = span / factor;\n    const nextStart = c - r * nextSpan;\n    const nextEnd = nextStart + nextSpan;\n    applyNextRange(nextStart, nextEnd, { anchor: { center: c, ratio: r } });\n  };\n\n  const zoomOut: ZoomState['zoomOut'] = (center, factor) => {\n    if (!Number.isFinite(center) || !Number.isFinite(factor)) return;\n    if (factor <= 1) return;\n\n    const c = clamp(center, 0, 100);\n    const span = end - start;\n    const r = span === 0 ? 0.5 : clamp01((c - start) / span);\n    const nextSpan = span * factor;\n    const nextStart = c - r * nextSpan;\n    const nextEnd = nextStart + nextSpan;\n    applyNextRange(nextStart, nextEnd, { anchor: { center: c, ratio: r } });\n  };\n\n  const pan: ZoomState['pan'] = (delta) => {\n    if (!Number.isFinite(delta)) return;\n    applyNextRange(start + delta, end + delta);\n  };\n\n  const onChange: ZoomState['onChange'] = (callback) => {\n    listeners.add(callback);\n    return () => {\n      listeners.delete(callback);\n    };\n  };\n\n  return { getRange, setRange, setRangeAnchored, setSpanConstraints, zoomIn, zoomOut, pan, onChange };\n}\n\n","import type { DataPoint, CartesianSeriesData } from '../config/types';\nimport type { ResolvedBarSeriesConfig, ResolvedSeriesConfig } from '../config/OptionResolver';\nimport type { LinearScale } from '../utils/scales';\nimport { computeBarLayoutPx } from './findNearestPoint';\nimport { getPointCount, getX, getY, getSize } from '../data/cartesianData';\n\nexport type PointsAtXMatch = Readonly<{\n  seriesIndex: number;\n  dataIndex: number;\n  point: DataPoint;\n}>;\n\nconst hasNaNXCache = new WeakMap<object, boolean>();\n\nconst seriesHasNaNX = (data: CartesianSeriesData): boolean => {\n  // Use data object as cache key (works for arrays, typed arrays, and XYArraysData)\n  const cacheKey = typeof data === 'object' && data !== null ? data : null;\n  if (cacheKey && hasNaNXCache.has(cacheKey)) {\n    return hasNaNXCache.get(cacheKey)!;\n  }\n\n  let hasNaN = false;\n  const n = getPointCount(data);\n\n  for (let i = 0; i < n; i++) {\n    const x = getX(data, i);\n    if (Number.isNaN(x)) {\n      hasNaN = true;\n      break;\n    }\n  }\n\n  if (cacheKey) hasNaNXCache.set(cacheKey, hasNaN);\n  return hasNaN;\n};\n\ntype BarHitTestLayout = Readonly<{\n  /** bar width in xScale range units (grid-local CSS px) */\n  barWidth: number;\n  /** gap between cluster slots, in xScale range units */\n  gap: number;\n  /** total cluster width (all bar slots), in xScale range units */\n  clusterWidth: number;\n  /** maps global series index -> cluster slot index */\n  clusterIndexByGlobalSeriesIndex: ReadonlyMap<number, number>;\n}>;\n\nconst computeBarHitTestLayout = (\n  series: ReadonlyArray<ResolvedSeriesConfig>,\n  xScale: LinearScale\n): BarHitTestLayout | null => {\n  // Mirror the bar renderer's shared layout math via `computeBarLayoutPx(...)`, but in xScale range units.\n  // IMPORTANT: Bar layout depends on all bar series (stacking + grouped slots), not per-series.\n  const barSeries: { readonly globalSeriesIndex: number; readonly s: ResolvedBarSeriesConfig }[] = [];\n  for (let i = 0; i < series.length; i++) {\n    const s = series[i];\n    if (s?.type === 'bar') barSeries.push({ globalSeriesIndex: i, s });\n  }\n  if (barSeries.length === 0) return null;\n\n  const layout = computeBarLayoutPx(\n    barSeries.map((b) => b.s),\n    xScale\n  );\n\n  const barWidthRange = layout.barWidthPx;\n  const gap = layout.gapPx;\n  const clusterWidth = layout.clusterWidthPx;\n  if (!Number.isFinite(barWidthRange) || !(barWidthRange > 0)) return null;\n\n  const clusterIndexByGlobalSeriesIndex = new Map<number, number>();\n  for (let i = 0; i < barSeries.length; i++) {\n    const globalSeriesIndex = barSeries[i].globalSeriesIndex;\n    const clusterIndex = layout.clusterSlots.clusterIndexBySeries[i] ?? 0;\n    clusterIndexByGlobalSeriesIndex.set(globalSeriesIndex, clusterIndex);\n  }\n\n  return {\n    barWidth: barWidthRange,\n    gap,\n    clusterWidth,\n    clusterIndexByGlobalSeriesIndex,\n  };\n};\n\nconst lowerBoundX = (data: CartesianSeriesData, xTarget: number): number => {\n  let lo = 0;\n  let hi = getPointCount(data);\n  while (lo < hi) {\n    const mid = (lo + hi) >>> 1;\n    const x = getX(data, mid);\n    if (x < xTarget) lo = mid + 1;\n    else hi = mid;\n  }\n  return lo;\n};\n\n/**\n * Finds (at most) one nearest point per series at a given x position.\n *\n * Coordinate system contract (mirrors `findNearestPoint`):\n * - `xValue` and optional `tolerance` MUST be in the same units as `xScale` **range**.\n *   (Example: if your `xScale.range()` is in grid-local CSS pixels, pass `payload.gridX` from `createEventManager`.)\n *   Note: ChartGPU's internal renderer scales are currently in clip space (NDC, typically \\[-1, 1\\]); in that case\n *   convert your pointer x into clip space before calling this helper.\n *\n * Behavior:\n * - Assumes each series is sorted by increasing x in domain space.\n * - Uses a lower-bound binary search in domain-x, then expands outward while x-distance alone can still improve.\n * - Skips points with non-finite domain x or non-finite scaled x. If a series contains any NaN x values, this helper\n *   falls back to an O(n) scan for correctness (NaN breaks total ordering for binary search).\n * - Stable tie-breaking: for equal distance, chooses the smaller `dataIndex`.\n *\n * If `tolerance` is provided, it is interpreted in **xScale range units**. Matches beyond tolerance are omitted.\n * If `tolerance` is omitted (or non-finite), the nearest point per series is returned when possible.\n *\n * Bar series special-case:\n * - Bars occupy x-intervals \\([left, right)\\) in **xScale range units** (grid-local CSS px for interaction scales),\n *   using the same shared layout math as the bar renderer (grouping + stacking slots).\n * - If `tolerance` is finite, a bar match is only returned when `xValue` falls inside the bar interval expanded by\n *   `tolerance` on both sides: \\([left - tolerance, right + tolerance)\\).\n * - If `tolerance` is omitted / non-finite, we first attempt an exact interval hit (no expansion) and otherwise fall\n *   back to the existing nearest-x behavior (so axis-trigger tooltips still work away from bars).\n */\nexport function findPointsAtX(\n  series: ReadonlyArray<ResolvedSeriesConfig>,\n  xValue: number,\n  xScale: LinearScale,\n  tolerance?: number,\n): ReadonlyArray<PointsAtXMatch> {\n  if (!Number.isFinite(xValue)) return [];\n\n  const maxDx =\n    tolerance === undefined || !Number.isFinite(tolerance) ? Number.POSITIVE_INFINITY : Math.max(0, tolerance);\n  const maxDxSq = maxDx * maxDx;\n\n  const xTarget = xScale.invert(xValue);\n  if (!Number.isFinite(xTarget)) return [];\n\n  const matches: PointsAtXMatch[] = [];\n  const barLayout = computeBarHitTestLayout(series, xScale);\n\n  for (let s = 0; s < series.length; s++) {\n    const seriesConfig = series[s];\n    // Pie and candlestick are non-cartesian (or not yet implemented); they can't match an x position.\n    if (seriesConfig.type === 'pie' || seriesConfig.type === 'candlestick') continue;\n\n    // Skip invisible series.\n    if (seriesConfig.visible === false) continue;\n\n    const data = seriesConfig.data as CartesianSeriesData;\n    const n = getPointCount(data);\n    if (n === 0) continue;\n\n    // Bar series: return the correct bar dataIndex for xValue when inside the bar interval.\n    // When tolerance is finite: require an (expanded) interval hit.\n    // When tolerance is non-finite: attempt exact hit, otherwise fall back to nearest-x behavior below.\n    if (seriesConfig.type === 'bar' && barLayout) {\n      const clusterIndex = barLayout.clusterIndexByGlobalSeriesIndex.get(s);\n      if (clusterIndex !== undefined) {\n        const { barWidth, gap, clusterWidth } = barLayout;\n        const offsetLeftFromCategoryCenter = -clusterWidth / 2 + clusterIndex * (barWidth + gap);\n\n        const hitTol =\n          tolerance === undefined || !Number.isFinite(tolerance) ? 0 : Math.max(0, tolerance);\n\n        // If we can't safely compute an interval hit, don't guess when tolerance is finite.\n        if (Number.isFinite(barWidth) && barWidth > 0 && Number.isFinite(offsetLeftFromCategoryCenter)) {\n          let hitIndex = -1;\n\n          const isHit = (xCenterRange: number): boolean => {\n            if (!Number.isFinite(xCenterRange)) return false;\n            const left = xCenterRange + offsetLeftFromCategoryCenter;\n            const right = left + barWidth;\n            // Expanded interval: [left - tol, right + tol)\n            return xValue >= left - hitTol && xValue < right + hitTol;\n          };\n\n          if (seriesHasNaNX(data)) {\n            // NaN breaks ordering; linear scan for correctness.\n            for (let i = 0; i < n; i++) {\n              const px = getX(data, i);\n              if (!Number.isFinite(px)) continue;\n              const xCenter = xScale.scale(px);\n              if (isHit(xCenter)) {\n                hitIndex = hitIndex < 0 ? i : Math.min(hitIndex, i);\n              }\n            }\n          } else {\n            // Use a lower-bound search around the adjusted x (accounts for cluster offset).\n            const xTargetAdjusted = xScale.invert(xValue - offsetLeftFromCategoryCenter);\n            if (Number.isFinite(xTargetAdjusted)) {\n              const insertionIndex = lowerBoundX(data, xTargetAdjusted);\n\n              const getXCenterAt = (idx: number): number | null => {\n                if (idx < 0 || idx >= n) return null;\n                const px = getX(data, idx);\n                if (!Number.isFinite(px)) return null;\n                const xCenter = xScale.scale(px);\n                return Number.isFinite(xCenter) ? xCenter : null;\n              };\n\n              // Scan left while intervals could still contain xValue.\n              for (let i = insertionIndex - 1; i >= 0; i--) {\n                const xCenter = getXCenterAt(i);\n                if (xCenter === null) continue;\n                const left = xCenter + offsetLeftFromCategoryCenter;\n                const right = left + barWidth;\n                if (right + hitTol <= xValue) break;\n                if (xValue >= left - hitTol && xValue < right + hitTol) {\n                  hitIndex = hitIndex < 0 ? i : Math.min(hitIndex, i);\n                }\n              }\n\n              // Scan right until intervals start strictly after xValue.\n              for (let i = insertionIndex; i < n; i++) {\n                const xCenter = getXCenterAt(i);\n                if (xCenter === null) continue;\n                const left = xCenter + offsetLeftFromCategoryCenter;\n                if (left - hitTol > xValue) break;\n                const right = left + barWidth;\n                if (xValue < right + hitTol) {\n                  hitIndex = hitIndex < 0 ? i : Math.min(hitIndex, i);\n                }\n              }\n            }\n          }\n\n          if (hitIndex >= 0) {\n            const x = getX(data, hitIndex);\n            const y = getY(data, hitIndex);\n            const size = getSize(data, hitIndex);\n            const point: DataPoint = size !== undefined ? [x, y, size] : [x, y];\n            matches.push({ seriesIndex: s, dataIndex: hitIndex, point });\n            continue;\n          }\n\n          // If tolerance is finite, require a hit (no nearest-x fallback).\n          if (tolerance !== undefined && Number.isFinite(tolerance)) {\n            continue;\n          }\n          // Else: fall through to nearest-x behavior (existing logic) for axis-trigger tooltips.\n        } else if (tolerance !== undefined && Number.isFinite(tolerance)) {\n          continue;\n        }\n      }\n    }\n\n    let bestDataIndex = -1;\n    let bestPoint: DataPoint | null = null;\n    let bestDxSq = maxDxSq;\n\n    const tryUpdate = (idx: number, dxSq: number) => {\n      if (!Number.isFinite(dxSq)) return;\n      const isBetter =\n        dxSq < bestDxSq || (dxSq === bestDxSq && (bestDataIndex < 0 || idx < bestDataIndex));\n      if (!isBetter) return;\n      bestDxSq = dxSq;\n      bestDataIndex = idx;\n      // Construct DataPoint for return\n      const x = getX(data, idx);\n      const y = getY(data, idx);\n      const size = getSize(data, idx);\n      bestPoint = size !== undefined ? [x, y, size] : [x, y];\n    };\n\n    // If the series contains NaN x values, binary search cannot be trusted (NaN breaks ordering).\n    // Fall back to a linear scan for correctness. Cached per data array for performance.\n    if (seriesHasNaNX(data)) {\n      for (let i = 0; i < n; i++) {\n        const px = getX(data, i);\n        if (!Number.isFinite(px)) continue;\n        const sx = xScale.scale(px);\n        if (!Number.isFinite(sx)) continue;\n        const dx = sx - xValue;\n        tryUpdate(i, dx * dx);\n      }\n    } else {\n      const insertionIndex = lowerBoundX(data, xTarget);\n\n      let left = insertionIndex - 1;\n      let right = insertionIndex;\n\n      const dxSqAt = (idx: number): number | null => {\n        const px = getX(data, idx);\n        if (!Number.isFinite(px)) return null;\n        const sx = xScale.scale(px);\n        if (!Number.isFinite(sx)) return null;\n        const dx = sx - xValue;\n        return dx * dx;\n      };\n\n      while (left >= 0 || right < n) {\n        while (left >= 0 && dxSqAt(left) === null) left--;\n        while (right < n && dxSqAt(right) === null) right++;\n        if (left < 0 && right >= n) break;\n\n        const dxSqLeft = left >= 0 ? (dxSqAt(left) ?? Number.POSITIVE_INFINITY) : Number.POSITIVE_INFINITY;\n        const dxSqRight = right < n ? (dxSqAt(right) ?? Number.POSITIVE_INFINITY) : Number.POSITIVE_INFINITY;\n\n        if (dxSqLeft > bestDxSq && dxSqRight > bestDxSq) break;\n\n        // If both sides are equally close in x, evaluate left first (smaller index) for stable ties.\n        if (dxSqLeft <= dxSqRight) {\n          if (left >= 0 && dxSqLeft <= bestDxSq) tryUpdate(left, dxSqLeft);\n          left--;\n          if (right < n && dxSqRight <= bestDxSq && dxSqRight === dxSqLeft) {\n            tryUpdate(right, dxSqRight);\n            right++;\n          }\n        } else {\n          if (right < n && dxSqRight <= bestDxSq) tryUpdate(right, dxSqRight);\n          right++;\n        }\n      }\n    }\n\n    if (bestPoint !== null) matches.push({ seriesIndex: s, dataIndex: bestDataIndex, point: bestPoint });\n  }\n\n  return matches;\n}\n\n","import type { ResolvedCandlestickSeriesConfig } from '../config/OptionResolver';\nimport type { OHLCDataPoint, OHLCDataPointTuple } from '../config/types';\nimport type { LinearScale } from '../utils/scales';\n\nexport interface CandlestickMatch {\n  seriesIndex: number;\n  dataIndex: number;\n  point: OHLCDataPoint;\n}\n\nconst clamp01 = (v: number): number => Math.min(1, Math.max(0, v));\n\nconst parsePercent = (value: string): number | null => {\n  const m = value.trim().match(/^(\\d+(?:\\.\\d+)?)%$/);\n  if (!m) return null;\n  const p = Number(m[1]) / 100;\n  return Number.isFinite(p) ? p : null;\n};\n\nconst isTupleDataPoint = (p: OHLCDataPoint): p is OHLCDataPointTuple => Array.isArray(p);\n\nconst getTimestamp = (p: OHLCDataPoint): number => (isTupleDataPoint(p) ? p[0] : p.timestamp);\nconst getOpen = (p: OHLCDataPoint): number => (isTupleDataPoint(p) ? p[1] : p.open);\nconst getClose = (p: OHLCDataPoint): number => (isTupleDataPoint(p) ? p[2] : p.close);\n\nconst categoryStepCache = new WeakMap<ReadonlyArray<OHLCDataPoint>, number>();\n\nconst computeCategoryStep = (data: ReadonlyArray<OHLCDataPoint>): number => {\n  const cached = categoryStepCache.get(data);\n  if (cached !== undefined) return cached;\n\n  const timestamps: number[] = [];\n  for (let i = 0; i < data.length; i++) {\n    const t = getTimestamp(data[i]);\n    if (Number.isFinite(t)) timestamps.push(t);\n  }\n\n  if (timestamps.length < 2) return 1;\n  timestamps.sort((a, b) => a - b);\n\n  let minStep = Number.POSITIVE_INFINITY;\n  for (let i = 1; i < timestamps.length; i++) {\n    const d = timestamps[i] - timestamps[i - 1];\n    if (d > 0 && d < minStep) minStep = d;\n  }\n  const step = Number.isFinite(minStep) && minStep > 0 ? minStep : 1;\n  categoryStepCache.set(data, step);\n  return step;\n};\n\n/**\n * Computes the candlestick body width in xScale **range-space** units.\n *\n * Notes:\n * - This mirrors `createCandlestickRenderer.ts` bar width semantics, but stays in range units\n *   (CSS pixels in ChartGPU interaction usage).\n * - No DPR conversions are applied here.\n */\nexport function computeCandlestickBodyWidthRange(\n  series: ResolvedCandlestickSeriesConfig,\n  data: ReadonlyArray<OHLCDataPoint>,\n  xScale: LinearScale,\n  plotWidthFallback?: number,\n): number {\n  if (data.length === 0) return 0;\n\n  const categoryStep = computeCategoryStep(data);\n\n  // Prefer deriving category width from a domain step via xScale.scale(t0 + step) - xScale.scale(t0).\n  let categoryWidthRange = 0;\n  if (Number.isFinite(categoryStep) && categoryStep > 0) {\n    let t0: number | null = null;\n    for (let i = 0; i < data.length; i++) {\n      const t = getTimestamp(data[i]);\n      if (Number.isFinite(t)) {\n        t0 = t;\n        break;\n      }\n    }\n\n    if (t0 != null) {\n      const p0 = xScale.scale(t0);\n      const p1 = xScale.scale(t0 + categoryStep);\n      const w = Math.abs(p1 - p0);\n      if (Number.isFinite(w) && w > 0) categoryWidthRange = w;\n    }\n  }\n\n  // Fallback: approximate based on plot width and data length.\n  if (!(categoryWidthRange > 0) || !Number.isFinite(categoryWidthRange)) {\n    const plotW = Number.isFinite(plotWidthFallback ?? Number.NaN) ? (plotWidthFallback as number) : 0;\n    categoryWidthRange = plotW / Math.max(1, data.length);\n  }\n\n  // barWidth semantics:\n  // - number: width in range units\n  // - percent string: percent of category width in range units\n  let width = 0;\n  const rawBarWidth = series.barWidth;\n  if (typeof rawBarWidth === 'number') {\n    width = Number.isFinite(rawBarWidth) ? Math.max(0, rawBarWidth) : 0;\n  } else if (typeof rawBarWidth === 'string') {\n    const p = parsePercent(rawBarWidth);\n    width = p == null ? 0 : categoryWidthRange * clamp01(p);\n  }\n\n  // Clamp by min/max width (in CSS px; our range-space is CSS px in interaction usage).\n  const minW = Number.isFinite(series.barMinWidth) ? Math.max(0, series.barMinWidth) : 0;\n  const maxWCandidate = Number.isFinite(series.barMaxWidth) ? Math.max(0, series.barMaxWidth) : Number.POSITIVE_INFINITY;\n  const maxW = Math.max(minW, maxWCandidate);\n  width = Math.min(Math.max(width, minW), maxW);\n\n  return Number.isFinite(width) ? width : 0;\n}\n\nconst monotonicTimestampCache = new WeakMap<ReadonlyArray<OHLCDataPoint>, boolean>();\n\nconst isMonotonicNonDecreasingFiniteTimestamps = (data: ReadonlyArray<OHLCDataPoint>): boolean => {\n  const cached = monotonicTimestampCache.get(data);\n  if (cached !== undefined) return cached;\n\n  let prev = Number.NEGATIVE_INFINITY;\n  for (let i = 0; i < data.length; i++) {\n    const t = getTimestamp(data[i]);\n    if (!Number.isFinite(t)) {\n      monotonicTimestampCache.set(data, false);\n      return false;\n    }\n    if (t < prev) {\n      monotonicTimestampCache.set(data, false);\n      return false;\n    }\n    prev = t;\n  }\n  monotonicTimestampCache.set(data, true);\n  return true;\n};\n\nconst lowerBoundByTimestamp = (data: ReadonlyArray<OHLCDataPoint>, xTarget: number): number => {\n  let lo = 0;\n  let hi = data.length;\n  while (lo < hi) {\n    const mid = (lo + hi) >>> 1;\n    const t = getTimestamp(data[mid]);\n    if (t < xTarget) lo = mid + 1;\n    else hi = mid;\n  }\n  return lo;\n};\n\n/**\n * Finds the candlestick body under the given cursor position.\n *\n * Coordinate system contract:\n * - `x`/`y` MUST be in the same units as `xScale`/`yScale` **range-space**\n *   (ChartGPU interaction uses grid-local CSS pixels).\n *\n * Hit-test semantics:\n * - Body-only hit-testing (wicks ignored).\n * - A candle hits if:\n *   - `abs(x - xCenter) <= barWidth / 2`, AND\n *   - `y` is between the scaled `open` and `close` (inclusive).\n *\n * Performance:\n * - Per-series lower-bound binary search on timestamp, then scans left/right while x-distance alone can still hit.\n * - If timestamps are not monotonic non-decreasing finite numbers, falls back to an O(n) scan for correctness.\n *\n * Edge cases:\n * - Skips non-finite timestamps/open/close.\n * - If `barWidthClip` is non-finite or <= 0, returns null.\n * - Returns the closest in x (min abs dx) among hits; ties broken by smaller `dataIndex` (then smaller `seriesIndex`).\n */\nexport function findCandlestick(\n  series: ReadonlyArray<ResolvedCandlestickSeriesConfig>,\n  x: number,\n  y: number,\n  xScale: LinearScale,\n  yScale: LinearScale,\n  barWidthClip: number,\n): CandlestickMatch | null {\n  if (!Number.isFinite(x) || !Number.isFinite(y)) return null;\n  if (!Number.isFinite(barWidthClip) || !(barWidthClip > 0)) return null;\n\n  const xTarget = xScale.invert(x);\n  if (!Number.isFinite(xTarget)) return null;\n\n  const halfW = barWidthClip / 2;\n\n  let best: CandlestickMatch | null = null;\n  let bestDx = Number.POSITIVE_INFINITY;\n\n  const tryUpdate = (\n    seriesIndex: number,\n    dataIndex: number,\n    point: OHLCDataPoint,\n    dx: number,\n  ): void => {\n    if (!Number.isFinite(dx)) return;\n    if (dx < bestDx) {\n      bestDx = dx;\n      best = { seriesIndex, dataIndex, point };\n      return;\n    }\n    if (dx === bestDx && best) {\n      if (dataIndex < best.dataIndex) {\n        best = { seriesIndex, dataIndex, point };\n      } else if (dataIndex === best.dataIndex && seriesIndex < best.seriesIndex) {\n        best = { seriesIndex, dataIndex, point };\n      }\n    }\n  };\n\n  const isBodyHitAt = (p: OHLCDataPoint): boolean => {\n    const open = getOpen(p);\n    const close = getClose(p);\n    if (!Number.isFinite(open) || !Number.isFinite(close)) return false;\n\n    const yOpen = yScale.scale(open);\n    const yClose = yScale.scale(close);\n    if (!Number.isFinite(yOpen) || !Number.isFinite(yClose)) return false;\n\n    const yMin = Math.min(yOpen, yClose);\n    const yMax = Math.max(yOpen, yClose);\n    return y >= yMin && y <= yMax;\n  };\n\n  for (let s = 0; s < series.length; s++) {\n    const cfg = series[s];\n    const data = cfg.data;\n    const n = data.length;\n    if (n === 0) continue;\n\n    const monotonic = isMonotonicNonDecreasingFiniteTimestamps(data);\n\n    if (!monotonic) {\n      // Fallback O(n) scan for correctness.\n      for (let i = 0; i < n; i++) {\n        const p = data[i];\n        const t = getTimestamp(p);\n        if (!Number.isFinite(t)) continue;\n        const xCenter = xScale.scale(t);\n        if (!Number.isFinite(xCenter)) continue;\n\n        const dx = Math.abs(x - xCenter);\n        if (dx > halfW) continue;\n        if (!isBodyHitAt(p)) continue;\n\n        tryUpdate(s, i, p, dx);\n      }\n      continue;\n    }\n\n    const insertionIndex = lowerBoundByTimestamp(data, xTarget);\n\n    // Scan left while xCenter can still be within [x - halfW, x + halfW].\n    for (let i = insertionIndex - 1; i >= 0; i--) {\n      const p = data[i];\n      const t = getTimestamp(p);\n      const xCenter = xScale.scale(t);\n      if (!Number.isFinite(xCenter)) continue;\n      if (xCenter < x - halfW) break;\n\n      const dx = Math.abs(x - xCenter);\n      if (dx > halfW) continue;\n      if (!isBodyHitAt(p)) continue;\n\n      tryUpdate(s, i, p, dx);\n    }\n\n    // Scan right while xCenter can still be within [x - halfW, x + halfW].\n    for (let i = insertionIndex; i < n; i++) {\n      const p = data[i];\n      const t = getTimestamp(p);\n      const xCenter = xScale.scale(t);\n      if (!Number.isFinite(xCenter)) continue;\n      if (xCenter > x + halfW) break;\n\n      const dx = Math.abs(x - xCenter);\n      if (dx > halfW) continue;\n      if (!isBodyHitAt(p)) continue;\n\n      tryUpdate(s, i, p, dx);\n    }\n  }\n\n  return best;\n}\n\n","import type { ResolvedPieSeriesConfig } from '../config/OptionResolver';\n\nconst TAU = Math.PI * 2;\n\nconst wrapToTau = (thetaRad: number): number => {\n  if (!Number.isFinite(thetaRad)) return 0;\n  const t = thetaRad % TAU;\n  return t < 0 ? t + TAU : t;\n};\n\nexport type PieSliceMatch = Readonly<{\n  seriesIndex: number;\n  dataIndex: number;\n  slice: ResolvedPieSeriesConfig['data'][number];\n}>;\n\nexport type PieHitTestConfig = Readonly<{\n  seriesIndex: number;\n  series: ResolvedPieSeriesConfig;\n}>;\n\nexport type PieCenterCssPx = Readonly<{ x: number; y: number }>;\nexport type PieRadiusCssPx = Readonly<{ inner: number; outer: number }>;\n\n/**\n * Finds the pie slice under a given pointer position.\n *\n * Coordinate contract:\n * - `x`/`y` are plot/grid-local CSS pixels (origin at plot top-left, +y down).\n * - `center` is plot-local CSS pixels.\n * - `radius` is CSS pixels (inner/outer). Points within the donut hole are not hoverable.\n *\n * Angle conventions:\n * - Uses +y up for polar angle (to match `pie.wgsl` atan2(p.y, p.x)).\n * - Wraps angles to [0, 2π).\n * - Matches `createPieRenderer.ts` start angle default (90°).\n *\n * Value conventions:\n * - Ignores non-finite and non-positive slice values (mirrors renderer).\n */\nexport function findPieSlice(\n  x: number,\n  y: number,\n  pieConfig: PieHitTestConfig,\n  center: PieCenterCssPx,\n  radius: PieRadiusCssPx\n): PieSliceMatch | null {\n  if (!Number.isFinite(x) || !Number.isFinite(y)) return null;\n  if (!Number.isFinite(center.x) || !Number.isFinite(center.y)) return null;\n\n  const inner = Number.isFinite(radius.inner) ? Math.max(0, radius.inner) : 0;\n  const outer = Number.isFinite(radius.outer) ? Math.max(0, radius.outer) : 0;\n  if (!(outer > 0)) return null;\n\n  // Polar coordinates:\n  // - Pointer `y` is down in CSS px, but shader uses +y up (atan2(p.y, p.x)).\n  const dx = x - center.x;\n  const dyUp = center.y - y;\n  const r = Math.hypot(dx, dyUp);\n  if (!Number.isFinite(r)) return null;\n\n  // Donut hole is non-hoverable; outer bound must be inside.\n  if (r <= inner) return null;\n  if (r > outer) return null;\n\n  const angle = wrapToTau(Math.atan2(dyUp, dx));\n\n  const series = pieConfig.series;\n  const data = series.data;\n\n  // Total positive value for angle allocation (mirrors renderer, exclude hidden slices).\n  let total = 0;\n  let validCount = 0;\n  for (let i = 0; i < data.length; i++) {\n    const item = data[i];\n    const v = item?.value;\n    if (typeof v === 'number' && Number.isFinite(v) && v > 0 && item.visible !== false) {\n      total += v;\n      validCount++;\n    }\n  }\n  if (!(total > 0) || validCount === 0) return null;\n\n  const startDeg =\n    typeof series.startAngle === 'number' && Number.isFinite(series.startAngle) ? series.startAngle : 90;\n  let current = wrapToTau((startDeg * Math.PI) / 180);\n\n  // Mirror renderer float-drift mitigation: force last slice to close the circle.\n  let accumulated = 0;\n  let emitted = 0;\n\n  for (let i = 0; i < data.length; i++) {\n    const slice = data[i];\n    const v = slice?.value;\n    if (typeof v !== 'number' || !Number.isFinite(v) || v <= 0) continue;\n    // Skip hidden slices\n    if (slice?.visible === false) continue;\n\n    emitted++;\n    const isLast = emitted === validCount;\n\n    const frac = v / total;\n    let span = frac * TAU;\n    if (isLast) {\n      span = Math.max(0, TAU - accumulated);\n    } else {\n      span = Math.max(0, Math.min(TAU, span));\n    }\n    accumulated += span;\n    if (!(span > 0)) continue;\n\n    const start = current;\n    // When there's only one visible slice, it should span the full circle (0 to TAU).\n    // Don't wrap the end angle in this case, as wrapping (start + TAU) gives start again.\n    const end = validCount === 1 ? current + TAU : wrapToTau(current + span);\n    current = wrapToTau(current + span);\n\n    // Match `pie.wgsl` wedge test (span and rel in [0, TAU) with wrap).\n    let wedgeSpan = end - start;\n    if (wedgeSpan < 0) wedgeSpan += TAU;\n\n    let rel = angle - start;\n    if (rel < 0) rel += TAU;\n\n    if (rel <= wedgeSpan) {\n      return { seriesIndex: pieConfig.seriesIndex, dataIndex: i, slice };\n    }\n  }\n\n  return null;\n}\n\n","export interface LinearScale {\n  /**\n   * Sets the scale domain (data range). Returns self for chaining.\n   */\n  domain(min: number, max: number): LinearScale;\n\n  /**\n   * Sets the scale range (pixel range). Returns self for chaining.\n   */\n  range(min: number, max: number): LinearScale;\n\n  /**\n   * Maps a domain value to a range value.\n   *\n   * Notes:\n   * - No clamping (will extrapolate outside the domain).\n   * - If the domain span is 0 (min === max), returns the midpoint of the range.\n   */\n  scale(value: number): number;\n\n  /**\n   * Maps a range value (pixel) back to a domain value.\n   *\n   * Notes:\n   * - No clamping (will extrapolate outside the range).\n   * - If the domain span is 0 (min === max), returns domain min for any input.\n   */\n  invert(pixel: number): number;\n}\n\nexport interface CategoryScale {\n  /**\n   * Sets the category domain (ordered list of unique category names).\n   * Returns self for chaining.\n   *\n   * Throws if duplicates exist (ambiguous mapping).\n   */\n  domain(categories: string[]): CategoryScale;\n\n  /**\n   * Sets the scale range (pixel range). Returns self for chaining.\n   */\n  range(min: number, max: number): CategoryScale;\n\n  /**\n   * Returns the center x-position for a category.\n   *\n   * Edge cases:\n   * - Unknown category: returns NaN\n   * - Empty domain: returns midpoint of range\n   */\n  scale(category: string): number;\n\n  /**\n   * Width allocated per category (always non-negative).\n   *\n   * Edge cases:\n   * - Empty domain: returns 0\n   * - Reversed ranges allowed\n   */\n  bandwidth(): number;\n\n  /**\n   * Returns the index of a category in the current domain.\n   *\n   * Edge cases:\n   * - Unknown category: returns -1\n   */\n  categoryIndex(category: string): number;\n}\n\nconst assertFinite = (label: string, value: number): void => {\n  if (!Number.isFinite(value)) {\n    throw new Error(`${label} must be a finite number. Received: ${String(value)}`);\n  }\n};\n\n/**\n * Creates a linear scale for mapping a numeric domain to a numeric range.\n *\n * Defaults to an identity mapping:\n * domain [0, 1] -> range [0, 1]\n */\nexport function createLinearScale(): LinearScale {\n  let domainMin = 0;\n  let domainMax = 1;\n  let rangeMin = 0;\n  let rangeMax = 1;\n\n  const self: LinearScale = {\n    domain(min: number, max: number) {\n      assertFinite('domain min', min);\n      assertFinite('domain max', max);\n      domainMin = min;\n      domainMax = max;\n      return self;\n    },\n\n    range(min: number, max: number) {\n      assertFinite('range min', min);\n      assertFinite('range max', max);\n      rangeMin = min;\n      rangeMax = max;\n      return self;\n    },\n\n    scale(value: number) {\n      if (!Number.isFinite(value)) return Number.NaN;\n\n      if (domainMin === domainMax) {\n        return (rangeMin + rangeMax) / 2;\n      }\n\n      const t = (value - domainMin) / (domainMax - domainMin);\n      return rangeMin + t * (rangeMax - rangeMin);\n    },\n\n    invert(pixel: number) {\n      if (!Number.isFinite(pixel)) return Number.NaN;\n\n      if (domainMin === domainMax) {\n        return domainMin;\n      }\n\n      if (rangeMin === rangeMax) {\n        return (domainMin + domainMax) / 2;\n      }\n\n      const t = (pixel - rangeMin) / (rangeMax - rangeMin);\n      return domainMin + t * (domainMax - domainMin);\n    },\n  };\n\n  return self;\n}\n\n/**\n * Creates a category scale for mapping string categories to evenly spaced\n * x-positions across a numeric range.\n *\n * Defaults:\n * - domain: []\n * - range: [0, 1]\n */\nexport function createCategoryScale(): CategoryScale {\n  let categories: readonly string[] = [];\n  let indexByCategory = new Map<string, number>();\n  let rangeMin = 0;\n  let rangeMax = 1;\n\n  const rebuildIndex = (nextCategories: readonly string[]) => {\n    const nextIndex = new Map<string, number>();\n    for (let i = 0; i < nextCategories.length; i++) {\n      const c = nextCategories[i];\n      // Enforce uniqueness to avoid ambiguous mapping\n      if (nextIndex.has(c)) {\n        throw new Error(`Category domain must not contain duplicates. Duplicate: ${JSON.stringify(c)}`);\n      }\n      nextIndex.set(c, i);\n    }\n    indexByCategory = nextIndex;\n  };\n\n  const self: CategoryScale = {\n    domain(nextCategories: string[]) {\n      categories = [...nextCategories];\n      rebuildIndex(categories);\n      return self;\n    },\n\n    range(min: number, max: number) {\n      assertFinite('range min', min);\n      assertFinite('range max', max);\n      rangeMin = min;\n      rangeMax = max;\n      return self;\n    },\n\n    categoryIndex(category: string) {\n      const idx = indexByCategory.get(category);\n      return idx === undefined ? -1 : idx;\n    },\n\n    bandwidth() {\n      const n = categories.length;\n      if (n === 0) return 0;\n      return Math.abs((rangeMax - rangeMin) / n);\n    },\n\n    scale(category: string) {\n      const n = categories.length;\n      if (n === 0) {\n        return (rangeMin + rangeMax) / 2;\n      }\n\n      const i = self.categoryIndex(category);\n      if (i < 0) return Number.NaN;\n\n      const step = (rangeMax - rangeMin) / n; // can be negative (reversed range)\n      return rangeMin + (i + 0.5) * step;\n    },\n  };\n\n  return self;\n}\n","export type TextOverlayAnchor = 'start' | 'middle' | 'end';\n\nexport interface TextOverlayLabelOptions {\n  readonly fontSize?: number;\n  readonly color?: string;\n  readonly anchor?: TextOverlayAnchor;\n  /**\n   * Rotation in degrees (CSS `rotate(<deg>deg)`).\n   */\n  readonly rotation?: number;\n}\n\nexport interface TextOverlay {\n  clear(): void;\n  addLabel(\n    text: string,\n    x: number,\n    y: number,\n    options?: TextOverlayLabelOptions\n  ): HTMLSpanElement;\n  dispose(): void;\n}\n\nconst getAnchorTransform = (\n  anchor: TextOverlayAnchor\n): Readonly<{ translateX: string; originX: string }> => {\n  switch (anchor) {\n    case 'start':\n      return { translateX: '0%', originX: '0%' };\n    case 'middle':\n      return { translateX: '-50%', originX: '50%' };\n    case 'end':\n      return { translateX: '-100%', originX: '100%' };\n  }\n};\n\nexport function createTextOverlay(container: HTMLElement): TextOverlay {\n  const computedStyle = getComputedStyle(container);\n  const computedPosition = computedStyle.position;\n  const computedOverflow = computedStyle.overflow;\n\n  const didSetRelative = computedPosition === 'static';\n  const didSetOverflowVisible = computedOverflow === 'hidden' || computedOverflow === 'scroll' || computedOverflow === 'auto';\n\n  const previousInlinePosition = didSetRelative ? container.style.position : null;\n  const previousInlineOverflow = didSetOverflowVisible ? container.style.overflow : null;\n\n  if (didSetRelative) {\n    container.style.position = 'relative';\n  }\n\n  if (didSetOverflowVisible) {\n    container.style.overflow = 'visible';\n  }\n\n  const overlay = document.createElement('div');\n  overlay.style.position = 'absolute';\n  overlay.style.inset = '0';\n  overlay.style.pointerEvents = 'none';\n  overlay.style.overflow = 'visible';\n  overlay.style.zIndex = '10'; // Above zoom slider (z-index: 4) and other overlays\n  container.appendChild(overlay);\n\n  let disposed = false;\n\n  const clear = (): void => {\n    if (disposed) return;\n    overlay.replaceChildren();\n  };\n\n  const addLabel: TextOverlay['addLabel'] = (text, x, y, options) => {\n    if (disposed) {\n      // Keep it non-throwing so callsites don't need try/catch in teardown paths.\n      return document.createElement('span');\n    }\n\n    const span = document.createElement('span');\n    span.textContent = text;\n    span.style.position = 'absolute';\n    span.style.left = `${x}px`;\n    span.style.top = `${y}px`;\n    span.style.pointerEvents = 'none';\n    span.style.userSelect = 'none';\n    span.style.whiteSpace = 'nowrap';\n    span.style.lineHeight = '1';\n\n    if (options?.fontSize != null) span.style.fontSize = `${options.fontSize}px`;\n    if (options?.color != null) span.style.color = options.color;\n\n    const rotation = options?.rotation ?? 0;\n    const anchor = options?.anchor ?? 'start';\n    const { translateX, originX } = getAnchorTransform(anchor);\n\n    span.style.transformOrigin = `${originX} 50%`;\n    span.style.transform = `translateX(${translateX}) translateY(-50%) rotate(${rotation}deg)`;\n\n    overlay.appendChild(span);\n    return span;\n  };\n\n  const dispose = (): void => {\n    if (disposed) return;\n    disposed = true;\n\n    try {\n      overlay.remove();\n    } finally {\n      if (previousInlinePosition !== null) {\n        container.style.position = previousInlinePosition;\n      }\n      if (previousInlineOverflow !== null) {\n        container.style.overflow = previousInlineOverflow;\n      }\n    }\n  };\n\n  return { clear, addLabel, dispose };\n}\n\n  ","import type { SeriesConfig } from '../config/types';\nimport type { ThemeConfig } from '../themes/types';\n\nexport type LegendPosition = 'top' | 'bottom' | 'left' | 'right';\n\nexport interface Legend {\n  update(series: ReadonlyArray<SeriesConfig>, theme: ThemeConfig): void;\n  dispose(): void;\n}\n\nconst getSeriesName = (series: SeriesConfig, index: number): string => {\n  const candidate = series.name?.trim();\n  return candidate ? candidate : `Series ${index + 1}`;\n};\n\nconst getSeriesColor = (\n  series: SeriesConfig,\n  index: number,\n  theme: ThemeConfig\n): string => {\n  const explicit = series.color?.trim();\n  if (explicit) return explicit;\n\n  const palette = theme.colorPalette;\n  if (palette.length > 0) return palette[index % palette.length] ?? '#000000';\n  return '#000000';\n};\n\nconst getPieSliceLabel = (sliceName: string | undefined, sliceIndex: number): string => {\n  const candidate = sliceName?.trim();\n  return candidate ? candidate : `Slice ${sliceIndex + 1}`;\n};\n\nconst getPieSliceColor = (\n  sliceColor: string | undefined,\n  seriesIndex: number,\n  sliceIndex: number,\n  theme: ThemeConfig\n): string => {\n  const explicit = sliceColor?.trim();\n  if (explicit) return explicit;\n\n  const palette = theme.colorPalette;\n  const len = palette.length;\n  if (len > 0) return palette[(seriesIndex + sliceIndex) % len] ?? '#000000';\n  return '#000000';\n};\n\nexport function createLegend(\n  container: HTMLElement,\n  position: LegendPosition = 'right',\n  onSeriesToggle?: (seriesIndex: number, sliceIndex?: number) => void\n): Legend {\n  const computedPosition = getComputedStyle(container).position;\n  const didSetRelative = computedPosition === 'static';\n  const previousInlinePosition = didSetRelative ? container.style.position : null;\n\n  if (didSetRelative) {\n    container.style.position = 'relative';\n  }\n\n  const root = document.createElement('div');\n  root.style.position = 'absolute';\n  root.style.pointerEvents = 'auto';\n  root.style.userSelect = 'none';\n  root.style.boxSizing = 'border-box';\n\n  // Theme-driven styling (set/update in update()).\n  root.style.padding = '8px';\n  root.style.borderRadius = '8px';\n  root.style.borderStyle = 'solid';\n  root.style.borderWidth = '1px';\n  root.style.maxHeight = 'calc(100% - 16px)';\n  root.style.overflow = 'auto';\n\n  const list = document.createElement('div');\n  list.style.display = 'flex';\n  list.style.gap = '8px';\n  root.appendChild(list);\n\n  // Event delegation for series toggle (fixes memory leak and improves performance)\n  if (onSeriesToggle) {\n    list.addEventListener('click', (e) => {\n      const target = e.target as HTMLElement;\n      const item = target.closest('[data-series-index]') as HTMLElement;\n      if (item) {\n        const seriesIndex = parseInt(item.dataset.seriesIndex!, 10);\n        if (!isNaN(seriesIndex)) {\n          // Check if this is a pie slice item\n          const sliceIndexStr = item.dataset.sliceIndex;\n          if (sliceIndexStr !== undefined) {\n            const sliceIndex = parseInt(sliceIndexStr, 10);\n            if (!isNaN(sliceIndex)) {\n              onSeriesToggle(seriesIndex, sliceIndex);\n              return;\n            }\n          }\n          // Regular series toggle\n          onSeriesToggle(seriesIndex);\n        }\n      }\n    });\n\n    // Keyboard navigation support for accessibility\n    list.addEventListener('keydown', (e) => {\n      if (e.key === 'Enter' || e.key === ' ') {\n        const target = e.target as HTMLElement;\n        const item = target.closest('[data-series-index]') as HTMLElement;\n        if (item) {\n          e.preventDefault();\n          const seriesIndex = parseInt(item.dataset.seriesIndex!, 10);\n          if (!isNaN(seriesIndex)) {\n            // Check if this is a pie slice item\n            const sliceIndexStr = item.dataset.sliceIndex;\n            if (sliceIndexStr !== undefined) {\n              const sliceIndex = parseInt(sliceIndexStr, 10);\n              if (!isNaN(sliceIndex)) {\n                onSeriesToggle(seriesIndex, sliceIndex);\n                return;\n              }\n            }\n            // Regular series toggle\n            onSeriesToggle(seriesIndex);\n          }\n        }\n      }\n    });\n  }\n\n  const applyPositionStyles = (p: LegendPosition): void => {\n    // Clear positional styles first so changing position is safe/idempotent.\n    root.style.top = '';\n    root.style.right = '';\n    root.style.bottom = '';\n    root.style.left = '';\n    root.style.maxWidth = '';\n\n    list.style.flexDirection = '';\n    list.style.flexWrap = '';\n    list.style.alignItems = '';\n\n    switch (p) {\n      case 'right': {\n        root.style.top = '8px';\n        root.style.right = '8px';\n        root.style.maxWidth = '40%';\n\n        list.style.flexDirection = 'column';\n        list.style.flexWrap = 'nowrap';\n        list.style.alignItems = 'flex-start';\n        return;\n      }\n      case 'left': {\n        root.style.top = '8px';\n        root.style.left = '8px';\n        root.style.maxWidth = '40%';\n\n        list.style.flexDirection = 'column';\n        list.style.flexWrap = 'nowrap';\n        list.style.alignItems = 'flex-start';\n        return;\n      }\n      case 'top': {\n        root.style.top = '8px';\n        root.style.left = '8px';\n        root.style.right = '8px';\n\n        list.style.flexDirection = 'row';\n        list.style.flexWrap = 'wrap';\n        list.style.alignItems = 'center';\n        return;\n      }\n      case 'bottom': {\n        root.style.bottom = '8px';\n        root.style.left = '8px';\n        root.style.right = '8px';\n\n        list.style.flexDirection = 'row';\n        list.style.flexWrap = 'wrap';\n        list.style.alignItems = 'center';\n        return;\n      }\n    }\n  };\n\n  applyPositionStyles(position);\n  container.appendChild(root);\n\n  let disposed = false;\n\n  const update: Legend['update'] = (series, theme) => {\n    if (disposed) return;\n\n    root.style.color = theme.textColor;\n    root.style.background = theme.backgroundColor;\n    root.style.borderColor = theme.axisLineColor;\n    root.style.fontFamily = theme.fontFamily;\n    root.style.fontSize = `${theme.fontSize}px`;\n\n    const items: HTMLElement[] = [];\n    for (let seriesIndex = 0; seriesIndex < series.length; seriesIndex++) {\n      const s = series[seriesIndex];\n\n      if (s.type === 'pie') {\n        for (let sliceIndex = 0; sliceIndex < s.data.length; sliceIndex++) {\n          const slice = s.data[sliceIndex];\n          const isVisible = slice?.visible !== false;\n\n          const item = document.createElement('div');\n          item.style.display = 'flex';\n          item.style.alignItems = 'center';\n          item.style.gap = '6px';\n          item.style.lineHeight = '1.1';\n          item.style.whiteSpace = 'nowrap';\n          item.style.cursor = onSeriesToggle ? 'pointer' : 'default';\n          item.style.opacity = isVisible ? '1' : '0.5';\n          item.style.transition = 'opacity 0.2s';\n\n          // Add accessibility attributes and data attributes for event delegation\n          if (onSeriesToggle) {\n            item.setAttribute('role', 'button');\n            item.setAttribute('aria-pressed', String(isVisible));\n            item.setAttribute('aria-label', `Toggle ${getPieSliceLabel(slice?.name, sliceIndex)} visibility`);\n            item.tabIndex = 0;\n            item.dataset.seriesIndex = String(seriesIndex);\n            item.dataset.sliceIndex = String(sliceIndex);\n          }\n\n          const swatch = document.createElement('div');\n          swatch.style.width = '10px';\n          swatch.style.height = '10px';\n          swatch.style.borderRadius = '2px';\n          swatch.style.flex = '0 0 auto';\n          swatch.style.background = getPieSliceColor(slice?.color, seriesIndex, sliceIndex, theme);\n          swatch.style.border = `1px solid ${theme.axisLineColor}`;\n\n          const label = document.createElement('span');\n          label.textContent = getPieSliceLabel(slice?.name, sliceIndex);\n          label.style.textDecoration = isVisible ? 'none' : 'line-through';\n\n          item.appendChild(swatch);\n          item.appendChild(label);\n          items.push(item);\n        }\n      } else {\n        const isVisible = s.visible !== false;\n\n        const item = document.createElement('div');\n        item.style.display = 'flex';\n        item.style.alignItems = 'center';\n        item.style.gap = '6px';\n        item.style.lineHeight = '1.1';\n        item.style.whiteSpace = 'nowrap';\n        item.style.cursor = onSeriesToggle ? 'pointer' : 'default';\n        item.style.opacity = isVisible ? '1' : '0.5';\n        item.style.transition = 'opacity 0.2s';\n\n        // Add accessibility attributes and data attribute for event delegation\n        if (onSeriesToggle) {\n          item.setAttribute('role', 'button');\n          item.setAttribute('aria-pressed', String(isVisible));\n          item.setAttribute('aria-label', `Toggle ${getSeriesName(s, seriesIndex)} visibility`);\n          item.tabIndex = 0;\n          item.dataset.seriesIndex = String(seriesIndex);\n        }\n\n        const swatch = document.createElement('div');\n        swatch.style.width = '10px';\n        swatch.style.height = '10px';\n        swatch.style.borderRadius = '2px';\n        swatch.style.flex = '0 0 auto';\n        swatch.style.background = getSeriesColor(s, seriesIndex, theme);\n        swatch.style.border = `1px solid ${theme.axisLineColor}`;\n\n        const label = document.createElement('span');\n        label.textContent = getSeriesName(s, seriesIndex);\n        label.style.textDecoration = isVisible ? 'none' : 'line-through';\n\n        item.appendChild(swatch);\n        item.appendChild(label);\n        items.push(item);\n      }\n    }\n\n    list.replaceChildren(...items);\n  };\n\n  const dispose: Legend['dispose'] = () => {\n    if (disposed) return;\n    disposed = true;\n\n    try {\n      root.remove();\n    } finally {\n      if (previousInlinePosition !== null) {\n        container.style.position = previousInlinePosition;\n      }\n    }\n  };\n\n  return { update, dispose };\n}\n\n","export interface Tooltip {\n  /**\n   * Show tooltip at container-local CSS pixel coordinates.\n   *\n   * `content` is treated as HTML (assigned via `innerHTML`).\n   */\n  show(x: number, y: number, content: string): void;\n  hide(): void;\n  dispose(): void;\n}\n\nconst clamp = (value: number, min: number, max: number): number => {\n  if (max < min) return min;\n  if (value < min) return min;\n  if (value > max) return max;\n  return value;\n};\n\nexport function createTooltip(container: HTMLElement): Tooltip {\n  const computedPosition = getComputedStyle(container).position;\n  const didSetRelative = computedPosition === 'static';\n  const previousInlinePosition = didSetRelative ? container.style.position : null;\n\n  if (didSetRelative) {\n    container.style.position = 'relative';\n  }\n\n  const root = document.createElement('div');\n  root.style.position = 'absolute';\n  root.style.left = '0';\n  root.style.top = '0';\n  root.style.pointerEvents = 'none';\n  root.style.userSelect = 'none';\n  root.style.boxSizing = 'border-box';\n\n  // Theme-friendly default visuals with CSS variable override points.\n  root.style.zIndex = 'var(--chartgpu-tooltip-z, 10)';\n  root.style.padding = 'var(--chartgpu-tooltip-padding, 6px 8px)';\n  root.style.borderRadius = 'var(--chartgpu-tooltip-radius, 8px)';\n  root.style.borderStyle = 'solid';\n  root.style.borderWidth = 'var(--chartgpu-tooltip-border-width, 1px)';\n  root.style.borderColor =\n    'var(--chartgpu-tooltip-border, rgba(224,224,224,0.35))';\n  root.style.boxShadow =\n    'var(--chartgpu-tooltip-shadow, 0 6px 18px rgba(0,0,0,0.35))';\n  root.style.maxWidth = 'var(--chartgpu-tooltip-max-width, min(320px, 100%))';\n  root.style.overflow = 'hidden';\n  root.style.fontFamily =\n    'var(--chartgpu-tooltip-font-family, system-ui, -apple-system, \"Segoe UI\", Roboto, Helvetica, Arial, \"Apple Color Emoji\", \"Segoe UI Emoji\")';\n  root.style.fontSize = 'var(--chartgpu-tooltip-font-size, 12px)';\n  root.style.lineHeight = 'var(--chartgpu-tooltip-line-height, 1.2)';\n  root.style.color = 'var(--chartgpu-tooltip-color, #e0e0e0)';\n  root.style.background = 'var(--chartgpu-tooltip-bg, rgba(26,26,46,0.95))';\n  root.style.whiteSpace = 'normal';\n\n  // Transition-ready baseline; keep fade-out visible until completion.\n  root.style.opacity = '0';\n  root.style.transitionProperty = 'opacity';\n  const fadeMs = 140;\n  root.style.transitionDuration = `${fadeMs}ms`;\n  root.style.transitionTimingFunction = 'ease';\n  root.style.willChange = 'opacity';\n\n  // Keep it out of layout/paint when hidden.\n  root.style.display = 'none';\n  root.style.visibility = 'hidden';\n\n  root.setAttribute('role', 'tooltip');\n  container.appendChild(root);\n\n  let disposed = false;\n  let transitionToken = 0;\n  let hideTimeoutId: number | null = null;\n  let rafId: number | null = null;\n\n  const clearPendingTransitions = (): void => {\n    if (hideTimeoutId != null) {\n      window.clearTimeout(hideTimeoutId);\n      hideTimeoutId = null;\n    }\n    if (rafId != null) {\n      window.cancelAnimationFrame(rafId);\n      rafId = null;\n    }\n  };\n\n  const isCurrentlyHidden = (): boolean =>\n    root.style.display === 'none' || root.style.visibility === 'hidden';\n\n  const measureSize = (): Readonly<{ width: number; height: number }> => {\n    // Measure without touching opacity to avoid restarting fades.\n    // If the tooltip is currently visible, this temporarily hides it from paint\n    // within the same call (no flicker between frames).\n    const prevVisibility = root.style.visibility;\n    root.style.visibility = 'hidden';\n\n    // offsetWidth/offsetHeight are rounded but stable for layout decisions here.\n    const width = root.offsetWidth;\n    const height = root.offsetHeight;\n\n    root.style.visibility = prevVisibility;\n    return { width, height };\n  };\n\n  const show: Tooltip['show'] = (x, y, content) => {\n    if (disposed) return;\n\n    transitionToken += 1;\n    clearPendingTransitions();\n\n    const wasHidden = isCurrentlyHidden();\n\n    root.innerHTML = content;\n\n    const dx = 12;\n    const dy = 12;\n    const pad = 8;\n\n    // Ensure it participates in layout for measurement & positioning.\n    // Keep it hidden from paint until we finish placing it.\n    root.style.display = 'block';\n    root.style.visibility = 'hidden';\n\n    const { width: w, height: h } = measureSize();\n\n    const containerW = container.clientWidth;\n    const containerH = container.clientHeight;\n\n    let left = x + dx;\n    let top = y + dy;\n\n    if (left + w > containerW - pad) left = x - dx - w;\n    if (top + h > containerH - pad) top = y - dy - h;\n\n    left = clamp(left, pad, containerW - pad - w);\n    top = clamp(top, pad, containerH - pad - h);\n\n    root.style.left = `${left}px`;\n    root.style.top = `${top}px`;\n\n    root.style.visibility = 'visible';\n\n    if (wasHidden) {\n      // Only fade in on hidden -> visible transition.\n      root.style.opacity = '0';\n      const myToken = transitionToken;\n      rafId = window.requestAnimationFrame(() => {\n        rafId = null;\n        if (disposed) return;\n        if (myToken !== transitionToken) return;\n        root.style.opacity = '1';\n      });\n    } else {\n      // Frequent updates while visible should not restart the fade.\n      // Also cancels an in-progress hide fade-out by restoring opacity.\n      root.style.opacity = '1';\n    }\n  };\n\n  const hide: Tooltip['hide'] = () => {\n    if (disposed) return;\n\n    transitionToken += 1;\n    clearPendingTransitions();\n\n    // If it's already hidden, keep idempotent and avoid extra work.\n    if (root.style.display === 'none' || root.style.visibility === 'hidden') {\n      root.style.opacity = '0';\n      root.style.visibility = 'hidden';\n      root.style.display = 'none';\n      return;\n    }\n\n    root.style.opacity = '0';\n\n    const myToken = transitionToken;\n    hideTimeoutId = window.setTimeout(() => {\n      hideTimeoutId = null;\n      if (disposed) return;\n      if (myToken !== transitionToken) return;\n      root.style.visibility = 'hidden';\n      root.style.display = 'none';\n    }, fadeMs + 50);\n  };\n\n  const dispose: Tooltip['dispose'] = () => {\n    if (disposed) return;\n    disposed = true;\n\n    try {\n      clearPendingTransitions();\n      root.remove();\n    } finally {\n      if (previousInlinePosition !== null) {\n        container.style.position = previousInlinePosition;\n      }\n    }\n  };\n\n  return { show, hide, dispose };\n}\n\n","import type { TooltipParams } from '../config/types';\n\nconst EM_DASH = '\\u2014';\n\nfunction escapeHtml(text: string): string {\n  // Escapes text for safe insertion into HTML text/attribute contexts.\n  // (We only use it for text nodes here, but keeping it generic is fine.)\n  return text\n    .replace(/&/g, '&amp;')\n    .replace(/</g, '&lt;')\n    .replace(/>/g, '&gt;')\n    .replace(/\"/g, '&quot;')\n    .replace(/'/g, '&#39;');\n}\n\nfunction formatNumber(value: number): string {\n  if (!Number.isFinite(value)) return EM_DASH;\n\n  // Normalize -0 to 0 for display stability.\n  const normalized = Object.is(value, -0) ? 0 : value;\n\n  // Maximum 2 decimal places, trim trailing zeros.\n  const fixed = normalized.toFixed(2);\n  const trimmed = fixed.replace(/\\.?0+$/, '');\n  return trimmed === '-0' ? '0' : trimmed;\n}\n\nfunction resolveSeriesName(params: TooltipParams): string {\n  const trimmed = params.seriesName.trim();\n  return trimmed.length > 0 ? trimmed : `Series ${params.seriesIndex + 1}`;\n}\n\nfunction sanitizeCssColor(value: string): string {\n  // Tooltip content is assigned via innerHTML, so treat color as untrusted.\n  // Allow only common safe color syntaxes; otherwise fall back.\n  const s = value.trim();\n  if (s.length === 0) return '#888';\n\n  // Hex: #RGB, #RRGGBB, #RRGGBBAA\n  if (/^#[0-9a-fA-F]{3}$/.test(s)) return s;\n  if (/^#[0-9a-fA-F]{6}$/.test(s)) return s;\n  if (/^#[0-9a-fA-F]{8}$/.test(s)) return s;\n\n  // rgb()/rgba() numeric forms (commas or space-separated with optional slash alpha)\n  if (\n    /^rgba?\\(\\s*\\d{1,3}\\s*(?:,\\s*|\\s+)\\d{1,3}\\s*(?:,\\s*|\\s+)\\d{1,3}(?:\\s*(?:,\\s*|\\/\\s*)(?:0|1|0?\\.\\d+))?\\s*\\)$/.test(\n      s,\n    )\n  ) {\n    return s;\n  }\n\n  // Named colors: basic CSS ident (letters only) to avoid weird tokens.\n  if (/^[a-zA-Z]+$/.test(s)) return s;\n\n  return '#888';\n}\n\nfunction isCandlestickValue(\n  value: readonly [number, number] | readonly [number, number, number, number, number],\n): value is readonly [number, number, number, number, number] {\n  return value.length === 5;\n}\n\nfunction formatPercentChange(open: number, close: number): string {\n  if (!Number.isFinite(open) || !Number.isFinite(close)) return EM_DASH;\n  if (open === 0) return EM_DASH; // Avoid division by zero\n\n  const change = ((close - open) / open) * 100;\n  if (!Number.isFinite(change)) return EM_DASH;\n\n  const sign = change > 0 ? '+' : '';\n  return `${sign}${change.toFixed(2)}%`;\n}\n\nfunction formatRowHtml(params: TooltipParams, valueText: string): string {\n  const safeName = escapeHtml(resolveSeriesName(params));\n  const safeValue = escapeHtml(valueText);\n  const safeColor = escapeHtml(sanitizeCssColor(params.color));\n\n  return [\n    '<div style=\"display:flex;align-items:center;justify-content:space-between;gap:12px;\">',\n    '<span style=\"display:flex;align-items:center;gap:8px;min-width:0;\">',\n    `<span style=\"width:8px;height:8px;border-radius:999px;flex:0 0 auto;background-color:${safeColor};\"></span>`,\n    `<span style=\"overflow:hidden;text-overflow:ellipsis;white-space:nowrap;\">${safeName}</span>`,\n    '</span>',\n    `<span style=\"font-variant-numeric:tabular-nums;white-space:nowrap;\">${safeValue}</span>`,\n    '</div>',\n  ].join('');\n}\n\nfunction formatCandlestickRowHtml(params: TooltipParams): string {\n  const [, open, close, low, high] = params.value as readonly [number, number, number, number, number];\n  \n  const safeName = escapeHtml(resolveSeriesName(params));\n  const safeColor = escapeHtml(sanitizeCssColor(params.color));\n\n  // Format OHLC values\n  const openStr = formatNumber(open);\n  const highStr = formatNumber(high);\n  const lowStr = formatNumber(low);\n  const closeStr = formatNumber(close);\n  \n  // Determine direction and arrow\n  const isUp = close > open;\n  const arrow = isUp ? '\\u25B2' : '\\u25BC'; // ▲ or ▼\n  const arrowColor = isUp ? '#22c55e' : '#ef4444';\n  const percentChange = formatPercentChange(open, close);\n\n  const ohlcText = `O: ${openStr} H: ${highStr} L: ${lowStr} C: ${closeStr}`;\n  const safeOHLC = escapeHtml(ohlcText);\n  const safeArrow = escapeHtml(arrow);\n  const safePercent = escapeHtml(percentChange);\n  const safeArrowColor = escapeHtml(arrowColor);\n\n  return [\n    '<div style=\"display:flex;flex-direction:column;gap:4px;\">',\n    // Series name row\n    '<div style=\"display:flex;align-items:center;gap:8px;\">',\n    `<span style=\"width:8px;height:8px;border-radius:999px;flex:0 0 auto;background-color:${safeColor};\"></span>`,\n    `<span style=\"overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-weight:600;\">${safeName}</span>`,\n    '</div>',\n    // OHLC values row\n    `<div style=\"font-variant-numeric:tabular-nums;white-space:nowrap;font-size:0.9em;\">${safeOHLC}</div>`,\n    // Change row with arrow\n    '<div style=\"display:flex;align-items:center;gap:6px;font-variant-numeric:tabular-nums;\">',\n    `<span style=\"color:${safeArrowColor};font-weight:700;\">${safeArrow}</span>`,\n    `<span style=\"color:${safeArrowColor};font-weight:600;\">${safePercent}</span>`,\n    '</div>',\n    '</div>',\n  ].join('');\n}\n\n/**\n * Default tooltip formatter for candlestick series in item mode.\n * Renders O/H/L/C values with colored arrow and percentage change.\n */\nexport function formatCandlestickTooltip(params: TooltipParams): string {\n  return formatCandlestickRowHtml(params);\n}\n\n/**\n * Default tooltip formatter for item mode.\n * Returns a compact single-row HTML snippet: dot + series name + y value.\n * For candlestick series, returns O/H/L/C with arrow and percentage change.\n */\nexport function formatTooltipItem(params: TooltipParams): string {\n  if (isCandlestickValue(params.value)) {\n    return formatCandlestickTooltip(params);\n  }\n  return formatRowHtml(params, formatNumber(params.value[1]));\n}\n\n/**\n * Default tooltip formatter for axis mode.\n * Renders an x header line then one row per series with the y value.\n * Candlestick series show O/H/L/C values with arrow and percentage change.\n */\nexport function formatTooltipAxis(params: TooltipParams[]): string {\n  if (params.length === 0) return '';\n\n  const xText = `x: ${formatNumber(params[0].value[0])}`;\n  const header = `<div style=\"margin:0 0 6px 0;font-weight:600;font-variant-numeric:tabular-nums;white-space:nowrap;\">${escapeHtml(\n    xText,\n  )}</div>`;\n\n  const rows = params\n    .map((p) => {\n      if (isCandlestickValue(p.value)) {\n        return formatCandlestickRowHtml(p);\n      }\n      return formatRowHtml(p, formatNumber(p.value[1]));\n    })\n    .join('<div style=\"height:4px;\"></div>');\n\n  return `${header}${rows}`;\n}\n\n","import type { EasingFunction } from '../utils/easing';\n\nexport type AnimationId = symbol;\n\nexport interface AnimationController {\n  animate(\n    from: number,\n    to: number,\n    duration: number,\n    easing: EasingFunction,\n    onUpdate: (value: number) => void,\n    onComplete?: () => void,\n  ): AnimationId;\n  animate(\n    from: ReadonlyArray<number>,\n    to: ReadonlyArray<number>,\n    duration: number,\n    easing: EasingFunction,\n    onUpdate: (value: ReadonlyArray<number>) => void,\n    onComplete?: () => void,\n  ): AnimationId;\n\n  cancel(animationId: AnimationId): void;\n  cancelAll(): void;\n\n  /**\n   * Progresses all active animations to `timestamp` (ms).\n   * Intended to be called once per frame by the caller (e.g. a render loop).\n   */\n  update(timestamp: number): void;\n}\n\ntype ScalarAnimation = Readonly<{\n  kind: 'scalar';\n  from: number;\n  to: number;\n  duration: number;\n  easing: EasingFunction;\n  onUpdate: (value: number) => void;\n  onComplete?: () => void;\n  startTime: number | null;\n}>;\n\ntype ArrayAnimation = Readonly<{\n  kind: 'array';\n  from: ReadonlyArray<number>;\n  to: ReadonlyArray<number>;\n  duration: number;\n  easing: EasingFunction;\n  onUpdate: (value: ReadonlyArray<number>) => void;\n  onComplete?: () => void;\n  startTime: number | null;\n  out: number[];\n}>;\n\ntype AnimationInternal = ScalarAnimation | ArrayAnimation;\n\nconst normalizeDurationMs = (duration: number): number =>\n  Number.isFinite(duration) ? duration : 0;\n\nconst normalizeTimestampMs = (timestamp: number): number | null =>\n  Number.isFinite(timestamp) ? timestamp : null;\n\nexport function createAnimationController(): AnimationController {\n  const animations = new Map<AnimationId, AnimationInternal>();\n\n  function animate(\n    from: number | ReadonlyArray<number>,\n    to: number | ReadonlyArray<number>,\n    duration: number,\n    easing: EasingFunction,\n    onUpdate: ((value: number) => void) | ((value: ReadonlyArray<number>) => void),\n    onComplete?: () => void,\n  ): AnimationId {\n    const id: AnimationId = Symbol('Animation');\n\n    if (Array.isArray(from) || Array.isArray(to)) {\n      if (!Array.isArray(from) || !Array.isArray(to)) {\n        throw new Error('Array animation requires both \"from\" and \"to\" to be arrays');\n      }\n      if (from.length !== to.length) {\n        throw new Error(\n          `Array animation length mismatch: from.length=${from.length}, to.length=${to.length}`,\n        );\n      }\n\n      const out = new Array<number>(from.length);\n      animations.set(id, {\n        kind: 'array',\n        from,\n        to,\n        duration,\n        easing,\n        onUpdate: onUpdate as (value: ReadonlyArray<number>) => void,\n        onComplete,\n        startTime: null,\n        out,\n      });\n      return id;\n    }\n\n    animations.set(id, {\n      kind: 'scalar',\n      from: from as number,\n      to: to as number,\n      duration,\n      easing,\n      onUpdate: onUpdate as (value: number) => void,\n      onComplete,\n      startTime: null,\n    });\n    return id;\n  }\n\n  function cancel(animationId: AnimationId): void {\n    animations.delete(animationId);\n  }\n\n  function cancelAll(): void {\n    animations.clear();\n  }\n\n  function update(timestamp: number): void {\n    const ts = normalizeTimestampMs(timestamp);\n    if (ts === null) return;\n\n    // Snapshot IDs to tolerate cancellation during callbacks and to ensure\n    // animations started during callbacks don't run until next tick.\n    const ids = Array.from(animations.keys());\n    for (const id of ids) {\n      const anim = animations.get(id);\n      if (!anim) continue; // cancelled\n\n      const startTime = anim.startTime ?? ts;\n      if (anim.startTime === null) {\n        // Mutate by replacement to keep internal entries immutable-by-type.\n        animations.set(id, { ...anim, startTime });\n      }\n\n      const durationMs = normalizeDurationMs(anim.duration);\n      const elapsed = Math.max(0, ts - startTime);\n\n      const shouldComplete = durationMs <= 0 || elapsed >= durationMs;\n      const rawT = durationMs <= 0 ? 1 : elapsed / durationMs;\n      const t = shouldComplete ? 1 : anim.easing(rawT);\n\n      if (anim.kind === 'scalar') {\n        const value = anim.from + (anim.to - anim.from) * t;\n        anim.onUpdate(value);\n\n        // Cancellation during callback should prevent onComplete.\n        if (!animations.has(id)) continue;\n      } else {\n        const n = anim.out.length;\n        for (let i = 0; i < n; i++) {\n          const a = anim.from[i] ?? 0;\n          const b = anim.to[i] ?? 0;\n          anim.out[i] = a + (b - a) * t;\n        }\n        anim.onUpdate(anim.out);\n\n        // Cancellation during callback should prevent onComplete.\n        if (!animations.has(id)) continue;\n      }\n\n      if (shouldComplete) {\n        anim.onComplete?.();\n        // If it was cancelled inside onComplete, deletion is harmless.\n        animations.delete(id);\n      }\n    }\n  }\n\n  return {\n    animate: animate as AnimationController['animate'],\n    cancel,\n    cancelAll,\n    update,\n  };\n}\n","export type EasingFunction = (t: number) => number;\n\nimport type { AnimationConfig } from '../config/types';\n\nexport type EasingName = NonNullable<AnimationConfig['easing']>;\n\nconst clamp01 = (t: number): number => {\n  if (Number.isNaN(t)) return 0;\n  if (t <= 0) return 0;\n  if (t >= 1) return 1;\n  return t;\n};\n\nexport function easeLinear(t: number): number {\n  return clamp01(t);\n}\n\nexport function easeCubicOut(t: number): number {\n  const x = clamp01(t);\n  const inv = 1 - x;\n  return 1 - inv * inv * inv;\n}\n\nexport function easeCubicInOut(t: number): number {\n  const x = clamp01(t);\n  // Standard easeInOutCubic:\n  // - accelerating cubic for the first half\n  // - decelerating cubic for the second half\n  if (x < 0.5) return 4 * x * x * x;\n  const y = -2 * x + 2;\n  return 1 - (y * y * y) / 2;\n}\n\nexport function easeBounceOut(t: number): number {\n  const x = clamp01(t);\n  // Standard easeOutBounce (Robert Penner) piecewise approximation.\n  const n1 = 7.5625;\n  const d1 = 2.75;\n\n  if (x < 1 / d1) {\n    return n1 * x * x;\n  }\n  if (x < 2 / d1) {\n    const a = x - 1.5 / d1;\n    return n1 * a * a + 0.75;\n  }\n  if (x < 2.5 / d1) {\n    const a = x - 2.25 / d1;\n    return n1 * a * a + 0.9375;\n  }\n\n  const a = x - 2.625 / d1;\n  return n1 * a * a + 0.984375;\n}\n\nexport function getEasing(\n  name: AnimationConfig['easing'] | null | undefined,\n): EasingFunction {\n  switch (name) {\n    case 'linear':\n      return easeLinear;\n    case 'cubicOut':\n      return easeCubicOut;\n    case 'cubicInOut':\n      return easeCubicInOut;\n    case 'bounceOut':\n      return easeBounceOut;\n    default:\n      return easeLinear;\n  }\n}\n","import type {\n  ResolvedBarSeriesConfig,\n  ResolvedCandlestickSeriesConfig,\n  ResolvedChartGPUOptions,\n  ResolvedPieSeriesConfig,\n} from '../config/OptionResolver';\nimport type {\n  AnimationConfig,\n  AnnotationConfig,\n  DataPoint,\n  DataPointTuple,\n  OHLCDataPoint,\n  PieCenter,\n  PieRadius,\n} from '../config/types';\nimport { GPUContext, isHTMLCanvasElement as isHTMLCanvasElementGPU } from './GPUContext';\nimport { createDataStore } from '../data/createDataStore';\nimport { sampleSeriesDataPoints } from '../data/sampleSeries';\nimport { ohlcSample } from '../data/ohlcSample';\nimport {\n  sliceVisibleRangeByX,\n  sliceVisibleRangeByOHLC,\n  isTupleOHLCDataPoint as isTupleOHLCDataPointImported,\n} from './renderCoordinator/data/computeVisibleSlice';\nimport { \n  getPointCount, \n  getX, \n  getY, \n  computeRawBoundsFromCartesianData \n} from '../data/cartesianData';\nimport type { CartesianSeriesData } from '../config/types';\nimport { renderAxisLabels } from './renderCoordinator/render/renderAxisLabels';\nimport { renderAnnotationLabels } from './renderCoordinator/render/renderAnnotationLabels';\nimport { prepareOverlays } from './renderCoordinator/render/renderOverlays';\nimport { processAnnotations } from './renderCoordinator/annotations/processAnnotations';\nimport {\n  prepareSeries,\n  encodeScatterDensityCompute,\n  renderSeries as renderSeriesPass,\n  renderAboveSeriesAnnotations,\n} from './renderCoordinator/render/renderSeries';\nimport { createAxisRenderer } from '../renderers/createAxisRenderer';\nimport { createGridRenderer } from '../renderers/createGridRenderer';\nimport type { GridArea } from '../renderers/createGridRenderer';\nimport { createAreaRenderer } from '../renderers/createAreaRenderer';\nimport { createLineRenderer } from '../renderers/createLineRenderer';\nimport { createBarRenderer } from '../renderers/createBarRenderer';\nimport { createScatterRenderer } from '../renderers/createScatterRenderer';\nimport { createScatterDensityRenderer } from '../renderers/createScatterDensityRenderer';\nimport { createPieRenderer } from '../renderers/createPieRenderer';\nimport { createCandlestickRenderer } from '../renderers/createCandlestickRenderer';\nimport { createCrosshairRenderer } from '../renderers/createCrosshairRenderer';\nimport { createHighlightRenderer } from '../renderers/createHighlightRenderer';\nimport { createRenderPipeline } from '../renderers/rendererUtils';\nimport { createReferenceLineRenderer } from '../renderers/createReferenceLineRenderer';\nimport type { ReferenceLineInstance } from '../renderers/createReferenceLineRenderer';\nimport { createAnnotationMarkerRenderer } from '../renderers/createAnnotationMarkerRenderer';\nimport type { AnnotationMarkerInstance } from '../renderers/createAnnotationMarkerRenderer';\nimport { createEventManager } from '../interaction/createEventManager';\nimport type { ChartGPUEventPayload } from '../interaction/createEventManager';\nimport { createInsideZoom } from '../interaction/createInsideZoom';\nimport { createZoomState } from '../interaction/createZoomState';\nimport type { ZoomRange, ZoomState } from '../interaction/createZoomState';\nimport { findNearestPoint } from '../interaction/findNearestPoint';\nimport { findPointsAtX } from '../interaction/findPointsAtX';\nimport { computeCandlestickBodyWidthRange, findCandlestick } from '../interaction/findCandlestick';\nimport { findPieSlice } from '../interaction/findPieSlice';\nimport { createLinearScale } from '../utils/scales';\nimport type { LinearScale } from '../utils/scales';\nimport { parseCssColorToGPUColor, parseCssColorToRgba01 } from '../utils/colors';\nimport { createTextOverlay } from '../components/createTextOverlay';\nimport type { TextOverlay, TextOverlayAnchor } from '../components/createTextOverlay';\nimport { createLegend } from '../components/createLegend';\nimport type { Legend } from '../components/createLegend';\nimport { createTooltip } from '../components/createTooltip';\nimport type { Tooltip } from '../components/createTooltip';\nimport type { TooltipParams } from '../config/types';\nimport { formatTooltipAxis, formatTooltipItem } from '../components/formatTooltip';\nimport { createAnimationController } from './createAnimationController';\nimport type { AnimationId } from './createAnimationController';\nimport { getEasing } from '../utils/easing';\nimport type { EasingFunction } from '../utils/easing';\n\nexport interface GPUContextLike {\n  readonly device: GPUDevice | null;\n  readonly canvas: HTMLCanvasElement | null;\n  readonly canvasContext: GPUCanvasContext | null;\n  readonly preferredFormat: GPUTextureFormat | null;\n  readonly initialized: boolean;\n  readonly devicePixelRatio?: number;\n}\n\n/** Type guard to check if canvas is HTMLCanvasElement (has DOM-specific properties). */\nconst isHTMLCanvasElement = isHTMLCanvasElementGPU;\n\n/** Gets canvas CSS width - clientWidth for HTMLCanvasElement */\nfunction getCanvasCssWidth(canvas: HTMLCanvasElement | null): number {\n  if (!canvas) {\n    return 0;\n  }\n\n  return canvas.clientWidth;\n}\n\n/**\n * Gets canvas CSS size derived strictly from device-pixel dimensions and DPR.\n *\n * This is intentionally different from `getCanvasCssWidth/Height(...)`:\n * - HTMLCanvasElement: `clientWidth/clientHeight` reflect DOM layout and can diverge (rounding, zoom, async resize)\n *   from the WebGPU render target size (`canvas.width/height` in device pixels).\n * - For GPU overlays that round-trip CSS↔device pixels in-shader, we must derive CSS size from\n *   `canvas.width/height` + DPR to keep transforms consistent with the render target.\n *\n * NOTE: Use this for GPU overlay coordinate conversion only (reference lines, markers).\n * Keep DOM overlays (labels/tooltips) using `clientWidth/clientHeight` for layout correctness.\n */\nfunction getCanvasCssSizeFromDevicePixels(\n  canvas: HTMLCanvasElement | null,\n): Readonly<{ width: number; height: number }> {\n  if (!canvas) return { width: 0, height: 0 };\n  const dpr = Number.isFinite(devicePixelRatio) && devicePixelRatio > 0 ? devicePixelRatio : 1;\n  // HTMLCanvasElement exposes `.width/.height` in device pixels.\n  return { width: canvas.width / dpr, height: canvas.height / dpr };\n}\n\nexport interface RenderCoordinator {\n  setOptions(resolvedOptions: ResolvedChartGPUOptions): void;\n  /**\n   * Appends new points to a cartesian series’ runtime data without requiring a full `setOptions(...)`\n   * resolver pass.\n   *\n   * Appends are coalesced and flushed once per render frame.\n   */\n  appendData(seriesIndex: number, newPoints: ReadonlyArray<DataPoint> | ReadonlyArray<OHLCDataPoint>): void;\n  /**\n   * Gets the current “interaction x” in domain units (or `null` when inactive).\n   *\n   * This is derived from pointer movement inside the plot grid and can also be driven\n   * externally via `setInteractionX(...)` (e.g. chart sync).\n   */\n  getInteractionX(): number | null;\n  /**\n   * Drives the chart’s crosshair + tooltip from a domain-space x value.\n   *\n   * Passing `null` clears the interaction (hides crosshair/tooltip).\n   */\n  setInteractionX(x: number | null, source?: unknown): void;\n  /**\n   * Subscribes to interaction x changes (domain units).\n   *\n   * Returns an unsubscribe function.\n   */\n  onInteractionXChange(callback: (x: number | null, source?: unknown) => void): () => void;\n  /**\n   * Returns the current percent-space zoom window (or `null` when zoom is disabled).\n   */\n  getZoomRange(): Readonly<{ start: number; end: number }> | null;\n  /**\n   * Sets the percent-space zoom window.\n   *\n   * No-op when zoom is disabled.\n   */\n  setZoomRange(start: number, end: number): void;\n  /**\n   * Subscribes to zoom window changes (percent space).\n   *\n   * Returns an unsubscribe function.\n   */\n  onZoomRangeChange(cb: (range: Readonly<{ start: number; end: number }>) => void): () => void;\n  render(): void;\n  dispose(): void;\n}\n\nexport type RenderCoordinatorCallbacks = Readonly<{\n  /**\n   * Optional hook for render-on-demand systems (like `ChartGPU`) to re-render when\n   * interaction state changes (e.g. crosshair on pointer move).\n   */\n  readonly onRequestRender?: () => void;\n  /**\n   * Called when GPU device is lost.\n   */\n  readonly onDeviceLost?: (reason: string) => void;\n}>;\n\ntype Bounds = Readonly<{ xMin: number; xMax: number; yMin: number; yMax: number }>;\n\nconst DEFAULT_TARGET_FORMAT: GPUTextureFormat = 'bgra8unorm';\nconst DEFAULT_TICK_COUNT: number = 5;\n\n// Story 6: time-axis label tiers + adaptive tick count (x-axis only).\nconst MS_PER_DAY = 24 * 60 * 60 * 1000;\n// Approximate month/year thresholds (requirements are ms-range based, not calendar-aware).\nconst MS_PER_MONTH_APPROX = 30 * MS_PER_DAY;\nconst MS_PER_YEAR_APPROX = 365 * MS_PER_DAY;\n\nconst MAX_TIME_X_TICK_COUNT = 9;\nconst MIN_TIME_X_TICK_COUNT = 1;\nconst MIN_X_LABEL_GAP_CSS_PX = 6;\n\nconst finiteOrNull = (v: number | null | undefined): number | null =>\n  typeof v === 'number' && Number.isFinite(v) ? v : null;\n\nconst finiteOrUndefined = (v: number | undefined): number | undefined =>\n  typeof v === 'number' && Number.isFinite(v) ? v : undefined;\n\n// Story 5.17: CPU-side update interpolation can be expensive for very large series.\n// We still animate domains for large series, but skip per-point y interpolation past this cap.\nconst MAX_ANIMATED_POINTS_PER_SERIES = 20_000;\n\nconst assertUnreachable = (value: never): never => {\n  // Intentionally minimal message: this is used for compile-time exhaustiveness.\n  throw new Error(`RenderCoordinator: unreachable value: ${String(value)}`);\n};\n\nconst isTupleDataPoint = (p: DataPoint): p is DataPointTuple => Array.isArray(p);\n\nconst getPointXY = (p: DataPoint): { readonly x: number; readonly y: number } => {\n  if (isTupleDataPoint(p)) return { x: p[0], y: p[1] };\n  return { x: p.x, y: p.y };\n};\n\n/**\n * Helper: Convert CartesianSeriesData to mutable DataPoint[] array.\n * Used for runtime storage that supports streaming appends.\n */\nconst cartesianDataToDataPointArray = (data: CartesianSeriesData): DataPoint[] => {\n  // If already a DataPoint array, clone it\n  if (Array.isArray(data)) {\n    return data.length === 0 ? [] : data.slice();\n  }\n\n  // Convert XYArraysData or InterleavedXYData to DataPoint[]\n  const n = getPointCount(data);\n  const out: DataPoint[] = new Array(n);\n  for (let i = 0; i < n; i++) {\n    const x = getX(data, i);\n    const y = getY(data, i);\n    out[i] = [x, y];\n  }\n  return out;\n};\n\nconst extendBoundsWithDataPoints = (bounds: Bounds | null, points: ReadonlyArray<DataPoint>): Bounds | null => {\n  if (points.length === 0) return bounds;\n\n  let b = bounds;\n  if (!b) {\n    // Try to seed from the appended points.\n    const seeded = computeRawBoundsFromCartesianData(points);\n    if (!seeded) return bounds;\n    b = seeded;\n  }\n\n  let xMin = b.xMin;\n  let xMax = b.xMax;\n  let yMin = b.yMin;\n  let yMax = b.yMax;\n\n  for (let i = 0; i < points.length; i++) {\n    const { x, y } = getPointXY(points[i]!);\n    if (!Number.isFinite(x) || !Number.isFinite(y)) continue;\n    if (x < xMin) xMin = x;\n    if (x > xMax) xMax = x;\n    if (y < yMin) yMin = y;\n    if (y > yMax) yMax = y;\n  }\n\n  // Keep bounds usable for downstream scale derivation.\n  if (xMin === xMax) xMax = xMin + 1;\n  if (yMin === yMax) yMax = yMin + 1;\n\n  return { xMin, xMax, yMin, yMax };\n};\n\nconst extendBoundsWithOHLCDataPoints = (bounds: Bounds | null, points: ReadonlyArray<OHLCDataPoint>): Bounds | null => {\n  if (points.length === 0) return bounds;\n\n  let xMin = bounds?.xMin ?? Number.POSITIVE_INFINITY;\n  let xMax = bounds?.xMax ?? Number.NEGATIVE_INFINITY;\n  let yMin = bounds?.yMin ?? Number.POSITIVE_INFINITY;\n  let yMax = bounds?.yMax ?? Number.NEGATIVE_INFINITY;\n\n  for (let i = 0; i < points.length; i++) {\n    const p = points[i]!;\n    const timestamp = isTupleOHLCDataPoint(p) ? p[0] : p.timestamp;\n    const low = isTupleOHLCDataPoint(p) ? p[3] : p.low;\n    const high = isTupleOHLCDataPoint(p) ? p[4] : p.high;\n\n    if (!Number.isFinite(timestamp) || !Number.isFinite(low) || !Number.isFinite(high)) continue;\n    if (timestamp < xMin) xMin = timestamp;\n    if (timestamp > xMax) xMax = timestamp;\n    if (low < yMin) yMin = low;\n    if (high > yMax) yMax = high;\n  }\n\n  if (!Number.isFinite(xMin) || !Number.isFinite(xMax) || !Number.isFinite(yMin) || !Number.isFinite(yMax)) {\n    return bounds;\n  }\n\n  // Keep bounds usable for downstream scale derivation.\n  if (xMin === xMax) xMax = xMin + 1;\n  if (yMin === yMax) yMax = yMin + 1;\n\n  return { xMin, xMax, yMin, yMax };\n};\n\nconst computeGlobalBounds = (\n  series: ResolvedChartGPUOptions['series'],\n  runtimeRawBoundsByIndex?: ReadonlyArray<Bounds | null> | null\n): Bounds => {\n  let xMin = Number.POSITIVE_INFINITY;\n  let xMax = Number.NEGATIVE_INFINITY;\n  let yMin = Number.POSITIVE_INFINITY;\n  let yMax = Number.NEGATIVE_INFINITY;\n\n  for (let s = 0; s < series.length; s++) {\n    const seriesConfig = series[s];\n    // Pie series are non-cartesian; they don't participate in x/y bounds.\n    if (seriesConfig.type === 'pie') continue;\n\n    const runtimeBoundsCandidate = runtimeRawBoundsByIndex?.[s] ?? null;\n    if (runtimeBoundsCandidate) {\n      const b = runtimeBoundsCandidate;\n      if (\n        Number.isFinite(b.xMin) &&\n        Number.isFinite(b.xMax) &&\n        Number.isFinite(b.yMin) &&\n        Number.isFinite(b.yMax)\n      ) {\n        if (b.xMin < xMin) xMin = b.xMin;\n        if (b.xMax > xMax) xMax = b.xMax;\n        if (b.yMin < yMin) yMin = b.yMin;\n        if (b.yMax > yMax) yMax = b.yMax;\n        continue;\n      }\n    }\n\n    // Prefer precomputed bounds from the original (unsampled) data when available.\n    // This ensures sampling cannot affect axis auto-bounds and avoids per-render O(n) scans.\n    const rawBoundsCandidate = seriesConfig.rawBounds;\n    if (rawBoundsCandidate) {\n      const b = rawBoundsCandidate;\n      if (\n        Number.isFinite(b.xMin) &&\n        Number.isFinite(b.xMax) &&\n        Number.isFinite(b.yMin) &&\n        Number.isFinite(b.yMax)\n      ) {\n        if (b.xMin < xMin) xMin = b.xMin;\n        if (b.xMax > xMax) xMax = b.xMax;\n        if (b.yMin < yMin) yMin = b.yMin;\n        if (b.yMax > yMax) yMax = b.yMax;\n        continue;\n      }\n    }\n\n    // Candlestick series: bounds should be precomputed in OptionResolver from timestamp/low/high.\n    // If we reach here, `rawBounds` was undefined; fall back to a raw OHLC scan so axes don't break.\n    if (seriesConfig.type === 'candlestick') {\n      const rawOHLC = (seriesConfig.rawData ?? seriesConfig.data) as ReadonlyArray<OHLCDataPoint>;\n      for (let i = 0; i < rawOHLC.length; i++) {\n        const p = rawOHLC[i]!;\n        if (isTupleOHLCDataPoint(p)) {\n          const timestamp = p[0];\n          const low = p[3];\n          const high = p[4];\n          if (!Number.isFinite(timestamp) || !Number.isFinite(low) || !Number.isFinite(high)) continue;\n\n          const yLow = Math.min(low, high);\n          const yHigh = Math.max(low, high);\n\n          if (timestamp < xMin) xMin = timestamp;\n          if (timestamp > xMax) xMax = timestamp;\n          if (yLow < yMin) yMin = yLow;\n          if (yHigh > yMax) yMax = yHigh;\n        } else {\n          const timestamp = p.timestamp;\n          const low = p.low;\n          const high = p.high;\n          if (!Number.isFinite(timestamp) || !Number.isFinite(low) || !Number.isFinite(high)) continue;\n\n          const yLow = Math.min(low, high);\n          const yHigh = Math.max(low, high);\n\n          if (timestamp < xMin) xMin = timestamp;\n          if (timestamp > xMax) xMax = timestamp;\n          if (yLow < yMin) yMin = yLow;\n          if (yHigh > yMax) yMax = yHigh;\n        }\n      }\n      continue;\n    }\n\n    // Cartesian series (line, area, bar, scatter): use CartesianSeriesData accessors\n    const data = seriesConfig.data as CartesianSeriesData;\n    const n = getPointCount(data);\n    for (let i = 0; i < n; i++) {\n      const x = getX(data, i);\n      const y = getY(data, i);\n      if (!Number.isFinite(x) || !Number.isFinite(y)) continue;\n      if (x < xMin) xMin = x;\n      if (x > xMax) xMax = x;\n      if (y < yMin) yMin = y;\n      if (y > yMax) yMax = y;\n    }\n  }\n\n  if (!Number.isFinite(xMin) || !Number.isFinite(xMax) || !Number.isFinite(yMin) || !Number.isFinite(yMax)) {\n    return { xMin: 0, xMax: 1, yMin: 0, yMax: 1 };\n  }\n\n  if (xMin === xMax) xMax = xMin + 1;\n  if (yMin === yMax) yMax = yMin + 1;\n\n  return { xMin, xMax, yMin, yMax };\n}; \n\nconst normalizeDomain = (\n  minCandidate: number,\n  maxCandidate: number\n): { readonly min: number; readonly max: number } => {\n  let min = minCandidate;\n  let max = maxCandidate;\n\n  if (!Number.isFinite(min) || !Number.isFinite(max)) {\n    min = 0;\n    max = 1;\n  }\n\n  if (min === max) {\n    max = min + 1;\n  } else if (min > max) {\n    const t = min;\n    min = max;\n    max = t;\n  }\n\n  return { min, max };\n};\n\nconst computeGridArea = (gpuContext: GPUContextLike, options: ResolvedChartGPUOptions): GridArea => {\n  const canvas = gpuContext.canvas;\n  if (!canvas) throw new Error('RenderCoordinator: gpuContext.canvas is required.');\n\n  // GridArea uses:\n  // - Margins (left, right, top, bottom) in CSS pixels\n  // - Canvas dimensions (canvasWidth, canvasHeight) in DEVICE pixels\n  // - devicePixelRatio for CSS-to-device conversion (worker-compatible)\n  // This allows renderers to multiply margins by DPR and subtract from canvas dimensions\n\n  const dpr = gpuContext.devicePixelRatio ?? 1;\n  const devicePixelRatio = (Number.isFinite(dpr) && dpr > 0) ? dpr : 1;\n\n  // Validate and sanitize canvas dimensions (device pixels)\n  // Canvas dimensions should be set by GPUContext initialization/resize, but guard against edge cases:\n  // - Race conditions during initialization\n  // - Canvas not yet sized (0 dimensions)\n  const rawCanvasWidth = canvas.width;\n  const rawCanvasHeight = canvas.height;\n  \n  if (!Number.isFinite(rawCanvasWidth) || !Number.isFinite(rawCanvasHeight)) {\n    throw new Error(\n      `RenderCoordinator: Invalid canvas dimensions: width=${rawCanvasWidth}, height=${rawCanvasHeight}. ` +\n      `Canvas must be initialized with finite dimensions before rendering.`\n    );\n  }\n  \n  // Be resilient: charts may be mounted into 0-sized containers (e.g. display:none during init).\n  // Renderers guard internally; clamping avoids hard crashes and allows future resize to recover.\n  const canvasWidth = Math.max(1, Math.floor(rawCanvasWidth));\n  const canvasHeight = Math.max(1, Math.floor(rawCanvasHeight));\n\n  // Validate and sanitize grid margins (CSS pixels)\n  // Grid margins come from resolved options and should be finite, but guard against edge cases\n  const left = Number.isFinite(options.grid.left) ? options.grid.left : 0;\n  const right = Number.isFinite(options.grid.right) ? options.grid.right : 0;\n  const top = Number.isFinite(options.grid.top) ? options.grid.top : 0;\n  const bottom = Number.isFinite(options.grid.bottom) ? options.grid.bottom : 0;\n\n  // Ensure margins are non-negative (negative margins could cause rendering issues)\n  const sanitizedLeft = Math.max(0, left);\n  const sanitizedRight = Math.max(0, right);\n  const sanitizedTop = Math.max(0, top);\n  const sanitizedBottom = Math.max(0, bottom);\n\n  return {\n    left: sanitizedLeft,\n    right: sanitizedRight,\n    top: sanitizedTop,\n    bottom: sanitizedBottom,\n    canvasWidth,                      // Device pixels (clamped above)\n    canvasHeight,                     // Device pixels (clamped above)\n    devicePixelRatio,                 // Explicit DPR for worker compatibility (validated above)\n  };\n};\n\nconst rgba01ToCssRgba = (rgba: readonly [number, number, number, number]): string => {\n  const r = Math.max(0, Math.min(255, Math.round(rgba[0] * 255)));\n  const g = Math.max(0, Math.min(255, Math.round(rgba[1] * 255)));\n  const b = Math.max(0, Math.min(255, Math.round(rgba[2] * 255)));\n  const a = Math.max(0, Math.min(1, rgba[3]));\n  return `rgba(${r},${g},${b},${a})`;\n};\n\nconst withAlpha = (cssColor: string, alphaMultiplier: number): string => {\n  const parsed = parseCssColorToRgba01(cssColor);\n  if (!parsed) return cssColor;\n  const a = Math.max(0, Math.min(1, parsed[3] * alphaMultiplier));\n  return rgba01ToCssRgba([parsed[0], parsed[1], parsed[2], a]);\n};\n\n\nconst computePlotClipRect = (\n  gridArea: GridArea\n): { readonly left: number; readonly right: number; readonly top: number; readonly bottom: number } => {\n  const { left, right, top, bottom, canvasWidth, canvasHeight, devicePixelRatio } = gridArea;\n\n  const plotLeft = left * devicePixelRatio;\n  const plotRight = canvasWidth - right * devicePixelRatio;\n  const plotTop = top * devicePixelRatio;\n  const plotBottom = canvasHeight - bottom * devicePixelRatio;\n\n  const plotLeftClip = (plotLeft / canvasWidth) * 2.0 - 1.0;\n  const plotRightClip = (plotRight / canvasWidth) * 2.0 - 1.0;\n  const plotTopClip = 1.0 - (plotTop / canvasHeight) * 2.0; // flip Y\n  const plotBottomClip = 1.0 - (plotBottom / canvasHeight) * 2.0; // flip Y\n\n  return {\n    left: plotLeftClip,\n    right: plotRightClip,\n    top: plotTopClip,\n    bottom: plotBottomClip,\n  };\n};\n\nconst clamp01 = (v: number): number => Math.min(1, Math.max(0, v));\nconst clampInt = (v: number, lo: number, hi: number): number => Math.min(hi, Math.max(lo, v | 0));\n\nconst lerp = (a: number, b: number, t01: number): number => a + (b - a) * clamp01(t01);\n\nconst lerpDomain = (\n  from: { readonly min: number; readonly max: number },\n  to: { readonly min: number; readonly max: number },\n  t01: number\n): { readonly min: number; readonly max: number } => {\n  return normalizeDomain(lerp(from.min, to.min, t01), lerp(from.max, to.max, t01));\n};\n\nconst computePlotScissorDevicePx = (\n  gridArea: GridArea\n): { readonly x: number; readonly y: number; readonly w: number; readonly h: number } => {\n  const { canvasWidth, canvasHeight, devicePixelRatio } = gridArea;\n\n  const plotLeftDevice = gridArea.left * devicePixelRatio;\n  const plotRightDevice = canvasWidth - gridArea.right * devicePixelRatio;\n  const plotTopDevice = gridArea.top * devicePixelRatio;\n  const plotBottomDevice = canvasHeight - gridArea.bottom * devicePixelRatio;\n\n  const scissorX = clampInt(Math.floor(plotLeftDevice), 0, Math.max(0, canvasWidth));\n  const scissorY = clampInt(Math.floor(plotTopDevice), 0, Math.max(0, canvasHeight));\n  const scissorR = clampInt(Math.ceil(plotRightDevice), 0, Math.max(0, canvasWidth));\n  const scissorB = clampInt(Math.ceil(plotBottomDevice), 0, Math.max(0, canvasHeight));\n  const scissorW = Math.max(0, scissorR - scissorX);\n  const scissorH = Math.max(0, scissorB - scissorY);\n\n  return { x: scissorX, y: scissorY, w: scissorW, h: scissorH };\n};\n\nconst clipXToCanvasCssPx = (xClip: number, canvasCssWidth: number): number => ((xClip + 1) / 2) * canvasCssWidth;\nconst clipYToCanvasCssPx = (yClip: number, canvasCssHeight: number): number => ((1 - yClip) / 2) * canvasCssHeight;\n\n// Alias for imported function to maintain compatibility with existing code\nconst isTupleOHLCDataPoint = isTupleOHLCDataPointImported;\n\nconst parseNumberOrPercent = (value: number | string, basis: number): number | null => {\n  if (typeof value === 'number') return Number.isFinite(value) ? value : null;\n  if (typeof value !== 'string') return null;\n\n  const s = value.trim();\n  if (s.length === 0) return null;\n\n  if (s.endsWith('%')) {\n    const pct = Number.parseFloat(s.slice(0, -1));\n    if (!Number.isFinite(pct)) return null;\n    return (pct / 100) * basis;\n  }\n\n  // Be permissive: allow numeric strings like \"120\".\n  const n = Number.parseFloat(s);\n  return Number.isFinite(n) ? n : null;\n};\n\nconst resolvePieCenterPlotCss = (\n  center: PieCenter | undefined,\n  plotWidthCss: number,\n  plotHeightCss: number\n): { readonly x: number; readonly y: number } => {\n  const xRaw = center?.[0] ?? '50%';\n  const yRaw = center?.[1] ?? '50%';\n\n  const x = parseNumberOrPercent(xRaw, plotWidthCss);\n  const y = parseNumberOrPercent(yRaw, plotHeightCss);\n\n  return {\n    x: Number.isFinite(x) ? x! : plotWidthCss * 0.5,\n    y: Number.isFinite(y) ? y! : plotHeightCss * 0.5,\n  };\n};\n\nconst isPieRadiusTuple = (\n  radius: PieRadius\n): radius is readonly [inner: number | string, outer: number | string] => Array.isArray(radius);\n\nconst resolvePieRadiiCss = (\n  radius: PieRadius | undefined,\n  maxRadiusCss: number\n): { readonly inner: number; readonly outer: number } => {\n  // Default similar to common chart libs (mirrors `createPieRenderer.ts`).\n  if (radius == null) return { inner: 0, outer: maxRadiusCss * 0.7 };\n\n  if (isPieRadiusTuple(radius)) {\n    const inner = parseNumberOrPercent(radius[0], maxRadiusCss);\n    const outer = parseNumberOrPercent(radius[1], maxRadiusCss);\n    const innerCss = Math.max(0, Number.isFinite(inner) ? inner! : 0);\n    const outerCss = Math.max(innerCss, Number.isFinite(outer) ? outer! : maxRadiusCss * 0.7);\n    return { inner: innerCss, outer: Math.min(maxRadiusCss, outerCss) };\n  }\n\n  const outer = parseNumberOrPercent(radius, maxRadiusCss);\n  const outerCss = Math.max(0, Number.isFinite(outer) ? outer! : maxRadiusCss * 0.7);\n  return { inner: 0, outer: Math.min(maxRadiusCss, outerCss) };\n};\n\nconst pad2 = (n: number): string => String(Math.trunc(n)).padStart(2, '0');\n\nconst MONTH_SHORT_EN: readonly string[] = [\n  'Jan',\n  'Feb',\n  'Mar',\n  'Apr',\n  'May',\n  'Jun',\n  'Jul',\n  'Aug',\n  'Sep',\n  'Oct',\n  'Nov',\n  'Dec',\n];\n\nconst formatTimeTickValue = (timestampMs: number, visibleRangeMs: number): string | null => {\n  if (!Number.isFinite(timestampMs)) return null;\n  if (!Number.isFinite(visibleRangeMs) || visibleRangeMs < 0) visibleRangeMs = 0;\n\n  const d = new Date(timestampMs);\n  // Guard against out-of-range timestamps that produce an invalid Date.\n  if (!Number.isFinite(d.getTime())) return null;\n  const yyyy = d.getFullYear();\n  const mm = d.getMonth() + 1; // 1-12\n  const dd = d.getDate();\n  const hh = d.getHours();\n  const min = d.getMinutes();\n\n  // Requirements (range in ms):\n  // - < 1 day: HH:mm\n  // - 1-7 days: MM/DD HH:mm\n  // - 1-12 weeks (and up to ~3 months): MM/DD\n  // - 3-12 months: MMM DD\n  // - > 1 year: YYYY/MM\n  if (visibleRangeMs < MS_PER_DAY) {\n    return `${pad2(hh)}:${pad2(min)}`;\n  }\n  // Treat the 7-day boundary as inclusive for the “1–7 days” tier.\n  if (visibleRangeMs <= 7 * MS_PER_DAY) {\n    return `${pad2(mm)}/${pad2(dd)} ${pad2(hh)}:${pad2(min)}`;\n  }\n  // Keep short calendar dates until the visible range reaches ~3 months.\n  // (This covers the 1–12 week requirement, plus the small 12w→3m gap.)\n  if (visibleRangeMs < 3 * MS_PER_MONTH_APPROX) {\n    return `${pad2(mm)}/${pad2(dd)}`;\n  }\n  if (visibleRangeMs <= MS_PER_YEAR_APPROX) {\n    const mmm = MONTH_SHORT_EN[d.getMonth()] ?? pad2(mm);\n    return `${mmm} ${pad2(dd)}`;\n  }\n  return `${yyyy}/${pad2(mm)}`;\n};\n\nconst generateLinearTicks = (domainMin: number, domainMax: number, tickCount: number): number[] => {\n  const count = Math.max(1, Math.floor(tickCount));\n  const ticks: number[] = new Array(count);\n  for (let i = 0; i < count; i++) {\n    const t = count === 1 ? 0.5 : i / (count - 1);\n    ticks[i] = domainMin + t * (domainMax - domainMin);\n  }\n  return ticks;\n};\n\nconst computeAdaptiveTimeXAxisTicks = (params: {\n  readonly axisMin: number | null;\n  readonly axisMax: number | null;\n  readonly xScale: LinearScale;\n  readonly plotClipLeft: number;\n  readonly plotClipRight: number;\n  readonly canvasCssWidth: number;\n  readonly visibleRangeMs: number;\n  readonly measureCtx: CanvasRenderingContext2D | null;\n  readonly measureCache?: Map<string, number>;\n  readonly fontSize: number;\n  readonly fontFamily: string;\n}): { readonly tickCount: number; readonly tickValues: readonly number[] } => {\n  const {\n    axisMin,\n    axisMax,\n    xScale,\n    plotClipLeft,\n    plotClipRight,\n    canvasCssWidth,\n    visibleRangeMs,\n    measureCtx,\n    measureCache,\n    fontSize,\n    fontFamily,\n  } = params;\n\n  // Domain fallback matches `createAxisRenderer` (use explicit min/max when provided).\n  const domainMin = finiteOrNull(axisMin) ?? xScale.invert(plotClipLeft);\n  const domainMax = finiteOrNull(axisMax) ?? xScale.invert(plotClipRight);\n\n  if (!measureCtx || canvasCssWidth <= 0) {\n    return { tickCount: DEFAULT_TICK_COUNT, tickValues: generateLinearTicks(domainMin, domainMax, DEFAULT_TICK_COUNT) };\n  }\n\n  // Ensure the measurement font matches the overlay labels.\n  measureCtx.font = `${fontSize}px ${fontFamily}`;\n  if (measureCache && measureCache.size > 2000) measureCache.clear();\n\n  // Pre-construct the font part of the cache key to avoid repeated concatenation.\n  const cacheKeyPrefix = measureCache ? `${fontSize}px ${fontFamily}@@` : null;\n\n  for (let tickCount = MAX_TIME_X_TICK_COUNT; tickCount >= MIN_TIME_X_TICK_COUNT; tickCount--) {\n    const tickValues = generateLinearTicks(domainMin, domainMax, tickCount);\n\n    // Compute label extents in *canvas-local CSS px* and ensure adjacent labels don't overlap.\n    let prevRight = Number.NEGATIVE_INFINITY;\n    let ok = true;\n\n    for (let i = 0; i < tickValues.length; i++) {\n      const v = tickValues[i]!;\n      const label = formatTimeTickValue(v, visibleRangeMs);\n      if (label == null) continue;\n\n      const w = (() => {\n        if (!cacheKeyPrefix) return measureCtx.measureText(label).width;\n        const key = cacheKeyPrefix + label;\n        const cached = measureCache!.get(key);\n        if (cached != null) return cached;\n        const measured = measureCtx.measureText(label).width;\n        measureCache!.set(key, measured);\n        return measured;\n      })();\n      const xClip = xScale.scale(v);\n      const xCss = clipXToCanvasCssPx(xClip, canvasCssWidth);\n\n      const anchor: TextOverlayAnchor =\n        tickCount === 1 ? 'middle' : i === 0 ? 'start' : i === tickValues.length - 1 ? 'end' : 'middle';\n\n      const left = anchor === 'start' ? xCss : anchor === 'end' ? xCss - w : xCss - w * 0.5;\n      const right = anchor === 'start' ? xCss + w : anchor === 'end' ? xCss : xCss + w * 0.5;\n\n      if (left < prevRight + MIN_X_LABEL_GAP_CSS_PX) {\n        ok = false;\n        break;\n      }\n      prevRight = right;\n    }\n\n    if (ok) {\n      return { tickCount, tickValues };\n    }\n  }\n\n  return { tickCount: MIN_TIME_X_TICK_COUNT, tickValues: generateLinearTicks(domainMin, domainMax, MIN_TIME_X_TICK_COUNT) };\n};\n\nconst computeBaseXDomain = (\n  options: ResolvedChartGPUOptions,\n  runtimeRawBoundsByIndex?: ReadonlyArray<Bounds | null> | null\n): { readonly min: number; readonly max: number } => {\n  const bounds = computeGlobalBounds(options.series, runtimeRawBoundsByIndex);\n  const baseMin = finiteOrUndefined(options.xAxis.min) ?? bounds.xMin;\n  const baseMax = finiteOrUndefined(options.xAxis.max) ?? bounds.xMax;\n  return normalizeDomain(baseMin, baseMax);\n};\n\n/**\n * Computes Y-axis domain bounds from the visible/rendered series data.\n * This avoids scanning the full raw dataset when yAxis.autoBounds === 'visible'.\n * \n * Performance: O(n) where n = total points across all visible series data.\n * This is called only when renderSeries changes (zoom/pan/data updates), not per-frame.\n */\nconst computeVisibleYBounds = (series: ResolvedChartGPUOptions['series']): Bounds => {\n  let yMin = Number.POSITIVE_INFINITY;\n  let yMax = Number.NEGATIVE_INFINITY;\n\n  for (let s = 0; s < series.length; s++) {\n    const seriesConfig = series[s];\n    // Pie series are non-cartesian; they don't participate in y bounds.\n    if (seriesConfig.type === 'pie') continue;\n\n    // Candlestick series: scan low/high from visible data\n    if (seriesConfig.type === 'candlestick') {\n      const visibleOHLC = seriesConfig.data as ReadonlyArray<OHLCDataPoint>;\n      for (let i = 0; i < visibleOHLC.length; i++) {\n        const p = visibleOHLC[i]!;\n        const low = isTupleOHLCDataPoint(p) ? p[3] : p.low;\n        const high = isTupleOHLCDataPoint(p) ? p[4] : p.high;\n        if (!Number.isFinite(low) || !Number.isFinite(high)) continue;\n\n        // Use Math.min/max to handle inverted low/high gracefully\n        const yLow = Math.min(low, high);\n        const yHigh = Math.max(low, high);\n\n        if (yLow < yMin) yMin = yLow;\n        if (yHigh > yMax) yMax = yHigh;\n      }\n      continue;\n    }\n\n    // Cartesian series (line, area, bar, scatter): scan y from visible data\n    const data = seriesConfig.data as CartesianSeriesData;\n    const n = getPointCount(data);\n    for (let i = 0; i < n; i++) {\n      const y = getY(data, i);\n      if (!Number.isFinite(y)) continue;\n      if (y < yMin) yMin = y;\n      if (y > yMax) yMax = y;\n    }\n  }\n\n  // Fallback for empty/invalid data: return safe default bounds\n  if (!Number.isFinite(yMin) || !Number.isFinite(yMax)) {\n    return { xMin: 0, xMax: 1, yMin: 0, yMax: 1 };\n  }\n\n  // Degenerate domain: add unit span to avoid zero-width range\n  if (yMin === yMax) yMax = yMin + 1;\n\n  return { xMin: 0, xMax: 1, yMin, yMax };\n};\n\nconst computeBaseYDomain = (\n  options: ResolvedChartGPUOptions,\n  runtimeRawBoundsByIndex?: ReadonlyArray<Bounds | null> | null,\n  visibleBoundsOverride?: Bounds | null\n): { readonly min: number; readonly max: number } => {\n  // Explicit min/max ALWAYS take precedence over auto-bounds\n  const explicitMin = finiteOrUndefined(options.yAxis.min);\n  const explicitMax = finiteOrUndefined(options.yAxis.max);\n\n  // If both min and max are explicit, use them directly (no auto-bounds needed)\n  if (explicitMin !== undefined && explicitMax !== undefined) {\n    return normalizeDomain(explicitMin, explicitMax);\n  }\n\n  // Determine which bounds to use based on autoBounds mode\n  const autoBoundsMode = options.yAxis.autoBounds ?? 'visible';\n  let bounds: Bounds;\n\n  if (autoBoundsMode === 'visible' && visibleBoundsOverride) {\n    // Use visible bounds from renderSeries (zoom-aware, computed from visible data only)\n    bounds = visibleBoundsOverride;\n  } else {\n    // Use global bounds from full dataset (pre-zoom behavior, computed from all raw data)\n    bounds = computeGlobalBounds(options.series, runtimeRawBoundsByIndex);\n  }\n\n  // Merge explicit bounds with computed bounds (partial override support)\n  const yMin = explicitMin ?? bounds.yMin;\n  const yMax = explicitMax ?? bounds.yMax;\n  return normalizeDomain(yMin, yMax);\n};\n\nconst computeVisibleXDomain = (\n  baseXDomain: { readonly min: number; readonly max: number },\n  zoomRange?: ZoomRange | null\n): { readonly min: number; readonly max: number; readonly spanFraction: number } => {\n  if (!zoomRange) return { ...baseXDomain, spanFraction: 1 };\n  const span = baseXDomain.max - baseXDomain.min;\n  if (!Number.isFinite(span) || span === 0) return { ...baseXDomain, spanFraction: 1 };\n\n  const start = zoomRange.start;\n  const end = zoomRange.end;\n  const xMin = baseXDomain.min + (start / 100) * span;\n  const xMax = baseXDomain.min + (end / 100) * span;\n  const normalized = normalizeDomain(xMin, xMax);\n\n  const fractionRaw = (end - start) / 100;\n  const spanFraction = Number.isFinite(fractionRaw) ? Math.max(0, Math.min(1, fractionRaw)) : 1;\n  return { min: normalized.min, max: normalized.max, spanFraction };\n};\n\ntype IntroPhase = 'pending' | 'running' | 'done';\n\nconst resolveAnimationConfig = (\n  animation: ResolvedChartGPUOptions['animation']\n):\n  | {\n      readonly durationMs: number;\n      readonly delayMs: number;\n      readonly easing: EasingFunction;\n    }\n  | null => {\n  if (animation === false || animation == null) return null;\n\n  const cfg: AnimationConfig | null = animation === true ? {} : animation;\n  if (!cfg) return null;\n\n  const durationMsRaw = cfg.duration ?? 300;\n  const delayMsRaw = cfg.delay ?? 0;\n\n  const durationMs = Number.isFinite(durationMsRaw) ? Math.max(0, durationMsRaw) : 300;\n  const delayMs = Number.isFinite(delayMsRaw) ? Math.max(0, delayMsRaw) : 0;\n\n  return {\n    durationMs,\n    delayMs,\n    easing: getEasing(cfg.easing),\n  };\n};\n\nconst resolveIntroAnimationConfig = (animation: ResolvedChartGPUOptions['animation']) => resolveAnimationConfig(animation);\nconst resolveUpdateAnimationConfig = (animation: ResolvedChartGPUOptions['animation']) => resolveAnimationConfig(animation);\n\n/**\n * Computes container-local CSS pixel anchor coordinates for a candlestick tooltip.\n *\n * The anchor is positioned near the candle body center for stable tooltip positioning\n * even when the cursor is at the edge of the candlestick.\n *\n * Coordinate transformations:\n * 1. Domain values (timestamp, open, close) from CandlestickMatch\n * 2. → xScale/yScale transform to grid-local CSS pixels\n * 3. → Add gridArea offset to get canvas-local CSS pixels\n * 4. → Add canvas offset to get container-local CSS pixels\n *\n * Returns null if any coordinate computation fails (non-finite values).\n */\nconst computeCandlestickTooltipAnchor = (\n  match: { readonly point: OHLCDataPoint },\n  xScale: LinearScale,\n  yScale: LinearScale,\n  gridArea: GridArea,\n  canvas: HTMLCanvasElement\n): Readonly<{ x: number; y: number }> | null => {\n  const point = match.point;\n  \n  const timestamp = isTupleOHLCDataPoint(point) ? point[0] : point.timestamp;\n  const open = isTupleOHLCDataPoint(point) ? point[1] : point.open;\n  const close = isTupleOHLCDataPoint(point) ? point[2] : point.close;\n\n  if (!Number.isFinite(timestamp) || !Number.isFinite(open) || !Number.isFinite(close)) {\n    return null;\n  }\n\n  // Body center in domain space\n  const bodyMidY = (open + close) / 2;\n\n  // Transform to grid-local CSS pixels\n  const xGridCss = xScale.scale(timestamp);\n  const yGridCss = yScale.scale(bodyMidY);\n\n  if (!Number.isFinite(xGridCss) || !Number.isFinite(yGridCss)) {\n    return null;\n  }\n\n  // Convert to canvas-local CSS pixels\n  const xCanvasCss = gridArea.left + xGridCss;\n  const yCanvasCss = gridArea.top + yGridCss;\n\n  // Convert to container-local CSS pixels\n  const xContainerCss = isHTMLCanvasElement(canvas) ? canvas.offsetLeft + xCanvasCss : xCanvasCss;\n  const yContainerCss = isHTMLCanvasElement(canvas) ? canvas.offsetTop + yCanvasCss : yCanvasCss;\n\n  if (!Number.isFinite(xContainerCss) || !Number.isFinite(yContainerCss)) {\n    return null;\n  }\n\n  return { x: xContainerCss, y: yContainerCss };\n};\n\nconst computeBaselineForBarsFromData = (seriesConfigs: ReadonlyArray<ResolvedBarSeriesConfig>): number => {\n  let yMin = Number.POSITIVE_INFINITY;\n  let yMax = Number.NEGATIVE_INFINITY;\n\n  for (let s = 0; s < seriesConfigs.length; s++) {\n    const data = seriesConfigs[s]!.data as CartesianSeriesData;\n    const n = getPointCount(data);\n    for (let i = 0; i < n; i++) {\n      const y = getY(data, i);\n      if (!Number.isFinite(y)) continue;\n      if (y < yMin) yMin = y;\n      if (y > yMax) yMax = y;\n    }\n  }\n\n  if (!Number.isFinite(yMin) || !Number.isFinite(yMax)) return 0;\n  if (yMin <= 0 && 0 <= yMax) return 0;\n  return Math.abs(yMin) < Math.abs(yMax) ? yMin : yMax;\n};\n\nconst computeBaselineForBarsFromAxis = (\n  seriesConfigs: ReadonlyArray<ResolvedBarSeriesConfig>,\n  yScale: LinearScale,\n  plotClipRect: Readonly<{ top: number; bottom: number }>\n): number => {\n  const yDomainA = yScale.invert(plotClipRect.bottom);\n  const yDomainB = yScale.invert(plotClipRect.top);\n  const yMin = Math.min(yDomainA, yDomainB);\n  const yMax = Math.max(yDomainA, yDomainB);\n\n  if (!Number.isFinite(yMin) || !Number.isFinite(yMax)) {\n    return computeBaselineForBarsFromData(seriesConfigs);\n  }\n\n  if (yMin <= 0 && 0 <= yMax) return 0;\n  if (yMin > 0) return yMin;\n  if (yMax < 0) return yMax;\n  return computeBaselineForBarsFromData(seriesConfigs);\n};\n\nconst createAnimatedBarYScale = (\n  baseYScale: LinearScale,\n  plotClipRect: Readonly<{ top: number; bottom: number }>,\n  barSeriesConfigs: ReadonlyArray<ResolvedBarSeriesConfig>,\n  progress01: number\n): LinearScale => {\n  const p = clamp01(progress01);\n  if (p >= 1) return baseYScale;\n\n  const baselineDomain = computeBaselineForBarsFromAxis(barSeriesConfigs, baseYScale, plotClipRect);\n  const baselineClip = baseYScale.scale(baselineDomain);\n\n  const wrapper: LinearScale = {\n    domain(min: number, max: number) {\n      baseYScale.domain(min, max);\n      return wrapper;\n    },\n    range(min: number, max: number) {\n      baseYScale.range(min, max);\n      return wrapper;\n    },\n    scale(value: number) {\n      const v = baseYScale.scale(value);\n      if (!Number.isFinite(v) || !Number.isFinite(baselineClip)) return v;\n      return baselineClip + (v - baselineClip) * p;\n    },\n    invert(pixel: number) {\n      return baseYScale.invert(pixel);\n    },\n  };\n\n  return wrapper;\n};\n\nexport function createRenderCoordinator(\n  gpuContext: GPUContext,\n  options: ResolvedChartGPUOptions,\n  callbacks?: RenderCoordinatorCallbacks\n): RenderCoordinator {\n  if (!gpuContext.initialized) {\n    throw new Error('RenderCoordinator: gpuContext must be initialized.');\n  }\n  const device = gpuContext.device;\n  if (!device) {\n    throw new Error('RenderCoordinator: gpuContext.device is required.');\n  }\n  if (!gpuContext.canvas) {\n    throw new Error('RenderCoordinator: gpuContext.canvas is required.');\n  }\n  if (!gpuContext.canvasContext) {\n    throw new Error('RenderCoordinator: gpuContext.canvasContext is required.');\n  }\n\n  // Listen for device loss and emit callback\n  // Note: We don't call dispose() here to avoid double-cleanup if user calls dispose() in callback.\n  // The coordinator is effectively non-functional after device loss until re-created.\n  device.lost.then((info) => {\n    callbacks?.onDeviceLost?.(info.message || info.reason || 'unknown');\n  }).catch(() => {\n    // Ignore errors in device.lost promise (can occur if device is destroyed before lost promise resolves)\n  });\n\n  const targetFormat = gpuContext.preferredFormat ?? DEFAULT_TARGET_FORMAT;\n  \n  // DOM-dependent features (overlays, legends) require HTMLCanvasElement.\n  const overlayContainer = isHTMLCanvasElement(gpuContext.canvas) ? gpuContext.canvas.parentElement : null;\n  const axisLabelOverlay: TextOverlay | null = overlayContainer ? createTextOverlay(overlayContainer) : null;\n  // Dedicated overlay for annotations (do not reuse axis label overlay).\n  const annotationOverlay: TextOverlay | null = overlayContainer ? createTextOverlay(overlayContainer) : null;\n\n  const handleSeriesToggle = (seriesIndex: number, sliceIndex?: number): void => {\n    if (disposed) return;\n\n    const series = currentOptions.series;\n    if (seriesIndex < 0 || seriesIndex >= series.length) return;\n\n    const s = series[seriesIndex];\n    if (!s) return;\n\n    // Handle pie slice toggle\n    if (sliceIndex !== undefined && s.type === 'pie') {\n      const pieData = (s as ResolvedPieSeriesConfig).data;\n      if (sliceIndex < 0 || sliceIndex >= pieData.length) return;\n\n      const updatedData = pieData.map((slice, i) =>\n        i === sliceIndex\n          ? { ...slice, visible: slice.visible === false ? true : false }\n          : slice\n      );\n\n      const updatedSeries = series.map((seriesItem, i) =>\n        i === seriesIndex\n          ? ({ ...seriesItem, data: updatedData } as typeof seriesItem)\n          : seriesItem\n      );\n\n      setOptions({ ...currentOptions, series: updatedSeries });\n      return;\n    }\n\n    // Toggle regular series visibility\n    const updatedSeries = series.map((seriesItem, i) =>\n      i === seriesIndex\n        ? ({ ...seriesItem, visible: seriesItem.visible === false ? true : false } as typeof seriesItem)\n        : seriesItem\n    );\n\n    // Update options with new series array\n    setOptions({ ...currentOptions, series: updatedSeries });\n  };\n\n  const legend: Legend | null = overlayContainer ? createLegend(overlayContainer, 'right', handleSeriesToggle) : null;\n  // Text measurement for axis labels. Only available in DOM contexts (not worker threads).\n  const tickMeasureCtx: CanvasRenderingContext2D | null = (() => {\n    if (typeof document === 'undefined') {\n      // Worker thread: DOM not available.\n      return null;\n    }\n    try {\n      const c = document.createElement('canvas');\n      return c.getContext('2d');\n    } catch {\n      return null;\n    }\n  })();\n  const tickMeasureCache: Map<string, number> | null = tickMeasureCtx ? new Map() : null;\n\n  let disposed = false;\n  let currentOptions: ResolvedChartGPUOptions = options;\n  let lastSeriesCount = options.series.length;\n\n  // Story 5.16: initial-load intro animation (series marks only).\n  let introPhase: IntroPhase = 'pending';\n  let introProgress01 = 0;\n  const introAnimController = createAnimationController();\n  let introAnimId: AnimationId | null = null;\n\n  // Story 5.17 (step 1): data update transition state (snapshots only; interpolation occurs later).\n  type UpdateTransitionSnapshot = Readonly<{\n    readonly xBaseDomain: { readonly min: number; readonly max: number };\n    readonly xVisibleDomain: { readonly min: number; readonly max: number };\n    readonly yBaseDomain: { readonly min: number; readonly max: number };\n    readonly series: ResolvedChartGPUOptions['series'];\n  }>;\n\n  type UpdateTransition = Readonly<{\n    readonly from: UpdateTransitionSnapshot;\n    readonly to: UpdateTransitionSnapshot;\n  }>;\n\n  let hasRenderedOnce = false;\n  const updateAnimController = createAnimationController();\n  let updateAnimId: AnimationId | null = null;\n  let updateProgress01 = 1;\n  let updateTransition: UpdateTransition | null = null;\n\n  type UpdateInterpolationCaches = Readonly<{\n    readonly cartesianDataBySeriesIndex: Array<DataPoint[] | null>;\n    readonly pieDataBySeriesIndex: Array<ResolvedPieSeriesConfig['data'] | null>;\n  }>;\n\n  const updateInterpolationCaches: UpdateInterpolationCaches = {\n    cartesianDataBySeriesIndex: [],\n    pieDataBySeriesIndex: [],\n  };\n\n  const resetUpdateInterpolationCaches = (): void => {\n    updateInterpolationCaches.cartesianDataBySeriesIndex.length = 0;\n    updateInterpolationCaches.pieDataBySeriesIndex.length = 0;\n  };\n\n  const interpolateCartesianSeriesDataByIndex = (\n    fromData: ReadonlyArray<DataPoint>,\n    toData: ReadonlyArray<DataPoint>,\n    t01: number,\n    cache: DataPoint[] | null\n  ): DataPoint[] | null => {\n    if (fromData.length !== toData.length) return null;\n    const n = toData.length;\n    if (n === 0) return cache ?? [];\n\n    const out =\n      cache && cache.length === n\n        ? cache\n        : (() => {\n            const created: DataPoint[] = new Array(n);\n            for (let i = 0; i < n; i++) {\n              const pTo = toData[i]!;\n              const { x } = getPointXY(pTo);\n              const size = isTupleDataPoint(pTo) ? pTo[2] : (pTo as any)?.size;\n              created[i] = isTupleDataPoint(pTo)\n                ? (size == null ? ([x, 0] as const) : ([x, 0, size] as const))\n                : (size == null ? ({ x, y: 0 } as const) : ({ x, y: 0, size } as const));\n            }\n            return created;\n          })();\n\n    const t = clamp01(t01);\n    for (let i = 0; i < n; i++) {\n      const yFrom = getPointXY(fromData[i]!).y;\n      const yTo = getPointXY(toData[i]!).y;\n      const y = Number.isFinite(yFrom) && Number.isFinite(yTo) ? lerp(yFrom, yTo, t) : yTo;\n      const p = out[i]!;\n      if (isTupleDataPoint(p)) {\n        (p as unknown as number[])[1] = y;\n      } else {\n        (p as any).y = y;\n      }\n    }\n\n    return out;\n  };\n\n  const interpolatePieSeriesByIndex = (\n    fromSeries: ResolvedPieSeriesConfig,\n    toSeries: ResolvedPieSeriesConfig,\n    t01: number,\n    cache: ResolvedPieSeriesConfig['data'] | null\n  ): ResolvedPieSeriesConfig => {\n    const fromData = fromSeries.data;\n    const toData = toSeries.data;\n    if (fromData.length !== toData.length) return toSeries;\n\n    const n = toData.length;\n    const out =\n      cache && cache.length === n\n        ? cache\n        : (() => {\n            const created: any[] = new Array(n);\n            for (let i = 0; i < n; i++) {\n              // Preserve name/color from \"to\"; patch value per frame.\n              created[i] = { ...toData[i]!, value: 0 };\n            }\n            return created as ResolvedPieSeriesConfig['data'];\n          })();\n\n    const t = clamp01(t01);\n    for (let i = 0; i < n; i++) {\n      const vFrom = (fromData[i] as any)?.value;\n      const vTo = (toData[i] as any)?.value;\n      const next =\n        typeof vFrom === 'number' && typeof vTo === 'number' && Number.isFinite(vFrom) && Number.isFinite(vTo)\n          ? Math.max(0, lerp(vFrom, vTo, t))\n          : typeof vTo === 'number' && Number.isFinite(vTo)\n            ? vTo\n            : 0;\n      (out[i] as any).value = next;\n    }\n\n    return { ...toSeries, data: out };\n  };\n\n  const interpolateSeriesForUpdate = (\n    fromSeries: ResolvedChartGPUOptions['series'],\n    toSeries: ResolvedChartGPUOptions['series'],\n    t01: number,\n    caches: UpdateInterpolationCaches | null\n  ): ResolvedChartGPUOptions['series'] => {\n    if (fromSeries.length !== toSeries.length) return toSeries;\n\n    const out: ResolvedChartGPUOptions['series'][number][] = new Array(toSeries.length);\n\n    for (let i = 0; i < toSeries.length; i++) {\n      const a = fromSeries[i]!;\n      const b = toSeries[i]!;\n\n      if (a.type !== b.type) {\n        out[i] = b;\n        continue;\n      }\n\n      if (b.type === 'pie') {\n        const cache = caches?.pieDataBySeriesIndex[i] ?? null;\n        const animated = interpolatePieSeriesByIndex(a as ResolvedPieSeriesConfig, b as ResolvedPieSeriesConfig, t01, cache);\n        if (caches) caches.pieDataBySeriesIndex[i] = animated.data as any;\n        out[i] = animated;\n        continue;\n      }\n\n      // Cartesian series: interpolate y-values by index. Keep x from \"to\".\n      const aAny = a as unknown as { readonly data: ReadonlyArray<DataPoint> };\n      const bAny = b as unknown as { readonly data: ReadonlyArray<DataPoint> };\n      const aData = aAny.data;\n      const bData = bAny.data;\n\n      if (aData.length !== bData.length) {\n        out[i] = b;\n        continue;\n      }\n      if (bData.length > MAX_ANIMATED_POINTS_PER_SERIES) {\n        out[i] = b;\n        continue;\n      }\n\n      const cache = caches?.cartesianDataBySeriesIndex[i] ?? null;\n      const animatedData = interpolateCartesianSeriesDataByIndex(aData, bData, t01, cache);\n      if (!animatedData) {\n        out[i] = b;\n        continue;\n      }\n      if (caches) caches.cartesianDataBySeriesIndex[i] = animatedData;\n\n      out[i] = { ...(b as any), data: animatedData };\n    }\n\n    return out;\n  };\n\n  const computeUpdateSnapshotAtProgress = (\n    transition: UpdateTransition,\n    t01: number,\n    zoomRange: ZoomRange | null\n  ): UpdateTransitionSnapshot => {\n    const xBase = lerpDomain(transition.from.xBaseDomain, transition.to.xBaseDomain, t01);\n    const xVisible = computeVisibleXDomain(xBase, zoomRange);\n    const yBase = lerpDomain(transition.from.yBaseDomain, transition.to.yBaseDomain, t01);\n    const series = interpolateSeriesForUpdate(transition.from.series, transition.to.series, t01, null);\n    return {\n      xBaseDomain: xBase,\n      xVisibleDomain: { min: xVisible.min, max: xVisible.max },\n      yBaseDomain: yBase,\n      series,\n    };\n  };\n\n  // Prevent spamming console.warn for repeated misuse.\n  const warnedPieAppendSeries = new Set<number>();\n  const warnedSamplingDefeatsFastPath = new Set<number>();\n\n  // Coordinator-owned runtime series store (cartesian only).\n  // - `runtimeRawDataByIndex[i]` owns a mutable array for streaming appends.\n  // - `runtimeRawBoundsByIndex[i]` tracks raw bounds for axis auto-bounds and zoom mapping.\n  let runtimeRawDataByIndex: Array<DataPoint[] | OHLCDataPoint[] | null> = new Array(options.series.length).fill(null);\n  let runtimeRawBoundsByIndex: Array<Bounds | null> = new Array(options.series.length).fill(null);\n\n  // Baseline sampled series list derived from runtime raw data (used as the “full span” baseline).\n  // Zoom-visible resampling is derived from this baseline + runtime raw as needed.\n  let runtimeBaseSeries: ResolvedChartGPUOptions['series'] = currentOptions.series;\n\n  // Zoom-aware sampled series list used for rendering + cartesian hit-testing.\n  // Derived from `currentOptions.series` (which still includes baseline sampled `data`).\n  let renderSeries: ResolvedChartGPUOptions['series'] = currentOptions.series;\n\n  // Cache for visible y-bounds computed from renderSeries (for yAxis.autoBounds === 'visible').\n  // Recomputed whenever renderSeries changes (zoom/pan/data updates).\n  let cachedVisibleYBounds: Bounds | null = null;\n\n  const shouldComputeVisibleYBounds = (opts: ResolvedChartGPUOptions): boolean => {\n    const autoBoundsMode = opts.yAxis.autoBounds ?? 'visible';\n    if (autoBoundsMode !== 'visible') return false;\n    // If both bounds are explicit, auto-bounds (including visible) are never consulted.\n    const explicitMin = finiteOrUndefined(opts.yAxis.min);\n    const explicitMax = finiteOrUndefined(opts.yAxis.max);\n    return !(explicitMin !== undefined && explicitMax !== undefined);\n  };\n\n  const recomputeCachedVisibleYBoundsIfNeeded = (): void => {\n    if (shouldComputeVisibleYBounds(currentOptions)) {\n      cachedVisibleYBounds = computeVisibleYBounds(renderSeries);\n    } else {\n      cachedVisibleYBounds = null;\n    }\n  };\n\n  // Cache for sampled data with buffer zones - enables fast slicing during pan without resampling.\n  interface SampledDataCache {\n    data: ReadonlyArray<DataPoint> | ReadonlyArray<OHLCDataPoint>;\n    cachedRange: { min: number; max: number };\n    timestamp: number;\n  }\n  let lastSampledData: Array<SampledDataCache | null> = [];\n\n  // Unified flush scheduler (appends + zoom-aware resampling + optional GPU streaming updates).\n  let flushScheduled = false;\n  let flushRafId: number | null = null;\n  let flushTimeoutId: number | null = null;\n\n  // Zoom changes are debounced to avoid churn while wheel/drag is active.\n  // When the debounce fires, we mark resampling \"due\" and schedule a unified flush.\n  let zoomResampleDebounceTimer: number | null = null;\n  let zoomResampleDue = false;\n\n  // Zoom changes can fire multiple times per frame; slicing and visible-bounds recompute can be O(n).\n  // Coalesce those updates to at most once per rendered frame.\n  let sliceRenderSeriesDue = false;\n\n  // Coalesced streaming appends (flushed at the start of `render()`).\n  const pendingAppendByIndex = new Map<number, Array<DataPoint | OHLCDataPoint>>();\n\n  // Tracks what the DataStore currently represents for each series index.\n  // Used to decide whether `appendSeries(...)` is a correct fast-path.\n  type GpuSeriesKind = 'unknown' | 'fullRawLine' | 'other';\n  let gpuSeriesKindByIndex: GpuSeriesKind[] = new Array(currentOptions.series.length).fill('unknown');\n  const appendedGpuThisFrame = new Set<number>();\n\n  // Tooltip is a DOM overlay element; enable by default unless explicitly disabled.\n  let tooltip: Tooltip | null =\n    overlayContainer && currentOptions.tooltip?.show !== false ? createTooltip(overlayContainer) : null;\n\n  // Cache tooltip state to avoid unnecessary DOM updates\n  let lastTooltipContent: string | null = null;\n  let lastTooltipX: number | null = null;\n  let lastTooltipY: number | null = null;\n\n  // Helper functions for tooltip/legend management\n  const showTooltipInternal = (x: number, y: number, content: string, _params: TooltipParams | TooltipParams[]) => {\n    tooltip?.show(x, y, content);\n  };\n\n  const hideTooltipInternal = () => {\n    tooltip?.hide();\n  };\n\n  const hideTooltip = () => {\n    lastTooltipContent = null;\n    lastTooltipX = null;\n    lastTooltipY = null;\n    hideTooltipInternal();\n  };\n\n  const updateLegend = (series: ResolvedChartGPUOptions['series'], theme: ResolvedChartGPUOptions['theme']) => {\n    legend?.update(series, theme);\n  };\n\n  updateLegend(currentOptions.series, currentOptions.theme);\n\n  let dataStore = createDataStore(device);\n\n  const gridRenderer = createGridRenderer(device, { targetFormat });\n  const xAxisRenderer = createAxisRenderer(device, { targetFormat });\n  const yAxisRenderer = createAxisRenderer(device, { targetFormat });\n  const crosshairRenderer = createCrosshairRenderer(device, { targetFormat });\n  crosshairRenderer.setVisible(false);\n  const highlightRenderer = createHighlightRenderer(device, { targetFormat });\n  highlightRenderer.setVisible(false);\n\n  // MSAA for the *annotation overlay* (above-series) pass to reduce shimmer during zoom.\n  // NOTE: In WebGPU, pipeline sampleCount must match the render pass attachment sampleCount.\n  // To keep MSAA scoped, we render the main scene to a single-sample texture, then:\n  // - MSAA overlay pass: blit main scene into an MSAA target + draw above-series annotations, resolve to swapchain\n  // - Top overlay pass: draw crosshair/axes/highlight (single-sample) on top of the resolved swapchain\n  const ANNOTATION_OVERLAY_MSAA_SAMPLE_COUNT = 4;\n\n  const referenceLineRenderer = createReferenceLineRenderer(device, { targetFormat });\n  const annotationMarkerRenderer = createAnnotationMarkerRenderer(device, { targetFormat });\n  const referenceLineRendererMsaa = createReferenceLineRenderer(device, {\n    targetFormat,\n    sampleCount: ANNOTATION_OVERLAY_MSAA_SAMPLE_COUNT,\n  });\n  const annotationMarkerRendererMsaa = createAnnotationMarkerRenderer(device, {\n    targetFormat,\n    sampleCount: ANNOTATION_OVERLAY_MSAA_SAMPLE_COUNT,\n  });\n\n  let mainColorTexture: GPUTexture | null = null;\n  let mainColorView: GPUTextureView | null = null;\n  let overlayMsaaTexture: GPUTexture | null = null;\n  let overlayMsaaView: GPUTextureView | null = null;\n  let overlayTargetsWidth = 0;\n  let overlayTargetsHeight = 0;\n  let overlayTargetsFormat: GPUTextureFormat | null = null;\n\n  const OVERLAY_BLIT_WGSL = `\nstruct VSOut { @builtin(position) pos: vec4f };\n\n@vertex\nfn vsMain(@builtin(vertex_index) i: u32) -> VSOut {\n  var positions = array<vec2f, 3>(\n    vec2f(-1.0, -1.0),\n    vec2f( 3.0, -1.0),\n    vec2f(-1.0,  3.0)\n  );\n  var o: VSOut;\n  o.pos = vec4f(positions[i], 0.0, 1.0);\n  return o;\n}\n\n// Using textureLoad (no filtering) for pixel-exact blit into the MSAA overlay pass.\n@group(0) @binding(0) var srcTex: texture_2d<f32>;\n\n@fragment\nfn fsMain(@builtin(position) pos: vec4f) -> @location(0) vec4f {\n  let xy = vec2<i32>(pos.xy);\n  return textureLoad(srcTex, xy, 0);\n}\n`;\n\n  const overlayBlitBindGroupLayout = device.createBindGroupLayout({\n    entries: [{ binding: 0, visibility: GPUShaderStage.FRAGMENT, texture: { sampleType: 'float', viewDimension: '2d' } }],\n  });\n\n  const overlayBlitPipeline = createRenderPipeline(device, {\n    label: 'renderCoordinator/overlayBlitPipeline',\n    bindGroupLayouts: [overlayBlitBindGroupLayout],\n    vertex: { code: OVERLAY_BLIT_WGSL, label: 'renderCoordinator/overlayBlit.wgsl' },\n    fragment: { code: OVERLAY_BLIT_WGSL, label: 'renderCoordinator/overlayBlit.wgsl', formats: targetFormat },\n    primitive: { topology: 'triangle-list', cullMode: 'none' },\n    multisample: { count: ANNOTATION_OVERLAY_MSAA_SAMPLE_COUNT },\n  });\n\n  let overlayBlitBindGroup: GPUBindGroup | null = null;\n\n  const destroyTexture = (tex: GPUTexture | null): void => {\n    if (!tex) return;\n    try {\n      tex.destroy();\n    } catch {\n      // best-effort\n    }\n  };\n\n  const ensureOverlayTargets = (canvasWidthDevicePx: number, canvasHeightDevicePx: number): void => {\n    const w = Number.isFinite(canvasWidthDevicePx) ? Math.max(1, Math.floor(canvasWidthDevicePx)) : 1;\n    const h = Number.isFinite(canvasHeightDevicePx) ? Math.max(1, Math.floor(canvasHeightDevicePx)) : 1;\n\n    if (mainColorTexture && overlayMsaaTexture && overlayBlitBindGroup && overlayTargetsWidth === w && overlayTargetsHeight === h && overlayTargetsFormat === targetFormat) {\n      return;\n    }\n\n    destroyTexture(mainColorTexture);\n    destroyTexture(overlayMsaaTexture);\n\n    mainColorTexture = device.createTexture({\n      label: 'renderCoordinator/mainColorTexture',\n      size: { width: w, height: h },\n      format: targetFormat,\n      usage: GPUTextureUsage.RENDER_ATTACHMENT | GPUTextureUsage.TEXTURE_BINDING,\n    });\n    mainColorView = mainColorTexture.createView();\n\n    overlayMsaaTexture = device.createTexture({\n      label: 'renderCoordinator/annotationOverlayMsaaTexture',\n      size: { width: w, height: h },\n      sampleCount: ANNOTATION_OVERLAY_MSAA_SAMPLE_COUNT,\n      format: targetFormat,\n      usage: GPUTextureUsage.RENDER_ATTACHMENT,\n    });\n    overlayMsaaView = overlayMsaaTexture.createView();\n\n    overlayBlitBindGroup = device.createBindGroup({\n      label: 'renderCoordinator/overlayBlitBindGroup',\n      layout: overlayBlitBindGroupLayout,\n      entries: [{ binding: 0, resource: mainColorView }],\n    });\n\n    overlayTargetsWidth = w;\n    overlayTargetsHeight = h;\n    overlayTargetsFormat = targetFormat;\n  };\n\n  const initialGridArea = computeGridArea(gpuContext, currentOptions);\n  \n  // Event manager requires HTMLCanvasElement (DOM events).\n  const eventManager = isHTMLCanvasElement(gpuContext.canvas) \n    ? createEventManager(gpuContext.canvas, initialGridArea)\n    : null;\n\n  type PointerSource = 'mouse' | 'sync';\n\n  type PointerState = Readonly<{\n    source: PointerSource;\n    x: number;\n    y: number;\n    gridX: number;\n    gridY: number;\n    isInGrid: boolean;\n    hasPointer: boolean;\n  }>;\n\n  let pointerState: PointerState = {\n    source: 'mouse',\n    x: 0,\n    y: 0,\n    gridX: 0,\n    gridY: 0,\n    isInGrid: false,\n    hasPointer: false,\n  };\n\n  // Interaction-x state (domain units). This drives chart sync.\n  let interactionX: number | null = null;\n  let interactionXSource: unknown = undefined;\n  const interactionXListeners = new Set<(x: number | null, source?: unknown) => void>();\n\n  // Cached interaction scales from the last render (used for pointer -> domain-x mapping).\n  let lastInteractionScales:\n    | {\n        readonly xScale: LinearScale;\n        readonly yScale: LinearScale;\n        readonly plotWidthCss: number;\n        readonly plotHeightCss: number;\n      }\n    | null = null;\n\n  const emitInteractionX = (nextX: number | null, source?: unknown): void => {\n    const snapshot = Array.from(interactionXListeners);\n    for (const cb of snapshot) cb(nextX, source);\n  };\n\n  const setInteractionXInternal = (nextX: number | null, source?: unknown): void => {\n    const normalized = nextX !== null && Number.isFinite(nextX) ? nextX : null;\n    if (interactionX === normalized && interactionXSource === source) return;\n    interactionX = normalized;\n    interactionXSource = source;\n    emitInteractionX(interactionX, interactionXSource);\n  };\n\n  const requestRender = (): void => {\n    callbacks?.onRequestRender?.();\n  };\n\n  const isFullSpanZoomRange = (range: ZoomRange | null): boolean => {\n    if (!range) return true;\n    return (\n      Number.isFinite(range.start) &&\n      Number.isFinite(range.end) &&\n      range.start <= 0 &&\n      range.end >= 100\n    );\n  };\n\n  const cancelScheduledFlush = (): void => {\n    if (flushRafId !== null) {\n      cancelAnimationFrame(flushRafId);\n      flushRafId = null;\n    }\n    if (flushTimeoutId !== null) {\n      clearTimeout(flushTimeoutId);\n      flushTimeoutId = null;\n    }\n    flushScheduled = false;\n  };\n\n  const cancelZoomResampleDebounce = (): void => {\n    if (zoomResampleDebounceTimer !== null) {\n      clearTimeout(zoomResampleDebounceTimer);\n      zoomResampleDebounceTimer = null;\n    }\n  };\n\n  const flushPendingAppends = (): boolean => {\n    if (pendingAppendByIndex.size === 0) return false;\n\n    appendedGpuThisFrame.clear();\n\n    const zoomRangeBefore = zoomState?.getRange() ?? null;\n    const isFullSpanZoomBefore = isFullSpanZoomRange(zoomRangeBefore);\n    const canAutoScroll =\n      currentOptions.autoScroll === true &&\n      zoomState != null &&\n      currentOptions.xAxis.min == null &&\n      currentOptions.xAxis.max == null;\n\n    // Capture the pre-append visible domain so we can preserve it for “panned away” behavior.\n    const prevBaseXDomain = computeBaseXDomain(currentOptions, runtimeRawBoundsByIndex);\n    const prevVisibleXDomain = zoomRangeBefore ? computeVisibleXDomain(prevBaseXDomain, zoomRangeBefore) : null;\n\n    let didAppendAny = false;\n\n    for (const [seriesIndex, points] of pendingAppendByIndex) {\n      if (points.length === 0) continue;\n      const s = currentOptions.series[seriesIndex];\n      if (!s || s.type === 'pie') continue;\n      didAppendAny = true;\n\n      if (s.type === 'candlestick') {\n        // Handle candlestick OHLC data.\n        let raw = runtimeRawDataByIndex[seriesIndex] as OHLCDataPoint[] | null;\n        if (!raw) {\n          const seed = (s.rawData ?? s.data) as ReadonlyArray<OHLCDataPoint>;\n          raw = seed.length === 0 ? [] : seed.slice();\n          runtimeRawDataByIndex[seriesIndex] = raw;\n          runtimeRawBoundsByIndex[seriesIndex] = s.rawBounds ?? null;\n        }\n\n        const ohlcPoints = points as unknown as ReadonlyArray<OHLCDataPoint>;\n        raw.push(...ohlcPoints);\n        runtimeRawBoundsByIndex[seriesIndex] = extendBoundsWithOHLCDataPoints(\n          runtimeRawBoundsByIndex[seriesIndex],\n          ohlcPoints\n        );\n      } else {\n        // Handle other cartesian series (line, area, bar, scatter).\n        let raw = runtimeRawDataByIndex[seriesIndex] as DataPoint[] | null;\n        if (!raw) {\n          const seed = (s.rawData ?? s.data) as CartesianSeriesData;\n          raw = cartesianDataToDataPointArray(seed);\n          runtimeRawDataByIndex[seriesIndex] = raw;\n          runtimeRawBoundsByIndex[seriesIndex] = s.rawBounds ?? computeRawBoundsFromCartesianData(seed);\n        }\n\n        const dataPoints = points as unknown as ReadonlyArray<DataPoint>;\n        \n        // Optional fast-path: if the GPU buffer currently represents the full, unsampled line series,\n        // we can append just the new points to the existing GPU buffer (no full re-upload).\n        const canUseFastPath =\n          s.type === 'line' && s.sampling === 'none' && isFullSpanZoomBefore && gpuSeriesKindByIndex[seriesIndex] === 'fullRawLine';\n\n        if (canUseFastPath) {\n          try {\n            dataStore.appendSeries(seriesIndex, dataPoints);\n            appendedGpuThisFrame.add(seriesIndex);\n          } catch {\n            // If the DataStore has not been initialized for this index (or any other error occurs),\n            // fall back to the normal full upload path later in render().\n          }\n        } else if (s.type === 'line' && s.sampling !== 'none' && !warnedSamplingDefeatsFastPath.has(seriesIndex)) {\n          // Warn users that sampling defeats the incremental append optimization\n          warnedSamplingDefeatsFastPath.add(seriesIndex);\n          console.warn(\n            `[ChartGPU] appendData() on series ${seriesIndex} with sampling='${s.sampling}' causes full buffer re-upload every frame. ` +\n              `For optimal streaming performance, use sampling='none'. ` +\n              `See docs/internal/INCREMENTAL_APPEND_OPTIMIZATION.md for details.`\n          );\n        }\n\n        raw.push(...dataPoints);\n        runtimeRawBoundsByIndex[seriesIndex] = extendBoundsWithDataPoints(\n          runtimeRawBoundsByIndex[seriesIndex],\n          dataPoints\n        );\n      }\n\n      // Invalidate cache for this series since data has changed\n      lastSampledData[seriesIndex] = null;\n    }\n\n    pendingAppendByIndex.clear();\n    if (!didAppendAny) return false;\n\n    // Dataset-aware zoom span constraints depend on raw point density.\n    // When streaming appends add points, recompute and apply constraints so wheel+slider remain consistent.\n    if (zoomState) {\n      const constraints = computeEffectiveZoomSpanConstraints();\n      const withConstraints = zoomState as unknown as {\n        setSpanConstraints?: (minSpan: number, maxSpan: number) => void;\n      };\n      withConstraints.setSpanConstraints?.(constraints.minSpan, constraints.maxSpan);\n    }\n\n    // Auto-scroll is applied only on append (not on `setOptions`).\n    if (canAutoScroll && zoomRangeBefore && prevVisibleXDomain) {\n      const r = zoomRangeBefore;\n      if (r.end >= 99.5) {\n        const span = r.end - r.start;\n        const anchored = zoomState! as unknown as {\n          setRangeAnchored?: (start: number, end: number, anchor: 'start' | 'end' | 'center') => void;\n        };\n        // Keep end pinned when constraints clamp the span.\n        if (anchored.setRangeAnchored) {\n          anchored.setRangeAnchored(100 - span, 100, 'end');\n        } else {\n          zoomState!.setRange(100 - span, 100);\n        }\n      } else {\n        const nextBaseXDomain = computeBaseXDomain(currentOptions, runtimeRawBoundsByIndex);\n        const span = nextBaseXDomain.max - nextBaseXDomain.min;\n        if (Number.isFinite(span) && span > 0) {\n          const nextStartRaw = ((prevVisibleXDomain.min - nextBaseXDomain.min) / span) * 100;\n          const nextEndRaw = ((prevVisibleXDomain.max - nextBaseXDomain.min) / span) * 100;\n          // Clamp defensively; ZoomState also clamps/orders internally.\n          const nextStart = Math.max(0, Math.min(100, nextStartRaw));\n          const nextEnd = Math.max(0, Math.min(100, nextEndRaw));\n          zoomState!.setRange(nextStart, nextEnd);\n        }\n      }\n    }\n\n    recomputeRuntimeBaseSeries();\n\n    // If zoom is disabled or full-span, `renderSeries` is just the baseline.\n    // (Zoom-visible resampling is handled by the unified flush when needed.)\n    const zoomRangeAfter = zoomState?.getRange() ?? null;\n    if (zoomRangeAfter == null || isFullSpanZoomRange(zoomRangeAfter)) {\n      renderSeries = runtimeBaseSeries;\n      // Recompute visible y-bounds from the baseline series\n      recomputeCachedVisibleYBoundsIfNeeded();\n    }\n\n    return true;\n  };\n\n  const executeFlush = (options?: { readonly requestRenderAfter?: boolean }): void => {\n    if (disposed) return;\n\n    const requestRenderAfter = options?.requestRenderAfter ?? true;\n\n    const didAppend = flushPendingAppends();\n\n    const zoomRange = zoomState?.getRange() ?? null;\n    const zoomIsFullSpan = isFullSpanZoomRange(zoomRange);\n    const zoomActiveNotFullSpan = zoomRange != null && !zoomIsFullSpan;\n\n    let didResample = false;\n\n    // Zoom changes (debounced): apply on flush.\n    if (zoomResampleDue) {\n      zoomResampleDue = false;\n      cancelZoomResampleDebounce();\n\n      if (!zoomRange || zoomIsFullSpan) {\n        renderSeries = runtimeBaseSeries;\n        // Recompute visible y-bounds from the baseline series\n        recomputeCachedVisibleYBoundsIfNeeded();\n      } else {\n        recomputeRenderSeries();\n      }\n      didResample = true;\n    } else if (didAppend && zoomActiveNotFullSpan) {\n      // Appends during an active zoom window require resampling the visible range.\n      // (Avoid doing this work when zoom is full-span or disabled.)\n      zoomResampleDue = false;\n      cancelZoomResampleDebounce();\n      recomputeRenderSeries();\n      didResample = true;\n    }\n\n    if ((didAppend || didResample) && requestRenderAfter) {\n      requestRender();\n    }\n  };\n\n  const scheduleFlush = (options?: { readonly immediate?: boolean }): void => {\n    if (disposed) return;\n    if (flushScheduled && !options?.immediate) return;\n\n    // Cancel any previous schedule so we coalesce to exactly one pending flush.\n    if (flushRafId !== null) {\n      cancelAnimationFrame(flushRafId);\n      flushRafId = null;\n    }\n    if (flushTimeoutId !== null) {\n      clearTimeout(flushTimeoutId);\n      flushTimeoutId = null;\n    }\n\n    flushScheduled = true;\n\n    flushRafId = requestAnimationFrame(() => {\n      flushRafId = null;\n      if (disposed) {\n        cancelScheduledFlush();\n        return;\n      }\n      // rAF fired first: cancel the fallback timeout.\n      if (flushTimeoutId !== null) {\n        clearTimeout(flushTimeoutId);\n        flushTimeoutId = null;\n      }\n      flushScheduled = false;\n      executeFlush();\n    });\n\n    // Fallback: ensure we flush even if rAF is delayed (high-frequency streams > 60Hz).\n    flushTimeoutId = (typeof self !== 'undefined' ? self : window).setTimeout(() => {\n      if (disposed) {\n        cancelScheduledFlush();\n        return;\n      }\n      if (!flushScheduled) return;\n\n      if (flushRafId !== null) {\n        cancelAnimationFrame(flushRafId);\n        flushRafId = null;\n      }\n      flushScheduled = false;\n      flushTimeoutId = null;\n      executeFlush();\n    }, 16);\n  };\n\n  const scheduleZoomResample = (): void => {\n    if (disposed) return;\n\n    cancelZoomResampleDebounce();\n    zoomResampleDue = false;\n\n    zoomResampleDebounceTimer = (typeof self !== 'undefined' ? self : window).setTimeout(() => {\n      zoomResampleDebounceTimer = null;\n      if (disposed) return;\n      zoomResampleDue = true;\n      scheduleFlush();\n    }, 100);\n  };\n\n  const getPlotSizeCssPx = (\n    canvas: HTMLCanvasElement,\n    gridArea: GridArea\n  ): { readonly plotWidthCss: number; readonly plotHeightCss: number } | null => {\n    let canvasWidthCss: number;\n    let canvasHeightCss: number;\n\n\n    // HTMLCanvasElement: use getBoundingClientRect() for actual CSS dimensions\n    const rect = canvas.getBoundingClientRect();\n    if (!(rect.width > 0) || !(rect.height > 0)) return null;\n    canvasWidthCss = rect.width;\n    canvasHeightCss = rect.height;\n\n    const plotWidthCss = canvasWidthCss - gridArea.left - gridArea.right;\n    const plotHeightCss = canvasHeightCss - gridArea.top - gridArea.bottom;\n    if (!(plotWidthCss > 0) || !(plotHeightCss > 0)) return null;\n\n    return { plotWidthCss, plotHeightCss };\n  };\n\n  const computeInteractionScalesGridCssPx = (\n    gridArea: GridArea,\n    domains: { readonly xDomain: { readonly min: number; readonly max: number }; readonly yDomain: { readonly min: number; readonly max: number } }\n  ):\n    | {\n        readonly xScale: LinearScale;\n        readonly yScale: LinearScale;\n        readonly plotWidthCss: number;\n        readonly plotHeightCss: number;\n      }\n    | null => {\n    const canvas = gpuContext.canvas;\n    if (!canvas) return null;\n\n    const plotSize = getPlotSizeCssPx(canvas, gridArea);\n    if (!plotSize) return null;\n\n    // IMPORTANT: grid-local CSS px ranges (0..plotWidth/Height), for interaction hit-testing.\n    const xScale = createLinearScale().domain(domains.xDomain.min, domains.xDomain.max).range(0, plotSize.plotWidthCss);\n    const yScale = createLinearScale().domain(domains.yDomain.min, domains.yDomain.max).range(plotSize.plotHeightCss, 0);\n\n    const result = { xScale, yScale, plotWidthCss: plotSize.plotWidthCss, plotHeightCss: plotSize.plotHeightCss };\n\n    return result;\n  };\n\n  const buildTooltipParams = (seriesIndex: number, dataIndex: number, point: DataPoint): TooltipParams => {\n    const s = currentOptions.series[seriesIndex];\n    const { x, y } = getPointXY(point);\n    return {\n      seriesName: s?.name ?? '',\n      seriesIndex,\n      dataIndex,\n      value: [x, y],\n      color: s?.color ?? '#888',\n    };\n  };\n\n  const buildCandlestickTooltipParams = (\n    seriesIndex: number,\n    dataIndex: number,\n    point: OHLCDataPoint\n  ): TooltipParams => {\n    const s = currentOptions.series[seriesIndex];\n    if (isTupleOHLCDataPoint(point)) {\n      return {\n        seriesName: s?.name ?? '',\n        seriesIndex,\n        dataIndex,\n        value: [point[0], point[1], point[2], point[3], point[4]] as const,\n        color: s?.color ?? '#888',\n      };\n    } else {\n      return {\n        seriesName: s?.name ?? '',\n        seriesIndex,\n        dataIndex,\n        value: [point.timestamp, point.open, point.close, point.low, point.high] as const,\n        color: s?.color ?? '#888',\n      };\n    }\n  };\n\n  // Helper: Find pie slice at pointer position (extracted to avoid duplication)\n  const findPieSliceAtPointer = (\n    series: ResolvedChartGPUOptions['series'],\n    gridX: number,\n    gridY: number,\n    plotWidthCss: number,\n    plotHeightCss: number\n  ): ReturnType<typeof findPieSlice> | null => {\n    const maxRadiusCss = 0.5 * Math.min(plotWidthCss, plotHeightCss);\n    if (!(maxRadiusCss > 0)) return null;\n\n    // Iterate from last to first for correct z-ordering (last series drawn on top)\n    for (let i = series.length - 1; i >= 0; i--) {\n      const s = series[i];\n      if (s.type !== 'pie') continue;\n      // Skip invisible series (pie hit-testing should respect visibility)\n      if (s.visible === false) continue;\n      const pieSeries = s as ResolvedPieSeriesConfig;\n      const center = resolvePieCenterPlotCss(pieSeries.center, plotWidthCss, plotHeightCss);\n      const radii = resolvePieRadiiCss(pieSeries.radius, maxRadiusCss);\n      const m = findPieSlice(gridX, gridY, { seriesIndex: i, series: pieSeries }, center, radii);\n      if (m) return m;\n    }\n    return null;\n  };\n\n  // Helper: Find candlestick match at pointer position (hoisted to avoid closure allocation)\n  const findCandlestickAtPointer = (\n    series: ResolvedChartGPUOptions['series'],\n    gridX: number,\n    gridY: number,\n    interactionScales: NonNullable<ReturnType<typeof computeInteractionScalesGridCssPx>>\n  ): { params: TooltipParams; match: { point: OHLCDataPoint }; seriesIndex: number } | null => {\n    // Iterate from last to first for correct z-ordering (last series drawn on top)\n    for (let i = series.length - 1; i >= 0; i--) {\n      const s = series[i];\n      if (s.type !== 'candlestick') continue;\n      // Skip invisible series (candlestick hit-testing should respect visibility)\n      if (s.visible === false) continue;\n\n      const cs = s as ResolvedCandlestickSeriesConfig;\n      const barWidthClip = computeCandlestickBodyWidthRange(\n        cs,\n        cs.data,\n        interactionScales.xScale,\n        interactionScales.plotWidthCss\n      );\n\n      const m = findCandlestick(\n        [cs],\n        gridX,\n        gridY,\n        interactionScales.xScale,\n        interactionScales.yScale,\n        barWidthClip\n      );\n      if (!m) continue;\n\n      const params = buildCandlestickTooltipParams(i, m.dataIndex, m.point);\n      return { params, match: { point: m.point }, seriesIndex: i };\n    }\n    return null;\n  };\n\n  const onMouseMove = (payload: ChartGPUEventPayload): void => {\n    pointerState = {\n      source: 'mouse',\n      x: payload.x,\n      y: payload.y,\n      gridX: payload.gridX,\n      gridY: payload.gridY,\n      isInGrid: payload.isInGrid,\n      hasPointer: true,\n    };\n\n    // If we're over the plot and we have recent interaction scales, update interaction-x in domain units.\n    // (Best-effort; render() refreshes scales and overlays.)\n    if (payload.isInGrid && lastInteractionScales) {\n      const xDomain = lastInteractionScales.xScale.invert(payload.gridX);\n      setInteractionXInternal(Number.isFinite(xDomain) ? xDomain : null, 'mouse');\n    } else if (!payload.isInGrid) {\n      // Clear interaction-x when leaving the plot area (keeps synced charts from “sticking”).\n      setInteractionXInternal(null, 'mouse');\n    }\n\n    crosshairRenderer.setVisible(payload.isInGrid);\n    requestRender();\n  };\n\n  const onMouseLeave = (_payload: ChartGPUEventPayload): void => {\n    // Only clear interaction overlays for real pointer interaction.\n    // If we're being driven by a sync-x, leaving the canvas shouldn't hide the overlays.\n    if (pointerState.source !== 'mouse') return;\n\n    pointerState = { ...pointerState, isInGrid: false, hasPointer: false };\n    crosshairRenderer.setVisible(false);\n    hideTooltip();\n    setInteractionXInternal(null, 'mouse');\n    requestRender();\n  };\n\n  // Register event listeners only if event manager is available (HTMLCanvasElement).\n  if (eventManager) {\n    eventManager.on('mousemove', onMouseMove);\n    eventManager.on('mouseleave', onMouseLeave);\n  }\n\n  // Optional internal “inside zoom” (wheel zoom + drag pan).\n  let zoomState: ZoomState | null = null;\n  let insideZoom: ReturnType<typeof createInsideZoom> | null = null;\n  let unsubscribeZoom: (() => void) | null = null;\n  let lastOptionsZoomRange: Readonly<{ start: number; end: number }> | null = null;\n  const zoomRangeListeners = new Set<(range: Readonly<{ start: number; end: number }>) => void>();\n\n  const emitZoomRange = (range: Readonly<{ start: number; end: number }>): void => {\n    const snapshot = Array.from(zoomRangeListeners);\n    for (const cb of snapshot) cb(range);\n  };\n\n  const getZoomOptionsConfig = (\n    opts: ResolvedChartGPUOptions\n  ): { readonly start: number; readonly end: number; readonly hasInside: boolean } | null => {\n    // Zoom is enabled when *either* inside or slider exists. A single shared percent-space\n    // window is used for both.\n    const insideCfg = opts.dataZoom?.find((z) => z?.type === 'inside');\n    const sliderCfg = opts.dataZoom?.find((z) => z?.type === 'slider');\n    const cfg = insideCfg ?? sliderCfg;\n    if (!cfg) return null;\n    const start = Number.isFinite(cfg.start) ? cfg.start! : 0;\n    const end = Number.isFinite(cfg.end) ? cfg.end! : 100;\n    return { start, end, hasInside: !!insideCfg };\n  };\n\n  const clampPercent = (v: number): number => Math.min(100, Math.max(0, v));\n\n  const getZoomSpanConstraintsFromOptions = (\n    opts: ResolvedChartGPUOptions\n  ): { readonly minSpan?: number; readonly maxSpan?: number } => {\n    let minSpan: number | null = null;\n    let maxSpan: number | null = null;\n\n    const list = opts.dataZoom ?? [];\n    for (const z of list) {\n      if (!z) continue;\n      if (z.type !== 'inside' && z.type !== 'slider') continue;\n\n      if (Number.isFinite(z.minSpan as number)) {\n        const v = clampPercent(z.minSpan as number);\n        minSpan = minSpan == null ? v : Math.max(minSpan, v);\n      }\n      if (Number.isFinite(z.maxSpan as number)) {\n        const v = clampPercent(z.maxSpan as number);\n        maxSpan = maxSpan == null ? v : Math.min(maxSpan, v);\n      }\n    }\n\n    return { minSpan: minSpan ?? undefined, maxSpan: maxSpan ?? undefined };\n  };\n\n  const computeDatasetAwareDefaultMinSpan = (): number | null => {\n    // Dataset-aware defaults only apply to numeric/time x domains (category is discrete UI-driven).\n    if (currentOptions.xAxis.type === 'category') return null;\n\n    let maxPoints = 0;\n    for (let i = 0; i < currentOptions.series.length; i++) {\n      const s = currentOptions.series[i]!;\n      if (s.type === 'pie') continue;\n      if (s.type === 'candlestick') {\n        const raw =\n          (runtimeRawDataByIndex[i] as ReadonlyArray<OHLCDataPoint> | null) ??\n          ((s.rawData ?? s.data) as ReadonlyArray<OHLCDataPoint>);\n        maxPoints = Math.max(maxPoints, raw.length);\n        continue;\n      }\n\n      const raw =\n        (runtimeRawDataByIndex[i] as DataPoint[] | null) ??\n        cartesianDataToDataPointArray((s.rawData ?? s.data) as CartesianSeriesData);\n      maxPoints = Math.max(maxPoints, raw.length);\n    }\n\n    if (maxPoints < 2) return null;\n    const v = 100 / (maxPoints - 1);\n    return Number.isFinite(v) ? clampPercent(v) : null;\n  };\n\n  const computeEffectiveZoomSpanConstraints = (): { readonly minSpan: number; readonly maxSpan: number } => {\n    const fromOptions = getZoomSpanConstraintsFromOptions(currentOptions);\n    const datasetMin = computeDatasetAwareDefaultMinSpan();\n\n    // Preserve legacy behavior when no constraints (and no dataset signal) are available.\n    // The coordinator will typically override this with datasetMin when the data supports it.\n    const minSpan = Number.isFinite(fromOptions.minSpan as number)\n      ? clampPercent(fromOptions.minSpan as number)\n      : datasetMin ?? 0.5;\n    const maxSpan = Number.isFinite(fromOptions.maxSpan as number)\n      ? clampPercent(fromOptions.maxSpan as number)\n      : 100;\n\n    return { minSpan, maxSpan };\n  };\n\n  const updateZoom = (): void => {\n    const cfg = getZoomOptionsConfig(currentOptions);\n\n    if (!cfg) {\n      insideZoom?.dispose();\n      insideZoom = null;\n      unsubscribeZoom?.();\n      unsubscribeZoom = null;\n      zoomState = null;\n      lastOptionsZoomRange = null;\n      return;\n    }\n\n    if (!zoomState) {\n      const constraints = computeEffectiveZoomSpanConstraints();\n      zoomState = createZoomState(cfg.start, cfg.end, constraints);\n      lastOptionsZoomRange = { start: cfg.start, end: cfg.end };\n      unsubscribeZoom = zoomState.onChange((range) => {\n        // Coalesce slicing (and visible-bounds recompute) to at most once per rendered frame.\n        sliceRenderSeriesDue = true;\n        // Immediate render for UI feedback (axes/crosshair/slider).\n        requestRender();\n        // Debounce resampling; the unified flush will do the work.\n        scheduleZoomResample();\n        // Ensure listeners get a stable readonly object.\n        emitZoomRange({ start: range.start, end: range.end });\n      });\n    } else {\n      const constraints = computeEffectiveZoomSpanConstraints();\n      const withConstraints = zoomState as unknown as {\n        setSpanConstraints?: (minSpan: number, maxSpan: number) => void;\n      };\n      withConstraints.setSpanConstraints?.(constraints.minSpan, constraints.maxSpan);\n\n      if (\n        lastOptionsZoomRange == null ||\n        lastOptionsZoomRange.start !== cfg.start ||\n        lastOptionsZoomRange.end !== cfg.end\n      ) {\n        // Only apply option-provided start/end when:\n        // - zoom is first created, or\n        // - start/end actually changed in options\n        zoomState.setRange(cfg.start, cfg.end);\n        lastOptionsZoomRange = { start: cfg.start, end: cfg.end };\n      }\n    }\n\n    // Only enable inside zoom handler when `{ type: 'inside' }` exists.\n    // Requires event manager (HTMLCanvasElement only).\n    if (cfg.hasInside && eventManager) {\n      if (!insideZoom) {\n        insideZoom = createInsideZoom(eventManager, zoomState);\n        insideZoom.enable();\n      }\n    } else {\n      insideZoom?.dispose();\n      insideZoom = null;\n    }\n  };\n\n  const initRuntimeSeriesFromOptions = (): void => {\n    const count = currentOptions.series.length;\n    runtimeRawDataByIndex = new Array(count).fill(null);\n    runtimeRawBoundsByIndex = new Array(count).fill(null);\n    pendingAppendByIndex.clear();\n\n    for (let i = 0; i < count; i++) {\n      const s = currentOptions.series[i]!;\n      if (s.type === 'pie') continue;\n\n      if (s.type === 'candlestick') {\n        // Store candlestick raw OHLC data (not for streaming append, but for zoom-aware resampling).\n        const rawOHLC = (s.rawData ?? s.data) as ReadonlyArray<OHLCDataPoint>;\n        const owned = rawOHLC.length === 0 ? [] : rawOHLC.slice();\n        runtimeRawDataByIndex[i] = owned;\n        runtimeRawBoundsByIndex[i] = s.rawBounds ?? null;\n        continue;\n      }\n\n      const raw = (s.rawData ?? s.data) as CartesianSeriesData;\n      // Coordinator-owned: convert to mutable DataPoint[] array (streaming appends mutate this).\n      const owned = cartesianDataToDataPointArray(raw);\n      runtimeRawDataByIndex[i] = owned;\n      runtimeRawBoundsByIndex[i] = s.rawBounds ?? computeRawBoundsFromCartesianData(raw);\n    }\n  };\n\n  const recomputeRuntimeBaseSeries = (): void => {\n    const next: ResolvedChartGPUOptions['series'][number][] = new Array(currentOptions.series.length);\n    for (let i = 0; i < currentOptions.series.length; i++) {\n      const s = currentOptions.series[i]!;\n      if (s.type === 'pie') {\n        next[i] = s;\n        continue;\n      }\n\n      if (s.type === 'candlestick') {\n        const rawOHLC =\n          (runtimeRawDataByIndex[i] as ReadonlyArray<OHLCDataPoint> | null) ??\n          ((s.rawData ?? s.data) as ReadonlyArray<OHLCDataPoint>);\n        const bounds = runtimeRawBoundsByIndex[i] ?? s.rawBounds ?? undefined;\n        const baselineSampled = s.sampling === 'ohlc' && rawOHLC.length > s.samplingThreshold\n          ? ohlcSample(rawOHLC, s.samplingThreshold)\n          : rawOHLC;\n        next[i] = { ...s, rawData: rawOHLC, rawBounds: bounds, data: baselineSampled };\n        continue;\n      }\n\n      const raw =\n        (runtimeRawDataByIndex[i] as DataPoint[] | null) ?? \n        cartesianDataToDataPointArray((s.rawData ?? s.data) as CartesianSeriesData);\n      const bounds = runtimeRawBoundsByIndex[i] ?? s.rawBounds ?? undefined;\n      const baselineSampled = sampleSeriesDataPoints(raw, s.sampling, s.samplingThreshold);\n      next[i] = { ...s, rawData: raw, rawBounds: bounds, data: baselineSampled };\n    }\n    runtimeBaseSeries = next;\n  };\n\n  function sliceRenderSeriesToVisibleRange(): void {\n    const zoomRange = zoomState?.getRange() ?? null;\n    const baseXDomain = computeBaseXDomain(currentOptions, runtimeRawBoundsByIndex);\n    const visibleX = computeVisibleXDomain(baseXDomain, zoomRange);\n\n    // Fast path: no zoom or full span - use baseline directly\n    const isFullSpan =\n      zoomRange == null ||\n      (Number.isFinite(zoomRange.start) &&\n        Number.isFinite(zoomRange.end) &&\n        zoomRange.start <= 0 &&\n        zoomRange.end >= 100);\n    \n    if (isFullSpan) {\n      renderSeries = runtimeBaseSeries;\n      // Recompute visible y-bounds from the full baseline series\n      recomputeCachedVisibleYBoundsIfNeeded();\n      return;\n    }\n\n    const next: ResolvedChartGPUOptions['series'][number][] = new Array(runtimeBaseSeries.length);\n\n    for (let i = 0; i < runtimeBaseSeries.length; i++) {\n      const baseline = runtimeBaseSeries[i]!;\n      \n      // Pie charts don't need slicing\n      if (baseline.type === 'pie') {\n        next[i] = baseline;\n        continue;\n      }\n\n      const cache = lastSampledData[i];\n      \n      // Strategy 1: Use cache if it covers visible range\n      if (cache && \n          visibleX.min >= cache.cachedRange.min && \n          visibleX.max <= cache.cachedRange.max) {\n        \n        if (baseline.type === 'candlestick') {\n          next[i] = {\n            ...baseline,\n            data: sliceVisibleRangeByOHLC(cache.data as ReadonlyArray<OHLCDataPoint>, visibleX.min, visibleX.max)\n          };\n        } else {\n          next[i] = {\n            ...baseline,\n            data: sliceVisibleRangeByX(cache.data as CartesianSeriesData, visibleX.min, visibleX.max)\n          };\n        }\n        continue;\n      }\n      \n      // Strategy 2: Fallback to baseline sampled data\n      if (baseline.type === 'candlestick') {\n        next[i] = {\n          ...baseline,\n          data: sliceVisibleRangeByOHLC(baseline.data as ReadonlyArray<OHLCDataPoint>, visibleX.min, visibleX.max)\n        };\n      } else {\n        next[i] = {\n          ...baseline,\n          data: sliceVisibleRangeByX(baseline.data as CartesianSeriesData, visibleX.min, visibleX.max)\n        };\n      }\n    }\n\n    renderSeries = next;\n    // Recompute visible y-bounds from the sliced renderSeries\n    recomputeCachedVisibleYBoundsIfNeeded();\n  }\n\n  function recomputeRenderSeries(): void {\n    const zoomRange = zoomState?.getRange() ?? null;\n    const baseXDomain = computeBaseXDomain(currentOptions, runtimeRawBoundsByIndex);\n    const visibleX = computeVisibleXDomain(baseXDomain, zoomRange);\n\n    // Add buffer zone (±10% beyond visible range) for caching\n    const bufferFactor = 0.1;\n    const visibleSpan = visibleX.max - visibleX.min;\n    const bufferSize = visibleSpan * bufferFactor;\n    const bufferedMin = visibleX.min - bufferSize;\n    const bufferedMax = visibleX.max + bufferSize;\n\n    // Sampling scale behavior:\n    // - Use `samplingThreshold` as baseline at full span.\n    // - As zoom span shrinks, raise the threshold so fewer points are dropped (more detail).\n    // - Clamp to avoid huge allocations / pathological thresholds.\n    const MIN_TARGET_POINTS = 2;\n    const MAX_TARGET_POINTS_ABS = 200_000;\n    const MAX_TARGET_MULTIPLIER = 32;\n    const spanFracSafe = Math.max(1e-3, Math.min(1, visibleX.spanFraction));\n\n    const next: ResolvedChartGPUOptions['series'][number][] = new Array(runtimeBaseSeries.length);\n\n    for (let i = 0; i < runtimeBaseSeries.length; i++) {\n      const s = runtimeBaseSeries[i]!;\n\n      if (s.type === 'pie') {\n        next[i] = s;\n        continue;\n      }\n\n      // Fast path: no zoom window / full span. Use baseline resolved `data` (already sampled by resolver).\n      const isFullSpan =\n        zoomRange == null ||\n        (Number.isFinite(zoomRange.start) &&\n          Number.isFinite(zoomRange.end) &&\n          zoomRange.start <= 0 &&\n          zoomRange.end >= 100);\n      if (isFullSpan) {\n        next[i] = s;\n        continue;\n      }\n\n      // Candlestick series: OHLC-specific slicing + sampling.\n      if (s.type === 'candlestick') {\n        const rawOHLC =\n          (runtimeRawDataByIndex[i] as ReadonlyArray<OHLCDataPoint> | null) ??\n          ((s.rawData ?? s.data) as ReadonlyArray<OHLCDataPoint>);\n        // Slice to buffered range for sampling\n        const bufferedOHLC = sliceVisibleRangeByOHLC(rawOHLC, bufferedMin, bufferedMax);\n\n        const sampling = s.sampling;\n        const baseThreshold = s.samplingThreshold;\n\n        const baseT = Number.isFinite(baseThreshold) ? Math.max(1, baseThreshold | 0) : 1;\n        const maxTarget = Math.min(MAX_TARGET_POINTS_ABS, Math.max(MIN_TARGET_POINTS, baseT * MAX_TARGET_MULTIPLIER));\n        const target = clampInt(Math.round(baseT / spanFracSafe), MIN_TARGET_POINTS, maxTarget);\n\n        const sampled = sampling === 'ohlc' && bufferedOHLC.length > target\n          ? ohlcSample(bufferedOHLC, target)\n          : bufferedOHLC;\n\n        // Store sampled data in cache with buffered range\n        lastSampledData[i] = {\n          data: sampled as unknown as ReadonlyArray<DataPoint>,\n          cachedRange: { min: bufferedMin, max: bufferedMax },\n          timestamp: Date.now()\n        };\n\n        // Slice to actual visible range for renderSeries\n        const visibleSampled = sliceVisibleRangeByOHLC(sampled, visibleX.min, visibleX.max);\n        next[i] = { ...s, data: visibleSampled };\n        continue;\n      }\n\n      // Cartesian series (line, area, bar, scatter).\n      const rawData =\n        (runtimeRawDataByIndex[i] as DataPoint[] | null) ?? \n        cartesianDataToDataPointArray((s.rawData ?? s.data) as CartesianSeriesData);\n      // Slice to buffered range for sampling\n      const bufferedRaw = sliceVisibleRangeByX(rawData, bufferedMin, bufferedMax);\n\n      const sampling = s.sampling;\n      const baseThreshold = s.samplingThreshold;\n\n      const baseT = Number.isFinite(baseThreshold) ? Math.max(1, baseThreshold | 0) : 1;\n      const maxTarget = Math.min(MAX_TARGET_POINTS_ABS, Math.max(MIN_TARGET_POINTS, baseT * MAX_TARGET_MULTIPLIER));\n      const target = clampInt(Math.round(baseT / spanFracSafe), MIN_TARGET_POINTS, maxTarget);\n\n      const sampled = sampleSeriesDataPoints(bufferedRaw as CartesianSeriesData, sampling, target);\n\n      // Store sampled data in cache with buffered range\n      lastSampledData[i] = {\n        data: sampled as unknown as ReadonlyArray<DataPoint>,\n        cachedRange: { min: bufferedMin, max: bufferedMax },\n        timestamp: Date.now()\n      };\n\n      // Slice to actual visible range for renderSeries\n      const visibleSampled = sliceVisibleRangeByX(sampled as CartesianSeriesData, visibleX.min, visibleX.max);\n      next[i] = { ...s, data: visibleSampled };\n    }\n\n    renderSeries = next;\n    // Recompute visible y-bounds from the updated renderSeries\n    recomputeCachedVisibleYBoundsIfNeeded();\n  }\n\n  initRuntimeSeriesFromOptions();\n  recomputeRuntimeBaseSeries();\n  updateZoom();\n  recomputeRenderSeries();\n  lastSampledData = new Array(currentOptions.series.length).fill(null);\n\n  const areaRenderers: Array<ReturnType<typeof createAreaRenderer>> = [];\n  const lineRenderers: Array<ReturnType<typeof createLineRenderer>> = [];\n  const scatterRenderers: Array<ReturnType<typeof createScatterRenderer>> = [];\n  const scatterDensityRenderers: Array<ReturnType<typeof createScatterDensityRenderer>> = [];\n  const pieRenderers: Array<ReturnType<typeof createPieRenderer>> = [];\n  const candlestickRenderers: Array<ReturnType<typeof createCandlestickRenderer>> = [];\n  const barRenderer = createBarRenderer(device, { targetFormat });\n\n  const ensureAreaRendererCount = (count: number): void => {\n    while (areaRenderers.length > count) {\n      const r = areaRenderers.pop();\n      r?.dispose();\n    }\n    while (areaRenderers.length < count) {\n      areaRenderers.push(createAreaRenderer(device, { targetFormat }));\n    }\n  };\n\n  const ensureLineRendererCount = (count: number): void => {\n    while (lineRenderers.length > count) {\n      const r = lineRenderers.pop();\n      r?.dispose();\n    }\n    while (lineRenderers.length < count) {\n      lineRenderers.push(createLineRenderer(device, { targetFormat }));\n    }\n  };\n\n  const ensureScatterRendererCount = (count: number): void => {\n    while (scatterRenderers.length > count) {\n      const r = scatterRenderers.pop();\n      r?.dispose();\n    }\n    while (scatterRenderers.length < count) {\n      scatterRenderers.push(createScatterRenderer(device, { targetFormat }));\n    }\n  };\n\n  const ensureScatterDensityRendererCount = (count: number): void => {\n    while (scatterDensityRenderers.length > count) {\n      const r = scatterDensityRenderers.pop();\n      r?.dispose();\n    }\n    while (scatterDensityRenderers.length < count) {\n      scatterDensityRenderers.push(createScatterDensityRenderer(device, { targetFormat }));\n    }\n  };\n\n  const ensurePieRendererCount = (count: number): void => {\n    while (pieRenderers.length > count) {\n      const r = pieRenderers.pop();\n      r?.dispose();\n    }\n    while (pieRenderers.length < count) {\n      pieRenderers.push(createPieRenderer(device, { targetFormat }));\n    }\n  };\n\n  const ensureCandlestickRendererCount = (count: number): void => {\n    while (candlestickRenderers.length > count) {\n      const r = candlestickRenderers.pop();\n      r?.dispose();\n    }\n    while (candlestickRenderers.length < count) {\n      candlestickRenderers.push(createCandlestickRenderer(device, { targetFormat }));\n    }\n  };\n\n  ensureAreaRendererCount(currentOptions.series.length);\n  ensureLineRendererCount(currentOptions.series.length);\n  ensureScatterRendererCount(currentOptions.series.length);\n  ensureScatterDensityRendererCount(currentOptions.series.length);\n  ensurePieRendererCount(currentOptions.series.length);\n  ensureCandlestickRendererCount(currentOptions.series.length);\n\n  const assertNotDisposed = (): void => {\n    if (disposed) throw new Error('RenderCoordinator is disposed.');\n  };\n\n  const cancelUpdateTransition = (): void => {\n    if (updateAnimId) {\n      try {\n        updateAnimController.cancel(updateAnimId);\n      } catch {\n        // best-effort\n      }\n    }\n    updateAnimId = null;\n    updateProgress01 = 1;\n    updateTransition = null;\n    resetUpdateInterpolationCaches();\n  };\n\n  const isDomainEqual = (a: { readonly min: number; readonly max: number }, b: { readonly min: number; readonly max: number }): boolean =>\n    a.min === b.min && a.max === b.max;\n\n  const didSeriesDataLikelyChange = (\n    prev: ResolvedChartGPUOptions['series'],\n    next: ResolvedChartGPUOptions['series']\n  ): boolean => {\n    if (prev.length !== next.length) return true;\n    for (let i = 0; i < prev.length; i++) {\n      const a = prev[i]!;\n      const b = next[i]!;\n      if (a.type !== b.type) return true;\n\n      // Prefer cheap reference checks (good enough for eligibility gating).\n      if (a.type === 'pie') {\n        const aPie = a as ResolvedPieSeriesConfig;\n        const bPie = b as ResolvedPieSeriesConfig;\n        if (aPie.data !== bPie.data) return true;\n        if (aPie.data.length !== bPie.data.length) return true;\n      } else {\n        const aAny = a as unknown as { readonly rawData?: ReadonlyArray<DataPoint>; readonly data: ReadonlyArray<DataPoint> };\n        const bAny = b as unknown as { readonly rawData?: ReadonlyArray<DataPoint>; readonly data: ReadonlyArray<DataPoint> };\n        const aRaw = (aAny.rawData ?? aAny.data) as ReadonlyArray<DataPoint>;\n        const bRaw = (bAny.rawData ?? bAny.data) as ReadonlyArray<DataPoint>;\n        if (aRaw !== bRaw) return true;\n        if (aRaw.length !== bRaw.length) return true;\n      }\n    }\n    return false;\n  };\n\n  /**\n   * Checks if only series visibility changed (no data, type, or structural changes).\n   * Used to avoid starting update animations during simple visibility toggles.\n   */\n  const didOnlyVisibilityChange = (\n    prev: ResolvedChartGPUOptions['series'],\n    next: ResolvedChartGPUOptions['series']\n  ): boolean => {\n    if (prev.length !== next.length) return false;\n\n    let hasVisibilityChange = false;\n    for (let i = 0; i < prev.length; i++) {\n      const a = prev[i]!;\n      const b = next[i]!;\n\n      // Check if anything other than visibility changed\n      if (a.type !== b.type) return false;\n\n      if (a.type === 'pie') {\n        const aPie = a as ResolvedPieSeriesConfig;\n        const bPie = b as ResolvedPieSeriesConfig;\n\n        // For pie charts, check if data arrays have the same length\n        if (aPie.data.length !== bPie.data.length) return false;\n\n        // Check each slice to ensure only visibility changed\n        for (let j = 0; j < aPie.data.length; j++) {\n          const sliceA = aPie.data[j];\n          const sliceB = bPie.data[j];\n\n          // If both slices are undefined/null, continue\n          if (!sliceA && !sliceB) continue;\n          if (!sliceA || !sliceB) return false;\n\n          // Check if anything other than visibility changed in this slice\n          if (sliceA.name !== sliceB.name) return false;\n          if (sliceA.value !== sliceB.value) return false;\n          if (sliceA.color !== sliceB.color) return false;\n\n          // Check if visibility changed\n          const aSliceVisible = sliceA.visible !== false;\n          const bSliceVisible = sliceB.visible !== false;\n          if (aSliceVisible !== bSliceVisible) {\n            hasVisibilityChange = true;\n          }\n        }\n      } else {\n        const aAny = a as unknown as { readonly rawData?: ReadonlyArray<DataPoint>; readonly data: ReadonlyArray<DataPoint> };\n        const bAny = b as unknown as { readonly rawData?: ReadonlyArray<DataPoint>; readonly data: ReadonlyArray<DataPoint> };\n        const aRaw = (aAny.rawData ?? aAny.data) as ReadonlyArray<DataPoint>;\n        const bRaw = (bAny.rawData ?? bAny.data) as ReadonlyArray<DataPoint>;\n        if (aRaw !== bRaw) return false;\n        if (aRaw.length !== bRaw.length) return false;\n      }\n\n      // Check if visibility actually changed for this series\n      const aVisible = a.visible !== false;\n      const bVisible = b.visible !== false;\n      if (aVisible !== bVisible) {\n        hasVisibilityChange = true;\n      }\n    }\n\n    return hasVisibilityChange;\n  };\n\n  const setOptions: RenderCoordinator['setOptions'] = (resolvedOptions) => {\n    assertNotDisposed();\n\n    // Capture \"from\" snapshot BEFORE overwriting coordinator state.\n    const fromZoomRange = zoomState?.getRange() ?? null;\n    const fromSnapshot: UpdateTransitionSnapshot = (() => {\n      // Requirement (mid-flight updates): if a transition is running, rebase from the current blended state.\n      if (updateTransition && updateAnimId) {\n        try {\n          updateAnimController.update(performance.now());\n        } catch {\n          // best-effort\n        }\n        return computeUpdateSnapshotAtProgress(updateTransition, updateProgress01, fromZoomRange);\n      }\n\n      const fromXBase = computeBaseXDomain(currentOptions, runtimeRawBoundsByIndex);\n      const fromXVisible = computeVisibleXDomain(fromXBase, fromZoomRange);\n      const fromYBase = computeBaseYDomain(currentOptions, runtimeRawBoundsByIndex, cachedVisibleYBounds);\n      return {\n        xBaseDomain: fromXBase,\n        xVisibleDomain: { min: fromXVisible.min, max: fromXVisible.max },\n        yBaseDomain: fromYBase,\n        series: renderSeries,\n      };\n    })();\n\n    // Cancel any prior update transition AFTER capturing the rebased \"from\" snapshot.\n    cancelUpdateTransition();\n    const likelyDataChanged = didSeriesDataLikelyChange(currentOptions.series, resolvedOptions.series);\n    const onlyVisibilityChanged = didOnlyVisibilityChange(currentOptions.series, resolvedOptions.series);\n\n    currentOptions = resolvedOptions;\n    runtimeBaseSeries = resolvedOptions.series;\n    renderSeries = resolvedOptions.series;\n    // Recompute visible y-bounds from the new series\n    cachedVisibleYBounds = null;\n    gpuSeriesKindByIndex = new Array(resolvedOptions.series.length).fill('unknown');\n    lastSampledData = new Array(resolvedOptions.series.length).fill(null);\n    legend?.update(resolvedOptions.series, resolvedOptions.theme);\n    cancelZoomResampleDebounce();\n    zoomResampleDue = false;\n    cancelScheduledFlush();\n    initRuntimeSeriesFromOptions();\n    recomputeRuntimeBaseSeries();\n    updateZoom();\n    recomputeRenderSeries();\n\n    // Tooltip enablement may change at runtime.\n    if (overlayContainer) {\n      const shouldHaveTooltip = currentOptions.tooltip?.show !== false;\n      if (shouldHaveTooltip && !tooltip) {\n        tooltip = createTooltip(overlayContainer);\n        lastTooltipContent = null;\n        lastTooltipX = null;\n        lastTooltipY = null;\n      }\n      if (!shouldHaveTooltip && tooltip) {\n        hideTooltip();\n      }\n        } else {\n          hideTooltip();\n        }\n\n    const nextCount = resolvedOptions.series.length;\n    ensureAreaRendererCount(nextCount);\n    ensureLineRendererCount(nextCount);\n    ensureScatterRendererCount(nextCount);\n    ensureScatterDensityRendererCount(nextCount);\n    ensurePieRendererCount(nextCount);\n    ensureCandlestickRendererCount(nextCount);\n\n    // When the series count shrinks, explicitly destroy per-index GPU buffers for removed series.\n    // This avoids recreating the entire DataStore and keeps existing buffers for retained indices.\n    if (nextCount < lastSeriesCount) {\n      for (let i = nextCount; i < lastSeriesCount; i++) {\n        dataStore.removeSeries(i);\n      }\n    }\n    lastSeriesCount = nextCount;\n\n    // If animation is explicitly disabled mid-flight, stop the intro without scheduling more frames.\n    if (currentOptions.animation === false && introPhase === 'running') {\n      introAnimController.cancelAll();\n      introAnimId = null;\n      introPhase = 'done';\n      introProgress01 = 1;\n    }\n\n    // If animation is explicitly disabled, ensure any running update transition is stopped.\n    if (currentOptions.animation === false) {\n      cancelUpdateTransition();\n      // Request a render to reflect the option changes immediately\n      requestRender();\n      return;\n    }\n\n    // Capture \"to\" snapshot after recompute.\n    const toZoomRange = zoomState?.getRange() ?? null;\n    const toXBase = computeBaseXDomain(currentOptions, runtimeRawBoundsByIndex);\n    const toXVisible = computeVisibleXDomain(toXBase, toZoomRange);\n    const toYBase = computeBaseYDomain(currentOptions, runtimeRawBoundsByIndex, cachedVisibleYBounds);\n    const toSeriesForTransition = renderSeries;\n\n    const domainChanged = !isDomainEqual(fromSnapshot.xBaseDomain, toXBase) || !isDomainEqual(fromSnapshot.yBaseDomain, toYBase);\n\n    // Skip update animations when only visibility changed.\n    // This allows the intro animation system to handle visibility changes smoothly,\n    // whether an intro animation is running or not.\n    const shouldSkipUpdateAnimation = onlyVisibilityChanged;\n\n    const shouldAnimateUpdate = hasRenderedOnce && (domainChanged || likelyDataChanged) && !shouldSkipUpdateAnimation;\n    if (!shouldAnimateUpdate) {\n      // When visibility changes after intro is complete, retrigger the startup animation for all chart types\n      if (onlyVisibilityChanged && introPhase === 'done' && hasRenderedOnce) {\n        // Reset intro animation state to retrigger on next render\n        introAnimController.cancelAll();\n        introAnimId = null;\n        introPhase = 'pending';\n        introProgress01 = 0;\n      }\n\n      // Request a render even when not animating (e.g., theme changes, option updates, visibility toggles during intro)\n      requestRender();\n      return;\n    }\n\n    const updateCfg = resolveUpdateAnimationConfig(currentOptions.animation);\n    if (!updateCfg) return;\n\n    updateTransition = {\n      from: {\n        xBaseDomain: fromSnapshot.xBaseDomain,\n        xVisibleDomain: fromSnapshot.xVisibleDomain,\n        yBaseDomain: fromSnapshot.yBaseDomain,\n        series: fromSnapshot.series,\n      },\n      to: {\n        xBaseDomain: toXBase,\n        xVisibleDomain: { min: toXVisible.min, max: toXVisible.max },\n        yBaseDomain: toYBase,\n        series: toSeriesForTransition,\n      },\n    };\n    resetUpdateInterpolationCaches();\n\n    const totalMs = updateCfg.delayMs + updateCfg.durationMs;\n    const easingWithDelay: EasingFunction = (t01) => {\n      const t = clamp01(t01);\n      if (!(totalMs > 0)) return 1;\n\n      const elapsedMs = t * totalMs;\n      if (elapsedMs <= updateCfg.delayMs) return 0;\n\n      if (!(updateCfg.durationMs > 0)) return 1;\n      const innerT = (elapsedMs - updateCfg.delayMs) / updateCfg.durationMs;\n      return updateCfg.easing(innerT);\n    };\n\n    updateProgress01 = 0;\n    const id = updateAnimController.animate(\n      0,\n      1,\n      totalMs,\n      easingWithDelay,\n      (value) => {\n        if (disposed || updateAnimId !== id) return;\n        updateProgress01 = clamp01(value);\n        // Render-on-demand: request frames only while the update transition is active.\n        if (updateProgress01 < 1) requestRender();\n      },\n      () => {\n        if (disposed || updateAnimId !== id) return;\n        updateProgress01 = 1;\n        updateTransition = null;\n        updateAnimId = null;\n        resetUpdateInterpolationCaches();\n      }\n    );\n    updateAnimId = id;\n\n    // Request initial render to kick off the animation.\n    // Without this, the animation won't start until something else triggers a render\n    // (e.g., pointer movement, which may not happen if the user is interacting with\n    // UI overlays like the legend).\n    requestRender();\n  };\n\n  const appendData: RenderCoordinator['appendData'] = (seriesIndex, newPoints) => {\n    assertNotDisposed();\n    if (!Number.isFinite(seriesIndex)) return;\n    if (seriesIndex < 0 || seriesIndex >= currentOptions.series.length) return;\n    if (!newPoints || newPoints.length === 0) return;\n\n    const s = currentOptions.series[seriesIndex]!;\n    if (s.type === 'pie') {\n      // Pie series are non-cartesian and currently not supported by streaming append.\n      if (!warnedPieAppendSeries.has(seriesIndex)) {\n        warnedPieAppendSeries.add(seriesIndex);\n        console.warn(\n          `RenderCoordinator.appendData(${seriesIndex}, ...): pie series are not supported by streaming append.`\n        );\n      }\n      return;\n    }\n\n    const existing = pendingAppendByIndex.get(seriesIndex);\n    if (existing) {\n      existing.push(...(newPoints as Array<DataPoint | OHLCDataPoint>));\n    } else {\n      // Copy into a mutable staging array so repeated appends coalesce without extra allocations.\n      pendingAppendByIndex.set(seriesIndex, Array.from(newPoints as Array<DataPoint | OHLCDataPoint>));\n    }\n\n    // Coalesce appends + any required resampling + GPU streaming updates into a single flush.\n    scheduleFlush();\n  };\n\n  const render: RenderCoordinator['render'] = () => {\n    assertNotDisposed();\n    if (!gpuContext.canvasContext || !gpuContext.canvas) return;\n\n    // Safety: if a render is triggered for other reasons (e.g. pointer movement) while appends\n    // are queued, flush them now so this frame draws up-to-date data. This avoids doing any work\n    // when there are no appends.\n    if (pendingAppendByIndex.size > 0 || zoomResampleDue) {\n      cancelScheduledFlush();\n      executeFlush({ requestRenderAfter: false });\n    }\n\n    if (sliceRenderSeriesDue) {\n      sliceRenderSeriesDue = false;\n      sliceRenderSeriesToVisibleRange();\n    }\n\n    const hasCartesianSeries = currentOptions.series.some((s) => s.type !== 'pie');\n    const seriesForIntro = renderSeries;\n\n    // Story 5.16: start/update intro animation once we have drawable series marks.\n    if (introPhase !== 'done') {\n      const introCfg = resolveIntroAnimationConfig(currentOptions.animation);\n\n      const hasDrawableSeriesMarks = (() => {\n        for (let i = 0; i < seriesForIntro.length; i++) {\n          const s = seriesForIntro[i]!;\n          switch (s.type) {\n            case 'pie': {\n              // Pie renderer only emits slices with value > 0.\n              if (s.data.some((it) => typeof it?.value === 'number' && Number.isFinite(it.value) && it.value > 0)) {\n                return true;\n              }\n              break;\n            }\n            case 'line':\n            case 'area':\n            case 'bar':\n            case 'scatter':\n            case 'candlestick': {\n              // TODO(step 2): normalize CartesianSeriesData to ReadonlyArray<DataPoint>\n              const dataLength =\n                Array.isArray(s.data) || ArrayBuffer.isView(s.data)\n                  ? (s.data as ArrayLike<unknown>).length\n                  : (s.data as { x: ArrayLike<unknown> }).x.length;\n              if (dataLength > 0) return true;\n              break;\n            }\n            default:\n              assertUnreachable(s);\n          }\n        }\n        return false;\n      })();\n\n      if (introPhase === 'pending' && introCfg && hasDrawableSeriesMarks) {\n        const totalMs = introCfg.delayMs + introCfg.durationMs;\n        const easingWithDelay: EasingFunction = (t01) => {\n          const t = clamp01(t01);\n          if (!(totalMs > 0)) return 1;\n\n          const elapsedMs = t * totalMs;\n          if (elapsedMs <= introCfg.delayMs) return 0;\n\n          if (!(introCfg.durationMs > 0)) return 1;\n          const innerT = (elapsedMs - introCfg.delayMs) / introCfg.durationMs;\n          return introCfg.easing(innerT);\n        };\n\n        introProgress01 = 0;\n        introPhase = 'running';\n        introAnimId = introAnimController.animate(\n          0,\n          1,\n          totalMs,\n          easingWithDelay,\n          (value) => {\n            if (disposed || introPhase !== 'running') return;\n            introProgress01 = clamp01(value);\n            // Render-on-demand: request frames only while the intro is active.\n            if (introProgress01 < 1) requestRender();\n          },\n          () => {\n            if (disposed) return;\n            introPhase = 'done';\n            introProgress01 = 1;\n            introAnimId = null;\n          }\n        );\n      }\n\n      // Progress animations based on wall-clock time. This is cheap when no animations are active.\n      introAnimController.update(performance.now());\n    }\n\n    // Story 5.17: progress update animation based on wall-clock time.\n    // (Interpolation is applied below; this tick just advances progress.)\n    if (updateTransition !== null && updateAnimId) {\n      updateAnimController.update(performance.now());\n    }\n\n    const gridArea = computeGridArea(gpuContext, currentOptions);\n    eventManager?.updateGridArea(gridArea);\n    const zoomRange = zoomState?.getRange() ?? null;\n\n    const updateP = updateTransition ? clamp01(updateProgress01) : 1;\n    const baseXDomain = updateTransition\n      ? lerpDomain(updateTransition.from.xBaseDomain, updateTransition.to.xBaseDomain, updateP)\n      : computeBaseXDomain(currentOptions, runtimeRawBoundsByIndex);\n    const yBaseDomain = updateTransition\n      ? lerpDomain(updateTransition.from.yBaseDomain, updateTransition.to.yBaseDomain, updateP)\n      : computeBaseYDomain(currentOptions, runtimeRawBoundsByIndex, cachedVisibleYBounds);\n    const visibleXDomain = computeVisibleXDomain(baseXDomain, zoomRange);\n\n    const plotClipRect = computePlotClipRect(gridArea);\n    const plotScissor = computePlotScissorDevicePx(gridArea);\n\n    const xScale = createLinearScale()\n      .domain(visibleXDomain.min, visibleXDomain.max)\n      .range(plotClipRect.left, plotClipRect.right);\n    const yScale = createLinearScale().domain(yBaseDomain.min, yBaseDomain.max).range(plotClipRect.bottom, plotClipRect.top);\n\n    // PERFORMANCE: Cache canvas CSS dimensions (used for both GPU overlays and label processing)\n    // Annotations (GPU overlays) are specified in data-space and converted to CANVAS-LOCAL CSS pixels.\n    const canvas = gpuContext.canvas;\n    // IMPORTANT: For GPU overlay annotations only, derive CSS size from device pixels to avoid\n    // DOM `clientWidth/clientHeight` mismatch with the WebGPU render target size.\n    const canvasCssForAnnotations = getCanvasCssSizeFromDevicePixels(canvas);\n    const canvasCssWidthForAnnotations = canvasCssForAnnotations.width;\n    const canvasCssHeightForAnnotations = canvasCssForAnnotations.height;\n\n    const plotLeftCss = canvasCssWidthForAnnotations > 0 ? clipXToCanvasCssPx(plotClipRect.left, canvasCssWidthForAnnotations) : 0;\n    const plotRightCss = canvasCssWidthForAnnotations > 0 ? clipXToCanvasCssPx(plotClipRect.right, canvasCssWidthForAnnotations) : 0;\n    const plotTopCss = canvasCssHeightForAnnotations > 0 ? clipYToCanvasCssPx(plotClipRect.top, canvasCssHeightForAnnotations) : 0;\n    const plotBottomCss = canvasCssHeightForAnnotations > 0 ? clipYToCanvasCssPx(plotClipRect.bottom, canvasCssHeightForAnnotations) : 0;\n    const plotWidthCss = Math.max(0, plotRightCss - plotLeftCss);\n    const plotHeightCss = Math.max(0, plotBottomCss - plotTopCss);\n\n    // Process annotations (convert to GPU instances for rendering)\n    const annotations: ReadonlyArray<AnnotationConfig> = hasCartesianSeries ? (currentOptions.annotations ?? []) : [];\n    const annotationResult = processAnnotations({\n      annotations,\n      xScale,\n      yScale,\n      plotBounds: {\n        leftCss: plotLeftCss,\n        rightCss: plotRightCss,\n        topCss: plotTopCss,\n        bottomCss: plotBottomCss,\n        widthCss: plotWidthCss,\n        heightCss: plotHeightCss,\n      },\n      canvasCssWidth: canvasCssWidthForAnnotations,\n      canvasCssHeight: canvasCssHeightForAnnotations,\n      theme: currentOptions.theme,\n    });\n\n    // Extract annotation instances for GPU rendering\n    const combinedReferenceLines: ReadonlyArray<ReferenceLineInstance> =\n      annotationResult.linesBelow.length + annotationResult.linesAbove.length > 0\n        ? [...annotationResult.linesBelow, ...annotationResult.linesAbove]\n        : [];\n    const combinedMarkers: ReadonlyArray<AnnotationMarkerInstance> =\n      annotationResult.markersBelow.length + annotationResult.markersAbove.length > 0\n        ? [...annotationResult.markersBelow, ...annotationResult.markersAbove]\n        : [];\n    const referenceLineBelowCount = annotationResult.linesBelow.length;\n    const referenceLineAboveCount = annotationResult.linesAbove.length;\n    const markerBelowCount = annotationResult.markersBelow.length;\n    const markerAboveCount = annotationResult.markersAbove.length;\n\n    // Story 6: compute an x tick count that prevents label overlap (time axis only).\n    // IMPORTANT: compute in CSS px, since labels are DOM elements in CSS px.\n    // Note: This requires HTMLCanvasElement for accurate CSS pixel measurement.\n    const canvasCssWidth = getCanvasCssWidth(gpuContext.canvas);\n    const visibleXRangeMs = Math.abs(visibleXDomain.max - visibleXDomain.min);\n\n    let xTickCount = DEFAULT_TICK_COUNT;\n    let xTickValues: readonly number[] = [];\n    if (currentOptions.xAxis.type === 'time') {\n      const computed = computeAdaptiveTimeXAxisTicks({\n        axisMin: finiteOrNull(currentOptions.xAxis.min),\n        axisMax: finiteOrNull(currentOptions.xAxis.max),\n        xScale,\n        plotClipLeft: plotClipRect.left,\n        plotClipRight: plotClipRect.right,\n        canvasCssWidth,\n        visibleRangeMs: visibleXRangeMs,\n        measureCtx: tickMeasureCtx,\n        measureCache: tickMeasureCache ?? undefined,\n        fontSize: currentOptions.theme.fontSize,\n        fontFamily: currentOptions.theme.fontFamily || 'sans-serif',\n      });\n      xTickCount = computed.tickCount;\n      xTickValues = computed.tickValues;\n    } else {\n      // Keep existing behavior for non-time x axes.\n      const domainMin = finiteOrUndefined(currentOptions.xAxis.min) ?? xScale.invert(plotClipRect.left);\n      const domainMax = finiteOrUndefined(currentOptions.xAxis.max) ?? xScale.invert(plotClipRect.right);\n      xTickValues = generateLinearTicks(domainMin, domainMax, xTickCount);\n    }\n\n    const interactionScales = computeInteractionScalesGridCssPx(gridArea, {\n      xDomain: { min: visibleXDomain.min, max: visibleXDomain.max },\n      yDomain: yBaseDomain,\n    });\n    lastInteractionScales = interactionScales;\n\n    // Story 5.17: during update transitions, render animated series snapshots.\n    const seriesForRender =\n      updateTransition && updateP < 1\n        ? interpolateSeriesForUpdate(updateTransition.from.series, updateTransition.to.series, updateP, updateInterpolationCaches)\n        : renderSeries;\n\n    // Keep `interactionX` in sync with real pointer movement (domain units).\n    if (\n      pointerState.source === 'mouse' &&\n      pointerState.hasPointer &&\n      pointerState.isInGrid &&\n      interactionScales\n    ) {\n      const xDomain = interactionScales.xScale.invert(pointerState.gridX);\n      setInteractionXInternal(Number.isFinite(xDomain) ? xDomain : null, 'mouse');\n    }\n\n    // Compute the effective interaction state:\n    // - mouse: use the latest pointer event payload\n    // - sync: derive a synthetic pointer position from `interactionX` (x only; y is arbitrary)\n    let effectivePointer: PointerState = pointerState;\n    if (pointerState.source === 'sync') {\n      if (interactionX === null || !interactionScales) {\n        effectivePointer = { ...pointerState, hasPointer: false, isInGrid: false };\n      } else {\n        const gridX = interactionScales.xScale.scale(interactionX);\n        const gridY = interactionScales.plotHeightCss * 0.5;\n        const isInGrid =\n          Number.isFinite(gridX) &&\n          Number.isFinite(gridY) &&\n          gridX >= 0 &&\n          gridX <= interactionScales.plotWidthCss &&\n          gridY >= 0 &&\n          gridY <= interactionScales.plotHeightCss;\n\n        effectivePointer = {\n          source: 'sync',\n          gridX: Number.isFinite(gridX) ? gridX : 0,\n          gridY: Number.isFinite(gridY) ? gridY : 0,\n          // Crosshair/tooltip expect CANVAS-LOCAL CSS px.\n          x: gridArea.left + (Number.isFinite(gridX) ? gridX : 0),\n          y: gridArea.top + (Number.isFinite(gridY) ? gridY : 0),\n          isInGrid,\n          hasPointer: isInGrid,\n        };\n      }\n    }\n\n    // Prepare overlay renderers (grid, axes, crosshair, highlight)\n    prepareOverlays(\n      { gridRenderer, xAxisRenderer, yAxisRenderer, crosshairRenderer, highlightRenderer },\n      {\n        currentOptions,\n        xScale,\n        yScale,\n        gridArea,\n        xTickCount,\n        hasCartesianSeries,\n        effectivePointer,\n        interactionScales,\n        seriesForRender,\n        withAlpha,\n      }\n    );\n\n    // Tooltip: on hover, find matches and render tooltip near cursor.\n    // Note: Tooltips require HTMLCanvasElement (DOM-specific positioning).\n    if (effectivePointer.hasPointer && effectivePointer.isInGrid && currentOptions.tooltip?.show !== false) {\n      const canvas = gpuContext.canvas;\n\n      if (interactionScales && canvas && isHTMLCanvasElement(canvas)) {\n        const formatter = currentOptions.tooltip?.formatter;\n        const trigger = currentOptions.tooltip?.trigger ?? 'item';\n\n        const containerX = canvas.offsetLeft + effectivePointer.x;\n        const containerY = canvas.offsetTop + effectivePointer.y;\n\n        if (effectivePointer.source === 'sync') {\n          // Sync semantics:\n          // - Tooltip should be driven by x only (no y).\n          // - In 'axis' mode, show one entry per series nearest in x.\n          // - In 'item' mode, pick a deterministic single entry (first matching series).\n          // findPointsAtX handles visibility filtering internally and returns correct series indices\n          const matches = findPointsAtX(seriesForRender, effectivePointer.gridX, interactionScales.xScale);\n          if (matches.length === 0) {\n            hideTooltip();\n          } else if (trigger === 'axis') {\n            const paramsArray = matches.map((m) => buildTooltipParams(m.seriesIndex, m.dataIndex, m.point));\n            const content = formatter\n              ? (formatter as (p: ReadonlyArray<TooltipParams>) => string)(paramsArray)\n              : formatTooltipAxis(paramsArray);\n            if (content && (content !== lastTooltipContent || containerX !== lastTooltipX || containerY !== lastTooltipY)) {\n              lastTooltipContent = content;\n              lastTooltipX = containerX;\n              lastTooltipY = containerY;\n              showTooltipInternal(containerX, containerY, content, paramsArray);\n            } else if (!content) {\n              hideTooltip();\n            }\n          } else {\n            const m0 = matches[0];\n            const params = buildTooltipParams(m0.seriesIndex, m0.dataIndex, m0.point);\n            const content = formatter ? (formatter as (p: TooltipParams) => string)(params) : formatTooltipItem(params);\n            if (content && (content !== lastTooltipContent || containerX !== lastTooltipX || containerY !== lastTooltipY)) {\n              lastTooltipContent = content;\n              lastTooltipX = containerX;\n              lastTooltipY = containerY;\n              showTooltipInternal(containerX, containerY, content, params);\n            } else if (!content) {\n              hideTooltip();\n            }\n          }\n        } else if (trigger === 'axis') {\n          // Story 4.14: pie slice tooltip hit-testing (mouse only).\n          // If the cursor is over a pie slice, prefer showing that slice tooltip.\n          // findPieSliceAtPointer handles visibility filtering internally and returns correct series indices\n          const pieMatch = findPieSliceAtPointer(\n            seriesForRender,\n            effectivePointer.gridX,\n            effectivePointer.gridY,\n            interactionScales.plotWidthCss,\n            interactionScales.plotHeightCss\n          );\n\n          if (pieMatch) {\n            const params: TooltipParams = {\n              seriesName: pieMatch.slice.name,\n              seriesIndex: pieMatch.seriesIndex,\n              dataIndex: pieMatch.dataIndex,\n              value: [0, pieMatch.slice.value],\n              color: pieMatch.slice.color,\n            };\n\n            const content = formatter\n              ? (formatter as (p: ReadonlyArray<TooltipParams>) => string)([params])\n              : formatTooltipItem(params);\n            if (content && (content !== lastTooltipContent || containerX !== lastTooltipX || containerY !== lastTooltipY)) {\n              lastTooltipContent = content;\n              lastTooltipX = containerX;\n              lastTooltipY = containerY;\n              showTooltipInternal(containerX, containerY, content, [params]);\n            } else if (!content) {\n              hideTooltip();\n            }\n          } else {\n            // Candlestick body hit-testing (mouse, axis trigger): include only when inside candle body.\n            // Hit-testing functions handle visibility filtering internally and return correct series indices\n            const candlestickResult = findCandlestickAtPointer(\n              seriesForRender,\n              effectivePointer.gridX,\n              effectivePointer.gridY,\n              interactionScales\n            );\n\n            const matches = findPointsAtX(seriesForRender, effectivePointer.gridX, interactionScales.xScale);\n            if (matches.length === 0) {\n              if (candlestickResult) {\n                const paramsArray = [candlestickResult.params];\n                const content = formatter\n                  ? (formatter as (p: ReadonlyArray<TooltipParams>) => string)(paramsArray)\n                  : formatTooltipAxis(paramsArray);\n                if (content) {\n                  // Use candlestick anchor for tooltip positioning\n                  const anchor = computeCandlestickTooltipAnchor(\n                    candlestickResult.match,\n                    interactionScales.xScale,\n                    interactionScales.yScale,\n                    gridArea,\n                    canvas\n                  );\n                  const tooltipX = anchor?.x ?? containerX;\n                  const tooltipY = anchor?.y ?? containerY;\n                  if (content !== lastTooltipContent || tooltipX !== lastTooltipX || tooltipY !== lastTooltipY) {\n                    lastTooltipContent = content;\n                    lastTooltipX = tooltipX;\n                    lastTooltipY = tooltipY;\n                    showTooltipInternal(tooltipX, tooltipY, content, paramsArray);\n                  }\n                } else {\n                  hideTooltip();\n                }\n              } else {\n                hideTooltip();\n              }\n            } else {\n              const paramsArray = matches.map((m) => buildTooltipParams(m.seriesIndex, m.dataIndex, m.point));\n              if (candlestickResult) paramsArray.push(candlestickResult.params);\n              const content = formatter\n                ? (formatter as (p: ReadonlyArray<TooltipParams>) => string)(paramsArray)\n                : formatTooltipAxis(paramsArray);\n              if (content) {\n                // Use candlestick anchor if candlestick is present in tooltip\n                let tooltipX = containerX;\n                let tooltipY = containerY;\n                if (candlestickResult) {\n                  const anchor = computeCandlestickTooltipAnchor(\n                    candlestickResult.match,\n                    interactionScales.xScale,\n                    interactionScales.yScale,\n                    gridArea,\n                    canvas\n                  );\n                  if (anchor) {\n                    tooltipX = anchor.x;\n                    tooltipY = anchor.y;\n                  }\n                }\n                if (content !== lastTooltipContent || tooltipX !== lastTooltipX || tooltipY !== lastTooltipY) {\n                  lastTooltipContent = content;\n                  lastTooltipX = tooltipX;\n                  lastTooltipY = tooltipY;\n                  showTooltipInternal(tooltipX, tooltipY, content, paramsArray);\n                }\n              } else {\n                hideTooltip();\n              }\n            }\n          }\n        } else {\n          // Story 4.14: pie slice tooltip hit-testing (mouse only).\n          // If the cursor is over a pie slice, prefer showing that slice tooltip.\n          // findPieSliceAtPointer handles visibility filtering internally and returns correct series indices\n          const pieMatch = findPieSliceAtPointer(\n            seriesForRender,\n            effectivePointer.gridX,\n            effectivePointer.gridY,\n            interactionScales.plotWidthCss,\n            interactionScales.plotHeightCss\n          );\n\n          if (pieMatch) {\n            const params: TooltipParams = {\n              seriesName: pieMatch.slice.name,\n              seriesIndex: pieMatch.seriesIndex,\n              dataIndex: pieMatch.dataIndex,\n              value: [0, pieMatch.slice.value],\n              color: pieMatch.slice.color,\n            };\n            const content = formatter\n              ? (formatter as (p: TooltipParams) => string)(params)\n              : formatTooltipItem(params);\n            if (content && (content !== lastTooltipContent || containerX !== lastTooltipX || containerY !== lastTooltipY)) {\n              lastTooltipContent = content;\n              lastTooltipX = containerX;\n              lastTooltipY = containerY;\n              showTooltipInternal(containerX, containerY, content, params);\n            } else if (!content) {\n              hideTooltip();\n            }\n          } else {\n            // Candlestick body hit-testing (mouse, item trigger): prefer candle body over nearest-point logic.\n            // Hit-testing functions handle visibility filtering internally and return correct series indices\n            const candlestickResult = findCandlestickAtPointer(\n              seriesForRender,\n              effectivePointer.gridX,\n              effectivePointer.gridY,\n              interactionScales\n            );\n            if (candlestickResult) {\n              const content = formatter\n                ? (formatter as (p: TooltipParams) => string)(candlestickResult.params)\n                : formatTooltipItem(candlestickResult.params);\n              if (content) {\n                // Use candlestick anchor for tooltip positioning\n                const anchor = computeCandlestickTooltipAnchor(\n                  candlestickResult.match,\n                  interactionScales.xScale,\n                  interactionScales.yScale,\n                  gridArea,\n                  canvas\n                );\n                const tooltipX = anchor?.x ?? containerX;\n                const tooltipY = anchor?.y ?? containerY;\n                if (content !== lastTooltipContent || tooltipX !== lastTooltipX || tooltipY !== lastTooltipY) {\n                  lastTooltipContent = content;\n                  lastTooltipX = tooltipX;\n                  lastTooltipY = tooltipY;\n                  showTooltipInternal(tooltipX, tooltipY, content, candlestickResult.params);\n                }\n              } else {\n                hideTooltip();\n              }\n              return;\n            }\n\n            const match = findNearestPoint(\n              seriesForRender,\n              effectivePointer.gridX,\n              effectivePointer.gridY,\n              interactionScales.xScale,\n              interactionScales.yScale\n            );\n            if (!match) {\n              hideTooltip();\n            } else {\n              const params = buildTooltipParams(match.seriesIndex, match.dataIndex, match.point);\n              const content = formatter\n                ? (formatter as (p: TooltipParams) => string)(params)\n                : formatTooltipItem(params);\n              if (content && (content !== lastTooltipContent || containerX !== lastTooltipX || containerY !== lastTooltipY)) {\n                lastTooltipContent = content;\n                lastTooltipX = containerX;\n                lastTooltipY = containerY;\n                showTooltipInternal(containerX, containerY, content, params);\n              } else if (!content) {\n                hideTooltip();\n              }\n            }\n          }\n        }\n            } else {\n              hideTooltip();\n            }\n        } else {\n          hideTooltip();\n        }\n\n    // Compute maxRadiusCss for pie intro animation\n    const plotSize = interactionScales ?? (canvas && isHTMLCanvasElement(canvas) ? getPlotSizeCssPx(canvas, gridArea) : null);\n    const maxRadiusCss =\n      plotSize && typeof plotSize.plotWidthCss === 'number' && typeof plotSize.plotHeightCss === 'number'\n        ? 0.5 * Math.min(plotSize.plotWidthCss, plotSize.plotHeightCss)\n        : 0;\n\n    // Prepare all series renderers (area, line, bar, scatter, pie, candlestick)\n    const seriesPreparation = prepareSeries(\n      {\n        lineRenderers,\n        areaRenderers,\n        barRenderer,\n        scatterRenderers,\n        scatterDensityRenderers,\n        pieRenderers,\n        candlestickRenderers,\n      },\n      {\n        currentOptions,\n        seriesForRender,\n        xScale,\n        yScale,\n        gridArea,\n        dataStore,\n        appendedGpuThisFrame,\n        gpuSeriesKindByIndex,\n        zoomState,\n        visibleXDomain,\n        introPhase,\n        introProgress01,\n        withAlpha,\n        maxRadiusCss,\n      }\n    );\n\n    const { visibleBarSeriesConfigs } = seriesPreparation;\n\n    // Prepare bar renderer with animated scale if intro is running\n    const introP = introPhase === 'running' ? clamp01(introProgress01) : 1;\n    const yScaleForBars = introP < 1 ? createAnimatedBarYScale(yScale, plotClipRect, visibleBarSeriesConfigs, introP) : yScale;\n    barRenderer.prepare(visibleBarSeriesConfigs, dataStore, xScale, yScaleForBars, gridArea);\n\n    // Prepare annotation GPU overlays (reference lines + point markers).\n    // Note: these renderers expect CANVAS-LOCAL CSS pixel coordinates; the coordinator owns\n    // data-space → canvas-space conversion and plot scissor state.\n    if (hasCartesianSeries) {\n      referenceLineRenderer.prepare(gridArea, combinedReferenceLines);\n      referenceLineRendererMsaa.prepare(gridArea, combinedReferenceLines);\n      annotationMarkerRenderer.prepare({\n        canvasWidth: gridArea.canvasWidth,\n        canvasHeight: gridArea.canvasHeight,\n        devicePixelRatio: gridArea.devicePixelRatio,\n        instances: combinedMarkers,\n      });\n      annotationMarkerRendererMsaa.prepare({\n        canvasWidth: gridArea.canvasWidth,\n        canvasHeight: gridArea.canvasHeight,\n        devicePixelRatio: gridArea.devicePixelRatio,\n        instances: combinedMarkers,\n      });\n    } else {\n      // Ensure prior frame instances don't persist visually if series mode changes.\n      referenceLineRenderer.prepare(gridArea, []);\n      referenceLineRendererMsaa.prepare(gridArea, []);\n      annotationMarkerRenderer.prepare({\n        canvasWidth: gridArea.canvasWidth,\n        canvasHeight: gridArea.canvasHeight,\n        devicePixelRatio: gridArea.devicePixelRatio,\n        instances: [],\n      });\n      annotationMarkerRendererMsaa.prepare({\n        canvasWidth: gridArea.canvasWidth,\n        canvasHeight: gridArea.canvasHeight,\n        devicePixelRatio: gridArea.devicePixelRatio,\n        instances: [],\n      });\n    }\n\n    ensureOverlayTargets(gridArea.canvasWidth, gridArea.canvasHeight);\n\n    // Swapchain view for the resolved MSAA overlay pass and for the final (load) overlay pass.\n    const swapchainView = gpuContext.canvasContext.getCurrentTexture().createView();\n    const encoder = device.createCommandEncoder({ label: 'renderCoordinator/commandEncoder' });\n    const clearValue = parseCssColorToGPUColor(currentOptions.theme.backgroundColor, { r: 0, g: 0, b: 0, a: 1 });\n\n    // Encode compute passes (scatter density) before the render pass.\n    encodeScatterDensityCompute(\n      { lineRenderers, areaRenderers, barRenderer, scatterRenderers, scatterDensityRenderers, pieRenderers, candlestickRenderers },\n      seriesForRender,\n      encoder\n    );\n\n    const mainPass = encoder.beginRenderPass({\n      label: 'renderCoordinator/mainPass',\n      colorAttachments: [\n        {\n          view: mainColorView!,\n          clearValue,\n          loadOp: 'clear',\n          storeOp: 'store',\n        },\n      ],\n    });\n\n    // Render order:\n    // - grid first (background)\n    // - pies early (non-cartesian, visible behind cartesian series)\n    // - area fills next (so they don't cover strokes/axes)\n    // - bars next (fills)\n    // - scatter next (points on top of fills, below strokes/overlays)\n    // - line strokes next\n    // - highlight next (on top of strokes)\n    // - axes last (on top)\n    if (gridRenderer) {\n      gridRenderer.render(mainPass);\n    }\n\n    // Render all series to the main pass with proper layering\n    renderSeriesPass(\n      { lineRenderers, areaRenderers, barRenderer, scatterRenderers, scatterDensityRenderers, pieRenderers, candlestickRenderers },\n      { referenceLineRenderer, referenceLineRendererMsaa, annotationMarkerRenderer, annotationMarkerRendererMsaa },\n      {\n        hasCartesianSeries,\n        gridArea,\n        mainPass,\n        plotScissor,\n        introPhase,\n        introProgress01,\n        referenceLineBelowCount,\n        markerBelowCount,\n      },\n      seriesPreparation\n    );\n\n    mainPass.end();\n\n    // MSAA annotation overlay pass: blit main color → MSAA target, then draw above-series annotations.\n    const overlayPass = encoder.beginRenderPass({\n      label: 'renderCoordinator/annotationOverlayMsaaPass',\n      colorAttachments: [\n        {\n          view: overlayMsaaView!,\n          resolveTarget: swapchainView,\n          clearValue,\n          loadOp: 'clear',\n          storeOp: 'discard',\n        },\n      ],\n    });\n\n    overlayPass.setPipeline(overlayBlitPipeline);\n    overlayPass.setBindGroup(0, overlayBlitBindGroup!);\n    overlayPass.draw(3);\n\n    // Render above-series annotations to the overlay pass\n    renderAboveSeriesAnnotations(\n      { referenceLineRenderer, referenceLineRendererMsaa, annotationMarkerRenderer, annotationMarkerRendererMsaa },\n      {\n        hasCartesianSeries,\n        gridArea,\n        overlayPass,\n        plotScissor,\n        referenceLineBelowCount,\n        referenceLineAboveCount,\n        markerBelowCount,\n        markerAboveCount,\n      }\n    );\n\n    overlayPass.end();\n\n    // Top overlays (single-sample): axes, highlights, crosshair.\n    const topOverlayPass = encoder.beginRenderPass({\n      label: 'renderCoordinator/topOverlayPass',\n      colorAttachments: [\n        {\n          view: swapchainView,\n          loadOp: 'load',\n          storeOp: 'store',\n        },\n      ],\n    });\n\n    highlightRenderer.render(topOverlayPass);\n    if (hasCartesianSeries) {\n      xAxisRenderer.render(topOverlayPass);\n      yAxisRenderer.render(topOverlayPass);\n    }\n    crosshairRenderer.render(topOverlayPass);\n\n    topOverlayPass.end();\n    device.queue.submit([encoder.finish()]);\n\n    hasRenderedOnce = true;\n\n    // Generate axis labels for DOM overlay\n    renderAxisLabels(axisLabelOverlay, overlayContainer, {\n      gpuContext,\n      currentOptions,\n      xScale,\n      yScale,\n      xTickValues,\n      plotClipRect,\n      visibleXRangeMs,\n    });\n\n    // Generate annotation labels (DOM overlay)\n    renderAnnotationLabels(annotationOverlay, overlayContainer, {\n      currentOptions,\n      xScale,\n      yScale,\n      canvasCssWidthForAnnotations,\n      canvasCssHeightForAnnotations,\n      plotLeftCss,\n      plotTopCss,\n      plotWidthCss,\n      plotHeightCss,\n      canvas,\n    });\n  };\n\n\n  const dispose: RenderCoordinator['dispose'] = () => {\n    if (disposed) return;\n    disposed = true;\n\n    // Story 5.16: stop intro animation and avoid further render requests.\n    try {\n      if (introAnimId) introAnimController.cancel(introAnimId);\n      introAnimController.cancelAll();\n    } catch {\n      // best-effort\n    }\n    introAnimId = null;\n    introPhase = 'done';\n    introProgress01 = 1;\n\n    // Story 5.17: stop update animation and avoid further render requests.\n    try {\n      if (updateAnimId) updateAnimController.cancel(updateAnimId);\n      updateAnimController.cancelAll();\n    } catch {\n      // best-effort\n    }\n    updateAnimId = null;\n    updateProgress01 = 1;\n    updateTransition = null;\n\n    cancelScheduledFlush();\n    cancelZoomResampleDebounce();\n    zoomResampleDue = false;\n\n    pendingAppendByIndex.clear();\n\n    insideZoom?.dispose();\n    insideZoom = null;\n    unsubscribeZoom?.();\n    unsubscribeZoom = null;\n    zoomState = null;\n    lastOptionsZoomRange = null;\n    zoomRangeListeners.clear();\n\n    eventManager?.dispose();\n    crosshairRenderer.dispose();\n    highlightRenderer.dispose();\n\n    for (let i = 0; i < areaRenderers.length; i++) {\n      areaRenderers[i].dispose();\n    }\n    areaRenderers.length = 0;\n\n    for (let i = 0; i < lineRenderers.length; i++) {\n      lineRenderers[i].dispose();\n    }\n    lineRenderers.length = 0;\n\n    for (let i = 0; i < scatterRenderers.length; i++) {\n      scatterRenderers[i].dispose();\n    }\n    scatterRenderers.length = 0;\n\n    for (let i = 0; i < pieRenderers.length; i++) {\n      pieRenderers[i].dispose();\n    }\n    pieRenderers.length = 0;\n\n    for (let i = 0; i < candlestickRenderers.length; i++) {\n      candlestickRenderers[i].dispose();\n    }\n    candlestickRenderers.length = 0;\n\n    barRenderer.dispose();\n\n    gridRenderer.dispose();\n    xAxisRenderer.dispose();\n    yAxisRenderer.dispose();\n    referenceLineRenderer.dispose();\n    annotationMarkerRenderer.dispose();\n    referenceLineRendererMsaa.dispose();\n    annotationMarkerRendererMsaa.dispose();\n\n    destroyTexture(mainColorTexture);\n    destroyTexture(overlayMsaaTexture);\n    mainColorTexture = null;\n    mainColorView = null;\n    overlayMsaaTexture = null;\n    overlayMsaaView = null;\n    overlayBlitBindGroup = null;\n\n    dataStore.dispose();\n\n    // Dispose tooltip/legend before the text overlay (all touch container positioning).\n    tooltip?.dispose();\n    tooltip = null;\n    legend?.dispose();\n    axisLabelOverlay?.dispose();\n    annotationOverlay?.dispose();\n  };\n\n  const getInteractionX: RenderCoordinator['getInteractionX'] = () => interactionX;\n\n  const setInteractionX: RenderCoordinator['setInteractionX'] = (x, source) => {\n    assertNotDisposed();\n    const normalized = x !== null && Number.isFinite(x) ? x : null;\n\n    // External interaction should not depend on y, so we treat it as “sync” mode.\n    pointerState = { ...pointerState, source: normalized === null ? 'mouse' : 'sync' };\n\n    setInteractionXInternal(normalized, source);\n\n    if (normalized === null && pointerState.hasPointer === false) {\n      crosshairRenderer.setVisible(false);\n      highlightRenderer.setVisible(false);\n      hideTooltipInternal();\n    }\n    requestRender();\n  };\n\n  const onInteractionXChange: RenderCoordinator['onInteractionXChange'] = (callback) => {\n    assertNotDisposed();\n    interactionXListeners.add(callback);\n    return () => {\n      interactionXListeners.delete(callback);\n    };\n  };\n\n  const getZoomRange: RenderCoordinator['getZoomRange'] = () => {\n    return zoomState?.getRange() ?? null;\n  };\n\n  const setZoomRange: RenderCoordinator['setZoomRange'] = (start, end) => {\n    assertNotDisposed();\n    if (!zoomState) return;\n    zoomState.setRange(start, end);\n    // onChange will requestRender + emit.\n  };\n\n  const onZoomRangeChange: RenderCoordinator['onZoomRangeChange'] = (cb) => {\n    assertNotDisposed();\n    zoomRangeListeners.add(cb);\n    return () => {\n      zoomRangeListeners.delete(cb);\n    };\n  };\n\n  return {\n    setOptions,\n    appendData,\n    getInteractionX,\n    setInteractionX,\n    onInteractionXChange,\n    getZoomRange,\n    setZoomRange,\n    onZoomRangeChange,\n    render,\n    dispose,\n  };\n}\n\n","import type {\n  AreaStyleConfig,\n  CandlestickItemStyleConfig,\n  CandlestickStyle,\n  ChartGPUOptions,\n  GridConfig,\n  LineStyleConfig,\n} from './types';\n\nexport const defaultGrid = {\n  left: 60,\n  right: 20,\n  top: 40,\n  bottom: 40,\n} as const satisfies Required<GridConfig>;\n\nexport const defaultPalette = [\n  '#5470C6',\n  '#91CC75',\n  '#FAC858',\n  '#EE6666',\n  '#73C0DE',\n  '#3BA272',\n  '#FC8452',\n  '#9A60B4',\n  '#EA7CCC',\n] as const;\n\nexport const defaultLineStyle = {\n  width: 2,\n  opacity: 1,\n} as const satisfies Required<Omit<LineStyleConfig, 'color'>>;\n\nexport const defaultAreaStyle = {\n  opacity: 0.25,\n} as const satisfies Required<Omit<AreaStyleConfig, 'color'>>;\n\nexport const candlestickDefaults = {\n  style: 'classic' as CandlestickStyle,\n  itemStyle: {\n    upColor: '#22c55e',\n    downColor: '#ef4444',\n    upBorderColor: '#22c55e',\n    downBorderColor: '#ef4444',\n    borderWidth: 1,\n  } as const satisfies Required<CandlestickItemStyleConfig>,\n  barWidth: '80%' as const,\n  barMinWidth: 1,\n  barMaxWidth: 50,\n  sampling: 'ohlc' as const,\n  samplingThreshold: 5000,\n} as const;\n\nexport const scatterDefaults = {\n  mode: 'points' as const,\n  // Bin size in CSS pixels for density mode. Must be > 0.\n  binSize: 2,\n  densityColormap: 'viridis' as const,\n  densityNormalization: 'log' as const,\n} as const;\n\nexport const defaultOptions = {\n  grid: defaultGrid,\n  xAxis: { type: 'value' },\n  yAxis: { type: 'value', autoBounds: 'visible' },\n  autoScroll: false,\n  theme: 'dark',\n  palette: defaultPalette,\n  series: [],\n} as const satisfies Readonly<\n  Required<Pick<ChartGPUOptions, 'grid' | 'xAxis' | 'yAxis' | 'autoScroll' | 'theme' | 'palette'>> & {\n    readonly series: readonly [];\n  }\n>;\n\n","import type { ThemeConfig } from './types';\n\nconst palette = [\n  '#00E5FF',\n  '#FF2D95',\n  '#B026FF',\n  '#00F5A0',\n  '#FFD300',\n  '#FF6B00',\n  '#4D5BFF',\n  '#FF3D3D',\n] as const;\n\nexport const darkTheme = {\n  backgroundColor: '#1a1a2e',\n  textColor: '#e0e0e0',\n  axisLineColor: 'rgba(224,224,224,0.35)',\n  axisTickColor: 'rgba(224,224,224,0.55)',\n  gridLineColor: 'rgba(255,255,255,0.1)',\n  colorPalette: [...palette],\n  fontFamily:\n    'system-ui, -apple-system, \"Segoe UI\", Roboto, Helvetica, Arial, \"Apple Color Emoji\", \"Segoe UI Emoji\"',\n  fontSize: 12,\n} satisfies ThemeConfig;\n","import type { ThemeConfig } from './types';\n\nconst palette = [\n  '#1F77B4',\n  '#FF7F0E',\n  '#2CA02C',\n  '#D62728',\n  '#9467BD',\n  '#8C564B',\n  '#E377C2',\n  '#17BECF',\n] as const;\n\nexport const lightTheme = {\n  backgroundColor: '#ffffff',\n  textColor: '#333333',\n  axisLineColor: 'rgba(0,0,0,0.35)',\n  axisTickColor: 'rgba(0,0,0,0.55)',\n  gridLineColor: 'rgba(0,0,0,0.1)',\n  colorPalette: [...palette],\n  fontFamily:\n    'system-ui, -apple-system, \"Segoe UI\", Roboto, Helvetica, Arial, \"Apple Color Emoji\", \"Segoe UI Emoji\"',\n  fontSize: 12,\n} satisfies ThemeConfig;\n","import type { ThemeConfig } from './types';\nimport { darkTheme } from './darkTheme';\nimport { lightTheme } from './lightTheme';\n\nexport { darkTheme, lightTheme };\nexport type { ThemeConfig };\n\nexport type ThemeName = 'dark' | 'light';\n\nexport function getTheme(name: ThemeName): ThemeConfig {\n  return name === 'dark' ? darkTheme : lightTheme;\n}\n","import type {\n  AreaStyleConfig,\n  AnnotationConfig,\n  AnnotationLabel,\n  AnnotationLabelAnchor,\n  AnnotationLabelBackground,\n  AnnotationPointMarker,\n  AxisConfig,\n  CandlestickItemStyleConfig,\n  CandlestickSeriesConfig,\n  CandlestickStyle,\n  ChartGPUOptions,\n  DataZoomConfig,\n  GridConfig,\n  LineStyleConfig,\n  OHLCDataPoint,\n  OHLCDataPointTuple,\n  AreaSeriesConfig,\n  BarSeriesConfig,\n  LineSeriesConfig,\n  PieDataItem,\n  PieSeriesConfig,\n  ScatterSeriesConfig,\n  ScatterSymbol,\n  SeriesSampling,\n} from './types';\nimport {\n  candlestickDefaults,\n  defaultAreaStyle,\n  defaultLineStyle,\n  defaultOptions,\n  defaultPalette,\n  scatterDefaults,\n} from './defaults';\nimport { getTheme } from '../themes';\nimport type { ThemeConfig } from '../themes/types';\nimport { sampleSeriesDataPoints } from '../data/sampleSeries';\nimport { ohlcSample } from '../data/ohlcSample';\nimport { computeRawBoundsFromCartesianData } from '../data/cartesianData';\n\nexport type ResolvedGridConfig = Readonly<Required<GridConfig>>;\nexport type ResolvedLineStyleConfig = Readonly<Required<Omit<LineStyleConfig, 'color'>> & { readonly color: string }>;\nexport type ResolvedAreaStyleConfig = Readonly<Required<Omit<AreaStyleConfig, 'color'>> & { readonly color: string }>;\n\nexport type RawBounds = Readonly<{ xMin: number; xMax: number; yMin: number; yMax: number }>;\n\nexport type ResolvedLineSeriesConfig = Readonly<\n  Omit<LineSeriesConfig, 'color' | 'lineStyle' | 'areaStyle' | 'sampling' | 'samplingThreshold' | 'data'> & {\n    readonly color: string;\n    readonly lineStyle: ResolvedLineStyleConfig;\n    readonly areaStyle?: ResolvedAreaStyleConfig;\n    readonly sampling: SeriesSampling;\n    readonly samplingThreshold: number;\n    /**\n     * Original (unsampled) series data.\n     *\n     * Used at runtime for zoom-aware re-sampling so we can increase detail when zoomed-in without\n     * losing outliers or permanently discarding points.\n     */\n    readonly rawData: Readonly<LineSeriesConfig['data']>;\n    readonly data: Readonly<LineSeriesConfig['data']>;\n    /**\n     * Bounds computed from the original (unsampled) data. Used for axis auto-bounds so sampling\n     * cannot clip outliers.\n     */\n    readonly rawBounds?: RawBounds;\n  }\n>;\n\nexport type ResolvedAreaSeriesConfig = Readonly<\n  Omit<AreaSeriesConfig, 'color' | 'areaStyle' | 'sampling' | 'samplingThreshold' | 'data'> & {\n    readonly color: string;\n    readonly areaStyle: ResolvedAreaStyleConfig;\n    readonly sampling: SeriesSampling;\n    readonly samplingThreshold: number;\n    /** Original (unsampled) series data (see `ResolvedLineSeriesConfig.rawData`). */\n    readonly rawData: Readonly<AreaSeriesConfig['data']>;\n    readonly data: Readonly<AreaSeriesConfig['data']>;\n    /**\n     * Bounds computed from the original (unsampled) data. Used for axis auto-bounds so sampling\n     * cannot clip outliers.\n     */\n    readonly rawBounds?: RawBounds;\n  }\n>;\n\nexport type ResolvedBarSeriesConfig = Readonly<\n  Omit<BarSeriesConfig, 'color' | 'sampling' | 'samplingThreshold' | 'data'> & {\n    readonly color: string;\n    readonly sampling: SeriesSampling;\n    readonly samplingThreshold: number;\n    /** Original (unsampled) series data (see `ResolvedLineSeriesConfig.rawData`). */\n    readonly rawData: Readonly<BarSeriesConfig['data']>;\n    readonly data: Readonly<BarSeriesConfig['data']>;\n    /**\n     * Bounds computed from the original (unsampled) data. Used for axis auto-bounds so sampling\n     * cannot clip outliers.\n     */\n    readonly rawBounds?: RawBounds;\n  }\n>;\n\nexport type ResolvedScatterSeriesConfig = Readonly<\n  Omit<\n    ScatterSeriesConfig,\n    'color' | 'sampling' | 'samplingThreshold' | 'data' | 'mode' | 'binSize' | 'densityColormap' | 'densityNormalization'\n  > & {\n    readonly color: string;\n    readonly sampling: SeriesSampling;\n    readonly samplingThreshold: number;\n    readonly mode: NonNullable<ScatterSeriesConfig['mode']>;\n    readonly binSize: number;\n    readonly densityColormap: NonNullable<ScatterSeriesConfig['densityColormap']>;\n    readonly densityNormalization: NonNullable<ScatterSeriesConfig['densityNormalization']>;\n    /** Original (unsampled) series data (see `ResolvedLineSeriesConfig.rawData`). */\n    readonly rawData: Readonly<ScatterSeriesConfig['data']>;\n    readonly data: Readonly<ScatterSeriesConfig['data']>;\n    /**\n     * Bounds computed from the original (unsampled) data. Used for axis auto-bounds so sampling\n     * cannot clip outliers.\n     */\n    readonly rawBounds?: RawBounds;\n  }\n>;\n\nexport type ResolvedPieDataItem = Readonly<\n  Omit<PieDataItem, 'color' | 'visible'> & {\n    readonly color: string;\n    readonly visible: boolean;\n  }\n>;\n\nexport type ResolvedPieSeriesConfig = Readonly<\n  Omit<PieSeriesConfig, 'color' | 'data'> & {\n    readonly color: string;\n    readonly data: ReadonlyArray<ResolvedPieDataItem>;\n  }\n>;\n\nexport type ResolvedCandlestickItemStyleConfig = Readonly<Required<CandlestickItemStyleConfig>>;\n\nexport type ResolvedCandlestickSeriesConfig = Readonly<\n  Omit<CandlestickSeriesConfig, 'color' | 'style' | 'itemStyle' | 'barWidth' | 'barMinWidth' | 'barMaxWidth' | 'sampling' | 'samplingThreshold' | 'data'> & {\n    readonly color: string;\n    readonly style: CandlestickStyle;\n    readonly itemStyle: ResolvedCandlestickItemStyleConfig;\n    readonly barWidth: number | string;\n    readonly barMinWidth: number;\n    readonly barMaxWidth: number;\n    readonly sampling: 'none' | 'ohlc';\n    readonly samplingThreshold: number;\n    /** Original (unsampled) series data. */\n    readonly rawData: Readonly<CandlestickSeriesConfig['data']>;\n    readonly data: Readonly<CandlestickSeriesConfig['data']>;\n    /**\n     * Bounds computed from the original (unsampled) data. Used for axis auto-bounds so sampling\n     * cannot clip outliers.\n     */\n    readonly rawBounds?: RawBounds;\n  }\n>;\n\nexport type ResolvedSeriesConfig =\n  | ResolvedLineSeriesConfig\n  | ResolvedAreaSeriesConfig\n  | ResolvedBarSeriesConfig\n  | ResolvedScatterSeriesConfig\n  | ResolvedPieSeriesConfig\n  | ResolvedCandlestickSeriesConfig;\n\nexport interface ResolvedChartGPUOptions\n  extends Omit<ChartGPUOptions, 'grid' | 'xAxis' | 'yAxis' | 'theme' | 'palette' | 'series' | 'legend'> {\n  readonly grid: ResolvedGridConfig;\n  readonly xAxis: AxisConfig;\n  readonly yAxis: AxisConfig;\n  readonly autoScroll: boolean;\n  readonly theme: ThemeConfig;\n  readonly palette: ReadonlyArray<string>;\n  readonly series: ReadonlyArray<ResolvedSeriesConfig>;\n  readonly annotations?: ReadonlyArray<AnnotationConfig>;\n  readonly legend?: import('./types').LegendConfig;\n}\n\nconst sanitizeDataZoom = (input: unknown): ReadonlyArray<DataZoomConfig> | undefined => {\n  if (!Array.isArray(input)) return undefined;\n\n  const out: DataZoomConfig[] = [];\n\n  for (const item of input) {\n    if (item === null || typeof item !== 'object' || Array.isArray(item)) continue;\n    const record = item as Record<string, unknown>;\n\n    const type = record.type;\n    if (type !== 'inside' && type !== 'slider') continue;\n\n    const xAxisIndexRaw = record.xAxisIndex;\n    const startRaw = record.start;\n    const endRaw = record.end;\n    const minSpanRaw = record.minSpan;\n    const maxSpanRaw = record.maxSpan;\n\n    const xAxisIndex =\n      typeof xAxisIndexRaw === 'number' && Number.isFinite(xAxisIndexRaw) ? xAxisIndexRaw : undefined;\n    const start = typeof startRaw === 'number' && Number.isFinite(startRaw) ? startRaw : undefined;\n    const end = typeof endRaw === 'number' && Number.isFinite(endRaw) ? endRaw : undefined;\n    const minSpan =\n      typeof minSpanRaw === 'number' && Number.isFinite(minSpanRaw) ? minSpanRaw : undefined;\n    const maxSpan =\n      typeof maxSpanRaw === 'number' && Number.isFinite(maxSpanRaw) ? maxSpanRaw : undefined;\n\n    out.push({ type, xAxisIndex, start, end, minSpan, maxSpan });\n  }\n\n  return out;\n};\n\nconst sanitizeAnnotations = (input: unknown): ReadonlyArray<AnnotationConfig> | undefined => {\n  if (!Array.isArray(input)) return undefined;\n\n  const out: AnnotationConfig[] = [];\n\n  const isLabelAnchor = (v: unknown): v is AnnotationLabelAnchor =>\n    v === 'start' || v === 'center' || v === 'end';\n\n  const isScatterSymbol = (v: unknown): v is ScatterSymbol =>\n    v === 'circle' || v === 'rect' || v === 'triangle';\n\n  const sanitizeString = (v: unknown): string | undefined => {\n    if (typeof v !== 'string') return undefined;\n    const t = v.trim();\n    return t.length > 0 ? t : undefined;\n  };\n\n  const sanitizeFiniteNumber = (v: unknown): number | undefined =>\n    typeof v === 'number' && Number.isFinite(v) ? v : undefined;\n\n  const sanitizeOpacity01 = (v: unknown): number | undefined => {\n    const n = sanitizeFiniteNumber(v);\n    if (n == null) return undefined;\n    return Math.min(1, Math.max(0, n));\n  };\n\n  const sanitizeLineDash = (v: unknown): readonly number[] | undefined => {\n    if (!Array.isArray(v)) return undefined;\n    const cleaned = v\n      .filter((x): x is number => typeof x === 'number' && Number.isFinite(x))\n      .map((x) => x);\n    if (cleaned.length === 0) return undefined;\n    Object.freeze(cleaned);\n    return cleaned;\n  };\n\n  const sanitizePadding = (v: unknown): number | readonly [number, number, number, number] | undefined => {\n    if (typeof v === 'number' && Number.isFinite(v)) return v;\n    if (!Array.isArray(v) || v.length !== 4) return undefined;\n    const t = sanitizeFiniteNumber(v[0]);\n    const r = sanitizeFiniteNumber(v[1]);\n    const b = sanitizeFiniteNumber(v[2]);\n    const l = sanitizeFiniteNumber(v[3]);\n    if (t == null || r == null || b == null || l == null) return undefined;\n    return [t, r, b, l] as const;\n  };\n\n  for (const item of input) {\n    if (item === null || typeof item !== 'object' || Array.isArray(item)) continue;\n    const record = item as Record<string, unknown>;\n\n    const type = record.type;\n    if (type !== 'lineX' && type !== 'lineY' && type !== 'point' && type !== 'text') continue;\n\n    const id = sanitizeString(record.id);\n    const layerRaw = record.layer;\n    const layer = layerRaw === 'belowSeries' || layerRaw === 'aboveSeries' ? layerRaw : undefined;\n\n    const styleRaw = record.style;\n    const style =\n      styleRaw && typeof styleRaw === 'object' && !Array.isArray(styleRaw)\n        ? (() => {\n            const s = styleRaw as Record<string, unknown>;\n            const color = sanitizeString(s.color);\n            const lineWidth = sanitizeFiniteNumber(s.lineWidth);\n            const lineDash = sanitizeLineDash(s.lineDash);\n            const opacity = sanitizeOpacity01(s.opacity);\n            const next: Record<string, unknown> = {\n              ...(color ? { color } : {}),\n              ...(lineWidth != null ? { lineWidth } : {}),\n              ...(lineDash ? { lineDash } : {}),\n              ...(opacity != null ? { opacity } : {}),\n            };\n            return Object.keys(next).length > 0 ? (next as AnnotationConfig['style']) : undefined;\n          })()\n        : undefined;\n\n    const labelRaw = record.label;\n    const label =\n      labelRaw && typeof labelRaw === 'object' && !Array.isArray(labelRaw)\n        ? (() => {\n            const l = labelRaw as Record<string, unknown>;\n            const text = sanitizeString(l.text);\n            const template = sanitizeString(l.template);\n            const decimalsRaw = l.decimals;\n            const decimals =\n              typeof decimalsRaw === 'number' && Number.isFinite(decimalsRaw) && decimalsRaw >= 0\n                ? Math.min(20, Math.floor(decimalsRaw))\n                : undefined;\n            const offsetRaw = l.offset;\n            const offset =\n              Array.isArray(offsetRaw) &&\n              offsetRaw.length === 2 &&\n              typeof offsetRaw[0] === 'number' &&\n              Number.isFinite(offsetRaw[0]) &&\n              typeof offsetRaw[1] === 'number' &&\n              Number.isFinite(offsetRaw[1])\n                ? ([offsetRaw[0], offsetRaw[1]] as const)\n                : undefined;\n            const anchorRaw = l.anchor;\n            const anchor = isLabelAnchor(anchorRaw) ? anchorRaw : undefined;\n            const bgRaw = l.background;\n            const background =\n              bgRaw && typeof bgRaw === 'object' && !Array.isArray(bgRaw)\n                ? (() => {\n                    const bg = bgRaw as Record<string, unknown>;\n                    const color = sanitizeString(bg.color);\n                    const opacity = sanitizeOpacity01(bg.opacity);\n                    const padding = sanitizePadding(bg.padding);\n                    const borderRadius = sanitizeFiniteNumber(bg.borderRadius);\n                    const next: AnnotationLabelBackground = {\n                      ...(color ? { color } : {}),\n                      ...(opacity != null ? { opacity } : {}),\n                      ...(padding != null ? { padding } : {}),\n                      ...(borderRadius != null ? { borderRadius } : {}),\n                    };\n                    return Object.keys(next).length > 0 ? next : undefined;\n                  })()\n                : undefined;\n\n            const next: AnnotationLabel = {\n              ...(text ? { text } : {}),\n              ...(template ? { template } : {}),\n              ...(decimals != null ? { decimals } : {}),\n              ...(offset ? { offset } : {}),\n              ...(anchor ? { anchor } : {}),\n              ...(background ? { background } : {}),\n            };\n\n            return Object.keys(next).length > 0 ? next : undefined;\n          })()\n        : undefined;\n\n    if (type === 'lineX') {\n      const x = sanitizeFiniteNumber(record.x);\n      if (x == null) continue;\n      const base: AnnotationConfig = { type: 'lineX', x, ...(id ? { id } : {}), ...(layer ? { layer } : {}), ...(style ? { style } : {}), ...(label ? { label } : {}) };\n      out.push(base);\n      continue;\n    }\n\n    if (type === 'lineY') {\n      const y = sanitizeFiniteNumber(record.y);\n      if (y == null) continue;\n      const base: AnnotationConfig = { type: 'lineY', y, ...(id ? { id } : {}), ...(layer ? { layer } : {}), ...(style ? { style } : {}), ...(label ? { label } : {}) };\n      out.push(base);\n      continue;\n    }\n\n    if (type === 'point') {\n      const x = sanitizeFiniteNumber(record.x);\n      const y = sanitizeFiniteNumber(record.y);\n      if (x == null || y == null) continue;\n      const markerRaw = record.marker;\n      const marker =\n        markerRaw && typeof markerRaw === 'object' && !Array.isArray(markerRaw)\n          ? (() => {\n              const m = markerRaw as Record<string, unknown>;\n              const symbolRaw = m.symbol;\n              const symbol = isScatterSymbol(symbolRaw) ? symbolRaw : undefined;\n              const size = sanitizeFiniteNumber(m.size);\n              const mStyleRaw = m.style;\n              const mStyle =\n                mStyleRaw && typeof mStyleRaw === 'object' && !Array.isArray(mStyleRaw)\n                  ? (() => {\n                      const s = mStyleRaw as Record<string, unknown>;\n                      const color = sanitizeString(s.color);\n                      const opacity = sanitizeOpacity01(s.opacity);\n                      const lineWidth = sanitizeFiniteNumber(s.lineWidth);\n                      const lineDash = sanitizeLineDash(s.lineDash);\n                      const next: Record<string, unknown> = {\n                        ...(color ? { color } : {}),\n                        ...(opacity != null ? { opacity } : {}),\n                        ...(lineWidth != null ? { lineWidth } : {}),\n                        ...(lineDash ? { lineDash } : {}),\n                      };\n                      return Object.keys(next).length > 0 ? (next as AnnotationConfig['style']) : undefined;\n                    })()\n                  : undefined;\n              const next: AnnotationPointMarker = {\n                ...(symbol ? { symbol } : {}),\n                ...(size != null ? { size } : {}),\n                ...(mStyle ? { style: mStyle } : {}),\n              };\n              return Object.keys(next).length > 0 ? next : undefined;\n            })()\n          : undefined;\n\n      const base: AnnotationConfig = {\n        type: 'point',\n        x,\n        y,\n        ...(marker ? { marker } : {}),\n        ...(id ? { id } : {}),\n        ...(layer ? { layer } : {}),\n        ...(style ? { style } : {}),\n        ...(label ? { label } : {}),\n      };\n      out.push(base);\n      continue;\n    }\n\n    // type === 'text'\n    {\n      const positionRaw = record.position;\n      const text = sanitizeString(record.text);\n      if (!text) continue;\n      if (!positionRaw || typeof positionRaw !== 'object' || Array.isArray(positionRaw)) continue;\n      const p = positionRaw as Record<string, unknown>;\n      const space = p.space;\n      if (space !== 'data' && space !== 'plot') continue;\n      const x = sanitizeFiniteNumber(p.x);\n      const y = sanitizeFiniteNumber(p.y);\n      if (x == null || y == null) continue;\n      const position = { space, x, y } as const;\n\n      const base: AnnotationConfig = {\n        type: 'text',\n        position,\n        text,\n        ...(id ? { id } : {}),\n        ...(layer ? { layer } : {}),\n        ...(style ? { style } : {}),\n        ...(label ? { label } : {}),\n      };\n      out.push(base);\n      continue;\n    }\n  }\n\n  if (out.length === 0) return undefined;\n  Object.freeze(out);\n  return out;\n};\n\nconst sanitizePalette = (palette: unknown): string[] => {\n  if (!Array.isArray(palette)) return [];\n  return palette\n    .filter((c): c is string => typeof c === 'string')\n    .map((c) => c.trim())\n    .filter((c) => c.length > 0);\n};\n\nconst resolveTheme = (themeInput: unknown): ThemeConfig => {\n  const base = getTheme('dark');\n\n  if (typeof themeInput === 'string') {\n    const name = themeInput.trim().toLowerCase();\n    return name === 'light' ? getTheme('light') : getTheme('dark');\n  }\n\n  if (themeInput === null || typeof themeInput !== 'object' || Array.isArray(themeInput)) {\n    return base;\n  }\n\n  const input = themeInput as Partial<Record<keyof ThemeConfig, unknown>>;\n  const takeString = (key: keyof ThemeConfig): string | undefined => {\n    const v = input[key];\n    if (typeof v !== 'string') return undefined;\n    const trimmed = v.trim();\n    return trimmed.length > 0 ? trimmed : undefined;\n  };\n\n  const fontSizeRaw = input.fontSize;\n  const fontSize =\n    typeof fontSizeRaw === 'number' && Number.isFinite(fontSizeRaw) ? fontSizeRaw : undefined;\n\n  const colorPaletteCandidate = sanitizePalette(input.colorPalette);\n\n  return {\n    backgroundColor: takeString('backgroundColor') ?? base.backgroundColor,\n    textColor: takeString('textColor') ?? base.textColor,\n    axisLineColor: takeString('axisLineColor') ?? base.axisLineColor,\n    axisTickColor: takeString('axisTickColor') ?? base.axisTickColor,\n    gridLineColor: takeString('gridLineColor') ?? base.gridLineColor,\n    colorPalette: colorPaletteCandidate.length > 0 ? colorPaletteCandidate : Array.from(base.colorPalette),\n    fontFamily: takeString('fontFamily') ?? base.fontFamily,\n    fontSize: fontSize ?? base.fontSize,\n  };\n};\n\nconst normalizeOptionalColor = (color: unknown): string | undefined => {\n  if (typeof color !== 'string') return undefined;\n  const trimmed = color.trim();\n  return trimmed.length > 0 ? trimmed : undefined;\n};\n\nconst normalizeSampling = (value: unknown): SeriesSampling | undefined => {\n  if (typeof value !== 'string') return undefined;\n  const v = value.trim().toLowerCase();\n  return v === 'none' || v === 'lttb' || v === 'average' || v === 'max' || v === 'min' || v === 'ohlc'\n    ? (v as SeriesSampling)\n    : undefined;\n};\n\nconst normalizeScatterMode = (value: unknown): NonNullable<ScatterSeriesConfig['mode']> | undefined => {\n  if (typeof value !== 'string') return undefined;\n  const v = value.trim().toLowerCase();\n  return v === 'points' || v === 'density' ? (v as NonNullable<ScatterSeriesConfig['mode']>) : undefined;\n};\n\nconst normalizeDensityNormalization = (\n  value: unknown\n): NonNullable<ScatterSeriesConfig['densityNormalization']> | undefined => {\n  if (typeof value !== 'string') return undefined;\n  const v = value.trim().toLowerCase();\n  return v === 'linear' || v === 'sqrt' || v === 'log'\n    ? (v as NonNullable<ScatterSeriesConfig['densityNormalization']>)\n    : undefined;\n};\n\nconst normalizeDensityBinSize = (value: unknown): number | undefined => {\n  if (typeof value !== 'number' || !Number.isFinite(value)) return undefined;\n  const v = Math.floor(value);\n  return v > 0 ? Math.max(1, v) : undefined;\n};\n\nconst normalizeDensityColormap = (\n  value: unknown\n): NonNullable<ScatterSeriesConfig['densityColormap']> | undefined => {\n  if (typeof value === 'string') {\n    const v = value.trim().toLowerCase();\n    return v === 'viridis' || v === 'plasma' || v === 'inferno'\n      ? (v as NonNullable<ScatterSeriesConfig['densityColormap']>)\n      : undefined;\n  }\n\n  if (!Array.isArray(value)) return undefined;\n\n  const isAlreadyCleanStringArray =\n    value.length > 0 && value.every((c) => typeof c === 'string' && c.length > 0 && c === c.trim());\n\n  if (isAlreadyCleanStringArray) {\n    const arr = value as string[];\n    if (!Object.isFrozen(arr)) Object.freeze(arr);\n    return arr as readonly string[];\n  }\n\n  const sanitized = value\n    .filter((c): c is string => typeof c === 'string')\n    .map((c) => c.trim())\n    .filter((c) => c.length > 0);\n\n  if (sanitized.length === 0) return undefined;\n  Object.freeze(sanitized);\n  return sanitized as readonly string[];\n};\n\nconst normalizeCandlestickSampling = (value: unknown): 'none' | 'ohlc' | undefined => {\n  if (typeof value !== 'string') return undefined;\n  const v = value.trim().toLowerCase();\n  return v === 'none' || v === 'ohlc' ? (v as 'none' | 'ohlc') : undefined;\n};\n\nconst normalizeSamplingThreshold = (value: unknown): number | undefined => {\n  if (typeof value !== 'number' || !Number.isFinite(value)) return undefined;\n  const t = Math.floor(value);\n  return t > 0 ? t : undefined;\n};\n\nconst normalizeAxisAutoBounds = (value: unknown): AxisConfig['autoBounds'] | undefined => {\n  if (typeof value !== 'string') return undefined;\n  const v = value.trim().toLowerCase();\n  return v === 'global' || v === 'visible' ? (v as AxisConfig['autoBounds']) : undefined;\n};\n\nconst isTupleOHLCDataPoint = (p: OHLCDataPoint): p is OHLCDataPointTuple => Array.isArray(p);\n\nconst computeRawBoundsFromOHLC = (data: ReadonlyArray<OHLCDataPoint>): RawBounds | undefined => {\n  if (data.length === 0) return undefined;\n\n  let xMin = Number.POSITIVE_INFINITY;\n  let xMax = Number.NEGATIVE_INFINITY;\n  let yMin = Number.POSITIVE_INFINITY;\n  let yMax = Number.NEGATIVE_INFINITY;\n\n  // Hoist tuple-vs-object detection once (assume homogeneous arrays).\n  const isTuple = isTupleOHLCDataPoint(data[0]!);\n\n  if (isTuple) {\n    // Tuple format path: [timestamp, open, close, low, high]\n    const dataAsTuples = data as ReadonlyArray<OHLCDataPointTuple>;\n\n    for (let i = 0; i < dataAsTuples.length; i++) {\n      const p = dataAsTuples[i]!;\n      const x = p[0];\n      const low = p[3];\n      const high = p[4];\n      if (!Number.isFinite(x) || !Number.isFinite(low) || !Number.isFinite(high)) continue;\n\n      const yLow = Math.min(low, high);\n      const yHigh = Math.max(low, high);\n\n      if (x < xMin) xMin = x;\n      if (x > xMax) xMax = x;\n      if (yLow < yMin) yMin = yLow;\n      if (yHigh > yMax) yMax = yHigh;\n    }\n  } else {\n    // Object format path: { timestamp, open, close, low, high }\n    const dataAsObjects = data as ReadonlyArray<Exclude<OHLCDataPoint, OHLCDataPointTuple>>;\n\n    for (let i = 0; i < dataAsObjects.length; i++) {\n      const p = dataAsObjects[i]!;\n      const x = p.timestamp;\n      const low = p.low;\n      const high = p.high;\n      if (!Number.isFinite(x) || !Number.isFinite(low) || !Number.isFinite(high)) continue;\n\n      const yLow = Math.min(low, high);\n      const yHigh = Math.max(low, high);\n\n      if (x < xMin) xMin = x;\n      if (x > xMax) xMax = x;\n      if (yLow < yMin) yMin = yLow;\n      if (yHigh > yMax) yMax = yHigh;\n    }\n  }\n\n  if (!Number.isFinite(xMin) || !Number.isFinite(xMax) || !Number.isFinite(yMin) || !Number.isFinite(yMax)) {\n    return undefined;\n  }\n\n  // Keep bounds usable for downstream scale derivation.\n  if (xMin === xMax) xMax = xMin + 1;\n  if (yMin === yMax) yMax = yMin + 1;\n\n  return { xMin, xMax, yMin, yMax };\n};\n\nconst assertUnreachable = (value: never): never => {\n  // Should never happen if SeriesConfig union is exhaustively handled.\n  // This is defensive runtime safety for JS callers / invalid inputs.\n  throw new Error(\n    `Unhandled series type: ${\n      (value as unknown as { readonly type?: unknown } | null)?.type ?? 'unknown'\n    }`\n  );\n};\n\nlet candlestickWarned = false;\nconst warnCandlestickNotImplemented = (): void => {\n  if (!candlestickWarned) {\n    console.warn(\n      'ChartGPU: Candlestick series rendering is not yet implemented. Series will be skipped.'\n    );\n    candlestickWarned = true;\n  }\n};\n\nexport function resolveOptions(userOptions: ChartGPUOptions = {}): ResolvedChartGPUOptions {\n  const baseTheme = resolveTheme(userOptions.theme);\n\n  // runtime safety for JS callers\n  const autoScrollRaw = (userOptions as unknown as { readonly autoScroll?: unknown }).autoScroll;\n  const autoScroll = typeof autoScrollRaw === 'boolean' ? autoScrollRaw : defaultOptions.autoScroll;\n\n  // runtime safety for JS callers\n  const animationRaw = (userOptions as unknown as { readonly animation?: unknown }).animation;\n  const animationCandidate: ChartGPUOptions['animation'] =\n    typeof animationRaw === 'boolean' ||\n    (animationRaw !== null && typeof animationRaw === 'object' && !Array.isArray(animationRaw))\n      ? (animationRaw as ChartGPUOptions['animation'])\n      : undefined;\n  // Default: animation enabled (with defaults) unless explicitly disabled.\n  const animation: ChartGPUOptions['animation'] = animationCandidate ?? true;\n\n  // Backward compatibility:\n  // - If `userOptions.palette` is provided (non-empty), treat it as an override for the theme palette.\n  const paletteOverride = sanitizePalette(userOptions.palette);\n\n  const themeCandidate: ThemeConfig =\n    paletteOverride.length > 0 ? { ...baseTheme, colorPalette: paletteOverride } : baseTheme;\n\n  // Ensure palette used for modulo indexing is never empty.\n  const paletteFromTheme = sanitizePalette(themeCandidate.colorPalette);\n  const safePalette =\n    paletteFromTheme.length > 0\n      ? paletteFromTheme\n      : sanitizePalette(defaultOptions.palette ?? defaultPalette).length > 0\n        ? sanitizePalette(defaultOptions.palette ?? defaultPalette)\n        : Array.from(defaultPalette);\n\n  const paletteForIndexing = safePalette.length > 0 ? safePalette : ['#000000'];\n  const theme: ThemeConfig = { ...themeCandidate, colorPalette: paletteForIndexing.slice() };\n\n  const grid: ResolvedGridConfig = {\n    left: userOptions.grid?.left ?? defaultOptions.grid.left,\n    right: userOptions.grid?.right ?? defaultOptions.grid.right,\n    top: userOptions.grid?.top ?? defaultOptions.grid.top,\n    bottom: userOptions.grid?.bottom ?? defaultOptions.grid.bottom,\n  };\n\n  const xAxis: AxisConfig = userOptions.xAxis\n    ? {\n        ...defaultOptions.xAxis,\n        ...userOptions.xAxis,\n        // runtime safety for JS callers\n        type: (userOptions.xAxis as unknown as Partial<AxisConfig>).type ?? defaultOptions.xAxis.type,\n        autoBounds:\n          normalizeAxisAutoBounds((userOptions.xAxis as unknown as { readonly autoBounds?: unknown }).autoBounds) ??\n          (defaultOptions.xAxis as AxisConfig).autoBounds,\n      }\n    : { ...defaultOptions.xAxis };\n\n  const yAxis: AxisConfig = userOptions.yAxis\n    ? {\n        ...defaultOptions.yAxis,\n        ...userOptions.yAxis,\n        // runtime safety for JS callers\n        type: (userOptions.yAxis as unknown as Partial<AxisConfig>).type ?? defaultOptions.yAxis.type,\n        autoBounds:\n          normalizeAxisAutoBounds((userOptions.yAxis as unknown as { readonly autoBounds?: unknown }).autoBounds) ??\n          defaultOptions.yAxis.autoBounds,\n      }\n    : { ...defaultOptions.yAxis };\n\n  const series: ReadonlyArray<ResolvedSeriesConfig> = (userOptions.series ?? []).map((s, i) => {\n    const explicitColor = normalizeOptionalColor(s.color);\n    const inheritedColor = theme.colorPalette[i % theme.colorPalette.length];\n    const color = explicitColor ?? inheritedColor;\n\n    // Ensure visible defaults to true (converts undefined to true, preserves explicit false)\n    const visible = s.visible !== false;\n\n    const sampling: SeriesSampling = normalizeSampling((s as unknown as { sampling?: unknown }).sampling) ?? 'lttb';\n    const samplingThreshold: number =\n      normalizeSamplingThreshold((s as unknown as { samplingThreshold?: unknown }).samplingThreshold) ?? 5000;\n\n    switch (s.type) {\n      case 'area': {\n        // Resolve effective fill color with precedence: areaStyle.color → series.color → palette\n        const areaStyleColor = normalizeOptionalColor(s.areaStyle?.color);\n        const effectiveColor = areaStyleColor ?? explicitColor ?? inheritedColor;\n\n        const areaStyle: ResolvedAreaStyleConfig = {\n          opacity: s.areaStyle?.opacity ?? defaultAreaStyle.opacity,\n          color: effectiveColor,\n        };\n\n        const rawBounds = computeRawBoundsFromCartesianData(s.data) ?? undefined;\n        return {\n          ...s,\n          visible,\n          rawData: s.data,\n          data: sampleSeriesDataPoints(s.data, sampling, samplingThreshold),\n          color: effectiveColor,\n          areaStyle,\n          sampling,\n          samplingThreshold,\n          rawBounds,\n        };\n      }\n      case 'line': {\n        // Resolve effective stroke color with precedence: lineStyle.color → series.color → palette\n        const lineStyleColor = normalizeOptionalColor(s.lineStyle?.color);\n        const effectiveStrokeColor = lineStyleColor ?? explicitColor ?? inheritedColor;\n\n        const lineStyle: ResolvedLineStyleConfig = {\n          width: s.lineStyle?.width ?? defaultLineStyle.width,\n          opacity: s.lineStyle?.opacity ?? defaultLineStyle.opacity,\n          color: effectiveStrokeColor,\n        };\n\n        // Avoid leaking the unresolved (user) areaStyle shape via object spread.\n        const { areaStyle: _userAreaStyle, ...rest } = s;\n        const rawBounds = computeRawBoundsFromCartesianData(s.data) ?? undefined;\n        const sampledData = sampleSeriesDataPoints(s.data, sampling, samplingThreshold);\n\n        return {\n          ...rest,\n          visible,\n          rawData: s.data,\n          data: sampledData,\n          color: effectiveStrokeColor,\n          lineStyle,\n          ...(s.areaStyle\n            ? {\n                areaStyle: {\n                  opacity: s.areaStyle.opacity ?? defaultAreaStyle.opacity,\n                  // Fill color precedence: areaStyle.color → resolved stroke color\n                  color: normalizeOptionalColor(s.areaStyle.color) ?? effectiveStrokeColor,\n                },\n              }\n            : {}),\n          sampling,\n          samplingThreshold,\n          rawBounds,\n        };\n      }\n      case 'bar': {\n        const rawBounds = computeRawBoundsFromCartesianData(s.data) ?? undefined;\n        return {\n          ...s,\n          visible,\n          rawData: s.data,\n          data: sampleSeriesDataPoints(s.data, sampling, samplingThreshold),\n          color,\n          sampling,\n          samplingThreshold,\n          rawBounds,\n        };\n      }\n      case 'scatter': {\n        const rawBounds = computeRawBoundsFromCartesianData(s.data) ?? undefined;\n        const mode =\n          normalizeScatterMode((s as unknown as { readonly mode?: unknown }).mode) ?? scatterDefaults.mode;\n        const binSize =\n          normalizeDensityBinSize((s as unknown as { readonly binSize?: unknown }).binSize) ?? scatterDefaults.binSize;\n        const densityColormap =\n          normalizeDensityColormap((s as unknown as { readonly densityColormap?: unknown }).densityColormap) ??\n          scatterDefaults.densityColormap;\n        const densityNormalization =\n          normalizeDensityNormalization(\n            (s as unknown as { readonly densityNormalization?: unknown }).densityNormalization\n          ) ?? scatterDefaults.densityNormalization;\n        return {\n          ...s,\n          visible,\n          rawData: s.data,\n          data: sampleSeriesDataPoints(s.data, sampling, samplingThreshold),\n          color,\n          mode,\n          binSize,\n          densityColormap,\n          densityNormalization,\n          sampling,\n          samplingThreshold,\n          rawBounds,\n        };\n      }\n      case 'pie': {\n        // Pie series intentionally do NOT support sampling at runtime.\n        // For JS callers, strip any extra sampling keys so they don't leak through the resolver.\n        const { sampling: _sampling, samplingThreshold: _samplingThreshold, ...rest } = s as PieSeriesConfig & {\n          readonly sampling?: unknown;\n          readonly samplingThreshold?: unknown;\n        };\n\n        const resolvedData: ReadonlyArray<ResolvedPieDataItem> = (s.data ?? []).map((item, itemIndex) => {\n          const itemColor = normalizeOptionalColor(item?.color);\n          const fallback = theme.colorPalette[(i + itemIndex) % theme.colorPalette.length];\n          // Ensure visible defaults to true (converts undefined to true, preserves explicit false)\n          const itemVisible = item?.visible !== false;\n          return {\n            ...item,\n            color: itemColor ?? fallback,\n            visible: itemVisible,\n          };\n        });\n\n        return { ...rest, visible, color, data: resolvedData };\n      }\n      case 'candlestick': {\n        warnCandlestickNotImplemented();\n\n        const resolvedSampling: 'none' | 'ohlc' =\n          normalizeCandlestickSampling((s as unknown as { sampling?: unknown }).sampling) ??\n          candlestickDefaults.sampling;\n\n        const resolvedSamplingThreshold: number =\n          normalizeSamplingThreshold((s as unknown as { samplingThreshold?: unknown }).samplingThreshold) ??\n          candlestickDefaults.samplingThreshold;\n\n        const resolvedItemStyle: ResolvedCandlestickItemStyleConfig = {\n          upColor: normalizeOptionalColor(s.itemStyle?.upColor) ?? candlestickDefaults.itemStyle.upColor,\n          downColor: normalizeOptionalColor(s.itemStyle?.downColor) ?? candlestickDefaults.itemStyle.downColor,\n          upBorderColor: normalizeOptionalColor(s.itemStyle?.upBorderColor) ?? candlestickDefaults.itemStyle.upBorderColor,\n          downBorderColor: normalizeOptionalColor(s.itemStyle?.downBorderColor) ?? candlestickDefaults.itemStyle.downBorderColor,\n          borderWidth: typeof s.itemStyle?.borderWidth === 'number' && Number.isFinite(s.itemStyle.borderWidth)\n            ? s.itemStyle.borderWidth\n            : candlestickDefaults.itemStyle.borderWidth,\n        };\n\n        const rawBounds = computeRawBoundsFromOHLC(s.data);\n\n        const sampledData =\n          resolvedSampling === 'ohlc' && s.data.length > resolvedSamplingThreshold\n            ? ohlcSample(s.data, resolvedSamplingThreshold)\n            : s.data;\n\n        return {\n          ...s,\n          visible,\n          rawData: s.data,\n          data: sampledData,\n          color,\n          style: s.style ?? candlestickDefaults.style,\n          itemStyle: resolvedItemStyle,\n          barWidth: s.barWidth ?? candlestickDefaults.barWidth,\n          barMinWidth: s.barMinWidth ?? candlestickDefaults.barMinWidth,\n          barMaxWidth: s.barMaxWidth ?? candlestickDefaults.barMaxWidth,\n          sampling: resolvedSampling,\n          samplingThreshold: resolvedSamplingThreshold,\n          rawBounds,\n        };\n      }\n      default: {\n        return assertUnreachable(s);\n      }\n    }\n  });\n\n  return {\n    grid,\n    xAxis,\n    yAxis,\n    autoScroll,\n    dataZoom: sanitizeDataZoom((userOptions as ChartGPUOptions).dataZoom),\n    annotations: sanitizeAnnotations((userOptions as ChartGPUOptions).annotations),\n    animation,\n    theme,\n    palette: theme.colorPalette,\n    series,\n    legend: userOptions.legend,\n  };\n}\n\n/**\n * Data zoom slider dimensions (CSS pixels).\n *\n * Note: these are internal implementation details used to reserve chart space for the\n * slider overlay. We intentionally do not re-export them from the public entrypoint.\n */\nconst DATA_ZOOM_SLIDER_HEIGHT_CSS_PX = 32;\nconst DATA_ZOOM_SLIDER_MARGIN_TOP_CSS_PX = 8;\nconst DATA_ZOOM_SLIDER_RESERVE_CSS_PX =\n  DATA_ZOOM_SLIDER_HEIGHT_CSS_PX + DATA_ZOOM_SLIDER_MARGIN_TOP_CSS_PX;\n\n/**\n * Checks if options include a slider-type dataZoom configuration.\n * \n * @param options - Chart options to check\n * @returns True if slider dataZoom exists\n */\nconst hasSliderDataZoom = (options: ChartGPUOptions): boolean =>\n  options.dataZoom?.some((z) => z?.type === 'slider') ?? false;\n\n/**\n * Resolves chart options with slider bottom-space reservation.\n * \n * This function wraps `resolveOptions()` and applies additional grid bottom spacing\n * when a slider-type dataZoom is configured. The reservation ensures x-axis labels\n * and ticks are visible above the slider overlay.\n * \n * **Usage**: Use this function instead of `resolveOptions()` when creating charts\n * to ensure consistent slider layout.\n * \n * @param userOptions - User-provided chart options\n * @returns Resolved options with slider bottom-space applied if needed\n */\nexport function resolveOptionsForChart(userOptions: ChartGPUOptions = {}): ResolvedChartGPUOptions {\n  const base: ResolvedChartGPUOptions = { ...resolveOptions(userOptions), tooltip: userOptions.tooltip };\n  if (!hasSliderDataZoom(userOptions)) return base;\n  return {\n    ...base,\n    grid: {\n      ...base.grid,\n      bottom: base.grid.bottom + DATA_ZOOM_SLIDER_RESERVE_CSS_PX,\n    },\n  };\n}\n\nexport const OptionResolver = { resolve: resolveOptions } as const;\n\n","import type { ZoomRange, ZoomState } from '../interaction/createZoomState';\nimport type { ThemeConfig } from '../themes/types';\n\nexport interface DataZoomSlider {\n  update(theme: ThemeConfig): void;\n  dispose(): void;\n}\n\nexport interface DataZoomSliderOptions {\n  readonly height?: number;\n  readonly marginTop?: number;\n  readonly zIndex?: number;\n  readonly showPreview?: boolean;\n}\n\nconst clamp = (v: number, lo: number, hi: number): number => Math.min(hi, Math.max(lo, v));\n\nconst normalizeRange = (range: ZoomRange): ZoomRange => {\n  let { start, end } = range;\n  if (start > end) {\n    const t = start;\n    start = end;\n    end = t;\n  }\n  return { start: clamp(start, 0, 100), end: clamp(end, 0, 100) };\n};\n\ntype DragMode = 'left-handle' | 'right-handle' | 'pan-window';\n\nexport function createDataZoomSlider(\n  container: HTMLElement,\n  zoomState: ZoomState,\n  options?: DataZoomSliderOptions\n): DataZoomSlider {\n  const height = options?.height ?? 32;\n  const marginTop = options?.marginTop ?? 8;\n  const zIndex = options?.zIndex ?? 4;\n  const showPreview = options?.showPreview ?? false;\n\n  const root = document.createElement('div');\n  root.style.display = 'block';\n  root.style.width = '100%';\n  root.style.height = `${height}px`;\n  root.style.marginTop = `${marginTop}px`;\n  root.style.boxSizing = 'border-box';\n  root.style.position = 'relative';\n  root.style.zIndex = `${zIndex}`;\n  root.style.userSelect = 'none';\n  root.style.touchAction = 'none';\n\n  // track: full-width bar that hosts preview + window selection.\n  const track = document.createElement('div');\n  track.style.position = 'relative';\n  track.style.height = '100%';\n  track.style.width = '100%';\n  track.style.boxSizing = 'border-box';\n  track.style.borderRadius = '8px';\n  track.style.borderStyle = 'solid';\n  track.style.borderWidth = '1px';\n  track.style.overflow = 'hidden';\n  root.appendChild(track);\n\n  // preview: miniature context under the selection (optional; can be a solid bar for now).\n  const preview = document.createElement('div');\n  preview.style.position = 'absolute';\n  preview.style.inset = '0';\n  preview.style.pointerEvents = 'none';\n  preview.style.opacity = '0.4';\n  preview.style.display = showPreview ? 'block' : 'none';\n  track.appendChild(preview);\n\n  // window: the selected range.\n  const windowEl = document.createElement('div');\n  windowEl.style.position = 'absolute';\n  windowEl.style.top = '0';\n  windowEl.style.bottom = '0';\n  windowEl.style.left = '0%';\n  windowEl.style.width = '100%';\n  windowEl.style.boxSizing = 'border-box';\n  windowEl.style.cursor = 'grab';\n  track.appendChild(windowEl);\n\n  // left/right handles.\n  const leftHandle = document.createElement('div');\n  leftHandle.style.position = 'absolute';\n  leftHandle.style.left = '0';\n  leftHandle.style.top = '0';\n  leftHandle.style.bottom = '0';\n  leftHandle.style.width = '10px';\n  leftHandle.style.cursor = 'ew-resize';\n  windowEl.appendChild(leftHandle);\n\n  const rightHandle = document.createElement('div');\n  rightHandle.style.position = 'absolute';\n  rightHandle.style.right = '0';\n  rightHandle.style.top = '0';\n  rightHandle.style.bottom = '0';\n  rightHandle.style.width = '10px';\n  rightHandle.style.cursor = 'ew-resize';\n  windowEl.appendChild(rightHandle);\n\n  // center grip (hit target for panning).\n  const centerGrip = document.createElement('div');\n  centerGrip.style.position = 'absolute';\n  centerGrip.style.left = '10px';\n  centerGrip.style.right = '10px';\n  centerGrip.style.top = '0';\n  centerGrip.style.bottom = '0';\n  centerGrip.style.cursor = 'grab';\n  windowEl.appendChild(centerGrip);\n\n  container.appendChild(root);\n\n  let disposed = false;\n  let activeDragCleanup: (() => void) | null = null;\n\n  const applyRangeToDom = (range: ZoomRange): void => {\n    const r = normalizeRange(range);\n    const span = clamp(r.end - r.start, 0, 100);\n    windowEl.style.left = `${r.start}%`;\n    windowEl.style.width = `${span}%`;\n  };\n\n  const getTrackWidthPx = (): number | null => {\n    // getBoundingClientRect() is robust even if the container is scaled.\n    const w = track.getBoundingClientRect().width;\n    return Number.isFinite(w) && w > 0 ? w : null;\n  };\n\n  const pxToPercent = (dxPx: number): number | null => {\n    const w = getTrackWidthPx();\n    if (w === null) return null;\n    const p = (dxPx / w) * 100;\n    return Number.isFinite(p) ? p : null;\n  };\n\n  const setPointerCaptureBestEffort = (el: Element, pointerId: number): void => {\n    try {\n      (el as HTMLElement).setPointerCapture(pointerId);\n    } catch {\n      // Ignore (best-effort).\n    }\n  };\n\n  const releasePointerCaptureBestEffort = (el: Element, pointerId: number): void => {\n    try {\n      (el as HTMLElement).releasePointerCapture(pointerId);\n    } catch {\n      // Ignore (best-effort).\n    }\n  };\n\n  const startDrag = (e: PointerEvent, mode: DragMode): void => {\n    if (disposed) return;\n    if (e.button !== 0) return;\n\n    e.preventDefault();\n\n    // If we somehow start a new drag while another is in-flight, clean up first.\n    activeDragCleanup?.();\n    activeDragCleanup = null;\n\n    const dragStartX = e.clientX;\n    const startRange = zoomState.getRange();\n\n    const target = e.currentTarget instanceof Element ? e.currentTarget : windowEl;\n    setPointerCaptureBestEffort(target, e.pointerId);\n\n    if (mode === 'pan-window') {\n      windowEl.style.cursor = 'grabbing';\n      centerGrip.style.cursor = 'grabbing';\n    }\n\n    const onMove = (ev: PointerEvent): void => {\n      if (disposed) return;\n      if (ev.pointerId !== e.pointerId) return;\n\n      ev.preventDefault();\n\n      const dxPercent = pxToPercent(ev.clientX - dragStartX);\n      if (dxPercent === null) return;\n\n      switch (mode) {\n        case 'left-handle': {\n          // UX: don't allow handle crossing; clamp left <= current end.\n          const nextStart = Math.min(startRange.end, startRange.start + dxPercent);\n          const anchored = zoomState as unknown as Partial<{\n            setRangeAnchored: (start: number, end: number, anchor: 'start' | 'end' | 'center') => void;\n          }>;\n          if (anchored.setRangeAnchored) {\n            // When clamped by minSpan/maxSpan, keep the right edge anchored (prevents jumpiness).\n            anchored.setRangeAnchored(nextStart, startRange.end, 'end');\n          } else {\n            zoomState.setRange(nextStart, startRange.end);\n          }\n          return;\n        }\n        case 'right-handle': {\n          // UX: don't allow handle crossing; clamp right >= current start.\n          const nextEnd = Math.max(startRange.start, startRange.end + dxPercent);\n          const anchored = zoomState as unknown as Partial<{\n            setRangeAnchored: (start: number, end: number, anchor: 'start' | 'end' | 'center') => void;\n          }>;\n          if (anchored.setRangeAnchored) {\n            // When clamped by minSpan/maxSpan, keep the left edge anchored (prevents jumpiness).\n            anchored.setRangeAnchored(startRange.start, nextEnd, 'start');\n          } else {\n            zoomState.setRange(startRange.start, nextEnd);\n          }\n          return;\n        }\n        case 'pan-window': {\n          zoomState.setRange(startRange.start + dxPercent, startRange.end + dxPercent);\n          return;\n        }\n      }\n    };\n\n    let cleanedUp = false;\n\n    const cleanup = (): void => {\n      if (cleanedUp) return;\n      cleanedUp = true;\n\n      window.removeEventListener('pointermove', onMove);\n      window.removeEventListener('pointerup', finish);\n      window.removeEventListener('pointercancel', finish);\n\n      if (mode === 'pan-window') {\n        windowEl.style.cursor = 'grab';\n        centerGrip.style.cursor = 'grab';\n      }\n\n      releasePointerCaptureBestEffort(target, e.pointerId);\n\n      // Only clear if we're still the active drag.\n      if (activeDragCleanup === cleanup) activeDragCleanup = null;\n    };\n\n    const finish = (ev: PointerEvent): void => {\n      if (ev.pointerId !== e.pointerId) return;\n      cleanup();\n    };\n\n    activeDragCleanup = cleanup;\n\n    window.addEventListener('pointermove', onMove, { passive: false });\n    window.addEventListener('pointerup', finish, { passive: true });\n    window.addEventListener('pointercancel', finish, { passive: true });\n  };\n\n  const onLeftDown = (e: PointerEvent): void => startDrag(e, 'left-handle');\n  const onRightDown = (e: PointerEvent): void => startDrag(e, 'right-handle');\n  const onPanDown = (e: PointerEvent): void => startDrag(e, 'pan-window');\n\n  leftHandle.addEventListener('pointerdown', onLeftDown, { passive: false });\n  rightHandle.addEventListener('pointerdown', onRightDown, { passive: false });\n  centerGrip.addEventListener('pointerdown', onPanDown, { passive: false });\n\n  // Keep DOM in sync with state.\n  const unsubscribe = zoomState.onChange((range) => {\n    if (disposed) return;\n    applyRangeToDom(range);\n  });\n\n  // Initialize UI.\n  applyRangeToDom(zoomState.getRange());\n\n  const update: DataZoomSlider['update'] = (theme) => {\n    if (disposed) return;\n\n    // Baseline track styling.\n    track.style.background = theme.backgroundColor;\n    track.style.borderColor = theme.axisLineColor;\n\n    // Preview styling (placeholder).\n    preview.style.background = theme.gridLineColor;\n\n    // Window styling.\n    windowEl.style.background = theme.gridLineColor;\n    windowEl.style.border = `1px solid ${theme.axisTickColor}`;\n    windowEl.style.borderRadius = '8px';\n    windowEl.style.boxSizing = 'border-box';\n\n    // Handles styling.\n    const handleBorder = `1px solid ${theme.axisLineColor}`;\n    leftHandle.style.background = theme.axisTickColor;\n    leftHandle.style.borderRight = handleBorder;\n    rightHandle.style.background = theme.axisTickColor;\n    rightHandle.style.borderLeft = handleBorder;\n\n    // Center grip styling: subtle stripes.\n    centerGrip.style.background = 'transparent';\n    centerGrip.style.backgroundImage =\n      'linear-gradient(90deg, rgba(255,255,255,0.0) 0, rgba(255,255,255,0.0) 42%, rgba(255,255,255,0.18) 42%, rgba(255,255,255,0.18) 46%, rgba(255,255,255,0.0) 46%, rgba(255,255,255,0.0) 54%, rgba(255,255,255,0.18) 54%, rgba(255,255,255,0.18) 58%, rgba(255,255,255,0.0) 58%, rgba(255,255,255,0.0) 100%)';\n    centerGrip.style.mixBlendMode = 'normal';\n  };\n\n  const dispose: DataZoomSlider['dispose'] = () => {\n    if (disposed) return;\n    disposed = true;\n\n    // If dispose happens during an active drag, ensure we remove all window listeners.\n    activeDragCleanup?.();\n    activeDragCleanup = null;\n\n    try {\n      unsubscribe();\n    } catch {\n      // Best-effort.\n    }\n\n    leftHandle.removeEventListener('pointerdown', onLeftDown);\n    rightHandle.removeEventListener('pointerdown', onRightDown);\n    centerGrip.removeEventListener('pointerdown', onPanDown);\n\n    root.remove();\n  };\n\n  return { update, dispose };\n}\n\n","/**\n * WebGPU support detection and validation\n * \n * Provides utilities to check if WebGPU is available and usable in the current environment.\n * Results are memoized to avoid redundant checks.\n */\n\n/**\n * Result of WebGPU support check\n */\nexport interface WebGPUSupportResult {\n  /** Whether WebGPU is supported and available */\n  readonly supported: boolean;\n  /** Optional reason explaining why WebGPU is not supported */\n  readonly reason?: string;\n}\n\n// Memoized support check result\nlet cachedSupportCheck: Promise<WebGPUSupportResult> | null = null;\n\n/**\n * Checks if WebGPU is supported and available in the current environment.\n * \n * This function performs comprehensive checks:\n * - SSR-safe: validates that window and navigator are available\n * - Checks for navigator.gpu API presence\n * - Attempts to request a WebGPU adapter to verify actual support\n * - First tries high-performance adapter to match GPUContext behavior\n * - Falls back to default adapter if high-performance fails\n * \n * The result is memoized for performance, so multiple calls return the same promise.\n * \n * @returns Promise resolving to support check result with optional reason\n * \n * @example\n * ```typescript\n * const { supported, reason } = await checkWebGPUSupport();\n * if (!supported) {\n *   console.error('WebGPU not available:', reason);\n * }\n * ```\n */\nexport async function checkWebGPUSupport(): Promise<WebGPUSupportResult> {\n  // Return cached result if available\n  if (cachedSupportCheck) {\n    return cachedSupportCheck;\n  }\n\n  // Create and cache the promise\n  cachedSupportCheck = (async (): Promise<WebGPUSupportResult> => {\n    // SSR-safe checks: ensure we're in a browser environment\n    if (typeof window === 'undefined') {\n      return {\n        supported: false,\n        reason: 'Not running in a browser environment (window is undefined).',\n      };\n    }\n\n    if (typeof navigator === 'undefined') {\n      return {\n        supported: false,\n        reason: 'Navigator is not available in this environment.',\n      };\n    }\n\n    // Check for navigator.gpu API\n    if (!navigator.gpu) {\n      return {\n        supported: false,\n        reason: 'WebGPU API (navigator.gpu) is not available. Your browser does not support WebGPU.',\n      };\n    }\n\n    // Attempt to request an adapter to verify actual support\n    try {\n      // First attempt: high-performance adapter (aligns with GPUContext behavior)\n      let adapter = await navigator.gpu.requestAdapter({\n        powerPreference: 'high-performance',\n      });\n\n      // Second attempt: default adapter if high-performance is unavailable\n      if (!adapter) {\n        adapter = await navigator.gpu.requestAdapter();\n      }\n\n      // If both attempts fail, WebGPU is not usable\n      if (!adapter) {\n        return {\n          supported: false,\n          reason: 'No compatible WebGPU adapter found. This may occur if: (1) no GPU is available, (2) GPU drivers are outdated or incompatible, (3) running in a VM or headless environment, or (4) WebGPU is disabled in browser settings.',\n        };\n      }\n\n      // Success: WebGPU is supported and an adapter is available\n      return { supported: true };\n    } catch (error) {\n      // Adapter request threw an error\n      let reason = 'Failed to request WebGPU adapter.';\n\n      // Try to extract useful error information\n      if (error instanceof DOMException) {\n        reason = `Failed to request WebGPU adapter: ${error.name}`;\n        if (error.message) {\n          reason += ` - ${error.message}`;\n        }\n      } else if (error instanceof Error) {\n        reason = `Failed to request WebGPU adapter: ${error.message}`;\n      } else {\n        reason = `Failed to request WebGPU adapter: ${String(error)}`;\n      }\n\n      return { supported: false, reason };\n    }\n  })();\n\n  return cachedSupportCheck;\n}\n","import { GPUContext } from './core/GPUContext';\nimport { createRenderCoordinator } from './core/createRenderCoordinator';\nimport type { RenderCoordinator } from './core/createRenderCoordinator';\nimport { resolveOptionsForChart } from './config/OptionResolver';\nimport type { ResolvedCandlestickSeriesConfig, ResolvedChartGPUOptions, ResolvedPieSeriesConfig } from './config/OptionResolver';\nimport type {\n  CartesianSeriesData,\n  ChartGPUOptions,\n  DataPoint,\n  DataPointTuple,\n  OHLCDataPoint,\n  OHLCDataPointTuple,\n  PieCenter,\n  PieRadius,\n} from './config/types';\nimport { createDataZoomSlider } from './components/createDataZoomSlider';\nimport type { DataZoomSlider } from './components/createDataZoomSlider';\nimport type { ZoomRange, ZoomState } from './interaction/createZoomState';\nimport { computeCandlestickBodyWidthRange, findCandlestick } from './interaction/findCandlestick';\nimport { findNearestPoint } from './interaction/findNearestPoint';\nimport type { NearestPointMatch } from './interaction/findNearestPoint';\nimport { findPieSlice } from './interaction/findPieSlice';\nimport { createLinearScale } from './utils/scales';\nimport type { LinearScale } from './utils/scales';\nimport { checkWebGPUSupport } from './utils/checkWebGPU';\nimport type {\n  PerformanceMetrics,\n  PerformanceCapabilities,\n  ExactFPS,\n  Milliseconds,\n  Bytes,\n  FrameTimeStats,\n  GPUTimingStats,\n  MemoryStats,\n  FrameDropStats,\n} from './config/types';\nimport {\n  computeRawBoundsFromCartesianData,\n  getPointCount as getCartesianPointCount,\n  getSize as getCartesianSize,\n  getX as getCartesianX,\n  getY as getCartesianY,\n} from './data/cartesianData';\n\n/**\n * Circular buffer size for frame timestamps (120 frames = 2 seconds at 60fps).\n */\nconst FRAME_BUFFER_SIZE = 120;\n\n/**\n * Expected frame time at 60fps (16.67ms).\n */\nconst EXPECTED_FRAME_TIME_MS = 1000 / 60;\n\n/**\n * Frame drop threshold multiplier (1.5x expected frame time).\n */\nconst FRAME_DROP_THRESHOLD_MULTIPLIER = 1.5;\n\n/**\n * Hit-test match for a chart element.\n */\nexport type ChartGPUHitTestMatch = Readonly<{\n  readonly kind: 'cartesian' | 'candlestick' | 'pie';\n  readonly seriesIndex: number;\n  readonly dataIndex: number;\n  readonly value: readonly [number, number];\n}>;\n\n/**\n * Result of a hit-test operation on a chart.\n */\nexport type ChartGPUHitTestResult = Readonly<{\n  readonly isInGrid: boolean;\n  readonly canvasX: number;\n  readonly canvasY: number;\n  readonly gridX: number;\n  readonly gridY: number;\n  readonly match: ChartGPUHitTestMatch | null;\n}>;\n\nexport interface ChartGPUInstance {\n  readonly options: Readonly<ChartGPUOptions>;\n  readonly disposed: boolean;\n  setOption(options: ChartGPUOptions): void;\n  /**\n   * Appends new points to a cartesian series at runtime (streaming).\n   *\n   * For candlestick series, pass `OHLCDataPoint[]`.\n   * For other cartesian series (line, area, bar, scatter), pass `DataPoint[]`.\n   * Pie series are non-cartesian and are not supported by streaming append.\n   */\n  appendData(seriesIndex: number, newPoints: DataPoint[] | OHLCDataPoint[]): void;\n  resize(): void;\n  dispose(): void;\n  on(eventName: 'crosshairMove', callback: ChartGPUCrosshairMoveCallback): void;\n  on(eventName: ChartGPUEventName, callback: ChartGPUEventCallback): void;\n  off(eventName: 'crosshairMove', callback: ChartGPUCrosshairMoveCallback): void;\n  off(eventName: ChartGPUEventName, callback: ChartGPUEventCallback): void;\n  /**\n   * Gets the current “interaction x” in domain units (or `null` when inactive).\n   *\n   * This is derived from pointer movement inside the plot grid and can also be driven\n   * externally via `setInteractionX(...)` (e.g. chart sync).\n   */\n  getInteractionX(): number | null;\n  /**\n   * Drives the chart’s crosshair + tooltip from a domain-space x value.\n   *\n   * Passing `null` clears the interaction (hides crosshair/tooltip).\n   */\n  setInteractionX(x: number | null, source?: unknown): void;\n  /**\n   * Alias for `setInteractionX(...)` for chart sync semantics.\n   */\n  setCrosshairX(x: number | null, source?: unknown): void;\n  /**\n   * Subscribes to interaction x changes (domain units).\n   *\n   * Returns an unsubscribe function.\n   */\n  onInteractionXChange(callback: (x: number | null, source?: unknown) => void): () => void;\n  /**\n   * Returns the current percent-space zoom window (or `null` when zoom is disabled).\n   */\n  getZoomRange(): Readonly<{ start: number; end: number }> | null;\n  /**\n   * Sets the percent-space zoom window.\n   *\n   * No-op when zoom is disabled.\n   */\n  setZoomRange(start: number, end: number): void;\n  /**\n   * Gets the latest performance metrics.\n   * Returns exact FPS and detailed frame statistics.\n   * \n   * @returns Current performance metrics, or null if not available\n   */\n  getPerformanceMetrics(): Readonly<PerformanceMetrics> | null;\n  /**\n   * Gets the performance capabilities of the current environment.\n   * Indicates which performance features are supported.\n   * \n   * @returns Performance capabilities, or null if not initialized\n   */\n  getPerformanceCapabilities(): Readonly<PerformanceCapabilities> | null;\n  /**\n   * Registers a callback to be notified of performance metric updates.\n   * Callback is invoked every frame with the latest metrics.\n   * \n   * @param callback - Function to call with updated metrics\n   * @returns Unsubscribe function to remove the callback\n   */\n  onPerformanceUpdate(callback: (metrics: Readonly<PerformanceMetrics>) => void): () => void;\n  /**\n   * Performs hit-testing on a pointer or mouse event.\n   *\n   * Returns coordinates and matched chart element (if any).\n   * Accepts both `PointerEvent` (for hover/click) and `MouseEvent` (for contextmenu/right-click).\n   *\n   * @param e - Pointer or mouse event to test\n   * @returns Hit-test result with coordinates and optional match\n   */\n  hitTest(e: PointerEvent | MouseEvent): ChartGPUHitTestResult;\n}\n\n// Type-only alias so callsites can write `ChartGPU[]` for chart instances (while `ChartGPU` the value\n// remains the creation API exported from `src/index.ts`).\nexport type ChartGPU = ChartGPUInstance;\n\nexport type ChartGPUEventName = 'click' | 'mouseover' | 'mouseout' | 'crosshairMove';\n\nexport type ChartGPUEventPayload = Readonly<{\n  readonly seriesIndex: number | null;\n  readonly dataIndex: number | null;\n  readonly value: readonly [number, number] | null;\n  readonly seriesName: string | null;\n  readonly event: PointerEvent;\n}>;\n\nexport type ChartGPUCrosshairMovePayload = Readonly<{\n  readonly x: number | null;\n  readonly source?: unknown;\n}>;\n\nexport type ChartGPUEventCallback = (payload: ChartGPUEventPayload) => void;\n\nexport type ChartGPUCrosshairMoveCallback = (payload: ChartGPUCrosshairMovePayload) => void;\n\ntype AnyChartGPUEventCallback = ChartGPUEventCallback | ChartGPUCrosshairMoveCallback;\n\ntype ListenerRegistry = Readonly<Record<ChartGPUEventName, Set<AnyChartGPUEventCallback>>>;\n\ntype TapCandidate = {\n  readonly pointerId: number;\n  readonly startClientX: number;\n  readonly startClientY: number;\n  readonly startTimeMs: number;\n};\n\nconst DEFAULT_TAP_MAX_DISTANCE_CSS_PX = 6;\nconst DEFAULT_TAP_MAX_TIME_MS = 500;\n\ntype Bounds = Readonly<{ xMin: number; xMax: number; yMin: number; yMax: number }>;\n\nconst isTupleDataPoint = (p: DataPoint): p is DataPointTuple => Array.isArray(p);\nconst isTupleOHLCDataPoint = (p: OHLCDataPoint): p is OHLCDataPointTuple => Array.isArray(p);\n\nconst getPointXY = (p: DataPoint): { readonly x: number; readonly y: number } => {\n  if (isTupleDataPoint(p)) return { x: p[0], y: p[1] };\n  return { x: p.x, y: p.y };\n};\n\nconst cartesianDataToDataPointArray = (data: CartesianSeriesData): DataPoint[] => {\n  // Clone DataPoint[] so we can mutate for streaming appends without touching user input.\n  if (Array.isArray(data)) return data.length === 0 ? [] : (data.slice() as DataPoint[]);\n\n  const n = getCartesianPointCount(data);\n  if (n === 0) return [];\n\n  const out: DataPoint[] = new Array(n);\n  for (let i = 0; i < n; i++) {\n    const x = getCartesianX(data, i);\n    const y = getCartesianY(data, i);\n    const size = getCartesianSize(data, i);\n    out[i] = (size === undefined ? [x, y] : [x, y, size]) as DataPointTuple;\n  }\n  return out;\n};\n\nconst getOHLCTimestamp = (p: OHLCDataPoint): number => (isTupleOHLCDataPoint(p) ? p[0] : p.timestamp);\nconst getOHLCClose = (p: OHLCDataPoint): number => (isTupleOHLCDataPoint(p) ? p[2] : p.close);\n\nconst hasSliderDataZoom = (options: ChartGPUOptions): boolean => options.dataZoom?.some((z) => z?.type === 'slider') ?? false;\n\nconst clamp = (v: number, lo: number, hi: number): number => Math.min(hi, Math.max(lo, v));\n\ntype InteractionScalesCache = {\n  rectWidthCss: number;\n  rectHeightCss: number;\n  plotWidthCss: number;\n  plotHeightCss: number;\n  xDomainMin: number;\n  xDomainMax: number;\n  yDomainMin: number;\n  yDomainMax: number;\n  xScale: LinearScale;\n  yScale: LinearScale;\n};\n\nconst computeRawBoundsFromData = (data: ReadonlyArray<DataPoint>): Bounds | null => {\n  let xMin = Number.POSITIVE_INFINITY;\n  let xMax = Number.NEGATIVE_INFINITY;\n  let yMin = Number.POSITIVE_INFINITY;\n  let yMax = Number.NEGATIVE_INFINITY;\n\n  for (let i = 0; i < data.length; i++) {\n    const { x, y } = getPointXY(data[i]!);\n    if (!Number.isFinite(x) || !Number.isFinite(y)) continue;\n    if (x < xMin) xMin = x;\n    if (x > xMax) xMax = x;\n    if (y < yMin) yMin = y;\n    if (y > yMax) yMax = y;\n  }\n\n  if (!Number.isFinite(xMin) || !Number.isFinite(xMax) || !Number.isFinite(yMin) || !Number.isFinite(yMax)) {\n    return null;\n  }\n\n  // Keep bounds usable for downstream scale derivation.\n  if (xMin === xMax) xMax = xMin + 1;\n  if (yMin === yMax) yMax = yMin + 1;\n\n  return { xMin, xMax, yMin, yMax };\n};\n\nconst extendBoundsWithDataPoints = (bounds: Bounds | null, points: ReadonlyArray<DataPoint>): Bounds | null => {\n  if (points.length === 0) return bounds;\n\n  let b = bounds;\n  if (!b) {\n    const seeded = computeRawBoundsFromData(points);\n    if (!seeded) return bounds;\n    b = seeded;\n  }\n\n  let xMin = b.xMin;\n  let xMax = b.xMax;\n  let yMin = b.yMin;\n  let yMax = b.yMax;\n\n  for (let i = 0; i < points.length; i++) {\n    const { x, y } = getPointXY(points[i]!);\n    if (!Number.isFinite(x) || !Number.isFinite(y)) continue;\n    if (x < xMin) xMin = x;\n    if (x > xMax) xMax = x;\n    if (y < yMin) yMin = y;\n    if (y > yMax) yMax = y;\n  }\n\n  // Keep bounds usable for downstream scale derivation.\n  if (xMin === xMax) xMax = xMin + 1;\n  if (yMin === yMax) yMax = yMin + 1;\n\n  return { xMin, xMax, yMin, yMax };\n};\n\nconst extendBoundsWithOHLCDataPoints = (bounds: Bounds | null, points: ReadonlyArray<OHLCDataPoint>): Bounds | null => {\n  if (points.length === 0) return bounds;\n\n  let xMin = bounds?.xMin ?? Number.POSITIVE_INFINITY;\n  let xMax = bounds?.xMax ?? Number.NEGATIVE_INFINITY;\n  let yMin = bounds?.yMin ?? Number.POSITIVE_INFINITY;\n  let yMax = bounds?.yMax ?? Number.NEGATIVE_INFINITY;\n\n  for (let i = 0; i < points.length; i++) {\n    const p = points[i]!;\n    const timestamp = getOHLCTimestamp(p);\n    const low = isTupleOHLCDataPoint(p) ? p[3] : p.low;\n    const high = isTupleOHLCDataPoint(p) ? p[4] : p.high;\n\n    if (!Number.isFinite(timestamp) || !Number.isFinite(low) || !Number.isFinite(high)) continue;\n    if (timestamp < xMin) xMin = timestamp;\n    if (timestamp > xMax) xMax = timestamp;\n    if (low < yMin) yMin = low;\n    if (high > yMax) yMax = high;\n  }\n\n  if (!Number.isFinite(xMin) || !Number.isFinite(xMax) || !Number.isFinite(yMin) || !Number.isFinite(yMax)) {\n    return bounds;\n  }\n\n  // Keep bounds usable for downstream scale derivation.\n  if (xMin === xMax) xMax = xMin + 1;\n  if (yMin === yMax) yMax = yMin + 1;\n\n  return { xMin, xMax, yMin, yMax };\n};\n\nconst computeGlobalBounds = (\n  series: ResolvedChartGPUOptions['series'],\n  runtimeRawBoundsByIndex?: ReadonlyArray<Bounds | null> | null\n): Bounds => {\n  let xMin = Number.POSITIVE_INFINITY;\n  let xMax = Number.NEGATIVE_INFINITY;\n  let yMin = Number.POSITIVE_INFINITY;\n  let yMax = Number.NEGATIVE_INFINITY;\n\n  for (let s = 0; s < series.length; s++) {\n    const seriesConfig = series[s]!;\n    // Pie series are non-cartesian; they don't participate in x/y bounds.\n    if (seriesConfig.type === 'pie') continue;\n\n    // Prefer the chart-owned runtime bounds (kept up to date by appendData()).\n    const runtimeBoundsCandidate = runtimeRawBoundsByIndex?.[s] ?? null;\n    if (runtimeBoundsCandidate) {\n      const b = runtimeBoundsCandidate;\n      if (\n        Number.isFinite(b.xMin) &&\n        Number.isFinite(b.xMax) &&\n        Number.isFinite(b.yMin) &&\n        Number.isFinite(b.yMax)\n      ) {\n        if (b.xMin < xMin) xMin = b.xMin;\n        if (b.xMax > xMax) xMax = b.xMax;\n        if (b.yMin < yMin) yMin = b.yMin;\n        if (b.yMax > yMax) yMax = b.yMax;\n        continue;\n      }\n    }\n\n    // Prefer resolver-provided bounds when available (avoids O(n) scans on initial setOption()).\n    // (Resolved series types include `rawBounds` for cartesian series; keep this defensive.)\n    const rawBoundsCandidate = (seriesConfig as unknown as { rawBounds?: Bounds | null }).rawBounds ?? null;\n    if (rawBoundsCandidate) {\n      const b = rawBoundsCandidate;\n      if (\n        Number.isFinite(b.xMin) &&\n        Number.isFinite(b.xMax) &&\n        Number.isFinite(b.yMin) &&\n        Number.isFinite(b.yMax)\n      ) {\n        if (b.xMin < xMin) xMin = b.xMin;\n        if (b.xMax > xMax) xMax = b.xMax;\n        if (b.yMin < yMin) yMin = b.yMin;\n        if (b.yMax > yMax) yMax = b.yMax;\n        continue;\n      }\n    }\n\n    if (seriesConfig.type === 'candlestick') {\n      // Fallback scan when resolver-provided bounds aren't present.\n      const data = seriesConfig.data as ReadonlyArray<OHLCDataPoint>;\n      for (let i = 0; i < data.length; i++) {\n        const p = data[i]!;\n        const timestamp = getOHLCTimestamp(p);\n        const low = isTupleOHLCDataPoint(p) ? p[3] : p.low;\n        const high = isTupleOHLCDataPoint(p) ? p[4] : p.high;\n\n        if (!Number.isFinite(timestamp) || !Number.isFinite(low) || !Number.isFinite(high)) continue;\n        if (timestamp < xMin) xMin = timestamp;\n        if (timestamp > xMax) xMax = timestamp;\n        if (low < yMin) yMin = low;\n        if (high > yMax) yMax = high;\n      }\n      continue;\n    }\n\n    const b = computeRawBoundsFromCartesianData(seriesConfig.data as CartesianSeriesData);\n    if (!b) continue;\n    if (b.xMin < xMin) xMin = b.xMin;\n    if (b.xMax > xMax) xMax = b.xMax;\n    if (b.yMin < yMin) yMin = b.yMin;\n    if (b.yMax > yMax) yMax = b.yMax;\n  }\n\n  if (!Number.isFinite(xMin) || !Number.isFinite(xMax) || !Number.isFinite(yMin) || !Number.isFinite(yMax)) {\n    return { xMin: 0, xMax: 1, yMin: 0, yMax: 1 };\n  }\n\n  if (xMin === xMax) xMax = xMin + 1;\n  if (yMin === yMax) yMax = yMin + 1;\n\n  return { xMin, xMax, yMin, yMax };\n};\n\nconst normalizeDomain = (\n  minCandidate: number,\n  maxCandidate: number\n): { readonly min: number; readonly max: number } => {\n  let min = minCandidate;\n  let max = maxCandidate;\n\n  if (!Number.isFinite(min) || !Number.isFinite(max)) {\n    min = 0;\n    max = 1;\n  }\n\n  if (min === max) {\n    max = min + 1;\n  } else if (min > max) {\n    const t = min;\n    min = max;\n    max = t;\n  }\n\n  return { min, max };\n};\n\ntype CartesianHitTestMatch = Readonly<{\n  kind: 'cartesian';\n  match: NearestPointMatch;\n}>;\n\ntype PieHitTestMatch = Readonly<{\n  kind: 'pie';\n  seriesIndex: number;\n  dataIndex: number;\n  sliceValue: number;\n}>;\n\ntype CandlestickHitTestMatch = Readonly<{\n  kind: 'candlestick';\n  seriesIndex: number;\n  dataIndex: number;\n  point: OHLCDataPoint;\n}>;\n\ntype HitTestMatch = CartesianHitTestMatch | PieHitTestMatch | CandlestickHitTestMatch;\n\nconst parseNumberOrPercent = (value: number | string, basis: number): number | null => {\n  if (typeof value === 'number') return Number.isFinite(value) ? value : null;\n  if (typeof value !== 'string') return null;\n\n  const s = value.trim();\n  if (s.length === 0) return null;\n\n  if (s.endsWith('%')) {\n    const pct = Number.parseFloat(s.slice(0, -1));\n    if (!Number.isFinite(pct)) return null;\n    return (pct / 100) * basis;\n  }\n\n  // Be permissive: allow numeric strings like \"120\" even though the public type primarily documents percent strings.\n  const n = Number.parseFloat(s);\n  return Number.isFinite(n) ? n : null;\n};\n\nconst resolvePieCenterPlotCss = (\n  center: PieCenter | undefined,\n  plotWidthCss: number,\n  plotHeightCss: number\n): { readonly x: number; readonly y: number } => {\n  const xRaw = center?.[0] ?? '50%';\n  const yRaw = center?.[1] ?? '50%';\n\n  const x = parseNumberOrPercent(xRaw, plotWidthCss);\n  const y = parseNumberOrPercent(yRaw, plotHeightCss);\n\n  return {\n    x: Number.isFinite(x) ? x! : plotWidthCss * 0.5,\n    y: Number.isFinite(y) ? y! : plotHeightCss * 0.5,\n  };\n};\n\nconst isPieRadiusTuple = (radius: PieRadius): radius is readonly [inner: number | string, outer: number | string] =>\n  Array.isArray(radius);\n\nconst resolvePieRadiiCss = (\n  radius: PieRadius | undefined,\n  maxRadiusCss: number\n): { readonly inner: number; readonly outer: number } => {\n  // Default similar to common chart libs (mirrors `createPieRenderer.ts` and coordinator helpers).\n  if (radius == null) return { inner: 0, outer: maxRadiusCss * 0.7 };\n\n  if (isPieRadiusTuple(radius)) {\n    const inner = parseNumberOrPercent(radius[0], maxRadiusCss);\n    const outer = parseNumberOrPercent(radius[1], maxRadiusCss);\n    const innerCss = Math.max(0, Number.isFinite(inner) ? inner! : 0);\n    const outerCss = Math.max(innerCss, Number.isFinite(outer) ? outer! : maxRadiusCss * 0.7);\n    return { inner: innerCss, outer: Math.min(maxRadiusCss, outerCss) };\n  }\n\n  const outer = parseNumberOrPercent(radius, maxRadiusCss);\n  const outerCss = Math.max(0, Number.isFinite(outer) ? outer! : maxRadiusCss * 0.7);\n  return { inner: 0, outer: Math.min(maxRadiusCss, outerCss) };\n};\n\nexport async function createChartGPU(\n  container: HTMLElement,\n  options: ChartGPUOptions\n): Promise<ChartGPUInstance> {\n  // Check WebGPU support before creating canvas or any resources\n  const supportCheck = await checkWebGPUSupport();\n  if (!supportCheck.supported) {\n    const reason = supportCheck.reason || 'Unknown reason';\n    throw new Error(\n      `ChartGPU: WebGPU is not available.\\n` +\n      `Reason: ${reason}\\n` +\n      `Browser support: Chrome/Edge 113+, Safari 18+, Firefox not yet supported.\\n` +\n      `Resources:\\n` +\n      `  - MDN WebGPU API: https://developer.mozilla.org/en-US/docs/Web/API/WebGPU_API\\n` +\n      `  - Browser compatibility: https://caniuse.com/webgpu\\n` +\n      `  - WebGPU specification: https://www.w3.org/TR/webgpu/\\n` +\n      `  - Check your system: https://webgpureport.org/`\n    );\n  }\n\n  const canvas = document.createElement('canvas');\n\n  // Ensure the canvas participates in layout and can size via the container.\n  canvas.style.display = 'block';\n  canvas.style.width = '100%';\n  canvas.style.height = '100%';\n\n  // Append before awaiting so it appears immediately and has measurable size.\n  container.appendChild(canvas);\n\n  let disposed = false;\n  let gpuContext: GPUContext | null = null;\n  let coordinator: RenderCoordinator | null = null;\n  let coordinatorTargetFormat: GPUTextureFormat | null = null;\n  let unsubscribeCoordinatorInteractionXChange: (() => void) | null = null;\n\n  let dataZoomSliderHost: HTMLDivElement | null = null;\n  let dataZoomSlider: DataZoomSlider | null = null;\n\n  let currentOptions: ChartGPUOptions = options;\n  let resolvedOptions: ResolvedChartGPUOptions = resolveOptionsForChart(currentOptions);\n\n  // Chart-owned runtime series store for hit-testing only (cartesian only).\n  // - `runtimeRawDataByIndex[i]` is a mutable array used to reflect streaming appends.\n  // - `runtimeRawBoundsByIndex[i]` is incrementally updated to keep scale/bounds derivation cheap.\n  let runtimeRawDataByIndex: Array<DataPoint[] | OHLCDataPoint[]> = new Array(resolvedOptions.series.length).fill(null).map(() => []);\n  let runtimeRawBoundsByIndex: Array<Bounds | null> = new Array(resolvedOptions.series.length).fill(null);\n  let runtimeHitTestSeriesCache: ResolvedChartGPUOptions['series'] | null = null;\n  let runtimeHitTestSeriesVersion = 0;\n\n  const initRuntimeHitTestStoreFromResolvedOptions = (): void => {\n    runtimeRawDataByIndex = new Array(resolvedOptions.series.length).fill(null).map(() => []);\n    runtimeRawBoundsByIndex = new Array(resolvedOptions.series.length).fill(null);\n    runtimeHitTestSeriesCache = null;\n    runtimeHitTestSeriesVersion++;\n\n    for (let i = 0; i < resolvedOptions.series.length; i++) {\n      const s = resolvedOptions.series[i]!;\n      if (s.type === 'pie') continue;\n\n      if (s.type === 'candlestick') {\n        const raw = ((s as unknown as { rawData?: ReadonlyArray<OHLCDataPoint> }).rawData ?? s.data) as ReadonlyArray<OHLCDataPoint>;\n        runtimeRawDataByIndex[i] = raw.length === 0 ? [] : raw.slice();\n        runtimeRawBoundsByIndex[i] = ((s as unknown as { rawBounds?: Bounds | null }).rawBounds ?? null);\n      } else {\n        const raw = ((s as unknown as { rawData?: CartesianSeriesData }).rawData ?? s.data) as CartesianSeriesData;\n        runtimeRawDataByIndex[i] = cartesianDataToDataPointArray(raw);\n        runtimeRawBoundsByIndex[i] =\n          ((s as unknown as { rawBounds?: Bounds | null }).rawBounds ?? null) ?? (computeRawBoundsFromCartesianData(raw) as Bounds | null);\n      }\n    }\n  };\n\n  const getRuntimeHitTestSeries = (): ResolvedChartGPUOptions['series'] => {\n    if (runtimeHitTestSeriesCache) return runtimeHitTestSeriesCache;\n    // Replace cartesian series `data` with chart-owned runtime data (pie series are unchanged).\n    runtimeHitTestSeriesCache = resolvedOptions.series.map((s, i) => {\n      if (s.type === 'pie') return s;\n      if (s.type === 'candlestick') {\n        return { ...s, data: runtimeRawDataByIndex[i] ?? (s.data as ReadonlyArray<OHLCDataPoint>) };\n      }\n      return { ...s, data: runtimeRawDataByIndex[i] ?? (s.data as ReadonlyArray<DataPoint>) };\n    }) as ResolvedChartGPUOptions['series'];\n    return runtimeHitTestSeriesCache;\n  };\n\n  initRuntimeHitTestStoreFromResolvedOptions();\n\n  // Cache global bounds and interaction scales; avoids O(N) data scans per pointer move.\n  let cachedGlobalBounds: Bounds = computeGlobalBounds(resolvedOptions.series, runtimeRawBoundsByIndex);\n  let interactionScalesCache: InteractionScalesCache | null = null;\n\n  const listeners: ListenerRegistry = {\n    click: new Set<ChartGPUEventCallback>(),\n    mouseover: new Set<ChartGPUEventCallback>(),\n    mouseout: new Set<ChartGPUEventCallback>(),\n    crosshairMove: new Set<ChartGPUCrosshairMoveCallback>(),\n  };\n\n  let tapCandidate: TapCandidate | null = null;\n  let suppressNextLostPointerCaptureId: number | null = null;\n\n  let hovered: HitTestMatch | null = null;\n\n  // Prevent spamming console.warn for repeated misuse.\n  const warnedPieAppendSeries = new Set<number>();\n\n  let scheduledRaf: number | null = null;\n  let lastConfigured: { width: number; height: number; format: GPUTextureFormat } | null = null;\n  let isDirty = true;\n\n  // Performance tracking state\n  const frameTimestamps = new Float64Array(FRAME_BUFFER_SIZE);\n  let frameTimestampIndex = 0;\n  let frameTimestampCount = 0;\n  let totalFrames = 0;\n  let totalDroppedFrames = 0;\n  let consecutiveDroppedFrames = 0;\n  let lastDropTimestamp = 0;\n  const startTime = performance.now();\n  let lastFrameTime = 0;\n  let lastCPUTime = 0;\n  const performanceUpdateCallbacks = new Set<(metrics: Readonly<PerformanceMetrics>) => void>();\n\n  const hasHoverListeners = (): boolean => listeners.mouseover.size > 0 || listeners.mouseout.size > 0;\n  const hasClickListeners = (): boolean => listeners.click.size > 0;\n\n  const cancelPendingFrame = (): void => {\n    if (scheduledRaf === null) return;\n    cancelAnimationFrame(scheduledRaf);\n    scheduledRaf = null;\n  };\n\n  const requestRender = (): void => {\n    if (disposed) return;\n    isDirty = true;\n    if (scheduledRaf !== null) return;\n\n    scheduledRaf = requestAnimationFrame(() => {\n      scheduledRaf = null;\n      if (disposed) return;\n\n      // Record frame timestamp BEFORE rendering\n      const frameStartTime = performance.now();\n      frameTimestamps[frameTimestampIndex] = frameStartTime;\n      frameTimestampIndex = (frameTimestampIndex + 1) % FRAME_BUFFER_SIZE;\n      if (frameTimestampCount < FRAME_BUFFER_SIZE) {\n        frameTimestampCount++;\n      }\n      totalFrames++;\n\n      // Frame drop detection (only after first frame)\n      if (lastFrameTime > 0) {\n        const deltaTime = frameStartTime - lastFrameTime;\n        if (deltaTime > EXPECTED_FRAME_TIME_MS * FRAME_DROP_THRESHOLD_MULTIPLIER) {\n          totalDroppedFrames++;\n          consecutiveDroppedFrames++;\n          lastDropTimestamp = frameStartTime;\n        } else {\n          // Reset consecutive counter on successful frame\n          consecutiveDroppedFrames = 0;\n        }\n      }\n      lastFrameTime = frameStartTime;\n\n      // Requirement: on RAF tick, call resize() first.\n      resizeInternal(false);\n      \n      if (isDirty) {\n        isDirty = false;\n        coordinator?.render();\n      }\n\n      const frameEndTime = performance.now();\n      lastCPUTime = frameEndTime - frameStartTime;\n\n      // Calculate and emit performance metrics\n      const metrics = calculatePerformanceMetrics();\n      for (const callback of performanceUpdateCallbacks) {\n        try {\n          callback(metrics);\n        } catch (error) {\n          console.error('Error in performance update callback:', error);\n        }\n      }\n    });\n  };\n\n  const unbindCoordinatorInteractionXChange = (): void => {\n    if (!unsubscribeCoordinatorInteractionXChange) return;\n    try {\n      unsubscribeCoordinatorInteractionXChange();\n    } finally {\n      unsubscribeCoordinatorInteractionXChange = null;\n    }\n  };\n\n  const disposeDataZoomSlider = (): void => {\n    dataZoomSlider?.dispose();\n    dataZoomSlider = null;\n  };\n\n  const disposeDataZoomSliderHost = (): void => {\n    dataZoomSliderHost?.remove();\n    dataZoomSliderHost = null;\n  };\n\n  const disposeDataZoomUi = (): void => {\n    disposeDataZoomSlider();\n    disposeDataZoomSliderHost();\n  };\n\n  const DATA_ZOOM_SLIDER_HEIGHT_CSS_PX = 32;\n  const DATA_ZOOM_SLIDER_MARGIN_TOP_CSS_PX = 8;\n  const DATA_ZOOM_SLIDER_RESERVE_CSS_PX = DATA_ZOOM_SLIDER_HEIGHT_CSS_PX + DATA_ZOOM_SLIDER_MARGIN_TOP_CSS_PX;\n\n  const ensureDataZoomSliderHost = (): HTMLDivElement => {\n    if (dataZoomSliderHost) return dataZoomSliderHost;\n\n    // Ensure the host's absolute positioning is anchored to the chart container.\n    // If the container is already positioned, avoid overwriting user styles.\n    try {\n      const pos = window.getComputedStyle(container).position;\n      if (pos === 'static') container.style.position = 'relative';\n    } catch {\n      // best-effort\n    }\n\n    const host = document.createElement('div');\n    host.style.position = 'absolute';\n    host.style.left = '0';\n    host.style.right = '0';\n    host.style.bottom = '0';\n    host.style.height = `${DATA_ZOOM_SLIDER_RESERVE_CSS_PX}px`;\n    host.style.paddingTop = `${DATA_ZOOM_SLIDER_MARGIN_TOP_CSS_PX}px`;\n    host.style.boxSizing = 'border-box';\n    host.style.pointerEvents = 'auto';\n    host.style.zIndex = '5';\n    container.appendChild(host);\n    dataZoomSliderHost = host;\n    return host;\n  };\n\n  const computeZoomInOutAnchorRatio = (range: ZoomRange, center: number): number => {\n    const span = range.end - range.start;\n    if (!Number.isFinite(span) || span === 0) return 0.5;\n    return clamp((center - range.start) / span, 0, 1);\n  };\n\n  const createCoordinatorZoomStateLike = (): ZoomState => {\n    const getRange: ZoomState['getRange'] = () => coordinator?.getZoomRange() ?? { start: 0, end: 100 };\n    const setRange: ZoomState['setRange'] = (start, end) => {\n      coordinator?.setZoomRange(start, end);\n    };\n    const zoomIn: ZoomState['zoomIn'] = (center, factor) => {\n      if (!Number.isFinite(center) || !Number.isFinite(factor) || factor <= 1) return;\n      const r = coordinator?.getZoomRange();\n      if (!r) return;\n      const c = clamp(center, 0, 100);\n      const ratio = computeZoomInOutAnchorRatio(r, c);\n      const span = r.end - r.start;\n      const nextSpan = span / factor;\n      const nextStart = c - ratio * nextSpan;\n      coordinator?.setZoomRange(nextStart, nextStart + nextSpan);\n    };\n    const zoomOut: ZoomState['zoomOut'] = (center, factor) => {\n      if (!Number.isFinite(center) || !Number.isFinite(factor) || factor <= 1) return;\n      const r = coordinator?.getZoomRange();\n      if (!r) return;\n      const c = clamp(center, 0, 100);\n      const ratio = computeZoomInOutAnchorRatio(r, c);\n      const span = r.end - r.start;\n      const nextSpan = span * factor;\n      const nextStart = c - ratio * nextSpan;\n      coordinator?.setZoomRange(nextStart, nextStart + nextSpan);\n    };\n    const pan: ZoomState['pan'] = (delta) => {\n      if (!Number.isFinite(delta)) return;\n      const r = coordinator?.getZoomRange();\n      if (!r) return;\n      coordinator?.setZoomRange(r.start + delta, r.end + delta);\n    };\n    const onChange: ZoomState['onChange'] = (callback) => coordinator?.onZoomRangeChange(callback) ?? (() => {});\n\n    return { getRange, setRange, zoomIn, zoomOut, pan, onChange };\n  };\n\n  const syncDataZoomUi = (): void => {\n    const shouldHaveSlider = hasSliderDataZoom(currentOptions);\n    if (!shouldHaveSlider) {\n      disposeDataZoomUi();\n      return;\n    }\n\n    // Slider requires a coordinator-backed zoom state.\n    if (!coordinator) return;\n    if (!coordinator.getZoomRange()) return;\n\n    const host = ensureDataZoomSliderHost();\n    if (!dataZoomSlider) {\n      dataZoomSlider = createDataZoomSlider(host, createCoordinatorZoomStateLike(), {\n        height: DATA_ZOOM_SLIDER_HEIGHT_CSS_PX,\n        marginTop: 0, // host provides vertical spacing\n      });\n    }\n    dataZoomSlider.update(resolvedOptions.theme);\n  };\n\n  const bindCoordinatorInteractionXChange = (): void => {\n    unbindCoordinatorInteractionXChange();\n    if (disposed) return;\n    if (!coordinator) return;\n\n    unsubscribeCoordinatorInteractionXChange = coordinator.onInteractionXChange((x, source) => {\n      emit('crosshairMove', { x, source });\n    });\n  };\n\n  const recreateCoordinator = (): void => {\n    if (disposed) return;\n    if (!gpuContext || !gpuContext.initialized) return;\n\n    const prevZoomRange = coordinator?.getZoomRange() ?? null;\n\n    unbindCoordinatorInteractionXChange();\n    // Coordinator recreation invalidates zoom subscriptions; recreate the slider if present.\n    disposeDataZoomSlider();\n    coordinator?.dispose();\n    coordinator = createRenderCoordinator(gpuContext, resolvedOptions, { onRequestRender: requestRender });\n    coordinatorTargetFormat = gpuContext.preferredFormat;\n    bindCoordinatorInteractionXChange();\n\n    if (prevZoomRange) coordinator.setZoomRange(prevZoomRange.start, prevZoomRange.end);\n    syncDataZoomUi();\n  };\n\n  const resizeInternal = (shouldRequestRenderAfterChanges: boolean): void => {\n    if (disposed) return;\n\n    const rect = canvas.getBoundingClientRect();\n    const dpr = window.devicePixelRatio || 1;\n\n    const maxDimension = gpuContext?.device?.limits.maxTextureDimension2D ?? 8192;\n    const width = Math.min(maxDimension, Math.max(1, Math.round(rect.width * dpr)));\n    const height = Math.min(maxDimension, Math.max(1, Math.round(rect.height * dpr)));\n\n    const sizeChanged = canvas.width !== width || canvas.height !== height;\n    if (sizeChanged) {\n      canvas.width = width;\n      canvas.height = height;\n    }\n\n    const device = gpuContext?.device;\n    const canvasContext = gpuContext?.canvasContext;\n    const preferredFormat = gpuContext?.preferredFormat;\n\n    let didConfigure = false;\n    if (device && canvasContext && preferredFormat) {\n      const shouldConfigure =\n        sizeChanged ||\n        !lastConfigured ||\n        lastConfigured.width !== canvas.width ||\n        lastConfigured.height !== canvas.height ||\n        lastConfigured.format !== preferredFormat;\n\n      if (shouldConfigure) {\n        canvasContext.configure({\n          device,\n          format: preferredFormat,\n          alphaMode: 'opaque',\n        });\n        lastConfigured = { width: canvas.width, height: canvas.height, format: preferredFormat };\n        didConfigure = true;\n\n        // Requirement: if the target format changes, recreate coordinator/pipelines.\n        if (coordinator && coordinatorTargetFormat !== preferredFormat) {\n          recreateCoordinator();\n        }\n      }\n    }\n\n    if (shouldRequestRenderAfterChanges && (sizeChanged || didConfigure)) {\n      // Requirement: resize() requests a render after size/config changes.\n      requestRender();\n    }\n  };\n\n  const resize = (): void => resizeInternal(true);\n\n  const getNearestPointFromPointerEvent = (\n    e: PointerEvent\n  ): { readonly match: HitTestMatch | null; readonly isInGrid: boolean } => {\n    const rect = canvas.getBoundingClientRect();\n    if (!(rect.width > 0) || !(rect.height > 0)) return { match: null, isInGrid: false };\n\n    const x = e.clientX - rect.left;\n    const y = e.clientY - rect.top;\n\n    const plotLeftCss = resolvedOptions.grid.left;\n    const plotTopCss = resolvedOptions.grid.top;\n    const plotWidthCss = rect.width - resolvedOptions.grid.left - resolvedOptions.grid.right;\n    const plotHeightCss = rect.height - resolvedOptions.grid.top - resolvedOptions.grid.bottom;\n    if (!(plotWidthCss > 0) || !(plotHeightCss > 0)) return { match: null, isInGrid: false };\n\n    const gridX = x - plotLeftCss;\n    const gridY = y - plotTopCss;\n\n    const isInGrid =\n      gridX >= 0 &&\n      gridX <= plotWidthCss &&\n      gridY >= 0 &&\n      gridY <= plotHeightCss;\n\n    if (!isInGrid) return { match: null, isInGrid: false };\n\n    const xMin = resolvedOptions.xAxis.min ?? cachedGlobalBounds.xMin;\n    const xMax = resolvedOptions.xAxis.max ?? cachedGlobalBounds.xMax;\n    const yMin = resolvedOptions.yAxis.min ?? cachedGlobalBounds.yMin;\n    const yMax = resolvedOptions.yAxis.max ?? cachedGlobalBounds.yMax;\n\n    // Make hit-testing zoom-aware (mirror coordinator percent->domain mapping).\n    const baseXDomain = normalizeDomain(xMin, xMax);\n    const zoomRange = coordinator?.getZoomRange() ?? null;\n    const xDomain = (() => {\n      if (!zoomRange) return baseXDomain;\n      const span = baseXDomain.max - baseXDomain.min;\n      if (!Number.isFinite(span) || span === 0) return baseXDomain;\n      const start = zoomRange.start;\n      const end = zoomRange.end;\n      const zMin = baseXDomain.min + (start / 100) * span;\n      const zMax = baseXDomain.min + (end / 100) * span;\n      return normalizeDomain(zMin, zMax);\n    })();\n    const yDomain = normalizeDomain(yMin, yMax);\n\n    // Cache hit-testing scales for identical (rect, grid, axis domain) inputs.\n    const canReuseScales =\n      interactionScalesCache !== null &&\n      interactionScalesCache.rectWidthCss === rect.width &&\n      interactionScalesCache.rectHeightCss === rect.height &&\n      interactionScalesCache.plotWidthCss === plotWidthCss &&\n      interactionScalesCache.plotHeightCss === plotHeightCss &&\n      interactionScalesCache.xDomainMin === xDomain.min &&\n      interactionScalesCache.xDomainMax === xDomain.max &&\n      interactionScalesCache.yDomainMin === yDomain.min &&\n      interactionScalesCache.yDomainMax === yDomain.max;\n\n    if (!canReuseScales) {\n      // IMPORTANT: grid-local CSS px ranges (0..plotWidth/Height), for interaction hit-testing.\n      const xScale = createLinearScale().domain(xDomain.min, xDomain.max).range(0, plotWidthCss);\n      const yScale = createLinearScale().domain(yDomain.min, yDomain.max).range(plotHeightCss, 0);\n      interactionScalesCache = {\n        rectWidthCss: rect.width,\n        rectHeightCss: rect.height,\n        plotWidthCss,\n        plotHeightCss,\n        xDomainMin: xDomain.min,\n        xDomainMax: xDomain.max,\n        yDomainMin: yDomain.min,\n        yDomainMax: yDomain.max,\n        xScale,\n        yScale,\n      };\n    }\n\n    // At this point, the cache must exist (either reused or created above).\n    const scales = interactionScalesCache!;\n\n    // Story 4.14: pie slice hit-testing (grid-local CSS px).\n    const pieMatch = (() => {\n      const maxRadiusCss = 0.5 * Math.min(plotWidthCss, plotHeightCss);\n      if (!(maxRadiusCss > 0)) return null;\n\n      // Prefer later series indices (deterministic and mirrors the coordinator tooltip logic).\n      for (let i = resolvedOptions.series.length - 1; i >= 0; i--) {\n        const s = resolvedOptions.series[i];\n        if (s.type !== 'pie') continue;\n\n        // Skip invisible series.\n        if (s.visible === false) continue;\n\n        const pieSeries = s as ResolvedPieSeriesConfig;\n        const center = resolvePieCenterPlotCss(pieSeries.center, plotWidthCss, plotHeightCss);\n        const radii = resolvePieRadiiCss(pieSeries.radius, maxRadiusCss);\n        const m = findPieSlice(gridX, gridY, { seriesIndex: i, series: pieSeries }, center, radii);\n        if (!m) continue;\n\n        const v = m.slice.value;\n        return {\n          kind: 'pie' as const,\n          seriesIndex: m.seriesIndex,\n          dataIndex: m.dataIndex,\n          sliceValue: typeof v === 'number' && Number.isFinite(v) ? v : 0,\n        };\n      }\n      return null;\n    })();\n\n    if (pieMatch) return { match: pieMatch, isInGrid: true };\n\n    // Candlestick body hit-testing (grid-local CSS px), prefer later series indices.\n    for (let i = resolvedOptions.series.length - 1; i >= 0; i--) {\n      const s = resolvedOptions.series[i];\n      if (s?.type !== 'candlestick') continue;\n\n      // Skip invisible series.\n      if (s.visible === false) continue;\n\n      const seriesCfg = s as ResolvedCandlestickSeriesConfig;\n      const barWidthRange = computeCandlestickBodyWidthRange(seriesCfg, seriesCfg.data, scales.xScale, plotWidthCss);\n      const m = findCandlestick([seriesCfg], gridX, gridY, scales.xScale, scales.yScale, barWidthRange);\n      if (!m) continue;\n\n      return {\n        match: { kind: 'candlestick', seriesIndex: i, dataIndex: m.dataIndex, point: m.point },\n        isInGrid: true,\n      };\n    }\n\n    const cartesianMatch = findNearestPoint(\n      getRuntimeHitTestSeries(),\n      gridX,\n      gridY,\n      scales.xScale,\n      scales.yScale\n    );\n\n    return {\n      match: cartesianMatch ? ({ kind: 'cartesian', match: cartesianMatch } as const) : null,\n      isInGrid: true,\n    };\n  };\n\n  const calculateExactFPS = (): ExactFPS => {\n    if (frameTimestampCount < 2) {\n      return 0 as ExactFPS;\n    }\n\n    const startIndex = (frameTimestampIndex - frameTimestampCount + FRAME_BUFFER_SIZE) % FRAME_BUFFER_SIZE;\n    \n    let totalDelta = 0;\n    for (let i = 1; i < frameTimestampCount; i++) {\n      const prevIndex = (startIndex + i - 1) % FRAME_BUFFER_SIZE;\n      const currIndex = (startIndex + i) % FRAME_BUFFER_SIZE;\n      const delta = frameTimestamps[currIndex] - frameTimestamps[prevIndex];\n      totalDelta += delta;\n    }\n\n    const avgFrameTime = totalDelta / (frameTimestampCount - 1);\n    const fps = avgFrameTime > 0 ? 1000 / avgFrameTime : 0;\n    \n    return fps as ExactFPS;\n  };\n\n  const calculateFrameTimeStats = (): FrameTimeStats => {\n    if (frameTimestampCount < 2) {\n      return {\n        min: 0 as Milliseconds,\n        max: 0 as Milliseconds,\n        avg: 0 as Milliseconds,\n        p50: 0 as Milliseconds,\n        p95: 0 as Milliseconds,\n        p99: 0 as Milliseconds,\n      };\n    }\n\n    const startIndex = (frameTimestampIndex - frameTimestampCount + FRAME_BUFFER_SIZE) % FRAME_BUFFER_SIZE;\n    \n    const deltas = new Array<number>(frameTimestampCount - 1);\n    let min = Number.POSITIVE_INFINITY;\n    let max = Number.NEGATIVE_INFINITY;\n    let sum = 0;\n    \n    for (let i = 1; i < frameTimestampCount; i++) {\n      const prevIndex = (startIndex + i - 1) % FRAME_BUFFER_SIZE;\n      const currIndex = (startIndex + i) % FRAME_BUFFER_SIZE;\n      const delta = frameTimestamps[currIndex] - frameTimestamps[prevIndex];\n      deltas[i - 1] = delta;\n      \n      if (delta < min) min = delta;\n      if (delta > max) max = delta;\n      sum += delta;\n    }\n\n    const avg = sum / deltas.length;\n\n    // Sort for percentile calculations\n    deltas.sort((a, b) => a - b);\n\n    const p50Index = Math.floor(deltas.length * 0.50);\n    const p95Index = Math.floor(deltas.length * 0.95);\n    const p99Index = Math.floor(deltas.length * 0.99);\n\n    return {\n      min: min as Milliseconds,\n      max: max as Milliseconds,\n      avg: avg as Milliseconds,\n      p50: deltas[p50Index] as Milliseconds,\n      p95: deltas[p95Index] as Milliseconds,\n      p99: deltas[p99Index] as Milliseconds,\n    };\n  };\n\n  const calculatePerformanceMetrics = (): PerformanceMetrics => {\n    const fps = calculateExactFPS();\n    const frameTimeStats = calculateFrameTimeStats();\n    \n    const gpuTiming: GPUTimingStats = {\n      enabled: false, // GPU timing not yet implemented for main thread\n      cpuTime: lastCPUTime as Milliseconds,\n      gpuTime: 0 as Milliseconds,\n    };\n    \n    const memory: MemoryStats = {\n      used: 0 as Bytes,\n      peak: 0 as Bytes,\n      allocated: 0 as Bytes,\n    };\n    \n    const frameDrops: FrameDropStats = {\n      totalDrops: totalDroppedFrames,\n      consecutiveDrops: consecutiveDroppedFrames,\n      lastDropTimestamp: lastDropTimestamp as Milliseconds,\n    };\n    \n    const elapsedTime = performance.now() - startTime;\n    \n    return {\n      fps,\n      frameTimeStats,\n      gpuTiming,\n      memory,\n      frameDrops,\n      totalFrames,\n      elapsedTime: elapsedTime as Milliseconds,\n    };\n  };\n\n  const buildPayload = (match: HitTestMatch | null, event: PointerEvent): ChartGPUEventPayload => {\n    if (!match) {\n      return { seriesIndex: null, dataIndex: null, value: null, seriesName: null, event };\n    }\n\n    const seriesIndex = match.kind === 'cartesian' ? match.match.seriesIndex : match.seriesIndex;\n    const dataIndex = match.kind === 'cartesian' ? match.match.dataIndex : match.dataIndex;\n\n    const series = resolvedOptions.series[seriesIndex];\n    const seriesNameRaw = series?.name ?? null;\n    const seriesName = seriesNameRaw && seriesNameRaw.trim().length > 0 ? seriesNameRaw : null;\n\n    if (match.kind === 'pie') {\n      // Pie series are non-cartesian; expose slice value in y so consumers can read a numeric.\n      return {\n        seriesIndex,\n        dataIndex,\n        value: [0, match.sliceValue],\n        seriesName,\n        event,\n      };\n    }\n\n    if (match.kind === 'candlestick') {\n      const timestamp = getOHLCTimestamp(match.point);\n      const close = getOHLCClose(match.point);\n      return {\n        seriesIndex,\n        dataIndex,\n        value: [timestamp, close],\n        seriesName,\n        event,\n      };\n    }\n\n    const { x, y } = getPointXY(match.match.point);\n    return {\n      seriesIndex,\n      dataIndex,\n      value: [x, y],\n      seriesName,\n      event,\n    };\n  };\n\n  const emit = (\n    eventName: ChartGPUEventName,\n    payload: ChartGPUEventPayload | ChartGPUCrosshairMovePayload\n  ): void => {\n    if (disposed) return;\n    for (const cb of listeners[eventName]) (cb as (p: typeof payload) => void)(payload);\n  };\n\n  const setHovered = (next: HitTestMatch | null, event: PointerEvent): void => {\n    const prev = hovered;\n    hovered = next;\n\n    if (prev === null && next === null) return;\n\n    if (prev === null && next !== null) {\n      emit('mouseover', buildPayload(next, event));\n      return;\n    }\n\n    if (prev !== null && next === null) {\n      emit('mouseout', buildPayload(prev, event));\n      return;\n    }\n\n    if (prev === null || next === null) return;\n\n    const prevSeriesIndex = prev.kind === 'cartesian' ? prev.match.seriesIndex : prev.seriesIndex;\n    const prevDataIndex = prev.kind === 'cartesian' ? prev.match.dataIndex : prev.dataIndex;\n    const nextSeriesIndex = next.kind === 'cartesian' ? next.match.seriesIndex : next.seriesIndex;\n    const nextDataIndex = next.kind === 'cartesian' ? next.match.dataIndex : next.dataIndex;\n\n    const samePoint = prevSeriesIndex === nextSeriesIndex && prevDataIndex === nextDataIndex;\n    if (samePoint) return;\n\n    emit('mouseout', buildPayload(prev, event));\n    emit('mouseover', buildPayload(next, event));\n  };\n\n  const clearTapCandidateIfMatches = (e: PointerEvent): void => {\n    if (!tapCandidate) return;\n    if (!e.isPrimary) return;\n    if (e.pointerId !== tapCandidate.pointerId) return;\n    tapCandidate = null;\n  };\n\n  const onPointerMove = (e: PointerEvent): void => {\n    if (disposed) return;\n    if (!hasHoverListeners()) return;\n    const { match, isInGrid } = getNearestPointFromPointerEvent(e);\n    if (!isInGrid) {\n      setHovered(null, e);\n      return;\n    }\n    setHovered(match, e);\n  };\n\n  const onPointerLeave = (e: PointerEvent): void => {\n    if (disposed) return;\n    if (!hasHoverListeners() && !tapCandidate) return;\n    clearTapCandidateIfMatches(e);\n    setHovered(null, e);\n  };\n\n  const onPointerCancel = (e: PointerEvent): void => {\n    if (disposed) return;\n    if (!hasHoverListeners() && !tapCandidate) return;\n    clearTapCandidateIfMatches(e);\n    setHovered(null, e);\n  };\n\n  const onLostPointerCapture = (e: PointerEvent): void => {\n    if (disposed) return;\n    if (!hasHoverListeners() && !tapCandidate && suppressNextLostPointerCaptureId !== e.pointerId) return;\n    if (suppressNextLostPointerCaptureId === e.pointerId) {\n      suppressNextLostPointerCaptureId = null;\n      return;\n    }\n    clearTapCandidateIfMatches(e);\n    setHovered(null, e);\n  };\n\n  const onPointerDown = (e: PointerEvent): void => {\n    if (disposed) return;\n    if (!hasClickListeners()) return;\n    if (!e.isPrimary) return;\n\n    // For mouse, only allow left button.\n    if (e.pointerType === 'mouse' && e.button !== 0) return;\n\n    tapCandidate = {\n      pointerId: e.pointerId,\n      startClientX: e.clientX,\n      startClientY: e.clientY,\n      startTimeMs: e.timeStamp,\n    };\n\n    // Optional pointer capture improves reliability for touch/pen.\n    try {\n      canvas.setPointerCapture(e.pointerId);\n    } catch {\n      // best-effort\n    }\n  };\n\n  const onPointerUp = (e: PointerEvent): void => {\n    if (disposed) return;\n    if (!hasClickListeners()) return;\n    if (!e.isPrimary) return;\n    if (!tapCandidate || e.pointerId !== tapCandidate.pointerId) return;\n\n    const dt = e.timeStamp - tapCandidate.startTimeMs;\n    const dx = e.clientX - tapCandidate.startClientX;\n    const dy = e.clientY - tapCandidate.startClientY;\n    const distSq = dx * dx + dy * dy;\n\n    tapCandidate = null;\n\n    // Release capture if we have it; suppress the resulting lostpointercapture.\n    try {\n      if (canvas.hasPointerCapture(e.pointerId)) {\n        suppressNextLostPointerCaptureId = e.pointerId;\n        canvas.releasePointerCapture(e.pointerId);\n      }\n    } catch {\n      // best-effort\n    }\n\n    const maxDist = DEFAULT_TAP_MAX_DISTANCE_CSS_PX;\n    const isTap = dt <= DEFAULT_TAP_MAX_TIME_MS && distSq <= maxDist * maxDist;\n    if (!isTap) return;\n\n    const { match } = getNearestPointFromPointerEvent(e);\n    emit('click', buildPayload(match, e));\n  };\n\n  canvas.addEventListener('pointermove', onPointerMove, { passive: true });\n  canvas.addEventListener('pointerleave', onPointerLeave, { passive: true });\n  canvas.addEventListener('pointercancel', onPointerCancel, { passive: true });\n  canvas.addEventListener('lostpointercapture', onLostPointerCapture, { passive: true });\n  canvas.addEventListener('pointerdown', onPointerDown, { passive: true });\n  canvas.addEventListener('pointerup', onPointerUp, { passive: true });\n\n  const dispose = (): void => {\n    if (disposed) return;\n    disposed = true;\n\n    try {\n      // Requirement: dispose order: cancel RAF, coordinator.dispose(), gpuContext.destroy(), remove canvas.\n      cancelPendingFrame();\n      disposeDataZoomUi();\n      unbindCoordinatorInteractionXChange();\n      coordinator?.dispose();\n      coordinator = null;\n      coordinatorTargetFormat = null;\n      gpuContext?.destroy();\n    } finally {\n      tapCandidate = null;\n      suppressNextLostPointerCaptureId = null;\n      hovered = null;\n      interactionScalesCache = null;\n\n      canvas.removeEventListener('pointermove', onPointerMove);\n      canvas.removeEventListener('pointerleave', onPointerLeave);\n      canvas.removeEventListener('pointercancel', onPointerCancel);\n      canvas.removeEventListener('lostpointercapture', onLostPointerCapture);\n      canvas.removeEventListener('pointerdown', onPointerDown);\n      canvas.removeEventListener('pointerup', onPointerUp);\n\n      listeners.click.clear();\n      listeners.mouseover.clear();\n      listeners.mouseout.clear();\n      listeners.crosshairMove.clear();\n\n      gpuContext = null;\n      canvas.remove();\n    }\n  };\n\n  const instance: ChartGPUInstance = {\n    get options() {\n      return currentOptions;\n    },\n    get disposed() {\n      return disposed;\n    },\n    setOption(nextOptions) {\n      if (disposed) return;\n      currentOptions = nextOptions;\n      resolvedOptions = resolveOptionsForChart(nextOptions);\n      coordinator?.setOptions(resolvedOptions);\n      initRuntimeHitTestStoreFromResolvedOptions();\n      cachedGlobalBounds = computeGlobalBounds(resolvedOptions.series, runtimeRawBoundsByIndex);\n      interactionScalesCache = null;\n      syncDataZoomUi();\n\n      // Requirement: setOption triggers a render (and thus series parsing/extent/scales update inside render).\n      requestRender();\n    },\n    appendData(seriesIndex, newPoints) {\n      if (disposed) return;\n      if (!Number.isFinite(seriesIndex)) return;\n      if (seriesIndex < 0 || seriesIndex >= resolvedOptions.series.length) return;\n      if (!newPoints || newPoints.length === 0) return;\n\n      const s = resolvedOptions.series[seriesIndex]!;\n      if (s.type === 'pie') {\n        // Pie series are non-cartesian and currently not supported by streaming append.\n        if (!warnedPieAppendSeries.has(seriesIndex)) {\n          warnedPieAppendSeries.add(seriesIndex);\n          console.warn(\n            `ChartGPU.appendData(${seriesIndex}, ...): pie series are not supported by streaming append. Use setOption(...) to replace pie data.`\n          );\n        }\n        return;\n      }\n\n      // Forward to coordinator (GPU buffers + render-state updates), then keep ChartGPU's\n      // hit-testing runtime store in sync.\n      coordinator?.appendData(seriesIndex, newPoints);\n\n      if (s.type === 'candlestick') {\n        // Handle candlestick series with OHLC data points.\n        const owned = (runtimeRawDataByIndex[seriesIndex] ?? []) as OHLCDataPoint[];\n        owned.push(...(newPoints as OHLCDataPoint[]));\n        runtimeRawDataByIndex[seriesIndex] = owned;\n\n        runtimeRawBoundsByIndex[seriesIndex] = extendBoundsWithOHLCDataPoints(\n          runtimeRawBoundsByIndex[seriesIndex],\n          newPoints as OHLCDataPoint[]\n        );\n      } else {\n        // Handle other cartesian series (line, area, bar, scatter).\n        const owned = (runtimeRawDataByIndex[seriesIndex] ?? []) as DataPoint[];\n        owned.push(...(newPoints as DataPoint[]));\n        runtimeRawDataByIndex[seriesIndex] = owned;\n\n        runtimeRawBoundsByIndex[seriesIndex] = extendBoundsWithDataPoints(\n          runtimeRawBoundsByIndex[seriesIndex],\n          newPoints as DataPoint[]\n        );\n      }\n\n      cachedGlobalBounds = computeGlobalBounds(resolvedOptions.series, runtimeRawBoundsByIndex);\n\n      runtimeHitTestSeriesCache = null;\n      runtimeHitTestSeriesVersion++;\n      interactionScalesCache = null;\n\n      // Ensure a render is scheduled (coalesced) like setOption does.\n      requestRender();\n    },\n    resize,\n    dispose,\n    on(eventName, callback) {\n      if (disposed) return;\n      listeners[eventName].add(callback as AnyChartGPUEventCallback);\n    },\n    off(eventName, callback) {\n      listeners[eventName].delete(callback as AnyChartGPUEventCallback);\n    },\n    getInteractionX() {\n      if (disposed) return null;\n      return coordinator?.getInteractionX() ?? null;\n    },\n    setInteractionX(x, source) {\n      if (disposed) return;\n      coordinator?.setInteractionX(x, source);\n    },\n    setCrosshairX(x, source) {\n      if (disposed) return;\n      coordinator?.setInteractionX(x, source);\n    },\n    onInteractionXChange(callback) {\n      if (disposed) return () => {};\n      return coordinator?.onInteractionXChange(callback) ?? (() => {});\n    },\n    getZoomRange() {\n      if (disposed) return null;\n      return coordinator?.getZoomRange() ?? null;\n    },\n    setZoomRange(start, end) {\n      if (disposed) return;\n      coordinator?.setZoomRange(start, end);\n    },\n    getPerformanceMetrics() {\n      if (disposed) return null;\n      return calculatePerformanceMetrics();\n    },\n    getPerformanceCapabilities() {\n      if (disposed) return null;\n      return {\n        gpuTimingSupported: false, // Not yet implemented for main thread\n        highResTimerSupported: typeof performance !== 'undefined' && typeof performance.now === 'function',\n        performanceMetricsSupported: true,\n      };\n    },\n    onPerformanceUpdate(callback) {\n      if (disposed) return () => {};\n      performanceUpdateCallbacks.add(callback);\n      return () => {\n        performanceUpdateCallbacks.delete(callback);\n      };\n    },\n    hitTest(e) {\n      const rect = canvas.getBoundingClientRect();\n      const canvasX = e.clientX - rect.left;\n      const canvasY = e.clientY - rect.top;\n\n      // Default result for cases where rect is invalid or disposed\n      if (disposed || !(rect.width > 0) || !(rect.height > 0)) {\n        return {\n          isInGrid: false,\n          canvasX,\n          canvasY,\n          gridX: 0,\n          gridY: 0,\n          match: null,\n        };\n      }\n\n      const plotLeftCss = resolvedOptions.grid.left;\n      const plotTopCss = resolvedOptions.grid.top;\n      const plotWidthCss = rect.width - resolvedOptions.grid.left - resolvedOptions.grid.right;\n      const plotHeightCss = rect.height - resolvedOptions.grid.top - resolvedOptions.grid.bottom;\n\n      const gridX = canvasX - plotLeftCss;\n      const gridY = canvasY - plotTopCss;\n\n      // If plot dimensions are invalid, return coords but no match\n      if (!(plotWidthCss > 0) || !(plotHeightCss > 0)) {\n        return {\n          isInGrid: false,\n          canvasX,\n          canvasY,\n          gridX,\n          gridY,\n          match: null,\n        };\n      }\n\n      const isInGrid =\n        gridX >= 0 &&\n        gridX <= plotWidthCss &&\n        gridY >= 0 &&\n        gridY <= plotHeightCss;\n\n      // If outside grid, return early\n      if (!isInGrid) {\n        return {\n          isInGrid: false,\n          canvasX,\n          canvasY,\n          gridX,\n          gridY,\n          match: null,\n        };\n      }\n\n      // Compute domain and scales for hit-testing\n      const xMin = resolvedOptions.xAxis.min ?? cachedGlobalBounds.xMin;\n      const xMax = resolvedOptions.xAxis.max ?? cachedGlobalBounds.xMax;\n      const yMin = resolvedOptions.yAxis.min ?? cachedGlobalBounds.yMin;\n      const yMax = resolvedOptions.yAxis.max ?? cachedGlobalBounds.yMax;\n\n      const baseXDomain = normalizeDomain(xMin, xMax);\n      const zoomRange = coordinator?.getZoomRange() ?? null;\n      const xDomain = (() => {\n        if (!zoomRange) return baseXDomain;\n        const span = baseXDomain.max - baseXDomain.min;\n        if (!Number.isFinite(span) || span === 0) return baseXDomain;\n        const start = zoomRange.start;\n        const end = zoomRange.end;\n        const zMin = baseXDomain.min + (start / 100) * span;\n        const zMax = baseXDomain.min + (end / 100) * span;\n        return normalizeDomain(zMin, zMax);\n      })();\n      const yDomain = normalizeDomain(yMin, yMax);\n\n      // Reuse or rebuild interaction scales cache\n      const canReuseScales =\n        interactionScalesCache !== null &&\n        interactionScalesCache.rectWidthCss === rect.width &&\n        interactionScalesCache.rectHeightCss === rect.height &&\n        interactionScalesCache.plotWidthCss === plotWidthCss &&\n        interactionScalesCache.plotHeightCss === plotHeightCss &&\n        interactionScalesCache.xDomainMin === xDomain.min &&\n        interactionScalesCache.xDomainMax === xDomain.max &&\n        interactionScalesCache.yDomainMin === yDomain.min &&\n        interactionScalesCache.yDomainMax === yDomain.max;\n\n      if (!canReuseScales) {\n        const xScale = createLinearScale().domain(xDomain.min, xDomain.max).range(0, plotWidthCss);\n        const yScale = createLinearScale().domain(yDomain.min, yDomain.max).range(plotHeightCss, 0);\n        interactionScalesCache = {\n          rectWidthCss: rect.width,\n          rectHeightCss: rect.height,\n          plotWidthCss,\n          plotHeightCss,\n          xDomainMin: xDomain.min,\n          xDomainMax: xDomain.max,\n          yDomainMin: yDomain.min,\n          yDomainMax: yDomain.max,\n          xScale,\n          yScale,\n        };\n      }\n\n      const scales = interactionScalesCache!;\n\n      // Pie slice hit-testing\n      const pieMatch = (() => {\n        const maxRadiusCss = 0.5 * Math.min(plotWidthCss, plotHeightCss);\n        if (!(maxRadiusCss > 0)) return null;\n\n        for (let i = resolvedOptions.series.length - 1; i >= 0; i--) {\n          const s = resolvedOptions.series[i];\n          if (s.type !== 'pie') continue;\n          const pieSeries = s as ResolvedPieSeriesConfig;\n          const center = resolvePieCenterPlotCss(pieSeries.center, plotWidthCss, plotHeightCss);\n          const radii = resolvePieRadiiCss(pieSeries.radius, maxRadiusCss);\n          const m = findPieSlice(gridX, gridY, { seriesIndex: i, series: pieSeries }, center, radii);\n          if (!m) continue;\n\n          const v = m.slice.value;\n          return {\n            kind: 'pie' as const,\n            seriesIndex: m.seriesIndex,\n            dataIndex: m.dataIndex,\n            sliceValue: typeof v === 'number' && Number.isFinite(v) ? v : 0,\n          };\n        }\n        return null;\n      })();\n\n      if (pieMatch) {\n        return {\n          isInGrid: true,\n          canvasX,\n          canvasY,\n          gridX,\n          gridY,\n          match: {\n            kind: 'pie',\n            seriesIndex: pieMatch.seriesIndex,\n            dataIndex: pieMatch.dataIndex,\n            value: [0, pieMatch.sliceValue],\n          },\n        };\n      }\n\n      // Candlestick body hit-testing\n      for (let i = resolvedOptions.series.length - 1; i >= 0; i--) {\n        const s = resolvedOptions.series[i];\n        if (s?.type !== 'candlestick') continue;\n\n        const seriesCfg = s as ResolvedCandlestickSeriesConfig;\n        const barWidthRange = computeCandlestickBodyWidthRange(seriesCfg, seriesCfg.data, scales.xScale, plotWidthCss);\n        const m = findCandlestick([seriesCfg], gridX, gridY, scales.xScale, scales.yScale, barWidthRange);\n        if (!m) continue;\n\n        const timestamp = getOHLCTimestamp(m.point);\n        const close = getOHLCClose(m.point);\n\n        return {\n          isInGrid: true,\n          canvasX,\n          canvasY,\n          gridX,\n          gridY,\n          match: {\n            kind: 'candlestick',\n            seriesIndex: i,\n            dataIndex: m.dataIndex,\n            value: [timestamp, close],\n          },\n        };\n      }\n\n      // Cartesian nearest-point hit-testing\n      const cartesianMatch = findNearestPoint(\n        getRuntimeHitTestSeries(),\n        gridX,\n        gridY,\n        scales.xScale,\n        scales.yScale\n      );\n\n      if (cartesianMatch) {\n        const { x, y } = getPointXY(cartesianMatch.point);\n        return {\n          isInGrid: true,\n          canvasX,\n          canvasY,\n          gridX,\n          gridY,\n          match: {\n            kind: 'cartesian',\n            seriesIndex: cartesianMatch.seriesIndex,\n            dataIndex: cartesianMatch.dataIndex,\n            value: [x, y],\n          },\n        };\n      }\n\n      // Inside grid but no match\n      return {\n        isInGrid: true,\n        canvasX,\n        canvasY,\n        gridX,\n        gridY,\n        match: null,\n      };\n    },\n  };\n\n  try {\n    // Establish initial canvas backing size before WebGPU initialization.\n    resizeInternal(false);\n\n    // Try to create GPU context; wrap errors with detailed WebGPU unavailability message\n    try {\n      gpuContext = await GPUContext.create(canvas);\n    } catch (error) {\n      const errorMessage = error instanceof Error ? error.message : String(error);\n      throw new Error(\n        `ChartGPU: WebGPU is not available.\\n` +\n        `Reason: ${errorMessage}\\n` +\n        `Browser support: Chrome/Edge 113+, Safari 18+, Firefox not yet supported.\\n` +\n        `Resources:\\n` +\n        `  - MDN WebGPU API: https://developer.mozilla.org/en-US/docs/Web/API/WebGPU_API\\n` +\n        `  - Browser compatibility: https://caniuse.com/webgpu\\n` +\n        `  - WebGPU specification: https://www.w3.org/TR/webgpu/\\n` +\n        `  - Check your system: https://webgpureport.org/`\n      );\n    }\n\n    gpuContext.device?.lost.then((info) => {\n      if (disposed) return;\n      if (info.reason !== 'destroyed') {\n        console.warn('WebGPU device lost:', info);\n      }\n      // Requirement: device loss routes through the same dispose path.\n      dispose();\n    });\n\n    // Ensure canvas configuration matches the final measured size/format.\n    resizeInternal(false);\n\n    // Requirement: after GPUContext is initialized, create RenderCoordinator with resolved options.\n    recreateCoordinator();\n\n    // Mount data-zoom UI (if configured).\n    syncDataZoomUi();\n\n    // Kick an initial render.\n    requestRender();\n    return instance;\n  } catch (error) {\n    instance.dispose();\n    throw error;\n  }\n}\n\nexport const ChartGPU = {\n  create: createChartGPU,\n};\n\n","import type { ChartGPU, ChartGPUCrosshairMovePayload } from '../ChartGPU';\n\nexport type DisconnectCharts = () => void;\n\n/**\n * Connects multiple charts so pointer movement in one chart drives crosshair/tooltip x\n * in the other charts (domain x sync). Returns a `disconnect()` function.\n *\n * Notes:\n * - Syncs interaction only (crosshair + tooltip x), not zoom/options.\n * - Uses a per-connection loop guard to prevent feedback.\n */\nexport function connectCharts(charts: ChartGPU[]): DisconnectCharts {\n  const connectionToken = Symbol('ChartGPU.connectCharts');\n\n  let disconnected = false;\n  const unsubscribeFns: Array<() => void> = [];\n\n  const broadcast = (sourceChart: ChartGPU, x: number | null): void => {\n    for (const chart of charts) {\n      if (chart === sourceChart) continue;\n      if (chart.disposed) continue;\n      chart.setCrosshairX(x, connectionToken);\n    }\n  };\n\n  for (const chart of charts) {\n    if (chart.disposed) continue;\n\n    const onCrosshairMove = (payload: ChartGPUCrosshairMovePayload): void => {\n      if (disconnected) return;\n      if (payload.source === connectionToken) return;\n      if (chart.disposed) return;\n      broadcast(chart, payload.x);\n    };\n\n    chart.on('crosshairMove', onCrosshairMove);\n    const unsub = (): void => chart.off('crosshairMove', onCrosshairMove);\n    unsubscribeFns.push(unsub);\n  }\n\n  return () => {\n    if (disconnected) return;\n    disconnected = true;\n\n    for (const unsub of unsubscribeFns) unsub();\n    unsubscribeFns.length = 0;\n\n    // Clear any “stuck” remote interactions.\n    for (const chart of charts) {\n      if (chart.disposed) continue;\n      chart.setCrosshairX(null, connectionToken);\n    }\n  };\n}\n\n","/**\n * Hit testing for chart annotations\n *\n * Detects which annotation (if any) the user clicked or hovered over.\n * Uses canvas-space coordinates and configurable hit tolerances.\n */\n\nimport type { AnnotationConfig, DataPoint } from '../config/types.js';\nimport type { ChartGPUInstance } from '../ChartGPU.js';\n\nexport interface AnnotationHitTestResult {\n  readonly annotationIndex: number;\n  readonly annotation: AnnotationConfig;\n  readonly hitType: 'line' | 'text' | 'point' | 'label';\n  readonly distanceCssPx: number;\n}\n\nexport interface AnnotationHitTesterOptions {\n  readonly lineTolerance?: number;      // Default: 20px\n  readonly textTolerance?: number;      // Default: 8px\n  readonly pointTolerance?: number;     // Default: 16px\n  readonly labelTolerance?: number;     // Default: 2px\n  readonly spatialGridThreshold?: number; // Default: 20 annotations\n}\n\nexport interface AnnotationHitTester {\n  hitTest(canvasX: number, canvasY: number): AnnotationHitTestResult | null;\n  updateTextBounds(textBounds: Map<number, DOMRect>): void;\n  invalidateCache(): void;\n  dispose(): void;\n}\n\ninterface CachedAnnotationBounds {\n  canvasX?: number;\n  canvasY?: number;\n  width?: number;\n  height?: number;\n}\n\n/**\n * Creates an annotation hit tester for detecting pointer interactions\n */\nexport function createAnnotationHitTester(\n  chart: ChartGPUInstance,\n  canvas: HTMLCanvasElement,\n  options: AnnotationHitTesterOptions = {}\n): AnnotationHitTester {\n  const lineTolerance = options.lineTolerance ?? 20;\n  const textTolerance = options.textTolerance ?? 8;\n  const pointTolerance = options.pointTolerance ?? 16;\n  // labelTolerance reserved for future use\n  // spatialGridThreshold reserved for future optimization when >20 annotations\n\n  // Cache for annotation bounds in canvas-space\n  let boundsCache = new Map<number, CachedAnnotationBounds>();\n  let textBoundsCache = new Map<number, DOMRect>();\n  let cacheValid = false;\n\n  // Type guards for data points\n  const isTupleDataPoint = (p: any): p is [number, number] => Array.isArray(p);\n  const isTupleOHLCDataPoint = (p: any): p is [number, number, number, number, number] => Array.isArray(p);\n  const getPointX = (p: any): number => (isTupleDataPoint(p) ? p[0] : p.x);\n  const getPointY = (p: any): number => (isTupleDataPoint(p) ? p[1] : p.y);\n  const getOHLCTimestamp = (p: any): number => (isTupleOHLCDataPoint(p) ? p[0] : p.timestamp);\n  const getOHLCHigh = (p: any): number => (isTupleOHLCDataPoint(p) ? p[2] : p.high);\n  const getOHLCLow = (p: any): number => (isTupleOHLCDataPoint(p) ? p[3] : p.low);\n\n  /**\n   * Compute the actual X domain from series data (with zoom applied)\n   */\n  function computeXDomain(): { min: number; max: number } {\n    const opts = chart.options;\n    let xMin = opts.xAxis?.min;\n    let xMax = opts.xAxis?.max;\n\n    // If not explicitly set, derive from series data\n    if (xMin === undefined || xMax === undefined) {\n      const series = opts.series ?? [];\n      let dataXMin = Number.POSITIVE_INFINITY;\n      let dataXMax = Number.NEGATIVE_INFINITY;\n\n      for (const s of series) {\n        if (s.type === 'pie') continue;\n\n        if (s.type === 'candlestick') {\n          const data = s.data;\n          for (const p of data) {\n            const timestamp = getOHLCTimestamp(p);\n            if (timestamp < dataXMin) dataXMin = timestamp;\n            if (timestamp > dataXMax) dataXMax = timestamp;\n          }\n        } else {\n          // TODO(step 2): normalize CartesianSeriesData to ReadonlyArray<DataPoint>\n          const data = s.data as ReadonlyArray<DataPoint>;\n          for (const p of data) {\n            const x = getPointX(p);\n            if (x < dataXMin) dataXMin = x;\n            if (x > dataXMax) dataXMax = x;\n          }\n        }\n      }\n\n      if (xMin === undefined) xMin = Number.isFinite(dataXMin) ? dataXMin : 0;\n      if (xMax === undefined) xMax = Number.isFinite(dataXMax) ? dataXMax : 100;\n    }\n\n    // Apply zoom if present\n    const zoomRange = chart.getZoomRange();\n    if (zoomRange) {\n      const span = xMax - xMin;\n      const zoomMin = xMin + (zoomRange.start / 100) * span;\n      const zoomMax = xMin + (zoomRange.end / 100) * span;\n      return { min: zoomMin, max: zoomMax };\n    }\n\n    return { min: xMin, max: xMax };\n  }\n\n  /**\n   * Compute the actual Y domain from series data\n   */\n  function computeYDomain(): { min: number; max: number } {\n    const opts = chart.options;\n    let yMin = opts.yAxis?.min;\n    let yMax = opts.yAxis?.max;\n\n    // If not explicitly set, derive from series data\n    if (yMin === undefined || yMax === undefined) {\n      const series = opts.series ?? [];\n      let dataYMin = Number.POSITIVE_INFINITY;\n      let dataYMax = Number.NEGATIVE_INFINITY;\n\n      for (const s of series) {\n        if (s.type === 'pie') continue;\n\n        if (s.type === 'candlestick') {\n          const data = s.data;\n          for (const p of data) {\n            const high = getOHLCHigh(p);\n            const low = getOHLCLow(p);\n            if (high > dataYMax) dataYMax = high;\n            if (low < dataYMin) dataYMin = low;\n          }\n        } else {\n          // TODO(step 2): normalize CartesianSeriesData to ReadonlyArray<DataPoint>\n          const data = s.data as ReadonlyArray<DataPoint>;\n          for (const p of data) {\n            const y = getPointY(p);\n            if (y < dataYMin) dataYMin = y;\n            if (y > dataYMax) dataYMax = y;\n          }\n        }\n      }\n\n      if (yMin === undefined) yMin = Number.isFinite(dataYMin) ? dataYMin : 0;\n      if (yMax === undefined) yMax = Number.isFinite(dataYMax) ? dataYMax : 100;\n    }\n\n    return { min: yMin, max: yMax };\n  }\n\n  /**\n   * Convert data-space coordinates to canvas-space CSS pixels\n   */\n  function dataToCanvas(x: number | undefined, y: number | undefined): { x: number; y: number } {\n    const chartOptions = chart.options;\n    const rect = canvas.getBoundingClientRect();\n\n    const grid = chartOptions.grid ?? { left: 60, right: 20, top: 40, bottom: 40 };\n    const canvasWidth = rect.width;\n    const canvasHeight = rect.height;\n\n    const plotLeft = grid.left ?? 60;\n    const plotRight = canvasWidth - (grid.right ?? 20);\n    const plotTop = grid.top ?? 40;\n    const plotBottom = canvasHeight - (grid.bottom ?? 40);\n    const plotWidth = plotRight - plotLeft;\n    const plotHeight = plotBottom - plotTop;\n\n    // Get scales from chart\n    const xAxis = chartOptions.xAxis;\n    const yAxis = chartOptions.yAxis;\n\n    let canvasX = 0;\n    let canvasY = 0;\n\n    // Convert X coordinate\n    if (x !== undefined && xAxis) {\n      if (xAxis.type === 'category' && Array.isArray((xAxis as any).data)) {\n        // Category scale: find index and map to plot space\n        const data = (xAxis as any).data as string[];\n        const index = data.indexOf(String(x));\n        if (index >= 0) {\n          const fraction = index / (data.length - 1 || 1);\n          canvasX = plotLeft + fraction * plotWidth;\n        }\n      } else {\n        // Linear scale - compute actual domain from data\n        const domain = computeXDomain();\n        const min = domain.min;\n        const max = domain.max;\n        const fraction = (x - min) / (max - min || 1);\n        canvasX = plotLeft + fraction * plotWidth;\n      }\n    }\n\n    // Convert Y coordinate (inverted: canvas top = max Y value)\n    if (y !== undefined && yAxis) {\n      // Compute actual domain from data\n      const domain = computeYDomain();\n      const min = domain.min;\n      const max = domain.max;\n      const fraction = (y - min) / (max - min || 1);\n      canvasY = plotBottom - fraction * plotHeight; // Inverted Y\n    }\n\n    return { x: canvasX, y: canvasY };\n  }\n\n  /**\n   * Convert plot-space coordinates (0-1 fractions) to canvas-space CSS pixels\n   */\n  function plotToCanvas(x: number, y: number): { x: number; y: number } {\n    const chartOptions = chart.options;\n    const rect = canvas.getBoundingClientRect();\n\n    const grid = chartOptions.grid ?? { left: 60, right: 20, top: 40, bottom: 40 };\n    const canvasWidth = rect.width;\n    const canvasHeight = rect.height;\n\n    const plotLeft = grid.left ?? 60;\n    const plotRight = canvasWidth - (grid.right ?? 20);\n    const plotTop = grid.top ?? 40;\n    const plotBottom = canvasHeight - (grid.bottom ?? 40);\n    const plotWidth = plotRight - plotLeft;\n    const plotHeight = plotBottom - plotTop;\n\n    return {\n      x: plotLeft + x * plotWidth,\n      y: plotTop + y * plotHeight,\n    };\n  }\n\n  /**\n   * Update cached bounds for all annotations\n   */\n  function updateCache(annotations: readonly AnnotationConfig[]): void {\n    boundsCache.clear();\n\n    annotations.forEach((annotation, index) => {\n      const bounds: CachedAnnotationBounds = {};\n\n      if (annotation.type === 'lineX' && annotation.x !== undefined) {\n        const { x } = dataToCanvas(annotation.x, undefined);\n        bounds.canvasX = x;\n      } else if (annotation.type === 'lineY' && annotation.y !== undefined) {\n        const { y } = dataToCanvas(undefined, annotation.y);\n        bounds.canvasY = y;\n      } else if (annotation.type === 'point' && annotation.x !== undefined && annotation.y !== undefined) {\n        const { x, y } = dataToCanvas(annotation.x, annotation.y);\n        bounds.canvasX = x;\n        bounds.canvasY = y;\n      } else if (annotation.type === 'text') {\n        const pos = annotation.position;\n        if (pos.space === 'plot') {\n          const { x, y } = plotToCanvas(pos.x, pos.y);\n          bounds.canvasX = x;\n          bounds.canvasY = y;\n        } else if (pos.space === 'data') {\n          const { x, y } = dataToCanvas(pos.x, pos.y);\n          bounds.canvasX = x;\n          bounds.canvasY = y;\n        }\n      }\n\n      boundsCache.set(index, bounds);\n    });\n\n    cacheValid = true;\n  }\n\n  /**\n   * Calculate distance from pointer to a line (vertical or horizontal)\n   */\n  function distanceToLine(\n    pointerX: number,\n    pointerY: number,\n    lineX?: number,\n    lineY?: number\n  ): number {\n    if (lineX !== undefined) {\n      // Vertical line: distance is horizontal difference\n      return Math.abs(pointerX - lineX);\n    } else if (lineY !== undefined) {\n      // Horizontal line: distance is vertical difference\n      return Math.abs(pointerY - lineY);\n    }\n    return Infinity;\n  }\n\n  /**\n   * Calculate distance from pointer to a point\n   */\n  function distanceToPoint(\n    pointerX: number,\n    pointerY: number,\n    pointX: number,\n    pointY: number\n  ): number {\n    const dx = pointerX - pointX;\n    const dy = pointerY - pointY;\n    return Math.sqrt(dx * dx + dy * dy);\n  }\n\n  /**\n   * Check if pointer is inside a rectangle (with tolerance padding)\n   */\n  function isInsideRect(\n    pointerX: number,\n    pointerY: number,\n    rect: DOMRect,\n    tolerance: number\n  ): boolean {\n    return (\n      pointerX >= rect.left - tolerance &&\n      pointerX <= rect.right + tolerance &&\n      pointerY >= rect.top - tolerance &&\n      pointerY <= rect.bottom + tolerance\n    );\n  }\n\n  /**\n   * Perform hit test at the given canvas position\n   */\n  function hitTest(canvasX: number, canvasY: number): AnnotationHitTestResult | null {\n    const annotations = chart.options.annotations ?? [];\n\n    if (annotations.length === 0) {\n      return null;\n    }\n\n    // Update cache if invalid\n    if (!cacheValid) {\n      updateCache(annotations);\n    }\n\n    let closestHit: AnnotationHitTestResult | null = null;\n    let closestDistance = Infinity;\n\n    // Priority order: Labels > Points > Text > Lines\n    // Test in reverse priority order (lines first) so higher priority overwrites\n\n    // 1. Test lines (lowest priority)\n    for (let i = 0; i < annotations.length; i++) {\n      const annotation = annotations[i];\n      const bounds = boundsCache.get(i);\n\n      if (!bounds) {\n        continue;\n      }\n\n      if (annotation.type === 'lineX' && bounds.canvasX !== undefined) {\n        const distance = distanceToLine(canvasX, canvasY, bounds.canvasX, undefined);\n        if (distance <= lineTolerance && distance < closestDistance) {\n          closestDistance = distance;\n          closestHit = {\n            annotationIndex: i,\n            annotation,\n            hitType: 'line',\n            distanceCssPx: distance,\n          };\n        }\n      } else if (annotation.type === 'lineY' && bounds.canvasY !== undefined) {\n        const distance = distanceToLine(canvasX, canvasY, undefined, bounds.canvasY);\n        if (distance <= lineTolerance && distance < closestDistance) {\n          closestDistance = distance;\n          closestHit = {\n            annotationIndex: i,\n            annotation,\n            hitType: 'line',\n            distanceCssPx: distance,\n          };\n        }\n      }\n    }\n\n    // 2. Test text (medium priority)\n    for (let i = 0; i < annotations.length; i++) {\n      const annotation = annotations[i];\n      const textRect = textBoundsCache.get(i);\n\n      if (annotation.type === 'text' && textRect) {\n        if (isInsideRect(canvasX, canvasY, textRect, textTolerance)) {\n          const centerX = textRect.left + textRect.width / 2;\n          const centerY = textRect.top + textRect.height / 2;\n          const distance = distanceToPoint(canvasX, canvasY, centerX, centerY);\n\n          if (distance < closestDistance) {\n            closestDistance = distance;\n            closestHit = {\n              annotationIndex: i,\n              annotation,\n              hitType: 'text',\n              distanceCssPx: distance,\n            };\n          }\n        }\n      }\n    }\n\n    // 3. Test points (high priority)\n    for (let i = 0; i < annotations.length; i++) {\n      const annotation = annotations[i];\n      const bounds = boundsCache.get(i);\n\n      if (bounds && annotation.type === 'point' && bounds.canvasX !== undefined && bounds.canvasY !== undefined) {\n        const distance = distanceToPoint(canvasX, canvasY, bounds.canvasX, bounds.canvasY);\n        if (distance <= pointTolerance && distance < closestDistance) {\n          closestDistance = distance;\n          closestHit = {\n            annotationIndex: i,\n            annotation,\n            hitType: 'point',\n            distanceCssPx: distance,\n          };\n        }\n      }\n    }\n\n    // 4. Test labels (highest priority) - TODO: implement once label bounds are available\n\n    return closestHit;\n  }\n\n  /**\n   * Update text bounds from DOM measurements\n   */\n  function updateTextBounds(textBounds: Map<number, DOMRect>): void {\n    textBoundsCache = new Map(textBounds);\n  }\n\n  /**\n   * Invalidate cache (call on zoom, pan, or resize)\n   */\n  function invalidateCache(): void {\n    cacheValid = false;\n  }\n\n  /**\n   * Dispose of resources\n   */\n  function dispose(): void {\n    boundsCache.clear();\n    textBoundsCache.clear();\n  }\n\n  return {\n    hitTest,\n    updateTextBounds,\n    invalidateCache,\n    dispose,\n  };\n}\n","/**\n * Drag handler for repositioning annotations\n *\n * Handles dragging annotations to reposition them:\n * - lineX: constrained to horizontal movement\n * - lineY: constrained to vertical movement\n * - text: free 2D movement (data or plot space)\n * - point: free 2D movement (data space)\n *\n * Uses optimistic updates during drag for 60 FPS performance.\n */\n\nimport type { AnnotationConfig, DataPoint } from '../config/types.js';\nimport type { ChartGPUInstance } from '../ChartGPU.js';\n\nexport interface AnnotationDragCallbacks {\n  onDragMove: (index: number, updates: Partial<AnnotationConfig>) => void;\n  onDragEnd: (index: number, updates: Partial<AnnotationConfig>) => void;\n  onDragCancel: () => void;\n}\n\nexport interface AnnotationDragHandler {\n  startDrag(\n    annotationIndex: number,\n    annotation: AnnotationConfig,\n    startPointerX: number,\n    startPointerY: number\n  ): void;\n  isDragging(): boolean;\n  dispose(): void;\n}\n\ninterface DragState {\n  annotationIndex: number;\n  annotation: AnnotationConfig;\n  startPointerX: number;\n  startPointerY: number;\n  pointerId: number | null;\n}\n\n/**\n * Creates a drag handler for repositioning annotations\n */\nexport function createAnnotationDragHandler(\n  chart: ChartGPUInstance,\n  canvas: HTMLCanvasElement,\n  callbacks: AnnotationDragCallbacks\n): AnnotationDragHandler {\n  let dragState: DragState | null = null;\n\n  // Type guards for data points\n  const isTupleDataPoint = (p: any): p is [number, number] => Array.isArray(p);\n  const isTupleOHLCDataPoint = (p: any): p is [number, number, number, number, number] => Array.isArray(p);\n  const getPointX = (p: any): number => (isTupleDataPoint(p) ? p[0] : p.x);\n  const getPointY = (p: any): number => (isTupleDataPoint(p) ? p[1] : p.y);\n  const getOHLCTimestamp = (p: any): number => (isTupleOHLCDataPoint(p) ? p[0] : p.timestamp);\n  const getOHLCHigh = (p: any): number => (isTupleOHLCDataPoint(p) ? p[2] : p.high);\n  const getOHLCLow = (p: any): number => (isTupleOHLCDataPoint(p) ? p[3] : p.low);\n\n  /**\n   * Compute the actual X domain from series data (with zoom applied)\n   */\n  function computeXDomain(): { min: number; max: number } {\n    const opts = chart.options;\n    let xMin = opts.xAxis?.min;\n    let xMax = opts.xAxis?.max;\n\n    if (xMin === undefined || xMax === undefined) {\n      const series = opts.series ?? [];\n      let dataXMin = Number.POSITIVE_INFINITY;\n      let dataXMax = Number.NEGATIVE_INFINITY;\n\n      for (const s of series) {\n        if (s.type === 'pie') continue;\n\n        if (s.type === 'candlestick') {\n          const data = s.data;\n          for (const p of data) {\n            const timestamp = getOHLCTimestamp(p);\n            if (timestamp < dataXMin) dataXMin = timestamp;\n            if (timestamp > dataXMax) dataXMax = timestamp;\n          }\n        } else {\n          // TODO(step 2): normalize CartesianSeriesData to ReadonlyArray<DataPoint>\n          const data = s.data as ReadonlyArray<DataPoint>;\n          for (const p of data) {\n            const x = getPointX(p);\n            if (x < dataXMin) dataXMin = x;\n            if (x > dataXMax) dataXMax = x;\n          }\n        }\n      }\n\n      if (xMin === undefined) xMin = Number.isFinite(dataXMin) ? dataXMin : 0;\n      if (xMax === undefined) xMax = Number.isFinite(dataXMax) ? dataXMax : 100;\n    }\n\n    const zoomRange = chart.getZoomRange();\n    if (zoomRange) {\n      const span = xMax - xMin;\n      const zoomMin = xMin + (zoomRange.start / 100) * span;\n      const zoomMax = xMin + (zoomRange.end / 100) * span;\n      return { min: zoomMin, max: zoomMax };\n    }\n\n    return { min: xMin, max: xMax };\n  }\n\n  /**\n   * Compute the actual Y domain from series data\n   */\n  function computeYDomain(): { min: number; max: number } {\n    const opts = chart.options;\n    let yMin = opts.yAxis?.min;\n    let yMax = opts.yAxis?.max;\n\n    if (yMin === undefined || yMax === undefined) {\n      const series = opts.series ?? [];\n      let dataYMin = Number.POSITIVE_INFINITY;\n      let dataYMax = Number.NEGATIVE_INFINITY;\n\n      for (const s of series) {\n        if (s.type === 'pie') continue;\n\n        if (s.type === 'candlestick') {\n          const data = s.data;\n          for (const p of data) {\n            const high = getOHLCHigh(p);\n            const low = getOHLCLow(p);\n            if (high > dataYMax) dataYMax = high;\n            if (low < dataYMin) dataYMin = low;\n          }\n        } else {\n          // TODO(step 2): normalize CartesianSeriesData to ReadonlyArray<DataPoint>\n          const data = s.data as ReadonlyArray<DataPoint>;\n          for (const p of data) {\n            const y = getPointY(p);\n            if (y < dataYMin) dataYMin = y;\n            if (y > dataYMax) dataYMax = y;\n          }\n        }\n      }\n\n      if (yMin === undefined) yMin = Number.isFinite(dataYMin) ? dataYMin : 0;\n      if (yMax === undefined) yMax = Number.isFinite(dataYMax) ? dataYMax : 100;\n    }\n\n    return { min: yMin, max: yMax };\n  }\n\n  /**\n   * Convert canvas-space CSS pixels to data-space coordinates\n   */\n  function canvasToData(canvasX: number, canvasY: number): { x: number; y: number } {\n    const chartOptions = chart.options;\n    const rect = canvas.getBoundingClientRect();\n\n    const grid = chartOptions.grid ?? { left: 60, right: 20, top: 40, bottom: 40 };\n    const canvasWidth = rect.width;\n    const canvasHeight = rect.height;\n\n    const plotLeft = grid.left ?? 60;\n    const plotRight = canvasWidth - (grid.right ?? 20);\n    const plotTop = grid.top ?? 40;\n    const plotBottom = canvasHeight - (grid.bottom ?? 40);\n    const plotWidth = plotRight - plotLeft;\n    const plotHeight = plotBottom - plotTop;\n\n    const xAxis = chartOptions.xAxis;\n    const yAxis = chartOptions.yAxis;\n\n    let dataX = 0;\n    let dataY = 0;\n\n    // Convert X coordinate\n    if (xAxis) {\n      const xFraction = (canvasX - plotLeft) / plotWidth;\n      if (xAxis.type === 'category' && Array.isArray((xAxis as any).data)) {\n        // Category scale: map fraction to category index\n        const data = (xAxis as any).data as any[];\n        const index = Math.round(xFraction * (data.length - 1 || 1));\n        dataX = data[Math.max(0, Math.min(index, data.length - 1))] as number;\n      } else {\n        // Linear scale - compute actual domain from data\n        const domain = computeXDomain();\n        dataX = domain.min + xFraction * (domain.max - domain.min);\n      }\n    }\n\n    // Convert Y coordinate (inverted: canvas top = max Y value)\n    if (yAxis) {\n      const yFraction = (plotBottom - canvasY) / plotHeight;\n      // Compute actual domain from data\n      const domain = computeYDomain();\n      dataY = domain.min + yFraction * (domain.max - domain.min);\n    }\n\n    return { x: dataX, y: dataY };\n  }\n\n  /**\n   * Convert canvas-space CSS pixels to plot-space coordinates (0-1 fractions)\n   */\n  function canvasToPlot(canvasX: number, canvasY: number): { x: number; y: number } {\n    const chartOptions = chart.options;\n    const rect = canvas.getBoundingClientRect();\n\n    const grid = chartOptions.grid ?? { left: 60, right: 20, top: 40, bottom: 40 };\n    const canvasWidth = rect.width;\n    const canvasHeight = rect.height;\n\n    const plotLeft = grid.left ?? 60;\n    const plotRight = canvasWidth - (grid.right ?? 20);\n    const plotTop = grid.top ?? 40;\n    const plotBottom = canvasHeight - (grid.bottom ?? 40);\n    const plotWidth = plotRight - plotLeft;\n    const plotHeight = plotBottom - plotTop;\n\n    const x = (canvasX - plotLeft) / plotWidth;\n    const y = (canvasY - plotTop) / plotHeight;\n\n    // Clamp to [0, 1]\n    return {\n      x: Math.max(0, Math.min(1, x)),\n      y: Math.max(0, Math.min(1, y)),\n    };\n  }\n\n  /**\n   * Handle pointer move during drag\n   */\n  function onPointerMove(e: PointerEvent): void {\n    if (!dragState) {\n      return;\n    }\n\n    e.preventDefault();\n\n    const rect = canvas.getBoundingClientRect();\n    const canvasX = e.clientX - rect.left;\n    const canvasY = e.clientY - rect.top;\n\n    const annotation = dragState.annotation;\n    const updates: any = {}; // Use 'any' to bypass TypeScript union narrowing issues\n\n    if (annotation.type === 'lineX') {\n      // Constrain to horizontal movement only\n      const { x } = canvasToData(canvasX, 0);\n      updates.x = x;\n    } else if (annotation.type === 'lineY') {\n      // Constrain to vertical movement only\n      const { y } = canvasToData(0, canvasY);\n      updates.y = y;\n    } else if (annotation.type === 'text') {\n      // Free 2D movement (respect original space)\n      const space = annotation.position.space;\n      if (space === 'plot') {\n        const { x, y } = canvasToPlot(canvasX, canvasY);\n        updates.position = { space, x, y };\n      } else {\n        // data space\n        const { x, y } = canvasToData(canvasX, canvasY);\n        updates.position = { space, x, y };\n      }\n    } else if (annotation.type === 'point') {\n      // Free 2D movement in data space\n      const { x, y } = canvasToData(canvasX, canvasY);\n      updates.x = x;\n      updates.y = y;\n    }\n\n    // Optimistic update (no history push)\n    callbacks.onDragMove(dragState.annotationIndex, updates);\n  }\n\n  /**\n   * Handle pointer up (drag end)\n   */\n  function onPointerUp(e: PointerEvent): void {\n    if (!dragState) return;\n\n    const rect = canvas.getBoundingClientRect();\n    const canvasX = e.clientX - rect.left;\n    const canvasY = e.clientY - rect.top;\n\n    const annotation = dragState.annotation;\n    const updates: any = {}; // Use 'any' to bypass TypeScript union narrowing issues\n\n    if (annotation.type === 'lineX') {\n      const { x } = canvasToData(canvasX, 0);\n      updates.x = x;\n    } else if (annotation.type === 'lineY') {\n      const { y } = canvasToData(0, canvasY);\n      updates.y = y;\n    } else if (annotation.type === 'text') {\n      const space = annotation.position.space;\n      if (space === 'plot') {\n        const { x, y } = canvasToPlot(canvasX, canvasY);\n        updates.position = { space, x, y };\n      } else {\n        const { x, y } = canvasToData(canvasX, canvasY);\n        updates.position = { space, x, y };\n      }\n    } else if (annotation.type === 'point') {\n      const { x, y } = canvasToData(canvasX, canvasY);\n      updates.x = x;\n      updates.y = y;\n    }\n\n    // Push single history entry with final position\n    callbacks.onDragEnd(dragState.annotationIndex, updates);\n\n    cleanup();\n  }\n\n  /**\n   * Handle pointer cancel (drag cancelled)\n   */\n  function onPointerCancel(): void {\n    if (!dragState) return;\n\n    // Revert to original position\n    callbacks.onDragCancel();\n\n    cleanup();\n  }\n\n  /**\n   * Handle keyboard events during drag\n   */\n  function onKeyDown(e: KeyboardEvent): void {\n    if (!dragState) return;\n\n    if (e.key === 'Escape') {\n      e.preventDefault();\n      onPointerCancel();\n    }\n  }\n\n  /**\n   * Cleanup drag state and event listeners\n   */\n  function cleanup(): void {\n    if (!dragState) return;\n\n    window.removeEventListener('pointermove', onPointerMove);\n    window.removeEventListener('pointerup', onPointerUp);\n    window.removeEventListener('pointercancel', onPointerCancel);\n    document.removeEventListener('keydown', onKeyDown);\n\n    if (dragState.pointerId !== null) {\n      try {\n        canvas.releasePointerCapture(dragState.pointerId);\n      } catch (err) {\n        // Ignore errors (pointer may already be released)\n      }\n    }\n\n    document.body.style.cursor = '';\n    dragState = null;\n  }\n\n  /**\n   * Start dragging an annotation\n   */\n  function startDrag(\n    annotationIndex: number,\n    annotation: AnnotationConfig,\n    startPointerX: number,\n    startPointerY: number\n  ): void {\n    // Cancel any existing drag\n    if (dragState) {\n      cleanup();\n    }\n\n    dragState = {\n      annotationIndex,\n      annotation,\n      startPointerX,\n      startPointerY,\n      pointerId: null,\n    };\n\n    // Set cursor based on annotation type\n    if (annotation.type === 'lineX') {\n      document.body.style.cursor = 'ew-resize';\n    } else if (annotation.type === 'lineY') {\n      document.body.style.cursor = 'ns-resize';\n    } else {\n      document.body.style.cursor = 'grabbing';\n    }\n\n    // Attach window-level listeners for smooth dragging outside canvas\n    window.addEventListener('pointermove', onPointerMove, { passive: false });\n    window.addEventListener('pointerup', onPointerUp, { passive: true });\n    window.addEventListener('pointercancel', onPointerCancel, { passive: true });\n    document.addEventListener('keydown', onKeyDown, { passive: false });\n\n    // Visual feedback: reduce opacity\n    callbacks.onDragMove(annotationIndex, {\n      style: { ...annotation.style, opacity: 0.7 },\n    });\n  }\n\n  /**\n   * Check if currently dragging\n   */\n  function isDragging(): boolean {\n    return dragState !== null;\n  }\n\n  /**\n   * Dispose of resources\n   */\n  function dispose(): void {\n    cleanup();\n  }\n\n  return {\n    startDrag,\n    isDragging,\n    dispose,\n  };\n}\n","/**\n * Configuration dialog for creating and editing annotations\n *\n * Provides a modal dialog for setting annotation properties:\n * - Label, color, line style, line width (for lines)\n * - Text content, color, font size (for text annotations)\n * - Label, color, marker size (for point annotations)\n */\n\nimport type { AnnotationConfig } from '../config/types.js';\n\nexport interface AnnotationConfigDialogOptions {\n  readonly palette?: readonly string[];\n  readonly zIndex?: number;\n}\n\nexport interface AnnotationConfigDialog {\n  showCreate(\n    annotationType: 'lineX' | 'lineY' | 'text' | 'point',\n    defaults: Partial<AnnotationConfig>,\n    onSave: (config: AnnotationConfig) => void,\n    onCancel: () => void\n  ): void;\n\n  showEdit(\n    annotation: AnnotationConfig,\n    onSave: (updates: Partial<AnnotationConfig>) => void,\n    onCancel: () => void\n  ): void;\n\n  hide(): void;\n  dispose(): void;\n}\n\nconst HIGH_CONTRAST_PALETTE = [\n  '#ef4444', // Red (critical)\n  '#f97316', // Orange (warning)\n  '#eab308', // Yellow (caution)\n  '#22c55e', // Green (success)\n  '#06b6d4', // Cyan (info)\n  '#3b82f6', // Blue (primary)\n  '#8b5cf6', // Purple (accent)\n  '#ec4899', // Pink (highlight)\n  '#ffffff', // White (high contrast)\n  '#94a3b8', // Gray (neutral)\n  '#64748b', // Dark gray (subtle)\n  '#1e293b', // Near-black (background)\n] as const;\n\n/**\n * Creates a configuration dialog for annotations\n */\nexport function createAnnotationConfigDialog(\n  container: HTMLElement,\n  options: AnnotationConfigDialogOptions = {}\n): AnnotationConfigDialog {\n  const palette = options.palette ?? HIGH_CONTRAST_PALETTE;\n  const zIndex = options.zIndex ?? 1000;\n\n  let overlay: HTMLDivElement | null = null;\n  let dialog: HTMLDivElement | null = null;\n  let currentOnSave: ((config: any) => void) | null = null;\n  let currentOnCancel: (() => void) | null = null;\n  let mode: 'create' | 'edit' = 'create';\n\n  /**\n   * Create the modal overlay\n   */\n  function createOverlay(): HTMLDivElement {\n    const div = document.createElement('div');\n    div.style.cssText = `\n      position: fixed;\n      top: 0;\n      left: 0;\n      right: 0;\n      bottom: 0;\n      background: rgba(0, 0, 0, 0.4);\n      z-index: ${zIndex + 1};\n      display: flex;\n      align-items: center;\n      justify-content: center;\n    `;\n    div.addEventListener('click', (e) => {\n      if (e.target === div) {\n        handleCancel();\n      }\n    });\n    return div;\n  }\n\n  /**\n   * Create the dialog box\n   */\n  function createDialog(): HTMLDivElement {\n    const div = document.createElement('div');\n    div.style.cssText = `\n      width: 320px;\n      background: #1a1a2e;\n      border: 1px solid #333;\n      border-radius: 8px;\n      box-shadow: 0 8px 24px rgba(0, 0, 0, 0.7);\n      padding: 20px;\n      font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, sans-serif;\n      color: #e0e0e0;\n    `;\n    return div;\n  }\n\n  /**\n   * Create a form field container\n   */\n  function createField(label: string, input: HTMLElement): HTMLDivElement {\n    const field = document.createElement('div');\n    field.style.cssText = `\n      margin-bottom: 16px;\n    `;\n\n    const labelEl = document.createElement('label');\n    labelEl.textContent = label;\n    labelEl.style.cssText = `\n      display: block;\n      margin-bottom: 8px;\n      font-size: 13px;\n      font-weight: 500;\n      color: #b0b0b0;\n    `;\n\n    field.appendChild(labelEl);\n    field.appendChild(input);\n    return field;\n  }\n\n  /**\n   * Create a text input\n   */\n  function createTextInput(placeholder: string, maxLength: number, defaultValue = ''): HTMLInputElement {\n    const input = document.createElement('input');\n    input.type = 'text';\n    input.placeholder = placeholder;\n    input.maxLength = maxLength;\n    input.value = defaultValue;\n    input.style.cssText = `\n      width: 100%;\n      padding: 8px 12px;\n      background: #2a2a3e;\n      border: 1px solid #444;\n      border-radius: 4px;\n      color: #e0e0e0;\n      font-size: 14px;\n      box-sizing: border-box;\n    `;\n    input.addEventListener('focus', () => {\n      input.style.borderColor = '#3b82f6';\n    });\n    input.addEventListener('blur', () => {\n      input.style.borderColor = '#444';\n    });\n    return input;\n  }\n\n  /**\n   * Create a textarea\n   */\n  function createTextArea(placeholder: string, maxLength: number, defaultValue = ''): HTMLTextAreaElement {\n    const textarea = document.createElement('textarea');\n    textarea.placeholder = placeholder;\n    textarea.maxLength = maxLength;\n    textarea.value = defaultValue;\n    textarea.rows = 3;\n    textarea.style.cssText = `\n      width: 100%;\n      padding: 8px 12px;\n      background: #2a2a3e;\n      border: 1px solid #444;\n      border-radius: 4px;\n      color: #e0e0e0;\n      font-size: 14px;\n      box-sizing: border-box;\n      resize: vertical;\n      font-family: inherit;\n    `;\n    textarea.addEventListener('focus', () => {\n      textarea.style.borderColor = '#3b82f6';\n    });\n    textarea.addEventListener('blur', () => {\n      textarea.style.borderColor = '#444';\n    });\n    return textarea;\n  }\n\n  /**\n   * Create a color picker grid\n   */\n  function createColorPicker(selectedColor: string): { container: HTMLDivElement; getValue: () => string } {\n    const container = document.createElement('div');\n    container.style.cssText = `\n      display: grid;\n      grid-template-columns: repeat(4, 1fr);\n      gap: 8px;\n    `;\n\n    let currentColor = selectedColor;\n\n    palette.forEach((color) => {\n      // Button wrapper for swatch\n      const swatch = document.createElement('button');\n      swatch.type = 'button';\n      swatch.dataset.color = color; // Store color for reliable comparison\n      swatch.style.cssText = `\n        position: relative;\n        width: 100%;\n        aspect-ratio: 1;\n        background: ${color};\n        border: none;\n        border-radius: 4px;\n        cursor: pointer;\n        transition: transform 0.15s ease-out, box-shadow 0.15s ease-out;\n        box-shadow: ${color === currentColor ? 'inset 0 0 0 2px #ffffff, inset 0 0 0 3px rgba(0, 0, 0, 0.3), 0 2px 8px rgba(0, 0, 0, 0.3)' : 'inset 0 0 0 1px rgba(255, 255, 255, 0.1)'};\n        transform: ${color === currentColor ? 'scale(1.05)' : 'scale(1)'};\n      `;\n\n      // Create checkmark SVG for selected state\n      const checkmark = document.createElementNS('http://www.w3.org/2000/svg', 'svg');\n      checkmark.setAttribute('viewBox', '0 0 24 24');\n      checkmark.setAttribute('fill', 'none');\n      checkmark.style.cssText = `\n        position: absolute;\n        top: 50%;\n        left: 50%;\n        transform: translate(-50%, -50%);\n        width: 60%;\n        height: 60%;\n        pointer-events: none;\n        opacity: ${color === currentColor ? '1' : '0'};\n        transition: opacity 0.15s ease-out;\n      `;\n\n      // Checkmark path with dual stroke for maximum contrast\n      const path = document.createElementNS('http://www.w3.org/2000/svg', 'path');\n      path.setAttribute('d', 'M20 6L9 17l-5-5');\n      path.setAttribute('stroke', '#ffffff');\n      path.setAttribute('stroke-width', '3');\n      path.setAttribute('stroke-linecap', 'round');\n      path.setAttribute('stroke-linejoin', 'round');\n      path.style.cssText = `\n        filter: drop-shadow(0 1px 2px rgba(0, 0, 0, 0.8)) drop-shadow(0 0 1px rgba(0, 0, 0, 0.9));\n      `;\n\n      checkmark.appendChild(path);\n      swatch.appendChild(checkmark);\n\n      // Click handler\n      swatch.addEventListener('click', () => {\n        currentColor = color;\n        // Update all swatches\n        Array.from(container.children).forEach((child) => {\n          const btn = child as HTMLButtonElement;\n          const btnColor = btn.dataset.color; // Use data attribute for reliable comparison\n          const isSelected = btnColor === color;\n\n          // Update box-shadow for border effect\n          btn.style.boxShadow = isSelected\n            ? 'inset 0 0 0 2px #ffffff, inset 0 0 0 3px rgba(0, 0, 0, 0.3), 0 2px 8px rgba(0, 0, 0, 0.3)'\n            : 'inset 0 0 0 1px rgba(255, 255, 255, 0.1)';\n\n          // Update scale\n          btn.style.transform = isSelected ? 'scale(1.05)' : 'scale(1)';\n\n          // Update checkmark visibility\n          const svg = btn.querySelector('svg');\n          if (svg) {\n            svg.style.opacity = isSelected ? '1' : '0';\n          }\n        });\n      });\n\n      // Hover effects\n      swatch.addEventListener('mouseenter', () => {\n        if (color !== currentColor) {\n          swatch.style.transform = 'scale(1.1)';\n          swatch.style.boxShadow = 'inset 0 0 0 2px rgba(255, 255, 255, 0.2), 0 4px 12px rgba(0, 0, 0, 0.4)';\n        }\n      });\n\n      swatch.addEventListener('mouseleave', () => {\n        if (color !== currentColor) {\n          swatch.style.transform = 'scale(1)';\n          swatch.style.boxShadow = 'inset 0 0 0 1px rgba(255, 255, 255, 0.1)';\n        }\n      });\n\n      container.appendChild(swatch);\n    });\n\n    return {\n      container,\n      getValue: () => currentColor,\n    };\n  }\n\n  /**\n   * Create a dropdown select\n   */\n  function createDropdown(\n    options: Array<{ label: string; value: string }>,\n    defaultValue: string\n  ): { container: HTMLSelectElement; getValue: () => string } {\n    const select = document.createElement('select');\n    select.style.cssText = `\n      width: 100%;\n      padding: 8px 12px;\n      background: #2a2a3e;\n      border: 1px solid #444;\n      border-radius: 4px;\n      color: #e0e0e0;\n      font-size: 14px;\n      cursor: pointer;\n    `;\n\n    options.forEach((opt) => {\n      const option = document.createElement('option');\n      option.value = opt.value;\n      option.textContent = opt.label;\n      if (opt.value === defaultValue) {\n        option.selected = true;\n      }\n      select.appendChild(option);\n    });\n\n    return {\n      container: select,\n      getValue: () => select.value,\n    };\n  }\n\n  /**\n   * Create a slider with numeric value display\n   */\n  function createSlider(\n    min: number,\n    max: number,\n    step: number,\n    defaultValue: number,\n    unit = ''\n  ): { container: HTMLDivElement; getValue: () => number } {\n    const container = document.createElement('div');\n    container.style.cssText = `\n      display: flex;\n      align-items: center;\n      gap: 12px;\n    `;\n\n    const slider = document.createElement('input');\n    slider.type = 'range';\n    slider.min = String(min);\n    slider.max = String(max);\n    slider.step = String(step);\n    slider.value = String(defaultValue);\n    slider.style.cssText = `\n      flex: 1;\n      cursor: pointer;\n    `;\n\n    const valueDisplay = document.createElement('span');\n    valueDisplay.textContent = `${defaultValue}${unit}`;\n    valueDisplay.style.cssText = `\n      min-width: 40px;\n      text-align: right;\n      font-size: 13px;\n      color: #b0b0b0;\n    `;\n\n    slider.addEventListener('input', () => {\n      valueDisplay.textContent = `${slider.value}${unit}`;\n    });\n\n    container.appendChild(slider);\n    container.appendChild(valueDisplay);\n\n    return {\n      container,\n      getValue: () => parseFloat(slider.value),\n    };\n  }\n\n  /**\n   * Create action buttons\n   */\n  function createButtons(saveLabel: string, onSaveClick: () => void, onCancelClick: () => void): HTMLDivElement {\n    const container = document.createElement('div');\n    container.style.cssText = `\n      display: flex;\n      justify-content: flex-end;\n      gap: 12px;\n      margin-top: 24px;\n    `;\n\n    const cancelBtn = document.createElement('button');\n    cancelBtn.type = 'button';\n    cancelBtn.textContent = 'Cancel';\n    cancelBtn.style.cssText = `\n      padding: 8px 16px;\n      background: transparent;\n      border: 1px solid #444;\n      border-radius: 4px;\n      color: #888;\n      font-size: 14px;\n      cursor: pointer;\n      transition: background 0.15s;\n    `;\n    cancelBtn.addEventListener('mouseenter', () => {\n      cancelBtn.style.background = '#2a2a3e';\n    });\n    cancelBtn.addEventListener('mouseleave', () => {\n      cancelBtn.style.background = 'transparent';\n    });\n    cancelBtn.addEventListener('click', onCancelClick);\n\n    const saveBtn = document.createElement('button');\n    saveBtn.type = 'button';\n    saveBtn.textContent = saveLabel;\n    saveBtn.style.cssText = `\n      padding: 8px 16px;\n      background: #2a2a3e;\n      border: 1px solid #444;\n      border-radius: 4px;\n      color: #e0e0e0;\n      font-size: 14px;\n      font-weight: 500;\n      cursor: pointer;\n      transition: background 0.15s;\n    `;\n    saveBtn.addEventListener('mouseenter', () => {\n      saveBtn.style.background = '#3a3a4e';\n    });\n    saveBtn.addEventListener('mouseleave', () => {\n      saveBtn.style.background = '#2a2a3e';\n    });\n    saveBtn.addEventListener('click', onSaveClick);\n\n    container.appendChild(cancelBtn);\n    container.appendChild(saveBtn);\n\n    return container;\n  }\n\n  /**\n   * Build form for line annotations (lineX/lineY)\n   */\n  function buildLineForm(defaults: Partial<AnnotationConfig>): HTMLDivElement {\n    const form = document.createElement('div');\n\n    // Extract label text from label object (if it exists)\n    const defaultLabelText = (defaults as any).label?.text ?? '';\n    const labelInput = createTextInput('Line label', 100, defaultLabelText);\n    const colorPicker = createColorPicker(defaults.style?.color ?? palette[0]);\n    const lineStyleDropdown = createDropdown(\n      [\n        { label: 'Solid', value: 'solid' },\n        { label: 'Dashed', value: 'dashed' },\n        { label: 'Dotted', value: 'dotted' },\n      ],\n      defaults.style?.lineDash ? (defaults.style.lineDash.length === 4 ? 'dashed' : 'dotted') : 'solid'\n    );\n    const lineWidthSlider = createSlider(1, 8, 1, defaults.style?.lineWidth ?? 2, 'px');\n\n    form.appendChild(createField('Label (optional)', labelInput));\n    form.appendChild(createField('Color', colorPicker.container));\n    form.appendChild(createField('Line Style', lineStyleDropdown.container));\n    form.appendChild(createField('Line Width', lineWidthSlider.container));\n\n    const buttons = createButtons(\n      mode === 'create' ? 'Create' : 'Save',\n      () => {\n        const lineDashMap: Record<string, number[] | undefined> = {\n          solid: undefined,\n          dashed: [4, 4],\n          dotted: [2, 2],\n        };\n\n        const labelText = labelInput.value.trim();\n        const config: Partial<AnnotationConfig> = {\n          ...defaults,\n          label: labelText\n            ? {\n                ...(defaults as any).label,\n                text: labelText,\n              }\n            : undefined,\n          style: {\n            ...defaults.style,\n            color: colorPicker.getValue(),\n            lineWidth: lineWidthSlider.getValue(),\n            lineDash: lineDashMap[lineStyleDropdown.getValue()],\n          },\n        };\n\n        handleSave(config);\n      },\n      () => handleCancel()\n    );\n\n    form.appendChild(buttons);\n\n    return form;\n  }\n\n  /**\n   * Build form for text annotations\n   */\n  function buildTextForm(defaults: Partial<AnnotationConfig>): HTMLDivElement {\n    const form = document.createElement('div');\n\n    // Extract text from text annotation\n    const defaultText = (defaults as any).text ?? '';\n    const textArea = createTextArea('Text content', 500, defaultText);\n    const colorPicker = createColorPicker(defaults.style?.color ?? palette[0]);\n\n    form.appendChild(createField('Text', textArea));\n    form.appendChild(createField('Color', colorPicker.container));\n\n    const buttons = createButtons(\n      mode === 'create' ? 'Create' : 'Save',\n      () => {\n        const text = textArea.value.trim();\n        if (!text) {\n          textArea.style.borderColor = '#ef4444';\n          textArea.focus();\n          return;\n        }\n\n        const config: Partial<AnnotationConfig> = {\n          ...defaults,\n          text,\n          style: {\n            ...defaults.style,\n            color: colorPicker.getValue(),\n          },\n        } as any; // Use 'any' to bypass type narrowing issues\n\n        handleSave(config);\n      },\n      () => handleCancel()\n    );\n\n    form.appendChild(buttons);\n\n    return form;\n  }\n\n  /**\n   * Build form for point annotations\n   */\n  function buildPointForm(defaults: Partial<AnnotationConfig>): HTMLDivElement {\n    const form = document.createElement('div');\n\n    // Extract label text from label object (if it exists)\n    const defaultLabelText = (defaults as any).label?.text ?? '';\n    const labelInput = createTextInput('Point label', 100, defaultLabelText);\n    const colorPicker = createColorPicker(defaults.style?.color ?? palette[0]);\n\n    // For point annotations, marker style might be in marker.style or just style\n    const defaultMarkerSize = (defaults as any).marker?.size ?? (defaults as any).marker?.style?.markerSize ?? 8;\n    const markerSizeSlider = createSlider(4, 16, 1, defaultMarkerSize, 'px');\n\n    form.appendChild(createField('Label (optional)', labelInput));\n    form.appendChild(createField('Color', colorPicker.container));\n    form.appendChild(createField('Marker Size', markerSizeSlider.container));\n\n    const buttons = createButtons(\n      mode === 'create' ? 'Create' : 'Save',\n      () => {\n        const labelText = labelInput.value.trim();\n        const config: Partial<AnnotationConfig> = {\n          ...defaults,\n          label: labelText\n            ? {\n                ...(defaults as any).label,\n                text: labelText,\n              }\n            : undefined,\n          marker: {\n            ...(defaults as any).marker,\n            size: markerSizeSlider.getValue(),\n            style: {\n              ...(defaults as any).marker?.style,\n              color: colorPicker.getValue(),\n            },\n          },\n        };\n\n        handleSave(config);\n      },\n      () => handleCancel()\n    );\n\n    form.appendChild(buttons);\n\n    return form;\n  }\n\n  /**\n   * Handle save action\n   */\n  function handleSave(config: any): void {\n    if (currentOnSave) {\n      currentOnSave(config);\n    }\n    hide();\n  }\n\n  /**\n   * Handle cancel action\n   */\n  function handleCancel(): void {\n    if (currentOnCancel) {\n      currentOnCancel();\n    }\n    hide();\n  }\n\n  /**\n   * Handle keyboard events\n   */\n  function handleKeyDown(e: KeyboardEvent): void {\n    if (e.key === 'Escape') {\n      e.preventDefault();\n      handleCancel();\n    }\n  }\n\n  /**\n   * Show dialog for creating a new annotation\n   */\n  function showCreate(\n    type: 'lineX' | 'lineY' | 'text' | 'point',\n    defaults: Partial<AnnotationConfig>,\n    onSave: (config: AnnotationConfig) => void,\n    onCancel: () => void\n  ): void {\n    mode = 'create';\n    currentOnSave = onSave;\n    currentOnCancel = onCancel;\n\n    overlay = createOverlay();\n    dialog = createDialog();\n\n    const title = document.createElement('h3');\n    title.textContent = `Add ${type === 'lineX' ? 'Vertical Line' : type === 'lineY' ? 'Horizontal Line' : type === 'text' ? 'Text Note' : 'Point Marker'}`;\n    title.style.cssText = `\n      margin: 0 0 20px 0;\n      font-size: 16px;\n      font-weight: 600;\n      color: #ffffff;\n    `;\n    dialog.appendChild(title);\n\n    let form: HTMLDivElement;\n    if (type === 'lineX' || type === 'lineY') {\n      form = buildLineForm(defaults);\n    } else if (type === 'text') {\n      form = buildTextForm(defaults);\n    } else {\n      form = buildPointForm(defaults);\n    }\n\n    dialog.appendChild(form);\n    overlay.appendChild(dialog);\n    container.appendChild(overlay);\n\n    document.addEventListener('keydown', handleKeyDown);\n\n    // Focus first input\n    const firstInput = dialog.querySelector('input, textarea') as HTMLElement;\n    if (firstInput) {\n      setTimeout(() => firstInput.focus(), 50);\n    }\n  }\n\n  /**\n   * Show dialog for editing an existing annotation\n   */\n  function showEdit(\n    annotation: AnnotationConfig,\n    onSave: (updates: Partial<AnnotationConfig>) => void,\n    onCancel: () => void\n  ): void {\n    mode = 'edit';\n    currentOnSave = onSave;\n    currentOnCancel = onCancel;\n\n    overlay = createOverlay();\n    dialog = createDialog();\n\n    const title = document.createElement('h3');\n    title.textContent = 'Edit Annotation';\n    title.style.cssText = `\n      margin: 0 0 20px 0;\n      font-size: 16px;\n      font-weight: 600;\n      color: #ffffff;\n    `;\n    dialog.appendChild(title);\n\n    let form: HTMLDivElement;\n    if (annotation.type === 'lineX' || annotation.type === 'lineY') {\n      form = buildLineForm(annotation);\n    } else if (annotation.type === 'text') {\n      form = buildTextForm(annotation);\n    } else {\n      form = buildPointForm(annotation);\n    }\n\n    dialog.appendChild(form);\n    overlay.appendChild(dialog);\n    container.appendChild(overlay);\n\n    document.addEventListener('keydown', handleKeyDown);\n\n    // Focus first input\n    const firstInput = dialog.querySelector('input, textarea') as HTMLElement;\n    if (firstInput) {\n      setTimeout(() => firstInput.focus(), 50);\n    }\n  }\n\n  /**\n   * Hide the dialog\n   */\n  function hide(): void {\n    if (overlay && overlay.parentNode) {\n      overlay.parentNode.removeChild(overlay);\n    }\n    overlay = null;\n    dialog = null;\n    currentOnSave = null;\n    currentOnCancel = null;\n\n    document.removeEventListener('keydown', handleKeyDown);\n  }\n\n  /**\n   * Dispose of resources\n   */\n  function dispose(): void {\n    hide();\n  }\n\n  return {\n    showCreate,\n    showEdit,\n    hide,\n    dispose,\n  };\n}\n","/**\n * Annotation authoring helper for ChartGPU instances.\n *\n * Provides right-click context menu for adding vertical lines and text annotations,\n * with undo/redo, JSON export, drag-to-reposition, and editing capabilities.\n */\n\nimport type { ChartGPUInstance, ChartGPUHitTestResult } from '../ChartGPU';\nimport type { AnnotationConfig, DataPoint, DataPointTuple, OHLCDataPoint, OHLCDataPointTuple } from '../config/types';\nimport { defaultGrid } from '../config/defaults';\nimport { createAnnotationHitTester } from './createAnnotationHitTester';\nimport { createAnnotationDragHandler } from './createAnnotationDragHandler';\nimport { createAnnotationConfigDialog } from '../components/createAnnotationConfigDialog';\n\n// Type guards and helpers\nconst isTupleDataPoint = (p: DataPoint): p is DataPointTuple => Array.isArray(p);\nconst isTupleOHLCDataPoint = (p: OHLCDataPoint): p is OHLCDataPointTuple => Array.isArray(p);\n\nconst getPointX = (p: DataPoint): number => (isTupleDataPoint(p) ? p[0] : p.x);\nconst getPointY = (p: DataPoint): number => (isTupleDataPoint(p) ? p[1] : p.y);\nconst getOHLCTimestamp = (p: OHLCDataPoint): number => (isTupleOHLCDataPoint(p) ? p[0] : p.timestamp);\n\n/**\n * Configuration options for annotation authoring.\n */\nexport interface AnnotationAuthoringOptions {\n  /**\n   * Z-index for the context menu (default: 1000).\n   */\n  readonly menuZIndex?: number;\n  /**\n   * Enable right-click context menu (default: true).\n   */\n  readonly enableContextMenu?: boolean;\n}\n\n/**\n * Annotation authoring instance returned by `createAnnotationAuthoring`.\n * \n * Provides programmatic control over annotations and manages UI lifecycle.\n */\nexport interface AnnotationAuthoringInstance {\n  /**\n   * Programmatically add a vertical line annotation.\n   * \n   * @param x - X-coordinate in data domain units\n   */\n  addVerticalLine(x: number): void;\n  /**\n   * Programmatically add a text annotation.\n   * \n   * @param x - X-coordinate (domain units for 'data' space, fraction [0-1] for 'plot' space)\n   * @param y - Y-coordinate (domain units for 'data' space, fraction [0-1] for 'plot' space)\n   * @param text - Annotation text content\n   * @param space - Coordinate space: 'data' (default) or 'plot'\n   */\n  addTextNote(x: number, y: number, text: string, space?: 'data' | 'plot'): void;\n  /**\n   * Undo the last annotation change.\n   * \n   * @returns `true` if undo was successful, `false` if nothing to undo\n   */\n  undo(): boolean;\n  /**\n   * Redo a previously undone change.\n   * \n   * @returns `true` if redo was successful, `false` if nothing to redo\n   */\n  redo(): boolean;\n  /**\n   * Export current annotations as JSON string.\n   * \n   * @returns JSON string representation of annotations array\n   */\n  exportJSON(): string;\n  /**\n   * Get the current annotations array.\n   * \n   * @returns Readonly copy of current annotations\n   */\n  getAnnotations(): readonly AnnotationConfig[];\n  /**\n   * Clean up event listeners and DOM elements.\n   * \n   * Safe to call multiple times. After disposal, the instance should not be used.\n   */\n  dispose(): void;\n}\n\ninterface HistoryEntry {\n  readonly annotations: readonly AnnotationConfig[];\n}\n\n/**\n * Creates an annotation authoring helper for a chart instance.\n * \n * Features:\n * - Right-click context menu for adding vertical lines and text annotations\n * - Optional toolbar with undo/redo/export buttons\n * - Undo/redo history (50 entries max)\n * - JSON export with clipboard integration\n * - Automatic coordinate conversion (data-space and plot-space)\n * - Event listener cleanup on dispose\n * \n * Annotations are persisted by calling `chart.setOption({ ...options, annotations })`,\n * so they integrate seamlessly with the chart's option system.\n * \n * @param container - The chart container element (must contain the chart canvas)\n * @param chart - The ChartGPU instance\n * @param options - Optional configuration for menu/toolbar z-index and visibility\n * @returns Annotation authoring instance with programmatic API and dispose method\n * @throws Error if canvas is not found\n * \n * @example\n * ```ts\n * const chart = await ChartGPU.create(container, options);\n * const authoring = createAnnotationAuthoring(container, chart, {\n *   showToolbar: true,\n *   enableContextMenu: true,\n * });\n * \n * // Programmatic API\n * authoring.addVerticalLine(Date.now());\n * authoring.addTextNote(x, y, 'Peak', 'data');\n * authoring.undo();\n * authoring.redo();\n * const json = authoring.exportJSON();\n * \n * // Cleanup\n * authoring.dispose();\n * chart.dispose();\n * ```\n */\nexport function createAnnotationAuthoring(\n  container: HTMLElement,\n  chart: ChartGPUInstance,\n  options: AnnotationAuthoringOptions = {}\n): AnnotationAuthoringInstance {\n  const {\n    menuZIndex = 1000,\n    enableContextMenu = true,\n  } = options;\n\n  // Find the canvas element\n  const canvas = container.querySelector('canvas');\n  if (!canvas) {\n    throw new Error('createAnnotationAuthoring: canvas element not found in container');\n  }\n\n  // History management\n  let history: HistoryEntry[] = [{ annotations: chart.options.annotations ?? [] }];\n  let historyIndex = 0;\n  let disposed = false;\n\n  // Create hit tester, drag handler, and config dialog\n  const hitTester = createAnnotationHitTester(chart, canvas, {\n    lineTolerance: 20,\n    textTolerance: 8,\n    pointTolerance: 16,\n  });\n\n  const configDialog = createAnnotationConfigDialog(container, {\n    zIndex: menuZIndex,\n  });\n\n  const dragHandler = createAnnotationDragHandler(chart, canvas, {\n    onDragMove: (index, updates) => {\n      // Optimistic update without history\n      const current = getCurrentAnnotations();\n      const next = current.map((a, i) => (i === index ? { ...a, ...updates } as AnnotationConfig : a));\n      applyAnnotations(next);\n    },\n    onDragEnd: (index, updates) => {\n      // Final position with history push\n      const current = getCurrentAnnotations();\n      const next = current.map((a, i) => (i === index ? { ...a, ...updates } as AnnotationConfig : a));\n      applyAnnotations(next);\n      pushHistory(next);\n    },\n    onDragCancel: () => {\n      // Revert to last history state (no push)\n      const entry = history[historyIndex];\n      if (entry) {\n        applyAnnotations(entry.annotations);\n      }\n    },\n  });\n\n  // Get current annotations\n  const getCurrentAnnotations = (): readonly AnnotationConfig[] => {\n    return chart.options.annotations ?? [];\n  };\n\n  // Push a new history entry\n  const pushHistory = (annotations: readonly AnnotationConfig[]): void => {\n    // Truncate any redo history\n    history = history.slice(0, historyIndex + 1);\n    history.push({ annotations: [...annotations] });\n    historyIndex = history.length - 1;\n\n    // Limit history size to 50 entries\n    if (history.length > 50) {\n      history.shift();\n      historyIndex--;\n    }\n  };\n\n  // Apply annotations to chart\n  const applyAnnotations = (annotations: readonly AnnotationConfig[]): void => {\n    chart.setOption({\n      ...chart.options,\n      annotations: [...annotations],\n    });\n    // Invalidate hit tester cache so it picks up the new/modified annotations\n    hitTester.invalidateCache();\n  };\n\n  // Context menu DOM\n  let contextMenu: HTMLDivElement | null = null;\n\n  const createContextMenu = (): HTMLDivElement => {\n    const menu = document.createElement('div');\n    menu.style.position = 'fixed';\n    menu.style.display = 'none';\n    menu.style.backgroundColor = '#1a1a2e';\n    menu.style.border = '1px solid #333';\n    menu.style.borderRadius = '8px';\n    menu.style.boxShadow = '0 4px 12px rgba(0, 0, 0, 0.5)';\n    menu.style.zIndex = String(menuZIndex);\n    menu.style.minWidth = '180px';\n    menu.style.padding = '6px 0';\n    menu.style.fontFamily = '-apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, sans-serif';\n    menu.style.fontSize = '14px';\n    menu.style.color = '#e0e0e0';\n\n    document.body.appendChild(menu);\n    return menu;\n  };\n\n  const createMenuItem = (text: string, onClick: () => void): HTMLDivElement => {\n    const item = document.createElement('div');\n    item.textContent = text;\n    item.style.padding = '8px 16px';\n    item.style.cursor = 'pointer';\n    item.style.transition = 'background-color 0.15s';\n    item.style.userSelect = 'none';\n\n    item.addEventListener('mouseenter', () => {\n      item.style.backgroundColor = '#2a2a3e';\n    });\n    item.addEventListener('mouseleave', () => {\n      item.style.backgroundColor = 'transparent';\n    });\n    item.addEventListener('click', () => {\n      onClick();\n      hideContextMenu();\n    });\n\n    return item;\n  };\n\n  const createMenuSeparator = (): HTMLDivElement => {\n    const separator = document.createElement('div');\n    separator.style.height = '1px';\n    separator.style.backgroundColor = '#333';\n    separator.style.margin = '6px 0';\n    return separator;\n  };\n\n  const populateContextMenuForAnnotation = (\n    menu: HTMLDivElement,\n    annotationIndex: number,\n    annotation: AnnotationConfig\n  ): void => {\n    // Clear existing items\n    menu.innerHTML = '';\n\n    // Edit and delete for the annotation\n    menu.appendChild(createMenuItem('Edit annotation...', () => handleEditAnnotation(annotationIndex, annotation)));\n    menu.appendChild(createMenuItem('Delete annotation', () => handleDeleteAnnotation(annotationIndex)));\n    menu.appendChild(createMenuSeparator());\n\n    // Add new annotations\n    menu.appendChild(createMenuItem('Add vertical line here', () => handleAddVerticalLine()));\n    menu.appendChild(createMenuItem('Add horizontal line here', () => handleAddHorizontalLine()));\n    menu.appendChild(createMenuItem('Add text note here', () => handleAddTextNote()));\n  };\n\n  const populateContextMenuForEmptySpace = (menu: HTMLDivElement): void => {\n    // Clear existing items\n    menu.innerHTML = '';\n\n    // Add new annotations\n    menu.appendChild(createMenuItem('Add vertical line here', () => handleAddVerticalLine()));\n    menu.appendChild(createMenuItem('Add horizontal line here', () => handleAddHorizontalLine()));\n    menu.appendChild(createMenuItem('Add text note here', () => handleAddTextNote()));\n  };\n\n  // Toolbar removed - UI decluttering\n\n  // Show context menu\n  let lastHitTestResult: ChartGPUHitTestResult | null = null;\n\n  const showContextMenu = (e: MouseEvent): void => {\n    if (!contextMenu) return;\n\n    lastHitTestResult = chart.hitTest(e);\n\n    // Perform annotation hit test\n    const rect = canvas.getBoundingClientRect();\n    const canvasX = e.clientX - rect.left;\n    const canvasY = e.clientY - rect.top;\n    const annotationHit = hitTester.hitTest(canvasX, canvasY);\n\n    if (annotationHit) {\n      // Right-clicked on an annotation - show edit/delete menu\n      populateContextMenuForAnnotation(contextMenu, annotationHit.annotationIndex, annotationHit.annotation);\n    } else {\n      // Right-clicked on empty space - show add menu\n      populateContextMenuForEmptySpace(contextMenu);\n    }\n\n    contextMenu.style.display = 'block';\n    contextMenu.style.left = `${e.clientX}px`;\n    contextMenu.style.top = `${e.clientY}px`;\n\n    // Adjust position if menu goes off-screen (check both viewport bounds)\n    requestAnimationFrame(() => {\n      if (!contextMenu || contextMenu.style.display !== 'block') return;\n\n      const menuRect = contextMenu.getBoundingClientRect();\n      let adjustedX = e.clientX;\n      let adjustedY = e.clientY;\n\n      // Adjust horizontal position if menu extends beyond right edge\n      if (menuRect.right > window.innerWidth) {\n        adjustedX = Math.max(0, e.clientX - menuRect.width);\n      }\n\n      // Adjust vertical position if menu extends beyond bottom edge\n      if (menuRect.bottom > window.innerHeight) {\n        adjustedY = Math.max(0, e.clientY - menuRect.height);\n      }\n\n      // Apply adjustments if needed\n      if (adjustedX !== e.clientX || adjustedY !== e.clientY) {\n        contextMenu.style.left = `${adjustedX}px`;\n        contextMenu.style.top = `${adjustedY}px`;\n      }\n    });\n  };\n\n  const hideContextMenu = (): void => {\n    if (!contextMenu) return;\n    contextMenu.style.display = 'none';\n    lastHitTestResult = null;\n  };\n\n  // Compute visible x-domain for freeform vertical lines\n  const computeVisibleXDomain = (): { min: number; max: number } => {\n    const opts = chart.options;\n    \n    // Get base domain\n    let xMin = opts.xAxis?.min;\n    let xMax = opts.xAxis?.max;\n\n    // If not explicitly set, derive from series data\n    if (xMin === undefined || xMax === undefined) {\n      const series = opts.series ?? [];\n      let dataXMin = Number.POSITIVE_INFINITY;\n      let dataXMax = Number.NEGATIVE_INFINITY;\n\n      for (const s of series) {\n        if (s.type === 'pie') continue;\n\n        if (s.type === 'candlestick') {\n          // Candlestick uses timestamp (first element)\n          const data = s.data;\n          for (const p of data) {\n            const timestamp = getOHLCTimestamp(p);\n            if (timestamp < dataXMin) dataXMin = timestamp;\n            if (timestamp > dataXMax) dataXMax = timestamp;\n          }\n        } else {\n          // Cartesian series\n          // TODO(step 2): normalize CartesianSeriesData to ReadonlyArray<DataPoint>\n          const data = s.data as ReadonlyArray<DataPoint>;\n          for (const p of data) {\n            const x = getPointX(p);\n            if (x < dataXMin) dataXMin = x;\n            if (x > dataXMax) dataXMax = x;\n          }\n        }\n      }\n\n      if (xMin === undefined) xMin = Number.isFinite(dataXMin) ? dataXMin : 0;\n      if (xMax === undefined) xMax = Number.isFinite(dataXMax) ? dataXMax : 100;\n    }\n\n    // Apply zoom if present\n    const zoomRange = chart.getZoomRange();\n    if (zoomRange) {\n      const span = xMax - xMin;\n      const zoomMin = xMin + (zoomRange.start / 100) * span;\n      const zoomMax = xMin + (zoomRange.end / 100) * span;\n      return { min: zoomMin, max: zoomMax };\n    }\n\n    return { min: xMin, max: xMax };\n  };\n\n  // Compute visible y-domain for horizontal lines\n  const computeVisibleYDomain = (): { min: number; max: number } => {\n    const opts = chart.options;\n\n    // Get base domain\n    let yMin = opts.yAxis?.min;\n    let yMax = opts.yAxis?.max;\n\n    // If not explicitly set, derive from series data\n    if (yMin === undefined || yMax === undefined) {\n      const series = opts.series ?? [];\n      let dataYMin = Number.POSITIVE_INFINITY;\n      let dataYMax = Number.NEGATIVE_INFINITY;\n\n      for (const s of series) {\n        if (s.type === 'pie') continue;\n\n        if (s.type === 'candlestick') {\n          // Candlestick uses low/high\n          const data = s.data;\n          for (const p of data) {\n            const low = isTupleOHLCDataPoint(p) ? p[3] : p.low;\n            const high = isTupleOHLCDataPoint(p) ? p[4] : p.high;\n            if (low < dataYMin) dataYMin = low;\n            if (high > dataYMax) dataYMax = high;\n          }\n        } else {\n          // Cartesian series\n          // TODO(step 2): normalize CartesianSeriesData to ReadonlyArray<DataPoint>\n          const data = s.data as ReadonlyArray<DataPoint>;\n          for (const p of data) {\n            const y = getPointY(p);\n            if (y < dataYMin) dataYMin = y;\n            if (y > dataYMax) dataYMax = y;\n          }\n        }\n      }\n\n      if (yMin === undefined) yMin = Number.isFinite(dataYMin) ? dataYMin : 0;\n      if (yMax === undefined) yMax = Number.isFinite(dataYMax) ? dataYMax : 100;\n    }\n\n    return { min: yMin, max: yMax };\n  };\n\n  // Convert grid-space coordinates to data-space x\n  const gridXToDataX = (gridX: number): number => {\n    const rect = canvas.getBoundingClientRect();\n    const grid = chart.options.grid ?? defaultGrid;\n    const plotWidthCss = rect.width - (grid.left ?? defaultGrid.left) - (grid.right ?? defaultGrid.right);\n    \n    const xDomain = computeVisibleXDomain();\n    const t = plotWidthCss > 0 ? gridX / plotWidthCss : 0;\n    return xDomain.min + t * (xDomain.max - xDomain.min);\n  };\n\n  // Convert grid-space coordinates to plot-space [0-1]\n  const gridToPlotSpace = (gridX: number, gridY: number): { x: number; y: number } => {\n    const rect = canvas.getBoundingClientRect();\n    const grid = chart.options.grid ?? defaultGrid;\n    const plotWidthCss = rect.width - (grid.left ?? defaultGrid.left) - (grid.right ?? defaultGrid.right);\n    const plotHeightCss = rect.height - (grid.top ?? defaultGrid.top) - (grid.bottom ?? defaultGrid.bottom);\n    \n    const px = plotWidthCss > 0 ? gridX / plotWidthCss : 0;\n    const py = plotHeightCss > 0 ? gridY / plotHeightCss : 0;\n    return { x: px, y: py };\n  };\n\n  // Handle \"Add vertical line here\"\n  const handleAddVerticalLine = (): void => {\n    if (!lastHitTestResult) return;\n\n    const { match, isInGrid, gridX } = lastHitTestResult;\n\n    let x: number;\n    if (match) {\n      // Use matched data point x\n      x = match.value[0];\n    } else if (isInGrid) {\n      // Compute x from grid position\n      x = gridXToDataX(gridX);\n    } else {\n      return; // Outside grid, do nothing\n    }\n\n    // Show configuration dialog\n    configDialog.showCreate(\n      'lineX',\n      {\n        type: 'lineX',\n        x,\n        layer: 'aboveSeries',\n        style: {\n          color: '#ffa500',\n          lineWidth: 2,\n        },\n      },\n      (config) => {\n        const current = getCurrentAnnotations();\n        const next = [...current, config as AnnotationConfig];\n        applyAnnotations(next);\n        pushHistory(next);\n      },\n      () => {\n        // Cancelled - do nothing\n      }\n    );\n  };\n\n  // Handle \"Add horizontal line here\"\n  const handleAddHorizontalLine = (): void => {\n    if (!lastHitTestResult) return;\n\n    const { match, isInGrid, gridY } = lastHitTestResult;\n\n    let y: number;\n    if (match) {\n      // Use matched data point y\n      y = match.value[1];\n    } else if (isInGrid) {\n      // Compute y from grid position using actual visible Y domain\n      const rect = canvas.getBoundingClientRect();\n      const grid = chart.options.grid ?? defaultGrid;\n      const plotHeightCss = rect.height - (grid.top ?? defaultGrid.top) - (grid.bottom ?? defaultGrid.bottom);\n\n      // Get actual visible Y domain (not hardcoded defaults!)\n      const yDomain = computeVisibleYDomain();\n\n      // Invert Y (canvas top = max Y value)\n      const t = plotHeightCss > 0 ? 1 - gridY / plotHeightCss : 0.5;\n      y = yDomain.min + t * (yDomain.max - yDomain.min);\n    } else {\n      return; // Outside grid, do nothing\n    }\n\n    // Show configuration dialog\n    configDialog.showCreate(\n      'lineY',\n      {\n        type: 'lineY',\n        y,\n        layer: 'aboveSeries',\n        style: {\n          color: '#ffa500',\n          lineWidth: 2,\n        },\n      },\n      (config) => {\n        const current = getCurrentAnnotations();\n        const next = [...current, config as AnnotationConfig];\n        applyAnnotations(next);\n        pushHistory(next);\n      },\n      () => {\n        // Cancelled - do nothing\n      }\n    );\n  };\n\n  // Handle \"Add text note here\"\n  const handleAddTextNote = (): void => {\n    if (!lastHitTestResult) return;\n\n    const { match, isInGrid, gridX, gridY } = lastHitTestResult;\n\n    let space: 'data' | 'plot';\n    let x: number;\n    let y: number;\n\n    if (match) {\n      // Use data-space position\n      space = 'data';\n      x = match.value[0];\n      y = match.value[1];\n    } else if (isInGrid) {\n      // Use plot-space position\n      const plotPos = gridToPlotSpace(gridX, gridY);\n      space = 'plot';\n      x = plotPos.x;\n      y = plotPos.y;\n    } else {\n      return; // Outside grid, do nothing\n    }\n\n    // Show configuration dialog\n    configDialog.showCreate(\n      'text',\n      {\n        type: 'text',\n        position: { space, x, y },\n        text: 'Note',\n        layer: 'aboveSeries',\n        style: {\n          color: '#00d4ff',\n        },\n      },\n      (config) => {\n        const current = getCurrentAnnotations();\n        const next = [...current, config as AnnotationConfig];\n        applyAnnotations(next);\n        pushHistory(next);\n      },\n      () => {\n        // Cancelled - do nothing\n      }\n    );\n  };\n\n  // Handle \"Edit annotation...\"\n  const handleEditAnnotation = (index: number, annotation: AnnotationConfig): void => {\n    configDialog.showEdit(\n      annotation,\n      (updates) => {\n        const current = getCurrentAnnotations();\n        const next = current.map((a, i) => (i === index ? { ...a, ...updates } as AnnotationConfig : a));\n        applyAnnotations(next);\n        pushHistory(next);\n      },\n      () => {\n        // Cancelled - do nothing\n      }\n    );\n  };\n\n  // Handle \"Delete annotation\"\n  const handleDeleteAnnotation = (index: number): void => {\n    const current = getCurrentAnnotations();\n    const next = current.filter((_, i) => i !== index);\n    applyAnnotations(next);\n    pushHistory(next);\n  };\n\n  // Pointer down event handler for drag\n  const onPointerDown = (e: PointerEvent): void => {\n    if (disposed || e.button === 2) return; // Ignore right-click\n\n    const rect = canvas.getBoundingClientRect();\n    const canvasX = e.clientX - rect.left;\n    const canvasY = e.clientY - rect.top;\n\n    const annotationHit = hitTester.hitTest(canvasX, canvasY);\n\n    if (annotationHit) {\n      e.preventDefault();\n      // Don't set pointer capture here - let drag handler manage window-level events\n\n      dragHandler.startDrag(\n        annotationHit.annotationIndex,\n        annotationHit.annotation,\n        e.clientX,\n        e.clientY\n      );\n    }\n  };\n\n  // Context menu event handler\n  const onContextMenu = (e: MouseEvent): void => {\n    if (disposed || !enableContextMenu) return;\n    e.preventDefault();\n    e.stopPropagation();\n    showContextMenu(e);\n  };\n\n  // Click outside to close context menu\n  const onDocumentClick = (e: MouseEvent): void => {\n    if (disposed) return;\n    if (contextMenu && !contextMenu.contains(e.target as Node)) {\n      hideContextMenu();\n    }\n  };\n\n  // Escape to close context menu\n  const onDocumentKeyDown = (e: KeyboardEvent): void => {\n    if (disposed) return;\n    if (e.key === 'Escape' && contextMenu && contextMenu.style.display === 'block') {\n      hideContextMenu();\n    }\n  };\n\n  // Scroll/resize to close context menu (prevents menu from floating at wrong position)\n  const onWindowScrollOrResize = (): void => {\n    if (disposed) return;\n    if (contextMenu && contextMenu.style.display === 'block') {\n      hideContextMenu();\n    }\n  };\n\n  // Public API\n  const addVerticalLine = (x: number): void => {\n    const current = getCurrentAnnotations();\n    const newAnnotation: AnnotationConfig = {\n      type: 'lineX',\n      x,\n      layer: 'aboveSeries',\n      style: {\n        color: '#ffa500',\n        lineWidth: 2,\n        opacity: 0.9,\n      },\n    };\n    const next = [...current, newAnnotation];\n    applyAnnotations(next);\n    pushHistory(next);\n  };\n\n  const addTextNote = (x: number, y: number, text: string, space: 'data' | 'plot' = 'data'): void => {\n    const current = getCurrentAnnotations();\n    const newAnnotation: AnnotationConfig = {\n      type: 'text',\n      position: { space, x, y },\n      text,\n      layer: 'aboveSeries',\n      style: {\n        color: '#00d4ff',\n        opacity: 1,\n      },\n    };\n    const next = [...current, newAnnotation];\n    applyAnnotations(next);\n    pushHistory(next);\n  };\n\n  const undo = (): boolean => {\n    if (historyIndex <= 0) return false;\n    historyIndex--;\n    const entry = history[historyIndex];\n    if (!entry) return false;\n    applyAnnotations(entry.annotations);\n    return true;\n  };\n\n  const redo = (): boolean => {\n    if (historyIndex >= history.length - 1) return false;\n    historyIndex++;\n    const entry = history[historyIndex];\n    if (!entry) return false;\n    applyAnnotations(entry.annotations);\n    return true;\n  };\n\n  const exportJSON = (): string => {\n    const annotations = getCurrentAnnotations();\n    return JSON.stringify(annotations, null, 2);\n  };\n\n  const getAnnotations = (): readonly AnnotationConfig[] => {\n    return getCurrentAnnotations();\n  };\n\n  const dispose = (): void => {\n    if (disposed) return;\n    disposed = true;\n\n    canvas.removeEventListener('pointerdown', onPointerDown);\n    canvas.removeEventListener('contextmenu', onContextMenu);\n    document.removeEventListener('click', onDocumentClick);\n    document.removeEventListener('keydown', onDocumentKeyDown);\n    window.removeEventListener('scroll', onWindowScrollOrResize, true);\n    window.removeEventListener('resize', onWindowScrollOrResize);\n\n    contextMenu?.remove();\n    contextMenu = null;\n\n    hitTester.dispose();\n    dragHandler.dispose();\n    configDialog.dispose();\n\n    history = [];\n  };\n\n  // Initialize\n  if (enableContextMenu) {\n    contextMenu = createContextMenu();\n    canvas.addEventListener('contextmenu', onContextMenu);\n    document.addEventListener('click', onDocumentClick);\n    document.addEventListener('keydown', onDocumentKeyDown);\n    // Capture phase for scroll to handle all scrollable ancestors\n    window.addEventListener('scroll', onWindowScrollOrResize, true);\n    window.addEventListener('resize', onWindowScrollOrResize);\n  }\n\n  // Attach pointer event for dragging (always enabled)\n  canvas.addEventListener('pointerdown', onPointerDown);\n\n  return {\n    addVerticalLine,\n    addTextNote,\n    undo,\n    redo,\n    exportJSON,\n    getAnnotations,\n    dispose,\n  };\n}\n","/**\n * RenderScheduler - 60fps render loop management\n * \n * Manages a requestAnimationFrame-based render loop that runs at 60fps,\n * providing delta time tracking and frame scheduling control.\n * \n * This module provides both functional and class-based APIs for maximum flexibility.\n * The functional API is preferred for better type safety and immutability.\n */\n\n/**\n * Callback function type for render frames.\n * Receives delta time in milliseconds since the last frame.\n */\nexport type RenderCallback = (deltaTime: number) => void;\n\nimport type { ExactFPS, Milliseconds, FrameTimeStats, FrameDropStats } from '../config/types';\n\n/**\n * Represents the state of a render scheduler.\n * All properties are readonly to ensure immutability.\n */\nexport interface RenderSchedulerState {\n  readonly id: symbol;\n  readonly running: boolean;\n}\n\n/**\n * Circular buffer for frame timestamps (120 frames = 2 seconds at 60fps).\n * Uses Float64Array for high-precision timestamps from performance.now().\n */\nconst FRAME_BUFFER_SIZE = 120;\n\n/**\n * Expected frame time at 60fps (16.67ms).\n * Used for frame drop detection.\n */\nconst EXPECTED_FRAME_TIME_MS = 1000 / 60;\n\n/**\n * Frame drop threshold multiplier (1.5x expected frame time).\n * Frame times exceeding this are counted as drops.\n */\nconst FRAME_DROP_THRESHOLD_MULTIPLIER = 1.5;\n\n/**\n * Internal mutable state for the render scheduler.\n * Stored separately from the public state interface.\n */\ninterface RenderSchedulerInternalState {\n  rafId: number | null;\n  callback: RenderCallback | null;\n  lastFrameTime: number;\n  dirty: boolean;\n  frameHandler: ((time: number) => void) | null;\n  \n  // Performance tracking\n  frameTimestamps: Float64Array;\n  frameTimestampIndex: number;\n  frameTimestampCount: number;\n  totalFrames: number;\n  totalDroppedFrames: number;\n  consecutiveDroppedFrames: number;\n  lastDropTimestamp: number;\n  startTime: number;\n}\n\n/**\n * Map to store internal mutable state for each scheduler state instance.\n * Keyed by the state's unique ID symbol.\n */\nconst internalStateMap = new Map<symbol, RenderSchedulerInternalState>();\n\n/**\n * Creates a new RenderScheduler state with initial values.\n * \n * @returns A new RenderSchedulerState instance\n */\nexport function createRenderScheduler(): RenderSchedulerState {\n  const id = Symbol('RenderScheduler');\n  const state: RenderSchedulerState = {\n    id,\n    running: false,\n  };\n\n  // Initialize internal mutable state\n  internalStateMap.set(id, {\n    rafId: null,\n    callback: null,\n    lastFrameTime: 0,\n    dirty: false,\n    frameHandler: null,\n    \n    // Performance tracking\n    frameTimestamps: new Float64Array(FRAME_BUFFER_SIZE),\n    frameTimestampIndex: 0,\n    frameTimestampCount: 0,\n    totalFrames: 0,\n    totalDroppedFrames: 0,\n    consecutiveDroppedFrames: 0,\n    lastDropTimestamp: 0,\n    startTime: performance.now(),\n  });\n\n  return state;\n}\n\n/**\n * Starts the render loop.\n * \n * Begins a requestAnimationFrame loop that calls the provided callback\n * every frame with the delta time in milliseconds since the last frame.\n * Returns a new state object with running set to true.\n * \n * @param state - The scheduler state to start\n * @param callback - Function to call each frame with delta time\n * @returns A new RenderSchedulerState with running set to true\n * @throws {Error} If callback is not provided\n * @throws {Error} If scheduler is already running\n * @throws {Error} If state is invalid\n */\nexport function startRenderScheduler(\n  state: RenderSchedulerState,\n  callback: RenderCallback\n): RenderSchedulerState {\n  if (!callback) {\n    throw new Error('Render callback is required');\n  }\n\n  const internalState = internalStateMap.get(state.id);\n  if (!internalState) {\n    throw new Error('Invalid scheduler state. Use createRenderScheduler() to create a new state.');\n  }\n\n  if (state.running) {\n    throw new Error('RenderScheduler is already running. Call stopRenderScheduler() before starting again.');\n  }\n\n  // Update internal state\n  internalState.callback = callback;\n  internalState.lastFrameTime = performance.now();\n  internalState.dirty = true;\n\n  const schedulerId = state.id;\n  const frameHandler = (currentTime: number) => {\n    // Look up internal state - may be null if scheduler was destroyed\n    const currentInternalState = internalStateMap.get(schedulerId);\n    if (!currentInternalState || !currentInternalState.callback) {\n      // Scheduler was stopped or destroyed, exit gracefully\n      return;\n    }\n\n    // Clear rafId at the start - we are no longer scheduled (now idle)\n    currentInternalState.rafId = null;\n\n    // Record frame timestamp in circular buffer BEFORE rendering\n    // Use performance.now() exclusively for exact FPS measurement\n    const timestamp = performance.now();\n    currentInternalState.frameTimestamps[currentInternalState.frameTimestampIndex] = timestamp;\n    currentInternalState.frameTimestampIndex = (currentInternalState.frameTimestampIndex + 1) % FRAME_BUFFER_SIZE;\n    if (currentInternalState.frameTimestampCount < FRAME_BUFFER_SIZE) {\n      currentInternalState.frameTimestampCount++;\n    }\n    currentInternalState.totalFrames++;\n\n    // Calculate deltaTime with capping to prevent animation jumps after idle\n    let deltaTime = currentTime - currentInternalState.lastFrameTime;\n    // Cap deltaTime to 100ms (1/10th second) to prevent huge jumps\n    const MAX_DELTA_TIME = 100;\n    if (deltaTime > MAX_DELTA_TIME) {\n      deltaTime = MAX_DELTA_TIME;\n    }\n\n    // Frame drop detection (only after first frame)\n    if (currentInternalState.lastFrameTime > 0 && deltaTime > EXPECTED_FRAME_TIME_MS * FRAME_DROP_THRESHOLD_MULTIPLIER) {\n      currentInternalState.totalDroppedFrames++;\n      currentInternalState.consecutiveDroppedFrames++;\n      currentInternalState.lastDropTimestamp = timestamp;\n    } else if (currentInternalState.lastFrameTime > 0) {\n      // Reset consecutive counter on successful frame\n      currentInternalState.consecutiveDroppedFrames = 0;\n    }\n\n    currentInternalState.lastFrameTime = currentTime;\n\n    // Only render if dirty\n    if (currentInternalState.dirty) {\n      // Reset dirty flag BEFORE calling callback\n      currentInternalState.dirty = false;\n\n      // Call the render callback with delta time\n      currentInternalState.callback(deltaTime);\n\n      // After callback returns, check if dirty was set again (callback-triggered renders for animations)\n      // Re-check internal state in case it was destroyed during callback execution\n      const nextInternalState = internalStateMap.get(schedulerId);\n      if (nextInternalState && nextInternalState.callback && nextInternalState.dirty) {\n        // Schedule another frame since callback requested a render\n        nextInternalState.rafId = requestAnimationFrame(frameHandler);\n      }\n    }\n    // If not dirty, we remain idle (rafId stays null, no frame scheduled)\n  };\n\n  // Store frameHandler in internal state so requestRender() can access it\n  internalState.frameHandler = frameHandler;\n\n  // Start the first frame\n  internalState.rafId = requestAnimationFrame(frameHandler);\n\n  // Return new state with running set to true\n  return {\n    id: state.id,\n    running: true,\n  };\n}\n\n/**\n * Stops the render loop.\n * \n * Cancels any pending requestAnimationFrame calls and stops the loop.\n * Returns a new state object with running set to false.\n * The scheduler can be restarted by calling startRenderScheduler() again.\n * \n * @param state - The scheduler state to stop\n * @returns A new RenderSchedulerState with running set to false\n * @throws {Error} If state is invalid\n */\nexport function stopRenderScheduler(state: RenderSchedulerState): RenderSchedulerState {\n  const internalState = internalStateMap.get(state.id);\n  if (!internalState) {\n    throw new Error('Invalid scheduler state. Use createRenderScheduler() to create a new state.');\n  }\n\n  internalState.callback = null;\n  internalState.frameHandler = null;\n\n  if (internalState.rafId !== null) {\n    cancelAnimationFrame(internalState.rafId);\n    internalState.rafId = null;\n  }\n\n  // Return new state with running set to false\n  return {\n    id: state.id,\n    running: false,\n  };\n}\n\n/**\n * Marks the current frame as dirty and schedules a render if idle.\n * \n * This function implements render-on-demand: it schedules a frame when the\n * scheduler is idle. Multiple calls coalesce into a single frame.\n * \n * @param state - The scheduler state\n * @throws {Error} If state is invalid\n */\nexport function requestRender(state: RenderSchedulerState): void {\n  const internalState = internalStateMap.get(state.id);\n  if (!internalState) {\n    throw new Error('Invalid scheduler state. Use createRenderScheduler() to create a new state.');\n  }\n\n  // Mark as dirty\n  internalState.dirty = true;\n\n  // If not running, return early\n  if (internalState.callback === null) {\n    return;\n  }\n\n  // If already scheduled, return early (coalescing)\n  if (internalState.rafId !== null) {\n    return;\n  }\n\n  // Idle - schedule a frame\n  // Reset lastFrameTime to current time to ensure reasonable deltaTime after idle\n  internalState.lastFrameTime = performance.now();\n  \n  // Schedule RAF using the stored frameHandler\n  if (internalState.frameHandler) {\n    internalState.rafId = requestAnimationFrame(internalState.frameHandler);\n  }\n}\n\n/**\n * Calculates exact FPS from frame timestamp deltas.\n * \n * Uses the circular buffer of performance.now() timestamps to calculate\n * frame-perfect FPS. Algorithm:\n * 1. Sum all frame time deltas in the buffer\n * 2. Divide by (count - 1) to get average frame time\n * 3. Convert to FPS: 1000ms / avg_frame_time\n * \n * Returns 0 if insufficient data (< 2 frames).\n * \n * @param state - The scheduler state\n * @returns Exact FPS measurement\n */\nexport function getCurrentFPS(state: RenderSchedulerState): ExactFPS {\n  const internalState = internalStateMap.get(state.id);\n  if (!internalState) {\n    return 0 as ExactFPS;\n  }\n\n  const count = internalState.frameTimestampCount;\n  if (count < 2) {\n    return 0 as ExactFPS; // Need at least 2 frames to calculate FPS\n  }\n\n  // Calculate sum of deltas between consecutive timestamps\n  const timestamps = internalState.frameTimestamps;\n  const bufferSize = FRAME_BUFFER_SIZE;\n  const startIndex = (internalState.frameTimestampIndex - count + bufferSize) % bufferSize;\n  \n  let totalDelta = 0;\n  for (let i = 1; i < count; i++) {\n    const prevIndex = (startIndex + i - 1) % bufferSize;\n    const currIndex = (startIndex + i) % bufferSize;\n    const delta = timestamps[currIndex] - timestamps[prevIndex];\n    totalDelta += delta;\n  }\n\n  const avgFrameTime = totalDelta / (count - 1);\n  const fps = avgFrameTime > 0 ? 1000 / avgFrameTime : 0;\n  \n  return fps as ExactFPS;\n}\n\n/**\n * Calculates frame time statistics from the circular buffer.\n * \n * Computes min, max, avg, and percentiles (p50, p95, p99) for frame times.\n * Returns zero stats if insufficient data.\n * \n * @param state - The scheduler state\n * @returns Frame time statistics\n */\nexport function getFrameStats(state: RenderSchedulerState): FrameTimeStats {\n  const internalState = internalStateMap.get(state.id);\n  if (!internalState) {\n    return {\n      min: 0 as Milliseconds,\n      max: 0 as Milliseconds,\n      avg: 0 as Milliseconds,\n      p50: 0 as Milliseconds,\n      p95: 0 as Milliseconds,\n      p99: 0 as Milliseconds,\n    };\n  }\n\n  const count = internalState.frameTimestampCount;\n  if (count < 2) {\n    return {\n      min: 0 as Milliseconds,\n      max: 0 as Milliseconds,\n      avg: 0 as Milliseconds,\n      p50: 0 as Milliseconds,\n      p95: 0 as Milliseconds,\n      p99: 0 as Milliseconds,\n    };\n  }\n\n  // Extract deltas from circular buffer\n  const timestamps = internalState.frameTimestamps;\n  const bufferSize = FRAME_BUFFER_SIZE;\n  const startIndex = (internalState.frameTimestampIndex - count + bufferSize) % bufferSize;\n  \n  const deltas = new Array<number>(count - 1);\n  let min = Number.POSITIVE_INFINITY;\n  let max = Number.NEGATIVE_INFINITY;\n  let sum = 0;\n  \n  for (let i = 1; i < count; i++) {\n    const prevIndex = (startIndex + i - 1) % bufferSize;\n    const currIndex = (startIndex + i) % bufferSize;\n    const delta = timestamps[currIndex] - timestamps[prevIndex];\n    deltas[i - 1] = delta;\n    \n    if (delta < min) min = delta;\n    if (delta > max) max = delta;\n    sum += delta;\n  }\n\n  const avg = sum / deltas.length;\n\n  // Sort for percentile calculations\n  deltas.sort((a, b) => a - b);\n\n  const p50Index = Math.floor(deltas.length * 0.50);\n  const p95Index = Math.floor(deltas.length * 0.95);\n  const p99Index = Math.floor(deltas.length * 0.99);\n\n  return {\n    min: min as Milliseconds,\n    max: max as Milliseconds,\n    avg: avg as Milliseconds,\n    p50: deltas[p50Index] as Milliseconds,\n    p95: deltas[p95Index] as Milliseconds,\n    p99: deltas[p99Index] as Milliseconds,\n  };\n}\n\n/**\n * Gets frame drop statistics for the scheduler.\n * \n * @param state - The scheduler state\n * @returns Frame drop statistics\n */\nexport function getFrameDropStats(state: RenderSchedulerState): FrameDropStats {\n  const internalState = internalStateMap.get(state.id);\n  if (!internalState) {\n    return {\n      totalDrops: 0,\n      consecutiveDrops: 0,\n      lastDropTimestamp: 0 as Milliseconds,\n    };\n  }\n\n  return {\n    totalDrops: internalState.totalDroppedFrames,\n    consecutiveDrops: internalState.consecutiveDroppedFrames,\n    lastDropTimestamp: internalState.lastDropTimestamp as Milliseconds,\n  };\n}\n\n/**\n * Gets total frames rendered and elapsed time.\n * \n * @param state - The scheduler state\n * @returns Object with totalFrames and elapsedTime\n */\nexport function getTotalFrames(state: RenderSchedulerState): { totalFrames: number; elapsedTime: Milliseconds } {\n  const internalState = internalStateMap.get(state.id);\n  if (!internalState) {\n    return { totalFrames: 0, elapsedTime: 0 as Milliseconds };\n  }\n\n  const elapsedTime = performance.now() - internalState.startTime;\n  return {\n    totalFrames: internalState.totalFrames,\n    elapsedTime: elapsedTime as Milliseconds,\n  };\n}\n\n/**\n * Destroys the render scheduler and cleans up resources.\n * Stops the loop if running and removes internal state from the map.\n * Returns a new state object with reset values.\n * After calling this, the scheduler must be recreated before use.\n * \n * **Important:** Always call this function when done with a scheduler to prevent memory leaks.\n * The internal state map will retain entries until explicitly destroyed.\n * \n * @param state - The scheduler state to destroy\n * @returns A new RenderSchedulerState with reset values\n */\nexport function destroyRenderScheduler(state: RenderSchedulerState): RenderSchedulerState {\n  const internalState = internalStateMap.get(state.id);\n  \n  if (internalState) {\n    // Stop the loop if running\n    if (internalState.rafId !== null) {\n      cancelAnimationFrame(internalState.rafId);\n      internalState.rafId = null;\n    }\n    \n    // Clear callback and frameHandler to prevent further execution\n    internalState.callback = null;\n    internalState.frameHandler = null;\n    \n    // Clean up internal state from map to prevent memory leak\n    internalStateMap.delete(state.id);\n  }\n\n  // Return new state with reset values\n  return createRenderScheduler();\n}\n\n/**\n * Convenience function that creates a scheduler and starts it in one step.\n * \n * @param callback - Function to call each frame with delta time\n * @returns A RenderSchedulerState with the loop running\n * @throws {Error} If callback is not provided\n * \n * @example\n * ```typescript\n * const scheduler = createRenderSchedulerAsync((deltaTime) => {\n *   renderFrame(deltaTime);\n * });\n * ```\n */\nexport function createRenderSchedulerAsync(callback: RenderCallback): RenderSchedulerState {\n  const state = createRenderScheduler();\n  return startRenderScheduler(state, callback);\n}\n\n/**\n * RenderScheduler class wrapper for backward compatibility.\n * \n * This class provides a class-based API that internally uses the functional implementation.\n * Use the functional API directly for better type safety and immutability.\n */\nexport class RenderScheduler {\n  private _state: RenderSchedulerState;\n\n  /**\n   * Checks if the scheduler is currently running.\n   */\n  get running(): boolean {\n    return this._state.running;\n  }\n\n  /**\n   * Creates a new RenderScheduler instance.\n   */\n  constructor() {\n    this._state = createRenderScheduler();\n  }\n\n  /**\n   * Starts the render loop.\n   * \n   * @param callback - Function to call each frame with delta time\n   * @throws {Error} If callback is not provided or scheduler already running\n   */\n  start(callback: RenderCallback): void {\n    this._state = startRenderScheduler(this._state, callback);\n  }\n\n  /**\n   * Stops the render loop.\n   */\n  stop(): void {\n    this._state = stopRenderScheduler(this._state);\n  }\n\n  /**\n   * Marks the current frame as dirty, indicating it needs to be rendered.\n   */\n  requestRender(): void {\n    requestRender(this._state);\n  }\n\n  /**\n   * Destroys the render scheduler and cleans up resources.\n   * After calling destroy(), the scheduler must be recreated before use.\n   */\n  destroy(): void {\n    this._state = destroyRenderScheduler(this._state);\n  }\n}\n","/**\n * ChartGPU - A GPU-accelerated charting library built with WebGPU\n */\n\nexport const version = '1.0.0';\n\n// Chart API (Phase 1)\nimport { ChartGPU as ChartGPUNamespace } from './ChartGPU';\n\n// Export ChartGPU namespace\nexport const ChartGPU = ChartGPUNamespace;\n\nexport { createChartGPU as createChart } from './ChartGPU';\nexport type { ChartGPUInstance } from './ChartGPU';\nexport type {\n  ChartGPUEventName,\n  ChartGPUEventPayload,\n  ChartGPUCrosshairMovePayload,\n  ChartGPUEventCallback,\n  ChartGPUCrosshairMoveCallback,\n  ChartGPUHitTestMatch,\n  ChartGPUHitTestResult,\n} from './ChartGPU';\nexport type {\n  AnnotationConfig,\n  AnnotationConfigBase,\n  AnnotationLabel,\n  AnnotationLabelAnchor,\n  AnnotationLabelBackground,\n  AnnotationLabelPadding,\n  AnnotationLayer,\n  AnnotationLineX,\n  AnnotationLineY,\n  AnnotationPoint,\n  AnnotationPointMarker,\n  AnnotationPosition,\n  AnnotationStyle,\n  AnnotationText,\n  AreaStyleConfig,\n  AnimationConfig,\n  AxisConfig,\n  AxisType,\n  BarItemStyleConfig,\n  CandlestickItemStyleConfig,\n  CandlestickSeriesConfig,\n  CandlestickStyle,\n  ChartGPUOptions,\n  DataZoomConfig,\n  DataPoint,\n  GridConfig,\n  LegendConfig,\n  LegendPosition,\n  LineStyleConfig,\n  AreaSeriesConfig,\n  LineSeriesConfig,\n  BarSeriesConfig,\n  PerformanceMetrics,\n  OHLCDataPoint,\n  PieCenter,\n  PieDataItem,\n  PieItemStyleConfig,\n  PieRadius,\n  PieSeriesConfig,\n  ScatterSeriesConfig,\n  ScatterSymbol,\n  ScatterPointTuple,\n  SeriesConfig,\n  SeriesSampling,\n  SeriesType,\n  TooltipConfig,\n  TooltipParams,\n} from './config/types';\n\n// Options defaults + resolution\nexport { candlestickDefaults, defaultOptions } from './config/defaults';\nexport { OptionResolver, resolveOptions } from './config/OptionResolver';\nexport type {\n  ResolvedCandlestickSeriesConfig,\n  ResolvedChartGPUOptions,\n  ResolvedAreaSeriesConfig,\n  ResolvedAreaStyleConfig,\n  ResolvedGridConfig,\n  ResolvedLineSeriesConfig,\n  ResolvedLineStyleConfig,\n  ResolvedPieDataItem,\n  ResolvedPieSeriesConfig,\n  ResolvedSeriesConfig,\n} from './config/OptionResolver';\n\n// Themes\nexport type { ThemeConfig } from './themes/types';\nexport { darkTheme, lightTheme, getTheme } from './themes';\nexport type { ThemeName } from './themes';\n\n// Scales - Pure utilities\nexport { createLinearScale, createCategoryScale } from './utils/scales';\nexport type { LinearScale, CategoryScale } from './utils/scales';\n\n// Chart sync (interaction)\nexport { connectCharts } from './interaction/createChartSync';\n\n// Annotation authoring (interaction)\nexport { createAnnotationAuthoring } from './interaction/createAnnotationAuthoring';\nexport type { AnnotationAuthoringInstance, AnnotationAuthoringOptions } from './interaction/createAnnotationAuthoring';\n\n// Core exports - Functional API (preferred)\nexport type {\n  GPUContextState,\n  GPUContextOptions,\n  SupportedCanvas,\n} from './core/GPUContext';\nexport {\n  createGPUContext,\n  createGPUContextAsync,\n  initializeGPUContext,\n  getCanvasTexture,\n  clearScreen,\n  destroyGPUContext,\n} from './core/GPUContext';\n\n// Class-based API (for backward compatibility)\nexport { GPUContext } from './core/GPUContext';\n\n// Render scheduler - Functional API (preferred)\nexport type { RenderSchedulerState, RenderCallback } from './core/RenderScheduler';\nexport {\n  createRenderScheduler,\n  createRenderSchedulerAsync,\n  startRenderScheduler,\n  stopRenderScheduler,\n  requestRender,\n  destroyRenderScheduler,\n} from './core/RenderScheduler';\n\n// Class-based API (for backward compatibility)\nexport { RenderScheduler } from './core/RenderScheduler';\n"],"names":["isHTMLCanvasElement","canvas","getCanvasDimensions","width","height","createGPUContext","options","dprRaw","dpr","alphaMode","powerPreference","initializeGPUContext","context","sanitizedDevicePixelRatio","device","adapter","event","canvasContext","preferredFormat","webgpuContext","error","targetWidth","targetHeight","maxDim","finalWidth","finalHeight","_b","_a","destroyError","getCanvasTexture","clearScreen","r","g","b","a","texture","encoder","destroyGPUContext","createGPUContextAsync","GPUContext","isTupleDataPoint","point","packDataPoints","points","MAX_POINTS","buffer","f32","i","x","y","MIN_BUFFER_BYTES","roundUpToMultipleOf4","bytes","nextPow2","n","computeGrownCapacityBytes","currentCapacityBytes","requiredBytes","required","grown","fnv1aUpdate","hash","words","h","hashFloat32ArrayBits","data","u32","createDataStore","series","disposed","p","packDataPointsWithXOffset","xOffset","assertNotDisposed","getSeriesEntry","index","entry","packed","pointCount","hash32","targetBytes","existing","capacityBytes","maxBufferSize","grownCapacityBytes","newPoints","prevPointCount","nextPointCount","appendPacked","appendBytes","nextData","fullPacked","byteOffset","appendWords","nextHash32","lttbIndicesForInterleavedXY","targetPoints","lastIndex","indices","bucketSize","out","lastX","lastY","bucket","rangeStart","rangeEndExclusive","nextRangeStart","nextRangeEndExclusive","avgX","avgY","sumX","sumY","avgCount","ax","ay","maxArea","maxIndex","bx","by","area2","absArea2","lttbIndicesForDataPoints","pLast","pa","pb","lttbSample","threshold","idx","isXYArraysData","isInterleavedXYData","getPointCount","getX","getY","getSize","computeRawBoundsFromCartesianData","xMin","xMax","yMin","yMax","count","clampTargetPoints","packToFloat32Array","sampleByBucketsFromCartesian","mode","size","getPointSize","x0","y0","size0","xLast","yLast","sizeLast","chosen","sumSize","sizeCount","bestY","bestIndex","sampleSeriesDataPoints","sampling","samplingThreshold","isTupleOHLCDataPoint","ohlcSample","isTuple","dataAsTuples","firstCandle","lastCandle","timestamp","open","close","high","low","candle","candleLow","candleHigh","dataAsObjects","getCanvasCssWidth","getCanvasCssHeight","clampInt","v","lo","hi","monotonicXCache","monotonicTimestampCache","isMonotonicNonDecreasingFiniteX","cacheKey","cached","prevX","isMonotonicNonDecreasingFiniteTimestamp","prevTimestamp","lowerBoundX","xTarget","mid","upperBoundX","lowerBoundTimestampTuple","timestampTarget","upperBoundTimestampTuple","lowerBoundTimestampObject","upperBoundTimestampObject","sliceCartesianData","start","end","s","e","TypedArrayConstructor","xSliced","ySliced","result","sizeSliced","sliceVisibleRangeByX","findVisibleRangeIndicesByX","sliceVisibleRangeByOHLC","canBinarySearch","clamp01","clamp255","parseHexNibble","hex","parseHexByte","parseHexColorToRgba01","color","c","parseRgbNumberOrPercent","token","parseAlphaNumberOrPercent","parseRgbFuncToRgba01","m","fn","parts","parseCssColorToRgba01","rgb","parseCssColorToGPUColor","fallback","rgba","finiteOrUndefined","assertUnreachable","value","getPointXY","computePlotScissorDevicePx","gridArea","canvasWidth","canvasHeight","devicePixelRatio","plotLeftDevice","plotRightDevice","plotTopDevice","plotBottomDevice","scissorX","scissorY","scissorR","scissorB","scissorW","scissorH","clipXToCanvasCssPx","xClip","canvasCssWidth","clipYToCanvasCssPx","yClip","canvasCssHeight","MS_PER_DAY","MS_PER_MONTH_APPROX","MS_PER_YEAR_APPROX","MONTH_SHORT_EN","parseNumberOrPercent","basis","pct","isPieRadiusTuple","radius","resolvePieRadiiCss","maxRadiusCss","inner","outer","innerCss","outerCss","pad2","formatTimeTickValue","timestampMs","visibleRangeMs","d","yyyy","mm","dd","hh","min","DEFAULT_MAX_TICK_FRACTION_DIGITS","computeMaxFractionDigitsFromStep","tickStep","cap","stepAbs","scaled","rounded","err","tol","createTickFormatter","maximumFractionDigits","formatTickValue","nf","normalized","formatted","getAxisTitleFontSize","baseFontSize","DEFAULT_TICK_LENGTH_CSS_PX","LABEL_PADDING_CSS_PX","DEFAULT_TICK_COUNT","styleAxisLabelSpan","span","isTitle","theme","renderAxisLabels","axisLabelOverlay","overlayContainer","gpuContext","currentOptions","xScale","yScale","xTickValues","plotClipRect","visibleXRangeMs","offsetX","offsetY","plotLeftCss","plotRightCss","plotTopCss","plotBottomCss","xTickLengthCssPx","xLabelY","isTimeXAxis","xFormatter","xDomainMin","xDomainMax","xTickCount","xTickStep","xCss","anchor","label","yTickCount","yTickLengthCssPx","yDomainMin","yDomainMax","yTickStep","yFormatter","yLabelX","ySpans","t","yCss","axisNameFontSize","xAxisName","xCenter","xTickLabelsBottom","bottomLimitCss","z","xTitleY","yAxisName","_c","maxTickLabelWidth","max","yCenter","yTitleX","toCssRgba","opacity01","base","formatNumber","decimals","templateRegex","renderTemplate","template","values","_m","key","mapAnchor","renderAnnotationLabels","annotationOverlay","canvasCssWidthForAnnotations","canvasCssHeightForAnnotations","plotWidthCss","plotHeightCss","annotations","labelCfg","anchorXCss","anchorYCss","dx","dy","text","defaultTemplate","trimmed","fontSize","bg","bgColor","padding","borderRadius","labelData","l","DEFAULT_MAX_DISTANCE_PX","DEFAULT_BAR_GAP","DEFAULT_BAR_CATEGORY_GAP","DEFAULT_SCATTER_RADIUS_CSS_PX","isPointInBar","barBounds","parsePercent","normalizeStackId","stack","getPointSizeCssPx","toScatterTuple","safeCallSymbolSize","getScatterRadiusCssPx","seriesCfg","perPoint","seriesSymbolSize","computeBarClusterSlots","seriesConfigs","stackIdToClusterIndex","clusterIndexBySeries","stackIdBySeries","clusterCount","stackId","computeBarCategoryStep","xs","minStep","computeCategoryWidthPx","categoryStep","p0","p1","w","sx","px","minDx","computeSharedBarLayout","barWidth","barGap","barCategoryGap","computeBarLayoutPx","clusterSlots","categoryWidthPx","layout","categoryInnerWidthPx","denom","maxBarWidthPx","barWidthPx","rawBarWidth","gapPx","clusterWidthPx","computeBaselineForBarsFromData","inferPlotHeightPxForBarHitTesting","maxY","py","computeBaselineDomainAndPx","plotHeightPx","yDomainA","yDomainB","baselineDomain","baselinePx","bucketStackedXKey","xCenterPx","xDomain","findNearestPoint","maxDistance","md","maxDistSq","bestSeriesIndex","bestDataIndex","bestPoint","bestDistSq","barSeriesConfigs","barSeriesIndexByBar","cfg","layoutPx","stackSumsByStackId","bestBarHit","originalSeriesIndex","clusterIndex","yDomain","left","right","baseDomain","topDomain","sumsForX","xKey","sums","basePx","topPx","bounds","seriesData","cartesianSeriesConfigs","cartesianSeriesIndexMap","scatterCfg","startIdx","sy","distSq","allowedSq","allowed","DEFAULT_CROSSHAIR_LINE_WIDTH_CSS_PX","DEFAULT_HIGHLIGHT_SIZE_CSS_PX","prepareOverlays","renderers","hasCartesianSeries","effectivePointer","interactionScales","seriesForRender","withAlpha","crosshairOptions","match","xGridCss","yGridCss","centerCssX","centerCssY","plotScissor","seriesColor","resolveAnnotationRgba","opacity","defaultColor","o","processAnnotations","plotBounds","linesBelow","linesAbove","markersBelow","markersAbove","labels","layer","targetLines","targetMarkers","styleColor","styleOpacity","lineWidth","lineDash","_d","markerSize","_e","markerColor","_g","_f","_h","markerOpacity","_j","_i","_k","fillRgba","_l","_n","shouldRenderArea","prepareSeries","dataStore","appendedGpuThisFrame","gpuSeriesKindByIndex","zoomState","visibleXDomain","introPhase","introProgress01","defaultBaseline","introP","baseline","k","zoomRange","areaLike","rawData","visible","animated","radiiCss","_exhaustive","visibleSeriesForRender","visibleBarSeriesConfigs","encodeScatterDensityCompute","renderSeries","annotationRenderers","prepResult","mainPass","referenceLineBelowCount","markerBelowCount","originalIndex","renderAboveSeriesAnnotations","overlayPass","referenceLineAboveCount","markerAboveCount","firstLine","firstMarker","gridWgsl","DEFAULT_VERTEX_ENTRY","DEFAULT_FRAGMENT_ENTRY","isPowerOfTwo","alignTo","alignment","getStageModule","stage","createShaderModule","code","createRenderPipeline","config","vertexStage","vertexEntryPoint","fragment","fragmentStage","fragmentEntryPoint","targets","formats","format","primitive","multisample","createUniformBuffer","alignedSize","maxSize","writeUniformBuffer","src","DEFAULT_TARGET_FORMAT","DEFAULT_AXIS_RGBA","createIdentityMat4Buffer","isFiniteGridArea","normalizeDomain","minCandidate","maxCandidate","generateAxisVertices","axisConfig","scale","orientation","tickCountOverride","top","bottom","plotLeft","plotRight","plotTop","plotBottom","plotLeftClip","plotRightClip","plotTopClip","plotBottomClip","tickLengthCssPx","tickCountRaw","tickCount","tickLengthDevicePx","tickDeltaClipX","tickDeltaClipY","domainMinRaw","domainMaxRaw","domain","domainMin","domainMax","totalSegments","vertices","y1","x1","createAxisRenderer","targetFormat","bindGroupLayout","vsUniformBuffer","fsUniformBufferLine","fsUniformBufferTick","bindGroupLine","bindGroupTick","pipeline","vertexBuffer","vertexCount","axisLineColor","axisTickColor","requiredSize","bufferSize","axisLineColorString","axisTickColorString","axisLineRgba","axisTickRgba","lineColorBuffer","tickColorBuffer","passEncoder","DEFAULT_HORIZONTAL_LINES","DEFAULT_VERTICAL_LINES","DEFAULT_GRID_COLOR","DEFAULT_GRID_RGBA","generateGridVertices","horizontal","vertical","plotWidth","plotHeight","totalLines","yDevice","xClipLeft","xClipRight","yClipTop","yClipBottom","createGridRenderer","fsUniformBuffer","bindGroup","lineCountOrOptions","isOptionsObject","lineCount","colorString","transformBuffer","colorBuffer","areaWgsl","parseSeriesColorToRgba01","computeDataBounds","computeClipAffineFromScale","v0","v1","writeTransformMat4F32","createAreaVertices","createAreaRenderer","vsUniformScratchBuffer","vsUniformScratchF32","fsUniformScratchF32","writeVsUniforms","seriesConfig","baselineValue","lineWgsl","createLineRenderer","currentVertexBuffer","currentVertexCount","dataBuffer","dataArray","bxAdjusted","barWgsl","INSTANCE_STRIDE_BYTES","INSTANCE_STRIDE_FLOATS","computePlotSizeCssPx","computePlotClipRect","computeCategoryWidthClip","fallbackCategoryCount","clipWidth","createBarRenderer","instanceBuffer","instanceCount","cpuInstanceStagingBuffer","cpuInstanceStagingF32","categoryXScratch","ensureCpuInstanceCapacityFloats","requiredFloats","nextFloats","computeBaselineForBarsFromAxis","plotSize","plotClipWidth","clipPerCssX","dataLength","categoryWidthClip","categoryInnerWidthClip","maxBarWidthClip","barWidthClip","gapClip","clusterWidthClip","baselineClip","fallbackBaselineDomain","maxBars","outFloats","seriesIndex","xClipCenter","baseClip","bClip","tClip","grownBytes","scatterWgsl","createScatterRenderer","lastCanvasWidth","lastCanvasHeight","lastViewportPx","lastScissor","viewportW","viewportH","hasValidDpr","getSeriesSizeCssPx","sizeCss","radiusCss","radiusDevicePx","scatterDensityBinningWgsl","scatterDensityColormapWgsl","lerp","lerpRgba","parseColorStop","css","getNamedStops","name","buildLutRGBA8","colormap","stops","seg","localT","colormapKey","normalizationToU32","createScatterDensityRenderer","computeBindGroupLayout","renderBindGroupLayout","computeUniformBuffer","computeUniformScratch","computeUniformF32","computeUniformU32","renderUniformBuffer","renderUniformScratch","renderUniformU32","binningModule","binPointsPipeline","reduceMaxPipeline","renderPipeline","binsBuffer","maxBuffer","binsCapacityU32","lutTexture","lutView","lastColormapKey","computeBindGroup","renderBindGroup","lastPointBuffer","lastPointCount","lastVisibleStart","lastVisibleEnd","lastBinSizePx","lastBinCountX","lastBinCountY","lastPlotScissor","lastNormalizationU32","computeDirty","hasPrepared","zeroBinsStaging","ensureLut","ensureBins","binCountX","binCountY","requiredU32","ensureBindGroups","pointBuffer","visibleStartIndex","visibleEndIndex","rawBounds","binSizeCss","binSizePx","normU32","rb","binTotal","visibleCount","pass","wg","groupsPoints","groupsBins","pieWgsl","TAU","wrapToTau","thetaRad","parseColor","cssColor","fallbackCssColor","parsed","fb","resolveCenterPlotCss","center","xRaw","yRaw","isRadiusTuple","resolveRadiiCss","IDENTITY_MAT4_F32","createPieRenderer","viewportWDevicePx","viewportHDevicePx","centerPlotCss","centerCanvasCssX","centerCanvasCssY","centerClipX","centerClipY","innerPx","outerPx","total","validCount","item","startDeg","current","accumulated","emitted","isLast","startRad","endRad","candlestickWgsl","DEFAULT_WICK_WIDTH_CSS_PX","getOHLC","computeCategoryStep","timestamps","createCandlestickRenderer","hollowMode","hollowInstanceBuffer","hollowInstanceCount","cpuHollowStagingBuffer","cpuHollowStagingF32","ensureCpuHollowCapacityFloats","backgroundColor","bodyWidthClip","minWidthClip","maxWidthClip","wickWidthCssPx","wickWidthClip","upColor","downColor","upBorderColor","downBorderColor","hollowF32","hollowOutFloats","openClip","closeClip","lowClip","highClip","isUp","borderColor","borderWidthClip","insetBodyWidthClip","fillColor","hollowRequiredBytes","crosshairWgsl","align4","SMALL_FULL_WRITE_MAX_BYTES","MAX_DIFF_RANGES_BEFORE_FULL_WRITE","MAX_CHANGED_WORDS_BEFORE_FULL_WRITE","toU32View","createStreamBuffer","clamped","limit","capacityWords","createSlot","slots","currentIndex","writeFull","slotIndex","newWords","usedWords","slot","mirror","usedBytes","writeRangesByDiff","ranges","rangeCount","changedWords","byteSize","nextVertexCount","nextIndex","DEFAULT_CROSSHAIR_RGBA","MAX_THICKNESS_DEVICE_PX","DASH_ON_DEVICE_PX","DASH_OFF_DEVICE_PX","MAX_VERTICES","computeThicknessOffsetsDevicePx","lineWidthCssPx","widthDevicePx","thickness","devicePxToClipX","xDevicePx","canvasWidthDevicePx","devicePxToClipY","yDevicePx","canvasHeightDevicePx","appendSegmentVerticesClip","generateDashedSegmentsAxisAligned","a0","a1","on","period","approxSegments","segments","s0","s1","generateCrosshairVertices","xCssPx","yCssPx","xDevice","thicknessOffsets","floats","dashSegmentsY","dashSegmentsX","projectedVertexCount","useDashed","addVerticalSolid","addHorizontalSolid","xd","ya","yb","yd","xa","xb","createCrosshairRenderer","stream","renderOptions","scissor","highlightWgsl","DEFAULT_RGBA","isFiniteScissor","brighten","factor","f","luminance","createHighlightRenderer","uniformBuffer","sizeCssPx","baseRadiusDevicePx","seriesRgba","ringRgba","outlineRgba","buf","referenceLineWgsl","MAX_DASH_VALUES","normalizeDash","cleaned","dashCount","dashTotal","createReferenceLineRenderer","sampleCountRaw","sampleCount","instanceCapacity","lines","plotWidthDevice","plotHeightDevice","uniforms","nextCapacity","line","dash","firstInstance","requestedCount","first","available","annotationMarkerWgsl","createAnnotationMarkerRenderer","instances","strokeWidthCss","strokeRgba","fr","fg","fa","sr","sg","sb","sa","DEFAULT_TAP_MAX_DISTANCE_CSS_PX","DEFAULT_TAP_MAX_TIME_MS","createEventManager","initialGridArea","listeners","tapCandidate","suppressNextLostPointerCaptureId","toPayload","rect","gridX","gridY","isInGrid","emit","eventName","payload","cb","clearTapCandidateIfMatches","onPointerMove","onPointerLeave","onPointerCancel","onLostPointerCapture","onPointerDown","onPointerUp","dt","maxDist","callback","nextGridArea","clamp","normalizeWheelDelta","basisCssPx","raw","normalizeWheelDeltaX","wheelDeltaToZoomFactor","deltaCssPx","abs","capped","isMiddleButtonDrag","isShiftLeftDrag","createInsideZoom","eventManager","enabled","lastPointer","isPanning","lastPanGridX","clearPan","onMouseMove","dxCss","deltaPct","onMouseLeave","_payload","onWheel","deltaYCss","deltaXCss","centerPct","enable","disable","DEFAULT_MIN_SPAN","DEFAULT_MAX_SPAN","normalizeZero","copyRange","createZoomState","initialStart","initialEnd","constraints","lastEmitted","minSpan","maxSpan","normalizedMinSpan","normalizedMaxSpan","next","snapshot","toAnchor","nextStart","nextEnd","spec","applyNextRange","targetSpan","anchorCenter","anchorRatio","shift","nextMinSpan","nextMaxSpan","nextMin","nextMax","eps","nextSpan","delta","hasNaNXCache","seriesHasNaNX","hasNaN","computeBarHitTestLayout","barSeries","barWidthRange","gap","clusterWidth","clusterIndexByGlobalSeriesIndex","globalSeriesIndex","findPointsAtX","xValue","tolerance","maxDx","maxDxSq","matches","barLayout","offsetLeftFromCategoryCenter","hitTol","hitIndex","isHit","xCenterRange","xTargetAdjusted","insertionIndex","getXCenterAt","bestDxSq","tryUpdate","dxSq","dxSqAt","dxSqLeft","dxSqRight","getTimestamp","getOpen","getClose","categoryStepCache","step","computeCandlestickBodyWidthRange","plotWidthFallback","categoryWidthRange","t0","minW","maxWCandidate","maxW","isMonotonicNonDecreasingFiniteTimestamps","prev","lowerBoundByTimestamp","findCandlestick","halfW","best","bestDx","dataIndex","isBodyHitAt","yOpen","yClose","findPieSlice","pieConfig","dyUp","angle","slice","wedgeSpan","rel","assertFinite","createLinearScale","rangeMin","rangeMax","self","pixel","createCategoryScale","categories","indexByCategory","rebuildIndex","nextCategories","category","getAnchorTransform","createTextOverlay","container","computedStyle","computedPosition","computedOverflow","didSetRelative","didSetOverflowVisible","previousInlinePosition","previousInlineOverflow","overlay","rotation","translateX","originX","getSeriesName","candidate","getSeriesColor","explicit","palette","getPieSliceLabel","sliceName","sliceIndex","getPieSliceColor","sliceColor","len","createLegend","position","onSeriesToggle","root","list","sliceIndexStr","items","isVisible","swatch","createTooltip","fadeMs","transitionToken","hideTimeoutId","rafId","clearPendingTransitions","isCurrentlyHidden","measureSize","prevVisibility","content","wasHidden","pad","containerW","containerH","myToken","EM_DASH","escapeHtml","resolveSeriesName","params","sanitizeCssColor","isCandlestickValue","formatPercentChange","change","formatRowHtml","valueText","safeName","safeValue","formatCandlestickRowHtml","safeColor","openStr","highStr","lowStr","closeStr","arrow","arrowColor","percentChange","ohlcText","safeOHLC","safeArrow","safePercent","safeArrowColor","formatCandlestickTooltip","formatTooltipItem","formatTooltipAxis","xText","header","rows","normalizeDurationMs","duration","normalizeTimestampMs","createAnimationController","animations","animate","from","to","easing","onUpdate","onComplete","id","cancel","animationId","cancelAll","update","ts","ids","anim","startTime","durationMs","elapsed","shouldComplete","rawT","easeLinear","easeCubicOut","inv","easeCubicInOut","easeBounceOut","n1","d1","getEasing","isHTMLCanvasElementGPU","getCanvasCssSizeFromDevicePixels","MAX_TIME_X_TICK_COUNT","MIN_TIME_X_TICK_COUNT","MIN_X_LABEL_GAP_CSS_PX","finiteOrNull","MAX_ANIMATED_POINTS_PER_SERIES","cartesianDataToDataPointArray","extendBoundsWithDataPoints","seeded","extendBoundsWithOHLCDataPoints","computeGlobalBounds","runtimeRawBoundsByIndex","runtimeBoundsCandidate","rawBoundsCandidate","rawOHLC","yLow","yHigh","computeGridArea","rawCanvasWidth","rawCanvasHeight","sanitizedLeft","sanitizedRight","sanitizedTop","sanitizedBottom","rgba01ToCssRgba","alphaMultiplier","t01","lerpDomain","isTupleOHLCDataPointImported","resolvePieCenterPlotCss","generateLinearTicks","ticks","computeAdaptiveTimeXAxisTicks","axisMin","axisMax","plotClipLeft","plotClipRight","measureCtx","measureCache","fontFamily","cacheKeyPrefix","tickValues","prevRight","ok","measured","computeBaseXDomain","baseMin","baseMax","computeVisibleYBounds","visibleOHLC","computeBaseYDomain","visibleBoundsOverride","explicitMin","explicitMax","autoBoundsMode","computeVisibleXDomain","baseXDomain","fractionRaw","spanFraction","resolveAnimationConfig","animation","durationMsRaw","delayMsRaw","delayMs","resolveIntroAnimationConfig","resolveUpdateAnimationConfig","computeCandlestickTooltipAnchor","bodyMidY","xCanvasCss","yCanvasCss","xContainerCss","yContainerCss","createAnimatedBarYScale","baseYScale","progress01","wrapper","createRenderCoordinator","callbacks","info","legend","pieData","updatedData","updatedSeries","seriesItem","setOptions","tickMeasureCtx","tickMeasureCache","lastSeriesCount","introAnimController","introAnimId","hasRenderedOnce","updateAnimController","updateAnimId","updateProgress01","updateTransition","updateInterpolationCaches","resetUpdateInterpolationCaches","interpolateCartesianSeriesDataByIndex","fromData","toData","cache","created","pTo","yFrom","yTo","interpolatePieSeriesByIndex","fromSeries","toSeries","vFrom","vTo","interpolateSeriesForUpdate","caches","aAny","bAny","aData","bData","animatedData","computeUpdateSnapshotAtProgress","transition","xBase","xVisible","yBase","warnedPieAppendSeries","warnedSamplingDefeatsFastPath","runtimeRawDataByIndex","runtimeBaseSeries","cachedVisibleYBounds","shouldComputeVisibleYBounds","opts","recomputeCachedVisibleYBoundsIfNeeded","lastSampledData","flushScheduled","flushRafId","flushTimeoutId","zoomResampleDebounceTimer","zoomResampleDue","sliceRenderSeriesDue","pendingAppendByIndex","tooltip","lastTooltipContent","lastTooltipX","lastTooltipY","showTooltipInternal","_params","hideTooltipInternal","hideTooltip","gridRenderer","xAxisRenderer","yAxisRenderer","crosshairRenderer","highlightRenderer","ANNOTATION_OVERLAY_MSAA_SAMPLE_COUNT","referenceLineRenderer","annotationMarkerRenderer","referenceLineRendererMsaa","annotationMarkerRendererMsaa","mainColorTexture","mainColorView","overlayMsaaTexture","overlayMsaaView","overlayTargetsWidth","overlayTargetsHeight","overlayTargetsFormat","OVERLAY_BLIT_WGSL","overlayBlitBindGroupLayout","overlayBlitPipeline","overlayBlitBindGroup","destroyTexture","tex","ensureOverlayTargets","pointerState","interactionX","interactionXSource","interactionXListeners","lastInteractionScales","emitInteractionX","nextX","source","setInteractionXInternal","requestRender","isFullSpanZoomRange","range","cancelScheduledFlush","cancelZoomResampleDebounce","flushPendingAppends","zoomRangeBefore","isFullSpanZoomBefore","canAutoScroll","prevBaseXDomain","prevVisibleXDomain","didAppendAny","seed","ohlcPoints","dataPoints","computeEffectiveZoomSpanConstraints","withConstraints","anchored","nextBaseXDomain","nextStartRaw","nextEndRaw","recomputeRuntimeBaseSeries","zoomRangeAfter","executeFlush","requestRenderAfter","didAppend","zoomIsFullSpan","zoomActiveNotFullSpan","didResample","recomputeRenderSeries","scheduleFlush","scheduleZoomResample","getPlotSizeCssPx","canvasWidthCss","canvasHeightCss","computeInteractionScalesGridCssPx","domains","buildTooltipParams","buildCandlestickTooltipParams","findPieSliceAtPointer","pieSeries","radii","findCandlestickAtPointer","cs","insideZoom","unsubscribeZoom","lastOptionsZoomRange","zoomRangeListeners","emitZoomRange","getZoomOptionsConfig","insideCfg","sliderCfg","clampPercent","getZoomSpanConstraintsFromOptions","computeDatasetAwareDefaultMinSpan","maxPoints","fromOptions","datasetMin","updateZoom","initRuntimeSeriesFromOptions","owned","baselineSampled","sliceRenderSeriesToVisibleRange","visibleX","bufferedMin","bufferedMax","MIN_TARGET_POINTS","MAX_TARGET_POINTS_ABS","MAX_TARGET_MULTIPLIER","spanFracSafe","bufferedOHLC","baseThreshold","baseT","maxTarget","target","sampled","visibleSampled","bufferedRaw","areaRenderers","lineRenderers","scatterRenderers","scatterDensityRenderers","pieRenderers","candlestickRenderers","barRenderer","ensureAreaRendererCount","ensureLineRendererCount","ensureScatterRendererCount","ensureScatterDensityRendererCount","ensurePieRendererCount","ensureCandlestickRendererCount","cancelUpdateTransition","isDomainEqual","didSeriesDataLikelyChange","aPie","bPie","aRaw","bRaw","didOnlyVisibilityChange","hasVisibilityChange","j","sliceA","sliceB","aSliceVisible","bSliceVisible","aVisible","bVisible","resolvedOptions","fromZoomRange","fromSnapshot","fromXBase","fromXVisible","fromYBase","likelyDataChanged","onlyVisibilityChanged","shouldHaveTooltip","nextCount","toZoomRange","toXBase","toXVisible","toYBase","toSeriesForTransition","domainChanged","updateCfg","totalMs","easingWithDelay","elapsedMs","innerT","seriesForIntro","introCfg","hasDrawableSeriesMarks","it","updateP","yBaseDomain","canvasCssForAnnotations","annotationResult","combinedReferenceLines","combinedMarkers","computed","formatter","trigger","containerX","containerY","paramsArray","m0","pieMatch","candlestickResult","tooltipX","tooltipY","seriesPreparation","yScaleForBars","swapchainView","clearValue","renderSeriesPass","topOverlayPass","defaultGrid","defaultPalette","defaultLineStyle","defaultAreaStyle","candlestickDefaults","scatterDefaults","defaultOptions","darkTheme","lightTheme","getTheme","sanitizeDataZoom","input","record","type","xAxisIndexRaw","startRaw","endRaw","minSpanRaw","maxSpanRaw","xAxisIndex","sanitizeAnnotations","isLabelAnchor","isScatterSymbol","sanitizeString","sanitizeFiniteNumber","sanitizeOpacity01","sanitizeLineDash","sanitizePadding","layerRaw","styleRaw","style","labelRaw","decimalsRaw","offsetRaw","offset","anchorRaw","bgRaw","background","markerRaw","marker","symbolRaw","symbol","mStyleRaw","mStyle","positionRaw","space","sanitizePalette","resolveTheme","themeInput","takeString","fontSizeRaw","colorPaletteCandidate","normalizeOptionalColor","normalizeSampling","normalizeScatterMode","normalizeDensityNormalization","normalizeDensityBinSize","normalizeDensityColormap","arr","sanitized","normalizeCandlestickSampling","normalizeSamplingThreshold","normalizeAxisAutoBounds","computeRawBoundsFromOHLC","candlestickWarned","warnCandlestickNotImplemented","resolveOptions","userOptions","baseTheme","autoScrollRaw","autoScroll","animationRaw","paletteOverride","themeCandidate","paletteFromTheme","safePalette","paletteForIndexing","grid","xAxis","yAxis","explicitColor","inheritedColor","effectiveColor","areaStyle","effectiveStrokeColor","lineStyle","_userAreaStyle","rest","sampledData","binSize","densityColormap","densityNormalization","_sampling","_samplingThreshold","resolvedData","itemIndex","itemColor","itemVisible","resolvedSampling","resolvedSamplingThreshold","resolvedItemStyle","DATA_ZOOM_SLIDER_HEIGHT_CSS_PX","DATA_ZOOM_SLIDER_MARGIN_TOP_CSS_PX","DATA_ZOOM_SLIDER_RESERVE_CSS_PX","hasSliderDataZoom","resolveOptionsForChart","OptionResolver","normalizeRange","createDataZoomSlider","marginTop","zIndex","showPreview","track","preview","windowEl","leftHandle","rightHandle","centerGrip","activeDragCleanup","applyRangeToDom","getTrackWidthPx","pxToPercent","dxPx","setPointerCaptureBestEffort","el","pointerId","releasePointerCaptureBestEffort","startDrag","dragStartX","startRange","onMove","ev","dxPercent","cleanedUp","cleanup","finish","onLeftDown","onRightDown","onPanDown","unsubscribe","handleBorder","cachedSupportCheck","checkWebGPUSupport","reason","FRAME_BUFFER_SIZE","EXPECTED_FRAME_TIME_MS","FRAME_DROP_THRESHOLD_MULTIPLIER","getCartesianPointCount","getCartesianX","getCartesianY","getCartesianSize","getOHLCTimestamp","getOHLCClose","computeRawBoundsFromData","createChartGPU","supportCheck","coordinator","coordinatorTargetFormat","unsubscribeCoordinatorInteractionXChange","dataZoomSliderHost","dataZoomSlider","runtimeHitTestSeriesCache","initRuntimeHitTestStoreFromResolvedOptions","getRuntimeHitTestSeries","cachedGlobalBounds","interactionScalesCache","hovered","scheduledRaf","lastConfigured","isDirty","frameTimestamps","frameTimestampIndex","frameTimestampCount","totalFrames","totalDroppedFrames","consecutiveDroppedFrames","lastDropTimestamp","lastFrameTime","lastCPUTime","performanceUpdateCallbacks","hasHoverListeners","hasClickListeners","cancelPendingFrame","frameStartTime","resizeInternal","metrics","calculatePerformanceMetrics","unbindCoordinatorInteractionXChange","disposeDataZoomSlider","disposeDataZoomSliderHost","disposeDataZoomUi","ensureDataZoomSliderHost","host","computeZoomInOutAnchorRatio","createCoordinatorZoomStateLike","ratio","syncDataZoomUi","bindCoordinatorInteractionXChange","recreateCoordinator","prevZoomRange","shouldRequestRenderAfterChanges","maxDimension","sizeChanged","didConfigure","resize","getNearestPointFromPointerEvent","zMin","zMax","scales","cartesianMatch","calculateExactFPS","startIndex","totalDelta","prevIndex","currIndex","avgFrameTime","calculateFrameTimeStats","deltas","sum","avg","p50Index","p95Index","p99Index","fps","frameTimeStats","gpuTiming","memory","frameDrops","elapsedTime","buildPayload","seriesNameRaw","seriesName","setHovered","prevSeriesIndex","prevDataIndex","nextSeriesIndex","nextDataIndex","dispose","instance","nextOptions","canvasX","canvasY","errorMessage","ChartGPU","connectCharts","charts","connectionToken","disconnected","unsubscribeFns","broadcast","sourceChart","chart","onCrosshairMove","unsub","createAnnotationHitTester","lineTolerance","textTolerance","pointTolerance","boundsCache","textBoundsCache","cacheValid","getPointX","getPointY","getOHLCHigh","getOHLCLow","computeXDomain","dataXMin","dataXMax","zoomMin","zoomMax","computeYDomain","dataYMin","dataYMax","dataToCanvas","chartOptions","fraction","plotToCanvas","updateCache","annotation","pos","distanceToLine","pointerX","pointerY","lineX","lineY","distanceToPoint","pointX","pointY","isInsideRect","hitTest","closestHit","closestDistance","distance","textRect","centerX","centerY","updateTextBounds","textBounds","invalidateCache","createAnnotationDragHandler","dragState","canvasToData","dataX","dataY","xFraction","yFraction","canvasToPlot","updates","onKeyDown","annotationIndex","startPointerX","startPointerY","isDragging","HIGH_CONTRAST_PALETTE","createAnnotationConfigDialog","dialog","currentOnSave","currentOnCancel","createOverlay","div","handleCancel","createDialog","createField","field","labelEl","createTextInput","placeholder","maxLength","defaultValue","createTextArea","textarea","createColorPicker","selectedColor","currentColor","checkmark","path","child","btn","isSelected","svg","createDropdown","select","opt","option","createSlider","unit","slider","valueDisplay","createButtons","saveLabel","onSaveClick","onCancelClick","cancelBtn","saveBtn","buildLineForm","defaults","form","defaultLabelText","labelInput","colorPicker","lineStyleDropdown","lineWidthSlider","buttons","lineDashMap","labelText","handleSave","buildTextForm","defaultText","textArea","buildPointForm","defaultMarkerSize","markerSizeSlider","hide","handleKeyDown","showCreate","onSave","onCancel","title","firstInput","showEdit","createAnnotationAuthoring","menuZIndex","enableContextMenu","history","historyIndex","hitTester","configDialog","dragHandler","getCurrentAnnotations","applyAnnotations","pushHistory","contextMenu","createContextMenu","menu","createMenuItem","onClick","hideContextMenu","createMenuSeparator","separator","populateContextMenuForAnnotation","handleEditAnnotation","handleDeleteAnnotation","handleAddVerticalLine","handleAddHorizontalLine","handleAddTextNote","populateContextMenuForEmptySpace","lastHitTestResult","showContextMenu","annotationHit","menuRect","adjustedX","adjustedY","computeVisibleYDomain","gridXToDataX","gridToPlotSpace","plotPos","_","onContextMenu","onDocumentClick","onDocumentKeyDown","onWindowScrollOrResize","addVerticalLine","newAnnotation","addTextNote","undo","redo","exportJSON","getAnnotations","internalStateMap","createRenderScheduler","state","startRenderScheduler","internalState","schedulerId","frameHandler","currentTime","currentInternalState","deltaTime","MAX_DELTA_TIME","nextInternalState","stopRenderScheduler","destroyRenderScheduler","createRenderSchedulerAsync","RenderScheduler","version","ChartGPUNamespace"],"mappings":"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"}