pptx-angular-viewer 4.24.3 → 4.26.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +65 -0
- package/README.md +9 -9
- package/ng-package.json +25 -0
- package/package.json +45 -20
- package/scripts/finalize-dist.mjs +24 -0
- package/scripts/inline-shared.mjs +43 -0
- package/tsconfig.lib.json +13 -0
- package/vitest-setup.ts +12 -0
- package/fesm2022/pptx-angular-viewer-bar-chart-3d-hit-test-B6eCwecE.mjs +0 -9855
- package/fesm2022/pptx-angular-viewer-bar-chart-3d-hit-test-B6eCwecE.mjs.map +0 -1
- package/fesm2022/pptx-angular-viewer-chart-3d-view-scene-IqColhvd.mjs +0 -1594
- package/fesm2022/pptx-angular-viewer-chart-3d-view-scene-IqColhvd.mjs.map +0 -1
- package/fesm2022/pptx-angular-viewer-chat-history-idb-7dzD77Ju.mjs +0 -73
- package/fesm2022/pptx-angular-viewer-chat-history-idb-7dzD77Ju.mjs.map +0 -1
- package/fesm2022/pptx-angular-viewer-chat-history-store-Ckeu-olx.mjs +0 -121
- package/fesm2022/pptx-angular-viewer-chat-history-store-Ckeu-olx.mjs.map +0 -1
- package/fesm2022/pptx-angular-viewer-view-overflow-BBD8nZlq.mjs +0 -1418
- package/fesm2022/pptx-angular-viewer-view-overflow-BBD8nZlq.mjs.map +0 -1
- package/fesm2022/pptx-angular-viewer-view-scene-htTUkvvA.mjs +0 -836
- package/fesm2022/pptx-angular-viewer-view-scene-htTUkvvA.mjs.map +0 -1
- package/fesm2022/pptx-angular-viewer.mjs +0 -169944
- package/fesm2022/pptx-angular-viewer.mjs.map +0 -1
- package/i18n/de.cjs +0 -4165
- package/i18n/de.d.cts +0 -3
- package/i18n/de.d.mts +0 -3
- package/i18n/de.mjs +0 -4138
- package/i18n/es.cjs +0 -4165
- package/i18n/es.d.cts +0 -3
- package/i18n/es.d.mts +0 -3
- package/i18n/es.mjs +0 -4138
- package/i18n/fr.cjs +0 -4165
- package/i18n/fr.d.cts +0 -3
- package/i18n/fr.d.mts +0 -3
- package/i18n/fr.mjs +0 -4138
- package/i18n/zh-CN.cjs +0 -4198
- package/i18n/zh-CN.d.cts +0 -3
- package/i18n/zh-CN.d.mts +0 -3
- package/i18n/zh-CN.mjs +0 -4171
- package/pptx-angular-viewer.css +0 -2
- package/types/pptx-angular-viewer.d.ts +0 -60042
- package/types/pptx-angular-viewer.d.ts.map +0 -1
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"pptx-angular-viewer-bar-chart-3d-hit-test-B6eCwecE.mjs","names":["DEFAULT_TEXT_COLOR","hexToRgb","hexToRgbChannels","colorWithOpacity","clampUnitInterval","hexToRgb","rgbToHex","tint","shade","seriesColor","paletteColor","computeValueRange","valueToY","formatAxisValue","PX_PER_PT","computeValueRange","LEGEND_ITEM_WIDTH","LEGEND_ITEM_HEIGHT","DEFAULT_COLOR","DEFAULT_ROT_X","pairs","leaderLine","categoryX","categoryX","tickLine","categoryX","GRIDLINE_COLOR","TICK_COUNT","MAJOR_TICK_LENGTH","tickLine","clamp","categoryTotals","buildBars","categoryX","categoryX","GRIDLINE_COLOR","buildBars","seriesColor","rangeForSeries","emptyChrome","emptyChrome","GRIDLINE_COLOR","TICK_COUNT","emptyChrome","emptyChrome","exhaustive"],"sources":["../../src/internal/shared-src/constants.ts","../../src/internal/shared-src/render/path-gradient-rect.ts","../../src/internal/shared-src/render/vector-subpath-paint.ts","../../src/internal/shared-src/render/subpath-fill-overlay.ts","../../src/internal/shared-src/render/fill-style.ts","../../src/internal/shared-src/render/element-style-transform.ts","../../src/internal/shared-src/render/chart-axis-nice.ts","../../src/internal/shared-src/render/chart-font.ts","../../src/internal/shared-src/render/chart-legend-placement.ts","../../src/internal/shared-src/render/chart-number-format-pattern.ts","../../src/internal/shared-src/render/chart-number-format.ts","../../src/internal/shared-src/render/chart-style-defaults.ts","../../src/internal/shared-src/render/chart-title-style.ts","../../src/internal/shared-src/render/chart-title-runs.ts","../../src/internal/shared-src/render/chart-title-band.ts","../../src/internal/shared-src/render/chart-helpers.ts","../../src/internal/shared-src/render/chart-area-fill.ts","../../src/internal/shared-src/render/chart-label-measure.ts","../../src/internal/shared-src/render/chart-label-lines.ts","../../src/internal/shared-src/render/chart-axis-range.ts","../../src/internal/shared-src/render/chart-axis.ts","../../src/internal/shared-src/render/chart-palette.ts","../../src/internal/shared-src/render/chart-marker-shape.ts","../../src/internal/shared-src/render/chart-datapoint-style.ts","../../src/internal/shared-src/render/chart-datapoint-picture-resolve.ts","../../src/internal/shared-src/render/chart-picture-pattern-def.ts","../../src/internal/shared-src/render/chart-datapoint-picture-fills.ts","../../src/internal/shared-src/render/chart-bar3d-face-picture-sample.ts","../../src/internal/shared-src/render/chart-bar3d-face-picture.ts","../../src/internal/shared-src/render/chart-legend-layout.ts","../../src/internal/shared-src/render/chart-legend-swatch.ts","../../src/internal/shared-src/render/chart-axis-style.ts","../../src/internal/shared-src/render/chart-axis-primitives.ts","../../src/internal/shared-src/render/chart-trendline-defaults.ts","../../src/internal/shared-src/render/chart-view-model-scale.ts","../../src/internal/shared-src/render/connector-dash.ts","../../src/internal/shared-src/render/chart-legend-build.ts","../../src/internal/shared-src/render/chart-view-model-bars.ts","../../src/internal/shared-src/render/chart-3d-surfaces.ts","../../src/internal/shared-src/render/chart-bar3d-series-depth.ts","../../src/internal/shared-src/render/chart-pie3d-tilt.ts","../../src/internal/shared-src/render/chart-3d-depth.ts","../../src/internal/shared-src/render/chart-auto-title.ts","../../src/internal/shared-src/render/chart-manual-layout.ts","../../src/internal/shared-src/render/chart-data-label-anchor.ts","../../src/internal/shared-src/render/chart-data-label-callout.ts","../../src/internal/shared-src/render/chart-data-label-text.ts","../../src/internal/shared-src/render/chart-line-path.ts","../../src/internal/shared-src/render/chart-category-position.ts","../../src/internal/shared-src/render/chart-category-labels.ts","../../src/internal/shared-src/render/chart-category-axis.ts","../../src/internal/shared-src/render/chart-scatter-x-axis.ts","../../src/internal/shared-src/render/chart-cartesian-plots.ts","../../src/internal/shared-src/render/chart-cartesian-area.ts","../../src/internal/shared-src/render/chart-axis-crossing.ts","../../src/internal/shared-src/render/chart-gridlines-toggle.ts","../../src/internal/shared-src/render/chart-cartesian-axes.ts","../../src/internal/shared-src/render/chart-cartesian-percent-stacked.ts","../../src/internal/shared-src/render/chart-cartesian-stacked-labels.ts","../../src/internal/shared-src/render/chart-cartesian-bars.ts","../../src/internal/shared-src/render/chart-cartesian-bubbles.ts","../../src/internal/shared-src/render/chart-cartesian-line-area.ts","../../src/internal/shared-src/render/chart-data-table-metrics.ts","../../src/internal/shared-src/render/chart-data-table-render.ts","../../src/internal/shared-src/render/chart-helper-lines.ts","../../src/internal/shared-src/render/chart-date-format.ts","../../src/internal/shared-src/render/chart-date-axis.ts","../../src/internal/shared-src/render/chart-horizontal-axis.ts","../../src/internal/shared-src/render/text-wrap-estimate.ts","../../src/internal/shared-src/render/chart-horizontal-bars-helpers.ts","../../src/internal/shared-src/render/chart-horizontal-bars.ts","../../src/internal/shared-src/render/chart-overlays-axis-titles.ts","../../src/internal/shared-src/render/chart-error-bars.ts","../../src/internal/shared-src/render/chart-trendline-equation-format.ts","../../src/internal/shared-src/render/chart-overlays-trendline-fit.ts","../../src/internal/shared-src/render/chart-overlays-trendline.ts","../../src/internal/shared-src/render/chart-cartesian.ts","../../src/internal/shared-src/render/chart-stock-close-label.ts","../../src/internal/shared-src/render/chart-stock-candles.ts","../../src/internal/shared-src/render/chart-combo-classify.ts","../../src/internal/shared-src/render/chart-combo-series.ts","../../src/internal/shared-src/render/chart-combo.ts","../../src/internal/shared-src/render/chart-combo-stock.ts","../../src/internal/shared-src/render/chart-cx-axis-units.ts","../../src/internal/shared-src/render/chart-distribution-range.ts","../../src/internal/shared-src/render/chart-box-whisker.ts","../../src/internal/shared-src/render/chart-histogram-binning.ts","../../src/internal/shared-src/render/chart-histogram.ts","../../src/internal/shared-src/render/chart-sunburst-hierarchy.ts","../../src/internal/shared-src/render/chart-surface-common.ts","../../src/internal/shared-src/render/chart-sunburst-view.ts","../../src/internal/shared-src/render/chart-funnel-sunburst.ts","../../src/internal/shared-src/render/chart-gradient-defs.ts","../../src/internal/shared-src/render/chart-legend-entries.ts","../../src/internal/shared-src/render/chart-ofpie-split.ts","../../src/internal/shared-src/render/chart-ofpie-secondary.ts","../../src/internal/shared-src/render/chart-ofpie.ts","../../src/internal/shared-src/render/chart-view-model-chrome.ts","../../src/internal/shared-src/render/chart-surface-axes.ts","../../src/internal/shared-src/render/chart-surface-bands.ts","../../src/internal/shared-src/render/chart-surface-legend.ts","../../src/internal/shared-src/render/chart-surface-isometric.ts","../../src/internal/shared-src/render/chart-surface-flat.ts","../../src/internal/shared-src/render/chart-treemap-squarify.ts","../../src/internal/shared-src/render/chart-treemap-hierarchy.ts","../../src/internal/shared-src/render/chart-treemap-view.ts","../../src/internal/shared-src/render/chart-user-shape-overlay.ts","../../src/internal/shared-src/render/chart-view-model-kinds.ts","../../src/internal/shared-src/render/chart-view-model-manual.ts","../../src/internal/shared-src/render/chart-pie-best-fit.ts","../../src/internal/shared-src/render/chart-pie-label-collision.ts","../../src/internal/shared-src/render/chart-pie-label-helpers.ts","../../src/internal/shared-src/render/chart-pie-labels.ts","../../src/internal/shared-src/render/chart-radar-geometry.ts","../../src/internal/shared-src/render/chart-view-model-points.ts","../../src/internal/shared-src/render/chart-view-model-pie.ts","../../src/internal/shared-src/render/chart-view-model-layout.ts","../../src/internal/shared-src/render/chart-view-model-radar.ts","../../src/internal/shared-src/render/chart-region-map-alias.ts","../../src/internal/shared-src/render/chart-region-map-data.ts","../../src/internal/shared-src/render/chart-region-map-colors.ts","../../src/internal/shared-src/render/chart-map-projection.ts","../../src/internal/shared-src/render/chart-region-map-fallback-table.ts","../../src/internal/shared-src/render/chart-region-map-view.ts","../../src/internal/shared-src/render/chart-waterfall-layout.ts","../../src/internal/shared-src/render/chart-waterfall-view.ts","../../src/internal/shared-src/render/chart-view-model-build.ts","../../src/internal/shared-src/render/chart-axis-render.ts","../../src/internal/shared-src/render/chart-pareto.ts","../../src/internal/shared-src/render/chart-interaction-pie.ts","../../src/internal/shared-src/render/chart-interaction-radar.ts","../../src/internal/shared-src/render/chart-interaction-stacked.ts","../../src/internal/shared-src/render/chart-interaction.ts","../../src/internal/shared-src/render/chart-canvas-drag.ts","../../src/internal/shared-src/render/chart-view-model-dom-helpers.ts","../../src/internal/shared-src/render/chart-view-model-dom.ts","../../src/internal/shared-src/render/chart-3d-oblique-bars.ts","../../src/internal/shared-src/render/chart-3d-persp-oblique.ts","../../src/internal/shared-src/render/chart-3d-persp-view.ts","../../src/internal/shared-src/render/chart-3d-pie-layout.ts","../../src/internal/shared-src/render/bar-chart-3d-hit-test.ts"],"sourcesContent":["/**\n * Scalar viewer defaults shared by the UI bindings.\n *\n * Subset of the React package's `constants/scalar.ts` that the Vue and Angular\n * viewers also need. Additional constant groups (toolbar presets, shape styles,\n * transitions, etc.) remain per-binding until those features are ported.\n */\n\n/** Default slide canvas width in pixels when the file declares none. */\nexport const DEFAULT_CANVAS_WIDTH = 1280;\n/** Default slide canvas height in pixels when the file declares none. */\nexport const DEFAULT_CANVAS_HEIGHT = 720;\n\n/** Fallback text colour. */\nexport const DEFAULT_TEXT_COLOR = '#111827';\n/** Fallback shape fill colour. */\nexport const DEFAULT_FILL_COLOR = '#3b82f6';\n/** Fallback shape stroke colour. */\nexport const DEFAULT_STROKE_COLOR = '#1f2937';\n/** Colour PowerPoint paints hyperlinked text in when the theme declares none. */\nexport const HYPERLINK_COLOR = '#0563C1';\n\n/**\n * Font stack declared on a text body that authors no typeface.\n *\n * Declaring one is not cosmetic: with no `font-family` on the body, a run that\n * inherits (a bullet marker, an unstyled run) picks up the HOST PAGE's font,\n * so the same deck measured different advances in each binding's demo chrome.\n */\nexport const DEFAULT_FONT_FAMILY = '\"Segoe UI\", \"Helvetica Neue\", Arial, sans-serif';\n/** Font size in px for a text body that authors none (PowerPoint's 18pt body). */\nexport const DEFAULT_TEXT_FONT_SIZE = 24;\n\n/**\n * OOXML default body text insets in px (`a:bodyPr` lIns/rIns = 91440 EMU,\n * tIns/bIns = 45720 EMU, divided by EMU_PER_PIXEL).\n */\nexport const DEFAULT_BODY_INSET_LR_PX = 91440 / 9525;\n/** See {@link DEFAULT_BODY_INSET_LR_PX}. */\nexport const DEFAULT_BODY_INSET_TB_PX = 45720 / 9525;\n","/**\n * PowerPoint `a:gradFill` with `a:path@type=\"rect\"` shades a shape toward its\n * own bounding rectangle. Its isolines are concentric rectangles with square\n * corners (a Chebyshev / L-infinity distance field: `d = max(|dx|, |dy|)`),\n * not circles or ellipses. SVG and CSS only offer elliptical/circular radial\n * gradients natively, so this repo previously approximated a rect path\n * gradient as a single ellipse (`fill-style.ts`'s old `buildRectPathGradient`\n * body) - a reasonable match near the centre of a roughly square shape, but\n * visibly wrong near the corners of anything else. There, PowerPoint's real\n * render reaches the outer stop colour fastest (the corner is the single\n * farthest point on both axes at once), while an ellipse reaches it slowest\n * (a circle/ellipse's corner-diagonal radius is always >= its axis radius),\n * so the ellipse left every corner closer to the centre colour than\n * PowerPoint actually paints it - most visible on a wide/short shape (a\n * banner, a button) with a vignette-style rect gradient.\n *\n * This module renders the true rectangular field directly, as a stack of\n * nested, axis-aligned `<rect>` bands (largest first, smallest last,\n * painter's-algorithm style) inside a small self-contained SVG. Each band's\n * four edges are linearly interpolated between the shape's own bounding box\n * (position 100, the outermost band) and `a:fillToRect`'s own inner\n * rectangle (position 0): `fillToRect` names a whole target rectangle, not a\n * point, so PowerPoint paints its position-0 colour flat across that entire\n * rectangle and only ramps the gradient in the \"frame\" around it, which this\n * reproduces exactly (with no `fillToRect` at all, the inner rectangle\n * collapses to a point, giving plain nested squares/rectangles shrinking to\n * the centre - the Chebyshev/L-infinity field described above). This is a\n * much closer match to PowerPoint's own render than a single closed-form\n * ellipse, while staying pure SVG markup (no filters, no blend modes, nothing\n * that raster export or an older browser might not support).\n *\n * The SVG uses a normalised 0-100 viewBox with `preserveAspectRatio=\"none\"`,\n * so it is meant to be painted via `background-image` paired with\n * `background-size: 100% 100%` and `background-repeat: no-repeat` (see\n * `resolveComputedFill` in `fill-style.ts`): it then stretches to the\n * element's own box regardless of aspect ratio, exactly like the CSS\n * `radial-gradient()` string it replaces.\n *\n * Deliberately dependency-free (no imports from `fill-style.ts`) so it stays\n * a pure, reusable decision function per this repo's shared-extraction rule,\n * and can later be reused by the SVG (`custGeom`) fill path without risking\n * an import cycle.\n */\n\n/** One colour stop, already sanitised: position 0-100, colour `#RRGGBB`. */\nexport interface RectPathGradientStop {\n\tposition: number;\n\tcolor: string;\n\topacity?: number;\n}\n\n/** A focal point as a fraction (0-1) of the shape's box, e.g. `a:gradFill`'s focus. */\nexport interface RectPathGradientFocalPoint {\n\tx: number;\n\ty: number;\n}\n\n/** OOXML `a:fillToRect`, as 0-1 insets from each edge. */\nexport interface RectPathGradientFillToRect {\n\tl: number;\n\tt: number;\n\tr: number;\n\tb: number;\n}\n\n/**\n * Bands rendered across the 0-1 distance range. Higher is smoother (closer to\n * the true continuous field) at the cost of a larger data URI; 40 keeps each\n * visible step under a couple of percent, which is not perceptible at normal\n * zoom for the smooth authoring gradients PowerPoint decks actually use.\n */\nconst BAND_COUNT = 40;\n\nfunction hexToRgb(color: string): { r: number; g: number; b: number } {\n\tconst hex = color.replace('#', '');\n\treturn {\n\t\tr: Number.parseInt(hex.slice(0, 2), 16) || 0,\n\t\tg: Number.parseInt(hex.slice(2, 4), 16) || 0,\n\t\tb: Number.parseInt(hex.slice(4, 6), 16) || 0,\n\t};\n}\n\nfunction toHexChannel(value: number): string {\n\treturn Math.min(255, Math.max(0, Math.round(value)))\n\t\t.toString(16)\n\t\t.padStart(2, '0');\n}\n\n/** Linearly interpolates two colour stops' colour and opacity at `t` (0 = a, 1 = b). */\nfunction lerpStops(\n\ta: RectPathGradientStop,\n\tb: RectPathGradientStop,\n\tt: number,\n): { color: string; opacity: number } {\n\tconst ca = hexToRgb(a.color);\n\tconst cb = hexToRgb(b.color);\n\tconst oa = a.opacity ?? 1;\n\tconst ob = b.opacity ?? 1;\n\treturn {\n\t\tcolor: `#${toHexChannel(ca.r + (cb.r - ca.r) * t)}${toHexChannel(ca.g + (cb.g - ca.g) * t)}${toHexChannel(ca.b + (cb.b - ca.b) * t)}`,\n\t\topacity: oa + (ob - oa) * t,\n\t};\n}\n\n/** Colour + opacity at a given position (0-100) along a sorted, non-empty stop list. */\nfunction colorAt(\n\tstops: RectPathGradientStop[],\n\tposition: number,\n): { color: string; opacity: number } {\n\tconst first = stops[0];\n\tconst last = stops[stops.length - 1];\n\tif (position <= first.position) {\n\t\treturn { color: first.color, opacity: first.opacity ?? 1 };\n\t}\n\tif (position >= last.position) {\n\t\treturn { color: last.color, opacity: last.opacity ?? 1 };\n\t}\n\tfor (let i = 0; i < stops.length - 1; i += 1) {\n\t\tconst from = stops[i];\n\t\tconst to = stops[i + 1];\n\t\tif (position >= from.position && position <= to.position) {\n\t\t\tconst span = to.position - from.position;\n\t\t\tconst t = span > 0 ? (position - from.position) / span : 0;\n\t\t\treturn lerpStops(from, to, t);\n\t\t}\n\t}\n\treturn { color: last.color, opacity: last.opacity ?? 1 };\n}\n\n/** An axis-aligned rectangle in 0-100 units. */\ninterface Rect100 {\n\tleft: number;\n\ttop: number;\n\tright: number;\n\tbottom: number;\n}\n\n/**\n * The inner target rectangle that gradient position 0 (the innermost stop)\n * maps to. `a:fillToRect` defines a whole sub-rectangle here, not a point:\n * PowerPoint paints its own position-0 colour flat across that entire\n * rectangle, and only ramps the gradient in the \"frame\" between it and the\n * shape's outer bounding box. A focal point translates this rectangle as a\n * rigid whole (its size is unaffected), matching `computeGradientCenter` in\n * `fill-style.ts`'s treatment of a focal point as a centre-blend (kept as a\n * private duplicate rather than an import - see the module doc).\n *\n * With no `fillToRect` there is no authored target rectangle to shrink to, so\n * this collapses to a single point (the resolved centre), matching this\n * module's previous point-based behaviour for that case.\n */\nfunction resolveInnerRect(\n\tfillToRect: RectPathGradientFillToRect | undefined,\n\tfocalPoint: RectPathGradientFocalPoint | undefined,\n): Rect100 {\n\tlet centerX = 50;\n\tlet centerY = 50;\n\tlet width = 0;\n\tlet height = 0;\n\n\tif (fillToRect) {\n\t\tconst { l, t, r, b } = fillToRect;\n\t\tcenterX = ((l + (1 - r)) / 2) * 100;\n\t\tcenterY = ((t + (1 - b)) / 2) * 100;\n\t\twidth = Math.max(0, Math.min(1, 1 - l - r)) * 100;\n\t\theight = Math.max(0, Math.min(1, 1 - t - b)) * 100;\n\t\tif (focalPoint) {\n\t\t\tcenterX = (centerX + focalPoint.x * 100) / 2;\n\t\t\tcenterY = (centerY + focalPoint.y * 100) / 2;\n\t\t}\n\t} else if (focalPoint) {\n\t\tcenterX = focalPoint.x * 100;\n\t\tcenterY = focalPoint.y * 100;\n\t}\n\n\treturn {\n\t\tleft: centerX - width / 2,\n\t\ttop: centerY - height / 2,\n\t\tright: centerX + width / 2,\n\t\tbottom: centerY + height / 2,\n\t};\n}\n\n/** Linear interpolation from `inner` (t=0) to the shape's own box (t=1). */\nfunction lerpEdge(inner: number, outer: number, t: number): number {\n\treturn inner + (outer - inner) * t;\n}\n\n/**\n * Builds the raw SVG markup for the nested-rectangle band approximation, in a\n * normalised 0-100 viewBox. Exported mainly so tests can inspect the actual\n * bands drawn; {@link buildRectPathGradientImage} is the entry point\n * renderers should use.\n */\nexport function buildRectPathGradientSvg(\n\tstops: RectPathGradientStop[],\n\tfocalPoint?: RectPathGradientFocalPoint,\n\tfillToRect?: RectPathGradientFillToRect,\n): string {\n\tif (stops.length === 0) {\n\t\treturn '<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 100 100\"/>';\n\t}\n\tconst sorted = [...stops].sort((a, b) => a.position - b.position);\n\tconst inner = resolveInnerRect(fillToRect, focalPoint);\n\t// The outer band is always the shape's real bounding box: PowerPoint's\n\t// last gradient stop paints at the shape's actual edges all the way\n\t// around, not just at whichever corner happens to be farthest from an\n\t// off-centre focal point (the earlier version of this module reached only\n\t// the farthest edge, mirroring a CSS radial-gradient's sizing keywords -\n\t// closer to a circle/ellipse's behaviour than a rect path gradient's).\n\n\tconst rects: string[] = [];\n\t// Draw outer-to-inner (painter's algorithm: later/smaller bands land on\n\t// top). `t` is this band's own position along the gradient: 1 at the\n\t// shape's outer edge (drawn first), shrinking to 0 at the inner target\n\t// rectangle (drawn last).\n\tfor (let i = BAND_COUNT; i >= 0; i -= 1) {\n\t\tconst t = i / BAND_COUNT;\n\t\tconst { color, opacity } = colorAt(sorted, t * 100);\n\t\tconst left = lerpEdge(inner.left, 0, t);\n\t\tconst top = lerpEdge(inner.top, 0, t);\n\t\tconst right = lerpEdge(inner.right, 100, t);\n\t\tconst bottom = lerpEdge(inner.bottom, 100, t);\n\t\tconst opacityAttr = opacity < 1 ? ` fill-opacity=\"${Math.max(0, opacity).toFixed(3)}\"` : '';\n\t\trects.push(\n\t\t\t`<rect x=\"${left.toFixed(2)}\" y=\"${top.toFixed(2)}\" width=\"${(right - left).toFixed(2)}\" height=\"${(bottom - top).toFixed(2)}\" fill=\"${color}\"${opacityAttr}/>`,\n\t\t);\n\t}\n\treturn `<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 100 100\" preserveAspectRatio=\"none\">${rects.join('')}</svg>`;\n}\n\n/**\n * Builds the `background-image: url(...)` CSS value for a `path=\"rect\"`\n * gradient fill. Pair with `background-size: 100% 100%` and\n * `background-repeat: no-repeat` so the normalised markup stretches to the\n * element's real box (see `resolveComputedFill` in `fill-style.ts`).\n */\nexport function buildRectPathGradientImage(\n\tstops: RectPathGradientStop[],\n\tfocalPoint?: RectPathGradientFocalPoint,\n\tfillToRect?: RectPathGradientFillToRect,\n): string {\n\tconst markup = buildRectPathGradientSvg(stops, focalPoint, fillToRect);\n\treturn `url(\"data:image/svg+xml,${encodeURIComponent(markup)}\")`;\n}\n","/**\n * Pure paint-decision logic for per-sub-path geometry, shared by custom\n * geometry (`a:custGeom`) AND multi-sub-path preset shapes (`a:prstGeom`).\n *\n * Kept free of any view-layer concern (JSX, Vue/Angular templates, DOM) so it\n * is unit-testable in isolation; each binding's SVG emission is a thin ~10-line\n * mapping over its result. Originally lived only in the React package\n * (`viewer/utils/vector-subpath-paint.ts`), which meant Vue and Vanilla (and,\n * for preset shapes, every binding including React) had no way to honour a\n * sub-path's own `@fill`/`@stroke` flags: they flattened every sub-path into\n * one merged path with a single element-level fill, so a stroke-only sub-path\n * inside a filled shape (an open eye/mouth on `smileyFace`) or a shading\n * sub-path (`lighten`/`darken`, the bevel highlight on `actionButton*`) either\n * rendered filled-and-distorted or vanished outright.\n *\n * Both geometry kinds evaluate to the exact same per-sub-path shape -\n * `{ d, fillMode, stroke }` - which is what lets ONE function\n * ({@link buildSubpathPaints}) paint either: `customGeometryPathsToSvgSubpaths`\n * (core) already returns that shape for custom geometry, and preset geometry's\n * `PresetSubpathResult` (`{ d, fill, stroke }`, from core's\n * `evaluatePresetShape`) is a one-line rename away - see\n * `./subpath-fill-overlay`, which resolves *which* elements need this\n * treatment and calls this to build the actual paints.\n */\nimport type { CustomGeometrySubpathSvg } from 'pptx-viewer-core';\n\nimport { colorWithOpacity, hexToRgbChannels } from './fill-style';\n\n/** Clamp a channel to 0-255 and format as a 2-digit hex byte. */\nfunction toHexByte(value: number): string {\n\tconst clamped = Math.max(0, Math.min(255, Math.round(value)));\n\treturn clamped.toString(16).padStart(2, '0');\n}\n\n/**\n * Lighten (`towardsWhite`) or darken a hex colour by a unit fraction. Returns\n * the input unchanged when it is not a 6-digit hex.\n */\nfunction shiftHex(hex: string, factor: number, towardsWhite: boolean): string {\n\tconst channels = hexToRgbChannels(hex);\n\tif (!channels) {\n\t\treturn hex;\n\t}\n\tconst shift = (c: number): number => (towardsWhite ? c + (255 - c) * factor : c * (1 - factor));\n\treturn `#${toHexByte(shift(channels.r))}${toHexByte(shift(channels.g))}${toHexByte(shift(channels.b))}`;\n}\n\n/**\n * Adjust a fill colour for an OOXML `@fill` mode (`a:path/@fill` on a custom\n * geometry sub-path, or the equivalent flag on a preset sub-path). `norm` /\n * `undefined` return the colour unchanged; `lighten` / `lightenLess` blend\n * towards white and `darken` / `darkenLess` towards black (the `*Less`\n * variants half as strongly). `none` is handled by the caller (no fill\n * emitted) and returns the input here.\n */\nexport function adjustFillForMode(\n\tfillHex: string,\n\tmode: CustomGeometrySubpathSvg['fillMode'],\n): string {\n\tswitch (mode) {\n\t\tcase 'lighten':\n\t\t\treturn shiftHex(fillHex, 0.4, true);\n\t\tcase 'lightenLess':\n\t\t\treturn shiftHex(fillHex, 0.2, true);\n\t\tcase 'darken':\n\t\t\treturn shiftHex(fillHex, 0.4, false);\n\t\tcase 'darkenLess':\n\t\t\treturn shiftHex(fillHex, 0.2, false);\n\t\tdefault:\n\t\t\treturn fillHex;\n\t}\n}\n\n/** Resolved paint intent for a single geometry sub-path. */\nexport interface SubpathPaint {\n\t/** SVG path data for this sub-path. */\n\td: string;\n\t/** Resolved fill paint, or `'none'` when this sub-path opts out of fill. */\n\tfill: string;\n\t/** Whether this sub-path draws its stroke (`@stroke` !== 0). */\n\tstroked: boolean;\n}\n\n/**\n * Resolve each sub-path's fill/stroke intent from its `@fill`/`@stroke` flags.\n *\n * A sub-path fills only when the shape has a fill *and* its own mode is not\n * `none`; the fill colour is adjusted per the sub-path's mode. Stroke is drawn\n * unless the sub-path sets `@stroke=\"0\"` (`stroke === false`).\n *\n * Shared between custom geometry and multi-sub-path preset shapes; the caller\n * adapts whichever core evaluator result it has into the common\n * `{ d, fillMode, stroke }` shape first (see `./subpath-fill-overlay`).\n */\nexport function buildSubpathPaints(\n\tsubpaths: CustomGeometrySubpathSvg[],\n\thasFill: boolean,\n\tfillColor: string,\n\tfillOpacity: number | undefined,\n): SubpathPaint[] {\n\treturn subpaths.map((subpath) => {\n\t\tconst fillOff = subpath.fillMode === 'none' || !hasFill;\n\t\treturn {\n\t\t\td: subpath.d,\n\t\t\tfill: fillOff\n\t\t\t\t? 'none'\n\t\t\t\t: colorWithOpacity(adjustFillForMode(fillColor, subpath.fillMode), fillOpacity),\n\t\t\tstroked: subpath.stroke !== false,\n\t\t};\n\t});\n}\n","/**\n * Per-sub-path FILL overlay: the shared mechanism behind two structurally\n * identical bugs.\n *\n * Both custom geometry (`a:custGeom`) and preset geometry (`a:prstGeom`) can\n * carry several sub-paths, each with its own `@fill` mode\n * (`norm`/`lighten`/`lightenLess`/`darken`/`darkenLess`/`none`) and `@stroke`\n * flag. Every binding paints a shape as ONE box: a single CSS\n * `background-color` clipped to a single merged `clip-path` built by\n * concatenating every sub-path's `d` together (`getResolvedShapeClipPath`,\n * `buildCustomGeometryClipPath`). That merge is lossy two ways:\n *\n * - It discards each sub-path's own `@fill`, so a preset's shading/bevel\n * sub-paths (`lighten`/`darken`, e.g. every `actionButton*`, curved arrows,\n * `bevel`, `foldedCorner`) paint as flat instead of shaded, and a `fill=\"none\"`\n * sub-path (`smileyFace`'s eyes/mouth) paints FILLED instead of as an open\n * stroke - because `clip-path` auto-closes every sub-path.\n * - It cannot vary the fill AT ALL across sub-paths, so it is architecturally\n * incapable of the above regardless of which colour is chosen.\n *\n * The fix is the same for both: paint the affected element as layered SVG\n * `<path>`s, each carrying its own resolved fill, instead of one CSS box. This\n * module decides WHICH elements need that (an element needs it only when at\n * least one sub-path's mode is not `norm`/unset, or it opts out of its stroke)\n * and builds the paints via the shared `./vector-subpath-paint`; a binding's\n * `ShapeEffectOverlay` renders the result as an `<svg>` sibling to the shape\n * box (mirroring `buildStrokeOutline`), and `getComputedFillStyle`\n * ({@link suppressesCssFill}) drops the CSS background so the flat colour does\n * not show underneath.\n *\n * Restricted to a solid (or absent) fill: a gradient/pattern/image fill keeps\n * the existing single merged clip-path box, since neither geometry kind's\n * sub-paths can carry an independent paint SERVER (only a solid, mode-shifted\n * colour), and the common case for both bug classes - shading/bevel highlights,\n * `smileyFace`'s eyes - is a solid theme colour.\n */\nimport type {\n\tCustomGeometryPath,\n\tCustomGeometryRawData,\n\tCustomGeometrySubpathSvg,\n\tPptxElement,\n} from 'pptx-viewer-core';\nimport {\n\tcustomGeometryPathsToSvgSubpaths,\n\tevaluateCustomGeometryPaths,\n\tevaluatePresetShape,\n\thasShapeProperties,\n} from 'pptx-viewer-core';\n\nimport { DEFAULT_FILL_COLOR } from '../constants';\nimport type { SubpathPaint } from './vector-subpath-paint';\nimport { buildSubpathPaints } from './vector-subpath-paint';\n\n/**\n * The box a preset is evaluated at: the element's authored extent, floored at\n * zero. Matches `getContainerStyle`'s `paintedElementSize` (not imported\n * directly, to avoid a `fill-style.ts` <-> `element-style.ts` <->\n * `subpath-fill-overlay.ts` import cycle: `fill-style.ts` consumes\n * {@link suppressesCssFill} and `element-style.ts` consumes `fill-style.ts`).\n * This used to pad out to `MIN_ELEMENT_SIZE`, which stretched a degenerate\n * shape's per-sub-path fill overlay past its authored extent in read-only\n * rendering (issue #285); any interaction-only padding now lives solely in\n * `elementHitTargetStyle`, which never touches paint.\n */\nfunction paintedSize(element: PptxElement): { width: number; height: number } {\n\treturn {\n\t\twidth: Math.max(element.width, 0),\n\t\theight: Math.max(element.height, 0),\n\t};\n}\n\n/** Everything a binding needs to paint an element's per-sub-path fill overlay. */\nexport interface SubpathFillOverlay {\n\t/** One paint per sub-path, in authoring order. */\n\treadonly paints: readonly SubpathPaint[];\n\t/** `viewBox` width, in the same coordinate space as every `paints[].d`. */\n\treadonly viewBoxWidth: number;\n\t/** `viewBox` height, in the same coordinate space as every `paints[].d`. */\n\treadonly viewBoxHeight: number;\n}\n\n/**\n * Whether any sub-path needs individual paint handling: a non-`norm` fill mode\n * or an explicit stroke opt-out. Mirrors the threshold the React custom-geometry\n * renderer already used, now shared with preset geometry too. A shape whose\n * sub-paths are all plain (unset/`norm` fill, stroked) renders identically\n * either way, so declining here keeps ordinary shapes on the cheaper CSS path.\n */\nfunction needsPerSubpathPaint(subpaths: readonly CustomGeometrySubpathSvg[]): boolean {\n\treturn subpaths.some(\n\t\t(sp) => (sp.fillMode !== undefined && sp.fillMode !== 'norm') || sp.stroke === false,\n\t);\n}\n\n/** The custom-geometry / preset slots read off an element. */\ninterface SubpathCapableElement {\n\tpathData?: string;\n\tpathWidth?: number;\n\tpathHeight?: number;\n\tcustomGeometryPaths?: CustomGeometryPath[];\n\tcustomGeometryRawData?: CustomGeometryRawData;\n\tshapeType?: string;\n\tshapeAdjustments?: Record<string, number>;\n}\n\n/** Resolved per-sub-path geometry needing individual paint, or `undefined`. */\ninterface SubpathGeometry {\n\tsubpaths: CustomGeometrySubpathSvg[];\n\twidth: number;\n\theight: number;\n}\n\n/** Sub-path-capable element types: `PptxCustomPathProperties` lives only on these. */\nfunction asSubpathCapable(element: PptxElement): SubpathCapableElement | undefined {\n\tif (element.type === 'shape' || element.type === 'image' || element.type === 'picture') {\n\t\treturn element;\n\t}\n\treturn undefined;\n}\n\n/**\n * Resolve an element's per-sub-path geometry when, and only when, it genuinely\n * needs individual paint handling - custom geometry with structured sub-paths,\n * or a preset whose evaluated sub-paths vary. Returns `undefined` for every\n * ordinary shape so callers keep their existing single merged fill/clip.\n */\nfunction getSubpathGeometry(element: PptxElement): SubpathGeometry | undefined {\n\tconst slots = asSubpathCapable(element);\n\tif (!slots) {\n\t\treturn undefined;\n\t}\n\n\t// Custom geometry: only the STRUCTURED sub-paths (from `a:custGeom/a:pathLst`)\n\t// carry per-sub-path `@fill`/`@stroke`; a freeform with only aggregate\n\t// `pathData` (no structured paths) has no per-sub-path intent to honour.\n\tif (slots.pathData && slots.pathWidth && slots.pathHeight) {\n\t\t// Live-evaluate the raw `a:pathLst` against the current adjust values so a\n\t\t// mid-drag `a:ahXY`/`a:ahPolar` reshape moves the per-sub-path overlay\n\t\t// with the clip path; falls back to the parse-time paths when the raw\n\t\t// XML is missing (older data) or the guide list cannot be evaluated.\n\t\tconst structured =\n\t\t\tevaluateCustomGeometryPaths(\n\t\t\t\tslots.customGeometryRawData,\n\t\t\t\tslots.pathWidth,\n\t\t\t\tslots.pathHeight,\n\t\t\t\tslots.shapeAdjustments,\n\t\t\t) ?? slots.customGeometryPaths;\n\t\tif (!structured || structured.length === 0) {\n\t\t\treturn undefined;\n\t\t}\n\t\tconst subpaths = customGeometryPathsToSvgSubpaths(\n\t\t\tstructured,\n\t\t\tslots.pathWidth,\n\t\t\tslots.pathHeight,\n\t\t);\n\t\treturn needsPerSubpathPaint(subpaths)\n\t\t\t? { subpaths, width: slots.pathWidth, height: slots.pathHeight }\n\t\t\t: undefined;\n\t}\n\n\t// Preset geometry: evaluate at the same PAINTED size the container box uses\n\t// (padded for degenerate shapes), so the overlay's viewBox lines up with it.\n\tif (!slots.shapeType) {\n\t\treturn undefined;\n\t}\n\tconst { width, height } = paintedSize(element);\n\tconst result = evaluatePresetShape(slots.shapeType, width, height, slots.shapeAdjustments);\n\t// `fillNone` (every sub-path opts out of fill, e.g. `arc`) is an OPEN preset:\n\t// `./stroke-only-preset` already routes it through the stroke overlay with no\n\t// fill at all, so it must not also be treated as a multi-sub-path FILL here.\n\tif (!result || result.fillNone || result.paths.length === 0) {\n\t\treturn undefined;\n\t}\n\tconst subpaths: CustomGeometrySubpathSvg[] = result.paths.map((p) => ({\n\t\td: p.d,\n\t\tfillMode: p.fill as CustomGeometrySubpathSvg['fillMode'],\n\t\tstroke: p.stroke,\n\t}));\n\treturn needsPerSubpathPaint(subpaths) ? { subpaths, width, height } : undefined;\n}\n\n/**\n * Whether an element's fill mode is one this overlay can reproduce (a solid\n * colour or none at all). A gradient/pattern/image fill keeps the existing\n * single merged clip-path box, since a sub-path can only carry a solid,\n * mode-shifted colour.\n */\nfunction hasReproducibleFillMode(element: PptxElement): boolean {\n\tif (!hasShapeProperties(element)) {\n\t\treturn false;\n\t}\n\tconst mode = element.shapeStyle?.fillMode;\n\treturn mode === undefined || mode === 'solid' || mode === 'none';\n}\n\n/**\n * Whether a binding must drop its CSS `background-color` / `background-image`\n * for this element because {@link buildSubpathFillOverlay} is painting the\n * fill instead. Mirrors `suppressesCssBorder`'s role for the stroke overlay;\n * consumed by shared `getComputedFillStyle`.\n */\nexport function suppressesCssFill(element: PptxElement): boolean {\n\treturn hasReproducibleFillMode(element) && getSubpathGeometry(element) !== undefined;\n}\n\n/**\n * Build the per-sub-path fill overlay for an element, or `undefined` when a\n * single merged fill/clip-path is correct (the ordinary case).\n */\nexport function buildSubpathFillOverlay(element: PptxElement): SubpathFillOverlay | undefined {\n\tif (!hasReproducibleFillMode(element)) {\n\t\treturn undefined;\n\t}\n\tconst geometry = getSubpathGeometry(element);\n\tif (!geometry) {\n\t\treturn undefined;\n\t}\n\tconst ss = hasShapeProperties(element) ? element.shapeStyle : undefined;\n\tconst hasFill =\n\t\tBoolean(ss?.fillColor) && ss?.fillColor !== 'transparent' && ss?.fillMode !== 'none';\n\tconst fillColor = ss?.fillColor ?? DEFAULT_FILL_COLOR;\n\treturn {\n\t\tpaints: buildSubpathPaints(geometry.subpaths, hasFill, fillColor, ss?.fillOpacity),\n\t\tviewBoxWidth: geometry.width,\n\t\tviewBoxHeight: geometry.height,\n\t};\n}\n","/**\n * Framework-agnostic fill resolver for the Vue viewer.\n *\n * Ports the rich structured gradient and pattern-fill logic from the React\n * package (`viewer/utils/color-gradient.ts`, `color-patterns.ts`,\n * `color-core.ts`) into a pure, unit-testable TypeScript module. It converts\n * structured OOXML gradient and pattern-fill data on a `ShapeStyle` into CSS\n * background declarations.\n *\n * Three public entry points:\n * - {@link buildGradientCss} — structured gradient → CSS gradient string\n * - {@link buildPatternFill} — OOXML preset pattern → CSS background image\n * - {@link getComputedFillStyle} — aggregate resolver (image → gradient →\n * pattern → solid), mirroring the React\n * `getShapeVisualStyle` fill ordering.\n *\n * Gradient rendering follows ECMA-376 Part 1, §20.1.8.35 (gradFill) and\n * §20.1.8.49 (pathFill). Pattern presets follow §20.1.10.33\n * (ST_PresetPatternVal).\n */\nimport type { PptxElement, PptxThemeColorRef, ShapeStyle } from 'pptx-viewer-core';\nimport { hasShapeProperties, ooxmlGradientAngleToCssDegrees } from 'pptx-viewer-core';\nimport { clampUnitInterval, colorWithOpacity, normalizeHexColor } from 'pptx-viewer-core/color';\n\nimport { DEFAULT_FILL_COLOR } from '../constants';\nimport { buildRectPathGradientImage } from './path-gradient-rect';\nimport { suppressesCssFill } from './subpath-fill-overlay';\n\nexport {\n\tclampUnitInterval,\n\tcolorWithOpacity,\n\thexToRgbChannels,\n\tnormalizeHexColor,\n} from 'pptx-viewer-core/color';\n\n/**\n * Clamps an image crop value (fractional, roughly -1..1) to a safe magnitude\n * while preserving sign. Returns 0 for non-finite or missing values, and caps\n * the magnitude at 0.95 to prevent the image from being fully cropped away.\n *\n * A negative value is a legitimate `a:srcRect` outward crop (PowerPoint pads\n * the image inside its frame rather than cropping it, e.g. a photo smaller\n * than its placeholder), so the sign must survive here the same way it does\n * for the sibling `a:fillRect` insets (issue #132); dropping it via\n * `Math.max(0, ...)` silently turned every negative inset into \"no crop\".\n */\nexport function clampCropValue(value: number | undefined): number {\n\tif (typeof value !== 'number' || !Number.isFinite(value)) {\n\t\treturn 0;\n\t}\n\tconst magnitude = Math.min(0.95, Math.abs(value));\n\treturn value < 0 ? -magnitude : magnitude;\n}\n\n/**\n * Creates a detached copy of a `Uint8Array` as an `ArrayBuffer`. Useful for\n * transferring binary data without shared-memory side-effects.\n */\nexport function createArrayBufferCopy(bytes: Uint8Array): ArrayBuffer {\n\tconst copy = new Uint8Array(bytes.byteLength);\n\tcopy.set(bytes);\n\treturn copy.buffer;\n}\n\n// ---------------------------------------------------------------------------\n// Gradient stop sanitization & conversion (from React `color-gradient.ts`)\n// ---------------------------------------------------------------------------\n\ntype GradientStop = NonNullable<ShapeStyle['fillGradientStops']>[number];\n/**\n * `colorRef` carries the stop's theme identity through sanitisation (see\n * {@link ShapeStyle.fillGradientStops}'s own `colorRef` field) so a gradient\n * stop picker can highlight the matching theme swatch and a theme swap can\n * re-resolve the stop, same as the shape's own {@link ShapeStyle.fillColorRef}.\n */\ntype SanitizedStop = {\n\tcolor: string;\n\tposition: number;\n\topacity?: number;\n\tcolorRef?: PptxThemeColorRef;\n};\n\n/**\n * Validates, normalizes, and sorts an array of gradient stops. Filters out\n * invalid entries (missing color/position), clamps positions to 0-100,\n * normalizes colours, and sorts by ascending position.\n */\nexport function sanitizeGradientStops(\n\tstops: ShapeStyle['fillGradientStops'] | undefined,\n): SanitizedStop[] {\n\tif (!stops || stops.length === 0) {\n\t\treturn [];\n\t}\n\treturn stops\n\t\t.filter(\n\t\t\t(stop: GradientStop) =>\n\t\t\t\ttypeof stop?.color === 'string' &&\n\t\t\t\tString(stop.color).trim().length > 0 &&\n\t\t\t\ttypeof stop?.position === 'number' &&\n\t\t\t\tNumber.isFinite(stop.position),\n\t\t)\n\t\t.map((stop: GradientStop) => ({\n\t\t\tcolor: normalizeHexColor(String(stop.color), DEFAULT_FILL_COLOR),\n\t\t\tposition: Math.max(0, Math.min(100, stop.position)),\n\t\t\topacity:\n\t\t\t\ttypeof stop.opacity === 'number' && Number.isFinite(stop.opacity)\n\t\t\t\t\t? clampUnitInterval(stop.opacity)\n\t\t\t\t\t: undefined,\n\t\t\tcolorRef: stop.colorRef,\n\t\t}))\n\t\t.sort((left, right) => left.position - right.position);\n}\n\n/**\n * Converts an OOXML gradient angle to the equivalent CSS `linear-gradient()`\n * angle, normalised to [0, 360).\n *\n * `a:lin/@ang` is measured clockwise from the positive x-axis (`ang=\"0\"` runs\n * left to right) whereas CSS measures clockwise from \"to top\" (`0deg` runs\n * bottom to top), so the two sit a quarter turn apart. Feeding an OOXML angle\n * straight into a CSS gradient renders the fill rotated 90 degrees.\n *\n * The parser stores `ShapeStyle.fillGradientAngle` in plain OOXML degrees; when\n * `alreadyDegrees` is false the input is treated as raw 60000ths of a degree.\n */\nexport function convertOoxmlAngleToCss(ooxmlAngle: number, alreadyDegrees = true): number {\n\tconst deg = alreadyDegrees ? ooxmlAngle : ooxmlAngle / 60000;\n\treturn ooxmlGradientAngleToCssDegrees(deg);\n}\n\n/**\n * Converts a single gradient stop to a CSS gradient color-stop string,\n * applying opacity via `rgba()` when present.\n */\nexport function toCssGradientStop(stop: SanitizedStop): string {\n\tconst color =\n\t\ttypeof stop.opacity === 'number' ? colorWithOpacity(stop.color, stop.opacity) : stop.color;\n\tconst pos = Math.max(0, Math.min(100, stop.position));\n\tconst posStr = pos === Math.round(pos) ? `${pos}%` : `${pos.toFixed(1)}%`;\n\treturn `${color} ${posStr}`;\n}\n\n/**\n * Computes the gradient center (as percentages) from a fillToRect and an\n * optional focalPoint offset.\n *\n * The fillToRect defines an inner rectangle; the gradient center defaults to\n * the center of that rectangle. When a focalPoint is also provided, it offsets\n * the center within the fillToRect bounds (averaged to avoid extreme shifts).\n */\nexport function computeGradientCenter(\n\tfillToRect?: ShapeStyle['fillGradientFillToRect'],\n\tfocalPoint?: ShapeStyle['fillGradientFocalPoint'],\n): { cx: number; cy: number } {\n\tif (fillToRect) {\n\t\tconst { l, t, r, b } = fillToRect;\n\t\tlet cx = ((l + (1 - r)) / 2) * 100;\n\t\tlet cy = ((t + (1 - b)) / 2) * 100;\n\t\tif (focalPoint) {\n\t\t\tconst fpX = focalPoint.x * 100;\n\t\t\tconst fpY = focalPoint.y * 100;\n\t\t\tcx = (cx + fpX) / 2;\n\t\t\tcy = (cy + fpY) / 2;\n\t\t}\n\t\treturn { cx, cy };\n\t}\n\tif (focalPoint) {\n\t\treturn { cx: focalPoint.x * 100, cy: focalPoint.y * 100 };\n\t}\n\treturn { cx: 50, cy: 50 };\n}\n\n/**\n * Builds a CSS radial-gradient for `path=\"circle\"` gradients.\n *\n * The explicit-size form is written as `ellipse R% R%`, never `circle R%`: CSS\n * only accepts a **length** as a circle's radius, so `radial-gradient(circle\n * 100% at 0% 0%, …)` is invalid and the browser drops the entire declaration -\n * the shape then renders with no fill at all. `ellipse R% R%` is also the more\n * faithful reading: OOXML measures a path gradient in the shape's own unit\n * square, so a \"circle\" is stretched to a non-square box exactly the way\n * percentage semi-axes are (identical to a circle when the shape is square).\n */\nexport function buildCirclePathGradient(\n\tstops: SanitizedStop[],\n\tfocalPoint?: ShapeStyle['fillGradientFocalPoint'],\n\tfillToRect?: ShapeStyle['fillGradientFillToRect'],\n): string {\n\tconst stopStr = stops.map(toCssGradientStop).join(', ');\n\tconst { cx, cy } = computeGradientCenter(fillToRect, focalPoint);\n\n\tconst posX =\n\t\tMath.round(cx) === 50 && !focalPoint && !fillToRect ? 'center' : `${Math.round(cx)}%`;\n\tconst posY =\n\t\tMath.round(cy) === 50 && !focalPoint && !fillToRect ? 'center' : `${Math.round(cy)}%`;\n\n\tif (fillToRect) {\n\t\tconst radius = Math.round(Math.max(cx, 100 - cx, cy, 100 - cy));\n\t\treturn `radial-gradient(ellipse ${radius}% ${radius}% at ${posX} ${posY}, ${stopStr})`;\n\t}\n\treturn `radial-gradient(circle at ${posX} ${posY}, ${stopStr})`;\n}\n\n/**\n * Builds the CSS `background-image` value for `path=\"rect\"` gradients.\n *\n * PowerPoint shades a rect path gradient toward the shape's own bounding\n * rectangle: its isolines are concentric rectangles with square corners (a\n * Chebyshev distance field), not circles or ellipses. SVG/CSS have no native\n * \"rectangular radial gradient\" primitive, so this renders the true field\n * directly as a small stack of nested `<rect>` bands inside a self-contained\n * SVG data URI (see `path-gradient-rect.ts` for the full reasoning), rather\n * than approximating it as a single ellipse. Pair the result with\n * `background-size: 100% 100%` and `background-repeat: no-repeat` so the\n * normalised markup stretches to the shape's real box (done for callers by\n * `resolveComputedFill` below).\n */\nexport function buildRectPathGradient(\n\tstops: SanitizedStop[],\n\tfocalPoint?: ShapeStyle['fillGradientFocalPoint'],\n\tfillToRect?: ShapeStyle['fillGradientFillToRect'],\n): string {\n\treturn buildRectPathGradientImage(stops, focalPoint, fillToRect);\n}\n\n/** Builds a CSS gradient approximation for `path=\"shape\"` gradients. */\nexport function buildShapePathGradient(\n\tstops: SanitizedStop[],\n\tfocalPoint?: ShapeStyle['fillGradientFocalPoint'],\n\tfillToRect?: ShapeStyle['fillGradientFillToRect'],\n): string {\n\tconst stopStr = stops.map(toCssGradientStop).join(', ');\n\n\tif (fillToRect) {\n\t\tconst { l, t, r, b } = fillToRect;\n\t\tconst { cx, cy } = computeGradientCenter(fillToRect, focalPoint);\n\n\t\tconst posX = `${Math.round(cx)}%`;\n\t\tconst posY = `${Math.round(cy)}%`;\n\t\tconst semiX = Math.max(cx, 100 - cx);\n\t\tconst semiY = Math.max(cy, 100 - cy);\n\n\t\tconst innerHalfW = ((1 - l - r) / 2) * 100;\n\t\tconst innerHalfH = ((1 - t - b) / 2) * 100;\n\n\t\tif (innerHalfW > 0.5 && innerHalfH > 0.5 && Math.abs(innerHalfW - innerHalfH) > 1) {\n\t\t\tconst aspect = innerHalfW / innerHalfH;\n\t\t\tconst adjustedSemiX = Math.round(Math.max(semiX, semiY * aspect));\n\t\t\tconst adjustedSemiY = Math.round(Math.max(semiY, semiX / aspect));\n\t\t\treturn `radial-gradient(${adjustedSemiX}% ${adjustedSemiY}% at ${posX} ${posY}, ${stopStr})`;\n\t\t}\n\t\tif (semiX > 0.5 || semiY > 0.5) {\n\t\t\treturn `radial-gradient(${Math.round(semiX)}% ${Math.round(semiY)}% at ${posX} ${posY}, ${stopStr})`;\n\t\t}\n\t\treturn `radial-gradient(farthest-side at ${posX} ${posY}, ${stopStr})`;\n\t}\n\n\tconst { cx, cy } = computeGradientCenter(undefined, focalPoint);\n\tconst posX = focalPoint ? `${Math.round(cx)}%` : 'center';\n\tconst posY = focalPoint ? `${Math.round(cy)}%` : 'center';\n\treturn `radial-gradient(farthest-side at ${posX} ${posY}, ${stopStr})`;\n}\n\n// ---------------------------------------------------------------------------\n// Gradient tile/flip mode (from React `color-gradient.ts`)\n// ---------------------------------------------------------------------------\n\n/**\n * OOXML gradient tile-flip mode from `a:gradFill/@flip`\n * (`ShapeStyle['fillGradientFlip']`). Controls how the gradient tile is\n * mirrored when tiled:\n * - `\"none\"` — clamp: gradient stops at 0% and 100%, no repeat.\n * - `\"x\"` — flip horizontally on each tile.\n * - `\"y\"` — flip vertically on each tile.\n * - `\"xy\"` — flip both axes on each tile.\n */\nexport type GradientTileFlipMode = NonNullable<ShapeStyle['fillGradientFlip']>;\n\n/**\n * Builds a CSS `background-size` + `background-repeat` pair that approximates\n * gradient tiling with flip. Standard CSS does not natively support gradient\n * flipping, so we approximate it by halving the background-size on the flipped\n * axis and repeating; the gradient itself is built with reflected stops (see\n * {@link buildReflectedGradientStops}).\n *\n * @param mode - The OOXML tile-flip mode.\n * @returns CSS properties to apply, or `undefined` if no tiling is needed.\n */\nexport function getGradientTileFlipCss(\n\tmode: GradientTileFlipMode | undefined,\n): { backgroundSize?: string; backgroundRepeat?: string } | undefined {\n\tif (!mode || mode === 'none') {\n\t\treturn undefined;\n\t}\n\n\tswitch (mode) {\n\t\tcase 'x':\n\t\t\treturn { backgroundSize: '50% 100%', backgroundRepeat: 'repeat-x' };\n\t\tcase 'y':\n\t\t\treturn { backgroundSize: '100% 50%', backgroundRepeat: 'repeat-y' };\n\t\tcase 'xy':\n\t\t\treturn { backgroundSize: '50% 50%', backgroundRepeat: 'repeat' };\n\t\tdefault:\n\t\t\treturn undefined;\n\t}\n}\n\n/**\n * Builds the `background-size` / `background-position` / `background-repeat`\n * that confine a gradient to the rectangle described by `a:gradFill/a:tileRect`.\n *\n * `tileRect` LTRB values are 0..1 insets from each edge, so the tile covers\n * `(1 - l - r)` x `(1 - t - b)` of the shape, offset by `l`/`t`. Returns\n * `undefined` when the rect is missing, degenerate, or effectively full-bleed\n * (no meaningful inset), so callers fall through to the plain gradient.\n *\n * Insets may be NEGATIVE, which makes the tile LARGER than the shape: PowerPoint's\n * stock \"radial gradient from a corner\" preset writes\n * `<a:tileRect l=\"-100000\" t=\"-100000\"/>` so the gradient's focal corner sits a\n * full shape-width outside the box. The percentage-position formula already\n * covers that case (a CSS background position of `100%` pins an oversized\n * image's right/bottom edge to the container's), so the guard tests the\n * MAGNITUDE of `1 - size`: an early `> 0.001` comparison was false for every\n * oversized tile and silently dropped the offset, dragging the focal point back\n * to the shape's own corner and painting a hard blob where PowerPoint renders a\n * soft wash.\n */\nexport function getGradientTileRectCss(\n\ttileRect: ShapeStyle['fillGradientTileRect'] | undefined,\n): { backgroundSize: string; backgroundPosition: string; backgroundRepeat: string } | undefined {\n\tif (!tileRect) {\n\t\treturn undefined;\n\t}\n\tconst { l, t, r, b } = tileRect;\n\tconst sizeW = 1 - l - r;\n\tconst sizeH = 1 - t - b;\n\tif (sizeW <= 0 || sizeH <= 0) {\n\t\treturn undefined;\n\t}\n\tif (Math.abs(sizeW - 1) < 0.001 && Math.abs(sizeH - 1) < 0.001) {\n\t\treturn undefined;\n\t}\n\tconst posX = Math.abs(1 - sizeW) > 0.001 ? (l / (1 - sizeW)) * 100 : 0;\n\tconst posY = Math.abs(1 - sizeH) > 0.001 ? (t / (1 - sizeH)) * 100 : 0;\n\treturn {\n\t\tbackgroundSize: `${Math.round(sizeW * 100)}% ${Math.round(sizeH * 100)}%`,\n\t\tbackgroundPosition: `${Math.round(posX)}% ${Math.round(posY)}%`,\n\t\tbackgroundRepeat: 'no-repeat',\n\t};\n}\n\n/**\n * Creates a reflected (mirrored) copy of gradient stops for tile-flip\n * rendering. The original stops run 0->100; the result packs one full\n * forward-backward cycle into 0-100: a forward pass mapped to 0-50 and a\n * mirrored pass mapped to 50-100. Combined with a halved `background-size`\n * (see {@link getGradientTileFlipCss}) this approximates OOXML tile-flip.\n *\n * @param stops - Original sanitized gradient stops (positions 0-100).\n * @returns A new stop array covering 0-100 with forward + mirrored stops.\n */\nexport function buildReflectedGradientStops(stops: SanitizedStop[]): SanitizedStop[] {\n\tif (stops.length === 0) {\n\t\treturn [];\n\t}\n\n\t// Forward pass: map positions from 0-100 to 0-50.\n\tconst forward = stops.map((s) => ({\n\t\t...s,\n\t\tposition: s.position / 2,\n\t}));\n\n\t// Reverse pass: map positions from 0-100 to 100-50 (mirrored).\n\tconst reversed = [...stops].reverse().map((s) => ({\n\t\t...s,\n\t\tposition: 50 + (100 - s.position) / 2,\n\t}));\n\n\treturn [...forward, ...reversed];\n}\n\n/**\n * Optional geometry context for {@link buildGradientCss}. Supplying it lets the\n * resolver apply the two OOXML linear-gradient attributes that depend on the\n * owning shape:\n * - `a:lin/@scaled` (default true): the angle is measured in the shape's unit\n * square then stretched to the box, so the visual angle depends on the\n * width/height aspect ratio.\n * - `a:gradFill/@rotWithShape=false`: the gradient must stay fixed to the page\n * frame, so it is counter-rotated by the element's own rotation.\n */\nexport interface GradientRenderContext {\n\t/** Element rotation in degrees (`PptxElementBase.rotation`). */\n\trotation?: number;\n\t/** Element width in px. */\n\twidth?: number;\n\t/** Element height in px. */\n\theight?: number;\n}\n\n/** Normalise a degree value into the [0, 360) range. */\nfunction normalizeDegrees(deg: number): number {\n\treturn ((deg % 360) + 360) % 360;\n}\n\n/**\n * Apply `a:lin/@scaled` (aspect-ratio) and `a:gradFill/@rotWithShape`\n * corrections to a linear-gradient angle. A no-op when no geometry context is\n * supplied or neither attribute is in force, so callers that pass only a style\n * keep the raw authored angle.\n */\nfunction adjustLinearGradientAngle(\n\tangle: number,\n\tgradient: ShapeStyle,\n\tcontext: GradientRenderContext | undefined,\n): number {\n\tif (!context) {\n\t\treturn angle;\n\t}\n\tlet result = angle;\n\tconst { width, height, rotation } = context;\n\tif (\n\t\tgradient.fillGradientScaled !== false &&\n\t\ttypeof width === 'number' &&\n\t\ttypeof height === 'number' &&\n\t\twidth > 0 &&\n\t\theight > 0 &&\n\t\twidth !== height\n\t) {\n\t\tconst rad = (result * Math.PI) / 180;\n\t\tresult = normalizeDegrees(\n\t\t\t(Math.atan2(height * Math.sin(rad), width * Math.cos(rad)) * 180) / Math.PI,\n\t\t);\n\t}\n\tif (gradient.fillGradientRotWithShape === false && typeof rotation === 'number') {\n\t\tresult = normalizeDegrees(result - rotation);\n\t}\n\treturn result;\n}\n\n/**\n * Converts a structured OOXML gradient on a `ShapeStyle` to a CSS\n * `linear-gradient(...)` / `radial-gradient(...)` string.\n *\n * Falls back to the prebuilt `style.fillGradient` string when no structured\n * stops are present, and returns `undefined` when there is no gradient fill.\n *\n * When `fillGradientFlip` is `x`/`y`/`xy` the linear gradient is built from\n * reflected stops so that, tiled via the matching {@link getGradientTileFlipCss}\n * `background-size`/`background-repeat`, it mirrors per tile the way OOXML\n * tile-flip does. Radial gradients are left unflipped (CSS cannot tile-mirror\n * a radial), matching the React port.\n *\n * @param gradient - The shape style carrying gradient configuration.\n * @param context - Optional element geometry enabling `@scaled` /\n * `@rotWithShape` angle corrections (linear only).\n * @returns A CSS gradient string, or `undefined`.\n */\nexport function buildGradientCss(\n\tgradient: ShapeStyle | undefined,\n\tcontext?: GradientRenderContext,\n): string | undefined {\n\tif (!gradient || gradient.fillMode !== 'gradient') {\n\t\treturn undefined;\n\t}\n\n\tconst stops = sanitizeGradientStops(gradient.fillGradientStops);\n\tif (stops.length === 0) {\n\t\treturn gradient.fillGradient;\n\t}\n\n\tconst gradientType = gradient.fillGradientType || 'linear';\n\tif (gradientType === 'radial') {\n\t\tconst pathType = gradient.fillGradientPathType || 'circle';\n\t\tconst fp = gradient.fillGradientFocalPoint;\n\t\tconst ftr = gradient.fillGradientFillToRect;\n\n\t\tif (pathType === 'rect') {\n\t\t\treturn buildRectPathGradient(stops, fp, ftr);\n\t\t}\n\t\tif (pathType === 'shape') {\n\t\t\treturn buildShapePathGradient(stops, fp, ftr);\n\t\t}\n\t\treturn buildCirclePathGradient(stops, fp, ftr);\n\t}\n\n\tconst normalizedAngle =\n\t\ttypeof gradient.fillGradientAngle === 'number' && Number.isFinite(gradient.fillGradientAngle)\n\t\t\t? gradient.fillGradientAngle\n\t\t\t: 90;\n\t// `@scaled` / `@rotWithShape` are corrections in OOXML angle space, so they\n\t// are applied first and the result converted to CSS degrees exactly once.\n\tconst effectiveAngle = convertOoxmlAngleToCss(\n\t\tadjustLinearGradientAngle(normalizedAngle, gradient, context),\n\t);\n\n\t// Tile-flip: reflect the stops so a single tile contains one mirrored\n\t// forward-backward cycle. The repeating/halved tiling is applied by the\n\t// caller via getGradientTileFlipCss (wired into getComputedFillStyle).\n\tconst flip = gradient.fillGradientFlip;\n\tconst linearStops = flip && flip !== 'none' ? buildReflectedGradientStops(stops) : stops;\n\n\treturn `linear-gradient(${Math.round(effectiveAngle)}deg, ${linearStops\n\t\t.map(toCssGradientStop)\n\t\t.join(', ')})`;\n}\n\n/**\n * Alias of {@link buildGradientCss} preserved for the per-binding gradient\n * modules (React/Angular `color-gradient.ts`) whose public symbol was named\n * `buildCssGradientFromShapeStyle`. Both bindings shim onto this name so their\n * existing consumers and colocated tests keep importing the same symbol.\n *\n * Note: unlike the original per-binding `buildCssGradientFromShapeStyle`, this\n * resolver also applies gradient tile-flip stop reflection for structured\n * linear gradients (see {@link buildGradientCss}); the matching halved/repeating\n * `background-size`/`background-repeat` is applied by {@link getComputedFillStyle}.\n */\nexport const buildCssGradientFromShapeStyle = buildGradientCss;\n\n// ---------------------------------------------------------------------------\n// Pattern fills (from React `color-patterns.ts`)\n// ---------------------------------------------------------------------------\n\n/** One tile of a preset pattern: its size plus the primitives that fill it. */\nexport interface PatternTile {\n\t/** Tile width in px. */\n\tw: number;\n\t/** Tile height in px. */\n\th: number;\n\t/** SVG primitives that paint the tile, with no wrapping element. */\n\tinner: string;\n}\n\n/**\n * Builds one tile of an OOXML preset pattern (ST_PresetPatternVal), painting a\n * foreground (`fg`) on a background (`bg`). Returns `null` for unknown presets.\n *\n * Kept separate from {@link getPatternSvg} because the tile is needed in two\n * different wrappers: a standalone `<svg>` document for the data-URI background\n * a CSS fill uses, and an SVG `<pattern>` paint server for a patterned OUTLINE,\n * which cannot go through `background-image` at all.\n *\n * Reference: ECMA-376 Part 1, §20.1.10.33.\n */\nexport function getPatternTile(preset: string, fg: string, bg: string): PatternTile | null {\n\tconst s = 8;\n\tconst svg = (w: number, h: number, inner: string): PatternTile => ({ w, h, inner });\n\tconst rect = (x: number, y: number, w: number, h: number, fill: string) =>\n\t\t`<rect x=\"${x}\" y=\"${y}\" width=\"${w}\" height=\"${h}\" fill=\"${fill}\"/>`;\n\tconst bgRect = (w: number, h: number) => rect(0, 0, w, h, bg);\n\tconst line = (\n\t\tx1: number,\n\t\ty1: number,\n\t\tx2: number,\n\t\ty2: number,\n\t\tstroke: string,\n\t\tsw: number,\n\t\textra = '',\n\t) =>\n\t\t`<line x1=\"${x1}\" y1=\"${y1}\" x2=\"${x2}\" y2=\"${y2}\" stroke=\"${stroke}\" stroke-width=\"${sw}\"${extra}/>`;\n\tconst circle = (cx: number, cy: number, r: number, fill: string) =>\n\t\t`<circle cx=\"${cx}\" cy=\"${cy}\" r=\"${r}\" fill=\"${fill}\"/>`;\n\n\tswitch (preset) {\n\t\t// ── Percentage fills ──────────────────────────────────────────────\n\t\tcase 'pct5':\n\t\t\treturn svg(s, s, bgRect(s, s) + rect(0, 0, 1, 1, fg));\n\t\tcase 'pct10':\n\t\t\treturn svg(s, s, bgRect(s, s) + rect(0, 0, 1, 1, fg) + rect(4, 4, 1, 1, fg));\n\t\tcase 'pct20':\n\t\t\treturn svg(4, 4, bgRect(4, 4) + rect(0, 0, 1, 1, fg) + rect(2, 2, 1, 1, fg));\n\t\tcase 'pct25':\n\t\t\treturn svg(\n\t\t\t\t4,\n\t\t\t\t4,\n\t\t\t\tbgRect(4, 4) +\n\t\t\t\t\trect(0, 0, 1, 1, fg) +\n\t\t\t\t\trect(2, 0, 1, 1, fg) +\n\t\t\t\t\trect(1, 2, 1, 1, fg) +\n\t\t\t\t\trect(3, 2, 1, 1, fg),\n\t\t\t);\n\t\tcase 'pct30':\n\t\t\treturn svg(\n\t\t\t\t4,\n\t\t\t\t4,\n\t\t\t\tbgRect(4, 4) +\n\t\t\t\t\trect(0, 0, 1, 1, fg) +\n\t\t\t\t\trect(2, 0, 1, 1, fg) +\n\t\t\t\t\trect(1, 1, 1, 1, fg) +\n\t\t\t\t\trect(3, 1, 1, 1, fg) +\n\t\t\t\t\trect(0, 2, 1, 1, fg) +\n\t\t\t\t\trect(2, 2, 1, 1, fg),\n\t\t\t);\n\t\tcase 'pct40':\n\t\t\treturn svg(\n\t\t\t\t4,\n\t\t\t\t4,\n\t\t\t\tbgRect(4, 4) +\n\t\t\t\t\trect(0, 0, 2, 1, fg) +\n\t\t\t\t\trect(1, 1, 1, 1, fg) +\n\t\t\t\t\trect(3, 1, 1, 1, fg) +\n\t\t\t\t\trect(0, 2, 2, 1, fg) +\n\t\t\t\t\trect(1, 3, 1, 1, fg) +\n\t\t\t\t\trect(3, 3, 1, 1, fg),\n\t\t\t);\n\t\tcase 'pct50':\n\t\t\treturn svg(2, 2, bgRect(2, 2) + rect(0, 0, 1, 1, fg) + rect(1, 1, 1, 1, fg));\n\t\tcase 'pct60':\n\t\t\treturn svg(4, 4, rect(0, 0, 4, 4, fg) + rect(0, 0, 2, 1, bg) + rect(1, 2, 2, 1, bg));\n\t\tcase 'pct70':\n\t\t\treturn svg(\n\t\t\t\t4,\n\t\t\t\t4,\n\t\t\t\trect(0, 0, 4, 4, fg) +\n\t\t\t\t\trect(0, 0, 1, 1, bg) +\n\t\t\t\t\trect(2, 0, 1, 1, bg) +\n\t\t\t\t\trect(1, 2, 1, 1, bg) +\n\t\t\t\t\trect(3, 2, 1, 1, bg),\n\t\t\t);\n\t\tcase 'pct75':\n\t\t\treturn svg(4, 4, rect(0, 0, 4, 4, fg) + rect(0, 0, 1, 1, bg) + rect(2, 2, 1, 1, bg));\n\t\tcase 'pct80':\n\t\t\treturn svg(4, 4, rect(0, 0, 4, 4, fg) + rect(0, 0, 1, 1, bg));\n\t\tcase 'pct90':\n\t\t\treturn svg(s, s, rect(0, 0, s, s, fg) + rect(0, 0, 1, 1, bg));\n\n\t\t// ── Horizontal lines ─────────────────────────────────────────────\n\t\tcase 'horz':\n\t\t\treturn svg(s, s, bgRect(s, s) + rect(0, 3, s, 2, fg));\n\t\tcase 'ltHorz':\n\t\t\treturn svg(s, s, bgRect(s, s) + rect(0, 0, s, 1, fg));\n\t\tcase 'dkHorz':\n\t\t\treturn svg(s, s, bgRect(s, s) + rect(0, 0, s, 4, fg));\n\t\tcase 'narHorz':\n\t\t\treturn svg(s, 4, bgRect(s, 4) + rect(0, 0, s, 1, fg) + rect(0, 2, s, 1, fg));\n\t\tcase 'wdHorz':\n\t\t\treturn svg(s, 12, bgRect(s, 12) + rect(0, 0, s, 2, fg));\n\n\t\t// ── Vertical lines ───────────────────────────────────────────────\n\t\tcase 'vert':\n\t\t\treturn svg(s, s, bgRect(s, s) + rect(3, 0, 2, s, fg));\n\t\tcase 'ltVert':\n\t\t\treturn svg(s, s, bgRect(s, s) + rect(0, 0, 1, s, fg));\n\t\tcase 'dkVert':\n\t\t\treturn svg(s, s, bgRect(s, s) + rect(0, 0, 4, s, fg));\n\t\tcase 'narVert':\n\t\t\treturn svg(4, s, bgRect(4, s) + rect(0, 0, 1, s, fg) + rect(2, 0, 1, s, fg));\n\t\tcase 'wdVert':\n\t\t\treturn svg(12, s, bgRect(12, s) + rect(0, 0, 2, s, fg));\n\n\t\t// ── Dash lines ───────────────────────────────────────────────────\n\t\tcase 'dashHorz':\n\t\t\treturn svg(s, 4, bgRect(s, 4) + rect(0, 0, 4, 1, fg));\n\t\tcase 'dashVert':\n\t\t\treturn svg(4, s, bgRect(4, s) + rect(0, 0, 1, 4, fg));\n\n\t\t// ── Cross / grid ─────────────────────────────────────────────────\n\t\tcase 'cross':\n\t\t\treturn svg(s, s, bgRect(s, s) + rect(3, 0, 2, s, fg) + rect(0, 3, s, 2, fg));\n\n\t\t// ── Diagonal lines (down) ────────────────────────────────────────\n\t\tcase 'dnDiag':\n\t\t\treturn svg(\n\t\t\t\ts,\n\t\t\t\ts,\n\t\t\t\tbgRect(s, s) +\n\t\t\t\t\tline(0, 0, s, s, fg, 2) +\n\t\t\t\t\tline(-s, 0, 0, s, fg, 2) +\n\t\t\t\t\tline(s, 0, s * 2, s, fg, 2),\n\t\t\t);\n\t\tcase 'ltDnDiag':\n\t\t\treturn svg(\n\t\t\t\ts,\n\t\t\t\ts,\n\t\t\t\tbgRect(s, s) +\n\t\t\t\t\tline(0, 0, s, s, fg, 1) +\n\t\t\t\t\tline(-s, 0, 0, s, fg, 1) +\n\t\t\t\t\tline(s, 0, s * 2, s, fg, 1),\n\t\t\t);\n\t\tcase 'dkDnDiag':\n\t\t\treturn svg(\n\t\t\t\ts,\n\t\t\t\ts,\n\t\t\t\tbgRect(s, s) +\n\t\t\t\t\tline(0, 0, s, s, fg, 3) +\n\t\t\t\t\tline(-s, 0, 0, s, fg, 3) +\n\t\t\t\t\tline(s, 0, s * 2, s, fg, 3),\n\t\t\t);\n\t\tcase 'wdDnDiag':\n\t\t\treturn svg(\n\t\t\t\t12,\n\t\t\t\t12,\n\t\t\t\tbgRect(12, 12) +\n\t\t\t\t\tline(0, 0, 12, 12, fg, 4) +\n\t\t\t\t\tline(-12, 0, 0, 12, fg, 4) +\n\t\t\t\t\tline(12, 0, 24, 12, fg, 4),\n\t\t\t);\n\t\tcase 'dashDnDiag':\n\t\t\treturn svg(s, s, bgRect(s, s) + line(0, 0, s, s, fg, 1, ' stroke-dasharray=\"4,4\"'));\n\n\t\t// ── Diagonal lines (up) ──────────────────────────────────────────\n\t\tcase 'upDiag':\n\t\t\treturn svg(\n\t\t\t\ts,\n\t\t\t\ts,\n\t\t\t\tbgRect(s, s) +\n\t\t\t\t\tline(0, s, s, 0, fg, 2) +\n\t\t\t\t\tline(-s, s, 0, 0, fg, 2) +\n\t\t\t\t\tline(s, s, s * 2, 0, fg, 2),\n\t\t\t);\n\t\tcase 'ltUpDiag':\n\t\t\treturn svg(\n\t\t\t\ts,\n\t\t\t\ts,\n\t\t\t\tbgRect(s, s) +\n\t\t\t\t\tline(0, s, s, 0, fg, 1) +\n\t\t\t\t\tline(-s, s, 0, 0, fg, 1) +\n\t\t\t\t\tline(s, s, s * 2, 0, fg, 1),\n\t\t\t);\n\t\tcase 'dkUpDiag':\n\t\t\treturn svg(\n\t\t\t\ts,\n\t\t\t\ts,\n\t\t\t\tbgRect(s, s) +\n\t\t\t\t\tline(0, s, s, 0, fg, 3) +\n\t\t\t\t\tline(-s, s, 0, 0, fg, 3) +\n\t\t\t\t\tline(s, s, s * 2, 0, fg, 3),\n\t\t\t);\n\t\tcase 'wdUpDiag':\n\t\t\treturn svg(\n\t\t\t\t12,\n\t\t\t\t12,\n\t\t\t\tbgRect(12, 12) +\n\t\t\t\t\tline(0, 12, 12, 0, fg, 4) +\n\t\t\t\t\tline(-12, 12, 0, 0, fg, 4) +\n\t\t\t\t\tline(12, 12, 24, 0, fg, 4),\n\t\t\t);\n\t\tcase 'dashUpDiag':\n\t\t\treturn svg(s, s, bgRect(s, s) + line(0, s, s, 0, fg, 1, ' stroke-dasharray=\"4,4\"'));\n\n\t\t// ── Diagonal cross ───────────────────────────────────────────────\n\t\tcase 'diagCross':\n\t\t\treturn svg(\n\t\t\t\ts,\n\t\t\t\ts,\n\t\t\t\tbgRect(s, s) +\n\t\t\t\t\tline(0, 0, s, s, fg, 1) +\n\t\t\t\t\tline(-s, 0, 0, s, fg, 1) +\n\t\t\t\t\tline(s, 0, s * 2, s, fg, 1) +\n\t\t\t\t\tline(0, s, s, 0, fg, 1) +\n\t\t\t\t\tline(-s, s, 0, 0, fg, 1) +\n\t\t\t\t\tline(s, s, s * 2, 0, fg, 1),\n\t\t\t);\n\n\t\t// ── Checkerboard ─────────────────────────────────────────────────\n\t\tcase 'smCheck':\n\t\t\treturn svg(4, 4, bgRect(4, 4) + rect(0, 0, 2, 2, fg) + rect(2, 2, 2, 2, fg));\n\t\tcase 'lgCheck':\n\t\t\treturn svg(s, s, bgRect(s, s) + rect(0, 0, 4, 4, fg) + rect(4, 4, 4, 4, fg));\n\n\t\t// ── Grids ────────────────────────────────────────────────────────\n\t\tcase 'smGrid':\n\t\t\treturn svg(s, s, bgRect(s, s) + rect(0, 0, s, 1, fg) + rect(0, 0, 1, s, fg));\n\t\tcase 'lgGrid':\n\t\t\treturn svg(16, 16, bgRect(16, 16) + rect(0, 0, 16, 1, fg) + rect(0, 0, 1, 16, fg));\n\t\tcase 'dotGrid':\n\t\t\treturn svg(\n\t\t\t\ts,\n\t\t\t\ts,\n\t\t\t\tbgRect(s, s) +\n\t\t\t\t\tcircle(0, 0, 0.5, fg) +\n\t\t\t\t\tcircle(4, 0, 0.5, fg) +\n\t\t\t\t\tcircle(0, 4, 0.5, fg) +\n\t\t\t\t\tcircle(4, 4, 0.5, fg) +\n\t\t\t\t\trect(0, 0, s, 0.5, fg) +\n\t\t\t\t\trect(0, 0, 0.5, s, fg),\n\t\t\t);\n\n\t\t// ── Confetti ─────────────────────────────────────────────────────\n\t\tcase 'smConfetti':\n\t\t\treturn svg(\n\t\t\t\ts,\n\t\t\t\ts,\n\t\t\t\tbgRect(s, s) +\n\t\t\t\t\trect(1, 0, 1, 1, fg) +\n\t\t\t\t\trect(5, 1, 1, 1, fg) +\n\t\t\t\t\trect(3, 3, 1, 1, fg) +\n\t\t\t\t\trect(7, 2, 1, 1, fg) +\n\t\t\t\t\trect(0, 5, 1, 1, fg) +\n\t\t\t\t\trect(4, 6, 1, 1, fg) +\n\t\t\t\t\trect(2, 7, 1, 1, fg) +\n\t\t\t\t\trect(6, 5, 1, 1, fg),\n\t\t\t);\n\t\tcase 'lgConfetti':\n\t\t\treturn svg(\n\t\t\t\ts,\n\t\t\t\ts,\n\t\t\t\tbgRect(s, s) +\n\t\t\t\t\trect(0, 0, 2, 2, fg) +\n\t\t\t\t\trect(5, 1, 2, 2, fg) +\n\t\t\t\t\trect(2, 4, 2, 2, fg) +\n\t\t\t\t\trect(6, 5, 2, 2, fg),\n\t\t\t);\n\n\t\t// ── Brick ────────────────────────────────────────────────────────\n\t\tcase 'horzBrick':\n\t\t\treturn svg(\n\t\t\t\ts,\n\t\t\t\ts,\n\t\t\t\tbgRect(s, s) +\n\t\t\t\t\trect(0, 0, s, 1, fg) +\n\t\t\t\t\trect(0, 0, 1, 4, fg) +\n\t\t\t\t\trect(0, 4, s, 1, fg) +\n\t\t\t\t\trect(4, 4, 1, 4, fg),\n\t\t\t);\n\t\tcase 'diagBrick':\n\t\t\treturn svg(\n\t\t\t\ts,\n\t\t\t\ts,\n\t\t\t\tbgRect(s, s) + line(0, 4, 4, 0, fg, 1) + line(4, s, s, 4, fg, 1) + line(0, s, s, 0, fg, 1),\n\t\t\t);\n\n\t\t// ── Diamond ──────────────────────────────────────────────────────\n\t\tcase 'solidDmnd':\n\t\t\treturn svg(s, s, `${bgRect(s, s)}<polygon points=\"4,0 8,4 4,8 0,4\" fill=\"${fg}\"/>`);\n\t\tcase 'openDmnd':\n\t\t\treturn svg(\n\t\t\t\ts,\n\t\t\t\ts,\n\t\t\t\tbgRect(s, s) +\n\t\t\t\t\tline(4, 0, s, 4, fg, 1) +\n\t\t\t\t\tline(s, 4, 4, s, fg, 1) +\n\t\t\t\t\tline(4, s, 0, 4, fg, 1) +\n\t\t\t\t\tline(0, 4, 4, 0, fg, 1),\n\t\t\t);\n\t\tcase 'dotDmnd':\n\t\t\treturn svg(\n\t\t\t\ts,\n\t\t\t\ts,\n\t\t\t\tbgRect(s, s) +\n\t\t\t\t\tcircle(4, 0, 0.75, fg) +\n\t\t\t\t\tcircle(s, 4, 0.75, fg) +\n\t\t\t\t\tcircle(4, s, 0.75, fg) +\n\t\t\t\t\tcircle(0, 4, 0.75, fg) +\n\t\t\t\t\tcircle(4, 4, 0.75, fg),\n\t\t\t);\n\n\t\t// ── Plaid ────────────────────────────────────────────────────────\n\t\tcase 'plaid':\n\t\t\treturn svg(\n\t\t\t\ts,\n\t\t\t\ts,\n\t\t\t\tbgRect(s, s) +\n\t\t\t\t\trect(0, 0, 4, 4, fg) +\n\t\t\t\t\trect(0, 0, s, 1, fg) +\n\t\t\t\t\trect(0, 2, s, 1, fg) +\n\t\t\t\t\trect(0, 0, 1, s, fg) +\n\t\t\t\t\trect(2, 0, 1, s, fg),\n\t\t\t);\n\n\t\t// ── Sphere ───────────────────────────────────────────────────────\n\t\tcase 'sphere': {\n\t\t\tconst defs = `<defs><radialGradient id=\"sph\" cx=\"35%\" cy=\"35%\" r=\"60%\"><stop offset=\"0%\" stop-color=\"${bg}\" stop-opacity=\"0.8\"/><stop offset=\"100%\" stop-color=\"${fg}\" stop-opacity=\"1\"/></radialGradient></defs>`;\n\t\t\treturn svg(s, s, `${bgRect(s, s)}${defs}<circle cx=\"4\" cy=\"4\" r=\"3.5\" fill=\"url(#sph)\"/>`);\n\t\t}\n\n\t\t// ── Weave ────────────────────────────────────────────────────────\n\t\tcase 'weave':\n\t\t\treturn svg(\n\t\t\t\ts,\n\t\t\t\ts,\n\t\t\t\tbgRect(s, s) +\n\t\t\t\t\tline(0, 0, 4, 4, fg, 1.5) +\n\t\t\t\t\tline(4, 4, 0, s, fg, 1.5) +\n\t\t\t\t\tline(s, 0, 4, 4, fg, 1.5) +\n\t\t\t\t\tline(4, 4, s, s, fg, 1.5) +\n\t\t\t\t\tline(4, 0, s, 4, fg, 1.5) +\n\t\t\t\t\tline(0, 4, 4, s, fg, 1.5),\n\t\t\t);\n\n\t\t// ── Divot ────────────────────────────────────────────────────────\n\t\tcase 'divot':\n\t\t\treturn svg(\n\t\t\t\ts,\n\t\t\t\ts,\n\t\t\t\tbgRect(s, s) +\n\t\t\t\t\tline(2, 1, 2, 3, fg, 1) +\n\t\t\t\t\tline(1, 2, 3, 2, fg, 1) +\n\t\t\t\t\tline(6, 5, 6, 7, fg, 1) +\n\t\t\t\t\tline(5, 6, 7, 6, fg, 1),\n\t\t\t);\n\n\t\t// ── Shingle ──────────────────────────────────────────────────────\n\t\tcase 'shingle':\n\t\t\treturn svg(\n\t\t\t\ts,\n\t\t\t\ts,\n\t\t\t\tbgRect(s, s) + line(0, 0, s, s, fg, 1) + line(0, s, 4, 4, fg, 1) + rect(0, 7, s, 1, fg),\n\t\t\t);\n\n\t\t// ── Wave ─────────────────────────────────────────────────────────\n\t\tcase 'wave':\n\t\t\treturn svg(\n\t\t\t\ts,\n\t\t\t\ts,\n\t\t\t\t`${bgRect(s, s)}<path d=\"M0,2 Q2,0 4,2 Q6,4 8,2\" stroke=\"${fg}\" stroke-width=\"1\" fill=\"none\"/><path d=\"M0,6 Q2,4 4,6 Q6,8 8,6\" stroke=\"${fg}\" stroke-width=\"1\" fill=\"none\"/>`,\n\t\t\t);\n\n\t\t// ── Trellis ──────────────────────────────────────────────────────\n\t\tcase 'trellis':\n\t\t\treturn svg(\n\t\t\t\t4,\n\t\t\t\t4,\n\t\t\t\tbgRect(4, 4) +\n\t\t\t\t\trect(0, 0, 4, 1, fg) +\n\t\t\t\t\trect(0, 2, 4, 1, fg) +\n\t\t\t\t\trect(0, 0, 1, 4, fg) +\n\t\t\t\t\trect(2, 0, 1, 4, fg),\n\t\t\t);\n\n\t\t// ── ZigZag ───────────────────────────────────────────────────────\n\t\tcase 'zigZag':\n\t\t\treturn svg(\n\t\t\t\ts,\n\t\t\t\ts,\n\t\t\t\t`${bgRect(s, s)}<path d=\"M0,4 L2,0 L4,4 L6,0 L8,4\" stroke=\"${fg}\" stroke-width=\"1\" fill=\"none\"/><path d=\"M0,8 L2,4 L4,8 L6,4 L8,8\" stroke=\"${fg}\" stroke-width=\"1\" fill=\"none\"/>`,\n\t\t\t);\n\n\t\tdefault:\n\t\t\treturn null;\n\t}\n}\n\n/**\n * Serialises one pattern tile into a standalone inline `<svg>` document, the\n * form a CSS `background-image` data-URI needs. Returns `null` for unknown\n * presets.\n */\nexport function getPatternSvg(preset: string, fg: string, bg: string): string | null {\n\tconst tile = getPatternTile(preset, fg, bg);\n\tif (!tile) {\n\t\treturn null;\n\t}\n\treturn `<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"${tile.w}\" height=\"${tile.h}\">${tile.inner}</svg>`;\n}\n\n/** Result of {@link buildPatternFill}. */\nexport interface PatternFillResult {\n\t/** CSS `background-image` value (inline SVG data-URI). */\n\tbackgroundImage?: string;\n\t/** Resolved pattern background colour (hex), used as the CSS `backgroundColor`. */\n\tbackgroundColor?: string;\n\t/**\n\t * Optional SVG `<defs>`/filter markup that a renderer can inject into a\n\t * shared `<svg>` element. Self-contained data-URI patterns do not need\n\t * this, so it is `undefined` for every current preset; it exists as the\n\t * extension hook for presets that cannot be expressed as a tiled data-URI.\n\t */\n\tsvgFilter?: { id: string; markup: string };\n}\n\n/**\n * Converts an OOXML preset pattern fill (`a:pattFill` — foreground/background\n * colour plus a preset such as `pct50`, `ltHorz`, `cross`, …) to a CSS\n * background built from an inline SVG data-URI.\n *\n * Mirrors React `buildPatternFillCss`, but accepts a `ShapeStyle` plus the\n * owning element id so future filter-based presets can emit a uniquely-named\n * `svgFilter`. Returns `undefined` when the style is not a pattern fill or the\n * preset is unknown.\n *\n * @param pattern - The shape style carrying pattern configuration.\n * @param elementId - The owning element id (namespaces any emitted filter id).\n */\nexport function buildPatternFill(\n\tpattern: ShapeStyle | undefined,\n\telementId: string,\n): PatternFillResult | undefined {\n\tif (!pattern || pattern.fillMode !== 'pattern' || !pattern.fillPatternPreset) {\n\t\treturn undefined;\n\t}\n\n\tconst fg = normalizeHexColor(pattern.fillColor, '#000000');\n\tconst bg = normalizeHexColor(pattern.fillPatternBackgroundColor, '#ffffff');\n\tconst preset = pattern.fillPatternPreset;\n\n\tconst svgPattern = getPatternSvg(preset, fg, bg);\n\tif (!svgPattern) {\n\t\treturn undefined;\n\t}\n\n\tconst encoded = encodeURIComponent(svgPattern);\n\t// `elementId` is reserved for namespacing future filter-based presets; the\n\t// current presets are fully self-contained data-URIs so no defs are emitted.\n\tvoid elementId;\n\treturn {\n\t\tbackgroundImage: `url(\"data:image/svg+xml,${encoded}\")`,\n\t\tbackgroundColor: bg,\n\t};\n}\n\n/**\n * Builds a CSS `background-image` + `background-color` pair for an OOXML pattern\n * fill (`a:pattFill`) directly from a `ShapeStyle`. This is the\n * binding-friendly variant (no `elementId`, no `svgFilter`) that the React and\n * Angular `color-*` modules historically exposed as `buildPatternFillCss`.\n *\n * Returns `undefined` when the style is not a pattern fill or the preset is\n * unknown. Mirrors {@link buildPatternFill} minus the filter-id namespacing.\n *\n * @param style - Resolved shape style.\n */\nexport function buildPatternFillCss(\n\tstyle: ShapeStyle | undefined,\n): { backgroundImage: string; backgroundColor: string } | undefined {\n\tif (!style || style.fillMode !== 'pattern' || !style.fillPatternPreset) {\n\t\treturn undefined;\n\t}\n\n\tconst fg = normalizeHexColor(style.fillColor, '#000000');\n\tconst bg = normalizeHexColor(style.fillPatternBackgroundColor, '#ffffff');\n\n\tconst svgPattern = getPatternSvg(style.fillPatternPreset, fg, bg);\n\tif (!svgPattern) {\n\t\treturn undefined;\n\t}\n\n\tconst encoded = encodeURIComponent(svgPattern);\n\treturn {\n\t\tbackgroundImage: `url(\"data:image/svg+xml,${encoded}\")`,\n\t\tbackgroundColor: bg,\n\t};\n}\n\n/**\n * All 52 OOXML pattern fill presets.\n * Reference: ECMA-376 §20.1.10.33 (ST_PresetPatternVal).\n */\nexport const OOXML_PATTERN_PRESETS = [\n\t'pct5',\n\t'pct10',\n\t'pct20',\n\t'pct25',\n\t'pct30',\n\t'pct40',\n\t'pct50',\n\t'pct60',\n\t'pct70',\n\t'pct75',\n\t'pct80',\n\t'pct90',\n\t'horz',\n\t'vert',\n\t'ltHorz',\n\t'ltVert',\n\t'dkHorz',\n\t'dkVert',\n\t'narHorz',\n\t'narVert',\n\t'wdHorz',\n\t'wdVert',\n\t'dashHorz',\n\t'dashVert',\n\t'cross',\n\t'dnDiag',\n\t'upDiag',\n\t'ltDnDiag',\n\t'ltUpDiag',\n\t'dkDnDiag',\n\t'dkUpDiag',\n\t'wdDnDiag',\n\t'wdUpDiag',\n\t'dashDnDiag',\n\t'dashUpDiag',\n\t'diagCross',\n\t'smCheck',\n\t'lgCheck',\n\t'smGrid',\n\t'lgGrid',\n\t'dotGrid',\n\t'smConfetti',\n\t'lgConfetti',\n\t'horzBrick',\n\t'diagBrick',\n\t'solidDmnd',\n\t'openDmnd',\n\t'dotDmnd',\n\t'plaid',\n\t'sphere',\n\t'weave',\n\t'divot',\n\t'shingle',\n\t'wave',\n\t'trellis',\n\t'zigZag',\n] as const;\n\nexport type OoxmlPatternPreset = (typeof OOXML_PATTERN_PRESETS)[number];\n\n// ---------------------------------------------------------------------------\n// Aggregate fill resolver\n// ---------------------------------------------------------------------------\n\n/** Result of {@link getComputedFillStyle}. */\nexport interface ComputedFillStyle {\n\tbackgroundColor?: string;\n\tbackgroundImage?: string;\n\tbackgroundSize?: string;\n\tbackgroundPosition?: string;\n\tbackgroundRepeat?: string;\n\t/** Carried through for renderers that need to inject pattern defs. */\n\tsvgFilter?: { id: string; markup: string };\n}\n\n/**\n * Aggregate fill resolver. Resolves the element's fill in the exact order the\n * React `getShapeVisualStyle` uses:\n *\n * 1. image fill (`fillMode === \"image\"` + `fillImageUrl`)\n * 2. gradient (structured `fillGradientStops`, falling back to the\n * prebuilt `fillGradient` string)\n * 3. pattern (`fillMode === \"pattern\"` + preset)\n * 4. solid (`fillColor`, unless `fillMode === \"none\"`)\n *\n * Returns `undefined` when the element carries no shape styling, and an\n * empty-ish object when no fill applies (so callers can spread the result\n * safely).\n *\n * A child of a group whose fill is `a:grpFill` (`fillMode === \"group\"`)\n * inherits the group's resolved fill: pass the parent group's `ShapeStyle`\n * (`GroupPptxElement.groupFill`) as {@link parentGroupFill} and it is resolved\n * in the child's own box.\n *\n * @param element - The PPTX element to resolve a fill for.\n * @param parentGroupFill - The enclosing group's fill style, used only when the\n * element's own fill is `a:grpFill`.\n */\nexport function getComputedFillStyle(\n\telement: PptxElement,\n\tparentGroupFill?: ShapeStyle,\n): ComputedFillStyle | undefined {\n\tif (!hasShapeProperties(element)) {\n\t\treturn undefined;\n\t}\n\tconst ss = element.shapeStyle;\n\tif (!ss) {\n\t\treturn {};\n\t}\n\n\t// A multi-sub-path preset (e.g. `smileyFace`, `actionButtonBlank`) or custom\n\t// geometry whose sub-paths carry their own `@fill` mode is painted by the\n\t// per-sub-path SVG overlay instead (`buildSubpathFillOverlay`): a single flat\n\t// `background-color` here would show through underneath it, and for a\n\t// `fill=\"none\"` sub-path (the smiley's eyes) it would paint a solid dot\n\t// where PowerPoint draws nothing.\n\tif (suppressesCssFill(element)) {\n\t\treturn { backgroundColor: 'transparent' };\n\t}\n\n\t// grpFill inheritance: paint the parent group's resolved fill in this\n\t// child's box. Without a parent fill there is nothing to inherit.\n\tif (ss.fillMode === 'group') {\n\t\treturn parentGroupFill ? resolveComputedFill(parentGroupFill, element) : {};\n\t}\n\n\treturn resolveComputedFill(ss, element);\n}\n\n/**\n * Resolves a concrete {@link ComputedFillStyle} from a {@link ShapeStyle} in the\n * context of `element` (id namespaces pattern filters; geometry drives gradient\n * `@scaled`/`@rotWithShape` corrections). Split out so grpFill children can\n * resolve the parent group's style through the identical pipeline.\n */\nfunction resolveComputedFill(ss: ShapeStyle, element: PptxElement): ComputedFillStyle {\n\t// 1. Image fill — highest priority.\n\tconst imageFillUrl = ss.fillMode === 'image' && ss.fillImageUrl ? ss.fillImageUrl : undefined;\n\tif (imageFillUrl) {\n\t\tconst tile = ss.fillImageMode === 'tile';\n\t\treturn {\n\t\t\tbackgroundColor: 'transparent',\n\t\t\tbackgroundImage: `url(${imageFillUrl})`,\n\t\t\tbackgroundRepeat: tile ? 'repeat' : 'no-repeat',\n\t\t\tbackgroundSize: tile ? 'auto' : '100% 100%',\n\t\t};\n\t}\n\n\t// 2. Gradient (structured, with prebuilt-string fallback).\n\tconst geometry: GradientRenderContext = {\n\t\trotation: element.rotation,\n\t\twidth: element.width,\n\t\theight: element.height,\n\t};\n\tconst gradient =\n\t\tbuildGradientCss(ss, geometry) ?? (ss.fillMode === 'gradient' ? ss.fillGradient : undefined);\n\tif (gradient) {\n\t\t// Tile-flip applies only to structured linear gradients: buildGradientCss\n\t\t// reflects the stops, and the matching halved/repeating background-size +\n\t\t// background-repeat completes the per-tile mirror (CSS has no native\n\t\t// gradient flip). Radial paths and prebuilt-string fallbacks are excluded.\n\t\tconst isStructuredLinear =\n\t\t\tss.fillMode === 'gradient' &&\n\t\t\t(ss.fillGradientType || 'linear') === 'linear' &&\n\t\t\tsanitizeGradientStops(ss.fillGradientStops).length > 0;\n\t\tconst tileFlip = isStructuredLinear ? getGradientTileFlipCss(ss.fillGradientFlip) : undefined;\n\t\tif (tileFlip) {\n\t\t\treturn {\n\t\t\t\tbackgroundImage: gradient,\n\t\t\t\tbackgroundSize: tileFlip.backgroundSize,\n\t\t\t\tbackgroundRepeat: tileFlip.backgroundRepeat,\n\t\t\t};\n\t\t}\n\t\t// tileRect confines the gradient to a sub-rectangle of the shape.\n\t\tconst tileRect =\n\t\t\tss.fillMode === 'gradient' ? getGradientTileRectCss(ss.fillGradientTileRect) : undefined;\n\t\tif (tileRect) {\n\t\t\treturn {\n\t\t\t\tbackgroundImage: gradient,\n\t\t\t\tbackgroundSize: tileRect.backgroundSize,\n\t\t\t\tbackgroundPosition: tileRect.backgroundPosition,\n\t\t\t\tbackgroundRepeat: tileRect.backgroundRepeat,\n\t\t\t};\n\t\t}\n\t\t// A `path=\"rect\"` gradient is rendered as an SVG data-URI image (see\n\t\t// `buildRectPathGradient`), not a CSS `<gradient>` function: unlike a CSS\n\t\t// gradient (which auto-sizes to the background box), an `url(...)` image\n\t\t// defaults to its own intrinsic size and to `repeat`, which would tile the\n\t\t// normalised 0-100 artwork instead of stretching it across the shape.\n\t\tconst isRectPathImage =\n\t\t\tss.fillMode === 'gradient' &&\n\t\t\t(ss.fillGradientType || 'linear') === 'radial' &&\n\t\t\t(ss.fillGradientPathType || 'circle') === 'rect' &&\n\t\t\tsanitizeGradientStops(ss.fillGradientStops).length > 0;\n\t\tif (isRectPathImage) {\n\t\t\treturn {\n\t\t\t\tbackgroundImage: gradient,\n\t\t\t\tbackgroundSize: '100% 100%',\n\t\t\t\tbackgroundRepeat: 'no-repeat',\n\t\t\t};\n\t\t}\n\t\treturn { backgroundImage: gradient };\n\t}\n\n\t// 3. Pattern fill.\n\tconst pattern = buildPatternFill(ss, element.id);\n\tif (pattern) {\n\t\treturn {\n\t\t\tbackgroundColor: pattern.backgroundColor,\n\t\t\tbackgroundImage: pattern.backgroundImage,\n\t\t\tbackgroundRepeat: 'repeat',\n\t\t\tbackgroundSize: 'auto',\n\t\t\tsvgFilter: pattern.svgFilter,\n\t\t};\n\t}\n\n\t// 4. Solid fill.\n\tif (ss.fillColor && ss.fillColor !== 'transparent' && ss.fillMode !== 'none') {\n\t\treturn { backgroundColor: colorWithOpacity(ss.fillColor, ss.fillOpacity) };\n\t}\n\n\treturn {};\n}\n","/**\n * Stroke/dash normalisation, compound-line box-shadow generation, SVG\n * dasharray, element transform strings, and drawing-unit parsing. Pure\n * TypeScript shared by the React, Vue, and Angular bindings.\n */\nimport type { StrokeDashType, PptxElement, TextOrientationMatrix } from 'pptx-viewer-core';\n\nimport { clampUnitInterval } from './fill-style';\n\n/** CSS `border-style` keyword used for stroke rendering. */\nexport type CssBorderStyle = 'solid' | 'dotted' | 'dashed' | 'double';\n\n/** A neutral CSS map (framework `CSSProperties` are structurally compatible). */\nexport type CssStyleMap = Record<string, string | number>;\n\nexport const TEXT_ORIENTATION_IDENTITY: TextOrientationMatrix = [1, 0, 0, 1];\n\nexport function isTextOrientationMatrix(value: unknown): value is TextOrientationMatrix {\n\treturn (\n\t\tArray.isArray(value) &&\n\t\tvalue.length === 4 &&\n\t\tvalue.every((entry) => typeof entry === 'number' && Number.isFinite(entry))\n\t);\n}\n\nexport function multiplyTextOrientationMatrices(\n\tleft: TextOrientationMatrix,\n\tright: TextOrientationMatrix,\n): TextOrientationMatrix {\n\treturn [\n\t\tleft[0] * right[0] + left[2] * right[1],\n\t\tleft[1] * right[0] + left[3] * right[1],\n\t\tleft[0] * right[2] + left[2] * right[3],\n\t\tleft[1] * right[2] + left[3] * right[3],\n\t];\n}\n\nexport function getElementOrientationMatrix(\n\telement: Pick<PptxElement, 'rotation' | 'flipHorizontal' | 'flipVertical'>,\n): TextOrientationMatrix {\n\tconst radians = ((Number(element.rotation) || 0) * Math.PI) / 180;\n\tconst cosine = Math.cos(radians);\n\tconst sine = Math.sin(radians);\n\tconst rotation: TextOrientationMatrix = [cosine, sine, -sine, cosine];\n\tconst flip: TextOrientationMatrix = [\n\t\telement.flipHorizontal ? -1 : 1,\n\t\t0,\n\t\t0,\n\t\telement.flipVertical ? -1 : 1,\n\t];\n\treturn multiplyTextOrientationMatrices(rotation, flip);\n}\n\nfunction textOrientationAngleScore(matrix: TextOrientationMatrix): number {\n\treturn Math.abs(Math.atan2(matrix[1], matrix[0]));\n}\n\n/**\n * Normalizes a raw stroke dash type string to a valid `StrokeDashType` enum value.\n * Performs case-insensitive matching against all OOXML dash types.\n * @param value - Raw dash type string (e.g. \"lgDash\", \"SysDot\").\n * @returns The canonical `StrokeDashType`, or `undefined` if unrecognized.\n */\nexport function normalizeStrokeDashType(\n\tvalue: StrokeDashType | string | undefined,\n): StrokeDashType | undefined {\n\tconst normalized = String(value || '')\n\t\t.trim()\n\t\t.toLowerCase();\n\tif (!normalized) {\n\t\treturn undefined;\n\t}\n\n\tconst dashMap: Record<string, StrokeDashType> = {\n\t\tsolid: 'solid',\n\t\tdot: 'dot',\n\t\tdash: 'dash',\n\t\tlgdash: 'lgDash',\n\t\tdashdot: 'dashDot',\n\t\tlgdashdot: 'lgDashDot',\n\t\tlgdashdotdot: 'lgDashDotDot',\n\t\tsysdot: 'sysDot',\n\t\tsysdash: 'sysDash',\n\t\tsysdashdot: 'sysDashDot',\n\t\tsysdashdotdot: 'sysDashDotDot',\n\t\tcustom: 'custom',\n\t};\n\treturn dashMap[normalized];\n}\n\n/**\n * Maps an OOXML stroke dash type to a CSS `border-style` value.\n *\n * A compound line (`a:ln/@cmpd`) maps to `double`, the one CSS border style that\n * paints more than one strand: it splits `border-width` into three equal parts\n * (line, gap, line), which is exactly ECMA-376's `dbl` (\"Double Lines of equal\n * width\"). `thickThin` / `thinThick` / `tri` have no CSS equivalent and are\n * approximated by the same `double`; the strand RATIO is lost but the line still\n * reads as compound, which a single solid stroke does not.\n *\n * This replaced an inset-`box-shadow` construction that could not work: inset\n * shadows paint front-to-back from the padding edge inward, and a `transparent`\n * ring paints nothing rather than punching a hole, so the \"gap\" ring was never\n * rendered and a compound outline came out as one THICKER solid line (verified\n * in Chromium). See {@link getCompoundLineBoxShadow}.\n *\n * A third strand for `tri` could be drawn with an `outline` + `outline-offset`\n * (which does leave a real see-through gap), but the outline is already spoken\n * for: every binding paints its selection / hover affordance with one, because\n * an affordance border would take part in layout. Correctness of the common\n * case beats a strand of the rarest one.\n *\n * @param dashType - The normalized dash type.\n * @param compoundLine - Optional compound line type (e.g. \"dbl\", \"tri\").\n * @returns A CSS border-style value, or `undefined`.\n */\nexport function getCssBorderDashStyle(\n\tdashType: StrokeDashType | undefined,\n\tcompoundLine?: string,\n): CssBorderStyle | undefined {\n\t// A compound line's strands outrank its dash pattern: CSS cannot express both\n\t// at once, and losing the multi-strand look is the more visible of the two.\n\tif (\n\t\tcompoundLine === 'dbl' ||\n\t\tcompoundLine === 'thickThin' ||\n\t\tcompoundLine === 'thinThick' ||\n\t\tcompoundLine === 'tri'\n\t) {\n\t\treturn 'double';\n\t}\n\tif (!dashType || dashType === 'solid') {\n\t\treturn 'solid';\n\t}\n\tif (dashType === 'dot' || dashType === 'sysDot') {\n\t\treturn 'dotted';\n\t}\n\treturn 'dashed';\n}\n\n/**\n * Always `undefined`: a compound line needs NO box-shadow.\n *\n * This used to build concentric inset `box-shadow` rings (\"outer strand is the\n * CSS border, inner strands are inset shadows\"), and it did not work. Inset\n * shadows are painted front-to-back from the padding edge inward, and the ring\n * that was supposed to be the GAP was declared `transparent` - which paints\n * nothing at all rather than punching a hole in the ring underneath it. The\n * result, confirmed by rendering both constructions in Chromium, is a single\n * solid band as thick as the whole compound line, on every browser.\n *\n * Compound lines are now painted by `border-style: double`\n * ({@link getCssBorderDashStyle}) on a CSS-bordered shape, and by the real\n * parallel strands of `buildStrokeOutline` on a stroke-only preset / connector.\n *\n * @deprecated Kept only so existing call sites keep compiling; drop the call.\n */\nexport function getCompoundLineBoxShadow(\n\t_compoundLine: string | undefined,\n\t_strokeWidth: number,\n\t_strokeColor: string,\n): string | undefined {\n\treturn undefined;\n}\n\n/**\n * The CSS `border-width` a compound line is painted at: the FULL stroke width.\n *\n * `border-style: double` divides `border-width` between its two strands and the\n * gap, so the border must carry the whole `a:ln/@w`. (It previously returned a\n * fraction, because the remaining strands were supposed to come from\n * {@link getCompoundLineBoxShadow} - which never painted them, so a compound\n * line was drawn at a third of its authored weight.)\n *\n * @param compoundLine - The compound line type (e.g. \"dbl\", \"tri\").\n * @param strokeWidth - Total stroke width in pixels.\n * @returns The CSS border width in pixels.\n * @deprecated Prefer `getComputedStrokeStyle`, which resolves the whole outline.\n */\nexport function getCompoundLineBorderWidth(\n\t_compoundLine: string | undefined,\n\tstrokeWidth: number,\n): number {\n\treturn strokeWidth;\n}\n\n/**\n * The CSS properties that paint a compound (`a:ln/@cmpd`) border: the full\n * stroke width with `border-style: double`.\n *\n * @param compoundLine - The compound line type from `a:ln/@cmpd`.\n * @param strokeColor - Resolved stroke colour (with opacity applied).\n * @param strokeWidth - Total stroke width in pixels.\n * @returns CSS properties to apply to the shape container element.\n * @deprecated Prefer `getComputedStrokeStyle`, which resolves the whole outline.\n */\nexport function getCompoundLineStyle(\n\tcompoundLine: string | undefined,\n\tstrokeColor: string,\n\tstrokeWidth: number,\n): CssStyleMap {\n\tif (!compoundLine || compoundLine === 'sng' || strokeWidth <= 0) {\n\t\treturn {};\n\t}\n\treturn {\n\t\tborderWidth: strokeWidth,\n\t\tborderColor: strokeColor,\n\t\tborderStyle: 'double',\n\t};\n}\n\n/**\n * Computes an SVG `stroke-dasharray` value for a given dash type and stroke width.\n * For custom dash types with parsed segments, segment values are expressed in\n * 1/1000 of the line width (per OOXML spec) and converted to pixel multiples.\n * @param dashType - The OOXML dash type.\n * @param strokeWidth - Stroke width in pixels (minimum 1).\n * @param customDashSegments - Optional array of `{dash, space}` segments for custom dashes.\n * @returns A space-separated dasharray string, or `undefined` for solid strokes.\n */\nexport function getSvgStrokeDasharray(\n\tdashType: StrokeDashType | undefined,\n\tstrokeWidth: number,\n\tcustomDashSegments?: Array<{ dash: number; space: number }>,\n): string | undefined {\n\tif (!dashType || dashType === 'solid') {\n\t\treturn undefined;\n\t}\n\tconst stroke = Math.max(strokeWidth, 1);\n\n\t// If custom dash with parsed segments, build dasharray from actual data.\n\t// Segment values are in 1/1000 of the line width, so divide by 1000\n\t// to get multiples of stroke-width.\n\tif (dashType === 'custom' && customDashSegments && customDashSegments.length > 0) {\n\t\treturn customDashSegments\n\t\t\t.flatMap((seg) => [(seg.dash / 1000) * stroke, (seg.space / 1000) * stroke])\n\t\t\t.join(' ');\n\t}\n\n\tswitch (dashType) {\n\t\tcase 'dot':\n\t\tcase 'sysDot':\n\t\t\treturn `${stroke} ${stroke * 2}`;\n\t\tcase 'dash':\n\t\tcase 'sysDash':\n\t\t\treturn `${stroke * 4} ${stroke * 2}`;\n\t\tcase 'lgDash':\n\t\t\treturn `${stroke * 7} ${stroke * 2.5}`;\n\t\tcase 'dashDot':\n\t\tcase 'sysDashDot':\n\t\t\treturn `${stroke * 4} ${stroke * 2} ${stroke} ${stroke * 2}`;\n\t\tcase 'lgDashDot':\n\t\t\treturn `${stroke * 7} ${stroke * 2.5} ${stroke} ${stroke * 2.5}`;\n\t\tcase 'lgDashDotDot':\n\t\tcase 'sysDashDotDot':\n\t\t\treturn `${stroke * 7} ${stroke * 2.5} ${stroke} ${stroke * 2} ${stroke} ${stroke * 2}`;\n\t\tcase 'custom':\n\t\t\treturn `${stroke * 3} ${stroke * 2}`;\n\t\tdefault:\n\t\t\treturn undefined;\n\t}\n}\n\n/**\n * Builds a CSS `transform` string combining flip and rotation transforms for an element.\n * Flips are expressed as `scaleX(-1)` / `scaleY(-1)`, rotation as `rotate(Ndeg)`.\n *\n * Order matters: OOXML `a:xfrm` mirrors the shape *within* its bounding box\n * (`flipH`/`flipV`) and *then* rotates the box by `rot`. With CSS\n * `transform-origin: center`, transforms apply right-to-left, so the flips must\n * come AFTER the rotation in the string (`rotate(θ) scaleX(-1)`) to be applied\n * first. Emitting `scaleX(-1) rotate(θ)` instead reflects the rotation direction\n * for any shape that is both flipped and rotated (e.g. the \"Balloons\" freeforms\n * render mirrored/tilted the wrong way). This matches the Angular binding's\n * `getContainerStyle`, which already emits `rotate() scaleX() scaleY()`.\n * @param element - The element whose transforms are read.\n * @returns A CSS transform string, or `undefined` if no transforms apply.\n */\nexport function getElementTransform(element: PptxElement): string | undefined {\n\tconst transforms: string[] = [];\n\tif (element.rotation) {\n\t\ttransforms.push(`rotate(${element.rotation}deg)`);\n\t}\n\tif (element.flipHorizontal) {\n\t\ttransforms.push('scaleX(-1)');\n\t}\n\tif (element.flipVertical) {\n\t\ttransforms.push('scaleY(-1)');\n\t}\n\tif (element.skewX) {\n\t\ttransforms.push(`skewX(${element.skewX}deg)`);\n\t}\n\tif (element.skewY) {\n\t\ttransforms.push(`skewY(${element.skewY}deg)`);\n\t}\n\treturn transforms.length > 0 ? transforms.join(' ') : undefined;\n}\n\n/**\n * Builds the element's CSS transform WITHOUT its rotation component\n * (flips + skews only). Used as the stable base while a live rotate-handle\n * drag appends its own `rotate(...)` for preview; recomputing the full\n * transform from {@link getElementTransform} ordering keeps flipped/skewed\n * shapes rendering correctly mid-rotation.\n * @param element - The element whose non-rotation transform is built.\n * @returns A CSS transform string, or `undefined` if none apply.\n */\nexport function getElementTransformWithoutRotation(element: PptxElement): string | undefined {\n\tconst transforms: string[] = [];\n\tif (element.flipHorizontal) {\n\t\ttransforms.push('scaleX(-1)');\n\t}\n\tif (element.flipVertical) {\n\t\ttransforms.push('scaleY(-1)');\n\t}\n\tif (element.skewX) {\n\t\ttransforms.push(`skewX(${element.skewX}deg)`);\n\t}\n\tif (element.skewY) {\n\t\ttransforms.push(`skewY(${element.skewY}deg)`);\n\t}\n\treturn transforms.length > 0 ? transforms.join(' ') : undefined;\n}\n\n/**\n * Builds a CSS transform that compensates for element flips so that text\n * inside a flipped shape renders in its natural reading direction.\n * Only includes `scaleX(-1)` / `scaleY(-1)`; rotation is not compensated.\n * @param element - The element whose flips are checked.\n * @returns A CSS transform string, or `undefined` if no flips are active.\n */\nexport function getTextCompensationTransform(element: PptxElement): string | undefined {\n\tconst transforms: string[] = [];\n\tconst normalizedRotation = (((Number(element.rotation) || 0) % 360) + 360) % 360;\n\tconst swapFlipAxis =\n\t\tnormalizedRotation > 90 &&\n\t\tnormalizedRotation < 270 &&\n\t\telement.flipHorizontal !== element.flipVertical;\n\tconst compensateHorizontal = swapFlipAxis ? element.flipVertical : element.flipHorizontal;\n\tconst compensateVertical = swapFlipAxis ? element.flipHorizontal : element.flipVertical;\n\tif (compensateHorizontal) {\n\t\ttransforms.push('scaleX(-1)');\n\t}\n\tif (compensateVertical) {\n\t\ttransforms.push('scaleY(-1)');\n\t}\n\tconst ancestorGroupTransform =\n\t\t'textStyle' in element ? element.textStyle?.ancestorGroupTransform : undefined;\n\tif (isTextOrientationMatrix(ancestorGroupTransform)) {\n\t\tconst localCompensation: TextOrientationMatrix = [\n\t\t\tcompensateHorizontal ? -1 : 1,\n\t\t\t0,\n\t\t\t0,\n\t\t\tcompensateVertical ? -1 : 1,\n\t\t];\n\t\tconst visibleTransform = multiplyTextOrientationMatrices(\n\t\t\tmultiplyTextOrientationMatrices(ancestorGroupTransform, getElementOrientationMatrix(element)),\n\t\t\tlocalCompensation,\n\t\t);\n\t\tconst determinant =\n\t\t\tvisibleTransform[0] * visibleTransform[3] - visibleTransform[1] * visibleTransform[2];\n\t\tif (determinant < -1e-6) {\n\t\t\tconst horizontalCandidate = multiplyTextOrientationMatrices(visibleTransform, [-1, 0, 0, 1]);\n\t\t\tconst verticalCandidate = multiplyTextOrientationMatrices(visibleTransform, [1, 0, 0, -1]);\n\t\t\ttransforms.push(\n\t\t\t\ttextOrientationAngleScore(horizontalCandidate) <=\n\t\t\t\t\ttextOrientationAngleScore(verticalCandidate)\n\t\t\t\t\t? 'scaleX(-1)'\n\t\t\t\t\t: 'scaleY(-1)',\n\t\t\t);\n\t\t}\n\t}\n\treturn transforms.length > 0 ? transforms.join(' ') : undefined;\n}\n\n/**\n * Parses an OOXML \"drawing percent\" value (expressed as hundredths-of-a-percent,\n * i.e. 100000 = 100%) into a 0-1 unit interval.\n * @param value - Raw value from OOXML (e.g. 50000 for 50%).\n * @returns A number between 0 and 1, or `undefined` if the value is not finite.\n */\nexport function parseDrawingPercent(value: unknown): number | undefined {\n\tconst parsed = Number.parseFloat(String(value ?? '').trim());\n\tif (!Number.isFinite(parsed)) {\n\t\treturn undefined;\n\t}\n\treturn clampUnitInterval(parsed / 100000);\n}\n","/**\n * PowerPoint's automatic value-axis scale.\n *\n * A chart that declares no `c:min` / `c:max` / `c:majorUnit` leaves the bounds\n * to the application, and PowerPoint does NOT simply run the axis to the largest\n * data point. It anchors the axis at zero, pads the data, then rounds out to a\n * round number and labels it in round steps. The reporter's deck (issue #132)\n * shows the difference plainly: a percentage chart whose bars top out at 52%\n * gets `0% 20% 40% 60%` from PowerPoint and got `0% 10% 21% 31% 42% 52%` here,\n * because the axis ran to the data maximum and was then divided into five.\n *\n * The rules, from Microsoft's documented automatic-scaling behaviour:\n *\n * - **Zero anchor.** With all-positive data, the axis starts at zero unless the\n * smallest value is at least 5/6 of the largest, in which case the data\n * occupies a narrow band high up and a zero-anchored axis would flatten it.\n * All-negative data mirrors this, ending at zero.\n * - **Headroom.** The far end is pushed out by 5% of the data span so the\n * tallest bar does not touch the top of the plot.\n * - **Round steps.** The major unit is the first \"nice\" number (1, 2, 2.5 or 5\n * times a power of ten) at or above `span / targetIntervals`, and the bounds\n * are then snapped outwards to whole multiples of it.\n *\n * The snap is what makes the interval count differ from `targetIntervals`:\n * rounding 0.544 up to a multiple of 0.2 lands on 0.6, which is three steps, not\n * four. That is the intent, and it is why PowerPoint's axes read in round\n * numbers while an evenly-divided one does not.\n */\n\n/** A resolved automatic axis scale. */\nexport interface NiceAxisBounds {\n\tmin: number;\n\tmax: number;\n\t/** Step between major gridlines; `max - min` is always a whole multiple. */\n\tmajorUnit: number;\n}\n\n/**\n * Steps PowerPoint rounds a major unit to, as mantissas of a power of ten.\n * Anything between two entries rounds UP to the larger, so a unit is never so\n * fine that the axis grows more gridlines than asked for.\n */\nconst NICE_STEPS = [1, 2, 2.5, 5, 10] as const;\n\n/** The fraction of the data span added as headroom beyond the last data point. */\nconst HEADROOM = 0.05;\n\n/**\n * Plot-area points of vertical room PowerPoint reserves per gridline before it\n * asks for another one, and the ceiling/floor on how many it will ever ask\n * for. See {@link axisTargetIntervals}'s doc comment for the PowerPoint COM\n * measurements these were fit to.\n */\nconst POINTS_PER_GRIDLINE = 20;\nconst MIN_TARGET_INTERVALS = 1;\nconst MAX_TARGET_INTERVALS = 10;\n\n/**\n * Pixels per point in the \"px\" unit `computePlotLayout` (and every renderer in\n * this engine) works in: 96 px per inch, 72 points per inch, so 4/3 px per pt.\n * Mirrors `EMU_PER_PIXEL` (core/constants.ts): `EMU_PER_POINT / EMU_PER_PIXEL`\n * reduces to the same 4/3.\n */\nconst PX_PER_POINT = 4 / 3;\n\n/** {@link niceValueAxisBounds}'s `targetIntervals` when no plot height is known. */\nconst DEFAULT_TARGET_INTERVALS = 4;\n\n/**\n * How close the smaller end of the data has to be to the larger before the axis\n * stops anchoring at zero. Below 5/6, zero anchoring keeps the bars readable;\n * above it, the data is a narrow band and zero would squash it flat.\n */\nconst ZERO_ANCHOR_RATIO = 5 / 6;\n\n/**\n * How many gridline intervals PowerPoint's automatic value-axis scale aims\n * for, given the chart's plot-area height in the \"px\" unit `computePlotLayout`\n * returns (96 px/inch; see `PX_PER_POINT` above).\n *\n * This is NOT a universal constant (see this module's original doc comment,\n * which admitted as much: \"matches the axes PowerPoint draws for a chart of\n * ORDINARY height\"): a short chart gets fewer, coarser gridlines than a tall\n * one, up to a point, because PowerPoint only has room to label so many\n * without the axis text crowding.\n *\n * Measured via PowerPoint COM automation (`New-Object -ComObject\n * PowerPoint.Application`, `Shapes.AddChart2`, reading back\n * `chart.Axes(2).MinimumScale/.MaximumScale/.MajorUnit`): building a fresh\n * clustered-column chart at increasing shape heights with the SAME 8-point,\n * single-category data (values 1.2-3.2, the exact case reported against this\n * engine, which this engine rendered 0-4 while PowerPoint drew 0-3.5):\n *\n * | chart height | plot height | PowerPoint axis | gridlines |\n * |--------------|-------------|------------------|-----------|\n * | 100pt | ~33pt | 0 to 5, unit 5 | 1 |\n * | 150pt | ~83pt | 0 to 4, unit 1 | 4 |\n * | 200pt | ~133pt | 0 to 3.5, unit 0.5 | 7 |\n * | 300pt | ~233pt | 0 to 3.5, unit 0.5 | 7 |\n * | 1000pt | ~933pt | 0 to 3.5, unit 0.5 | 7 (unchanged) |\n *\n * Cross-checked against two more datasets (0-52 and 0-9) at the same set of\n * heights to separate \"the target interval count\" from \"which nice-number\n * bucket a particular span happens to round into\": PowerPoint never asked for\n * more than about 10 intervals even at a 1000pt-tall chart, it only asks for\n * FEWER on a plot area too short to fit that many labels. That saturation\n * (not a straight line) is why this is clamped at the top, not just scaled.\n *\n * Modelled as one gridline interval per ~20pt of plot height (roughly one\n * axis-label line plus padding), clamped to `[1, 10]`. This will not be exact\n * for every data range: the actual PowerPoint algorithm also nudges the count\n * by how the span happens to snap to a nice number (see the module doc\n * comment), which this simplified model does not attempt to reproduce. It is\n * a large improvement over hard-coding the short-chart answer (4) for every\n * chart regardless of size, which is the bug this was added to fix.\n */\nexport function axisTargetIntervals(plotHeightPx: number): number {\n\tif (!Number.isFinite(plotHeightPx) || plotHeightPx <= 0) {\n\t\treturn DEFAULT_TARGET_INTERVALS;\n\t}\n\tconst plotHeightPt = plotHeightPx / PX_PER_POINT;\n\tconst raw = Math.round(plotHeightPt / POINTS_PER_GRIDLINE);\n\treturn Math.min(MAX_TARGET_INTERVALS, Math.max(MIN_TARGET_INTERVALS, raw));\n}\n\n/** The smallest nice step at or above `value`. */\nexport function niceAxisStep(value: number): number {\n\tif (!Number.isFinite(value) || value <= 0) {\n\t\treturn 1;\n\t}\n\tconst exponent = Math.floor(Math.log10(value));\n\tconst power = 10 ** exponent;\n\tconst mantissa = value / power;\n\tconst step = NICE_STEPS.find((candidate) => mantissa <= candidate + 1e-12) ?? 10;\n\treturn step * power;\n}\n\n/** Round `value` outwards (away from zero-ward `toward`) to a multiple of `unit`. */\nfunction snap(value: number, unit: number, direction: 'up' | 'down'): number {\n\tconst scaled = value / unit;\n\t// Guard against float noise turning an exact multiple into the next one out.\n\tconst rounded = direction === 'up' ? Math.ceil(scaled - 1e-9) : Math.floor(scaled + 1e-9);\n\treturn rounded * unit;\n}\n\n/**\n * Resolve the automatic bounds and major unit for a value axis.\n *\n * @param dataMin Smallest plotted value.\n * @param dataMax Largest plotted value.\n * @param targetIntervals Roughly how many gridline steps to aim for. The snap to\n * a round unit means the result is usually one fewer. Defaults to 4 only\n * when the caller has no idea how tall the chart's plot area is; pass\n * {@link axisTargetIntervals}`(plotHeightPx)` instead whenever that height is\n * known; see that function's doc comment for why a fixed constant undershot\n * real PowerPoint on any chart of ordinary-or-larger size.\n * @param headroom Fraction of the data span added beyond the far end. 2D\n * charts get PowerPoint's 5%; a right-angle-axes 3D bar chart gets none\n * (its axis on data topping out at exactly 5 ends at 5, see\n * `chart-3d-oblique-layout.ts`).\n */\nexport function niceValueAxisBounds(\n\tdataMin: number,\n\tdataMax: number,\n\ttargetIntervals = DEFAULT_TARGET_INTERVALS,\n\theadroom = HEADROOM,\n): NiceAxisBounds {\n\tif (!Number.isFinite(dataMin) || !Number.isFinite(dataMax)) {\n\t\treturn { min: 0, max: 1, majorUnit: 0.5 };\n\t}\n\tconst low = Math.min(dataMin, dataMax);\n\tconst high = Math.max(dataMin, dataMax);\n\tconst intervals = Math.max(1, Math.round(targetIntervals));\n\n\t// Flat data (every point identical) has no span to scale. Zero-anchor it\n\t// where that reads sensibly, and otherwise bracket the single value.\n\tif (low === high) {\n\t\tif (low === 0) {\n\t\t\treturn { min: 0, max: 1, majorUnit: 1 / intervals };\n\t\t}\n\t\tconst unit = niceAxisStep(Math.abs(low) / intervals);\n\t\treturn low > 0\n\t\t\t? { min: 0, max: snap(low, unit, 'up') || unit, majorUnit: unit }\n\t\t\t: { min: snap(low, unit, 'down'), max: 0, majorUnit: unit };\n\t}\n\n\tconst dataSpan = high - low;\n\tconst padding = dataSpan * headroom;\n\n\t// Decide which end, if either, pins to zero.\n\tlet paddedMin: number;\n\tlet paddedMax: number;\n\tif (low >= 0) {\n\t\tpaddedMin = low < high * ZERO_ANCHOR_RATIO ? 0 : low - padding;\n\t\tpaddedMax = high + padding;\n\t} else if (high <= 0) {\n\t\tpaddedMax = high > low * ZERO_ANCHOR_RATIO ? 0 : high + padding;\n\t\tpaddedMin = low - padding;\n\t} else {\n\t\t// Straddles zero: both ends are data-driven, and zero falls inside.\n\t\tpaddedMin = low - padding;\n\t\tpaddedMax = high + padding;\n\t}\n\n\tconst unit = niceAxisStep((paddedMax - paddedMin) / intervals);\n\tconst min = paddedMin === 0 ? 0 : snap(paddedMin, unit, 'down');\n\tlet max = paddedMax === 0 ? 0 : snap(paddedMax, unit, 'up');\n\tif (max <= min) {\n\t\tmax = min + unit;\n\t}\n\treturn { min, max, majorUnit: unit };\n}\n","/**\n * chart-font.ts: the single pt -> px boundary for chart text.\n *\n * Core parses every chart font size in POINTS (`c:txPr` run sizes are stored\n * as `sz / 100`, e.g. `sz=\"1195\"` -> 11.95 pt; see core's chart-axis-parser),\n * and that unit is part of core's public model: editors and inspectors read\n * and write points. The SVG chart view-model, however, lives in slide-pixel\n * space (96 dpi), where PowerPoint paints one point as 4/3 px. Rendering the\n * parsed number directly as `SvgText.fontSize` therefore drew ALL chart text\n * at 75% of its true size (issue #132).\n *\n * Every parsed chart font size must cross the pt -> px boundary exactly once,\n * at the moment it enters an `SvgText` descriptor, and that conversion lives\n * here. Do NOT convert in core (its unit is points by contract) and do NOT\n * convert again in a binding projector (the view-model is already px).\n *\n * The default constants are PowerPoint's chart text defaults expressed in px:\n * 10 pt body text (axis ticks, category labels, axis titles) and 9 pt data\n * labels.\n *\n * @module chart-font\n */\n\n/** CSS pixels per typographic point (96 dpi / 72 dpi = 4/3). */\nexport const CHART_PX_PER_PT = 4 / 3;\n\n/**\n * Convert a chart font size parsed in points (core's unit) to slide-px for\n * `SvgText.fontSize`. E.g. 11.95 pt -> 15.93 px.\n */\nexport function chartFontPx(sizePt: number): number {\n\treturn sizePt * CHART_PX_PER_PT;\n}\n\n/**\n * PowerPoint's default chart body text size (10 pt) in slide-px (13.33):\n * axis tick labels, category labels, axis titles, and display-unit captions\n * fall back to this when the chart XML declares no explicit size.\n */\nexport const DEFAULT_CHART_TEXT_PX = chartFontPx(10);\n\n/**\n * PowerPoint's default data-label text size (9 pt) in slide-px (12): value /\n * category / percent labels attached to data marks fall back to this.\n */\nexport const DEFAULT_CHART_DATA_LABEL_PX = chartFontPx(9);\n","/**\n * chart-legend-placement.ts: `c:legendPos` -> layout behaviour, shared by\n * every chart-type builder's plot-area reservation and legend positioning.\n *\n * `ST_LegendPos` has five values: `b`/`t`/`l`/`r` reserve a band of plot-area\n * space on that side, but `tr` (top-right corner) is an OVERLAY per\n * PowerPoint's own quick-layout behaviour: it floats over the plot rather\n * than reserving space anywhere. Every legend-placement branch across the\n * shared chart engine used to test only `'b'`/`'t'`/`'r'`/`'l'`, so a `tr`\n * legend fell through every branch: no space was reserved (harmless) but the\n * legend positioning code ALSO had no branch for it, so it rendered wherever\n * the untouched default (bottom-centred) put it instead of the top-right\n * corner.\n *\n * No dependencies: kept separate from `chart-legend-layout.ts` (which needs\n * `ChartViewModel`) so every legend-placement call site, including the\n * plot-layout reservation code that runs before a `ChartViewModel` exists,\n * can import this with no risk of a circular import.\n *\n * @module chart-legend-placement\n */\n\n/** The four sides a legend can occupy; `tr`'s corner styling maps to `'r'`. */\nexport type LegendPlacementSide = 'b' | 't' | 'l' | 'r';\n\n/** Resolved behaviour for one `c:legendPos` value. */\nexport interface LegendPlacement {\n\t/**\n\t * The side other legend-positioning code should treat this as: `'tr'`\n\t * shares its coordinate math with `'r'` (a right-aligned column starting at\n\t * the top), since positioning it there already reads as \"top-right corner\"\n\t * without inventing a fifth branch everywhere.\n\t */\n\tside: LegendPlacementSide;\n\t/**\n\t * `true` when the legend floats OVER the plot instead of reserving band\n\t * space for itself (only `'tr'`, matching PowerPoint's own quick-layout\n\t * behaviour for a top-right legend).\n\t */\n\toverlaysPlot: boolean;\n}\n\nconst KNOWN_SIDES = new Set<string>(['b', 't', 'l', 'r']);\n\n/**\n * Resolve a `c:legendPos` value (`b`/`t`/`l`/`r`/`tr`, or absent) to its\n * placement behaviour. An unrecognised or absent value defaults to `'b'`,\n * matching every builder's pre-existing fallback.\n */\nexport function resolveLegendPlacement(legendPos: string | undefined): LegendPlacement {\n\tif (legendPos === 'tr') {\n\t\treturn { side: 'r', overlaysPlot: true };\n\t}\n\tconst side =\n\t\tlegendPos !== undefined && KNOWN_SIDES.has(legendPos)\n\t\t\t? (legendPos as LegendPlacementSide)\n\t\t\t: 'b';\n\treturn { side, overlaysPlot: false };\n}\n\n/** A plot rectangle in the same terms `computePlotLayout`/`computeLayout` build one in. */\nexport interface LegendReservationRect {\n\tplotLeft: number;\n\tplotTop: number;\n\tplotRight: number;\n\tplotBottom: number;\n}\n\n/**\n * Shrink `rect` to reserve a legend band for `legendPos`, or return it\n * unchanged for an overlay (`'tr'`) legend or one with no reservation side.\n * The single source of the `20`/`80` reservation constants every chart-type\n * builder's plot-layout function used to repeat.\n */\nexport function reserveLegendSpace(\n\tlegendPos: string | undefined,\n\trect: LegendReservationRect,\n): LegendReservationRect {\n\tconst placement = resolveLegendPlacement(legendPos);\n\tif (placement.overlaysPlot) {\n\t\treturn rect;\n\t}\n\tif (placement.side === 'b') {\n\t\treturn { ...rect, plotBottom: rect.plotBottom - 20 };\n\t}\n\tif (placement.side === 't') {\n\t\treturn { ...rect, plotTop: rect.plotTop + 20 };\n\t}\n\tif (placement.side === 'r') {\n\t\treturn { ...rect, plotRight: rect.plotRight - 80 };\n\t}\n\tif (placement.side === 'l') {\n\t\treturn { ...rect, plotLeft: rect.plotLeft + 80 };\n\t}\n\treturn rect;\n}\n","/**\n * chart-number-format-pattern.ts: the numeric-placeholder pattern engine\n * behind `chart-number-format.ts`, split out to keep that file within the\n * repo's ~300-LOC limit.\n *\n * @module chart-number-format-pattern\n */\n\n/**\n * ECMA-376 18.8.30's fixed 8-name colour list for a format section's leading\n * `[Red]`/`[Blue]`/etc. token. `[ColorN]` (indexed palette) and conditions\n * (`[>100]`) are not colours and are ignored, same as any unrecognised token:\n * a colour hint that cannot be resolved falls back to the caller's own\n * colour rather than crashing.\n */\nconst NAMED_FORMAT_COLORS: Record<string, string> = {\n\tblack: '#000000',\n\tblue: '#0000FF',\n\tcyan: '#00FFFF',\n\tgreen: '#00FF00',\n\tmagenta: '#FF00FF',\n\tred: '#FF0000',\n\twhite: '#FFFFFF',\n\tyellow: '#FFFF00',\n};\n\n/** The numeric placeholder run of a format section, and the literals around it. */\nexport interface Pattern {\n\tprefix: string;\n\tsuffix: string;\n\t/** Digits required left of the point (`0` placeholders). */\n\tintDigits: number;\n\t/** Digits shown right of the point: `[required, optional]`. */\n\tdecimals: { required: number; optional: number };\n\t/** `#,##0` style grouping. */\n\tgrouped: boolean;\n\t/** Multiplier applied before formatting: 100 per `%`, 0.001 per trailing `,`. */\n\tscale: number;\n\t/** `0.00E+00` scientific notation. */\n\tscientific: boolean;\n\t/** Colour from a recognised `[Red]`/`[Blue]`/etc. token in this section. */\n\tcolor?: string;\n}\n\nconst PLACEHOLDER = /[0#?]/u;\n\n/**\n * Parse one format section. Returns `undefined` when the section contains no\n * numeric placeholder at all, which means the caller should fall back.\n */\nexport function parsePattern(code: string): Pattern | undefined {\n\tlet scale = 1;\n\tlet scientific = false;\n\tlet color: string | undefined;\n\tconst chars: Array<{ ch: string; literal: boolean }> = [];\n\n\tlet inQuotes = false;\n\tfor (let i = 0; i < code.length; i += 1) {\n\t\tconst ch = code[i];\n\t\tif (ch === '\"') {\n\t\t\tinQuotes = !inQuotes;\n\t\t\tcontinue;\n\t\t}\n\t\tif (inQuotes) {\n\t\t\tchars.push({ ch, literal: true });\n\t\t\tcontinue;\n\t\t}\n\t\tif (ch === '\\\\' || ch === '*' || ch === '_') {\n\t\t\t// Escape / repeat / skip-width: the next char is a literal (and for\n\t\t\t// `_` the width padding is not reproducible in SVG text anyway).\n\t\t\tconst next = code[i + 1];\n\t\t\ti += 1;\n\t\t\tif (ch === '\\\\' && next !== undefined) {\n\t\t\t\tchars.push({ ch: next, literal: true });\n\t\t\t}\n\t\t\tcontinue;\n\t\t}\n\t\tif (ch === '%') {\n\t\t\tscale *= 100;\n\t\t\tchars.push({ ch, literal: true });\n\t\t\tcontinue;\n\t\t}\n\t\tif (ch === 'E' && (code[i + 1] === '+' || code[i + 1] === '-')) {\n\t\t\tscientific = true;\n\t\t\tchars.push({ ch: 'E', literal: false });\n\t\t\ti += 1;\n\t\t\tcontinue;\n\t\t}\n\t\tif (ch === '[') {\n\t\t\t// Colour / condition / locale block: skipped wholesale, except a\n\t\t\t// recognised named colour, whose value the caller can apply to the\n\t\t\t// rendered text (the number itself is unaffected either way).\n\t\t\tconst close = code.indexOf(']', i);\n\t\t\tconst token = code.slice(i + 1, close === -1 ? code.length : close);\n\t\t\tconst named = NAMED_FORMAT_COLORS[token.trim().toLowerCase()];\n\t\t\tif (named && color === undefined) {\n\t\t\t\tcolor = named;\n\t\t\t}\n\t\t\ti = close === -1 ? code.length : close;\n\t\t\tcontinue;\n\t\t}\n\t\tchars.push({ ch, literal: false });\n\t}\n\n\tconst firstDigit = chars.findIndex((c) => !c.literal && PLACEHOLDER.test(c.ch));\n\tif (firstDigit === -1) {\n\t\treturn undefined;\n\t}\n\tlet lastDigit = firstDigit;\n\tfor (let i = chars.length - 1; i >= firstDigit; i -= 1) {\n\t\tconst c = chars[i];\n\t\tif (!c.literal && (PLACEHOLDER.test(c.ch) || c.ch === '.' || c.ch === ',' || c.ch === 'E')) {\n\t\t\tlastDigit = i;\n\t\t\tbreak;\n\t\t}\n\t}\n\n\tconst numeric = chars.slice(firstDigit, lastDigit + 1);\n\tconst prefix = chars\n\t\t.slice(0, firstDigit)\n\t\t.map((c) => c.ch)\n\t\t.join('');\n\tconst suffix = chars\n\t\t.slice(lastDigit + 1)\n\t\t.map((c) => c.ch)\n\t\t.join('');\n\n\t// Trailing commas immediately before the decimal point (or at the end of the\n\t// integer run) scale by thousands; a comma between placeholders groups.\n\tlet grouped = false;\n\tlet intDigits = 0;\n\tlet required = 0;\n\tlet optional = 0;\n\tlet afterPoint = false;\n\tlet inExponent = false;\n\tfor (let i = 0; i < numeric.length; i += 1) {\n\t\tconst { ch, literal } = numeric[i];\n\t\tif (literal) {\n\t\t\tcontinue;\n\t\t}\n\t\tif (ch === 'E') {\n\t\t\tinExponent = true;\n\t\t\tcontinue;\n\t\t}\n\t\tif (inExponent) {\n\t\t\tcontinue;\n\t\t}\n\t\tif (ch === '.') {\n\t\t\tafterPoint = true;\n\t\t\tcontinue;\n\t\t}\n\t\tif (ch === ',') {\n\t\t\tconst next = numeric.slice(i + 1).find((c) => !c.literal);\n\t\t\tif (!next || next.ch === '.' || !PLACEHOLDER.test(next.ch)) {\n\t\t\t\tscale /= 1000;\n\t\t\t} else {\n\t\t\t\tgrouped = true;\n\t\t\t}\n\t\t\tcontinue;\n\t\t}\n\t\tif (!PLACEHOLDER.test(ch)) {\n\t\t\tcontinue;\n\t\t}\n\t\tif (afterPoint) {\n\t\t\tif (ch === '0') {\n\t\t\t\trequired += 1;\n\t\t\t} else {\n\t\t\t\toptional += 1;\n\t\t\t}\n\t\t} else if (ch === '0') {\n\t\t\tintDigits += 1;\n\t\t}\n\t}\n\n\treturn {\n\t\tprefix,\n\t\tsuffix,\n\t\tintDigits,\n\t\tdecimals: { required, optional },\n\t\tgrouped,\n\t\tscale,\n\t\tscientific,\n\t\tcolor,\n\t};\n}\n\n/** Apply `#,###` grouping to the integer part of an already-rounded string. */\nfunction group(intPart: string): string {\n\treturn intPart.replace(/\\B(?=(\\d{3})+(?!\\d))/gu, ',');\n}\n\n/** Render `value` through a parsed pattern. */\nexport function applyPattern(value: number, pattern: Pattern, forcePositive: boolean): string {\n\tconst scaled = value * pattern.scale;\n\tconst magnitude = forcePositive ? Math.abs(scaled) : scaled;\n\n\tif (pattern.scientific) {\n\t\tconst digits = pattern.decimals.required + pattern.decimals.optional;\n\t\tconst exponential = magnitude.toExponential(digits);\n\t\tconst [mantissa, exponent] = exponential.split('e');\n\t\tconst sign = exponent.startsWith('-') ? '-' : '+';\n\t\tconst power = Math.abs(Number(exponent)).toString().padStart(2, '0');\n\t\treturn `${pattern.prefix}${mantissa}E${sign}${power}${pattern.suffix}`;\n\t}\n\n\tconst maxDecimals = pattern.decimals.required + pattern.decimals.optional;\n\tlet body = magnitude.toFixed(maxDecimals);\n\tif (pattern.decimals.optional > 0) {\n\t\t// Optional (`#`/`?`) decimals are dropped when they are zero.\n\t\tbody = body.replace(/(\\.\\d*?)0+$/u, '$1').replace(/\\.$/u, '');\n\t\tconst [, frac = ''] = body.split('.');\n\t\tif (frac.length < pattern.decimals.required) {\n\t\t\tbody = Number(body).toFixed(pattern.decimals.required);\n\t\t}\n\t}\n\n\tconst [rawIntPart, fracPart] = body.split('.');\n\tlet intPart = rawIntPart;\n\t// A magnitude that rounds to zero at this pattern's precision (a genuinely\n\t// tiny negative value, e.g. a -1e-13 floating-point residue from axis-tick\n\t// or \"value minus zero-line\" arithmetic) still prints \"-0\" / \"-0.00\" from\n\t// `toFixed`, because the STRING carries the sign even though the rounded\n\t// NUMBER is zero. `Number(body)` folds \"-0\" back to `-0`, and `-0 !== 0` is\n\t// `false` in JS, so this only drops the sign when the printed magnitude is\n\t// actually zero (a real negative value's rounded body is never zero).\n\t// COM-verified: PowerPoint never shows a bare \"-\" in front of an\n\t// axis/data-label zero this way.\n\tconst hasMinusChar = intPart.startsWith('-');\n\tconst negative = hasMinusChar && Number(body) !== 0;\n\tif (hasMinusChar) {\n\t\tintPart = intPart.slice(1);\n\t}\n\tif (intPart.length < pattern.intDigits) {\n\t\tintPart = intPart.padStart(pattern.intDigits, '0');\n\t}\n\tif (pattern.intDigits === 0 && intPart === '0' && fracPart !== undefined) {\n\t\t// `#.##` drops the leading zero; `0.##` keeps it.\n\t\tintPart = '';\n\t}\n\tif (pattern.grouped) {\n\t\tintPart = group(intPart);\n\t}\n\n\tconst number = fracPart === undefined ? intPart : `${intPart}.${fracPart}`;\n\treturn `${negative ? '-' : ''}${pattern.prefix}${number}${pattern.suffix}`;\n}\n","/**\n * ECMA-376 / SpreadsheetML number-format codes, applied to chart labels.\n *\n * A chart's value axis and its data labels both carry a `c:numFmt/@formatCode`\n * (or inherit one from the series' `c:numCache/c:formatCode` when\n * `@sourceLinked=\"1\"`). Ignoring it is what made a percentage chart render its\n * axis as `0.1 0.2 0.3` and its bars as `0.52` where PowerPoint shows `10% 20%\n * 30%` and `52%`: the cached values ARE fractions, and the format code is the\n * only thing that says so.\n *\n * This covers the codes charts actually use - literal text, digit placeholders,\n * thousands separators, percent, scientific notation, and the\n * `positive;negative;zero` section split - and deliberately stops short of a\n * full Excel format engine. Anything it does not recognise falls back to the\n * caller's default rendering, so an exotic code degrades to today's output\n * rather than to a wrong number. The numeric-placeholder pattern engine itself\n * lives in `chart-number-format-pattern.ts`.\n */\nimport { applyPattern, parsePattern } from './chart-number-format-pattern';\n\n/** Format codes that mean \"no explicit format\"; the caller's default wins. */\nconst GENERAL = new Set(['', 'general', '@']);\n\n/** Split a format code into its `positive;negative;zero;text` sections. */\nfunction sections(code: string): string[] {\n\tconst out: string[] = [];\n\tlet current = '';\n\tlet inQuotes = false;\n\tfor (let i = 0; i < code.length; i += 1) {\n\t\tconst ch = code[i];\n\t\tif (ch === '\"') {\n\t\t\tinQuotes = !inQuotes;\n\t\t\tcurrent += ch;\n\t\t\tcontinue;\n\t\t}\n\t\tif (ch === '\\\\') {\n\t\t\tcurrent += ch + (code[i + 1] ?? '');\n\t\t\ti += 1;\n\t\t\tcontinue;\n\t\t}\n\t\tif (ch === ';' && !inQuotes) {\n\t\t\tout.push(current);\n\t\t\tcurrent = '';\n\t\t\tcontinue;\n\t\t}\n\t\tcurrent += ch;\n\t}\n\tout.push(current);\n\treturn out;\n}\n\n/** Pick the section that applies to `value` (positive / negative / zero). */\nfunction sectionFor(value: number, parts: string[]): { code: string; forcePositive: boolean } {\n\tif (parts.length === 1) {\n\t\treturn { code: parts[0], forcePositive: false };\n\t}\n\tif (value < 0 && parts[1] !== undefined) {\n\t\t// A dedicated negative section supplies its own sign (often none, or\n\t\t// parentheses), so the magnitude is formatted unsigned.\n\t\treturn { code: parts[1], forcePositive: true };\n\t}\n\tif (value === 0 && parts[2] !== undefined) {\n\t\treturn { code: parts[2], forcePositive: false };\n\t}\n\treturn { code: parts[0], forcePositive: false };\n}\n\n/** A formatted number, plus a colour from its section's `[Red]`/`[Blue]`/etc. token, when present. */\nexport interface FormattedChartNumber {\n\ttext: string;\n\tcolor?: string;\n}\n\n/**\n * Format `value` with an ECMA-376 number-format code, also surfacing a\n * `[Red]`/`[Blue]`/etc. section colour when the code declares one.\n *\n * Returns `undefined` when the code is absent, `General`, or beyond this\n * subset, which tells the caller to keep its own default formatting.\n */\nexport function formatChartNumberWithColor(\n\tvalue: number,\n\tformatCode?: string,\n): FormattedChartNumber | undefined {\n\tif (!Number.isFinite(value)) {\n\t\treturn undefined;\n\t}\n\tconst code = (formatCode ?? '').trim();\n\tif (GENERAL.has(code.toLowerCase())) {\n\t\treturn undefined;\n\t}\n\t// Date/time codes are the province of `chart-date-axis`; a value axis never\n\t// carries one, and mistaking `d` for a digit would corrupt the label.\n\tif (/(?:^|[^\\\\\"])(?:yy|mm?m|dd?|hh|ss)/iu.test(code) && !/[0#?]/u.test(code)) {\n\t\treturn undefined;\n\t}\n\tconst { code: section, forcePositive } = sectionFor(value, sections(code));\n\tconst pattern = parsePattern(section);\n\tif (!pattern) {\n\t\treturn undefined;\n\t}\n\ttry {\n\t\treturn { text: applyPattern(value, pattern, forcePositive), color: pattern.color };\n\t} catch {\n\t\treturn undefined;\n\t}\n}\n\n/**\n * Format `value` with an ECMA-376 number-format code.\n *\n * Returns `undefined` when the code is absent, `General`, or beyond this\n * subset, which tells the caller to keep its own default formatting.\n */\nexport function formatChartNumber(value: number, formatCode?: string): string | undefined {\n\treturn formatChartNumberWithColor(value, formatCode)?.text;\n}\n","/**\n * chart-style-defaults.ts: resolves the font sizes/colours a chart renderer\n * should fall back to when the chart's own XML leaves an element unstyled,\n * consulting the parsed Office 2013+ chart-style part\n * (`PptxChartData.chartStyleDefinition`, core's model of `style#.xml`,\n * `cs:chartStyle` - the part behind PowerPoint's built-in \"Chart Styles\"\n * gallery) before falling back to this viewer's own fixed chart defaults\n * (`chart-font.ts`'s `DEFAULT_CHART_TEXT_PX`/`DEFAULT_CHART_DATA_LABEL_PX`,\n * and the `#334155` label colour used across the cartesian/pie/radar/\n * waterfall render modules).\n *\n * Pure decision function (CLAUDE.md Rule 2): every binding's chart SVG\n * render code shares one shared bundle, so a call site should resolve this\n * once per chart and thread the fields through instead of hardcoding its own\n * copy of the same fallback constants.\n *\n * @module chart-style-defaults\n */\nimport { chartFontPx, DEFAULT_CHART_DATA_LABEL_PX, DEFAULT_CHART_TEXT_PX } from './chart-font';\n\n/** The subset of `PptxChartStylePartEntry` (core) this module reads. */\ninterface ChartStylePartEntryLike {\n\tfontSize?: number;\n\tbold?: boolean;\n\titalic?: boolean;\n\tcolor?: string;\n\tlineColor?: string;\n\tlineWidth?: number;\n\tfillColor?: string;\n}\n\n/** The subset of `PptxChartStyleDefinition` (core) this module reads. */\ninterface ChartStyleDefinitionLike {\n\ttitle?: ChartStylePartEntryLike;\n\taxisTitle?: ChartStylePartEntryLike;\n\tcategoryAxis?: ChartStylePartEntryLike;\n\tvalueAxis?: ChartStylePartEntryLike;\n\tlegend?: ChartStylePartEntryLike;\n\tdataLabel?: ChartStylePartEntryLike;\n\tdataPoint?: ChartStylePartEntryLike;\n\tdataPointLine?: ChartStylePartEntryLike;\n\tgridlineMajor?: ChartStylePartEntryLike;\n\tgridlineMinor?: ChartStylePartEntryLike;\n\tchartArea?: ChartStylePartEntryLike;\n\tplotArea?: ChartStylePartEntryLike;\n}\n\n/** The subset of `PptxChartData` this module reads. */\ninterface ChartDataLike {\n\tchartStyleDefinition?: ChartStyleDefinitionLike;\n}\n\n/**\n * PowerPoint's own default data-point/axis-label colour (`#334155`), matched\n * across `chart-cartesian-bars.ts`, `chart-cartesian-plots.ts`,\n * `chart-pie-labels.ts`, and the other chart-family renderers, used here as\n * the terminal fallback when neither the chart style part nor the chart's\n * own XML names a colour.\n */\nconst DEFAULT_LABEL_COLOR = '#334155';\n\n/**\n * PowerPoint's chart title default text size (12 px), matching\n * `chart-manual-layout.ts`'s `CHART_TITLE_FONT_PX`, used as the terminal\n * fallback for the title font size.\n */\nconst DEFAULT_TITLE_TEXT_PX = 12;\n\n/** Resolved font sizes/colours a chart renderer should use, in slide-px. */\nexport interface ChartStyleDefaults {\n\t/** Axis tick labels, category labels, axis titles (10 pt PowerPoint default). */\n\tbodyTextPx: number;\n\t/** Value/category/percent data labels (9 pt PowerPoint default). */\n\tdataLabelTextPx: number;\n\t/** Legend entry text. */\n\tlegendTextPx: number;\n\t/** The chart's own title text. */\n\ttitleTextPx: number;\n\taxisTextColor: string;\n\tdataLabelTextColor: string;\n\tlegendTextColor: string;\n\ttitleTextColor: string;\n\t/** Major gridline stroke colour, when the style part names one. */\n\tgridlineColor: string | undefined;\n\t/** Chart-area (outer frame) fill, when the style part names one. */\n\tchartAreaFillColor: string | undefined;\n\t/** Plot-area (inner panel) fill, when the style part names one. */\n\tplotAreaFillColor: string | undefined;\n\t/**\n\t * Default series line/marker stroke width (points), when the active chart\n\t * style's `cs:dataPointLine`/`cs:dataPoint` names a directly-authored\n\t * `cs:spPr/a:ln/@w` (C2 wave-1 skip: the built-in style number driving\n\t * default series line widths). Most built-in styles reference a theme\n\t * line-style matrix index instead of authoring a literal width, which this\n\t * resolver does not follow (see `PptxChartStylePartEntry.lineWidth`'s doc\n\t * comment); `undefined` means \"use the renderer's own fixed default\".\n\t */\n\tseriesLineWidthPt: number | undefined;\n}\n\nfunction sizePx(entry: ChartStylePartEntryLike | undefined, fallbackPx: number): number {\n\treturn entry?.fontSize !== undefined ? chartFontPx(entry.fontSize) : fallbackPx;\n}\n\nfunction colorOr(entry: ChartStylePartEntryLike | undefined, fallback: string): string {\n\treturn entry?.color ?? fallback;\n}\n\n/**\n * Resolve the font sizes/colours a chart renderer should use for `chartData`,\n * preferring the parsed chart-style part and falling back to this viewer's\n * fixed chart defaults when the part is absent (the common case for charts\n * authored via automation) or leaves a given element unstyled.\n */\nexport function resolveChartStyleDefaults(\n\tchartData: ChartDataLike | undefined,\n): ChartStyleDefaults {\n\tconst def = chartData?.chartStyleDefinition;\n\t// A category/value axis style entry decides tick and axis-title text;\n\t// PowerPoint applies the same size to both in every built-in style, so\n\t// either one (whichever is present) stands in for \"the\" axis default.\n\tconst axisEntry = def?.categoryAxis ?? def?.valueAxis ?? def?.axisTitle;\n\n\treturn {\n\t\tbodyTextPx: sizePx(axisEntry, DEFAULT_CHART_TEXT_PX),\n\t\tdataLabelTextPx: sizePx(def?.dataLabel, DEFAULT_CHART_DATA_LABEL_PX),\n\t\tlegendTextPx: sizePx(def?.legend, DEFAULT_CHART_TEXT_PX),\n\t\ttitleTextPx: sizePx(def?.title, DEFAULT_TITLE_TEXT_PX),\n\t\taxisTextColor: colorOr(axisEntry, DEFAULT_LABEL_COLOR),\n\t\tdataLabelTextColor: colorOr(def?.dataLabel, DEFAULT_LABEL_COLOR),\n\t\tlegendTextColor: colorOr(def?.legend, DEFAULT_LABEL_COLOR),\n\t\ttitleTextColor: colorOr(def?.title, DEFAULT_LABEL_COLOR),\n\t\tgridlineColor: def?.gridlineMajor?.lineColor ?? def?.gridlineMinor?.lineColor,\n\t\tchartAreaFillColor: def?.chartArea?.fillColor,\n\t\tplotAreaFillColor: def?.plotArea?.fillColor,\n\t\tseriesLineWidthPt: def?.dataPointLine?.lineWidth ?? def?.dataPoint?.lineWidth,\n\t};\n}\n","/**\n * Chart title text style: the font every binding draws `vm.title` with.\n *\n * Cascade (highest wins): the title's own `c:tx/c:rich` / `c:txPr` run\n * properties (`PptxChartStyle.titleFont*`), then the chart-style part's\n * title entry, then this viewer's fixed defaults (12 px, semi-bold, slate).\n * Returned as a framework-neutral descriptor the bindings map straight onto\n * SVG `<text>` attributes, so a chart authored with a 24 pt red title reads\n * the same in all five bindings.\n *\n * @module chart-title-style\n */\nimport type { PptxChartData } from 'pptx-viewer-core';\n\nimport { chartFontPx } from './chart-font';\nimport { resolveChartStyleDefaults } from './chart-style-defaults';\n\n/** Semi-bold weight the bindings historically hardcoded for the title. */\nconst DEFAULT_TITLE_FONT_WEIGHT = 600;\n/** Slate-800; the colour the bindings historically hardcoded for the title. */\nconst DEFAULT_TITLE_FILL = '#1e293b';\n\n/** Resolved SVG text attributes for the chart title. */\nexport interface ChartTitleTextStyle {\n\t/** `font-size`, in slide-px. */\n\tfontSize: number;\n\t/** `font-weight`. */\n\tfontWeight: number;\n\t/** `fill`. */\n\tfill: string;\n\t/** `font-family`, only when the title names a typeface. */\n\tfontFamily?: string;\n}\n\n/**\n * The lowest baseline that keeps a title of `fontSizePx` inside the chart:\n * its ascent (about 0.8em) plus the chart's own 8px top margin.\n */\nexport function titleBaselineFor(fontSizePx: number): number {\n\treturn Math.round((fontSizePx * 0.8 + 8) * 100) / 100;\n}\n\n/**\n * Lower an automatic title baseline that a large title font would push out of\n * the chart (see {@link titleBaselineFor}), and move a top legend sitting in\n * the title band down by the same amount so the two do not collide.\n */\nexport function fitTitleBand(\n\tvm: { title: string | undefined; titleY: number; legendY: number; legend: readonly unknown[] },\n\tfontSizePx: number,\n): { titleY: number; legendY: number } {\n\tconst target = titleBaselineFor(fontSizePx);\n\tif (vm.title === undefined || vm.titleY >= target) {\n\t\treturn { titleY: vm.titleY, legendY: vm.legendY };\n\t}\n\tconst delta = target - vm.titleY;\n\tconst topLegend = vm.legend.length > 0 && vm.legendY <= target + 4;\n\treturn { titleY: target, legendY: topLegend ? vm.legendY + delta : vm.legendY };\n}\n\n/**\n * Resolve the title font for `chartData`. Pure; safe to call for a chart with\n * no title (the result is simply unused).\n */\nexport function resolveChartTitleTextStyle(\n\tchartData: PptxChartData | undefined,\n): ChartTitleTextStyle {\n\tconst style = chartData?.style;\n\tconst defaults = resolveChartStyleDefaults(chartData);\n\tconst hasStylePartTitle = chartData?.chartStyleDefinition?.title !== undefined;\n\tconst fontSize =\n\t\tstyle?.titleFontSize !== undefined ? chartFontPx(style.titleFontSize) : defaults.titleTextPx;\n\t// The title's own run properties, then the style part's `cs:title` entry\n\t// (every built-in style authors `b=\"0\"`: PowerPoint's auto title is not\n\t// bold), then the viewer default.\n\tconst bold = style?.titleFontBold ?? chartData?.chartStyleDefinition?.title?.bold;\n\tconst fontWeight = bold === undefined ? DEFAULT_TITLE_FONT_WEIGHT : bold ? 700 : 400;\n\tconst fill =\n\t\tstyle?.titleFontColor ?? (hasStylePartTitle ? defaults.titleTextColor : DEFAULT_TITLE_FILL);\n\tconst fontFamily = style?.titleFontFamily?.trim() || undefined;\n\treturn fontFamily ? { fontSize, fontWeight, fill, fontFamily } : { fontSize, fontWeight, fill };\n}\n","/**\n * Chart title rich text: per-run render spans and the flat-text-edit\n * collapse rule.\n *\n * `PptxChartData.titleRuns` (core) carries the title's per-run bold/italic/\n * size/colour, parsed from `c:title/c:tx/c:rich`; until this module, no\n * binding read it, so a title with several differently-styled runs rendered\n * (and re-saved) as one flat string in a single style. `resolveChartTitleRunSpans`\n * gives every binding a framework-neutral list of `<tspan>` descriptors to\n * draw instead of the single flat `vm.title` text node.\n * `collapseChartTitleRunsForEdit` is the companion write-side rule: when an\n * inspector's flat title-text field is edited, a MULTI-run body collapses to\n * ONE run in the title's dominant style (the run covering most of the\n * text), rather than leaving other runs' stale text behind - see\n * `chart-title-serializer.ts`'s `runsStale` doc for why an edited `title`\n * and an untouched `titleRuns` must not silently disagree. A single-run\n * title is left to the flat `title` patch alone: core's serializer already\n * patches that one run's text in place, preserving whatever formatting this\n * narrow typed model does not carry (e.g. a `schemeClr` reference).\n *\n * @module chart-title-runs\n */\nimport type { PptxChartData, PptxChartTitleRun } from 'pptx-viewer-core';\n\nimport { chartFontPx } from './chart-font';\nimport { resolveChartTitleTextStyle } from './chart-title-style';\n\n/** One resolved `<tspan>` for a chart title run. */\nexport interface ChartTitleRunSpan {\n\t/** This run's text (`a:t`). */\n\ttext: string;\n\t/** `font-size`, in slide-px. */\n\tfontSize: number;\n\t/** `font-weight`. */\n\tfontWeight: number;\n\t/** `font-style`, only when the run is italic. */\n\tfontStyle?: 'italic';\n\t/** `fill`. */\n\tfill: string;\n\t/** `font-family`, only when the title names a typeface. */\n\tfontFamily?: string;\n}\n\n/**\n * Resolve `chartData.titleRuns` into per-run SVG `<tspan>` descriptors, each\n * run's own bold/italic/size/colour falling back to the title's cascade\n * (`resolveChartTitleTextStyle`) for whatever it does not override.\n *\n * Returns `undefined` when the title has no typed runs at all (an auto/plain\n * title, or one authored as a linked-cell reference), so a binding should\n * keep rendering the flat `vm.title` in `vm.titleStyle` unchanged. A single\n * run still resolves to a one-element array: this lets a per-run override\n * (e.g. italic on the title's only run) render even when\n * `resolveChartTitleTextStyle`'s coarser `chartData.style.titleFont*` cascade\n * does not carry it. Its text follows the flat title so single-run edits\n * render immediately while core retains the original run for lossless save.\n */\nexport function resolveChartTitleRunSpans(\n\tchartData: PptxChartData | undefined,\n): ChartTitleRunSpan[] | undefined {\n\tconst runs = chartData?.titleRuns;\n\tif (!runs || runs.length === 0) {\n\t\treturn undefined;\n\t}\n\tconst base = resolveChartTitleTextStyle(chartData);\n\treturn runs.map((run) => ({\n\t\ttext: runs.length === 1 ? (chartData?.title ?? run.text) : run.text,\n\t\tfontSize: run.fontSize !== undefined ? chartFontPx(run.fontSize) : base.fontSize,\n\t\tfontWeight: run.bold !== undefined ? (run.bold ? 700 : 400) : base.fontWeight,\n\t\t...(run.italic ? { fontStyle: 'italic' as const } : {}),\n\t\tfill: run.color ?? base.fill,\n\t\t...(base.fontFamily ? { fontFamily: base.fontFamily } : {}),\n\t}));\n}\n\n/**\n * The dominant style among `runs`: the longest run's (by text length; ties\n * keep the first), since that is the style covering most of the visible\n * title text.\n */\nfunction dominantRunStyle(runs: readonly PptxChartTitleRun[]): Omit<PptxChartTitleRun, 'text'> {\n\tlet best = runs[0];\n\tfor (const run of runs.slice(1)) {\n\t\tif (run.text.length > best.text.length) {\n\t\t\tbest = run;\n\t\t}\n\t}\n\tconst { bold, italic, fontSize, color } = best;\n\treturn {\n\t\t...(bold !== undefined ? { bold } : {}),\n\t\t...(italic !== undefined ? { italic } : {}),\n\t\t...(fontSize !== undefined ? { fontSize } : {}),\n\t\t...(color !== undefined ? { color } : {}),\n\t};\n}\n\n/**\n * Compute the `{ title, titleRuns }` patch for an inspector's flat title-text\n * field being edited to `newText`. Every binding's chart title input should\n * call this instead of patching `title` alone.\n *\n * A title with zero or one run just gets the new flat text (`titleRuns`\n * untouched, letting core's single-run patch path preserve that run's full\n * authored formatting). A title with two or more runs collapses to ONE run\n * carrying `newText` in the dominant style, so the edit does not leave a\n * second, now-stale run's text trailing the new title.\n */\nexport function collapseChartTitleRunsForEdit(\n\tchartData: PptxChartData | undefined,\n\tnewText: string,\n): Pick<PptxChartData, 'title' | 'titleRuns'> {\n\tconst runs = chartData?.titleRuns;\n\tif (!runs || runs.length <= 1) {\n\t\treturn { title: newText };\n\t}\n\treturn { title: newText, titleRuns: [{ ...dominantRunStyle(runs), text: newText }] };\n}\n","/**\n * chart-title-band.ts: where a chart's title sits and how much room it takes\n * at the top of the chart, derived from the title's own font size.\n *\n * Every chart family used to reserve a fixed 20 px band for the title and\n * draw its baseline at y=12..14, which fits the viewer's 12 px default but\n * clips anything larger: PowerPoint's own default title is 14 pt (18.67 px),\n * and an 18 pt title lost its top to the chart's SVG edge, in 2D and in the\n * 3D chrome overlay alike.\n *\n * PowerPoint lays the title out as a text box whose top sits a fixed inset\n * below the chart area's top (about 7.2 pt of chart-area padding plus the\n * title's own 3.6 pt text inset), so its first baseline is that inset plus\n * the font's ascent. For a 14 pt title that puts the baseline 24 pt below the\n * chart top, matching `gt/chart-01`'s measured title baseline (the\n * oblique-3D chrome's `OBLIQUE_TITLE_BASELINE`). The plot area then starts\n * below the title box, after the same 8 px inset the layout keeps at every\n * other edge.\n *\n * `chartTitleBand` is the pure decision; `chartTitleBandFor` resolves the\n * title font for a chart and returns `undefined` for a chart without a title\n * (whose layout is unchanged); `withChartTitleBand` is the view-model\n * post-pass that moves the title baseline and a top legend to match.\n *\n * @module chart-title-band\n */\nimport type { PptxChartData } from 'pptx-viewer-core';\n\nimport { CHART_PX_PER_PT } from './chart-font';\nimport { resolveLegendPlacement } from './chart-legend-placement';\nimport { resolveChartTitleRunSpans } from './chart-title-runs';\nimport { resolveChartTitleTextStyle } from './chart-title-style';\nimport type { ChartViewModel } from './chart-view-model-types';\n\n/** Chart-area padding (7.2 pt) plus the title box's top text inset (3.6 pt), in px. */\nexport const CHART_TITLE_TOP_INSET_PX = 10.8 * CHART_PX_PER_PT;\n/** The title box's bottom text inset (3.6 pt), in px. */\nconst TITLE_BOTTOM_INSET_PX = 3.6 * CHART_PX_PER_PT;\n/** Font ascent above the baseline, as a fraction of the font size. */\nconst TITLE_ASCENT = 0.95;\n/** Font descent below the baseline, as a fraction of the font size. */\nconst TITLE_DESCENT = 0.25;\n/** Baseline-to-baseline distance of a wrapped title, as a fraction of the font size. */\nconst TITLE_LINE_HEIGHT = 1.2;\n/** The fixed title reservation every layout used before the band was font-sized. */\nexport const LEGACY_CHART_TITLE_BAND_PX = 20;\n\n/** Where the title's first baseline sits and how far down its band reaches. */\nexport interface ChartTitleBand {\n\t/** The first line's baseline (`vm.titleY`), in px below the chart top. */\n\tbaselineY: number;\n\t/**\n\t * The title box's bottom edge, in px below the chart top. Layouts add this\n\t * to their 8 px top inset, so the plot starts 8 px below the title box.\n\t */\n\tbandHeight: number;\n}\n\n/**\n * The title band for a title drawn at `fontSizePx` over `lines` lines.\n * Pure. Non-finite or non-positive inputs fall back to a single 12 px line.\n */\nexport function chartTitleBand(fontSizePx: number, lines = 1): ChartTitleBand {\n\tconst size = Number.isFinite(fontSizePx) && fontSizePx > 0 ? fontSizePx : 12;\n\tconst lineCount = Number.isFinite(lines) && lines >= 1 ? Math.floor(lines) : 1;\n\tconst baselineY = CHART_TITLE_TOP_INSET_PX + size * TITLE_ASCENT;\n\tconst lastBaseline = baselineY + (lineCount - 1) * size * TITLE_LINE_HEIGHT;\n\treturn {\n\t\tbaselineY,\n\t\tbandHeight: lastBaseline + size * TITLE_DESCENT + TITLE_BOTTOM_INSET_PX,\n\t};\n}\n\n/** The largest font size the title draws with: its base style or any larger run. */\nexport function chartTitleFontPx(chartData: PptxChartData | undefined): number {\n\tconst base = resolveChartTitleTextStyle(chartData).fontSize;\n\tconst runs = resolveChartTitleRunSpans(chartData) ?? [];\n\treturn runs.reduce((max, run) => Math.max(max, run.fontSize), base);\n}\n\n/**\n * The title band for `chartData`, or `undefined` when the chart shows no\n * title (`style.hasTitle` off), so a title-less chart's layout is untouched.\n * The title renders as one SVG `<text>` line, so the band is one line tall.\n */\nexport function chartTitleBandFor(\n\tchartData: PptxChartData | undefined,\n): ChartTitleBand | undefined {\n\tif (!chartData?.style?.hasTitle) {\n\t\treturn undefined;\n\t}\n\treturn chartTitleBand(chartTitleFontPx(chartData));\n}\n\n/**\n * The height a layout reserves above its plot for the title: the band's\n * height, or 0 without a title. Replaces the fixed `hasTitle ? 20 : 0`.\n */\nexport function chartTitleReservePx(chartData: PptxChartData | undefined): number {\n\treturn chartTitleBandFor(chartData)?.bandHeight ?? 0;\n}\n\n/**\n * Put a finished view-model's title on the font-sized baseline, and move a\n * top (`'t'`) legend down by however much the band grew past the legacy\n * 20 px reservation, so it stays between the title and the plot. A chart\n * without a title, or a view-model without one, is returned unchanged.\n */\nexport function withChartTitleBand(vm: ChartViewModel, chartData: PptxChartData): ChartViewModel {\n\tconst band = chartTitleBandFor(chartData);\n\tif (!band || vm.title === undefined) {\n\t\treturn vm;\n\t}\n\tconst placement = resolveLegendPlacement(chartData.style?.legendPosition ?? 'b');\n\tconst topLegend = chartData.style?.hasLegend && placement.side === 't' && !placement.overlaysPlot;\n\treturn {\n\t\t...vm,\n\t\ttitleY: band.baselineY,\n\t\t...(topLegend ? { legendY: vm.legendY + band.bandHeight - LEGACY_CHART_TITLE_BAND_PX } : {}),\n\t};\n}\n","import type {\n\tPptxChartData,\n\tPptxChartSeries,\n\tPptxChartStyle,\n\tPptxChartAxisFormatting,\n} from 'pptx-viewer-core';\n\nimport { axisTargetIntervals, niceValueAxisBounds } from './chart-axis-nice';\nimport { chartFontPx } from './chart-font';\nimport { reserveLegendSpace } from './chart-legend-placement';\nimport { formatChartNumber } from './chart-number-format';\nimport { chartTitleBand } from './chart-title-band';\n\n/**\n * Framework-agnostic chart helpers, a focused Vue port of the React package's\n * `viewer/utils/chart-helpers.ts`, `chart-layout.ts`, and\n * `chart-style-palettes.ts`.\n *\n * This module only covers the common-type renderers (bar / column / stacked /\n * line / area / pie / doughnut) and the shared chrome. Advanced axis/overlay\n * features (log axes, secondary axes, display units, trendlines, error bars,\n * data tables) live in `chart-axis.ts` / `chart-axis-render.ts` /\n * `chart-cartesian.ts` and are consumed via `chart/ChartViewModelSvg.vue`.\n *\n * These small pure helpers are an extraction candidate: long-term they (and\n * their React counterparts) should live in a shared, framework-agnostic\n * package so all three UI bindings reuse one implementation.\n */\n\n// ── Style palettes ───────────────────────────────────────────────\n\nconst ACCENT1 = '#4472C4';\nconst ACCENT2 = '#ED7D31';\nconst ACCENT3 = '#A5A5A5';\nconst ACCENT4 = '#FFC000';\nconst ACCENT5 = '#5B9BD5';\nconst ACCENT6 = '#70AD47';\n\nconst ACCENTS = [ACCENT1, ACCENT2, ACCENT3, ACCENT4, ACCENT5, ACCENT6];\n\n/**\n * The default fallback palette used when no chart style is specified.\n *\n * The Office accent cycle (accent1-6 plus the two chart extras), i.e. what\n * PowerPoint paints for a chart with no style part. This MUST stay identical\n * to `chart-view-model.ts`'s `DEFAULT_PALETTE` (which aliases it): the two\n * used to differ (this one was a Tailwind-ish set), and since the bindings\n * reach the shared engine through both entry points, the same deck fell back\n * to two different palettes depending on the binding.\n */\nexport const DEFAULT_CHART_PALETTE: ReadonlyArray<string> = [\n\t'#4472C4',\n\t'#ED7D31',\n\t'#A5A5A5',\n\t'#FFC000',\n\t'#5B9BD5',\n\t'#70AD47',\n\t'#FF0000',\n\t'#00B0F0',\n];\n\n/** Parse a hex colour string (#RRGGBB) into [r, g, b]. */\nfunction hexToRgb(hex: string): [number, number, number] {\n\tconst h = hex.replace('#', '');\n\treturn [\n\t\tparseInt(h.substring(0, 2), 16),\n\t\tparseInt(h.substring(2, 4), 16),\n\t\tparseInt(h.substring(4, 6), 16),\n\t];\n}\n\n/** Convert [r, g, b] back to #RRGGBB. */\nfunction rgbToHex(r: number, g: number, b: number): string {\n\tconst clamp = (v: number): number => Math.max(0, Math.min(255, Math.round(v)));\n\treturn `#${clamp(r).toString(16).padStart(2, '0')}${clamp(g)\n\t\t.toString(16)\n\t\t.padStart(2, '0')}${clamp(b).toString(16).padStart(2, '0')}`;\n}\n\n/** Apply a tint (lighten towards white). `amount` in [0, 1]. */\nfunction tint(hex: string, amount: number): string {\n\tconst [r, g, b] = hexToRgb(hex);\n\treturn rgbToHex(r + (255 - r) * amount, g + (255 - g) * amount, b + (255 - b) * amount);\n}\n\n/** Apply a shade (darken towards black). `amount` in [0, 1]. */\nfunction shade(hex: string, amount: number): string {\n\tconst [r, g, b] = hexToRgb(hex);\n\treturn rgbToHex(r * (1 - amount), g * (1 - amount), b * (1 - amount));\n}\n\nfunction colorfulSequential(offset: number): string[] {\n\tconst out: string[] = [];\n\tfor (let i = 0; i < 8; i++) {\n\t\tout.push(ACCENTS[(i + offset) % ACCENTS.length]);\n\t}\n\treturn out;\n}\n\nfunction monochromaticRamp(base: string): string[] {\n\treturn [\n\t\tshade(base, 0.5),\n\t\tshade(base, 0.35),\n\t\tshade(base, 0.15),\n\t\tbase,\n\t\ttint(base, 0.2),\n\t\ttint(base, 0.4),\n\t\ttint(base, 0.6),\n\t\ttint(base, 0.8),\n\t];\n}\n\nfunction colorfulVariant(offset: number, tintAmount: number): string[] {\n\treturn ACCENTS.map((_, i) => {\n\t\tconst idx = (i + offset) % ACCENTS.length;\n\t\treturn tintAmount > 0 ? tint(ACCENTS[idx], tintAmount) : shade(ACCENTS[idx], -tintAmount);\n\t}).concat([\n\t\ttint(ACCENTS[offset % ACCENTS.length], 0.4),\n\t\tshade(ACCENTS[(offset + 1) % ACCENTS.length], 0.2),\n\t]);\n}\n\nfunction darkPalette(offset: number, shadeAmount: number): string[] {\n\treturn colorfulSequential(offset).map((c) => shade(c, shadeAmount));\n}\n\nfunction tonedPalette(offset: number, tintAmount: number): string[] {\n\treturn colorfulSequential(offset).map((c) => tint(c, tintAmount));\n}\n\nfunction buildPalette(styleId: number): string[] {\n\tconst id = Math.max(1, Math.min(48, styleId));\n\tif (id <= 8) {\n\t\treturn colorfulSequential(id - 1);\n\t}\n\tif (id <= 16) {\n\t\tconst accentIdx = (id - 9) % ACCENTS.length;\n\t\treturn monochromaticRamp(ACCENTS[accentIdx]);\n\t}\n\tif (id <= 24) {\n\t\tconst sub = id - 17;\n\t\tconst tintAmt = sub < 4 ? sub * 0.1 : -(sub - 4) * 0.1;\n\t\treturn colorfulVariant(sub, tintAmt);\n\t}\n\tif (id <= 32) {\n\t\tconst sub = id - 25;\n\t\treturn darkPalette(sub, 0.25 + (sub % 4) * 0.1);\n\t}\n\tif (id <= 40) {\n\t\tconst sub = id - 33;\n\t\treturn tonedPalette(sub, 0.15 + (sub % 4) * 0.08);\n\t}\n\tconst sub = id - 41;\n\treturn tonedPalette(sub, 0.4 + (sub % 4) * 0.1);\n}\n\nconst paletteCache = new Map<number, string[]>();\n\n/**\n * Get the colour palette for a chart style index (1–48). Falls back to the\n * default palette when undefined or out of range.\n */\nexport function getChartStylePalette(styleId?: number): ReadonlyArray<string> {\n\tif (styleId === undefined || styleId < 1 || styleId > 48) {\n\t\treturn DEFAULT_CHART_PALETTE;\n\t}\n\tlet palette = paletteCache.get(styleId);\n\tif (!palette) {\n\t\tpalette = buildPalette(styleId);\n\t\tpaletteCache.set(styleId, palette);\n\t}\n\treturn palette;\n}\n\n/**\n * Resolve a series colour: explicit colour → marker fill → parsed palette →\n * style palette. The marker fallback covers scatter series authored with\n * `c:ser/c:spPr/a:ln/a:noFill` plus a coloured `c:marker/c:spPr`: the points\n * paint the marker fill directly, so the legend swatch must match it rather\n * than fall back to the palette.\n */\nexport function seriesColor(\n\tseries: PptxChartSeries,\n\tindex: number,\n\tstyleId?: number,\n\tcolorPalette?: string[],\n): string {\n\tconst explicit = series.color ?? series.marker?.spPr?.fillColor;\n\tif (explicit) {\n\t\treturn explicit;\n\t}\n\tif (colorPalette && colorPalette.length > 0) {\n\t\treturn colorPalette[index % colorPalette.length];\n\t}\n\tconst palette = getChartStylePalette(styleId);\n\treturn palette[index % palette.length];\n}\n\n/** Palette colour for an index with no series object (e.g. per-slice pie colouring). */\nexport function paletteColor(index: number, styleId?: number, colorPalette?: string[]): string {\n\tif (colorPalette && colorPalette.length > 0) {\n\t\treturn colorPalette[index % colorPalette.length];\n\t}\n\tconst palette = getChartStylePalette(styleId);\n\treturn palette[index % palette.length];\n}\n\n// ── Value range ──────────────────────────────────────────────────\n\nexport interface ValueRange {\n\tmin: number;\n\tmax: number;\n\tspan: number;\n\t/** When true, the range represents log-scaled values (see `chart-axis.ts`). */\n\tlogScale?: boolean;\n\t/** Logarithmic base (e.g. 10, 2, Math.E). Only meaningful when logScale is true. */\n\tlogBase?: number;\n\t/** Whether values increase from top to bottom (`c:orientation=\"maxMin\"`). */\n\treverseOrder?: boolean;\n\t/**\n\t * Step between major gridlines when the bounds came from the automatic\n\t * scale, which always spans a whole number of them. Tick generators use it\n\t * instead of dividing the span evenly, which is what keeps the labels on\n\t * round numbers. Absent when an explicit `c:min`/`c:max` overrode the\n\t * automatic bounds, since the unit no longer divides them.\n\t */\n\tmajorUnit?: number;\n}\n\n/**\n * Automatic Y-axis range, on PowerPoint's terms: zero-anchored where that reads\n * sensibly, padded, and rounded out to whole major units. See\n * `chart-axis-nice.ts` for the rules. Running the axis to the raw data maximum\n * instead put the top gridline on whatever the tallest bar happened to be.\n *\n * @param plotHeightPx The chart's plot-area height (same \"px\" unit\n * `computePlotLayout` returns), when the caller has it. PowerPoint's real\n * gridline count depends on how much vertical room the axis has to label\n * them in; omitting this falls back to a constant tuned for a short chart\n * (see `axisTargetIntervals`'s doc comment).\n */\nexport function computeValueRange(\n\tseries: ReadonlyArray<PptxChartSeries>,\n\tplotHeightPx?: number,\n): ValueRange {\n\tconst allValues = series.flatMap((s) => s.values);\n\tif (allValues.length === 0) {\n\t\treturn { min: 0, max: 1, span: 1 };\n\t}\n\tconst { min, max, majorUnit } = niceValueAxisBounds(\n\t\tMath.min(...allValues),\n\t\tMath.max(...allValues),\n\t\tplotHeightPx !== undefined ? axisTargetIntervals(plotHeightPx) : undefined,\n\t);\n\treturn { min, max, span: Math.max(max - min, Number.EPSILON), majorUnit };\n}\n\n/**\n * Map a data value to a Y pixel coordinate (top = max, bottom = min).\n * Routes through logarithmic scaling when `range.logScale` is set (the log\n * helpers live in `chart-axis.ts`; the branch is inlined here to avoid a\n * circular import).\n */\nexport function valueToY(val: number, range: ValueRange, topY: number, bottomY: number): number {\n\tconst usable = bottomY - topY;\n\tlet ratio: number;\n\tif (range.logScale && range.logBase) {\n\t\tconst base = range.logBase;\n\t\tconst clampedVal = Math.max(val, range.min);\n\t\tconst logVal = Math.log(clampedVal) / Math.log(base);\n\t\tconst logMin = Math.log(range.min) / Math.log(base);\n\t\tratio = (logVal - logMin) / range.span;\n\t} else {\n\t\tratio = (val - range.min) / range.span;\n\t}\n\treturn range.reverseOrder ? topY + ratio * usable : bottomY - ratio * usable;\n}\n\n/**\n * Compact axis-value formatting (1.2K / 3.4M / integer / one-decimal).\n *\n * `formatCode` is the chart's own `c:numFmt/@formatCode`. When the source\n * declares one - `0%`, `#,##0`, `$#,##0.00` - it WINS: the cached values behind\n * a percentage chart are fractions, and the compact fallback renders them as\n * `0.5` where PowerPoint shows `50%`. Codes outside the supported subset fall\n * through to the compact form, which is what every caller did before.\n */\nexport function formatAxisValue(val: number, formatCode?: string): string {\n\tconst formatted = formatChartNumber(val, formatCode);\n\tif (formatted !== undefined) {\n\t\treturn formatted;\n\t}\n\tif (Math.abs(val) >= 1_000_000) {\n\t\treturn `${(val / 1_000_000).toFixed(1)}M`;\n\t}\n\tif (Math.abs(val) >= 1_000) {\n\t\treturn `${(val / 1_000).toFixed(1)}K`;\n\t}\n\tif (Number.isInteger(val)) {\n\t\treturn String(val);\n\t}\n\treturn val.toFixed(1);\n}\n\n// ── Layout ───────────────────────────────────────────────────────\n\nexport interface PlotLayout {\n\tplotLeft: number;\n\tplotTop: number;\n\tplotRight: number;\n\tplotBottom: number;\n\tplotWidth: number;\n\tplotHeight: number;\n\tsvgWidth: number;\n\tsvgHeight: number;\n}\n\n/**\n * Reserved-space options for `computeLayout` (secondary axes + data table).\n * Structurally identical to `LayoutOptions` in `chart-axis.ts`; declared here\n * as a plain shape to avoid a circular import (chart-axis depends on this file).\n */\nexport interface ComputeLayoutOptions {\n\thasSecondaryValueAxis?: boolean;\n\thasSecondaryCategoryAxis?: boolean;\n\thasDataTable?: boolean;\n\tdataTableRowCount?: number;\n}\n\n/**\n * Compute the plot rectangle within the SVG, reserving room for axes, title,\n * legend, optional secondary axes, and an optional data table.\n */\nexport function computeLayout(\n\telementWidth: number,\n\telementHeight: number,\n\tstyle: PptxChartStyle | undefined,\n\thasAxes: boolean,\n\tlegendPos: string,\n\toptions?: ComputeLayoutOptions,\n): PlotLayout {\n\t// Match the element frame exactly; bindings stretch the viewBox with\n\t// preserveAspectRatio \"none\", so a minimum would scale non-uniformly\n\t// (see computePlotLayout in chart-view-model.ts).\n\tconst svgWidth = Math.max(1, elementWidth);\n\tconst svgHeight = Math.max(1, elementHeight);\n\tlet plotLeft = hasAxes ? 48 : 8;\n\tlet plotTop = 8;\n\tlet plotRight = svgWidth - 8;\n\tlet plotBottom = svgHeight - (hasAxes ? 24 : 8);\n\n\tif (style?.hasTitle) {\n\t\tplotTop += chartTitleBand(\n\t\t\tstyle.titleFontSize !== undefined ? chartFontPx(style.titleFontSize) : 12,\n\t\t).bandHeight;\n\t}\n\tif (style?.hasLegend) {\n\t\t// `tr` (top-right corner) overlays the plot per PowerPoint's own\n\t\t// quick-layout behaviour: no band is reserved for it.\n\t\t({ plotLeft, plotTop, plotRight, plotBottom } = reserveLegendSpace(legendPos, {\n\t\t\tplotLeft,\n\t\t\tplotTop,\n\t\t\tplotRight,\n\t\t\tplotBottom,\n\t\t}));\n\t}\n\n\t// Reserve space for a secondary value axis on the right.\n\tif (options?.hasSecondaryValueAxis) {\n\t\tplotRight -= 40;\n\t}\n\t// Reserve space for a secondary category axis on the top.\n\tif (options?.hasSecondaryCategoryAxis) {\n\t\tplotTop += 16;\n\t}\n\t// Reserve space for a data table below the chart.\n\tif (options?.hasDataTable) {\n\t\tconst rowCount = options.dataTableRowCount ?? 1;\n\t\tplotBottom -= 14 + rowCount * 14;\n\t}\n\n\tconst pw = Math.max(plotRight - plotLeft, 1);\n\tconst ph = Math.max(plotBottom - plotTop, 1);\n\treturn {\n\t\tplotLeft,\n\t\tplotTop,\n\t\tplotRight: plotLeft + pw,\n\t\tplotBottom: plotTop + ph,\n\t\tplotWidth: pw,\n\t\tplotHeight: ph,\n\t\tsvgWidth,\n\t\tsvgHeight,\n\t};\n}\n\n// ── Derived helpers ──────────────────────────────────────────────\n\n/** Find the primary value-axis formatting (non-right, or first valAx). */\nexport function getPrimaryValueAxis(\n\taxes: PptxChartAxisFormatting[] | undefined,\n): PptxChartAxisFormatting | undefined {\n\tif (!axes) {\n\t\treturn undefined;\n\t}\n\treturn (\n\t\taxes.find((a) => a.axisType === 'valAx' && a.axPos !== 'r') ??\n\t\taxes.find((a) => a.axisType === 'valAx')\n\t);\n}\n\n/**\n * Resolve category labels for a chart: use the declared categories, otherwise\n * synthesise 1-based labels for the longest series.\n */\nexport function resolveCategoryLabels(chartData: PptxChartData): string[] {\n\tif (chartData.categories.length > 0) {\n\t\treturn chartData.categories;\n\t}\n\tconst longest = chartData.series.reduce((max, s) => Math.max(max, s.values.length), 0);\n\treturn Array.from({ length: longest }, (_, i) => String(i + 1));\n}\n","/**\n * The chart-area (and plot-area) background, resolved once for every binding.\n *\n * All five viewers painted a hardcoded `#0f172a11` wash across the whole chart\n * SVG. PowerPoint decks routinely write `<c:spPr><a:noFill/></c:spPr>` on\n * `c:chartSpace` and `c:plotArea` precisely so the chart floats on the slide;\n * the wash boxed every such chart into a visible grey panel that is not in the\n * source. Honouring the authored fill (an explicit `<a:noFill/>`) was the\n * first fix, but a chart with NO `c:spPr` at all (the common case: only a\n * deliberately-styled chart writes one) still fell back to the same synthetic\n * wash, which is just as wrong: real PowerPoint never paints a highlight box\n * behind an unstyled chart, it is fully transparent like the `noFill` case.\n * Measured against a real-world deck (a plain single-series bar chart with no\n * `c:chartSpace/c:spPr` at all) PowerPoint's own export shows no grey\n * anywhere; this module now treats \"no fill recorded\" the same whether the\n * source said `noFill` explicitly or said nothing, matching `plotAreaFill`\n * below, which never had a synthetic default in the first place.\n */\n\nimport type { PptxChartData } from 'pptx-viewer-core';\n\n/**\n * The wash the bindings used to paint whenever a chart declared no fill of\n * its own. No longer used as an automatic default for real chart data (see\n * the module doc comment); kept only for `buildFallbackViewModel`'s\n * unsupported/empty-chart placeholder, which has no chart data to read a fill\n * from and still wants a visible box to represent \"a chart goes here\".\n */\nexport const DEFAULT_CHART_AREA_FILL = '#0f172a11';\n\n/** Resolve one recorded fill value to an SVG `fill`, or `undefined` to skip. */\nfunction resolve(fill: string | undefined, fallback: string | undefined): string | undefined {\n\tif (fill === 'none') {\n\t\treturn undefined;\n\t}\n\treturn fill ?? fallback;\n}\n\n/**\n * SVG `fill` for the chart-area rect, or `undefined` when nothing should be\n * painted: the source declared `a:noFill`, or (matching real PowerPoint)\n * simply never wrote a `c:chartSpace/c:spPr` at all.\n */\nexport function chartAreaFill(chartData: PptxChartData | undefined): string | undefined {\n\treturn resolve(chartData?.style?.chartAreaFill, undefined);\n}\n\n/**\n * SVG `fill` for the plot-area rect, or `undefined` when nothing should be\n * painted. Unlike the chart area there is no default wash: a plot area that\n * says nothing inherits the chart area behind it.\n */\nexport function plotAreaFill(chartData: PptxChartData | undefined): string | undefined {\n\treturn resolve(chartData?.style?.plotAreaFill, undefined);\n}\n\n/**\n * PowerPoint's own \"Rounded corners\" checkbox radius (Format Chart Area),\n * approximated as a fixed slide-px value close to its rendered look; there is\n * no authored radius value in `c:roundedCorners` (it is a plain boolean), so\n * every rounded chart gets the same corner.\n */\nconst ROUNDED_CORNERS_RADIUS_PX = 8;\n\n/**\n * SVG `rx`/`ry` corner radius for the chart-area rect when\n * `c:chartSpace/c:roundedCorners` is set, or `undefined` (square corners)\n * otherwise.\n */\nexport function chartAreaCornerRadius(chartData: PptxChartData | undefined): number | undefined {\n\treturn chartData?.roundedCorners === true ? ROUNDED_CORNERS_RADIUS_PX : undefined;\n}\n","/**\n * The box PowerPoint draws around a chart data label, sized from the label\n * text's MEASURED width.\n *\n * COM ground truth (`DataLabel.Width/Height` of boxed pie labels in\n * `chart-pie-best-fit.pptx`, 12pt Calibri): the box is the text's advance\n * width plus 3pt of padding on each side, and one line box (ascent + descent\n * + line gap, 1.2207em for Calibri) plus 1.5pt above and below: \"25\" is\n * 18.16 x 17.65pt, \"Cat 1\" (two lines) 30.86 x 32.3pt. The width used to be\n * estimated as 0.52em per character, which is about right for digits but\n * off by a third for narrow or wide text.\n *\n * The width comes from a {@link ChartTextMeasurer}. By default that is a\n * shared `<canvas>` 2D context, which measures identically in all five\n * bindings; a host (or a test) can inject its own with\n * {@link setChartTextMeasurer}. Where there is no DOM (node, vitest's default\n * environment) the old per-character estimate is the fallback.\n *\n * @module chart-label-measure\n */\nimport type { SvgText } from './chart-svg-primitives';\n\n/** The font a label paints with, as its `SvgText` carries it. */\nexport interface ChartTextFont {\n\t/** px */\n\tfontSize: number;\n\tfontFamily?: string;\n\tfontWeight?: 'normal' | 'bold';\n\tfontStyle?: 'normal' | 'italic';\n}\n\n/** Measures the advance width of `text` in px, or `undefined` when it cannot. */\nexport type ChartTextMeasurer = (text: string, font: ChartTextFont) => number | undefined;\n\n/** px per pt. */\nconst PX_PER_PT = 4 / 3;\n/** COM: 3pt of padding left and right of the text. */\nexport const DATA_LABEL_PAD_X = 3 * PX_PER_PT;\n/** COM: 1.5pt of padding above and below the text. */\nexport const DATA_LABEL_PAD_Y = 1.5 * PX_PER_PT;\n/** One line box as a fraction of the font size (Calibri's win ascent + descent). */\nexport const DATA_LABEL_LINE_HEIGHT = 1.2207;\n/** Where the line box's top sits above the baseline, as a fraction of the font size. */\nconst ASCENT = 0.952;\n\nlet injected: ChartTextMeasurer | undefined;\nlet canvasContext: CanvasRenderingContext2D | null | undefined;\n\n/**\n * Replace the text measurer (`undefined` restores the canvas default). Meant\n * for hosts that render charts somewhere a canvas cannot measure, and tests.\n */\nexport function setChartTextMeasurer(measurer: ChartTextMeasurer | undefined): void {\n\tinjected = measurer;\n}\n\nfunction canvasMeasure(text: string, font: ChartTextFont): number | undefined {\n\tif (canvasContext === undefined) {\n\t\ttry {\n\t\t\tcanvasContext =\n\t\t\t\ttypeof document === 'undefined' ? null : document.createElement('canvas').getContext('2d');\n\t\t} catch {\n\t\t\tcanvasContext = null;\n\t\t}\n\t}\n\tif (!canvasContext) {\n\t\treturn undefined;\n\t}\n\tconst style = font.fontStyle === 'italic' ? 'italic ' : '';\n\tconst weight = font.fontWeight === 'bold' ? 'bold ' : '';\n\tconst family = font.fontFamily ? `\"${font.fontFamily}\", sans-serif` : 'sans-serif';\n\tcanvasContext.font = `${style}${weight}${font.fontSize}px ${family}`;\n\tconst width = canvasContext.measureText(text).width;\n\treturn Number.isFinite(width) && width > 0 ? width : undefined;\n}\n\n/** The old per-character estimate, kept as the no-DOM fallback. */\nexport function estimateChartTextWidth(text: string, fontSize: number): number {\n\treturn text.length * fontSize * 0.52;\n}\n\n/** The advance width of `text` in px: measured when possible, else estimated. */\nexport function measureChartTextWidth(text: string, font: ChartTextFont): number {\n\tif (!text) {\n\t\treturn 0;\n\t}\n\tconst measured = injected ? injected(text, font) : canvasMeasure(text, font);\n\treturn measured ?? estimateChartTextWidth(text, font.fontSize);\n}\n\n/** A label box's size in px: the widest line plus padding, by the line count. */\nexport function dataLabelBoxSize(label: SvgText): { w: number; h: number } {\n\tconst lines = label.text.split('\\n');\n\tconst font: ChartTextFont = {\n\t\tfontSize: label.fontSize,\n\t\t...(label.fontFamily ? { fontFamily: label.fontFamily } : {}),\n\t\t...(label.fontWeight ? { fontWeight: label.fontWeight } : {}),\n\t\t...(label.fontStyle ? { fontStyle: label.fontStyle } : {}),\n\t};\n\tconst textWidth = Math.max(...lines.map((line) => measureChartTextWidth(line, font)));\n\treturn {\n\t\tw: textWidth + DATA_LABEL_PAD_X * 2,\n\t\th: lines.length * label.fontSize * DATA_LABEL_LINE_HEIGHT + DATA_LABEL_PAD_Y * 2,\n\t};\n}\n\n/** The rectangle PowerPoint draws around `label`, from its anchor and baseline. */\nexport function dataLabelBox(label: SvgText): { x: number; y: number; w: number; h: number } {\n\tconst { w, h } = dataLabelBoxSize(label);\n\tconst x =\n\t\tlabel.textAnchor === 'middle'\n\t\t\t? label.x - w / 2\n\t\t\t: label.textAnchor === 'end'\n\t\t\t\t? label.x - w + DATA_LABEL_PAD_X\n\t\t\t\t: label.x - DATA_LABEL_PAD_X;\n\tconst centred = label.dominantBaseline === 'central' || label.dominantBaseline === 'middle';\n\tconst y = centred ? label.y - h / 2 : label.y - label.fontSize * ASCENT - DATA_LABEL_PAD_Y;\n\treturn { x, y, w, h };\n}\n","/**\n * chart-label-lines.ts: turn a data label whose text contains line breaks\n * (for example a pie's default \"Category\" + newline + \"25%\") into one\n * single-line `SvgText` per line.\n *\n * SVG `<text>` collapses a newline to a space, and each binding paints an\n * `SvgText` as one `<text>` node, so splitting here (pure, shared) makes every\n * binding draw the lines without any template change.\n *\n * @module chart-label-lines\n */\nimport { DATA_LABEL_LINE_HEIGHT } from './chart-label-measure';\nimport type { SvgText } from './chart-svg-primitives';\n\n/**\n * Split `label` on `\\n` into stacked single-line labels. A single-line label is\n * returned as-is (same object). A vertically centred label (`central` /\n * `middle`) stays centred as a block; otherwise `y` is the first line's\n * baseline and the rest stack below it.\n */\nexport function splitLabelLines(label: SvgText): SvgText[] {\n\tconst lines = label.text.split(/\\r?\\n/);\n\tif (lines.length < 2) {\n\t\treturn [label];\n\t}\n\tconst step = label.fontSize * DATA_LABEL_LINE_HEIGHT;\n\tconst centred = label.dominantBaseline === 'central' || label.dominantBaseline === 'middle';\n\tconst top = centred ? label.y - ((lines.length - 1) * step) / 2 : label.y;\n\treturn lines.map((text, i) => ({ ...label, text, y: top + i * step }));\n}\n","import type { PptxChartAxisFormatting, PptxChartSeries } from 'pptx-viewer-core';\n\nimport type { ValueRange } from './chart-helpers';\nimport { computeValueRange } from './chart-helpers';\n\nconst LOG_EXPONENT_TOLERANCE = 1e-12;\n\n/** Compute a logarithmic range snapped to powers of the requested base. */\nexport function computeLogValueRange(\n\tseries: ReadonlyArray<PptxChartSeries>,\n\tlogBase: number,\n): ValueRange {\n\tconst allValues = series.flatMap((item) => item.values).filter((value) => value > 0);\n\tif (allValues.length === 0) {\n\t\treturn { min: 1, max: logBase, span: 1, logScale: true, logBase };\n\t}\n\tconst dataMin = Math.min(...allValues);\n\tconst dataMax = Math.max(...allValues);\n\tconst logMin = Math.floor(Math.log(dataMin) / Math.log(logBase));\n\tconst logMax = Math.ceil(Math.log(dataMax) / Math.log(logBase));\n\tconst min = logBase ** logMin;\n\tconst max = logBase ** Math.max(logMax, logMin + 1);\n\treturn {\n\t\tmin,\n\t\tmax,\n\t\tspan: Math.max(Math.log(max) / Math.log(logBase) - Math.log(min) / Math.log(logBase), 1),\n\t\tlogScale: true,\n\t\tlogBase,\n\t};\n}\n\n/**\n * Compute a value range using one parsed value axis's scale and bounds.\n *\n * @param plotHeightPx The chart's plot-area height, when known; forwarded to\n * `computeValueRange`'s automatic-scale gridline count (see\n * `axisTargetIntervals`'s doc comment). Not used on the log-scale branch,\n * which snaps to powers of the log base regardless of chart size.\n */\nexport function computeValueRangeForAxis(\n\tseries: ReadonlyArray<PptxChartSeries>,\n\taxis: PptxChartAxisFormatting | undefined,\n\tplotHeightPx?: number,\n): ValueRange {\n\tconst requestedLogBase = axis?.logBase ?? 10;\n\tconst logBase =\n\t\taxis?.logScale && Number.isFinite(requestedLogBase) && requestedLogBase > 1\n\t\t\t? requestedLogBase\n\t\t\t: axis?.logScale\n\t\t\t\t? 10\n\t\t\t\t: undefined;\n\tconst automatic = logBase\n\t\t? computeLogValueRange(series, logBase)\n\t\t: computeValueRange(series, plotHeightPx);\n\tconst validMin =\n\t\ttypeof axis?.min === 'number' && Number.isFinite(axis.min) && (!logBase || axis.min > 0)\n\t\t\t? axis.min\n\t\t\t: undefined;\n\tconst validMax =\n\t\ttypeof axis?.max === 'number' && Number.isFinite(axis.max) && (!logBase || axis.max > 0)\n\t\t\t? axis.max\n\t\t\t: undefined;\n\tconst min = validMin ?? automatic.min;\n\tlet max = validMax ?? automatic.max;\n\t// An explicit bound breaks the automatic scale's guarantee that the span is a\n\t// whole number of major units, so the unit no longer describes these bounds.\n\tconst majorUnit =\n\t\tvalidMin === undefined && validMax === undefined ? automatic.majorUnit : undefined;\n\tif (max <= min) {\n\t\tmax = logBase ? min * logBase : min + 1;\n\t}\n\tconst span = logBase\n\t\t? Math.log(max) / Math.log(logBase) - Math.log(min) / Math.log(logBase)\n\t\t: max - min;\n\treturn {\n\t\tmin,\n\t\tmax,\n\t\tspan: Math.max(span, Number.EPSILON),\n\t\t...(majorUnit !== undefined ? { majorUnit } : {}),\n\t\t...(logBase ? { logScale: true, logBase } : {}),\n\t\t...(axis?.orientation === 'maxMin' ? { reverseOrder: true } : {}),\n\t};\n}\n\n/** Map a data value to a logarithmic Y coordinate. */\nexport function valueToYLog(val: number, range: ValueRange, topY: number, bottomY: number): number {\n\tconst base = range.logBase ?? 10;\n\tconst logValue = Math.log(Math.max(val, range.min)) / Math.log(base);\n\tconst logMin = Math.log(range.min) / Math.log(base);\n\tconst ratio = (logValue - logMin) / range.span;\n\treturn range.reverseOrder ? topY + ratio * (bottomY - topY) : bottomY - ratio * (bottomY - topY);\n}\n\n/** Generate one tick for each power of the range's logarithmic base. */\nexport function generateLogTicks(range: ValueRange): number[] {\n\tif (!range.logScale || !range.logBase) {\n\t\treturn [];\n\t}\n\tconst base = range.logBase;\n\tconst logMin = Math.log(range.min) / Math.log(base);\n\tconst logMax = Math.log(range.max) / Math.log(base);\n\tconst firstExponent = Math.ceil(logMin - LOG_EXPONENT_TOLERANCE);\n\tconst lastExponent = Math.floor(logMax + LOG_EXPONENT_TOLERANCE);\n\tif (lastExponent < firstExponent) {\n\t\treturn range.min === range.max ? [range.min] : [range.min, range.max];\n\t}\n\treturn Array.from(\n\t\t{ length: lastExponent - firstExponent + 1 },\n\t\t(_unused, index) => base ** (firstExponent + index),\n\t);\n}\n\nfunction generateIntervalTicks(range: ValueRange, unit: number): number[] {\n\tif (!Number.isFinite(unit) || unit <= 0 || range.logScale) {\n\t\treturn [];\n\t}\n\tconst tolerance = Math.max(1, Math.abs(range.min), Math.abs(range.max)) * 1e-12;\n\tconst first = Math.ceil((range.min - tolerance) / unit);\n\tconst last = Math.floor((range.max + tolerance) / unit);\n\tconst count = Math.min(Math.max(last - first + 1, 0), 2000);\n\treturn Array.from({ length: count }, (_, index) => (first + index) * unit);\n}\n\n/** Generate major tick values, honoring an explicit `c:majorUnit`. */\nexport function generateAxisTicks(\n\trange: ValueRange,\n\taxis: PptxChartAxisFormatting | undefined,\n\tdefaultIntervals: number,\n): number[] {\n\tif (range.logScale && range.logBase) {\n\t\treturn generateLogTicks(range);\n\t}\n\tconst explicit = generateIntervalTicks(range, axis?.majorUnit ?? 0);\n\tif (explicit.length > 0) {\n\t\treturn explicit;\n\t}\n\t// The automatic scale already picked a round step and snapped the bounds to\n\t// whole multiples of it, so stepping by that unit reproduces PowerPoint's\n\t// labels exactly. Dividing the span evenly instead is what put ticks on\n\t// 10.4 / 20.8 / 31.2 where PowerPoint writes 20 / 40 / 60.\n\tconst automatic = generateIntervalTicks(range, range.majorUnit ?? 0);\n\tif (automatic.length > 0) {\n\t\treturn automatic;\n\t}\n\treturn Array.from(\n\t\t{ length: defaultIntervals + 1 },\n\t\t(_, index) => range.min + (range.span / defaultIntervals) * index,\n\t);\n}\n\n/** Generate minor gridline values, excluding positions occupied by major ticks. */\nexport function generateMinorAxisTicks(\n\trange: ValueRange,\n\taxis: PptxChartAxisFormatting | undefined,\n): number[] {\n\tconst minor = generateIntervalTicks(range, axis?.minorUnit ?? 0);\n\tif (minor.length === 0) {\n\t\treturn [];\n\t}\n\tconst majorUnit = axis?.majorUnit;\n\tif (!majorUnit || !Number.isFinite(majorUnit) || majorUnit <= 0) {\n\t\treturn minor;\n\t}\n\tconst tolerance = Math.max(1, Math.abs(range.min), Math.abs(range.max)) * 1e-10;\n\treturn minor.filter(\n\t\t(value) => Math.abs(value / majorUnit - Math.round(value / majorUnit)) > tolerance,\n\t);\n}\n\n/** Find any parsed logarithmic value axis. */\nexport function findLogAxis(\n\taxes: PptxChartAxisFormatting[] | undefined,\n): PptxChartAxisFormatting | undefined {\n\treturn axes?.find((axis) => axis.axisType === 'valAx' && axis.logScale);\n}\n\n/**\n * Compute the primary value range for a chart.\n *\n * @param plotHeightPx See `computeValueRangeForAxis`'s parameter of the same name.\n */\nexport function computeValueRangeForChart(\n\tseries: ReadonlyArray<PptxChartSeries>,\n\taxes?: PptxChartAxisFormatting[],\n\tplotHeightPx?: number,\n): ValueRange {\n\tconst primaryAxis =\n\t\taxes?.find((axis) => axis.axisType === 'valAx' && axis.axPos === 'l') ??\n\t\taxes?.find((axis) => axis.axisType === 'valAx' && axis.axPos !== 'r');\n\treturn computeValueRangeForAxis(series, primaryAxis, plotHeightPx);\n}\n","/**\n * chart-axis.ts — framework-agnostic axis maths beyond the linear-Y basics in\n * `chart-helpers.ts`.\n *\n * Three concerns, all pure and reused by every binding:\n * - **log scale**: `computeLogValueRange` / `valueToYLog` / `generateLogTicks`\n * and the auto-detecting `computeValueRangeForChart`.\n * - **display units**: `getDisplayUnitDivisor` / `getDisplayUnitLabel` /\n * `formatAxisValueWithUnits` (thousands / millions / … scaling).\n * - **secondary axes & data-table reservation**: detection + series→axis split\n * helpers and `computeLayoutOptions` feeding the extended `computeLayout`.\n *\n * Extracted from the React `viewer/utils/chart-helpers.ts` (log + display units)\n * and `viewer/utils/chart-layout.ts` (secondary axes + data table).\n *\n * @module chart-axis\n */\nimport type {\n\tPptxChartAxisFormatting,\n\tPptxChartDataTable,\n\tPptxChartSeries,\n} from 'pptx-viewer-core';\n\nexport {\n\tcomputeLogValueRange,\n\tcomputeValueRangeForAxis,\n\tcomputeValueRangeForChart,\n\tfindLogAxis,\n\tgenerateAxisTicks,\n\tgenerateLogTicks,\n\tgenerateMinorAxisTicks,\n\tvalueToYLog,\n} from './chart-axis-range';\n\n// ── Display units ────────────────────────────────────────────────\n\nconst DISPLAY_UNIT_DIVISORS: Record<string, number> = {\n\thundreds: 100,\n\tthousands: 1_000,\n\ttenThousands: 10_000,\n\thundredThousands: 100_000,\n\tmillions: 1_000_000,\n\ttenMillions: 10_000_000,\n\thundredMillions: 100_000_000,\n\tbillions: 1_000_000_000,\n\ttrillions: 1_000_000_000_000,\n};\n\nconst DISPLAY_UNIT_LABELS: Record<string, string> = {\n\thundreds: 'Hundreds',\n\tthousands: 'Thousands',\n\ttenThousands: 'Ten Thousands',\n\thundredThousands: 'Hundred Thousands',\n\tmillions: 'Millions',\n\ttenMillions: 'Ten Millions',\n\thundredMillions: 'Hundred Millions',\n\tbillions: 'Billions',\n\ttrillions: 'Trillions',\n};\n\n/** Get the numeric divisor for a built-in display unit name. */\nexport function getDisplayUnitDivisor(unit: string | undefined, customValue?: number): number {\n\tif (!unit) {\n\t\treturn 1;\n\t}\n\tif (unit === 'custom' && customValue) {\n\t\treturn customValue;\n\t}\n\treturn DISPLAY_UNIT_DIVISORS[unit] ?? 1;\n}\n\n/** Get the human-readable label for a display unit (custom label overrides built-in). */\nexport function getDisplayUnitLabel(\n\tunit: string | undefined,\n\tcustomLabel?: string | { text?: string } | null,\n): string {\n\tif (typeof customLabel === 'string') {\n\t\treturn customLabel;\n\t}\n\tif (customLabel === null) {\n\t\treturn '';\n\t}\n\tif (customLabel?.text) {\n\t\treturn customLabel.text;\n\t}\n\tif (!unit || unit === 'custom') {\n\t\treturn '';\n\t}\n\treturn DISPLAY_UNIT_LABELS[unit] ?? '';\n}\n\n/**\n * Format an axis value with display unit scaling applied. PowerPoint writes\n * the scaled value in the axis' General number format, i.e. with as many\n * decimals as it needs (COM-verified charts-com.pptx slide 4: ticks of\n * 1..6 at \"thousands\" read 0.001 .. 0.006); rounding to one decimal turned\n * every tick of that axis into \"0.0\".\n */\nexport function formatAxisValueWithUnits(value: number, axis?: PptxChartAxisFormatting): string {\n\tif (!axis?.displayUnits) {\n\t\treturn String(value);\n\t}\n\tconst divisor = getDisplayUnitDivisor(axis.displayUnits, axis.displayUnitsValue);\n\t// Ten significant digits drops the binary-float noise of the division\n\t// (0.0030000000000000001) without truncating any authored precision.\n\treturn String(Number((value / divisor).toPrecision(10)));\n}\n\n/** Distance left of the plot for a units caption: past the widest tick label. */\nexport function unitsCaptionOffset(\n\ttickLabels: ReadonlyArray<{ text: string; fontSize?: number }>,\n): number {\n\tconst widest = tickLabels.reduce(\n\t\t(w, label) => Math.max(w, label.text.length * (label.fontSize ?? 9) * 0.55),\n\t\t0,\n\t);\n\treturn Math.max(24, widest + 14);\n}\n\n// ── Layout options (secondary axes + data table) ─────────────────\n\n/** Options for extended layout computation with secondary axes and data tables. */\nexport interface LayoutOptions {\n\thasSecondaryValueAxis?: boolean;\n\thasSecondaryCategoryAxis?: boolean;\n\t/** The primary (only, in the common case) category axis sits at the top. */\n\tcategoryAxisAtTop?: boolean;\n\thasDataTable?: boolean;\n\tdataTableRowCount?: number;\n}\n\n/** Check whether any axis in the list is a secondary value axis (position \"r\"). */\nexport function hasSecondaryValueAxis(axes: PptxChartAxisFormatting[] | undefined): boolean {\n\tif (!axes) {\n\t\treturn false;\n\t}\n\treturn axes.some((a) => a.axisType === 'valAx' && a.axPos === 'r');\n}\n\nfunction categoryAxes(axes: PptxChartAxisFormatting[] | undefined): PptxChartAxisFormatting[] {\n\treturn axes?.filter((a) => a.axisType === 'catAx' || a.axisType === 'dateAx') ?? [];\n}\n\n/**\n * Check whether the chart has a genuine SECOND category axis positioned at the\n * top (a combo chart with one bottom + one top category axis). A single\n * category axis that itself carries `axPos=\"t\"` (the only axis, just\n * relocated) is NOT a secondary axis: see `isPrimaryCategoryAxisAtTop`.\n */\nexport function hasSecondaryCategoryAxis(axes: PptxChartAxisFormatting[] | undefined): boolean {\n\tconst cats = categoryAxes(axes);\n\treturn cats.length > 1 && cats.some((a) => a.axPos === 't');\n}\n\n/**\n * Check whether the chart's PRIMARY (and, in the common case, only) category\n * axis is positioned at the top of the plot area (`c:catAx/c:axPos val=\"t\"`).\n * Mirrors the axis selection in `chart-category-axis.ts`'s\n * `primaryCategoryAxis`: prefer a non-top axis when one exists (the top one is\n * then the genuine secondary axis, handled separately), otherwise fall back to\n * the first category axis, which is the only one there is.\n */\nexport function isPrimaryCategoryAxisAtTop(axes: PptxChartAxisFormatting[] | undefined): boolean {\n\tconst cats = categoryAxes(axes);\n\tif (cats.length === 0) {\n\t\treturn false;\n\t}\n\tconst primary = cats.find((a) => a.axPos !== 't') ?? cats[0];\n\treturn primary.axPos === 't';\n}\n\n/** Get the secondary value axis formatting, if present. */\nexport function getSecondaryValueAxis(\n\taxes: PptxChartAxisFormatting[] | undefined,\n): PptxChartAxisFormatting | undefined {\n\tif (!axes) {\n\t\treturn undefined;\n\t}\n\treturn axes.find((a) => a.axisType === 'valAx' && a.axPos === 'r');\n}\n\n/** Get the secondary category axis formatting, if present. */\nexport function getSecondaryCategoryAxis(\n\taxes: PptxChartAxisFormatting[] | undefined,\n): PptxChartAxisFormatting | undefined {\n\tif (!axes) {\n\t\treturn undefined;\n\t}\n\treturn axes.find((a) => (a.axisType === 'catAx' || a.axisType === 'dateAx') && a.axPos === 't');\n}\n\n/** Compute layout options from chart data for use with computeLayout. */\nexport function computeLayoutOptions(\n\taxes: PptxChartAxisFormatting[] | undefined,\n\tdataTable: PptxChartDataTable | null | undefined,\n\tseriesCount: number,\n): LayoutOptions {\n\treturn {\n\t\thasSecondaryValueAxis: hasSecondaryValueAxis(axes),\n\t\thasSecondaryCategoryAxis: hasSecondaryCategoryAxis(axes),\n\t\tcategoryAxisAtTop: isPrimaryCategoryAxisAtTop(axes),\n\t\thasDataTable: Boolean(dataTable),\n\t\tdataTableRowCount: dataTable ? seriesCount : undefined,\n\t};\n}\n\n// ── Series-to-axis mapping ────────────────────────────────────────\n\n/** Get the axis ID of the secondary value axis, if present. */\nexport function getSecondaryValueAxisId(\n\taxes: PptxChartAxisFormatting[] | undefined,\n): number | undefined {\n\tconst ax = getSecondaryValueAxis(axes);\n\treturn ax?.axisId;\n}\n\n/** Get the axis ID of the primary value axis (position \"l\" or first valAx). */\nexport function getPrimaryValueAxisId(\n\taxes: PptxChartAxisFormatting[] | undefined,\n): number | undefined {\n\tif (!axes) {\n\t\treturn undefined;\n\t}\n\tconst primary = axes.find((a) => a.axisType === 'valAx' && a.axPos === 'l');\n\treturn primary?.axisId ?? axes.find((a) => a.axisType === 'valAx')?.axisId;\n}\n\n/**\n * Determine whether a series is mapped to the secondary axis.\n *\n * A series is secondary if it has an `axisId` that matches the secondary value\n * axis ID. When no axis IDs are set on series this returns false (callers that\n * want a combo heuristic apply it themselves).\n */\nexport function isSeriesOnSecondaryAxis(\n\tseries: PptxChartSeries,\n\taxes: PptxChartAxisFormatting[] | undefined,\n): boolean {\n\tif (!axes) {\n\t\treturn false;\n\t}\n\tconst secAxisId = getSecondaryValueAxisId(axes);\n\tif (secAxisId === undefined) {\n\t\treturn false;\n\t}\n\n\tif (series.axisId !== undefined) {\n\t\treturn series.axisId === secAxisId;\n\t}\n\n\treturn false;\n}\n\n/**\n * Split chart series into primary and secondary groups based on axis mapping.\n *\n * Returns `{ primary, secondary }` where each entry preserves the original index.\n */\nexport function splitSeriesByAxis(\n\tseries: ReadonlyArray<PptxChartSeries>,\n\taxes: PptxChartAxisFormatting[] | undefined,\n): {\n\tprimary: { series: PptxChartSeries; index: number }[];\n\tsecondary: { series: PptxChartSeries; index: number }[];\n} {\n\tconst primary: { series: PptxChartSeries; index: number }[] = [];\n\tconst secondary: { series: PptxChartSeries; index: number }[] = [];\n\n\tfor (let i = 0; i < series.length; i++) {\n\t\tif (isSeriesOnSecondaryAxis(series[i], axes)) {\n\t\t\tsecondary.push({ series: series[i], index: i });\n\t\t} else {\n\t\t\tprimary.push({ series: series[i], index: i });\n\t\t}\n\t}\n\n\treturn { primary, secondary };\n}\n\n/** Height occupied by data table rows. */\nexport function computeDataTableHeight(\n\tdataTable: PptxChartDataTable | undefined,\n\tseriesCount: number,\n): number {\n\tif (!dataTable) {\n\t\treturn 0;\n\t}\n\tconst rowCount = Math.max(seriesCount, 1);\n\treturn 14 + rowCount * 14;\n}\n","/**\n * chart-palette.ts — colour-ramp helpers for chart styling.\n *\n * `tint` (lighten toward white) and `shade` (darken toward black) are the two\n * primitive colour transforms behind the Office chart style-id palettes. The\n * full style-id → palette mapping (`getChartStylePalette`) and the default\n * fallback palette (`DEFAULT_CHART_PALETTE`) live in `chart-helpers.ts` and are\n * re-exported here so a binding can pull the whole palette surface from one\n * module.\n *\n * Extracted from the React `viewer/utils/chart-style-palettes.ts`.\n *\n * @module chart-palette\n */\n\nexport { DEFAULT_CHART_PALETTE, getChartStylePalette } from './chart-helpers';\n\n/** Parse a hex colour string (#RRGGBB) into [r, g, b]. */\nfunction hexToRgb(hex: string): [number, number, number] {\n\tconst h = hex.replace('#', '');\n\treturn [\n\t\tparseInt(h.substring(0, 2), 16),\n\t\tparseInt(h.substring(2, 4), 16),\n\t\tparseInt(h.substring(4, 6), 16),\n\t];\n}\n\n/** Convert [r, g, b] back to #RRGGBB. */\nfunction rgbToHex(r: number, g: number, b: number): string {\n\tconst clamp = (v: number): number => Math.max(0, Math.min(255, Math.round(v)));\n\treturn `#${clamp(r).toString(16).padStart(2, '0')}${clamp(g)\n\t\t.toString(16)\n\t\t.padStart(2, '0')}${clamp(b).toString(16).padStart(2, '0')}`;\n}\n\n/**\n * Apply a tint (lighten towards white) to a colour.\n * `amount` in [0, 1] where 0 = no change, 1 = white.\n */\nexport function tint(hex: string, amount: number): string {\n\tconst [r, g, b] = hexToRgb(hex);\n\treturn rgbToHex(r + (255 - r) * amount, g + (255 - g) * amount, b + (255 - b) * amount);\n}\n\n/**\n * Apply a shade (darken towards black) to a colour.\n * `amount` in [0, 1] where 0 = no change, 1 = black.\n */\nexport function shade(hex: string, amount: number): string {\n\tconst [r, g, b] = hexToRgb(hex);\n\treturn rgbToHex(r * (1 - amount), g * (1 - amount), b * (1 - amount));\n}\n","/**\n * chart-marker-shape.ts: framework-agnostic marker-symbol primitive builder for\n * line / scatter / area chart data points.\n *\n * OOXML line/scatter series carry a `c:marker` with a `c:symbol` (circle,\n * diamond, square, triangle, star, x, plus, dot, dash, none, ...) and an\n * optional `c:size` (2-72 points). The base view-model historically drew every\n * data point as a fixed-radius circle, ignoring both. This helper resolves the\n * parsed marker into the correct `SvgPrimitive` at the requested size, and\n * returns `null` for `symbol === 'none'` so no dot is drawn.\n *\n * @module chart-marker-shape\n */\n\nimport type { PptxChartMarkerSymbol } from 'pptx-viewer-core';\n\nimport type { ChartPartRef, SvgCircle, SvgPath, SvgPolygon, SvgRect } from './chart-view-model';\n\n/** The concrete primitive kinds a marker can resolve to (all support `opacity`). */\nexport type MarkerPrimitive = SvgCircle | SvgRect | SvgPath | SvgPolygon;\n\n/** Inputs for a single marker primitive. */\nexport interface MarkerShapeInput {\n\t/** Parsed marker symbol; `undefined` falls back to the default dot. */\n\tsymbol: PptxChartMarkerSymbol | undefined;\n\t/** Parsed marker size in points (diameter). `undefined` uses `defaultRadius`. */\n\tsize: number | undefined;\n\tcx: number;\n\tcy: number;\n\tfill: string;\n\t/** Radius used when no marker size is present (preserves the legacy dot size). */\n\tdefaultRadius: number;\n\tpart?: ChartPartRef;\n}\n\n/**\n * PowerPoint's automatic marker-symbol cycle: the fixed shape sequence a\n * \"Line/Scatter with Markers\" chart cycles through when a series' `c:marker`\n * carries no `c:symbol` (only its fill/line colour is \"automatic\"; the shape\n * itself was assumed to always be a circle before this was measured).\n *\n * COM-measured ground truth (`PowerPoint.Application`, a stacked\n * Line-with-Markers chart, N series each with `<c:marker><c:spPr>.../></c:marker>`\n * and no `c:symbol`, `SeriesCollection(i).MarkerStyle` read back after a real\n * save/reopen round trip): idx 0..8 resolved to\n * Diamond, Square, Triangle, X, Star, Circle, Plus, Dot, Dash - a clean\n * 9-element cycle with no partial/ambiguous entries across 9 independent\n * series (this is ALSO what the chart-style-driven, explicit-symbol path a\n * modern \"Line with Markers\" preset writes on save resolves every series to a\n * uniform Circle, so that path is unrelated: this cycle is specifically\n * what PowerPoint's renderer falls back to for a chart with no `c:symbol` at\n * all). Confirmed against a real-world deck: series `c:idx=\"1\"`/`\"2\"` (a\n * gapped, 1-based pair, not `0`/`1`) resolved to Square/Triangle exactly as\n * this cycle predicts (`AUTOMATIC_MARKER_CYCLE[1]` / `[2]`).\n */\nconst AUTOMATIC_MARKER_CYCLE: readonly PptxChartMarkerSymbol[] = [\n\t'diamond',\n\t'square',\n\t'triangle',\n\t'x',\n\t'star',\n\t'circle',\n\t'plus',\n\t'dot',\n\t'dash',\n];\n\n/**\n * Resolve the automatic marker shape for a series with no authored\n * `c:symbol`, keyed by the series' `c:idx` (or its array position when the\n * chart has none): {@link AUTOMATIC_MARKER_CYCLE} repeats every 9 series.\n */\nexport function automaticMarkerSymbol(seriesIdx: number): PptxChartMarkerSymbol {\n\tconst length = AUTOMATIC_MARKER_CYCLE.length;\n\tconst normalized = ((seriesIdx % length) + length) % length;\n\treturn AUTOMATIC_MARKER_CYCLE[normalized];\n}\n\n/** Resolve the drawn radius (px) from the parsed point size or the default. */\nfunction markerRadius(size: number | undefined, defaultRadius: number): number {\n\tif (size === undefined || !Number.isFinite(size) || size <= 0) {\n\t\treturn defaultRadius;\n\t}\n\t// OOXML marker size is a point diameter; treat 1pt ~ 1px at chart scale.\n\treturn size / 2;\n}\n\n/** Build the SVG points string for a regular/irregular polygon vertex list. */\nfunction polygonPoints(vertices: ReadonlyArray<[number, number]>): string {\n\treturn vertices.map(([x, y]) => `${x.toFixed(2)},${y.toFixed(2)}`).join(' ');\n}\n\nfunction starVertices(cx: number, cy: number, r: number): Array<[number, number]> {\n\tconst inner = r * 0.5;\n\tconst out: Array<[number, number]> = [];\n\tfor (let i = 0; i < 10; i++) {\n\t\tconst radius = i % 2 === 0 ? r : inner;\n\t\tconst angle = -Math.PI / 2 + (Math.PI * i) / 5;\n\t\tout.push([cx + radius * Math.cos(angle), cy + radius * Math.sin(angle)]);\n\t}\n\treturn out;\n}\n\n/**\n * Build the marker primitive for one data point, honouring `symbol` and `size`.\n * Returns `null` when `symbol === 'none'` (draw nothing).\n */\nexport function buildMarkerPrimitive(input: MarkerShapeInput): MarkerPrimitive | null {\n\tconst { symbol, cx, cy, fill, part } = input;\n\tif (symbol === 'none') {\n\t\treturn null;\n\t}\n\tconst r = markerRadius(input.size, input.defaultRadius);\n\tconst stroke = fill;\n\n\tswitch (symbol) {\n\t\tcase 'square':\n\t\t\treturn { kind: 'rect', x: cx - r, y: cy - r, w: r * 2, h: r * 2, fill, part };\n\t\tcase 'dash':\n\t\t\treturn { kind: 'rect', x: cx - r, y: cy - r * 0.32, w: r * 2, h: r * 0.64, fill, part };\n\t\tcase 'diamond':\n\t\t\treturn {\n\t\t\t\tkind: 'polygon',\n\t\t\t\tpoints: polygonPoints([\n\t\t\t\t\t[cx, cy - r],\n\t\t\t\t\t[cx + r, cy],\n\t\t\t\t\t[cx, cy + r],\n\t\t\t\t\t[cx - r, cy],\n\t\t\t\t]),\n\t\t\t\tfill,\n\t\t\t\tstroke,\n\t\t\t\tstrokeWidth: 0,\n\t\t\t\tpart,\n\t\t\t};\n\t\tcase 'triangle':\n\t\t\treturn {\n\t\t\t\tkind: 'polygon',\n\t\t\t\tpoints: polygonPoints([\n\t\t\t\t\t[cx, cy - r],\n\t\t\t\t\t[cx + r * 0.9, cy + r * 0.75],\n\t\t\t\t\t[cx - r * 0.9, cy + r * 0.75],\n\t\t\t\t]),\n\t\t\t\tfill,\n\t\t\t\tstroke,\n\t\t\t\tstrokeWidth: 0,\n\t\t\t\tpart,\n\t\t\t};\n\t\tcase 'star':\n\t\t\treturn {\n\t\t\t\tkind: 'polygon',\n\t\t\t\tpoints: polygonPoints(starVertices(cx, cy, r)),\n\t\t\t\tfill,\n\t\t\t\tstroke,\n\t\t\t\tstrokeWidth: 0,\n\t\t\t\tpart,\n\t\t\t};\n\t\tcase 'plus':\n\t\t\treturn {\n\t\t\t\tkind: 'path',\n\t\t\t\td: `M${(cx - r).toFixed(2)},${cy.toFixed(2)} L${(cx + r).toFixed(2)},${cy.toFixed(2)} M${cx.toFixed(2)},${(cy - r).toFixed(2)} L${cx.toFixed(2)},${(cy + r).toFixed(2)}`,\n\t\t\t\tfill: 'none',\n\t\t\t\tstroke,\n\t\t\t\tstrokeWidth: Math.max(1, r * 0.4),\n\t\t\t\tpart,\n\t\t\t};\n\t\tcase 'x':\n\t\t\treturn {\n\t\t\t\tkind: 'path',\n\t\t\t\td: `M${(cx - r).toFixed(2)},${(cy - r).toFixed(2)} L${(cx + r).toFixed(2)},${(cy + r).toFixed(2)} M${(cx + r).toFixed(2)},${(cy - r).toFixed(2)} L${(cx - r).toFixed(2)},${(cy + r).toFixed(2)}`,\n\t\t\t\tfill: 'none',\n\t\t\t\tstroke,\n\t\t\t\tstrokeWidth: Math.max(1, r * 0.4),\n\t\t\t\tpart,\n\t\t\t};\n\t\tcase 'dot':\n\t\t\treturn { kind: 'circle', cx, cy, r: Math.max(r * 0.6, 1), fill, part };\n\t\tdefault:\n\t\t\t// circle / auto / picture / undefined -> filled circle.\n\t\t\treturn { kind: 'circle', cx, cy, r, fill, part };\n\t}\n}\n","/**\n * chart-datapoint-style.ts: framework-agnostic resolution of per-data-point\n * formatting overrides (`c:dPt`).\n *\n * A chart series may override the appearance of individual data points: a\n * per-point fill colour, or (for pie/doughnut) a slice \"explosion\" pull-out\n * distance. These helpers resolve the effective value for a given point index,\n * falling back to the series-level default, so every binding (React/Vue/Angular)\n * can render edited per-point formatting identically without re-implementing the\n * lookup.\n *\n * @module chart-datapoint-style\n */\n\nimport type { PptxChartDataPointPicture, PptxChartMarkerSymbol } from 'pptx-viewer-core';\n\nimport { automaticMarkerSymbol } from './chart-marker-shape';\n\n/** Minimal shape props subset needed to resolve a point fill. */\ninterface PointShapeProps {\n\tfillColor?: string;\n}\n\n/** Minimal marker shape consumed here (mirrors `PptxChartMarker`). */\nexport interface ChartMarkerLike {\n\tsymbol?: PptxChartMarkerSymbol;\n\tsize?: number;\n\tspPr?: PointShapeProps;\n}\n\n/** Minimal data-point shape consumed here (mirrors `PptxChartDataPoint`). */\nexport interface ChartDataPointLike {\n\tidx: number;\n\tspPr?: PointShapeProps;\n\texplosion?: number;\n\tmarker?: ChartMarkerLike;\n\tpicture?: PptxChartDataPointPicture;\n\t/**\n\t * A picture fill implied by a bare `c:dPt/c:spPr/a:blipFill` with no\n\t * sibling `c:pictureOptions` (mirrors `PptxChartDataPoint.impliedPicture`).\n\t * {@link resolveActiveDataPointPicture} falls back to this only when\n\t * {@link picture} did not resolve an image of its own.\n\t */\n\timpliedPicture?: PptxChartDataPointPicture;\n}\n\n/** Minimal series shape consumed here (mirrors `PptxChartSeries`). */\nexport interface ChartSeriesLike {\n\tcolor?: string;\n\tmarker?: ChartMarkerLike;\n\tdataPoints?: ChartDataPointLike[];\n\t/**\n\t * This series' `c:ser/c:idx/@val` (mirrors `PptxChartSeries.idx`). Used to\n\t * key the automatic marker-symbol cycle so a chart with non-sequential or\n\t * gapped indices (a deleted/filtered series) still lands on the same shape\n\t * PowerPoint does; falls back to the caller-supplied array position when\n\t * absent.\n\t */\n\tidx?: number;\n\t/**\n\t * Series-level picture-fill flags (`c:ser/c:pictureOptions`): paints every\n\t * point in the series with one picture unless a `c:dPt` resolves its own\n\t * (see {@link resolveActiveDataPointPicture}).\n\t */\n\tpicture?: PptxChartDataPointPicture;\n\t/**\n\t * A picture fill implied by a bare `c:ser/c:spPr/a:blipFill` with no\n\t * sibling `c:pictureOptions` (mirrors `PptxChartSeries.impliedPicture`).\n\t */\n\timpliedPicture?: PptxChartDataPointPicture;\n}\n\n/** The marker attributes actually drawn for one data point. */\nexport interface ResolvedPointMarker {\n\tsymbol: PptxChartMarkerSymbol | undefined;\n\tsize: number | undefined;\n\t/** Marker-specific fill, when the point or series pins one. */\n\tfill: string | undefined;\n}\n\n/** Look up the `c:dPt` override for a point index, if any. */\nexport function findDataPoint(\n\tseries: ChartSeriesLike,\n\tpointIndex: number,\n): ChartDataPointLike | undefined {\n\treturn series.dataPoints?.find((p) => p.idx === pointIndex);\n}\n\n/**\n * Resolve the effective fill colour for a single data point: the per-point\n * `c:dPt` fill when present, otherwise the series colour, otherwise\n * `fallbackColor`. Returns `undefined` only when nothing is set.\n */\nexport function resolveDataPointFill(\n\tseries: ChartSeriesLike,\n\tpointIndex: number,\n\tfallbackColor?: string,\n): string | undefined {\n\tconst point = findDataPoint(series, pointIndex);\n\treturn point?.spPr?.fillColor ?? series.color ?? fallbackColor;\n}\n\n/**\n * Resolve the fill for a data point in a \"vary colours\" context, where every\n * point in a single series is drawn with a distinct palette colour (pie /\n * doughnut slices, or a bar/column series with `c:varyColors=1`). A per-point\n * `c:dPt` fill still wins; otherwise the supplied per-point `paletteColor` is\n * used (NOT the single series colour, which would make every point identical).\n */\nexport function resolveVaryColorFill(\n\tseries: ChartSeriesLike,\n\tpointIndex: number,\n\tpaletteColor: string,\n): string {\n\treturn findDataPoint(series, pointIndex)?.spPr?.fillColor ?? paletteColor;\n}\n\n/**\n * Resolve the slice explosion (pull-out distance, 0-100) for a pie/doughnut\n * data point: the per-point `c:dPt` explosion when present, otherwise the\n * series-level explosion, otherwise `0`.\n */\nexport function resolveDataPointExplosion(\n\tseries: ChartSeriesLike & { explosion?: number },\n\tpointIndex: number,\n): number {\n\tconst point = findDataPoint(series, pointIndex);\n\treturn point?.explosion ?? series.explosion ?? 0;\n}\n\n/**\n * Resolve the marker actually drawn for one data point.\n *\n * OOXML lets a `c:dPt` carry its own `c:marker`, which overrides the series\n * `c:ser/c:marker` for that point alone: the classic use is highlighting a\n * single outlier with a bigger star while the rest of the line keeps its small\n * circles. Every field falls back independently, matching PowerPoint: a point\n * marker that sets only `c:symbol` keeps the series size and fill.\n *\n * This exists because the per-point marker was a write-only feature. The core\n * parser read `c:dPt/c:marker`, the save writer round-tripped it, and three\n * bindings shipped an inspector control for it, but the renderer only ever\n * looked at `series.marker`, so editing a point marker changed the file and\n * left the canvas untouched. Resolving it here fixes every binding at once,\n * since they all paint the same shared view model.\n *\n * A resolved symbol of `'auto'` (or a marker present with no `c:symbol` at\n * all, which the core parser also normalises to `'auto'`) is resolved to a\n * concrete shape via {@link automaticMarkerSymbol}, keyed by `series.idx`\n * (falling back to `seriesPosition`, the series' array index, when the chart\n * carries no `c:idx`). A series/point with NO marker element at all\n * (`marker` and `point` both `undefined`) keeps `symbol: undefined`\n * unchanged: that is a chart type that draws no marker at all, not an\n * automatic one, and must not start cycling shapes.\n */\nexport function resolveDataPointMarker(\n\tseries: ChartSeriesLike,\n\tpointIndex: number,\n\tseriesPosition = 0,\n): ResolvedPointMarker {\n\tconst point = findDataPoint(series, pointIndex)?.marker;\n\tconst hasMarker = point !== undefined || series.marker !== undefined;\n\tconst rawSymbol = point?.symbol ?? series.marker?.symbol;\n\tconst symbol =\n\t\thasMarker && (rawSymbol === undefined || rawSymbol === 'auto')\n\t\t\t? automaticMarkerSymbol(series.idx ?? seriesPosition)\n\t\t\t: rawSymbol;\n\treturn {\n\t\tsymbol,\n\t\tsize: point?.size ?? series.marker?.size,\n\t\tfill: point?.spPr?.fillColor ?? series.marker?.spPr?.fillColor,\n\t};\n}\n\n/**\n * Insert or replace the `c:dPt` override carrying `point.idx`, returning a NEW\n * array (the input is never mutated).\n *\n * WHY this is shared rather than open-coded per inspector: `c:dPt` entries are\n * SPARSE and unordered. A deck may carry a single override for point 7 and\n * nothing else, so `dataPoints[n] = ...` retargets the edit at whichever point\n * happens to occupy that slot, and `dataPoints[0]` pins every edit to the first\n * override regardless of which point the user picked. The renderer resolves a\n * point through {@link findDataPoint}, which keys on `c:idx`, so any editor that\n * writes by array position disagrees with what gets painted. Keeping the write\n * next to the lookup it has to agree with is what stops the two drifting.\n */\nexport function upsertDataPoint<P extends ChartDataPointLike>(\n\tdataPoints: readonly P[] | undefined,\n\tpoint: P,\n): P[] {\n\tconst next = [...(dataPoints ?? [])];\n\tconst position = next.findIndex((candidate) => candidate.idx === point.idx);\n\tif (position >= 0) {\n\t\tnext[position] = point;\n\t} else {\n\t\tnext.push(point);\n\t}\n\treturn next;\n}\n\n// Picture-fill resolution (c:pictureOptions, the bare-a:blipFill\n// impliedPicture case, and bar3D face targeting) lives in\n// chart-datapoint-picture-resolve.ts, split out to keep this file within the\n// repo's ~300-LOC limit: `resolveActiveDataPointPicture`,\n// `resolveDataPointPictureFill`, `resolveBarFaceTargets`, `DataPointPictureFill`,\n// `BarPictureFace`, `BarFaceTargets`.\n","/**\n * chart-datapoint-picture-resolve.ts: framework-agnostic resolution of a\n * data point's (or its series') picture fill into a paintable descriptor.\n *\n * Split out of `chart-datapoint-style.ts` to keep that file within the\n * repo's ~300-LOC limit: that file resolves per-point formatting in\n * general (fill colour, marker, explosion); this one owns specifically the\n * picture-fill half (`c:pictureOptions` AND the bare-`a:blipFill`\n * `impliedPicture` case, plus `bar3D` face targeting), which had grown into\n * its own coherent concern.\n *\n * @module chart-datapoint-picture-resolve\n */\n\nimport type { PptxChartDataPointPicture } from 'pptx-viewer-core';\n\nimport type { ChartSeriesLike } from './chart-datapoint-style';\nimport { findDataPoint } from './chart-datapoint-style';\nimport { chartFontPx } from './chart-font';\n\n/**\n * An SVG `<pattern>` a binding must render into its chart's `<defs>` to paint\n * a data point's picture fill (`c:dPt/c:pictureOptions`, C2-G9 render half).\n * Pure decision function (CLAUDE.md Rule 2): every field a binding needs to\n * build the pattern element and point the rect's `fill` at it, with no\n * chart-type-specific logic left for the binding to reimplement.\n */\nexport interface DataPointPictureFill {\n\t/** Unique id for this point's `<pattern>` element; also its `fill=\"url(#...)\"` target. */\n\tpatternId: string;\n\timageUrl: string;\n\t/** `stretch` fills the whole rect with one scaled copy; `stack`/`stackScale` tile it. */\n\tformat: NonNullable<PptxChartDataPointPicture['pictureFormat']>;\n\t/**\n\t * Height (px) of one repeated tile for `stack`/`stackScale`\n\t * (`c:pictureStackUnit`, converted from points). `undefined` for `stretch`,\n\t * where the image covers the whole rect and stacking is meaningless.\n\t */\n\ttileHeightPx?: number;\n\t/**\n\t * Effective opacity (0-1) from the blip's `a:alphaModFix` (see\n\t * `PptxChartDataPointPicture.opacity`'s doc comment). `undefined` (fully\n\t * opaque) when the blip carries no `alphaModFix`.\n\t */\n\topacity?: number;\n}\n\n/** PowerPoint's own default picture-fill format when `c:pictureFormat` is absent. */\nconst DEFAULT_PICTURE_FORMAT: NonNullable<PptxChartDataPointPicture['pictureFormat']> = 'stretch';\n\n/**\n * Resolve the picture-fill flags actually in effect for a point: its OWN\n * `c:dPt/c:pictureOptions` when it resolved an image, otherwise the series'\n * `c:ser/c:pictureOptions` (C2-G9 series-level half). A point with its own\n * picture wins OUTRIGHT (not merged field-by-field with the series' flags),\n * matching how a `c:dPt/c:spPr` fully replaces the series' formatting\n * elsewhere in this resolver (`resolveDataPointFill`, `chart-datapoint-style.ts`).\n *\n * `impliedPicture` (a bare `a:blipFill` with no `c:pictureOptions` sibling,\n * see `PptxChartDataPoint.impliedPicture`'s doc comment) is checked at the\n * SAME tier as `picture`, once `picture` itself did not resolve an image: a\n * point's own fill (explicit flags or implied) still wins outright over the\n * series', and vice versa.\n */\nexport function resolveActiveDataPointPicture(\n\tseries: ChartSeriesLike,\n\tpointIndex: number,\n): PptxChartDataPointPicture | undefined {\n\tconst point = findDataPoint(series, pointIndex);\n\tconst pointPicture = point?.picture?.imageUrl\n\t\t? point.picture\n\t\t: point?.impliedPicture?.imageUrl\n\t\t\t? point.impliedPicture\n\t\t\t: undefined;\n\tif (pointPicture) {\n\t\treturn pointPicture;\n\t}\n\tif (series.picture?.imageUrl) {\n\t\treturn series.picture;\n\t}\n\treturn series.impliedPicture?.imageUrl ? series.impliedPicture : undefined;\n}\n\n/** Which face of a 3-D bar/column a picture fill targets. */\nexport type BarPictureFace = 'front' | 'side' | 'end';\n\n/** Whether a picture fill paints each of a 3-D bar's three faces. */\nexport interface BarFaceTargets {\n\tfront: boolean;\n\tside: boolean;\n\tend: boolean;\n}\n\n/**\n * Resolve which 3-D bar/column faces a picture fill paints\n * (`c:applyToFront`/`c:applyToSides`/`c:applyToEnd`).\n *\n * COM-verified ground truth (PowerPoint Object 16, `c:dPt/c:pictureOptions`\n * with an embedded picture): a `c:pictureOptions` that sets NONE of the three\n * `applyTo*` flags renders IDENTICALLY to one that sets all three to `1` (the\n * picture paints every face). Once at least one flag is present, PowerPoint\n * treats an omitted sibling as `0` (not targeted) rather than re-applying the\n * all-faces default. `picture` undefined (no picture fill at all) targets no\n * face.\n */\nexport function resolveBarFaceTargets(\n\tpicture: PptxChartDataPointPicture | undefined,\n): BarFaceTargets {\n\tif (!picture) {\n\t\treturn { front: false, side: false, end: false };\n\t}\n\tconst { applyToFront, applyToSides, applyToEnd } = picture;\n\tif (applyToFront === undefined && applyToSides === undefined && applyToEnd === undefined) {\n\t\treturn { front: true, side: true, end: true };\n\t}\n\treturn { front: applyToFront ?? false, side: applyToSides ?? false, end: applyToEnd ?? false };\n}\n\n/**\n * Resolve a data point's picture-fill pattern descriptor from\n * {@link resolveActiveDataPointPicture}, or `undefined` when the point (and\n * its series) have no picture fill, the runtime could not resolve the image\n * ({@link PptxChartDataPointPicture.imageUrl} absent), or (when `face` is\n * given) the resolved flags do not target that face\n * ({@link resolveBarFaceTargets}, C2-G9 3-D face-targeting half).\n *\n * `face` is only meaningful for a 3-D bar/column's oblique-projection faces\n * (front rect, side + end/top extrusion polygons); every other picture-filled\n * chart mark (a plain 2-D bar, a pie slice, ...) has exactly one face and\n * calls this without it, preserving the pre-face-targeting behaviour of\n * always painting the picture once resolved.\n */\nexport function resolveDataPointPictureFill(\n\tseries: ChartSeriesLike,\n\tpointIndex: number,\n\tseriesIndex: number,\n\tface?: BarPictureFace,\n): DataPointPictureFill | undefined {\n\tconst picture = resolveActiveDataPointPicture(series, pointIndex);\n\tif (!picture?.imageUrl) {\n\t\treturn undefined;\n\t}\n\tif (face) {\n\t\tconst targets = resolveBarFaceTargets(picture);\n\t\tconst targeted =\n\t\t\tface === 'front' ? targets.front : face === 'side' ? targets.side : targets.end;\n\t\tif (!targeted) {\n\t\t\treturn undefined;\n\t\t}\n\t}\n\tconst format = picture.pictureFormat ?? DEFAULT_PICTURE_FORMAT;\n\treturn {\n\t\tpatternId: `chart-dpt-pic-${seriesIndex}-${pointIndex}${face && face !== 'front' ? `-${face}` : ''}`,\n\t\timageUrl: picture.imageUrl,\n\t\tformat,\n\t\t...(format !== 'stretch' && picture.pictureStackUnit !== undefined\n\t\t\t? { tileHeightPx: chartFontPx(picture.pictureStackUnit) }\n\t\t\t: {}),\n\t\t...(picture.opacity !== undefined ? { opacity: picture.opacity } : {}),\n\t};\n}\n","/**\n * chart-picture-pattern-def.ts: builds the `<pattern>` `ChartSvgDef` for a\n * data point's picture fill, and the bounding-box helper that lets a\n * non-rectangular primitive (a 3-D bar's oblique-projection side/top\n * extrusion polygon) reuse the exact same sizing math as a plain rect.\n *\n * Split out of `chart-datapoint-picture-fills.ts` (the flat/front-face case)\n * so `chart-3d-depth.ts` (the side/end-face case, C2-G9 3-D face-targeting\n * half) can build an identical pattern def without duplicating the\n * stretch/stack tile-sizing rules.\n *\n * @module chart-picture-pattern-def\n */\nimport type { ChartSvgDef } from './chart-view-model-types';\n\n/** Axis-aligned bounding box, in SVG user-space coordinates. */\nexport interface BoundingBox {\n\tx: number;\n\ty: number;\n\tw: number;\n\th: number;\n}\n\n/**\n * Bounding box of an SVG `polygon`'s `points` attribute (`\"x1,y1 x2,y2 ...\"`).\n * The oblique-projection top/side extrusion faces are parallelograms, not\n * axis-aligned rects, so a `<pattern>` sized to their bounding box is an\n * approximation (the image is not sheared to the parallelogram's slant) -\n * consistent with this renderer's other oblique-projection simplifications\n * (see `chart-3d-depth.ts`'s module doc).\n */\nexport function polygonBoundingBox(points: string): BoundingBox {\n\tconst coords = points\n\t\t.trim()\n\t\t.split(/\\s+/u)\n\t\t.map((pair) => pair.split(',').map(Number));\n\tconst xs = coords.map(([x]) => x);\n\tconst ys = coords.map(([, y]) => y);\n\tconst minX = Math.min(...xs);\n\tconst minY = Math.min(...ys);\n\tconst maxX = Math.max(...xs);\n\tconst maxY = Math.max(...ys);\n\treturn { x: minX, y: minY, w: maxX - minX, h: maxY - minY };\n}\n\n/**\n * Build the `<pattern>` def for one picture-filled primitive's bounding box.\n * `stretch` covers the whole box with one non-uniformly scaled copy, matching\n * PowerPoint's \"Stretch\" option; `stack`/`stackScale` repeat the image at\n * {@link tileHeightPx} (falling back to the box's own height, i.e. one tile,\n * when the point set no `c:pictureStackUnit`), cropped to the tile like\n * PowerPoint's \"Stack\" fill.\n */\nexport function buildPictureFillPatternDef(\n\tid: string,\n\thref: string,\n\tformat: 'stretch' | 'stack' | 'stackScale',\n\tbox: BoundingBox,\n\ttileHeightPx: number | undefined,\n): ChartSvgDef {\n\tconst stretch = format === 'stretch';\n\treturn {\n\t\tkind: 'pattern',\n\t\tid,\n\t\thref,\n\t\tpatternUnits: 'userSpaceOnUse',\n\t\tx: box.x,\n\t\ty: box.y,\n\t\twidth: box.w,\n\t\theight: stretch ? box.h : (tileHeightPx ?? box.h),\n\t\tpreserveAspectRatio: stretch ? 'none' : 'xMidYMid slice',\n\t};\n}\n","/**\n * chart-datapoint-picture-fills.ts: wires {@link resolveDataPointPictureFill}'s\n * pure pattern descriptor onto an already-built primitive list (C2-G9 render\n * half).\n *\n * `resolveDataPointPictureFill` (`chart-datapoint-picture-resolve.ts`) resolves WHAT\n * picture, in WHAT format, a data point wants; it has no geometry, so it\n * cannot size the `<pattern>` it describes. This module is the one place that\n * has both: it walks the finished `SvgRect` primitives every bar/column\n * builder already tags with a `part: { role: 'dataPoint', ... }` ref, resolves\n * each one's picture fill against the point's actual rect, and rewrites that\n * rect's `fill` to `url(#...)`. Every bar/column builder therefore gets\n * picture fills for free, with no per-builder change and no risk of the\n * lookup and the paint drifting apart (see `upsertDataPoint`'s doc comment for\n * why keying by index alone is the historical failure mode here).\n *\n * @module chart-datapoint-picture-fills\n */\nimport type { PptxChartData } from 'pptx-viewer-core';\n\nimport { resolveDataPointPictureFill } from './chart-datapoint-picture-resolve';\nimport { buildPictureFillPatternDef } from './chart-picture-pattern-def';\nimport type { ChartSvgDef, SvgPrimitive, SvgRect } from './chart-view-model-types';\n\n/**\n * Apply every resolvable `c:dPt/c:pictureOptions` picture fill found among\n * `primitives`'s data-point rects, returning the (possibly) rewritten\n * primitive list plus the `<pattern>` defs a binding must render into the\n * chart's `<defs>` for the `url(#...)` fills to resolve.\n *\n * `elementId` prefixes every pattern id so two chart instances on the same\n * slide (sharing one HTML document's id namespace) never collide; the pure\n * resolver's own `patternId` is scoped only to series/point index.\n *\n * This rect IS the front face of a `bar3D` chart's oblique-projection bar (the\n * side/end extrusion polygons are separate `SvgPolygon` primitives, patterned\n * by `chart-3d-depth.ts`), so a `bar3D` chart resolves the fill with\n * `face: 'front'`: `c:applyToFront=0` then correctly leaves this rect on its\n * plain solid/derived fill instead of always painting the picture regardless\n * of the flag. Every other chart kind (a flat 2-D bar, a pie slice, ...) has\n * only one face and is resolved with no face argument, unconditionally\n * painting the picture once resolved (unchanged pre-face-targeting behaviour).\n */\nexport function applyDataPointPictureFills(\n\tchartData: PptxChartData,\n\telementId: string,\n\tprimitives: readonly SvgPrimitive[],\n): { primitives: SvgPrimitive[]; defs: ChartSvgDef[] } {\n\tconst face = chartData.chartType === 'bar3D' ? 'front' : undefined;\n\tconst defs: ChartSvgDef[] = [];\n\tconst next = primitives.map((primitive): SvgPrimitive => {\n\t\tif (\n\t\t\tprimitive.kind !== 'rect' ||\n\t\t\t!primitive.part ||\n\t\t\tprimitive.part.role !== 'dataPoint' ||\n\t\t\tprimitive.part.pointIndex === undefined\n\t\t) {\n\t\t\treturn primitive;\n\t\t}\n\t\tconst series = chartData.series[primitive.part.seriesIndex];\n\t\tif (!series) {\n\t\t\treturn primitive;\n\t\t}\n\t\tconst resolved = resolveDataPointPictureFill(\n\t\t\tseries,\n\t\t\tprimitive.part.pointIndex,\n\t\t\tprimitive.part.seriesIndex,\n\t\t\tface,\n\t\t);\n\t\tif (!resolved) {\n\t\t\treturn primitive;\n\t\t}\n\t\tconst patternId = `${elementId}-${resolved.patternId}`;\n\t\tdefs.push(\n\t\t\tbuildPictureFillPatternDef(\n\t\t\t\tpatternId,\n\t\t\t\tresolved.imageUrl,\n\t\t\t\tresolved.format,\n\t\t\t\tprimitive,\n\t\t\t\tresolved.tileHeightPx,\n\t\t\t),\n\t\t);\n\t\treturn {\n\t\t\t...primitive,\n\t\t\tfill: `url(#${patternId})`,\n\t\t\t...(resolved.opacity !== undefined ? { opacity: resolved.opacity } : {}),\n\t\t} satisfies SvgRect;\n\t});\n\treturn { primitives: next, defs };\n}\n","/**\n * chart-bar3d-face-picture-sample.ts: first-pixel colour sampling for a\n * `bar3D` chart's untargeted extrusion face picture fallback (C2-G9\n * face-targeting gap, see `chart-bar3d-face-picture.ts`'s module doc for the\n * COM-verified ground truth this exists to reproduce).\n *\n * PowerPoint paints an untargeted face (a `c:pictureOptions` picture exists\n * but `c:applyToSides`/`c:applyToEnd` do not target it) with a FLAT colour\n * sampled from the picture's own top-left pixel (COM-verified: two\n * independent `Series.ApplyPictToFront/Sides/End` test decks both matched the\n * image's pixel at (0,0), not an average or the centre pixel).\n *\n * {@link resolveBarFacePicturePixelColor} is the entry point a binding (via\n * `resolveExtrusionFaceFill`) should call: it tries a SYNCHRONOUS, DOM-free\n * decode first (`pptx-viewer-core`'s `sampleFirstPixelColorFromBytes`, which\n * covers PNG/GIF/BMP/baseline-JPEG), which resolves on the very first render\n * with no flash and works in a DOM-less render path (SSR, headless export, a\n * Node MCP tool) where the async path never resolves at all. Only when the\n * sync decoder cannot handle the format (progressive JPEG, WebP, EMF/WMF)\n * does this fall back to the pre-existing ASYNC decode (`Image` + `<canvas>`,\n * DOM-only), which caches the sampled colour by image URL (a\n * `c:pictureOptions` data URL is content-addressed: identical pictures share\n * one decode) and exposes a subscribe hook so a binding can re-render once a\n * sample lands.\n *\n * Usage from a binding: call {@link resolveBarFacePicturePixelColor}\n * synchronously while building the view model (used internally by\n * `resolveExtrusionFaceFill`); subscribe once per mounted chart view via\n * {@link subscribeBarFacePicturePixelSamples} and rebuild the view model\n * (or otherwise force a re-render) whenever it fires, mirroring how\n * `ColorChangedImage`/`use-color-change-image.ts` already re-render once\n * `applyColorChange` (`image-color-change.ts`) resolves. That subscription\n * only ever fires for the async fallback path now; a synchronously-resolved\n * sample needs no re-render since it lands before the current render even\n * finishes.\n *\n * @module chart-bar3d-face-picture-sample\n */\nimport { parseDataUrlToBytes, sampleFirstPixelColorFromBytes } from 'pptx-viewer-core';\n\n/** Decodes an image URL (typically a `data:` URL) and resolves its sampled colour, or `undefined` when it cannot be decoded. */\nexport type BarFacePictureSampler = (imageUrl: string) => Promise<string | undefined>;\n\nconst sampleCache = new Map<string, string | undefined>();\nconst inFlight = new Map<string, Promise<void>>();\nconst listeners = new Set<() => void>();\n/** Bumped every time a sample resolves; a cheap primitive snapshot for `useSyncExternalStore`-style hooks (see {@link getBarFacePicturePixelSampleVersion}). */\nlet sampleVersion = 0;\n\n/**\n * Synchronously read a previously-resolved sample. `undefined` means either\n * \"not sampled yet\" (call {@link ensureBarFacePicturePixelSampled} to start)\n * or \"sampled, but no colour could be decoded\" (e.g. no DOM); the caller\n * cannot tell these apart and does not need to, since both keep using the\n * pre-existing resolved point/series colour fallback.\n */\nexport function getCachedBarFacePicturePixelColor(imageUrl: string): string | undefined {\n\treturn sampleCache.get(imageUrl);\n}\n\n/**\n * Subscribe to every sample that resolves (successfully or not). Fires once\n * per {@link ensureBarFacePicturePixelSampled} call that was not already\n * cached/in-flight. A binding calls this once per mounted chart and forces a\n * view-model rebuild in the listener; it does not need to filter by image\n * URL, since a rebuild the sample did not affect is a cheap no-op diff.\n */\nexport function subscribeBarFacePicturePixelSamples(listener: () => void): () => void {\n\tlisteners.add(listener);\n\treturn () => listeners.delete(listener);\n}\n\nfunction notifyBarFacePicturePixelListeners(): void {\n\tsampleVersion += 1;\n\tfor (const listener of listeners) {\n\t\tlistener();\n\t}\n}\n\n/**\n * A monotonically increasing counter, bumped once per resolved sample.\n * Framework `useSyncExternalStore`-style hooks (React) use this as the\n * snapshot value paired with {@link subscribeBarFacePicturePixelSamples}: a\n * plain number compares cheaply with `Object.is`, unlike re-deriving a\n * snapshot object on every call.\n */\nexport function getBarFacePicturePixelSampleVersion(): number {\n\treturn sampleVersion;\n}\n\n/** Format one 0-255 channel as a 2-digit hex pair. */\nfunction hexChannel(value: number): string {\n\treturn Math.max(0, Math.min(255, Math.round(value)))\n\t\t.toString(16)\n\t\t.padStart(2, '0');\n}\n\n/**\n * Decode `imageUrl` via the browser's `Image` + `<canvas>` pipeline and read\n * the pixel at (0,0) - PowerPoint's own sample point (see this module's doc\n * comment). Resolves to `undefined` outside a DOM (SSR, headless vitest) or\n * on any decode failure; the caller's fallback (the resolved point/series\n * colour) is never worse than what shipped before this module existed.\n *\n * Drawing with an explicit 1x1 SOURCE rect (not a full-image draw scaled down\n * to a 1x1 canvas) is load-bearing: scaling the whole image down would let\n * the browser box-filter/average pixels, which is exactly the \"solid\n * majority colour\" reading COM ground truth already ruled out (a 16x16\n * mostly-red image with one green corner pixel painted the untargeted face\n * solid GREEN, not red).\n *\n * Resolves to a `#rrggbb` HEX string, matching every other colour this\n * renderer passes through `tint`/`shade` (`chart-palette.ts`'s `hexToRgb`\n * only parses hex, not `rgb(...)`).\n */\nexport function decodeFirstPixelColor(imageUrl: string): Promise<string | undefined> {\n\tif (typeof Image === 'undefined' || typeof document === 'undefined') {\n\t\treturn Promise.resolve(undefined);\n\t}\n\treturn new Promise((resolve) => {\n\t\tconst img = new Image();\n\t\timg.crossOrigin = 'anonymous';\n\t\timg.onload = () => {\n\t\t\ttry {\n\t\t\t\tconst canvas = document.createElement('canvas');\n\t\t\t\tcanvas.width = 1;\n\t\t\t\tcanvas.height = 1;\n\t\t\t\tconst ctx = canvas.getContext('2d');\n\t\t\t\tif (!ctx) {\n\t\t\t\t\tresolve(undefined);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tctx.drawImage(img, 0, 0, 1, 1, 0, 0, 1, 1);\n\t\t\t\tconst [r, g, b, a] = ctx.getImageData(0, 0, 1, 1).data;\n\t\t\t\tresolve(a === 0 ? undefined : `#${hexChannel(r)}${hexChannel(g)}${hexChannel(b)}`);\n\t\t\t} catch {\n\t\t\t\t// A tainted canvas (cross-origin picture with no CORS headers) or any\n\t\t\t\t// other decode failure: keep the caller's existing fallback.\n\t\t\t\tresolve(undefined);\n\t\t\t}\n\t\t};\n\t\timg.onerror = () => resolve(undefined);\n\t\timg.src = imageUrl;\n\t});\n}\n\n/**\n * Kick off sampling `imageUrl` if it is not already cached or in flight.\n * Fire-and-forget: never throws, never returns the sample itself (read it\n * back via {@link getCachedBarFacePicturePixelColor} once\n * {@link subscribeBarFacePicturePixelSamples} fires). Safe to call on every\n * view-model build; a cached/in-flight URL is a single `Map` lookup.\n */\nexport function ensureBarFacePicturePixelSampled(\n\timageUrl: string,\n\tsampler: BarFacePictureSampler = decodeFirstPixelColor,\n): void {\n\tif (sampleCache.has(imageUrl) || inFlight.has(imageUrl)) {\n\t\treturn;\n\t}\n\tconst pending = sampler(imageUrl)\n\t\t.then((color) => {\n\t\t\tsampleCache.set(imageUrl, color);\n\t\t\treturn undefined;\n\t\t})\n\t\t.catch(() => {\n\t\t\tsampleCache.set(imageUrl, undefined);\n\t\t})\n\t\t.finally(() => {\n\t\t\tinFlight.delete(imageUrl);\n\t\t\tnotifyBarFacePicturePixelListeners();\n\t\t});\n\tinFlight.set(imageUrl, pending);\n}\n\n/**\n * Attempt a synchronous, DOM-free decode of `imageUrl`'s pixel (0,0) via\n * `pptx-viewer-core`. Returns `undefined` for a non-`data:` URL, a format the\n * sync decoder does not cover (progressive JPEG, WebP, EMF/WMF), or a decode\n * failure - never throws.\n */\nfunction trySampleFirstPixelColorSync(imageUrl: string): string | undefined {\n\tconst parsed = parseDataUrlToBytes(imageUrl);\n\tif (!parsed) {\n\t\treturn undefined;\n\t}\n\ttry {\n\t\treturn sampleFirstPixelColorFromBytes(parsed.bytes);\n\t} catch {\n\t\treturn undefined;\n\t}\n}\n\n/**\n * Resolve `imageUrl`'s sampled first-pixel colour for use THIS render: an\n * already-cached/synchronously-decoded result is returned immediately (no\n * flash); otherwise this tries the synchronous decoder once, caching and\n * returning its result if it succeeds, and only falls back to kicking off\n * the async `Image`/`<canvas>` decode (returning `undefined` for this\n * render, resolved later via {@link subscribeBarFacePicturePixelSamples})\n * when the sync decoder cannot handle the format.\n */\nexport function resolveBarFacePicturePixelColor(imageUrl: string): string | undefined {\n\tconst cached = getCachedBarFacePicturePixelColor(imageUrl);\n\tif (cached !== undefined) {\n\t\treturn cached;\n\t}\n\tif (sampleCache.has(imageUrl) || inFlight.has(imageUrl)) {\n\t\treturn undefined; // already resolved to \"undecodable\", or an async decode is already running\n\t}\n\tconst sync = trySampleFirstPixelColorSync(imageUrl);\n\tif (sync !== undefined) {\n\t\tsampleCache.set(imageUrl, sync);\n\t\treturn sync;\n\t}\n\tensureBarFacePicturePixelSampled(imageUrl);\n\treturn undefined;\n}\n\n/** Test-only: reset every module-level cache/subscription between specs. */\nexport function resetBarFacePicturePixelCacheForTests(): void {\n\tsampleCache.clear();\n\tinFlight.clear();\n\tlisteners.clear();\n\tsampleVersion = 0;\n}\n","/**\n * chart-bar3d-face-picture.ts: picture-fill face targeting for a `bar3D`\n * chart's oblique-projection extrusion faces (C2-G9 3-D face-targeting half).\n *\n * Split out of `chart-3d-depth.ts` (the depth/extrusion geometry module,\n * which stayed within the repo's ~300-LOC guidance without this) so the two\n * concerns - \"where do the top/side face polygons sit\" vs. \"what paints\n * them\" - live in separate files. `chart-3d-depth.ts`'s `barExtrusion` calls\n * {@link resolveExtrusionFaceFill} once per face; this module owns resolving\n * `c:applyToSides`/`c:applyToEnd` against the point's (or series') picture\n * and building the `<pattern>` def, leaving the front rect's own\n * `c:applyToFront` targeting to `chart-datapoint-picture-fills.ts` (a\n * completely separate primitive, painted in a later pass).\n *\n * @module chart-bar3d-face-picture\n */\nimport { resolveBarFacePicturePixelColor } from './chart-bar3d-face-picture-sample';\nimport {\n\tresolveActiveDataPointPicture,\n\tresolveDataPointPictureFill,\n} from './chart-datapoint-picture-resolve';\nimport type { ChartSeriesLike } from './chart-datapoint-style';\nimport { shade, tint } from './chart-palette';\nimport { buildPictureFillPatternDef, polygonBoundingBox } from './chart-picture-pattern-def';\nimport type { ChartSvgDef, SvgRect } from './chart-view-model-types';\n\n/**\n * A `bar3D` chart's series data, threaded through the depth pass so its\n * extrusion faces can resolve their own picture-fill targeting. `elementId`\n * prefixes every pattern id, matching `chart-datapoint-picture-fills.ts`'s\n * front-face pattern ids so two chart instances on the same slide never\n * collide.\n */\nexport interface BarFacePictureContext {\n\tseries: readonly ChartSeriesLike[];\n\telementId: string;\n}\n\n/**\n * Resolve the fallback fill for a `bar3D` extrusion face (top/end or side)\n * that no picture targets: `baseColor` (the resolved point/series colour, OR\n * - once decoded - the picture's own sampled colour, see\n * {@link resolveExtrusionFaceFill}), shaded (side) or tinted (top/end) with\n * the SAME per-face 3-D lighting every solid-filled bar already gets.\n *\n * COM-verified ground truth (PowerPoint Object 16, 2026-09): a `bar3D` point\n * whose fill is picture-only (`c:pictureOptions` with an embedded picture,\n * NO `c:spPr/a:solidFill`) and whose `c:applyToSides`/`c:applyToEnd` are\n * explicitly `0` does NOT paint that face black, and does NOT paint the\n * actual picture there either. Two independent test decks (a real\n * `Series.ApplyPictToFront/Sides/End` chart built through PowerPoint's own\n * object model, not hand-authored XML) confirm PowerPoint paints a FLAT\n * solid colour there, run through its ordinary per-face lighting, that\n * tracks the fill picture itself: a yellow/purple striped fill painted a\n * solid purple (the stripe colour sitting at the image's first pixel) on\n * both untargeted faces, and a 16x16 mostly-red fill with a single green\n * pixel at (0,0) painted those faces solid GREEN, not the majority red -\n * i.e. PowerPoint samples the picture's pixel at (0,0), not an average or\n * the centre. {@link resolveExtrusionFaceFill} now reproduces that: it calls\n * `chart-bar3d-face-picture-sample.ts`'s `resolveBarFacePicturePixelColor`\n * (a synchronous, DOM-free decode first, an async `Image`/`<canvas>` decode\n * as the fallback for formats the sync decoder does not cover) and, once a\n * sample has landed, tints/shades THAT colour instead of the resolved\n * point/series one. Before a sample resolves (or when neither decode path\n * can handle the format), this resolved point/series colour is still the\n * fallback used here, which is why this function keeps taking a plain colour\n * rather than an image URL.\n */\nexport function resolveUntargetedBarFaceFill(face: 'side' | 'end', baseColor: string): string {\n\treturn face === 'end' ? tint(baseColor, 0.22) : shade(baseColor, 0.25);\n}\n\n/**\n * Resolve one extrusion face's fill: a `c:dPt`/`c:ser` picture-fill pattern\n * when {@link resolveDataPointPictureFill} targets this face\n * (`c:applyToSides`/`c:applyToEnd`); otherwise this face is untargeted, and\n * PowerPoint paints it a flat colour sampled from the picture itself when one\n * is configured at all (see {@link resolveUntargetedBarFaceFill}'s doc\n * comment). This tints/shades the SAMPLED colour whenever one resolves -\n * synchronously, on this very render, for a format the DOM-free decoder\n * covers (PNG/GIF/BMP/baseline JPEG); otherwise the async `Image`/`<canvas>`\n * decode is kicked off (fire-and-forget - the caller re-renders once it\n * resolves) and this falls back to tinting/shading `resolvedColor` (the\n * resolved point/series colour) for this render, same as before sampling\n * existed. A point with no picture fill at all always uses `resolvedColor`.\n * Pushes the pattern def onto `defs` when one is built.\n */\nexport function resolveExtrusionFaceFill(\n\tfacePoints: string,\n\tface: 'side' | 'end',\n\tresolvedColor: string,\n\trect: SvgRect,\n\tpicture: BarFacePictureContext | undefined,\n\tdefs: ChartSvgDef[],\n): string {\n\tconst fallback = resolveUntargetedBarFaceFill(face, resolvedColor);\n\tif (!picture || !rect.part || rect.part.pointIndex === undefined) {\n\t\treturn fallback;\n\t}\n\tconst series = picture.series[rect.part.seriesIndex];\n\tif (!series) {\n\t\treturn fallback;\n\t}\n\tconst resolved = resolveDataPointPictureFill(\n\t\tseries,\n\t\trect.part.pointIndex,\n\t\trect.part.seriesIndex,\n\t\tface,\n\t);\n\tif (resolved) {\n\t\tconst patternId = `${picture.elementId}-${resolved.patternId}`;\n\t\tdefs.push(\n\t\t\tbuildPictureFillPatternDef(\n\t\t\t\tpatternId,\n\t\t\t\tresolved.imageUrl,\n\t\t\t\tresolved.format,\n\t\t\t\tpolygonBoundingBox(facePoints),\n\t\t\t\tresolved.tileHeightPx,\n\t\t\t),\n\t\t);\n\t\treturn `url(#${patternId})`;\n\t}\n\tconst activePicture = resolveActiveDataPointPicture(series, rect.part.pointIndex);\n\tif (!activePicture?.imageUrl) {\n\t\treturn fallback;\n\t}\n\tconst sampled = resolveBarFacePicturePixelColor(activePicture.imageUrl);\n\tif (sampled !== undefined) {\n\t\treturn resolveUntargetedBarFaceFill(face, sampled);\n\t}\n\treturn fallback;\n}\n","/**\n * Chart legend swatch layout: positions each `ChartViewModel` legend entry\n * (colour swatch + label) for the two anchor modes the shared chart engine\n * produces:\n *\n * - horizontal row (`legendAnchor !== 'start'`, i.e. bottom/top legends):\n * entries are centred on `vm.legendX` across a fixed-width row.\n * - vertical stack (`legendAnchor === 'start'`, i.e. left/right legends):\n * entries stack downward from `vm.legendY` at a fixed line height.\n *\n * Every binding's chart projector (React/Vue/Angular/Svelte/Vanilla) declared\n * this same `LEGEND_ITEM_WIDTH = 80` constant and placement formula\n * independently; this module is the single source of truth so a layout tweak\n * lands once for all five.\n *\n * @module chart-legend-layout\n */\nimport { chartFontPx } from './chart-font';\nimport type { LegendLineSwatch } from './chart-legend-swatch';\nimport type { ChartViewModel } from './chart-view-model';\n\n// Horizontal centre-to-centre spacing between legend swatches in a row, and\n// vertical spacing between legend swatches stacked in a side column.\nconst LEGEND_ITEM_WIDTH = 80,\n\tLEGEND_ITEM_HEIGHT = 14;\n\n// Legend label defaults, unchanged from the hardcoded values every binding's\n// projector used before `c:legendEntry/c:txPr` overrides existed. Only a\n// chart that actually authors a legend-entry text override diverges from these.\nconst DEFAULT_LEGEND_FONT_SIZE = 9,\n\tDEFAULT_LEGEND_TEXT_COLOR = '#475569';\n\n/** One positioned legend entry: swatch origin + colour + label + resolved text style. */\nexport interface ChartLegendLayoutItem {\n\tx: number;\n\ty: number;\n\tcolor: string;\n\tlabel: string;\n\t/** Label font size in slide-px, already crossed the pt -> px boundary (see chart-font.ts). */\n\tfontSize: number;\n\t/** Label text colour; `c:legendEntry/c:txPr` colour when set, else the default slate. */\n\tfill: string;\n\tfontWeight: 'normal' | 'bold';\n\tfontStyle: 'normal' | 'italic';\n\tfontFamily?: string;\n\t/** Present for a line-drawn series: draw a line + marker sample instead of the rect swatch. */\n\tlineSwatch?: LegendLineSwatch;\n}\n\n/**\n * Compute the positioned legend entries for a chart view model.\n *\n * @param vm - The chart view model (`vm.legend` / `vm.legendX` / `vm.legendY`\n * / `vm.legendAnchor`, as produced by `buildChartViewModel`). Each entry may\n * carry a `textStyle` applied by `applyLegendEntryOverrides` from that\n * entry's `c:legendEntry/c:txPr` override.\n */\nexport function computeChartLegendLayout(vm: ChartViewModel): ChartLegendLayoutItem[] {\n\tconst vertical = vm.legendAnchor === 'start';\n\treturn vm.legend.map((entry, i) => {\n\t\tconst x = vertical\n\t\t\t\t? vm.legendX\n\t\t\t\t: vm.legendX - (vm.legend.length * LEGEND_ITEM_WIDTH) / 2 + i * LEGEND_ITEM_WIDTH,\n\t\t\ty = vertical ? vm.legendY + i * LEGEND_ITEM_HEIGHT : vm.legendY,\n\t\t\ttextStyle = entry.textStyle;\n\t\treturn {\n\t\t\tx,\n\t\t\ty,\n\t\t\tcolor: entry.color,\n\t\t\tlabel: entry.label,\n\t\t\tfontSize:\n\t\t\t\ttextStyle?.fontSize !== undefined\n\t\t\t\t\t? chartFontPx(textStyle.fontSize)\n\t\t\t\t\t: DEFAULT_LEGEND_FONT_SIZE,\n\t\t\tfill: textStyle?.color ?? DEFAULT_LEGEND_TEXT_COLOR,\n\t\t\tfontWeight: textStyle?.bold ? 'bold' : 'normal',\n\t\t\tfontStyle: textStyle?.italic ? 'italic' : 'normal',\n\t\t\tfontFamily: textStyle?.fontFamily,\n\t\t\t...(entry.lineSwatch ? { lineSwatch: entry.lineSwatch } : {}),\n\t\t};\n\t});\n}\n","/**\n * chart-legend-swatch.ts: legend swatch shape for line-drawn chart kinds\n * (line, scatter, and the line series of a bar+line combo).\n *\n * PowerPoint draws two different legend swatch shapes depending on how a\n * series is plotted: a filled rectangle for area-like series (bar, area,\n * pie, ...), and a short line segment with the series' own point marker for\n * a line-drawn series (line, scatter). The shared engine used to draw a\n * plain rect for every chart kind, so a line chart's legend never showed the\n * line/marker sample PowerPoint does, even though the plotted series itself\n * rendered correctly.\n *\n * This is a pure decision function (CLAUDE.md Rule 2), one step further than\n * a plain descriptor: `buildLineLegendSwatch` returns ready-to-render\n * `SvgPrimitive`s (a `line` plus the series' own marker shape, via the same\n * `buildMarkerPrimitive` the chart's data points use), positioned in a local\n * 10x10 box matching the existing rect swatch's origin/size. Every binding\n * already has a generic primitive -> JSX/template mapper for the main chart\n * primitives, so drawing a line-style swatch is just running these through\n * that SAME mapper instead of a per-binding reimplementation of line/marker\n * shape logic. `resolveLegendSwatchKind` is the single place that decides\n * which chart kinds get a line sample instead of a rect, so a new binding (or\n * a future chart kind) cannot diverge on the answer.\n *\n * @module chart-legend-swatch\n */\nimport type { PptxChartSeries } from 'pptx-viewer-core';\n\nimport { resolveDataPointMarker } from './chart-datapoint-style';\nimport { buildMarkerPrimitive } from './chart-marker-shape';\nimport type { SvgPrimitive } from './chart-svg-primitives';\nimport type { SupportedChartKind } from './chart-view-model-kinds';\n\n/** Which shape a binding draws for one legend entry's colour swatch. */\nexport type LegendSwatchKind = 'rect' | 'line';\n\n/** Ready-to-render primitives for a line-style legend swatch (see module doc). */\nexport interface LegendLineSwatch {\n\t/**\n\t * Positioned in the same local box the rect swatch uses (`x: 0, y: -7,\n\t * width: 10, height: 10`): a horizontal line across its vertical centre,\n\t * plus the series' own marker shape at the box's centre. Empty only when\n\t * the series draws neither (`a:ln/a:noFill` AND `c:symbol=\"none\"`), which\n\t * never happens for an un-authored series (the default marker is a circle).\n\t */\n\tprimitives: SvgPrimitive[];\n}\n\n/** Legend swatch line width in px: a fixed icon size, independent of the plotted series' own stroke width. */\nexport const LEGEND_LINE_SWATCH_WIDTH = 2;\n\n/** Legend swatch marker radius in px: a fixed icon size, independent of the series' own `c:marker/c:size`. */\nexport const LEGEND_MARKER_RADIUS = 3;\n\n/** Vertical centre of the swatch box (matches the rect swatch's `y: -7, height: 10`). */\nconst SWATCH_CENTER_Y = -2;\n/** Swatch box width in px (matches the rect swatch's `width: 10`). */\nconst SWATCH_WIDTH = 10;\n\n/**\n * Which chart kinds get a line-style legend swatch instead of a filled rect.\n *\n * Deliberately narrow: only kinds whose whole plot is a drawn line/marker\n * (line, scatter). A filled radar or an area chart still reads as a filled\n * region in PowerPoint's own legend, so they keep the rect swatch; a\n * bar+line combo resolves its line series individually (see\n * `chart-combo.ts`), not through this whole-chart check.\n */\nexport function resolveLegendSwatchKind(kind: SupportedChartKind): LegendSwatchKind {\n\treturn kind === 'line' || kind === 'scatter' ? 'line' : 'rect';\n}\n\n/**\n * Build the line-style legend swatch primitives for one series.\n *\n * The marker uses the series' OWN marker (`c:ser/c:marker`), never a `c:dPt`\n * per-point override: a legend sample represents the whole series, matching\n * PowerPoint. `pointIndex: -1` is not a real data point, so\n * {@link resolveDataPointMarker}'s `c:dPt` lookup never matches it. The marker\n * is always drawn at {@link LEGEND_MARKER_RADIUS}, ignoring the series' own\n * `c:marker/c:size`, so the legend icon stays a consistent small size\n * regardless of how large the plotted markers are.\n */\nexport function buildLineLegendSwatch(\n\tseries: Pick<PptxChartSeries, 'marker' | 'color' | 'lineNoFill' | 'dataPoints' | 'idx'>,\n\tcolor: string,\n\tseriesPosition = 0,\n): LegendLineSwatch {\n\tconst resolved = resolveDataPointMarker(series, -1, seriesPosition),\n\t\tprimitives: SvgPrimitive[] = [];\n\tif (!series.lineNoFill) {\n\t\tprimitives.push({\n\t\t\tkind: 'line',\n\t\t\tx1: 0,\n\t\t\ty1: SWATCH_CENTER_Y,\n\t\t\tx2: SWATCH_WIDTH,\n\t\t\ty2: SWATCH_CENTER_Y,\n\t\t\tstroke: color,\n\t\t\tstrokeWidth: LEGEND_LINE_SWATCH_WIDTH,\n\t\t});\n\t}\n\tconst marker = buildMarkerPrimitive({\n\t\tsymbol: resolved.symbol,\n\t\t// Deliberately ignore the series' authored size (see doc comment above).\n\t\tsize: undefined,\n\t\tcx: SWATCH_WIDTH / 2,\n\t\tcy: SWATCH_CENTER_Y,\n\t\tfill: resolved.fill ?? color,\n\t\tdefaultRadius: LEGEND_MARKER_RADIUS,\n\t});\n\tif (marker) {\n\t\tprimitives.push(marker);\n\t}\n\treturn { primitives };\n}\n\n/**\n * Build a trendline's own legend swatch: a plain dashed/dotted line sample,\n * no marker (a trendline has no data points of its own). Same local box as\n * {@link buildLineLegendSwatch} so it lines up with every other entry.\n */\nexport function buildTrendlineLegendSwatch(\n\tcolor: string,\n\tstrokeWidth: number,\n\tdashArray: string | undefined,\n): LegendLineSwatch {\n\treturn {\n\t\tprimitives: [\n\t\t\t{\n\t\t\t\tkind: 'line',\n\t\t\t\tx1: 0,\n\t\t\t\ty1: SWATCH_CENTER_Y,\n\t\t\t\tx2: SWATCH_WIDTH,\n\t\t\t\ty2: SWATCH_CENTER_Y,\n\t\t\t\tstroke: color,\n\t\t\t\tstrokeWidth,\n\t\t\t\tdashArray,\n\t\t\t},\n\t\t],\n\t};\n}\n","import type {\n\tPptxChartAxisFormatting,\n\tPptxChartDisplayUnitsLabel,\n\tPptxChartShapeProps,\n} from 'pptx-viewer-core';\n\nimport { DEFAULT_CHART_TEXT_PX, chartFontPx } from './chart-font';\nimport type { SvgLine, SvgText } from './chart-view-model';\n\nconst DEFAULT_COLOR = '#64748b';\n\nfunction dashArray(style: string | undefined, width: number): string | undefined {\n\tif (!style || style === 'solid') {\n\t\treturn undefined;\n\t}\n\tconst unit = Math.max(width, 1);\n\tif (style === 'dot' || style === 'sysDot') {\n\t\treturn `${unit} ${unit * 2}`;\n\t}\n\tif (style === 'lgDash') {\n\t\treturn `${unit * 6} ${unit * 3}`;\n\t}\n\treturn `${unit * 3} ${unit * 2}`;\n}\n\n/**\n * SvgText style for axis-driven chart text (tick labels, category labels,\n * captions). `axis.fontSize` is parsed in POINTS by core; it crosses the\n * pt -> px boundary exactly here (see chart-font.ts). `defaultFontSizePx` is\n * already px and defaults to PowerPoint's 10 pt chart text (13.33 px).\n */\nexport function chartAxisTextStyle(\n\taxis: PptxChartAxisFormatting | undefined,\n\tdefaultFontSizePx = DEFAULT_CHART_TEXT_PX,\n): Pick<SvgText, 'fontSize' | 'fill' | 'fontWeight' | 'fontFamily'> {\n\treturn {\n\t\tfontSize: axis?.fontSize !== undefined ? chartFontPx(axis.fontSize) : defaultFontSizePx,\n\t\tfill: axis?.fontColor ?? DEFAULT_COLOR,\n\t\t...(axis?.fontBold !== undefined ? { fontWeight: axis.fontBold ? 'bold' : 'normal' } : {}),\n\t\t...(axis?.fontFamily ? { fontFamily: axis.fontFamily } : {}),\n\t};\n}\n\n/**\n * Text style for a display-units caption (`c:dispUnitsLbl` /\n * ChartEx `cx:unitsLabel`), starting from the axis's own text style and\n * overriding with the label's distinct `txPr` when one was parsed (only a\n * ChartEx `cx:unitsLabel/cx:txPr` populates these fields today; classic\n * `c:dispUnitsLbl` has no run-font child of its own).\n */\nexport function unitsLabelTextStyle(\n\taxis: PptxChartAxisFormatting | undefined,\n\tbaseStyle: Pick<SvgText, 'fontSize' | 'fill' | 'fontWeight' | 'fontFamily'>,\n): Pick<SvgText, 'fontSize' | 'fill' | 'fontWeight' | 'fontFamily'> {\n\tconst label = axis?.displayUnitsLabel;\n\tif (typeof label !== 'object' || label === null) {\n\t\treturn baseStyle;\n\t}\n\tconst { fontFamily, fontSize, fontBold, fontColor } = label as PptxChartDisplayUnitsLabel;\n\treturn {\n\t\t...baseStyle,\n\t\t...(fontSize !== undefined ? { fontSize: chartFontPx(fontSize) } : {}),\n\t\t...(fontColor ? { fill: fontColor } : {}),\n\t\t...(fontBold !== undefined ? { fontWeight: fontBold ? 'bold' : 'normal' } : {}),\n\t\t...(fontFamily ? { fontFamily } : {}),\n\t};\n}\n\nexport function chartLineStyle(\n\tshape: PptxChartShapeProps | null | undefined,\n\tfallbackColor = DEFAULT_COLOR,\n\tfallbackWidth = 1,\n): Pick<SvgLine, 'stroke' | 'strokeWidth' | 'dashArray'> {\n\tconst strokeWidth = shape?.strokeWidth ?? fallbackWidth;\n\treturn {\n\t\tstroke: shape?.strokeColor ?? fallbackColor,\n\t\tstrokeWidth,\n\t\t...(dashArray(shape?.strokeDashStyle, strokeWidth)\n\t\t\t? { dashArray: dashArray(shape?.strokeDashStyle, strokeWidth) }\n\t\t\t: {}),\n\t};\n}\n","import type { PptxChartAxisFormatting, PptxChartShapeProps } from 'pptx-viewer-core';\n\nimport { chartLineStyle } from './chart-axis-style';\nimport type { PlotLayout, SvgLine } from './chart-view-model';\n\nexport function buildVerticalTickMark(\n\taxisX: number,\n\ty: number,\n\tplacement: PptxChartAxisFormatting['majorTickMark'],\n\tside: 'left' | 'right',\n\tlength: number,\n\tshape: PptxChartShapeProps | undefined,\n): SvgLine | undefined {\n\tif (!placement || placement === 'none') {\n\t\treturn undefined;\n\t}\n\tconst inward = side === 'left' ? 1 : -1;\n\tconst startOffset = placement === 'cross' ? -inward * length : 0;\n\tconst endOffset = placement === 'out' ? -inward * length : inward * length;\n\treturn {\n\t\tkind: 'line',\n\t\tx1: axisX + startOffset,\n\t\ty1: y,\n\t\tx2: axisX + endOffset,\n\t\ty2: y,\n\t\t...chartLineStyle(shape),\n\t};\n}\n\nexport function buildVerticalAxisLine(\n\taxis: PptxChartAxisFormatting | undefined,\n\taxisX: number,\n\tlayout: PlotLayout,\n): SvgLine | undefined {\n\treturn axis?.spPr\n\t\t? {\n\t\t\t\tkind: 'line',\n\t\t\t\tx1: axisX,\n\t\t\t\ty1: layout.plotTop,\n\t\t\t\tx2: axisX,\n\t\t\t\ty2: layout.plotBottom,\n\t\t\t\t...chartLineStyle(axis.spPr),\n\t\t\t}\n\t\t: undefined;\n}\n\nexport function buildStyledGridline(\n\ty: number,\n\tlayout: PlotLayout,\n\tshape: PptxChartShapeProps | undefined,\n\tfallbackColor: string,\n\tfallbackWidth: number,\n\tfallbackDash: string | undefined,\n\topacity: number | undefined,\n): SvgLine {\n\tconst style = chartLineStyle(shape, fallbackColor, fallbackWidth);\n\treturn {\n\t\tkind: 'line',\n\t\tx1: layout.plotLeft,\n\t\ty1: y,\n\t\tx2: layout.plotRight,\n\t\ty2: y,\n\t\t...style,\n\t\t...((shape ? style.dashArray : fallbackDash)\n\t\t\t? { dashArray: shape ? style.dashArray : fallbackDash }\n\t\t\t: {}),\n\t\t...(opacity !== undefined ? { opacity } : {}),\n\t};\n}\n\n/**\n * A vertical major/minor gridline spanning the full plot height at `x`.\n * `buildStyledGridline`'s counterpart for a scatter/bubble chart's X value\n * axis (`c:valAx/@axPos=\"b\"`), which is a real numeric axis with its own\n * `c:majorGridlines`, not the category axis every other cartesian kind draws.\n */\nexport function buildVerticalStyledGridline(\n\tx: number,\n\tlayout: PlotLayout,\n\tshape: PptxChartShapeProps | undefined,\n\tfallbackColor: string,\n\tfallbackWidth: number,\n\tfallbackDash: string | undefined,\n\topacity: number | undefined,\n): SvgLine {\n\tconst style = chartLineStyle(shape, fallbackColor, fallbackWidth);\n\treturn {\n\t\tkind: 'line',\n\t\tx1: x,\n\t\ty1: layout.plotTop,\n\t\tx2: x,\n\t\ty2: layout.plotBottom,\n\t\t...style,\n\t\t...((shape ? style.dashArray : fallbackDash)\n\t\t\t? { dashArray: shape ? style.dashArray : fallbackDash }\n\t\t\t: {}),\n\t\t...(opacity !== undefined ? { opacity } : {}),\n\t};\n}\n","/**\n * chart-trendline-defaults.ts: PowerPoint's own default trendline stroke\n * (1.5pt, dotted), applied when a trendline carries no `c:spPr`.\n *\n * Split into its own module (rather than living in `chart-overlays-trendline.ts`,\n * which draws the trendline itself) so `chart-legend-build.ts` can share the\n * exact same default for the trendline's legend swatch without importing the\n * `chart-view-model` barrel that module pulls in, which would be circular\n * (the barrel re-exports `chart-legend-build.ts` itself).\n *\n * @module chart-trendline-defaults\n */\nexport const DEFAULT_TRENDLINE_WIDTH = 1.5;\nexport const DEFAULT_TRENDLINE_DASH = 'sysDot';\n","/**\n * chart-view-model-scale.ts: palette, value-range and axis-value helpers of\n * the chart engine. Split out of `chart-view-model.ts`, which re-exports\n * everything here; see that module's header for the palette caveat.\n *\n * @module chart-view-model-scale\n */\n/* eslint-disable one-var -- this module predates the rule and combining every\n sibling `const`/`let` in a function into one comma-list (oxlint's own\n `--fix` cannot do this safely once a non-declaration statement sits between\n them) would churn geometry code far beyond this change's scope. */\n\nimport type { PptxChartSeries } from 'pptx-viewer-core';\n\nimport { axisTargetIntervals, niceValueAxisBounds } from './chart-axis-nice';\nimport { DEFAULT_CHART_PALETTE } from './chart-helpers';\nimport { formatChartNumber } from './chart-number-format';\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Palette\n// ─────────────────────────────────────────────────────────────────────────────\n\n/**\n * Default Office accent palette (accent1-accent6 plus the two chart extras).\n *\n * An alias of `DEFAULT_CHART_PALETTE` (chart-helpers.ts), on purpose: the two\n * shared entry points used to carry different fallback palettes, so the same\n * unstyled chart painted Office accents in one binding and a Tailwind-ish set\n * in another depending on which helper its renderer imported.\n */\nexport const DEFAULT_PALETTE: readonly string[] = DEFAULT_CHART_PALETTE;\n\n/** Return the palette colour for an index, preferring a parsed colour palette. */\nexport function paletteColor(index: number, colorPalette: readonly string[] | undefined): string {\n\tconst pal = colorPalette && colorPalette.length > 0 ? colorPalette : DEFAULT_PALETTE;\n\treturn pal[index % pal.length];\n}\n\n/**\n * Resolve a series' colour, preferring the series' own `color` property, then\n * its marker fill (scatter series often author `a:ln/a:noFill` on the series\n * and put the colour on `c:marker/c:spPr`; the points paint that fill, so the\n * legend swatch must match it), then the palette.\n */\nexport function seriesColor(\n\tseries: PptxChartSeries,\n\tindex: number,\n\tcolorPalette: readonly string[] | undefined,\n): string {\n\treturn series.color ?? series.marker?.spPr?.fillColor ?? paletteColor(index, colorPalette);\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Value range\n// ─────────────────────────────────────────────────────────────────────────────\n\n/** Min/max/span of a value axis. */\nexport interface ValueRange {\n\tmin: number;\n\tmax: number;\n\tspan: number;\n\t/** When true, the range is log-scaled (min/max are data-space power-of-base bounds, span is in log-space). */\n\tlogScale?: boolean;\n\t/** Logarithmic base (e.g. 10, 2, Math.E). Only meaningful when logScale is true. */\n\tlogBase?: number;\n\t/** Whether values increase from top to bottom. */\n\treverseOrder?: boolean;\n\t/**\n\t * Step between major gridlines when the bounds came from the automatic\n\t * scale. See the same field on `ValueRange` in `chart-helpers.ts`.\n\t */\n\tmajorUnit?: number;\n}\n\n/**\n * Automatic Y-axis range, on PowerPoint's terms. See `chart-axis-nice.ts`; this\n * mirrors `computeValueRange` in `chart-helpers.ts`.\n *\n * @param plotHeightPx The chart's plot-area height (`PlotLayout.plotHeight`),\n * when the caller has it; see `axisTargetIntervals`'s doc comment for why\n * this changes the gridline count PowerPoint's automatic scale picks.\n */\nexport function computeValueRange(\n\tseries: ReadonlyArray<PptxChartSeries>,\n\tplotHeightPx?: number,\n): ValueRange {\n\tlet dataMin = Number.POSITIVE_INFINITY,\n\t\tdataMax = Number.NEGATIVE_INFINITY;\n\tfor (const item of series) {\n\t\tfor (const value of item.values) {\n\t\t\tif (value < dataMin) {\n\t\t\t\tdataMin = value;\n\t\t\t}\n\t\t\tif (value > dataMax) {\n\t\t\t\tdataMax = value;\n\t\t\t}\n\t\t}\n\t}\n\tif (dataMin === Number.POSITIVE_INFINITY) {\n\t\treturn { min: 0, max: 1, span: 1 };\n\t}\n\tconst { min, max, majorUnit } = niceValueAxisBounds(\n\t\tdataMin,\n\t\tdataMax,\n\t\tplotHeightPx !== undefined ? axisTargetIntervals(plotHeightPx) : undefined,\n\t);\n\treturn { min, max, span: Math.max(max - min, Number.EPSILON), majorUnit };\n}\n\n/**\n * Value range for a stacked bar: the per-category sums, then the same automatic\n * scale as any other value axis.\n *\n * @param plotHeightPx See `computeValueRange`'s parameter of the same name.\n */\nexport function computeStackedValueRange(\n\tseries: ReadonlyArray<PptxChartSeries>,\n\tcatCount: number,\n\tplotHeightPx?: number,\n): ValueRange {\n\tlet maxSum = 0,\n\t\tminSum = 0;\n\tfor (let ci = 0; ci < catCount; ci++) {\n\t\tlet pos = 0,\n\t\t\tneg = 0;\n\t\tfor (const s of series) {\n\t\t\tconst v = s.values[ci] ?? 0;\n\t\t\tif (v >= 0) {\n\t\t\t\tpos += v;\n\t\t\t} else {\n\t\t\t\tneg += v;\n\t\t\t}\n\t\t}\n\t\tmaxSum = Math.max(maxSum, pos);\n\t\tminSum = Math.min(minSum, neg);\n\t}\n\tconst { min, max, majorUnit } = niceValueAxisBounds(\n\t\tMath.min(minSum, 0),\n\t\tMath.max(maxSum, 0),\n\t\tplotHeightPx !== undefined ? axisTargetIntervals(plotHeightPx) : undefined,\n\t);\n\treturn { min, max, span: Math.max(max - min, Number.EPSILON), majorUnit };\n}\n\n/**\n * Map a data value to a Y pixel coordinate (top = max, bottom = min).\n * Routes through logarithmic scaling when `range.logScale` is set (the branch is\n * inlined here, mirroring `valueToYLog` in `chart-axis.ts`, to avoid a circular\n * import). Linear behaviour is unchanged when `logScale`/`logBase` are absent.\n */\nexport function valueToY(val: number, range: ValueRange, topY: number, bottomY: number): number {\n\tconst usable = bottomY - topY;\n\tlet ratio: number;\n\tif (range.logScale && range.logBase) {\n\t\tconst base = range.logBase,\n\t\t\tclampedVal = Math.max(val, range.min),\n\t\t\tlogVal = Math.log(clampedVal) / Math.log(base),\n\t\t\tlogMin = Math.log(range.min) / Math.log(base);\n\t\tratio = (logVal - logMin) / range.span;\n\t} else {\n\t\tratio = (val - range.min) / range.span;\n\t}\n\treturn range.reverseOrder ? topY + ratio * usable : bottomY - ratio * usable;\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Formatting\n// ─────────────────────────────────────────────────────────────────────────────\n\n/**\n * Format a numeric axis or data label to a short human-readable string, or\n * through the chart's own `c:numFmt/@formatCode` when it declares one. See\n * `formatAxisValue` in `chart-helpers.ts`, which this mirrors.\n */\nexport function formatAxisValue(val: number, formatCode?: string): string {\n\tconst formatted = formatChartNumber(val, formatCode);\n\tif (formatted !== undefined) {\n\t\treturn formatted;\n\t}\n\tif (Math.abs(val) >= 1_000_000) {\n\t\treturn `${(val / 1_000_000).toFixed(1)}M`;\n\t}\n\tif (Math.abs(val) >= 1_000) {\n\t\treturn `${(val / 1_000).toFixed(1)}K`;\n\t}\n\tif (Number.isInteger(val)) {\n\t\treturn String(val);\n\t}\n\treturn val.toFixed(1);\n}\n\n/**\n * Build the hover-tooltip text for a plain data mark (bar / line / area /\n * scatter / bubble / pie / radar point), projected as each primitive's `title`\n * field (see the doc comment on `SvgPath.title`).\n *\n * Mirrors the region map's own `\"<name>: <value>\"` tooltip (chart-waterfall-map.ts):\n * join whichever of the series name and category/point label are known, then\n * append the formatted value. Either label may be absent (a scatter/bubble\n * point has no category; an un-named series has no name); the result degrades\n * to just the value when neither is.\n */\nexport function buildMarkTooltip(\n\tseriesName: string | undefined,\n\tcategoryLabel: string | undefined,\n\tvalue: number,\n\tnumberFormat?: string,\n): string {\n\tconst label = [seriesName, categoryLabel]\n\t\t\t.filter((part): part is string => Boolean(part && part.length > 0))\n\t\t\t.join(', '),\n\t\tformatted = formatAxisValue(value, numberFormat);\n\treturn label.length > 0 ? `${label}: ${formatted}` : formatted;\n}\n","/**\n * Dash patterns for connector lines.\n *\n * Split out of `connector-path.ts` alongside the arrow markers: a connector's\n * stroke decoration is a separate concern from where the line is routed, and\n * both are configured independently in the inspector.\n *\n * Pure and framework-agnostic.\n */\n\nimport { getSvgStrokeDasharray, normalizeStrokeDashType } from './element-style-transform';\n\n/** A single custom-dash segment (percent-of-line-width, 1000ths of a percent). */\nexport interface DashSegment {\n\tdash: number;\n\tspace: number;\n}\n\n/**\n * Return the SVG `stroke-dasharray` string for a given OOXML stroke dash preset\n * and width, or `undefined` for solid lines (no attribute needed).\n *\n * Produces a distinct pattern per preset (`dash`, `lgDash`, `dashDot`,\n * `sysDashDotDot`, etc.) rather than collapsing every non-dot preset to a single\n * `3w/w` approximation, and honours a `custDash` segment list (`a:custDash/a:ds`)\n * when supplied. This delegates to the same {@link getSvgStrokeDasharray} the\n * shape/border code uses, so connectors and shape outlines stay in lock-step.\n *\n * @param dash Raw `a:ln/@prstDash` token (e.g. `\"lgDashDot\"`).\n * @param strokeWidth Resolved stroke width in px.\n * @param customDashSegments Optional `custDash` segments; when present they take\n * precedence and are rendered as an explicit pattern.\n */\nexport function buildDashArray(\n\tdash: string | undefined,\n\tstrokeWidth: number,\n\tcustomDashSegments?: ReadonlyArray<DashSegment>,\n): string | undefined {\n\tconst segments =\n\t\tcustomDashSegments && customDashSegments.length > 0\n\t\t\t? customDashSegments.map((seg) => ({ dash: seg.dash, space: seg.space }))\n\t\t\t: undefined;\n\t// A `custDash` implies the `custom` dash family even when no `@prstDash`\n\t// token was authored alongside it.\n\tconst dashType = segments ? 'custom' : normalizeStrokeDashType(dash);\n\treturn getSvgStrokeDasharray(dashType, strokeWidth, segments);\n}\n","/**\n * chart-legend-build.ts: builds the base `LegendEntry[]` (colour + label +\n * optional line-style swatch) and the legend's anchor position for a chart\n * view-model. Split out of `chart-view-model-layout.ts` to keep it within the\n * repo's ~300-LOC limit.\n *\n * @module chart-legend-build\n */\nimport type { PptxChartSeries, PptxChartTrendlineType } from 'pptx-viewer-core';\n\nimport { resolveLegendPlacement } from './chart-legend-placement';\nimport { buildLineLegendSwatch, buildTrendlineLegendSwatch } from './chart-legend-swatch';\nimport type { LegendSwatchKind } from './chart-legend-swatch';\nimport { DEFAULT_TRENDLINE_DASH, DEFAULT_TRENDLINE_WIDTH } from './chart-trendline-defaults';\nimport { seriesColor } from './chart-view-model-scale';\nimport type { LegendEntry } from './chart-view-model-types';\nimport { buildDashArray } from './connector-dash';\n\n/** Excel's own trendline-family legend prefix (`\"Linear (Series1)\"`, ...). */\nconst TRENDLINE_LEGEND_PREFIX: Record<PptxChartTrendlineType, string> = {\n\tlinear: 'Linear',\n\texponential: 'Expon.',\n\tlogarithmic: 'Log.',\n\tpower: 'Power',\n\tpolynomial: 'Poly.',\n\tmovingAvg: 'Moving Average',\n};\n\n/**\n * Resolve a legend's anchor position from its declared side, independent of\n * what entries it holds. Split out of `buildLegend` so a non-series legend\n * (the surface chart's value-band legend, `chart-surface-legend.ts`) can\n * reuse the exact same placement rules instead of re-deriving them.\n */\nexport function resolveLegendAnchorPosition(\n\tsvgWidth: number,\n\tsvgHeight: number,\n\tplotTop: number,\n\tlegendPos: string,\n): { legendX: number; legendY: number; legendAnchor: 'start' | 'middle' | 'end' } {\n\tlet legendX = svgWidth / 2,\n\t\tlegendY = svgHeight - 8,\n\t\tlegendAnchor: 'start' | 'middle' | 'end' = 'middle';\n\n\t// `tr` shares `'r'`'s coordinates (a right-aligned column starting at\n\t// plotTop): that is already \"top-right corner\"; it just does not reserve\n\t// plot-area space the way a reserved `'r'` legend does (see computePlotLayout).\n\tconst side = resolveLegendPlacement(legendPos).side;\n\tif (side === 'r') {\n\t\tlegendX = svgWidth - 75;\n\t\tlegendY = plotTop;\n\t\tlegendAnchor = 'start';\n\t} else if (side === 'l') {\n\t\tlegendX = 4;\n\t\tlegendY = plotTop;\n\t\tlegendAnchor = 'start';\n\t} else if (side === 't') {\n\t\tlegendY = 28;\n\t}\n\n\treturn { legendX, legendY, legendAnchor };\n}\n\n/**\n * Build the base legend entries + anchor position for a chart view model.\n *\n * @param swatchKind Which legend entries draw a line + marker sample instead\n * of the default filled rect (see `chart-legend-swatch.ts`). A single value\n * applies to every entry (the whole-chart line/scatter case); an array\n * resolves per series index (a bar+line combo, where only the line series\n * get the line sample). Defaults to `'rect'` for every existing caller that\n * predates line-aware legends.\n */\nexport function buildLegend(\n\tseries: ReadonlyArray<PptxChartSeries>,\n\tcolorPalette: readonly string[] | undefined,\n\tsvgWidth: number,\n\tlegendPos: string,\n\tsvgHeight: number,\n\tplotTop: number,\n\tswatchKind: LegendSwatchKind | ReadonlyArray<LegendSwatchKind> = 'rect',\n): {\n\tlegend: LegendEntry[];\n\tlegendX: number;\n\tlegendY: number;\n\tlegendAnchor: 'start' | 'middle' | 'end';\n} {\n\tconst legend: LegendEntry[] = series.map((s, i) => {\n\t\tconst color = seriesColor(s, i, colorPalette),\n\t\t\tkind = Array.isArray(swatchKind) ? (swatchKind[i] ?? 'rect') : swatchKind;\n\t\treturn {\n\t\t\tcolor,\n\t\t\tlabel: s.name,\n\t\t\t...(kind === 'line' ? { lineSwatch: buildLineLegendSwatch(s, color, i) } : {}),\n\t\t};\n\t});\n\n\t// A trendline gets its own legend entry, right after its owning series\n\t// (Excel/PowerPoint: `\"Linear (Series1)\"`, a dotted line sample). Trendlines\n\t// are only ever legal on bar/line/area/scatter series, so this is a no-op\n\t// for every other chart kind (`series.trendlines` is simply absent there).\n\tseries.forEach((s, i) => {\n\t\tif (!s.trendlines || s.trendlines.length === 0) {\n\t\t\treturn;\n\t\t}\n\t\tconst fallbackColor = seriesColor(s, i, colorPalette);\n\t\ts.trendlines.forEach((tl) => {\n\t\t\tconst color = tl.color ?? fallbackColor;\n\t\t\tconst strokeWidth = tl.lineWidth ?? DEFAULT_TRENDLINE_WIDTH;\n\t\t\tlegend.push({\n\t\t\t\tcolor,\n\t\t\t\tlabel: tl.name ?? `${TRENDLINE_LEGEND_PREFIX[tl.trendlineType]} (${s.name})`,\n\t\t\t\tlineSwatch: buildTrendlineLegendSwatch(\n\t\t\t\t\tcolor,\n\t\t\t\t\tstrokeWidth,\n\t\t\t\t\tbuildDashArray(tl.lineDashStyle ?? DEFAULT_TRENDLINE_DASH, strokeWidth),\n\t\t\t\t),\n\t\t\t});\n\t\t});\n\t});\n\n\tconst { legendX, legendY, legendAnchor } = resolveLegendAnchorPosition(\n\t\tsvgWidth,\n\t\tsvgHeight,\n\t\tplotTop,\n\t\tlegendPos,\n\t);\n\n\treturn { legend, legendX, legendY, legendAnchor };\n}\n","/**\n * chart-view-model-bars.ts: bar / column rectangle and line-point geometry of\n * the chart engine. Split out of `chart-view-model.ts`, which re-exports\n * everything here.\n *\n * @module chart-view-model-bars\n */\n/* eslint-disable one-var -- this module predates the rule and combining every\n sibling `const`/`let` in a function into one comma-list (oxlint's own\n `--fix` cannot do this safely once a non-declaration statement sits between\n them) would churn geometry code far beyond this change's scope. */\n\nimport type { PptxChartSeries } from 'pptx-viewer-core';\n\nimport { seriesColor, valueToY } from './chart-view-model-scale';\nimport type { ValueRange } from './chart-view-model-scale';\nimport type { PlotLayout } from './chart-view-model-types';\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Bar / column\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport interface BarRect {\n\tx: number;\n\ty: number;\n\tw: number;\n\th: number;\n\tfill: string;\n\t/** Source series index, carried so plot builders can tag interactive parts. */\n\tseriesIndex?: number;\n\t/** Source category index, carried so plot builders can tag interactive parts. */\n\tpointIndex?: number;\n}\n\nexport function computeBarRects(\n\tseries: ReadonlyArray<PptxChartSeries>,\n\tcatCount: number,\n\tlayout: PlotLayout,\n\trange: ValueRange,\n\tcolorPalette: readonly string[] | undefined,\n): BarRect[] {\n\tconst rects: BarRect[] = [],\n\t\tseriesCount = Math.max(series.length, 1),\n\t\tbarGroupWidth = layout.plotWidth / Math.max(catCount, 1),\n\t\tsingleBarWidth = (barGroupWidth * 0.7) / seriesCount,\n\t\tgroupOffset = (barGroupWidth - singleBarWidth * seriesCount) / 2;\n\n\tfor (let ci = 0; ci < catCount; ci++) {\n\t\tfor (let si = 0; si < series.length; si++) {\n\t\t\tconst val = series[si].values[ci] ?? 0,\n\t\t\t\tx = layout.plotLeft + barGroupWidth * ci + groupOffset + singleBarWidth * si,\n\t\t\t\tzeroY = valueToY(0, range, layout.plotTop, layout.plotBottom),\n\t\t\t\tvalY = valueToY(val, range, layout.plotTop, layout.plotBottom),\n\t\t\t\ty = Math.min(zeroY, valY),\n\t\t\t\th = Math.max(Math.abs(zeroY - valY), 1);\n\t\t\trects.push({\n\t\t\t\tx,\n\t\t\t\ty,\n\t\t\t\tw: singleBarWidth,\n\t\t\t\th,\n\t\t\t\tfill: seriesColor(series[si], si, colorPalette),\n\t\t\t});\n\t\t}\n\t}\n\treturn rects;\n}\n\nexport function computeStackedBarRects(\n\tseries: ReadonlyArray<PptxChartSeries>,\n\tcatCount: number,\n\tlayout: PlotLayout,\n\trange: ValueRange,\n\tcolorPalette: readonly string[] | undefined,\n): BarRect[] {\n\tconst rects: BarRect[] = [],\n\t\tbarW = (layout.plotWidth / Math.max(catCount, 1)) * 0.7,\n\t\tbarOffset = (layout.plotWidth / Math.max(catCount, 1) - barW) / 2,\n\t\tzeroY = valueToY(0, range, layout.plotTop, layout.plotBottom);\n\n\tfor (let ci = 0; ci < catCount; ci++) {\n\t\tlet posTop = zeroY,\n\t\t\tnegBottom = zeroY;\n\n\t\tfor (let si = 0; si < series.length; si++) {\n\t\t\tconst val = series[si].values[ci] ?? 0;\n\t\t\tif (val === 0) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tconst x = layout.plotLeft + (layout.plotWidth / Math.max(catCount, 1)) * ci + barOffset,\n\t\t\t\th = Math.max(\n\t\t\t\t\tMath.abs(\n\t\t\t\t\t\tvalueToY(val, range, layout.plotTop, layout.plotBottom) -\n\t\t\t\t\t\t\tvalueToY(0, range, layout.plotTop, layout.plotBottom),\n\t\t\t\t\t),\n\t\t\t\t\t1,\n\t\t\t\t);\n\t\t\tif (val > 0) {\n\t\t\t\tconst y = posTop - h;\n\t\t\t\trects.push({\n\t\t\t\t\tx,\n\t\t\t\t\ty,\n\t\t\t\t\tw: barW,\n\t\t\t\t\th,\n\t\t\t\t\tfill: seriesColor(series[si], si, colorPalette),\n\t\t\t\t\tseriesIndex: si,\n\t\t\t\t\tpointIndex: ci,\n\t\t\t\t});\n\t\t\t\tposTop = y;\n\t\t\t} else {\n\t\t\t\tconst y = negBottom;\n\t\t\t\trects.push({\n\t\t\t\t\tx,\n\t\t\t\t\ty,\n\t\t\t\t\tw: barW,\n\t\t\t\t\th,\n\t\t\t\t\tfill: seriesColor(series[si], si, colorPalette),\n\t\t\t\t\tseriesIndex: si,\n\t\t\t\t\tpointIndex: ci,\n\t\t\t\t});\n\t\t\t\tnegBottom = y + h;\n\t\t\t}\n\t\t}\n\t}\n\treturn rects;\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Line / area\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport interface LinePoint {\n\tx: number;\n\ty: number;\n}\n\nexport function computeLinePoints(\n\tvalues: ReadonlyArray<number>,\n\tcatCount: number,\n\tlayout: PlotLayout,\n\trange: ValueRange,\n): LinePoint[] {\n\tconst n = Math.max(catCount, 2);\n\treturn values.map((val, i) => {\n\t\tconst nx = n > 1 ? i / (n - 1) : 0,\n\t\t\tx = layout.plotLeft + layout.plotWidth * nx,\n\t\t\ty = valueToY(val, range, layout.plotTop, layout.plotBottom);\n\t\treturn { x, y };\n\t});\n}\n\nexport function linePointsToSvgString(points: ReadonlyArray<LinePoint>): string {\n\treturn points.map((p) => `${p.x.toFixed(2)},${p.y.toFixed(2)}`).join(' ');\n}\n","/**\n * Background wall/floor panels for the 3D bar/line/area oblique-depth pass.\n *\n * `c:floor`, `c:sideWall`, and `c:backWall` (CT_Surface) are parsed onto\n * `PptxChartData.floor` / `.sideWall` / `.backWall` but, until this module,\n * never painted: a 3D cartesian chart authored with coloured walls rendered\n * with no walls at all. Each panel is a flat quadrilateral swept from the\n * plot's front bounding box to its back bounding box by the same oblique\n * depth vector ({@link ../chart-3d-depth.ts}) that offsets bar/line/area\n * extrusion, so the walls sit in the same illusion of depth as the marks\n * they frame.\n *\n * Deliberately additive and silent: a chart with no authored fill on a given\n * surface renders no panel for it, so an untouched chart's appearance is\n * unchanged. Only cartesian 3D kinds (bar3D/line3D/area3D) call this; pie3D\n * has no plot rectangle to wall in, matching PowerPoint's own behaviour.\n *\n * @module chart-3d-surfaces\n */\nimport type { PptxChart3DSurface } from 'pptx-viewer-core';\n\nimport type { DepthVector } from './chart-3d-depth';\nimport type { SvgPolygon, SvgPrimitive } from './chart-view-model';\nimport type { SurfaceWallColors } from './surface-chart-3d-walls';\n\n/** The three `c:chart`-level 3D surfaces this module can paint. */\nexport interface Chart3DSurfaces {\n\tfloor?: PptxChart3DSurface;\n\tsideWall?: PptxChart3DSurface;\n\tbackWall?: PptxChart3DSurface;\n}\n\n/**\n * Resolve `c:floor`/`c:sideWall`/`c:backWall` fill colours into the shape the\n * WebGL scenes' wall-panel builder ({@link ../surface-chart-3d-walls.ts},\n * `buildSurfaceWallMeshes`) needs, or `undefined` when none of the three is\n * authored. Single parsing/resolution point for BOTH the flat oblique-depth\n * 2D wall panels ({@link build3DSurfacePanels}) and every interactive WebGL\n * chart scene (surface, bar3D, and future line3D/area3D), so a chart's walls\n * read identically across every presentation instead of each caller\n * re-reading `chartData.floor?.spPr?.fillColor` its own way.\n */\nexport function resolveChart3DWallColors(surfaces: Chart3DSurfaces): SurfaceWallColors | undefined {\n\tconst floor = surfaces.floor?.spPr?.fillColor;\n\tconst sideWall = surfaces.sideWall?.spPr?.fillColor;\n\tconst backWall = surfaces.backWall?.spPr?.fillColor;\n\tif (!floor && !sideWall && !backWall) {\n\t\treturn undefined;\n\t}\n\treturn { floor, sideWall, backWall };\n}\n\ninterface Bounds {\n\tminX: number;\n\tmaxX: number;\n\tminY: number;\n\tmaxY: number;\n}\n\n/** Bounding box of the primitive kinds that carry plottable geometry (rect, polygon, polyline). */\nexport function primitivesBounds(prims: readonly SvgPrimitive[]): Bounds | undefined {\n\tlet minX = Number.POSITIVE_INFINITY;\n\tlet maxX = Number.NEGATIVE_INFINITY;\n\tlet minY = Number.POSITIVE_INFINITY;\n\tlet maxY = Number.NEGATIVE_INFINITY;\n\tlet found = false;\n\n\tconst consider = (x: number, y: number): void => {\n\t\tminX = Math.min(minX, x);\n\t\tmaxX = Math.max(maxX, x);\n\t\tminY = Math.min(minY, y);\n\t\tmaxY = Math.max(maxY, y);\n\t\tfound = true;\n\t};\n\n\tfor (const prim of prims) {\n\t\tif (prim.kind === 'rect') {\n\t\t\tconsider(prim.x, prim.y);\n\t\t\tconsider(prim.x + prim.w, prim.y + prim.h);\n\t\t} else if (prim.kind === 'polygon' || prim.kind === 'polyline') {\n\t\t\tfor (const pair of prim.points.trim().split(/\\s+/u)) {\n\t\t\t\tconst [x, y] = pair.split(',').map(Number);\n\t\t\t\tif (Number.isFinite(x) && Number.isFinite(y)) {\n\t\t\t\t\tconsider(x, y);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\treturn found ? { minX, maxX, minY, maxY } : undefined;\n}\n\nfunction panel(\n\tpoints: readonly [number, number][],\n\tsurface: PptxChart3DSurface | undefined,\n): SvgPolygon | undefined {\n\tconst fillColor = surface?.spPr?.fillColor;\n\tif (!fillColor) {\n\t\treturn undefined;\n\t}\n\treturn {\n\t\tkind: 'polygon',\n\t\tpoints: points.map(([x, y]) => `${x.toFixed(2)},${y.toFixed(2)}`).join(' '),\n\t\tfill: fillColor,\n\t\tstroke: surface.spPr?.strokeColor ?? 'none',\n\t\tstrokeWidth: surface.spPr?.strokeWidth ?? 0,\n\t};\n}\n\n/**\n * Build the floor/back-wall/side-wall background panels, furthest-back first\n * so callers can prepend them ahead of the per-mark extrusion. Returns an\n * empty array when none of the three surfaces has an authored fill colour,\n * or when there is no plottable geometry to frame.\n */\nexport function build3DSurfacePanels(\n\tprims: readonly SvgPrimitive[],\n\tsurfaces: Chart3DSurfaces,\n\tdepth: DepthVector,\n): SvgPolygon[] {\n\tconst bounds = primitivesBounds(prims);\n\tif (!bounds) {\n\t\treturn [];\n\t}\n\tconst { minX, maxX, minY, maxY } = bounds;\n\tconst { dx, dy } = depth;\n\n\tconst backWall = panel(\n\t\t[\n\t\t\t[minX + dx, minY + dy],\n\t\t\t[maxX + dx, minY + dy],\n\t\t\t[maxX + dx, maxY + dy],\n\t\t\t[minX + dx, maxY + dy],\n\t\t],\n\t\tsurfaces.backWall,\n\t);\n\tconst floor = panel(\n\t\t[\n\t\t\t[minX, maxY],\n\t\t\t[maxX, maxY],\n\t\t\t[maxX + dx, maxY + dy],\n\t\t\t[minX + dx, maxY + dy],\n\t\t],\n\t\tsurfaces.floor,\n\t);\n\tconst sideWall = panel(\n\t\t[\n\t\t\t[maxX, minY],\n\t\t\t[maxX + dx, minY + dy],\n\t\t\t[maxX + dx, maxY + dy],\n\t\t\t[maxX, maxY],\n\t\t],\n\t\tsurfaces.sideWall,\n\t);\n\n\treturn [backWall, floor, sideWall].filter((p): p is SvgPolygon => p !== undefined);\n}\n","/**\n * Per-series depth staggering for the `bar3D` oblique-depth pass\n * ({@link ./chart-3d-depth.ts}).\n *\n * Before this module, every series in a `bar3D` chart shared the exact same\n * depth offset: a chart with two series drew both series' extrusion at the\n * identical (dx, dy), so the second series sat in the same depth plane as\n * the first instead of receding behind it the way PowerPoint's 3D column\n * chart lays series out along a depth (\"series\") axis. This is the most\n * visible gap between the oblique illusion and an actual 3D projection for\n * the chart type PowerPoint authors use most.\n *\n * `computeSeriesDepth` scales the chart's base depth vector by each series'\n * position along that axis (front = smallest offset, back = the full base\n * magnitude); callers then paint the resulting per-series extrusion groups\n * back-to-front (farthest first) for correct occlusion where staggered\n * series overlap on screen.\n *\n * @module chart-bar3d-series-depth\n */\nimport type { DepthVector } from './chart-3d-depth';\n\n/**\n * A series' fractional position along the depth axis, in `(0, 1]`.\n *\n * Series 0 (nearest the viewer) gets `1 / seriesCount`; the last series gets\n * `1` (the chart's full base depth magnitude). `seriesCount <= 1` returns\n * `1`, which reproduces the previous single-shared-depth behaviour exactly\n * for the common single-series `bar3D` chart, so that case does not regress.\n */\nexport function seriesDepthFactor(seriesIndex: number, seriesCount: number): number {\n\tif (seriesCount <= 1) {\n\t\treturn 1;\n\t}\n\treturn (seriesIndex + 1) / seriesCount;\n}\n\n/** Scale a depth vector by a fractional factor, keeping its direction. */\nexport function scaleDepthVector(depth: DepthVector, factor: number): DepthVector {\n\treturn { dx: depth.dx * factor, dy: depth.dy * factor, magnitude: depth.magnitude * factor };\n}\n\n/** This series' depth offset: the base vector scaled by its position on the depth axis. */\nexport function computeSeriesDepth(\n\tdepth: DepthVector,\n\tseriesIndex: number,\n\tseriesCount: number,\n): DepthVector {\n\treturn scaleDepthVector(depth, seriesDepthFactor(seriesIndex, seriesCount));\n}\n\n/**\n * Order series indexes back-to-front (farthest first) for a painter's-\n * algorithm draw order: the series with the larger depth factor recedes\n * further from the viewer, so it must be painted before (behind) a nearer\n * series' extrusion for staggered bars to occlude correctly.\n */\nexport function sortSeriesBackToFront(\n\tseriesIndexes: readonly number[],\n\tseriesCount: number,\n): number[] {\n\treturn [...seriesIndexes].sort(\n\t\t(a, b) => seriesDepthFactor(b, seriesCount) - seriesDepthFactor(a, seriesCount),\n\t);\n}\n","/**\n * chart-pie3d-tilt.ts: elliptical tilt foreshortening for `pie3D`.\n *\n * `chart-3d-depth.ts` gives every 3D chart type an additive oblique-projection\n * depth pass, but a `pie3D` chart's flat face itself stayed a perfect circle:\n * PowerPoint's own `pie3D` renders the disc as an ellipse once `c:view3D`'s\n * `rotX` tilts it away from square-on, because a circle viewed off-axis\n * foreshortens vertically. This module supplies that missing squash within\n * the same illusion-based approach (no camera/projection rewrite): it scales\n * the pie's already-built flat geometry vertically about its centre, so the\n * slices, their leader lines, and their data labels all move together.\n *\n * @module chart-pie3d-tilt\n */\nimport type { PptxChartView3D } from 'pptx-viewer-core';\n\nimport type { ChartViewModel, SvgLine } from './chart-view-model';\n\nconst DEFAULT_ROT_X = 15;\n/** Never squash a tilted pie3D past this fraction of its true radius. */\nconst MIN_PIE_TILT_SCALE = 0.15;\n\n/**\n * The vertical squash a tilted `pie3D` face should get. Viewed from `rotX`\n * degrees off square-on, a circle of radius r projects to an ellipse whose\n * vertical radius is `r * cos(rotX)`. Clamped so an extreme rotX never\n * collapses the pie to an illegible sliver.\n */\nexport function computePieTiltScale(view3D: PptxChartView3D | undefined): number {\n\tconst rotX = view3D?.rotX ?? DEFAULT_ROT_X;\n\tconst scale = Math.cos((rotX * Math.PI) / 180);\n\treturn Math.min(1, Math.max(Math.abs(scale), MIN_PIE_TILT_SCALE));\n}\n\n/**\n * Squash a generated pie-slice path (`M`/`L`/`A`/`Z` grammar) vertically about\n * `cy` by `scaleY`, turning its circular arcs into elliptical ones. `rx` is\n * left untouched (the tilt is purely a foreshortening of the vertical axis);\n * `ry` and every y-coordinate scale by `scaleY` around the pie's centre.\n */\nexport function squashSlicePathVertical(d: string, cy: number, scaleY: number): string {\n\tconst tokens = d.match(/[MLAZ][^MLAZ]*/gu);\n\tif (!tokens) {\n\t\treturn d;\n\t}\n\tconst squashY = (y: number): number => cy + (y - cy) * scaleY;\n\treturn tokens\n\t\t.map((token) => {\n\t\t\tconst cmd = token[0];\n\t\t\tconst nums = token\n\t\t\t\t.slice(1)\n\t\t\t\t.trim()\n\t\t\t\t.split(/[ ,]+/u)\n\t\t\t\t.filter((s) => s.length > 0)\n\t\t\t\t.map(Number);\n\t\t\tif (cmd === 'M' || cmd === 'L') {\n\t\t\t\tconst out: number[] = [];\n\t\t\t\tfor (let i = 0; i < nums.length; i += 2) {\n\t\t\t\t\tout.push(nums[i], squashY(nums[i + 1]));\n\t\t\t\t}\n\t\t\t\treturn `${cmd}${pairs(out)}`;\n\t\t\t}\n\t\t\tif (cmd === 'A') {\n\t\t\t\t// rx ry xrot large sweep x y -> squash ry + the endpoint's y only.\n\t\t\t\tconst [rx, ry, xrot, largeArc, sweep, ex, ey] = nums;\n\t\t\t\treturn `A${rx},${ry * scaleY},${xrot},${largeArc},${sweep},${ex},${squashY(ey)}`;\n\t\t\t}\n\t\t\treturn 'Z';\n\t\t})\n\t\t.join('');\n}\n\nfunction pairs(nums: number[]): string {\n\tconst out: string[] = [];\n\tfor (let i = 0; i < nums.length; i += 2) {\n\t\tout.push(`${nums[i]},${nums[i + 1]}`);\n\t}\n\treturn out.join(' ');\n}\n\n/**\n * Squash a pie3D flat view-model's slices, leader lines and data labels by\n * `scaleY` about `cy` (from {@link computePieTiltScale}), so the whole disc\n * (and everything anchored to its rim) tilts together.\n */\nexport function applyPieTiltForeshortening(\n\tvm: ChartViewModel,\n\tcy: number,\n\tscaleY: number,\n): ChartViewModel {\n\tconst primitives = vm.primitives.map((p) => {\n\t\tif (p.kind === 'path') {\n\t\t\treturn { ...p, d: squashSlicePathVertical(p.d, cy, scaleY) };\n\t\t}\n\t\tif (p.kind === 'line') {\n\t\t\tconst line = p as SvgLine;\n\t\t\treturn { ...line, y1: cy + (line.y1 - cy) * scaleY, y2: cy + (line.y2 - cy) * scaleY };\n\t\t}\n\t\tif (p.kind === 'polygon' || p.kind === 'polyline') {\n\t\t\t// A data-label box or leader line (`chart-data-label-callout`): moved\n\t\t\t// with its label rather than squashed, so the box still fits the text.\n\t\t\tconst pts = p.points.split(' ').map((pair) => pair.split(',').map(Number));\n\t\t\tconst dy = (pts.reduce((sum, [, y]) => sum + y, 0) / pts.length - cy) * (scaleY - 1);\n\t\t\treturn {\n\t\t\t\t...p,\n\t\t\t\tpoints: pts.map(([x, y]) => `${x},${Math.round((y + dy) * 100) / 100}`).join(' '),\n\t\t\t};\n\t\t}\n\t\treturn p;\n\t});\n\tconst dataLabels = vm.dataLabels.map((label) => ({\n\t\t...label,\n\t\ty: cy + (label.y - cy) * scaleY,\n\t}));\n\treturn { ...vm, primitives, dataLabels };\n}\n","/**\n * chart-3d-depth.ts: pseudo-3D depth treatment for the flat chart engine.\n *\n * The shared chart engine projects `bar3D` / `pie3D` / `line3D` / `area3D` with\n * their 2D geometry (folded onto `bar` / `pie` / `line` / `area`). This module\n * layers a lightweight oblique-projection depth pass on top of that flat output,\n * driven by the chart's `c:view3D` parameters (`rotX`, `rotY`, `depthPercent`),\n * so a 3D chart reads as 3D instead of collapsing to a flat plot.\n *\n * The pass is deliberately additive: it inserts shaded \"extrusion\" primitives\n * BEHIND the existing flat marks (top + side faces for bars, a downward thickness\n * band for pie slices, an offset ribbon for line/area). It never mutates the\n * front-face geometry, so interactivity (`part` refs, value-drag) is unchanged.\n *\n * @module chart-3d-depth\n */\nimport type { PptxChartView3D } from 'pptx-viewer-core';\n\nimport type { Chart3DSurfaces } from './chart-3d-surfaces';\nimport { build3DSurfacePanels } from './chart-3d-surfaces';\nimport type { BarFacePictureContext } from './chart-bar3d-face-picture';\nimport { resolveExtrusionFaceFill } from './chart-bar3d-face-picture';\nimport { computeSeriesDepth, sortSeriesBackToFront } from './chart-bar3d-series-depth';\nimport { shade } from './chart-palette';\nimport { applyPieTiltForeshortening, computePieTiltScale } from './chart-pie3d-tilt';\nimport type {\n\tChartSvgDef,\n\tChartViewModel,\n\tSvgPath,\n\tSvgPolygon,\n\tSvgPolyline,\n\tSvgPrimitive,\n\tSvgRect,\n} from './chart-view-model';\n\nexport type { BarFacePictureContext } from './chart-bar3d-face-picture';\n\n/** Oblique depth offset vector (px) derived from the chart's view3D. */\nexport interface DepthVector {\n\tdx: number;\n\tdy: number;\n\tmagnitude: number;\n}\n\nconst DEFAULT_ROT_X = 15;\nconst DEFAULT_ROT_Y = 20;\nconst MIN_DEPTH_PX = 5;\nconst MAX_DEPTH_PX = 22;\n\n/**\n * Resolve the oblique depth vector from `c:view3D`. `rotY` drives the horizontal\n * skew, `rotX` the vertical skew, `depthPercent` the magnitude. Absent values\n * fall back to PowerPoint-like defaults so an untagged 3D chart still gets depth.\n */\nexport function computeDepthVector(view3D: PptxChartView3D | undefined): DepthVector {\n\tconst rotX = view3D?.rotX ?? DEFAULT_ROT_X;\n\tconst rotY = view3D?.rotY ?? DEFAULT_ROT_Y;\n\tconst depthScale = Math.min(Math.max((view3D?.depthPercent ?? 100) / 100, 0.4), 2);\n\tconst magnitude = Math.min(Math.max(13 * depthScale, MIN_DEPTH_PX), MAX_DEPTH_PX);\n\tconst rx = (rotX * Math.PI) / 180;\n\tconst ry = (rotY * Math.PI) / 180;\n\treturn {\n\t\tdx: Math.sin(ry) * magnitude,\n\t\tdy: -Math.sin(rx) * magnitude,\n\t\tmagnitude,\n\t};\n}\n\n/**\n * Top (\"end\") + right-side extrusion faces for one bar rectangle.\n *\n * `picture` (bar3D only) resolves each face's OWN picture-fill targeting\n * independently of the front rect's (`chart-datapoint-picture-fills.ts`),\n * via {@link resolveExtrusionFaceFill}: `c:applyToSides`/`c:applyToEnd` paint\n * the corresponding face with the point's (or series') picture; an\n * untargeted face keeps the tinted/shaded solid fill it always had.\n */\nfunction barExtrusion(\n\trect: SvgRect,\n\tdepth: DepthVector,\n\tpicture?: BarFacePictureContext,\n): { polygons: SvgPolygon[]; defs: ChartSvgDef[] } {\n\tconst { x, y, w, h, fill } = rect;\n\tconst { dx, dy } = depth;\n\tconst defs: ChartSvgDef[] = [];\n\tconst topPoints = `${x},${y} ${x + w},${y} ${x + w + dx},${y + dy} ${x + dx},${y + dy}`;\n\tconst topFace: SvgPolygon = {\n\t\tkind: 'polygon',\n\t\tpoints: topPoints,\n\t\tfill: resolveExtrusionFaceFill(topPoints, 'end', fill, rect, picture, defs),\n\t\tstroke: 'none',\n\t\tstrokeWidth: 0,\n\t};\n\tconst sidePoints = `${x + w},${y} ${x + w},${y + h} ${x + w + dx},${y + h + dy} ${x + w + dx},${y + dy}`;\n\tconst sideFace: SvgPolygon = {\n\t\tkind: 'polygon',\n\t\tpoints: sidePoints,\n\t\tfill: resolveExtrusionFaceFill(sidePoints, 'side', fill, rect, picture, defs),\n\t\tstroke: 'none',\n\t\tstrokeWidth: 0,\n\t};\n\treturn { polygons: [topFace, sideFace], defs };\n}\n\n/** Translate a generated pie-slice path (`M`/`L`/`A`/`Z` grammar) by (dx, dy). */\nexport function translateSlicePath(d: string, dx: number, dy: number): string {\n\tconst tokens = d.match(/[MLAZ][^MLAZ]*/gu);\n\tif (!tokens) {\n\t\treturn d;\n\t}\n\treturn tokens\n\t\t.map((token) => {\n\t\t\tconst cmd = token[0];\n\t\t\tconst nums = token\n\t\t\t\t.slice(1)\n\t\t\t\t.trim()\n\t\t\t\t.split(/[ ,]+/u)\n\t\t\t\t.filter((s) => s.length > 0)\n\t\t\t\t.map(Number);\n\t\t\tif (cmd === 'M' || cmd === 'L') {\n\t\t\t\tconst out: number[] = [];\n\t\t\t\tfor (let i = 0; i < nums.length; i += 2) {\n\t\t\t\t\tout.push(nums[i] + dx, nums[i + 1] + dy);\n\t\t\t\t}\n\t\t\t\treturn `${cmd}${pairs(out)}`;\n\t\t\t}\n\t\t\tif (cmd === 'A') {\n\t\t\t\t// rx ry xrot large sweep x y -> translate only the endpoint (last pair).\n\t\t\t\tconst head = nums.slice(0, 5);\n\t\t\t\tconst ex = nums[5] + dx;\n\t\t\t\tconst ey = nums[6] + dy;\n\t\t\t\treturn `A${head.join(',')},${ex},${ey}`;\n\t\t\t}\n\t\t\treturn 'Z';\n\t\t})\n\t\t.join('');\n}\n\nfunction pairs(nums: number[]): string {\n\tconst out: string[] = [];\n\tfor (let i = 0; i < nums.length; i += 2) {\n\t\tout.push(`${nums[i]},${nums[i + 1]}`);\n\t}\n\treturn out.join(' ');\n}\n\n/** Shaded downward thickness copies of each pie slice (drawn behind the flat pie). */\nfunction pieExtrusion(paths: SvgPath[], depth: DepthVector): SvgPath[] {\n\tconst offsetY = Math.max(depth.magnitude, 6);\n\treturn paths.map((p) => ({\n\t\tkind: 'path',\n\t\td: translateSlicePath(p.d, 0, offsetY),\n\t\tfill: shade(p.fill, 0.32),\n\t\tstroke: shade(p.fill, 0.4),\n\t\tstrokeWidth: 0.5,\n\t}));\n}\n\n/** Shaded offset copies of line/area marks (drawn behind for a depth ribbon). */\nfunction ribbonExtrusion(prims: SvgPrimitive[], depth: DepthVector): SvgPrimitive[] {\n\tconst out: SvgPrimitive[] = [];\n\tfor (const prim of prims) {\n\t\tif (prim.kind === 'polyline') {\n\t\t\tconst pl = prim as SvgPolyline;\n\t\t\tout.push({\n\t\t\t\t...pl,\n\t\t\t\tpoints: shiftPoints(pl.points, depth.dx, depth.dy),\n\t\t\t\tstroke: shade(pl.stroke, 0.3),\n\t\t\t\tfill: 'none',\n\t\t\t\tpart: undefined,\n\t\t\t});\n\t\t} else if (prim.kind === 'polygon') {\n\t\t\tconst pg = prim as SvgPolygon;\n\t\t\tout.push({\n\t\t\t\t...pg,\n\t\t\t\tpoints: shiftPoints(pg.points, depth.dx, depth.dy),\n\t\t\t\tfill: shade(pg.fill === 'none' ? '#888888' : pg.fill, 0.3),\n\t\t\t\tpart: undefined,\n\t\t\t});\n\t\t}\n\t}\n\treturn out;\n}\n\nfunction shiftPoints(points: string, dx: number, dy: number): string {\n\treturn points\n\t\t.trim()\n\t\t.split(/\\s+/u)\n\t\t.map((pair) => {\n\t\t\tconst [px, py] = pair.split(',').map(Number);\n\t\t\treturn `${px + dx},${py + dy}`;\n\t\t})\n\t\t.join(' ');\n}\n\n/**\n * Apply a pseudo-3D depth pass to a flat view-model for a 3D chart type. Returns\n * a new view-model whose `primitives` are prefixed with shaded extrusion faces;\n * non-3D types (or unsupported kinds) return the input unchanged.\n */\nexport function applyChart3DDepth(\n\tvm: ChartViewModel,\n\tchartType: string,\n\tview3D: PptxChartView3D | undefined,\n\tsurfaces?: Chart3DSurfaces,\n\tgrouping?: 'clustered' | 'stacked' | 'percentStacked',\n\tpieCenter?: { cx: number; cy: number },\n\tpicture?: BarFacePictureContext,\n): ChartViewModel {\n\tconst depth = computeDepthVector(view3D);\n\tlet extrusion: SvgPrimitive[] = [];\n\tconst extrusionDefs: ChartSvgDef[] = [];\n\tlet isCartesian = false;\n\tlet workingVm = vm;\n\n\tif (chartType === 'bar3D') {\n\t\tconst bars = vm.primitives.filter(\n\t\t\t(p): p is SvgRect => p.kind === 'rect' && p.part?.role === 'dataPoint',\n\t\t);\n\t\tconst extrudeBar = (rect: SvgRect, barDepth: DepthVector): SvgPolygon[] => {\n\t\t\tconst { polygons, defs } = barExtrusion(rect, barDepth, picture);\n\t\t\textrusionDefs.push(...defs);\n\t\t\treturn polygons;\n\t\t};\n\t\t// A stacked (or percent-stacked) 3D column keeps every series' segment\n\t\t// coplanar (they visually belong to one bar), so it uses the chart's one\n\t\t// shared depth vector, same as before. A clustered 3D column lays series\n\t\t// out along PowerPoint's depth (\"series\") axis, so each series recedes by\n\t\t// its own offset - the single biggest gap between this oblique illusion\n\t\t// and an actual 3D projection: previously every series shared the exact\n\t\t// same depth plane. Series are then painted back-to-front so a nearer\n\t\t// series' extrusion correctly occludes one staggered behind it.\n\t\tif (grouping === 'stacked' || grouping === 'percentStacked') {\n\t\t\textrusion = bars.flatMap((r) => extrudeBar(r, depth));\n\t\t} else {\n\t\t\tconst seriesIndexes = [...new Set(bars.map((r) => r.part?.seriesIndex ?? 0))];\n\t\t\tconst seriesCount = seriesIndexes.length;\n\t\t\textrusion = sortSeriesBackToFront(seriesIndexes, seriesCount).flatMap((seriesIndex) => {\n\t\t\t\tconst seriesDepth = computeSeriesDepth(depth, seriesIndex, seriesCount);\n\t\t\t\treturn bars\n\t\t\t\t\t.filter((r) => (r.part?.seriesIndex ?? 0) === seriesIndex)\n\t\t\t\t\t.flatMap((r) => extrudeBar(r, seriesDepth));\n\t\t\t});\n\t\t}\n\t\tisCartesian = true;\n\t} else if (chartType === 'pie3D') {\n\t\tconst tiltScale = computePieTiltScale(view3D);\n\t\tif (pieCenter && tiltScale < 1) {\n\t\t\tworkingVm = applyPieTiltForeshortening(vm, pieCenter.cy, tiltScale);\n\t\t}\n\t\tconst slices = workingVm.primitives.filter((p): p is SvgPath => p.kind === 'path');\n\t\textrusion = pieExtrusion(slices, depth);\n\t} else if (chartType === 'line3D' || chartType === 'area3D') {\n\t\textrusion = ribbonExtrusion(vm.primitives, depth);\n\t\tisCartesian = true;\n\t} else {\n\t\treturn vm;\n\t}\n\n\t// c:floor / c:sideWall / c:backWall only apply to a cartesian 3D plot\n\t// (bar3D/line3D/area3D); pie3D has no plot rectangle to wall in, matching\n\t// PowerPoint's own behaviour.\n\tconst panels =\n\t\tisCartesian && surfaces ? build3DSurfacePanels(workingVm.primitives, surfaces, depth) : [];\n\n\tif (extrusion.length === 0 && panels.length === 0) {\n\t\treturn workingVm;\n\t}\n\treturn {\n\t\t...workingVm,\n\t\tprimitives: [...panels, ...extrusion, ...workingVm.primitives],\n\t\t...(extrusionDefs.length > 0 ? { defs: [...(workingVm.defs ?? []), ...extrusionDefs] } : {}),\n\t};\n}\n","/**\n * The text a chart's title shows, including PowerPoint's AUTO title.\n *\n * A `c:title` with no `c:tx` (the default for a chart inserted in\n * PowerPoint) is not an empty title: PowerPoint shows the only series' name\n * for a single-series chart (a pie titled \"Sales\"), and the literal\n * \"Chart Title\" otherwise. Every chart family's view model resolves its title\n * through here, so the 2D chart and the 3D chart's chrome overlay agree.\n *\n * @module chart-auto-title\n */\nimport type { PptxChartData } from 'pptx-viewer-core';\n\n/** PowerPoint's own placeholder for an auto title on a multi-series chart. */\nexport const CHART_AUTO_TITLE = 'Chart Title';\n\n/**\n * Office 2016+ extended (`cx:`) chart types, which have no classic-chart\n * \"use the lone series' name as the title\" convention: COM-verified against\n * every chartex-family slide in charts-com.pptx (waterfall on slide 26\n * through box-whisker on slide 32), an empty `cx:title` always renders the\n * literal \"Chart Title\", even for a single-series chart like waterfall or\n * funnel. A `cx:series` with no authored `cx:tx` also falls back to a\n * synthesized name (\"Series 1\"), which would otherwise leak into the title.\n */\nconst CHARTEX_ONLY_TYPES = new Set<PptxChartData['chartType']>([\n\t'waterfall',\n\t'funnel',\n\t'treemap',\n\t'sunburst',\n\t'boxWhisker',\n\t'histogram',\n\t'regionMap',\n]);\n\n/**\n * A classic chart with NO `c:title` element still gets an auto title when it\n * plots exactly one series and `c:autoTitleDeleted` is not set: PowerPoint\n * titles it with that series' name (COM-verified, charts-com.pptx slides 5,\n * 6 and 24: an ofPie and a pie with no `c:title` show \"Sales\"). Returns the\n * chart with `style.hasTitle` switched on in that case, so the layout\n * reserves the title band; otherwise the chart itself. An explicit\n * `style.hasTitle === false` (the title toggled off in the editor) and the\n * ChartEx families never auto-title this way.\n */\nexport function withAutoTitle(chartData: PptxChartData): PptxChartData {\n\tif (\n\t\tchartData.style?.hasTitle !== undefined ||\n\t\tchartData.chartChrome?.autoTitleDeleted === true ||\n\t\tCHARTEX_ONLY_TYPES.has(chartData.chartType) ||\n\t\tchartData.series.length !== 1 ||\n\t\t!chartData.series[0].name\n\t) {\n\t\treturn chartData;\n\t}\n\treturn { ...chartData, style: { ...chartData.style, hasTitle: true } };\n}\n\n/** The title text to draw, or `undefined` when the chart shows no title. */\nexport function resolveChartTitleText(chartData: PptxChartData): string | undefined {\n\tif (!chartData.style?.hasTitle) {\n\t\treturn undefined;\n\t}\n\tif (chartData.title) {\n\t\treturn chartData.title;\n\t}\n\tconst isChartExOnlyType = CHARTEX_ONLY_TYPES.has(chartData.chartType);\n\tif (!isChartExOnlyType && chartData.series.length === 1) {\n\t\treturn chartData.series[0].name || undefined;\n\t}\n\treturn chartData.series.length > 0 ? CHART_AUTO_TITLE : undefined;\n}\n","/**\n * chart-manual-layout.ts: pure conversion of `c:layout/c:manualLayout`\n * (CT_ManualLayout) into pixel rectangles for the chart engine.\n *\n * Core parses a chart's manual title / plot-area / legend placement into\n * `chartData.layouts` (see `PptxChartLayouts`), but until now the view-model\n * never read it, so a chart whose author dragged the legend into a corner or\n * shrank the plot area rendered with the automatic layout in every binding.\n *\n * ECMA-376 21.2.2.95 (manualLayout) semantics, all values fractions of the\n * chart (element) width / height:\n *\n * - `xMode` / `yMode` `edge`: `x` / `y` is the absolute position of the\n * element's left / top edge. `factor` (the default when absent): `x` / `y`\n * is an offset from the element's automatic position.\n * - `wMode` / `hMode` `factor` (the default): `w` / `h` is the element's\n * width / height. `edge`: `w` / `h` is the position of its right / bottom\n * edge, so the size is `edge - left`.\n *\n * Every field falls back to the automatic value on its own: PowerPoint\n * commonly writes only `x`/`y` for a moved title or legend, and only that\n * pair should override.\n */\n\nimport type { PptxChartData, PptxChartLayouts, PptxChartManualLayout } from 'pptx-viewer-core';\n\n/** An axis-aligned rectangle in the chart's pixel space. */\nexport interface ChartLayoutRect {\n\tx: number;\n\ty: number;\n\twidth: number;\n\theight: number;\n}\n\n/** The chart frame the fractions are measured against. */\nexport interface ChartFrameSize {\n\twidth: number;\n\theight: number;\n}\n\n/** True when the layout carries at least one of the four placement fields. */\nexport function hasManualLayoutFields(\n\tlayout: PptxChartManualLayout | null | undefined,\n): layout is PptxChartManualLayout {\n\treturn (\n\t\tlayout !== null &&\n\t\tlayout !== undefined &&\n\t\t(layout.x !== undefined ||\n\t\t\tlayout.y !== undefined ||\n\t\t\tlayout.width !== undefined ||\n\t\t\tlayout.height !== undefined)\n\t);\n}\n\n/** The manual layout of one chart region, when the chart declares one. */\nexport function manualLayoutOf(\n\tchartData: Pick<PptxChartData, 'layouts'> | undefined,\n\tregion: keyof PptxChartLayouts,\n): PptxChartManualLayout | undefined {\n\tconst layout = chartData?.layouts?.[region];\n\treturn hasManualLayoutFields(layout) ? layout : undefined;\n}\n\n/**\n * Resolve a manual layout to a pixel rectangle. Each field the layout omits\n * keeps its `auto` value; `factor`-mode positions offset from `auto`.\n * Returns `undefined` when the layout carries no placement field at all.\n */\nexport function resolveManualLayoutRect(\n\tlayout: PptxChartManualLayout | null | undefined,\n\tframe: ChartFrameSize,\n\tauto: ChartLayoutRect,\n): ChartLayoutRect | undefined {\n\tif (!hasManualLayoutFields(layout)) {\n\t\treturn undefined;\n\t}\n\tconst x =\n\t\tlayout.x === undefined\n\t\t\t? auto.x\n\t\t\t: layout.xMode === 'edge'\n\t\t\t\t? layout.x * frame.width\n\t\t\t\t: auto.x + layout.x * frame.width;\n\tconst y =\n\t\tlayout.y === undefined\n\t\t\t? auto.y\n\t\t\t: layout.yMode === 'edge'\n\t\t\t\t? layout.y * frame.height\n\t\t\t\t: auto.y + layout.y * frame.height;\n\tconst width =\n\t\tlayout.width === undefined\n\t\t\t? auto.width\n\t\t\t: layout.widthMode === 'edge'\n\t\t\t\t? layout.width * frame.width - x\n\t\t\t\t: layout.width * frame.width;\n\tconst height =\n\t\tlayout.height === undefined\n\t\t\t? auto.height\n\t\t\t: layout.heightMode === 'edge'\n\t\t\t\t? layout.height * frame.height - y\n\t\t\t\t: layout.height * frame.height;\n\treturn { x, y, width: Math.max(width, 1), height: Math.max(height, 1) };\n}\n\n/** Font size the bindings draw the chart title with (`fontSize={12}`). */\nexport const CHART_TITLE_FONT_PX = 12;\n/** Average glyph advance of that title font, used to estimate its box width. */\nconst TITLE_GLYPH_ADVANCE = 0.6;\n\n/** Legend metrics shared with `chart-legend-layout.ts` (`LEGEND_ITEM_*`). */\nconst LEGEND_ITEM_WIDTH = 80,\n\tLEGEND_ITEM_HEIGHT = 14;\n\n/** A text anchor point in the chart's pixel space. */\nexport interface ChartAnchorPoint {\n\tx: number;\n\ty: number;\n}\n\n/**\n * Where a manually placed title's text anchor (middle, baseline) goes.\n *\n * The title's automatic box is a full-width band whose text is centred, so\n * a `factor` offset shifts that band. When the layout gives no width, the\n * box is as wide as the text (PowerPoint sizes a title to its content), so\n * an `edge` x lands the text's LEFT edge there rather than its centre.\n */\nexport function manualTitleAnchor(\n\tlayout: PptxChartManualLayout | null | undefined,\n\tframe: ChartFrameSize,\n\ttitle: string,\n\tauto: ChartAnchorPoint,\n): ChartAnchorPoint | undefined {\n\tconst textWidth = Math.max(title.length * CHART_TITLE_FONT_PX * TITLE_GLYPH_ADVANCE, 1);\n\tconst autoRect: ChartLayoutRect = {\n\t\tx: auto.x - textWidth / 2,\n\t\ty: auto.y - CHART_TITLE_FONT_PX,\n\t\twidth: textWidth,\n\t\theight: CHART_TITLE_FONT_PX * 1.4,\n\t};\n\tconst rect = resolveManualLayoutRect(layout, frame, autoRect);\n\tif (!rect) {\n\t\treturn undefined;\n\t}\n\treturn { x: rect.x + rect.width / 2, y: rect.y + CHART_TITLE_FONT_PX };\n}\n\n/**\n * Where a manually placed legend's anchor goes, in the convention\n * `computeChartLegendLayout` reads: a vertical legend (`legendAnchor:\n * 'start'`) starts its first row at the anchor; a horizontal one centres its\n * row on the anchor's x with the anchor's y as the baseline.\n */\nexport function manualLegendAnchor(\n\tlayout: PptxChartManualLayout | null | undefined,\n\tframe: ChartFrameSize,\n\tentryCount: number,\n\tvertical: boolean,\n\tauto: ChartAnchorPoint,\n): ChartAnchorPoint | undefined {\n\tconst count = Math.max(entryCount, 1);\n\tconst autoRect: ChartLayoutRect = vertical\n\t\t? { x: auto.x, y: auto.y, width: LEGEND_ITEM_WIDTH, height: count * LEGEND_ITEM_HEIGHT }\n\t\t: {\n\t\t\t\tx: auto.x - (count * LEGEND_ITEM_WIDTH) / 2,\n\t\t\t\ty: auto.y - LEGEND_ITEM_HEIGHT / 2,\n\t\t\t\twidth: count * LEGEND_ITEM_WIDTH,\n\t\t\t\theight: LEGEND_ITEM_HEIGHT,\n\t\t\t};\n\tconst rect = resolveManualLayoutRect(layout, frame, autoRect);\n\tif (!rect) {\n\t\treturn undefined;\n\t}\n\treturn vertical\n\t\t? { x: rect.x, y: rect.y }\n\t\t: { x: rect.x + rect.width / 2, y: rect.y + rect.height / 2 };\n}\n\n/**\n * Shift a data label's automatic anchor point to its author-dragged position\n * from `c:dLbl/c:layout/c:manualLayout` when the label declares one.\n *\n * A per-label manual layout has no natural \"auto rect\": PowerPoint records a\n * drag as an offset from wherever the label would otherwise sit, so this\n * treats the automatic point as a nominal 1x1 rect and reuses\n * `resolveManualLayoutRect`'s edge/factor arithmetic unchanged. A label with no\n * `layout` (the overwhelming majority) returns `point` unmodified.\n */\nexport function applyLabelManualLayout(\n\tlayout: PptxChartManualLayout | null | undefined,\n\tframe: ChartFrameSize,\n\tpoint: ChartAnchorPoint,\n): ChartAnchorPoint {\n\tif (!hasManualLayoutFields(layout)) {\n\t\treturn point;\n\t}\n\tconst rect = resolveManualLayoutRect(layout, frame, {\n\t\tx: point.x,\n\t\ty: point.y,\n\t\twidth: 1,\n\t\theight: 1,\n\t});\n\treturn rect ? { x: rect.x, y: rect.y } : point;\n}\n\n/**\n * Offset from the chart element's pixel space to a view-model's SVG space.\n *\n * Cartesian view-models use the element box as their viewBox (no offset);\n * the pie family lays out on a `size x size` square that the bindings centre\n * with `xMidYMid meet`, so a manual layout measured on the element has to be\n * shifted by half the letterbox on each axis.\n */\nexport function chartFrameToViewOffset(\n\tframe: ChartFrameSize,\n\tview: { svgWidth: number; svgHeight: number },\n): ChartAnchorPoint {\n\treturn { x: (frame.width - view.svgWidth) / 2, y: (frame.height - view.svgHeight) / 2 };\n}\n","/**\n * chart-data-label-anchor.ts: `c:dLblPos` -> pixel anchor for bar / column /\n * line / area / scatter data labels, plus the per-point manual-drag offset\n * (`c:dLbl/c:layout`) applied on top of it.\n *\n * `c:dLblPos` is parsed and preserved end-to-end (`chart-data-label-parser.ts`,\n * `chart-data-labels-serializer.ts`) but every cartesian builder used a fixed\n * \"outside end\" offset regardless of its value: `ctr` (centred in a bar),\n * `inBase` / `inEnd` (inside the bar, near the base / value end) and the\n * line/scatter `t`/`b`/`l`/`r` positions were all silently ignored. Only pie\n * (`chart-pie-labels.ts`) ever consulted `position`.\n *\n * @module chart-data-label-anchor\n */\nimport type {\n\tPptxChartData,\n\tPptxChartDataLabel,\n\tPptxChartDataLabelPosition,\n\tPptxChartSeries,\n} from 'pptx-viewer-core';\n\nimport { applyLabelManualLayout } from './chart-manual-layout';\nimport type { ChartAnchorPoint, ChartFrameSize } from './chart-manual-layout';\n\n/** A bar/column rectangle in the chart's pixel space. */\nexport interface LabelAnchorRect {\n\tx: number;\n\ty: number;\n\twidth: number;\n\theight: number;\n}\n\n/** A resolved label anchor: where to draw it, and how to align text on it. */\nexport interface LabelAnchor {\n\tx: number;\n\ty: number;\n\ttextAnchor: 'start' | 'middle' | 'end';\n\tdominantBaseline?: 'central';\n}\n\n/** This point's `c:dLbl` override, when the series declares one. */\nexport function findPointLabel(\n\tseries: PptxChartSeries,\n\tpointIndex: number,\n): PptxChartDataLabel | undefined {\n\treturn series.dataLabels?.find((label) => label.idx === pointIndex);\n}\n\n/**\n * Cascade a data label's `c:dLblPos`: the per-point `c:dLbl` wins, then the\n * series-level `c:ser/c:dLbls`, then the chart-type-level `c:*Chart/c:dLbls`.\n * Mirrors the content-flag cascade in `chart-data-label-text.ts`'s\n * `resolveDataLabelContent`.\n */\nexport function resolveLabelPosition(\n\tchartData: PptxChartData,\n\tseries: PptxChartSeries,\n\tpointIndex: number,\n): PptxChartDataLabelPosition | undefined {\n\treturn (\n\t\tfindPointLabel(series, pointIndex)?.position ??\n\t\tseries.dataLabelOptions?.position ??\n\t\tchartData.style?.dataLabels?.position\n\t);\n}\n\n/**\n * Anchor a bar/column data label from its `c:dLblPos`.\n *\n * `rect` is the bar's own rectangle; `value` decides which end is the \"value\n * end\" for `inEnd`/`outEnd` on a signed axis (a negative bar's value end is\n * its bottom, not its top). Positions outside `CT_DLblPos`'s bar/column set\n * (`t`/`b`/`l`/`r`) fall through to the historical `outEnd`-style default, same\n * as an absent `position`, so an untouched chart renders byte-identically.\n */\nexport function resolveBarLabelAnchor(\n\tposition: PptxChartDataLabelPosition | undefined,\n\trect: LabelAnchorRect,\n\tvalue: number,\n\torientation: 'vertical' | 'horizontal',\n): LabelAnchor {\n\tconst positive = value >= 0;\n\tif (orientation === 'vertical') {\n\t\tconst midX = rect.x + rect.width / 2;\n\t\tswitch (position) {\n\t\t\tcase 'ctr':\n\t\t\t\treturn {\n\t\t\t\t\tx: midX,\n\t\t\t\t\ty: rect.y + rect.height / 2,\n\t\t\t\t\ttextAnchor: 'middle',\n\t\t\t\t\tdominantBaseline: 'central',\n\t\t\t\t};\n\t\t\tcase 'inBase':\n\t\t\t\treturn {\n\t\t\t\t\tx: midX,\n\t\t\t\t\ty: positive ? rect.y + rect.height - 4 : rect.y + 10,\n\t\t\t\t\ttextAnchor: 'middle',\n\t\t\t\t};\n\t\t\tcase 'inEnd':\n\t\t\t\treturn {\n\t\t\t\t\tx: midX,\n\t\t\t\t\ty: positive ? rect.y + 10 : rect.y + rect.height - 4,\n\t\t\t\t\ttextAnchor: 'middle',\n\t\t\t\t};\n\t\t\tdefault:\n\t\t\t\t// outEnd / bestFit / absent: beyond the value end (above a positive\n\t\t\t\t// bar's top, below a negative bar's bottom).\n\t\t\t\treturn {\n\t\t\t\t\tx: midX,\n\t\t\t\t\ty: positive ? rect.y - 4 : rect.y + rect.height + 10,\n\t\t\t\t\ttextAnchor: 'middle',\n\t\t\t\t};\n\t\t}\n\t}\n\t// Horizontal (transposed) bars: the value end is the right edge for a\n\t// positive value, the left edge for a negative one.\n\tconst midY = rect.y + rect.height / 2;\n\tswitch (position) {\n\t\tcase 'ctr':\n\t\t\treturn {\n\t\t\t\tx: rect.x + rect.width / 2,\n\t\t\t\ty: midY,\n\t\t\t\ttextAnchor: 'middle',\n\t\t\t\tdominantBaseline: 'central',\n\t\t\t};\n\t\tcase 'inBase':\n\t\t\treturn {\n\t\t\t\tx: positive ? rect.x + 4 : rect.x + rect.width - 4,\n\t\t\t\ty: midY,\n\t\t\t\ttextAnchor: positive ? 'start' : 'end',\n\t\t\t\tdominantBaseline: 'central',\n\t\t\t};\n\t\tcase 'inEnd':\n\t\t\treturn {\n\t\t\t\tx: positive ? rect.x + rect.width - 4 : rect.x + 4,\n\t\t\t\ty: midY,\n\t\t\t\ttextAnchor: positive ? 'end' : 'start',\n\t\t\t\tdominantBaseline: 'central',\n\t\t\t};\n\t\tdefault:\n\t\t\treturn {\n\t\t\t\tx: positive ? rect.x + rect.width + 4 : rect.x - 4,\n\t\t\t\ty: midY,\n\t\t\t\ttextAnchor: positive ? 'start' : 'end',\n\t\t\t\tdominantBaseline: 'central',\n\t\t\t};\n\t}\n}\n\n/**\n * Anchor a line/area/scatter/bubble marker's data label from its `c:dLblPos`\n * (`t`/`b`/`l`/`r`/`ctr`; the bar-only `inBase`/`inEnd`/`outEnd` values fall\n * through to the historical \"above the marker\" default, matching PowerPoint's\n * own Format Data Labels list for these chart kinds).\n */\nexport function resolveMarkerLabelAnchor(\n\tposition: PptxChartDataLabelPosition | undefined,\n\tpoint: ChartAnchorPoint,\n\toffset = 7,\n): LabelAnchor {\n\tswitch (position) {\n\t\tcase 'ctr':\n\t\t\treturn { x: point.x, y: point.y, textAnchor: 'middle', dominantBaseline: 'central' };\n\t\tcase 'b':\n\t\t\treturn { x: point.x, y: point.y + offset + 4, textAnchor: 'middle' };\n\t\tcase 'l':\n\t\t\treturn {\n\t\t\t\tx: point.x - offset - 3,\n\t\t\t\ty: point.y,\n\t\t\t\ttextAnchor: 'end',\n\t\t\t\tdominantBaseline: 'central',\n\t\t\t};\n\t\tcase 'r':\n\t\t\treturn {\n\t\t\t\tx: point.x + offset + 3,\n\t\t\t\ty: point.y,\n\t\t\t\ttextAnchor: 'start',\n\t\t\t\tdominantBaseline: 'central',\n\t\t\t};\n\t\tdefault:\n\t\t\t// 't' / bestFit / inBase / inEnd / outEnd / absent: PowerPoint's own\n\t\t\t// default for a line/scatter/bubble marker is above it.\n\t\t\treturn { x: point.x, y: point.y - offset, textAnchor: 'middle' };\n\t}\n}\n\n/**\n * Full per-point placement pipeline for a bar/column label: resolve\n * `c:dLblPos`, anchor it on the bar rect, then shift by any per-point\n * `c:dLbl/c:layout` manual drag. `frame` is the chart element's own pixel box\n * (`layout.svgWidth` / `svgHeight` in every cartesian builder), which is what\n * a manual layout's fractional coordinates are measured against.\n */\nexport function resolveBarLabelPlacement(\n\tchartData: PptxChartData,\n\tseries: PptxChartSeries,\n\tpointIndex: number,\n\trect: LabelAnchorRect,\n\tvalue: number,\n\torientation: 'vertical' | 'horizontal',\n\tframe: ChartFrameSize,\n): LabelAnchor {\n\tconst point = findPointLabel(series, pointIndex),\n\t\tposition =\n\t\t\tpoint?.position ?? series.dataLabelOptions?.position ?? chartData.style?.dataLabels?.position,\n\t\tanchor = resolveBarLabelAnchor(position, rect, value, orientation),\n\t\tshifted = applyLabelManualLayout(point?.layout, frame, anchor);\n\treturn { ...anchor, x: shifted.x, y: shifted.y };\n}\n\n/**\n * Full per-point placement pipeline for a line/area/scatter/bubble marker\n * label: resolve `c:dLblPos`, anchor it against the marker point, then shift\n * by any per-point `c:dLbl/c:layout` manual drag.\n *\n * @param defaultPosition - Position to use when nothing at any cascade level\n * authored a `c:dLblPos`. Line/scatter/bubble markers keep the historical\n * \"above the point\" default (`resolveMarkerLabelAnchor`'s own fallback\n * branch); a stock chart's close label defaults to `'r'` (right of the tick,\n * PowerPoint's own placement) instead, so this only needs to be passed by\n * callers wanting a different default.\n */\nexport function resolveMarkerLabelPlacement(\n\tchartData: PptxChartData,\n\tseries: PptxChartSeries,\n\tpointIndex: number,\n\tpoint: ChartAnchorPoint,\n\tframe: ChartFrameSize,\n\toffset = 7,\n\tdefaultPosition?: PptxChartDataLabelPosition,\n): LabelAnchor {\n\tconst override = findPointLabel(series, pointIndex),\n\t\tposition =\n\t\t\toverride?.position ??\n\t\t\tseries.dataLabelOptions?.position ??\n\t\t\tchartData.style?.dataLabels?.position ??\n\t\t\tdefaultPosition,\n\t\tanchor = resolveMarkerLabelAnchor(position, point, offset),\n\t\tshifted = applyLabelManualLayout(override?.layout, frame, anchor);\n\treturn { ...anchor, x: shifted.x, y: shifted.y };\n}\n","/**\n * The box, callout pointer and leader line PowerPoint draws around a chart\n * data label (`c:dLbls/c:spPr`, `c15:spPr/a:prstGeom`, `c15:showLeaderLines`;\n * parsed by core's `chart-data-label-box.ts`).\n *\n * COM-verified against charts-com.pptx slide 17: series 1's labels are pale\n * yellow `wedgeRectCallout` boxes whose pointer reaches the top of their bar,\n * including the one label the author dragged away. They used to render as\n * bare text. The decorations are ordinary polygon / line primitives placed\n * BEFORE the label text in paint order, so every binding draws them with no\n * projector change.\n *\n * @module chart-data-label-callout\n */\nimport type { PptxChartData, PptxChartSeries } from 'pptx-viewer-core';\n\nimport { findPointLabel } from './chart-data-label-anchor';\nimport { dataLabelBox } from './chart-label-measure';\nimport type { SvgPolygon, SvgPolyline, SvgPrimitive, SvgText } from './chart-view-model-types';\n\nconst r2 = (v: number) => Math.round(v * 100) / 100;\n\n/** A box outline, with a pointer to `target` spliced into the edge facing it. */\nfunction calloutPoints(\n\tbox: { x: number; y: number; w: number; h: number },\n\ttarget: { x: number; y: number } | undefined,\n): string {\n\tconst { x, y, w, h } = box;\n\tconst corners = [\n\t\t[x, y],\n\t\t[x + w, y],\n\t\t[x + w, y + h],\n\t\t[x, y + h],\n\t];\n\tif (!target) {\n\t\treturn corners.map(([px, py]) => `${r2(px)},${r2(py)}`).join(' ');\n\t}\n\tconst below = target.y > y + h;\n\tconst above = target.y < y;\n\tconst base = Math.max(6, Math.min(w, h) * 0.5);\n\tconst cx = Math.min(Math.max(target.x, x + base), x + w - base);\n\tconst cy = Math.min(Math.max(target.y, y + base / 2), y + h - base / 2);\n\tconst pts: number[][] = [];\n\tif (below) {\n\t\tpts.push(\n\t\t\tcorners[0],\n\t\t\tcorners[1],\n\t\t\tcorners[2],\n\t\t\t[cx + base / 2, y + h],\n\t\t\t[target.x, target.y],\n\t\t\t[cx - base / 2, y + h],\n\t\t\tcorners[3],\n\t\t);\n\t} else if (above) {\n\t\tpts.push(\n\t\t\tcorners[0],\n\t\t\t[cx - base / 2, y],\n\t\t\t[target.x, target.y],\n\t\t\t[cx + base / 2, y],\n\t\t\tcorners[1],\n\t\t\tcorners[2],\n\t\t\tcorners[3],\n\t\t);\n\t} else if (target.x > x + w) {\n\t\tpts.push(\n\t\t\tcorners[0],\n\t\t\tcorners[1],\n\t\t\t[x + w, cy - base / 4],\n\t\t\t[target.x, target.y],\n\t\t\t[x + w, cy + base / 4],\n\t\t\tcorners[2],\n\t\t\tcorners[3],\n\t\t);\n\t} else {\n\t\tpts.push(\n\t\t\tcorners[0],\n\t\t\tcorners[1],\n\t\t\tcorners[2],\n\t\t\tcorners[3],\n\t\t\t[x, cy + base / 4],\n\t\t\t[target.x, target.y],\n\t\t\t[x, cy - base / 4],\n\t\t);\n\t}\n\treturn pts.map(([px, py]) => `${r2(px)},${r2(py)}`).join(' ');\n}\n\n/**\n * How far PowerPoint lifts an unmoved callout label off its point so the\n * pointer shows (COM: charts-com.pptx slide 17, about one and a half label\n * lines); 0 for a plain label or one the author dragged.\n */\nexport function calloutLabelLift(\n\tchartData: PptxChartData,\n\tseries: PptxChartSeries,\n\tfontSize: number,\n\tmoved: boolean,\n): number {\n\tconst opts = series.dataLabelOptions ?? chartData.style?.dataLabels;\n\tconst callout = opts?.calloutShape?.toLowerCase().includes('callout') === true;\n\treturn callout && !moved ? Math.round(fontSize * 1.6) : 0;\n}\n\n/**\n * Decorations for one data label: its box (a callout pointing at `target`\n * when the label box is a `wedge*Callout`), or a leader line from a moved\n * label back to its point. Empty when the label authors none of these.\n *\n * @param moved Whether the label was dragged (`c:dLbl/c:layout`); PowerPoint\n * draws a leader line only for a moved label, callout or not.\n */\nexport function buildDataLabelDecorations(\n\tchartData: PptxChartData,\n\tseries: PptxChartSeries,\n\tlabel: SvgText,\n\ttarget: { x: number; y: number },\n\tmoved: boolean,\n): SvgPrimitive[] {\n\tconst opts = series.dataLabelOptions ?? chartData.style?.dataLabels;\n\tconst shape = opts?.labelShape;\n\tconst callout = opts?.calloutShape?.toLowerCase().includes('callout') === true;\n\tconst leader = moved && (opts?.extLeaderLines ?? opts?.showLeaderLines) === true;\n\tif (!shape && !callout && !leader) {\n\t\treturn [];\n\t}\n\tconst box = dataLabelBox(label);\n\tconst out: SvgPrimitive[] = leader ? [leaderLine(box, target, opts)] : [];\n\tif (shape || callout) {\n\t\t// The pointer only shows when the point lies outside the box: a label\n\t\t// PowerPoint centres on its point (area, doughnut) draws a plain box.\n\t\tconst pointer = callout && !contains(box, target) ? target : undefined;\n\t\tout.push({\n\t\t\tkind: 'polygon',\n\t\t\tpoints: calloutPoints(box, pointer),\n\t\t\tfill: shape?.fillColor ?? 'none',\n\t\t\tstroke: shape?.strokeColor ?? 'none',\n\t\t\t// An `a:ln` with no `@w` is PowerPoint's hairline default, not \"no line\".\n\t\t\tstrokeWidth: shape?.strokeWidth ?? (shape?.strokeColor ? 1 : 0),\n\t\t} satisfies SvgPolygon);\n\t}\n\treturn out;\n}\n\n/**\n * {@link buildDataLabelDecorations} for the label of point `pointIndex`,\n * reading whether the author dragged it (`c:dLbl/c:layout`) itself. The\n * `target` is what PowerPoint points the callout and leader line at: the\n * marker (line, scatter, radar), the bubble or band centre (bubble, area), the\n * rim (pie) or the middle of the ring (doughnut).\n */\nexport function buildPointLabelDecorations(\n\tchartData: PptxChartData,\n\tseries: PptxChartSeries,\n\tpointIndex: number,\n\tlabel: SvgText,\n\ttarget: { x: number; y: number },\n): SvgPrimitive[] {\n\tconst moved = Boolean(findPointLabel(series, pointIndex)?.layout);\n\treturn buildDataLabelDecorations(chartData, series, label, target, moved);\n}\n\nfunction contains(\n\tbox: { x: number; y: number; w: number; h: number },\n\tp: { x: number; y: number },\n) {\n\treturn p.x >= box.x && p.x <= box.x + box.w && p.y >= box.y && p.y <= box.y + box.h;\n}\n\n/** PowerPoint's elbow stub: the leader leaves the box edge facing the point. */\nconst LEADER_STUB = 5;\n\nfunction leaderLine(\n\tbox: { x: number; y: number; w: number; h: number },\n\ttarget: { x: number; y: number },\n\topts: { leaderLineStyle?: { strokeColor?: string; strokeWidth?: number } } | undefined,\n): SvgPolyline {\n\t// COM: a leader leaves the middle of the box side that faces the point with\n\t// a short horizontal stub, then runs straight to the point.\n\tlet from: [number, number];\n\tlet elbow: [number, number];\n\tif (target.x < box.x || target.x > box.x + box.w) {\n\t\tconst x = target.x < box.x ? box.x : box.x + box.w;\n\t\tconst dir = target.x < box.x ? -1 : 1;\n\t\tfrom = [x, box.y + box.h / 2];\n\t\telbow = [x + dir * LEADER_STUB, box.y + box.h / 2];\n\t} else {\n\t\tconst y = target.y > box.y + box.h ? box.y + box.h : box.y;\n\t\tconst dir = target.y > box.y + box.h ? 1 : -1;\n\t\tfrom = [box.x + box.w / 2, y];\n\t\telbow = [box.x + box.w / 2, y + dir * LEADER_STUB];\n\t}\n\treturn {\n\t\tkind: 'polyline',\n\t\tpoints: [from, elbow, [target.x, target.y]].map(([x, y]) => `${r2(x)},${r2(y)}`).join(' '),\n\t\tfill: 'none',\n\t\tstroke: opts?.leaderLineStyle?.strokeColor ?? '#A6A6A6',\n\t\tstrokeWidth: opts?.leaderLineStyle?.strokeWidth ?? 1,\n\t};\n}\n\n/**\n * Push a point's label and, into `boxes`, its decorations (see\n * {@link buildPointLabelDecorations}). A builder appends `boxes` after its own\n * marks, so the box sits over the series and under the label text.\n */\nexport function pushPointLabel(\n\tdataLabels: SvgText[],\n\tboxes: SvgPrimitive[],\n\tchartData: PptxChartData,\n\tseries: PptxChartSeries,\n\tpointIndex: number,\n\ttarget: { x: number; y: number },\n\tlabel: SvgText,\n): void {\n\tdataLabels.push(label);\n\tboxes.push(...buildPointLabelDecorations(chartData, series, pointIndex, label, target));\n}\n","/**\n * chart-data-label-text.ts: what a chart data label actually SAYS.\n *\n * `c:dLbls` does not just switch labels on. It carries `c:showVal`,\n * `c:showCatName`, `c:showSerName`, `c:showPercent`, `c:showBubbleSize` and\n * `c:separator`, and PowerPoint combines whichever are set. Every builder in\n * this engine used to print `formatAxisValue(value, numberFormat)` regardless,\n * so a pie configured to show percentages - the most common labelled chart in a\n * business deck - displayed raw values, and a combined \"Category, 34%\" label was\n * impossible.\n *\n * The flags live in three places and override each other in this order:\n *\n * 1. the per-point `c:dLbl` for this index (highest),\n * 2. the SERIES-level `c:ser/c:dLbls`,\n * 3. the chart-type-level `c:*Chart/c:dLbls` (lowest).\n *\n * Order 2 is the one that matters in practice and the one that was missing:\n * PowerPoint writes the user's choices onto the series and leaves the\n * chart-type-level group all-zero, so reading only the chart level reports\n * \"show nothing\" for a chart that visibly shows percentages. Verified against a\n * COM-authored pie in `e2e/fixtures/chart-data-fidelity.pptx`.\n *\n * @module chart-data-label-text\n */\nimport type { PptxChartData, PptxChartLegendTextStyle, PptxChartSeries } from 'pptx-viewer-core';\n\nimport { chartFontPx } from './chart-font';\nimport { formatChartNumberWithColor } from './chart-number-format';\nimport type { SvgText } from './chart-view-model';\nimport { formatAxisValue } from './chart-view-model';\n\n/** The label content flags, after the three-level cascade has been applied. */\nexport interface ResolvedDataLabelContent {\n\tshowValue: boolean;\n\tshowCategory: boolean;\n\tshowSeriesName: boolean;\n\tshowPercent: boolean;\n\tshowBubbleSize: boolean;\n\t/** Text joining the enabled components. PowerPoint's default is `\", \"`, or a newline for category + percentage. */\n\tseparator: string;\n\t/** `c:dLbl/c:delete`: this one label is suppressed. */\n\tdeleted: boolean;\n\t/** Literal `c:dLbl/c:tx/c:rich` text, which replaces everything else. */\n\tcustomText?: string;\n}\n\n/** PowerPoint's default separator between combined label components. */\nconst DEFAULT_SEPARATOR = ', ';\n\n/**\n * PowerPoint's default separator when a label shows the category name AND the\n * percentage and the file carries no `c:separator` (a pie's \"Cat 1\" over\n * \"25%\"): a line break, not \", \". Every other combination keeps \", \".\n */\nconst CATEGORY_PERCENT_SEPARATOR = '\\n';\n\n/**\n * Resolve the label content flags for one point.\n *\n * When NOTHING anywhere sets a content flag the result is \"value only\", which is\n * what every builder did unconditionally before this module existed, so charts\n * with no `c:dLbls` content markup render byte-identically.\n */\nexport function resolveDataLabelContent(\n\tchartData: PptxChartData,\n\tseries: PptxChartSeries,\n\tpointIndex: number,\n): ResolvedDataLabelContent {\n\tconst chartLevel = chartData.style?.dataLabels;\n\tconst seriesLevel = series.dataLabelOptions;\n\tconst point = series.dataLabels?.find((label) => label.idx === pointIndex);\n\n\tconst pick = (\n\t\tfromPoint: boolean | undefined,\n\t\tfromSeries: boolean | undefined,\n\t\tfromChart: boolean | undefined,\n\t): boolean | undefined => fromPoint ?? fromSeries ?? fromChart;\n\n\tconst showValue = pick(point?.showVal, seriesLevel?.showValue, chartLevel?.showValue);\n\tconst showCategory = pick(\n\t\tpoint?.showCatName,\n\t\tseriesLevel?.showCategory,\n\t\tchartLevel?.showCategory,\n\t);\n\tconst showSeriesName = pick(\n\t\tpoint?.showSerName,\n\t\tseriesLevel?.showSeriesName,\n\t\tchartLevel?.showSeriesName,\n\t);\n\tconst showPercent = pick(point?.showPercent, seriesLevel?.showPercent, chartLevel?.showPercent);\n\tconst showBubbleSize = pick(\n\t\tpoint?.showBubbleSize,\n\t\tseriesLevel?.showBubbleSize,\n\t\tchartLevel?.showBubbleSize,\n\t);\n\n\t// \"Declared\" means a flag is written at ANY level, even as `0`. PowerPoint\n\t// writes an all-zero chart-type-level group on every chart it authors;\n\t// that group means \"no labels\", never \"fall back to the value\".\n\tconst anyDeclared = [showValue, showCategory, showSeriesName, showPercent, showBubbleSize].some(\n\t\t(flag) => flag !== undefined,\n\t);\n\t// Labels switched on by one series' own `c:dLbls` (no chart-level group)\n\t// must not leak onto its sibling series that declare nothing.\n\tconst siblingOwnsLabels =\n\t\t!anyDeclared &&\n\t\tchartLevel === undefined &&\n\t\tseriesLevel === undefined &&\n\t\tchartData.series.some((other) => other !== series && other.dataLabelOptions !== undefined);\n\n\t// PowerPoint 2013+ \"Value From Cells\", series-wide form\n\t// (`c15:datalabelsRange`): one cell range's cache supplies every label in\n\t// the group, aligned by point index. Falls back to the chart-type level\n\t// the same way the content flags do; a literal per-point override\n\t// (`point?.text`, which already resolves the per-point\n\t// `c15:dlblFieldTable` mechanism at parse time) always wins.\n\tconst rangeGroup =\n\t\tseriesLevel?.dataLabelsRange !== undefined\n\t\t\t? seriesLevel\n\t\t\t: chartLevel?.dataLabelsRange !== undefined\n\t\t\t\t? chartLevel\n\t\t\t\t: undefined;\n\tconst rangeText =\n\t\trangeGroup?.showDataLabelsRange !== false\n\t\t\t? rangeGroup?.dataLabelsRange?.cache[pointIndex]\n\t\t\t: undefined;\n\n\treturn {\n\t\t// Nothing declared anywhere => the historical \"just print the value\"\n\t\t// (what the serializer writes for a bare `hasDataLabels: true`).\n\t\tshowValue: anyDeclared ? showValue === true : !siblingOwnsLabels,\n\t\tshowCategory: showCategory === true,\n\t\tshowSeriesName: showSeriesName === true,\n\t\tshowPercent: showPercent === true,\n\t\tshowBubbleSize: showBubbleSize === true,\n\t\tseparator:\n\t\t\tpoint?.separator ??\n\t\t\tseriesLevel?.separator ??\n\t\t\tchartLevel?.separator ??\n\t\t\t(showCategory === true && showPercent === true\n\t\t\t\t? CATEGORY_PERCENT_SEPARATOR\n\t\t\t\t: DEFAULT_SEPARATOR),\n\t\tdeleted: point?.deleted === true,\n\t\t...(point?.text !== undefined\n\t\t\t? { customText: point.text }\n\t\t\t: rangeText !== undefined\n\t\t\t\t? { customText: rangeText }\n\t\t\t\t: {}),\n\t};\n}\n\n/** Inputs `buildDataLabelText` needs beyond the chart and series. */\nexport interface DataLabelTextParams {\n\tchartData: PptxChartData;\n\tseries: PptxChartSeries;\n\tpointIndex: number;\n\tvalue: number;\n\t/**\n\t * Denominator for `c:showPercent`. Defaults to the sum of this series'\n\t * absolute values, which is what a percentage means on a pie / doughnut /\n\t * ofPie, the only kinds PowerPoint offers the flag for.\n\t */\n\tpercentBase?: number;\n}\n\n/** A built data label: its text, and the `[Red]`/`[Blue]` colour it carries, if any. */\nexport interface DataLabelTextResult {\n\ttext: string;\n\t/**\n\t * A colour from the resolved number-format's `[Red]`/`[Blue]`/etc. section\n\t * (see `chart-number-format.ts`). Only set when the label renders AS the\n\t * formatted value with no other combined component: a joined \"Category,\n\t * -42\" label has no way to tint just the number in one flat `<text>`\n\t * element, so the caller's own default colour applies there instead.\n\t */\n\tcolor?: string;\n}\n\n/**\n * Build the text of one data label, or `undefined` when the label is deleted or\n * resolves to nothing. Pure: the caller decides where to draw it.\n */\nexport function buildDataLabelText(params: DataLabelTextParams): DataLabelTextResult | undefined {\n\tconst { chartData, series, pointIndex, value, percentBase } = params;\n\tconst content = resolveDataLabelContent(chartData, series, pointIndex);\n\tif (content.deleted) {\n\t\treturn undefined;\n\t}\n\tif (content.customText !== undefined) {\n\t\treturn { text: content.customText };\n\t}\n\n\t// c:dLbl/c:numFmt > c:ser/c:dLbls/c:numFmt (series level) >\n\t// c:*Chart/c:dLbls/c:numFmt (chart-type level) > the series' own cell\n\t// format: the same point > series > chart-type cascade the content flags\n\t// above use. A label may show a different (typically more compact) format\n\t// than the axis/series it belongs to.\n\tconst point = series.dataLabels?.find((label) => label.idx === pointIndex);\n\tconst seriesLevelOptions = series.dataLabelOptions;\n\tconst chartLevelOptions = chartData.style?.dataLabels;\n\tconst numberFormat =\n\t\tpoint?.numberFormat ??\n\t\tseriesLevelOptions?.numberFormat ??\n\t\tchartLevelOptions?.numberFormat ??\n\t\tseries.numberFormat;\n\n\tconst parts: string[] = [];\n\tlet valueColor: string | undefined;\n\t// PowerPoint's own component order, matching the Format Data Labels list.\n\tif (content.showSeriesName && series.name.length > 0) {\n\t\tparts.push(series.name);\n\t}\n\tif (content.showCategory) {\n\t\tconst category = chartData.categories[pointIndex];\n\t\tif (category !== undefined && category.length > 0) {\n\t\t\tparts.push(category);\n\t\t}\n\t}\n\tif (content.showValue) {\n\t\tconst formatted = formatChartNumberWithColor(value, numberFormat);\n\t\tparts.push(formatted?.text ?? formatAxisValue(value, numberFormat));\n\t\tvalueColor = formatted?.color;\n\t}\n\tif (content.showPercent) {\n\t\tconst base = percentBase ?? series.values.reduce((total, entry) => total + Math.abs(entry), 0);\n\t\tparts.push(base > 0 ? `${Math.round((Math.abs(value) / base) * 100)}%` : '0%');\n\t}\n\tif (content.showBubbleSize) {\n\t\tconst size = series.bubbleSizes?.[pointIndex];\n\t\tif (size !== undefined) {\n\t\t\tparts.push(formatAxisValue(size, series.numberFormat));\n\t\t}\n\t}\n\n\tconst text = parts.join(content.separator);\n\tif (text.length === 0) {\n\t\treturn undefined;\n\t}\n\treturn { text, color: parts.length === 1 && content.showValue ? valueColor : undefined };\n}\n\n/**\n * Resolve one label's own font (`c:dLbl`/`c:dLbls`/`c:ser`-`c:dLbls`/\n * ChartEx `cx:dataLabel`/`cx:dataLabels` `txPr`, C2-G1 data-label half),\n * following the same point > series > chart-type cascade the content flags\n * and number format already use. Returns `undefined` when nothing at any\n * level authored a font, so an untouched chart keeps whatever fixed default\n * the caller already draws with.\n */\nexport function resolveDataLabelTextStyle(\n\tchartData: PptxChartData,\n\tseries: PptxChartSeries,\n\tpointIndex: number,\n): PptxChartLegendTextStyle | undefined {\n\tconst point = series.dataLabels?.find((label) => label.idx === pointIndex);\n\treturn point?.txPr ?? series.dataLabelOptions?.txPr ?? chartData.style?.dataLabels?.txPr;\n}\n\n/**\n * Convert a resolved data-label font ({@link resolveDataLabelTextStyle}) into\n * the `SvgText` fields it overrides, in the units `SvgText` expects (px, not\n * points; `bold`/`italic` as the CSS-shaped `fontWeight`/`fontStyle`).\n *\n * Every field is independent and omitted when the source `txPr` (classic\n * `c:dLbls`/`c:dLbl`, or ChartEx `cx:dataLabels`/`cx:dataLabel`, which core\n * parses onto this SAME `txPr` field, see this module's header) didn't set\n * it, so a caller spreads the result over its own fixed label defaults\n * without clobbering fields the source left alone. Returns `{}` (a no-op\n * spread) for `undefined`, so every call site can use this unconditionally.\n */\nexport function dataLabelFontOverride(\n\tstyle: PptxChartLegendTextStyle | undefined,\n): Partial<Pick<SvgText, 'fontFamily' | 'fontSize' | 'fontWeight' | 'fontStyle' | 'fill'>> {\n\tif (!style) {\n\t\treturn {};\n\t}\n\treturn {\n\t\t...(style.fontFamily ? { fontFamily: style.fontFamily } : {}),\n\t\t...(style.fontSize !== undefined ? { fontSize: chartFontPx(style.fontSize) } : {}),\n\t\t...(style.bold !== undefined ? { fontWeight: style.bold ? 'bold' : 'normal' } : {}),\n\t\t...(style.italic !== undefined ? { fontStyle: style.italic ? 'italic' : 'normal' } : {}),\n\t\t...(style.color ? { fill: style.color } : {}),\n\t};\n}\n","/**\n * chart-line-path.ts: bezier smoothing for line-series paths.\n *\n * OOXML line/scatter series may set `c:smooth`, which PowerPoint renders as a\n * smoothed curve through the data points rather than straight segments. This\n * helper converts a point list into an SVG path `d` string using a Catmull-Rom\n * spline expressed as cubic beziers, so every binding can render the smoothed\n * line identically.\n *\n * @module chart-line-path\n */\n\nimport type { LinePoint } from './chart-view-model';\n\n/**\n * Build a smoothed cubic-bezier path `d` through `points` (Catmull-Rom spline).\n * Returns a straight `M…L…` fallback for fewer than three points.\n */\nexport function smoothLinePath(points: ReadonlyArray<LinePoint>): string {\n\tif (points.length === 0) {\n\t\treturn '';\n\t}\n\tif (points.length === 1) {\n\t\treturn `M${points[0].x.toFixed(2)},${points[0].y.toFixed(2)}`;\n\t}\n\tif (points.length === 2) {\n\t\treturn `M${points[0].x.toFixed(2)},${points[0].y.toFixed(2)} L${points[1].x.toFixed(2)},${points[1].y.toFixed(2)}`;\n\t}\n\n\tlet d = `M${points[0].x.toFixed(2)},${points[0].y.toFixed(2)}`;\n\tfor (let i = 0; i < points.length - 1; i++) {\n\t\tconst p0 = points[i - 1] ?? points[i];\n\t\tconst p1 = points[i];\n\t\tconst p2 = points[i + 1];\n\t\tconst p3 = points[i + 2] ?? p2;\n\t\tconst cp1x = p1.x + (p2.x - p0.x) / 6;\n\t\tconst cp1y = p1.y + (p2.y - p0.y) / 6;\n\t\tconst cp2x = p2.x - (p3.x - p1.x) / 6;\n\t\tconst cp2y = p2.y - (p3.y - p1.y) / 6;\n\t\td += ` C${cp1x.toFixed(2)},${cp1y.toFixed(2)} ${cp2x.toFixed(2)},${cp2y.toFixed(2)} ${p2.x.toFixed(2)},${p2.y.toFixed(2)}`;\n\t}\n\treturn d;\n}\n","import type { PlotLayout } from './chart-view-model';\n\nexport function categoryX(\n\tdisplayIndex: number,\n\tcount: number,\n\tlayout: PlotLayout,\n\tspacing: 'bar' | 'line',\n): number {\n\tif (spacing === 'bar') {\n\t\treturn layout.plotLeft + (layout.plotWidth / Math.max(count, 1)) * (displayIndex + 0.5);\n\t}\n\treturn count > 1\n\t\t? layout.plotLeft + (layout.plotWidth / (count - 1)) * displayIndex\n\t\t: layout.plotLeft + layout.plotWidth / 2;\n}\n","import type { PptxChartAxisFormatting } from 'pptx-viewer-core';\n\nimport { chartAxisTextStyle } from './chart-axis-style';\nimport { categoryX } from './chart-category-position';\nimport { DEFAULT_CHART_TEXT_PX, chartFontPx } from './chart-font';\nimport type { PlotLayout, SvgText } from './chart-view-model';\n\ninterface LabelGroup {\n\ttext: string;\n\tstart: number;\n\tend: number;\n}\n\nfunction groupedLabels(values: ReadonlyArray<string>): LabelGroup[] {\n\tconst groups: LabelGroup[] = [];\n\tvalues.forEach((text, index) => {\n\t\tconst previous = groups[groups.length - 1];\n\t\tif (previous?.text === text) {\n\t\t\tprevious.end = index;\n\t\t} else {\n\t\t\tgroups.push({ text, start: index, end: index });\n\t\t}\n\t});\n\treturn groups;\n}\n\n/** Build leaf and grouped parent category labels in separate axis bands. */\nexport function buildMultiLevelCategoryLabels(\n\tcategoryLabels: ReadonlyArray<string>,\n\tcategoryLevels: ReadonlyArray<ReadonlyArray<string>> | undefined,\n\tsourceIndices: ReadonlyArray<number>,\n\tlayout: PlotLayout,\n\tspacing: 'bar' | 'line',\n\taxis: PptxChartAxisFormatting | undefined,\n\tlabelY: number,\n\tlabelsAbove: boolean,\n\toffset: number,\n): SvgText[] {\n\tconst sourceLevels = categoryLevels?.length ? categoryLevels : [categoryLabels];\n\tconst levels = axis?.noMultiLevelLabels ? sourceLevels.slice(0, 1) : sourceLevels;\n\tconst skip = Math.max(1, axis?.tickLabelSkip ?? 1);\n\tconst textAnchor: SvgText['textAnchor'] =\n\t\taxis?.labelAlignment === 'l' ? 'start' : axis?.labelAlignment === 'r' ? 'end' : 'middle';\n\tconst direction = labelsAbove ? -1 : 1;\n\t// Band height tracks the rendered px size (axis.fontSize is parsed in points).\n\tconst fontPx = axis?.fontSize !== undefined ? chartFontPx(axis.fontSize) : DEFAULT_CHART_TEXT_PX;\n\tconst bandHeight = Math.max(fontPx, 8) + 4;\n\t// `SvgText.y` is the ALPHABETIC BASELINE (this is the one label emitter that\n\t// does not set `dominant-baseline`), so `offset` - the gap `c:lblOffset` asks\n\t// for between the axis and its labels - only becomes a real gap once the\n\t// glyph ascent is added below the axis, or the descent removed above it.\n\t// Without this the ink of a label under the axis starts ~0.8 em higher than\n\t// intended and crowds the plot: measured against PowerPoint the gap was 1.2px\n\t// where it should be 17.6px.\n\tconst baselineShift = labelsAbove ? -0.2 * fontPx : 0.8 * fontPx;\n\treturn levels.flatMap((level, levelIndex) => {\n\t\tconst values = sourceIndices.map((sourceIndex) => level[sourceIndex] ?? '');\n\t\treturn groupedLabels(values).flatMap((group) => {\n\t\t\tif (!group.text || group.start % skip !== 0) {\n\t\t\t\treturn [];\n\t\t\t}\n\t\t\tconst startX = categoryX(group.start, sourceIndices.length, layout, spacing);\n\t\t\tconst endX = categoryX(group.end, sourceIndices.length, layout, spacing);\n\t\t\treturn [\n\t\t\t\t{\n\t\t\t\t\tkind: 'text' as const,\n\t\t\t\t\tx: (startX + endX) / 2,\n\t\t\t\t\ty: labelY + direction * (offset + levelIndex * bandHeight) + baselineShift,\n\t\t\t\t\ttext: group.text,\n\t\t\t\t\ttextAnchor,\n\t\t\t\t\t...chartAxisTextStyle(axis),\n\t\t\t\t},\n\t\t\t];\n\t\t});\n\t});\n}\n","import type { PptxChartAxisFormatting, PptxChartData } from 'pptx-viewer-core';\n\nimport { chartLineStyle } from './chart-axis-style';\nimport { buildMultiLevelCategoryLabels } from './chart-category-labels';\nimport { categoryX } from './chart-category-position';\nimport type { PlotLayout, SvgLine, SvgText } from './chart-view-model';\n\nexport { categoryX } from './chart-category-position';\n\nexport interface CategoryAxisPlan {\n\taxis: PptxChartAxisFormatting | undefined;\n\tsourceIndices: number[];\n\tlabels: SvgText[];\n\ttickMarks: SvgLine[];\n}\n\nfunction primaryCategoryAxis(\n\taxes: ReadonlyArray<PptxChartAxisFormatting> | undefined,\n): PptxChartAxisFormatting | undefined {\n\tconst categoryAxes = axes?.filter(\n\t\t(axis) => axis.axisType === 'catAx' || axis.axisType === 'dateAx',\n\t);\n\treturn categoryAxes?.find((axis) => axis.axPos !== 't') ?? categoryAxes?.[0];\n}\n\n/**\n * One horizontal-axis tick mark (a short vertical stroke at `x`, straddling\n * `y` per `placement`). Exported for `chart-scatter-x-axis.ts`, a scatter/\n * bubble chart's X axis being a real value axis rather than this module's own\n * category-slot axis, but wanting the identical tick-mark geometry.\n */\nexport function tickLine(\n\tx: number,\n\ty: number,\n\tplacement: PptxChartAxisFormatting['majorTickMark'],\n\ttopAxis: boolean,\n\tlength: number,\n\taxis: PptxChartAxisFormatting,\n): SvgLine | undefined {\n\tif (!placement || placement === 'none') {\n\t\treturn undefined;\n\t}\n\tconst inward = topAxis ? length : -length;\n\tconst outward = -inward;\n\tconst [start, end] =\n\t\tplacement === 'cross' ? [-length, length] : placement === 'in' ? [0, inward] : [0, outward];\n\treturn {\n\t\tkind: 'line',\n\t\tx1: x,\n\t\ty1: y + start,\n\t\tx2: x,\n\t\ty2: y + end,\n\t\t...chartLineStyle(axis.spPr),\n\t};\n}\n\nfunction buildTickMarks(\n\taxis: PptxChartAxisFormatting | undefined,\n\tsourceCount: number,\n\tlayout: PlotLayout,\n\tspacing: 'bar' | 'line',\n\taxisY?: number,\n): SvgLine[] {\n\tif (!axis || axis.deleted) {\n\t\treturn [];\n\t}\n\tconst result: SvgLine[] = [];\n\tconst topAxis = axis.axPos === 't';\n\tconst y = axisY ?? (topAxis ? layout.plotTop : layout.plotBottom);\n\tif (axis.spPr) {\n\t\tresult.push({\n\t\t\tkind: 'line',\n\t\t\tx1: layout.plotLeft,\n\t\t\ty1: y,\n\t\t\tx2: layout.plotRight,\n\t\t\ty2: y,\n\t\t\t...chartLineStyle(axis.spPr),\n\t\t});\n\t}\n\tconst majorSkip = Math.max(1, axis.tickMarkSkip ?? 1);\n\tfor (let displayIndex = 0; displayIndex < sourceCount; displayIndex += majorSkip) {\n\t\tconst x = categoryX(displayIndex, sourceCount, layout, spacing);\n\t\tconst major = tickLine(x, y, axis.majorTickMark, topAxis, 4, axis);\n\t\tif (major) {\n\t\t\tresult.push(major);\n\t\t}\n\t\tif (axis.minorTickMark !== undefined && displayIndex + majorSkip < sourceCount) {\n\t\t\tconst nextX = categoryX(displayIndex + majorSkip, sourceCount, layout, spacing);\n\t\t\tconst minor = tickLine((x + nextX) / 2, y, axis.minorTickMark, topAxis, 2.5, axis);\n\t\t\tif (minor) {\n\t\t\t\tresult.push(minor);\n\t\t\t}\n\t\t}\n\t}\n\treturn result;\n}\n\n/** Build category order, labels, and explicit tick marks from the primary category/date axis. */\nexport function buildCategoryAxisPlan(\n\tcategoryLabels: ReadonlyArray<string>,\n\tlayout: PlotLayout,\n\tspacing: 'bar' | 'line',\n\taxes: ReadonlyArray<PptxChartAxisFormatting> | undefined,\n\tselectedAxis?: PptxChartAxisFormatting,\n\taxisY?: number,\n\tcategoryLevels?: ReadonlyArray<ReadonlyArray<string>>,\n): CategoryAxisPlan {\n\tconst axis = selectedAxis ?? primaryCategoryAxis(axes);\n\tconst sourceIndices = categoryLabels.map((_label, index) => index);\n\tif (axis?.orientation === 'maxMin') {\n\t\tsourceIndices.reverse();\n\t}\n\tif (axis?.deleted || axis?.tickLblPos === 'none') {\n\t\treturn {\n\t\t\taxis,\n\t\t\tsourceIndices,\n\t\t\tlabels: [],\n\t\t\ttickMarks: buildTickMarks(axis, sourceIndices.length, layout, spacing, axisY),\n\t\t};\n\t}\n\tconst topAxis = axis?.axPos === 't';\n\tconst high = axis?.tickLblPos === 'high';\n\tconst low = axis?.tickLblPos === 'low';\n\tconst labelsAbove = high || (!low && topAxis);\n\tconst offset = 4 + 8 * ((axis?.labelOffset ?? 100) / 100);\n\tconst labelY = high\n\t\t? layout.plotTop\n\t\t: low\n\t\t\t? layout.plotBottom\n\t\t\t: (axisY ?? (topAxis ? layout.plotTop : layout.plotBottom));\n\tconst labels = buildMultiLevelCategoryLabels(\n\t\tcategoryLabels,\n\t\tcategoryLevels,\n\t\tsourceIndices,\n\t\tlayout,\n\t\tspacing,\n\t\taxis,\n\t\tlabelY,\n\t\tlabelsAbove,\n\t\toffset,\n\t);\n\treturn {\n\t\taxis,\n\t\tsourceIndices,\n\t\tlabels,\n\t\ttickMarks: buildTickMarks(axis, sourceIndices.length, layout, spacing, axisY),\n\t};\n}\n\n/** Reorder category-bound data for non-interactive overlays and data tables. */\nexport function chartDataInCategoryOrder(\n\tchartData: PptxChartData,\n\tsourceIndices: ReadonlyArray<number>,\n): PptxChartData {\n\tif (sourceIndices.every((sourceIndex, displayIndex) => sourceIndex === displayIndex)) {\n\t\treturn chartData;\n\t}\n\treturn {\n\t\t...chartData,\n\t\tcategories: sourceIndices.map((sourceIndex) => chartData.categories[sourceIndex] ?? ''),\n\t\tcategoryLevels: chartData.categoryLevels?.map((level) =>\n\t\t\tsourceIndices.map((sourceIndex) => level[sourceIndex] ?? ''),\n\t\t),\n\t\tseries: chartData.series.map((series) => ({\n\t\t\t...series,\n\t\t\tvalues: sourceIndices.map((sourceIndex) => series.values[sourceIndex] ?? 0),\n\t\t\terrBars: series.errBars?.map((errorBars) => ({\n\t\t\t\t...errorBars,\n\t\t\t\tcustomPlus: errorBars.customPlus\n\t\t\t\t\t? sourceIndices.map((sourceIndex) => errorBars.customPlus?.[sourceIndex] ?? 0)\n\t\t\t\t\t: undefined,\n\t\t\t\tcustomMinus: errorBars.customMinus\n\t\t\t\t\t? sourceIndices.map((sourceIndex) => errorBars.customMinus?.[sourceIndex] ?? 0)\n\t\t\t\t\t: undefined,\n\t\t\t})),\n\t\t})),\n\t};\n}\n","/**\n * chart-scatter-x-axis.ts: a genuine \"nice\" VALUE axis for a scatter/bubble\n * chart's X axis (Excel-style automatic min/max/major-unit, vertical\n * gridlines), reusing the exact same maths the Y value axis already gets.\n *\n * OOXML gives a scatter/bubble chart TWO `c:valAx` elements (never a\n * `c:catAx`): one `axPos=\"l\"` (the Y axis every cartesian kind already\n * scales), one `axPos=\"b\"` (the X axis). The engine used to treat that X\n * axis as a row of evenly-spaced CATEGORY labels (`chartData.categories`,\n * itself a side effect of the embedded-workbook fallback reading the X\n * column generically), so it drew the raw data values themselves as tick\n * labels with no gridlines at all, instead of PowerPoint's own rounded\n * \"0, 0.5, 1, 1.5, ...\" scale with a vertical gridline at each tick.\n *\n * Reuses `computeValueRangeForAxis` (the same automatic-scale + `c:min`/\n * `c:max`/`c:majorUnit` honouring the Y axis uses) by feeding it \"pseudo\n * series\" whose `values` are each real series' X data\n * (`seriesXValues`), so a single well-tested function produces both axes'\n * bounds with no separate min/max algorithm to drift.\n *\n * @module chart-scatter-x-axis\n */\nimport type { PptxChartAxisFormatting, PptxChartData, PptxChartSeries } from 'pptx-viewer-core';\n\nimport { computeValueRangeForAxis, generateAxisTicks } from './chart-axis';\nimport { buildVerticalStyledGridline } from './chart-axis-primitives';\nimport { chartAxisTextStyle } from './chart-axis-style';\nimport { tickLine } from './chart-category-axis';\nimport { DEFAULT_CHART_TEXT_PX } from './chart-font';\nimport type { PlotLayout, SvgLine, SvgText, ValueRange } from './chart-view-model';\nimport { formatAxisValue, seriesXValues, valueToY } from './chart-view-model';\n\nconst GRIDLINE_COLOR = '#e2e8f0';\nconst TICK_COUNT = 5;\nconst MAJOR_TICK_LENGTH = 4;\n\nexport interface ScatterXAxisPlan {\n\t/**\n\t * The resolved X-axis range, in real data units (not pixels). `undefined`\n\t * when not one series carries a finite X value (no `c:xVal` and no numeric\n\t * `chartData.categories` to fall back to): there is no real X axis to\n\t * scale, and callers keep their own point-order fallback instead of\n\t * plotting everything at a meaningless {min:0, max:1}.\n\t */\n\trange: ValueRange | undefined;\n\tgridlines: SvgLine[];\n\tlabels: SvgText[];\n\t/** Map a real X value to its pixel X inside the plot box. Identity when `range` is `undefined`. */\n\ttoPixelX: (value: number) => number;\n}\n\n/** The `c:valAx` positioned at the bottom: a scatter/bubble chart's X axis. */\nfunction findScatterXAxis(\n\taxes: PptxChartAxisFormatting[] | undefined,\n): PptxChartAxisFormatting | undefined {\n\treturn (\n\t\taxes?.find((axis) => axis.axisType === 'valAx' && axis.axPos === 'b') ??\n\t\taxes?.find((axis) => axis.axisType === 'valAx' && axis.axPos !== 'l')\n\t);\n}\n\n/**\n * Build the nice-scaled X-axis range, vertical gridlines/tick marks, bottom\n * tick labels, and a value-to-pixel mapper for a scatter or bubble chart.\n */\nexport function buildScatterXAxisPlan(\n\tchartData: PptxChartData,\n\tlayout: PlotLayout,\n): ScatterXAxisPlan {\n\tconst xAxis = findScatterXAxis(chartData.axes);\n\tconst perSeriesX = chartData.series.map((series) => seriesXValues(chartData, series));\n\tconst hasFiniteX = perSeriesX.some((values) => values?.some((value) => Number.isFinite(value)));\n\tif (!hasFiniteX) {\n\t\treturn { range: undefined, gridlines: [], labels: [], toPixelX: (value) => value };\n\t}\n\tconst pseudoSeries: PptxChartSeries[] = chartData.series.map((series, index) => ({\n\t\t...series,\n\t\tvalues: [...(perSeriesX[index] ?? [])],\n\t}));\n\tconst range = computeValueRangeForAxis(pseudoSeries, xAxis, layout.plotWidth);\n\tconst toPixelX = (value: number): number =>\n\t\tvalueToY(value, range, layout.plotRight, layout.plotLeft);\n\n\tconst showGridlines = xAxis ? xAxis.majorGridlines === true : true;\n\tconst gridlines: SvgLine[] = [];\n\tconst labels: SvgText[] = [];\n\tconst textStyle = chartAxisTextStyle(xAxis, DEFAULT_CHART_TEXT_PX);\n\n\tfor (const tickValue of generateAxisTicks(range, xAxis, TICK_COUNT)) {\n\t\tconst x = toPixelX(tickValue);\n\t\tif (showGridlines) {\n\t\t\tgridlines.push(\n\t\t\t\tbuildVerticalStyledGridline(\n\t\t\t\t\tx,\n\t\t\t\t\tlayout,\n\t\t\t\t\txAxis?.majorGridlinesSpPr,\n\t\t\t\t\tGRIDLINE_COLOR,\n\t\t\t\t\t1,\n\t\t\t\t\tundefined,\n\t\t\t\t\tundefined,\n\t\t\t\t),\n\t\t\t);\n\t\t}\n\t\tconst tick =\n\t\t\txAxis && tickLine(x, layout.plotBottom, xAxis.majorTickMark, false, MAJOR_TICK_LENGTH, xAxis);\n\t\tif (tick) {\n\t\t\tgridlines.push(tick);\n\t\t}\n\t\tif (xAxis?.tickLblPos !== 'none') {\n\t\t\tlabels.push({\n\t\t\t\tkind: 'text',\n\t\t\t\tx,\n\t\t\t\ty: layout.plotBottom + 12,\n\t\t\t\ttext: formatAxisValue(tickValue, xAxis?.numFmt?.formatCode),\n\t\t\t\ttextAnchor: 'middle',\n\t\t\t\t...textStyle,\n\t\t\t});\n\t\t}\n\t}\n\n\treturn { range, gridlines, labels, toPixelX };\n}\n","/**\n * chart-cartesian-plots.ts: per-kind plot-primitive builders for the enriched\n * cartesian chart engine (scatter / bubble). Line and area live in\n * `chart-cartesian-line-area.ts`, bar in `chart-cartesian-bars.ts`.\n *\n * Split out of `chart-cartesian.ts` to keep each module within the repo's\n * ~300-LOC limit. These are pure helpers consumed by `buildCartesianViewModel`;\n * they reuse the geometry primitives in `chart-view-model.ts`.\n *\n * @module chart-cartesian-plots\n */\nimport type { PptxChartData, PptxChartSeries } from 'pptx-viewer-core';\n\nimport { resolveMarkerLabelPlacement } from './chart-data-label-anchor';\nimport { pushPointLabel } from './chart-data-label-callout';\nimport {\n\tbuildDataLabelText,\n\tdataLabelFontOverride,\n\tresolveDataLabelTextStyle,\n} from './chart-data-label-text';\nimport { resolveDataPointFill, resolveDataPointMarker } from './chart-datapoint-style';\nimport { DEFAULT_CHART_DATA_LABEL_PX } from './chart-font';\nimport { smoothLinePath } from './chart-line-path';\nimport { buildMarkerPrimitive } from './chart-marker-shape';\nimport { buildScatterXAxisPlan } from './chart-scatter-x-axis';\nimport type {\n\tChartPartRef,\n\tPlotLayout,\n\tSvgPath,\n\tSvgPolyline,\n\tSvgPrimitive,\n\tSvgText,\n\tValueRange,\n} from './chart-view-model';\nimport {\n\tcomputeScatterDots,\n\tformatAxisValue,\n\tlinePointsToSvgString,\n\tseriesColor,\n\tseriesXValues,\n} from './chart-view-model';\n\n/**\n * Chart-element pixel box a manual `c:dLbl/c:layout` drag is measured\n * against. Exported for `chart-cartesian-bubbles.ts`, which shares this\n * module's XY plumbing.\n */\nexport function elementFrame(layout: PlotLayout): { width: number; height: number } {\n\treturn { width: layout.svgWidth, height: layout.svgHeight };\n}\n\n/** Aggregate result of a per-kind plot builder: primitives + data labels. */\nexport interface SeriesPlotResult {\n\tprimitives: SvgPrimitive[];\n\tdataLabels: SvgText[];\n}\n\n/**\n * Hover-tooltip text for an XY (scatter/bubble) point: `\"<series>: (x, y)\"`.\n * Neither kind has a category label to hang the tooltip off, unlike\n * `buildMarkTooltip`'s bar/line/area/pie/radar marks, so this formats the raw\n * coordinate pair instead. Exported for `chart-cartesian-bubbles.ts`.\n */\nexport function xyMarkTooltip(\n\tseriesName: string,\n\txVal: number | undefined,\n\tyVal: number,\n\tnumberFormat: string | undefined,\n): string {\n\tconst y = formatAxisValue(yVal, numberFormat),\n\t\tcoords = xVal !== undefined ? `(${formatAxisValue(xVal)}, ${y})` : y;\n\treturn seriesName.length > 0 ? `${seriesName}: ${coords}` : coords;\n}\n\n/**\n * Build the marker for a data point (honouring `marker.symbol`/`size`) and push\n * it, unless the symbol is `none`. Shared by the line / area / scatter builders.\n *\n * `pointIndex` is the SOURCE index (the `c:idx` a `c:dPt` is keyed by), not the\n * display position, because a chart with hidden/filtered categories renders\n * fewer points than the series declares and the override must still land on the\n * point the author picked.\n */\nexport function pushMarker(\n\tout: SvgPrimitive[],\n\tseries: PptxChartSeries,\n\tpointIndex: number,\n\tcx: number,\n\tcy: number,\n\tfill: string,\n\tdefaultRadius: number,\n\tpart: ChartPartRef,\n\topacity?: number,\n\ttitle?: string,\n\tseriesPosition = part.seriesIndex ?? 0,\n): void {\n\tconst marker = resolveDataPointMarker(series, pointIndex, seriesPosition),\n\t\tm = buildMarkerPrimitive({\n\t\t\tsymbol: marker.symbol,\n\t\t\tsize: marker.size,\n\t\t\tcx,\n\t\t\tcy,\n\t\t\t// A marker fill (series or per-point) wins over the plot fill, which is\n\t\t\t// what the line/area body is drawn with.\n\t\t\tfill: marker.fill ?? fill,\n\t\t\tdefaultRadius,\n\t\t\tpart,\n\t\t});\n\tif (!m) {\n\t\treturn;\n\t}\n\tif (opacity !== undefined) {\n\t\tm.opacity = opacity;\n\t}\n\tif (title !== undefined) {\n\t\tm.title = title;\n\t}\n\tout.push(m);\n}\n\n/**\n * Whether `c:scatterStyle` joins the points with a line.\n *\n * `lineMarker` is what PowerPoint writes for essentially every scatter chart,\n * including the marker-only ones: it expresses \"no line\" as an `a:ln/a:noFill`\n * on the series, not by switching the style to `marker`. Both have to be\n * checked, and the series flag has to win, or a \"Scatter with Straight Lines\"\n * deck loses its lines and a marker-only deck grows some.\n */\nfunction scatterDrawsLine(chartData: PptxChartData, series: PptxChartSeries): boolean {\n\tif (series.lineNoFill === true) {\n\t\treturn false;\n\t}\n\tconst style = chartData.scatterStyle;\n\treturn (\n\t\tstyle === 'line' || style === 'lineMarker' || style === 'smooth' || style === 'smoothMarker'\n\t);\n}\n\n/** Build scatter-chart primitives, honouring `c:scatterStyle` connecting lines. */\nexport function buildScatter(\n\tchartData: PptxChartData,\n\tlayout: PlotLayout,\n\trange: ValueRange,\n): SeriesPlotResult {\n\tconst primitives: SvgPrimitive[] = [],\n\t\tdataLabels: SvgText[] = [],\n\t\tlabelBoxes: SvgPrimitive[] = [],\n\t\tshowLabels = chartData.style?.hasDataLabels,\n\t\tallIndices = chartData.series.flatMap((s) => s.values.map((_, i) => i)),\n\t\tmaxXIndex = Math.max(1, ...allIndices),\n\t\tperSeriesX = chartData.series.map((series) => seriesXValues(chartData, series)),\n\t\t// The chart's own nice-scaled X axis (see `chart-scatter-x-axis.ts`), not\n\t\t// the raw data's tight min/max: sharing this domain with the drawn\n\t\t// gridlines keeps every point aligned with them, and the axis's own\n\t\t// headroom/rounding keeps an edge point from sitting flush against the\n\t\t// plot boundary.\n\t\txDomain = buildScatterXAxisPlan(chartData, layout).range,\n\t\tsmoothStyle = chartData.scatterStyle === 'smooth' || chartData.scatterStyle === 'smoothMarker';\n\n\tfor (let si = 0; si < chartData.series.length; si++) {\n\t\tconst series = chartData.series[si],\n\t\t\tc = seriesColor(series, si, chartData.colorPalette),\n\t\t\tdots = computeScatterDots(series.values, maxXIndex, layout, range, perSeriesX[si], xDomain);\n\t\t// The connecting line goes down FIRST so the markers sit on top of it.\n\t\tif (scatterDrawsLine(chartData, series) && dots.length >= 2) {\n\t\t\tconst points = dots.map((dot) => ({ x: dot.cx, y: dot.cy })),\n\t\t\t\tseriesPart: ChartPartRef = { role: 'series', seriesIndex: si };\n\t\t\tprimitives.push(\n\t\t\t\t(series.smooth ?? smoothStyle)\n\t\t\t\t\t? ({\n\t\t\t\t\t\t\tkind: 'path',\n\t\t\t\t\t\t\td: smoothLinePath(points),\n\t\t\t\t\t\t\tstroke: c,\n\t\t\t\t\t\t\tstrokeWidth: 2.4,\n\t\t\t\t\t\t\tfill: 'none',\n\t\t\t\t\t\t\tpart: seriesPart,\n\t\t\t\t\t\t} satisfies SvgPath)\n\t\t\t\t\t: ({\n\t\t\t\t\t\t\tkind: 'polyline',\n\t\t\t\t\t\t\tpoints: linePointsToSvgString(points),\n\t\t\t\t\t\t\tstroke: c,\n\t\t\t\t\t\t\tstrokeWidth: 2.4,\n\t\t\t\t\t\t\tfill: 'none',\n\t\t\t\t\t\t\tpart: seriesPart,\n\t\t\t\t\t\t} satisfies SvgPolyline),\n\t\t\t);\n\t\t}\n\t\tdots.forEach((dot, vi) => {\n\t\t\tconst part: ChartPartRef = { role: 'dataPoint', seriesIndex: si, pointIndex: vi };\n\t\t\tpushMarker(\n\t\t\t\tprimitives,\n\t\t\t\tseries,\n\t\t\t\tvi,\n\t\t\t\tdot.cx,\n\t\t\t\tdot.cy,\n\t\t\t\tresolveDataPointFill(series, vi, c) ?? c,\n\t\t\t\t4,\n\t\t\t\tpart,\n\t\t\t\t0.85,\n\t\t\t\txyMarkTooltip(\n\t\t\t\t\tseries.name,\n\t\t\t\t\tperSeriesX[si]?.[vi],\n\t\t\t\t\tseries.values[vi] ?? 0,\n\t\t\t\t\tseries.numberFormat,\n\t\t\t\t),\n\t\t\t);\n\t\t});\n\t\tif (showLabels) {\n\t\t\tseries.values.forEach((val, vi) => {\n\t\t\t\tconst dot = dots[vi],\n\t\t\t\t\tlabel = buildDataLabelText({ chartData, series, pointIndex: vi, value: val });\n\t\t\t\tif (!dot || label === undefined) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\t// c:dLblPos (t/b/l/r/ctr) decides where round the marker the label\n\t\t\t\t// sits (right of it when none is authored: COM, callouts-com.pptx);\n\t\t\t\t// a per-point c:dLbl/c:layout drag shifts it further.\n\t\t\t\tconst target = { x: dot.cx, y: dot.cy },\n\t\t\t\t\tanchor = resolveMarkerLabelPlacement(\n\t\t\t\t\t\tchartData,\n\t\t\t\t\t\tseries,\n\t\t\t\t\t\tvi,\n\t\t\t\t\t\ttarget,\n\t\t\t\t\t\telementFrame(layout),\n\t\t\t\t\t\t6,\n\t\t\t\t\t\t'r',\n\t\t\t\t\t);\n\t\t\t\tpushPointLabel(dataLabels, labelBoxes, chartData, series, vi, target, {\n\t\t\t\t\tkind: 'text',\n\t\t\t\t\tx: anchor.x,\n\t\t\t\t\ty: anchor.y,\n\t\t\t\t\ttext: label.text,\n\t\t\t\t\tfontSize: DEFAULT_CHART_DATA_LABEL_PX,\n\t\t\t\t\tfill: label.color ?? '#334155',\n\t\t\t\t\ttextAnchor: anchor.textAnchor,\n\t\t\t\t\t...(anchor.dominantBaseline ? { dominantBaseline: anchor.dominantBaseline } : {}),\n\t\t\t\t\t...dataLabelFontOverride(resolveDataLabelTextStyle(chartData, series, vi)),\n\t\t\t\t});\n\t\t\t});\n\t\t}\n\t}\n\treturn { primitives: [...primitives, ...labelBoxes], dataLabels };\n}\n","/**\n * chart-cartesian-area.ts: area-chart plot-primitive builder, split out of\n * `chart-cartesian-line-area.ts` (which still owns `buildLines`) to keep each\n * module within the repo's ~300-LOC limit.\n *\n * @module chart-cartesian-area\n */\nimport type { PptxChartData } from 'pptx-viewer-core';\n\nimport { pushMarker } from './chart-cartesian-plots';\nimport type { SeriesPlotResult } from './chart-cartesian-plots';\nimport { resolveMarkerLabelPlacement } from './chart-data-label-anchor';\nimport { pushPointLabel } from './chart-data-label-callout';\nimport {\n\tbuildDataLabelText,\n\tdataLabelFontOverride,\n\tresolveDataLabelTextStyle,\n} from './chart-data-label-text';\nimport { resolveDataPointFill } from './chart-datapoint-style';\nimport { DEFAULT_CHART_DATA_LABEL_PX } from './chart-font';\nimport { computeStackedSeriesPlots } from './chart-stacked-series';\nimport type { LineAreaStacking } from './chart-stacked-series';\nimport type {\n\tChartPartRef,\n\tPlotLayout,\n\tSvgPolyline,\n\tSvgPrimitive,\n\tSvgText,\n\tValueRange,\n} from './chart-view-model';\nimport {\n\tbuildMarkTooltip,\n\tcomputeLinePoints,\n\tlinePointsToSvgString,\n\tseriesColor,\n\tvalueToY,\n} from './chart-view-model';\n\n/**\n * Build area-chart primitives (fill polygon + outline).\n *\n * Stacked/percentStacked fills the band between this series' running-sum top\n * and the previous series' top (its own base) instead of down to the zero\n * baseline, so layers stack visually like a PowerPoint stacked area chart\n * rather than each series washing over the ones below it. Data labels and\n * marker tooltips read the series' own value (or percent share), matching\n * `buildLines` and stacked bar's label convention.\n */\nexport function buildAreas(\n\tchartData: PptxChartData,\n\tcatCount: number,\n\tlayout: PlotLayout,\n\trange: ValueRange,\n\tsourceIndices: ReadonlyArray<number>,\n\txPositions?: ReadonlyArray<number>,\n\tstacking: LineAreaStacking = 'clustered',\n): SeriesPlotResult {\n\tconst primitives: SvgPrimitive[] = [],\n\t\tdataLabels: SvgText[] = [],\n\t\tlabelBoxes: SvgPrimitive[] = [],\n\t\tshowLabels = chartData.style?.hasDataLabels,\n\t\tisStackedMode = stacking !== 'clustered',\n\t\tisPercent = stacking === 'percentStacked',\n\t\tbaselineY = valueToY(0, range, layout.plotTop, layout.plotBottom),\n\t\tallDisplayValues = chartData.series.map((series) =>\n\t\t\tseries.values.length === 0\n\t\t\t\t? undefined\n\t\t\t\t: sourceIndices.map((sourceIndex) => series.values[sourceIndex] ?? 0),\n\t\t),\n\t\tstackedPlots = isStackedMode\n\t\t\t? computeStackedSeriesPlots(\n\t\t\t\t\tallDisplayValues.map((values) => values ?? []),\n\t\t\t\t\tcatCount,\n\t\t\t\t\tisPercent,\n\t\t\t\t)\n\t\t\t: undefined;\n\n\tfor (let si = 0; si < chartData.series.length; si++) {\n\t\tconst series = chartData.series[si],\n\t\t\tdisplayValues = allDisplayValues[si];\n\t\tif (!displayValues) {\n\t\t\tcontinue;\n\t\t}\n\t\t// eslint-disable-next-line one-var -- pre-existing, unrelated to this change\n\t\tconst plot = stackedPlots?.[si],\n\t\t\ttopValues = plot ? plot.cumulative : displayValues,\n\t\t\tpts = computeLinePoints(topValues, catCount, layout, range).map((point, index) => ({\n\t\t\t\t...point,\n\t\t\t\tx: xPositions?.[index] ?? point.x,\n\t\t\t})),\n\t\t\tc = seriesColor(series, si, chartData.colorPalette),\n\t\t\tlineStr = linePointsToSvgString(pts),\n\t\t\tfirstPt = pts[0],\n\t\t\tlastPt = pts[pts.length - 1];\n\t\tif (plot) {\n\t\t\t// Stacked band: fill between this series' cumulative top and its own\n\t\t\t// base (the previous series' top), like a stream-graph layer, at full\n\t\t\t// opacity so adjacent bands read as distinct rather than washed.\n\t\t\tconst baseStr = linePointsToSvgString(\n\t\t\t\t[\n\t\t\t\t\t...computeLinePoints(plot.base, catCount, layout, range).map((point, index) => ({\n\t\t\t\t\t\t...point,\n\t\t\t\t\t\tx: xPositions?.[index] ?? point.x,\n\t\t\t\t\t})),\n\t\t\t\t].reverse(),\n\t\t\t);\n\t\t\tprimitives.push({\n\t\t\t\tkind: 'polyline',\n\t\t\t\tpoints: `${lineStr} ${baseStr}`,\n\t\t\t\tstroke: 'none',\n\t\t\t\tstrokeWidth: 0,\n\t\t\t\tfill: c,\n\t\t\t\tpart: { role: 'series', seriesIndex: si },\n\t\t\t} satisfies SvgPolyline);\n\t\t} else if (firstPt && lastPt) {\n\t\t\tprimitives.push({\n\t\t\t\tkind: 'polyline',\n\t\t\t\tpoints: `${firstPt.x.toFixed(2)},${baselineY.toFixed(2)} ${lineStr} ${lastPt.x.toFixed(2)},${baselineY.toFixed(2)}`,\n\t\t\t\tstroke: 'none',\n\t\t\t\tstrokeWidth: 0,\n\t\t\t\tfill: c,\n\t\t\t\topacity: 0.25,\n\t\t\t\tpart: { role: 'series', seriesIndex: si },\n\t\t\t} satisfies SvgPolyline);\n\t\t}\n\t\tprimitives.push({\n\t\t\tkind: 'polyline',\n\t\t\tpoints: lineStr,\n\t\t\tstroke: c,\n\t\t\tstrokeWidth: 2,\n\t\t\tfill: 'none',\n\t\t\tpart: { role: 'series', seriesIndex: si },\n\t\t} satisfies SvgPolyline);\n\t\tpts.forEach((pt, displayIndex) => {\n\t\t\tconst idx = sourceIndices[displayIndex] ?? displayIndex,\n\t\t\t\tpart: ChartPartRef = { role: 'dataPoint', seriesIndex: si, pointIndex: idx };\n\t\t\tpushMarker(\n\t\t\t\tprimitives,\n\t\t\t\tseries,\n\t\t\t\tidx,\n\t\t\t\tpt.x,\n\t\t\t\tpt.y,\n\t\t\t\tresolveDataPointFill(series, idx, c) ?? c,\n\t\t\t\t2,\n\t\t\t\tpart,\n\t\t\t\tundefined,\n\t\t\t\tbuildMarkTooltip(\n\t\t\t\t\tseries.name,\n\t\t\t\t\tchartData.categories[idx],\n\t\t\t\t\tseries.values[idx] ?? 0,\n\t\t\t\t\tseries.numberFormat,\n\t\t\t\t),\n\t\t\t);\n\t\t});\n\t\tif (showLabels) {\n\t\t\tconst labelValues = plot ? plot.own : displayValues;\n\t\t\tlabelValues.forEach((val, displayIndex) => {\n\t\t\t\tconst pt = pts[displayIndex];\n\t\t\t\tif (!pt) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tif (isPercent) {\n\t\t\t\t\tif (val === 0) {\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\t// Centre on the VISIBLE segment (the filled band between this\n\t\t\t\t\t// series' running-sum top and its own base), matching\n\t\t\t\t\t// PowerPoint's own percentStacked convention and stacked bar's\n\t\t\t\t\t// `y + h/2` placement, rather than a fixed offset above the top\n\t\t\t\t\t// line: at extreme category skews a thin band's label used to\n\t\t\t\t\t// float noticeably off the band it names.\n\t\t\t\t\tconst baseVal = plot?.base[displayIndex] ?? 0,\n\t\t\t\t\t\ttopVal = plot?.cumulative[displayIndex] ?? val,\n\t\t\t\t\t\tbaseY = valueToY(baseVal, range, layout.plotTop, layout.plotBottom),\n\t\t\t\t\t\ttopY = valueToY(topVal, range, layout.plotTop, layout.plotBottom);\n\t\t\t\t\tdataLabels.push({\n\t\t\t\t\t\tkind: 'text',\n\t\t\t\t\t\tx: pt.x,\n\t\t\t\t\t\ty: (baseY + topY) / 2,\n\t\t\t\t\t\ttext: `${Math.round(val)}%`,\n\t\t\t\t\t\tfontSize: DEFAULT_CHART_DATA_LABEL_PX,\n\t\t\t\t\t\tfill: '#ffffff',\n\t\t\t\t\t\ttextAnchor: 'middle',\n\t\t\t\t\t\tdominantBaseline: 'central',\n\t\t\t\t\t\tfontWeight: 'bold',\n\t\t\t\t\t\t...dataLabelFontOverride(\n\t\t\t\t\t\t\tresolveDataLabelTextStyle(\n\t\t\t\t\t\t\t\tchartData,\n\t\t\t\t\t\t\t\tseries,\n\t\t\t\t\t\t\t\tsourceIndices[displayIndex] ?? displayIndex,\n\t\t\t\t\t\t\t),\n\t\t\t\t\t\t),\n\t\t\t\t\t});\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\t// eslint-disable-next-line one-var -- an early return sits between this const and the previous one\n\t\t\t\tconst pointIndex = sourceIndices[displayIndex] ?? displayIndex,\n\t\t\t\t\tlabel = buildDataLabelText({ chartData, series, pointIndex, value: val });\n\t\t\t\tif (label === undefined) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\t// PowerPoint centres an area label in the band it names, the\n\t\t\t\t// middle of this series' own slice at the category (COM,\n\t\t\t\t// callouts-com.pptx), and points its callout / leader line there.\n\t\t\t\tconst bandBase = plot\n\t\t\t\t\t\t? valueToY(plot.base[displayIndex] ?? 0, range, layout.plotTop, layout.plotBottom)\n\t\t\t\t\t\t: baselineY,\n\t\t\t\t\tmid = { x: pt.x, y: (pt.y + bandBase) / 2 },\n\t\t\t\t\tanchor = resolveMarkerLabelPlacement(\n\t\t\t\t\t\tchartData,\n\t\t\t\t\t\tseries,\n\t\t\t\t\t\tpointIndex,\n\t\t\t\t\t\tmid,\n\t\t\t\t\t\t{ width: layout.svgWidth, height: layout.svgHeight },\n\t\t\t\t\t\t6,\n\t\t\t\t\t\t'ctr',\n\t\t\t\t\t);\n\t\t\t\tpushPointLabel(dataLabels, labelBoxes, chartData, series, pointIndex, mid, {\n\t\t\t\t\tkind: 'text',\n\t\t\t\t\tx: anchor.x,\n\t\t\t\t\ty: anchor.y,\n\t\t\t\t\ttext: label.text,\n\t\t\t\t\tfontSize: DEFAULT_CHART_DATA_LABEL_PX,\n\t\t\t\t\tfill: label.color ?? '#334155',\n\t\t\t\t\ttextAnchor: anchor.textAnchor,\n\t\t\t\t\t...(anchor.dominantBaseline ? { dominantBaseline: anchor.dominantBaseline } : {}),\n\t\t\t\t\t...dataLabelFontOverride(resolveDataLabelTextStyle(chartData, series, pointIndex)),\n\t\t\t\t});\n\t\t\t});\n\t\t}\n\t}\n\treturn { primitives: [...primitives, ...labelBoxes], dataLabels };\n}\n","import type { PptxChartAxisFormatting } from 'pptx-viewer-core';\n\nimport type { PlotLayout, ValueRange } from './chart-view-model';\nimport { valueToY } from './chart-view-model';\n\nfunction clamp(value: number, min: number, max: number): number {\n\treturn Math.min(Math.max(value, min), max);\n}\n\n/** Resolve where the horizontal category/date axis crosses its linked value axis. */\nexport function horizontalAxisY(\n\tvalueAxis: PptxChartAxisFormatting | undefined,\n\trange: ValueRange,\n\tlayout: PlotLayout,\n\tfallback: 'top' | 'bottom',\n): number {\n\tif (valueAxis?.crosses === 'max') {\n\t\treturn layout.plotTop;\n\t}\n\tif (valueAxis?.crosses === 'min') {\n\t\treturn layout.plotBottom;\n\t}\n\tconst crossingValue = valueAxis?.crossesAt ?? 0;\n\tif (valueAxis?.crossesAt !== undefined || valueAxis?.crosses === 'autoZero') {\n\t\treturn valueToY(\n\t\t\tclamp(crossingValue, range.min, range.max),\n\t\t\trange,\n\t\t\tlayout.plotTop,\n\t\t\tlayout.plotBottom,\n\t\t);\n\t}\n\treturn fallback === 'top' ? layout.plotTop : layout.plotBottom;\n}\n\n/** Resolve where a vertical value axis crosses a category axis. */\nexport function verticalAxisX(\n\tcategoryAxis: PptxChartAxisFormatting | undefined,\n\tcategoryCount: number,\n\tlayout: PlotLayout,\n\tfallback: 'left' | 'right',\n\tdateValues?: ReadonlyArray<number>,\n): number {\n\tif (categoryAxis?.crosses === 'max') {\n\t\treturn layout.plotRight;\n\t}\n\tif (categoryAxis?.crosses === 'min') {\n\t\treturn layout.plotLeft;\n\t}\n\tif (categoryAxis?.crossesAt !== undefined) {\n\t\tif (categoryAxis.axisType === 'dateAx' && dateValues?.length) {\n\t\t\tconst min = categoryAxis.min ?? Math.min(...dateValues);\n\t\t\tconst max = categoryAxis.max ?? Math.max(...dateValues);\n\t\t\tconst ratio =\n\t\t\t\tmax === min ? 0.5 : (clamp(categoryAxis.crossesAt, min, max) - min) / (max - min);\n\t\t\treturn layout.plotLeft + ratio * layout.plotWidth;\n\t\t}\n\t\tconst index = clamp(categoryAxis.crossesAt - 1, 0, Math.max(categoryCount - 1, 0));\n\t\tconst ratio = categoryCount <= 1 ? 0.5 : index / (categoryCount - 1);\n\t\treturn layout.plotLeft + ratio * layout.plotWidth;\n\t}\n\treturn fallback === 'right' ? layout.plotRight : layout.plotLeft;\n}\n","/**\n * `chart-gridlines-toggle` - read/write helpers for the inspector's simple\n * \"Show Gridlines\" checkbox (`ChartDisplayOptions` in React/Vue/Angular,\n * the inline checkbox in Svelte's `ChartSection`).\n *\n * WHY this exists: every binding wired that checkbox straight to\n * `style.hasGridlines`, a field the renderer never reads. Actual gridline\n * visibility comes from the value axis's `majorGridlines` flag\n * (`c:valAx/c:majorGridlines`, see `chart-axis-render.ts` /\n * `chart-cartesian-axes.ts`), which the checkbox never touched. So toggling\n * \"Show Gridlines\" silently did nothing.\n *\n * {@link chartGridlinesState} and {@link chartGridlinesPatch} read and write\n * the primary value axis's `majorGridlines` instead, creating a minimal\n * `valAx` entry when the chart has none yet. `style.hasGridlines` is still\n * kept in sync for any legacy reader of that field (e.g. a converter that has\n * not been updated to look at the axis).\n *\n * @module render/chart-gridlines-toggle\n */\nimport type { PptxChartAxisFormatting, PptxChartData } from 'pptx-viewer-core';\n\n/**\n * Find the chart's primary (non-secondary) value axis: the one positioned\n * \"l\" (left), or the first `valAx` entry when none declares a position.\n * Mirrors `getPrimaryValueAxisId` in `chart-axis.ts`.\n */\nfunction primaryValueAxis(\n\taxes: PptxChartAxisFormatting[] | undefined,\n): PptxChartAxisFormatting | undefined {\n\tif (!axes) {\n\t\treturn undefined;\n\t}\n\treturn (\n\t\taxes.find((axis) => axis.axisType === 'valAx' && axis.axPos === 'l') ??\n\t\taxes.find((axis) => axis.axisType === 'valAx')\n\t);\n}\n\n/**\n * Whether the chart's primary value axis currently shows major gridlines.\n *\n * A parsed value axis is authoritative: `c:majorGridlines` present means\n * shown, absent means hidden, exactly as PowerPoint renders it. A chart with\n * no parsed value axis (SDK/AI-created, never saved) falls back to the legacy\n * `style.hasGridlines` flag and then to `true`, because that is what the\n * renderer draws for such a chart (PowerPoint's own default chart has major\n * gridlines), so the checkbox and the canvas agree.\n *\n * This is also the renderer's decision ({@link shouldRenderMajorGridlines});\n * the two are one function so the inspector can never disagree with the\n * canvas.\n */\nexport function chartGridlinesState(chartData: PptxChartData): boolean {\n\tconst axis = primaryValueAxis(chartData.axes);\n\tif (axis) {\n\t\treturn axis.majorGridlines ?? false;\n\t}\n\treturn chartData.style?.hasGridlines ?? true;\n}\n\n/** Whether the cartesian renderer should draw primary major gridlines. */\nexport const shouldRenderMajorGridlines = chartGridlinesState;\n\n/**\n * Build a `Partial<PptxChartData>` patch that toggles major gridlines on the\n * primary value axis, creating a minimal `valAx` entry when the chart's\n * `axes` array has none. Also updates `style.hasGridlines` to the same value\n * so a legacy reader of that field stays consistent.\n */\nexport function chartGridlinesPatch(\n\tchartData: PptxChartData,\n\tshow: boolean,\n): Partial<PptxChartData> {\n\tconst axes = chartData.axes ? [...chartData.axes] : [];\n\tlet index = axes.findIndex((axis) => axis.axisType === 'valAx' && axis.axPos === 'l');\n\tif (index === -1) {\n\t\tindex = axes.findIndex((axis) => axis.axisType === 'valAx');\n\t}\n\tif (index === -1) {\n\t\taxes.push({ axisType: 'valAx', majorGridlines: show });\n\t} else {\n\t\taxes[index] = { ...axes[index], majorGridlines: show };\n\t}\n\treturn {\n\t\taxes,\n\t\tstyle: { ...chartData.style, hasGridlines: show },\n\t};\n}\n","import type { PptxChartData } from 'pptx-viewer-core';\n\nimport { getSecondaryValueAxis } from './chart-axis';\nimport { verticalAxisX } from './chart-axis-crossing';\nimport { buildPrimaryAxis, buildSecondaryAxis } from './chart-axis-render';\nimport { shouldRenderMajorGridlines } from './chart-gridlines-toggle';\nimport type { PlotLayout, SvgLine, SvgText, ValueRange } from './chart-view-model';\nimport { buildGridlinesAndLabels } from './chart-view-model';\n\nexport interface CartesianAxesResult {\n\tgridlines: SvgLine[];\n\taxisLabels: SvgText[];\n\tsecondaryGridlines: SvgLine[] | undefined;\n\tsecondaryAxisLabels: SvgText[] | undefined;\n}\n\nfunction hasRicherAxisFeatures(chartData: PptxChartData): boolean {\n\treturn Boolean(\n\t\tchartData.dataTable ||\n\t\tchartData.axes?.some(\n\t\t\t(axis) =>\n\t\t\t\taxis.crosses !== undefined ||\n\t\t\t\taxis.crossesAt !== undefined ||\n\t\t\t\taxis.crossBetween !== undefined ||\n\t\t\t\t(axis.axisType === 'valAx' &&\n\t\t\t\t\tBoolean(\n\t\t\t\t\t\taxis.logScale ||\n\t\t\t\t\t\taxis.displayUnits ||\n\t\t\t\t\t\t// A `c:numFmt` is only honoured on the `buildPrimaryAxis`\n\t\t\t\t\t\t// path; the fast path has no axis to read it from. The two\n\t\t\t\t\t\t// agree tick-for-tick when no log scale or display unit is\n\t\t\t\t\t\t// in play, so routing a formatted axis here costs nothing.\n\t\t\t\t\t\taxis.numFmt?.formatCode ||\n\t\t\t\t\t\taxis.axPos === 'r' ||\n\t\t\t\t\t\taxis.orientation === 'maxMin' ||\n\t\t\t\t\t\taxis.majorUnit !== undefined ||\n\t\t\t\t\t\taxis.minorUnit !== undefined ||\n\t\t\t\t\t\taxis.minorGridlines ||\n\t\t\t\t\t\taxis.majorTickMark !== undefined ||\n\t\t\t\t\t\taxis.minorTickMark !== undefined ||\n\t\t\t\t\t\taxis.tickLblPos !== undefined,\n\t\t\t\t\t)),\n\t\t),\n\t);\n}\n\n/** Build crossed primary and secondary value axes for a cartesian chart. */\nexport function buildCartesianAxes(\n\tchartData: PptxChartData,\n\tlayout: PlotLayout,\n\tprimaryRange: ValueRange,\n\tsecondaryRange: ValueRange | undefined,\n\tcategoryCount: number,\n): CartesianAxesResult {\n\t// `c:majorGridlines` absent on a parsed value axis means PowerPoint draws\n\t// none; the same decision feeds the inspector's \"Show Gridlines\" checkbox.\n\tconst showMajorGridlines = shouldRenderMajorGridlines(chartData);\n\tif (!hasRicherAxisFeatures(chartData)) {\n\t\tconst { gridlines, axisLabels } = buildGridlinesAndLabels(\n\t\t\tprimaryRange,\n\t\t\tlayout,\n\t\t\tshowMajorGridlines,\n\t\t);\n\t\treturn { gridlines, axisLabels, secondaryGridlines: undefined, secondaryAxisLabels: undefined };\n\t}\n\tconst primaryAxis =\n\t\tchartData.axes?.find((axis) => axis.axisType === 'valAx' && axis.axPos !== 'r') ??\n\t\tchartData.axes?.find((axis) => axis.axisType === 'valAx');\n\tconst categoryAxisFor = (axisId: number | undefined) =>\n\t\tchartData.axes?.find(\n\t\t\t(axis) => (axis.axisType === 'catAx' || axis.axisType === 'dateAx') && axis.axisId === axisId,\n\t\t);\n\tconst axisX = (axisId: number | undefined, fallback: 'left' | 'right') =>\n\t\tverticalAxisX(\n\t\t\tcategoryAxisFor(axisId),\n\t\t\tcategoryCount,\n\t\t\tlayout,\n\t\t\tfallback,\n\t\t\tchartData.dateCategories?.values,\n\t\t);\n\tconst primary = buildPrimaryAxis(\n\t\tprimaryRange,\n\t\tlayout,\n\t\tprimaryAxis,\n\t\taxisX(primaryAxis?.crossAxisId, 'left'),\n\t\tshowMajorGridlines,\n\t);\n\tif (!secondaryRange) {\n\t\treturn { ...primary, secondaryGridlines: undefined, secondaryAxisLabels: undefined };\n\t}\n\tconst secondaryAxis = getSecondaryValueAxis(chartData.axes);\n\tconst secondary = buildSecondaryAxis(\n\t\tsecondaryRange,\n\t\tlayout,\n\t\tsecondaryAxis,\n\t\taxisX(secondaryAxis?.crossAxisId, 'right'),\n\t);\n\treturn {\n\t\t...primary,\n\t\tsecondaryGridlines: secondary.gridlines,\n\t\tsecondaryAxisLabels: secondary.axisLabels,\n\t};\n}\n","/**\n * chart-cartesian-percent-stacked.ts: the percentStacked bar/column builder,\n * split out of `chart-cartesian-bars.ts` (which still owns clustered and\n * plain stacked) to keep each module within the repo's ~300-LOC limit.\n *\n * @module chart-cartesian-percent-stacked\n */\nimport type { PptxChartData, PptxChartSeries } from 'pptx-viewer-core';\n\nimport type { SeriesPlotResult } from './chart-cartesian-plots';\nimport { dataLabelFontOverride, resolveDataLabelTextStyle } from './chart-data-label-text';\nimport { resolveDataPointFill } from './chart-datapoint-style';\nimport { DEFAULT_CHART_DATA_LABEL_PX } from './chart-font';\nimport type { PlotLayout, SvgPrimitive, SvgRect, SvgText, ValueRange } from './chart-view-model';\nimport { buildMarkTooltip, paletteColor, seriesColor, valueToY } from './chart-view-model';\n\n/** Per-category absolute totals (for percentStacked normalisation). */\nfunction categoryTotals(series: ReadonlyArray<PptxChartSeries>, catCount: number): number[] {\n\treturn Array.from({ length: catCount }, (_, ci) =>\n\t\tseries.reduce((sum, s) => sum + Math.abs(s.values[ci] ?? 0), 0),\n\t);\n}\n\n/**\n * Build percentStacked bar/column primitives: normalise each category to\n * 100% with in-bar percent labels (matching React's `renderStackedBarChart`).\n * `invertNegativeFill` is injected from `chart-cartesian-bars.ts` (the only\n * other consumer of `c:invertIfNegative`) rather than duplicated here.\n */\nexport function buildPercentStackedBars(\n\tchartData: PptxChartData,\n\tcatCount: number,\n\tlayout: PlotLayout,\n\tprimaryRange: ValueRange,\n\tsourceIndices: ReadonlyArray<number>,\n\tinvertNegativeFill: (\n\t\tseries: PptxChartSeries,\n\t\tpointIndex: number,\n\t\tvalue: number,\n\t\tbaseFill: string,\n\t) => string,\n): SeriesPlotResult {\n\tconst primitives: SvgPrimitive[] = [],\n\t\tdataLabels: SvgText[] = [],\n\t\tseries = chartData.series,\n\t\tpalette = chartData.colorPalette,\n\t\tshowLabels = chartData.style?.hasDataLabels,\n\t\tbarGroupWidth = layout.plotWidth / Math.max(catCount, 1),\n\t\tbarW = barGroupWidth * 0.6,\n\t\tbarOffset = (barGroupWidth - barW) / 2,\n\t\tdisplaySeries = series.map((entry) => ({\n\t\t\t...entry,\n\t\t\tvalues: sourceIndices.map((sourceIndex) => entry.values[sourceIndex] ?? 0),\n\t\t})),\n\t\ttotals = categoryTotals(displaySeries, catCount);\n\n\tfor (let ci = 0; ci < catCount; ci++) {\n\t\tlet posRunning = 0,\n\t\t\tnegRunning = 0;\n\t\tconst catTotal = totals[ci] || 1;\n\n\t\tfor (let si = 0; si < series.length; si++) {\n\t\t\tconst sourceIndex = sourceIndices[ci] ?? ci,\n\t\t\t\trawVal = series[si].values[sourceIndex] ?? 0,\n\t\t\t\tval = catTotal > 0 ? (rawVal / catTotal) * 100 : 0,\n\t\t\t\tisNeg = val < 0,\n\t\t\t\tbase = isNeg ? negRunning : posRunning,\n\t\t\t\ttop = base + val,\n\t\t\t\tx = layout.plotLeft + barGroupWidth * ci + barOffset,\n\t\t\t\tbaseY = valueToY(base, primaryRange, layout.plotTop, layout.plotBottom),\n\t\t\t\ttopY = valueToY(top, primaryRange, layout.plotTop, layout.plotBottom),\n\t\t\t\ty = Math.min(baseY, topY),\n\t\t\t\th = Math.max(Math.abs(baseY - topY), 0.5),\n\t\t\t\tpctBaseFill =\n\t\t\t\t\tresolveDataPointFill(series[si], sourceIndex, paletteColor(si, palette)) ??\n\t\t\t\t\tseriesColor(series[si], si, palette);\n\t\t\tprimitives.push({\n\t\t\t\tkind: 'rect',\n\t\t\t\tx,\n\t\t\t\ty,\n\t\t\t\tw: barW,\n\t\t\t\th,\n\t\t\t\tfill: invertNegativeFill(series[si], sourceIndex, rawVal, pctBaseFill),\n\t\t\t\tpart: { role: 'dataPoint', seriesIndex: si, pointIndex: sourceIndex },\n\t\t\t\ttitle: buildMarkTooltip(\n\t\t\t\t\tseries[si].name,\n\t\t\t\t\tchartData.categories[sourceIndex],\n\t\t\t\t\trawVal,\n\t\t\t\t\tseries[si].numberFormat,\n\t\t\t\t),\n\t\t\t} satisfies SvgRect);\n\n\t\t\tif (showLabels && Math.abs(val) > 0) {\n\t\t\t\tdataLabels.push({\n\t\t\t\t\tkind: 'text',\n\t\t\t\t\tx: x + barW / 2,\n\t\t\t\t\ty: y + h / 2 + 3,\n\t\t\t\t\ttext: `${Math.round(val)}%`,\n\t\t\t\t\tfontSize: DEFAULT_CHART_DATA_LABEL_PX,\n\t\t\t\t\tfill: '#ffffff',\n\t\t\t\t\ttextAnchor: 'middle',\n\t\t\t\t\tfontWeight: 'bold',\n\t\t\t\t\t...dataLabelFontOverride(resolveDataLabelTextStyle(chartData, series[si], sourceIndex)),\n\t\t\t\t});\n\t\t\t}\n\n\t\t\tif (isNeg) {\n\t\t\t\tnegRunning += val;\n\t\t\t} else {\n\t\t\t\tposRunning += val;\n\t\t\t}\n\t\t}\n\t}\n\treturn { primitives, dataLabels };\n}\n","/**\n * chart-cartesian-stacked-labels.ts: the (non-percent) stacked bar/column data\n * labels, split out of `chart-cartesian-bars.ts` to keep that file within the\n * repo's ~300-LOC limit.\n *\n * @module chart-cartesian-stacked-labels\n */\nimport type { PptxChartData, PptxChartSeries } from 'pptx-viewer-core';\n\nimport { resolveBarLabelPlacement } from './chart-data-label-anchor';\nimport {\n\tbuildDataLabelText,\n\tdataLabelFontOverride,\n\tresolveDataLabelTextStyle,\n} from './chart-data-label-text';\nimport { DEFAULT_CHART_DATA_LABEL_PX } from './chart-font';\nimport type { PlotLayout, SvgText, ValueRange } from './chart-view-model';\nimport { valueToY } from './chart-view-model';\n\n/**\n * Push the abs-value stacked data labels matching the original cartesian\n * builder: one label per (category x series) at the bar mid, only when data\n * labels are on. `c:dLblPos` (ctr/inBase/inEnd/outEnd) repositions the label\n * on the bar rect, and a per-point `c:dLbl/c:layout` drag shifts it further,\n * via the same `resolveBarLabelPlacement` pipeline the clustered path uses.\n */\nexport function pushClusteredStackedLabels(\n\tchartData: PptxChartData,\n\tseries: ReadonlyArray<PptxChartSeries>,\n\tsourceIndices: ReadonlyArray<number>,\n\tcatCount: number,\n\tlayout: PlotLayout,\n\trange: ValueRange,\n\tdataLabels: SvgText[],\n): void {\n\tconst barGroupWidth = layout.plotWidth / catCount,\n\t\tseriesCount = Math.max(series.length, 1),\n\t\tsingleBarWidth = (barGroupWidth * 0.7) / seriesCount,\n\t\tgroupOffset = (barGroupWidth - singleBarWidth * seriesCount) / 2;\n\n\tfor (let ci = 0; ci < catCount; ci++) {\n\t\tconst sourceIndex = sourceIndices[ci] ?? ci;\n\t\tfor (let si = 0; si < series.length; si++) {\n\t\t\tconst val = series[si].values[sourceIndex] ?? 0,\n\t\t\t\tbarX = layout.plotLeft + barGroupWidth * ci + groupOffset + singleBarWidth * si,\n\t\t\t\tzeroY = valueToY(0, range, layout.plotTop, layout.plotBottom),\n\t\t\t\tvalY = valueToY(val, range, layout.plotTop, layout.plotBottom),\n\t\t\t\tbarY = Math.min(zeroY, valY),\n\t\t\t\tbarH = Math.max(Math.abs(zeroY - valY), 1),\n\t\t\t\tlabel = buildDataLabelText({\n\t\t\t\t\tchartData,\n\t\t\t\t\tseries: series[si],\n\t\t\t\t\tpointIndex: sourceIndex,\n\t\t\t\t\tvalue: val,\n\t\t\t\t});\n\t\t\tif (label === undefined) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tconst anchor = resolveBarLabelPlacement(\n\t\t\t\tchartData,\n\t\t\t\tseries[si],\n\t\t\t\tsourceIndex,\n\t\t\t\t{ x: barX, y: barY, width: singleBarWidth, height: barH },\n\t\t\t\tval,\n\t\t\t\t'vertical',\n\t\t\t\t{ width: layout.svgWidth, height: layout.svgHeight },\n\t\t\t);\n\t\t\tdataLabels.push({\n\t\t\t\tkind: 'text',\n\t\t\t\tx: anchor.x,\n\t\t\t\ty: anchor.y,\n\t\t\t\ttext: label.text,\n\t\t\t\tfontSize: DEFAULT_CHART_DATA_LABEL_PX,\n\t\t\t\tfill: label.color ?? '#334155',\n\t\t\t\ttextAnchor: anchor.textAnchor,\n\t\t\t\t...(anchor.dominantBaseline ? { dominantBaseline: anchor.dominantBaseline } : {}),\n\t\t\t\t...dataLabelFontOverride(resolveDataLabelTextStyle(chartData, series[si], sourceIndex)),\n\t\t\t});\n\t\t}\n\t}\n}\n","/**\n * chart-cartesian-bars.ts: bar / column plot-primitive builders for the enriched\n * cartesian chart engine (clustered, stacked, percentStacked).\n *\n * Split out of `chart-cartesian-plots.ts` to keep each module within the repo's\n * ~300-LOC limit. Pure helpers consumed by `buildCartesianViewModel`. Clustered\n * bars honour a secondary value range; non-percent stacked reuses the original\n * `computeStackedBarRects` geometry byte-for-byte; percentStacked normalises each\n * category to 100% with in-bar percent labels (matching React).\n *\n * @module chart-cartesian-bars\n */\nimport type { PptxChartData, PptxChartSeries } from 'pptx-viewer-core';\n\nimport { buildPercentStackedBars } from './chart-cartesian-percent-stacked';\nimport type { SeriesPlotResult } from './chart-cartesian-plots';\nimport { pushClusteredStackedLabels } from './chart-cartesian-stacked-labels';\nimport { findPointLabel, resolveBarLabelPlacement } from './chart-data-label-anchor';\nimport { buildDataLabelDecorations, calloutLabelLift } from './chart-data-label-callout';\nimport {\n\tbuildDataLabelText,\n\tdataLabelFontOverride,\n\tresolveDataLabelTextStyle,\n} from './chart-data-label-text';\nimport { resolveDataPointFill, resolveVaryColorFill } from './chart-datapoint-style';\nimport { DEFAULT_CHART_DATA_LABEL_PX } from './chart-font';\nimport type { PlotLayout, SvgPrimitive, SvgRect, SvgText, ValueRange } from './chart-view-model';\nimport {\n\tbuildMarkTooltip,\n\tcomputeStackedBarRects,\n\tpaletteColor,\n\tseriesColor,\n\tvalueToY,\n} from './chart-view-model';\n\n/**\n * Blend a `#RRGGBB` colour halfway toward white. Returns the input unchanged\n * when it is not a parseable 6-digit hex (e.g. a named colour or gradient ref).\n */\nfunction blendToWhite(color: string): string {\n\tconst match = /^#?([0-9a-f]{6})$/iu.exec(color.trim());\n\tif (!match) {\n\t\treturn color;\n\t}\n\t// eslint-disable-next-line one-var -- pre-existing, unrelated to this change\n\tconst value = Number.parseInt(match[1], 16),\n\t\tmix = (channel: number): number => Math.round(channel + (255 - channel) * 0.5),\n\t\tr = mix((value >> 16) & 0xff),\n\t\tg = mix((value >> 8) & 0xff),\n\t\tb = mix(value & 0xff);\n\treturn `#${((r << 16) | (g << 8) | b).toString(16).padStart(6, '0').toUpperCase()}`;\n}\n\n/**\n * Apply PowerPoint's `c:invertIfNegative` treatment to a bar fill: when the\n * point value is negative and invert-if-negative is set (a per-point `c:dPt`\n * override wins over the series-level flag), the bar is drawn in a lightened\n * fill. Convention: a 50% blend of the base fill toward white. PowerPoint has no\n * single canonical inverted colour; a lightened same-hue fill echoes its default\n * \"hollow\" appearance and is deterministic across bindings.\n */\nfunction invertNegativeFill(\n\tseries: PptxChartSeries,\n\tpointIndex: number,\n\tvalue: number,\n\tbaseFill: string,\n): string {\n\tif (value >= 0) {\n\t\treturn baseFill;\n\t}\n\tconst point = series.dataPoints?.find((p) => p.idx === pointIndex),\n\t\tinvert = point?.invertIfNegative ?? series.invertIfNegative ?? false;\n\treturn invert ? blendToWhite(baseFill) : baseFill;\n}\n\n/**\n * Bar primitives for clustered / stacked / percentStacked, honouring a secondary\n * value range for secondary-mapped series (clustered only). Returns rects + data\n * labels. Mirrors React's `renderDefaultBarChart` / `renderStackedBarChart`.\n */\nexport function buildBars(\n\tchartData: PptxChartData,\n\tcatCount: number,\n\tlayout: PlotLayout,\n\tprimaryRange: ValueRange,\n\tsecondaryRange: ValueRange | undefined,\n\tsecondaryIdx: ReadonlySet<number>,\n\tgrouping: 'clustered' | 'stacked' | 'percentStacked',\n\tsourceIndices: ReadonlyArray<number>,\n): SeriesPlotResult {\n\tconst primitives: SvgPrimitive[] = [],\n\t\tdataLabels: SvgText[] = [],\n\t\tlabelBoxes: SvgPrimitive[] = [],\n\t\tseries = chartData.series,\n\t\tpalette = chartData.colorPalette,\n\t\tshowLabels = chartData.style?.hasDataLabels,\n\t\t// Single-series bar/column with c:varyColors=1 gives every category a distinct\n\t\t// palette colour (a per-point c:dPt fill still wins). Multi-series charts keep\n\t\t// their per-series colours (varyColors has no cross-series meaning there).\n\t\tvaryColorsSingle = chartData.varyColors === true && series.length === 1;\n\n\tif (grouping === 'clustered') {\n\t\tconst seriesCount = Math.max(series.length, 1),\n\t\t\tbarGroupWidth = layout.plotWidth / Math.max(catCount, 1),\n\t\t\t// Honour c:overlap (% overlap between adjacent series). overlap=0 reproduces\n\t\t\t// the original side-by-side layout exactly. Read before singleBarWidth: a\n\t\t\t// gapWidth-based bar width must size itself so the OVERLAPPED cluster (not\n\t\t\t// seriesCount side-by-side bars) fills the gap-reduced group width; see the\n\t\t\t// comment below.\n\t\t\toverlap = chartData.barOverlap ?? 0,\n\t\t\t// Honour c:gapWidth (gap between clusters, % of a bar width) when parsed;\n\t\t\t// otherwise keep the legacy 0.7-of-group heuristic byte-for-byte.\n\t\t\t//\n\t\t\t// COM-verified ground truth (PowerPoint Object 16, single category, six\n\t\t\t// series, gapWidth=5, overlap=23): dividing by seriesCount alone (the\n\t\t\t// pre-existing formula) sizes every bar as if the cluster were laid out\n\t\t\t// SIDE BY SIDE, then shrinks it further by overlap when computing `step`\n\t\t\t// below - so at high overlap the bars render far too NARROW (in the\n\t\t\t// limit, overlap=100 should make every bar in a cluster the same width\n\t\t\t// as a single-series bar, independent of seriesCount, since they fully\n\t\t\t// coincide; the old formula kept shrinking by 1/seriesCount regardless).\n\t\t\t// `overlapSpan` is how many bar-widths wide the OVERLAPPED cluster spans;\n\t\t\t// `clusterWidth` below re-derives the same relationship from `step`.\n\t\t\toverlapSpan = 1 + (seriesCount - 1) * (1 - overlap / 100),\n\t\t\t// COM-verified ground truth (PowerPoint's own Office-default 3-series\n\t\t\t// clustered column chart, gapWidth=219, overlap=-27, four categories):\n\t\t\t// the rendered bar is 17.6% of the category pitch. ECMA-376's own wording\n\t\t\t// for c:gapWidth is \"the amount of space between bar or column clusters,\n\t\t\t// AS A PERCENTAGE OF THE BAR OR COLUMN WIDTH\" - i.e. the gap between\n\t\t\t// clusters is `gapWidth% * singleBarWidth`, not a percentage of the pitch\n\t\t\t// or of the cluster width. So `pitch = clusterWidth + gap = barWidth *\n\t\t\t// overlapSpan + barWidth * gapWidth / 100 = barWidth * (overlapSpan +\n\t\t\t// gapWidth / 100)`. The previous formula divided the gap-shrunk group\n\t\t\t// width by `overlapSpan` (`pitch / ((1 + gapWidth / 100) * overlapSpan)`),\n\t\t\t// which treats the gap as a percentage of the PITCH and then shrinks the\n\t\t\t// cluster a second time, rendering every bar roughly half its correct\n\t\t\t// width whenever gapWidth and overlap are both non-trivial (this fixture:\n\t\t\t// 8.9% computed vs. 17.6% measured). Single-series charts are unaffected:\n\t\t\t// `overlapSpan` is 1 regardless of `overlap`, so both formulas agree.\n\t\t\tsingleBarWidth =\n\t\t\t\tchartData.barGapWidth !== undefined\n\t\t\t\t\t? barGroupWidth / (overlapSpan + Math.max(chartData.barGapWidth, 0) / 100)\n\t\t\t\t\t: (barGroupWidth * 0.7) / seriesCount,\n\t\t\tstep = singleBarWidth * (1 - overlap / 100),\n\t\t\tclusterWidth = singleBarWidth + step * (seriesCount - 1),\n\t\t\tgroupOffset = (barGroupWidth - clusterWidth) / 2;\n\n\t\tfor (let displayIndex = 0; displayIndex < catCount; displayIndex++) {\n\t\t\tconst sourceIndex = sourceIndices[displayIndex] ?? displayIndex;\n\t\t\tfor (let si = 0; si < series.length; si++) {\n\t\t\t\tconst val = series[si].values[sourceIndex] ?? 0,\n\t\t\t\t\tx = layout.plotLeft + barGroupWidth * displayIndex + groupOffset + step * si,\n\t\t\t\t\tactiveRange = secondaryIdx.has(si) && secondaryRange ? secondaryRange : primaryRange,\n\t\t\t\t\tzeroY = valueToY(0, activeRange, layout.plotTop, layout.plotBottom),\n\t\t\t\t\tvalY = valueToY(val, activeRange, layout.plotTop, layout.plotBottom),\n\t\t\t\t\ty = Math.min(zeroY, valY),\n\t\t\t\t\th = Math.max(Math.abs(zeroY - valY), 1),\n\t\t\t\t\tbaseFill = varyColorsSingle\n\t\t\t\t\t\t? resolveVaryColorFill(series[si], sourceIndex, paletteColor(sourceIndex, palette))\n\t\t\t\t\t\t: (resolveDataPointFill(series[si], sourceIndex, paletteColor(si, palette)) ??\n\t\t\t\t\t\t\tseriesColor(series[si], si, palette));\n\t\t\t\tprimitives.push({\n\t\t\t\t\tkind: 'rect',\n\t\t\t\t\tx,\n\t\t\t\t\ty,\n\t\t\t\t\tw: singleBarWidth,\n\t\t\t\t\th,\n\t\t\t\t\tfill: invertNegativeFill(series[si], sourceIndex, val, baseFill),\n\t\t\t\t\trx: 1,\n\t\t\t\t\tpart: { role: 'dataPoint', seriesIndex: si, pointIndex: sourceIndex },\n\t\t\t\t\ttitle: buildMarkTooltip(\n\t\t\t\t\t\tseries[si].name,\n\t\t\t\t\t\tchartData.categories[sourceIndex],\n\t\t\t\t\t\tval,\n\t\t\t\t\t\tseries[si].numberFormat,\n\t\t\t\t\t),\n\t\t\t\t} satisfies SvgRect);\n\n\t\t\t\tif (showLabels) {\n\t\t\t\t\t// c:showVal / c:showCatName / c:showPercent decide what the label\n\t\t\t\t\t// says; the historical raw value is what you get when nothing does.\n\t\t\t\t\tconst label = buildDataLabelText({\n\t\t\t\t\t\tchartData,\n\t\t\t\t\t\tseries: series[si],\n\t\t\t\t\t\tpointIndex: sourceIndex,\n\t\t\t\t\t\tvalue: val,\n\t\t\t\t\t});\n\t\t\t\t\tif (label !== undefined) {\n\t\t\t\t\t\t// c:dLblPos (ctr/inBase/inEnd/outEnd) decides where on the bar the\n\t\t\t\t\t\t// label sits; a per-point c:dLbl/c:layout drag shifts it further.\n\t\t\t\t\t\tconst anchor = resolveBarLabelPlacement(\n\t\t\t\t\t\t\tchartData,\n\t\t\t\t\t\t\tseries[si],\n\t\t\t\t\t\t\tsourceIndex,\n\t\t\t\t\t\t\t{ x, y, width: singleBarWidth, height: h },\n\t\t\t\t\t\t\tval,\n\t\t\t\t\t\t\t'vertical',\n\t\t\t\t\t\t\t{ width: layout.svgWidth, height: layout.svgHeight },\n\t\t\t\t\t\t);\n\t\t\t\t\t\tconst moved = Boolean(findPointLabel(series[si], sourceIndex)?.layout);\n\t\t\t\t\t\tconst lift = calloutLabelLift(\n\t\t\t\t\t\t\tchartData,\n\t\t\t\t\t\t\tseries[si],\n\t\t\t\t\t\t\tDEFAULT_CHART_DATA_LABEL_PX,\n\t\t\t\t\t\t\tmoved,\n\t\t\t\t\t\t);\n\t\t\t\t\t\tconst text: SvgText = {\n\t\t\t\t\t\t\tkind: 'text',\n\t\t\t\t\t\t\tx: anchor.x,\n\t\t\t\t\t\t\ty: anchor.y - lift,\n\t\t\t\t\t\t\ttext: label.text,\n\t\t\t\t\t\t\tfontSize: DEFAULT_CHART_DATA_LABEL_PX,\n\t\t\t\t\t\t\tfill: label.color ?? '#334155',\n\t\t\t\t\t\t\ttextAnchor: anchor.textAnchor,\n\t\t\t\t\t\t\t...(anchor.dominantBaseline ? { dominantBaseline: anchor.dominantBaseline } : {}),\n\t\t\t\t\t\t\t...dataLabelFontOverride(\n\t\t\t\t\t\t\t\tresolveDataLabelTextStyle(chartData, series[si], sourceIndex),\n\t\t\t\t\t\t\t),\n\t\t\t\t\t\t};\n\t\t\t\t\t\tdataLabels.push(text);\n\t\t\t\t\t\t// Label box / callout pointer / leader line (chart-data-label-callout).\n\t\t\t\t\t\tlabelBoxes.push(\n\t\t\t\t\t\t\t...buildDataLabelDecorations(\n\t\t\t\t\t\t\t\tchartData,\n\t\t\t\t\t\t\t\tseries[si],\n\t\t\t\t\t\t\t\ttext,\n\t\t\t\t\t\t\t\t{ x: x + singleBarWidth / 2, y: val >= 0 ? y : y + h },\n\t\t\t\t\t\t\t\tmoved,\n\t\t\t\t\t\t\t),\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn { primitives: [...primitives, ...labelBoxes], dataLabels };\n\t}\n\n\t// Non-percent stacked: preserve the original `computeStackedBarRects` geometry\n\t// byte-for-byte (bar width 0.7, running from the zero line), with the original\n\t// abs-value data labels. Only percentStacked uses the normalised running-sum\n\t// path below (matching React's `renderStackedBarChart`).\n\tif (grouping === 'stacked') {\n\t\tconst displaySeries = series.map((entry) => ({\n\t\t\t\t...entry,\n\t\t\t\tvalues: sourceIndices.map((sourceIndex) => entry.values[sourceIndex] ?? 0),\n\t\t\t})),\n\t\t\trects = computeStackedBarRects(displaySeries, catCount, layout, primaryRange, palette);\n\t\tfor (const r of rects) {\n\t\t\tlet fill = r.fill,\n\t\t\t\tpart: SvgRect['part'],\n\t\t\t\ttitle: string | undefined;\n\t\t\tif (r.seriesIndex !== undefined && r.pointIndex !== undefined) {\n\t\t\t\tconst sourcePointIndex = sourceIndices[r.pointIndex] ?? r.pointIndex;\n\t\t\t\tfill = resolveDataPointFill(series[r.seriesIndex], sourcePointIndex, r.fill) ?? r.fill;\n\t\t\t\t// eslint-disable-next-line one-var -- pre-existing, unrelated to this change\n\t\t\t\tconst value = series[r.seriesIndex].values[sourcePointIndex] ?? 0;\n\t\t\t\tfill = invertNegativeFill(series[r.seriesIndex], sourcePointIndex, value, fill);\n\t\t\t\tpart = { role: 'dataPoint', seriesIndex: r.seriesIndex, pointIndex: sourcePointIndex };\n\t\t\t\ttitle = buildMarkTooltip(\n\t\t\t\t\tseries[r.seriesIndex].name,\n\t\t\t\t\tchartData.categories[sourcePointIndex],\n\t\t\t\t\tvalue,\n\t\t\t\t\tseries[r.seriesIndex].numberFormat,\n\t\t\t\t);\n\t\t\t}\n\t\t\tprimitives.push({ kind: 'rect', x: r.x, y: r.y, w: r.w, h: r.h, fill, rx: 1, part, title });\n\t\t}\n\t\tif (showLabels) {\n\t\t\tpushClusteredStackedLabels(\n\t\t\t\tchartData,\n\t\t\t\tseries,\n\t\t\t\tsourceIndices,\n\t\t\t\tcatCount,\n\t\t\t\tlayout,\n\t\t\t\tprimaryRange,\n\t\t\t\tdataLabels,\n\t\t\t);\n\t\t}\n\t\treturn { primitives, dataLabels };\n\t}\n\n\t// percentStacked: normalise each category to 100% with in-bar percent labels.\n\t// Split into its own module (`chart-cartesian-percent-stacked.ts`) to keep\n\t// this file within the repo's ~300-LOC limit; `invertNegativeFill` is\n\t// injected since it is this file's own helper.\n\treturn buildPercentStackedBars(\n\t\tchartData,\n\t\tcatCount,\n\t\tlayout,\n\t\tprimaryRange,\n\t\tsourceIndices,\n\t\tinvertNegativeFill,\n\t);\n}\n","/**\n * chart-cartesian-bubbles.ts: bubble-chart plot-primitive builder, split out\n * of `chart-cartesian-plots.ts` (which still owns `buildScatter` and the\n * shared XY plumbing this file imports) to keep each module within the\n * repo's ~300-LOC limit.\n *\n * @module chart-cartesian-bubbles\n */\nimport type { PptxChartData } from 'pptx-viewer-core';\n\nimport { elementFrame, xyMarkTooltip } from './chart-cartesian-plots';\nimport type { SeriesPlotResult } from './chart-cartesian-plots';\nimport { resolveMarkerLabelPlacement } from './chart-data-label-anchor';\nimport { pushPointLabel } from './chart-data-label-callout';\nimport {\n\tbuildDataLabelText,\n\tdataLabelFontOverride,\n\tresolveDataLabelTextStyle,\n} from './chart-data-label-text';\nimport { resolveDataPointFill } from './chart-datapoint-style';\nimport { DEFAULT_CHART_DATA_LABEL_PX } from './chart-font';\nimport { buildScatterXAxisPlan } from './chart-scatter-x-axis';\nimport type { PlotLayout, SvgCircle, SvgPrimitive, SvgText, ValueRange } from './chart-view-model';\nimport {\n\tcomputeBubbleRadius,\n\tcomputeScatterDots,\n\tformatAxisValue,\n\tseriesColor,\n\tseriesXValues,\n} from './chart-view-model';\n\n/**\n * Build bubble-chart primitives.\n *\n * Every series carries its own `c:xVal`, `c:yVal` AND `c:bubbleSize`, so each\n * one is a complete bubble series. The engine used to read sizes off \"the third\n * series\", which drew equal-sized dots for the ordinary one-series bubble chart\n * and silently deleted every series past the second from a three-series one.\n *\n * Honours `c:bubbleChart`'s three display options (`chartData.bubbleOptions`):\n * `bubbleScale` (a percent multiplier on the whole size envelope), `sizeRepresents`\n * (`'area'`, ECMA-376's own default: radius scales with the square root of the\n * value so the bubble's AREA tracks it; `'w'`: radius scales linearly with the\n * value), and `showNegativeBubbles` (default false: a negative-size point is not\n * plotted at all, matching PowerPoint, rather than floored to zero).\n */\nexport function buildBubbles(\n\tchartData: PptxChartData,\n\tlayout: PlotLayout,\n\trange: ValueRange,\n): SeriesPlotResult {\n\tconst primitives: SvgPrimitive[] = [],\n\t\tdataLabels: SvgText[] = [],\n\t\tlabelBoxes: SvgPrimitive[] = [],\n\t\tshowLabels = chartData.style?.hasDataLabels,\n\t\tallIndices = chartData.series.flatMap((s) => s.values.map((_, i) => i)),\n\t\tmaxXIndex = Math.max(1, ...allIndices),\n\t\tperSeriesX = chartData.series.map((series) => seriesXValues(chartData, series)),\n\t\t// The chart's own nice-scaled X axis (see `chart-scatter-x-axis.ts`), not\n\t\t// the raw data's tight min/max: sharing this domain with the drawn\n\t\t// gridlines keeps every bubble aligned with them, and the axis's own\n\t\t// headroom/rounding is what keeps an edge bubble from being clipped by\n\t\t// the plot boundary.\n\t\txDomain = buildScatterXAxisPlan(chartData, layout).range,\n\t\t// One size scale for the whole chart, so bubbles stay comparable across series.\n\t\tallSizes = chartData.series.flatMap((series) => series.bubbleSizes ?? []),\n\t\tmaxBubble = allSizes.length > 0 ? Math.max(1, ...allSizes.map(Math.abs)) : 1,\n\t\tmedianRadius = Math.min(layout.plotWidth, layout.plotHeight) * 0.04,\n\t\t// c:bubbleScale/c:sizeRepresents/c:showNegBubbles: PowerPoint's own\n\t\t// defaults (100%, area-proportional, negative bubbles hidden) apply even\n\t\t// when the chart authors none of the three `c:bubbleChart` elements.\n\t\tradiusOptions = {\n\t\t\tbubbleScale: chartData.bubbleOptions?.bubbleScale,\n\t\t\tsizeRepresents: chartData.bubbleOptions?.sizeRepresents ?? ('area' as const),\n\t\t},\n\t\tshowNegativeBubbles = chartData.bubbleOptions?.showNegativeBubbles === true;\n\n\tfor (let si = 0; si < chartData.series.length; si++) {\n\t\tconst series = chartData.series[si],\n\t\t\tc = seriesColor(series, si, chartData.colorPalette),\n\t\t\tdots = computeScatterDots(series.values, maxXIndex, layout, range, perSeriesX[si], xDomain);\n\t\tdots.forEach((dot, vi) => {\n\t\t\tconst size = series.bubbleSizes?.[vi];\n\t\t\tif (size !== undefined && size < 0 && !showNegativeBubbles) {\n\t\t\t\t// c:showNegBubbles default false: PowerPoint does not plot a\n\t\t\t\t// negative-size bubble at all, it does not floor it to zero.\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tconst r = computeBubbleRadius(size, maxBubble, medianRadius, radiusOptions),\n\t\t\t\tlabel =\n\t\t\t\t\tsize !== undefined\n\t\t\t\t\t\t? `${xyMarkTooltip(series.name, perSeriesX[si]?.[vi], series.values[vi] ?? 0, series.numberFormat)}, size ${formatAxisValue(size)}`\n\t\t\t\t\t\t: xyMarkTooltip(\n\t\t\t\t\t\t\t\tseries.name,\n\t\t\t\t\t\t\t\tperSeriesX[si]?.[vi],\n\t\t\t\t\t\t\t\tseries.values[vi] ?? 0,\n\t\t\t\t\t\t\t\tseries.numberFormat,\n\t\t\t\t\t\t\t);\n\t\t\tprimitives.push({\n\t\t\t\tkind: 'circle',\n\t\t\t\tcx: dot.cx,\n\t\t\t\tcy: dot.cy,\n\t\t\t\tr,\n\t\t\t\tfill: resolveDataPointFill(series, vi, c) ?? c,\n\t\t\t\topacity: 0.6,\n\t\t\t\tpart: { role: 'dataPoint', seriesIndex: si, pointIndex: vi },\n\t\t\t\ttitle: label,\n\t\t\t} satisfies SvgCircle);\n\t\t});\n\t\tif (showLabels) {\n\t\t\tseries.values.forEach((val, vi) => {\n\t\t\t\tconst dot = dots[vi],\n\t\t\t\t\tsize = series.bubbleSizes?.[vi];\n\t\t\t\tif (size !== undefined && size < 0 && !showNegativeBubbles) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tconst label = buildDataLabelText({ chartData, series, pointIndex: vi, value: val });\n\t\t\t\tif (!dot || label === undefined) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\t// Right of the bubble's EDGE when no c:dLblPos is authored (COM,\n\t\t\t\t// callouts-com.pptx); the callout / leader line points at its centre.\n\t\t\t\tconst target = { x: dot.cx, y: dot.cy },\n\t\t\t\t\tr = computeBubbleRadius(size, maxBubble, medianRadius, radiusOptions),\n\t\t\t\t\tanchor = resolveMarkerLabelPlacement(\n\t\t\t\t\t\tchartData,\n\t\t\t\t\t\tseries,\n\t\t\t\t\t\tvi,\n\t\t\t\t\t\ttarget,\n\t\t\t\t\t\telementFrame(layout),\n\t\t\t\t\t\tr + 3,\n\t\t\t\t\t\t'r',\n\t\t\t\t\t);\n\t\t\t\tpushPointLabel(dataLabels, labelBoxes, chartData, series, vi, target, {\n\t\t\t\t\tkind: 'text',\n\t\t\t\t\tx: anchor.x,\n\t\t\t\t\ty: anchor.y,\n\t\t\t\t\ttext: label.text,\n\t\t\t\t\tfontSize: DEFAULT_CHART_DATA_LABEL_PX,\n\t\t\t\t\tfill: label.color ?? '#334155',\n\t\t\t\t\ttextAnchor: anchor.textAnchor,\n\t\t\t\t\t...(anchor.dominantBaseline ? { dominantBaseline: anchor.dominantBaseline } : {}),\n\t\t\t\t\t...dataLabelFontOverride(resolveDataLabelTextStyle(chartData, series, vi)),\n\t\t\t\t});\n\t\t\t});\n\t\t}\n\t}\n\treturn { primitives: [...primitives, ...labelBoxes], dataLabels };\n}\n","/**\n * chart-cartesian-line-area.ts: line and area plot-primitive builders for the\n * enriched cartesian chart engine, including stacked / percentStacked\n * geometry.\n *\n * Split out of `chart-cartesian-plots.ts` to keep each module within the\n * repo's ~300-LOC limit. Pure helpers consumed by `buildCartesianViewModel`;\n * they reuse the geometry primitives in `chart-view-model.ts`, the running-sum\n * math in `chart-stacked-series.ts`, and `pushMarker` from\n * `chart-cartesian-plots.ts` (shared with scatter).\n *\n * @module chart-cartesian-line-area\n */\nimport type { PptxChartData } from 'pptx-viewer-core';\n\nimport { resolveBlankDisplay, visibleRuns } from './chart-blank-display';\nimport { pushMarker } from './chart-cartesian-plots';\nimport type { SeriesPlotResult } from './chart-cartesian-plots';\nimport { resolveMarkerLabelPlacement } from './chart-data-label-anchor';\nimport { pushPointLabel } from './chart-data-label-callout';\nimport {\n\tbuildDataLabelText,\n\tdataLabelFontOverride,\n\tresolveDataLabelTextStyle,\n} from './chart-data-label-text';\nimport { resolveDataPointFill } from './chart-datapoint-style';\nimport { DEFAULT_CHART_DATA_LABEL_PX } from './chart-font';\nimport { smoothLinePath } from './chart-line-path';\nimport { computeStackedSeriesPlots } from './chart-stacked-series';\nimport type { LineAreaStacking } from './chart-stacked-series';\nimport { resolveChartStyleDefaults } from './chart-style-defaults';\nimport type {\n\tChartPartRef,\n\tPlotLayout,\n\tSvgPath,\n\tSvgPolyline,\n\tSvgPrimitive,\n\tSvgText,\n\tValueRange,\n} from './chart-view-model';\nimport {\n\tbuildMarkTooltip,\n\tcomputeLinePoints,\n\tlinePointsToSvgString,\n\tseriesColor,\n} from './chart-view-model';\n\n/** PowerPoint's own default line-chart series stroke width when nothing overrides it. */\nconst DEFAULT_LINE_STROKE_WIDTH = 2.4;\n\n/**\n * Build line-chart primitives, honouring a secondary value range per series\n * (clustered only: `stacking !== 'clustered'` always plots against\n * `primaryRange`, matching `isStacked` disabling the secondary-axis split in\n * chart-cartesian.ts).\n *\n * Stacked/percentStacked plots each series at its running-sum height (each\n * line sits on top of the ones below it, so the top-most line traces the\n * category total), computed from every series' own blank-resolved values via\n * `computeStackedSeriesPlots`. Data labels and marker tooltips still read the\n * series' own value (or percent share), not the cumulative height it is\n * plotted at, mirroring stacked bar's label convention.\n */\nexport function buildLines(\n\tchartData: PptxChartData,\n\tcatCount: number,\n\tlayout: PlotLayout,\n\tprimaryRange: ValueRange,\n\tsecondaryRange: ValueRange | undefined,\n\tsecondaryIdx: ReadonlySet<number>,\n\tsourceIndices: ReadonlyArray<number>,\n\txPositions?: ReadonlyArray<number>,\n\tstacking: LineAreaStacking = 'clustered',\n): SeriesPlotResult {\n\tconst primitives: SvgPrimitive[] = [],\n\t\tdataLabels: SvgText[] = [],\n\t\tlabelBoxes: SvgPrimitive[] = [],\n\t\t// C2 wave-1 skip: the chart-style number (`c:style`/`c14:style`) drives\n\t\t// the default series line width via its `cs:dataPointLine`/`cs:dataPoint`\n\t\t// entry when one is directly authored; falls back to the historical\n\t\t// fixed default so an untouched chart with no style part renders\n\t\t// byte-identical.\n\t\tlineStrokeWidth =\n\t\t\tresolveChartStyleDefaults(chartData).seriesLineWidthPt ?? DEFAULT_LINE_STROKE_WIDTH,\n\t\tshowLabels = chartData.style?.hasDataLabels,\n\t\tisStackedMode = stacking !== 'clustered',\n\t\tisPercent = stacking === 'percentStacked',\n\t\t// Resolve every series' own (blank-handled) values first: stacking needs\n\t\t// all of them at once to compute the running sums.\n\t\tresolved = chartData.series.map((series) => {\n\t\t\tif (series.values.length === 0) {\n\t\t\t\treturn undefined;\n\t\t\t}\n\t\t\tconst rawValues = sourceIndices.map((sourceIndex) => series.values[sourceIndex] ?? 0),\n\t\t\t\tdisplayBlanks = sourceIndices.map((sourceIndex) => series.blanks?.[sourceIndex] ?? false),\n\t\t\t\t// Honour c:dispBlanksAs: gap breaks the line at blanks, span interpolates,\n\t\t\t\t// zero/unset keep the placeholder 0 (existing behaviour).\n\t\t\t\t{ values: displayValues, visible } = resolveBlankDisplay(\n\t\t\t\t\trawValues,\n\t\t\t\t\tdisplayBlanks,\n\t\t\t\t\tchartData.chartChrome?.dispBlanksAs,\n\t\t\t\t);\n\t\t\treturn { displayValues, visible };\n\t\t}),\n\t\tstackedPlots = isStackedMode\n\t\t\t? computeStackedSeriesPlots(\n\t\t\t\t\tresolved.map((entry) => entry?.displayValues ?? []),\n\t\t\t\t\tcatCount,\n\t\t\t\t\tisPercent,\n\t\t\t\t)\n\t\t\t: undefined;\n\n\tfor (let si = 0; si < chartData.series.length; si++) {\n\t\tconst series = chartData.series[si],\n\t\t\tentry = resolved[si];\n\t\tif (!entry) {\n\t\t\tcontinue;\n\t\t}\n\t\t// eslint-disable-next-line one-var -- pre-existing, unrelated to this change\n\t\tconst { displayValues, visible } = entry,\n\t\t\tactiveRange = isStackedMode\n\t\t\t\t? primaryRange\n\t\t\t\t: secondaryIdx.has(si) && secondaryRange\n\t\t\t\t\t? secondaryRange\n\t\t\t\t\t: primaryRange,\n\t\t\tplotValues = stackedPlots ? stackedPlots[si].cumulative : displayValues,\n\t\t\tpts = computeLinePoints(plotValues, catCount, layout, activeRange).map((point, index) => ({\n\t\t\t\t...point,\n\t\t\t\tx: xPositions?.[index] ?? point.x,\n\t\t\t})),\n\t\t\tc = seriesColor(series, si, chartData.colorPalette),\n\t\t\t// c:smooth draws a bezier path through the points; otherwise a polyline.\n\t\t\tseriesPart: ChartPartRef = { role: 'series', seriesIndex: si },\n\t\t\tallVisible = visible.every(Boolean);\n\t\tif (allVisible) {\n\t\t\tprimitives.push(\n\t\t\t\tseries.smooth\n\t\t\t\t\t? ({\n\t\t\t\t\t\t\tkind: 'path',\n\t\t\t\t\t\t\td: smoothLinePath(pts),\n\t\t\t\t\t\t\tstroke: c,\n\t\t\t\t\t\t\tstrokeWidth: lineStrokeWidth,\n\t\t\t\t\t\t\tfill: 'none',\n\t\t\t\t\t\t\tpart: seriesPart,\n\t\t\t\t\t\t} satisfies SvgPath)\n\t\t\t\t\t: ({\n\t\t\t\t\t\t\tkind: 'polyline',\n\t\t\t\t\t\t\tpoints: linePointsToSvgString(pts),\n\t\t\t\t\t\t\tstroke: c,\n\t\t\t\t\t\t\tstrokeWidth: lineStrokeWidth,\n\t\t\t\t\t\t\tfill: 'none',\n\t\t\t\t\t\t\tpart: seriesPart,\n\t\t\t\t\t\t} satisfies SvgPolyline),\n\t\t\t);\n\t\t} else {\n\t\t\t// gap mode: draw one polyline per contiguous run of visible points.\n\t\t\tfor (const run of visibleRuns(visible)) {\n\t\t\t\tif (run.length < 2) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tprimitives.push({\n\t\t\t\t\tkind: 'polyline',\n\t\t\t\t\tpoints: linePointsToSvgString(run.map((i) => pts[i])),\n\t\t\t\t\tstroke: c,\n\t\t\t\t\tstrokeWidth: lineStrokeWidth,\n\t\t\t\t\tfill: 'none',\n\t\t\t\t\tpart: seriesPart,\n\t\t\t\t} satisfies SvgPolyline);\n\t\t\t}\n\t\t}\n\t\tpts.forEach((pt, displayIndex) => {\n\t\t\tif (!visible[displayIndex]) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tconst idx = sourceIndices[displayIndex] ?? displayIndex,\n\t\t\t\tpart: ChartPartRef = { role: 'dataPoint', seriesIndex: si, pointIndex: idx };\n\t\t\tpushMarker(\n\t\t\t\tprimitives,\n\t\t\t\tseries,\n\t\t\t\tidx,\n\t\t\t\tpt.x,\n\t\t\t\tpt.y,\n\t\t\t\tresolveDataPointFill(series, idx, c) ?? c,\n\t\t\t\t2.5,\n\t\t\t\tpart,\n\t\t\t\tundefined,\n\t\t\t\tbuildMarkTooltip(\n\t\t\t\t\tseries.name,\n\t\t\t\t\tchartData.categories[idx],\n\t\t\t\t\tseries.values[idx] ?? 0,\n\t\t\t\t\tseries.numberFormat,\n\t\t\t\t),\n\t\t\t);\n\t\t});\n\t\tif (showLabels) {\n\t\t\t// percentStacked reads like the bar case: a plain rounded percent, not\n\t\t\t// routed through c:dLbls content options (showValue/showCategory/...),\n\t\t\t// since the plotted quantity is a derived share, not the raw datum.\n\t\t\tconst labelValues = stackedPlots ? stackedPlots[si].own : displayValues;\n\t\t\tlabelValues.forEach((val, displayIndex) => {\n\t\t\t\tconst pt = pts[displayIndex];\n\t\t\t\tif (!pt || !visible[displayIndex]) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tif (isPercent) {\n\t\t\t\t\tif (val === 0) {\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tdataLabels.push({\n\t\t\t\t\t\tkind: 'text',\n\t\t\t\t\t\tx: pt.x,\n\t\t\t\t\t\ty: pt.y - 7,\n\t\t\t\t\t\ttext: `${Math.round(val)}%`,\n\t\t\t\t\t\tfontSize: DEFAULT_CHART_DATA_LABEL_PX,\n\t\t\t\t\t\tfill: '#334155',\n\t\t\t\t\t\ttextAnchor: 'middle',\n\t\t\t\t\t\t...dataLabelFontOverride(\n\t\t\t\t\t\t\tresolveDataLabelTextStyle(\n\t\t\t\t\t\t\t\tchartData,\n\t\t\t\t\t\t\t\tseries,\n\t\t\t\t\t\t\t\tsourceIndices[displayIndex] ?? displayIndex,\n\t\t\t\t\t\t\t),\n\t\t\t\t\t\t),\n\t\t\t\t\t});\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\t// eslint-disable-next-line one-var -- an early return sits between this const and the previous one\n\t\t\t\tconst pointIndex = sourceIndices[displayIndex] ?? displayIndex,\n\t\t\t\t\tlabel = buildDataLabelText({ chartData, series, pointIndex, value: val });\n\t\t\t\tif (label === undefined) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\t// c:dLblPos (t/b/l/r/ctr) decides where round the marker the label\n\t\t\t\t// sits (right of it when none is authored: COM, callouts-com.pptx);\n\t\t\t\t// a per-point c:dLbl/c:layout drag shifts it further.\n\t\t\t\tconst anchor = resolveMarkerLabelPlacement(\n\t\t\t\t\tchartData,\n\t\t\t\t\tseries,\n\t\t\t\t\tpointIndex,\n\t\t\t\t\tpt,\n\t\t\t\t\t{ width: layout.svgWidth, height: layout.svgHeight },\n\t\t\t\t\t7,\n\t\t\t\t\t'r',\n\t\t\t\t);\n\t\t\t\tpushPointLabel(dataLabels, labelBoxes, chartData, series, pointIndex, pt, {\n\t\t\t\t\tkind: 'text',\n\t\t\t\t\tx: anchor.x,\n\t\t\t\t\ty: anchor.y,\n\t\t\t\t\ttext: label.text,\n\t\t\t\t\tfontSize: DEFAULT_CHART_DATA_LABEL_PX,\n\t\t\t\t\tfill: label.color ?? '#334155',\n\t\t\t\t\ttextAnchor: anchor.textAnchor,\n\t\t\t\t\t...(anchor.dominantBaseline ? { dominantBaseline: anchor.dominantBaseline } : {}),\n\t\t\t\t\t...dataLabelFontOverride(resolveDataLabelTextStyle(chartData, series, pointIndex)),\n\t\t\t\t});\n\t\t\t});\n\t\t}\n\t}\n\treturn { primitives: [...primitives, ...labelBoxes], dataLabels };\n}\n","/**\n * Geometry shared by the chart data table (`c:dTable`) renderer and the plot\n * layout that reserves room for it, so the two can never disagree.\n *\n * COM-verified against charts-com.pptx slide 2: PowerPoint draws the table\n * directly under the plot, its category header row REPLACING the category\n * axis labels, its data columns aligned with the plot's category bands, and\n * the series-key column hanging LEFT of the plot under the value-axis\n * labels. Cell text uses the chart's axis font (12pt in the built-in styles)\n * rather than a fixed 8px.\n *\n * @module chart-data-table-metrics\n */\nimport type { PptxChartData } from 'pptx-viewer-core';\n\nimport { chartFontPx } from './chart-font';\nimport { resolveChartStyleDefaults } from './chart-style-defaults';\n\n/** Resolved data-table geometry. */\nexport interface DataTableMetrics {\n\t/** Cell text size in px. */\n\tfontSize: number;\n\t/** Height of the header row and of each series row. */\n\trowH: number;\n\t/** Width of the series-key column left of the plot (0 without keys). */\n\tkeyW: number;\n\t/** Total table height: header plus one row per series. */\n\theight: number;\n}\n\n/** Resolve the table metrics for `chartData`, or `undefined` without a table. */\nexport function resolveDataTableMetrics(chartData: PptxChartData): DataTableMetrics | undefined {\n\tconst table = chartData.dataTable;\n\tif (!table) {\n\t\treturn undefined;\n\t}\n\tconst fontSize =\n\t\ttable.txPr?.fontSize !== undefined\n\t\t\t? chartFontPx(table.txPr.fontSize)\n\t\t\t: resolveChartStyleDefaults(chartData).bodyTextPx;\n\tconst rowH = Math.max(14, Math.round(fontSize * 1.45));\n\tconst longestName = chartData.series.reduce((m, s) => Math.max(m, (s.name ?? '').length), 0);\n\tconst keyW =\n\t\ttable.showKeys === false ? 0 : Math.min(160, Math.max(40, longestName * fontSize * 0.55 + 24));\n\treturn { fontSize, rowH, keyW, height: rowH * (1 + chartData.series.length) };\n}\n\n/**\n * The category axis labels to draw: none when a data table is shown, since\n * its header row carries the category names in their place.\n */\nexport function labelsBesideTable<T>(chartData: PptxChartData, axis: { labels: T[] }): T[] {\n\treturn chartData.dataTable ? [] : axis.labels;\n}\n","/**\n * chart-data-table-render.ts - SVG primitives for a chart's data table\n * (`c:dTable`), rendered as a grid below the plot area.\n *\n * Laid out the way PowerPoint lays it out (COM-verified, charts-com.pptx\n * slide 2; geometry in `chart-data-table-metrics.ts`): directly under the\n * plot, the category header row standing in for the category axis labels,\n * one data column per plot category band, and the series-key column hanging\n * left of the plot. The table used to start 4px below the plot with its own\n * key column INSIDE the plot width, so its columns drifted off the bars and\n * its header collided with the category labels drawn in the same band.\n *\n * Honours every flag `PptxChartDataTable` carries: `showHorzBorder` /\n * `showVertBorder` / `showOutline` / `showKeys`, plus `spPr` (border stroke\n * colour/width, optional background fill) and `txPr` (cell text colour /\n * font-family / size / bold / italic).\n *\n * @module chart-data-table-render\n */\nimport type { PptxChartData, PptxChartSeries } from 'pptx-viewer-core';\n\nimport { resolveDataTableMetrics } from './chart-data-table-metrics';\nimport type { PlotLayout, SvgLine, SvgPrimitive, SvgText } from './chart-view-model';\nimport { formatAxisValue, seriesColor } from './chart-view-model';\n\n/** Minimum row height; the real height scales with the cell font. */\nexport const DATA_TABLE_ROW_H = 14;\n/** Minimum header-row height. */\nexport const DATA_TABLE_HEADER_H = 14;\n/** Minimum width of the series-key column. */\nexport const DATA_TABLE_KEY_W = 40;\nexport const DATA_TABLE_PADDING = 4;\n/** PowerPoint's built-in table rule colour (tx1 at 15%). */\nconst DEFAULT_BORDER_COLOR = '#D9D9D9';\n/** PowerPoint's built-in chart text colour (tx1 at 65%). */\nconst DEFAULT_TEXT_COLOR = '#595959';\n\n/**\n * Build `SvgPrimitive[]` for the data table below the plot area. Columns =\n * categories; rows = series, with an optional series-key column.\n *\n * @param chartData Full parsed chart data (`dataTable` must be present).\n * @param layout Plot-area bounding box; the table hangs from `plotBottom`.\n * @param colorPalette Optional resolved colour palette (same as chart).\n */\nexport function computeDataTablePrimitives(\n\tchartData: PptxChartData,\n\tlayout: PlotLayout,\n\tcolorPalette?: readonly string[],\n): SvgPrimitive[] {\n\tconst table = chartData.dataTable;\n\tconst metrics = resolveDataTableMetrics(chartData);\n\tconst categories = chartData.categories;\n\tconst series = chartData.series;\n\tif (!table || !metrics || (categories.length === 0 && series.length === 0)) {\n\t\treturn [];\n\t}\n\n\tconst out: SvgPrimitive[] = [];\n\tconst showH = table.showHorzBorder !== false;\n\tconst showV = table.showVertBorder !== false;\n\tconst showO = table.showOutline !== false;\n\tconst showK = table.showKeys !== false;\n\tconst stroke = table.spPr?.strokeColor ?? DEFAULT_BORDER_COLOR;\n\tconst strokeWidth = table.spPr?.strokeWidth ?? 1;\n\tconst text = {\n\t\tfontSize: metrics.fontSize,\n\t\tfill: table.txPr?.color ?? DEFAULT_TEXT_COLOR,\n\t\tfontFamily: table.txPr?.fontFamily,\n\t\tfontStyle: (table.txPr?.italic ? 'italic' : 'normal') as 'italic' | 'normal',\n\t\tfontWeight: (table.txPr?.bold ? 'bold' : 'normal') as 'bold' | 'normal',\n\t\tdominantBaseline: 'central' as const,\n\t};\n\tconst { rowH, keyW } = metrics;\n\tconst catCount = Math.max(categories.length, 1);\n\tconst cellW = layout.plotWidth / catCount;\n\tconst top = layout.plotBottom;\n\tconst bottom = top + metrics.height;\n\tconst left = layout.plotLeft - keyW;\n\tconst right = layout.plotLeft + layout.plotWidth;\n\tconst line = (x1: number, y1: number, x2: number, y2: number): SvgLine => ({\n\t\tkind: 'line',\n\t\tx1,\n\t\ty1,\n\t\tx2,\n\t\ty2,\n\t\tstroke,\n\t\tstrokeWidth,\n\t});\n\tconst label = (x: number, y: number, value: string, anchor: 'start' | 'middle'): SvgText => ({\n\t\tkind: 'text',\n\t\tx,\n\t\ty,\n\t\ttext: value,\n\t\ttextAnchor: anchor,\n\t\t...text,\n\t});\n\n\tif (table.spPr?.fillColor) {\n\t\tout.push({\n\t\t\tkind: 'rect',\n\t\t\tx: left,\n\t\t\ty: top,\n\t\t\tw: right - left,\n\t\t\th: bottom - top,\n\t\t\tfill: table.spPr.fillColor,\n\t\t});\n\t}\n\tif (showO) {\n\t\t// The header row spans the data columns only; the key column starts\n\t\t// under it, exactly as PowerPoint frames the table.\n\t\tout.push(line(layout.plotLeft, top, right, top));\n\t\tout.push(line(right, top, right, bottom));\n\t\tout.push(line(right, bottom, left, bottom));\n\t\tout.push(line(left, bottom, left, top + rowH));\n\t\tout.push(line(left, top + rowH, layout.plotLeft, top + rowH));\n\t\tout.push(line(layout.plotLeft, top, layout.plotLeft, top + rowH));\n\t}\n\n\tcategories.forEach((cat, ci) => {\n\t\tout.push(label(layout.plotLeft + ci * cellW + cellW / 2, top + rowH / 2, cat, 'middle'));\n\t\tif (showV && ci > 0) {\n\t\t\tconst x = layout.plotLeft + ci * cellW;\n\t\t\tout.push(line(x, top, x, bottom));\n\t\t}\n\t});\n\tif (showV && showK) {\n\t\tout.push(line(layout.plotLeft, top, layout.plotLeft, bottom));\n\t}\n\n\tseries.forEach((s: PptxChartSeries, si: number) => {\n\t\tconst rowTop = top + rowH * (si + 1);\n\t\tconst cy = rowTop + rowH / 2;\n\t\tif (showH) {\n\t\t\tout.push(line(showK ? left : layout.plotLeft, rowTop, right, rowTop));\n\t\t}\n\t\tif (showK) {\n\t\t\tconst swatch = Math.max(6, Math.round(metrics.fontSize * 0.55));\n\t\t\tout.push({\n\t\t\t\tkind: 'rect',\n\t\t\t\tx: left + DATA_TABLE_PADDING,\n\t\t\t\ty: cy - swatch / 2,\n\t\t\t\tw: swatch,\n\t\t\t\th: swatch,\n\t\t\t\tfill: seriesColor(s, si, colorPalette),\n\t\t\t});\n\t\t\tout.push(label(left + DATA_TABLE_PADDING + swatch + 3, cy, s.name, 'start'));\n\t\t}\n\t\tcategories.forEach((_cat, ci) => {\n\t\t\tconst val = s.values[ci];\n\t\t\tconst x = layout.plotLeft + ci * cellW + cellW / 2;\n\t\t\tout.push(label(x, cy, val !== undefined ? formatAxisValue(val) : '', 'middle'));\n\t\t});\n\t});\n\n\treturn out;\n}\n","/**\n * chart-helper-lines.ts: shared drop-line / hi-low-line / up-down-bar primitives.\n *\n * OOXML line and stock charts may declare `c:dropLines`, `c:hiLowLines`, and\n * `c:upDownBars` on the chart-type container. Historically these rendered only\n * in the React chart chrome (drop/hi-low), and up-down bars nowhere, so the\n * framework-agnostic view-model (Vue / Angular / Vanilla / Svelte) never drew\n * them. These pure builders project each into `SvgPrimitive[]` so every binding\n * renders them from a single source.\n *\n * dropLines - a vertical line from each data point down to the axis baseline.\n * hiLowLines - a vertical line spanning the highest and lowest series value\n * in each category (requires >= 2 series).\n * upDownBars - a bar between the first and last series value in each category,\n * coloured by whether the last value rose or fell (>= 2 series).\n *\n * @module chart-helper-lines\n */\n\nimport type { PptxChartData } from 'pptx-viewer-core';\n\nimport type { PlotLayout, SvgLine, SvgRect, ValueRange } from './chart-view-model';\nimport { valueToY } from './chart-view-model';\n\n/** Placement context shared by the helper-line builders. */\nexport interface HelperLineOptions {\n\t/** `'bar'` centres on category slots; `'line'` anchors at data points. */\n\tmode: 'line' | 'bar';\n\t/** Pre-computed per-category X positions (from the horizontal-axis builder). */\n\txPositions?: ReadonlyArray<number>;\n}\n\n/** X pixel for a category index, preferring an explicit x-position. */\nfunction categoryX(\n\tindex: number,\n\tcatCount: number,\n\tlayout: PlotLayout,\n\toptions: HelperLineOptions,\n): number {\n\tconst explicit = options.xPositions?.[index];\n\tif (explicit !== undefined) {\n\t\treturn explicit;\n\t}\n\tif (options.mode === 'bar') {\n\t\tconst slot = layout.plotWidth / Math.max(catCount, 1);\n\t\treturn layout.plotLeft + slot * index + slot / 2;\n\t}\n\tconst maxIdx = Math.max(catCount - 1, 1);\n\treturn layout.plotLeft + (index / maxIdx) * layout.plotWidth;\n}\n\n/** SVG dash pattern for a helper-line dash style, if any. */\nfunction dashFor(dashStyle: string | undefined): string | undefined {\n\tif (!dashStyle || dashStyle === 'solid') {\n\t\treturn undefined;\n\t}\n\treturn dashStyle === 'dot' || dashStyle === 'sysDot' ? '1 2' : '4 3';\n}\n\n/**\n * Drop lines: a vertical line from every data point down to the value-axis\n * baseline (`range.min`). Returns `[]` when `c:dropLines` is absent.\n */\nexport function computeDropLinePrimitives(\n\tchartData: PptxChartData,\n\tlayout: PlotLayout,\n\trange: ValueRange,\n\tcatCount: number,\n\toptions: HelperLineOptions,\n): SvgLine[] {\n\tconst style = chartData.dropLines;\n\tif (!style) {\n\t\treturn [];\n\t}\n\tconst baselineY = valueToY(range.min, range, layout.plotTop, layout.plotBottom);\n\tconst dashArray = dashFor(style.dashStyle);\n\tconst out: SvgLine[] = [];\n\tfor (const series of chartData.series) {\n\t\tseries.values.forEach((val, vi) => {\n\t\t\tconst x = categoryX(vi, catCount, layout, options);\n\t\t\tout.push({\n\t\t\t\tkind: 'line',\n\t\t\t\tx1: x,\n\t\t\t\ty1: valueToY(val, range, layout.plotTop, layout.plotBottom),\n\t\t\t\tx2: x,\n\t\t\t\ty2: baselineY,\n\t\t\t\tstroke: style.color ?? '#94a3b8',\n\t\t\t\tstrokeWidth: style.width ?? 0.8,\n\t\t\t\tdashArray,\n\t\t\t});\n\t\t});\n\t}\n\treturn out;\n}\n\n/**\n * Hi-low lines: a vertical line joining the highest and lowest series value in\n * each category. Returns `[]` when `c:hiLowLines` is absent or fewer than two\n * series are present.\n */\nexport function computeHiLowLinePrimitives(\n\tchartData: PptxChartData,\n\tlayout: PlotLayout,\n\trange: ValueRange,\n\tcatCount: number,\n\toptions: HelperLineOptions,\n): SvgLine[] {\n\tconst style = chartData.hiLowLines;\n\tif (!style || chartData.series.length < 2) {\n\t\treturn [];\n\t}\n\tconst dashArray = dashFor(style.dashStyle);\n\tconst out: SvgLine[] = [];\n\tfor (let vi = 0; vi < catCount; vi++) {\n\t\tlet high = Number.NEGATIVE_INFINITY;\n\t\tlet low = Number.POSITIVE_INFINITY;\n\t\tfor (const series of chartData.series) {\n\t\t\tconst v = series.values[vi];\n\t\t\tif (v !== undefined) {\n\t\t\t\thigh = Math.max(high, v);\n\t\t\t\tlow = Math.min(low, v);\n\t\t\t}\n\t\t}\n\t\tif (!Number.isFinite(high) || !Number.isFinite(low)) {\n\t\t\tcontinue;\n\t\t}\n\t\tconst x = categoryX(vi, catCount, layout, options);\n\t\tout.push({\n\t\t\tkind: 'line',\n\t\t\tx1: x,\n\t\t\ty1: valueToY(high, range, layout.plotTop, layout.plotBottom),\n\t\t\tx2: x,\n\t\t\ty2: valueToY(low, range, layout.plotTop, layout.plotBottom),\n\t\t\tstroke: style.color ?? '#334155',\n\t\t\tstrokeWidth: style.width ?? 1,\n\t\t\tdashArray,\n\t\t});\n\t}\n\treturn out;\n}\n\n/**\n * Up-down bars: a bar between the first and last series value in each category.\n * Rising categories (last >= first) use the `upBars` fill, falling ones the\n * `downBars` fill. Returns `[]` when `c:upDownBars` is absent or fewer than two\n * series are present.\n */\nexport function computeUpDownBarPrimitives(\n\tchartData: PptxChartData,\n\tlayout: PlotLayout,\n\trange: ValueRange,\n\tcatCount: number,\n\toptions: HelperLineOptions,\n): SvgRect[] {\n\tconst bars = chartData.upDownBars;\n\tif (!bars || chartData.series.length < 2) {\n\t\treturn [];\n\t}\n\tconst first = chartData.series[0];\n\tconst last = chartData.series[chartData.series.length - 1];\n\tconst slot = layout.plotWidth / Math.max(catCount, 1);\n\tconst gapWidth = bars.gapWidth ?? 150;\n\tconst barW = Math.max(slot / (1 + Math.max(gapWidth, 0) / 100), 1);\n\tconst upFill = bars.upBars?.fillColor ?? '#e2e8f0';\n\tconst downFill = bars.downBars?.fillColor ?? '#334155';\n\tconst out: SvgRect[] = [];\n\tfor (let vi = 0; vi < catCount; vi++) {\n\t\tconst firstVal = first.values[vi];\n\t\tconst lastVal = last.values[vi];\n\t\tif (firstVal === undefined || lastVal === undefined) {\n\t\t\tcontinue;\n\t\t}\n\t\tconst firstY = valueToY(firstVal, range, layout.plotTop, layout.plotBottom);\n\t\tconst lastY = valueToY(lastVal, range, layout.plotTop, layout.plotBottom);\n\t\tconst x = categoryX(vi, catCount, layout, options) - barW / 2;\n\t\tout.push({\n\t\t\tkind: 'rect',\n\t\t\tx,\n\t\t\ty: Math.min(firstY, lastY),\n\t\t\tw: barW,\n\t\t\th: Math.max(Math.abs(firstY - lastY), 1),\n\t\t\tfill: lastVal >= firstVal ? upFill : downFill,\n\t\t});\n\t}\n\treturn out;\n}\n\n/**\n * Convenience: all three helper-line families for a chart, concatenated.\n * Drawn under the series marks by the caller (they push the data marks first).\n */\nexport function computeHelperLinePrimitives(\n\tchartData: PptxChartData,\n\tlayout: PlotLayout,\n\trange: ValueRange,\n\tcatCount: number,\n\toptions: HelperLineOptions,\n): Array<SvgLine | SvgRect> {\n\treturn [\n\t\t...computeUpDownBarPrimitives(chartData, layout, range, catCount, options),\n\t\t...computeDropLinePrimitives(chartData, layout, range, catCount, options),\n\t\t...computeHiLowLinePrimitives(chartData, layout, range, catCount, options),\n\t];\n}\n","/**\n * chart-date-format.ts: a small Excel/ECMA-376 date-format-code renderer for\n * date-axis labels and date-valued data labels.\n *\n * `chart-date-axis.ts`'s `formatDate` used to only sniff whether a format code\n * CONTAINED the substrings `\"yyyy\"`/`\"d\"` and always emit one of three fixed\n * shapes (`\"D Mon\"`, `\"Mon YYYY\"`, `\"YYYY\"`) via a hardcoded `en-US` short-month\n * `toLocaleString`. It ignored the code's actual punctuation/order and\n * numeric-vs-name choice entirely, so `mm/dd/yyyy` rendered as `\"5 Jan 2024\"`\n * instead of `\"01/05/2024\"`, and `mmmm yyyy` (full month name) rendered\n * identically to `mmm yyyy`.\n *\n * This module renders the tokens charts actually use: `yyyy`/`yy`,\n * `mmmm`/`mmm`/`mm`/`m`, `dddd`/`ddd`/`dd`/`d`, `hh`/`h`, `mm`/`m` (minutes,\n * when adjacent to an hour or second token), `ss`/`s`, `AM/PM`/`A/P`, plus\n * quoted literal text and `\\`-escapes. Anything the tokenizer finds no\n * `y`/`m`/`d`/`h`/`s` letter in falls back to the historical calendar-unit\n * heuristic, so an absent or unusable code degrades to today's output rather\n * than to garbage.\n *\n * @module chart-date-format\n */\n\nconst MONTH_ABBR = [\n\t'Jan',\n\t'Feb',\n\t'Mar',\n\t'Apr',\n\t'May',\n\t'Jun',\n\t'Jul',\n\t'Aug',\n\t'Sep',\n\t'Oct',\n\t'Nov',\n\t'Dec',\n];\nconst MONTH_FULL = [\n\t'January',\n\t'February',\n\t'March',\n\t'April',\n\t'May',\n\t'June',\n\t'July',\n\t'August',\n\t'September',\n\t'October',\n\t'November',\n\t'December',\n];\nconst WEEKDAY_ABBR = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'];\nconst WEEKDAY_FULL = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'];\n\n/** One scanned unit of a format code: a run of the same date/time letter, a literal run, or an AM/PM marker. */\ntype RawToken =\n\t| { kind: 'letters'; letter: 'y' | 'm' | 'd' | 'h' | 's'; count: number }\n\t| { kind: 'literal'; text: string }\n\t| { kind: 'ampm'; upper: boolean; short: boolean };\n\n/** Split a format code into literal runs, AM/PM markers, and `y`/`m`/`d`/`h`/`s` letter runs. */\nfunction scanDateFormatTokens(code: string): RawToken[] {\n\tconst tokens: RawToken[] = [];\n\tlet i = 0;\n\twhile (i < code.length) {\n\t\tconst ch = code[i];\n\t\tif (ch === '\"') {\n\t\t\tconst close = code.indexOf('\"', i + 1);\n\t\t\ttokens.push({\n\t\t\t\tkind: 'literal',\n\t\t\t\ttext: close === -1 ? code.slice(i + 1) : code.slice(i + 1, close),\n\t\t\t});\n\t\t\ti = close === -1 ? code.length : close + 1;\n\t\t\tcontinue;\n\t\t}\n\t\tif (ch === '\\\\') {\n\t\t\ttokens.push({ kind: 'literal', text: code[i + 1] ?? '' });\n\t\t\ti += 2;\n\t\t\tcontinue;\n\t\t}\n\t\tconst rest = code.slice(i);\n\t\tif (/^am\\/pm/iu.test(rest)) {\n\t\t\ttokens.push({ kind: 'ampm', upper: ch === ch.toUpperCase(), short: false });\n\t\t\ti += 5;\n\t\t\tcontinue;\n\t\t}\n\t\tif (/^a\\/p/iu.test(rest)) {\n\t\t\ttokens.push({ kind: 'ampm', upper: ch === ch.toUpperCase(), short: true });\n\t\t\ti += 3;\n\t\t\tcontinue;\n\t\t}\n\t\tif (/[ymdhs]/iu.test(ch)) {\n\t\t\tlet j = i + 1;\n\t\t\twhile (j < code.length && code[j].toLowerCase() === ch.toLowerCase()) {\n\t\t\t\tj += 1;\n\t\t\t}\n\t\t\ttokens.push({\n\t\t\t\tkind: 'letters',\n\t\t\t\tletter: ch.toLowerCase() as 'y' | 'm' | 'd' | 'h' | 's',\n\t\t\t\tcount: j - i,\n\t\t\t});\n\t\t\ti = j;\n\t\t\tcontinue;\n\t\t}\n\t\ttokens.push({ kind: 'literal', text: ch });\n\t\ti += 1;\n\t}\n\treturn tokens;\n}\n\nfunction findNonLiteral(\n\ttokens: readonly RawToken[],\n\tindex: number,\n\tstep: 1 | -1,\n): RawToken | undefined {\n\tfor (let i = index + step; i >= 0 && i < tokens.length; i += step) {\n\t\tif (tokens[i].kind !== 'literal') {\n\t\t\treturn tokens[i];\n\t\t}\n\t}\n\treturn undefined;\n}\n\nfunction pad(n: number, width: number): string {\n\treturn String(n).padStart(width, '0');\n}\n\n/** Render one classified date-part token (year/month/day/hour/minute/second). */\nfunction renderDatePart(\n\tpart: 'year' | 'month' | 'day' | 'hour' | 'minute' | 'second',\n\tcount: number,\n\tdate: Date,\n\ttwelveHour: boolean,\n): string {\n\tswitch (part) {\n\t\tcase 'year':\n\t\t\treturn count >= 4 ? pad(date.getUTCFullYear(), 4) : pad(date.getUTCFullYear() % 100, 2);\n\t\tcase 'month':\n\t\t\tif (count >= 4) {\n\t\t\t\treturn MONTH_FULL[date.getUTCMonth()] ?? '';\n\t\t\t}\n\t\t\tif (count === 3) {\n\t\t\t\treturn MONTH_ABBR[date.getUTCMonth()] ?? '';\n\t\t\t}\n\t\t\treturn count >= 2 ? pad(date.getUTCMonth() + 1, 2) : String(date.getUTCMonth() + 1);\n\t\tcase 'day':\n\t\t\tif (count >= 4) {\n\t\t\t\treturn WEEKDAY_FULL[date.getUTCDay()] ?? '';\n\t\t\t}\n\t\t\tif (count === 3) {\n\t\t\t\treturn WEEKDAY_ABBR[date.getUTCDay()] ?? '';\n\t\t\t}\n\t\t\treturn count >= 2 ? pad(date.getUTCDate(), 2) : String(date.getUTCDate());\n\t\tcase 'hour': {\n\t\t\tconst h24 = date.getUTCHours();\n\t\t\tconst h = twelveHour ? (h24 % 12 === 0 ? 12 : h24 % 12) : h24;\n\t\t\treturn count >= 2 ? pad(h, 2) : String(h);\n\t\t}\n\t\tcase 'minute':\n\t\t\treturn count >= 2 ? pad(date.getUTCMinutes(), 2) : String(date.getUTCMinutes());\n\t\tcase 'second':\n\t\t\treturn count >= 2 ? pad(date.getUTCSeconds(), 2) : String(date.getUTCSeconds());\n\t}\n}\n\n/**\n * Render `date` through an Excel/ECMA-376 date-format code. `m` is ambiguous\n * in Excel's own grammar (month vs. minute); it is read as minutes only when\n * it sits immediately next to an hour or second token, skipping over literal\n * separators like `:` (the same rule that lets Excel tell `h:mm` from\n * `mmm yyyy` apart), and as month otherwise.\n */\nfunction renderExcelDateFormat(date: Date, code: string): string {\n\tconst tokens = scanDateFormatTokens(code);\n\tconst hasAmPm = tokens.some((t) => t.kind === 'ampm');\n\tlet out = '';\n\tfor (const [index, token] of tokens.entries()) {\n\t\tif (token.kind === 'literal') {\n\t\t\tout += token.text;\n\t\t\tcontinue;\n\t\t}\n\t\tif (token.kind === 'ampm') {\n\t\t\tconst hour = date.getUTCHours(),\n\t\t\t\ttext = token.short ? (hour < 12 ? 'A' : 'P') : hour < 12 ? 'AM' : 'PM';\n\t\t\tout += token.upper ? text : text.toLowerCase();\n\t\t\tcontinue;\n\t\t}\n\t\tif (token.letter === 'm') {\n\t\t\tconst prev = findNonLiteral(tokens, index, -1),\n\t\t\t\tnext = findNonLiteral(tokens, index, 1),\n\t\t\t\tisMinute =\n\t\t\t\t\t(prev?.kind === 'letters' && prev.letter === 'h') ||\n\t\t\t\t\t(next?.kind === 'letters' && next.letter === 's');\n\t\t\tout += renderDatePart(isMinute ? 'minute' : 'month', token.count, date, hasAmPm);\n\t\t\tcontinue;\n\t\t}\n\t\tconst part = { y: 'year', d: 'day', h: 'hour', s: 'second' } as const;\n\t\tout += renderDatePart(part[token.letter], token.count, date, hasAmPm);\n\t}\n\treturn out;\n}\n\n/**\n * Format a date-axis / date-valued label. Tries the source `format` code\n * (when it contains at least one recognised date/time letter) through the\n * token renderer above; falls back to a calendar-unit-sized heuristic\n * (`\"D Mon\"` / `\"Mon YYYY\"` / `\"YYYY\"`) when the code is absent or unusable,\n * matching the engine's pre-token-renderer output.\n */\nexport function formatDate(date: Date, unit: 'days' | 'months' | 'years', format?: string): string {\n\tif (format && /[ymdhs]/iu.test(format)) {\n\t\tconst rendered = renderExcelDateFormat(date, format);\n\t\tif (rendered.length > 0) {\n\t\t\treturn rendered;\n\t\t}\n\t}\n\tconst month = date.toLocaleString('en-US', { month: 'short', timeZone: 'UTC' }),\n\t\tyear = String(date.getUTCFullYear()),\n\t\tday = String(date.getUTCDate());\n\tif (unit === 'years') {\n\t\treturn year;\n\t}\n\tif (unit === 'months') {\n\t\treturn `${month} ${year}`;\n\t}\n\treturn `${day} ${month}`;\n}\n","import type { PptxChartAxisFormatting, PptxChartData } from 'pptx-viewer-core';\n\nimport { chartAxisTextStyle, chartLineStyle } from './chart-axis-style';\nimport { formatDate } from './chart-date-format';\nimport type { PlotLayout, SvgLine, SvgText } from './chart-view-model';\n\nconst DAY_MS = 86_400_000;\n\nexport interface DateAxisPlan {\n\tsourceIndices: number[];\n\txPositions: number[];\n\tlabels: SvgText[];\n\ttickMarks: SvgLine[];\n}\n\nexport function excelSerialToDate(serial: number, date1904 = false): Date {\n\tconst epoch = date1904 ? Date.UTC(1904, 0, 1) : Date.UTC(1899, 11, serial < 60 ? 31 : 30);\n\treturn new Date(epoch + serial * DAY_MS);\n}\n\nfunction primaryDateAxis(chartData: PptxChartData): PptxChartAxisFormatting | undefined {\n\treturn (\n\t\tchartData.axes?.find((axis) => axis.axisType === 'dateAx' && axis.axPos !== 't') ??\n\t\tchartData.axes?.find((axis) => axis.axisType === 'dateAx')\n\t);\n}\n\nfunction serialToX(serial: number, min: number, max: number, layout: PlotLayout): number {\n\tconst ratio = max === min ? 0.5 : (serial - min) / (max - min);\n\treturn layout.plotLeft + ratio * layout.plotWidth;\n}\n\nfunction addUnit(date: Date, amount: number, unit: 'days' | 'months' | 'years'): Date {\n\tconst next = new Date(date);\n\tif (unit === 'days') {\n\t\tnext.setUTCDate(next.getUTCDate() + amount);\n\t} else if (unit === 'months') {\n\t\tnext.setUTCMonth(next.getUTCMonth() + amount);\n\t} else {\n\t\tnext.setUTCFullYear(next.getUTCFullYear() + amount);\n\t}\n\treturn next;\n}\n\nfunction tickLine(\n\tx: number,\n\ty: number,\n\taxis: PptxChartAxisFormatting,\n\tminor: boolean,\n): SvgLine | undefined {\n\tconst placement = minor ? axis.minorTickMark : axis.majorTickMark;\n\tif (!placement || placement === 'none') {\n\t\treturn undefined;\n\t}\n\tconst length = minor ? 2.5 : 4;\n\tconst direction = axis.axPos === 't' ? 1 : -1;\n\tconst inward = direction * length;\n\tconst outward = -inward;\n\tconst [start, end] =\n\t\tplacement === 'cross' ? [-length, length] : placement === 'in' ? [0, inward] : [0, outward];\n\treturn {\n\t\tkind: 'line',\n\t\tx1: x,\n\t\ty1: y + start,\n\t\tx2: x,\n\t\ty2: y + end,\n\t\t...chartLineStyle(axis.spPr),\n\t};\n}\n\nfunction calendarTicks(\n\tmin: number,\n\tmax: number,\n\tdate1904: boolean,\n\tunit: 'days' | 'months' | 'years',\n\tstep: number,\n): number[] {\n\tconst result: number[] = [];\n\tlet date = excelSerialToDate(min, date1904);\n\tfor (\n\t\tlet guard = 0;\n\t\tguard < 1000 && date.getTime() <= excelSerialToDate(max, date1904).getTime();\n\t\tguard++\n\t) {\n\t\tresult.push(min + (date.getTime() - excelSerialToDate(min, date1904).getTime()) / DAY_MS);\n\t\tdate = addUnit(date, step, unit);\n\t}\n\treturn result;\n}\n\n/** Build a continuous calendar scale for classic ChartML date categories. */\nexport function buildDateAxisPlan(\n\tchartData: PptxChartData,\n\tlayout: PlotLayout,\n\tselectedAxis?: PptxChartAxisFormatting,\n\taxisY?: number,\n): DateAxisPlan | undefined {\n\tconst dates = chartData.dateCategories;\n\tconst axis = selectedAxis ?? primaryDateAxis(chartData);\n\tif (!dates || !axis || dates.values.length === 0) {\n\t\treturn undefined;\n\t}\n\tconst indexed = dates.values\n\t\t.map((value, index) => ({ value, index }))\n\t\t.sort((a, b) => a.value - b.value);\n\tconst dataMin = indexed[0]?.value ?? 0;\n\tconst dataMax = indexed[indexed.length - 1]?.value ?? dataMin;\n\tconst min = axis.min ?? dataMin;\n\tconst max = axis.max ?? dataMax;\n\tconst visible = indexed.filter(({ value }) => value >= min && value <= max);\n\tif (axis.orientation === 'maxMin') {\n\t\tvisible.reverse();\n\t}\n\tconst sourceIndices = visible.map(({ index }) => index);\n\tconst xPositions = visible.map(({ value }) => {\n\t\tconst x = serialToX(value, min, max, layout);\n\t\treturn axis.orientation === 'maxMin'\n\t\t\t? layout.plotLeft + layout.plotWidth - (x - layout.plotLeft)\n\t\t\t: x;\n\t});\n\tconst unit = axis.majorTimeUnit ?? axis.baseTimeUnit ?? 'days';\n\tconst ticks = calendarTicks(\n\t\tmin,\n\t\tmax,\n\t\tdates.date1904 ?? false,\n\t\tunit,\n\t\tMath.max(1, axis.majorUnit ?? 1),\n\t);\n\tconst y = axisY ?? (axis.axPos === 't' ? layout.plotTop : layout.plotBottom);\n\tconst offset = 4 + 8 * ((axis.labelOffset ?? 100) / 100);\n\tconst labelsAbove =\n\t\taxis.tickLblPos === 'high' || (axis.tickLblPos !== 'low' && axis.axPos === 't');\n\tconst labelY =\n\t\taxis.tickLblPos === 'high' ? layout.plotTop : axis.tickLblPos === 'low' ? layout.plotBottom : y;\n\tconst labelSkip = Math.max(1, axis.tickLabelSkip ?? 1);\n\tconst labels =\n\t\taxis.deleted || axis.tickLblPos === 'none'\n\t\t\t? []\n\t\t\t: ticks.flatMap((serial, index) => {\n\t\t\t\t\tif (index % labelSkip !== 0) {\n\t\t\t\t\t\treturn [];\n\t\t\t\t\t}\n\t\t\t\t\tlet x = serialToX(serial, min, max, layout);\n\t\t\t\t\tif (axis.orientation === 'maxMin') {\n\t\t\t\t\t\tx = layout.plotLeft + layout.plotWidth - (x - layout.plotLeft);\n\t\t\t\t\t}\n\t\t\t\t\treturn [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tkind: 'text' as const,\n\t\t\t\t\t\t\tx,\n\t\t\t\t\t\t\ty: labelsAbove ? labelY - offset : labelY + offset,\n\t\t\t\t\t\t\ttext: formatDate(\n\t\t\t\t\t\t\t\texcelSerialToDate(serial, dates.date1904),\n\t\t\t\t\t\t\t\tunit,\n\t\t\t\t\t\t\t\taxis.numFmt?.formatCode ?? dates.formatCode,\n\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t...chartAxisTextStyle(axis),\n\t\t\t\t\t\t\ttextAnchor: 'middle' as const,\n\t\t\t\t\t\t},\n\t\t\t\t\t];\n\t\t\t\t});\n\tconst tickMarks = axis.deleted\n\t\t? []\n\t\t: ticks.flatMap((serial, index) => {\n\t\t\t\tif (index % Math.max(1, axis.tickMarkSkip ?? 1) !== 0) {\n\t\t\t\t\treturn [];\n\t\t\t\t}\n\t\t\t\tlet x = serialToX(serial, min, max, layout);\n\t\t\t\tif (axis.orientation === 'maxMin') {\n\t\t\t\t\tx = layout.plotLeft + layout.plotWidth - (x - layout.plotLeft);\n\t\t\t\t}\n\t\t\t\tconst line = tickLine(x, y, axis, false);\n\t\t\t\treturn line ? [line] : [];\n\t\t\t});\n\tif (!axis.deleted && axis.spPr) {\n\t\ttickMarks.unshift({\n\t\t\tkind: 'line',\n\t\t\tx1: layout.plotLeft,\n\t\t\ty1: y,\n\t\t\tx2: layout.plotRight,\n\t\t\ty2: y,\n\t\t\t...chartLineStyle(axis.spPr),\n\t\t});\n\t}\n\tif (!axis.deleted && axis.minorTickMark && axis.minorTickMark !== 'none') {\n\t\tconst minorUnit = axis.minorTimeUnit ?? axis.baseTimeUnit ?? unit;\n\t\tfor (const serial of calendarTicks(\n\t\t\tmin,\n\t\t\tmax,\n\t\t\tdates.date1904 ?? false,\n\t\t\tminorUnit,\n\t\t\tMath.max(1, axis.minorUnit ?? 1),\n\t\t)) {\n\t\t\tlet x = serialToX(serial, min, max, layout);\n\t\t\tif (axis.orientation === 'maxMin') {\n\t\t\t\tx = layout.plotLeft + layout.plotWidth - (x - layout.plotLeft);\n\t\t\t}\n\t\t\tconst line = tickLine(x, y, axis, true);\n\t\t\tif (line) {\n\t\t\t\ttickMarks.push(line);\n\t\t\t}\n\t\t}\n\t}\n\treturn { sourceIndices, xPositions, labels, tickMarks };\n}\n","import type { PptxChartAxisFormatting, PptxChartData } from 'pptx-viewer-core';\n\nimport { horizontalAxisY } from './chart-axis-crossing';\nimport { buildCategoryAxisPlan, categoryX, chartDataInCategoryOrder } from './chart-category-axis';\nimport { buildDateAxisPlan } from './chart-date-axis';\nimport type {\n\tPlotLayout,\n\tSupportedChartKind,\n\tSvgLine,\n\tSvgText,\n\tValueRange,\n} from './chart-view-model';\nimport { buildCategoryLabels } from './chart-view-model';\n\nexport interface CartesianHorizontalAxisPlan {\n\tcatAxisStyle: 'bar' | 'line';\n\tsourceIndices: number[];\n\txPositions?: number[];\n\tlabels: SvgText[];\n\ttickMarks: SvgLine[];\n\tdisplayChartData: PptxChartData;\n}\n\nexport function buildCartesianHorizontalAxis(\n\tchartData: PptxChartData,\n\tcategoryLabels: ReadonlyArray<string>,\n\tlayout: PlotLayout,\n\tkind: SupportedChartKind,\n\tprimaryRange: ValueRange,\n\tsecondaryRange?: ValueRange,\n): CartesianHorizontalAxisPlan {\n\tlet catAxisStyle: 'bar' | 'line' =\n\t\tkind === 'line' || kind === 'area' || kind === 'scatter' || kind === 'bubble' ? 'line' : 'bar';\n\tconst horizontalAxes = chartData.axes?.filter(\n\t\t(axis) => axis.axisType === 'catAx' || axis.axisType === 'dateAx',\n\t);\n\tconst primaryAxis = horizontalAxes?.find((axis) => axis.axPos !== 't') ?? horizontalAxes?.[0];\n\tconst secondaryAxis = horizontalAxes?.find((axis) => axis.axPos === 't' && axis !== primaryAxis);\n\tconst linkedValueAxis = (axis: PptxChartAxisFormatting | undefined) =>\n\t\tchartData.axes?.find(\n\t\t\t(candidate) => candidate.axisType === 'valAx' && candidate.axisId === axis?.crossAxisId,\n\t\t);\n\tconst primaryValueAxis = linkedValueAxis(primaryAxis);\n\tif (primaryValueAxis?.crossBetween === 'between') {\n\t\tcatAxisStyle = 'bar';\n\t} else if (primaryValueAxis?.crossBetween === 'midCat') {\n\t\tcatAxisStyle = 'line';\n\t}\n\tconst rangeAndY = (axis: PptxChartAxisFormatting | undefined) => {\n\t\tconst valueAxis = linkedValueAxis(axis);\n\t\tconst range = valueAxis?.axPos === 'r' && secondaryRange ? secondaryRange : primaryRange;\n\t\treturn horizontalAxisY(valueAxis, range, layout, axis?.axPos === 't' ? 'top' : 'bottom');\n\t};\n\tconst supportsDateScale =\n\t\tkind === 'line' || kind === 'area' || kind === 'combo' || kind === 'stock';\n\tconst datePlan =\n\t\tsupportsDateScale && primaryAxis?.axisType === 'dateAx'\n\t\t\t? buildDateAxisPlan(chartData, layout, primaryAxis, rangeAndY(primaryAxis))\n\t\t\t: undefined;\n\tconst categoryPlan =\n\t\tkind === 'scatter' || kind === 'bubble' || datePlan\n\t\t\t? undefined\n\t\t\t: buildCategoryAxisPlan(\n\t\t\t\t\tcategoryLabels,\n\t\t\t\t\tlayout,\n\t\t\t\t\tcatAxisStyle,\n\t\t\t\t\tchartData.axes,\n\t\t\t\t\tprimaryAxis,\n\t\t\t\t\trangeAndY(primaryAxis),\n\t\t\t\t\tchartData.categoryLevels,\n\t\t\t\t);\n\tconst secondaryPlan = secondaryAxis\n\t\t? secondaryAxis.axisType === 'dateAx'\n\t\t\t? buildDateAxisPlan(chartData, layout, secondaryAxis, rangeAndY(secondaryAxis))\n\t\t\t: buildCategoryAxisPlan(\n\t\t\t\t\tcategoryLabels,\n\t\t\t\t\tlayout,\n\t\t\t\t\tlinkedValueAxis(secondaryAxis)?.crossBetween === 'between' ? 'bar' : 'line',\n\t\t\t\t\tchartData.axes,\n\t\t\t\t\tsecondaryAxis,\n\t\t\t\t\trangeAndY(secondaryAxis),\n\t\t\t\t\tchartData.categoryLevels,\n\t\t\t\t)\n\t\t: undefined;\n\tconst sourceIndices =\n\t\tdatePlan?.sourceIndices ??\n\t\tcategoryPlan?.sourceIndices ??\n\t\tcategoryLabels.map((_label, index) => index);\n\treturn {\n\t\tcatAxisStyle,\n\t\tsourceIndices,\n\t\txPositions:\n\t\t\tdatePlan?.xPositions ??\n\t\t\tcategoryPlan?.sourceIndices.map((_sourceIndex, displayIndex) =>\n\t\t\t\tcategoryX(displayIndex, categoryPlan.sourceIndices.length, layout, catAxisStyle),\n\t\t\t),\n\t\tlabels: [\n\t\t\t...(datePlan?.labels ??\n\t\t\t\tcategoryPlan?.labels ??\n\t\t\t\tbuildCategoryLabels(categoryLabels, layout, catAxisStyle)),\n\t\t\t...(secondaryPlan?.labels ?? []),\n\t\t],\n\t\ttickMarks: [\n\t\t\t...(datePlan?.tickMarks ?? categoryPlan?.tickMarks ?? []),\n\t\t\t...(secondaryPlan?.tickMarks ?? []),\n\t\t],\n\t\tdisplayChartData:\n\t\t\tdatePlan || categoryPlan ? chartDataInCategoryOrder(chartData, sourceIndices) : chartData,\n\t};\n}\n","/**\n * Word wrapping for contexts where the real glyph advances cannot be measured.\n *\n * Some render targets have no text-measurement API available at the point the\n * layout is decided: a PDF content stream being assembled, or SVG labels that\n * must be laid out before the document is in a document. Both need to break a\n * string into lines that will roughly fit a width, and both are better served\n * by one approximation than by two that drift apart.\n *\n * This is deliberately not a substitute for measured text. Anything that can\n * measure (the paragraph renderers, which resolve real advances) must.\n *\n * @module text-wrap-estimate\n */\n\nfunction estimatedGlyphAdvanceRatio(glyph: string): number {\n\tif (/\\p{Mark}/u.test(glyph)) {\n\t\treturn 0;\n\t}\n\tif (/\\s/u.test(glyph)) {\n\t\treturn 0.33;\n\t}\n\tif (\n\t\t/[\\p{Script=Han}\\p{Script=Hiragana}\\p{Script=Katakana}\\p{Script=Hangul}\\p{Extended_Pictographic}]/u.test(\n\t\t\tglyph,\n\t\t)\n\t) {\n\t\treturn 1;\n\t}\n\tif (/[A-Z]/u.test(glyph)) {\n\t\treturn 0.65;\n\t}\n\tif (/[a-z0-9]/u.test(glyph)) {\n\t\treturn 0.55;\n\t}\n\tif (/[,.;:!?()\\u005b\\u005d{}'\"`\\-_/\\\\]/u.test(glyph)) {\n\t\treturn 0.35;\n\t}\n\treturn 0.6;\n}\n\nfunction estimatedTextWidth(glyphs: readonly string[], fontSize: number): number {\n\treturn glyphs.reduce((sum, glyph) => sum + estimatedGlyphAdvanceRatio(glyph) * fontSize, 0);\n}\n\n/**\n * Estimate the rendered width of a single line of `text` at `fontSize`,\n * without a real text-measurement API (see the module doc comment for when\n * that applies). Used to size layout reservations ahead of render, such as\n * how much horizontal space a chart must leave for its widest label.\n *\n * @param text - The line to measure. Only its own glyphs are considered; this\n * does not wrap or split the string.\n * @param fontSize - Font size used to estimate glyph advances.\n * @returns The estimated width in the same units as `fontSize`.\n */\nexport function estimateTextWidth(text: string, fontSize: number): number {\n\treturn estimatedTextWidth(Array.from(text), fontSize);\n}\n\nconst HANGING_PUNCTUATION_RE =\n\t/^[\\u3001\\u3002\\uff0c\\uff0e\\uff01\\uff1f\\uff1b\\uff1a\\u3009\\u300b\\u300d\\u300f\\u3011\\u3015\\u3017\\u3019\\u301b\\uff09\\uff3d\\uff5d\\u2019\\u201d\\u00bb\\u203a]$/u;\nconst BREAKABLE_GLYPH_RE =\n\t/^[\\p{Script=Han}\\p{Script=Hiragana}\\p{Script=Katakana}\\p{Script=Hangul}\\p{Extended_Pictographic}]$/u;\n\nfunction estimatedWrapUnits(text: string): string[] {\n\tconst units: string[] = [];\n\tlet unbreakableRun = '';\n\tconst flushRun = () => {\n\t\tif (unbreakableRun.length > 0) {\n\t\t\tunits.push(unbreakableRun);\n\t\t\tunbreakableRun = '';\n\t\t}\n\t};\n\n\tfor (const glyph of Array.from(text)) {\n\t\tif (/\\s/u.test(glyph) || BREAKABLE_GLYPH_RE.test(glyph)) {\n\t\t\tflushRun();\n\t\t\tunits.push(glyph);\n\t\t} else {\n\t\t\tunbreakableRun += glyph;\n\t\t}\n\t}\n\tflushRun();\n\treturn units;\n}\n\n/** Options for {@link wrapTextByEstimatedWidth}. */\nexport interface EstimatedWrapOptions {\n\t/**\n\t * Keep an empty line for each blank authored paragraph. Paginated text wants\n\t * the vertical gap preserved; a label centred in a shape does not.\n\t */\n\tkeepBlankLines?: boolean;\n}\n\n/**\n * Break `text` into lines that approximately fit `maxWidth`.\n *\n * Authored line breaks are always honoured. Words are never split or dropped:\n * a single word longer than the line gets a line of its own and overflows,\n * which is what PowerPoint does too.\n *\n * @param text - The text to wrap.\n * @param maxWidth - Available width, in the same units as `fontSize`.\n * @param fontSize - Font size used to estimate glyph advances.\n * @param options - See {@link EstimatedWrapOptions}.\n * @returns The wrapped lines, empty when there is nothing to render.\n */\nexport function wrapTextByEstimatedWidth(\n\ttext: string,\n\tmaxWidth: number,\n\tfontSize: number,\n\toptions: EstimatedWrapOptions = {},\n): string[] {\n\tif (!text || text.trim().length === 0) {\n\t\treturn [];\n\t}\n\n\tif (!(maxWidth > 0) || !(fontSize > 0)) {\n\t\treturn [];\n\t}\n\n\tconst lines: string[] = [];\n\tfor (const paragraph of text.split(/\\r?\\n/u)) {\n\t\tif (paragraph.trim().length === 0) {\n\t\t\tif (options.keepBlankLines) {\n\t\t\t\tlines.push('');\n\t\t\t}\n\t\t\tcontinue;\n\t\t}\n\n\t\tlet current = '';\n\t\tlet pendingWhitespace = false;\n\t\tfor (const unit of estimatedWrapUnits(paragraph)) {\n\t\t\tif (/^\\s+$/u.test(unit)) {\n\t\t\t\tpendingWhitespace = current.length > 0;\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tconst separator = pendingWhitespace && current.length > 0 ? ' ' : '';\n\t\t\tconst candidate = `${current}${separator}${unit}`;\n\t\t\tif (current.length === 0 || estimatedTextWidth(Array.from(candidate), fontSize) <= maxWidth) {\n\t\t\t\tcurrent = candidate;\n\t\t\t\tpendingWhitespace = false;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (HANGING_PUNCTUATION_RE.test(unit)) {\n\t\t\t\tcurrent += unit;\n\t\t\t\tpendingWhitespace = false;\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tlines.push(current);\n\t\t\tcurrent = unit;\n\t\t\tpendingWhitespace = false;\n\t\t}\n\t\tconst completed = current.trimEnd();\n\t\tif (completed.length > 0) {\n\t\t\tlines.push(completed);\n\t\t}\n\t}\n\n\treturn lines;\n}\n","/**\n * chart-horizontal-bars-helpers.ts: geometry/fill helpers for the transposed\n * (horizontal) bar-chart builder, split out of `chart-horizontal-bars.ts` to\n * keep that file within the repo's ~300-LOC limit.\n *\n * @module chart-horizontal-bars-helpers\n */\nimport type { PptxChartData, PptxChartSeries } from 'pptx-viewer-core';\n\nimport { resolveDataPointFill, resolveVaryColorFill } from './chart-datapoint-style';\nimport { DEFAULT_CHART_TEXT_PX } from './chart-font';\nimport type { PlotLayout, SvgLine, SvgText, ValueRange } from './chart-view-model';\nimport {\n\tAXIS_LABEL_COLOR,\n\taxisTickValues,\n\tformatAxisValue,\n\tGRIDLINE_COLOR,\n\tpaletteColor,\n\tseriesColor,\n} from './chart-view-model';\nimport { estimateTextWidth } from './text-wrap-estimate';\n\n/** Map a value onto the horizontal (x) axis: min at the left, max at the right. */\nexport function valueToX(val: number, range: ValueRange, leftX: number, rightX: number): number {\n\tconst usable = rightX - leftX;\n\tlet ratio: number;\n\tif (range.logScale && range.logBase) {\n\t\tconst base = range.logBase,\n\t\t\tclampedVal = Math.max(val, range.min),\n\t\t\tlogVal = Math.log(clampedVal) / Math.log(base),\n\t\t\tlogMin = Math.log(range.min) / Math.log(base);\n\t\tratio = (logVal - logMin) / range.span;\n\t} else {\n\t\tratio = (val - range.min) / range.span;\n\t}\n\treturn range.reverseOrder ? rightX - ratio * usable : leftX + ratio * usable;\n}\n\n/** Vertical value gridlines + bottom tick labels (the transposed value axis). */\nexport function buildTransposedValueAxis(\n\trange: ValueRange,\n\tlayout: PlotLayout,\n): { gridlines: SvgLine[]; axisLabels: SvgText[] } {\n\tconst gridlines: SvgLine[] = [],\n\t\taxisLabels: SvgText[] = [];\n\tfor (const val of axisTickValues(range)) {\n\t\tconst x = valueToX(val, range, layout.plotLeft, layout.plotRight);\n\t\tgridlines.push({\n\t\t\tkind: 'line',\n\t\t\tx1: x,\n\t\t\ty1: layout.plotTop,\n\t\t\tx2: x,\n\t\t\ty2: layout.plotBottom,\n\t\t\tstroke: GRIDLINE_COLOR,\n\t\t\tstrokeWidth: 1,\n\t\t});\n\t\taxisLabels.push({\n\t\t\tkind: 'text',\n\t\t\tx,\n\t\t\ty: layout.plotBottom + 12,\n\t\t\ttext: formatAxisValue(val),\n\t\t\tfontSize: DEFAULT_CHART_TEXT_PX,\n\t\t\tfill: AXIS_LABEL_COLOR,\n\t\t\ttextAnchor: 'middle',\n\t\t});\n\t}\n\treturn { gridlines, axisLabels };\n}\n\n/** Left-anchored category labels, one per band, centred on the band. */\nexport function buildSideCategoryLabels(\n\tcategoryLabels: ReadonlyArray<string>,\n\tlayout: PlotLayout,\n): SvgText[] {\n\tconst catCount = Math.max(categoryLabels.length, 1),\n\t\tband = layout.plotHeight / catCount;\n\treturn categoryLabels.map((label, i) => ({\n\t\tkind: 'text' as const,\n\t\tx: layout.plotLeft - 4,\n\t\ty: layout.plotTop + band * (i + 0.5),\n\t\ttext: label,\n\t\tfontSize: DEFAULT_CHART_TEXT_PX,\n\t\tfill: AXIS_LABEL_COLOR,\n\t\ttextAnchor: 'end' as const,\n\t\tdominantBaseline: 'central',\n\t}));\n}\n\n/**\n * Width, in px, of the widest category label at the given font size: how\n * much horizontal space a horizontal-bar chart's LEFT axis band must reserve\n * so its category text does not clip against the chart's own left edge (see\n * `leftAxisBand` in chart-view-model-layout.ts, which turns this into the\n * actual plot-area inset). Returns 0 for no labels, which leaves the default\n * numeric-axis inset unchanged.\n */\nexport function widestCategoryLabelWidth(\n\tcategoryLabels: ReadonlyArray<string>,\n\tfontSize: number,\n): number {\n\treturn categoryLabels.reduce(\n\t\t(max, label) => Math.max(max, estimateTextWidth(label, fontSize)),\n\t\t0,\n\t);\n}\n\n/** Per-category absolute totals (for percentStacked normalisation). */\nexport function categoryTotals(series: ReadonlyArray<PptxChartSeries>, catCount: number): number[] {\n\treturn Array.from({ length: catCount }, (_, ci) =>\n\t\tseries.reduce((sum, s) => sum + Math.abs(s.values[ci] ?? 0), 0),\n\t);\n}\n\n/** Resolve the fill for one bar, honouring dPt overrides and varyColors. */\nexport function barFill(\n\tchartData: PptxChartData,\n\tseries: PptxChartSeries,\n\tseriesIndex: number,\n\tpointIndex: number,\n): string {\n\tconst palette = chartData.colorPalette;\n\tif (chartData.varyColors === true && chartData.series.length === 1) {\n\t\treturn resolveVaryColorFill(series, pointIndex, paletteColor(pointIndex, palette));\n\t}\n\treturn (\n\t\tresolveDataPointFill(series, pointIndex, paletteColor(seriesIndex, palette)) ??\n\t\tseriesColor(series, seriesIndex, palette)\n\t);\n}\n","/**\n * chart-horizontal-bars.ts: transposed (horizontal) bar-chart view-model\n * builder for `c:barDir val=\"bar\"` charts.\n *\n * The cartesian engine in `chart-cartesian.ts` is column-oriented: categories\n * run along the x axis and values up the y axis. A PowerPoint \"Bar\" chart is\n * the transpose (categories down the left, values along the bottom), so this\n * module builds that layout directly: vertical value gridlines, bottom value\n * labels, left-anchored category labels, and bars growing from the zero line\n * to the right. Clustered, stacked and percentStacked groupings are covered;\n * secondary-axis series, trendlines and data tables fall outside this builder\n * (charts using those keep the column engine's vertical rendering).\n *\n * @module chart-horizontal-bars\n */\nimport type { PptxChartData, PptxElement } from 'pptx-viewer-core';\n\nimport { resolveChartTitleText } from './chart-auto-title';\nimport { computeValueRangeForChart } from './chart-axis-range';\nimport { resolveBarLabelPlacement } from './chart-data-label-anchor';\nimport { dataLabelFontOverride, resolveDataLabelTextStyle } from './chart-data-label-text';\nimport { DEFAULT_CHART_DATA_LABEL_PX, DEFAULT_CHART_TEXT_PX } from './chart-font';\nimport {\n\tbarFill,\n\tbuildSideCategoryLabels,\n\tbuildTransposedValueAxis,\n\tcategoryTotals,\n\tvalueToX,\n\twidestCategoryLabelWidth,\n} from './chart-horizontal-bars-helpers';\nimport type {\n\tChartViewModel,\n\tSvgLine,\n\tSvgPrimitive,\n\tSvgRect,\n\tSvgText,\n\tValueRange,\n} from './chart-view-model';\nimport {\n\tZERO_LINE_COLOR,\n\tbuildLegend,\n\tbuildMarkTooltip,\n\tcomputePlotLayout,\n\tcomputeStackedValueRange,\n\tformatAxisValue,\n} from './chart-view-model';\n\nexport { valueToX } from './chart-horizontal-bars-helpers';\n\n/**\n * Build the full horizontal-bar view-model. Mirrors the column engine's\n * clustered / stacked / percentStacked geometry with the axes transposed.\n */\nexport function buildHorizontalBarViewModel(\n\telement: PptxElement,\n\tchartData: PptxChartData,\n\tcategoryLabels: ReadonlyArray<string>,\n): ChartViewModel {\n\tconst layout = computePlotLayout(element.width, element.height, chartData, true, {\n\t\t\tleftCategoryLabelWidth: widestCategoryLabelWidth(categoryLabels, DEFAULT_CHART_TEXT_PX),\n\t\t}),\n\t\tcatCount = Math.max(categoryLabels.length, 1),\n\t\tseries = chartData.series,\n\t\tgrouping = chartData.grouping ?? 'clustered',\n\t\tisStacked = grouping === 'stacked' || grouping === 'percentStacked',\n\t\tisPercent = grouping === 'percentStacked',\n\t\t// The value axis runs along the WIDTH here (categories run down the left,\n\t\t// values along the bottom: this builder transposes the column engine), so\n\t\t// the gridline-count budget is keyed off plotWidth, not plotHeight.\n\t\trange: ValueRange = isPercent\n\t\t\t? { min: 0, max: 100, span: 100 }\n\t\t\t: isStacked\n\t\t\t\t? computeStackedValueRange(series, catCount, layout.plotWidth)\n\t\t\t\t: computeValueRangeForChart(series, chartData.axes, layout.plotWidth),\n\t\t{ gridlines, axisLabels } = buildTransposedValueAxis(range, layout),\n\t\tzeroX = valueToX(0, range, layout.plotLeft, layout.plotRight),\n\t\tzeroLine: SvgLine | undefined =\n\t\t\trange.min < 0 && range.max > 0\n\t\t\t\t? {\n\t\t\t\t\t\tkind: 'line',\n\t\t\t\t\t\tx1: zeroX,\n\t\t\t\t\t\ty1: layout.plotTop,\n\t\t\t\t\t\tx2: zeroX,\n\t\t\t\t\t\ty2: layout.plotBottom,\n\t\t\t\t\t\tstroke: ZERO_LINE_COLOR,\n\t\t\t\t\t\tstrokeWidth: 1,\n\t\t\t\t\t}\n\t\t\t\t: undefined,\n\t\tprimitives: SvgPrimitive[] = [],\n\t\tdataLabels: SvgText[] = [],\n\t\tshowLabels = chartData.style?.hasDataLabels,\n\t\tband = layout.plotHeight / catCount;\n\n\tif (!isStacked) {\n\t\tconst seriesCount = Math.max(series.length, 1),\n\t\t\t// See chart-cartesian-bars.ts's `buildBars` (clustered branch) for the\n\t\t\t// COM-verified reasoning: the bar's own size must divide the gap-reduced\n\t\t\t// band by how many bar-heights the OVERLAPPED cluster spans, not by the\n\t\t\t// raw series count, or a high-overlap cluster renders far too thin.\n\t\t\t// `gapWidth` is a percentage of the BAR height, not of the band or the\n\t\t\t// cluster, so the gap term adds to `overlapSpan` rather than multiplying\n\t\t\t// a (1 + gapWidth/100) band-shrink by it; see chart-cartesian-bars.ts's\n\t\t\t// `singleBarWidth` comment for the COM measurement that proved this.\n\t\t\toverlap = chartData.barOverlap ?? 0,\n\t\t\toverlapSpan = 1 + (seriesCount - 1) * (1 - overlap / 100),\n\t\t\tsingleBarHeight =\n\t\t\t\tchartData.barGapWidth !== undefined\n\t\t\t\t\t? band / (overlapSpan + Math.max(chartData.barGapWidth, 0) / 100)\n\t\t\t\t\t: (band * 0.7) / seriesCount,\n\t\t\tstep = singleBarHeight * (1 - overlap / 100),\n\t\t\tclusterHeight = singleBarHeight + step * (seriesCount - 1),\n\t\t\tgroupOffset = (band - clusterHeight) / 2;\n\n\t\tfor (let ci = 0; ci < catCount; ci++) {\n\t\t\tfor (let si = 0; si < series.length; si++) {\n\t\t\t\tconst val = series[si].values[ci] ?? 0,\n\t\t\t\t\ty = layout.plotTop + band * ci + groupOffset + step * si,\n\t\t\t\t\tvalX = valueToX(val, range, layout.plotLeft, layout.plotRight),\n\t\t\t\t\tx = Math.min(zeroX, valX),\n\t\t\t\t\tw = Math.max(Math.abs(valX - zeroX), 1);\n\t\t\t\tprimitives.push({\n\t\t\t\t\tkind: 'rect',\n\t\t\t\t\tx,\n\t\t\t\t\ty,\n\t\t\t\t\tw,\n\t\t\t\t\th: singleBarHeight,\n\t\t\t\t\tfill: barFill(chartData, series[si], si, ci),\n\t\t\t\t\trx: 1,\n\t\t\t\t\tpart: { role: 'dataPoint', seriesIndex: si, pointIndex: ci },\n\t\t\t\t\ttitle: buildMarkTooltip(\n\t\t\t\t\t\tseries[si].name,\n\t\t\t\t\t\tcategoryLabels[ci],\n\t\t\t\t\t\tval,\n\t\t\t\t\t\tseries[si].numberFormat,\n\t\t\t\t\t),\n\t\t\t\t} satisfies SvgRect);\n\t\t\t\tif (showLabels) {\n\t\t\t\t\t// c:dLblPos (ctr/inBase/inEnd/outEnd) decides where on the bar the\n\t\t\t\t\t// label sits; a per-point c:dLbl/c:layout drag shifts it further.\n\t\t\t\t\tconst anchor = resolveBarLabelPlacement(\n\t\t\t\t\t\tchartData,\n\t\t\t\t\t\tseries[si],\n\t\t\t\t\t\tci,\n\t\t\t\t\t\t{ x, y, width: w, height: singleBarHeight },\n\t\t\t\t\t\tval,\n\t\t\t\t\t\t'horizontal',\n\t\t\t\t\t\t{ width: layout.svgWidth, height: layout.svgHeight },\n\t\t\t\t\t);\n\t\t\t\t\tdataLabels.push({\n\t\t\t\t\t\tkind: 'text',\n\t\t\t\t\t\tx: anchor.x,\n\t\t\t\t\t\ty: anchor.y,\n\t\t\t\t\t\ttext: formatAxisValue(val, series[si].numberFormat),\n\t\t\t\t\t\tfontSize: DEFAULT_CHART_DATA_LABEL_PX,\n\t\t\t\t\t\tfill: '#334155',\n\t\t\t\t\t\ttextAnchor: anchor.textAnchor,\n\t\t\t\t\t\tdominantBaseline: 'central',\n\t\t\t\t\t\t...dataLabelFontOverride(resolveDataLabelTextStyle(chartData, series[si], ci)),\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t} else {\n\t\tconst totals = isPercent ? categoryTotals(series, catCount) : [],\n\t\t\tbarH = band * (isPercent ? 0.6 : 0.7),\n\t\t\tbarOffset = (band - barH) / 2;\n\t\tfor (let ci = 0; ci < catCount; ci++) {\n\t\t\tlet posRunning = 0,\n\t\t\t\tnegRunning = 0;\n\t\t\tconst catTotal = isPercent ? totals[ci] || 1 : 1;\n\t\t\tfor (let si = 0; si < series.length; si++) {\n\t\t\t\tconst rawVal = series[si].values[ci] ?? 0,\n\t\t\t\t\tval = isPercent ? (rawVal / catTotal) * 100 : rawVal;\n\t\t\t\tif (val === 0) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\t// eslint-disable-next-line one-var -- pre-existing, unrelated to this change\n\t\t\t\tconst isNeg = val < 0,\n\t\t\t\t\tbase = isNeg ? negRunning : posRunning,\n\t\t\t\t\ttop = base + val,\n\t\t\t\t\ty = layout.plotTop + band * ci + barOffset,\n\t\t\t\t\tbaseX = valueToX(base, range, layout.plotLeft, layout.plotRight),\n\t\t\t\t\ttopX = valueToX(top, range, layout.plotLeft, layout.plotRight),\n\t\t\t\t\tx = Math.min(baseX, topX),\n\t\t\t\t\tw = Math.max(Math.abs(topX - baseX), 0.5);\n\t\t\t\tprimitives.push({\n\t\t\t\t\tkind: 'rect',\n\t\t\t\t\tx,\n\t\t\t\t\ty,\n\t\t\t\t\tw,\n\t\t\t\t\th: barH,\n\t\t\t\t\tfill: barFill(chartData, series[si], si, ci),\n\t\t\t\t\trx: 1,\n\t\t\t\t\tpart: { role: 'dataPoint', seriesIndex: si, pointIndex: ci },\n\t\t\t\t\ttitle: buildMarkTooltip(\n\t\t\t\t\t\tseries[si].name,\n\t\t\t\t\t\tcategoryLabels[ci],\n\t\t\t\t\t\trawVal,\n\t\t\t\t\t\tseries[si].numberFormat,\n\t\t\t\t\t),\n\t\t\t\t} satisfies SvgRect);\n\t\t\t\tif (showLabels && Math.abs(val) > 0) {\n\t\t\t\t\tif (isPercent) {\n\t\t\t\t\t\t// A percentStacked segment's label is always centred in the\n\t\t\t\t\t\t// segment (PowerPoint's own convention); dLblPos does not apply.\n\t\t\t\t\t\tdataLabels.push({\n\t\t\t\t\t\t\tkind: 'text',\n\t\t\t\t\t\t\tx: x + w / 2,\n\t\t\t\t\t\t\ty: y + barH / 2,\n\t\t\t\t\t\t\ttext: `${Math.round(val)}%`,\n\t\t\t\t\t\t\tfontSize: DEFAULT_CHART_DATA_LABEL_PX,\n\t\t\t\t\t\t\tfill: '#ffffff',\n\t\t\t\t\t\t\ttextAnchor: 'middle',\n\t\t\t\t\t\t\tdominantBaseline: 'central',\n\t\t\t\t\t\t\tfontWeight: 'bold',\n\t\t\t\t\t\t\t...dataLabelFontOverride(resolveDataLabelTextStyle(chartData, series[si], ci)),\n\t\t\t\t\t\t});\n\t\t\t\t\t} else {\n\t\t\t\t\t\tconst anchor = resolveBarLabelPlacement(\n\t\t\t\t\t\t\tchartData,\n\t\t\t\t\t\t\tseries[si],\n\t\t\t\t\t\t\tci,\n\t\t\t\t\t\t\t{ x, y, width: w, height: barH },\n\t\t\t\t\t\t\trawVal,\n\t\t\t\t\t\t\t'horizontal',\n\t\t\t\t\t\t\t{ width: layout.svgWidth, height: layout.svgHeight },\n\t\t\t\t\t\t);\n\t\t\t\t\t\tdataLabels.push({\n\t\t\t\t\t\t\tkind: 'text',\n\t\t\t\t\t\t\tx: anchor.x,\n\t\t\t\t\t\t\ty: anchor.y,\n\t\t\t\t\t\t\ttext: formatAxisValue(rawVal, series[si].numberFormat),\n\t\t\t\t\t\t\tfontSize: DEFAULT_CHART_DATA_LABEL_PX,\n\t\t\t\t\t\t\tfill: '#334155',\n\t\t\t\t\t\t\ttextAnchor: anchor.textAnchor,\n\t\t\t\t\t\t\tdominantBaseline: 'central',\n\t\t\t\t\t\t\t...dataLabelFontOverride(resolveDataLabelTextStyle(chartData, series[si], ci)),\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif (isNeg) {\n\t\t\t\t\tnegRunning += val;\n\t\t\t\t} else {\n\t\t\t\t\tposRunning += val;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t// eslint-disable-next-line one-var -- pre-existing, unrelated to this change\n\tconst legendPos = chartData.style?.legendPosition ?? 'b',\n\t\t{ legend, legendX, legendY, legendAnchor } = buildLegend(\n\t\t\tseries,\n\t\t\tchartData.colorPalette,\n\t\t\tlayout.svgWidth,\n\t\t\tlegendPos,\n\t\t\tlayout.svgHeight,\n\t\t\tlayout.plotTop,\n\t\t);\n\n\treturn {\n\t\tsvgWidth: layout.svgWidth,\n\t\tsvgHeight: layout.svgHeight,\n\t\ttitle: resolveChartTitleText(chartData),\n\t\ttitleX: layout.svgWidth / 2,\n\t\ttitleY: 12,\n\t\tgridlines,\n\t\taxisLabels,\n\t\tzeroLine,\n\t\tcategoryLabels: buildSideCategoryLabels(categoryLabels, layout),\n\t\tprimitives,\n\t\tdataLabels,\n\t\tlegend: chartData.style?.hasLegend ? legend : [],\n\t\tlegendX,\n\t\tlegendY,\n\t\tlegendAnchor,\n\t};\n}\n","/**\n * chart-overlays-axis-titles.ts: `computeAxisTitlePrimitives`, building\n * `SvgText[]` for the X and Y axis titles. Split out of chart-overlays.ts to\n * keep that module under the repo's file-size guideline.\n *\n * Ported / adapted from:\n * packages/react/src/viewer/utils/chart-chrome.tsx (axis titles)\n *\n * @module chart-overlays-axis-titles\n */\n\nimport type { PptxChartData } from 'pptx-viewer-core';\n\nimport { DEFAULT_CHART_TEXT_PX, chartFontPx } from './chart-font';\nimport type { PlotLayout, SvgText } from './chart-view-model';\n\n/** Fill colour for axis title text. */\nconst AXIS_TITLE_COLOR = '#475569';\n\n/**\n * Build `SvgText[]` for the X and Y axis titles.\n *\n * Axis titles are read from `chartData.axes`:\n * - the primary category axis (`catAx`, `axPos === 'b'`) drives the X title\n * - the primary value axis (`valAx`, `axPos === 'l'` or first `valAx`) drives the Y title\n *\n * **Rotation note**: `SvgText` has no `transform` or `rotate` field. The Y\n * axis title is therefore placed to the left of the plot without rotation and\n * noted inline. If the orchestrator adds a `transform?: string` field to\n * `SvgText` (or a new `SvgTransform` wrapper primitive), the Y title can be\n * rendered rotated -90 degrees by passing\n * `transform: \\`rotate(-90, ${x}, ${y})\\`` (the template expression is\n * straightforward once the field exists).\n *\n * @param chartData Full parsed chart data.\n * @param layout Plot-area bounding box.\n */\nexport function computeAxisTitlePrimitives(\n\tchartData: PptxChartData,\n\tlayout: PlotLayout,\n): SvgText[] {\n\tconst out: SvgText[] = [];\n\tconst axes = chartData.axes;\n\tif (!axes || axes.length === 0) {\n\t\treturn out;\n\t}\n\n\t// Axis-title font: core folds a parsed/edited title size into `axis.fontSize`\n\t// (points); convert at the pt -> px boundary, defaulting to PowerPoint's\n\t// 10 pt chart text. See chart-font.ts.\n\tconst titleFontPx = (axis: { fontSize?: number }): number =>\n\t\taxis.fontSize !== undefined ? chartFontPx(axis.fontSize) : DEFAULT_CHART_TEXT_PX;\n\n\t// X axis title (category axis at bottom).\n\tconst catAxis = axes.find((a) => a.axisType === 'catAx' && a.axPos !== 'r' && a.titleText);\n\tif (catAxis?.titleText) {\n\t\tconst xTitle: SvgText = {\n\t\t\tkind: 'text',\n\t\t\tx: layout.plotLeft + layout.plotWidth / 2,\n\t\t\ty: layout.plotBottom + 22,\n\t\t\ttext: catAxis.titleText,\n\t\t\tfontSize: titleFontPx(catAxis),\n\t\t\tfill: AXIS_TITLE_COLOR,\n\t\t\ttextAnchor: 'middle',\n\t\t\tfontWeight: 'bold',\n\t\t};\n\t\tout.push(xTitle);\n\t}\n\n\t// Y axis title (value axis at left), rotated -90 degrees about its own\n\t// anchor and centred vertically on the plot area.\n\tconst valAxis =\n\t\taxes.find((a) => a.axisType === 'valAx' && a.axPos !== 'r' && a.titleText) ??\n\t\taxes.find((a) => a.axisType === 'valAx' && a.titleText);\n\tif (valAxis?.titleText) {\n\t\tconst yx = 12;\n\t\tconst yy = layout.plotTop + layout.plotHeight / 2;\n\t\tconst yTitle: SvgText = {\n\t\t\tkind: 'text',\n\t\t\tx: yx,\n\t\t\ty: yy,\n\t\t\ttext: valAxis.titleText,\n\t\t\tfontSize: titleFontPx(valAxis),\n\t\t\tfill: AXIS_TITLE_COLOR,\n\t\t\ttextAnchor: 'middle',\n\t\t\tfontWeight: 'bold',\n\t\t\ttransform: `rotate(-90, ${yx}, ${yy})`,\n\t\t};\n\t\tout.push(yTitle);\n\t}\n\n\treturn out;\n}\n","import type { PptxChartData, PptxChartErrBars, PptxChartSeries } from 'pptx-viewer-core';\n\nimport type { PlotLayout, SvgLine, SvgPrimitive, ValueRange } from './chart-view-model';\nimport { valueToY } from './chart-view-model';\n\nconst DEFAULT_COLOR = '#334155';\nconst CAP_HALF_WIDTH = 4;\n\nexport interface ErrorBarRenderOptions {\n\t/** Source point indexes in display order after category/date-axis filtering. */\n\tsourceIndices?: ReadonlyArray<number>;\n\t/** Exact display X positions for reordered category/date points. */\n\txPositions?: ReadonlyArray<number>;\n\t/** Per-series Y ranges, used by secondary-axis combo series. */\n\tseriesRanges?: ReadonlyArray<ValueRange | undefined>;\n\t/** Per-series category mapping mode for mixed bar/line charts. */\n\tseriesModes?: ReadonlyArray<'line' | 'bar' | undefined>;\n\t/**\n\t * A scatter/bubble chart's own nice-scaled X-axis range (see\n\t * `chart-scatter-x-axis.ts`), shared across every series so an X error bar\n\t * anchors to the SAME domain the plotted points use. Without it each\n\t * series fell back to its own tight per-series min/max (`numericXRange`),\n\t * which drifted from the chart-wide domain the dots share once that\n\t * domain gained the automatic scale's headroom/rounding.\n\t */\n\tscatterXRange?: ValueRange;\n}\n\nfunction categoryX(value: number, count: number, layout: PlotLayout, mode: 'line' | 'bar'): number {\n\tif (mode === 'bar') {\n\t\tconst slot = layout.plotWidth / Math.max(count, 1);\n\t\treturn layout.plotLeft + slot * value + slot / 2;\n\t}\n\treturn layout.plotLeft + (value / Math.max(count - 1, 1)) * layout.plotWidth;\n}\n\nfunction positionedCategoryX(\n\tvalue: number,\n\tpositions: ReadonlyArray<number> | undefined,\n\tfallback: (value: number) => number,\n): number {\n\tif (!positions || positions.length === 0) {\n\t\treturn fallback(value);\n\t}\n\tconst lower = Math.floor(value);\n\tconst upper = Math.ceil(value);\n\tconst at = (index: number): number => {\n\t\tif (positions[index] !== undefined) {\n\t\t\treturn positions[index];\n\t\t}\n\t\tconst lastIndex = positions.length - 1;\n\t\tconst last = positions[lastIndex] ?? 0;\n\t\tconst beforeLast =\n\t\t\tlastIndex > 0 ? (positions[lastIndex - 1] ?? positions[0] ?? 0) : (positions[0] ?? 0);\n\t\tconst gap = last - beforeLast;\n\t\treturn last + gap * (index - positions.length + 1);\n\t};\n\treturn at(lower) + (at(upper) - at(lower)) * (value - lower);\n}\n\nfunction numericX(value: number, range: ValueRange, layout: PlotLayout): number {\n\treturn layout.plotLeft + ((value - range.min) / Math.max(range.span, 1e-9)) * layout.plotWidth;\n}\n\nfunction xValuesForSeries(\n\tchartData: PptxChartData,\n\tseries: PptxChartSeries,\n\tindexes: ReadonlyArray<number>,\n): { values: number[]; numeric: boolean } {\n\tconst seriesType = series.seriesChartType ?? chartData.chartType;\n\tconst numeric = seriesType === 'scatter' || seriesType === 'bubble';\n\tif (!numeric) {\n\t\treturn { values: indexes.map((_index, displayIndex) => displayIndex), numeric: false };\n\t}\n\treturn {\n\t\tvalues: indexes.map((index) => {\n\t\t\tconst parsed = Number(chartData.categories[index]);\n\t\t\treturn Number.isFinite(parsed) ? parsed : index;\n\t\t}),\n\t\tnumeric: true,\n\t};\n}\n\nfunction numericXRange(values: number[]): ValueRange {\n\tconst min = Math.min(...values);\n\tconst max = Math.max(...values);\n\treturn { min, max, span: Math.max(max - min, 1) };\n}\n\n/**\n * Sample variance of `values` (Bessel's-corrected, `n - 1` denominator), the\n * same convention Excel's own `STDEV`/`STDEV.S` (and its \"Standard\n * Deviation\"/\"Standard Error\" chart error-bar options) use, not the\n * population variance (`n` denominator) `STDEVP`/`STDEV.P` would give. A\n * single-point series has no sample variance; `n - 1` clamped to 1 keeps the\n * result `0` instead of dividing by zero.\n */\nfunction sampleVariance(values: number[]): number {\n\tconst count = values.length;\n\tif (count === 0) {\n\t\treturn 0;\n\t}\n\tconst mean = values.reduce((sum, value) => sum + value, 0) / count;\n\treturn values.reduce((sum, value) => sum + (value - mean) ** 2, 0) / Math.max(count - 1, 1);\n}\n\nfunction errorValue(\n\terrBars: PptxChartErrBars,\n\tvalues: number[],\n\tdisplayIndex: number,\n\tsourceIndex: number,\n\tdirection: 'plus' | 'minus',\n): number {\n\tswitch (errBars.valType) {\n\t\tcase 'fixedVal':\n\t\t\treturn errBars.val ?? 0;\n\t\tcase 'percentage':\n\t\t\treturn Math.abs(values[displayIndex] ?? 0) * ((errBars.val ?? 0) / 100);\n\t\tcase 'stdDev':\n\t\t\treturn Math.sqrt(sampleVariance(values)) * (errBars.val ?? 1);\n\t\tcase 'stdErr':\n\t\t\treturn Math.sqrt(sampleVariance(values) / Math.max(values.length, 1));\n\t\tcase 'cust':\n\t\t\treturn direction === 'plus'\n\t\t\t\t? (errBars.customPlus?.[sourceIndex] ?? 0)\n\t\t\t\t: (errBars.customMinus?.[sourceIndex] ?? 0);\n\t}\n}\n\nfunction line(x1: number, y1: number, x2: number, y2: number, color: string): SvgLine {\n\treturn { kind: 'line', x1, y1, x2, y2, stroke: color, strokeWidth: 1 };\n}\n\nfunction appendYBar(\n\tout: SvgPrimitive[],\n\terrBars: PptxChartErrBars,\n\tx: number,\n\tbaseValue: number,\n\terror: number,\n\tdirection: 'plus' | 'minus',\n\trange: ValueRange,\n\tlayout: PlotLayout,\n): void {\n\tconst color = errBars.color ?? DEFAULT_COLOR;\n\tconst baseY = valueToY(baseValue, range, layout.plotTop, layout.plotBottom);\n\tconst endValue = direction === 'plus' ? baseValue + error : baseValue - error;\n\tconst endY = valueToY(endValue, range, layout.plotTop, layout.plotBottom);\n\tout.push(line(x, baseY, x, endY, color));\n\tif (!errBars.noEndCap) {\n\t\tout.push(line(x - CAP_HALF_WIDTH, endY, x + CAP_HALF_WIDTH, endY, color));\n\t}\n}\n\nfunction appendXBar(\n\tout: SvgPrimitive[],\n\terrBars: PptxChartErrBars,\n\tbaseXValue: number,\n\terror: number,\n\tdirection: 'plus' | 'minus',\n\ty: number,\n\ttoPixel: (value: number) => number,\n): void {\n\tconst color = errBars.color ?? DEFAULT_COLOR;\n\tconst baseX = toPixel(baseXValue);\n\tconst endValue = direction === 'plus' ? baseXValue + error : baseXValue - error;\n\tconst endX = toPixel(endValue);\n\tout.push(line(baseX, y, endX, y, color));\n\tif (!errBars.noEndCap) {\n\t\tout.push(line(endX, y - CAP_HALF_WIDTH, endX, y + CAP_HALF_WIDTH, color));\n\t}\n}\n\n/** Build X- and Y-direction ChartML error-bar primitives for cartesian series. */\nexport function computeErrorBarPrimitives(\n\tchartData: PptxChartData,\n\tcatCount: number,\n\tlayout: PlotLayout,\n\trange: ValueRange,\n\tmode: 'line' | 'bar' = 'line',\n\toptions: ErrorBarRenderOptions = {},\n): SvgPrimitive[] {\n\tconst out: SvgPrimitive[] = [];\n\tchartData.series.forEach((series, seriesIndex) => {\n\t\tconst indexes = options.sourceIndices ?? series.values.map((_value, index) => index);\n\t\tconst yValues = indexes.map((index) => series.values[index] ?? 0);\n\t\tconst xValues = xValuesForSeries(chartData, series, indexes);\n\t\tconst xRange = xValues.numeric\n\t\t\t? (options.scatterXRange ?? numericXRange(xValues.values))\n\t\t\t: undefined;\n\t\tconst seriesMode = options.seriesModes?.[seriesIndex] ?? mode;\n\t\tconst yRange = options.seriesRanges?.[seriesIndex] ?? range;\n\t\tseries.errBars?.forEach((errBars) => {\n\t\t\tindexes.forEach((sourceIndex, displayIndex) => {\n\t\t\t\tconst yValue = yValues[displayIndex] ?? 0;\n\t\t\t\tconst baseXValue = xValues.values[displayIndex] ?? displayIndex;\n\t\t\t\tconst categoryMapper = (value: number) =>\n\t\t\t\t\tpositionedCategoryX(value, options.xPositions, (index) =>\n\t\t\t\t\t\tcategoryX(index, indexes.length || catCount, layout, seriesMode),\n\t\t\t\t\t);\n\t\t\t\tconst toPixel = xValues.numeric\n\t\t\t\t\t? (value: number) => numericX(value, xRange!, layout)\n\t\t\t\t\t: categoryMapper;\n\t\t\t\tconst x = toPixel(baseXValue);\n\t\t\t\tconst y = valueToY(yValue, yRange, layout.plotTop, layout.plotBottom);\n\t\t\t\tfor (const direction of ['plus', 'minus'] as const) {\n\t\t\t\t\tif (errBars.barType !== direction && errBars.barType !== 'both') {\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\t\t\t\t\tconst values = errBars.direction === 'x' ? xValues.values : yValues;\n\t\t\t\t\tconst error = errorValue(errBars, values, displayIndex, sourceIndex, direction);\n\t\t\t\t\tif (errBars.direction === 'x') {\n\t\t\t\t\t\tappendXBar(out, errBars, baseXValue, error, direction, y, toPixel);\n\t\t\t\t\t} else {\n\t\t\t\t\t\tappendYBar(out, errBars, x, yValue, error, direction, yRange, layout);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t});\n\t\t});\n\t});\n\treturn out;\n}\n","/**\n * chart-trendline-equation-format.ts: Excel-style trendline equation text\n * formatting.\n *\n * Excel's own trendline equation display (`c:trendlineLbl` with\n * `c:dispEq val=\"1\"`) rounds every coefficient to a handful of SIGNIFICANT\n * digits in plain decimal notation, not a fixed number of decimal places: a\n * small slope like 0.003742 stays \"0.003742\"-ish (four significant figures),\n * where `.toFixed(2)` would flatten it to \"0.00\" and silently erase the fit.\n * It also lays out each trendline family in its own fixed shape (exponential\n * as `y = a e^(bx)`, a polynomial in DESCENDING powers), which this module\n * is the single source of truth for so it cannot drift between the fit types.\n *\n * @module chart-trendline-equation-format\n */\n\n/** Excel's own significant-digit count for a trendline equation coefficient. */\nconst SIGNIFICANT_DIGITS = 4;\n\n/**\n * Format one coefficient to `SIGNIFICANT_DIGITS` significant figures in plain\n * decimal notation (falls back to exponential only where `Number#toString`\n * itself would, i.e. extreme magnitudes), with insignificant trailing zeros\n * dropped. `-0` normalises to `\"0\"`.\n */\nexport function formatTrendlineCoefficient(value: number): string {\n\tif (!Number.isFinite(value) || value === 0) {\n\t\treturn '0';\n\t}\n\t// `toPrecision` rounds to N significant digits (possibly as exponential\n\t// notation for extreme magnitudes); round-tripping through `Number` then\n\t// `String` drops insignificant trailing zeros and only KEEPS exponential\n\t// notation where plain decimal would be absurd, matching Excel's own\n\t// General-format display.\n\tconst rounded = Number(value.toPrecision(SIGNIFICANT_DIGITS));\n\treturn rounded === 0 ? '0' : String(rounded);\n}\n\n/** `sign` + `formatted absolute value`, for gluing a term onto a running equation. */\nfunction signedTerm(value: number): { sign: '+' | '-'; abs: string } {\n\treturn { sign: value < 0 ? '-' : '+', abs: formatTrendlineCoefficient(Math.abs(value)) };\n}\n\n/** `y = mx + b` (linear) or `y = mx - b` when the intercept is negative. */\nexport function formatLinearEquation(slope: number, intercept: number): string {\n\tconst { sign, abs } = signedTerm(intercept);\n\treturn `y = ${formatTrendlineCoefficient(slope)}x ${sign} ${abs}`;\n}\n\n/** `y = a e^(bx)`: Excel's own exponential trendline layout. */\nexport function formatExponentialEquation(a: number, b: number): string {\n\treturn `y = ${formatTrendlineCoefficient(a)} e^(${formatTrendlineCoefficient(b)}x)`;\n}\n\n/** `y = a ln(x) + b` (logarithmic), `-` glue when the intercept is negative. */\nexport function formatLogarithmicEquation(slope: number, intercept: number): string {\n\tconst { sign, abs } = signedTerm(intercept);\n\treturn `y = ${formatTrendlineCoefficient(slope)}ln(x) ${sign} ${abs}`;\n}\n\n/** `y = a x^b` (power). */\nexport function formatPowerEquation(a: number, b: number): string {\n\treturn `y = ${formatTrendlineCoefficient(a)}x^${formatTrendlineCoefficient(b)}`;\n}\n\n/**\n * `y = a_n x^n + ... + a_1 x + a_0`: a polynomial in DESCENDING powers of x\n * (Excel's own layout), from `coeffsAscending` ([a0, a1, ..., an], the order\n * `fitPolynomial` returns them in). The highest-order term never shows a\n * redundant leading `+`; `x^1` drops its exponent; the constant term (`x^0`)\n * drops the variable entirely.\n */\nexport function formatPolynomialEquation(coeffsAscending: readonly number[]): string {\n\tconst order = coeffsAscending.length - 1;\n\tlet out = 'y = ';\n\tfor (let power = order; power >= 0; power--) {\n\t\tconst coeff = coeffsAscending[power] ?? 0;\n\t\tconst { sign, abs } = signedTerm(coeff);\n\t\tconst variable = power === 0 ? '' : power === 1 ? 'x' : `x^${power}`;\n\t\tout +=\n\t\t\tpower === order\n\t\t\t\t? `${sign === '-' ? '-' : ''}${abs}${variable}`\n\t\t\t\t: ` ${sign} ${abs}${variable}`;\n\t}\n\treturn out;\n}\n","/**\n * chart-overlays-trendline-fit.ts: per-series trendline point computation\n * (linear / exponential / logarithmic / power / polynomial / moving-average),\n * built on the regression math in chart-overlays-regression.ts. Split out of\n * chart-overlays.ts to keep that module under the repo's file-size guideline.\n *\n * Excel fits a trendline against x = 1, 2, ..., n on a category chart (bar /\n * line / area): the category POSITION, never a 0-based array index. A scatter\n * chart has no categories at all; Excel fits against the series' own real\n * `c:xVal` data instead. Collapsing both cases to a bare 0-based index (the\n * previous behaviour here) shifted every category-chart fit by one unit and\n * made a scatter trendline ignore its own X axis entirely, fitting against\n * point ORDER instead of the X values a reader actually sees on the chart.\n *\n * Ported / adapted from:\n * packages/react/src/viewer/utils/chart-trendlines.tsx (regression engine)\n * packages/shared/src/render/chart-trendlines.ts (shared port)\n *\n * @module chart-overlays-trendline-fit\n */\n\nimport type { PptxChartSeries, PptxChartTrendline } from 'pptx-viewer-core';\n\nimport {\n\tcomputeLinearRegression,\n\tcomputeRSquared,\n\tfitPolynomial,\n} from './chart-overlays-regression';\nimport {\n\tformatExponentialEquation,\n\tformatLinearEquation,\n\tformatLogarithmicEquation,\n\tformatPolynomialEquation,\n\tformatPowerEquation,\n} from './chart-trendline-equation-format';\nimport type { PlotLayout, ValueRange } from './chart-view-model';\nimport { valueToY } from './chart-view-model';\n\n/**\n * Map a (possibly fractional / extrapolated) category index to an X pixel.\n * `mode === 'bar'` centres on category slots; `'line'` anchors at data points.\n * Mirrors `xToPixel` from chart-overlay-utils.ts (React) and the shared port.\n */\nexport function xToPixel(\n\txVal: number,\n\tcatCount: number,\n\tlayout: PlotLayout,\n\tmode: 'line' | 'bar',\n): number {\n\tif (mode === 'bar') {\n\t\tconst slotWidth = layout.plotWidth / Math.max(catCount, 1);\n\t\treturn layout.plotLeft + slotWidth * xVal + slotWidth / 2;\n\t}\n\tconst maxIdx = Math.max(catCount - 1, 1);\n\treturn layout.plotLeft + (xVal / maxIdx) * layout.plotWidth;\n}\n\ninterface TrendlinePoint {\n\tx: number;\n\ty: number;\n}\n\nexport interface ComputedTrend {\n\tpoints: TrendlinePoint[];\n\tequation: string;\n\trSquared: number;\n}\n\n/** A scatter chart's shared X-axis domain, matching `computeScatterDots`' own normalisation. */\nexport interface TrendlineXDomain {\n\tmin: number;\n\tspan: number;\n}\n\n/**\n * Compute the polyline points (and equation / R-squared) for one trendline\n * over a series. Returns empty points when the type is unsupported or data\n * is too sparse.\n *\n * @param xDomain A scatter chart's X-axis domain (from `computeScatterXDomain`),\n * present only when `series.xValues` should be used both for the fit AND for\n * placing the drawn curve. Absent (category charts) fits against x = 1..n and\n * places the curve via the existing 0-based `xToPixel` category convention.\n */\nexport function computeTrendlinePoints(\n\ttrendline: PptxChartTrendline,\n\tseries: PptxChartSeries,\n\tcatCount: number,\n\tlayout: PlotLayout,\n\trange: ValueRange,\n\tmode: 'line' | 'bar',\n\txDomain?: TrendlineXDomain,\n): ComputedTrend {\n\tconst yVals = series.values;\n\tconst n = yVals.length;\n\tif (n < 2) {\n\t\treturn { points: [], equation: '', rSquared: 0 };\n\t}\n\n\tconst useRealX = xDomain !== undefined && (series.xValues?.length ?? 0) >= n;\n\t// Fit-space X: the series' own real data for a scatter chart, else Excel's\n\t// 1-based category position (never a bare 0-based index).\n\tconst xVals = useRealX ? series.xValues!.slice(0, n) : yVals.map((_v, i) => i + 1);\n\n\t// A fit-space X maps to a pixel either through the scatter domain's own\n\t// normalisation (matching `computeScatterDots`, so the curve lines up with\n\t// the actual plotted points) or, for a category chart, through the\n\t// existing 0-based `xToPixel` convention (fitX is 1-based, so shift back).\n\tconst toPixelX = (fitX: number): number =>\n\t\tuseRealX\n\t\t\t? layout.plotLeft +\n\t\t\t\t(xDomain!.span > 0 ? (fitX - xDomain!.min) / xDomain!.span : 0) * layout.plotWidth\n\t\t\t: xToPixel(fitX - 1, catCount, layout, mode);\n\n\tconst forward = trendline.forward ?? 0;\n\tconst backward = trendline.backward ?? 0;\n\tconst minX = Math.min(...xVals);\n\tconst maxX = Math.max(...xVals);\n\tconst startX = minX - backward;\n\tconst endX = maxX + forward;\n\tconst steps = Math.max(Math.ceil((endX - startX) * 4), 20);\n\n\tlet evalFn: (x: number) => number;\n\tlet equation = '';\n\tlet rSquared = 0;\n\n\tswitch (trendline.trendlineType) {\n\t\tcase 'linear': {\n\t\t\tconst reg = computeLinearRegression(xVals, yVals);\n\t\t\tconst fixedIntercept = trendline.intercept;\n\t\t\tconst slope =\n\t\t\t\tfixedIntercept !== undefined\n\t\t\t\t\t? yVals.reduce((s, y, i) => s + (y - fixedIntercept) * xVals[i], 0) /\n\t\t\t\t\t\txVals.reduce((s, x) => s + x * x, 0)\n\t\t\t\t\t: reg.slope;\n\t\t\tconst b = fixedIntercept ?? reg.intercept;\n\t\t\tevalFn = (x) => slope * x + b;\n\t\t\tequation = formatLinearEquation(slope, b);\n\t\t\trSquared = reg.rSquared;\n\t\t\tbreak;\n\t\t}\n\t\tcase 'exponential': {\n\t\t\tconst posY = yVals.filter((y) => y > 0).map((y) => Math.log(y));\n\t\t\tconst posX = xVals.filter((_x, i) => yVals[i] > 0);\n\t\t\tif (posY.length < 2) {\n\t\t\t\treturn { points: [], equation: '', rSquared: 0 };\n\t\t\t}\n\t\t\tconst reg = computeLinearRegression(posX, posY);\n\t\t\tconst a = Math.exp(reg.intercept);\n\t\t\tconst b = reg.slope;\n\t\t\tevalFn = (x) => a * Math.exp(b * x);\n\t\t\tequation = formatExponentialEquation(a, b);\n\t\t\trSquared = reg.rSquared;\n\t\t\tbreak;\n\t\t}\n\t\tcase 'logarithmic': {\n\t\t\tconst posLnX = xVals.filter((x) => x > 0).map((x) => Math.log(x));\n\t\t\tconst filteredY = yVals.filter((_y, i) => xVals[i] > 0);\n\t\t\tif (posLnX.length < 2) {\n\t\t\t\treturn { points: [], equation: '', rSquared: 0 };\n\t\t\t}\n\t\t\tconst reg = computeLinearRegression(posLnX, filteredY);\n\t\t\tevalFn = (x) => (x > 0 ? reg.slope * Math.log(x) + reg.intercept : 0);\n\t\t\tequation = formatLogarithmicEquation(reg.slope, reg.intercept);\n\t\t\trSquared = reg.rSquared;\n\t\t\tbreak;\n\t\t}\n\t\tcase 'power': {\n\t\t\tconst logXArr = xVals.filter((x, i) => x > 0 && yVals[i] > 0).map((x) => Math.log(x));\n\t\t\tconst logYArr = yVals.filter((y, i) => y > 0 && xVals[i] > 0).map((y) => Math.log(y));\n\t\t\tif (logXArr.length < 2) {\n\t\t\t\treturn { points: [], equation: '', rSquared: 0 };\n\t\t\t}\n\t\t\tconst reg = computeLinearRegression(logXArr, logYArr);\n\t\t\tconst a = Math.exp(reg.intercept);\n\t\t\tevalFn = (x) => (x > 0 ? a * x ** reg.slope : 0);\n\t\t\tequation = formatPowerEquation(a, reg.slope);\n\t\t\trSquared = reg.rSquared;\n\t\t\tbreak;\n\t\t}\n\t\tcase 'polynomial': {\n\t\t\tconst order = Math.min(trendline.order ?? 2, 6);\n\t\t\tconst coeffs = fitPolynomial(xVals, yVals, order);\n\t\t\tevalFn = (x) => coeffs.reduce((s, c, i) => s + c * x ** i, 0);\n\t\t\tequation = formatPolynomialEquation(coeffs);\n\t\t\trSquared = computeRSquared(xVals, yVals, evalFn);\n\t\t\tbreak;\n\t\t}\n\t\tcase 'movingAvg': {\n\t\t\tconst period = trendline.period ?? 2;\n\t\t\tconst maPoints: TrendlinePoint[] = [];\n\t\t\tfor (let i = period - 1; i < n; i++) {\n\t\t\t\tlet sum = 0;\n\t\t\t\tfor (let j = i - period + 1; j <= i; j++) {\n\t\t\t\t\tsum += yVals[j];\n\t\t\t\t}\n\t\t\t\tconst avgVal = sum / period;\n\t\t\t\tconst px = toPixelX(xVals[i]);\n\t\t\t\tconst py = valueToY(avgVal, range, layout.plotTop, layout.plotBottom);\n\t\t\t\tmaPoints.push({ x: px, y: py });\n\t\t\t}\n\t\t\treturn {\n\t\t\t\tpoints: maPoints,\n\t\t\t\tequation: `${period}-period moving average`,\n\t\t\t\trSquared: 0,\n\t\t\t};\n\t\t}\n\t\tdefault:\n\t\t\treturn { points: [], equation: '', rSquared: 0 };\n\t}\n\n\tconst points: TrendlinePoint[] = [];\n\tfor (let step = 0; step <= steps; step++) {\n\t\tconst xVal = startX + ((endX - startX) * step) / steps;\n\t\tconst yVal = evalFn(xVal);\n\t\tif (!Number.isFinite(yVal)) {\n\t\t\tcontinue;\n\t\t}\n\t\tconst px = toPixelX(xVal);\n\t\tconst py = valueToY(yVal, range, layout.plotTop, layout.plotBottom);\n\t\tpoints.push({ x: px, y: py });\n\t}\n\n\treturn { points, equation, rSquared };\n}\n","/**\n * chart-overlays-trendline.ts: public `computeTrendlinePrimitives` API,\n * turning each series' `computeTrendlinePoints` fit into `SvgPrimitive[]`.\n * Split out of chart-overlays.ts to keep that module under the repo's\n * file-size guideline.\n *\n * Ported / adapted from:\n * packages/react/src/viewer/utils/chart-trendlines.tsx (regression engine)\n * packages/shared/src/render/chart-trendlines.ts (shared port)\n *\n * @module chart-overlays-trendline\n */\n\nimport type { PptxChartData, PptxChartSeries, PptxChartTrendline } from 'pptx-viewer-core';\n\nimport { DEFAULT_CHART_DATA_LABEL_PX } from './chart-font';\nimport { applyLabelManualLayout } from './chart-manual-layout';\nimport { computeTrendlinePoints } from './chart-overlays-trendline-fit';\nimport { DEFAULT_TRENDLINE_DASH, DEFAULT_TRENDLINE_WIDTH } from './chart-trendline-defaults';\nimport type { PlotLayout, SvgPath, SvgPrimitive, SvgText, ValueRange } from './chart-view-model';\nimport {\n\tcomputeScatterXDomain,\n\tformatAxisValue,\n\tseriesColor,\n\tseriesXValues,\n} from './chart-view-model';\nimport { buildDashArray } from './connector-dash';\n\n/** Vertical gap between the equation line and the R-squared line below it. */\nconst LABEL_LINE_HEIGHT = 12;\n\n/**\n * Build `SvgPrimitive[]` for all trendlines declared by every series in\n * `chartData`. Returns an empty array when no series declares a trendline.\n *\n * Each trendline produces:\n * - one `SvgPath` (dashed polyline in the series / trendline colour,\n * honouring the trendline's own `c:spPr` dash style and width), and\n * - optionally one `SvgText` per label line (the equation, then R-squared\n * on its OWN line below it, matching PowerPoint's own two-line label\n * rather than one line joined with a separator).\n *\n * A scatter chart's series fits (and draws) against its own real `c:xVal`\n * data; every other cartesian kind fits against the category position\n * (1-based, Excel's own convention), never a bare 0-based array index. See\n * `chart-overlays-trendline-fit.ts`.\n *\n * @param chartData Full parsed chart data.\n * @param catCount Number of categories (x-slots), e.g. `chartData.categories.length || 1`.\n * @param layout Plot-area bounding box from `computePlotLayout`.\n * @param range Value-axis range from `computeValueRange` / `computeStackedValueRange`.\n * @param mode `'bar'` for bar/column, `'line'` for line/area/scatter.\n * @param colorPalette Optional resolved palette (same as passed to `seriesColor`).\n */\nexport function computeTrendlinePrimitives(\n\tchartData: PptxChartData,\n\tcatCount: number,\n\tlayout: PlotLayout,\n\trange: ValueRange,\n\tmode: 'line' | 'bar' = 'line',\n\tcolorPalette?: readonly string[],\n): SvgPrimitive[] {\n\tconst out: SvgPrimitive[] = [];\n\t// Only a scatter chart's own real X data changes the fit; every other\n\t// cartesian kind (including bubble, which cannot carry a trendline at\n\t// all) keeps the category-position convention `computeTrendlinePoints`\n\t// falls back to when `xDomain` is `undefined`.\n\tconst xDomain =\n\t\tchartData.chartType === 'scatter'\n\t\t\t? computeScatterXDomain(chartData.series.map((s) => seriesXValues(chartData, s)))\n\t\t\t: undefined;\n\n\tchartData.series.forEach((series: PptxChartSeries, si: number) => {\n\t\tif (!series.trendlines || series.trendlines.length === 0) {\n\t\t\treturn;\n\t\t}\n\n\t\tseries.trendlines.forEach((tl: PptxChartTrendline) => {\n\t\t\tconst { points, equation, rSquared } = computeTrendlinePoints(\n\t\t\t\ttl,\n\t\t\t\tseries,\n\t\t\t\tcatCount,\n\t\t\t\tlayout,\n\t\t\t\trange,\n\t\t\t\tmode,\n\t\t\t\txDomain,\n\t\t\t);\n\t\t\tif (points.length < 2) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst pathD = points\n\t\t\t\t.map((p, i) => `${i === 0 ? 'M' : 'L'} ${p.x.toFixed(2)} ${p.y.toFixed(2)}`)\n\t\t\t\t.join(' ');\n\t\t\tconst strokeColor = tl.color ?? seriesColor(series, si, colorPalette);\n\t\t\tconst strokeWidth = tl.lineWidth ?? DEFAULT_TRENDLINE_WIDTH;\n\n\t\t\tconst pathPrimitive: SvgPath = {\n\t\t\t\tkind: 'path',\n\t\t\t\td: pathD,\n\t\t\t\tfill: 'none',\n\t\t\t\tstroke: strokeColor,\n\t\t\t\tstrokeWidth,\n\t\t\t\tdashArray: buildDashArray(tl.lineDashStyle ?? DEFAULT_TRENDLINE_DASH, strokeWidth),\n\t\t\t};\n\t\t\tout.push(pathPrimitive);\n\n\t\t\tconst labelLines: string[] = [];\n\t\t\tif (tl.displayEq && equation) {\n\t\t\t\tlabelLines.push(equation);\n\t\t\t}\n\t\t\tif (tl.displayRSq) {\n\t\t\t\t// `c:trendlineLbl/c:numFmt`: an explicit format code wins over the\n\t\t\t\t// default fixed 4-decimal display; `sourceLinked` (or no numFmt at\n\t\t\t\t// all) keeps that default, matching PowerPoint's own R-squared display.\n\t\t\t\tconst numberFormat =\n\t\t\t\t\ttl.label && tl.label.sourceLinked === false ? tl.label.numberFormatCode : undefined;\n\t\t\t\tlabelLines.push(\n\t\t\t\t\tnumberFormat\n\t\t\t\t\t\t? `R² = ${formatAxisValue(rSquared, numberFormat)}`\n\t\t\t\t\t\t: `R² = ${rSquared.toFixed(4)}`,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tif (labelLines.length > 0) {\n\t\t\t\tconst last = points[points.length - 1];\n\t\t\t\t// `c:trendlineLbl/c:layout/c:manualLayout`: a dragged label wins over\n\t\t\t\t// the default \"hug the trendline's last point\" anchor.\n\t\t\t\tconst anchor = applyLabelManualLayout(\n\t\t\t\t\ttl.label?.layout,\n\t\t\t\t\t{ width: layout.svgWidth, height: layout.svgHeight },\n\t\t\t\t\t{ x: last.x, y: last.y - 6 },\n\t\t\t\t);\n\t\t\t\tlabelLines.forEach((line, lineIndex) => {\n\t\t\t\t\tout.push({\n\t\t\t\t\t\tkind: 'text',\n\t\t\t\t\t\tx: anchor.x,\n\t\t\t\t\t\ty: anchor.y + lineIndex * LABEL_LINE_HEIGHT,\n\t\t\t\t\t\ttext: line,\n\t\t\t\t\t\tfontSize: DEFAULT_CHART_DATA_LABEL_PX,\n\t\t\t\t\t\tfill: strokeColor,\n\t\t\t\t\t\ttextAnchor: 'end',\n\t\t\t\t\t} satisfies SvgText);\n\t\t\t\t});\n\t\t\t}\n\t\t});\n\t});\n\n\treturn out;\n}\n","/**\n * chart-cartesian.ts: enriched cartesian (bar / line / area / scatter / bubble)\n * chart view-model builder.\n *\n * Shared cartesian rendering covers value axes, category axes, secondary axes,\n * stacking, interaction metadata, and overlays.\n *\n * @module chart-cartesian\n */\nimport type { PptxChartData, PptxElement } from 'pptx-viewer-core';\n\nimport { resolveChartTitleText } from './chart-auto-title';\nimport {\n\tcomputeLayoutOptions,\n\tcomputeValueRangeForAxis,\n\tcomputeValueRangeForChart,\n\tsplitSeriesByAxis,\n} from './chart-axis';\nimport { buildAreas } from './chart-cartesian-area';\nimport { buildCartesianAxes } from './chart-cartesian-axes';\nimport { buildBars } from './chart-cartesian-bars';\nimport { buildBubbles } from './chart-cartesian-bubbles';\nimport { buildLines } from './chart-cartesian-line-area';\nimport { buildScatter } from './chart-cartesian-plots';\nimport type { SeriesPlotResult } from './chart-cartesian-plots';\nimport { computeDataTablePrimitives } from './chart-data-table-render';\nimport { computeHelperLinePrimitives } from './chart-helper-lines';\nimport { buildCartesianHorizontalAxis } from './chart-horizontal-axis';\nimport { buildHorizontalBarViewModel } from './chart-horizontal-bars';\nimport { resolveLegendSwatchKind } from './chart-legend-swatch';\nimport {\n\tcomputeAxisTitlePrimitives,\n\tcomputeErrorBarPrimitives,\n\tcomputeTrendlinePrimitives,\n} from './chart-overlays';\nimport { buildScatterXAxisPlan } from './chart-scatter-x-axis';\nimport type {\n\tChartValueDrag,\n\tChartViewModel,\n\tSupportedChartKind,\n\tSvgPrimitive,\n\tValueRange,\n} from './chart-view-model';\nimport {\n\tbuildLegend,\n\tbuildZeroLine,\n\tcomputePlotLayout,\n\tcomputeStackedValueRange,\n} from './chart-view-model';\n\nfunction stackedRange(\n\tchartData: PptxChartData,\n\tcatCount: number,\n\tisPercent: boolean,\n\tplotHeightPx: number,\n): ValueRange {\n\tif (isPercent) {\n\t\treturn { min: 0, max: 100, span: 100 };\n\t}\n\treturn computeStackedValueRange(chartData.series, catCount, plotHeightPx);\n}\n\n/**\n * Build the enriched cartesian view-model for bar / line / area / scatter /\n * bubble charts. Honours log axes, display units, secondary value axes,\n * percentStacked normalisation, and overlay/data-table depth, while staying\n * byte-identical to the original builder when none of those features is present.\n */\nexport function buildCartesianViewModel(\n\telement: PptxElement,\n\tchartData: PptxChartData,\n\tcategoryLabels: ReadonlyArray<string>,\n\tkind: SupportedChartKind,\n): ChartViewModel {\n\t// `c:barDir val=\"bar\"`: PowerPoint's horizontal Bar chart is the transpose\n\t// of this column-oriented engine, so it gets its own dedicated builder.\n\tif (kind === 'bar' && chartData.barDirection === 'bar') {\n\t\treturn buildHorizontalBarViewModel(element, chartData, categoryLabels);\n\t}\n\tconst seriesCount = chartData.series.length;\n\t// eslint-disable-next-line one-var -- pre-existing, unrelated to this change\n\tconst layoutOpts = computeLayoutOptions(chartData.axes, chartData.dataTable, seriesCount);\n\t// eslint-disable-next-line one-var -- pre-existing, unrelated to this change\n\tconst layout = computePlotLayout(element.width, element.height, chartData, true, layoutOpts);\n\t// eslint-disable-next-line one-var -- pre-existing, unrelated to this change\n\tconst catCount = Math.max(categoryLabels.length, 1);\n\n\t// Stacking applies to bar, line and area (`GROUPING_SUPPORTED_TYPES` in\n\t// chart-editor-options.ts, and lineChart/areaChart both parse a real\n\t// `c:grouping`): a stacked or percentStacked line/area chart must render\n\t// running-sum geometry and go static (no value-drag) the same way stacked\n\t// bar segments do, not silently fall back to clustered/draggable.\n\t// eslint-disable-next-line one-var -- pre-existing, unrelated to this change\n\tconst isStacked =\n\t\t(kind === 'bar' || kind === 'line' || kind === 'area') &&\n\t\t(chartData.grouping === 'stacked' || chartData.grouping === 'percentStacked');\n\t// eslint-disable-next-line one-var -- pre-existing, unrelated to this change\n\tconst isPercent = isStacked && chartData.grouping === 'percentStacked';\n\n\t// Split series across primary/secondary value axes (clustered cartesian only).\n\t// eslint-disable-next-line one-var -- pre-existing, unrelated to this change\n\tconst { secondary } = splitSeriesByAxis(chartData.series, chartData.axes);\n\t// eslint-disable-next-line one-var -- pre-existing, unrelated to this change\n\tconst secondaryIdx = new Set<number>(secondary.map((e) => e.index));\n\t// eslint-disable-next-line one-var -- pre-existing, unrelated to this change\n\tconst useSecondary = !isStacked && secondaryIdx.size > 0;\n\t// eslint-disable-next-line one-var -- pre-existing, unrelated to this change\n\tconst primaryPlotSeries = useSecondary\n\t\t? chartData.series.filter((_s, i) => !secondaryIdx.has(i))\n\t\t: chartData.series;\n\t// eslint-disable-next-line one-var -- pre-existing, unrelated to this change\n\tconst secondaryPlotSeries = useSecondary\n\t\t? chartData.series.filter((_s, i) => secondaryIdx.has(i))\n\t\t: [];\n\n\t// eslint-disable-next-line one-var -- pre-existing, unrelated to this change\n\tconst primaryAxis = chartData.axes?.find(\n\t\t(axis) => axis.axisType === 'valAx' && axis.axPos !== 'r',\n\t);\n\t// eslint-disable-next-line one-var -- pre-existing, unrelated to this change\n\tconst primaryRange = isStacked\n\t\t? {\n\t\t\t\t...stackedRange(chartData, catCount, isPercent, layout.autoPlotHeight),\n\t\t\t\t...(primaryAxis?.orientation === 'maxMin' ? { reverseOrder: true } : {}),\n\t\t\t}\n\t\t: computeValueRangeForChart(\n\t\t\t\tprimaryPlotSeries.length > 0 ? primaryPlotSeries : chartData.series,\n\t\t\t\tchartData.axes,\n\t\t\t\tlayout.autoPlotHeight,\n\t\t\t);\n\t// eslint-disable-next-line one-var -- pre-existing, unrelated to this change\n\tconst secondaryRange =\n\t\tuseSecondary && secondaryPlotSeries.length > 0\n\t\t\t? computeValueRangeForAxis(\n\t\t\t\t\tsecondaryPlotSeries,\n\t\t\t\t\tchartData.axes?.find((axis) => axis.axisType === 'valAx' && axis.axPos === 'r'),\n\t\t\t\t\tlayout.autoPlotHeight,\n\t\t\t\t)\n\t\t\t: undefined;\n\n\t// eslint-disable-next-line one-var -- pre-existing, unrelated to this change\n\tconst axisRes = buildCartesianAxes(chartData, layout, primaryRange, secondaryRange, catCount);\n\t// A scatter/bubble X axis is a real value axis (`c:valAx/@axPos=\"b\"`), not\n\t// the category-slot axis other kinds draw: nice bounds + vertical\n\t// gridlines + real tick labels. See `chart-scatter-x-axis.ts`.\n\t// eslint-disable-next-line one-var -- pre-existing, unrelated to this change\n\tconst scatterXAxis =\n\t\tkind === 'scatter' || kind === 'bubble' ? buildScatterXAxisPlan(chartData, layout) : undefined;\n\t// eslint-disable-next-line one-var -- pre-existing, unrelated to this change\n\tconst zeroLine = primaryRange.logScale ? undefined : buildZeroLine(primaryRange, layout);\n\t// eslint-disable-next-line one-var -- pre-existing, unrelated to this change\n\tconst horizontalAxis = buildCartesianHorizontalAxis(\n\t\tchartData,\n\t\tcategoryLabels,\n\t\tlayout,\n\t\tkind,\n\t\tprimaryRange,\n\t\tsecondaryRange,\n\t);\n\t// eslint-disable-next-line one-var -- pre-existing, unrelated to this change\n\tconst { catAxisStyle, sourceIndices, displayChartData } = horizontalAxis;\n\n\t// eslint-disable-next-line one-var -- pre-existing, unrelated to this change\n\tconst legendPos = chartData.style?.legendPosition ?? 'b';\n\t// eslint-disable-next-line one-var -- pre-existing, unrelated to this change\n\tconst { legend, legendX, legendY, legendAnchor } = buildLegend(\n\t\tchartData.series,\n\t\tchartData.colorPalette,\n\t\tlayout.svgWidth,\n\t\tlegendPos,\n\t\tlayout.svgHeight,\n\t\tlayout.plotTop,\n\t\tresolveLegendSwatchKind(kind),\n\t);\n\n\tlet plot: SeriesPlotResult;\n\tif (kind === 'bar') {\n\t\tplot = buildBars(\n\t\t\tchartData,\n\t\t\tcatCount,\n\t\t\tlayout,\n\t\t\tprimaryRange,\n\t\t\tsecondaryRange,\n\t\t\tsecondaryIdx,\n\t\t\tisStacked ? (isPercent ? 'percentStacked' : 'stacked') : 'clustered',\n\t\t\tsourceIndices,\n\t\t);\n\t} else if (kind === 'line') {\n\t\tplot = buildLines(\n\t\t\tchartData,\n\t\t\tcatCount,\n\t\t\tlayout,\n\t\t\tprimaryRange,\n\t\t\tsecondaryRange,\n\t\t\tsecondaryIdx,\n\t\t\tsourceIndices,\n\t\t\thorizontalAxis.xPositions,\n\t\t\tisStacked ? (isPercent ? 'percentStacked' : 'stacked') : 'clustered',\n\t\t);\n\t} else if (kind === 'area') {\n\t\tplot = buildAreas(\n\t\t\tchartData,\n\t\t\tcatCount,\n\t\t\tlayout,\n\t\t\tprimaryRange,\n\t\t\tsourceIndices,\n\t\t\thorizontalAxis.xPositions,\n\t\t\tisStacked ? (isPercent ? 'percentStacked' : 'stacked') : 'clustered',\n\t\t);\n\t} else if (kind === 'scatter') {\n\t\tplot = buildScatter(chartData, layout, primaryRange);\n\t} else {\n\t\tplot = buildBubbles(chartData, layout, primaryRange);\n\t}\n\n\t// Drop lines / hi-low lines / up-down bars (line + area kinds). Drawn behind\n\t// the series marks so the data stays legible on top.\n\t// eslint-disable-next-line one-var -- pre-existing, unrelated to this change\n\tconst helperLines =\n\t\tkind === 'line' || kind === 'area'\n\t\t\t? computeHelperLinePrimitives(chartData, layout, primaryRange, catCount, {\n\t\t\t\t\tmode: 'line',\n\t\t\t\t\txPositions: horizontalAxis.xPositions,\n\t\t\t\t})\n\t\t\t: [];\n\n\t// eslint-disable-next-line one-var -- pre-existing, unrelated to this change\n\tconst primitives: SvgPrimitive[] = [\n\t\t...helperLines,\n\t\t...plot.primitives,\n\t\t...horizontalAxis.tickMarks,\n\t];\n\n\t// Overlays (depth): regression trendlines, error bars, axis titles, data table.\n\t// eslint-disable-next-line one-var -- pre-existing, unrelated to this change\n\tconst overlays: SvgPrimitive[] = [\n\t\t...computeTrendlinePrimitives(\n\t\t\tdisplayChartData,\n\t\t\tcatCount,\n\t\t\tlayout,\n\t\t\tprimaryRange,\n\t\t\tcatAxisStyle,\n\t\t\tchartData.colorPalette,\n\t\t),\n\t\t...computeErrorBarPrimitives(displayChartData, catCount, layout, primaryRange, catAxisStyle, {\n\t\t\tscatterXRange: scatterXAxis?.range,\n\t\t}),\n\t\t...computeAxisTitlePrimitives(chartData, layout),\n\t];\n\t// eslint-disable-next-line one-var -- pre-existing, unrelated to this change\n\tconst dataTablePrims = computeDataTablePrimitives(\n\t\tdisplayChartData,\n\t\tlayout,\n\t\tchartData.colorPalette,\n\t);\n\n\tprimitives.push(...overlays, ...dataTablePrims);\n\n\t// eslint-disable-next-line one-var -- pre-existing, unrelated to this change\n\tconst title = resolveChartTitleText(chartData);\n\n\t// Vertical drag-to-value only has a single-value meaning for un-stacked marks:\n\t// stacked/percentStacked bar segments sit on running sums, so dragging one\n\t// would not track the pointer.\n\t// eslint-disable-next-line one-var -- pre-existing, unrelated to this change\n\tconst valueDrag: ChartValueDrag | undefined = isStacked\n\t\t? undefined\n\t\t: {\n\t\t\t\trange: primaryRange,\n\t\t\t\tsecondaryRange,\n\t\t\t\tsecondarySeriesIndexes: useSecondary ? [...secondaryIdx] : undefined,\n\t\t\t\tplotTop: layout.plotTop,\n\t\t\t\tplotBottom: layout.plotBottom,\n\t\t\t};\n\n\treturn {\n\t\tsvgWidth: layout.svgWidth,\n\t\tsvgHeight: layout.svgHeight,\n\t\ttitle,\n\t\ttitleX: layout.svgWidth / 2,\n\t\ttitleY: 12,\n\t\tgridlines: scatterXAxis?.range\n\t\t\t? [...axisRes.gridlines, ...scatterXAxis.gridlines]\n\t\t\t: axisRes.gridlines,\n\t\taxisLabels: axisRes.axisLabels,\n\t\tzeroLine,\n\t\tcategoryLabels: scatterXAxis?.range ? scatterXAxis.labels : horizontalAxis.labels,\n\t\tprimitives,\n\t\tdataLabels: plot.dataLabels,\n\t\tlegend: chartData.style?.hasLegend ? legend : [],\n\t\tlegendX,\n\t\tlegendY,\n\t\tlegendAnchor,\n\t\tsecondaryGridlines: axisRes.secondaryGridlines,\n\t\tsecondaryAxisLabels: axisRes.secondaryAxisLabels,\n\t\toverlays: overlays.length > 0 ? overlays : undefined,\n\t\tdataTable: dataTablePrims.length > 0 ? dataTablePrims : undefined,\n\t\tvalueDrag,\n\t};\n}\n","/**\n * chart-stock-close-label.ts: the close-price data label for a stock\n * (HLC/OHLC) chart candle (limitations.md \"Stock/candlestick 'close' label\").\n *\n * The candle body/wick geometry lives in `chart-combo-stock.ts`; this module\n * owns only the close series' own data label, which used to be a fixed\n * `formatAxisValue(close)` string drawn a constant 4px above the candle's\n * high point regardless of the close series' own `c:dLbls`/`c:dLbl` content\n * flags, number format, or `c:dLblPos`. Routing it through the same\n * `buildDataLabelText`/`resolveMarkerLabelPlacement` cascade every other\n * chart kind's markers use (CLAUDE.md Rule 2: one shared pipeline, not a\n * stock-specific reimplementation) fixes all three at once and adds\n * per-point manual-drag support for free.\n *\n * @module chart-stock-close-label\n */\nimport type { PptxChartData, PptxChartSeries } from 'pptx-viewer-core';\n\nimport { resolveMarkerLabelPlacement } from './chart-data-label-anchor';\nimport {\n\tbuildDataLabelText,\n\tdataLabelFontOverride,\n\tresolveDataLabelTextStyle,\n} from './chart-data-label-text';\nimport { DEFAULT_CHART_DATA_LABEL_PX } from './chart-font';\nimport type { SvgText } from './chart-view-model';\n\n/**\n * Build the close series' own label for one candle. Returns `undefined` when\n * the label resolves to nothing (deleted, or every content flag off), same\n * as every other `buildDataLabelText` consumer.\n *\n * `x`/`closeY` are the candle's own tick position (the close value's pixel\n * coordinate), not the candle's high point: PowerPoint anchors this label to\n * the close tick, defaulting to its right (`'r'`) when the close series'\n * `c:dLblPos` cascade authored no position, distinct from line/scatter\n * markers' own \"above the point\" default.\n */\nexport function buildStockCloseLabel(\n\tchartData: PptxChartData,\n\tcloseSeries: PptxChartSeries,\n\tsourceIndex: number,\n\tclose: number,\n\tx: number,\n\tcloseY: number,\n\tframe: { width: number; height: number },\n): SvgText | undefined {\n\tconst label = buildDataLabelText({\n\t\tchartData,\n\t\tseries: closeSeries,\n\t\tpointIndex: sourceIndex,\n\t\tvalue: close,\n\t});\n\tif (label === undefined) {\n\t\treturn undefined;\n\t}\n\tconst anchor = resolveMarkerLabelPlacement(\n\t\tchartData,\n\t\tcloseSeries,\n\t\tsourceIndex,\n\t\t{ x, y: closeY },\n\t\tframe,\n\t\t6,\n\t\t'r',\n\t);\n\treturn {\n\t\tkind: 'text',\n\t\tx: anchor.x,\n\t\ty: anchor.y,\n\t\ttext: label.text,\n\t\tfontSize: DEFAULT_CHART_DATA_LABEL_PX,\n\t\tfill: label.color ?? '#334155',\n\t\ttextAnchor: anchor.textAnchor,\n\t\t...(anchor.dominantBaseline ? { dominantBaseline: anchor.dominantBaseline } : {}),\n\t\t...dataLabelFontOverride(resolveDataLabelTextStyle(chartData, closeSeries, sourceIndex)),\n\t};\n}\n","/**\n * chart-stock-candles.ts: shared HLC/OHLC candle geometry (hi-lo wick, close\n * tick, candle body) for a stock chart's price series.\n *\n * PowerPoint draws two distinct shapes depending on whether an Open series is\n * present:\n * - HLC (High/Low/Close, no Open): a vertical hi-lo wick with NO body, plus\n * a short horizontal tick at the close value (`c:upDownBars` is absent).\n * - OHLC (Open/High/Low/Close): the same wick, plus a candle body from open\n * to close, filled from `c:upDownBars/c:upBars`(`downBars`) - never a\n * hardcoded colour, and never green/red by default (PowerPoint's own\n * default is white-ish up / dark down, see `DEFAULT_UP_FILL`/`DEFAULT_DOWN_FILL`).\n *\n * Used by both a standalone stock chart (`chart-combo-stock.ts`) and the\n * price portion of a volume+stock combo (`chart-combo.ts`, where a\n * `c:barChart` volume series sits alongside `c:stockChart` price series on a\n * secondary axis): one geometry function fixes the visual for both call\n * sites at once (CLAUDE.md Rule 2).\n *\n * @module chart-stock-candles\n */\nimport type { PptxChartData, PptxChartSeries } from 'pptx-viewer-core';\n\nimport { seriesColor } from './chart-helpers';\nimport { buildStockCloseLabel } from './chart-stock-close-label';\nimport type {\n\tPlotLayout,\n\tSvgLine,\n\tSvgPrimitive,\n\tSvgRect,\n\tSvgText,\n\tValueRange,\n} from './chart-view-model';\nimport { valueToY } from './chart-view-model';\n\n/** PowerPoint's own default up/down bar fill when a stock chart carries no `c:upDownBars`. */\nconst DEFAULT_UP_FILL = '#FFFFFF';\nconst DEFAULT_DOWN_FILL = '#404040';\nconst DEFAULT_WICK_COLOR = '#334155';\n\n/** The resolved price series for one candle group, in OOXML stock-series order. */\nexport interface StockCandleSeries {\n\t/** Present only for OHLC; its absence is what selects the HLC (tick) rendering. */\n\topen?: PptxChartSeries;\n\thigh: PptxChartSeries;\n\tlow: PptxChartSeries;\n\tclose: PptxChartSeries;\n\t/** `close`'s index within `chartData.series`, for its own colour and data-point tagging. */\n\tcloseIndex: number;\n}\n\n/**\n * Build the wick + (tick or body) primitives for every category. `range` and\n * `xPositions` are the caller's own axis placement, so this same function\n * serves a standalone stock chart (primary axis) and a volume-combo's price\n * series (typically the secondary axis) alike.\n */\nexport function computeStockCandlePrimitives(\n\tseriesSet: StockCandleSeries,\n\tchartData: PptxChartData,\n\tlayout: PlotLayout,\n\trange: ValueRange,\n\tcatCount: number,\n\tsourceIndices: ReadonlyArray<number>,\n\txPositions: ReadonlyArray<number> | undefined,\n): SvgPrimitive[] {\n\tconst { open, high, low, close, closeIndex } = seriesSet;\n\tconst primitives: SvgPrimitive[] = [];\n\tconst barGroupWidth = layout.plotWidth / Math.max(catCount, 1);\n\tconst candleWidth = barGroupWidth * 0.5;\n\tconst tickHalfWidth = Math.max(candleWidth * 0.4, 4);\n\tconst wickColor = chartData.hiLowLines?.color ?? DEFAULT_WICK_COLOR;\n\tconst wickWidth = chartData.hiLowLines?.width ?? 1;\n\tconst closeColor = seriesColor(\n\t\tclose,\n\t\tcloseIndex,\n\t\tchartData.style?.styleId,\n\t\tchartData.colorPalette,\n\t);\n\tconst upDownBars = chartData.upDownBars;\n\n\tfor (let displayIndex = 0; displayIndex < catCount; displayIndex++) {\n\t\tconst sourceIndex = sourceIndices[displayIndex] ?? displayIndex;\n\t\tconst highVal = high.values[sourceIndex];\n\t\tconst lowVal = low.values[sourceIndex];\n\t\tif (highVal === undefined || lowVal === undefined) {\n\t\t\tcontinue;\n\t\t}\n\t\tconst closeVal = close.values[sourceIndex];\n\t\tconst cx =\n\t\t\txPositions?.[displayIndex] ??\n\t\t\tlayout.plotLeft + barGroupWidth * displayIndex + barGroupWidth / 2;\n\t\tconst highY = valueToY(highVal, range, layout.plotTop, layout.plotBottom);\n\t\tconst lowY = valueToY(lowVal, range, layout.plotTop, layout.plotBottom);\n\n\t\tprimitives.push({\n\t\t\tkind: 'line',\n\t\t\tx1: cx,\n\t\t\ty1: highY,\n\t\t\tx2: cx,\n\t\t\ty2: lowY,\n\t\t\tstroke: wickColor,\n\t\t\tstrokeWidth: wickWidth,\n\t\t} satisfies SvgLine);\n\n\t\tconst openVal = open?.values[sourceIndex];\n\t\tif (open && openVal !== undefined && closeVal !== undefined) {\n\t\t\t// OHLC: a filled candle body from open to close, coloured by the\n\t\t\t// chart's own up/down bar formatting (never a hardcoded palette).\n\t\t\tconst isUp = closeVal >= openVal;\n\t\t\tconst openY = valueToY(openVal, range, layout.plotTop, layout.plotBottom);\n\t\t\tconst closeY = valueToY(closeVal, range, layout.plotTop, layout.plotBottom);\n\t\t\tconst barProps = isUp ? upDownBars?.upBars : upDownBars?.downBars;\n\t\t\tprimitives.push({\n\t\t\t\tkind: 'rect',\n\t\t\t\tx: cx - candleWidth / 2,\n\t\t\t\ty: Math.min(openY, closeY),\n\t\t\t\tw: candleWidth,\n\t\t\t\th: Math.max(Math.abs(openY - closeY), 1),\n\t\t\t\tfill: barProps?.fillColor ?? (isUp ? DEFAULT_UP_FILL : DEFAULT_DOWN_FILL),\n\t\t\t\tpart: { role: 'dataPoint', seriesIndex: closeIndex, pointIndex: sourceIndex },\n\t\t\t} satisfies SvgRect);\n\t\t} else if (closeVal !== undefined) {\n\t\t\t// HLC: no body. A short tick to the right of the wick marks the close,\n\t\t\t// coloured like the Close series itself (matches PowerPoint's legend).\n\t\t\tconst closeY = valueToY(closeVal, range, layout.plotTop, layout.plotBottom);\n\t\t\tprimitives.push({\n\t\t\t\tkind: 'line',\n\t\t\t\tx1: cx,\n\t\t\t\ty1: closeY,\n\t\t\t\tx2: cx + tickHalfWidth,\n\t\t\t\ty2: closeY,\n\t\t\t\tstroke: closeColor,\n\t\t\t\tstrokeWidth: 1.5,\n\t\t\t} satisfies SvgLine);\n\t\t}\n\t}\n\treturn primitives;\n}\n\n/** One `chartData.series` entry tagged `seriesChartType: 'stock'` (combo charts only). */\nexport interface ComboStockSeriesEntry {\n\tseries: PptxChartSeries;\n\tindex: number;\n}\n\n/**\n * Pick out a combo chart's stock-tagged series (a volume+stock combo writes\n * `c:barChart` for the volume bar and `c:stockChart` for the HLC/OHLC price\n * series; the loader tags the latter with `seriesChartType: 'stock'`), in\n * their original `chartData.series` order.\n */\nexport function findComboStockSeries(\n\tseries: ReadonlyArray<PptxChartSeries>,\n): ComboStockSeriesEntry[] {\n\treturn series\n\t\t.map((s, index) => ({ series: s, index }))\n\t\t.filter((entry) => entry.series.seriesChartType === 'stock');\n}\n\n/**\n * Build the candle geometry AND close-value data labels for a combo chart's\n * stock-tagged series (the volume bar is rendered separately by the caller).\n * Mirrors `buildStockViewModel`'s own candle + label loop so a volume+stock\n * combo matches a standalone stock chart pixel-for-pixel modulo axis choice.\n */\nexport function computeComboStockOverlay(\n\tstockEntries: ReadonlyArray<ComboStockSeriesEntry>,\n\tchartData: PptxChartData,\n\tlayout: PlotLayout,\n\trange: ValueRange,\n\tcatCount: number,\n\tsourceIndices: ReadonlyArray<number>,\n\txPositions: ReadonlyArray<number> | undefined,\n): { primitives: SvgPrimitive[]; dataLabels: SvgText[] } {\n\tif (stockEntries.length < 3) {\n\t\treturn { primitives: [], dataLabels: [] };\n\t}\n\tconst hasFour = stockEntries.length >= 4;\n\tconst open = hasFour ? stockEntries[0].series : undefined;\n\tconst high = stockEntries[hasFour ? 1 : 0].series;\n\tconst low = stockEntries[hasFour ? 2 : 1].series;\n\tconst closeEntry = stockEntries[stockEntries.length - 1];\n\n\tconst primitives = computeStockCandlePrimitives(\n\t\t{ open, high, low, close: closeEntry.series, closeIndex: closeEntry.index },\n\t\tchartData,\n\t\tlayout,\n\t\trange,\n\t\tcatCount,\n\t\tsourceIndices,\n\t\txPositions,\n\t);\n\n\tconst dataLabels: SvgText[] = [];\n\tif (chartData.style?.hasDataLabels) {\n\t\tconst barGroupWidth = layout.plotWidth / Math.max(catCount, 1);\n\t\tfor (let displayIndex = 0; displayIndex < catCount; displayIndex++) {\n\t\t\tconst sourceIndex = sourceIndices[displayIndex] ?? displayIndex;\n\t\t\tconst close = closeEntry.series.values[sourceIndex];\n\t\t\tif (close === undefined) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tconst cx =\n\t\t\t\txPositions?.[displayIndex] ??\n\t\t\t\tlayout.plotLeft + barGroupWidth * displayIndex + barGroupWidth / 2;\n\t\t\tconst closeY = valueToY(close, range, layout.plotTop, layout.plotBottom);\n\t\t\tconst label = buildStockCloseLabel(\n\t\t\t\tchartData,\n\t\t\t\tcloseEntry.series,\n\t\t\t\tsourceIndex,\n\t\t\t\tclose,\n\t\t\t\tcx,\n\t\t\t\tcloseY,\n\t\t\t\t{\n\t\t\t\t\twidth: layout.svgWidth,\n\t\t\t\t\theight: layout.svgHeight,\n\t\t\t\t},\n\t\t\t);\n\t\t\tif (label) {\n\t\t\t\tdataLabels.push(label);\n\t\t\t}\n\t\t}\n\t}\n\treturn { primitives, dataLabels };\n}\n","/**\n * chart-combo-classify.ts: per-series type classification + clustered-bar\n * geometry for the bar/line combo chart (`chart-combo.ts`), split out to keep\n * that file within the repo's ~300-LOC limit.\n *\n * `buildComboViewModel` used to hardcode \"series 0 is the bar, every other\n * series is a line\", ignoring the parser's own per-series\n * {@link PptxChartSeries.seriesChartType} (set for every series of a genuine\n * multi-container combo: `c:barChart`/`c:lineChart`/etc. each tag their own\n * `c:ser` entries). That made a 2-bar + 1-line combo render its second bar\n * series as a line, and a line-first combo (`c:lineChart` before `c:barChart`\n * in the source XML) render its bar series as a line too. Classifying by the\n * actual tag - falling back to the historical index-0-is-bar heuristic only\n * when no series carries a tag at all - fixes both without disturbing the\n * many existing combo fixtures/tests that never set `seriesChartType`.\n *\n * Area-typed combo series get their own \"area\" lane (filled polygon down to\n * the zero baseline, drawn by `appendAreaSeries` in `chart-combo-series.ts`),\n * matching PowerPoint's own bar+area combo rendering instead of degrading\n * them to a plain unfilled line.\n *\n * @module chart-combo-classify\n */\nimport type { PptxChartData, PptxChartSeries } from 'pptx-viewer-core';\n\nimport { resolveBarLabelPlacement } from './chart-data-label-anchor';\nimport { DEFAULT_CHART_DATA_LABEL_PX } from './chart-font';\nimport type { ChartPartRef, PlotLayout, SvgRect, SvgText, ValueRange } from './chart-view-model';\nimport { formatAxisValue, seriesColor, valueToY } from './chart-view-model';\n\nexport type ComboSeriesKind = 'bar' | 'line' | 'area';\n\n/**\n * Which combo lane a series belongs to. Series 0 defaults to \"bar\" and every\n * other series defaults to \"line\" ONLY when the series carries no\n * `seriesChartType` tag at all (legacy/untagged combo data); a tagged series\n * always uses its own tag, regardless of position.\n */\nexport function classifyComboSeries(series: PptxChartSeries, index: number): ComboSeriesKind {\n\tconst type = series.seriesChartType;\n\tif (type === 'bar' || type === 'bar3D') {\n\t\treturn 'bar';\n\t}\n\tif (type === 'area' || type === 'area3D') {\n\t\treturn 'area';\n\t}\n\tif (type === undefined) {\n\t\treturn index === 0 ? 'bar' : 'line';\n\t}\n\t// line, line3D, scatter, and anything else this builder does not have a\n\t// dedicated lane for: render as a line rather than silently dropping the\n\t// series.\n\treturn 'line';\n}\n\n/** Original `chartData.series` indices split into the bar, line and area lanes. */\nexport function groupComboSeriesIndices(series: ReadonlyArray<PptxChartSeries>): {\n\tbarIndices: number[];\n\tlineIndices: number[];\n\tareaIndices: number[];\n} {\n\tconst barIndices: number[] = [];\n\tconst lineIndices: number[] = [];\n\tconst areaIndices: number[] = [];\n\tseries.forEach((entry, index) => {\n\t\tconst kind = classifyComboSeries(entry, index);\n\t\tconst target = kind === 'bar' ? barIndices : kind === 'area' ? areaIndices : lineIndices;\n\t\ttarget.push(index);\n\t});\n\treturn { barIndices, lineIndices, areaIndices };\n}\n\n/**\n * Clustered bar rects for an arbitrary subset of `chartData.series` (their\n * ORIGINAL indices, so colour/legend stay keyed to the whole series list, not\n * the subset). With exactly one index this reduces to the previous\n * single-bar-per-category geometry byte-for-byte.\n */\nexport function computeComboBarCluster(\n\tbarIndices: ReadonlyArray<number>,\n\tchartData: PptxChartData,\n\tcatCount: number,\n\tlayout: PlotLayout,\n\tprimaryRange: ValueRange,\n\tsecondaryRange: ValueRange | undefined,\n\tsecondaryIndexes: ReadonlySet<number>,\n\tsourceIndices: ReadonlyArray<number>,\n\txPositions?: ReadonlyArray<number>,\n): SvgRect[] {\n\tif (barIndices.length === 0) {\n\t\treturn [];\n\t}\n\tconst seriesCount = barIndices.length,\n\t\tbarGroupWidth = layout.plotWidth / Math.max(catCount, 1),\n\t\tsingleBarWidth = (barGroupWidth * 0.7) / seriesCount,\n\t\tclusterWidth = singleBarWidth * seriesCount,\n\t\trects: SvgRect[] = [];\n\n\tfor (let displayIndex = 0; displayIndex < catCount; displayIndex++) {\n\t\tconst sourceIndex = sourceIndices[displayIndex] ?? displayIndex,\n\t\t\tcenter =\n\t\t\t\txPositions?.[displayIndex] ??\n\t\t\t\tlayout.plotLeft + barGroupWidth * displayIndex + barGroupWidth / 2,\n\t\t\tclusterLeft = center - clusterWidth / 2;\n\t\tbarIndices.forEach((originalIndex, si) => {\n\t\t\tconst series = chartData.series[originalIndex],\n\t\t\t\tvalue = series.values[sourceIndex] ?? 0,\n\t\t\t\trange =\n\t\t\t\t\tsecondaryIndexes.has(originalIndex) && secondaryRange ? secondaryRange : primaryRange,\n\t\t\t\tzeroY = valueToY(0, range, layout.plotTop, layout.plotBottom),\n\t\t\t\tvalY = valueToY(value, range, layout.plotTop, layout.plotBottom),\n\t\t\t\tpart: ChartPartRef = {\n\t\t\t\t\trole: 'dataPoint',\n\t\t\t\t\tseriesIndex: originalIndex,\n\t\t\t\t\tpointIndex: sourceIndex,\n\t\t\t\t};\n\t\t\trects.push({\n\t\t\t\tkind: 'rect',\n\t\t\t\tx: clusterLeft + singleBarWidth * si,\n\t\t\t\ty: Math.min(zeroY, valY),\n\t\t\t\tw: singleBarWidth,\n\t\t\t\th: Math.max(Math.abs(zeroY - valY), 1),\n\t\t\t\tfill: seriesColor(series, originalIndex, chartData.colorPalette),\n\t\t\t\trx: 1,\n\t\t\t\tpart,\n\t\t\t});\n\t\t});\n\t}\n\treturn rects;\n}\n\n/** Data labels for {@link computeComboBarCluster}'s rects, one call per bar-lane series. */\nexport function appendComboBarClusterLabels(\n\tbarIndices: ReadonlyArray<number>,\n\tchartData: PptxChartData,\n\tlayout: PlotLayout,\n\tcatCount: number,\n\tprimaryRange: ValueRange,\n\tsecondaryRange: ValueRange | undefined,\n\tsecondaryIndexes: ReadonlySet<number>,\n\tsourceIndices: ReadonlyArray<number>,\n\tlabels: SvgText[],\n\txPositions?: ReadonlyArray<number>,\n): void {\n\tif (!chartData.style?.hasDataLabels || barIndices.length === 0) {\n\t\treturn;\n\t}\n\tconst seriesCount = barIndices.length,\n\t\tbarGroupWidth = layout.plotWidth / Math.max(catCount, 1),\n\t\tsingleBarWidth = (barGroupWidth * 0.7) / seriesCount,\n\t\tclusterWidth = singleBarWidth * seriesCount;\n\n\tfor (let displayIndex = 0; displayIndex < catCount; displayIndex++) {\n\t\tconst sourceIndex = sourceIndices[displayIndex] ?? displayIndex,\n\t\t\tcenter =\n\t\t\t\txPositions?.[displayIndex] ??\n\t\t\t\tlayout.plotLeft + barGroupWidth * displayIndex + barGroupWidth / 2,\n\t\t\tclusterLeft = center - clusterWidth / 2;\n\t\tbarIndices.forEach((originalIndex, si) => {\n\t\t\tconst series = chartData.series[originalIndex],\n\t\t\t\tvalue = series.values[sourceIndex] ?? 0,\n\t\t\t\trange =\n\t\t\t\t\tsecondaryIndexes.has(originalIndex) && secondaryRange ? secondaryRange : primaryRange,\n\t\t\t\tzeroY = valueToY(0, range, layout.plotTop, layout.plotBottom),\n\t\t\t\tvalY = valueToY(value, range, layout.plotTop, layout.plotBottom),\n\t\t\t\tx = clusterLeft + singleBarWidth * si,\n\t\t\t\tbarY = Math.min(zeroY, valY),\n\t\t\t\tbarH = Math.max(Math.abs(zeroY - valY), 1),\n\t\t\t\tanchor = resolveBarLabelPlacement(\n\t\t\t\t\tchartData,\n\t\t\t\t\tseries,\n\t\t\t\t\tsourceIndex,\n\t\t\t\t\t{ x, y: barY, width: singleBarWidth, height: barH },\n\t\t\t\t\tvalue,\n\t\t\t\t\t'vertical',\n\t\t\t\t\t{ width: layout.svgWidth, height: layout.svgHeight },\n\t\t\t\t);\n\t\t\tlabels.push({\n\t\t\t\tkind: 'text',\n\t\t\t\tx: anchor.x,\n\t\t\t\ty: anchor.y,\n\t\t\t\ttext: formatAxisValue(value, series.numberFormat),\n\t\t\t\tfontSize: DEFAULT_CHART_DATA_LABEL_PX,\n\t\t\t\tfill: '#334155',\n\t\t\t\ttextAnchor: anchor.textAnchor,\n\t\t\t\t...(anchor.dominantBaseline ? { dominantBaseline: anchor.dominantBaseline } : {}),\n\t\t\t});\n\t\t});\n\t}\n}\n","/**\n * chart-combo-series.ts: per-series primitive/label builders for the combo\n * (bar + line) chart, split out of `chart-combo.ts` to keep that file within\n * the repo's ~300-LOC limit.\n *\n * @module chart-combo-series\n */\nimport type { PptxChartData, PptxChartSeries } from 'pptx-viewer-core';\n\nimport { resolveBarLabelPlacement, resolveMarkerLabelPlacement } from './chart-data-label-anchor';\nimport { DEFAULT_CHART_DATA_LABEL_PX } from './chart-font';\nimport type {\n\tChartPartRef,\n\tPlotLayout,\n\tSvgCircle,\n\tSvgPolyline,\n\tSvgPrimitive,\n\tSvgText,\n\tValueRange,\n} from './chart-view-model';\nimport { formatAxisValue, seriesColor, valueToY } from './chart-view-model';\n\n/** Bar-series data labels, honouring `c:dLblPos` and any per-point manual drag. */\nexport function appendBarLabels(\n\tseries: PptxChartSeries,\n\tchartData: PptxChartData,\n\tlayout: PlotLayout,\n\tcatCount: number,\n\trange: ValueRange,\n\tsourceIndices: ReadonlyArray<number>,\n\tlabels: SvgText[],\n\txPositions?: ReadonlyArray<number>,\n): void {\n\tif (!chartData.style?.hasDataLabels) {\n\t\treturn;\n\t}\n\tconst groupWidth = layout.plotWidth / catCount;\n\tconst barWidth = groupWidth * 0.7;\n\tconst offset = (groupWidth - barWidth) / 2;\n\tsourceIndices.forEach((sourceIndex, displayIndex) => {\n\t\tconst value = series.values[sourceIndex] ?? 0;\n\t\tconst zeroY = valueToY(0, range, layout.plotTop, layout.plotBottom);\n\t\tconst valueY = valueToY(value, range, layout.plotTop, layout.plotBottom);\n\t\tconst x =\n\t\t\txPositions?.[displayIndex] ??\n\t\t\tlayout.plotLeft + groupWidth * displayIndex + offset + barWidth / 2;\n\t\tconst barY = Math.min(zeroY, valueY);\n\t\tconst barH = Math.max(Math.abs(zeroY - valueY), 1);\n\t\t// c:dLblPos (ctr/inBase/inEnd/outEnd) decides where on the bar the label\n\t\t// sits; a per-point c:dLbl/c:layout drag shifts it further.\n\t\tconst anchor = resolveBarLabelPlacement(\n\t\t\tchartData,\n\t\t\tseries,\n\t\t\tsourceIndex,\n\t\t\t{ x: x - barWidth / 2, y: barY, width: barWidth, height: barH },\n\t\t\tvalue,\n\t\t\t'vertical',\n\t\t\t{ width: layout.svgWidth, height: layout.svgHeight },\n\t\t);\n\t\tlabels.push({\n\t\t\tkind: 'text',\n\t\t\tx: anchor.x,\n\t\t\ty: anchor.y,\n\t\t\ttext: formatAxisValue(value, series.numberFormat),\n\t\t\tfontSize: DEFAULT_CHART_DATA_LABEL_PX,\n\t\t\tfill: '#334155',\n\t\t\ttextAnchor: anchor.textAnchor,\n\t\t\t...(anchor.dominantBaseline ? { dominantBaseline: anchor.dominantBaseline } : {}),\n\t\t});\n\t});\n}\n\n/** One combo line-series' polyline + markers + data labels. */\nexport function appendLineSeries(\n\tseries: PptxChartSeries,\n\tseriesIndex: number,\n\tchartData: PptxChartData,\n\tlayout: PlotLayout,\n\trange: ValueRange,\n\tbarGroupWidth: number,\n\tsourceIndices: ReadonlyArray<number>,\n\tprimitives: SvgPrimitive[],\n\tdataLabels: SvgText[],\n\txPositions?: ReadonlyArray<number>,\n): void {\n\tif (series.values.length === 0) {\n\t\treturn;\n\t}\n\tconst fill = seriesColor(series, seriesIndex, chartData.colorPalette);\n\tconst points = sourceIndices.map((sourceIndex, displayIndex) => {\n\t\tconst value = series.values[sourceIndex] ?? 0;\n\t\treturn {\n\t\t\tx:\n\t\t\t\txPositions?.[displayIndex] ??\n\t\t\t\tlayout.plotLeft + barGroupWidth * displayIndex + barGroupWidth / 2,\n\t\t\ty: valueToY(value, range, layout.plotTop, layout.plotBottom),\n\t\t\tsourceIndex,\n\t\t\tvalue,\n\t\t};\n\t});\n\tprimitives.push({\n\t\tkind: 'polyline',\n\t\tpoints: points.map((point) => `${point.x.toFixed(2)},${point.y.toFixed(2)}`).join(' '),\n\t\tstroke: fill,\n\t\tstrokeWidth: 2.4,\n\t\tfill: 'none',\n\t} satisfies SvgPolyline);\n\tprimitives.push(\n\t\t...points.map(\n\t\t\t(point) =>\n\t\t\t\t({\n\t\t\t\t\tkind: 'circle',\n\t\t\t\t\tcx: point.x,\n\t\t\t\t\tcy: point.y,\n\t\t\t\t\tr: 2.5,\n\t\t\t\t\tfill,\n\t\t\t\t\tpart: { role: 'dataPoint', seriesIndex, pointIndex: point.sourceIndex },\n\t\t\t\t}) satisfies SvgCircle,\n\t\t),\n\t);\n\tif (!chartData.style?.hasDataLabels) {\n\t\treturn;\n\t}\n\tpoints.forEach((point) => {\n\t\t// c:dLblPos (t/b/l/r/ctr) decides where round the marker the label sits;\n\t\t// a per-point c:dLbl/c:layout drag shifts it further.\n\t\tconst anchor = resolveMarkerLabelPlacement(\n\t\t\tchartData,\n\t\t\tseries,\n\t\t\tpoint.sourceIndex,\n\t\t\tpoint,\n\t\t\t{ width: layout.svgWidth, height: layout.svgHeight },\n\t\t\t7,\n\t\t);\n\t\tdataLabels.push({\n\t\t\tkind: 'text',\n\t\t\tx: anchor.x,\n\t\t\ty: anchor.y,\n\t\t\ttext: formatAxisValue(point.value, series.numberFormat),\n\t\t\tfontSize: DEFAULT_CHART_DATA_LABEL_PX,\n\t\t\tfill: '#334155',\n\t\t\ttextAnchor: anchor.textAnchor,\n\t\t\t...(anchor.dominantBaseline ? { dominantBaseline: anchor.dominantBaseline } : {}),\n\t\t});\n\t});\n}\n\n/**\n * One combo area-series' filled polygon (down to the zero baseline) + outline\n * + markers + data labels, matching PowerPoint's bar+area combo rendering\n * instead of degrading a `c:areaChart` combo member to an unfilled line.\n * Clustered only (no stacking lane exists in a combo chart).\n */\nexport function appendAreaSeries(\n\tseries: PptxChartSeries,\n\tseriesIndex: number,\n\tchartData: PptxChartData,\n\tlayout: PlotLayout,\n\trange: ValueRange,\n\tbarGroupWidth: number,\n\tsourceIndices: ReadonlyArray<number>,\n\tprimitives: SvgPrimitive[],\n\tdataLabels: SvgText[],\n\txPositions?: ReadonlyArray<number>,\n): void {\n\tif (series.values.length === 0) {\n\t\treturn;\n\t}\n\tconst fill = seriesColor(series, seriesIndex, chartData.colorPalette);\n\tconst baselineY = valueToY(0, range, layout.plotTop, layout.plotBottom);\n\tconst points = sourceIndices.map((sourceIndex, displayIndex) => {\n\t\tconst value = series.values[sourceIndex] ?? 0;\n\t\treturn {\n\t\t\tx:\n\t\t\t\txPositions?.[displayIndex] ??\n\t\t\t\tlayout.plotLeft + barGroupWidth * displayIndex + barGroupWidth / 2,\n\t\t\ty: valueToY(value, range, layout.plotTop, layout.plotBottom),\n\t\t\tsourceIndex,\n\t\t\tvalue,\n\t\t};\n\t});\n\tconst firstPt = points[0];\n\tconst lastPt = points[points.length - 1];\n\tconst lineStr = points.map((point) => `${point.x.toFixed(2)},${point.y.toFixed(2)}`).join(' ');\n\tif (firstPt && lastPt) {\n\t\tprimitives.push({\n\t\t\tkind: 'polyline',\n\t\t\tpoints: `${firstPt.x.toFixed(2)},${baselineY.toFixed(2)} ${lineStr} ${lastPt.x.toFixed(2)},${baselineY.toFixed(2)}`,\n\t\t\tstroke: 'none',\n\t\t\tstrokeWidth: 0,\n\t\t\tfill,\n\t\t\topacity: 0.25,\n\t\t\tpart: { role: 'series', seriesIndex } as ChartPartRef,\n\t\t} satisfies SvgPolyline);\n\t}\n\tprimitives.push({\n\t\tkind: 'polyline',\n\t\tpoints: lineStr,\n\t\tstroke: fill,\n\t\tstrokeWidth: 2,\n\t\tfill: 'none',\n\t\tpart: { role: 'series', seriesIndex } as ChartPartRef,\n\t} satisfies SvgPolyline);\n\tprimitives.push(\n\t\t...points.map(\n\t\t\t(point) =>\n\t\t\t\t({\n\t\t\t\t\tkind: 'circle',\n\t\t\t\t\tcx: point.x,\n\t\t\t\t\tcy: point.y,\n\t\t\t\t\tr: 2.5,\n\t\t\t\t\tfill,\n\t\t\t\t\tpart: { role: 'dataPoint', seriesIndex, pointIndex: point.sourceIndex },\n\t\t\t\t}) satisfies SvgCircle,\n\t\t),\n\t);\n\tif (!chartData.style?.hasDataLabels) {\n\t\treturn;\n\t}\n\tpoints.forEach((point) => {\n\t\tconst anchor = resolveMarkerLabelPlacement(\n\t\t\tchartData,\n\t\t\tseries,\n\t\t\tpoint.sourceIndex,\n\t\t\tpoint,\n\t\t\t{ width: layout.svgWidth, height: layout.svgHeight },\n\t\t\t7,\n\t\t);\n\t\tdataLabels.push({\n\t\t\tkind: 'text',\n\t\t\tx: anchor.x,\n\t\t\ty: anchor.y,\n\t\t\ttext: formatAxisValue(point.value, series.numberFormat),\n\t\t\tfontSize: DEFAULT_CHART_DATA_LABEL_PX,\n\t\t\tfill: '#334155',\n\t\t\ttextAnchor: anchor.textAnchor,\n\t\t\t...(anchor.dominantBaseline ? { dominantBaseline: anchor.dominantBaseline } : {}),\n\t\t});\n\t});\n}\n","import type { PptxChartData, PptxElement } from 'pptx-viewer-core';\n\nimport { resolveChartTitleText } from './chart-auto-title';\nimport {\n\tcomputeLayoutOptions,\n\tcomputeValueRangeForAxis,\n\tgetPrimaryValueAxisId,\n\tgetSecondaryValueAxis,\n\tsplitSeriesByAxis,\n} from './chart-axis';\nimport { verticalAxisX } from './chart-axis-crossing';\nimport { buildPrimaryAxis, buildSecondaryAxis } from './chart-axis-render';\nimport {\n\tappendComboBarClusterLabels,\n\tcomputeComboBarCluster,\n\tgroupComboSeriesIndices,\n} from './chart-combo-classify';\nimport { appendAreaSeries, appendLineSeries } from './chart-combo-series';\nimport { computeDataTablePrimitives } from './chart-data-table-render';\nimport { computeErrorBarPrimitives } from './chart-error-bars';\nimport { shouldRenderMajorGridlines } from './chart-gridlines-toggle';\nimport { computeHelperLinePrimitives } from './chart-helper-lines';\nimport { buildCartesianHorizontalAxis } from './chart-horizontal-axis';\nimport type { LegendSwatchKind } from './chart-legend-swatch';\nimport { computeAxisTitlePrimitives, computeTrendlinePrimitives } from './chart-overlays';\nimport { computeComboStockOverlay, findComboStockSeries } from './chart-stock-candles';\nimport type {\n\tChartViewModel,\n\tPlotLayout,\n\tSvgPrimitive,\n\tSvgText,\n\tValueRange,\n} from './chart-view-model';\nimport {\n\tbuildGridlinesAndLabels,\n\tbuildLegend,\n\tbuildZeroLine,\n\tcomputePlotLayout,\n} from './chart-view-model';\n\nfunction rangeForSeries(\n\tindex: number,\n\tprimaryRange: ValueRange,\n\tsecondaryRange: ValueRange | undefined,\n\tsecondaryIndexes: ReadonlySet<number>,\n): ValueRange {\n\treturn secondaryRange && secondaryIndexes.has(index) ? secondaryRange : primaryRange;\n}\n\n/** Build a bar + line combo chart, including independently scaled secondary series. */\nexport function buildComboViewModel(\n\telement: PptxElement,\n\tchartData: PptxChartData,\n\tcategoryLabels: ReadonlyArray<string>,\n): ChartViewModel {\n\tconst layoutOptions = computeLayoutOptions(\n\t\tchartData.axes,\n\t\tchartData.dataTable,\n\t\tchartData.series.length,\n\t);\n\tconst layout: PlotLayout = computePlotLayout(\n\t\telement.width,\n\t\telement.height,\n\t\tchartData,\n\t\ttrue,\n\t\tlayoutOptions,\n\t);\n\tconst catCount = Math.max(categoryLabels.length, 1);\n\tconst { primary, secondary } = splitSeriesByAxis(chartData.series, chartData.axes);\n\tconst secondaryIndexes = new Set(secondary.map((entry) => entry.index));\n\tconst primarySeries =\n\t\tprimary.length > 0 ? primary.map((entry) => entry.series) : chartData.series;\n\tconst primaryAxisId = getPrimaryValueAxisId(chartData.axes);\n\tconst primaryAxis = chartData.axes?.find((axis) => axis.axisId === primaryAxisId);\n\tconst secondaryAxisFormatting = getSecondaryValueAxis(chartData.axes);\n\tconst primaryRange = computeValueRangeForAxis(primarySeries, primaryAxis, layout.autoPlotHeight);\n\tconst secondaryRange =\n\t\tsecondary.length > 0\n\t\t\t? computeValueRangeForAxis(\n\t\t\t\t\tsecondary.map((entry) => entry.series),\n\t\t\t\t\tsecondaryAxisFormatting,\n\t\t\t\t\tlayout.autoPlotHeight,\n\t\t\t\t)\n\t\t\t: undefined;\n\n\tconst primaryCategoryAxis = chartData.axes?.find(\n\t\t(axis) =>\n\t\t\t(axis.axisType === 'catAx' || axis.axisType === 'dateAx') &&\n\t\t\taxis.axisId === primaryAxis?.crossAxisId,\n\t);\n\tconst primaryAxisX = verticalAxisX(\n\t\tprimaryCategoryAxis,\n\t\tcatCount,\n\t\tlayout,\n\t\t'left',\n\t\tchartData.dateCategories?.values,\n\t);\n\tconst showMajorGridlines = shouldRenderMajorGridlines(chartData);\n\tconst primaryRendered =\n\t\tprimaryCategoryAxis?.crosses !== undefined || primaryCategoryAxis?.crossesAt !== undefined\n\t\t\t? buildPrimaryAxis(primaryRange, layout, primaryAxis, primaryAxisX, showMajorGridlines)\n\t\t\t: buildGridlinesAndLabels(primaryRange, layout, showMajorGridlines);\n\tconst { gridlines, axisLabels } = primaryRendered;\n\tconst secondaryCategoryAxis = chartData.axes?.find(\n\t\t(axis) =>\n\t\t\t(axis.axisType === 'catAx' || axis.axisType === 'dateAx') &&\n\t\t\taxis.axisId === secondaryAxisFormatting?.crossAxisId,\n\t);\n\tconst secondaryAxis = secondaryRange\n\t\t? buildSecondaryAxis(\n\t\t\t\tsecondaryRange,\n\t\t\t\tlayout,\n\t\t\t\tsecondaryAxisFormatting,\n\t\t\t\tverticalAxisX(\n\t\t\t\t\tsecondaryCategoryAxis,\n\t\t\t\t\tcatCount,\n\t\t\t\t\tlayout,\n\t\t\t\t\t'right',\n\t\t\t\t\tchartData.dateCategories?.values,\n\t\t\t\t),\n\t\t\t)\n\t\t: undefined;\n\tconst zeroLine = primaryRange.logScale ? undefined : buildZeroLine(primaryRange, layout);\n\tconst horizontalAxis = buildCartesianHorizontalAxis(\n\t\tchartData,\n\t\tcategoryLabels,\n\t\tlayout,\n\t\t'combo',\n\t\tprimaryRange,\n\t\tsecondaryRange,\n\t);\n\tconst sourceIndices = horizontalAxis.sourceIndices;\n\tconst legendPos = chartData.style?.legendPosition ?? 'b';\n\t// Which lane (bar rect vs. line+marker) each series renders in: its own\n\t// `seriesChartType` tag when the combo's source XML carries one, or the\n\t// legacy \"series 0 is the bar, everything else is a line\" guess when it\n\t// doesn't (see chart-combo-classify.ts). The legend swatch follows the\n\t// same split.\n\tconst { barIndices, lineIndices, areaIndices } = groupComboSeriesIndices(chartData.series);\n\tconst barIndexSet = new Set(barIndices);\n\tconst areaIndexSet = new Set(areaIndices);\n\tconst comboSwatchKinds: LegendSwatchKind[] = chartData.series.map((_s, i) =>\n\t\tbarIndexSet.has(i) || areaIndexSet.has(i) ? 'rect' : 'line',\n\t);\n\tconst { legend, legendX, legendY, legendAnchor } = buildLegend(\n\t\tchartData.series,\n\t\tchartData.colorPalette,\n\t\tlayout.svgWidth,\n\t\tlegendPos,\n\t\tlayout.svgHeight,\n\t\tlayout.plotTop,\n\t\tcomboSwatchKinds,\n\t);\n\tconst primitives: SvgPrimitive[] = [];\n\tconst dataLabels: SvgText[] = [];\n\n\t// A volume+stock combo (`c:barChart` volume + `c:stockChart` HLC/OHLC price\n\t// series) draws its own hi-lo wick / candle body below from the price\n\t// series alone, on their own axis. Running the generic drop/hi-low/up-down\n\t// helper here would wrongly fold the volume bar into the \"highest/lowest\n\t// series per category\" calculation those helpers do over ALL series.\n\tconst stockEntries = findComboStockSeries(chartData.series);\n\tconst isStockCombo = stockEntries.length >= 3;\n\tconst stockIndexes = new Set(stockEntries.map((entry) => entry.index));\n\tif (!isStockCombo) {\n\t\tconst helperOpts = { mode: 'line' as const, xPositions: horizontalAxis.xPositions };\n\t\tprimitives.push(\n\t\t\t...computeHelperLinePrimitives(chartData, layout, primaryRange, catCount, helperOpts),\n\t\t);\n\t}\n\n\tprimitives.push(\n\t\t...computeComboBarCluster(\n\t\t\tbarIndices,\n\t\t\tchartData,\n\t\t\tcatCount,\n\t\t\tlayout,\n\t\t\tprimaryRange,\n\t\t\tsecondaryRange,\n\t\t\tsecondaryIndexes,\n\t\t\tsourceIndices,\n\t\t\thorizontalAxis.xPositions,\n\t\t),\n\t);\n\tappendComboBarClusterLabels(\n\t\tbarIndices,\n\t\tchartData,\n\t\tlayout,\n\t\tcatCount,\n\t\tprimaryRange,\n\t\tsecondaryRange,\n\t\tsecondaryIndexes,\n\t\tsourceIndices,\n\t\tdataLabels,\n\t\thorizontalAxis.xPositions,\n\t);\n\n\tconst barGroupWidth = layout.plotWidth / catCount;\n\t// Area lane first so its filled polygon paints behind bar/line marks that\n\t// share the same category slot, matching PowerPoint's own draw order.\n\tfor (const seriesIndex of areaIndices) {\n\t\tconst series = chartData.series[seriesIndex];\n\t\tconst range = rangeForSeries(seriesIndex, primaryRange, secondaryRange, secondaryIndexes);\n\t\tappendAreaSeries(\n\t\t\tseries,\n\t\t\tseriesIndex,\n\t\t\tchartData,\n\t\t\tlayout,\n\t\t\trange,\n\t\t\tbarGroupWidth,\n\t\t\tsourceIndices,\n\t\t\tprimitives,\n\t\t\tdataLabels,\n\t\t\thorizontalAxis.xPositions,\n\t\t);\n\t}\n\tfor (const seriesIndex of lineIndices) {\n\t\t// The stock-tagged series are drawn as candles below, not as lines.\n\t\tif (stockIndexes.has(seriesIndex)) {\n\t\t\tcontinue;\n\t\t}\n\t\tconst series = chartData.series[seriesIndex];\n\t\tconst range = rangeForSeries(seriesIndex, primaryRange, secondaryRange, secondaryIndexes);\n\t\tappendLineSeries(\n\t\t\tseries,\n\t\t\tseriesIndex,\n\t\t\tchartData,\n\t\t\tlayout,\n\t\t\trange,\n\t\t\tbarGroupWidth,\n\t\t\tsourceIndices,\n\t\t\tprimitives,\n\t\t\tdataLabels,\n\t\t\thorizontalAxis.xPositions,\n\t\t);\n\t}\n\n\tif (isStockCombo) {\n\t\tconst closeIndex = stockEntries[stockEntries.length - 1].index;\n\t\tconst stockRange = rangeForSeries(closeIndex, primaryRange, secondaryRange, secondaryIndexes);\n\t\tconst overlay = computeComboStockOverlay(\n\t\t\tstockEntries,\n\t\t\tchartData,\n\t\t\tlayout,\n\t\t\tstockRange,\n\t\t\tcatCount,\n\t\t\tsourceIndices,\n\t\t\thorizontalAxis.xPositions,\n\t\t);\n\t\tprimitives.push(...overlay.primitives);\n\t\tdataLabels.push(...overlay.dataLabels);\n\t}\n\tprimitives.push(...horizontalAxis.tickMarks);\n\tconst displayChartData = horizontalAxis.displayChartData;\n\t// Overlay depth. Error bars were already here; trendlines, axis titles and\n\t// the data-table block were not, even though `computeLayoutOptions` above\n\t// reserves the table's strip, so the space was cleared and left blank.\n\tconst overlays: SvgPrimitive[] = [\n\t\t...computeErrorBarPrimitives(displayChartData, catCount, layout, primaryRange, 'line', {\n\t\t\txPositions: horizontalAxis.xPositions,\n\t\t\tseriesRanges: chartData.series.map((_series, index) =>\n\t\t\t\trangeForSeries(index, primaryRange, secondaryRange, secondaryIndexes),\n\t\t\t),\n\t\t\tseriesModes: chartData.series.map((_series, index) =>\n\t\t\t\tbarIndexSet.has(index) ? 'bar' : 'line',\n\t\t\t),\n\t\t}),\n\t\t...computeTrendlinePrimitives(\n\t\t\tdisplayChartData,\n\t\t\tcatCount,\n\t\t\tlayout,\n\t\t\tprimaryRange,\n\t\t\t'bar',\n\t\t\tchartData.colorPalette,\n\t\t),\n\t\t...computeAxisTitlePrimitives(chartData, layout),\n\t];\n\tconst dataTablePrimitives = computeDataTablePrimitives(\n\t\tdisplayChartData,\n\t\tlayout,\n\t\tchartData.colorPalette,\n\t);\n\tprimitives.push(...overlays, ...dataTablePrimitives);\n\n\treturn {\n\t\tsvgWidth: layout.svgWidth,\n\t\tsvgHeight: layout.svgHeight,\n\t\ttitle: resolveChartTitleText(chartData),\n\t\ttitleX: layout.svgWidth / 2,\n\t\ttitleY: 12,\n\t\tgridlines,\n\t\taxisLabels,\n\t\tzeroLine,\n\t\tcategoryLabels: horizontalAxis.labels,\n\t\tprimitives,\n\t\tdataLabels,\n\t\tlegend: chartData.style?.hasLegend ? legend : [],\n\t\tlegendX,\n\t\tlegendY,\n\t\tlegendAnchor,\n\t\tsecondaryGridlines: secondaryAxis?.gridlines,\n\t\tsecondaryAxisLabels: secondaryAxis?.axisLabels,\n\t\toverlays: overlays.length > 0 ? overlays : undefined,\n\t\tdataTable: dataTablePrimitives.length > 0 ? dataTablePrimitives : undefined,\n\t};\n}\n","/**\n * View-model builders for combo and stock chart kinds.\n *\n * Ported from:\n * packages/react/src/viewer/utils/chart-waterfall-combo.tsx (renderComboChart)\n * packages/react/src/viewer/utils/chart-stock.tsx (renderStockChart)\n *\n * All functions here are pure TypeScript with zero Angular dependencies.\n * The component consumes a single `ChartViewModel` (same contract as the\n * helpers in chart-renderer-helpers.ts) that is the projection of a\n * `ChartPptxElement` -> SVG primitives.\n *\n * Combo charts:\n * series[0] → bar/column rectangles (one per category)\n * series[1…N] → line + dots (one polyline + N circles per series)\n *\n * Stock charts (HLC / OHLC):\n * 3-series HLC → series: High, Low, Close. A vertical hi-lo wick, no body,\n * plus a short close tick (PowerPoint has no `c:upDownBars` on HLC).\n * 4-series OHLC → series: Open, High, Low, Close. The wick plus a candle\n * body from open to close, filled from `c:upDownBars` (see\n * `chart-stock-candles.ts`; never a hardcoded up/down colour).\n *\n * @module chart-combo-stock\n */\n\nimport type { PptxChartData, PptxElement } from 'pptx-viewer-core';\n\nimport { resolveChartTitleText } from './chart-auto-title';\nimport { computeLayoutOptions, computeValueRangeForChart } from './chart-axis';\nimport { verticalAxisX } from './chart-axis-crossing';\nimport { buildPrimaryAxis } from './chart-axis-render';\nimport { computeDataTablePrimitives } from './chart-data-table-render';\nimport { shouldRenderMajorGridlines } from './chart-gridlines-toggle';\nimport { computeDropLinePrimitives } from './chart-helper-lines';\nimport { buildCartesianHorizontalAxis } from './chart-horizontal-axis';\nimport {\n\tcomputeAxisTitlePrimitives,\n\tcomputeErrorBarPrimitives,\n\tcomputeTrendlinePrimitives,\n} from './chart-overlays';\nimport { computeStockCandlePrimitives } from './chart-stock-candles';\nimport { buildStockCloseLabel } from './chart-stock-close-label';\nimport type {\n\tChartViewModel,\n\tPlotLayout,\n\tSvgPrimitive,\n\tSvgText,\n\tValueRange,\n} from './chart-view-model';\nimport {\n\tbuildGridlinesAndLabels,\n\tbuildLegend,\n\tbuildZeroLine,\n\tcomputePlotLayout,\n\tvalueToY,\n} from './chart-view-model';\n\nexport { buildComboViewModel } from './chart-combo';\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Stock chart\n// ─────────────────────────────────────────────────────────────────────────────\n\n/**\n * Build a `ChartViewModel` for a stock (HLC / OHLC) candlestick chart.\n *\n * Series layout convention (mirrors the React renderer):\n * 3-series: series[0] = High, series[1] = Low, series[2] = Close\n * 4-series: series[0] = Open, series[1] = High, series[2] = Low, series[3] = Close\n *\n * The wick/tick/body geometry itself lives in `chart-stock-candles.ts`\n * (shared with the price portion of a volume+stock combo); this builder only\n * resolves the series slots, axes, legend and overlay depth around it.\n *\n * @param element - The chart element providing width/height.\n * @param chartData - Parsed chart data including series and style.\n * @param categoryLabels - Ordered category axis labels.\n * @returns A fully assembled `ChartViewModel` ready for the template.\n */\nexport function buildStockViewModel(\n\telement: PptxElement,\n\tchartData: PptxChartData,\n\tcategoryLabels: ReadonlyArray<string>,\n): ChartViewModel {\n\tconst layout: PlotLayout = computePlotLayout(\n\t\telement.width,\n\t\telement.height,\n\t\tchartData,\n\t\ttrue,\n\t\tcomputeLayoutOptions(chartData.axes, chartData.dataTable, chartData.series.length),\n\t);\n\tconst catCount = Math.max(categoryLabels.length, 1);\n\n\t// Through `computeValueRangeForChart`, not the bare linear helper: a stock\n\t// chart is as entitled to a log or display-unit value axis as any other\n\t// cartesian kind, and the bare helper silently ignores `c:scaling`.\n\tconst range: ValueRange = computeValueRangeForChart(\n\t\tchartData.series,\n\t\tchartData.axes,\n\t\tlayout.plotHeight,\n\t);\n\n\tconst valueAxis = chartData.axes?.find((axis) => axis.axisType === 'valAx' && axis.axPos !== 'r');\n\tconst categoryAxis = chartData.axes?.find(\n\t\t(axis) =>\n\t\t\t(axis.axisType === 'catAx' || axis.axisType === 'dateAx') &&\n\t\t\taxis.axisId === valueAxis?.crossAxisId,\n\t);\n\tconst showMajorGridlines = shouldRenderMajorGridlines(chartData);\n\tconst renderedAxis =\n\t\tcategoryAxis?.crosses !== undefined || categoryAxis?.crossesAt !== undefined\n\t\t\t? buildPrimaryAxis(\n\t\t\t\t\trange,\n\t\t\t\t\tlayout,\n\t\t\t\t\tvalueAxis,\n\t\t\t\t\tverticalAxisX(categoryAxis, catCount, layout, 'left', chartData.dateCategories?.values),\n\t\t\t\t\tshowMajorGridlines,\n\t\t\t\t)\n\t\t\t: buildGridlinesAndLabels(range, layout, showMajorGridlines);\n\tconst { gridlines, axisLabels } = renderedAxis;\n\tconst zeroLine = buildZeroLine(range, layout);\n\tconst horizontalAxis = buildCartesianHorizontalAxis(\n\t\tchartData,\n\t\tcategoryLabels,\n\t\tlayout,\n\t\t'stock',\n\t\trange,\n\t);\n\tconst sourceIndices = horizontalAxis.sourceIndices;\n\n\tconst legendPos = chartData.style?.legendPosition ?? 'b';\n\tconst { legend, legendX, legendY, legendAnchor } = buildLegend(\n\t\tchartData.series,\n\t\tchartData.colorPalette,\n\t\tlayout.svgWidth,\n\t\tlegendPos,\n\t\tlayout.svgHeight,\n\t\tlayout.plotTop,\n\t);\n\n\t// ── Resolve OHLC series slots ──────────────────────────────────────────\n\tconst hasFour = chartData.series.length >= 4;\n\tconst openSeries = hasFour ? chartData.series[0] : undefined;\n\tconst highSeries = chartData.series[hasFour ? 1 : 0];\n\tconst lowSeries = chartData.series[hasFour ? 2 : 1];\n\tconst closeSeries = chartData.series[hasFour ? 3 : 2];\n\n\tconst primitives: SvgPrimitive[] = [];\n\tconst dataLabels: SvgText[] = [];\n\n\t// `c:dropLines` is independent of the wick/tick/body geometry below (which\n\t// already draws the hi-lo wick and any up/down body from `c:hiLowLines` /\n\t// `c:upDownBars` itself), so only drop lines need the generic helper here.\n\tprimitives.push(\n\t\t...computeDropLinePrimitives(chartData, layout, range, catCount, {\n\t\t\tmode: 'bar',\n\t\t\txPositions: horizontalAxis.xPositions,\n\t\t}),\n\t);\n\n\tif (highSeries && lowSeries && closeSeries) {\n\t\tconst closeIndex = hasFour ? 3 : 2;\n\t\tprimitives.push(\n\t\t\t...computeStockCandlePrimitives(\n\t\t\t\t{ open: openSeries, high: highSeries, low: lowSeries, close: closeSeries, closeIndex },\n\t\t\t\tchartData,\n\t\t\t\tlayout,\n\t\t\t\trange,\n\t\t\t\tcatCount,\n\t\t\t\tsourceIndices,\n\t\t\t\thorizontalAxis.xPositions,\n\t\t\t),\n\t\t);\n\n\t\tif (chartData.style?.hasDataLabels) {\n\t\t\tconst barGroupWidth = layout.plotWidth / catCount;\n\t\t\tfor (let displayIndex = 0; displayIndex < catCount; displayIndex++) {\n\t\t\t\tconst sourceIndex = sourceIndices[displayIndex] ?? displayIndex;\n\t\t\t\tconst close = closeSeries.values[sourceIndex];\n\t\t\t\tif (close === undefined) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tconst cx =\n\t\t\t\t\thorizontalAxis.xPositions?.[displayIndex] ??\n\t\t\t\t\tlayout.plotLeft + barGroupWidth * displayIndex + barGroupWidth / 2;\n\t\t\t\tconst closeY = valueToY(close, range, layout.plotTop, layout.plotBottom);\n\t\t\t\tconst closeLabel = buildStockCloseLabel(\n\t\t\t\t\tchartData,\n\t\t\t\t\tcloseSeries,\n\t\t\t\t\tsourceIndex,\n\t\t\t\t\tclose,\n\t\t\t\t\tcx,\n\t\t\t\t\tcloseY,\n\t\t\t\t\t{\n\t\t\t\t\t\twidth: layout.svgWidth,\n\t\t\t\t\t\theight: layout.svgHeight,\n\t\t\t\t\t},\n\t\t\t\t);\n\t\t\t\tif (closeLabel) {\n\t\t\t\t\tdataLabels.push(closeLabel);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\tprimitives.push(...horizontalAxis.tickMarks);\n\n\t// Overlay depth, matching every other cartesian kind: regression trendlines,\n\t// error bars, axis titles and the data-table block. `computePlotLayout`\n\t// already reserved room for the table via `computeLayoutOptions`, so without\n\t// these the space was reserved and left blank.\n\tconst displayChartData = horizontalAxis.displayChartData;\n\tconst overlays: SvgPrimitive[] = [\n\t\t...computeTrendlinePrimitives(\n\t\t\tdisplayChartData,\n\t\t\tcatCount,\n\t\t\tlayout,\n\t\t\trange,\n\t\t\t'bar',\n\t\t\tchartData.colorPalette,\n\t\t),\n\t\t...computeErrorBarPrimitives(displayChartData, catCount, layout, range, 'bar', {\n\t\t\txPositions: horizontalAxis.xPositions,\n\t\t}),\n\t\t...computeAxisTitlePrimitives(chartData, layout),\n\t];\n\tconst dataTablePrimitives = computeDataTablePrimitives(\n\t\tdisplayChartData,\n\t\tlayout,\n\t\tchartData.colorPalette,\n\t);\n\tprimitives.push(...overlays, ...dataTablePrimitives);\n\n\tconst title = resolveChartTitleText(chartData);\n\n\treturn {\n\t\tsvgWidth: layout.svgWidth,\n\t\tsvgHeight: layout.svgHeight,\n\t\ttitle,\n\t\ttitleX: layout.svgWidth / 2,\n\t\ttitleY: 12,\n\t\tgridlines,\n\t\taxisLabels,\n\t\tzeroLine,\n\t\tcategoryLabels: horizontalAxis.labels,\n\t\tprimitives,\n\t\tdataLabels,\n\t\tlegend: chartData.style?.hasLegend ? legend : [],\n\t\tlegendX,\n\t\tlegendY,\n\t\tlegendAnchor,\n\t\toverlays: overlays.length > 0 ? overlays : undefined,\n\t\tdataTable: dataTablePrimitives.length > 0 ? dataTablePrimitives : undefined,\n\t};\n}\n","/**\n * chart-cx-axis-units.ts: value-axis display-units support (classic\n * `c:dispUnits`, ChartEx `cx:units`, C1 gap) for the chart-type renderers\n * that build their own axis chrome with `buildGridlinesAndLabels`\n * (histogram/pareto, waterfall, box-whisker) rather than the richer\n * cartesian `buildPrimaryAxis` pipeline (`chart-cartesian-axes.ts`, used by\n * classic bar/line/area/scatter charts).\n *\n * Those renderers never consulted ANY axis formatting before this module:\n * they render the same for a chart with or without `c:dispUnits`/`cx:units`.\n * `buildValueAxisGridlinesAndLabels` is a drop-in replacement for\n * `buildGridlinesAndLabels` that adds unit-scaled tick text plus the rotated\n * caption when the chart's value axis declares one, reusing the exact\n * divisor/caption helpers `buildPrimaryAxis` already uses for classic\n * cartesian charts (`chart-axis.ts`'s `formatAxisValueWithUnits`/\n * `getDisplayUnitLabel`) so a ChartEx axis renders identically to a classic\n * one once its `cx:units` parses into the same `displayUnits`/\n * `displayUnitsValue`/`displayUnitsLabel` fields (see\n * `chart-cx-axis-parser.ts`). Falls back to the base builder's output\n * unchanged when the axis declares no display units, so an untouched chart\n * renders byte-identical.\n *\n * @module chart-cx-axis-units\n */\nimport type { PptxChartAxisFormatting } from 'pptx-viewer-core';\n\nimport { formatAxisValueWithUnits, getDisplayUnitLabel } from './chart-axis';\nimport { chartAxisTextStyle, unitsLabelTextStyle } from './chart-axis-style';\nimport type { PlotLayout, SvgLine, SvgText, ValueRange } from './chart-view-model';\nimport { axisTickValues, buildGridlinesAndLabels } from './chart-view-model';\n\n/** Find a chart's value axis among its parsed `c:catAx`/`c:valAx`/`cx:axis` entries. */\nexport function findValueAxis(\n\taxes: readonly PptxChartAxisFormatting[] | undefined,\n): PptxChartAxisFormatting | undefined {\n\treturn axes?.find((axis) => axis.axisType === 'valAx');\n}\n\n/**\n * `buildGridlinesAndLabels`, but with tick text scaled by the value axis's\n * display units and a rotated unit caption appended, when `axis` declares\n * one (`axis?.displayUnits` truthy). `range` and `layout` are forwarded to\n * the base builder unchanged.\n */\nexport function buildValueAxisGridlinesAndLabels(\n\trange: ValueRange,\n\tlayout: PlotLayout,\n\taxis: PptxChartAxisFormatting | undefined,\n\tshowMajorGridlines = true,\n): { gridlines: SvgLine[]; axisLabels: SvgText[] } {\n\tconst base = buildGridlinesAndLabels(range, layout, showMajorGridlines);\n\tif (!axis?.displayUnits) {\n\t\treturn base;\n\t}\n\tconst ticks = axisTickValues(range);\n\tconst axisLabels = base.axisLabels.map((label, index) => {\n\t\tconst val = ticks[index];\n\t\treturn val === undefined ? label : { ...label, text: formatAxisValueWithUnits(val, axis) };\n\t});\n\tconst unitLabel = getDisplayUnitLabel(axis.displayUnits, axis.displayUnitsLabel);\n\tif (unitLabel) {\n\t\tconst labelX = layout.plotLeft - 36;\n\t\tconst midY = (layout.plotTop + layout.plotBottom) / 2;\n\t\taxisLabels.push({\n\t\t\tkind: 'text',\n\t\t\tx: labelX,\n\t\t\ty: midY,\n\t\t\ttext: unitLabel,\n\t\t\t...unitsLabelTextStyle(axis, chartAxisTextStyle(axis)),\n\t\t\ttextAnchor: 'middle',\n\t\t\ttransform: `rotate(-90, ${labelX}, ${midY})`,\n\t\t});\n\t}\n\treturn { gridlines: base.gridlines, axisLabels };\n}\n","import type { PptxChartSeries } from 'pptx-viewer-core';\n\nimport type { ValueRange } from './chart-view-model';\n\n/** Range with zero included and the upper bound floored at one. */\nexport function distributionRange(series: ReadonlyArray<PptxChartSeries>): ValueRange {\n\tconst all = series.flatMap((item) => item.values);\n\tconst min = Math.min(...all, 0);\n\tconst max = Math.max(...all, 1);\n\treturn { min, max, span: Math.max(max - min, 1) };\n}\n","import type { PptxChartBoxWhiskerOptions, PptxChartData, PptxElement } from 'pptx-viewer-core';\n\nimport { resolveChartTitleText } from './chart-auto-title';\nimport { computeBoxStats, groupRowsByCategory } from './chart-box-whisker-stats';\nimport type { BoxStats } from './chart-box-whisker-stats';\nimport { buildValueAxisGridlinesAndLabels, findValueAxis } from './chart-cx-axis-units';\nimport { distributionRange } from './chart-distribution-range';\nimport type {\n\tChartViewModel,\n\tPlotLayout,\n\tSvgCircle,\n\tSvgLine,\n\tSvgPrimitive,\n\tSvgRect,\n\tValueRange,\n} from './chart-view-model';\nimport {\n\tbuildCategoryLabels,\n\tbuildLegend,\n\tbuildZeroLine,\n\tcomputePlotLayout,\n\tseriesColor,\n\tvalueToY,\n} from './chart-view-model';\n\nconst WHISKER_COLOR = '#64748b';\nconst MEDIAN_COLOR = '#1e293b';\n\ninterface BoxPoint {\n\tx: number;\n\ty: number;\n\tseriesIndex: number;\n\t/** The raw source row this observation came from, its stable point identity. */\n\trowIndex: number;\n\toutlier: boolean;\n}\n\nexport interface BoxWhiskerGeometry {\n\tstats: BoxStats;\n\tboxX: number;\n\tboxW: number;\n\txMid: number;\n\tyMin: number;\n\tyMax: number;\n\tyQ1: number;\n\tyQ3: number;\n\tyMed: number;\n\tyMean: number;\n\tfill: string;\n\tseriesIndex: number;\n\tcategoryIndex: number;\n\toptions: PptxChartBoxWhiskerOptions | undefined;\n\tpoints: BoxPoint[];\n}\n\n/**\n * Build one box per (series, category) pair, the way PowerPoint's\n * `cx:boxWhisker` chart actually groups data: a series' raw rows repeat their\n * category label once per underlying observation (see\n * `groupRowsByCategory`'s doc comment), and each series draws its OWN box in\n * every category it has observations for, side by side with the other\n * series' boxes in that same category (COM-verified: `charts-com.pptx` slide\n * 32 draws 3 colour-coded boxes per category, not one box mixing all series).\n */\nexport function computeBoxWhiskerGeometry(\n\tchartData: PptxChartData,\n\trawCategories: ReadonlyArray<string>,\n\tlayout: PlotLayout,\n\trange: ValueRange,\n\tcolorPalette: readonly string[] | undefined,\n): BoxWhiskerGeometry[] {\n\tconst { uniqueCategories, rowIndexesByCategory } = groupRowsByCategory(rawCategories);\n\tconst catCount = Math.max(uniqueCategories.length, 1);\n\tconst seriesCount = Math.max(chartData.series.length, 1);\n\tconst groupWidth = layout.plotWidth / catCount;\n\tconst slotWidth = groupWidth / seriesCount;\n\tconst boxW = slotWidth * 0.7;\n\n\tconst output: BoxWhiskerGeometry[] = [];\n\tuniqueCategories.forEach((category, categoryIndex) => {\n\t\tconst rows = rowIndexesByCategory.get(category) ?? [];\n\t\tchartData.series.forEach((series, seriesIndex) => {\n\t\t\tconst observations = rows\n\t\t\t\t.map((row) => ({ row, value: series.values[row] }))\n\t\t\t\t.filter((item): item is { row: number; value: number } => item.value !== undefined);\n\t\t\tconst values = observations.map((item) => item.value);\n\t\t\tconst options = series.boxWhiskerOptions;\n\t\t\tconst stats = computeBoxStats(values, options?.quartileMethod ?? 'exclusive');\n\t\t\tif (!stats) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tconst iqr = stats.q3 - stats.q1;\n\t\t\tconst lowerFence = stats.q1 - 1.5 * iqr;\n\t\t\tconst upperFence = stats.q3 + 1.5 * iqr;\n\t\t\tconst inlierValues = values.filter(\n\t\t\t\t(value) => !options || (value >= lowerFence && value <= upperFence),\n\t\t\t);\n\t\t\tconst whiskerMin = inlierValues.length > 0 ? Math.min(...inlierValues) : stats.min;\n\t\t\tconst whiskerMax = inlierValues.length > 0 ? Math.max(...inlierValues) : stats.max;\n\t\t\tconst boxX =\n\t\t\t\tlayout.plotLeft +\n\t\t\t\tgroupWidth * categoryIndex +\n\t\t\t\tslotWidth * seriesIndex +\n\t\t\t\t(slotWidth - boxW) / 2;\n\t\t\tconst mean = values.reduce((sum, value) => sum + value, 0) / values.length;\n\t\t\toutput.push({\n\t\t\t\tstats,\n\t\t\t\tboxX,\n\t\t\t\tboxW,\n\t\t\t\txMid: boxX + boxW / 2,\n\t\t\t\tyMin: valueToY(whiskerMin, range, layout.plotTop, layout.plotBottom),\n\t\t\t\tyMax: valueToY(whiskerMax, range, layout.plotTop, layout.plotBottom),\n\t\t\t\tyQ1: valueToY(stats.q1, range, layout.plotTop, layout.plotBottom),\n\t\t\t\tyQ3: valueToY(stats.q3, range, layout.plotTop, layout.plotBottom),\n\t\t\t\tyMed: valueToY(stats.median, range, layout.plotTop, layout.plotBottom),\n\t\t\t\tyMean: valueToY(mean, range, layout.plotTop, layout.plotBottom),\n\t\t\t\tfill: seriesColor(series, seriesIndex, colorPalette),\n\t\t\t\tseriesIndex,\n\t\t\t\tcategoryIndex,\n\t\t\t\toptions,\n\t\t\t\tpoints: observations.map((item, index) => ({\n\t\t\t\t\tx: boxX + boxW * (0.2 + (0.6 * (index + 1)) / (observations.length + 1)),\n\t\t\t\t\ty: valueToY(item.value, range, layout.plotTop, layout.plotBottom),\n\t\t\t\t\tseriesIndex,\n\t\t\t\t\trowIndex: item.row,\n\t\t\t\t\toutlier: item.value < whiskerMin || item.value > whiskerMax,\n\t\t\t\t})),\n\t\t\t});\n\t\t});\n\t});\n\treturn output;\n}\n\nfunction whiskerPrimitives(geometry: BoxWhiskerGeometry): SvgPrimitive[] {\n\tconst g = geometry;\n\treturn [\n\t\t{\n\t\t\tkind: 'line',\n\t\t\tx1: g.xMid,\n\t\t\ty1: g.yMax,\n\t\t\tx2: g.xMid,\n\t\t\ty2: g.yQ3,\n\t\t\tstroke: WHISKER_COLOR,\n\t\t\tstrokeWidth: 1,\n\t\t},\n\t\t{\n\t\t\tkind: 'line',\n\t\t\tx1: g.xMid,\n\t\t\ty1: g.yQ1,\n\t\t\tx2: g.xMid,\n\t\t\ty2: g.yMin,\n\t\t\tstroke: WHISKER_COLOR,\n\t\t\tstrokeWidth: 1,\n\t\t},\n\t\t{\n\t\t\tkind: 'line',\n\t\t\tx1: g.boxX + g.boxW * 0.25,\n\t\t\ty1: g.yMax,\n\t\t\tx2: g.boxX + g.boxW * 0.75,\n\t\t\ty2: g.yMax,\n\t\t\tstroke: WHISKER_COLOR,\n\t\t\tstrokeWidth: 1,\n\t\t},\n\t\t{\n\t\t\tkind: 'line',\n\t\t\tx1: g.boxX + g.boxW * 0.25,\n\t\t\ty1: g.yMin,\n\t\t\tx2: g.boxX + g.boxW * 0.75,\n\t\t\ty2: g.yMin,\n\t\t\tstroke: WHISKER_COLOR,\n\t\t\tstrokeWidth: 1,\n\t\t},\n\t\t{\n\t\t\tkind: 'rect',\n\t\t\tx: g.boxX,\n\t\t\ty: Math.min(g.yQ1, g.yQ3),\n\t\t\tw: g.boxW,\n\t\t\th: Math.abs(g.yQ1 - g.yQ3),\n\t\t\tfill: g.fill,\n\t\t\trx: 1,\n\t\t\topacity: 0.8,\n\t\t\tpart: { role: 'dataPoint', seriesIndex: g.seriesIndex, pointIndex: g.categoryIndex },\n\t\t},\n\t\t{\n\t\t\tkind: 'line',\n\t\t\tx1: g.boxX,\n\t\t\ty1: g.yMed,\n\t\t\tx2: g.boxX + g.boxW,\n\t\t\ty2: g.yMed,\n\t\t\tstroke: MEDIAN_COLOR,\n\t\t\tstrokeWidth: 2,\n\t\t},\n\t] satisfies Array<SvgLine | SvgRect>;\n}\n\nfunction optionPrimitives(geometry: BoxWhiskerGeometry): SvgPrimitive[] {\n\tconst options = geometry.options;\n\tif (!options) {\n\t\treturn [];\n\t}\n\tconst output: SvgPrimitive[] = [];\n\tif (options.showMeanLine) {\n\t\toutput.push({\n\t\t\tkind: 'line',\n\t\t\tx1: geometry.boxX,\n\t\t\ty1: geometry.yMean,\n\t\t\tx2: geometry.boxX + geometry.boxW,\n\t\t\ty2: geometry.yMean,\n\t\t\tstroke: '#0f766e',\n\t\t\tstrokeWidth: 1.5,\n\t\t} satisfies SvgLine);\n\t}\n\tif (options.showMeanMarker) {\n\t\toutput.push({\n\t\t\tkind: 'circle',\n\t\t\tcx: geometry.xMid,\n\t\t\tcy: geometry.yMean,\n\t\t\tr: 3,\n\t\t\tfill: '#0f766e',\n\t\t} satisfies SvgCircle);\n\t}\n\tfor (const point of geometry.points) {\n\t\tif (\n\t\t\t(point.outlier && !options.showOutlierPoints) ||\n\t\t\t(!point.outlier && !options.showInnerPoints)\n\t\t) {\n\t\t\tcontinue;\n\t\t}\n\t\toutput.push({\n\t\t\tkind: 'circle',\n\t\t\tcx: point.x,\n\t\t\tcy: point.y,\n\t\t\tr: 2.25,\n\t\t\tfill: point.outlier ? '#dc2626' : MEDIAN_COLOR,\n\t\t\tpart: { role: 'dataPoint', seriesIndex: point.seriesIndex, pointIndex: point.rowIndex },\n\t\t} satisfies SvgCircle);\n\t}\n\treturn output;\n}\n\nexport function buildBoxWhiskerViewModel(\n\telement: PptxElement,\n\tchartData: PptxChartData,\n\tcategoryLabels: ReadonlyArray<string>,\n): ChartViewModel {\n\tconst layout = computePlotLayout(element.width, element.height, chartData, true);\n\tconst range = distributionRange(chartData.series);\n\tconst geometries = computeBoxWhiskerGeometry(\n\t\tchartData,\n\t\tcategoryLabels,\n\t\tlayout,\n\t\trange,\n\t\tchartData.colorPalette,\n\t);\n\tconst primitives = geometries.flatMap((geometry) => [\n\t\t...whiskerPrimitives(geometry),\n\t\t...optionPrimitives(geometry),\n\t]);\n\tconst { gridlines, axisLabels } = buildValueAxisGridlinesAndLabels(\n\t\trange,\n\t\tlayout,\n\t\tfindValueAxis(chartData.axes),\n\t);\n\tconst { legend, legendX, legendY, legendAnchor } = buildLegend(\n\t\tchartData.series,\n\t\tchartData.colorPalette,\n\t\tlayout.svgWidth,\n\t\tchartData.style?.legendPosition ?? 'b',\n\t\tlayout.svgHeight,\n\t\tlayout.plotTop,\n\t);\n\tconst { uniqueCategories } = groupRowsByCategory(categoryLabels);\n\treturn {\n\t\tsvgWidth: layout.svgWidth,\n\t\tsvgHeight: layout.svgHeight,\n\t\ttitle: resolveChartTitleText(chartData),\n\t\ttitleX: layout.svgWidth / 2,\n\t\ttitleY: 12,\n\t\tgridlines,\n\t\taxisLabels,\n\t\tzeroLine: buildZeroLine(range, layout),\n\t\tcategoryLabels: buildCategoryLabels(uniqueCategories, layout, 'bar'),\n\t\tprimitives,\n\t\tdataLabels: [],\n\t\tlegend: chartData.style?.hasLegend ? legend : [],\n\t\tlegendX,\n\t\tlegendY,\n\t\tlegendAnchor,\n\t};\n}\n","/**\n * Raw-observation binning for the histogram/Pareto ChartEx series: numeric\n * range binning (`cx:layoutPr/cx:binning`) and category aggregation\n * (`cx:layoutPr/cx:aggregation`). Split out of `chart-histogram.ts` (which\n * consumes both to build the bar view-model) to keep each file under the\n * repo's ~300-LOC budget.\n *\n * @module chart-histogram-binning\n */\nimport type { PptxChartHistogramOptions } from 'pptx-viewer-core';\n\nimport { groupRowsByCategory } from './chart-box-whisker-stats';\nimport { formatAxisValue } from './chart-view-model';\n\nexport interface HistogramBin {\n\tvalue: number;\n\tlabel: string;\n\tsourceIndices: number[];\n}\n\nfunction binLabel(lower: number, upper: number, closed: 'l' | 'r'): string {\n\treturn closed === 'r'\n\t\t? `(${formatAxisValue(lower)}, ${formatAxisValue(upper)}]`\n\t\t: `[${formatAxisValue(lower)}, ${formatAxisValue(upper)})`;\n}\n\n/**\n * Excel/PowerPoint's automatic histogram bin count when the author specifies\n * neither `binSize` nor `binCount` (Scott's normal reference rule: bin width\n * = 3.49 * sample standard deviation * n^(-1/3), then the count needed to\n * span the data at that width). COM-verified against charts-com.pptx slide\n * 30 / chartEx5.xml: 76 raw values spanning 1-24 (sample sd ~4.898) gave\n * PowerPoint's own 6 bins of width 4 each; Scott's rule on the same data\n * gives a raw width of ~4.035, which needs exactly 6 bins to span the range,\n * matching PowerPoint bin-for-bin. The previous `ceil(sqrt(n))` fallback\n * gave 9 bins on the same data, visibly narrower than PowerPoint's own.\n */\nexport function scottBinCount(values: ReadonlyArray<number>, min: number, max: number): number {\n\tif (values.length < 2 || max <= min) {\n\t\treturn 1;\n\t}\n\tconst mean = values.reduce((sum, value) => sum + value, 0) / values.length;\n\tconst variance =\n\t\tvalues.reduce((sum, value) => sum + (value - mean) ** 2, 0) / (values.length - 1);\n\tconst sd = Math.sqrt(variance);\n\tif (!(sd > 0)) {\n\t\treturn 1;\n\t}\n\tconst width = 3.49 * sd * values.length ** (-1 / 3);\n\treturn Math.max(1, Math.ceil((max - min) / width));\n}\n\n/** Bin raw observations according to ChartEx binning properties. */\nexport function computeHistogramBins(\n\tvalues: ReadonlyArray<number>,\n\toptions: PptxChartHistogramOptions,\n): HistogramBin[] {\n\tconst closed = options.intervalClosed ?? 'l';\n\tconst finite = values\n\t\t.map((value, sourceIndex) => ({ value, sourceIndex }))\n\t\t.filter((item) => Number.isFinite(item.value));\n\tif (finite.length === 0) {\n\t\treturn [];\n\t}\n\tconst underflow = typeof options.underflow === 'number' ? options.underflow : undefined;\n\tconst overflow = typeof options.overflow === 'number' ? options.overflow : undefined;\n\tconst under =\n\t\tunderflow === undefined\n\t\t\t? []\n\t\t\t: finite.filter((item) =>\n\t\t\t\t\tclosed === 'r' ? item.value <= underflow : item.value < underflow,\n\t\t\t\t);\n\tconst over =\n\t\toverflow === undefined\n\t\t\t? []\n\t\t\t: finite.filter((item) => (closed === 'l' ? item.value >= overflow : item.value > overflow));\n\tconst regular = finite.filter((item) => !under.includes(item) && !over.includes(item));\n\tconst result: HistogramBin[] = [];\n\tif (underflow !== undefined) {\n\t\tresult.push({\n\t\t\tvalue: under.length,\n\t\t\tlabel: `${closed === 'r' ? '≤' : '<'} ${formatAxisValue(underflow)}`,\n\t\t\tsourceIndices: under.map((item) => item.sourceIndex),\n\t\t});\n\t}\n\tif (regular.length > 0) {\n\t\tconst min = Math.min(...regular.map((item) => item.value));\n\t\tconst max = Math.max(...regular.map((item) => item.value));\n\t\tconst requestedSize = options.binSize && options.binSize > 0 ? options.binSize : undefined;\n\t\tconst requestedCount = options.binCount && options.binCount > 0 ? options.binCount : undefined;\n\t\tconst start = requestedSize ? Math.floor(min / requestedSize) * requestedSize : min;\n\t\tconst count = requestedSize\n\t\t\t? Math.max(\n\t\t\t\t\tclosed === 'l'\n\t\t\t\t\t\t? Math.floor((max - start) / requestedSize) + 1\n\t\t\t\t\t\t: Math.ceil((max - start) / requestedSize),\n\t\t\t\t\t1,\n\t\t\t\t)\n\t\t\t: Math.max(\n\t\t\t\t\trequestedCount ??\n\t\t\t\t\t\tscottBinCount(\n\t\t\t\t\t\t\tregular.map((item) => item.value),\n\t\t\t\t\t\t\tmin,\n\t\t\t\t\t\t\tmax,\n\t\t\t\t\t\t),\n\t\t\t\t\t1,\n\t\t\t\t);\n\t\tconst width = requestedSize ?? Math.max((max - start) / count, 1);\n\t\tconst bins = Array.from({ length: count }, (_, index) => ({\n\t\t\tvalue: 0,\n\t\t\tlabel: binLabel(start + index * width, start + (index + 1) * width, closed),\n\t\t\tsourceIndices: [] as number[],\n\t\t}));\n\t\tfor (const item of regular) {\n\t\t\tconst rawIndex =\n\t\t\t\tclosed === 'r'\n\t\t\t\t\t? Math.ceil((item.value - start) / width) - 1\n\t\t\t\t\t: Math.floor((item.value - start) / width);\n\t\t\tconst index = Math.max(0, Math.min(rawIndex, bins.length - 1));\n\t\t\tbins[index].value += 1;\n\t\t\tbins[index].sourceIndices.push(item.sourceIndex);\n\t\t}\n\t\tresult.push(...bins);\n\t}\n\tif (overflow !== undefined) {\n\t\tresult.push({\n\t\t\tvalue: over.length,\n\t\t\tlabel: `${closed === 'l' ? '≥' : '>'} ${formatAxisValue(overflow)}`,\n\t\t\tsourceIndices: over.map((item) => item.sourceIndex),\n\t\t});\n\t}\n\treturn result;\n}\n\n/**\n * Aggregate raw observations by their (repeated) category label instead of by\n * numeric value range: `cx:layoutPr/cx:aggregation` (COM-verified against\n * charts-com.pptx slide 31 / chartEx6.xml) means the source rows are\n * CATEGORICAL, one row per occurrence, with the value column carrying a\n * constant `1` so summing it counts occurrences per category. Summing\n * (rather than literally counting rows) also does the right thing for a\n * dataset that authors a real numeric measure per row instead of a bare `1`.\n */\nexport function aggregateByCategory(\n\tvalues: ReadonlyArray<number>,\n\trawCategories: ReadonlyArray<string>,\n): HistogramBin[] {\n\tconst { uniqueCategories, rowIndexesByCategory } = groupRowsByCategory(rawCategories);\n\treturn uniqueCategories.map((label) => {\n\t\tconst rows = rowIndexesByCategory.get(label) ?? [];\n\t\treturn {\n\t\t\tvalue: rows.reduce((sum, row) => sum + (values[row] ?? 0), 0),\n\t\t\tlabel,\n\t\t\tsourceIndices: rows,\n\t\t};\n\t});\n}\n","import type { PptxChartData, PptxElement } from 'pptx-viewer-core';\n\nimport { resolveChartTitleText } from './chart-auto-title';\nimport { buildValueAxisGridlinesAndLabels, findValueAxis } from './chart-cx-axis-units';\nimport { dataLabelFontOverride, resolveDataLabelTextStyle } from './chart-data-label-text';\nimport { distributionRange } from './chart-distribution-range';\nimport { DEFAULT_CHART_DATA_LABEL_PX } from './chart-font';\nimport { aggregateByCategory, computeHistogramBins } from './chart-histogram-binning';\nimport { buildParetoAxis, buildParetoPrimitives, orderParetoEntries } from './chart-pareto';\nimport type { ParetoEntry } from './chart-pareto';\nimport type {\n\tChartViewModel,\n\tPlotLayout,\n\tSvgPrimitive,\n\tSvgRect,\n\tSvgText,\n\tValueRange,\n} from './chart-view-model';\nimport {\n\tbuildCategoryLabels,\n\tbuildLegend,\n\tbuildZeroLine,\n\tcomputePlotLayout,\n\tformatAxisValue,\n\tpaletteColor,\n\tvalueToY,\n} from './chart-view-model';\n\n// Re-exported so `chart-distribution.ts`'s existing `export * from\n// './chart-histogram'` barrel keeps surfacing these after the split.\nexport {\n\taggregateByCategory,\n\tcomputeHistogramBins,\n\tscottBinCount,\n} from './chart-histogram-binning';\nexport type { HistogramBin } from './chart-histogram-binning';\n\nconst DATA_LABEL_COLOR = '#334155';\n\nexport interface HistogramBar {\n\tx: number;\n\ty: number;\n\tw: number;\n\th: number;\n\tfill: string;\n\tpointIndex?: number;\n}\n\nexport function computeHistogramBars(\n\tvalues: ReadonlyArray<number>,\n\tcatCount: number,\n\tlayout: PlotLayout,\n\trange: ValueRange,\n\tseriesColorOverride: string | undefined,\n\tcolorPalette: readonly string[] | undefined,\n): HistogramBar[] {\n\tconst count = Math.max(catCount, values.length, 1);\n\tconst barWidth = layout.plotWidth / count;\n\t// A histogram (and a Pareto's frequency bars) plots ONE distribution, not\n\t// one colour-coded category per bar: every bar takes the series' own\n\t// colour (COM-verified against charts-com.pptx slides 30-31, chartEx5/6:\n\t// PowerPoint paints every bin/bar the same single accent colour).\n\tconst fill = seriesColorOverride ?? paletteColor(0, colorPalette);\n\treturn values.map((val, pointIndex) => {\n\t\tconst zeroY = valueToY(0, range, layout.plotTop, layout.plotBottom);\n\t\tconst valY = valueToY(val, range, layout.plotTop, layout.plotBottom);\n\t\treturn {\n\t\t\tx: layout.plotLeft + barWidth * pointIndex,\n\t\t\ty: Math.min(zeroY, valY),\n\t\t\tw: Math.max(barWidth - 0.5, 1),\n\t\t\th: Math.max(Math.abs(zeroY - valY), 1),\n\t\t\tfill,\n\t\t\tpointIndex,\n\t\t};\n\t});\n}\n\nexport function buildHistogramViewModel(\n\telement: PptxElement,\n\tchartData: PptxChartData,\n\tcategoryLabels: ReadonlyArray<string>,\n): ChartViewModel {\n\tconst paretoIndex = chartData.series.findIndex(\n\t\t(item) => item.histogramOptions?.layout === 'pareto',\n\t);\n\tconst layout = computePlotLayout(element.width, element.height, chartData, true, {\n\t\thasSecondaryValueAxis: paretoIndex >= 0,\n\t});\n\tconst histogramIndex = Math.max(\n\t\tchartData.series.findIndex((series) => series.histogramOptions?.layout !== 'pareto'),\n\t\t0,\n\t);\n\tconst series = chartData.series[histogramIndex];\n\tconst options = series?.histogramOptions;\n\tconst bins = options?.aggregateByCategory\n\t\t? aggregateByCategory(series?.values ?? [], categoryLabels)\n\t\t: options?.layout === 'histogram'\n\t\t\t? computeHistogramBins(series?.values ?? [], options)\n\t\t\t: undefined;\n\tconst baseEntries: ParetoEntry[] = (\n\t\tbins?.map((bin) => ({ value: bin.value, label: bin.label })) ??\n\t\t(series?.values ?? []).map((value, index) => ({\n\t\t\tvalue,\n\t\t\tlabel: categoryLabels[index] ?? '',\n\t\t}))\n\t).map((entry, sourcePointIndex) => ({ ...entry, sourcePointIndex }));\n\tconst entries = paretoIndex >= 0 ? orderParetoEntries(baseEntries) : baseEntries;\n\tconst values = entries.map((entry) => entry.value);\n\tconst labels = entries.map((entry) => entry.label);\n\tconst range = distributionRange([{ name: series?.name ?? '', values }]);\n\tconst bars = computeHistogramBars(\n\t\tvalues,\n\t\tlabels.length,\n\t\tlayout,\n\t\trange,\n\t\tseries?.color,\n\t\tchartData.colorPalette,\n\t);\n\tconst primitives: SvgPrimitive[] = bars.map(\n\t\t(bar, displayIndex) =>\n\t\t\t({\n\t\t\t\tkind: 'rect',\n\t\t\t\tx: bar.x,\n\t\t\t\ty: bar.y,\n\t\t\t\tw: bar.w,\n\t\t\t\th: bar.h,\n\t\t\t\tfill: bar.fill,\n\t\t\t\topacity: 0.85,\n\t\t\t\t...(bins\n\t\t\t\t\t? {}\n\t\t\t\t\t: {\n\t\t\t\t\t\t\tpart: {\n\t\t\t\t\t\t\t\trole: 'dataPoint',\n\t\t\t\t\t\t\t\tseriesIndex: histogramIndex,\n\t\t\t\t\t\t\t\tpointIndex: entries[displayIndex]?.sourcePointIndex ?? displayIndex,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t}),\n\t\t\t}) satisfies SvgRect,\n\t);\n\tif (paretoIndex >= 0) {\n\t\tprimitives.push(\n\t\t\t...buildParetoPrimitives(entries, layout, chartData.series[paretoIndex], paretoIndex),\n\t\t);\n\t}\n\tconst dataLabels: SvgText[] = chartData.style?.hasDataLabels\n\t\t? bars.map((bar, index) => ({\n\t\t\t\tkind: 'text',\n\t\t\t\tx: bar.x + bar.w / 2,\n\t\t\t\ty: bar.y - 4,\n\t\t\t\ttext: formatAxisValue(values[index]),\n\t\t\t\tfontSize: DEFAULT_CHART_DATA_LABEL_PX,\n\t\t\t\tfill: DATA_LABEL_COLOR,\n\t\t\t\ttextAnchor: 'middle',\n\t\t\t\t...(series\n\t\t\t\t\t? dataLabelFontOverride(\n\t\t\t\t\t\t\tresolveDataLabelTextStyle(\n\t\t\t\t\t\t\t\tchartData,\n\t\t\t\t\t\t\t\tseries,\n\t\t\t\t\t\t\t\tentries[index]?.sourcePointIndex ?? index,\n\t\t\t\t\t\t\t),\n\t\t\t\t\t\t)\n\t\t\t\t\t: {}),\n\t\t\t}))\n\t\t: [];\n\tconst { gridlines, axisLabels } = buildValueAxisGridlinesAndLabels(\n\t\trange,\n\t\tlayout,\n\t\tfindValueAxis(chartData.axes),\n\t);\n\tconst paretoAxis = paretoIndex >= 0 ? buildParetoAxis(layout) : undefined;\n\tconst { legend, legendX, legendY, legendAnchor } = buildLegend(\n\t\tchartData.series,\n\t\tchartData.colorPalette,\n\t\tlayout.svgWidth,\n\t\tchartData.style?.legendPosition ?? 'b',\n\t\tlayout.svgHeight,\n\t\tlayout.plotTop,\n\t);\n\treturn {\n\t\tsvgWidth: layout.svgWidth,\n\t\tsvgHeight: layout.svgHeight,\n\t\ttitle: resolveChartTitleText(chartData),\n\t\ttitleX: layout.svgWidth / 2,\n\t\ttitleY: 12,\n\t\tgridlines,\n\t\taxisLabels,\n\t\tzeroLine: buildZeroLine(range, layout),\n\t\tcategoryLabels: buildCategoryLabels(labels, layout, 'bar'),\n\t\tprimitives,\n\t\tdataLabels,\n\t\tlegend: chartData.style?.hasLegend ? legend : [],\n\t\tlegendX,\n\t\tlegendY,\n\t\tlegendAnchor,\n\t\tsecondaryGridlines: paretoAxis?.secondaryGridlines,\n\t\tsecondaryAxisLabels: paretoAxis?.secondaryAxisLabels,\n\t};\n}\n","import type { PptxChartData } from 'pptx-viewer-core';\n\nimport { paletteColor } from './chart-view-model';\n\n/** One sunburst ring arc segment. */\nexport interface SunburstArc {\n\t/** SVG path `d` of the arc (donut wedge). */\n\td: string;\n\t/** Fill colour. */\n\tfill: string;\n\t/** Opacity (outer rings fade), clamped to at least 0.1. */\n\topacity: number;\n\t/** Source leaf point for interactive outer-ring arcs. */\n\tpointIndex?: number;\n\t/** Zero-based rendered ring index, where zero is innermost. */\n\tlevel?: number;\n\t/** Category label represented by this arc when hierarchy data is available. */\n\tlabel?: string;\n\t/** Label anchor X, at the arc's mid-angle and mid-radius. */\n\tlabelX: number;\n\t/** Label anchor Y, at the arc's mid-angle and mid-radius. */\n\tlabelY: number;\n\t/**\n\t * SVG rotation in degrees to draw the label radiating outward from the\n\t * centre, flipped upright whenever a literal radial angle would otherwise\n\t * render the text upside down (COM-verified against charts-com.pptx slide\n\t * 29 / chartEx4.xml: every ring's labels, at every angle around the\n\t * circle, read left-to-right rather than upside down on the wedge's\n\t * \"far\" half).\n\t */\n\tlabelRotation: number;\n}\n\n/** Label position + upright radial rotation for a wedge spanning `[startAngle, endAngle)`. */\nfunction arcLabelPlacement(\n\tcx: number,\n\tcy: number,\n\tradius: number,\n\tstartAngle: number,\n\tendAngle: number,\n): { labelX: number; labelY: number; labelRotation: number } {\n\tconst midAngle = (startAngle + endAngle) / 2;\n\tlet rotation = (midAngle * 180) / Math.PI + 90;\n\t// Flip upright: a rotation in (90, 270) draws the text upside down.\n\tif (rotation > 90 && rotation < 270) {\n\t\trotation -= 180;\n\t}\n\treturn {\n\t\tlabelX: cx + radius * Math.cos(midAngle),\n\t\tlabelY: cy + radius * Math.sin(midAngle),\n\t\tlabelRotation: rotation,\n\t};\n}\n\nfunction arcPath(\n\tcx: number,\n\tcy: number,\n\tinnerRadius: number,\n\touterRadius: number,\n\tstartAngle: number,\n\tendAngle: number,\n): string {\n\tconst sweep = endAngle - startAngle;\n\tconst largeArc = sweep > Math.PI ? 1 : 0;\n\tconst x1 = cx + outerRadius * Math.cos(startAngle);\n\tconst y1 = cy + outerRadius * Math.sin(startAngle);\n\tconst x2 = cx + outerRadius * Math.cos(endAngle);\n\tconst y2 = cy + outerRadius * Math.sin(endAngle);\n\tconst x3 = cx + innerRadius * Math.cos(endAngle);\n\tconst y3 = cy + innerRadius * Math.sin(endAngle);\n\tconst x4 = cx + innerRadius * Math.cos(startAngle);\n\tconst y4 = cy + innerRadius * Math.sin(startAngle);\n\treturn `M ${x1} ${y1} A ${outerRadius} ${outerRadius} 0 ${largeArc} 1 ${x2} ${y2} L ${x3} ${y3} A ${innerRadius} ${innerRadius} 0 ${largeArc} 0 ${x4} ${y4} Z`;\n}\n\n/** Compute the legacy one-ring-per-series sunburst geometry. */\nexport function computeSunburstArcs(\n\tseries: PptxChartData['series'],\n\tcx: number,\n\tcy: number,\n\tmaxR: number,\n\tcolorPalette: readonly string[] | undefined,\n): SunburstArc[] {\n\tconst seriesCount = Math.max(series.length, 1);\n\tconst ringWidth = maxR / (seriesCount + 0.5);\n\tconst out: SunburstArc[] = [];\n\n\tfor (let si = 0; si < series.length; si++) {\n\t\tconst values = series[si].values;\n\t\tconst innerRadius = ringWidth * (si + 0.5);\n\t\tconst outerRadius = ringWidth * (si + 1.5);\n\t\tconst total = values.reduce((acc, value) => acc + Math.abs(value), 0) || 1;\n\t\tlet startAngle = -Math.PI / 2;\n\t\tfor (let pointIndex = 0; pointIndex < values.length; pointIndex++) {\n\t\t\tconst endAngle = startAngle + (Math.abs(values[pointIndex]) / total) * Math.PI * 2;\n\t\t\tout.push({\n\t\t\t\td: arcPath(cx, cy, innerRadius, outerRadius, startAngle, endAngle),\n\t\t\t\tfill: paletteColor(pointIndex, colorPalette),\n\t\t\t\topacity: Math.max(0.1, 0.9 - si * 0.1),\n\t\t\t\tpointIndex,\n\t\t\t\tlevel: si,\n\t\t\t\t...arcLabelPlacement(cx, cy, (innerRadius + outerRadius) / 2, startAngle, endAngle),\n\t\t\t});\n\t\t\tstartAngle = endAngle;\n\t\t}\n\t}\n\treturn out;\n}\n\nfunction hierarchyKey(levels: ReadonlyArray<ReadonlyArray<string>>, level: number, index: number) {\n\treturn levels\n\t\t.slice(level)\n\t\t.map((labels) => labels[index] ?? '')\n\t\t.join('\\u0000');\n}\n\n/**\n * Compute one aligned ring per ChartEx category level. Levels are stored leaf\n * first, so the highest parent level becomes the innermost ring. Parent wedges\n * aggregate the values of their contiguous descendant leaves.\n */\nexport function computeHierarchicalSunburstArcs(\n\tcategoryLevels: ReadonlyArray<ReadonlyArray<string>>,\n\tvalues: ReadonlyArray<number>,\n\tcx: number,\n\tcy: number,\n\tmaxR: number,\n\tcolorPalette: readonly string[] | undefined,\n): SunburstArc[] {\n\tconst levels = categoryLevels.filter((level) => level.length > 0);\n\tconst leafCount = Math.max(values.length, ...levels.map((level) => level.length), 0);\n\tif (levels.length === 0 || leafCount === 0) {\n\t\treturn [];\n\t}\n\tconst rawWeights = Array.from({ length: leafCount }, (_, index) => Math.abs(values[index] ?? 0));\n\tconst weights = rawWeights.some((value) => value !== 0) ? rawWeights : rawWeights.map(() => 1);\n\tconst total = weights.reduce((sum, value) => sum + value, 0);\n\tconst prefix = [0];\n\tfor (const weight of weights) {\n\t\tprefix.push((prefix[prefix.length - 1] ?? 0) + weight);\n\t}\n\n\tconst ringWidth = maxR / (levels.length + 0.5);\n\tconst rootLabels = levels[levels.length - 1] ?? [];\n\tconst rootColors = new Map<string, number>();\n\tconst out: SunburstArc[] = [];\n\tfor (let level = levels.length - 1; level >= 0; level--) {\n\t\tconst ringIndex = levels.length - 1 - level;\n\t\tconst innerRadius = ringWidth * (ringIndex + 0.5);\n\t\tconst outerRadius = ringWidth * (ringIndex + 1.5);\n\t\tlet start = 0;\n\t\twhile (start < leafCount) {\n\t\t\tconst key = hierarchyKey(levels, level, start);\n\t\t\tlet end = start + 1;\n\t\t\twhile (end < leafCount && hierarchyKey(levels, level, end) === key) {\n\t\t\t\tend++;\n\t\t\t}\n\t\t\tconst startAngle = -Math.PI / 2 + (prefix[start] / total) * Math.PI * 2;\n\t\t\tconst endAngle = -Math.PI / 2 + (prefix[end] / total) * Math.PI * 2;\n\t\t\tconst rootLabel = rootLabels[start] ?? '';\n\t\t\tif (!rootColors.has(rootLabel)) {\n\t\t\t\trootColors.set(rootLabel, rootColors.size);\n\t\t\t}\n\t\t\tout.push({\n\t\t\t\td: arcPath(cx, cy, innerRadius, outerRadius, startAngle, endAngle),\n\t\t\t\tfill: paletteColor(rootColors.get(rootLabel) ?? start, colorPalette),\n\t\t\t\topacity: Math.max(0.1, 0.9 - ringIndex * 0.1),\n\t\t\t\tlevel: ringIndex,\n\t\t\t\tlabel: levels[level][start] ?? '',\n\t\t\t\t...(level === 0 && end === start + 1 ? { pointIndex: start } : {}),\n\t\t\t\t...arcLabelPlacement(cx, cy, (innerRadius + outerRadius) / 2, startAngle, endAngle),\n\t\t\t});\n\t\t\tstart = end;\n\t\t}\n\t}\n\treturn out;\n}\n","/**\n * Shared colour ramp and view-model chrome helpers for the surface and\n * treemap chart kinds.\n *\n * Split out of `chart-surface-treemap.ts` (which re-exports `surfaceColor`)\n * to keep that file's several chart-kind builders each under the repo's\n * per-file line budget.\n *\n * @module chart-surface-common\n */\n\nimport type { ChartViewModel } from './chart-view-model';\n\n/**\n * Map a normalised value t in [0..1] to a surface colour ramp (blue-green-red).\n *\n * Exported so the interactive 3D scene adapter (`surface-chart-3d-data.ts`)\n * tints its mesh with the exact same ramp as this module's flat/isometric SVG\n * fallback: one colour formula, never two to drift apart.\n */\nexport function surfaceColor(t: number): { r: number; g: number; b: number } {\n\treturn {\n\t\tr: Math.round(30 + 200 * t),\n\t\tg: Math.round(80 + 100 * (1 - Math.abs(t - 0.5) * 2)),\n\t\tb: Math.round(200 * (1 - t) + 30),\n\t};\n}\n\n/** Darken an rgb triplet by a factor in [0..1]. */\nexport function darkenRgb(r: number, g: number, b: number, factor: number): string {\n\treturn `rgb(${Math.round(r * factor)},${Math.round(g * factor)},${Math.round(b * factor)})`;\n}\n\n/** The chart-chrome fields every surface/treemap view-model leaves empty. */\nexport function emptyChrome(): Pick<\n\tChartViewModel,\n\t'gridlines' | 'axisLabels' | 'zeroLine' | 'categoryLabels' | 'dataLabels'\n> {\n\treturn {\n\t\tgridlines: [],\n\t\taxisLabels: [],\n\t\tzeroLine: undefined,\n\t\tcategoryLabels: [],\n\t\tdataLabels: [],\n\t};\n}\n","/**\n * View-model builder for the sunburst chart kind: concentric arc rings, one\n * ring per series (or, for a ChartEx hierarchy, one ring per category\n * level), each ring split into arc segments proportional to abs(value).\n *\n * Split out of `chart-funnel-sunburst.ts` (which re-exports this) to keep\n * that file's funnel + sunburst builders each under the repo's per-file\n * line budget.\n *\n * Ported from:\n * packages/react/src/viewer/utils/chart-sunburst-funnel.tsx (renderSunburstChart)\n * packages/vue/src/viewer/components/chart/SunburstChart.vue\n *\n * @module chart-sunburst-view\n */\n\nimport type { PptxChartData, PptxElement } from 'pptx-viewer-core';\n\nimport { resolveChartTitleText } from './chart-auto-title';\nimport { computeHierarchicalSunburstArcs, computeSunburstArcs } from './chart-sunburst-hierarchy';\nimport { emptyChrome } from './chart-surface-common';\nimport type { ChartViewModel, SvgPath, SvgPrimitive, SvgText } from './chart-view-model';\nimport { computePlotLayout, paletteColor } from './chart-view-model';\n\ntype HierarchicalChartData = PptxChartData & { categoryLevels?: string[][] };\n\n/**\n * Build the view-model for a sunburst chart: concentric arc rings, one per\n * series. Mirrors `renderSunburstChart` (React) / `SunburstChart.vue`.\n */\nexport function buildSunburstViewModel(\n\telement: PptxElement,\n\tchartData: PptxChartData,\n\tcategoryLabels: ReadonlyArray<string>,\n): ChartViewModel {\n\tconst layout = computePlotLayout(element.width, element.height, chartData, false);\n\tconst cx = layout.plotLeft + layout.plotWidth / 2;\n\tconst cy = layout.plotTop + layout.plotHeight / 2;\n\tconst maxR = Math.min(layout.plotWidth, layout.plotHeight) / 2 - 4;\n\tconst categoryLevels = (chartData as HierarchicalChartData).categoryLevels;\n\n\tconst arcs = categoryLevels?.length\n\t\t? computeHierarchicalSunburstArcs(\n\t\t\t\tcategoryLevels,\n\t\t\t\tchartData.series[0]?.values ?? [],\n\t\t\t\tcx,\n\t\t\t\tcy,\n\t\t\t\tmaxR,\n\t\t\t\tchartData.colorPalette,\n\t\t\t)\n\t\t: computeSunburstArcs(chartData.series, cx, cy, maxR, chartData.colorPalette);\n\tconst primitives: SvgPrimitive[] = arcs.map(\n\t\t(arc) =>\n\t\t\t({\n\t\t\t\tkind: 'path',\n\t\t\t\td: arc.d,\n\t\t\t\tfill: arc.fill,\n\t\t\t\tstroke: '#ffffff',\n\t\t\t\tstrokeWidth: 1,\n\t\t\t\topacity: arc.opacity,\n\t\t\t\tpart:\n\t\t\t\t\tarc.pointIndex === undefined\n\t\t\t\t\t\t? undefined\n\t\t\t\t\t\t: { role: 'dataPoint', seriesIndex: 0, pointIndex: arc.pointIndex },\n\t\t\t}) satisfies SvgPath,\n\t);\n\n\t// One label per arc, radiating outward and kept upright (COM-verified:\n\t// charts-com.pptx slide 29 labels every ring, at every angle).\n\tconst dataLabels: SvgText[] = arcs\n\t\t.filter((arc): arc is typeof arc & { label: string } => Boolean(arc.label))\n\t\t.map((arc) => ({\n\t\t\tkind: 'text',\n\t\t\tx: arc.labelX,\n\t\t\ty: arc.labelY,\n\t\t\ttext: arc.label,\n\t\t\tfontSize: 10,\n\t\t\tfill: '#ffffff',\n\t\t\ttextAnchor: 'middle',\n\t\t\tdominantBaseline: 'central',\n\t\t\ttransform: `rotate(${arc.labelRotation}, ${arc.labelX}, ${arc.labelY})`,\n\t\t}));\n\n\tconst legendLabels = categoryLevels?.length\n\t\t? [...new Set(categoryLevels[categoryLevels.length - 1]?.filter(Boolean) ?? categoryLabels)]\n\t\t: categoryLabels;\n\tconst legend = chartData.style?.hasLegend\n\t\t? legendLabels.map((label, i) => ({ color: paletteColor(i, chartData.colorPalette), label }))\n\t\t: [];\n\n\tconst title = resolveChartTitleText(chartData);\n\n\treturn {\n\t\tsvgWidth: layout.svgWidth,\n\t\tsvgHeight: layout.svgHeight,\n\t\ttitle,\n\t\ttitleX: layout.svgWidth / 2,\n\t\ttitleY: 14,\n\t\t...emptyChrome(),\n\t\tprimitives,\n\t\tdataLabels,\n\t\tlegend,\n\t\tlegendX: layout.svgWidth / 2,\n\t\tlegendY: layout.svgHeight - 8,\n\t\tlegendAnchor: 'middle',\n\t};\n}\n","/**\n * View-model builder for the funnel chart kind, plus the barrel that\n * re-exports its sunburst sibling (`chart-sunburst-view.ts`) so every\n * existing `./chart-funnel-sunburst` import keeps working after the two\n * were split into their own files to stay under the repo's per-file line\n * budget.\n *\n * Ported from:\n * packages/react/src/viewer/utils/chart-sunburst-funnel.tsx (renderFunnelChart,\n * renderSunburstChart)\n * packages/vue/src/viewer/components/chart/FunnelChart.vue\n * packages/vue/src/viewer/components/chart/SunburstChart.vue\n *\n * Both bindings carried identical geometry; this module reconciles them into one\n * pure builder per kind that returns the engine's standard `ChartViewModel`\n * (SVG primitives only, zero framework / DOM dependencies).\n *\n * Funnel: one descending centred bar per value of series[0], width\n * proportional to abs(value), all one colour; value label inline,\n * category name on a left-side axis.\n * Sunburst: concentric arc rings, one ring per series, each ring split into arc\n * segments proportional to abs(value); outer rings fade in opacity.\n *\n * @module chart-funnel-sunburst\n */\n\nimport type { PptxChartData, PptxElement } from 'pptx-viewer-core';\n\nimport { resolveChartTitleText } from './chart-auto-title';\nimport { dataLabelFontOverride, resolveDataLabelTextStyle } from './chart-data-label-text';\nimport { DEFAULT_CHART_TEXT_PX } from './chart-font';\nimport type { ChartViewModel, SvgPath, SvgPrimitive, SvgText } from './chart-view-model';\nimport {\n\tAXIS_LABEL_COLOR,\n\tcomputePlotLayout,\n\tformatAxisValue,\n\tpaletteColor,\n} from './chart-view-model';\n\nexport type { SunburstArc } from './chart-sunburst-hierarchy';\nexport { computeHierarchicalSunburstArcs, computeSunburstArcs } from './chart-sunburst-hierarchy';\nexport { buildSunburstViewModel } from './chart-sunburst-view';\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Shared empty-chrome helper (funnel / sunburst have no cartesian axes)\n// ─────────────────────────────────────────────────────────────────────────────\n\nfunction emptyChrome(): Pick<\n\tChartViewModel,\n\t'gridlines' | 'axisLabels' | 'zeroLine' | 'categoryLabels'\n> {\n\treturn {\n\t\tgridlines: [],\n\t\taxisLabels: [],\n\t\tzeroLine: undefined,\n\t\tcategoryLabels: [],\n\t};\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Funnel geometry\n// ─────────────────────────────────────────────────────────────────────────────\n\n/** One funnel bar plus its centred label descriptor. */\nexport interface FunnelSegment {\n\t/** SVG path `d` of the bar (a plain centred rectangle). */\n\td: string;\n\t/** Fill colour: the series' own colour, the same for every bar. */\n\tfill: string;\n\t/** Bar width in px. */\n\ttopW: number;\n\t/** Same as `topW`: a funnel bar has no taper. Kept for API stability. */\n\tbotW: number;\n\t/** Centred label X. */\n\tlabelX: number;\n\t/** Centred label Y. */\n\tlabelY: number;\n\t/** Label text: the point's formatted value. */\n\tlabelText: string;\n\t/** Label font size. */\n\tfontSize: number;\n\t/** Category-axis label X (left of the plot area). */\n\tcategoryLabelX: number;\n\t/** Category-axis label Y (vertically centred on the bar). */\n\tcategoryLabelY: number;\n\t/** Category-axis label text. */\n\tcategoryText: string;\n}\n\n/**\n * Compute the descending funnel bars for series[0].\n *\n * Each bar is a plain rectangle centred on the plot's horizontal midline,\n * its width proportional to `abs(value) / max(abs(values))`. COM-verified\n * against charts-com.pptx slide 27 (chartEx2.xml): PowerPoint draws flat\n * centred bars, not tapering trapezoids, all painted the series' one colour\n * (never a colour cycling per bar), with the point's VALUE as its inline\n * label and the category name on a left-side axis instead.\n */\nexport function computeFunnelSegments(\n\tvalues: ReadonlyArray<number>,\n\tplotLeft: number,\n\tplotTop: number,\n\tplotWidth: number,\n\tplotHeight: number,\n\tcategories: ReadonlyArray<string>,\n\tcolorPalette: readonly string[] | undefined,\n\tseriesColorOverride?: string,\n): FunnelSegment[] {\n\tconst count = values.length;\n\tif (count === 0) {\n\t\treturn [];\n\t}\n\tconst maxVal = Math.max(...values.map((v) => Math.abs(v)), 1);\n\tconst segH = plotHeight / Math.max(count, 1);\n\tconst centerX = plotLeft + plotWidth / 2;\n\t// An explicit series colour (c:ser/cx:series spPr solidFill) wins over the\n\t// palette default; either way every bar takes the SAME single colour.\n\tconst fill = seriesColorOverride ?? paletteColor(0, colorPalette);\n\tconst out: FunnelSegment[] = [];\n\n\tfor (let i = 0; i < count; i++) {\n\t\tconst val = values[i];\n\t\tconst w = (Math.abs(val) / maxVal) * plotWidth;\n\t\tconst y = plotTop + i * segH;\n\t\tconst labelY = y + segH / 2 + 4;\n\n\t\tconst d = [\n\t\t\t`M ${centerX - w / 2} ${y}`,\n\t\t\t`L ${centerX + w / 2} ${y}`,\n\t\t\t`L ${centerX + w / 2} ${y + segH}`,\n\t\t\t`L ${centerX - w / 2} ${y + segH}`,\n\t\t\t'Z',\n\t\t].join(' ');\n\n\t\tout.push({\n\t\t\td,\n\t\t\tfill,\n\t\t\ttopW: w,\n\t\t\tbotW: w,\n\t\t\tlabelX: centerX,\n\t\t\tlabelY,\n\t\t\tlabelText: formatAxisValue(val),\n\t\t\tfontSize: Math.min(10, segH * 0.4),\n\t\t\tcategoryLabelX: plotLeft - 8,\n\t\t\tcategoryLabelY: labelY,\n\t\t\tcategoryText: categories[i] ?? '',\n\t\t});\n\t}\n\treturn out;\n}\n\n/**\n * Build the view-model for a funnel chart: descending centred bars from\n * series[0], each labelled with its value; the category names form a\n * left-side axis instead of the inline label (COM-verified: charts-com.pptx\n * slide 27). Mirrors `renderFunnelChart` (React) / `FunnelChart.vue`.\n */\nexport function buildFunnelViewModel(\n\telement: PptxElement,\n\tchartData: PptxChartData,\n\tcategoryLabels: ReadonlyArray<string>,\n): ChartViewModel {\n\tconst layout = computePlotLayout(element.width, element.height, chartData, false);\n\tconst values = chartData.series[0]?.values ?? [];\n\tconst segments = computeFunnelSegments(\n\t\tvalues,\n\t\tlayout.plotLeft,\n\t\tlayout.plotTop,\n\t\tlayout.plotWidth,\n\t\tlayout.plotHeight,\n\t\tcategoryLabels,\n\t\tchartData.colorPalette,\n\t\tchartData.series[0]?.color,\n\t);\n\n\tconst primitives: SvgPrimitive[] = [];\n\tconst dataLabels: SvgText[] = [];\n\n\tfor (const seg of segments) {\n\t\tprimitives.push({\n\t\t\tkind: 'path',\n\t\t\td: seg.d,\n\t\t\tfill: seg.fill,\n\t\t\tstroke: '#ffffff',\n\t\t\tstrokeWidth: 1,\n\t\t} satisfies SvgPath);\n\t}\n\tconst funnelSeries = chartData.series[0];\n\tsegments.forEach((seg, i) => {\n\t\tdataLabels.push({\n\t\t\tkind: 'text',\n\t\t\tx: seg.labelX,\n\t\t\ty: seg.labelY,\n\t\t\ttext: seg.labelText,\n\t\t\tfontSize: seg.fontSize,\n\t\t\tfill: '#ffffff',\n\t\t\ttextAnchor: 'middle',\n\t\t\tfontWeight: 'bold',\n\t\t\t...(funnelSeries\n\t\t\t\t? dataLabelFontOverride(resolveDataLabelTextStyle(chartData, funnelSeries, i))\n\t\t\t\t: {}),\n\t\t});\n\t});\n\n\tconst title = resolveChartTitleText(chartData);\n\tconst categoryAxisLabels: SvgText[] = segments.map((seg) => ({\n\t\tkind: 'text',\n\t\tx: seg.categoryLabelX,\n\t\ty: seg.categoryLabelY,\n\t\ttext: seg.categoryText,\n\t\tfontSize: DEFAULT_CHART_TEXT_PX,\n\t\tfill: AXIS_LABEL_COLOR,\n\t\ttextAnchor: 'end',\n\t}));\n\n\treturn {\n\t\tsvgWidth: layout.svgWidth,\n\t\tsvgHeight: layout.svgHeight,\n\t\ttitle,\n\t\ttitleX: layout.svgWidth / 2,\n\t\ttitleY: 14,\n\t\t...emptyChrome(),\n\t\tcategoryLabels: categoryAxisLabels,\n\t\tprimitives,\n\t\tdataLabels,\n\t\t// Funnel does not draw a separate legend swatch list (labels are inline).\n\t\tlegend: [],\n\t\tlegendX: layout.svgWidth / 2,\n\t\tlegendY: layout.svgHeight - 8,\n\t\tlegendAnchor: 'middle',\n\t};\n}\n","/**\n * Chart gradient fills (`c:spPr/a:gradFill` on the chart area, plot area and\n * series) as `<linearGradient>` / `<radialGradient>` defs every binding\n * renders from the view model.\n *\n * COM-verified against charts-com.pptx slide 23 (chart style 209): the chart\n * area is a radial dark wash and every bar a top-lit vertical gradient;\n * both used to render flat (no chart area at all, bars in plain palette\n * colours) because only `a:solidFill` was ever read.\n *\n * Gradients use `objectBoundingBox` units, so one def per series paints each\n * of its bars across that bar's own box, as PowerPoint does\n * (`rotWithShape=\"1\"`).\n *\n * @module chart-gradient-defs\n */\nimport type { PptxChartData, PptxChartGradientFill } from 'pptx-viewer-core';\n\nimport type { ChartSvgGradientDef } from './chart-svg-def-types';\nimport type { ChartViewModel, SvgPrimitive } from './chart-view-model-types';\n\n/** Build the def for `fill` under `id`. */\nexport function buildGradientDef(id: string, fill: PptxChartGradientFill): ChartSvgGradientDef {\n\tconst stops = fill.stops.map((stop) => ({\n\t\toffset: Math.min(Math.max(stop.position / 100, 0), 1),\n\t\tcolor: stop.color,\n\t\t...(stop.opacity !== undefined ? { opacity: stop.opacity } : {}),\n\t}));\n\tif (fill.type === 'radial') {\n\t\treturn {\n\t\t\tkind: 'radialGradient',\n\t\t\tid,\n\t\t\tcx: fill.focalPoint?.x ?? 0.5,\n\t\t\tcy: fill.focalPoint?.y ?? 0.5,\n\t\t\t// `a:path path=\"circle\"` reaches the box corners, not its edges.\n\t\t\tr: Math.SQRT1_2,\n\t\t\tstops,\n\t\t};\n\t}\n\t// `a:lin/@ang` is clockwise from left-to-right; in bounding-box space the\n\t// vector through the centre at that angle spans the unit box.\n\tconst rad = ((fill.angle ?? 0) * Math.PI) / 180;\n\tconst dx = Math.cos(rad) / 2;\n\tconst dy = Math.sin(rad) / 2;\n\tconst r = (v: number) => Math.round(v * 10000) / 10000;\n\treturn {\n\t\tkind: 'linearGradient',\n\t\tid,\n\t\tx1: r(0.5 - dx),\n\t\ty1: r(0.5 - dy),\n\t\tx2: r(0.5 + dx),\n\t\ty2: r(0.5 + dy),\n\t\tstops,\n\t};\n}\n\nfunction paintSeries(\n\tprimitive: SvgPrimitive,\n\tseriesFills: ReadonlyMap<number, string>,\n\tchartData: PptxChartData,\n): SvgPrimitive {\n\tif ((primitive.kind !== 'rect' && primitive.kind !== 'path') || !primitive.part) {\n\t\treturn primitive;\n\t}\n\tconst { seriesIndex, pointIndex } = primitive.part;\n\tconst url = seriesFills.get(seriesIndex);\n\tif (url === undefined) {\n\t\treturn primitive;\n\t}\n\tconst overridden =\n\t\tpointIndex !== undefined &&\n\t\tchartData.series[seriesIndex]?.dataPoints?.some(\n\t\t\t(p) => p.idx === pointIndex && p.spPr?.fillColor !== undefined,\n\t\t);\n\treturn overridden ? primitive : { ...primitive, fill: url };\n}\n\n/**\n * Point the chart area, plot area and series marks of a finished view model\n * at gradient defs when the chart authors gradient fills.\n */\nexport function withGradientFills(\n\tvm: ChartViewModel,\n\tchartData: PptxChartData,\n\telementId: string,\n): ChartViewModel {\n\tconst defs: ChartSvgGradientDef[] = [];\n\tconst idFor = (suffix: string) => `${elementId}-grad-${suffix}`.replace(/[^A-Za-z0-9_-]/gu, '_');\n\tlet next = vm;\n\tconst area = chartData.style?.chartAreaGradient;\n\tif (area) {\n\t\tdefs.push(buildGradientDef(idFor('area'), area));\n\t\tnext = { ...next, areaFill: `url(#${idFor('area')})` };\n\t}\n\tconst plot = chartData.style?.plotAreaGradient;\n\tif (plot) {\n\t\tdefs.push(buildGradientDef(idFor('plot'), plot));\n\t\tnext = { ...next, plotFill: `url(#${idFor('plot')})` };\n\t}\n\tconst seriesFills = new Map<number, string>();\n\tchartData.series.forEach((series, si) => {\n\t\tif (series.gradientFill) {\n\t\t\tdefs.push(buildGradientDef(idFor(`s${si}`), series.gradientFill));\n\t\t\tseriesFills.set(si, `url(#${idFor(`s${si}`)})`);\n\t\t}\n\t});\n\tif (seriesFills.size > 0) {\n\t\tnext = {\n\t\t\t...next,\n\t\t\tprimitives: next.primitives.map((p) => paintSeries(p, seriesFills, chartData)),\n\t\t};\n\t}\n\treturn defs.length > 0 ? { ...next, defs: [...(next.defs ?? []), ...defs] } : next;\n}\n","/**\n * chart-legend-entries.ts - applies `c:legendEntry` overrides (deletion + a\n * per-entry `c:txPr` text-style) onto an already-built legend list.\n *\n * Every chart kind builds its own base `LegendEntry[]` (series order for most\n * kinds, category/slice order for pie / doughnut / ofPie), then\n * `buildChartViewModel` runs the result through {@link applyLegendEntryOverrides}\n * exactly once before returning. `c:legendEntry/@idx` indexes into that base\n * list in the same order it was built, matching how PowerPoint itself assigns\n * legend-entry indices. A deleted entry is dropped outright (not merely\n * hidden), so the remaining entries re-flow to fill the gap the way\n * PowerPoint's own legend does. Consuming it at this single choke point means\n * every chart kind, and all five bindings (which only ever read the finished\n * `ChartViewModel.legend`), honour `c:legendEntry` identically without any\n * per-kind or per-binding code.\n *\n * @module chart-legend-entries\n */\nimport type { PptxChartLegendEntry } from 'pptx-viewer-core';\n\nimport type { LegendEntry } from './chart-view-model';\n\n/**\n * Filter deleted entries and attach per-entry text-style overrides, falling\n * back to the chart-level legend default (`PptxChartStyle.legendTextStyle`,\n * itself `c:legend/c:txPr` or `c:chartSpace/c:txPr`) for any entry that has no\n * `c:legendEntry/c:txPr` override of its own. Returns the input array\n * unchanged (same reference) when there is nothing to apply, so a chart with\n * neither kind of override pays no extra cost.\n */\nexport function applyLegendEntryOverrides(\n\tlegend: readonly LegendEntry[],\n\tentries: readonly PptxChartLegendEntry[] | undefined,\n\tdefaultTextStyle?: LegendEntry['textStyle'],\n): LegendEntry[] {\n\tif ((!entries || entries.length === 0) && !defaultTextStyle) {\n\t\treturn legend as LegendEntry[];\n\t}\n\tconst byIndex = new Map((entries ?? []).map((entry) => [entry.index, entry]));\n\tconst result: LegendEntry[] = [];\n\tlegend.forEach((item, index) => {\n\t\tconst override = byIndex.get(index);\n\t\tif (override?.deleted) {\n\t\t\treturn;\n\t\t}\n\t\tconst textStyle = override?.textStyle ?? defaultTextStyle;\n\t\tresult.push(textStyle ? { ...item, textStyle } : item);\n\t});\n\treturn result;\n}\n","/**\n * chart-ofpie-split.ts: split-membership + layout geometry for the pie-of-pie /\n * bar-of-pie chart (`c:ofPieChart`).\n *\n * Split out of `chart-ofpie.ts` to keep each module within the repo's ~300-LOC\n * limit. Resolves which of a single series' points move to the SECONDARY plot\n * (`resolveSecondaryIndices`), the per-slice angular spans (`sliceAngles`), and\n * the primary/secondary plot placement (`computeOfPieGeom`).\n *\n * @module chart-ofpie-split\n */\nimport type { PptxChartOfPieOptions, PptxElement } from 'pptx-viewer-core';\n\n/** Angular span (radians) of a single pie slice, with its bisector. */\nexport interface SliceAngle {\n\tstart: number;\n\tend: number;\n\tmid: number;\n}\n\n/** Resolved plot placement for a pie-of-pie / bar-of-pie chart. */\nexport interface OfPieGeom {\n\tsvgWidth: number;\n\tsvgHeight: number;\n\tprimaryCx: number;\n\tprimaryCy: number;\n\tprimaryR: number;\n\tsecondaryCx: number;\n\tsecondaryCy: number;\n\tsecondaryR: number;\n}\n\n/**\n * Resolve which point indices belong to the secondary plot per `c:ofPieChart`\n * split rules: `pos` / `auto` (the last N points, default 2), `val` / `percent`\n * (points below a threshold), or `cust` (an explicit index list). Never returns\n * every point, so the primary pie always keeps at least one real slice.\n */\nexport function resolveSecondaryIndices(\n\tvalues: ReadonlyArray<number>,\n\toptions: PptxChartOfPieOptions,\n): Set<number> {\n\tconst n = values.length;\n\tconst result = new Set<number>();\n\tif (n <= 1) {\n\t\treturn result;\n\t}\n\tconst splitType = options.splitType ?? 'auto';\n\tif (splitType === 'cust') {\n\t\tfor (const idx of options.custSplit ?? []) {\n\t\t\tif (idx >= 0 && idx < n) {\n\t\t\t\tresult.add(idx);\n\t\t\t}\n\t\t}\n\t} else if (splitType === 'val') {\n\t\tconst threshold = options.splitPos ?? 0;\n\t\tvalues.forEach((v, i) => {\n\t\t\tif (v < threshold) {\n\t\t\t\tresult.add(i);\n\t\t\t}\n\t\t});\n\t} else if (splitType === 'percent') {\n\t\tconst total = values.reduce((s, v) => s + Math.abs(v), 0) || 1;\n\t\tconst threshold = options.splitPos ?? 0;\n\t\tvalues.forEach((v, i) => {\n\t\t\tif ((Math.abs(v) / total) * 100 < threshold) {\n\t\t\t\tresult.add(i);\n\t\t\t}\n\t\t});\n\t} else {\n\t\t// 'pos' and 'auto': the last N points (auto defaults to 2).\n\t\tconst count = Math.min(Math.max(Math.round(options.splitPos ?? 2), 1), n - 1);\n\t\tfor (let i = n - count; i < n; i++) {\n\t\t\tresult.add(i);\n\t\t}\n\t}\n\t// Never move every point to the secondary plot: keep at least one primary slice.\n\tif (result.size >= n) {\n\t\tresult.delete(0);\n\t}\n\treturn result;\n}\n\n/**\n * Cumulative clockwise slice angles for a set of values, starting at\n * `startAngle` (radians, SVG orientation: 0 = 3 o'clock, positive = down).\n */\nexport function sliceAngles(\n\tvalues: ReadonlyArray<number>,\n\tstartAngle = -Math.PI / 2,\n): SliceAngle[] {\n\tconst total = values.reduce((s, v) => s + Math.abs(v), 0) || 1;\n\tlet cursor = startAngle;\n\treturn values.map((v) => {\n\t\tconst span = (Math.abs(v) / total) * Math.PI * 2;\n\t\tconst start = cursor;\n\t\tcursor += span;\n\t\treturn { start, end: cursor, mid: (start + cursor) / 2 };\n\t});\n}\n\n/** Compute the primary + secondary plot placement for a chart element. */\nexport function computeOfPieGeom(\n\telement: PptxElement,\n\tsecondPieSize: number,\n\ttoBar = false,\n): OfPieGeom {\n\t// Match the element frame exactly; bindings stretch the viewBox with\n\t// preserveAspectRatio \"none\", so a minimum would scale non-uniformly.\n\tconst svgWidth = Math.max(element.width, 1);\n\tconst svgHeight = Math.max(element.height, 1);\n\t// COM-verified placement (charts-com.pptx slides 5 and 6): pie-of-pie puts\n\t// the primary pie at about a quarter of the width with a radius near 30% of\n\t// the height and the secondary pie at 78%; bar-of-pie gives the primary pie\n\t// far more room (38% across, radius 42% of the height) and a slim bar at 80%.\n\tconst primaryR = toBar\n\t\t? Math.max(Math.min(svgWidth * 0.24, svgHeight * 0.42), 4)\n\t\t: Math.max(Math.min(svgWidth * 0.2, svgHeight * 0.3), 4);\n\tconst secScale = Math.min(Math.max(secondPieSize / 100, 0.3), 1.4);\n\treturn {\n\t\tsvgWidth,\n\t\tsvgHeight,\n\t\tprimaryCx: svgWidth * (toBar ? 0.38 : 0.25),\n\t\tprimaryCy: svgHeight * 0.5,\n\t\tprimaryR,\n\t\tsecondaryCx: svgWidth * (toBar ? 0.8 : 0.78),\n\t\tsecondaryCy: svgHeight * 0.5,\n\t\tsecondaryR: Math.max(primaryR * secScale, 4),\n\t};\n}\n","/**\n * chart-ofpie-secondary.ts: secondary-plot + connector builders for the\n * pie-of-pie / bar-of-pie chart (`c:ofPieChart`).\n *\n * Split out of `chart-ofpie.ts` to keep each module within the repo's ~300-LOC\n * limit. Builds the expanded secondary plot (a smaller pie or a vertical stacked\n * bar) and the `c:serLines` connectors joining the primary \"Other\" slice to it.\n *\n * @module chart-ofpie-secondary\n */\nimport { DEFAULT_CHART_DATA_LABEL_PX } from './chart-font';\nimport type { OfPieGeom, SliceAngle } from './chart-ofpie-split';\nimport { sliceAngles } from './chart-ofpie-split';\nimport type { SvgLine, SvgPath, SvgRect, SvgText } from './chart-view-model';\nimport { computePieSlicePath, formatAxisValue } from './chart-view-model';\n\n/** A bold centred value label for a slice / bar segment. */\nexport function sliceLabel(x: number, y: number, value: number): SvgText {\n\treturn {\n\t\tkind: 'text',\n\t\tx,\n\t\ty,\n\t\ttext: formatAxisValue(value),\n\t\tfontSize: DEFAULT_CHART_DATA_LABEL_PX,\n\t\tfill: '#ffffff',\n\t\ttextAnchor: 'middle',\n\t\tfontWeight: 'bold',\n\t\tdominantBaseline: 'central',\n\t};\n}\n\n/**\n * Secondary pie plot: expands the aggregated \"Other\" slice into its points.\n * `startAngle` is where its first slice begins (PowerPoint starts it where the\n * primary \"Other\" slice ends; see `buildOfPieViewModel`).\n */\nexport function buildSecondaryPie(\n\tgeom: OfPieGeom,\n\tsecondaryValues: number[],\n\tfills: string[],\n\tshowLabels: boolean,\n\tstartAngle?: number,\n): { primitives: SvgPath[]; labels: SvgText[] } {\n\tconst angles = sliceAngles(secondaryValues, startAngle);\n\tconst primitives: SvgPath[] = [];\n\tconst labels: SvgText[] = [];\n\tangles.forEach((a, i) => {\n\t\tconst geoSlice = computePieSlicePath(\n\t\t\tgeom.secondaryCx,\n\t\t\tgeom.secondaryCy,\n\t\t\tgeom.secondaryR,\n\t\t\t0,\n\t\t\ta.start,\n\t\t\ta.end,\n\t\t);\n\t\tprimitives.push({\n\t\t\tkind: 'path',\n\t\t\td: geoSlice.d,\n\t\t\tfill: fills[i],\n\t\t\tstroke: '#ffffff',\n\t\t\tstrokeWidth: 1.5,\n\t\t});\n\t\tif (showLabels) {\n\t\t\tlabels.push(sliceLabel(geoSlice.labelX, geoSlice.labelY, secondaryValues[i]));\n\t\t}\n\t});\n\treturn { primitives, labels };\n}\n\n/** Secondary bar plot (bar-of-pie): a vertical stack of the secondary points. */\nexport function buildSecondaryBar(\n\tgeom: OfPieGeom,\n\tsecondaryValues: number[],\n\tfills: string[],\n\tshowLabels: boolean,\n): { primitives: SvgRect[]; labels: SvgText[] } {\n\tconst total = secondaryValues.reduce((s, v) => s + Math.abs(v), 0) || 1;\n\tconst { x: barX, y: barTop, w: barW, h: barH } = secondaryBarBox(geom);\n\tconst primitives: SvgRect[] = [];\n\tconst labels: SvgText[] = [];\n\tlet cursorY = barTop;\n\tsecondaryValues.forEach((v, i) => {\n\t\tconst h = Math.max((Math.abs(v) / total) * barH, 1);\n\t\tprimitives.push({ kind: 'rect', x: barX, y: cursorY, w: barW, h, fill: fills[i] });\n\t\tif (showLabels) {\n\t\t\tlabels.push(sliceLabel(geom.secondaryCx, cursorY + h / 2, v));\n\t\t}\n\t\tcursorY += h;\n\t});\n\treturn { primitives, labels };\n}\n\n/**\n * Two connector lines (c:serLines) from the rim ends of the \"Other\" slice to\n * the secondary plot: its top and bottom points for a pie, its left corners\n * for a bar. PowerPoint draws them solid, thin and grey (the built-in\n * `tx1` 35% line; COM-verified charts-com.pptx slides 5 and 6).\n */\nexport function buildSerLines(geom: OfPieGeom, otherAngle: SliceAngle, toBar: boolean): SvgLine[] {\n\tconst rim = (angle: number) => ({\n\t\tx: geom.primaryCx + geom.primaryR * Math.cos(angle),\n\t\ty: geom.primaryCy + geom.primaryR * Math.sin(angle),\n\t});\n\tconst upper = rim(otherAngle.start);\n\tconst lower = rim(otherAngle.end);\n\tconst bar = secondaryBarBox(geom);\n\tconst targetX = toBar ? bar.x : geom.secondaryCx;\n\tconst topY = toBar ? bar.y : geom.secondaryCy - geom.secondaryR;\n\tconst bottomY = toBar ? bar.y + bar.h : geom.secondaryCy + geom.secondaryR;\n\tconst line = (from: { x: number; y: number }, ty: number): SvgLine => ({\n\t\tkind: 'line',\n\t\tx1: from.x,\n\t\ty1: from.y,\n\t\tx2: targetX,\n\t\ty2: ty,\n\t\tstroke: '#A6A6A6',\n\t\tstrokeWidth: 1,\n\t});\n\treturn [line(upper, topY), line(lower, bottomY)];\n}\n\n/** The secondary bar's box (bar-of-pie), shared by the bar and its serLines. */\nexport function secondaryBarBox(geom: OfPieGeom): { x: number; y: number; w: number; h: number } {\n\tconst w = geom.secondaryR * 1.1;\n\tconst h = geom.secondaryR * 2;\n\treturn { x: geom.secondaryCx - w / 2, y: geom.secondaryCy - h / 2, w, h };\n}\n","/**\n * chart-ofpie.ts: framework-agnostic view-model builder for the OOXML\n * \"Pie of Pie\" / \"Bar of Pie\" chart (`c:ofPieChart`, CT_OfPieChart).\n *\n * A single data series is split into a PRIMARY pie plus a SECONDARY plot (a\n * smaller pie for `ofPieType === 'pie'`, or a vertical stacked bar for\n * `ofPieType === 'bar'`). The primary pie shows the points kept in the first\n * plot plus one aggregated \"Other\" slice standing in for every point moved to\n * the secondary plot; the secondary plot expands that \"Other\" slice into its\n * constituent points. `c:serLines` draws the two connector lines linking the\n * \"Other\" slice to the secondary plot.\n *\n * Split membership + layout live in `chart-ofpie-split`; the secondary plot and\n * connector geometry in `chart-ofpie-secondary`. Geometry reuses the shared pie\n * primitives so every binding renders identical `ofPie` output.\n *\n * @module chart-ofpie\n */\nimport type { PptxChartData, PptxElement } from 'pptx-viewer-core';\n\nimport { resolveChartTitleText } from './chart-auto-title';\nimport { resolveVaryColorFill } from './chart-datapoint-style';\nimport {\n\tbuildSecondaryBar,\n\tbuildSecondaryPie,\n\tbuildSerLines,\n\tsliceLabel,\n} from './chart-ofpie-secondary';\nimport type { OfPieGeom } from './chart-ofpie-split';\nimport { computeOfPieGeom, resolveSecondaryIndices, sliceAngles } from './chart-ofpie-split';\nimport type {\n\tChartViewModel,\n\tLegendEntry,\n\tSvgPath,\n\tSvgPrimitive,\n\tSvgText,\n} from './chart-view-model';\nimport { computePieSlicePath, paletteColor } from './chart-view-model';\n\n/** Build primary-pie slice paths + optional value labels. */\nfunction buildPrimarySlices(\n\tgeom: OfPieGeom,\n\tprimaryValues: number[],\n\tfills: string[],\n\tshowLabels: boolean,\n\tstartAngle: number,\n): { primitives: SvgPath[]; labels: SvgText[] } {\n\tconst angles = sliceAngles(primaryValues, startAngle);\n\tconst primitives: SvgPath[] = [];\n\tconst labels: SvgText[] = [];\n\tangles.forEach((a, i) => {\n\t\tconst geoSlice = computePieSlicePath(\n\t\t\tgeom.primaryCx,\n\t\t\tgeom.primaryCy,\n\t\t\tgeom.primaryR,\n\t\t\t0,\n\t\t\ta.start,\n\t\t\ta.end,\n\t\t);\n\t\tprimitives.push({\n\t\t\tkind: 'path',\n\t\t\td: geoSlice.d,\n\t\t\tfill: fills[i],\n\t\t\tstroke: '#ffffff',\n\t\t\tstrokeWidth: 1.5,\n\t\t\tpart: { role: 'dataPoint', seriesIndex: 0, pointIndex: i },\n\t\t});\n\t\tif (showLabels) {\n\t\t\tlabels.push(sliceLabel(geoSlice.labelX, geoSlice.labelY, primaryValues[i]));\n\t\t}\n\t});\n\treturn { primitives, labels };\n}\n\n/**\n * Build the full pie-of-pie / bar-of-pie view-model. Splits the first series\n * into a primary pie (kept points + one aggregated \"Other\" slice) and a\n * secondary pie/bar expanding the moved points, with serLines connectors.\n */\nexport function buildOfPieViewModel(\n\telement: PptxElement,\n\tchartData: PptxChartData,\n\tcategoryLabels: ReadonlyArray<string>,\n): ChartViewModel {\n\tconst options = chartData.ofPieOptions ?? { ofPieType: 'pie' };\n\tconst series = chartData.series[0];\n\tconst values = series?.values ?? [];\n\tconst palette = chartData.colorPalette;\n\tconst showLabels = chartData.style?.hasDataLabels === true;\n\n\tconst secondaryIdx = resolveSecondaryIndices(values, options);\n\tconst keptIndices = values.map((_v, i) => i).filter((i) => !secondaryIdx.has(i));\n\tconst secondaryIndices = values.map((_v, i) => i).filter((i) => secondaryIdx.has(i));\n\n\tconst geom = computeOfPieGeom(element, options.secondPieSize ?? 75, options.ofPieType === 'bar');\n\n\t// Colours: each point keeps its original palette colour. The aggregated\n\t// \"Other\" slice is the series' point AFTER the last real one: PowerPoint\n\t// styles it with the `c:dPt` whose idx equals the point count (accent1\n\t// lumMod 60% in every built-in style; COM-verified charts-com.pptx slides\n\t// 5-6), falling back to the next palette colour.\n\tconst pointFill = (i: number): string =>\n\t\tseries ? resolveVaryColorFill(series, i, paletteColor(i, palette)) : paletteColor(i, palette);\n\tconst keptFills = keptIndices.map(pointFill);\n\tconst secondaryFills = secondaryIndices.map(pointFill);\n\tconst otherFill = pointFill(values.length);\n\n\tconst otherSum = secondaryIndices.reduce((s, i) => s + Math.abs(values[i]), 0);\n\tconst primaryValues = [...keptIndices.map((i) => Math.abs(values[i])), otherSum];\n\tconst primaryFills = [...keptFills, otherFill];\n\n\t// Rotation: PowerPoint turns the primary pie so the \"Other\" slice is\n\t// centred on 3 o'clock, facing the secondary plot, and starts the\n\t// secondary pie where that slice ends (COM-verified charts-com.pptx\n\t// slide 5: kept slices from +28.4deg clockwise, Other centred on 0deg,\n\t// secondary slices from +28.4deg).\n\tconst primaryTotal = primaryValues.reduce((s, v) => s + v, 0) || 1;\n\tconst otherHalfSpan = (otherSum / primaryTotal) * Math.PI;\n\tconst primary = buildPrimarySlices(geom, primaryValues, primaryFills, showLabels, otherHalfSpan);\n\tconst secondaryValues = secondaryIndices.map((i) => Math.abs(values[i]));\n\tconst toBar = options.ofPieType === 'bar';\n\tconst secondary =\n\t\tsecondaryValues.length > 0\n\t\t\t? toBar\n\t\t\t\t? buildSecondaryBar(geom, secondaryValues, secondaryFills, showLabels)\n\t\t\t\t: buildSecondaryPie(geom, secondaryValues, secondaryFills, showLabels, otherHalfSpan)\n\t\t\t: { primitives: [], labels: [] };\n\n\tconst primitives: SvgPrimitive[] = [];\n\t// Connector lines behind the plots.\n\tif (options.serLines !== false && secondaryValues.length > 0) {\n\t\tconst primaryAngles = sliceAngles(primaryValues, otherHalfSpan);\n\t\tprimitives.push(...buildSerLines(geom, primaryAngles[primaryAngles.length - 1], toBar));\n\t}\n\tprimitives.push(...primary.primitives, ...secondary.primitives);\n\n\tconst dataLabels: SvgText[] = [...primary.labels, ...secondary.labels];\n\n\tconst legend: LegendEntry[] = categoryLabels.map((label, i) => ({\n\t\tcolor: paletteColor(i, palette),\n\t\tlabel,\n\t}));\n\tconst title = resolveChartTitleText(chartData);\n\n\treturn {\n\t\tsvgWidth: geom.svgWidth,\n\t\tsvgHeight: geom.svgHeight,\n\t\ttitle,\n\t\ttitleX: geom.svgWidth / 2,\n\t\ttitleY: 14,\n\t\tgridlines: [],\n\t\taxisLabels: [],\n\t\tzeroLine: undefined,\n\t\tcategoryLabels: [],\n\t\tprimitives,\n\t\tdataLabels,\n\t\tlegend: chartData.style?.hasLegend ? legend : [],\n\t\tlegendX: geom.svgWidth / 2,\n\t\tlegendY: geom.svgHeight - 8,\n\t\tlegendAnchor: 'middle',\n\t};\n}\n","/**\n * chart-view-model-chrome.ts: chart chrome (value-axis gridlines/labels, zero\n * line, category labels) shared by the cartesian chart kinds. Split out of\n * `chart-view-model-layout.ts` to keep that module's plot layout math under\n * the repo's 300-LOC file guideline; re-exported by `chart-view-model.ts`.\n * Legend building (`buildLegend`) lives in `chart-legend-build.ts`, not here.\n *\n * @module chart-view-model-chrome\n */\n/* eslint-disable one-var -- this module predates the rule and combining every\n sibling `const`/`let` in a function into one comma-list (oxlint's own\n `--fix` cannot do this safely once a non-declaration statement sits between\n them) would churn geometry code far beyond this change's scope. */\n\nimport { DEFAULT_CHART_TEXT_PX } from './chart-font';\nimport { formatAxisValue, valueToY } from './chart-view-model-scale';\nimport type { ValueRange } from './chart-view-model-scale';\nimport type { PlotLayout, SvgLine, SvgText } from './chart-view-model-types';\n\nexport const GRIDLINE_COLOR = '#e2e8f0';\nexport const AXIS_LABEL_COLOR = '#64748b';\nexport const ZERO_LINE_COLOR = '#94a3b8';\nconst TICK_COUNT = 5;\n\n/**\n * Tick values for a range: one per major unit when the automatic scale supplied\n * one (it snapped the bounds to whole multiples, so this lands on round numbers\n * exactly as PowerPoint does), otherwise an even division of the span.\n * Exported for the transposed (horizontal-bar) axis builder.\n */\nexport function axisTickValues(range: ValueRange): number[] {\n\tconst unit = range.majorUnit;\n\tif (unit !== undefined && Number.isFinite(unit) && unit > 0 && !range.logScale) {\n\t\tconst steps = Math.round((range.max - range.min) / unit);\n\t\tif (steps >= 1 && steps <= 100) {\n\t\t\treturn Array.from({ length: steps + 1 }, (_unused, index) => range.min + unit * index);\n\t\t}\n\t}\n\treturn Array.from(\n\t\t{ length: TICK_COUNT + 1 },\n\t\t(_unused, index) => range.min + (range.span / TICK_COUNT) * index,\n\t);\n}\n\nexport function buildGridlinesAndLabels(\n\trange: ValueRange,\n\tlayout: PlotLayout,\n\t/**\n\t * `false` keeps the tick labels but draws no gridlines: a value axis whose\n\t * `c:majorGridlines` is absent (see `shouldRenderMajorGridlines`).\n\t */\n\tshowMajorGridlines = true,\n): { gridlines: SvgLine[]; axisLabels: SvgText[] } {\n\tconst gridlines: SvgLine[] = [],\n\t\taxisLabels: SvgText[] = [];\n\n\tfor (const val of axisTickValues(range)) {\n\t\tconst y = valueToY(val, range, layout.plotTop, layout.plotBottom);\n\n\t\tif (showMajorGridlines) {\n\t\t\tgridlines.push({\n\t\t\t\tkind: 'line',\n\t\t\t\tx1: layout.plotLeft,\n\t\t\t\ty1: y,\n\t\t\t\tx2: layout.plotRight,\n\t\t\t\ty2: y,\n\t\t\t\tstroke: GRIDLINE_COLOR,\n\t\t\t\tstrokeWidth: 1,\n\t\t\t});\n\t\t}\n\n\t\taxisLabels.push({\n\t\t\tkind: 'text',\n\t\t\tx: layout.plotLeft - 4,\n\t\t\ty,\n\t\t\ttext: formatAxisValue(val),\n\t\t\tfontSize: DEFAULT_CHART_TEXT_PX,\n\t\t\tfill: AXIS_LABEL_COLOR,\n\t\t\ttextAnchor: 'end',\n\t\t\tdominantBaseline: 'central',\n\t\t});\n\t}\n\n\treturn { gridlines, axisLabels };\n}\n\nexport function buildZeroLine(range: ValueRange, layout: PlotLayout): SvgLine | undefined {\n\tif (range.min >= 0 || range.max <= 0) {\n\t\treturn undefined;\n\t}\n\tconst y = valueToY(0, range, layout.plotTop, layout.plotBottom);\n\treturn {\n\t\tkind: 'line',\n\t\tx1: layout.plotLeft,\n\t\ty1: y,\n\t\tx2: layout.plotRight,\n\t\ty2: y,\n\t\tstroke: ZERO_LINE_COLOR,\n\t\tstrokeWidth: 1,\n\t};\n}\n\nexport function buildCategoryLabels(\n\tcategoryLabels: ReadonlyArray<string>,\n\tlayout: PlotLayout,\n\tcatSpacing: 'bar' | 'line',\n): SvgText[] {\n\tconst catCount = Math.max(categoryLabels.length, 1);\n\treturn categoryLabels.map((label, i) => {\n\t\tconst x =\n\t\t\tcatSpacing === 'bar'\n\t\t\t\t? layout.plotLeft + (layout.plotWidth / catCount) * (i + 0.5)\n\t\t\t\t: catCount > 1\n\t\t\t\t\t? layout.plotLeft + (layout.plotWidth / (catCount - 1)) * i\n\t\t\t\t\t: layout.plotLeft + layout.plotWidth / 2;\n\t\treturn {\n\t\t\tkind: 'text',\n\t\t\tx,\n\t\t\ty: layout.plotBottom + 12,\n\t\t\ttext: label,\n\t\t\tfontSize: DEFAULT_CHART_TEXT_PX,\n\t\t\tfill: AXIS_LABEL_COLOR,\n\t\t\ttextAnchor: 'middle',\n\t\t} satisfies SvgText;\n\t});\n}\n","/**\n * Axis chrome for the surface chart kind: category/series edge labels for\n * both projections, plus the value (Z) axis the 3-D isometric one alone\n * draws. COM-verified against `charts-com.pptx` slides 7-10 (surface types\n * 83-86): every one of the four surface subtypes labels its category and\n * series axes, and the two 3-D ones additionally draw a left-side numeric\n * value axis; the two top-view (\"Contour\") ones draw no value axis at all,\n * since a top-view surface has no Z dimension to show a scale for.\n *\n * Split out of `chart-surface-flat.ts` / `chart-surface-isometric.ts` to keep\n * each view-model builder under the repo's ~300-LOC budget.\n *\n * @module chart-surface-axes\n */\nimport type { PptxChartSeries } from 'pptx-viewer-core';\n\nimport { DEFAULT_CHART_TEXT_PX } from './chart-font';\nimport { AXIS_LABEL_COLOR, buildGridlinesAndLabels } from './chart-view-model-chrome';\nimport type { ValueRange } from './chart-view-model-scale';\nimport type { PlotLayout, SvgLine, SvgText } from './chart-view-model-types';\n\n/** Category-axis (bottom) + series-axis (right) labels for the 2-D top-view grid. */\nexport function buildSurfaceTopViewAxisLabels(\n\tcategoryLabels: ReadonlyArray<string>,\n\tseries: ReadonlyArray<PptxChartSeries>,\n\tlayout: PlotLayout,\n): SvgText[] {\n\tconst catCount = Math.max(categoryLabels.length, 1);\n\tconst cellW = layout.plotWidth / catCount;\n\tconst labels: SvgText[] = categoryLabels.map((label, i) => ({\n\t\tkind: 'text',\n\t\tx: layout.plotLeft + cellW * (i + 0.5),\n\t\ty: layout.plotBottom + 14,\n\t\ttext: label,\n\t\tfontSize: DEFAULT_CHART_TEXT_PX,\n\t\tfill: AXIS_LABEL_COLOR,\n\t\ttextAnchor: 'middle',\n\t}));\n\n\tconst seriesCount = Math.max(series.length, 1);\n\tconst cellH = layout.plotHeight / seriesCount;\n\tseries.forEach((s, i) => {\n\t\tlabels.push({\n\t\t\tkind: 'text',\n\t\t\tx: layout.plotRight + 6,\n\t\t\ty: layout.plotTop + cellH * (i + 0.5),\n\t\t\ttext: s.name,\n\t\t\tfontSize: DEFAULT_CHART_TEXT_PX,\n\t\t\tfill: AXIS_LABEL_COLOR,\n\t\t\ttextAnchor: 'start',\n\t\t\tdominantBaseline: 'central',\n\t\t});\n\t});\n\treturn labels;\n}\n\n/** Project a grid point at the given cell/row and z=0 to offset screen space. */\ntype Project = (col: number, row: number) => { screenX: number; screenY: number };\n\n/**\n * Category/series edge labels for the isometric 3-D mesh, placed along the\n * two front-bottom receding edges the way PowerPoint draws them: category\n * labels trail the near-left edge (row = `rows`), series labels trail the\n * near-right edge (col = `cols`).\n */\nexport function buildSurfaceIsometricEdgeLabels(\n\tcategoryLabels: ReadonlyArray<string>,\n\tseries: ReadonlyArray<PptxChartSeries>,\n\tcols: number,\n\trows: number,\n\tproject: Project,\n): SvgText[] {\n\tconst labels: SvgText[] = [];\n\tconst catCount = Math.max(categoryLabels.length, 1);\n\tfor (let c = 0; c < catCount; c++) {\n\t\tconst label = categoryLabels[c];\n\t\tif (!label) {\n\t\t\tcontinue;\n\t\t}\n\t\tconst p = project(Math.min(c, cols), rows);\n\t\tlabels.push({\n\t\t\tkind: 'text',\n\t\t\tx: p.screenX,\n\t\t\ty: p.screenY + 14,\n\t\t\ttext: label,\n\t\t\tfontSize: DEFAULT_CHART_TEXT_PX,\n\t\t\tfill: AXIS_LABEL_COLOR,\n\t\t\ttextAnchor: 'middle',\n\t\t});\n\t}\n\n\tseries.forEach((s, i) => {\n\t\tconst p = project(cols, Math.min(i, rows));\n\t\tlabels.push({\n\t\t\tkind: 'text',\n\t\t\tx: p.screenX + 8,\n\t\t\ty: p.screenY + 6,\n\t\t\ttext: s.name,\n\t\t\tfontSize: DEFAULT_CHART_TEXT_PX,\n\t\t\tfill: AXIS_LABEL_COLOR,\n\t\t\ttextAnchor: 'start',\n\t\t});\n\t});\n\treturn labels;\n}\n\n/**\n * Left-side numeric value (Z) axis for the isometric 3-D surface, drawn as a\n * plain vertical ladder (not iso-skewed, matching PowerPoint's own static\n * left axis) spanning the plot's full height with one tick per\n * `range.majorUnit`. 3-D surface only; a top-view surface has no value axis.\n */\nexport function buildSurfaceValueAxis(\n\trange: ValueRange,\n\tlayout: PlotLayout,\n): { gridlines: SvgLine[]; axisLabels: SvgText[] } {\n\tconst { axisLabels } = buildGridlinesAndLabels(range, layout, false);\n\tconst gridlines: SvgLine[] = [\n\t\t{\n\t\t\tkind: 'line',\n\t\t\tx1: layout.plotLeft,\n\t\t\ty1: layout.plotTop,\n\t\t\tx2: layout.plotLeft,\n\t\t\ty2: layout.plotBottom,\n\t\t\tstroke: AXIS_LABEL_COLOR,\n\t\t\tstrokeWidth: 1,\n\t\t},\n\t];\n\treturn { gridlines, axisLabels };\n}\n","/**\n * Isometric projection primitive, `c:bandFmts` colour-band resolution, and\n * `c:floor` / `c:sideWall` / `c:backWall` backdrop panels for the surface\n * chart's isometric SVG renderer ({@link ./chart-surface-treemap.ts}).\n *\n * Split out of `chart-surface-treemap.ts` to keep that file's two view-model\n * builders (isometric + flat) readable; everything here is pure geometry/\n * colour resolution with no view-model assembly of its own.\n *\n * @module chart-surface-bands\n */\nimport type { PptxChart3DSurface, PptxChartBandFmt } from 'pptx-viewer-core';\n\nimport type { SvgPolygon } from './chart-view-model';\n\nexport const ISO_COS30 = Math.cos(Math.PI / 6);\nexport const ISO_SIN30 = Math.sin(Math.PI / 6);\n\n/** Project a 3-D (x, y, z) grid coordinate to 2-D isometric screen space. */\nexport function isoProject(x: number, y: number, z: number): { screenX: number; screenY: number } {\n\treturn {\n\t\tscreenX: (x - y) * ISO_COS30,\n\t\tscreenY: (x + y) * ISO_SIN30 - z,\n\t};\n}\n\n/**\n * Resolve a surface facet's fill from `c:bandFmts` (discrete colour bands)\n * when authored, falling back to `undefined` so the caller uses the\n * continuous colour ramp instead.\n *\n * PowerPoint assigns bands from the value axis's major-unit intervals; this\n * renderer has no axis-tick model for a surface chart, so `bandFmts` (sorted\n * by `index`) is treated as N equal-width bands across the normalised\n * `[0, 1]` value range, which reproduces the common case (bands evenly\n * spaced end to end) without needing the authored major-unit spacing.\n */\nexport function resolveSurfaceBandFill(\n\tt: number,\n\tbandFmts: ReadonlyArray<PptxChartBandFmt> | undefined,\n): string | undefined {\n\tif (!bandFmts || bandFmts.length === 0) {\n\t\treturn undefined;\n\t}\n\tconst sorted = [...bandFmts].sort((a, b) => a.index - b.index);\n\tconst bucket = Math.min(sorted.length - 1, Math.max(0, Math.floor(t * sorted.length)));\n\treturn sorted[bucket]?.spPr?.fillColor;\n}\n\nfunction wallPanel(\n\tcorners: ReadonlyArray<[number, number, number]>,\n\tsurface: PptxChart3DSurface | undefined,\n\toffsetX: number,\n\toffsetY: number,\n): SvgPolygon | undefined {\n\tconst fillColor = surface?.spPr?.fillColor;\n\tif (!fillColor) {\n\t\treturn undefined;\n\t}\n\tconst points = corners\n\t\t.map(([x, y, z]) => {\n\t\t\tconst p = isoProject(x, y, z);\n\t\t\treturn `${(p.screenX + offsetX).toFixed(2)},${(p.screenY + offsetY).toFixed(2)}`;\n\t\t})\n\t\t.join(' ');\n\treturn {\n\t\tkind: 'polygon',\n\t\tpoints,\n\t\tfill: fillColor,\n\t\tstroke: surface.spPr?.strokeColor ?? 'none',\n\t\tstrokeWidth: surface.spPr?.strokeWidth ?? 0,\n\t};\n}\n\n/** The three `c:chart`-level 3D surfaces the isometric renderer can paint. */\nexport interface SurfaceWallSources {\n\tfloor?: PptxChart3DSurface;\n\tsideWall?: PptxChart3DSurface;\n\tbackWall?: PptxChart3DSurface;\n}\n\n/**\n * Build the floor/back-wall/side-wall backdrop panels for the isometric\n * surface renderer, in back-to-front paint order (so the caller can prepend\n * them ahead of the mesh facets). Back wall and side wall meet at the far\n * (row=0, col=0) corner; the floor spans the whole footprint at z=0. Wall\n * height uses the fixed headroom (`zScale`) rather than the data height,\n * matching PowerPoint's static walls. Omits any panel whose surface has no\n * authored fill colour.\n */\nexport function buildSurfaceWallPanels(\n\tcols: number,\n\trows: number,\n\tcellSize: number,\n\tzScale: number,\n\toffsetX: number,\n\toffsetY: number,\n\tsurfaces: SurfaceWallSources,\n): SvgPolygon[] {\n\tconst backWall = wallPanel(\n\t\t[\n\t\t\t[0, 0, 0],\n\t\t\t[cols * cellSize, 0, 0],\n\t\t\t[cols * cellSize, 0, zScale],\n\t\t\t[0, 0, zScale],\n\t\t],\n\t\tsurfaces.backWall,\n\t\toffsetX,\n\t\toffsetY,\n\t);\n\tconst sideWall = wallPanel(\n\t\t[\n\t\t\t[0, 0, 0],\n\t\t\t[0, rows * cellSize, 0],\n\t\t\t[0, rows * cellSize, zScale],\n\t\t\t[0, 0, zScale],\n\t\t],\n\t\tsurfaces.sideWall,\n\t\toffsetX,\n\t\toffsetY,\n\t);\n\tconst floor = wallPanel(\n\t\t[\n\t\t\t[0, 0, 0],\n\t\t\t[cols * cellSize, 0, 0],\n\t\t\t[cols * cellSize, rows * cellSize, 0],\n\t\t\t[0, rows * cellSize, 0],\n\t\t],\n\t\tsurfaces.floor,\n\t\toffsetX,\n\t\toffsetY,\n\t);\n\treturn [backWall, sideWall, floor].filter((p): p is SvgPolygon => p !== undefined);\n}\n","/**\n * Value-band legend for the surface chart kind.\n *\n * PowerPoint never labels a surface chart's legend with series names: every\n * one of its four surface subtypes (3-D Surface, 3-D Surface (Wireframe),\n * Contour, Wireframe Contour) instead divides the value axis into major-unit\n * bands and shows one legend swatch per band (\"0-0.5\", \"0.5-1\", ...),\n * because the whole point of the colour ramp is to read a Z value off the\n * mesh's colour, not to identify which authored series a facet came from.\n * COM-verified against `charts-com.pptx` slides 7-10 (surface types 83-86):\n * a series-name legend never appears on any of the four.\n *\n * Split out of `chart-surface-bands.ts` (which owns the colour ramp and wall\n * panels) to keep each module focused and under the repo's ~300-LOC budget.\n *\n * @module chart-surface-legend\n */\nimport type { PptxChartBandFmt } from 'pptx-viewer-core';\n\nimport { resolveLegendAnchorPosition } from './chart-legend-build';\nimport { resolveSurfaceBandFill } from './chart-surface-bands';\nimport { surfaceColor } from './chart-surface-common';\nimport { axisTickValues } from './chart-view-model-chrome';\nimport { formatAxisValue } from './chart-view-model-scale';\nimport type { ValueRange } from './chart-view-model-scale';\nimport type { LegendEntry } from './chart-view-model-types';\n\n/** One value band: `[min, max)` of the data range, with the colour it paints. */\nexport interface SurfaceValueBand {\n\tmin: number;\n\tmax: number;\n\t/** Normalised midpoint in `[0, 1]`, used to sample the continuous colour ramp. */\n\tmidT: number;\n\tcolor: string;\n}\n\n/**\n * Divide `range` into the same major-unit bands its value axis would draw\n * ticks at (`axisTickValues`), so a legend built from these lines up exactly\n * with the colour a viewer would read off the mesh at each gridline. Falls\n * back to a single band spanning the whole range when the axis has no more\n * than one tick (a flat or single-point dataset).\n */\nexport function buildSurfaceValueBands(\n\trange: ValueRange,\n\tbandFmts: ReadonlyArray<PptxChartBandFmt> | undefined,\n): SurfaceValueBand[] {\n\tconst ticks = axisTickValues(range);\n\tconst boundaries = ticks.length >= 2 ? ticks : [range.min, range.max];\n\n\tconst bands: SurfaceValueBand[] = [];\n\tfor (let i = 0; i < boundaries.length - 1; i++) {\n\t\tconst min = boundaries[i],\n\t\t\tmax = boundaries[i + 1];\n\t\tconst midT = range.span > 0 ? ((min + max) / 2 - range.min) / range.span : 0.5;\n\t\tconst clampedT = Math.min(1, Math.max(0, midT));\n\t\tconst { r, g, b } = surfaceColor(clampedT);\n\t\tbands.push({\n\t\t\tmin,\n\t\t\tmax,\n\t\t\tmidT: clampedT,\n\t\t\tcolor: resolveSurfaceBandFill(clampedT, bandFmts) ?? `rgb(${r},${g},${b})`,\n\t\t});\n\t}\n\treturn bands;\n}\n\n/**\n * Build the surface chart's value-band legend entries + anchor position,\n * mirroring `buildLegend`'s return shape so callers swap one for the other\n * without touching their view-model assembly.\n */\nexport function buildSurfaceLegend(\n\tbands: ReadonlyArray<SurfaceValueBand>,\n\tsvgWidth: number,\n\tlegendPos: string,\n\tsvgHeight: number,\n\tplotTop: number,\n): {\n\tlegend: LegendEntry[];\n\tlegendX: number;\n\tlegendY: number;\n\tlegendAnchor: 'start' | 'middle' | 'end';\n} {\n\tconst legend: LegendEntry[] = bands.map((band) => ({\n\t\tcolor: band.color,\n\t\tlabel: `${formatAxisValue(band.min)}-${formatAxisValue(band.max)}`,\n\t}));\n\tconst { legendX, legendY, legendAnchor } = resolveLegendAnchorPosition(\n\t\tsvgWidth,\n\t\tsvgHeight,\n\t\tplotTop,\n\t\tlegendPos,\n\t);\n\treturn { legend, legendX, legendY, legendAnchor };\n}\n\n/** Look up the band a normalised `t` in `[0, 1]` falls into, for mesh/grid fills. */\nexport function surfaceBandColorAt(bands: ReadonlyArray<SurfaceValueBand>, t: number): string {\n\tif (bands.length === 0) {\n\t\tconst { r, g, b } = surfaceColor(t);\n\t\treturn `rgb(${r},${g},${b})`;\n\t}\n\tconst clamped = Math.min(1, Math.max(0, t));\n\tconst bucket = Math.min(bands.length - 1, Math.floor(clamped * bands.length));\n\treturn bands[bucket].color;\n}\n","/**\n * Isometric-projection view-model builder for the surface chart kind\n * (`c:surface3DChart`, PowerPoint's \"3-D Surface\" / \"3-D Surface\n * (Wireframe)\" types).\n *\n * Split out of `chart-surface-treemap.ts` (which re-exports the dispatcher\n * that calls this) to keep that file's several chart-kind builders each\n * under the repo's per-file line budget.\n *\n * COM-verified against `charts-com.pptx` slides 7-8 (surface types 83/84):\n * PowerPoint draws a static left-side numeric value axis, category labels\n * trailing the near-left receding edge, series labels trailing the\n * near-right one, and a value-band legend (never a per-series one). A\n * wireframe surface omits every facet's fill, drawing mesh edges only.\n *\n * Ported from:\n * packages/react/src/viewer/utils/chart-surface-treemap.tsx (renderIsometricSurfaceFallback)\n *\n * @module chart-surface-isometric\n */\n\nimport type { PptxChartData, PptxElement } from 'pptx-viewer-core';\n\nimport { resolveChartTitleText } from './chart-auto-title';\nimport { buildSurfaceIsometricEdgeLabels, buildSurfaceValueAxis } from './chart-surface-axes';\nimport { buildSurfaceWallPanels, ISO_COS30, ISO_SIN30, isoProject } from './chart-surface-bands';\nimport { emptyChrome } from './chart-surface-common';\nimport {\n\tbuildSurfaceLegend,\n\tbuildSurfaceValueBands,\n\tsurfaceBandColorAt,\n} from './chart-surface-legend';\nimport type { ChartValueDrag, ChartViewModel, SvgPolygon } from './chart-view-model';\nimport { buildMarkTooltip, computePlotLayout, computeValueRange } from './chart-view-model';\n\n/**\n * Build the view-model for a surface chart's isometric 3-D-like projection.\n *\n * Mirrors `renderIsometricSurfaceFallback` in React's `chart-surface-treemap.tsx`.\n */\nexport function buildIsometricSurfaceViewModel(\n\telement: PptxElement,\n\tchartData: PptxChartData,\n\tcategoryLabels: ReadonlyArray<string>,\n): ChartViewModel {\n\tconst layout = computePlotLayout(element.width, element.height, chartData, false);\n\tconst range = computeValueRange(chartData.series, layout.autoPlotHeight);\n\tconst bands = buildSurfaceValueBands(range, chartData.bandFmts);\n\tconst catCount = Math.max(categoryLabels.length, 1);\n\tconst seriesCount = chartData.series.length;\n\t// See `chart-surface-flat.ts`'s `isWireframe` for why absent defaults to filled.\n\tconst isWireframe = chartData.wireframe === true;\n\n\t// Grid cell count (vertices = cells + 1 in each dimension).\n\tconst cols = Math.max(catCount - 1, 1);\n\tconst rows = Math.max(seriesCount - 1, 1);\n\n\tconst gridSpan = cols + rows;\n\tconst cellByWidth = (layout.plotWidth * 0.9) / (gridSpan * ISO_COS30);\n\tconst cellByHeight = (layout.plotHeight * 0.65) / (gridSpan * ISO_SIN30);\n\tconst cellSize = Math.max(Math.min(cellByWidth, cellByHeight), 0.5);\n\n\tconst zHeadroom = layout.plotHeight * 0.3;\n\tconst zScale = range.span > 0 ? zHeadroom : 0;\n\n\tconst normValue = (r: number, c: number): number => {\n\t\tconst ri = Math.min(r, seriesCount - 1);\n\t\tconst ci = Math.min(c, catCount - 1);\n\t\tconst val = chartData.series[ri]?.values[ci] ?? 0;\n\t\treturn range.span > 0 ? (val - range.min) / range.span : 0;\n\t};\n\n\t// Compute isometric bounding box to centre the projection.\n\tconst projectedPoints: Array<{ screenX: number; screenY: number }> = [];\n\tfor (let r = 0; r <= rows; r++) {\n\t\tfor (let c = 0; c <= cols; c++) {\n\t\t\tprojectedPoints.push(isoProject(c * cellSize, r * cellSize, normValue(r, c) * zScale));\n\t\t}\n\t}\n\n\tconst minSX = Math.min(...projectedPoints.map((p) => p.screenX));\n\tconst maxSX = Math.max(...projectedPoints.map((p) => p.screenX));\n\tconst minSY = Math.min(...projectedPoints.map((p) => p.screenY));\n\tconst maxSY = Math.max(...projectedPoints.map((p) => p.screenY));\n\tconst projW = maxSX - minSX;\n\tconst projH = maxSY - minSY;\n\n\t// Reserve a left-hand column for the value axis so the mesh does not draw\n\t// over its own tick labels; only the 3-D projection has one (a top-view\n\t// surface has no Z axis at all, see `chart-surface-flat.ts`).\n\tconst axisReserve = 34;\n\tconst meshLeft = layout.plotLeft + axisReserve;\n\tconst meshWidth = layout.plotWidth - axisReserve;\n\n\tconst offsetX = meshLeft + meshWidth / 2 - (minSX + projW / 2);\n\tconst offsetY = layout.plotTop + layout.plotHeight / 2 - (minSY + projH / 2);\n\tconst project = (col: number, row: number): { screenX: number; screenY: number } => {\n\t\tconst p = isoProject(col * cellSize, row * cellSize, 0);\n\t\treturn { screenX: p.screenX + offsetX, screenY: p.screenY + offsetY };\n\t};\n\n\t// Cells sorted back-to-front (painter's algorithm: lower row+col = farther).\n\ttype CellEntry = { row: number; col: number; depth: number };\n\tconst cells: CellEntry[] = [];\n\tfor (let r = 0; r < rows; r++) {\n\t\tfor (let c = 0; c < cols; c++) {\n\t\t\tcells.push({ row: r, col: c, depth: r + c });\n\t\t}\n\t}\n\tcells.sort((a, b) => a.depth - b.depth);\n\n\tconst primitives: SvgPolygon[] = [];\n\n\t// Floor/wall backdrop panels, painted first so the mesh draws over them.\n\t// A wireframe surface has no backdrop at all, matching PowerPoint.\n\tif (!isWireframe) {\n\t\tprimitives.push(\n\t\t\t...buildSurfaceWallPanels(cols, rows, cellSize, zScale, offsetX, offsetY, {\n\t\t\t\tfloor: chartData.floor,\n\t\t\t\tsideWall: chartData.sideWall,\n\t\t\t\tbackWall: chartData.backWall,\n\t\t\t}),\n\t\t);\n\t}\n\n\tfor (const { row, col } of cells) {\n\t\t// Four corners of the isometric parallelogram.\n\t\tconst corners: Array<[number, number]> = [\n\t\t\t[col, row],\n\t\t\t[col + 1, row],\n\t\t\t[col + 1, row + 1],\n\t\t\t[col, row + 1],\n\t\t];\n\t\tconst verts = corners.map(([c, r]) => {\n\t\t\tconst nv = normValue(r, c);\n\t\t\treturn isoProject(c * cellSize, r * cellSize, nv * zScale);\n\t\t});\n\n\t\tconst avgT =\n\t\t\t(normValue(row, col) +\n\t\t\t\tnormValue(row, col + 1) +\n\t\t\t\tnormValue(row + 1, col + 1) +\n\t\t\t\tnormValue(row + 1, col)) /\n\t\t\t4;\n\n\t\tconst color = surfaceBandColorAt(bands, avgT);\n\t\tconst points = verts\n\t\t\t.map((v) => `${(v.screenX + offsetX).toFixed(2)},${(v.screenY + offsetY).toFixed(2)}`)\n\t\t\t.join(' ');\n\n\t\t// Face fill polygon, tagged with the grid vertex it is ANCHORED at (its\n\t\t// top-left corner). A mesh facet spans four data points, so there is no\n\t\t// one value it \"is\"; the anchor is the only unambiguous mapping, and\n\t\t// without it a surface chart is the one kind whose marks cannot be\n\t\t// selected on canvas at all. The final row/column of vertices anchors no\n\t\t// facet and therefore carries no mark, which is the honest consequence of\n\t\t// a mesh having one fewer cell than vertices per axis. The hover tooltip\n\t\t// (matching every other chart kind's `buildMarkTooltip`) reports that same\n\t\t// anchor value, so hover and click select the exact same data point.\n\t\tprimitives.push({\n\t\t\tkind: 'polygon',\n\t\t\tpoints,\n\t\t\tfill: isWireframe ? 'none' : color,\n\t\t\tstroke: isWireframe ? color : 'none',\n\t\t\tstrokeWidth: isWireframe ? 1 : 0,\n\t\t\topacity: isWireframe ? 1 : 0.9,\n\t\t\tpart: { role: 'dataPoint', seriesIndex: row, pointIndex: col },\n\t\t\ttitle: buildMarkTooltip(\n\t\t\t\tchartData.series[row]?.name,\n\t\t\t\tcategoryLabels[col],\n\t\t\t\tchartData.series[row]?.values[col] ?? 0,\n\t\t\t\tchartData.series[row]?.numberFormat,\n\t\t\t),\n\t\t} satisfies SvgPolygon);\n\n\t\t// Subtle edge overlay for depth perception. A wireframe surface already\n\t\t// drew its only outline above (an unfilled facet), so it skips this.\n\t\tif (!isWireframe) {\n\t\t\tprimitives.push({\n\t\t\t\tkind: 'polygon',\n\t\t\t\tpoints,\n\t\t\t\tfill: 'none',\n\t\t\t\tstroke: color,\n\t\t\t\tstrokeWidth: 0.5,\n\t\t\t\topacity: 0.7,\n\t\t\t} satisfies SvgPolygon);\n\t\t}\n\t}\n\n\tconst legendPos = chartData.style?.legendPosition ?? 'b';\n\tconst { legend, legendX, legendY, legendAnchor } = buildSurfaceLegend(\n\t\tbands,\n\t\tlayout.svgWidth,\n\t\tlegendPos,\n\t\tlayout.svgHeight,\n\t\tlayout.plotTop,\n\t);\n\n\tconst title = resolveChartTitleText(chartData);\n\tconst { gridlines: axisGridlines, axisLabels } = buildSurfaceValueAxis(range, layout);\n\tconst edgeLabels = buildSurfaceIsometricEdgeLabels(\n\t\tcategoryLabels,\n\t\tchartData.series,\n\t\tcols,\n\t\trows,\n\t\tproject,\n\t);\n\n\t// Each cell is anchored at one (series, category) data point (see the\n\t// primitive-building loop above), so it drags vertically to a new value the\n\t// SAME way a line/bar mark does, through the shared `ChartValueDrag` path\n\t// (`chart-canvas-drag.ts`). The mesh does not visually reposition mid-drag\n\t// (its Y comes from the whole grid's shape, not one cell), but the pointer\n\t// delta -> value mapping still reads naturally: up increases, down decreases.\n\tconst valueDrag: ChartValueDrag = {\n\t\trange,\n\t\tplotTop: layout.plotTop,\n\t\tplotBottom: layout.plotBottom,\n\t};\n\n\treturn {\n\t\tsvgWidth: layout.svgWidth,\n\t\tsvgHeight: layout.svgHeight,\n\t\ttitle,\n\t\ttitleX: layout.svgWidth / 2,\n\t\ttitleY: 14,\n\t\t...emptyChrome(),\n\t\tgridlines: axisGridlines,\n\t\taxisLabels,\n\t\tcategoryLabels: edgeLabels,\n\t\tprimitives,\n\t\tlegend: chartData.style?.hasLegend ? legend : [],\n\t\tlegendX,\n\t\tlegendY,\n\t\tlegendAnchor,\n\t\tvalueDrag,\n\t};\n}\n","/**\n * 2-D top-view grid builder for the surface chart kind (`c:surfaceChart`,\n * PowerPoint's \"Contour\" / \"Wireframe Contour\" types), plus the\n * `buildSurfaceViewModel` dispatcher between it and the isometric 3-D\n * builder (`c:surface3DChart`).\n *\n * Split out of `chart-surface-treemap.ts` (which re-exports\n * `buildSurfaceViewModel`) to keep that file's several chart-kind builders\n * each under the repo's per-file line budget.\n *\n * COM-verified against `charts-com.pptx` slides 9-10 (surface types 85/86,\n * \"Contour\" and \"Wireframe Contour\"): PowerPoint draws these as a flat,\n * head-on grid of value bands (category axis along the bottom, series axis\n * along the right, no Z axis), never as an isometric projection; a filled\n * band paints the whole cell, a wireframe one draws its outline only.\n *\n * Ported from:\n * packages/react/src/viewer/utils/chart-surface-treemap.tsx (renderSurfaceChart)\n *\n * @module chart-surface-flat\n */\n\nimport type { PptxChartData, PptxElement } from 'pptx-viewer-core';\n\nimport { resolveChartTitleText } from './chart-auto-title';\nimport { buildSurfaceTopViewAxisLabels } from './chart-surface-axes';\nimport { buildIsometricSurfaceViewModel } from './chart-surface-isometric';\nimport {\n\tbuildSurfaceLegend,\n\tbuildSurfaceValueBands,\n\tsurfaceBandColorAt,\n} from './chart-surface-legend';\nimport type { ChartValueDrag, ChartViewModel, SvgPolygon } from './chart-view-model';\nimport { buildMarkTooltip, computePlotLayout, computeValueRange } from './chart-view-model';\n\nfunction buildFlatSurfaceViewModel(\n\telement: PptxElement,\n\tchartData: PptxChartData,\n\tcategoryLabels: ReadonlyArray<string>,\n): ChartViewModel {\n\tconst layout = computePlotLayout(element.width, element.height, chartData, false);\n\tconst range = computeValueRange(chartData.series, layout.autoPlotHeight);\n\tconst bands = buildSurfaceValueBands(range, chartData.bandFmts);\n\tconst catCount = Math.max(categoryLabels.length, 1);\n\tconst seriesCount = chartData.series.length;\n\tconst cellW = layout.plotWidth / catCount;\n\tconst cellH = layout.plotHeight / Math.max(seriesCount, 1);\n\t// A wireframe (Excel/PowerPoint \"Wireframe Contour\") surface draws band\n\t// outlines only, never a filled cell. Every surface chart PowerPoint itself\n\t// authors writes `c:wireframe` explicitly (val=\"0\" or \"1\"; COM-verified\n\t// against `charts-com.pptx` slides 7-10), so the absent-element case only\n\t// arises from hand-written XML; this treats it as the filled default, since\n\t// \"surface chart\" names a coloured surface and an unfilled default would\n\t// make the common case look broken.\n\tconst isWireframe = chartData.wireframe === true;\n\n\tconst primitives: SvgPolygon[] = [];\n\n\tfor (let si = 0; si < seriesCount; si++) {\n\t\tfor (let ci = 0; ci < catCount; ci++) {\n\t\t\tconst val = chartData.series[si]?.values[ci] ?? 0;\n\t\t\tconst t = range.span > 0 ? (val - range.min) / range.span : 0;\n\t\t\tconst color = surfaceBandColorAt(bands, t);\n\t\t\tconst x = layout.plotLeft + ci * cellW,\n\t\t\t\ty = layout.plotTop + si * cellH;\n\t\t\tconst points = [\n\t\t\t\t`${x.toFixed(2)},${y.toFixed(2)}`,\n\t\t\t\t`${(x + cellW).toFixed(2)},${y.toFixed(2)}`,\n\t\t\t\t`${(x + cellW).toFixed(2)},${(y + cellH).toFixed(2)}`,\n\t\t\t\t`${x.toFixed(2)},${(y + cellH).toFixed(2)}`,\n\t\t\t].join(' ');\n\t\t\tprimitives.push({\n\t\t\t\tkind: 'polygon',\n\t\t\t\tpoints,\n\t\t\t\tfill: isWireframe ? 'none' : color,\n\t\t\t\tstroke: isWireframe ? color : 'none',\n\t\t\t\tstrokeWidth: isWireframe ? 1 : 0,\n\t\t\t\topacity: isWireframe ? 1 : 0.9,\n\t\t\t\tpart: { role: 'dataPoint', seriesIndex: si, pointIndex: ci },\n\t\t\t\ttitle: buildMarkTooltip(\n\t\t\t\t\tchartData.series[si]?.name,\n\t\t\t\t\tcategoryLabels[ci],\n\t\t\t\t\tval,\n\t\t\t\t\tchartData.series[si]?.numberFormat,\n\t\t\t\t),\n\t\t\t} satisfies SvgPolygon);\n\t\t}\n\t}\n\n\tconst legendPos = chartData.style?.legendPosition ?? 'b';\n\tconst { legend, legendX, legendY, legendAnchor } = buildSurfaceLegend(\n\t\tbands,\n\t\tlayout.svgWidth,\n\t\tlegendPos,\n\t\tlayout.svgHeight,\n\t\tlayout.plotTop,\n\t);\n\n\tconst title = resolveChartTitleText(chartData);\n\tconst categoryAndSeriesLabels = buildSurfaceTopViewAxisLabels(\n\t\tcategoryLabels,\n\t\tchartData.series,\n\t\tlayout,\n\t);\n\n\t// One cell per (series, category) already carries an unambiguous single\n\t// value, so the same vertical drag-to-value path a line/bar mark uses\n\t// applies directly.\n\tconst valueDrag: ChartValueDrag = {\n\t\trange,\n\t\tplotTop: layout.plotTop,\n\t\tplotBottom: layout.plotBottom,\n\t};\n\n\treturn {\n\t\tsvgWidth: layout.svgWidth,\n\t\tsvgHeight: layout.svgHeight,\n\t\ttitle,\n\t\ttitleX: layout.svgWidth / 2,\n\t\ttitleY: 14,\n\t\tgridlines: [],\n\t\taxisLabels: [],\n\t\tzeroLine: undefined,\n\t\tcategoryLabels: categoryAndSeriesLabels,\n\t\tdataLabels: [],\n\t\tprimitives,\n\t\tlegend: chartData.style?.hasLegend ? legend : [],\n\t\tlegendX,\n\t\tlegendY,\n\t\tlegendAnchor,\n\t\tvalueDrag,\n\t};\n}\n\n/**\n * Build the view-model for a surface chart.\n *\n * Renders the flat, head-on 2-D grid PowerPoint draws for its \"Contour\" /\n * \"Wireframe Contour\" top-view types (`chartData.surfaceTopView`), and the\n * isometric 3-D-like projection for its \"3-D Surface\" / \"3-D Surface\n * (Wireframe)\" types otherwise. Mirrors `renderSurfaceChart` /\n * `renderIsometricSurfaceFallback` in React's `chart-surface-treemap.tsx`.\n */\nexport function buildSurfaceViewModel(\n\telement: PptxElement,\n\tchartData: PptxChartData,\n\tcategoryLabels: ReadonlyArray<string>,\n): ChartViewModel {\n\tif (chartData.surfaceTopView) {\n\t\treturn buildFlatSurfaceViewModel(element, chartData, categoryLabels);\n\t}\n\treturn buildIsometricSurfaceViewModel(element, chartData, categoryLabels);\n}\n","/**\n * Squarified treemap layout algorithm, generic over any weighted node.\n * Split out of `chart-treemap-hierarchy.ts` (which supplies the node/box\n * shapes and drives the recursive render) to keep each file under the\n * repo's ~300-LOC budget.\n *\n * @module chart-treemap-squarify\n */\n\nexport interface TreemapBox {\n\tx: number;\n\ty: number;\n\tw: number;\n\th: number;\n}\n\ninterface WeightedNode {\n\tweight: number;\n}\n\n/** Worst (largest) aspect-ratio deviation from square a row of `areas` would have at `side` thickness. */\nfunction worstAspectRatio(areas: readonly number[], side: number): number {\n\tconst sum = areas.reduce((total, area) => total + area, 0);\n\tconst max = Math.max(...areas);\n\tconst min = Math.min(...areas);\n\tconst sideSq = side * side;\n\tconst sumSq = sum * sum;\n\treturn Math.max((sideSq * max) / sumSq, sumSq / (sideSq * min));\n}\n\n/**\n * Squarified treemap layout (Bruls, Huizing & van Wijk): repeatedly lays out\n * the widest possible \"row\" of items along the box's shorter side, adding\n * items to the row only while doing so keeps improving (or not worsening)\n * that row's worst aspect ratio, so cells stay close to square instead of\n * degenerating into thin slivers the way a plain alternating slice-and-dice\n * split does. COM-verified against charts-com.pptx slide 28 (chartEx3.xml):\n * PowerPoint's own treemap mixes row and column splits within the SAME\n * parent region (e.g. a tall cell beside a further row/column split), which\n * a single alternating dimension split can never reproduce.\n */\nexport function squarify<TNode extends WeightedNode>(\n\tnodes: readonly TNode[],\n\tbox: TreemapBox,\n): Array<[TNode, TreemapBox]> {\n\tconst sorted = [...nodes].sort((a, b) => b.weight - a.weight);\n\tconst total = sorted.reduce((sum, node) => sum + node.weight, 0);\n\t// Equal-area fallback when every node is weightless (matches the previous\n\t// slice-and-dice behaviour for this degenerate case).\n\tconst scale = total > 0 ? (box.w * box.h) / total : (box.w * box.h) / sorted.length;\n\tconst items = sorted.map((node) => ({ node, area: (total > 0 ? node.weight : 1) * scale }));\n\n\tconst result: Array<[TNode, TreemapBox]> = [];\n\tlet rect = { ...box };\n\tlet remaining = items;\n\n\twhile (remaining.length > 0) {\n\t\tconst side = Math.min(rect.w, rect.h);\n\t\tlet row = [remaining[0]];\n\t\tlet rowAreas = [remaining[0].area];\n\t\tlet worst = worstAspectRatio(rowAreas, side);\n\t\tlet cursor = 1;\n\t\twhile (cursor < remaining.length) {\n\t\t\tconst candidateAreas = [...rowAreas, remaining[cursor].area];\n\t\t\tconst candidateWorst = worstAspectRatio(candidateAreas, side);\n\t\t\tif (candidateWorst > worst) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\trow = [...row, remaining[cursor]];\n\t\t\trowAreas = candidateAreas;\n\t\t\tworst = candidateWorst;\n\t\t\tcursor++;\n\t\t}\n\n\t\tconst rowTotalArea = rowAreas.reduce((sum, area) => sum + area, 0);\n\t\tconst thickness = side > 0 ? rowTotalArea / side : 0;\n\t\tconst layoutVertically = rect.w >= rect.h;\n\t\tlet offset = layoutVertically ? rect.y : rect.x;\n\t\tfor (const item of row) {\n\t\t\tconst length = thickness > 0 ? item.area / thickness : 0;\n\t\t\tif (layoutVertically) {\n\t\t\t\tresult.push([item.node, { x: rect.x, y: offset, w: thickness, h: length }]);\n\t\t\t} else {\n\t\t\t\tresult.push([item.node, { x: offset, y: rect.y, w: length, h: thickness }]);\n\t\t\t}\n\t\t\toffset += length;\n\t\t}\n\n\t\trect = layoutVertically\n\t\t\t? { ...rect, x: rect.x + thickness, w: rect.w - thickness }\n\t\t\t: { ...rect, y: rect.y + thickness, h: rect.h - thickness };\n\t\tremaining = remaining.slice(row.length);\n\t}\n\treturn result;\n}\n","import type { PptxChartData, PptxChartParentLabelLayout, PptxChartSeries } from 'pptx-viewer-core';\n\nimport { dataLabelFontOverride, resolveDataLabelTextStyle } from './chart-data-label-text';\nimport type { TreemapBox } from './chart-treemap-squarify';\nimport { squarify } from './chart-treemap-squarify';\nimport type { SvgRect, SvgText } from './chart-view-model';\nimport { paletteColor } from './chart-view-model';\n\ninterface TreemapNode {\n\tlabel: string;\n\tweight: number;\n\tchildren?: TreemapNode[];\n\tseriesIndex?: number;\n\tpointIndex?: number;\n\tcolorIndex: number;\n\tparentLabelLayout: PptxChartParentLabelLayout;\n}\n\nexport type TreemapPrimitive = SvgRect | SvgText;\n\nfunction normalizedLevels(\n\tlevels: ReadonlyArray<ReadonlyArray<string>>,\n\tpointCount: number,\n): string[][] {\n\treturn levels.map((level) => {\n\t\tlet previous = '';\n\t\treturn Array.from({ length: pointCount }, (_, index) => {\n\t\t\tconst label = level[index]?.trim() ?? '';\n\t\t\tif (label) {\n\t\t\t\tprevious = label;\n\t\t\t}\n\t\t\treturn label || previous;\n\t\t});\n\t});\n}\n\nfunction findOrAddParent(\n\tchildren: TreemapNode[],\n\tlabel: string,\n\tcolorIndex: number,\n\tparentLabelLayout: PptxChartParentLabelLayout,\n): TreemapNode {\n\tconst existing = children.find((child) => child.children && child.label === label);\n\tif (existing) {\n\t\treturn existing;\n\t}\n\tconst parent: TreemapNode = {\n\t\tlabel,\n\t\tweight: 0,\n\t\tchildren: [],\n\t\tcolorIndex,\n\t\tparentLabelLayout,\n\t};\n\tchildren.push(parent);\n\treturn parent;\n}\n\nfunction buildSeriesHierarchy(\n\tseries: PptxChartSeries,\n\tseriesIndex: number,\n\tcategoryLabels: ReadonlyArray<string>,\n\tcategoryLevels: ReadonlyArray<ReadonlyArray<string>> | undefined,\n\tcolorStride: number,\n): TreemapNode[] {\n\tconst pointCount = series.values.length;\n\tconst levels = normalizedLevels(categoryLevels ?? [], pointCount);\n\tconst layout = series.treemapOptions?.parentLabelLayout ?? 'banner';\n\tconst roots: TreemapNode[] = [];\n\tfor (let pointIndex = 0; pointIndex < pointCount; pointIndex++) {\n\t\tlet children = roots;\n\t\tfor (let levelIndex = levels.length - 1; levelIndex >= 1; levelIndex--) {\n\t\t\tconst label = levels[levelIndex][pointIndex] || `Group ${levelIndex}`;\n\t\t\tchildren = findOrAddParent(children, label, pointIndex, layout).children!;\n\t\t}\n\t\tchildren.push({\n\t\t\tlabel: levels[0]?.[pointIndex] || categoryLabels[pointIndex] || String(pointIndex + 1),\n\t\t\tweight: Math.abs(series.values[pointIndex] ?? 0),\n\t\t\tseriesIndex,\n\t\t\tpointIndex,\n\t\t\tcolorIndex: seriesIndex * colorStride + pointIndex,\n\t\t\tparentLabelLayout: layout,\n\t\t});\n\t}\n\treturn roots;\n}\n\nfunction aggregate(node: TreemapNode): number {\n\tif (node.children) {\n\t\tnode.weight = node.children.reduce((sum, child) => sum + aggregate(child), 0);\n\t}\n\treturn node.weight;\n}\n\n/** Propagate a single colour index from a top-level branch down to every one of its leaves. */\nfunction propagateColor(node: TreemapNode, colorIndex: number): void {\n\tnode.colorIndex = colorIndex;\n\tif (node.children) {\n\t\tfor (const child of node.children) {\n\t\t\tpropagateColor(child, colorIndex);\n\t\t}\n\t}\n}\n\nfunction renderNodes(\n\tnodes: TreemapNode[],\n\tbox: TreemapBox,\n\tchartData: PptxChartData,\n\tprimitives: TreemapPrimitive[],\n): void {\n\tconst colorPalette = chartData.colorPalette;\n\tfor (const [node, allocation] of squarify(nodes, box)) {\n\t\tconst cell = {\n\t\t\tx: allocation.x + 1,\n\t\t\ty: allocation.y + 1,\n\t\t\tw: Math.max(allocation.w - 2, 1),\n\t\t\th: Math.max(allocation.h - 2, 1),\n\t\t};\n\t\tif (node.children) {\n\t\t\tconst showParent = node.parentLabelLayout !== 'none' && cell.w > 28 && cell.h > 16;\n\t\t\tif (showParent) {\n\t\t\t\tprimitives.push({\n\t\t\t\t\tkind: 'text',\n\t\t\t\t\tx: cell.x + 4,\n\t\t\t\t\ty: cell.y + 11,\n\t\t\t\t\ttext: node.label,\n\t\t\t\t\tfontSize: 10,\n\t\t\t\t\tfill: '#303030',\n\t\t\t\t\ttextAnchor: 'start',\n\t\t\t\t\tfontWeight: 'bold',\n\t\t\t\t});\n\t\t\t}\n\t\t\tconst bannerHeight = showParent && node.parentLabelLayout === 'banner' ? 16 : 0;\n\t\t\trenderNodes(\n\t\t\t\tnode.children,\n\t\t\t\t{ ...cell, y: cell.y + bannerHeight, h: Math.max(cell.h - bannerHeight, 1) },\n\t\t\t\tchartData,\n\t\t\t\tprimitives,\n\t\t\t);\n\t\t\tcontinue;\n\t\t}\n\t\tprimitives.push({\n\t\t\tkind: 'rect',\n\t\t\t...cell,\n\t\t\tfill: paletteColor(node.colorIndex, colorPalette),\n\t\t\trx: 2,\n\t\t\topacity: 0.85,\n\t\t\tpart: {\n\t\t\t\trole: 'dataPoint',\n\t\t\t\tseriesIndex: node.seriesIndex!,\n\t\t\t\tpointIndex: node.pointIndex!,\n\t\t\t},\n\t\t});\n\t\tif (cell.w > 30 && cell.h > 14) {\n\t\t\tconst leafSeries = chartData.series[node.seriesIndex!];\n\t\t\tprimitives.push({\n\t\t\t\tkind: 'text',\n\t\t\t\tx: cell.x + cell.w / 2,\n\t\t\t\ty: cell.y + cell.h / 2,\n\t\t\t\ttext: node.label,\n\t\t\t\tfontSize: Math.min(10, cell.h * 0.3),\n\t\t\t\tfill: '#ffffff',\n\t\t\t\ttextAnchor: 'middle',\n\t\t\t\tfontWeight: 'bold',\n\t\t\t\tdominantBaseline: 'central',\n\t\t\t\t...(leafSeries\n\t\t\t\t\t? dataLabelFontOverride(\n\t\t\t\t\t\t\tresolveDataLabelTextStyle(chartData, leafSeries, node.pointIndex!),\n\t\t\t\t\t\t)\n\t\t\t\t\t: {}),\n\t\t\t});\n\t\t}\n\t}\n}\n\n/**\n * The top-level branch labels a treemap's legend should show, in the same\n * order `buildHierarchicalTreemapPrimitives` assigns colour indexes to its\n * roots: one label per authored `c:ser`/`cx:series` when there is more than\n * one, else one per unique top ChartEx category level, else (a flat,\n * non-hierarchical treemap) one per leaf category. A legend built from\n * anything else would show swatches that do not match what a leaf's fill\n * colour actually is.\n */\nexport function treemapBranchLabels(\n\tchartData: PptxChartData,\n\tcategoryLabels: ReadonlyArray<string>,\n): string[] {\n\tif (chartData.series.length > 1) {\n\t\treturn chartData.series.map((series) => series.name);\n\t}\n\tconst levels = chartData.categoryLevels;\n\tif (levels && levels.length > 1) {\n\t\tconst pointCount = chartData.series[0]?.values.length ?? categoryLabels.length;\n\t\tconst topLevel = normalizedLevels(levels, pointCount).at(-1) ?? [];\n\t\tconst seen: string[] = [];\n\t\tfor (const label of topLevel) {\n\t\t\tif (!seen.includes(label)) {\n\t\t\t\tseen.push(label);\n\t\t\t}\n\t\t}\n\t\treturn seen;\n\t}\n\treturn [...categoryLabels];\n}\n\n/** Build nested treemap rectangles from ChartEx leaf-first category levels. */\nexport function buildHierarchicalTreemapPrimitives(\n\tchartData: PptxChartData,\n\tcategoryLabels: ReadonlyArray<string>,\n\tbox: TreemapBox,\n): TreemapPrimitive[] {\n\t// Only used to keep each node's initial colorIndex distinct while the tree\n\t// is being built; propagateColor (below) overwrites every one of them with\n\t// its top-level branch's colour before rendering, so this stride never\n\t// actually reaches the renderer.\n\tconst colorStride = Math.max(\n\t\tcategoryLabels.length,\n\t\t...chartData.series.map((s) => s.values.length),\n\t\t1,\n\t);\n\tlet roots = chartData.series.flatMap((series, seriesIndex) =>\n\t\tbuildSeriesHierarchy(\n\t\t\tseries,\n\t\t\tseriesIndex,\n\t\t\tcategoryLabels,\n\t\t\tchartData.categoryLevels,\n\t\t\tcolorStride,\n\t\t),\n\t);\n\tif (chartData.series.length > 1) {\n\t\troots = chartData.series.map((series, seriesIndex) => ({\n\t\t\tlabel: series.name,\n\t\t\tweight: 0,\n\t\t\tchildren: buildSeriesHierarchy(\n\t\t\t\tseries,\n\t\t\t\tseriesIndex,\n\t\t\t\tcategoryLabels,\n\t\t\t\tchartData.categoryLevels,\n\t\t\t\tcolorStride,\n\t\t\t),\n\t\t\tcolorIndex: seriesIndex * colorStride,\n\t\t\tparentLabelLayout: series.treemapOptions?.parentLabelLayout ?? 'banner',\n\t\t}));\n\t}\n\tfor (const root of roots) {\n\t\taggregate(root);\n\t}\n\t// One colour per TOP-LEVEL branch, propagated to every one of its leaves\n\t// (COM-verified against charts-com.pptx slide 28 / chartEx3.xml: every\n\t// leaf under \"Branch 1\" paints the same colour as \"Branch 1\"'s legend\n\t// swatch). A flat, non-hierarchical treemap has one leaf per root, so\n\t// this is equivalent to the previous per-category colour there.\n\troots.forEach((root, index) => propagateColor(root, index));\n\tconst primitives: TreemapPrimitive[] = [];\n\trenderNodes(roots, box, chartData, primitives);\n\treturn primitives;\n}\n","/**\n * View-model builder for the treemap chart kind.\n *\n * Split out of `chart-surface-treemap.ts` (which re-exports this) to keep\n * that file's several chart-kind builders each under the repo's per-file\n * line budget.\n *\n * Ported from:\n * packages/react/src/viewer/utils/chart-surface-treemap.tsx (renderTreemapChart)\n *\n * @module chart-treemap-view\n */\n\nimport type { PptxChartData, PptxElement } from 'pptx-viewer-core';\n\nimport { resolveChartTitleText } from './chart-auto-title';\nimport { emptyChrome } from './chart-surface-common';\nimport { buildHierarchicalTreemapPrimitives, treemapBranchLabels } from './chart-treemap-hierarchy';\nimport type { ChartViewModel, LegendEntry } from './chart-view-model';\nimport { buildLegend, computePlotLayout, paletteColor } from './chart-view-model';\n\n/**\n * Build the view-model for a treemap chart.\n *\n * Uses a slice-and-dice layout (alternate horizontal/vertical splits) with\n * items sorted largest-first. Inline labels are added when the cell is wide\n * enough. Mirrors `renderTreemapChart` in React's `chart-surface-treemap.tsx`.\n */\nexport function buildTreemapViewModel(\n\telement: PptxElement,\n\tchartData: PptxChartData,\n\tcategoryLabels: ReadonlyArray<string>,\n): ChartViewModel {\n\tconst layout = computePlotLayout(element.width, element.height, chartData, false);\n\tconst primitives = buildHierarchicalTreemapPrimitives(chartData, categoryLabels, {\n\t\tx: layout.plotLeft,\n\t\ty: layout.plotTop,\n\t\tw: layout.plotWidth,\n\t\th: layout.plotHeight,\n\t});\n\n\t// Legend: one entry per series (matching React: no per-item legend).\n\tconst legendPos = chartData.style?.legendPosition ?? 'b';\n\tconst { legend, legendX, legendY, legendAnchor } = buildLegend(\n\t\tchartData.series,\n\t\tchartData.colorPalette,\n\t\tlayout.svgWidth,\n\t\tlegendPos,\n\t\tlayout.svgHeight,\n\t\tlayout.plotTop,\n\t);\n\n\t// One legend entry per TOP-LEVEL branch, matching the one colour every leaf\n\t// under that branch is painted with (COM-verified: charts-com.pptx slide\n\t// 28 legend reads \"Branch 1/2/3\", never one swatch per leaf).\n\tconst branchLabels = treemapBranchLabels(chartData, categoryLabels);\n\tconst catLegend: LegendEntry[] = branchLabels.map((label, i) => ({\n\t\tcolor: paletteColor(i, chartData.colorPalette),\n\t\tlabel,\n\t}));\n\n\tconst title = resolveChartTitleText(chartData);\n\n\treturn {\n\t\tsvgWidth: layout.svgWidth,\n\t\tsvgHeight: layout.svgHeight,\n\t\ttitle,\n\t\ttitleX: layout.svgWidth / 2,\n\t\ttitleY: 14,\n\t\t...emptyChrome(),\n\t\tprimitives,\n\t\t// Prefer per-category legend over per-series legend for treemap.\n\t\tlegend: chartData.style?.hasLegend ? (catLegend.length > 0 ? catLegend : legend) : [],\n\t\tlegendX,\n\t\tlegendY,\n\t\tlegendAnchor,\n\t};\n}\n","/**\n * Chart drawing-overlay projector (`c:userShapes`).\n *\n * Projects the parsed {@link PptxChartUserShape} model (resolved by core from\n * the chart's separate `ppt/drawings/drawingN.xml` part) into `SvgPrimitive`\n * descriptors positioned on top of the chart plot. Anchor geometry is\n * chart-relative: `relSizeAnchor` corners are fractions of the chart area,\n * `absSizeAnchor` extents are EMU converted to pixels. Rendered last so the\n * overlay sits above the data marks.\n *\n * A `grpSp` entry (grouped annotation shapes with their own nested\n * transform) is expanded into positioned leaves via core's\n * `flattenChartUserShapes` before projecting, so this module never has to\n * know about groups itself.\n *\n * @module chart-user-shape-overlay\n */\n\nimport type { PptxChartData } from 'pptx-viewer-core';\nimport { flattenChartUserShapes } from 'pptx-viewer-core';\n\nimport { DEFAULT_CHART_TEXT_PX, chartFontPx } from './chart-font';\nimport type { SvgLine, SvgPolygon, SvgPrimitive, SvgText } from './chart-view-model';\n\n/** The raw, un-flattened overlay model as parsed/edited (may contain `grpSp` entries). */\ntype RawUserShape = NonNullable<PptxChartData['userShapes']>[number];\n\n/** A leaf overlay shape (never `grpSp`), after `flattenChartUserShapes` applies any group transform. */\ntype UserShape = ReturnType<typeof flattenChartUserShapes>[number];\n\n/** EMU per CSS pixel at 96 DPI, mirroring core's `EMU_PER_PIXEL`. */\nconst EMU_PER_PIXEL = 9525;\n\n/**\n * Build an SVG `transform` for a leaf's own composed rotation/flip (already\n * resolved by core's `flattenChartUserShapes`: a group's rotation composed\n * onto each contained leaf, added; flip, XORed), about the leaf's OWN box\n * centre. Mirrors {@link https://ecma-international.org/ ECMA-376}'s \"flip,\n * then rotate, both about own centre\" order (see\n * `element-style-transform.ts`'s `getElementTransform` doc for the same\n * convention applied as CSS elsewhere in this codebase): the flip\n * (`translate` + `scale` + `translate` back) is placed AFTER `rotate` in the\n * string so it applies FIRST (SVG, like CSS, applies a transform list\n * right-to-left to a point). `undefined` when neither rotation nor flip is\n * set, so an ordinary unrotated shape's markup is unchanged.\n */\nfunction overlayTransform(\n\trotation: number | undefined,\n\tflipH: boolean | undefined,\n\tflipV: boolean | undefined,\n\tbox: { x: number; y: number; w: number; h: number },\n): string | undefined {\n\tif (!rotation && !flipH && !flipV) {\n\t\treturn undefined;\n\t}\n\tconst cx = box.x + box.w / 2;\n\tconst cy = box.y + box.h / 2;\n\tconst parts: string[] = [];\n\tif (rotation) {\n\t\tparts.push(`rotate(${rotation} ${cx} ${cy})`);\n\t}\n\tif (flipH || flipV) {\n\t\tconst sx = flipH ? -1 : 1;\n\t\tconst sy = flipV ? -1 : 1;\n\t\tparts.push(`translate(${cx} ${cy}) scale(${sx} ${sy}) translate(${-cx} ${-cy})`);\n\t}\n\treturn parts.join(' ');\n}\n\n/** Resolve the pixel bounding box of an anchored overlay shape. */\nfunction shapeBox(\n\tshape: UserShape,\n\tsvgWidth: number,\n\tsvgHeight: number,\n): { x: number; y: number; w: number; h: number } {\n\tconst x = shape.from.x * svgWidth;\n\tconst y = shape.from.y * svgHeight;\n\tif (shape.anchor === 'rel' && shape.to) {\n\t\treturn {\n\t\t\tx,\n\t\t\ty,\n\t\t\tw: Math.max((shape.to.x - shape.from.x) * svgWidth, 0),\n\t\t\th: Math.max((shape.to.y - shape.from.y) * svgHeight, 0),\n\t\t};\n\t}\n\tconst ext = shape.ext ?? { cx: 0, cy: 0 };\n\t// `buildChartUserShapeOverlay` always passes a `chartBox` to\n\t// `flattenChartUserShapes`, so a group-nested leaf's offset is already\n\t// folded into `from` and this is normally undefined; it is only set as a\n\t// fallback for some other, chartBox-less caller of `flattenChartUserShapes`\n\t// (see `absGroupOffsetEmu`'s doc), in which case it is an extra EMU\n\t// position delta applied here in the same absolute-EMU-to-pixel unit\n\t// `ext` already uses, not as a further fraction of `from`.\n\tconst offset = shape.absGroupOffsetEmu;\n\treturn {\n\t\tx: x + (offset ? offset.x / EMU_PER_PIXEL : 0),\n\t\ty: y + (offset ? offset.y / EMU_PER_PIXEL : 0),\n\t\tw: ext.cx / EMU_PER_PIXEL,\n\t\th: ext.cy / EMU_PER_PIXEL,\n\t};\n}\n\n/**\n * Build the text primitives for a shape's paragraphs, stacked vertically.\n * `rotation` (the shape's own composed spin, degrees) is applied to each\n * line about the SHAPE's own box centre so the text rotates as one rigid\n * unit with its box; flip is deliberately NOT applied to text (mirroring it\n * would render backwards), matching how an ordinary rotated/flipped slide\n * shape keeps its text upright via `element-style-transform.ts`'s\n * `getTextCompensationTransform`.\n */\nfunction textPrimitives(\n\tshape: UserShape,\n\tbox: { x: number; y: number; w: number; h: number },\n\trotation: number | undefined,\n): SvgText[] {\n\tif (!shape.paragraphs || shape.paragraphs.length === 0) {\n\t\treturn [];\n\t}\n\t// para.fontSize is parsed in POINTS (core's chart-user-shapes-parser); it\n\t// crosses the pt -> px boundary here (see chart-font.ts).\n\tconst fontPxOf = (para: NonNullable<UserShape['paragraphs']>[number]): number =>\n\t\tpara.fontSize !== undefined ? chartFontPx(para.fontSize) : DEFAULT_CHART_TEXT_PX;\n\tconst lineH = Math.max(12, ...shape.paragraphs.map((para) => fontPxOf(para) * 1.2));\n\tconst totalH = shape.paragraphs.length * lineH;\n\tlet cursorY = box.y + Math.max((box.h - totalH) / 2, 0) + lineH * 0.75;\n\tconst cx = box.x + box.w / 2;\n\tconst cy = box.y + box.h / 2;\n\tconst out: SvgText[] = [];\n\tfor (const para of shape.paragraphs) {\n\t\tif (para.text.length === 0) {\n\t\t\tcursorY += lineH;\n\t\t\tcontinue;\n\t\t}\n\t\tconst align = para.align ?? 'ctr';\n\t\tconst anchor: SvgText['textAnchor'] =\n\t\t\talign === 'l' ? 'start' : align === 'r' ? 'end' : 'middle';\n\t\tconst tx = align === 'l' ? box.x + 2 : align === 'r' ? box.x + box.w - 2 : box.x + box.w / 2;\n\t\tout.push({\n\t\t\tkind: 'text',\n\t\t\tx: tx,\n\t\t\ty: cursorY,\n\t\t\ttext: para.text,\n\t\t\tfontSize: fontPxOf(para),\n\t\t\tfill: para.color ?? '#1e293b',\n\t\t\ttextAnchor: anchor,\n\t\t\tfontWeight: para.bold ? 'bold' : 'normal',\n\t\t\t...(rotation ? { transform: `rotate(${rotation} ${cx} ${cy})` } : {}),\n\t\t});\n\t\tcursorY += lineH;\n\t}\n\treturn out;\n}\n\n/** Project a single overlay shape into its SVG primitives. */\nfunction projectShape(shape: UserShape, svgWidth: number, svgHeight: number): SvgPrimitive[] {\n\tconst box = shapeBox(shape, svgWidth, svgHeight);\n\tconst transform = overlayTransform(shape.rotation, shape.flipH, shape.flipV, box);\n\tconst primitives: SvgPrimitive[] = [];\n\n\tif (shape.kind === 'cxnSp') {\n\t\t// A connector spans the anchor diagonal.\n\t\tprimitives.push({\n\t\t\tkind: 'line',\n\t\t\tx1: box.x,\n\t\t\ty1: box.y,\n\t\t\tx2: box.x + box.w,\n\t\t\ty2: box.y + box.h,\n\t\t\tstroke: shape.stroke ?? '#000000',\n\t\t\tstrokeWidth: shape.strokeWidth ?? 1,\n\t\t\t...(transform ? { transform } : {}),\n\t\t} satisfies SvgLine);\n\t\treturn primitives;\n\t}\n\n\t// sp / pic: draw the shape box (a polygon carries both fill and stroke)\n\t// when it has a fill or a stroke. `SvgRect` has no stroke, so a polygon is\n\t// used to preserve the shape outline.\n\tif ((shape.fill || shape.stroke) && box.w > 0 && box.h > 0) {\n\t\tprimitives.push({\n\t\t\tkind: 'polygon',\n\t\t\tpoints: `${box.x},${box.y} ${box.x + box.w},${box.y} ${box.x + box.w},${box.y + box.h} ${box.x},${box.y + box.h}`,\n\t\t\tfill: shape.fill ?? 'none',\n\t\t\tstroke: shape.stroke ?? 'none',\n\t\t\tstrokeWidth: shape.strokeWidth ?? (shape.stroke ? 1 : 0),\n\t\t\t...(transform ? { transform } : {}),\n\t\t} satisfies SvgPolygon);\n\t}\n\n\tprimitives.push(...textPrimitives(shape, box, shape.rotation));\n\treturn primitives;\n}\n\n/**\n * Build overlay primitives for all of a chart's user shapes.\n *\n * @param userShapes - Parsed overlay shapes from `chartData.userShapes`.\n * @param svgWidth - View-model SVG width (chart area width in px).\n * @param svgHeight - View-model SVG height (chart area height in px).\n * @returns Overlay primitives, or an empty array when there are none.\n */\nexport function buildChartUserShapeOverlay(\n\tuserShapes: ReadonlyArray<RawUserShape> | undefined,\n\tsvgWidth: number,\n\tsvgHeight: number,\n): SvgPrimitive[] {\n\tif (!userShapes || userShapes.length === 0) {\n\t\treturn [];\n\t}\n\t// The chart's own rendered box, in EMU (matching the unit `ext` already\n\t// uses): lets core resolve a top-level `relSizeAnchor` group's real\n\t// (possibly non-square) rotation aspect and fold a grouped `absSizeAnchor`\n\t// leaf's offset straight into `from`, instead of approximating both (see\n\t// `ChartUserShapesChartBox`'s doc in `chart-user-shapes-parser.ts`).\n\tconst leaves = flattenChartUserShapes(userShapes, {\n\t\twidth: svgWidth * EMU_PER_PIXEL,\n\t\theight: svgHeight * EMU_PER_PIXEL,\n\t});\n\treturn leaves.flatMap((shape) => projectShape(shape, svgWidth, svgHeight));\n}\n","/**\n * chart-view-model-kinds.ts: the supported chart kinds, their preserveAspectRatio\n * and the chart-type to kind resolver. Split out of `chart-view-model.ts`,\n * which re-exports everything here.\n *\n * @module chart-view-model-kinds\n */\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Supported chart kinds\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport type SupportedChartKind =\n\t| 'bar'\n\t| 'line'\n\t| 'area'\n\t| 'pie'\n\t| 'doughnut'\n\t| 'scatter'\n\t| 'bubble'\n\t| 'radar'\n\t| 'combo'\n\t| 'stock'\n\t| 'surface'\n\t| 'treemap'\n\t| 'waterfall'\n\t| 'regionMap'\n\t| 'funnel'\n\t| 'sunburst'\n\t| 'histogram'\n\t| 'boxWhisker';\n\n/**\n * The `preserveAspectRatio` a chart kind's `<svg>` must carry.\n *\n * Cartesian charts stretch to fill the element box (`none`); the kinds whose\n * geometry is round or laid out on a fixed-ratio canvas (pie, doughnut, radar,\n * and the region map's 1000x500 world outline) keep their proportions instead.\n *\n * A pure decision function because all five bindings need the same answer and\n * four of them had written their own copy of the `kind === 'pie' || ...` chain;\n * one of the copies (React's) disagreed with the rest.\n */\nexport function chartPreserveAspectRatio(\n\tkind: SupportedChartKind | 'unsupported',\n): 'none' | 'xMidYMid meet' {\n\treturn kind === 'pie' || kind === 'doughnut' || kind === 'radar' || kind === 'regionMap'\n\t\t? 'xMidYMid meet'\n\t\t: 'none';\n}\n\nexport function resolveChartKind(chartType: string): SupportedChartKind | 'unsupported' {\n\tswitch (chartType) {\n\t\tcase 'bar':\n\t\tcase 'bar3D':\n\t\t\treturn 'bar';\n\t\tcase 'line':\n\t\tcase 'line3D':\n\t\t\treturn 'line';\n\t\tcase 'area':\n\t\tcase 'area3D':\n\t\t\treturn 'area';\n\t\tcase 'pie':\n\t\tcase 'pie3D':\n\t\tcase 'ofPie':\n\t\t\treturn 'pie';\n\t\tcase 'doughnut':\n\t\t\treturn 'doughnut';\n\t\tcase 'scatter':\n\t\t\treturn 'scatter';\n\t\tcase 'bubble':\n\t\t\treturn 'bubble';\n\t\tcase 'radar':\n\t\tcase 'radar3D':\n\t\t\treturn 'radar';\n\t\tcase 'combo':\n\t\t\treturn 'combo';\n\t\tcase 'stock':\n\t\t\treturn 'stock';\n\t\tcase 'surface':\n\t\tcase 'surface3D':\n\t\t\treturn 'surface';\n\t\tcase 'treemap':\n\t\t\treturn 'treemap';\n\t\tcase 'waterfall':\n\t\t\treturn 'waterfall';\n\t\tcase 'regionMap':\n\t\t\treturn 'regionMap';\n\t\tcase 'funnel':\n\t\t\treturn 'funnel';\n\t\tcase 'sunburst':\n\t\t\treturn 'sunburst';\n\t\tcase 'histogram':\n\t\t\treturn 'histogram';\n\t\tcase 'boxWhisker':\n\t\t\treturn 'boxWhisker';\n\t\tdefault:\n\t\t\treturn 'unsupported';\n\t}\n}\n","/**\n * chart-view-model-manual.ts: the `c:manualLayout` post-pass for the chart\n * title and legend.\n *\n * The plot area's manual layout is honoured where the plot rect is computed\n * (`computePlotLayout`, `computePieLayout`), which every kind's builder goes\n * through. Title and legend anchors, however, are stamped by each builder\n * (cartesian, combo, pie, radar, surface, ...) from its own defaults, so the\n * manual placement is applied once here, after the builder has produced its\n * automatic anchor: that automatic anchor is what a `factor`-mode offset is\n * relative to.\n *\n * @module chart-view-model-manual\n */\n\nimport type { PptxChartData } from 'pptx-viewer-core';\n\nimport {\n\tchartFrameToViewOffset,\n\tmanualLayoutOf,\n\tmanualLegendAnchor,\n\tmanualTitleAnchor,\n} from './chart-manual-layout';\nimport type { ChartFrameSize } from './chart-manual-layout';\nimport type { ChartViewModel } from './chart-view-model-types';\n\n/**\n * Re-anchor a finished view-model's title and legend from\n * `chartData.layouts`. Returns the view-model unchanged when the chart\n * declares no manual title / legend layout, or the region is not shown.\n *\n * @param frame - The chart element's box; manual layouts are fractions of it.\n */\nexport function withManualLayouts(\n\tvm: ChartViewModel,\n\tchartData: Pick<PptxChartData, 'layouts'>,\n\tframe: ChartFrameSize,\n): ChartViewModel {\n\tconst titleLayout = manualLayoutOf(chartData, 'title'),\n\t\tlegendLayout = manualLayoutOf(chartData, 'legend');\n\tif (!titleLayout && !legendLayout) {\n\t\treturn vm;\n\t}\n\t// Manual layouts are measured on the element; a letterboxed (pie) view-model\n\t// lives in a centred square, so translate the automatic anchor out to the\n\t// element, resolve, and translate the result back in.\n\tconst offset = chartFrameToViewOffset(frame, vm);\n\tlet next = vm;\n\n\tif (titleLayout && vm.title !== undefined) {\n\t\tconst anchor = manualTitleAnchor(titleLayout, frame, vm.title, {\n\t\t\tx: vm.titleX + offset.x,\n\t\t\ty: vm.titleY + offset.y,\n\t\t});\n\t\tif (anchor) {\n\t\t\tnext = { ...next, titleX: anchor.x - offset.x, titleY: anchor.y - offset.y };\n\t\t}\n\t}\n\n\tif (legendLayout && vm.legend.length > 0) {\n\t\tconst anchor = manualLegendAnchor(\n\t\t\tlegendLayout,\n\t\t\tframe,\n\t\t\tvm.legend.length,\n\t\t\tvm.legendAnchor === 'start',\n\t\t\t{ x: vm.legendX + offset.x, y: vm.legendY + offset.y },\n\t\t);\n\t\tif (anchor) {\n\t\t\tnext = { ...next, legendX: anchor.x - offset.x, legendY: anchor.y - offset.y };\n\t\t}\n\t}\n\n\treturn next;\n}\n","/**\n * Where PowerPoint puts a pie data label at `c:dLblPos val=\"bestFit\"`.\n *\n * COM ground truth (`chart-pie-best-fit.pptx`: eight pies of different slice\n * sizes, boxed 12pt labels, measured from `Slide.Export` pixels at two pie\n * sizes, R = 89.6pt and 190.3pt):\n *\n * - A label that fits inside its slice sits INSIDE it, on the slice's\n * mid-angle, pushed out until the box corner farthest from the centre is\n * 4pt inside the rim. The 4pt is the same for both pie sizes, so it is a\n * fixed inset, not a fraction of the radius. (The renderer used to put\n * every such label at 0.7 of the radius, well short of PowerPoint's.)\n * - \"Fits\" means that box, so placed, stays inside the slice's two edges:\n * PowerPoint tolerates about 1.5pt of overhang (a 10% slice with a\n * two-line label is on the boundary: one of three stays inside).\n * - A label that does not fit goes OUTSIDE, on the mid-angle, with the box\n * side facing the pie 2pt beyond the rim. PowerPoint then nudges outside\n * labels apart when they collide and draws leader lines to the nudged\n * ones; that pass is `chart-pie-label-collision` (an approximation).\n *\n * All lengths are in the chart's px space (1pt = 4/3px).\n *\n * @module chart-pie-best-fit\n */\n\n/** px per pt. */\nconst PX_PER_PT = 4 / 3;\n/** COM: the farthest box corner of an inside label sits this far inside the rim. */\nexport const BEST_FIT_RIM_INSET = 4 * PX_PER_PT;\n/** COM: how far a box may overhang a slice edge and still count as inside. */\nexport const BEST_FIT_EDGE_TOLERANCE = 1.5 * PX_PER_PT;\n/** COM: the gap between the rim and an outside label's box. */\nexport const BEST_FIT_OUTSIDE_GAP = 2 * PX_PER_PT;\n\n/** A slice as the placement needs it: centre, radius and its two edge angles. */\nexport interface BestFitSlice {\n\tcx: number;\n\tcy: number;\n\touterR: number;\n\t/** Radians, SVG convention (0 = 3 o'clock, clockwise positive). */\n\tstartAngle: number;\n\tendAngle: number;\n}\n\n/** Where the label box's centre goes, and whether that is inside the slice. */\nexport interface BestFitPlacement {\n\tx: number;\n\ty: number;\n\tinside: boolean;\n}\n\n/** Farthest distance from the origin of a `w x h` box centred at (`x`, `y`). */\nfunction farCorner(x: number, y: number, w: number, h: number): number {\n\treturn Math.hypot(Math.abs(x) + w / 2, Math.abs(y) + h / 2);\n}\n\n/**\n * The distance along direction (`ux`, `uy`) at which the box's farthest\n * corner reaches `limit`, or `undefined` when even a centred box pokes out.\n */\nfunction insideDistance(\n\tux: number,\n\tuy: number,\n\tw: number,\n\th: number,\n\tlimit: number,\n): number | undefined {\n\tif (farCorner(0, 0, w, h) > limit) {\n\t\treturn undefined;\n\t}\n\tlet lo = 0;\n\tlet hi = limit;\n\tfor (let i = 0; i < 40; i++) {\n\t\tconst mid = (lo + hi) / 2;\n\t\tif (farCorner(mid * ux, mid * uy, w, h) > limit) {\n\t\t\thi = mid;\n\t\t} else {\n\t\t\tlo = mid;\n\t\t}\n\t}\n\treturn lo;\n}\n\n/** How far the box (centre `x`, `y`, relative to the pie centre) crosses either slice edge. */\nfunction edgeOverhang(x: number, y: number, w: number, h: number, slice: BestFitSlice): number {\n\tlet worst = Number.NEGATIVE_INFINITY;\n\tfor (const [dx, dy] of [\n\t\t[-w / 2, -h / 2],\n\t\t[w / 2, -h / 2],\n\t\t[-w / 2, h / 2],\n\t\t[w / 2, h / 2],\n\t]) {\n\t\tconst px = x + dx;\n\t\tconst py = y + dy;\n\t\t// Signed distance from each edge line, positive on the slice's side.\n\t\tconst fromStart = Math.cos(slice.startAngle) * py - Math.sin(slice.startAngle) * px;\n\t\tconst fromEnd = Math.sin(slice.endAngle) * px - Math.cos(slice.endAngle) * py;\n\t\tworst = Math.max(worst, -fromStart, -fromEnd);\n\t}\n\treturn worst;\n}\n\n/**\n * Place a `w x h` label box for a slice at `bestFit` (see the module doc).\n * A slice of half the pie or more always has room, so its label stays inside.\n */\nexport function placeBestFitLabel(slice: BestFitSlice, w: number, h: number): BestFitPlacement {\n\tconst mid = (slice.startAngle + slice.endAngle) / 2;\n\tconst ux = Math.cos(mid);\n\tconst uy = Math.sin(mid);\n\tconst distance = insideDistance(ux, uy, w, h, slice.outerR - BEST_FIT_RIM_INSET);\n\tif (distance !== undefined) {\n\t\tconst x = distance * ux;\n\t\tconst y = distance * uy;\n\t\tconst reflex = slice.endAngle - slice.startAngle >= Math.PI;\n\t\tif (reflex || edgeOverhang(x, y, w, h, slice) <= BEST_FIT_EDGE_TOLERANCE) {\n\t\t\treturn { x: slice.cx + x, y: slice.cy + y, inside: true };\n\t\t}\n\t}\n\t// Outside: the box's extent towards the centre starts just beyond the rim.\n\tconst extent = (Math.abs(ux) * w) / 2 + (Math.abs(uy) * h) / 2;\n\tconst outside = slice.outerR + BEST_FIT_OUTSIDE_GAP + extent;\n\treturn { x: slice.cx + outside * ux, y: slice.cy + outside * uy, inside: false };\n}\n","/**\n * chart-pie-label-collision.ts: nudge colliding OUTSIDE pie labels apart.\n *\n * At `c:dLblPos val=\"bestFit\"` PowerPoint puts a label that does not fit in its\n * slice outside the rim; when two such labels overlap it moves them apart\n * (vertically, within their own side of the pie) and draws a leader line to\n * each one it moved. This module is the pure geometry half: it takes the\n * outside label boxes and returns how far each one moves. The caller decides\n * what to draw (a moved label gets a leader line; see `chart-pie-labels`).\n *\n * The algorithm is a per-side sweep: labels on the right (or left) of the pie\n * are sorted top to bottom, each is pushed below the previous one when they\n * overlap, and if the stack then runs past the bottom bound it is shifted back\n * up. Constants are not COM-measured; the gap is one line of breathing room.\n *\n * @module chart-pie-label-collision\n */\n\n/** Minimum vertical gap (px) kept between two nudged labels. */\nexport const LABEL_COLLISION_GAP = 2;\n\n/** One outside label box: its centre and size, keyed by an opaque id. */\nexport interface OutsideLabelBox {\n\tid: number;\n\t/** Box centre, in the same space as `pieCx`. */\n\tx: number;\n\ty: number;\n\tw: number;\n\th: number;\n}\n\n/** How far one label moves (`dx`/`dy` are 0 when it stays put). */\nexport interface LabelNudge {\n\tid: number;\n\tdx: number;\n\tdy: number;\n}\n\n/** The pie disc a nudged label must never be pushed into. */\nexport interface PieDisc {\n\tcx: number;\n\tcy: number;\n\tr: number;\n}\n\n/** Distance from the disc centre to the nearest point of a box centred at (`x`, `y`). */\nfunction boxDistanceToCentre(box: OutsideLabelBox, y: number, disc: PieDisc): number {\n\tconst nearestX = Math.max(box.x - box.w / 2, Math.min(disc.cx, box.x + box.w / 2));\n\tconst nearestY = Math.max(y - box.h / 2, Math.min(disc.cy, y + box.h / 2));\n\treturn Math.hypot(nearestX - disc.cx, nearestY - disc.cy);\n}\n\n/**\n * A vertical nudge moves a label ALONG the rim only near 3 and 9 o'clock; near\n * 6 and 12 o'clock it drives the label into the pie. Push such a label\n * outward horizontally until its box clears the disc again.\n */\nfunction clearOfDisc(box: OutsideLabelBox, y: number, disc: PieDisc): number {\n\tif (boxDistanceToCentre(box, y, disc) >= disc.r) {\n\t\treturn 0;\n\t}\n\tconst sign = box.x >= disc.cx ? 1 : -1;\n\tlet dx = 0;\n\twhile (\n\t\tdx < disc.r * 2 &&\n\t\tboxDistanceToCentre({ ...box, x: box.x + sign * dx }, y, disc) < disc.r\n\t) {\n\t\tdx += 1;\n\t}\n\treturn sign * dx;\n}\n\n/** Whether two boxes overlap horizontally (they share x extent). */\nfunction overlapsX(a: OutsideLabelBox, b: OutsideLabelBox): boolean {\n\treturn Math.abs(a.x - b.x) < (a.w + b.w) / 2;\n}\n\n/** Sweep one side's labels; returns the resolved centre y per box, by input order. */\nfunction sweepSide(\n\tboxes: ReadonlyArray<OutsideLabelBox>,\n\tminY: number,\n\tmaxY: number,\n): Map<number, number> {\n\tconst sorted = [...boxes].sort((a, b) => a.y - b.y || a.id - b.id);\n\tconst ys = sorted.map((box) => box.y);\n\tfor (let i = 1; i < sorted.length; i++) {\n\t\tconst prev = sorted[i - 1]!;\n\t\tconst box = sorted[i]!;\n\t\tif (overlapsX(prev, box)) {\n\t\t\tys[i] = Math.max(ys[i]!, ys[i - 1]! + (prev.h + box.h) / 2 + LABEL_COLLISION_GAP);\n\t\t}\n\t}\n\t// Past the bottom bound: shift the tail back up, keeping the gaps.\n\tfor (let i = sorted.length - 1; i >= 0; i--) {\n\t\tconst box = sorted[i]!;\n\t\tconst limit =\n\t\t\ti === sorted.length - 1\n\t\t\t\t? maxY - box.h / 2\n\t\t\t\t: ys[i + 1]! - (box.h + sorted[i + 1]!.h) / 2 - LABEL_COLLISION_GAP;\n\t\tif (ys[i]! > limit) {\n\t\t\tys[i] = Math.max(limit, minY + box.h / 2);\n\t\t}\n\t}\n\treturn new Map(sorted.map((box, i) => [box.id, ys[i]!]));\n}\n\n/**\n * Compute the vertical nudges that separate overlapping outside labels.\n * `disc` splits the labels into a left and a right column and keeps every\n * nudged label outside the pie; `minY`/`maxY` bound the drawing area. Labels\n * that do not collide get `dx: 0, dy: 0`.\n */\nexport function nudgeOutsideLabels(\n\tboxes: ReadonlyArray<OutsideLabelBox>,\n\tdisc: PieDisc,\n\tminY: number,\n\tmaxY: number,\n): LabelNudge[] {\n\tconst resolved = new Map<number, number>();\n\tfor (const side of [\n\t\tboxes.filter((box) => box.x >= disc.cx),\n\t\tboxes.filter((box) => box.x < disc.cx),\n\t]) {\n\t\tfor (const [id, y] of sweepSide(side, minY, maxY)) {\n\t\t\tresolved.set(id, y);\n\t\t}\n\t}\n\treturn boxes.map((box) => {\n\t\tconst y = resolved.get(box.id) ?? box.y;\n\t\treturn { id: box.id, dx: y === box.y ? 0 : clearOfDisc(box, y, disc), dy: y - box.y };\n\t});\n}\n","/**\n * chart-pie-label-helpers.ts: small pure helpers `chart-pie-labels` shares\n * between its inside, outside and bestFit placement paths (label font,\n * manual-drag offset, leader-line geometry). Split out to keep that module\n * within the repo's file-size limit.\n *\n * @module chart-pie-label-helpers\n */\nimport type { PptxChartShapeProps } from 'pptx-viewer-core';\n\nimport { chartFontPx } from './chart-font';\nimport type { ChartAnchorPoint } from './chart-manual-layout';\nimport { applyLabelManualLayout, chartFrameToViewOffset } from './chart-manual-layout';\nimport type { PieLabelContent, PieLabelParams } from './chart-pie-labels';\nimport type { PieSliceGeometry, SvgLine, SvgText } from './chart-view-model';\n\n/**\n * Resolve a label's SvgText font, starting from the given defaults (the\n * fixed inside/outside styling this module always used) and overriding with\n * a per-point txPr (C2-G1 data-label half) when the resolved label content\n * carries one. Returns every field required by `SvgText` so callers can\n * spread the result without a duplicate-key/optional-override conflict.\n */\nexport function labelTextStyle(\n\tcontent: PieLabelContent,\n\tdefaults: Pick<SvgText, 'fontSize'> & Partial<Pick<SvgText, 'fontWeight'>>,\n): Pick<SvgText, 'fontFamily' | 'fontSize' | 'fontWeight'> {\n\tconst fontWeight =\n\t\tcontent.bold !== undefined ? (content.bold ? 'bold' : 'normal') : defaults.fontWeight;\n\treturn {\n\t\tfontSize: content.fontSize !== undefined ? chartFontPx(content.fontSize) : defaults.fontSize,\n\t\t...(fontWeight !== undefined ? { fontWeight } : {}),\n\t\t...(content.fontFamily ? { fontFamily: content.fontFamily } : {}),\n\t};\n}\n\n/**\n * Shift an automatic label point by its manual-layout drag, when both a\n * `layoutFor` resolver and the chart `frame` were given. The pie engine lays\n * out on a letterboxed `size x size` SVG square distinct from the element's\n * own box, so the offset is applied in frame-space and converted back.\n */\nexport function applyManualDrag(\n\tpoint: ChartAnchorPoint,\n\tpointIndex: number,\n\tparams: PieLabelParams,\n): ChartAnchorPoint {\n\tconst { layoutFor, frame, svgWidth, svgHeight } = params;\n\tif (!layoutFor || !frame || svgWidth === undefined || svgHeight === undefined) {\n\t\treturn point;\n\t}\n\tconst layout = layoutFor(pointIndex);\n\tconst viewOffset = chartFrameToViewOffset(frame, { svgWidth, svgHeight });\n\tconst framePoint = { x: point.x + viewOffset.x, y: point.y + viewOffset.y };\n\tconst shifted = applyLabelManualLayout(layout, frame, framePoint);\n\treturn { x: shifted.x - viewOffset.x, y: shifted.y - viewOffset.y };\n}\n\n/** A leader line from the slice's rim point to a label at `to`. */\nexport function leaderLine(\n\tslice: PieSliceGeometry,\n\tcx: number,\n\tcy: number,\n\touterR: number,\n\tto: ChartAnchorPoint,\n\tstyle: PptxChartShapeProps | undefined,\n): SvgLine {\n\treturn {\n\t\tkind: 'line',\n\t\tx1: cx + outerR * Math.cos(slice.midAngle),\n\t\ty1: cy + outerR * Math.sin(slice.midAngle),\n\t\tx2: to.x,\n\t\ty2: to.y,\n\t\tstroke: style?.strokeColor ?? '#94a3b8',\n\t\tstrokeWidth: 0.75,\n\t};\n}\n","/**\n * chart-pie-labels.ts: pie / doughnut data-label placement, including outside\n * (`c:dLblPos` = `outEnd` / `bestFit`) labels with `c:leaderLines` connectors,\n * per-point manual drag offsets (`c:dLbl/c:layout`, C2-G15/limitations \"Pie/\n * doughnut manual-layout label offset\"), and a per-point font override\n * (`c:dLbl`/`c:dLbls` `txPr`, C2-G1 data-label half).\n *\n * PowerPoint pins pie data labels either INSIDE each slice (`ctr`, `inEnd`) or\n * OUTSIDE the rim (`outEnd`, `bestFit`). Outside labels are joined to their slice\n * by a leader line when `c:dLbls/c:showLeaderLines` is set (the default for\n * offset labels). The flat engine previously only produced centred inside labels;\n * this module adds the outside placement + leader-line geometry so offset pie\n * labels render with their connectors.\n *\n * @module chart-pie-labels\n */\nimport type {\n\tPptxChartDataLabelPosition,\n\tPptxChartManualLayout,\n\tPptxChartShapeProps,\n} from 'pptx-viewer-core';\n\nimport { DEFAULT_CHART_DATA_LABEL_PX } from './chart-font';\nimport { splitLabelLines } from './chart-label-lines';\nimport { dataLabelBoxSize } from './chart-label-measure';\nimport type { ChartAnchorPoint, ChartFrameSize } from './chart-manual-layout';\nimport { placeBestFitLabel } from './chart-pie-best-fit';\nimport { nudgeOutsideLabels } from './chart-pie-label-collision';\nimport { applyManualDrag, labelTextStyle, leaderLine } from './chart-pie-label-helpers';\nimport { formatAxisValue } from './chart-view-model';\nimport type { PieSliceGeometry, SvgLine, SvgPrimitive, SvgText } from './chart-view-model';\n\n/** A `bestFit` label placed outside the rim, held back until collisions are resolved. */\ninterface PendingOutside {\n\ti: number;\n\tslice: PieSliceGeometry;\n\tlabel: SvgText;\n\tauto: ChartAnchorPoint;\n\tw: number;\n\th: number;\n}\n\n/** Distance (px) an outside label sits beyond the slice rim. */\nconst LEADER_LENGTH = 14;\n\n/** One resolved label: its text plus any per-point styling overrides. */\nexport interface PieLabelContent {\n\ttext: string;\n\tcolor?: string;\n\t/** Per-point font override (C2-G1 data-label half: `c:dLbl`/`c:dLbls` `txPr`), in points. */\n\tfontFamily?: string;\n\tfontSize?: number;\n\tbold?: boolean;\n}\n\nexport interface PieLabelParams {\n\tslices: ReadonlyArray<PieSliceGeometry>;\n\tvalues: ReadonlyArray<number>;\n\tcx: number;\n\tcy: number;\n\touterR: number;\n\t/** Resolved `c:dLblPos`; `outEnd` places labels outside the rim, `bestFit` inside or out. */\n\tposition?: PptxChartDataLabelPosition;\n\t/** A point's own `c:dLblPos` (point > series > chart cascade), overriding `position`. */\n\tpositionFor?: (pointIndex: number) => PptxChartDataLabelPosition | undefined;\n\t/** A doughnut has no `bestFit` of its own: its labels keep the ring placement. */\n\tdoughnut?: boolean;\n\t/** `c:showLeaderLines`. Defaults to on for outside labels. */\n\tshowLeaderLines?: boolean;\n\t/**\n\t * Leader-line stroke styling (`PptxChartDataLabelOptions.leaderLineStyle`,\n\t * resolved from the base `c:leaderLines/c:spPr` or its chart15-extension\n\t * mirror, `c:extLst/c:ext/c15:leaderLines/c:spPr`). Only the stroke colour\n\t * is honoured here; omit to keep this module's own default leader-line\n\t * colour (`#94a3b8`), which is what every chart rendered before this\n\t * extension was modelled.\n\t */\n\tleaderLineStyle?: PptxChartShapeProps;\n\t/** Series `c:numFmt` / cache format code applied to each label value. */\n\tnumberFormat?: string;\n\t/**\n\t * Resolves the TEXT (and, for a value-only label, its `[Red]`/`[Blue]`\n\t * number-format colour, plus any per-point font override) of the label at\n\t * `pointIndex`, so `c:showPercent` / `c:showCatName` / `c:separator` can be\n\t * honoured (see `chart-data-label-text`). Returning `undefined` suppresses\n\t * that one label (a `c:dLbl/c:delete`). Omit to print the formatted value,\n\t * which is what this module did before the content flags were wired up.\n\t */\n\tlabelText?: (pointIndex: number, value: number) => PieLabelContent | undefined;\n\t/**\n\t * Resolves this point's manual drag offset (`c:dLbl/c:layout/c:manualLayout`).\n\t * `frame` (the chart element's own pixel box, distinct from the pie's\n\t * `size x size` SVG viewBox) must be given alongside this for the offset to\n\t * apply; omit both to keep the automatic placement, matching every chart\n\t * this module rendered before manual layout support existed.\n\t */\n\tlayoutFor?: (pointIndex: number) => PptxChartManualLayout | null | undefined;\n\tframe?: ChartFrameSize;\n\t/** The pie's own SVG viewBox size, needed to convert `frame`-space offsets. */\n\tsvgWidth?: number;\n\tsvgHeight?: number;\n\t/**\n\t * The label box / callout decorations for one label (see\n\t * `chart-data-label-callout`), given the point its pointer aims at: the\n\t * rim at the slice's mid-angle, or `targetRadius` out along it.\n\t */\n\tdecorate?: (pointIndex: number, label: SvgText, target: ChartAnchorPoint) => SvgPrimitive[];\n\t/** Where along the mid-angle a callout points; defaults to `outerR` (the rim). */\n\ttargetRadius?: number;\n}\n\nexport interface PieLabelResult {\n\tlabels: SvgText[];\n\tleaderLines: SvgLine[];\n\t/** Label boxes / callouts from `decorate`, painted under the labels. */\n\tboxes: SvgPrimitive[];\n}\n\n/** Whether a data-label position renders outside the pie rim (a doughnut's `bestFit` too). */\nexport function isOutsidePosition(position: PptxChartDataLabelPosition | undefined): boolean {\n\treturn position === 'outEnd' || position === 'bestFit';\n}\n\n/**\n * Build pie/doughnut data labels. Inside positions reuse each slice's centroid\n * (white bold, centred). Outside positions place the label beyond the rim with a\n * leader line from the rim point to the label anchor. `bestFit` goes inside the\n * slice near the rim when the label fits, else just outside (`chart-pie-best-fit`).\n */\nexport function buildPieDataLabels(params: PieLabelParams): PieLabelResult {\n\tconst {\n\t\tslices,\n\t\tvalues,\n\t\tcx,\n\t\tcy,\n\t\touterR,\n\t\tposition,\n\t\tshowLeaderLines,\n\t\tnumberFormat,\n\t\tlabelText,\n\t\tleaderLineStyle,\n\t\tdecorate,\n\t} = params;\n\tconst labels: SvgText[] = [];\n\tconst leaderLines: SvgLine[] = [];\n\tconst boxes: SvgPrimitive[] = [];\n\tconst push = (i: number, label: SvgText, midAngle: number) => {\n\t\t// The box/callout is sized from the whole label; the painted text is\n\t\t// one primitive per line so no binding needs multi-line support.\n\t\tlabels.push(...splitLabelLines(label));\n\t\tconst r = params.targetRadius ?? outerR;\n\t\tif (decorate) {\n\t\t\tconst target = { x: cx + r * Math.cos(midAngle), y: cy + r * Math.sin(midAngle) };\n\t\t\tboxes.push(...decorate(i, label, target));\n\t\t}\n\t};\n\n\tconst pendingOutside: PendingOutside[] = [];\n\tconst placeBestFit = (\n\t\ti: number,\n\t\tslice: PieSliceGeometry,\n\t\tlabel: SvgText,\n\t\tauto: ChartAnchorPoint,\n\t\tnudged: ChartAnchorPoint = auto,\n\t) => {\n\t\tconst moved = applyManualDrag(nudged, i, params);\n\t\tpush(i, { ...label, x: moved.x, y: moved.y }, slice.midAngle);\n\t\t// PowerPoint draws a leader line only to a label that left its spot.\n\t\tif (showLeaderLines !== false && (moved.x !== auto.x || moved.y !== auto.y)) {\n\t\t\tleaderLines.push(leaderLine(slice, cx, cy, outerR, moved, leaderLineStyle));\n\t\t}\n\t};\n\n\tslices.forEach((slice, i) => {\n\t\tconst val = values[i];\n\t\tif (val === undefined) {\n\t\t\treturn;\n\t\t}\n\t\tconst resolved = labelText ? labelText(i, val) : { text: formatAxisValue(val, numberFormat) };\n\t\tif (resolved === undefined) {\n\t\t\treturn;\n\t\t}\n\t\tconst { text, color } = resolved;\n\t\tconst pointPosition = params.positionFor?.(i) ?? position;\n\t\tif (pointPosition === 'bestFit' && !params.doughnut) {\n\t\t\tconst label: SvgText = {\n\t\t\t\tkind: 'text',\n\t\t\t\tx: 0,\n\t\t\t\ty: 0,\n\t\t\t\ttext,\n\t\t\t\tfill: color ?? '#334155',\n\t\t\t\ttextAnchor: 'middle',\n\t\t\t\tdominantBaseline: 'central',\n\t\t\t\t...labelTextStyle(resolved, { fontSize: DEFAULT_CHART_DATA_LABEL_PX }),\n\t\t\t};\n\t\t\tconst { w, h } = dataLabelBoxSize(label);\n\t\t\tconst auto = placeBestFitLabel({ ...slice, outerR }, w, h);\n\t\t\tif (!auto.inside) {\n\t\t\t\t// Outside labels may collide: placed after the loop, once nudged apart.\n\t\t\t\tpendingOutside.push({ i, slice, label, auto, w, h });\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tplaceBestFit(i, slice, label, auto);\n\t\t\treturn;\n\t\t}\n\t\tif (!isOutsidePosition(pointPosition)) {\n\t\t\tconst { x, y } = applyManualDrag({ x: slice.labelX, y: slice.labelY }, i, params);\n\t\t\tpush(\n\t\t\t\ti,\n\t\t\t\t{\n\t\t\t\t\tkind: 'text',\n\t\t\t\t\tx,\n\t\t\t\t\ty,\n\t\t\t\t\ttext,\n\t\t\t\t\tfill: color ?? '#ffffff',\n\t\t\t\t\ttextAnchor: 'middle',\n\t\t\t\t\tdominantBaseline: 'central',\n\t\t\t\t\t...labelTextStyle(resolved, {\n\t\t\t\t\t\tfontSize: DEFAULT_CHART_DATA_LABEL_PX,\n\t\t\t\t\t\tfontWeight: 'bold',\n\t\t\t\t\t}),\n\t\t\t\t},\n\t\t\t\tslice.midAngle,\n\t\t\t);\n\t\t\treturn;\n\t\t}\n\n\t\tconst cos = Math.cos(slice.midAngle);\n\t\tconst sin = Math.sin(slice.midAngle);\n\t\tconst autoLabelX = cx + (outerR + LEADER_LENGTH) * cos;\n\t\tconst autoLabelY = cy + (outerR + LEADER_LENGTH) * sin;\n\t\tconst { x: labelX, y: labelY } = applyManualDrag({ x: autoLabelX, y: autoLabelY }, i, params);\n\t\tconst anchor: 'start' | 'end' = cos >= 0 ? 'start' : 'end';\n\n\t\tpush(\n\t\t\ti,\n\t\t\t{\n\t\t\t\tkind: 'text',\n\t\t\t\tx: labelX + (cos >= 0 ? 2 : -2),\n\t\t\t\ty: labelY,\n\t\t\t\ttext,\n\t\t\t\tfill: color ?? '#334155',\n\t\t\t\ttextAnchor: anchor,\n\t\t\t\tdominantBaseline: 'central',\n\t\t\t\t...labelTextStyle(resolved, { fontSize: DEFAULT_CHART_DATA_LABEL_PX }),\n\t\t\t},\n\t\t\tslice.midAngle,\n\t\t);\n\n\t\t// Leader lines default ON for offset labels (only suppressed when the source\n\t\t// explicitly clears c:showLeaderLines). Points at the MOVED label position\n\t\t// so a dragged label keeps its connector pointing at it.\n\t\tif (showLeaderLines !== false) {\n\t\t\tleaderLines.push(\n\t\t\t\tleaderLine(slice, cx, cy, outerR, { x: labelX, y: labelY }, leaderLineStyle),\n\t\t\t);\n\t\t}\n\t});\n\n\t// Outside bestFit labels: nudge colliding ones apart (a moved label gets a\n\t// leader line from placeBestFit), see chart-pie-label-collision.\n\tconst nudges = nudgeOutsideLabels(\n\t\tpendingOutside.map((p) => ({ id: p.i, x: p.auto.x, y: p.auto.y, w: p.w, h: p.h })),\n\t\t{ cx, cy, r: outerR },\n\t\t0,\n\t\tparams.svgHeight ?? Number.POSITIVE_INFINITY,\n\t);\n\tfor (const p of pendingOutside) {\n\t\tconst nudge = nudges.find((n) => n.id === p.i);\n\t\tplaceBestFit(p.i, p.slice, p.label, p.auto, {\n\t\t\tx: p.auto.x + (nudge?.dx ?? 0),\n\t\t\ty: p.auto.y + (nudge?.dy ?? 0),\n\t\t});\n\t}\n\n\treturn { labels, leaderLines, boxes };\n}\n","/**\n * chart-radar-geometry.ts: radar (spider) chart polar-coordinate geometry,\n * split out of `chart-view-model-points.ts` to keep that file within the\n * repo's ~300-LOC limit. Re-exported from there (and from `chart-view-model.ts`)\n * so the public import surface is unchanged.\n *\n * @module chart-radar-geometry\n */\n\n/** Angle (radians) of the i-th radar spoke; 0 points up (-90°), clockwise. */\nexport function radarAngle(index: number, catCount: number): number {\n\tconst n = Math.max(catCount, 1);\n\treturn (Math.PI * 2 * index) / n - Math.PI / 2;\n}\n\nexport interface RadarPoint {\n\tx: number;\n\ty: number;\n}\n\n/** Project a series' values onto radar (polar) coordinates around (cx, cy). */\nexport function computeRadarPoints(\n\tvalues: ReadonlyArray<number>,\n\tmaxVal: number,\n\tradius: number,\n\tcx: number,\n\tcy: number,\n\tcatCount: number,\n): RadarPoint[] {\n\tconst denom = maxVal > 0 ? maxVal : 1;\n\treturn values.slice(0, Math.max(catCount, 1)).map((val, i) => {\n\t\tconst angle = radarAngle(i, catCount),\n\t\t\tr = (Math.abs(val) / denom) * radius;\n\t\treturn { x: cx + r * Math.cos(angle), y: cy + r * Math.sin(angle) };\n\t});\n}\n\n/** Points string for a radar gridline ring at radius `rr`. */\nexport function radarRingPoints(cx: number, cy: number, rr: number, catCount: number): string {\n\tconst n = Math.max(catCount, 1);\n\treturn Array.from({ length: n }, (_, i) => {\n\t\tconst angle = radarAngle(i, n);\n\t\treturn `${(cx + rr * Math.cos(angle)).toFixed(2)},${(cy + rr * Math.sin(angle)).toFixed(2)}`;\n\t}).join(' ');\n}\n","/**\n * chart-view-model-points.ts: pie / doughnut, scatter, bubble and radar\n * geometry of the chart engine. Split out of `chart-view-model.ts`, which\n * re-exports everything here.\n *\n * @module chart-view-model-points\n */\n/* eslint-disable one-var -- this module predates the rule and combining every\n sibling `const`/`let` in a function into one comma-list (oxlint's own\n `--fix` cannot do this safely once a non-declaration statement sits between\n them) would churn geometry code far beyond this change's scope. */\n\nimport type { PptxChartData, PptxChartSeries } from 'pptx-viewer-core';\n\nimport {\n\tchartFrameToViewOffset,\n\tmanualLayoutOf,\n\tresolveManualLayoutRect,\n} from './chart-manual-layout';\nimport { chartTitleReservePx } from './chart-title-band';\nimport { valueToY } from './chart-view-model-scale';\nimport type { ValueRange } from './chart-view-model-scale';\nimport type { PlotLayout } from './chart-view-model-types';\n\n// Pie / doughnut\n\nexport interface PieSliceGeometry {\n\td: string;\n\tmidAngle: number;\n\tlabelX: number;\n\tlabelY: number;\n\t/** Edge angles (radians) and centre (after any explosion), for `bestFit` labels. */\n\tstartAngle: number;\n\tendAngle: number;\n\tcx: number;\n\tcy: number;\n}\n\nexport function computePieSlicePath(\n\tcx: number,\n\tcy: number,\n\touterR: number,\n\tinnerR: number,\n\tstartAngle: number,\n\tendAngle: number,\n): PieSliceGeometry {\n\tconst largeArc = endAngle - startAngle > Math.PI ? 1 : 0,\n\t\tx1 = cx + outerR * Math.cos(startAngle),\n\t\ty1 = cy + outerR * Math.sin(startAngle),\n\t\tx2 = cx + outerR * Math.cos(endAngle),\n\t\ty2 = cy + outerR * Math.sin(endAngle);\n\n\tlet d: string;\n\tif (innerR > 0) {\n\t\tconst ix1 = cx + innerR * Math.cos(startAngle),\n\t\t\tiy1 = cy + innerR * Math.sin(startAngle),\n\t\t\tix2 = cx + innerR * Math.cos(endAngle),\n\t\t\tiy2 = cy + innerR * Math.sin(endAngle);\n\t\td = `M${x1},${y1} A${outerR},${outerR} 0 ${largeArc} 1 ${x2},${y2} L${ix2},${iy2} A${innerR},${innerR} 0 ${largeArc} 0 ${ix1},${iy1} Z`;\n\t} else {\n\t\td = `M${cx},${cy} L${x1},${y1} A${outerR},${outerR} 0 ${largeArc} 1 ${x2},${y2} Z`;\n\t}\n\n\tconst midAngle = (startAngle + endAngle) / 2,\n\t\t// A doughnut label sits on the middle of its ring (COM, callouts-com.pptx);\n\t\t// 0.7 of the radius would put it in the hole of any hole over 40%.\n\t\tlabelR = innerR > 0 ? (innerR + outerR) / 2 : outerR * 0.7,\n\t\tlabelX = cx + labelR * Math.cos(midAngle),\n\t\tlabelY = cy + labelR * Math.sin(midAngle);\n\n\treturn { d, midAngle, labelX, labelY, startAngle, endAngle, cx, cy };\n}\n\n/** Constant padding (px) PowerPoint leaves inside an automatic pie plot area. */\nexport const PIE_AUTO_INSET_PX = 6.7;\n\nexport function computePieLayout(\n\telementWidth: number,\n\telementHeight: number,\n\tchartData: PptxChartData,\n\tisDoughnut: boolean,\n): { cx: number; cy: number; outerR: number; innerR: number; size: number } {\n\tconst size = Math.min(Math.max(elementWidth, 1), Math.max(elementHeight, 1)),\n\t\ttitleOffset = chartTitleReservePx(chartData),\n\t\tlegendOffset = chartData.style?.hasLegend ? 20 : 0;\n\tlet cx = size / 2,\n\t\tcy = titleOffset + (size - titleOffset - legendOffset) / 2,\n\t\t// Automatic plot area: 42% of the free height, less a fixed inset.\n\t\t// PowerPoint keeps a constant padding (about 5pt, 6.7px) between the\n\t\t// pie and the plot-area edge, so the pie is smaller than a pure\n\t\t// percentage of the box by the same PIXELS at every size: about 8% of the\n\t\t// radius in a small (~200px) chart, under 1% in a large one, which is\n\t\t// the documented discrepancy. Not COM-measured; the constant is fitted to\n\t\t// that reported worst case.\n\t\touterR = Math.max((size - titleOffset - legendOffset) * 0.42 - PIE_AUTO_INSET_PX, 0);\n\t// c:plotArea/c:layout/c:manualLayout is measured on the element, while the\n\t// pie is laid out on a centred `size x size` square: translate the automatic\n\t// disc out to the element, resolve, and translate the centre back in. The\n\t// pie fills the smaller side of whatever rectangle the author drew.\n\tconst offset = chartFrameToViewOffset(\n\t\t\t{ width: elementWidth, height: elementHeight },\n\t\t\t{ svgWidth: size, svgHeight: size },\n\t\t),\n\t\tmanual = resolveManualLayoutRect(\n\t\t\tmanualLayoutOf(chartData, 'plotArea'),\n\t\t\t{ width: elementWidth, height: elementHeight },\n\t\t\t{\n\t\t\t\tx: offset.x + cx - outerR,\n\t\t\t\ty: offset.y + cy - outerR,\n\t\t\t\twidth: 2 * outerR,\n\t\t\t\theight: 2 * outerR,\n\t\t\t},\n\t\t);\n\tif (manual) {\n\t\tcx = manual.x + manual.width / 2 - offset.x;\n\t\tcy = manual.y + manual.height / 2 - offset.y;\n\t\touterR = Math.min(manual.width, manual.height) / 2;\n\t}\n\t// Honour c:holeSize (10-90% of the outer diameter) when parsed; otherwise\n\t// keep the legacy 0.55 ratio byte-for-byte.\n\tconst holeRatio =\n\t\t\tisDoughnut && chartData.doughnutHoleSize !== undefined\n\t\t\t\t? Math.min(Math.max(chartData.doughnutHoleSize, 10), 90) / 100\n\t\t\t\t: 0.55,\n\t\tinnerR = isDoughnut ? outerR * holeRatio : 0;\n\treturn { cx, cy, outerR, innerR, size };\n}\n\n/** Options for {@link computePieSlices}: start-angle rotation and per-slice explosion. */\nexport interface PieSliceOptions {\n\t/** Absolute start angle (radians). Defaults to -PI/2 (12 o'clock). */\n\tstartAngle?: number;\n\t/** Per-slice pull-out distance as a percentage of the outer radius (0-100). */\n\texplosions?: ReadonlyArray<number>;\n}\n\nexport function computePieSlices(\n\tvalues: ReadonlyArray<number>,\n\tcx: number,\n\tcy: number,\n\touterR: number,\n\tinnerR: number,\n\toptions?: PieSliceOptions,\n): PieSliceGeometry[] {\n\tconst total = values.reduce((s, v) => s + Math.abs(v), 0) || 1;\n\tlet cumAngle = options?.startAngle ?? -Math.PI / 2;\n\treturn values.map((val, i) => {\n\t\tconst sliceAngle = (Math.abs(val) / total) * Math.PI * 2,\n\t\t\tstartAngle = cumAngle;\n\t\tcumAngle += sliceAngle;\n\t\t// A c:explosion pulls the slice outward along its bisector.\n\t\tconst explosion = options?.explosions?.[i] ?? 0;\n\t\tif (explosion > 0) {\n\t\t\tconst mid = (startAngle + cumAngle) / 2,\n\t\t\t\toffset = outerR * (explosion / 100);\n\t\t\treturn computePieSlicePath(\n\t\t\t\tcx + Math.cos(mid) * offset,\n\t\t\t\tcy + Math.sin(mid) * offset,\n\t\t\t\touterR,\n\t\t\t\tinnerR,\n\t\t\t\tstartAngle,\n\t\t\t\tcumAngle,\n\t\t\t);\n\t\t}\n\t\treturn computePieSlicePath(cx, cy, outerR, innerR, startAngle, cumAngle);\n\t});\n}\n\n// Scatter\n\nexport interface ScatterDot {\n\tcx: number;\n\tcy: number;\n}\n\n/**\n * X values a scatter / bubble series is plotted against.\n *\n * The series' own `c:xVal` wins. Only when it has none does the chart-level\n * category list stand in, which is all the engine used to have and is why every\n * series in a multi-series scatter was plotted against series 1's x axis.\n *\n * Lives here (not `chart-cartesian-plots.ts`, its original home) so\n * `chart-scatter-x-axis.ts` can share it without a circular import: that\n * module builds the X axis's own nice min/max/major-unit scale, and\n * `chart-cartesian-plots.ts` / `chart-cartesian-bubbles.ts` need that same\n * scale to place their points on it.\n */\nexport function seriesXValues(\n\tchartData: PptxChartData,\n\tseries: PptxChartSeries,\n): ReadonlyArray<number> | undefined {\n\tif (series.xValues && series.xValues.length > 0) {\n\t\treturn series.xValues;\n\t}\n\tconst fromCategories = chartData.categories.map(Number);\n\treturn fromCategories.length > 0 ? fromCategories : undefined;\n}\n\n/**\n * The x extent a scatter / bubble plot is drawn against.\n *\n * Every `CT_ScatterSer` / `CT_BubbleSer` carries its own `c:xVal`, so the\n * domain has to be computed ACROSS series before any of them is projected;\n * letting each series derive its own min/span would stretch every series to\n * fill the plot and destroy the relationship between them.\n */\nexport interface ScatterXDomain {\n\tmin: number;\n\tspan: number;\n}\n\n/**\n * Union x domain of several series' x values. Returns `undefined` when no\n * series declares a finite x value, in which case callers fall back to\n * positioning points by index.\n */\nexport function computeScatterXDomain(\n\tperSeriesXValues: ReadonlyArray<ReadonlyArray<number> | undefined>,\n): ScatterXDomain | undefined {\n\tconst finite: number[] = [];\n\tfor (const values of perSeriesXValues) {\n\t\tfor (const value of values ?? []) {\n\t\t\tif (Number.isFinite(value)) {\n\t\t\t\tfinite.push(value);\n\t\t\t}\n\t\t}\n\t}\n\tif (finite.length === 0) {\n\t\treturn undefined;\n\t}\n\tconst min = Math.min(...finite);\n\treturn { min, span: Math.max(Math.max(...finite) - min, 1) };\n}\n\nexport function computeScatterDots(\n\tvalues: ReadonlyArray<number>,\n\tmaxXIndex: number,\n\tlayout: PlotLayout,\n\trange: ValueRange,\n\txValues?: ReadonlyArray<number>,\n\txDomain?: ScatterXDomain,\n): ScatterDot[] {\n\tconst finiteX = xValues?.slice(0, values.length).filter(Number.isFinite),\n\t\tminX = xDomain ? xDomain.min : finiteX?.length ? Math.min(...finiteX) : 0,\n\t\tspanX = xDomain\n\t\t\t? xDomain.span\n\t\t\t: finiteX?.length\n\t\t\t\t? Math.max(Math.max(...finiteX) - minX, 1)\n\t\t\t\t: maxXIndex;\n\treturn values.map((val, i) => ({\n\t\tcx:\n\t\t\tlayout.plotLeft +\n\t\t\t(spanX > 0 ? (Number.isFinite(xValues?.[i]) ? xValues![i] - minX : i) / spanX : 0) *\n\t\t\t\tlayout.plotWidth,\n\t\tcy: valueToY(val, range, layout.plotTop, layout.plotBottom),\n\t}));\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Bubble\n// ─────────────────────────────────────────────────────────────────────────────\n\n/** `c:bubbleScale` / `c:sizeRepresents` inputs to {@link computeBubbleRadius}. */\nexport interface BubbleRadiusOptions {\n\t/** `c:bubbleScale` (0-300%). PowerPoint's own default, 100, leaves the envelope unscaled. */\n\tbubbleScale?: number;\n\t/**\n\t * `c:sizeRepresents`. `'area'` (ECMA-376's own default) sizes bubbles so the\n\t * rendered AREA is proportional to the value (radius scales with the square\n\t * root of it); `'w'` sizes so the DIAMETER is proportional (radius scales\n\t * linearly). Defaults to `'w'` here so this raw helper's pre-existing\n\t * 3-argument callers stay byte-identical; `buildBubbles` resolves the\n\t * chart-wide `'area'` default itself before calling in.\n\t */\n\tsizeRepresents?: 'area' | 'w';\n}\n\n/**\n * Radius of a bubble given its size value, the max size in the chart, and a\n * median radius derived from the plot area. When no size value is present the\n * bubble uses the median radius (scaled by `bubbleScale`); otherwise it scales\n * from 0.5x to 2x the median, linearly (`sizeRepresents: 'w'`) or by square\n * root (`'area'`, so the bubble's rendered AREA, not its diameter, tracks the\n * value).\n */\nexport function computeBubbleRadius(\n\tsizeVal: number | undefined,\n\tmaxBubble: number,\n\tmedianRadius: number,\n\toptions?: BubbleRadiusOptions,\n): number {\n\tconst scale = (options?.bubbleScale ?? 100) / 100;\n\tif (sizeVal === undefined) {\n\t\treturn medianRadius * scale;\n\t}\n\tconst denom = maxBubble > 0 ? maxBubble : 1,\n\t\tmagnitude = Math.abs(sizeVal),\n\t\tratio =\n\t\t\t(options?.sizeRepresents ?? 'w') === 'area'\n\t\t\t\t? Math.sqrt(magnitude) / Math.sqrt(denom)\n\t\t\t\t: magnitude / denom;\n\treturn medianRadius * scale * 0.5 + ratio * medianRadius * scale * 1.5;\n}\n\n// Radar (spider) chart polar-coordinate geometry lives in its own module\n// (`chart-radar-geometry.ts`); re-exported here so this module's existing\n// consumers (and `chart-view-model.ts`'s `export *`) see no change.\nexport { computeRadarPoints, radarAngle, radarRingPoints } from './chart-radar-geometry';\nexport type { RadarPoint } from './chart-radar-geometry';\n","/**\n * chart-view-model-pie.ts: the fallback (unsupported / empty) and pie /\n * doughnut view-model builders. Split out of `chart-view-model.ts`, which\n * re-exports `buildFallbackViewModel`.\n *\n * @module chart-view-model-pie\n */\n/* eslint-disable one-var -- this module predates the rule and combining every\n sibling `const`/`let` in a function into one comma-list (oxlint's own\n `--fix` cannot do this safely once a non-declaration statement sits between\n them) would churn geometry code far beyond this change's scope. */\n\nimport type { PptxChartData, PptxElement } from 'pptx-viewer-core';\n\nimport { DEFAULT_CHART_AREA_FILL } from './chart-area-fill';\nimport { resolveChartTitleText } from './chart-auto-title';\nimport { findPointLabel, resolveLabelPosition } from './chart-data-label-anchor';\nimport { buildDataLabelDecorations } from './chart-data-label-callout';\nimport { buildDataLabelText, resolveDataLabelTextStyle } from './chart-data-label-text';\nimport { resolveDataPointExplosion, resolveVaryColorFill } from './chart-datapoint-style';\nimport { resolveLegendPlacement } from './chart-legend-placement';\nimport { buildPieDataLabels } from './chart-pie-labels';\nimport { chartTitleReservePx } from './chart-title-band';\nimport { computePieLayout, computePieSlices } from './chart-view-model-points';\nimport { buildMarkTooltip, paletteColor } from './chart-view-model-scale';\nimport type {\n\tChartViewModel,\n\tLegendEntry,\n\tSvgPath,\n\tSvgPrimitive,\n\tSvgRect,\n\tSvgText,\n} from './chart-view-model-types';\n\nexport function buildFallbackViewModel(\n\twidth: number,\n\theight: number,\n\tlabel: string,\n): ChartViewModel {\n\t// Match the frame box exactly (bindings stretch with preserveAspectRatio\n\t// \"none\"; a minimum here would scale the fallback non-uniformly).\n\tconst svgWidth = Math.max(width, 1),\n\t\tsvgHeight = Math.max(height, 1);\n\treturn {\n\t\tsvgWidth,\n\t\tsvgHeight,\n\t\t// No chart data to read a fill from, so the historical wash stands.\n\t\tareaFill: DEFAULT_CHART_AREA_FILL,\n\t\ttitle: undefined,\n\t\ttitleX: svgWidth / 2,\n\t\ttitleY: 14,\n\t\tgridlines: [],\n\t\taxisLabels: [],\n\t\tzeroLine: undefined,\n\t\tcategoryLabels: [],\n\t\tprimitives: [\n\t\t\t{\n\t\t\t\tkind: 'rect',\n\t\t\t\tx: 4,\n\t\t\t\ty: 4,\n\t\t\t\tw: svgWidth - 8,\n\t\t\t\th: svgHeight - 8,\n\t\t\t\tfill: '#f1f5f9',\n\t\t\t\trx: 4,\n\t\t\t} satisfies SvgRect,\n\t\t],\n\t\tdataLabels: [\n\t\t\t{\n\t\t\t\tkind: 'text',\n\t\t\t\tx: svgWidth / 2,\n\t\t\t\ty: svgHeight / 2,\n\t\t\t\ttext: label,\n\t\t\t\tfontSize: 10,\n\t\t\t\tfill: '#94a3b8',\n\t\t\t\ttextAnchor: 'middle',\n\t\t\t\tdominantBaseline: 'central',\n\t\t\t} satisfies SvgText,\n\t\t],\n\t\tlegend: [],\n\t\tlegendX: svgWidth / 2,\n\t\tlegendY: svgHeight - 8,\n\t\tlegendAnchor: 'middle',\n\t};\n}\n\nexport function buildPieViewModel(\n\telement: PptxElement,\n\tchartData: PptxChartData,\n\tcategoryLabels: ReadonlyArray<string>,\n\tisDoughnut: boolean,\n): ChartViewModel {\n\tconst { cx, cy, outerR, innerR, size } = computePieLayout(\n\t\t\telement.width,\n\t\t\telement.height,\n\t\t\tchartData,\n\t\t\tisDoughnut,\n\t\t),\n\t\tsvgWidth = Math.max(size, 100),\n\t\tsvgHeight = Math.max(size, 60),\n\t\tpieSeries = chartData.series[0],\n\t\tvalues = pieSeries?.values ?? [],\n\t\t// c:firstSliceAng rotates the pie clockwise from 12 o'clock; c:explosion (per\n\t\t// series or per c:dPt) pulls slices outward.\n\t\tstartAngle = -Math.PI / 2 + ((chartData.firstSliceAngle ?? 0) * Math.PI) / 180,\n\t\texplosions = pieSeries\n\t\t\t? values.map((_v, i) => resolveDataPointExplosion(pieSeries, i))\n\t\t\t: undefined,\n\t\tslices = computePieSlices(values, cx, cy, outerR, innerR, { startAngle, explosions }),\n\t\tprimitives: SvgPrimitive[] = slices.map(\n\t\t\t({ d }, i) =>\n\t\t\t\t({\n\t\t\t\t\tkind: 'path',\n\t\t\t\t\td,\n\t\t\t\t\t// Pie/doughnut vary colours per slice (c:varyColors defaults on), so each\n\t\t\t\t\t// slice takes its palette colour, with a per-point c:dPt fill overriding.\n\t\t\t\t\tfill: pieSeries\n\t\t\t\t\t\t? resolveVaryColorFill(pieSeries, i, paletteColor(i, chartData.colorPalette))\n\t\t\t\t\t\t: paletteColor(i, chartData.colorPalette),\n\t\t\t\t\tstroke: '#ffffff',\n\t\t\t\t\tstrokeWidth: 1.5,\n\t\t\t\t\tpart: { role: 'dataPoint', seriesIndex: 0, pointIndex: i },\n\t\t\t\t\ttitle: buildMarkTooltip(\n\t\t\t\t\t\tpieSeries?.name,\n\t\t\t\t\t\tcategoryLabels[i],\n\t\t\t\t\t\tvalues[i] ?? 0,\n\t\t\t\t\t\tpieSeries?.numberFormat,\n\t\t\t\t\t),\n\t\t\t\t}) satisfies SvgPath,\n\t\t),\n\t\tdataLabels: SvgText[] = [];\n\tif (chartData.style?.hasDataLabels) {\n\t\t// Offset (outEnd / bestFit) labels sit outside the rim with c:leaderLines.\n\t\t// A pie's percentage base is the whole series, and `c:showPercent` is the\n\t\t// flag that makes the difference between \"40\" and \"40%\" on the commonest\n\t\t// labelled chart in a business deck.\n\t\tconst percentBase = values.reduce((total, entry) => total + Math.abs(entry), 0),\n\t\t\tlabelResult = buildPieDataLabels({\n\t\t\t\tslices,\n\t\t\t\tvalues,\n\t\t\t\tcx,\n\t\t\t\tcy,\n\t\t\t\touterR,\n\t\t\t\tposition: chartData.style.dataLabels?.position,\n\t\t\t\t// PowerPoint writes a pie's `c:dLblPos` on the series (`c:ser/c:dLbls`),\n\t\t\t\t// which the chart-level `position` above never saw.\n\t\t\t\tpositionFor: pieSeries\n\t\t\t\t\t? (pointIndex) => resolveLabelPosition(chartData, pieSeries, pointIndex)\n\t\t\t\t\t: undefined,\n\t\t\t\tdoughnut: isDoughnut,\n\t\t\t\tshowLeaderLines: chartData.style.dataLabels?.showLeaderLines,\n\t\t\t\t// Series-level `c:ser/c:dLbls` (where PowerPoint actually writes the\n\t\t\t\t// leader-line style, see chart-data-label-parser.ts) overrides the\n\t\t\t\t// chart-type-level group, matching the point > series > chart-type\n\t\t\t\t// cascade every other data-label field already follows.\n\t\t\t\tleaderLineStyle:\n\t\t\t\t\tpieSeries?.dataLabelOptions?.leaderLineStyle ??\n\t\t\t\t\tchartData.style.dataLabels?.leaderLineStyle,\n\t\t\t\tnumberFormat: chartData.series[0]?.numberFormat,\n\t\t\t\tlabelText: pieSeries\n\t\t\t\t\t? (pointIndex, value) => {\n\t\t\t\t\t\t\tconst built = buildDataLabelText({\n\t\t\t\t\t\t\t\tchartData,\n\t\t\t\t\t\t\t\tseries: pieSeries,\n\t\t\t\t\t\t\t\tpointIndex,\n\t\t\t\t\t\t\t\tvalue,\n\t\t\t\t\t\t\t\tpercentBase,\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\tif (!built) {\n\t\t\t\t\t\t\t\treturn undefined;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tconst style = resolveDataLabelTextStyle(chartData, pieSeries, pointIndex);\n\t\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\t\t...built,\n\t\t\t\t\t\t\t\t...(style?.fontFamily ? { fontFamily: style.fontFamily } : {}),\n\t\t\t\t\t\t\t\t...(style?.fontSize !== undefined ? { fontSize: style.fontSize } : {}),\n\t\t\t\t\t\t\t\t...(style?.bold !== undefined ? { bold: style.bold } : {}),\n\t\t\t\t\t\t\t\t// The label's own `txPr` colour (a number-format colour wins).\n\t\t\t\t\t\t\t\t...(!built.color && style?.color ? { color: style.color } : {}),\n\t\t\t\t\t\t\t};\n\t\t\t\t\t\t}\n\t\t\t\t\t: undefined,\n\t\t\t\tlayoutFor: pieSeries\n\t\t\t\t\t? (pointIndex) => pieSeries.dataLabels?.find((label) => label.idx === pointIndex)?.layout\n\t\t\t\t\t: undefined,\n\t\t\t\tframe: { width: element.width, height: element.height },\n\t\t\t\tsvgWidth,\n\t\t\t\tsvgHeight,\n\t\t\t\t// COM (callouts-com.pptx): a pie callout points at the rim, a\n\t\t\t\t// doughnut's at the middle of its ring. A dragged doughnut label\n\t\t\t\t// also gets a leader line; the pie's own come from `c:leaderLines`.\n\t\t\t\ttargetRadius: isDoughnut ? (innerR + outerR) / 2 : outerR,\n\t\t\t\tdecorate: pieSeries\n\t\t\t\t\t? (pointIndex, label, target) =>\n\t\t\t\t\t\t\tbuildDataLabelDecorations(\n\t\t\t\t\t\t\t\tchartData,\n\t\t\t\t\t\t\t\tpieSeries,\n\t\t\t\t\t\t\t\tlabel,\n\t\t\t\t\t\t\t\ttarget,\n\t\t\t\t\t\t\t\tisDoughnut && Boolean(findPointLabel(pieSeries, pointIndex)?.layout),\n\t\t\t\t\t\t\t)\n\t\t\t\t\t: undefined,\n\t\t\t});\n\t\tdataLabels.push(...labelResult.labels);\n\t\tprimitives.push(...labelResult.leaderLines, ...labelResult.boxes);\n\t}\n\n\tconst legendPos = chartData.style?.legendPosition ?? 'b',\n\t\t// Legend swatches must match the slices: a per-point `c:dPt` fill overrides\n\t\t// the palette on the slice, so it overrides it on the swatch too.\n\t\tlegend: LegendEntry[] = categoryLabels.map((label, i) => ({\n\t\t\tcolor: pieSeries\n\t\t\t\t? resolveVaryColorFill(pieSeries, i, paletteColor(i, chartData.colorPalette))\n\t\t\t\t: paletteColor(i, chartData.colorPalette),\n\t\t\tlabel,\n\t\t}));\n\tlet legendX = svgWidth / 2;\n\tlet legendY = svgHeight - 8;\n\tlet legendAnchor: 'start' | 'middle' | 'end' = 'middle';\n\n\tif (legendPos === 't') {\n\t\tlegendY = chartData.style?.hasTitle ? 24 : 8;\n\t} else if (resolveLegendPlacement(legendPos).overlaysPlot) {\n\t\t// `tr`: a right-aligned column starting near the top rather than the\n\t\t// automatic bottom-centred row, matching PowerPoint's own quick-layout\n\t\t// behaviour and the same 'start'-anchored vertical stack `'r'` uses\n\t\t// elsewhere in this engine (see chart-view-model-layout.ts's buildLegend).\n\t\tlegendX = svgWidth - 75;\n\t\t// Clear the font-sized title band (the old fixed band put this at 24).\n\t\tlegendY = chartData.style?.hasTitle ? chartTitleReservePx(chartData) + 4 : 8;\n\t\tlegendAnchor = 'start';\n\t}\n\n\tconst title = resolveChartTitleText(chartData);\n\n\treturn {\n\t\tsvgWidth,\n\t\tsvgHeight,\n\t\ttitle,\n\t\ttitleX: svgWidth / 2,\n\t\ttitleY: 14,\n\t\tgridlines: [],\n\t\taxisLabels: [],\n\t\tzeroLine: undefined,\n\t\tcategoryLabels: [],\n\t\tprimitives,\n\t\tdataLabels,\n\t\tlegend: chartData.style?.hasLegend ? legend : [],\n\t\tlegendX,\n\t\tlegendY,\n\t\tlegendAnchor,\n\t};\n}\n","/**\n * chart-view-model-layout.ts: plot-area layout math for the chart engine\n * (the plot inset, legend/title/data-table/secondary-axis reservations, and\n * `c:plotArea/c:layout/c:manualLayout` overrides). Chart chrome (gridlines,\n * axis / category labels) lives in `chart-view-model-chrome.ts`; legend\n * building lives in `chart-legend-build.ts`. All three are re-exported by\n * `chart-view-model.ts`.\n *\n * @module chart-view-model-layout\n */\n/* eslint-disable one-var -- this module predates the rule and combining every\n sibling `const`/`let` in a function into one comma-list (oxlint's own\n `--fix` cannot do this safely once a non-declaration statement sits between\n them) would churn geometry code far beyond this change's scope. */\n\nimport type { PptxChartData } from 'pptx-viewer-core';\n\nimport { resolveDataTableMetrics } from './chart-data-table-metrics';\nimport { chartFontPx, DEFAULT_CHART_TEXT_PX } from './chart-font';\nimport { reserveLegendSpace } from './chart-legend-placement';\nimport { manualLayoutOf, resolveManualLayoutRect } from './chart-manual-layout';\nimport { chartTitleReservePx } from './chart-title-band';\nimport type { PlotLayout, PlotLayoutOptions } from './chart-view-model-types';\n\n/**\n * Compute the plot layout for a chart element.\n * Mirrors `computeLayout` from chart-layout.ts (React). When `options` is omitted\n * (or all its flags are falsy) the output is byte-identical to the original\n * viewer-first single-axis layout; the secondary-axis / data-table reservations\n * only apply when explicitly requested.\n */\n/**\n * Vertical space to reserve under the plot for the category axis: the gap\n * `c:lblOffset` asks for, plus one line box of the axis font.\n *\n * The old flat 24 px was calibrated when chart text was drawn pt-as-px. Once\n * `chartFontPx` scaled every label by 4/3, an 11.95 pt axis no longer fitted in\n * 24 px and its labels were pushed back up onto the plot. The `Math.max(24, …)`\n * floor keeps the previous behaviour for default-font and axis-less charts, so\n * only oversized-font charts move.\n *\n * @param chartData The chart whose category axis is being measured.\n * @returns Pixels to reserve below the plot area.\n */\nfunction categoryAxisBand(chartData: PptxChartData): number {\n\tconst axis = chartData.axes?.find(\n\t\t\t(candidate) => candidate.axisType === 'catAx' || candidate.axisType === 'dateAx',\n\t\t),\n\t\tfontPx = axis?.fontSize !== undefined ? chartFontPx(axis.fontSize) : DEFAULT_CHART_TEXT_PX,\n\t\toffset = 4 + 8 * ((axis?.labelOffset ?? 100) / 100);\n\treturn Math.max(24, offset + fontPx * 1.2);\n}\n\n/** Whether the primary value axis shows a display-units caption. */\nfunction hasDisplayUnitsCaption(chartData: PptxChartData): boolean {\n\tconst axis = chartData.axes?.find((a) => a.axisType === 'valAx' && a.axPos !== 'r');\n\treturn Boolean(axis?.displayUnits) && axis?.displayUnitsLabel !== null;\n}\n\n/**\n * Horizontal space to reserve to the LEFT of the plot for the axis band.\n *\n * The 40 px default is sized for a value axis's short numeric ticks (up to a\n * few digits). A horizontal-bar chart's left axis instead carries the\n * category TEXT (the chart is transposed: categories run down the left,\n * values along the bottom), which is routinely wider than that, e.g. an\n * inserted chart's default \"Category 1\" label measures ~72 px at the default\n * 13.33 px axis font. Left at the 40 px default, that text clipped against\n * the chart's own SVG edge (x=0) before it ever reached the plot area,\n * rendering \"Category 1\" as \"egory 1\". `leftCategoryLabelWidth` (from\n * `widestCategoryLabelWidth` in chart-horizontal-bars-helpers.ts) lets the\n * horizontal-bar builder widen this band to fit its actual label text; every\n * other caller keeps the unchanged 40 px numeric-axis default.\n */\nfunction leftAxisBand(leftCategoryLabelWidth: number | undefined): number {\n\treturn Math.max(40, (leftCategoryLabelWidth ?? 0) + 4);\n}\n\nexport function computePlotLayout(\n\telementWidth: number,\n\telementHeight: number,\n\tchartData: PptxChartData,\n\thasAxes: boolean,\n\toptions?: PlotLayoutOptions,\n): PlotLayout {\n\t// The SVG viewBox must equal the element's frame box exactly: bindings render\n\t// it with `preserveAspectRatio=\"none\"`, so ANY minimum here (historically\n\t// 320x180) makes the chart scale non-uniformly inside its host (issue #132:\n\t// a 475x174 frame got a 475x180 viewBox, squeezing y by 0.967).\n\tconst svgWidth = Math.max(1, elementWidth),\n\t\tsvgHeight = Math.max(1, elementHeight);\n\n\tlet plotLeft = hasAxes ? 8 + leftAxisBand(options?.leftCategoryLabelWidth) : 8,\n\t\tplotTop = 8,\n\t\tplotRight = svgWidth - 8,\n\t\tplotBottom = svgHeight - (hasAxes ? categoryAxisBand(chartData) : 8);\n\n\t// `c:catAx/c:axPos val=\"t\"` on the PRIMARY (and, in the common case, only)\n\t// category axis: PowerPoint draws that axis's tick labels above the plot,\n\t// not below it. Reserving the label band at the bottom regardless of\n\t// `axPos` (the historical behaviour here) leaves no room at the top, so the\n\t// labels get drawn outside the chart's own SVG bounds and clip against its\n\t// edge. Move the reservation to match where the labels actually land.\n\tif (hasAxes && options?.categoryAxisAtTop) {\n\t\tplotBottom = svgHeight - 8;\n\t\tplotTop += categoryAxisBand(chartData);\n\t}\n\n\tconst style = chartData.style,\n\t\tlegendPos = style?.legendPosition ?? 'b';\n\n\t// The title band is sized from the title's own font (chart-title-band.ts);\n\t// a chart without a title reserves nothing, as before.\n\tplotTop += chartTitleReservePx(chartData);\n\tif (style?.hasLegend) {\n\t\t// `tr` (top-right corner) overlays the plot per PowerPoint's own\n\t\t// quick-layout behaviour: no band is reserved for it, unlike b/t/l/r.\n\t\t({ plotLeft, plotTop, plotRight, plotBottom } = reserveLegendSpace(legendPos, {\n\t\t\tplotLeft,\n\t\t\tplotTop,\n\t\t\tplotRight,\n\t\t\tplotBottom,\n\t\t}));\n\t}\n\n\t// A display-units caption (\"Thousands\") needs its own band left of the\n\t// primary value axis' tick labels, as PowerPoint gives it.\n\tif (hasAxes && hasDisplayUnitsCaption(chartData)) {\n\t\tplotLeft += 20;\n\t}\n\t// Secondary value axis on the right.\n\tif (options?.hasSecondaryValueAxis) {\n\t\tplotRight -= 40;\n\t}\n\t// Secondary category axis on the top.\n\tif (options?.hasSecondaryCategoryAxis) {\n\t\tplotTop += 16;\n\t}\n\t// Data table below the chart: its header row replaces the category axis\n\t// labels, and its key column hangs left of the plot (COM-verified\n\t// charts-com.pptx slide 2; see chart-data-table-metrics).\n\tconst tableMetrics = options?.hasDataTable ? resolveDataTableMetrics(chartData) : undefined;\n\tif (tableMetrics) {\n\t\tif (hasAxes && !options?.categoryAxisAtTop) {\n\t\t\tplotBottom += categoryAxisBand(chartData) - 8;\n\t\t}\n\t\tplotBottom -= tableMetrics.height;\n\t\tplotLeft = Math.max(plotLeft, 8 + tableMetrics.keyW);\n\t}\n\n\t// The automatic plot height, before any manual layout override below can\n\t// change it: see `PlotLayout.autoPlotHeight`'s doc comment.\n\tconst autoPlotHeight = Math.max(plotBottom - plotTop, 1);\n\n\t// c:plotArea/c:layout/c:manualLayout: the author placed the plot area by\n\t// hand. Each field the layout omits keeps the automatic value above, which\n\t// is also what a `factor`-mode offset is relative to. An `outer` target\n\t// (the default) includes the axis labels, so the plot proper is inset by\n\t// the same bands the automatic layout reserves for them.\n\tconst plotLayout = manualLayoutOf(chartData, 'plotArea'),\n\t\tmanual = resolveManualLayoutRect(\n\t\t\tplotLayout,\n\t\t\t{ width: svgWidth, height: svgHeight },\n\t\t\t{ x: plotLeft, y: plotTop, width: plotRight - plotLeft, height: plotBottom - plotTop },\n\t\t);\n\tif (plotLayout && manual) {\n\t\tplotLeft = manual.x;\n\t\tplotTop = manual.y;\n\t\tplotRight = manual.x + manual.width;\n\t\tplotBottom = manual.y + manual.height;\n\t\tif (hasAxes && plotLayout.layoutTarget !== 'inner') {\n\t\t\tplotLeft += leftAxisBand(options?.leftCategoryLabelWidth);\n\t\t\tplotBottom -= categoryAxisBand(chartData) - 8;\n\t\t}\n\t}\n\n\tconst plotWidth = Math.max(plotRight - plotLeft, 1),\n\t\tplotHeight = Math.max(plotBottom - plotTop, 1);\n\n\treturn {\n\t\tsvgWidth,\n\t\tsvgHeight,\n\t\tplotLeft,\n\t\tplotTop,\n\t\tplotRight: plotLeft + plotWidth,\n\t\tplotBottom: plotTop + plotHeight,\n\t\tplotWidth,\n\t\tplotHeight,\n\t\tautoPlotHeight,\n\t};\n}\n","/**\n * chart-view-model-radar.ts: the radar / spider view-model builder. Split out\n * of `chart-view-model.ts`.\n *\n * @module chart-view-model-radar\n */\n/* eslint-disable one-var -- this module predates the rule and combining every\n sibling `const`/`let` in a function into one comma-list (oxlint's own\n `--fix` cannot do this safely once a non-declaration statement sits between\n them) would churn geometry code far beyond this change's scope. */\n\nimport type { PptxChartData, PptxElement } from 'pptx-viewer-core';\n\nimport { resolveChartTitleText } from './chart-auto-title';\nimport {\n\tfindPointLabel,\n\tresolveLabelPosition,\n\tresolveMarkerLabelPlacement,\n} from './chart-data-label-anchor';\nimport { pushPointLabel } from './chart-data-label-callout';\nimport {\n\tbuildDataLabelText,\n\tdataLabelFontOverride,\n\tresolveDataLabelTextStyle,\n} from './chart-data-label-text';\nimport { DEFAULT_CHART_DATA_LABEL_PX, DEFAULT_CHART_TEXT_PX } from './chart-font';\nimport { buildLegend } from './chart-legend-build';\nimport { applyLabelManualLayout } from './chart-manual-layout';\nimport { computeRadarPoints, radarAngle, radarRingPoints } from './chart-radar-geometry';\nimport { computePlotLayout } from './chart-view-model-layout';\nimport { buildMarkTooltip, seriesColor } from './chart-view-model-scale';\nimport type {\n\tChartViewModel,\n\tSvgCircle,\n\tSvgLine,\n\tSvgPolygon,\n\tSvgPrimitive,\n\tSvgText,\n} from './chart-view-model-types';\n\nconst RADAR_RINGS = 4,\n\tRADAR_RING_COLOR = '#cbd5e1',\n\tRADAR_SPOKE_COLOR = '#94a3b8',\n\tRADAR_LABEL_COLOR = '#64748b',\n\t// COM (callouts-com.pptx): with no c:dLblPos, PowerPoint centres a radar\n\t// label on the spoke, this many label font sizes out past its point.\n\tRADAR_LABEL_RADIAL_EM = 3.5;\n\nconst clamp = (v: number, lo: number, hi: number) => Math.min(Math.max(v, lo), Math.max(lo, hi));\n\n/**\n * Build the view-model for a radar / spider chart. Polar, so it has no\n * cartesian gridlines/axes; ring + spoke geometry and the data polygons all\n * live in `primitives`, perimeter category labels in `categoryLabels`.\n * Mirrors React's `renderRadarChart` (chart-radar.tsx).\n */\nexport function buildRadarViewModel(\n\telement: PptxElement,\n\tchartData: PptxChartData,\n\tcategoryLabels: ReadonlyArray<string>,\n): ChartViewModel {\n\tconst layout = computePlotLayout(element.width, element.height, chartData, false),\n\t\tcx = layout.plotLeft + layout.plotWidth / 2,\n\t\tcy = layout.plotTop + layout.plotHeight / 2,\n\t\tradius = Math.max(Math.min(layout.plotWidth, layout.plotHeight) / 2 - 4, 1),\n\t\tcatCount = Math.max(categoryLabels.length, 1),\n\t\tmaxVal = Math.max(1, ...chartData.series.flatMap((s) => s.values.map((v) => Math.abs(v)))),\n\t\tprimitives: SvgPrimitive[] = [],\n\t\tperimeterLabels: SvgText[] = [];\n\n\t// Concentric gridline rings (dashed except the outermost).\n\tfor (let r = 1; r <= RADAR_RINGS; r++) {\n\t\tconst rr = (radius * r) / RADAR_RINGS;\n\t\tprimitives.push({\n\t\t\tkind: 'polygon',\n\t\t\tpoints: radarRingPoints(cx, cy, rr, catCount),\n\t\t\tfill: 'none',\n\t\t\tstroke: RADAR_RING_COLOR,\n\t\t\tstrokeWidth: 0.5,\n\t\t\tdashArray: r < RADAR_RINGS ? '3 2' : undefined,\n\t\t} satisfies SvgPolygon);\n\t}\n\n\t// Axis spokes + perimeter category labels.\n\tfor (let i = 0; i < catCount; i++) {\n\t\tconst angle = radarAngle(i, catCount);\n\t\tprimitives.push({\n\t\t\tkind: 'line',\n\t\t\tx1: cx,\n\t\t\ty1: cy,\n\t\t\tx2: cx + radius * Math.cos(angle),\n\t\t\ty2: cy + radius * Math.sin(angle),\n\t\t\tstroke: RADAR_SPOKE_COLOR,\n\t\t\tstrokeWidth: 0.5,\n\t\t} satisfies SvgLine);\n\t\tconst labelR = radius + 10;\n\t\tperimeterLabels.push({\n\t\t\tkind: 'text',\n\t\t\tx: cx + labelR * Math.cos(angle),\n\t\t\ty: cy + labelR * Math.sin(angle),\n\t\t\ttext: categoryLabels[i] ?? '',\n\t\t\tfontSize: DEFAULT_CHART_TEXT_PX,\n\t\t\tfill: RADAR_LABEL_COLOR,\n\t\t\ttextAnchor: 'middle',\n\t\t\tdominantBaseline: 'central',\n\t\t});\n\t}\n\n\t// Per-series data polygons + vertex dots. `c:radarStyle` (PowerPoint's own\n\t// default is `marker`) decides the polygon fill and whether vertex markers\n\t// are drawn: `filled` paints the enclosed area solid (PowerPoint's own\n\t// ~60% opacity) with no markers; `standard` is an outline only, also with\n\t// no markers; `marker` (the pre-existing behaviour, also the fallback for\n\t// an absent/unrecognised value) draws a light fill plus vertex markers.\n\tconst radarStyle = chartData.radarStyle ?? 'marker',\n\t\tpolygonFill = radarStyle === 'standard' ? 'none' : undefined,\n\t\tpolygonOpacity = radarStyle === 'filled' ? 0.6 : radarStyle === 'standard' ? undefined : 0.2;\n\tconst dataLabels: SvgText[] = [],\n\t\tlabelBoxes: SvgPrimitive[] = [],\n\t\tframe = { width: layout.svgWidth, height: layout.svgHeight };\n\tchartData.series.forEach((series, si) => {\n\t\tconst c = seriesColor(series, si, chartData.colorPalette),\n\t\t\tpts = computeRadarPoints(series.values, maxVal, radius, cx, cy, catCount);\n\t\tif (pts.length === 0) {\n\t\t\treturn;\n\t\t}\n\t\tconst pointsStr = pts.map((p) => `${p.x.toFixed(2)},${p.y.toFixed(2)}`).join(' ');\n\t\tprimitives.push({\n\t\t\tkind: 'polygon',\n\t\t\tpoints: pointsStr,\n\t\t\tfill: polygonFill ?? c,\n\t\t\topacity: polygonOpacity,\n\t\t\tstroke: c,\n\t\t\tstrokeWidth: 1.5,\n\t\t\tpart: { role: 'series', seriesIndex: si },\n\t\t\ttitle: series.name.length > 0 ? series.name : undefined,\n\t\t} satisfies SvgPolygon);\n\t\tif (radarStyle === 'marker') {\n\t\t\tpts.forEach((p, vi) => {\n\t\t\t\tprimitives.push({\n\t\t\t\t\tkind: 'circle',\n\t\t\t\t\tcx: p.x,\n\t\t\t\t\tcy: p.y,\n\t\t\t\t\tr: 3,\n\t\t\t\t\tfill: c,\n\t\t\t\t\tpart: { role: 'dataPoint', seriesIndex: si, pointIndex: vi },\n\t\t\t\t\ttitle: buildMarkTooltip(\n\t\t\t\t\t\tseries.name,\n\t\t\t\t\t\tcategoryLabels[vi],\n\t\t\t\t\t\tseries.values[vi] ?? 0,\n\t\t\t\t\t\tseries.numberFormat,\n\t\t\t\t\t),\n\t\t\t\t} satisfies SvgCircle);\n\t\t\t});\n\t\t}\n\n\t\tif (chartData.style?.hasDataLabels) {\n\t\t\tpts.forEach((p, vi) => {\n\t\t\t\tconst val = series.values[vi],\n\t\t\t\t\tlabel =\n\t\t\t\t\t\tval === undefined\n\t\t\t\t\t\t\t? undefined\n\t\t\t\t\t\t\t: buildDataLabelText({ chartData, series, pointIndex: vi, value: val });\n\t\t\t\tif (label === undefined) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tconst font = dataLabelFontOverride(resolveDataLabelTextStyle(chartData, series, vi)),\n\t\t\t\t\tfontSize = font.fontSize ?? DEFAULT_CHART_DATA_LABEL_PX;\n\t\t\t\tlet anchor: Pick<SvgText, 'x' | 'y' | 'textAnchor' | 'dominantBaseline'>;\n\t\t\t\tif (resolveLabelPosition(chartData, series, vi) === undefined) {\n\t\t\t\t\tconst angle = radarAngle(vi, catCount),\n\t\t\t\t\t\tout = RADAR_LABEL_RADIAL_EM * fontSize,\n\t\t\t\t\t\t// Kept inside the chart box, as PowerPoint keeps every label.\n\t\t\t\t\t\tauto = {\n\t\t\t\t\t\t\tx: clamp(p.x + out * Math.cos(angle), fontSize, frame.width - fontSize),\n\t\t\t\t\t\t\ty: clamp(p.y + out * Math.sin(angle), fontSize, frame.height - fontSize),\n\t\t\t\t\t\t};\n\t\t\t\t\tanchor = {\n\t\t\t\t\t\t...applyLabelManualLayout(findPointLabel(series, vi)?.layout, frame, auto),\n\t\t\t\t\t\ttextAnchor: 'middle',\n\t\t\t\t\t\tdominantBaseline: 'central',\n\t\t\t\t\t};\n\t\t\t\t} else {\n\t\t\t\t\tanchor = resolveMarkerLabelPlacement(chartData, series, vi, p, frame, 7);\n\t\t\t\t}\n\t\t\t\tpushPointLabel(dataLabels, labelBoxes, chartData, series, vi, p, {\n\t\t\t\t\tkind: 'text',\n\t\t\t\t\t...anchor,\n\t\t\t\t\ttext: label.text,\n\t\t\t\t\tfontSize: DEFAULT_CHART_DATA_LABEL_PX,\n\t\t\t\t\tfill: label.color ?? '#334155',\n\t\t\t\t\t...font,\n\t\t\t\t});\n\t\t\t});\n\t\t}\n\t});\n\n\tconst legendPos = chartData.style?.legendPosition ?? 'b',\n\t\t{ legend, legendX, legendY, legendAnchor } = buildLegend(\n\t\t\tchartData.series,\n\t\t\tchartData.colorPalette,\n\t\t\tlayout.svgWidth,\n\t\t\tlegendPos,\n\t\t\tlayout.svgHeight,\n\t\t\tlayout.plotTop,\n\t\t),\n\t\ttitle = resolveChartTitleText(chartData);\n\n\treturn {\n\t\tsvgWidth: layout.svgWidth,\n\t\tsvgHeight: layout.svgHeight,\n\t\ttitle,\n\t\ttitleX: layout.svgWidth / 2,\n\t\ttitleY: 12,\n\t\tgridlines: [],\n\t\taxisLabels: [],\n\t\tzeroLine: undefined,\n\t\tcategoryLabels: perimeterLabels,\n\t\tprimitives: [...primitives, ...labelBoxes],\n\t\tdataLabels,\n\t\tlegend: chartData.style?.hasLegend ? legend : [],\n\t\tlegendX,\n\t\tlegendY,\n\t\tlegendAnchor,\n\t};\n}\n","/**\n * Region-label -> region-code alias lookup for the regionMap chart kind.\n *\n * Split out of `chart-waterfall-map.ts` (which re-exports `resolveRegionCode`)\n * to keep that file's two unrelated chart kinds (waterfall, regionMap) each\n * under the repo's per-file line budget.\n *\n * @module chart-region-map-alias\n */\n\n/**\n * Mapping from common category label strings (country names, ISO codes) to\n * internal region keys. Case-insensitive lookup.\n * Mirrors `REGION_ALIAS_MAP` from React's `chart-map.tsx`.\n */\nconst REGION_ALIAS_MAP: Record<string, string> = {\n\tus: 'US',\n\tusa: 'US',\n\t'united states': 'US',\n\t'united states of america': 'US',\n\tca: 'CA',\n\tcan: 'CA',\n\tcanada: 'CA',\n\tbr: 'BR',\n\tbra: 'BR',\n\tbrazil: 'BR',\n\tgb: 'GB',\n\tgbr: 'GB',\n\tuk: 'GB',\n\t'united kingdom': 'GB',\n\tfr: 'FR',\n\tfra: 'FR',\n\tfrance: 'FR',\n\tde: 'DE',\n\tdeu: 'DE',\n\tgermany: 'DE',\n\tit: 'IT',\n\tita: 'IT',\n\titaly: 'IT',\n\tes: 'ES',\n\tesp: 'ES',\n\tspain: 'ES',\n\tru: 'RU',\n\trus: 'RU',\n\trussia: 'RU',\n\tcn: 'CN',\n\tchn: 'CN',\n\tchina: 'CN',\n\tin: 'IN',\n\tind: 'IN',\n\tindia: 'IN',\n\tjp: 'JP',\n\tjpn: 'JP',\n\tjapan: 'JP',\n\tkr: 'KR',\n\tkor: 'KR',\n\t'south korea': 'KR',\n\tkorea: 'KR',\n\tau: 'AU',\n\taus: 'AU',\n\taustralia: 'AU',\n\tmx: 'MX',\n\tmex: 'MX',\n\tmexico: 'MX',\n\tid: 'ID',\n\tidn: 'ID',\n\tindonesia: 'ID',\n\ttr: 'TR',\n\ttur: 'TR',\n\tturkey: 'TR',\n\tsa: 'SA',\n\tsau: 'SA',\n\t'saudi arabia': 'SA',\n\tza: 'ZA',\n\tzaf: 'ZA',\n\t'south africa': 'ZA',\n\tar: 'AR',\n\targ: 'AR',\n\targentina: 'AR',\n\tng: 'NG',\n\tnga: 'NG',\n\tnigeria: 'NG',\n\teg: 'EG',\n\tegy: 'EG',\n\tegypt: 'EG',\n};\n\n/** Resolve a category label to a region key (case-insensitive). */\nexport function resolveRegionCode(label: string): string | undefined {\n\tconst normalized = label.trim().toLowerCase();\n\treturn REGION_ALIAS_MAP[normalized];\n}\n","import type { PptxChartRegionMapOptions, PptxCxValueColorPosition } from 'pptx-viewer-core';\n\nexport interface RegionMapEntry {\n\tsourceIndex: number;\n\tlabel: string;\n\tvalue: number;\n\tentityId?: string;\n\tcode?: string;\n}\n\ntype RegionCodeResolver = (label: string) => string | undefined;\n\nfunction sourceIndices(indices: number[] | undefined, length: number): number[] {\n\treturn Array.from({ length }, (_, position) => indices?.[position] ?? position);\n}\n\nfunction valueAtSource<T>(\n\tvalues: readonly T[],\n\tindices: number[],\n\tsourceIndex: number,\n): T | undefined {\n\tconst position = indices.indexOf(sourceIndex);\n\treturn position >= 0 ? values[position] : undefined;\n}\n\nfunction cachedEntityName(cache: unknown, entityId: string): string | undefined {\n\tif (!cache || typeof cache !== 'object') {\n\t\treturn undefined;\n\t}\n\tconst record = cache as Record<string, unknown>;\n\tif (String(record['@_entityId'] ?? '') === entityId && record['@_entityName'] !== undefined) {\n\t\treturn String(record['@_entityName']);\n\t}\n\tfor (const value of Object.values(record)) {\n\t\tif (Array.isArray(value)) {\n\t\t\tfor (const item of value) {\n\t\t\t\tconst name = cachedEntityName(item, entityId);\n\t\t\t\tif (name) {\n\t\t\t\t\treturn name;\n\t\t\t\t}\n\t\t\t}\n\t\t} else {\n\t\t\tconst name = cachedEntityName(value, entityId);\n\t\t\tif (name) {\n\t\t\t\treturn name;\n\t\t\t}\n\t\t}\n\t}\n\treturn undefined;\n}\n\n/** Resolve provider IDs directly, by suffix, or through an authored geo cache. */\nexport function resolveRegionEntityCode(\n\tentityId: string | undefined,\n\toptions: PptxChartRegionMapOptions | undefined,\n\tresolveCode: RegionCodeResolver,\n): string | undefined {\n\tif (!entityId) {\n\t\treturn undefined;\n\t}\n\tconst direct = resolveCode(entityId);\n\tif (direct) {\n\t\treturn direct;\n\t}\n\tconst tokens = entityId.split(/[:/|._-]+/u).filter(Boolean);\n\tfor (let index = tokens.length - 1; index >= 0; index--) {\n\t\tconst resolved = resolveCode(tokens[index] ?? '');\n\t\tif (resolved) {\n\t\t\treturn resolved;\n\t\t}\n\t}\n\tconst cachedName = cachedEntityName(options?.geographyCache, entityId);\n\treturn cachedName ? resolveCode(cachedName) : undefined;\n}\n\n/** Align region-map dimensions by their original `cx:pt/@idx` source indexes. */\nexport function buildRegionMapEntries(\n\tcategories: readonly string[],\n\tvalues: readonly number[],\n\toptions: PptxChartRegionMapOptions | undefined,\n\tresolveCode: RegionCodeResolver,\n): RegionMapEntry[] {\n\tconst entityIds = options?.entityIds ?? [];\n\tconst categoryIndices = sourceIndices(options?.categorySourceIndices, categories.length);\n\tconst valueIndices = sourceIndices(options?.valueSourceIndices, values.length);\n\tconst entityIndices = sourceIndices(options?.entityIdSourceIndices, entityIds.length);\n\tconst indices = [...new Set([...categoryIndices, ...valueIndices, ...entityIndices])].sort(\n\t\t(a, b) => a - b,\n\t);\n\treturn indices.map((sourceIndex) => {\n\t\tconst category = valueAtSource(categories, categoryIndices, sourceIndex) ?? '';\n\t\tconst value = valueAtSource(values, valueIndices, sourceIndex) ?? 0;\n\t\tconst entityId = valueAtSource(entityIds, entityIndices, sourceIndex);\n\t\treturn {\n\t\t\tsourceIndex,\n\t\t\tlabel: category || entityId || `Region ${sourceIndex + 1}`,\n\t\t\tvalue,\n\t\t\t...(entityId ? { entityId } : {}),\n\t\t\tcode: resolveRegionEntityCode(entityId, options, resolveCode) ?? resolveCode(category),\n\t\t};\n\t});\n}\n\n/** Office's bestFitOnly is implementation-defined; require a readable label box. */\nexport function shouldRenderRegionLabel(\n\tlayout: PptxChartRegionMapOptions['regionLabelLayout'],\n\tprojectedWidth: number,\n\tprojectedHeight: number,\n): boolean {\n\tif (layout === 'none') {\n\t\treturn false;\n\t}\n\tif (layout === 'bestFitOnly') {\n\t\treturn projectedWidth >= 18 && projectedHeight >= 10;\n\t}\n\treturn true;\n}\n\n/** Format geographic values using the authored culture when it is valid. */\nexport function formatRegionMapValue(value: number, cultureLanguage: string | undefined): string {\n\tif (!cultureLanguage) {\n\t\treturn String(value);\n\t}\n\ttry {\n\t\treturn new Intl.NumberFormat(cultureLanguage, { maximumFractionDigits: 2 }).format(value);\n\t} catch {\n\t\treturn String(value);\n\t}\n}\n\n/** Interpolate between two `#RRGGBB` hex colours by ratio `t` in [0, 1]. */\nexport function lerpColor(a: string, b: string, t: number): string {\n\tconst clamp = (v: number): number => Math.max(0, Math.min(255, Math.round(v))),\n\t\tha = a.replace('#', ''),\n\t\thb = b.replace('#', ''),\n\t\tr1 = parseInt(ha.substring(0, 2), 16),\n\t\tg1 = parseInt(ha.substring(2, 4), 16),\n\t\tb1 = parseInt(ha.substring(4, 6), 16),\n\t\tr2 = parseInt(hb.substring(0, 2), 16),\n\t\tg2 = parseInt(hb.substring(2, 4), 16),\n\t\tb2 = parseInt(hb.substring(4, 6), 16),\n\t\tr = clamp(r1 + (r2 - r1) * t),\n\t\tg = clamp(g1 + (g2 - g1) * t),\n\t\tbl = clamp(b1 + (b2 - b1) * t),\n\t\ttoHex = (n: number): string => n.toString(16).padStart(2, '0');\n\treturn `#${toHex(r)}${toHex(g)}${toHex(bl)}`;\n}\n\n/** One resolved `cx:valueColors` gradient stop: a colour at a normalised [0, 1] position. */\nexport interface RegionMapColorStop {\n\tposition: number;\n\tcolor: string;\n}\n\n/**\n * Resolve `cx:valueColors` (2-3 hex stops) + `cx:valueColorPositions` (their\n * breakpoints) into normalised [0, 1] gradient stops, or `undefined` when the\n * chart authors no value-color scale (the categorical/sequential palette\n * applies instead).\n *\n * `cx:colorPosition/@type` breakpoints: `min`/`max` pin to the data extremes;\n * `number` is an absolute value re-normalised against `minVal`/`maxVal`;\n * `percent` is already a 0-100 fraction of the range. A stop with no\n * authored position falls back to an even split across the stop count,\n * matching PowerPoint's own default (min/mid/max for 3 stops).\n */\nexport function resolveValueColorStops(\n\tvalueColors: readonly string[] | undefined,\n\tvalueColorPositions: readonly PptxCxValueColorPosition[] | undefined,\n\tminVal: number,\n\tmaxVal: number,\n): RegionMapColorStop[] | undefined {\n\tif (!valueColors || valueColors.length < 2) {\n\t\treturn undefined;\n\t}\n\tconst span = maxVal - minVal || 1,\n\t\tcount = valueColors.length,\n\t\tresolvePosition = (position: PptxCxValueColorPosition | undefined, index: number): number => {\n\t\t\tif (position?.kind === 'min') {\n\t\t\t\treturn 0;\n\t\t\t}\n\t\t\tif (position?.kind === 'max') {\n\t\t\t\treturn 1;\n\t\t\t}\n\t\t\tif (position?.kind === 'number' && position.value !== undefined) {\n\t\t\t\treturn Math.min(1, Math.max(0, (position.value - minVal) / span));\n\t\t\t}\n\t\t\tif (position?.kind === 'percent' && position.value !== undefined) {\n\t\t\t\treturn Math.min(1, Math.max(0, position.value / 100));\n\t\t\t}\n\t\t\treturn count === 1 ? 0 : index / (count - 1);\n\t\t};\n\treturn valueColors.map((color, index) => ({\n\t\tcolor,\n\t\tposition: resolvePosition(valueColorPositions?.[index], index),\n\t}));\n}\n\n/**\n * Build a colour-scale function from resolved gradient stops: linearly\n * interpolates between the two stops bracketing `t`, clamping to the nearest\n * stop outside the authored range.\n */\nexport function buildValueColorScale(stops: readonly RegionMapColorStop[]): (t: number) => string {\n\tconst sorted = [...stops].sort((a, b) => a.position - b.position);\n\treturn (t: number): string => {\n\t\tconst clamped = Math.max(0, Math.min(1, t)),\n\t\t\tfirst = sorted[0];\n\t\tif (!first) {\n\t\t\treturn '#94a3b8';\n\t\t}\n\t\tif (sorted.length === 1) {\n\t\t\treturn first.color;\n\t\t}\n\t\tfor (let i = 0; i < sorted.length - 1; i++) {\n\t\t\tconst a = sorted[i],\n\t\t\t\tb = sorted[i + 1];\n\t\t\tif (clamped >= a.position && clamped <= b.position) {\n\t\t\t\treturn lerpColor(a.color, b.color, (clamped - a.position) / (b.position - a.position || 1));\n\t\t\t}\n\t\t}\n\t\tconst last = sorted[sorted.length - 1] ?? first;\n\t\treturn clamped <= first.position ? first.color : last.color;\n\t};\n}\n","/**\n * Colour-scale and colour-legend helpers for the regionMap chart kind.\n *\n * Split out of `chart-waterfall-map.ts` (which re-exports `sequentialColorScale`\n * / `normalizeValue`) to keep that file's two unrelated chart kinds (waterfall,\n * regionMap) each under the repo's per-file line budget.\n *\n * @module chart-region-map-colors\n */\n\nimport { lerpColor } from './chart-region-map-data';\nimport type { SvgRect, SvgText } from './chart-view-model';\nimport { formatAxisValue } from './chart-view-model';\n\n/** Bands the region-map colour legend is drawn with. See its use site. */\nconst REGION_LEGEND_BANDS = 32;\n\n/**\n * 3-stop sequential colour scale: light (#dbeafe) -> mid (#3b82f6) -> dark (#1e3a5f).\n * Mirrors `sequentialColorScale` in React's `chart-map.tsx`.\n */\nexport function sequentialColorScale(t: number): string {\n\tconst clamped = Math.max(0, Math.min(1, t));\n\tif (clamped <= 0.5) {\n\t\treturn lerpColor('#dbeafe', '#3b82f6', clamped * 2);\n\t}\n\treturn lerpColor('#3b82f6', '#1e3a5f', (clamped - 0.5) * 2);\n}\n\n/** Normalise a value to [0..1] within a min/max range. */\nexport function normalizeValue(value: number, min: number, max: number): number {\n\tif (max === min) {\n\t\treturn 0.5;\n\t}\n\treturn (value - min) / (max - min);\n}\n\nexport interface RegionMapColorLegendParams {\n\tsvgWidth: number;\n\tlegendY: number;\n\tminVal: number;\n\tmaxVal: number;\n\tcolorScale: (t: number) => string;\n\tattribution?: string;\n\tsvgHeight: number;\n}\n\n/**\n * Build the colour-legend bar (banded gradient approximation), its min/max\n * value labels, and the optional attribution text, in the same order the\n * regionMap view-model draws them.\n */\nexport function buildRegionMapColorLegend(\n\tparams: RegionMapColorLegendParams,\n): Array<SvgRect | SvgText> {\n\tconst { svgWidth, legendY, minVal, maxVal, colorScale, attribution, svgHeight } = params;\n\tconst primitives: Array<SvgRect | SvgText> = [];\n\n\tconst barW = Math.min(svgWidth * 0.4, 160);\n\tconst barX = (svgWidth - barW) / 2;\n\n\t// The ramp is banded, not a paint server: `SvgPrimitive` has no gradient\n\t// kind, and inventing one would need a matching change in all five\n\t// projectors. Two half-width rects (what this used to emit) read as a\n\t// two-tone bar rather than a scale, so the band count is high enough that\n\t// the seams fall below a pixel at any legend width a slide can produce.\n\tfor (let band = 0; band < REGION_LEGEND_BANDS; band++) {\n\t\tprimitives.push({\n\t\t\tkind: 'rect',\n\t\t\tx: barX + (band / REGION_LEGEND_BANDS) * barW,\n\t\t\ty: legendY,\n\t\t\t// A hair of overlap: adjacent rects on fractional pixel boundaries\n\t\t\t// otherwise leave hairline gaps once the slide's zoom transform lands.\n\t\t\tw: barW / REGION_LEGEND_BANDS + 0.5,\n\t\t\th: 8,\n\t\t\tfill: colorScale((band + 0.5) / REGION_LEGEND_BANDS),\n\t\t} satisfies SvgRect);\n\t}\n\n\t// Legend min/max labels.\n\tprimitives.push(\n\t\t{\n\t\t\tkind: 'text',\n\t\t\tx: barX,\n\t\t\ty: legendY + 18,\n\t\t\ttext: formatAxisValue(minVal),\n\t\t\tfontSize: 7,\n\t\t\tfill: '#64748b',\n\t\t\ttextAnchor: 'middle',\n\t\t} satisfies SvgText,\n\t\t{\n\t\t\tkind: 'text',\n\t\t\tx: barX + barW,\n\t\t\ty: legendY + 18,\n\t\t\ttext: formatAxisValue(maxVal),\n\t\t\tfontSize: 7,\n\t\t\tfill: '#64748b',\n\t\t\ttextAnchor: 'middle',\n\t\t} satisfies SvgText,\n\t);\n\n\tif (attribution) {\n\t\tprimitives.push({\n\t\t\tkind: 'text',\n\t\t\tx: svgWidth - 4,\n\t\t\ty: svgHeight - 4,\n\t\t\ttext: attribution,\n\t\t\tfontSize: 5,\n\t\t\tfill: '#64748b',\n\t\t\ttextAnchor: 'end',\n\t\t} satisfies SvgText);\n\t}\n\n\treturn primitives;\n}\n","/**\n * Simplified world-region outlines and coordinate-projection helpers for the\n * regionMap chart kind.\n *\n * Split out of `chart-waterfall-map.ts` (which re-exports the regionMap\n * builder that consumes these) to keep that file's two unrelated chart kinds\n * (waterfall, regionMap) each under the repo's per-file line budget.\n *\n * @module chart-map-projection\n */\n\nimport type { PptxChartRegionMapOptions } from 'pptx-viewer-core';\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Simplified world region outlines (1000 x 500 viewBox)\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport interface RegionDef {\n\tcode: string;\n\tname: string;\n\t/** SVG path d attribute (simplified outline on a 1000 x 500 coordinate system). */\n\tpath: string;\n\t/** Label anchor [x, y] in the 1000 x 500 space. */\n\tlabelXY: [number, number];\n}\n\n/** Simplified world region outlines (mirrors `WORLD_REGIONS` in React's chart-map.tsx). */\nexport const WORLD_REGIONS: RegionDef[] = [\n\t{\n\t\tcode: 'US',\n\t\tname: 'United States',\n\t\tpath: 'M130,160 L250,155 265,170 270,190 260,210 230,215 200,220 170,215 145,205 130,195Z M280,175 L295,165 310,170 310,185 295,195 280,190Z',\n\t\tlabelXY: [200, 190],\n\t},\n\t{\n\t\tcode: 'CA',\n\t\tname: 'Canada',\n\t\tpath: 'M120,90 L280,85 290,100 295,130 280,150 250,155 200,155 160,155 130,155 115,140 110,115Z',\n\t\tlabelXY: [200, 125],\n\t},\n\t{\n\t\tcode: 'MX',\n\t\tname: 'Mexico',\n\t\tpath: 'M145,215 L200,220 210,235 200,255 185,265 165,260 150,245 140,230Z',\n\t\tlabelXY: [175, 240],\n\t},\n\t{\n\t\tcode: 'BR',\n\t\tname: 'Brazil',\n\t\tpath: 'M270,300 L310,280 335,290 340,320 330,355 310,370 285,365 265,345 260,320Z',\n\t\tlabelXY: [300, 330],\n\t},\n\t{\n\t\tcode: 'AR',\n\t\tname: 'Argentina',\n\t\tpath: 'M260,370 L280,365 290,380 285,410 275,435 260,445 250,425 248,395Z',\n\t\tlabelXY: [268, 410],\n\t},\n\t{\n\t\tcode: 'GB',\n\t\tname: 'United Kingdom',\n\t\tpath: 'M440,120 L448,110 455,115 455,135 448,142 440,138Z',\n\t\tlabelXY: [448, 128],\n\t},\n\t{\n\t\tcode: 'FR',\n\t\tname: 'France',\n\t\tpath: 'M450,145 L470,140 480,150 478,168 465,175 450,170 445,158Z',\n\t\tlabelXY: [463, 158],\n\t},\n\t{\n\t\tcode: 'DE',\n\t\tname: 'Germany',\n\t\tpath: 'M478,125 L498,120 505,130 502,148 490,152 478,148 475,138Z',\n\t\tlabelXY: [490, 138],\n\t},\n\t{\n\t\tcode: 'IT',\n\t\tname: 'Italy',\n\t\tpath: 'M490,155 L498,152 505,162 500,180 492,190 488,178 486,165Z',\n\t\tlabelXY: [495, 172],\n\t},\n\t{\n\t\tcode: 'ES',\n\t\tname: 'Spain',\n\t\tpath: 'M432,168 L460,165 465,175 460,188 442,192 430,185 428,175Z',\n\t\tlabelXY: [448, 180],\n\t},\n\t{\n\t\tcode: 'RU',\n\t\tname: 'Russia',\n\t\tpath: 'M510,60 L780,50 830,70 840,100 820,120 750,115 700,105 650,100 580,105 530,110 510,100 505,80Z',\n\t\tlabelXY: [670, 85],\n\t},\n\t{\n\t\tcode: 'TR',\n\t\tname: 'Turkey',\n\t\tpath: 'M530,165 L570,160 585,170 580,182 555,185 530,180Z',\n\t\tlabelXY: [558, 175],\n\t},\n\t{\n\t\tcode: 'EG',\n\t\tname: 'Egypt',\n\t\tpath: 'M530,200 L555,195 565,205 560,225 545,230 530,222Z',\n\t\tlabelXY: [548, 215],\n\t},\n\t{\n\t\tcode: 'NG',\n\t\tname: 'Nigeria',\n\t\tpath: 'M475,275 L500,270 510,280 505,298 490,302 475,295Z',\n\t\tlabelXY: [492, 288],\n\t},\n\t{\n\t\tcode: 'ZA',\n\t\tname: 'South Africa',\n\t\tpath: 'M520,380 L545,370 560,380 555,400 540,410 520,405 515,392Z',\n\t\tlabelXY: [538, 392],\n\t},\n\t{\n\t\tcode: 'SA',\n\t\tname: 'Saudi Arabia',\n\t\tpath: 'M565,220 L600,210 615,225 610,250 590,258 570,250 560,238Z',\n\t\tlabelXY: [590, 238],\n\t},\n\t{\n\t\tcode: 'IN',\n\t\tname: 'India',\n\t\tpath: 'M640,210 L665,195 685,210 688,240 678,268 660,278 645,265 635,240Z',\n\t\tlabelXY: [662, 240],\n\t},\n\t{\n\t\tcode: 'CN',\n\t\tname: 'China',\n\t\tpath: 'M700,120 L775,115 800,130 805,160 790,180 760,185 730,180 710,168 695,150 690,135Z',\n\t\tlabelXY: [750, 155],\n\t},\n\t{\n\t\tcode: 'JP',\n\t\tname: 'Japan',\n\t\tpath: 'M835,145 L845,135 852,140 850,158 842,165 835,160Z',\n\t\tlabelXY: [843, 152],\n\t},\n\t{\n\t\tcode: 'KR',\n\t\tname: 'South Korea',\n\t\tpath: 'M815,158 L825,152 830,160 827,170 818,172 813,165Z',\n\t\tlabelXY: [822, 163],\n\t},\n\t{\n\t\tcode: 'ID',\n\t\tname: 'Indonesia',\n\t\tpath: 'M740,295 L780,288 810,292 830,298 825,310 790,312 755,308 740,305Z',\n\t\tlabelXY: [785, 302],\n\t},\n\t{\n\t\tcode: 'AU',\n\t\tname: 'Australia',\n\t\tpath: 'M790,350 L850,340 880,355 885,385 870,405 840,410 810,400 790,380Z',\n\t\tlabelXY: [838, 378],\n\t},\n];\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Region bounding-box helpers\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport interface RegionBounds {\n\tminX: number;\n\tminY: number;\n\tmaxX: number;\n\tmaxY: number;\n}\n\nexport function regionBounds(region: RegionDef): RegionBounds {\n\tconst coordinates = region.path.match(/-?\\d+(?:\\.\\d+)?/gu)?.map(Number) ?? [];\n\tconst xs: number[] = [];\n\tconst ys: number[] = [];\n\tfor (let index = 0; index < coordinates.length; index += 2) {\n\t\txs.push(coordinates[index] ?? 0);\n\t\tys.push(coordinates[index + 1] ?? 0);\n\t}\n\treturn {\n\t\tminX: Math.min(...xs),\n\t\tminY: Math.min(...ys),\n\t\tmaxX: Math.max(...xs),\n\t\tmaxY: Math.max(...ys),\n\t};\n}\n\nexport function regionViewBounds(\n\tviewedRegionType: PptxChartRegionMapOptions['viewedRegionType'],\n\tregionValues: ReadonlyMap<string, unknown>,\n): RegionBounds {\n\tif (!viewedRegionType || viewedRegionType === 'world' || regionValues.size === 0) {\n\t\treturn { minX: 0, minY: 0, maxX: 1000, maxY: 500 };\n\t}\n\tconst matched = WORLD_REGIONS.filter((region) => regionValues.has(region.code));\n\tconst targets = viewedRegionType === 'countryRegion' ? matched.slice(0, 1) : matched;\n\tif (targets.length === 0) {\n\t\treturn { minX: 0, minY: 0, maxX: 1000, maxY: 500 };\n\t}\n\tconst bounds = targets.map(regionBounds);\n\tconst padding = 10;\n\treturn {\n\t\tminX: Math.max(0, Math.min(...bounds.map((item) => item.minX)) - padding),\n\t\tminY: Math.max(0, Math.min(...bounds.map((item) => item.minY)) - padding),\n\t\tmaxX: Math.min(1000, Math.max(...bounds.map((item) => item.maxX)) + padding),\n\t\tmaxY: Math.min(500, Math.max(...bounds.map((item) => item.maxY)) + padding),\n\t};\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Path scaling\n// ─────────────────────────────────────────────────────────────────────────────\n\n/**\n * Pre-scale and translate each coordinate pair in a simple SVG path `d`\n * attribute (M/L/Z commands only, space/comma delimited).\n *\n * This avoids needing a `transform` attribute on `SvgPath` which doesn't exist\n * in the existing primitive schema.\n */\nexport function scalePathD(d: string, scale: number, dx: number, dy: number): string {\n\t// Tokenise into command letters and numbers by MATCHING each token type\n\t// directly, rather than splitting on whitespace/comma delimiters: every\n\t// `WORLD_REGIONS` path is written in compact SVG syntax, where a command\n\t// letter directly abuts its first coordinate (\"M130,160\") and the closing\n\t// \"Z\" of one subpath directly abuts the last number before it (\"130,195Z\").\n\t// A delimiter-based split leaves \"M130\" and \"195Z\" as single un-split\n\t// tokens; `parseFloat(\"195Z\")` silently truncates to 195 without ever\n\t// yielding a \"Z\", so the subpath is never closed and every coordinate\n\t// after it pairs up one token late, corrupting the rest of the shape and\n\t// eventually running the loop out of tokens mid-pair, i.e. exactly the\n\t// \"attribute d: Unexpected end of attribute\" the browser reports. Matching\n\t// letters and numbers as their own tokens (instead of splitting the\n\t// string on delimiters) handles both spaced and compact syntax alike.\n\tconst tokens = d.match(/[A-Za-z]|-?\\d+(?:\\.\\d+)?/gu) ?? [];\n\tconst out: string[] = [];\n\tlet i = 0;\n\twhile (i < tokens.length) {\n\t\tconst tok = tokens[i];\n\t\tif (tok === undefined) {\n\t\t\ti++;\n\t\t\tcontinue;\n\t\t}\n\t\t// Command letter (M, L, Z, etc.)\n\t\tif (/^[A-Za-z]$/u.test(tok)) {\n\t\t\tout.push(tok);\n\t\t\ti++;\n\t\t\tcontinue;\n\t\t}\n\t\t// Coordinate pair: tok = x value, tokens[i+1] = y value.\n\t\tconst xRaw = parseFloat(tok);\n\t\tconst yRaw = parseFloat(tokens[i + 1] ?? '');\n\t\tif (!Number.isNaN(xRaw) && !Number.isNaN(yRaw)) {\n\t\t\tout.push(`${(xRaw * scale + dx).toFixed(2)},${(yRaw * scale + dy).toFixed(2)}`);\n\t\t\ti += 2;\n\t\t} else {\n\t\t\tout.push(tok);\n\t\t\ti++;\n\t\t}\n\t}\n\treturn out.join(' ');\n}\n","/**\n * Fallback table for regionMap categories that could not be matched to a\n * known world region (rendered as SVG text rows below the map/legend).\n *\n * Split out of `chart-waterfall-map.ts` (which re-exports the regionMap\n * builder that consumes this) to keep that file's two unrelated chart kinds\n * (waterfall, regionMap) each under the repo's per-file line budget.\n *\n * @module chart-region-map-fallback-table\n */\n\nimport type { SvgRect, SvgText } from './chart-view-model';\nimport { formatAxisValue } from './chart-view-model';\n\n/** Row height (px) used both to size the reserved table area and to draw it. */\nexport const FALLBACK_ROW_HEIGHT = 14;\n\nexport interface UnmatchedRegionRow {\n\tlabel: string;\n\tvalue: number;\n}\n\n/** Height (px) to reserve for the fallback table, or 0 when there is nothing to show. */\nexport function fallbackTableHeight(unmatchedRows: ReadonlyArray<UnmatchedRegionRow>): number {\n\tif (unmatchedRows.length === 0) {\n\t\treturn 0;\n\t}\n\tconst maxFallbackRows = Math.min(unmatchedRows.length, 5);\n\treturn (maxFallbackRows + 1) * FALLBACK_ROW_HEIGHT + 8;\n}\n\n/**\n * Build the \"Additional regions (not shown on map)\" fallback table primitives:\n * a header label, up to 5 alternating-striped rows, and a \"+N more\" footer\n * when there are more than 5 unmatched rows.\n */\nexport function buildRegionMapFallbackTable(\n\tunmatchedRows: ReadonlyArray<UnmatchedRegionRow>,\n\tlegendY: number,\n\tsvgWidth: number,\n\tsvgHeight: number,\n): Array<SvgRect | SvgText> {\n\tif (unmatchedRows.length === 0) {\n\t\treturn [];\n\t}\n\n\tconst primitives: Array<SvgRect | SvgText> = [];\n\tconst maxFallbackRows = Math.min(unmatchedRows.length, 5);\n\tconst tableY = legendY + 26;\n\tconst fontSize = Math.min(8, FALLBACK_ROW_HEIGHT * 0.7);\n\tconst colW = Math.min((svgWidth - 20) / 2, 120);\n\tconst tableX = (svgWidth - colW * 2) / 2;\n\n\tprimitives.push({\n\t\tkind: 'text',\n\t\tx: svgWidth / 2,\n\t\ty: tableY,\n\t\ttext: 'Additional regions (not shown on map)',\n\t\tfontSize: 7,\n\t\tfill: '#94a3b8',\n\t\ttextAnchor: 'middle',\n\t} satisfies SvgText);\n\n\tfor (let i = 0; i < maxFallbackRows; i++) {\n\t\tconst row = unmatchedRows[i];\n\t\tif (row === undefined) {\n\t\t\tcontinue;\n\t\t}\n\t\tconst ry = tableY + FALLBACK_ROW_HEIGHT * (i + 1);\n\t\tif (ry + FALLBACK_ROW_HEIGHT > svgHeight) {\n\t\t\tbreak;\n\t\t}\n\n\t\tif (i % 2 === 0) {\n\t\t\tprimitives.push({\n\t\t\t\tkind: 'rect',\n\t\t\t\tx: tableX,\n\t\t\t\ty: ry - FALLBACK_ROW_HEIGHT + 4,\n\t\t\t\tw: colW * 2,\n\t\t\t\th: FALLBACK_ROW_HEIGHT,\n\t\t\t\tfill: '#f1f5f9',\n\t\t\t\trx: 2,\n\t\t\t} satisfies SvgRect);\n\t\t}\n\n\t\tprimitives.push(\n\t\t\t{\n\t\t\t\tkind: 'text',\n\t\t\t\tx: tableX + 4,\n\t\t\t\ty: ry,\n\t\t\t\ttext: row.label,\n\t\t\t\tfontSize,\n\t\t\t\tfill: '#334155',\n\t\t\t\ttextAnchor: 'start',\n\t\t\t} satisfies SvgText,\n\t\t\t{\n\t\t\t\tkind: 'text',\n\t\t\t\tx: tableX + colW + 4,\n\t\t\t\ty: ry,\n\t\t\t\ttext: formatAxisValue(row.value),\n\t\t\t\tfontSize,\n\t\t\t\tfill: '#475569',\n\t\t\t\ttextAnchor: 'start',\n\t\t\t} satisfies SvgText,\n\t\t);\n\t}\n\n\tif (unmatchedRows.length > 5) {\n\t\tconst moreY = tableY + FALLBACK_ROW_HEIGHT * 6;\n\t\tprimitives.push({\n\t\t\tkind: 'text',\n\t\t\tx: svgWidth / 2,\n\t\t\ty: moreY,\n\t\t\ttext: `+${unmatchedRows.length - 5} more regions`,\n\t\t\tfontSize: 6,\n\t\t\tfill: '#94a3b8',\n\t\t\ttextAnchor: 'middle',\n\t\t} satisfies SvgText);\n\t}\n\n\treturn primitives;\n}\n","/**\n * View-model builder for the regionMap (choropleth) chart kind.\n *\n * Split out of `chart-waterfall-map.ts` (which re-exports this) to keep that\n * file's two unrelated chart kinds (waterfall, regionMap) each under the\n * repo's per-file line budget.\n *\n * Ported from:\n * packages/react/src/viewer/utils/chart-map.tsx\n *\n * RegionMap - choropleth SVG with simplified world region outlines coloured by\n * the first data series; unmatched regions fall back to a table.\n *\n * @module chart-region-map-view\n */\n\nimport type { PptxChartData, PptxElement } from 'pptx-viewer-core';\n\nimport { regionBounds, regionViewBounds, scalePathD, WORLD_REGIONS } from './chart-map-projection';\nimport { resolveRegionCode } from './chart-region-map-alias';\nimport {\n\tbuildRegionMapColorLegend,\n\tnormalizeValue,\n\tsequentialColorScale,\n} from './chart-region-map-colors';\nimport {\n\tbuildRegionMapEntries,\n\tbuildValueColorScale,\n\tformatRegionMapValue,\n\tresolveValueColorStops,\n\tshouldRenderRegionLabel,\n} from './chart-region-map-data';\nimport {\n\tbuildRegionMapFallbackTable,\n\tfallbackTableHeight,\n} from './chart-region-map-fallback-table';\nimport type { UnmatchedRegionRow } from './chart-region-map-fallback-table';\nimport type { ChartValueDrag, ChartViewModel, SvgPath, SvgRect, SvgText } from './chart-view-model';\nimport { formatAxisValue } from './chart-view-model';\n\n/**\n * Build the view-model for a regionMap (choropleth) chart.\n *\n * Matches category labels against known world regions, colours them by the\n * first series' values using a sequential blue colour scale, and renders a\n * simple colour-legend bar below the map. Unmatched regions are collected\n * into a small fallback table rendered as SVG text rows.\n *\n * Mirrors `renderMapChart` in React's `chart-map.tsx`.\n */\nexport function buildRegionMapViewModel(\n\telement: PptxElement,\n\tchartData: PptxChartData,\n\tcategoryLabels: ReadonlyArray<string>,\n): ChartViewModel {\n\t// Match the element frame exactly; bindings stretch the viewBox with\n\t// preserveAspectRatio \"none\", so a minimum would scale non-uniformly.\n\tconst svgWidth = Math.max(element.width, 1);\n\tconst svgHeight = Math.max(element.height, 1);\n\n\tconst categories = categoryLabels.length > 0 ? categoryLabels : chartData.categories;\n\tconst series = chartData.series[0];\n\tconst options = series?.regionMapOptions;\n\tconst entries = buildRegionMapEntries(\n\t\tcategories,\n\t\tseries?.values ?? [],\n\t\toptions,\n\t\tresolveRegionCode,\n\t);\n\tconst values = entries.map((entry) => entry.value);\n\n\tconst finiteVals = values.filter((v) => Number.isFinite(v));\n\tconst minVal = finiteVals.length > 0 ? Math.min(...finiteVals) : 0;\n\tconst maxVal = finiteVals.length > 0 ? Math.max(...finiteVals) : 1;\n\t// cx:valueColors/cx:valueColorPositions: a chart-authored 2-3 stop\n\t// gradient the region-map colours by value, instead of the fixed\n\t// blue sequential scale. Falls back to that scale when the chart\n\t// authors no value-color gradient (the common case).\n\tconst valueColorStops = resolveValueColorStops(\n\t\toptions?.valueColors,\n\t\toptions?.valueColorPositions,\n\t\tminVal,\n\t\tmaxVal,\n\t);\n\tconst colorScale = valueColorStops ? buildValueColorScale(valueColorStops) : sequentialColorScale;\n\n\t// Build region -> value lookup.\n\tconst regionValueMap = new Map<string, { value: number; label: string; sourceIndex: number }>();\n\tconst unmatchedRows: UnmatchedRegionRow[] = [];\n\n\tfor (const entry of entries) {\n\t\tif (entry.code !== undefined) {\n\t\t\tregionValueMap.set(entry.code, {\n\t\t\t\tvalue: entry.value,\n\t\t\t\tlabel: entry.label,\n\t\t\t\tsourceIndex: entry.sourceIndex,\n\t\t\t});\n\t\t} else {\n\t\t\tunmatchedRows.push({ label: entry.label, value: entry.value });\n\t\t}\n\t}\n\n\t// Layout measurements.\n\tconst legendHeight = 30;\n\tconst fallbackTableH = fallbackTableHeight(unmatchedRows);\n\tconst titleH = chartData.title ? 22 : 0;\n\tconst mapAreaH = Math.max(svgHeight - titleH - legendHeight - fallbackTableH - 8, 80);\n\n\tconst viewBounds = regionViewBounds(options?.viewedRegionType, regionValueMap);\n\tconst viewWidth = Math.max(viewBounds.maxX - viewBounds.minX, 1);\n\tconst viewHeight = Math.max(viewBounds.maxY - viewBounds.minY, 1);\n\tconst mapScale = Math.min((svgWidth - 20) / viewWidth, mapAreaH / viewHeight);\n\tconst mapOffsetX = (svgWidth - viewWidth * mapScale) / 2 - viewBounds.minX * mapScale;\n\tconst mapOffsetY = titleH + 4 - viewBounds.minY * mapScale;\n\n\tconst primitives: Array<SvgPath | SvgRect | SvgText> = [];\n\n\t// Background.\n\tprimitives.push({\n\t\tkind: 'rect',\n\t\tx: 0,\n\t\ty: 0,\n\t\tw: svgWidth,\n\t\th: svgHeight,\n\t\tfill: '#f8fafc',\n\t\trx: 4,\n\t} satisfies SvgRect);\n\n\t// Title text.\n\tconst titlePrimitive: SvgText | undefined = chartData.title\n\t\t? {\n\t\t\t\tkind: 'text',\n\t\t\t\tx: svgWidth / 2,\n\t\t\t\ty: 16,\n\t\t\t\ttext: chartData.title,\n\t\t\t\tfontSize: 12,\n\t\t\t\tfill: '#334155',\n\t\t\t\ttextAnchor: 'middle',\n\t\t\t\tfontWeight: 'bold',\n\t\t\t\tdominantBaseline: 'auto',\n\t\t\t}\n\t\t: undefined;\n\n\t// Region shape paths.\n\tfor (const region of WORLD_REGIONS) {\n\t\tconst entry = regionValueMap.get(region.code);\n\t\tlet fill = '#e2e8f0';\n\n\t\tif (entry !== undefined) {\n\t\t\tconst t = normalizeValue(entry.value, minVal, maxVal);\n\t\t\tfill = colorScale(t);\n\t\t}\n\n\t\t// Embed the transform in the path's d attribute via a manual coordinate\n\t\t// scale+translate since SvgPath has no transform field. We replicate\n\t\t// React's `transform=\"translate(mapOffsetX,mapOffsetY) scale(mapScale)\"`\n\t\t// by pre-scaling every coordinate pair in the path string.\n\t\tconst scaledPath = scalePathD(region.path, mapScale, mapOffsetX, mapOffsetY);\n\n\t\tprimitives.push({\n\t\t\tkind: 'path',\n\t\t\td: scaledPath,\n\t\t\tfill,\n\t\t\tstroke: '#94a3b8',\n\t\t\tstrokeWidth: Math.max(0.5 / mapScale, 0.3),\n\t\t\t// Hover tooltip. A choropleth prints only the value inside the shape\n\t\t\t// (and only where the shape is big enough), so without this the reader\n\t\t\t// has no way to find out WHICH country a patch of colour is.\n\t\t\ttitle: entry ? `${region.name}: ${formatAxisValue(entry.value)}` : region.name,\n\t\t\t...(entry\n\t\t\t\t? {\n\t\t\t\t\t\tpart: {\n\t\t\t\t\t\t\trole: 'dataPoint' as const,\n\t\t\t\t\t\t\tseriesIndex: 0,\n\t\t\t\t\t\t\tpointIndex: entry.sourceIndex,\n\t\t\t\t\t\t},\n\t\t\t\t\t}\n\t\t\t\t: {}),\n\t\t} satisfies SvgPath);\n\n\t\t// Inline data label for matched regions.\n\t\tconst bounds = regionBounds(region);\n\t\tif (\n\t\t\tentry !== undefined &&\n\t\t\tshouldRenderRegionLabel(\n\t\t\t\toptions?.regionLabelLayout,\n\t\t\t\t(bounds.maxX - bounds.minX) * mapScale,\n\t\t\t\t(bounds.maxY - bounds.minY) * mapScale,\n\t\t\t)\n\t\t) {\n\t\t\tconst lx = region.labelXY[0] * mapScale + mapOffsetX;\n\t\t\tconst ly = region.labelXY[1] * mapScale + mapOffsetY + 4;\n\t\t\tprimitives.push({\n\t\t\t\tkind: 'text',\n\t\t\t\tx: lx,\n\t\t\t\ty: ly,\n\t\t\t\ttext: formatRegionMapValue(entry.value, options?.cultureLanguage),\n\t\t\t\tfontSize: Math.max(6, 7 * mapScale),\n\t\t\t\tfill: '#1e293b',\n\t\t\t\ttextAnchor: 'middle',\n\t\t\t\tfontWeight: 'bold',\n\t\t\t\tdominantBaseline: 'central',\n\t\t\t} satisfies SvgText);\n\t\t}\n\t}\n\n\t// Colour legend bar, min/max labels, and optional attribution.\n\tconst legendY = mapOffsetY + mapAreaH + 4;\n\tprimitives.push(\n\t\t...buildRegionMapColorLegend({\n\t\t\tsvgWidth,\n\t\t\tsvgHeight,\n\t\t\tlegendY,\n\t\t\tminVal,\n\t\t\tmaxVal,\n\t\t\tcolorScale,\n\t\t\tattribution: options?.attribution,\n\t\t}),\n\t);\n\n\t// Fallback table for unmatched regions.\n\tprimitives.push(...buildRegionMapFallbackTable(unmatchedRows, legendY, svgWidth, svgHeight));\n\n\tconst dataLabels: SvgText[] = titlePrimitive !== undefined ? [titlePrimitive] : [];\n\n\t// A region's value is a plain number driving the colour scale, with no\n\t// vertical pixel position of its own (unlike a bar/line mark, or even a\n\t// surface cell's grid row), so there is no \"up\" a region already visually\n\t// sits toward. Rather than declare drag meaningless, this reuses the exact\n\t// generic vertical-drag contract every other kind uses (`chart-canvas-drag.ts`\n\t// only ever needs a pixel range + `ValueRange`, never an actual mark\n\t// position): the drag maps top-of-map/bottom-of-map to the current\n\t// max/min value, matching the legend bar's own gradient direction, so a\n\t// region dragged to the top of the map reads its value up toward the\n\t// legend's high end, and to the bottom toward its low end.\n\tconst valueDrag: ChartValueDrag = {\n\t\trange: { min: minVal, max: maxVal, span: Math.max(maxVal - minVal, Number.EPSILON) },\n\t\tplotTop: mapOffsetY,\n\t\tplotBottom: mapOffsetY + mapAreaH,\n\t};\n\n\treturn {\n\t\tsvgWidth,\n\t\tsvgHeight,\n\t\ttitle: undefined, // Rendered inline as a dataLabel text primitive above.\n\t\ttitleX: svgWidth / 2,\n\t\ttitleY: 14,\n\t\tgridlines: [],\n\t\taxisLabels: [],\n\t\tzeroLine: undefined,\n\t\tcategoryLabels: [],\n\t\tprimitives,\n\t\tdataLabels,\n\t\tlegend: [],\n\t\tlegendX: svgWidth / 2,\n\t\tlegendY: svgHeight - 8,\n\t\tlegendAnchor: 'middle',\n\t\tvalueDrag,\n\t};\n}\n","import type { PptxChartWaterfallOptions } from 'pptx-viewer-core';\n\nimport type { ValueRange } from './chart-view-model';\nimport { computeValueRange } from './chart-view-model';\n\nexport interface WaterfallStep {\n\tsourceIndex: number;\n\tvalue: number;\n\tstartValue: number;\n\tendValue: number;\n\tisSubtotal: boolean;\n}\n\n/** Resolve ChartEx waterfall deltas and absolute subtotal bars. */\nexport function buildWaterfallSteps(\n\tvalues: ReadonlyArray<number>,\n\toptions: PptxChartWaterfallOptions | undefined,\n): WaterfallStep[] {\n\tconst subtotalIndices = new Set(\n\t\toptions?.subtotalIndices ?? (values.length > 0 ? [values.length - 1] : []),\n\t);\n\tconst steps: WaterfallStep[] = [];\n\tlet runningTotal = 0;\n\tfor (let sourceIndex = 0; sourceIndex < values.length; sourceIndex++) {\n\t\tconst value = values[sourceIndex] ?? 0;\n\t\tconst isSubtotal = subtotalIndices.has(sourceIndex);\n\t\tconst startValue = isSubtotal ? 0 : runningTotal;\n\t\tconst endValue = isSubtotal ? value : runningTotal + value;\n\t\tsteps.push({ sourceIndex, value, startValue, endValue, isSubtotal });\n\t\trunningTotal = endValue;\n\t}\n\treturn steps;\n}\n\n/**\n * Compute a value range containing every cumulative and absolute bar endpoint.\n *\n * @param plotHeightPx The chart's plot-area height, when known; see\n * `axisTargetIntervals`'s doc comment for why this changes the automatic\n * scale's gridline count.\n */\nexport function computeWaterfallRange(\n\tsteps: ReadonlyArray<WaterfallStep>,\n\tplotHeightPx?: number,\n): ValueRange {\n\treturn computeValueRange(\n\t\t[\n\t\t\t{\n\t\t\t\tname: 'Waterfall range',\n\t\t\t\tvalues: steps.flatMap((step) => [step.startValue, step.endValue]),\n\t\t\t},\n\t\t],\n\t\tplotHeightPx,\n\t);\n}\n","/**\n * View-model builder for the waterfall chart kind.\n *\n * Split out of `chart-waterfall-map.ts` (which re-exports this) to keep that\n * file's two unrelated chart kinds (waterfall, regionMap) each under the\n * repo's per-file line budget.\n *\n * Ported from:\n * packages/react/src/viewer/utils/chart-waterfall-combo.tsx (waterfall only)\n *\n * Waterfall - running-total bars with positive/negative/total colouring and\n * dashed connector lines between bars.\n *\n * @module chart-waterfall-view\n */\n\nimport type { PptxChartData, PptxElement } from 'pptx-viewer-core';\n\nimport { resolveChartTitleText } from './chart-auto-title';\nimport { findValueAxis, buildValueAxisGridlinesAndLabels } from './chart-cx-axis-units';\nimport { dataLabelFontOverride, resolveDataLabelTextStyle } from './chart-data-label-text';\nimport { DEFAULT_CHART_DATA_LABEL_PX } from './chart-font';\nimport { resolveLegendAnchorPosition } from './chart-legend-build';\nimport type { ChartViewModel, LegendEntry, SvgLine, SvgRect, SvgText } from './chart-view-model';\nimport {\n\tbuildZeroLine,\n\tbuildCategoryLabels,\n\tcomputePlotLayout,\n\tformatAxisValue,\n\tvalueToY,\n} from './chart-view-model';\nimport { paletteColor } from './chart-view-model-scale';\nimport { buildWaterfallSteps, computeWaterfallRange } from './chart-waterfall-layout';\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Waterfall colours: PowerPoint paints the three bar roles with the chart's\n// first three palette colours, Increase / Decrease / Total (COM-verified,\n// charts-com.pptx slide 26: #156082 / #E97132 / #196B24, the Office 2023\n// theme's accent1..3). The legend below uses the same three, in this order.\n// ─────────────────────────────────────────────────────────────────────────────\n\nconst WF_CONNECTOR_COLOR = '#94a3b8';\n\n/** The Increase / Decrease / Total colours for a waterfall's palette. */\nexport function waterfallRoleColors(colorPalette: readonly string[] | undefined): {\n\tincrease: string;\n\tdecrease: string;\n\ttotal: string;\n} {\n\treturn {\n\t\tincrease: paletteColor(0, colorPalette),\n\t\tdecrease: paletteColor(1, colorPalette),\n\t\ttotal: paletteColor(2, colorPalette),\n\t};\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Public: buildWaterfallViewModel\n// ─────────────────────────────────────────────────────────────────────────────\n\n/**\n * Build the view-model for a waterfall chart.\n *\n * Each bar starts from the running total of all previous values; the last bar\n * shows the grand total (reset to 0 base). Positive values get a green fill,\n * negative values get a red fill, and the final total bar uses indigo.\n * Dashed connector lines join adjacent bar tops/bottoms.\n *\n * Mirrors `renderWaterfallChart` in React's `chart-waterfall-combo.tsx`.\n */\nexport function buildWaterfallViewModel(\n\telement: PptxElement,\n\tchartData: PptxChartData,\n\tcategoryLabels: ReadonlyArray<string>,\n): ChartViewModel {\n\tconst layout = computePlotLayout(element.width, element.height, chartData, true);\n\tconst series = chartData.series[0];\n\tconst values = series?.values ?? [];\n\tconst steps = buildWaterfallSteps(values, series?.waterfallOptions);\n\tconst range = computeWaterfallRange(steps, layout.autoPlotHeight);\n\tconst catCount = Math.max(categoryLabels.length, values.length, 1);\n\n\tconst barWidth = (layout.plotWidth / catCount) * 0.6;\n\tconst gap = (layout.plotWidth / catCount) * 0.2;\n\n\tconst roles = waterfallRoleColors(chartData.colorPalette);\n\tconst primitives: Array<SvgRect | SvgLine> = [];\n\tconst dataLabels: SvgText[] = [];\n\n\tfor (const step of steps) {\n\t\tconst { sourceIndex, value, startValue, endValue, isSubtotal } = step;\n\t\tconst barStartY = valueToY(startValue, range, layout.plotTop, layout.plotBottom);\n\t\tconst barEndY = valueToY(endValue, range, layout.plotTop, layout.plotBottom);\n\t\tconst i = sourceIndex;\n\t\tconst x = layout.plotLeft + (layout.plotWidth / catCount) * i + gap;\n\t\tconst y = Math.min(barStartY, barEndY);\n\t\tconst h = Math.max(Math.abs(barEndY - barStartY), 1);\n\t\tconst barColor = isSubtotal ? roles.total : value >= 0 ? roles.increase : roles.decrease;\n\n\t\tprimitives.push({\n\t\t\tkind: 'rect',\n\t\t\tx,\n\t\t\ty,\n\t\t\tw: barWidth,\n\t\t\th,\n\t\t\tfill: barColor,\n\t\t\trx: 1,\n\t\t\tpart: { role: 'dataPoint', seriesIndex: 0, pointIndex: sourceIndex },\n\t\t} satisfies SvgRect);\n\n\t\tif (chartData.style?.hasDataLabels) {\n\t\t\tdataLabels.push({\n\t\t\t\tkind: 'text',\n\t\t\t\tx: x + barWidth / 2,\n\t\t\t\ty: y - 4,\n\t\t\t\ttext: formatAxisValue(value),\n\t\t\t\tfontSize: DEFAULT_CHART_DATA_LABEL_PX,\n\t\t\t\tfill: '#334155',\n\t\t\t\ttextAnchor: 'middle',\n\t\t\t\t...(series\n\t\t\t\t\t? dataLabelFontOverride(resolveDataLabelTextStyle(chartData, series, sourceIndex))\n\t\t\t\t\t: {}),\n\t\t\t} satisfies SvgText);\n\t\t}\n\n\t\t// Connector line to the next bar (not drawn after the last bar).\n\t\tif (series?.waterfallOptions?.connectorLines !== false && i < values.length - 1) {\n\t\t\tconst nextX = layout.plotLeft + (layout.plotWidth / catCount) * (i + 1) + gap;\n\t\t\tprimitives.push({\n\t\t\t\tkind: 'line',\n\t\t\t\tx1: x + barWidth,\n\t\t\t\ty1: barEndY,\n\t\t\t\tx2: nextX,\n\t\t\t\ty2: barEndY,\n\t\t\t\tstroke: WF_CONNECTOR_COLOR,\n\t\t\t\tstrokeWidth: 0.8,\n\t\t\t\tdashArray: '3 2',\n\t\t\t} satisfies SvgLine);\n\t\t}\n\t}\n\n\tconst { gridlines, axisLabels } = buildValueAxisGridlinesAndLabels(\n\t\trange,\n\t\tlayout,\n\t\tfindValueAxis(chartData.axes),\n\t);\n\tconst zeroLine = buildZeroLine(range, layout);\n\tconst catLabels = buildCategoryLabels(categoryLabels, layout, 'bar');\n\n\t// A waterfall's legend always lists its three fixed bar roles, never the\n\t// authored series (there is exactly one, and it never appears by name):\n\t// COM-verified against charts-com.pptx slide 26, whose legend reads\n\t// \"Increase / Decrease / Total\" in that order and colour.\n\tconst legendPos = chartData.style?.legendPosition ?? 'b';\n\tconst legend: LegendEntry[] = [\n\t\t{ color: roles.increase, label: 'Increase' },\n\t\t{ color: roles.decrease, label: 'Decrease' },\n\t\t{ color: roles.total, label: 'Total' },\n\t];\n\tconst { legendX, legendY, legendAnchor } = resolveLegendAnchorPosition(\n\t\tlayout.svgWidth,\n\t\tlayout.svgHeight,\n\t\tlayout.plotTop,\n\t\tlegendPos,\n\t);\n\n\tconst title = resolveChartTitleText(chartData);\n\n\treturn {\n\t\tsvgWidth: layout.svgWidth,\n\t\tsvgHeight: layout.svgHeight,\n\t\ttitle,\n\t\ttitleX: layout.svgWidth / 2,\n\t\ttitleY: 12,\n\t\tgridlines,\n\t\taxisLabels,\n\t\tzeroLine,\n\t\tcategoryLabels: catLabels,\n\t\tprimitives,\n\t\tdataLabels,\n\t\tlegend: chartData.style?.hasLegend ? legend : [],\n\t\tlegendX,\n\t\tlegendY,\n\t\tlegendAnchor,\n\t};\n}\n","/**\n * chart-view-model-build.ts: `buildChartViewModel` and the post-passes every\n * chart kind's view-model goes through (legend entries, area fills, user-shape\n * overlay, manual layouts). Split out of `chart-view-model.ts`, which\n * re-exports everything here.\n *\n * @module chart-view-model-build\n */\n/* eslint-disable one-var -- this module predates the rule and combining every\n sibling `const`/`let` in a function into one comma-list (oxlint's own\n `--fix` cannot do this safely once a non-declaration statement sits between\n them) would churn geometry code far beyond this change's scope. */\n\nimport type { ChartPptxElement, PptxChartData, PptxElement } from 'pptx-viewer-core';\n\nimport { applyChart3DDepth } from './chart-3d-depth';\nimport { chartAreaCornerRadius, chartAreaFill, plotAreaFill } from './chart-area-fill';\nimport { withAutoTitle } from './chart-auto-title';\nimport { buildCartesianViewModel } from './chart-cartesian';\nimport { buildComboViewModel, buildStockViewModel } from './chart-combo-stock';\nimport { labelsBesideTable } from './chart-data-table-metrics';\nimport { applyDataPointPictureFills } from './chart-datapoint-picture-fills';\nimport { buildBoxWhiskerViewModel, buildHistogramViewModel } from './chart-distribution';\nimport { buildFunnelViewModel, buildSunburstViewModel } from './chart-funnel-sunburst';\nimport { withGradientFills } from './chart-gradient-defs';\nimport { splitLabelLines } from './chart-label-lines';\nimport { applyLegendEntryOverrides } from './chart-legend-entries';\nimport { manualLayoutOf } from './chart-manual-layout';\nimport { buildOfPieViewModel } from './chart-ofpie';\nimport { buildSurfaceViewModel, buildTreemapViewModel } from './chart-surface-treemap';\nimport { withChartTitleBand } from './chart-title-band';\nimport { resolveChartTitleRunSpans } from './chart-title-runs';\nimport { fitTitleBand, resolveChartTitleTextStyle } from './chart-title-style';\nimport { buildChartUserShapeOverlay } from './chart-user-shape-overlay';\nimport { resolveChartKind } from './chart-view-model-kinds';\nimport type { SupportedChartKind } from './chart-view-model-kinds';\nimport { withManualLayouts } from './chart-view-model-manual';\nimport { buildFallbackViewModel, buildPieViewModel } from './chart-view-model-pie';\nimport { computePieLayout } from './chart-view-model-points';\nimport { buildRadarViewModel } from './chart-view-model-radar';\nimport type { ChartViewModel } from './chart-view-model-types';\nimport { buildRegionMapViewModel, buildWaterfallViewModel } from './chart-waterfall-map';\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Main view-model builder\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport function buildChartViewModel(element: PptxElement): ChartViewModel {\n\tconst vm = buildChartViewModelInner(element);\n\t// A label with a line break (a \"\\n\" `c:separator`) paints as one `<text>` per\n\t// line in every binding; single-line labels pass through untouched.\n\treturn vm.dataLabels.some((label) => label.text.includes('\\n'))\n\t\t? { ...vm, dataLabels: vm.dataLabels.flatMap(splitLabelLines) }\n\t\t: vm;\n}\n\nfunction buildChartViewModelInner(element: PptxElement): ChartViewModel {\n\tif (element.type !== 'chart') {\n\t\treturn buildFallbackViewModel(element.width, element.height, 'Chart');\n\t}\n\tconst chartEl = element as ChartPptxElement,\n\t\tchartData = chartEl.chartData ? withAutoTitle(chartEl.chartData) : chartEl.chartData;\n\n\tif (!chartData || chartData.series.length === 0) {\n\t\treturn buildFallbackViewModel(element.width, element.height, chartData?.title ?? 'Chart');\n\t}\n\n\tconst chartType = chartData.chartType ?? 'bar',\n\t\tkind = resolveChartKind(chartType);\n\n\tif (kind === 'unsupported') {\n\t\treturn buildFallbackViewModel(element.width, element.height, chartData.title ?? chartType);\n\t}\n\n\tconst longestLen = chartData.series.reduce((m, s) => Math.max(m, s.values.length), 0),\n\t\tcategoryLabels =\n\t\t\tchartData.categories.length > 0\n\t\t\t\t? chartData.categories\n\t\t\t\t: Array.from({ length: longestLen }, (_, i) => String(i + 1));\n\n\t// Pie-of-pie / bar-of-pie splits one series across a primary + secondary plot.\n\tif (chartType === 'ofPie') {\n\t\treturn finishViewModel(\n\t\t\tbuildOfPieViewModel(element, chartData, categoryLabels),\n\t\t\tchartData,\n\t\t\telement,\n\t\t);\n\t}\n\n\t// 3D chart kinds keep their flat geometry but get an oblique depth pass driven\n\t// by c:view3D so they read as 3D instead of collapsing to a flat plot.\n\tconst flat = buildFlatViewModel(element, chartData, categoryLabels, kind);\n\tif (is3DChartType(chartType)) {\n\t\t// pie3D's ellipse tilt foreshortens about the same centre buildPieViewModel\n\t\t// laid the slices out from (doughnut3D does not exist in OOXML, so this is\n\t\t// always a hole-less pie layout).\n\t\tlet pieCenter: { cx: number; cy: number } | undefined;\n\t\tif (chartType === 'pie3D') {\n\t\t\tconst pieLayout = computePieLayout(element.width, element.height, chartData, false);\n\t\t\tpieCenter = { cx: pieLayout.cx, cy: pieLayout.cy };\n\t\t}\n\t\tconst walls = {\n\t\t\tfloor: chartData.floor,\n\t\t\tsideWall: chartData.sideWall,\n\t\t\tbackWall: chartData.backWall,\n\t\t};\n\t\t// bar3D's oblique-projection side/end extrusion faces resolve their OWN\n\t\t// picture-fill targeting (`c:applyToSides`/`c:applyToEnd`), independent of\n\t\t// the front rect's (`withDataPointPictureFills` below); see\n\t\t// `chart-3d-depth.ts`'s `barExtrusion`.\n\t\tconst bar3DPicture =\n\t\t\tchartType === 'bar3D' ? { series: chartData.series, elementId: element.id } : undefined;\n\t\treturn finishViewModel(\n\t\t\tapplyChart3DDepth(\n\t\t\t\tflat,\n\t\t\t\tchartType,\n\t\t\t\tchartData.view3D,\n\t\t\t\twalls,\n\t\t\t\tchartData.grouping,\n\t\t\t\tpieCenter,\n\t\t\t\tbar3DPicture,\n\t\t\t),\n\t\t\tchartData,\n\t\t\telement,\n\t\t);\n\t}\n\treturn finishViewModel(flat, chartData, element);\n}\n\n/**\n * The post-passes every chart kind's view-model goes through, in order: the\n * font-sized title baseline (`chart-title-band.ts`), the `c:manualLayout`\n * title / legend re-anchoring (on those automatic anchors), the `c:userShapes` overlay, the chart / plot area fills, and the\n * `c:legendEntry` overrides.\n */\nfunction finishViewModel(\n\tvm: ChartViewModel,\n\tchartData: PptxChartData,\n\tframe: { id: string; width: number; height: number },\n): ChartViewModel {\n\treturn withLegendEntries(\n\t\twithGradientFills(\n\t\t\twithChartAreaFill(\n\t\t\t\twithDataPointPictureFills(\n\t\t\t\t\twithUserShapeOverlay(\n\t\t\t\t\t\twithManualLayouts(withChartTitleBand(vm, chartData), chartData, frame),\n\t\t\t\t\t\tchartData,\n\t\t\t\t\t),\n\t\t\t\t\tchartData,\n\t\t\t\t\tframe.id,\n\t\t\t\t),\n\t\t\t\tchartData,\n\t\t\t),\n\t\t\tchartData,\n\t\t\tframe.id,\n\t\t),\n\t\tchartData,\n\t);\n}\n\n/**\n * Rewrite data-point rects with a `c:dPt/c:pictureOptions` picture fill to\n * `url(#...)` and attach the `<pattern>` defs a binding must render for it\n * (C2-G9 render half). Runs after the user-shape overlay so overlay\n * primitives (which carry no `part`) are never mistaken for data points, and\n * before the legend/area-fill passes since those don't touch `primitives`.\n */\nfunction withDataPointPictureFills(\n\tvm: ChartViewModel,\n\tchartData: PptxChartData,\n\telementId: string,\n): ChartViewModel {\n\tconst { primitives, defs } = applyDataPointPictureFills(chartData, elementId, vm.primitives);\n\tif (defs.length === 0) {\n\t\treturn vm;\n\t}\n\treturn { ...vm, primitives, defs: [...(vm.defs ?? []), ...defs] };\n}\n\n/**\n * Apply `c:legendEntry` deletion + text-style overrides to a finished\n * view-model's legend. The single call site every chart kind's `vm.legend`\n * passes through before returning from `buildChartViewModel`; see\n * `chart-legend-entries.ts`.\n */\nfunction withLegendEntries(vm: ChartViewModel, chartData: PptxChartData): ChartViewModel {\n\tconst legend = applyLegendEntryOverrides(\n\t\tvm.legend,\n\t\tchartData.style?.legendEntries,\n\t\tchartData.style?.legendTextStyle,\n\t);\n\treturn legend === vm.legend ? vm : { ...vm, legend };\n}\n\n/**\n * Stamp the resolved chart-area / plot-area fills onto a finished view-model so\n * every binding paints (or skips) the same background rect. A chart that\n * declares `<a:noFill/>` gets `areaFill: undefined` and no rect at all.\n */\nfunction withChartAreaFill(vm: ChartViewModel, chartData: PptxChartData): ChartViewModel {\n\tconst titleRunSpans = resolveChartTitleRunSpans(chartData);\n\tconst titleStyle = resolveChartTitleTextStyle(chartData);\n\treturn {\n\t\t...vm,\n\t\t// The kinds lay the title baseline out for a 12px title; a style-part\n\t\t// title (18.62pt in every built-in style, e.g. PowerPoint's auto\n\t\t// \"Chart Title\") would otherwise poke out of the top of the chart.\n\t\t...(manualLayoutOf(chartData, 'title') ? {} : fitTitleBand(vm, titleStyle.fontSize)),\n\t\tcategoryLabels: labelsBesideTable(chartData, { labels: vm.categoryLabels }),\n\t\tareaFill: chartAreaFill(chartData),\n\t\tareaRadius: chartAreaCornerRadius(chartData),\n\t\ttitleStyle,\n\t\t...(titleRunSpans ? { titleRunSpans } : {}),\n\t\tplotFill: plotAreaFill(chartData),\n\t};\n}\n\n/**\n * Append the chart's `c:userShapes` drawing overlay to a finished view-model.\n *\n * The overlay primitives are positioned in the same SVG coordinate space as the\n * chart (`svgWidth` x `svgHeight`) and layered last so they sit above the data\n * marks. Returns the view-model unchanged when the chart has no overlay.\n */\nfunction withUserShapeOverlay(vm: ChartViewModel, chartData: PptxChartData): ChartViewModel {\n\tconst overlay = buildChartUserShapeOverlay(chartData.userShapes, vm.svgWidth, vm.svgHeight);\n\tif (overlay.length === 0) {\n\t\treturn vm;\n\t}\n\treturn {\n\t\t...vm,\n\t\tprimitives: [...vm.primitives, ...overlay],\n\t\tuserShapes: overlay,\n\t};\n}\n\n/** Whether a chart type carries an inherent 3D depth treatment. */\nfunction is3DChartType(chartType: string): boolean {\n\treturn (\n\t\tchartType === 'bar3D' ||\n\t\tchartType === 'pie3D' ||\n\t\tchartType === 'line3D' ||\n\t\tchartType === 'area3D'\n\t);\n}\n\n/** Build the flat (2D) view-model for a resolved chart kind. */\nfunction buildFlatViewModel(\n\telement: PptxElement,\n\tchartData: PptxChartData,\n\tcategoryLabels: ReadonlyArray<string>,\n\tkind: SupportedChartKind,\n): ChartViewModel {\n\tif (kind === 'pie' || kind === 'doughnut') {\n\t\treturn buildPieViewModel(element, chartData, categoryLabels, kind === 'doughnut');\n\t}\n\n\tif (kind === 'radar') {\n\t\treturn buildRadarViewModel(element, chartData, categoryLabels);\n\t}\n\n\tif (kind === 'combo') {\n\t\treturn buildComboViewModel(element, chartData, categoryLabels);\n\t}\n\tif (kind === 'stock') {\n\t\treturn buildStockViewModel(element, chartData, categoryLabels);\n\t}\n\tif (kind === 'surface') {\n\t\treturn buildSurfaceViewModel(element, chartData, categoryLabels);\n\t}\n\tif (kind === 'treemap') {\n\t\treturn buildTreemapViewModel(element, chartData, categoryLabels);\n\t}\n\tif (kind === 'waterfall') {\n\t\treturn buildWaterfallViewModel(element, chartData, categoryLabels);\n\t}\n\tif (kind === 'regionMap') {\n\t\treturn buildRegionMapViewModel(element, chartData, categoryLabels);\n\t}\n\tif (kind === 'funnel') {\n\t\treturn buildFunnelViewModel(element, chartData, categoryLabels);\n\t}\n\tif (kind === 'sunburst') {\n\t\treturn buildSunburstViewModel(element, chartData, categoryLabels);\n\t}\n\tif (kind === 'histogram') {\n\t\treturn buildHistogramViewModel(element, chartData, categoryLabels);\n\t}\n\tif (kind === 'boxWhisker') {\n\t\treturn buildBoxWhiskerViewModel(element, chartData, categoryLabels);\n\t}\n\n\treturn buildCartesianViewModel(element, chartData, categoryLabels, kind);\n}\n","/**\n * chart-axis-render.ts: value-axis gridline + label primitive builders that\n * honour the richer cartesian axis features (log scale, display units, and a\n * secondary right-side value axis).\n *\n * These complement the linear single-axis `buildGridlinesAndLabels` in\n * `chart-view-model.ts`. They are pure and reuse the existing axis maths in\n * `chart-axis.ts` (`generateLogTicks`, `formatAxisValueWithUnits`,\n * `getDisplayUnitLabel`) and the shared `valueToY` / `formatAxisValue`.\n *\n * @module chart-axis-render\n */\nimport type { PptxChartAxisFormatting } from 'pptx-viewer-core';\n\nimport {\n\tformatAxisValueWithUnits,\n\tgenerateAxisTicks,\n\tgenerateMinorAxisTicks,\n\tgetDisplayUnitLabel,\n\tunitsCaptionOffset,\n} from './chart-axis';\nimport {\n\tbuildStyledGridline,\n\tbuildVerticalAxisLine,\n\tbuildVerticalTickMark,\n} from './chart-axis-primitives';\nimport { chartAxisTextStyle, unitsLabelTextStyle } from './chart-axis-style';\nimport type { PlotLayout, SvgLine, SvgText, ValueRange } from './chart-view-model';\nimport { formatAxisValue, valueToY } from './chart-view-model';\n\nconst GRIDLINE_COLOR = '#e2e8f0';\nconst SECONDARY_GRID_COLOR = '#e2e8f0';\nconst TICK_COUNT = 5;\nconst MAJOR_TICK_LENGTH = 4;\nconst MINOR_TICK_LENGTH = 2.5;\n\ntype VerticalAxisSide = 'left' | 'right';\n\n/** Resolve label placement at the low or high side of a vertical chart axis. */\nfunction valueAxisLabelPlacement(\n\tlayout: PlotLayout,\n\tposition: PptxChartAxisFormatting['tickLblPos'],\n\tdefaultSide: VerticalAxisSide,\n\taxisX: number,\n): Pick<SvgText, 'x' | 'textAnchor'> {\n\tif (!position || position === 'nextTo') {\n\t\treturn defaultSide === 'left'\n\t\t\t? { x: axisX - 4, textAnchor: 'end' }\n\t\t\t: { x: axisX + 4, textAnchor: 'start' };\n\t}\n\tconst side = position === 'high' ? 'right' : position === 'low' ? 'left' : defaultSide;\n\treturn side === 'left'\n\t\t? { x: layout.plotLeft - 4, textAnchor: 'end' }\n\t\t: { x: layout.plotRight + 4, textAnchor: 'start' };\n}\n\n/**\n * Format a value-axis tick: display-unit scaled when the axis declares units,\n * otherwise through the axis's own `c:numFmt/@formatCode`. Without the format\n * code a percentage axis renders its cached fractions raw (`0.2` for `20%`).\n */\nfunction formatTick(val: number, axis: PptxChartAxisFormatting | undefined): string {\n\tif (axis?.displayUnits) {\n\t\treturn formatAxisValueWithUnits(val, axis);\n\t}\n\treturn formatAxisValue(val, axis?.numFmt?.formatCode);\n}\n\n/**\n * Build primary value-axis gridlines + left-side labels, honouring log scale and\n * display units. When neither is active the output is identical (same tick count,\n * coordinates, and label text) to `buildGridlinesAndLabels`, so the linear default\n * path is unchanged.\n */\nexport function buildPrimaryAxis(\n\trange: ValueRange,\n\tlayout: PlotLayout,\n\taxis: PptxChartAxisFormatting | undefined,\n\taxisX = layout.plotLeft,\n\t/**\n\t * `false` keeps the axis line, tick marks and labels but draws no major\n\t * gridlines: `c:majorGridlines` absent on the axis (the caller decides via\n\t * `shouldRenderMajorGridlines`; defaults to drawn for legacy callers).\n\t */\n\tshowMajorGridlines = true,\n): { gridlines: SvgLine[]; axisLabels: SvgText[] } {\n\tconst gridlines: SvgLine[] = [];\n\tconst axisLabels: SvgText[] = [];\n\n\tconst tickVals = generateAxisTicks(range, axis, TICK_COUNT);\n\tconst minorTickVals = generateMinorAxisTicks(range, axis);\n\tconst axisLine = buildVerticalAxisLine(axis, axisX, layout);\n\tif (axisLine) {\n\t\tgridlines.push(axisLine);\n\t}\n\tif (axis?.minorGridlines) {\n\t\tfor (const val of minorTickVals) {\n\t\t\tconst y = valueToY(val, range, layout.plotTop, layout.plotBottom);\n\t\t\tgridlines.push(\n\t\t\t\tbuildStyledGridline(y, layout, axis.minorGridlinesSpPr, GRIDLINE_COLOR, 0.5, '1 2', 0.5),\n\t\t\t);\n\t\t}\n\t}\n\tfor (const val of minorTickVals) {\n\t\tconst y = valueToY(val, range, layout.plotTop, layout.plotBottom);\n\t\tconst tick = buildVerticalTickMark(\n\t\t\taxisX,\n\t\t\ty,\n\t\t\taxis?.minorTickMark,\n\t\t\t'left',\n\t\t\tMINOR_TICK_LENGTH,\n\t\t\taxis?.spPr,\n\t\t);\n\t\tif (tick) {\n\t\t\tgridlines.push(tick);\n\t\t}\n\t}\n\n\tfor (const val of tickVals) {\n\t\tconst y = valueToY(val, range, layout.plotTop, layout.plotBottom);\n\t\tif (showMajorGridlines) {\n\t\t\tgridlines.push(\n\t\t\t\tbuildStyledGridline(\n\t\t\t\t\ty,\n\t\t\t\t\tlayout,\n\t\t\t\t\taxis?.majorGridlinesSpPr,\n\t\t\t\t\tGRIDLINE_COLOR,\n\t\t\t\t\t1,\n\t\t\t\t\tundefined,\n\t\t\t\t\tundefined,\n\t\t\t\t),\n\t\t\t);\n\t\t}\n\t\tconst tick = buildVerticalTickMark(\n\t\t\taxisX,\n\t\t\ty,\n\t\t\taxis?.majorTickMark,\n\t\t\t'left',\n\t\t\tMAJOR_TICK_LENGTH,\n\t\t\taxis?.spPr,\n\t\t);\n\t\tif (tick) {\n\t\t\tgridlines.push(tick);\n\t\t}\n\t\tif (axis?.tickLblPos !== 'none') {\n\t\t\taxisLabels.push({\n\t\t\t\tkind: 'text',\n\t\t\t\t...valueAxisLabelPlacement(layout, axis?.tickLblPos, 'left', axisX),\n\t\t\t\ty,\n\t\t\t\ttext: formatTick(val, axis),\n\t\t\t\t...chartAxisTextStyle(axis),\n\t\t\t\tdominantBaseline: 'central',\n\t\t\t});\n\t\t}\n\t}\n\n\t// Units caption: rotated, past the widest tick, hung from the axis top (COM).\n\tif (axis?.displayUnits) {\n\t\tconst unitLabel = getDisplayUnitLabel(axis.displayUnits, axis.displayUnitsLabel);\n\t\tif (unitLabel) {\n\t\t\tconst style = unitsLabelTextStyle(axis, chartAxisTextStyle(axis));\n\t\t\tconst labelX = Math.max(\n\t\t\t\tlayout.plotLeft - unitsCaptionOffset(axisLabels),\n\t\t\t\tstyle.fontSize ?? 12,\n\t\t\t);\n\t\t\taxisLabels.push({\n\t\t\t\tkind: 'text',\n\t\t\t\tx: labelX,\n\t\t\t\ty: layout.plotTop,\n\t\t\t\ttext: unitLabel,\n\t\t\t\t...style,\n\t\t\t\ttextAnchor: 'end',\n\t\t\t\ttransform: `rotate(-90, ${labelX}, ${layout.plotTop})`,\n\t\t\t});\n\t\t}\n\t}\n\n\treturn { gridlines, axisLabels };\n}\n\n/**\n * Build secondary (right-side) value-axis gridlines + labels. Labels sit just\n * to the right of `plotRight`; gridlines span the plot like the primary ones\n * but in a lighter dashed style. Logarithmic ranges emit power-of-base ticks.\n */\nexport function buildSecondaryAxis(\n\trange: ValueRange,\n\tlayout: PlotLayout,\n\taxis: PptxChartAxisFormatting | undefined,\n\taxisX = layout.plotRight,\n): { gridlines: SvgLine[]; axisLabels: SvgText[] } {\n\tconst gridlines: SvgLine[] = [];\n\tconst axisLabels: SvgText[] = [];\n\tconst textStyle = chartAxisTextStyle(axis);\n\tconst captionStyle = chartAxisTextStyle(axis);\n\tconst axisLine = buildVerticalAxisLine(axis, axisX, layout);\n\tif (axisLine) {\n\t\tgridlines.push(axisLine);\n\t}\n\n\tconst tickValues = generateAxisTicks(range, axis, TICK_COUNT - 1);\n\tconst minorTickValues = generateMinorAxisTicks(range, axis);\n\tif (axis?.minorGridlines) {\n\t\tfor (const val of minorTickValues) {\n\t\t\tconst y = valueToY(val, range, layout.plotTop, layout.plotBottom);\n\t\t\tgridlines.push(\n\t\t\t\tbuildStyledGridline(\n\t\t\t\t\ty,\n\t\t\t\t\tlayout,\n\t\t\t\t\taxis.minorGridlinesSpPr,\n\t\t\t\t\tSECONDARY_GRID_COLOR,\n\t\t\t\t\t0.5,\n\t\t\t\t\t'1 2',\n\t\t\t\t\t0.35,\n\t\t\t\t),\n\t\t\t);\n\t\t}\n\t}\n\tfor (const val of minorTickValues) {\n\t\tconst y = valueToY(val, range, layout.plotTop, layout.plotBottom);\n\t\tconst tick = buildVerticalTickMark(\n\t\t\taxisX,\n\t\t\ty,\n\t\t\taxis?.minorTickMark,\n\t\t\t'right',\n\t\t\tMINOR_TICK_LENGTH,\n\t\t\taxis?.spPr,\n\t\t);\n\t\tif (tick) {\n\t\t\tgridlines.push(tick);\n\t\t}\n\t}\n\tfor (const val of tickValues) {\n\t\tconst y = valueToY(val, range, layout.plotTop, layout.plotBottom);\n\t\tgridlines.push(\n\t\t\tbuildStyledGridline(\n\t\t\t\ty,\n\t\t\t\tlayout,\n\t\t\t\taxis?.majorGridlinesSpPr,\n\t\t\t\tSECONDARY_GRID_COLOR,\n\t\t\t\t0.5,\n\t\t\t\t'2 3',\n\t\t\t\t0.5,\n\t\t\t),\n\t\t);\n\t\tconst tick = buildVerticalTickMark(\n\t\t\taxisX,\n\t\t\ty,\n\t\t\taxis?.majorTickMark,\n\t\t\t'right',\n\t\t\tMAJOR_TICK_LENGTH,\n\t\t\taxis?.spPr,\n\t\t);\n\t\tif (tick) {\n\t\t\tgridlines.push(tick);\n\t\t}\n\t\tif (axis?.tickLblPos !== 'none') {\n\t\t\taxisLabels.push({\n\t\t\t\tkind: 'text',\n\t\t\t\t...valueAxisLabelPlacement(layout, axis?.tickLblPos, 'right', axisX),\n\t\t\t\ty,\n\t\t\t\ttext: formatTick(val, axis),\n\t\t\t\t...textStyle,\n\t\t\t\tdominantBaseline: 'central',\n\t\t\t});\n\t\t}\n\t}\n\n\t// Secondary axis title (rotated +90 on the right).\n\tif (axis?.titleText) {\n\t\tconst titleX = layout.plotRight + 36;\n\t\tconst midY = (layout.plotTop + layout.plotBottom) / 2;\n\t\taxisLabels.push({\n\t\t\tkind: 'text',\n\t\t\tx: titleX,\n\t\t\ty: midY,\n\t\t\ttext: axis.titleText,\n\t\t\t...captionStyle,\n\t\t\ttextAnchor: 'middle',\n\t\t\ttransform: `rotate(-90, ${titleX}, ${midY})`,\n\t\t});\n\t}\n\n\t// Secondary display-units caption.\n\tif (axis?.displayUnits) {\n\t\tconst unitLabel = getDisplayUnitLabel(axis.displayUnits, axis.displayUnitsLabel);\n\t\tif (unitLabel) {\n\t\t\tconst labelX = layout.plotRight + (axis.titleText ? 52 : 36);\n\t\t\tconst midY = (layout.plotTop + layout.plotBottom) / 2;\n\t\t\taxisLabels.push({\n\t\t\t\tkind: 'text',\n\t\t\t\tx: labelX,\n\t\t\t\ty: midY,\n\t\t\t\ttext: unitLabel,\n\t\t\t\t...unitsLabelTextStyle(axis, captionStyle),\n\t\t\t\ttextAnchor: 'middle',\n\t\t\t\ttransform: `rotate(-90, ${labelX}, ${midY})`,\n\t\t\t});\n\t\t}\n\t}\n\n\treturn { gridlines, axisLabels };\n}\n","import type { PptxChartData, PptxChartSeries } from 'pptx-viewer-core';\nimport {\n\tchartDataChangeType,\n\tisParetoChartData,\n\tresolveDisplayedChartTypeName,\n} from 'pptx-viewer-core';\n\nimport { buildSecondaryAxis } from './chart-axis-render';\nimport type { PlotLayout, SvgCircle, SvgPolyline, SvgPrimitive, SvgText } from './chart-view-model';\n\nexport interface ParetoEntry {\n\tvalue: number;\n\tlabel: string;\n\tsourcePointIndex: number;\n}\n\n/**\n * Running cumulative total, expressed as a percentage of the grand total, in\n * the order given (no reordering). Rounded to 2 decimal places, matching how\n * PowerPoint labels a Pareto chart's cumulative line.\n *\n * Shared by the insert-chart \"Pareto\" default ({@link ../render/chart-ex-insert-defaults})\n * and the Change Chart Type \"Pareto\" conversion ({@link ../render/chart-editor-options})\n * so both build the same cumulative-percentage-of-total representation that\n * `docs/guide/limitations.md` documents: `chartType: \"histogram\"` with a\n * `clusteredColumn`-layout frequency series and a `paretoLine`-layout\n * cumulative-percentage series.\n */\nexport function cumulativePercentOfTotal(values: ReadonlyArray<number>): number[] {\n\tconst total = values.reduce((sum, value) => sum + value, 0);\n\tif (total === 0) {\n\t\treturn values.map(() => 0);\n\t}\n\tlet running = 0;\n\treturn values.map((value) => {\n\t\trunning += value;\n\t\treturn Math.round((running / total) * 10000) / 100;\n\t});\n}\n\n/**\n * Convert to the \"Pareto\" representation this SDK models: `chartType:\n * 'histogram'` with the existing first series left as the frequency bars\n * (`clusteredColumn` at the OOXML layer, since `buildSeries` in\n * `chart-cx-generator.ts` only writes `paretoLine` for a series whose\n * `histogramOptions.layout` is `'pareto'`) plus an appended cumulative-percent\n * series, unless one is already present (re-selecting \"Pareto\" is then a\n * no-op past the type change). The cumulative series is computed over the\n * frequency values sorted descending, matching the order\n * `buildHistogramViewModel` displays them in once `paretoIndex >= 0`.\n *\n * Mirrors the MCP `createChart`/`updateChart` tools' `chartType: \"pareto\"`\n * alias (`applyParetoChartTypeAlias` in `pptx-viewer-mcp`), which builds the\n * same shape for AI-driven edits; this is the UI-facing equivalent used by\n * `chart-editor-options.ts`'s `patchChartData` for the Change Chart Type\n * picker.\n */\nexport function applyParetoConversion(data: PptxChartData): PptxChartData {\n\tconst histogramData = chartDataChangeType(data, 'histogram');\n\tconst [frequency] = histogramData.series;\n\tif (!frequency) {\n\t\treturn histogramData;\n\t}\n\tconst hasParetoLine = histogramData.series.some(\n\t\t(series) => series.histogramOptions?.layout === 'pareto',\n\t);\n\tif (hasParetoLine) {\n\t\treturn histogramData;\n\t}\n\tconst sortedDescending = [...frequency.values].sort((a, b) => Math.max(b, 0) - Math.max(a, 0));\n\treturn {\n\t\t...histogramData,\n\t\tseries: [\n\t\t\t...histogramData.series,\n\t\t\t{\n\t\t\t\tname: 'Cumulative %',\n\t\t\t\tvalues: cumulativePercentOfTotal(sortedDescending),\n\t\t\t\thistogramOptions: { layout: 'pareto' },\n\t\t\t},\n\t\t],\n\t};\n}\n\n/** Sort by descending non-negative frequency while retaining stable source mapping. */\nexport function orderParetoEntries(entries: ReadonlyArray<ParetoEntry>): ParetoEntry[] {\n\treturn [...entries].sort(\n\t\t(left, right) =>\n\t\t\tMath.max(right.value, 0) - Math.max(left.value, 0) ||\n\t\t\tleft.sourcePointIndex - right.sourcePointIndex,\n\t);\n}\n\n/** Build cumulative percentage line marks in Pareto display order. */\nexport function buildParetoPrimitives(\n\tentries: ReadonlyArray<ParetoEntry>,\n\tlayout: PlotLayout,\n\tseries: PptxChartSeries,\n\tseriesIndex: number,\n): SvgPrimitive[] {\n\tconst total = entries.reduce((sum, entry) => sum + Math.max(entry.value, 0), 0);\n\tif (total <= 0) {\n\t\treturn [];\n\t}\n\tlet cumulative = 0;\n\tconst points = entries.map((entry, displayIndex) => {\n\t\tcumulative += Math.max(entry.value, 0);\n\t\tconst percentage = displayIndex === entries.length - 1 ? 100 : (cumulative / total) * 100;\n\t\treturn {\n\t\t\tx: layout.plotLeft + (layout.plotWidth * (displayIndex + 0.5)) / entries.length,\n\t\t\ty: layout.plotBottom - (layout.plotHeight * percentage) / 100,\n\t\t\tpointIndex: entry.sourcePointIndex,\n\t\t};\n\t});\n\tconst color = series.color ?? '#ED7D31';\n\treturn [\n\t\t{\n\t\t\tkind: 'polyline',\n\t\t\tpoints: points.map((point) => `${point.x},${point.y}`).join(' '),\n\t\t\tstroke: color,\n\t\t\tstrokeWidth: 2,\n\t\t\tfill: 'none',\n\t\t\tpart: { role: 'series', seriesIndex },\n\t\t} satisfies SvgPolyline,\n\t\t...points.map(\n\t\t\t(point) =>\n\t\t\t\t({\n\t\t\t\t\tkind: 'circle',\n\t\t\t\t\tcx: point.x,\n\t\t\t\t\tcy: point.y,\n\t\t\t\t\tr: 2.5,\n\t\t\t\t\tfill: color,\n\t\t\t\t\tpart: { role: 'dataPoint', seriesIndex, pointIndex: point.pointIndex },\n\t\t\t\t}) satisfies SvgCircle,\n\t\t),\n\t];\n}\n\n/**\n * True when `data` is the shape this SDK models as \"Pareto\": `chartType:\n * 'histogram'` with at least one series whose `histogramOptions.layout` is\n * `'pareto'` (the cumulative-percentage line `applyParetoConversion` appends).\n * Pareto has no `PptxChartType` of its own (see docs/guide/limitations.md's\n * ChartEx row), so this is the only way to recognise one from data alone.\n *\n * Delegates to `pptx-viewer-core`'s `isParetoChartData` so the detection\n * logic has one implementation shared with `pptx-viewer-mcp`, which cannot\n * import from this (internal, per-binding-bundled) package.\n */\nexport function isParetoChart(data: Pick<PptxChartData, 'chartType' | 'series'>): boolean {\n\treturn isParetoChartData(data);\n}\n\n/**\n * The chart type a type picker or inspector should show as \"current\" /\n * \"selected\". `data.chartType` alone reads a Pareto chart back as\n * `'histogram'` because Pareto is a display-only overlay on the histogram\n * shape (see {@link applyParetoConversion}); this restores the round trip for\n * display purposes only; it never changes what is stored or serialized.\n *\n * Consumed by every binding's Change Chart Type picker and chart-type\n * inspector label so re-opening a Pareto chart shows \"Pareto\", not\n * \"Histogram\", without introducing a `PptxChartType` of `'pareto'`.\n *\n * Delegates to `pptx-viewer-core`'s `resolveDisplayedChartTypeName` (see\n * {@link isParetoChart}).\n */\nexport function resolveDisplayedChartType(\n\tdata: Pick<PptxChartData, 'chartType' | 'series'>,\n): PptxChartData['chartType'] | 'pareto' {\n\treturn resolveDisplayedChartTypeName(data);\n}\n\n/** Build the fixed Pareto percentage axis using shared secondary-axis conventions. */\nexport function buildParetoAxis(layout: PlotLayout): {\n\tsecondaryGridlines: ReturnType<typeof buildSecondaryAxis>['gridlines'];\n\tsecondaryAxisLabels: SvgText[];\n} {\n\tconst axis = buildSecondaryAxis({ min: 0, max: 100, span: 100 }, layout, {\n\t\taxisType: 'valAx',\n\t\taxPos: 'r',\n\t\tmajorUnit: 20,\n\t\tmajorTickMark: 'out',\n\t});\n\treturn {\n\t\tsecondaryGridlines: axis.gridlines,\n\t\tsecondaryAxisLabels: axis.axisLabels.map((label) => ({\n\t\t\t...label,\n\t\t\ttext: `${label.text}%`,\n\t\t})),\n\t};\n}\n","/**\n * chart-interaction-pie.ts: drag-to-value math for a pie / doughnut slice.\n *\n * A pie slice has no vertical value axis to invert (chart-canvas-drag.ts's\n * `ChartValueDrag` model does not apply), so dragging instead follows the\n * ANGLE under the pointer: grabbing a slice's trailing edge and sweeping it\n * changes that point's share of the whole, and every other slice renormalises\n * automatically because a slice's angle is its value's share of the series\n * total. `buildPieDragGeometry` reuses `computePieLayout` (the exact function\n * `buildPieViewModel` lays the disc out with) so the centre/radius can never\n * drift from what is actually on screen.\n *\n * @module chart-interaction-pie\n */\nimport type { PptxChartData } from 'pptx-viewer-core';\n\nimport { roundDragValue, shareToValue } from './chart-interaction';\nimport { computePieLayout } from './chart-view-model';\nimport type { ValueRange } from './chart-view-model';\n\nconst TWO_PI = Math.PI * 2;\n/** Keep the dragged span strictly inside (0, 2*PI) so the share never hits 0 or 1. */\nconst ANGLE_EPSILON = TWO_PI * 0.001;\n\n/** Geometry a pie/doughnut slice drag needs, resolved once at drag start. */\nexport interface PieDragGeometry {\n\tcx: number;\n\tcy: number;\n\t/** Series 0's current values (a pie/doughnut chart plots a single series). */\n\tvalues: readonly number[];\n\tpointIndex: number;\n\t/** Absolute angle (radians) of the first slice's leading edge. */\n\tstartAngle: number;\n}\n\n/**\n * Resolve the drag geometry for series 0's slice at `pointIndex`, or `null`\n * when `chartData` is not a pie/doughnut, has no series, or the index is out\n * of range. `element` is the chart's frame box (EMU-agnostic width/height, the\n * same units `PptxElement.width/height` and `computePieLayout` use).\n */\nexport function buildPieDragGeometry(\n\telement: { width: number; height: number },\n\tchartData: PptxChartData,\n\tpointIndex: number,\n): PieDragGeometry | null {\n\tif (chartData.chartType !== 'pie' && chartData.chartType !== 'doughnut') {\n\t\treturn null;\n\t}\n\tconst series = chartData.series[0];\n\tif (!series || pointIndex < 0 || pointIndex >= series.values.length) {\n\t\treturn null;\n\t}\n\tconst isDoughnut = chartData.chartType === 'doughnut',\n\t\t{ cx, cy } = computePieLayout(element.width, element.height, chartData, isDoughnut),\n\t\t// Mirrors buildPieViewModel's own startAngle line exactly (chart-view-model-pie.ts).\n\t\tstartAngle = -Math.PI / 2 + ((chartData.firstSliceAngle ?? 0) * Math.PI) / 180;\n\treturn { cx, cy, values: series.values, pointIndex, startAngle };\n}\n\n/**\n * New value for a slice given the pointer's angle (radians, same convention\n * as {@link PieDragGeometry.startAngle}/`leadingAngle`) and the series'\n * values. The slice's leading edge stays put; the span from there to the\n * pointer's angle becomes the slice's new share of the series total, and\n * {@link shareToValue} converts that share back to an absolute value holding\n * every other (unchanged) slice's value fixed.\n *\n * Split out of {@link resolvePieDragValue} so the interactive 3D pie scene\n * (`pie-chart-3d-drag.ts`) can reuse the SAME renormalisation formula from a\n * pointer angle it derives its own way (a raycast against the pie's plane,\n * rather than `atan2` over a 2D view-box position), so a dragged pie3D wedge\n * renormalises identically to its flat SVG counterpart.\n */\nexport function resolvePieSliceShareValue(\n\tpointerAngle: number,\n\tleadingAngle: number,\n\tvalues: readonly number[],\n\tpointIndex: number,\n): number {\n\tconst total = values.reduce((sum, v) => sum + Math.abs(v), 0) || 1,\n\t\trawSpan = ((pointerAngle - leadingAngle) % TWO_PI) + TWO_PI,\n\t\tspan = Math.min(Math.max(rawSpan % TWO_PI, ANGLE_EPSILON), TWO_PI - ANGLE_EPSILON),\n\t\tshare = span / TWO_PI,\n\t\town = values[pointIndex] ?? 0,\n\t\tsign = own < 0 ? -1 : 1,\n\t\tothers = total - Math.abs(own),\n\t\tabsValue = shareToValue(share, others),\n\t\trange: ValueRange = {\n\t\t\tmin: 0,\n\t\t\tmax: Math.max(total, absValue, 1),\n\t\t\tspan: Math.max(total, absValue, 1),\n\t\t};\n\treturn roundDragValue(sign * absValue, range);\n}\n\n/**\n * New value for the dragged slice given the pointer's (view-box) position.\n * See {@link resolvePieSliceShareValue} for the renormalisation itself; this\n * wrapper only derives the pointer's angle and the slice's own leading edge\n * from the 2D drag geometry.\n */\nexport function resolvePieDragValue(\n\tgeometry: PieDragGeometry,\n\tpointerX: number,\n\tpointerY: number,\n): number {\n\tconst { cx, cy, values, pointIndex, startAngle } = geometry,\n\t\ttotal = values.reduce((sum, v) => sum + Math.abs(v), 0) || 1,\n\t\tbefore = values.slice(0, pointIndex).reduce((sum, v) => sum + Math.abs(v), 0),\n\t\tleadingAngle = startAngle + (before / total) * TWO_PI,\n\t\tpointerAngle = Math.atan2(pointerY - cy, pointerX - cx);\n\treturn resolvePieSliceShareValue(pointerAngle, leadingAngle, values, pointIndex);\n}\n","/**\n * chart-interaction-radar.ts: drag-to-value math for a radar/spider vertex.\n *\n * A radar chart has no straight value axis either: each category is its own\n * spoke radiating from the plot centre. Dragging a vertex is a RADIAL drag\n * along its fixed spoke direction (`radarAngle`), so the pointer's component\n * along that spoke, scaled by the ring radius/max-value ratio\n * `buildRadarViewModel` already draws with, is the new value.\n *\n * @module chart-interaction-radar\n */\nimport type { PptxChartData } from 'pptx-viewer-core';\n\nimport { roundDragValue } from './chart-interaction';\nimport { computePlotLayout, radarAngle } from './chart-view-model';\nimport type { ValueRange } from './chart-view-model';\n\n/** Geometry a radar vertex drag needs, resolved once at drag start. */\nexport interface RadarDragGeometry {\n\tcx: number;\n\tcy: number;\n\t/** Outer ring radius (view-box units). */\n\tradius: number;\n\t/** Largest absolute value across every series, the outer ring's value. */\n\tmaxVal: number;\n\t/** This vertex's fixed spoke angle (radians). */\n\tangle: number;\n}\n\n/**\n * Resolve the drag geometry for `pointIndex`'s vertex, or `null` when\n * `chartData` is not a radar chart or the index is out of range. Mirrors\n * `buildRadarViewModel`'s own cx/cy/radius/maxVal derivation exactly\n * (chart-view-model-radar.ts) so the drag target never drifts from what is\n * actually drawn.\n */\nexport function buildRadarDragGeometry(\n\telement: { width: number; height: number },\n\tchartData: PptxChartData,\n\tcategoryLabels: ReadonlyArray<string>,\n\tpointIndex: number,\n): RadarDragGeometry | null {\n\tif (chartData.chartType !== 'radar') {\n\t\treturn null;\n\t}\n\tconst catCount = Math.max(categoryLabels.length, 1);\n\tif (pointIndex < 0 || pointIndex >= catCount) {\n\t\treturn null;\n\t}\n\tconst layout = computePlotLayout(element.width, element.height, chartData, false),\n\t\tcx = layout.plotLeft + layout.plotWidth / 2,\n\t\tcy = layout.plotTop + layout.plotHeight / 2,\n\t\tradius = Math.max(Math.min(layout.plotWidth, layout.plotHeight) / 2 - 4, 1),\n\t\tmaxVal = Math.max(1, ...chartData.series.flatMap((s) => s.values.map((v) => Math.abs(v)))),\n\t\tangle = radarAngle(pointIndex, catCount);\n\treturn { cx, cy, radius, maxVal, angle };\n}\n\n/**\n * New value for the dragged vertex given the pointer's (view-box) position:\n * the pointer vector from the centre is projected onto the spoke direction\n * (perpendicular drift is ignored, matching \"radial drag along the category\n * spoke\"), clamped to non-negative, then scaled back from ring radius to\n * value via the same `radius / maxVal` ratio the renderer draws with.\n */\nexport function resolveRadarDragValue(\n\tgeometry: RadarDragGeometry,\n\tpointerX: number,\n\tpointerY: number,\n): number {\n\tconst { cx, cy, radius, maxVal, angle } = geometry,\n\t\tdx = pointerX - cx,\n\t\tdy = pointerY - cy,\n\t\tradial = Math.max(dx * Math.cos(angle) + dy * Math.sin(angle), 0),\n\t\tvalue = (radial / radius) * maxVal,\n\t\trange: ValueRange = {\n\t\t\tmin: 0,\n\t\t\tmax: Math.max(maxVal, value, 1),\n\t\t\tspan: Math.max(maxVal, value, 1),\n\t\t};\n\treturn roundDragValue(value, range);\n}\n","/**\n * chart-interaction-stacked.ts: drag-to-value math for one segment of a\n * stacked / percentStacked bar, line, or area mark.\n *\n * `chart-cartesian.ts` deliberately omits `ChartViewModel.valueDrag` for a\n * stacked chart (a segment sits on a running sum, so a naive vertical drag\n * would not track the pointer the way a clustered mark's does). This module\n * is the actual stacked-aware inversion: the segment's BASE (the running sum\n * of the series below it, same sign group) is held fixed, and the pointer's\n * projected value/percent minus that base becomes the dragged series' own new\n * contribution. `computeStackedSeriesPlots` (chart-stacked-series.ts) is the\n * exact running-sum bookkeeping the stacked line/area builders already use,\n * so `baseValue` here can never disagree with what is on screen; plain\n * stacked bars use the same running-sum math (see `computeStackedBarRects`'s\n * own doc comment).\n *\n * @module chart-interaction-stacked\n */\nimport type { PptxChartData } from 'pptx-viewer-core';\n\nimport { computeLayoutOptions } from './chart-axis';\nimport { roundDragValue, shareToValue, valueFromY } from './chart-interaction';\nimport { computeStackedSeriesPlots } from './chart-stacked-series';\nimport { computePlotLayout, computeStackedValueRange } from './chart-view-model';\nimport type { ValueRange } from './chart-view-model';\n\n/** Geometry a stacked/percentStacked segment drag needs, resolved once at drag start. */\nexport interface StackedDragGeometry {\n\trange: ValueRange;\n\tplotTop: number;\n\tplotBottom: number;\n\t/** Running sum of the same-sign series below this one, at this category. */\n\tbaseValue: number;\n\t/** Sum of every OTHER series' absolute value at this category (percentStacked only). */\n\totherAbsSum: number;\n\tpercent: boolean;\n}\n\n/**\n * Resolve the drag geometry for one (seriesIndex, pointIndex) stacked\n * segment, or `null` when the chart is not stacked/percentStacked, the series\n * has no values, or the point is out of range.\n */\nexport function buildStackedDragGeometry(\n\telement: { width: number; height: number },\n\tchartData: PptxChartData,\n\tseriesIndex: number,\n\tpointIndex: number,\n): StackedDragGeometry | null {\n\tconst grouping = chartData.grouping;\n\tif (grouping !== 'stacked' && grouping !== 'percentStacked') {\n\t\treturn null;\n\t}\n\tconst seriesValues = chartData.series.map((s) => s.values),\n\t\tdraggedValues = seriesValues[seriesIndex];\n\tif (!draggedValues || pointIndex < 0 || pointIndex >= draggedValues.length) {\n\t\treturn null;\n\t}\n\tconst percent = grouping === 'percentStacked',\n\t\tcatCount = Math.max(\n\t\t\tchartData.categories.length,\n\t\t\t...seriesValues.map((values) => values.length),\n\t\t\tpointIndex + 1,\n\t\t),\n\t\tplots = computeStackedSeriesPlots(seriesValues, catCount, percent),\n\t\tbaseValue = plots[seriesIndex]?.base[pointIndex] ?? 0,\n\t\totherAbsSum = seriesValues.reduce(\n\t\t\t(sum, values, si) => (si === seriesIndex ? sum : sum + Math.abs(values[pointIndex] ?? 0)),\n\t\t\t0,\n\t\t),\n\t\tlayoutOpts = computeLayoutOptions(chartData.axes, chartData.dataTable, chartData.series.length),\n\t\tlayout = computePlotLayout(element.width, element.height, chartData, true, layoutOpts),\n\t\t// Computed from the SAME `layout.autoPlotHeight` `chart-cartesian.ts`'s\n\t\t// `stackedRange` uses, so a drag never disagrees with what is on screen.\n\t\trange: ValueRange = percent\n\t\t\t? { min: 0, max: 100, span: 100 }\n\t\t\t: computeStackedValueRange(chartData.series, catCount, layout.autoPlotHeight);\n\treturn {\n\t\trange,\n\t\tplotTop: layout.plotTop,\n\t\tplotBottom: layout.plotBottom,\n\t\tbaseValue,\n\t\totherAbsSum,\n\t\tpercent,\n\t};\n}\n\n/**\n * New value for the dragged series at this category given the pointer's Y\n * (view-box units). The pointer projects to a cumulative value/percent at the\n * segment's top edge; subtracting the fixed base below it gives the dragged\n * series' own new share. A plain stacked chart uses that directly (the other\n * series' absolute values are untouched, so the category total simply grows\n * or shrinks); percentStacked instead treats it as a percentage SHARE and\n * converts it back to an absolute value via {@link shareToValue}, holding\n * every other series' value fixed (matching the pie slice renormalisation).\n */\nexport function resolveStackedDragValue(geometry: StackedDragGeometry, pointerY: number): number {\n\tconst { range, plotTop, plotBottom, baseValue, otherAbsSum, percent } = geometry,\n\t\tpointerScalar = valueFromY(pointerY, range, plotTop, plotBottom),\n\t\tdelta = pointerScalar - baseValue;\n\tif (!percent) {\n\t\treturn roundDragValue(delta, range);\n\t}\n\tconst sign = delta < 0 ? -1 : 1,\n\t\tabsValue = shareToValue(Math.abs(delta) / 100, otherAbsSum),\n\t\tvalueRange: ValueRange = {\n\t\t\tmin: 0,\n\t\t\tmax: Math.max(otherAbsSum, absValue, 1),\n\t\t\tspan: Math.max(otherAbsSum, absValue, 1),\n\t\t};\n\treturn roundDragValue(sign * absValue, valueRange);\n}\n","/**\n * chart-interaction.ts: framework-agnostic support for direct on-canvas chart\n * editing.\n *\n * The chart view-model engine tags data-mark primitives (bars, dots, slices,\n * series lines) with a `ChartPartRef`. This module is the other half of that\n * contract: it converts part refs to/from DOM `data-*` attributes so bindings\n * can hit-test via event delegation, inverts the value-axis projection so a\n * vertical drag maps back to a data value, and applies the resulting edits to\n * `PptxChartData` immutably so they flow through each binding's normal\n * update/history pipeline.\n *\n * Used by the React / Vue / Angular chart renderers in edit mode; rendering\n * stays untouched when a chart is not editable.\n *\n * @module chart-interaction\n */\nimport type { PptxChartData } from 'pptx-viewer-core';\n\nimport { buildPieDragGeometry, resolvePieDragValue } from './chart-interaction-pie';\nimport type { PieDragGeometry } from './chart-interaction-pie';\nimport { buildRadarDragGeometry, resolveRadarDragValue } from './chart-interaction-radar';\nimport type { RadarDragGeometry } from './chart-interaction-radar';\nimport { buildStackedDragGeometry, resolveStackedDragValue } from './chart-interaction-stacked';\nimport type { StackedDragGeometry } from './chart-interaction-stacked';\nimport { collapseChartTitleRunsForEdit } from './chart-title-runs';\nimport type {\n\tChartPartRef,\n\tChartValueDrag,\n\tSupportedChartKind,\n\tValueRange,\n} from './chart-view-model';\nimport { valueToY } from './chart-view-model';\n\n// ─────────────────────────────────────────────────────────────────────────────\n// DOM data-attribute bridge\n// ─────────────────────────────────────────────────────────────────────────────\n\n/** Attribute carrying the part role ('dataPoint' | 'series' | 'title'). */\nexport const CHART_PART_ATTR = 'data-chart-part';\n/** Attribute carrying the series index of a tagged mark. */\nexport const CHART_PART_SERIES_ATTR = 'data-chart-series';\n/** Attribute carrying the point/category index of a tagged mark. */\nexport const CHART_PART_POINT_ATTR = 'data-chart-point';\n\n/** Attribute record for a tagged mark, spreadable onto an SVG node. */\nexport function chartPartToAttrs(part: ChartPartRef): Record<string, string> {\n\tconst attrs: Record<string, string> = {\n\t\t[CHART_PART_ATTR]: part.role,\n\t\t[CHART_PART_SERIES_ATTR]: String(part.seriesIndex),\n\t};\n\tif (part.pointIndex !== undefined) {\n\t\tattrs[CHART_PART_POINT_ATTR] = String(part.pointIndex);\n\t}\n\treturn attrs;\n}\n\n/** Minimal structural view of a DOM element for hit-testing (no DOM lib dependency). */\nexport interface ChartPartElement {\n\tgetAttribute(qualifiedName: string): string | null;\n\tclosest(selectors: string): ChartPartElement | null;\n}\n\n/** Recover a `ChartPartRef` from a tagged element's attributes. */\nexport function chartPartFromElement(el: ChartPartElement | null): ChartPartRef | null {\n\tif (!el) {\n\t\treturn null;\n\t}\n\tconst role = el.getAttribute(CHART_PART_ATTR);\n\tif (role !== 'dataPoint' && role !== 'series') {\n\t\treturn null;\n\t}\n\tconst seriesIndex = Number.parseInt(el.getAttribute(CHART_PART_SERIES_ATTR) ?? '', 10);\n\tif (!Number.isInteger(seriesIndex) || seriesIndex < 0) {\n\t\treturn null;\n\t}\n\tconst pointRaw = el.getAttribute(CHART_PART_POINT_ATTR);\n\tif (pointRaw === null) {\n\t\treturn { role, seriesIndex };\n\t}\n\tconst pointIndex = Number.parseInt(pointRaw, 10);\n\tif (!Number.isInteger(pointIndex) || pointIndex < 0) {\n\t\treturn { role, seriesIndex };\n\t}\n\treturn { role, seriesIndex, pointIndex };\n}\n\n/**\n * Resolve the chart part under an event target by walking up to the nearest\n * tagged ancestor. Accepts the raw `event.target` (unknown) and returns null\n * for anything that is not an element inside a tagged mark.\n */\nexport function findChartPartTarget(target: unknown): ChartPartRef | null {\n\tif (!target || typeof target !== 'object') {\n\t\treturn null;\n\t}\n\tconst el = target as Partial<ChartPartElement>;\n\tif (typeof el.closest !== 'function' || typeof el.getAttribute !== 'function') {\n\t\treturn null;\n\t}\n\treturn chartPartFromElement((el as ChartPartElement).closest(`[${CHART_PART_ATTR}]`));\n}\n\n/** Structural equality for (possibly null) part refs. */\nexport function isSameChartPart(a: ChartPartRef | null, b: ChartPartRef | null): boolean {\n\tif (!a || !b) {\n\t\treturn a === b;\n\t}\n\treturn a.role === b.role && a.seriesIndex === b.seriesIndex && a.pointIndex === b.pointIndex;\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Drag-to-value math\n// ─────────────────────────────────────────────────────────────────────────────\n\n/**\n * Inverse of `valueToY`: map a Y coordinate (view-box units) back to a data\n * value. Mirrors the linear and logarithmic branches of the forward mapping.\n */\nexport function valueFromY(y: number, range: ValueRange, topY: number, bottomY: number): number {\n\tconst usable = bottomY - topY;\n\tif (usable === 0) {\n\t\treturn range.min;\n\t}\n\tconst ratio = range.reverseOrder ? (y - topY) / usable : (bottomY - y) / usable;\n\tif (range.logScale && range.logBase) {\n\t\tconst base = range.logBase;\n\t\tconst logMin = Math.log(range.min) / Math.log(base);\n\t\tconst logVal = logMin + ratio * range.span;\n\t\treturn base ** logVal;\n\t}\n\treturn range.min + ratio * range.span;\n}\n\n/**\n * Round a dragged value to a step two orders of magnitude below the axis span,\n * so drags produce human-scale numbers (span 0..500 snaps to whole units,\n * 0..5 to 0.05) instead of 14-decimal floats.\n */\nexport function roundDragValue(value: number, range: ValueRange): number {\n\tif (!Number.isFinite(value) || range.span <= 0) {\n\t\treturn value;\n\t}\n\tconst step = 10 ** (Math.floor(Math.log10(range.span)) - 2);\n\tconst rounded = Math.round(value / step) * step;\n\t// Snap away float noise from the multiplication (e.g. 0.30000000000000004).\n\treturn Number.parseFloat(rounded.toPrecision(12));\n}\n\n/**\n * Convert a target SHARE (0..1, exclusive) of a whole back to an absolute\n * value, holding every other part's absolute value (`otherAbsSum`) fixed:\n * `share = value / (value + otherAbsSum)` solved for `value`. Used by both a\n * dragged pie/doughnut slice's angle share and a dragged percentStacked\n * segment's percent share, so the two renormalise identically. `share` is\n * clamped short of 1 so a lone part (no others to renormalise against) still\n * returns a finite, monotonically increasing value instead of Infinity.\n */\nexport function shareToValue(share: number, otherAbsSum: number): number {\n\tconst clamped = Math.min(Math.max(share, 0), 0.999999);\n\tif (clamped <= 0) {\n\t\treturn 0;\n\t}\n\tconst ratio = clamped / (1 - clamped);\n\treturn otherAbsSum > 0 ? ratio * otherAbsSum : ratio;\n}\n\n/** The value range a series maps against (secondary when axis-mapped there). */\nfunction rangeForSeries(drag: ChartValueDrag, seriesIndex: number): ValueRange {\n\tconst useSecondary =\n\t\tdrag.secondaryRange !== undefined &&\n\t\t(drag.secondarySeriesIndexes?.includes(seriesIndex) ?? false);\n\treturn useSecondary && drag.secondaryRange ? drag.secondaryRange : drag.range;\n}\n\n/**\n * Value for a dragged data point at `viewY` (view-box units), using the\n * secondary range when the part's series is mapped to the secondary axis.\n */\nexport function dragValueForPart(viewY: number, drag: ChartValueDrag, seriesIndex: number): number {\n\tconst range = rangeForSeries(drag, seriesIndex);\n\treturn roundDragValue(valueFromY(viewY, range, drag.plotTop, drag.plotBottom), range);\n}\n\n/**\n * Y coordinate (view-box units) where a data point's value currently sits.\n * Drags anchor here so the value tracks the pointer's MOVEMENT rather than\n * jumping to the pointer's absolute position when the user grabs the middle\n * of a bar.\n */\nexport function dragAnchorViewY(value: number, drag: ChartValueDrag, seriesIndex: number): number {\n\treturn valueToY(value, rangeForSeries(drag, seriesIndex), drag.plotTop, drag.plotBottom);\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Immutable chart-data edits\n// ─────────────────────────────────────────────────────────────────────────────\n\n/**\n * Return a copy of `chartData` with one point's value replaced. Returns the\n * input unchanged when the series or point index is out of range.\n */\nexport function withChartPointValue(\n\tchartData: PptxChartData,\n\tseriesIndex: number,\n\tpointIndex: number,\n\tvalue: number,\n): PptxChartData {\n\tconst series = chartData.series[seriesIndex];\n\tif (!series || pointIndex < 0 || pointIndex >= series.values.length) {\n\t\treturn chartData;\n\t}\n\treturn {\n\t\t...chartData,\n\t\tseries: chartData.series.map((s, i) =>\n\t\t\ti === seriesIndex\n\t\t\t\t? { ...s, values: s.values.map((v, j) => (j === pointIndex ? value : v)) }\n\t\t\t\t: s,\n\t\t),\n\t};\n}\n\n/**\n * Return a copy of `chartData` with the title replaced. A non-empty title\n * turns the title on; an empty one turns it off (matching PowerPoint, where\n * clearing the title hides it).\n */\nexport function withChartTitle(chartData: PptxChartData, title: string): PptxChartData {\n\tconst trimmed = title.trim();\n\treturn {\n\t\t...chartData,\n\t\t// A multi-run title collapses to one run in its dominant style so this\n\t\t// edit does not leave another, now-stale run's text trailing the new\n\t\t// title; see `collapseChartTitleRunsForEdit`'s doc.\n\t\t...collapseChartTitleRunsForEdit(chartData, trimmed),\n\t\tstyle: { ...chartData.style, hasTitle: trimmed.length > 0 },\n\t};\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Non-cartesian mark drag (pie/doughnut slice, radar vertex, stacked segment)\n// ─────────────────────────────────────────────────────────────────────────────\n\n/**\n * Drag geometry for a mark kind `ChartValueDrag` cannot describe (no single\n * vertical value axis): a pie/doughnut slice, a radar vertex, or one segment\n * of a stacked/percentStacked bar/line/area. `kind` is a discriminant, not the\n * chart's own `SupportedChartKind` (`bar`/`line`/`area` all resolve to\n * `'stackedSegment'` since they share the same running-sum math).\n */\nexport type ChartMarkDragGeometry =\n\t| ({ kind: 'pie' } & PieDragGeometry)\n\t| ({ kind: 'radar' } & RadarDragGeometry)\n\t| ({ kind: 'stackedSegment' } & StackedDragGeometry);\n\n/**\n * Resolve a mark drag's geometry for the given chart kind and part, or `null`\n * when that kind/part combination has no drag meaning (e.g. a clustered bar,\n * which uses `ChartValueDrag`/`dragValueForPart` instead).\n */\nexport function buildChartMarkDragGeometry(params: {\n\tkind: SupportedChartKind;\n\telement: { width: number; height: number };\n\tchartData: PptxChartData;\n\tcategoryLabels: ReadonlyArray<string>;\n\tseriesIndex: number;\n\tpointIndex: number;\n}): ChartMarkDragGeometry | null {\n\tconst { kind, element, chartData, categoryLabels, seriesIndex, pointIndex } = params;\n\tif (kind === 'pie' || kind === 'doughnut') {\n\t\tconst geometry = buildPieDragGeometry(element, chartData, pointIndex);\n\t\treturn geometry ? { kind: 'pie', ...geometry } : null;\n\t}\n\tif (kind === 'radar') {\n\t\tconst geometry = buildRadarDragGeometry(element, chartData, categoryLabels, pointIndex);\n\t\treturn geometry ? { kind: 'radar', ...geometry } : null;\n\t}\n\tif (kind === 'bar' || kind === 'line' || kind === 'area') {\n\t\tconst geometry = buildStackedDragGeometry(element, chartData, seriesIndex, pointIndex);\n\t\treturn geometry ? { kind: 'stackedSegment', ...geometry } : null;\n\t}\n\treturn null;\n}\n\n/**\n * New value for a dragged mark, dispatched by the geometry's own `kind`. This\n * is the single entry point every binding's pointer handler calls; each kind's\n * actual math lives in its own `chart-interaction-*.ts` sibling.\n */\nexport function resolveChartDragValue(\n\tgeometry: ChartMarkDragGeometry,\n\tpointer: { x: number; y: number },\n): number {\n\tswitch (geometry.kind) {\n\t\tcase 'pie':\n\t\t\treturn resolvePieDragValue(geometry, pointer.x, pointer.y);\n\t\tcase 'radar':\n\t\t\treturn resolveRadarDragValue(geometry, pointer.x, pointer.y);\n\t\tcase 'stackedSegment':\n\t\t\treturn resolveStackedDragValue(geometry, pointer.y);\n\t\tdefault: {\n\t\t\tconst exhaustive: never = geometry;\n\t\t\treturn exhaustive;\n\t\t}\n\t}\n}\n","/**\n * chart-canvas-drag.ts: the framework-neutral half of direct on-canvas chart\n * editing - the value-drag state machine, the hit-target stylesheet, and the\n * selected-part highlight.\n *\n * Every binding's chart projector already emits the `data-chart-*` hit-testing\n * attributes (`chartPartToAttrs`), and the shared view model already carries\n * the inversion data (`ChartViewModel.valueDrag`). What was missing outside\n * React / Vue / Angular was the small amount of glue between a pointer and a\n * new `PptxChartData`, which those three had each written for themselves. It is\n * pure DOM plus arithmetic - no framework touches it - so it lives here and the\n * bindings keep only their own reactive plumbing.\n *\n * The drag is deliberately modelled as an immutable-ish record the caller owns:\n * a binding stores the state wherever its framework prefers (a `let`, a ref, a\n * signal) and calls {@link advanceChartValueDrag} per pointermove. Nothing here\n * subscribes to events, so it is equally usable from an effect, a composable, a\n * Svelte action or a plain DOM listener.\n *\n * @module chart-canvas-drag\n */\nimport type { PptxChartData } from 'pptx-viewer-core';\n\nimport { dragAnchorViewY, dragValueForPart, withChartPointValue } from './chart-interaction';\nimport type { ChartPartRef, ChartValueDrag, ChartViewModel } from './chart-view-model';\n\n/**\n * Minimum pointer travel (px) before a mark press becomes a value drag.\n *\n * Without a threshold every click on a bar would commit a (tiny) value change,\n * so a user could not select a mark without editing it.\n */\nexport const CHART_DRAG_THRESHOLD_PX = 3;\n\nconst STYLE_ELEMENT_ID = 'pptx-chart-interaction-styles';\nconst INTERACTION_CSS = `\n.pptx-chart-interactive svg [data-chart-part] { pointer-events: auto; cursor: pointer; }\n.pptx-chart-interactive svg [data-chart-part]:hover { filter: brightness(1.12); }\n.pptx-chart-interactive svg [data-chart-part='title'] { cursor: text; }\n/* A data label is decoration painted ON TOP of the mark it describes, so it\n must never intercept that mark's click. The treemap made this unmissable -\n its label sits dead-centre on the cell, so clicking a cell hit the <text> and\n selected nothing - but every kind's data labels overlap their marks. Only\n labels are excluded: the chart title is itself a part and stays clickable.\n Bindings whose chart <svg> is blanket pointer-events:none (React) never saw\n this; the other three did, which is exactly why the rule belongs here. */\n.pptx-chart-interactive svg text:not([data-chart-part]) { pointer-events: none; }\n.pptx-chart-interactive svg .pptx-chart-part-selected { filter: drop-shadow(0 0 2.5px #3b82f6); }\n.pptx-chart-interactive svg .pptx-chart-part-selected:hover { filter: drop-shadow(0 0 2.5px #3b82f6) brightness(1.12); }\n`;\n\n/**\n * Inject the (singleton) interaction stylesheet for chart part hit targets.\n *\n * The projectors emit the hit-target attributes unconditionally, but the marks\n * stay pointer-transparent until a root carries `pptx-chart-interactive`, so\n * charts on thumbnails and export surfaces cannot be grabbed.\n */\nexport function ensureChartInteractionStyles(): void {\n\tif (typeof document === 'undefined' || document.getElementById(STYLE_ELEMENT_ID)) {\n\t\treturn;\n\t}\n\tconst style = document.createElement('style');\n\tstyle.id = STYLE_ELEMENT_ID;\n\tstyle.textContent = INTERACTION_CSS;\n\tdocument.head.appendChild(style);\n}\n\n/** Class a chart root carries while its marks are grabbable. */\nexport const CHART_INTERACTIVE_CLASS = 'pptx-chart-interactive';\n\n/** Class marking the currently selected mark. */\nexport const CHART_PART_SELECTED_CLASS = 'pptx-chart-part-selected';\n\n/**\n * Whether `node` sits inside a chart root that is currently armed for mark\n * interaction (carries {@link CHART_INTERACTIVE_CLASS}).\n *\n * The 2D marks get this gate for free from the stylesheet above (they are\n * pointer-transparent until the root is armed). A 3D scene's WebGL canvas has\n * no such CSS gate, so its pointer wiring asks this instead, keeping \"is a\n * mark press the scene's or the stage's?\" a single decision every binding\n * already makes by toggling the one class.\n */\nexport function isChartInteractionArmed(node: Element | null | undefined): boolean {\n\tlet current: Element | null | undefined = node;\n\t// Walk out through shadow roots: a `<pptx-three-view>` canvas sits inside\n\t// the element's shadow tree, and `closest` never crosses that boundary.\n\twhile (current && typeof current.closest === 'function') {\n\t\tif (current.closest(`.${CHART_INTERACTIVE_CLASS}`) !== null) {\n\t\t\treturn true;\n\t\t}\n\t\tconst root = typeof current.getRootNode === 'function' ? current.getRootNode() : null;\n\t\tcurrent = (root as { host?: Element } | null)?.host ?? null;\n\t}\n\treturn false;\n}\n\n/**\n * Re-apply the selected-part highlight class inside `root`.\n *\n * Called after every render: the projectors re-create the SVG marks on each\n * chart change, which drops DOM-only classes. A null `part` only clears.\n */\nexport function applyChartPartHighlight(root: Element | null, part: ChartPartRef | null): void {\n\tif (!root) {\n\t\treturn;\n\t}\n\tfor (const node of root.querySelectorAll(`.${CHART_PART_SELECTED_CLASS}`)) {\n\t\tnode.classList.remove(CHART_PART_SELECTED_CLASS);\n\t}\n\tif (!part) {\n\t\treturn;\n\t}\n\tconst pointSelector =\n\t\tpart.pointIndex !== undefined\n\t\t\t? `[data-chart-point='${part.pointIndex}']`\n\t\t\t: ':not([data-chart-point])';\n\tconst selector = `[data-chart-part='${part.role}'][data-chart-series='${part.seriesIndex}']${pointSelector}`;\n\tfor (const node of root.querySelectorAll(selector)) {\n\t\tnode.classList.add(CHART_PART_SELECTED_CLASS);\n\t}\n}\n\n/** State of an in-flight data-point value drag. Owned by the calling binding. */\nexport interface ChartValueDragState {\n\tpart: ChartPartRef;\n\tdrag: ChartValueDrag;\n\tsvgHeight: number;\n\tstartClientY: number;\n\t/** View-box Y of the point's value at drag start; the drag tracks deltas from here. */\n\tanchorViewY: number;\n\tbaseChartData: PptxChartData;\n\t/** Whether the pointer has passed {@link CHART_DRAG_THRESHOLD_PX}. */\n\tmoved: boolean;\n\t/** Most recent previewed data, or null while the drag is still a click. */\n\tlastData: PptxChartData | null;\n}\n\n/**\n * Start a value drag on a data-point mark, or return `null` when the press is\n * not on something draggable (a legend swatch, a series line, an axis, or a\n * chart kind whose marks have no single-value meaning - stacked bars sit on\n * running sums, so dragging one would not track the pointer).\n *\n * The view model MUST be built from the COMMITTED chart data, not from a\n * preview, or the axis rescales under the pointer mid-drag and the mark runs\n * away from the cursor.\n */\nexport function beginChartValueDrag(params: {\n\tpart: ChartPartRef;\n\tviewModel: ChartViewModel;\n\tchartData: PptxChartData;\n\tclientY: number;\n}): ChartValueDragState | null {\n\tconst { part, viewModel, chartData, clientY } = params;\n\tif (part.role !== 'dataPoint' || part.pointIndex === undefined || !viewModel.valueDrag) {\n\t\treturn null;\n\t}\n\tconst startValue = chartData.series[part.seriesIndex]?.values[part.pointIndex] ?? 0;\n\treturn {\n\t\tpart,\n\t\tdrag: viewModel.valueDrag,\n\t\tsvgHeight: viewModel.svgHeight,\n\t\tstartClientY: clientY,\n\t\tanchorViewY: dragAnchorViewY(startValue, viewModel.valueDrag, part.seriesIndex),\n\t\tbaseChartData: chartData,\n\t\tmoved: false,\n\t\tlastData: null,\n\t};\n}\n\n/** Result of one pointermove during a value drag. */\nexport interface ChartValueDragStep {\n\t/** The chart data with the dragged point's new value applied. */\n\tchartData: PptxChartData;\n\t/** The new value, for the floating mid-drag badge. */\n\tvalue: number;\n}\n\n/**\n * Advance an in-flight drag to the pointer's current Y.\n *\n * Returns `null` (leaving `state` untouched) while the press is still inside\n * the click threshold or the SVG has no measurable height. Otherwise MUTATES\n * `state.moved` / `state.lastData` and returns the step, so the caller can\n * preview it and commit `state.lastData` once on release.\n *\n * `svgHeight` is the rendered pixel height of the chart's `<svg>`; the drag is\n * scaled by it because the view model is in view-box units and the element is\n * itself inside the slide's zoom transform.\n */\nexport function advanceChartValueDrag(\n\tstate: ChartValueDragState,\n\tclientY: number,\n\tsvgHeight: number,\n): ChartValueDragStep | null {\n\tif (!state.moved && Math.abs(clientY - state.startClientY) < CHART_DRAG_THRESHOLD_PX) {\n\t\treturn null;\n\t}\n\tif (svgHeight === 0 || state.part.pointIndex === undefined) {\n\t\treturn null;\n\t}\n\tstate.moved = true;\n\tconst deltaViewY = ((clientY - state.startClientY) / svgHeight) * state.svgHeight;\n\tconst value = dragValueForPart(\n\t\tstate.anchorViewY + deltaViewY,\n\t\tstate.drag,\n\t\tstate.part.seriesIndex,\n\t);\n\tconst chartData = withChartPointValue(\n\t\tstate.baseChartData,\n\t\tstate.part.seriesIndex,\n\t\tstate.part.pointIndex,\n\t\tvalue,\n\t);\n\tstate.lastData = chartData;\n\treturn { chartData, value };\n}\n","/**\n * Small SVG-node helpers for `chart-view-model-dom.ts`'s primitive, pattern\n * and line renderers (moved here from the vanilla binding so the 3D chart\n * overlay can draw the same chart chrome). Split out to keep that file within\n * the repo's ~300-LOC limit.\n *\n * @module chart-view-model-dom-helpers\n */\nimport { chartPartToAttrs } from './chart-interaction';\nimport type { ChartPartRef, ChartSvgDef } from './chart-view-model';\n\nconst SVG_NS = 'http://www.w3.org/2000/svg';\n\n/** Set attributes on an SVG element, skipping undefined values. */\nexport function setSvgAttrs(el: Element, attrs: Record<string, string | number | undefined>): void {\n\tfor (const [name, value] of Object.entries(attrs)) {\n\t\tif (value !== undefined) {\n\t\t\tel.setAttribute(name, String(value));\n\t\t}\n\t}\n}\n\n/** Create an SVG element in `doc` with the given attributes (undefined values skipped). */\nexport function createSvgEl<K extends keyof SVGElementTagNameMap>(\n\tdoc: Document,\n\ttag: K,\n\tattrs?: Record<string, string | number | undefined>,\n): SVGElementTagNameMap[K] {\n\tconst el = doc.createElementNS(SVG_NS, tag);\n\tif (attrs) {\n\t\tsetSvgAttrs(el, attrs);\n\t}\n\treturn el;\n}\n\n/**\n * One `ChartSvgDef` to its SVG node: a data point's picture-fill\n * `<pattern>`, or a chart gradient (`<linearGradient>` / `<radialGradient>`\n * in bounding-box units, see `chart-gradient-defs.ts`).\n */\nexport function renderPatternDef(doc: Document, def: ChartSvgDef): SVGElement {\n\tif (def.kind !== 'pattern') {\n\t\tconst gradient =\n\t\t\tdef.kind === 'linearGradient'\n\t\t\t\t? createSvgEl(doc, 'linearGradient', {\n\t\t\t\t\t\tid: def.id,\n\t\t\t\t\t\tx1: def.x1,\n\t\t\t\t\t\ty1: def.y1,\n\t\t\t\t\t\tx2: def.x2,\n\t\t\t\t\t\ty2: def.y2,\n\t\t\t\t\t})\n\t\t\t\t: createSvgEl(doc, 'radialGradient', { id: def.id, cx: def.cx, cy: def.cy, r: def.r });\n\t\tfor (const stop of def.stops) {\n\t\t\tgradient.appendChild(\n\t\t\t\tcreateSvgEl(doc, 'stop', {\n\t\t\t\t\toffset: stop.offset,\n\t\t\t\t\t'stop-color': stop.color,\n\t\t\t\t\t'stop-opacity': stop.opacity,\n\t\t\t\t}),\n\t\t\t);\n\t\t}\n\t\treturn gradient;\n\t}\n\tconst pattern = createSvgEl(doc, 'pattern', {\n\t\tid: def.id,\n\t\tpatternUnits: def.patternUnits,\n\t\tx: def.x,\n\t\ty: def.y,\n\t\twidth: def.width,\n\t\theight: def.height,\n\t});\n\tpattern.appendChild(\n\t\tcreateSvgEl(doc, 'image', {\n\t\t\thref: def.href,\n\t\t\tx: 0,\n\t\t\ty: 0,\n\t\t\twidth: def.width,\n\t\t\theight: def.height,\n\t\t\tpreserveAspectRatio: def.preserveAspectRatio,\n\t\t}),\n\t);\n\treturn pattern;\n}\n\n/**\n * Append the shared descriptor's tooltip as an SVG `<title>` child, when set.\n * Shared by every mark-primitive branch (rect / path / polyline / circle /\n * line / polygon) so a hover reveals the same value/label text the other four\n * bindings show.\n */\nexport function appendTitle(doc: Document, el: SVGElement, title: string | undefined): void {\n\tif (title === undefined) {\n\t\treturn;\n\t}\n\tconst titleEl = createSvgEl(doc, 'title', {});\n\ttitleEl.textContent = title;\n\tel.appendChild(titleEl);\n}\n\n/**\n * `data-chart-*` hit-testing attributes for a tagged data-mark primitive.\n * Inert without pointer events; emitted for parity with the other bindings so\n * hosts layering interaction on top can reuse the same shared hit-testing.\n */\nexport function applyPartAttrs(el: SVGElement, part: ChartPartRef | undefined): void {\n\tif (part) {\n\t\tsetSvgAttrs(el, chartPartToAttrs(part));\n\t}\n}\n","/**\n * Pure-DOM projector for the framework-agnostic chart view-model engine.\n *\n * `buildChartViewModel` projects a chart element into a `ChartViewModel` of\n * pure `SvgPrimitive` descriptors; this module maps that descriptor list to\n * real SVG DOM (no framework), mirroring Vue's `ChartViewModelSvg.vue` and\n * React's `renderChartViewModel`. The vanilla binding renders its charts with\n * it, and the 3D chart scene draws its SVG chrome overlay (title, legend,\n * axis labels) with the same code so 2D and 3D text match exactly.\n *\n * Moved here from `packages/vanilla/src/viewer/render/elements/chart-svg.ts`.\n *\n * @module chart-view-model-dom\n */\nimport { computeChartLegendLayout } from './chart-legend-layout';\nimport type { ChartViewModel, SvgLine, SvgPrimitive, SvgText } from './chart-view-model';\nimport {\n\tappendTitle,\n\tapplyPartAttrs,\n\tcreateSvgEl,\n\trenderPatternDef,\n} from './chart-view-model-dom-helpers';\n\n/** Render a full `ChartViewModel` to an `<svg>` element. */\nexport function renderChartViewModelSvg(\n\tdoc: Document,\n\tvm: ChartViewModel,\n\tpreserveAspectRatio: 'none' | 'xMidYMid meet',\n): SVGSVGElement {\n\tconst svg = createSvgEl(doc, 'svg', {\n\t\tclass: 'pptxv-chart-svg',\n\t\tviewBox: `0 0 ${vm.svgWidth} ${vm.svgHeight}`,\n\t\tpreserveAspectRatio,\n\t});\n\tsvg.style.setProperty('width', '100%');\n\tsvg.style.setProperty('height', '100%');\n\tsvg.style.setProperty('display', 'block');\n\n\t// c:dPt/c:pictureOptions picture-fill patterns, rendered before anything\n\t// references them via fill=\"url(#...)\".\n\tif (vm.defs && vm.defs.length > 0) {\n\t\tconst defs = createSvgEl(doc, 'defs', {});\n\t\tfor (const def of vm.defs) {\n\t\t\tdefs.appendChild(renderPatternDef(doc, def));\n\t\t}\n\t\tsvg.appendChild(defs);\n\t}\n\n\t// Skipped entirely when the deck declares `<a:noFill/>` on `c:chartSpace`:\n\t// an SVG `rect` with no `fill` paints black, so the element must not exist.\n\tif (vm.areaFill) {\n\t\tsvg.appendChild(\n\t\t\tcreateSvgEl(doc, 'rect', {\n\t\t\t\tx: 0,\n\t\t\t\ty: 0,\n\t\t\t\twidth: vm.svgWidth,\n\t\t\t\theight: vm.svgHeight,\n\t\t\t\trx: vm.areaRadius,\n\t\t\t\tfill: vm.areaFill,\n\t\t\t}),\n\t\t);\n\t}\n\n\tif (vm.title) {\n\t\tconst title = createSvgEl(doc, 'text', {\n\t\t\tx: vm.titleX,\n\t\t\ty: vm.titleY,\n\t\t\t'text-anchor': 'middle',\n\t\t\t'font-size': vm.titleStyle?.fontSize ?? 12,\n\t\t\t'font-weight': vm.titleStyle?.fontWeight ?? 600,\n\t\t\t'font-family': vm.titleStyle?.fontFamily,\n\t\t\tfill: vm.titleStyle?.fill ?? '#1e293b',\n\t\t\t'data-chart-part': 'title',\n\t\t});\n\t\tif (vm.titleRunSpans && vm.titleRunSpans.length > 0) {\n\t\t\tfor (const run of vm.titleRunSpans) {\n\t\t\t\tconst tspan = createSvgEl(doc, 'tspan', {\n\t\t\t\t\t'font-size': run.fontSize,\n\t\t\t\t\t'font-weight': run.fontWeight,\n\t\t\t\t\t'font-style': run.fontStyle,\n\t\t\t\t\t'font-family': run.fontFamily,\n\t\t\t\t\tfill: run.fill,\n\t\t\t\t});\n\t\t\t\ttspan.textContent = run.text;\n\t\t\t\ttitle.appendChild(tspan);\n\t\t\t}\n\t\t} else {\n\t\t\ttitle.textContent = vm.title;\n\t\t}\n\t\tsvg.appendChild(title);\n\t}\n\n\tfor (const gl of vm.gridlines) {\n\t\tsvg.appendChild(renderChartLineSvg(doc, gl));\n\t}\n\tfor (const gl of vm.secondaryGridlines ?? []) {\n\t\tsvg.appendChild(renderChartLineSvg(doc, gl));\n\t}\n\tfor (const lbl of vm.axisLabels) {\n\t\tsvg.appendChild(renderChartTextSvg(doc, lbl));\n\t}\n\tfor (const lbl of vm.secondaryAxisLabels ?? []) {\n\t\tsvg.appendChild(renderChartTextSvg(doc, lbl));\n\t}\n\tif (vm.zeroLine) {\n\t\tsvg.appendChild(renderChartLineSvg(doc, vm.zeroLine));\n\t}\n\tfor (const lbl of vm.categoryLabels) {\n\t\tsvg.appendChild(renderChartTextSvg(doc, lbl));\n\t}\n\n\tfor (const prim of vm.primitives) {\n\t\tconst node = renderChartPrimitiveSvg(doc, prim);\n\t\tif (node) {\n\t\t\tsvg.appendChild(node);\n\t\t}\n\t}\n\n\tfor (const dl of vm.dataLabels) {\n\t\tsvg.appendChild(renderChartTextSvg(doc, dl));\n\t}\n\n\tappendChartLegendSvg(doc, svg, vm);\n\treturn svg;\n}\n\n/** One `SvgPrimitive` descriptor to its SVG node (`null` for non-visual kinds). */\nexport function renderChartPrimitiveSvg(doc: Document, prim: SvgPrimitive): SVGElement | null {\n\tswitch (prim.kind) {\n\t\tcase 'rect': {\n\t\t\tconst el = createSvgEl(doc, 'rect', {\n\t\t\t\tx: prim.x,\n\t\t\t\ty: prim.y,\n\t\t\t\twidth: prim.w,\n\t\t\t\theight: prim.h,\n\t\t\t\tfill: prim.fill,\n\t\t\t\trx: prim.rx ?? 0,\n\t\t\t\topacity: prim.opacity ?? 1,\n\t\t\t});\n\t\t\tappendTitle(doc, el, prim.title);\n\t\t\tapplyPartAttrs(el, prim.part);\n\t\t\treturn el;\n\t\t}\n\t\tcase 'path': {\n\t\t\tconst el = createSvgEl(doc, 'path', {\n\t\t\t\td: prim.d,\n\t\t\t\tfill: prim.fill,\n\t\t\t\tstroke: prim.stroke ?? 'none',\n\t\t\t\t'stroke-width': prim.strokeWidth ?? 0,\n\t\t\t\t'stroke-dasharray': prim.dashArray,\n\t\t\t\t'fill-opacity': prim.opacity ?? 1,\n\t\t\t});\n\t\t\t// The shared descriptor's tooltip, as an SVG <title> child. It is the\n\t\t\t// shape's ACCESSIBLE NAME as well as its hover text, and a choropleth\n\t\t\t// patch carries no label of its own: without it a region map announces\n\t\t\t// nothing and names nothing.\n\t\t\tappendTitle(doc, el, prim.title);\n\t\t\tapplyPartAttrs(el, prim.part);\n\t\t\treturn el;\n\t\t}\n\t\tcase 'polyline': {\n\t\t\tconst el = createSvgEl(doc, 'polyline', {\n\t\t\t\tpoints: prim.points,\n\t\t\t\tstroke: prim.stroke,\n\t\t\t\t'stroke-width': prim.strokeWidth,\n\t\t\t\tfill: prim.fill,\n\t\t\t\topacity: prim.opacity ?? 1,\n\t\t\t});\n\t\t\tappendTitle(doc, el, prim.title);\n\t\t\tapplyPartAttrs(el, prim.part);\n\t\t\treturn el;\n\t\t}\n\t\tcase 'circle': {\n\t\t\tconst el = createSvgEl(doc, 'circle', {\n\t\t\t\tcx: prim.cx,\n\t\t\t\tcy: prim.cy,\n\t\t\t\tr: prim.r,\n\t\t\t\tfill: prim.fill,\n\t\t\t\topacity: prim.opacity ?? 1,\n\t\t\t});\n\t\t\tappendTitle(doc, el, prim.title);\n\t\t\tapplyPartAttrs(el, prim.part);\n\t\t\treturn el;\n\t\t}\n\t\tcase 'line':\n\t\t\treturn renderChartLineSvg(doc, prim);\n\t\tcase 'polygon': {\n\t\t\tconst el = createSvgEl(doc, 'polygon', {\n\t\t\t\tpoints: prim.points,\n\t\t\t\tfill: prim.fill,\n\t\t\t\tstroke: prim.stroke,\n\t\t\t\t'stroke-width': prim.strokeWidth,\n\t\t\t\topacity: prim.opacity ?? 1,\n\t\t\t\t'stroke-dasharray': prim.dashArray,\n\t\t\t\ttransform: prim.transform,\n\t\t\t});\n\t\t\tappendTitle(doc, el, prim.title);\n\t\t\tapplyPartAttrs(el, prim.part);\n\t\t\treturn el;\n\t\t}\n\t\tcase 'text':\n\t\t\treturn renderChartTextSvg(doc, prim);\n\t\t// Non-visual descriptor (gradient defs); the Vue/React projectors skip\n\t\t// it in their primitive switch as well.\n\t\tcase 'areaGradient':\n\t\t\treturn null;\n\t}\n}\n\nexport function renderChartLineSvg(doc: Document, line: SvgLine): SVGLineElement {\n\tconst el = createSvgEl(doc, 'line', {\n\t\tx1: line.x1,\n\t\ty1: line.y1,\n\t\tx2: line.x2,\n\t\ty2: line.y2,\n\t\tstroke: line.stroke,\n\t\t'stroke-width': line.strokeWidth,\n\t\t'stroke-dasharray': line.dashArray,\n\t\topacity: line.opacity ?? 1,\n\t\ttransform: line.transform,\n\t});\n\tappendTitle(doc, el, line.title);\n\treturn el;\n}\n\nexport function renderChartTextSvg(doc: Document, text: SvgText): SVGTextElement {\n\tconst el = createSvgEl(doc, 'text', {\n\t\tx: text.x,\n\t\ty: text.y,\n\t\t'text-anchor': text.textAnchor,\n\t\t'font-size': text.fontSize,\n\t\tfill: text.fill,\n\t\t'font-weight': text.fontWeight ?? 'normal',\n\t\t'font-style': text.fontStyle ?? 'normal',\n\t\t'font-family': text.fontFamily,\n\t\t'dominant-baseline': text.dominantBaseline,\n\t\topacity: text.opacity ?? 1,\n\t\ttransform: text.transform,\n\t});\n\tel.textContent = text.text;\n\treturn el;\n}\n\n/** Legend swatches + labels (horizontal row, or a vertical stack on the side). */\nexport function appendChartLegendSvg(doc: Document, svg: SVGElement, vm: ChartViewModel): void {\n\tcomputeChartLegendLayout(vm).forEach((item) => {\n\t\tconst g = createSvgEl(doc, 'g', {\n\t\t\t\tclass: 'pptxv-chart-legend-item',\n\t\t\t\ttransform: `translate(${item.x.toFixed(1)},${item.y.toFixed(1)})`,\n\t\t\t}),\n\t\t\tlabel = createSvgEl(doc, 'text', {\n\t\t\t\tx: 13,\n\t\t\t\ty: 3,\n\t\t\t\t'font-size': item.fontSize,\n\t\t\t\tfill: item.fill,\n\t\t\t\t'font-weight': item.fontWeight,\n\t\t\t\t'font-style': item.fontStyle,\n\t\t\t\t'font-family': item.fontFamily,\n\t\t\t});\n\t\tif (item.lineSwatch) {\n\t\t\tfor (const prim of item.lineSwatch.primitives) {\n\t\t\t\tconst node = renderChartPrimitiveSvg(doc, prim);\n\t\t\t\tif (node) {\n\t\t\t\t\tg.appendChild(node);\n\t\t\t\t}\n\t\t\t}\n\t\t} else {\n\t\t\tg.appendChild(\n\t\t\t\tcreateSvgEl(doc, 'rect', { x: 0, y: -7, width: 10, height: 10, rx: 2, fill: item.color }),\n\t\t\t);\n\t\t}\n\t\tlabel.textContent = item.label;\n\t\tg.appendChild(label);\n\t\tsvg.appendChild(g);\n\t});\n}\n","/**\n * Bars, gridlines and value-label text for the right-angle-axes 3D bar chart\n * (`chart-3d-oblique-layout.ts`), in the layout's world space.\n *\n * @module chart-3d-oblique-bars\n */\nimport type { PptxBar3DShape, PptxChartData } from 'pptx-viewer-core';\n\nimport type {\n\tObliqueBar,\n\tObliqueChartLayout,\n\tObliqueGridline,\n\tObliqueTaper,\n} from './chart-3d-oblique-layout';\nimport { formatAxisValueWithUnits } from './chart-axis';\nimport { axisTickValues } from './chart-view-model-chrome';\nimport type { ChartViewModel } from './chart-view-model-types';\n\ntype Grouping = ObliqueChartLayout['grouping'];\n\n/** Value-axis label text (`percentStacked` axes read as whole percents). */\nexport function formatValueLabel(chartData: PptxChartData, grouping: Grouping, v: number): string {\n\tif (grouping === 'percentStacked') {\n\t\treturn `${Math.round(v * 100)}%`;\n\t}\n\treturn formatAxisValueWithUnits(\n\t\tv,\n\t\tchartData.axes?.find((a) => a.axisType === 'valAx'),\n\t);\n}\n\n/**\n * A shaped bar's taper between world positions `lo` and `hi` along a value\n * axis `extent` long. A cone or pyramid comes to a point at its value end\n * (the far end from the baseline, so a negative bar points down); the\n * `...ToMax` shapes are slices of one solid whose apex sits at the axis end.\n */\nexport function obliqueBarTaper(\n\tshape: PptxBar3DShape,\n\tlo: number,\n\thi: number,\n\textent: number,\n\tvalue: number,\n): ObliqueTaper {\n\tswitch (shape) {\n\t\tcase 'cone':\n\t\tcase 'pyramid':\n\t\t\treturn value >= 0 ? { bottom: 1, top: 0 } : { bottom: 0, top: 1 };\n\t\tcase 'coneToMax':\n\t\tcase 'pyramidToMax': {\n\t\t\tconst at = (p: number): number => Math.min(1, Math.max(0, 1 - p / Math.max(extent, 1e-9)));\n\t\t\treturn { bottom: at(lo), top: at(hi) };\n\t\t}\n\t\tdefault:\n\t\t\treturn { bottom: 1, top: 1 };\n\t}\n}\n\n/** Axis position (world units along the value axis) of a value. */\nfunction valuePos(layout: ObliqueChartLayout, v: number): number {\n\treturn (v - layout.range.min) * layout.valueScale;\n}\n\nexport function buildBars(\n\tchartData: PptxChartData,\n\tvm: ChartViewModel,\n\tlayout: ObliqueChartLayout,\n\tdims: { nCat: number; slots: number; rows: number; gapWidth: number; gapDepth: number },\n): ObliqueBar[] {\n\tconst catExtent = layout.horizontal ? layout.box.h : layout.box.w;\n\tconst catWidth = catExtent / dims.nCat;\n\tconst barW = catWidth / (dims.slots + dims.gapWidth);\n\tconst rowDepth = barW * (1 + dims.gapDepth);\n\tconst colors = seriesColors(chartData, vm);\n\tconst valueExtent = layout.horizontal ? layout.box.w : layout.box.h;\n\tconst baseline = Math.min(Math.max(0, layout.range.min), layout.range.max);\n\tconst bars: ObliqueBar[] = [];\n\tfor (let c = 0; c < dims.nCat; c++) {\n\t\tlet pos = baseline;\n\t\tlet neg = baseline;\n\t\tconst total = chartData.series.reduce((sum, s) => sum + Math.abs(s.values[c] ?? 0), 0);\n\t\tchartData.series.forEach((series, s) => {\n\t\t\tconst raw = series.values[c];\n\t\t\tif (raw === undefined || Number.isNaN(raw)) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tconst value = layout.grouping === 'percentStacked' ? (total ? raw / total : 0) : raw;\n\t\t\tlet from = baseline;\n\t\t\tlet to = value;\n\t\t\tif (layout.grouping === 'stacked' || layout.grouping === 'percentStacked') {\n\t\t\t\tfrom = value >= 0 ? pos : neg;\n\t\t\t\tto = from + value;\n\t\t\t\tif (value >= 0) {\n\t\t\t\t\tpos = to;\n\t\t\t\t} else {\n\t\t\t\t\tneg = to;\n\t\t\t\t}\n\t\t\t}\n\t\t\tconst shape = series.shape ?? chartData.barShape ?? 'box';\n\t\t\tconst slot = layout.grouping === 'clustered' ? s : 0;\n\t\t\tconst row = layout.grouping === 'standard' ? s : 0;\n\t\t\tconst catStart = c * catWidth + (dims.gapWidth * barW) / 2 + slot * barW;\n\t\t\tconst lo = valuePos(layout, Math.max(Math.min(from, to), layout.range.min));\n\t\t\tconst hi = valuePos(layout, Math.min(Math.max(from, to), layout.range.max));\n\t\t\tconst z = row * rowDepth + (rowDepth - barW) / 2;\n\t\t\tconst along = layout.horizontal\n\t\t\t\t? { x: lo, w: Math.max(hi - lo, 0), y: catStart, h: barW }\n\t\t\t\t: { x: catStart, w: barW, y: lo, h: Math.max(hi - lo, 0) };\n\t\t\tbars.push({\n\t\t\t\t...along,\n\t\t\t\tz,\n\t\t\t\td: barW,\n\t\t\t\tcolor: colors[s],\n\t\t\t\tseriesIndex: s,\n\t\t\t\tcategoryIndex: c,\n\t\t\t\tvalue: raw,\n\t\t\t\tshape,\n\t\t\t\ttaper: obliqueBarTaper(shape, lo, hi, valueExtent, raw),\n\t\t\t});\n\t\t});\n\t}\n\treturn bars;\n}\n\n/** Series colours as the flat chart resolved them (legend swatches carry them). */\nfunction seriesColors(chartData: PptxChartData, vm: ChartViewModel): string[] {\n\treturn chartData.series.map(\n\t\t(s, i) =>\n\t\t\tvm.legend.find((entry) => entry.label === s.name)?.color ?? vm.legend[i]?.color ?? '#4472c4',\n\t);\n}\n\nexport function buildGridlines(layout: ObliqueChartLayout): ObliqueGridline[] {\n\tconst { w, h, d } = layout.box;\n\tconst lines: ObliqueGridline[] = [];\n\tconst span = layout.range.max - layout.range.min;\n\tfor (const v of axisTickValues({ ...layout.range, span })) {\n\t\tconst p = valuePos(layout, v);\n\t\tif (layout.horizontal) {\n\t\t\tlines.push({ from: [p, 0, d], to: [p, h, d] }, { from: [p, 0, 0], to: [p, 0, d] });\n\t\t} else {\n\t\t\tlines.push({ from: [0, p, d], to: [w, p, d] }, { from: [0, p, 0], to: [0, p, d] });\n\t\t}\n\t}\n\treturn lines;\n}\n","/**\n * The right-angle-axes (`c:view3D/@rAngAx=1`) variant of the perspective\n * chart camera (`chart-3d-persp-view.ts`), for the line / area / surface box:\n * PowerPoint draws such a chart as an oblique projection, like the bar chart\n * (`chart-3d-oblique-layout.ts`): the front plane is flat and each unit of\n * depth shifts `sin(rotY)` right and `sin(rotX)` up.\n *\n * The oblique camera plugs into the same `PerspView` pipeline: its \"camera\n * space\" is the box-centred point with depth folded in (`Z = 1`), so\n * `perspToScreen`, the rect fit and the labels work unchanged.\n *\n * @module chart-3d-persp-oblique\n */\nimport type * as THREE from 'three';\n\nimport type { PerspBox, PerspCamera, PerspView } from './chart-3d-persp-view';\n\ntype ThreeModule = typeof THREE;\n\n/** An oblique camera's depth shear, screen units per unit of depth. */\nexport interface PerspOblique {\n\t/** Rightward shift per unit of depth, `sin(rotY)`. */\n\tshearX: number;\n\t/** Upward shift per unit of depth, `sin(rotX)`. */\n\tshearY: number;\n}\n\n/** The oblique camera for a box and its `c:view3D` angles (degrees). */\nexport function perspObliqueCameraFor(\n\tbox: PerspBox,\n\trotXDeg: number,\n\trotYDeg: number,\n): PerspCamera {\n\treturn {\n\t\tbox,\n\t\tyaw: 0,\n\t\tpitch: 0,\n\t\tdist: 1,\n\t\toblique: {\n\t\t\tshearX: Math.sin((rotYDeg * Math.PI) / 180),\n\t\t\tshearY: Math.sin((rotXDeg * Math.PI) / 180),\n\t\t},\n\t};\n}\n\n/** Oblique \"camera space\": box-centred, depth sheared in, `Z = 1`. */\nexport function perspObliqueToCamera(\n\tbox: PerspBox,\n\toblique: PerspOblique,\n\tp: readonly [number, number, number],\n): [number, number, number] {\n\tconst x = p[0] - box.w / 2;\n\tconst y = p[1] - box.h / 2;\n\tconst z = p[2] - box.d / 2;\n\treturn [x + z * oblique.shearX, y + z * oblique.shearY, 1];\n}\n\n/**\n * A three.js camera for an oblique view: an affine projection of the\n * box-centred space of {@link perspObliqueBoxMatrix}, nearer depth drawn in\n * front. Its inverse unprojects to straight rays, so picking works as for the\n * perspective camera.\n */\nexport function buildPerspObliqueCamera(\n\tthree: ThreeModule,\n\tview: PerspView,\n\toblique: PerspOblique,\n\tsvgWidth: number,\n\tsvgHeight: number,\n): THREE.Camera {\n\tconst camera = new three.Camera();\n\tconst reach = Math.hypot(view.box.w, view.box.h, view.box.d);\n\tconst sx = (2 * view.focal) / svgWidth;\n\tconst sy = (2 * view.focal) / svgHeight;\n\tcamera.projectionMatrix.set(\n\t\tsx,\n\t\t0,\n\t\tsx * oblique.shearX,\n\t\t(2 * view.cx) / svgWidth - 1,\n\t\t0,\n\t\tsy,\n\t\tsy * oblique.shearY,\n\t\t1 - (2 * view.cy) / svgHeight,\n\t\t0,\n\t\t0,\n\t\t1 / reach,\n\t\t0,\n\t\t0,\n\t\t0,\n\t\t0,\n\t\t1,\n\t);\n\tcamera.projectionMatrixInverse.copy(camera.projectionMatrix).invert();\n\treturn camera;\n}\n\n/** Box space to the box-centred space of {@link buildPerspObliqueCamera}. */\nexport function perspObliqueBoxMatrix(three: ThreeModule, box: PerspBox): THREE.Matrix4 {\n\treturn new three.Matrix4().makeTranslation(-box.w / 2, -box.h / 2, -box.d / 2);\n}\n","/**\n * PowerPoint's perspective 3D chart camera (`c:view3D/@rAngAx=0`: line3D,\n * area3D, surface3D), as a pure projection plus its three.js camera.\n *\n * Fitted to PowerPoint's own exports of the three-d-parity deck: the ends and\n * corners of every wall gridline in `gt/chart-10..12,16` were traced and a\n * camera fitted to them (0.4-2pt RMS per chart):\n *\n * - The plot is a box `w x h x d` (x categories, y values, z depth away from\n * the viewer). It is yawed by `rotY` about its vertical centre line, then\n * pitched toward the viewer by `0.92 * rotX` (the fitted pitch was\n * 13.6-14.0 degrees for every `rotX = 15` chart).\n * - The camera looks at the box centre from `diagonal / (2 tan(fov / 2))`\n * away, `fov` being `c:view3D/c:perspective` in degrees (default 30): the\n * box's bounding sphere just fills the field of view. The fitted distances\n * were 1.8-1.9 box diagonals.\n *\n * A box point `(x, y, z)` (origin at the front-bottom-left corner) lands at\n * chart px `(cx + f X / Z, cy - f Y / Z)`, `(X, Y, Z)` being the point in\n * camera space; {@link fitPerspView} picks `f`, `cx`, `cy` so the box fills a\n * target rect.\n *\n * @module chart-3d-persp-view\n */\nimport type * as THREE from 'three';\n\nimport {\n\tbuildPerspObliqueCamera,\n\tperspObliqueBoxMatrix,\n\tperspObliqueToCamera,\n} from './chart-3d-persp-oblique';\nimport type { PerspOblique } from './chart-3d-persp-oblique';\n\ntype ThreeModule = typeof THREE;\n\n/** Fitted pitch per degree of `rotX`. */\nexport const PERSP_PITCH_PER_ROTX = 0.92;\n/** `c:perspective` default: the field of view in degrees. */\nexport const PERSP_DEFAULT_FOV = 30;\n\nexport interface PerspBox {\n\tw: number;\n\th: number;\n\td: number;\n}\n\nexport interface PerspCamera {\n\tbox: PerspBox;\n\t/** Yaw (`rotY`) in radians: positive brings the box's right end toward the viewer. */\n\tyaw: number;\n\t/** Pitch in radians: positive tips the top of the box away (the viewer looks down). */\n\tpitch: number;\n\t/** Camera distance from the box centre, world units. */\n\tdist: number;\n\t/** Set for a right-angle-axes chart: an oblique projection instead (`chart-3d-persp-oblique.ts`). */\n\toblique?: PerspOblique;\n}\n\nexport interface PerspView extends PerspCamera {\n\t/** Focal length: chart px per world unit at unit depth. */\n\tfocal: number;\n\t/** Chart px of the box centre. */\n\tcx: number;\n\tcy: number;\n}\n\n/** Camera-space coordinates `(X, Y, Z)` of a box point; `Z` is the depth ahead of the camera. */\nexport function perspToCamera(\n\tcamera: PerspCamera,\n\tp: readonly [number, number, number],\n): [number, number, number] {\n\tif (camera.oblique) {\n\t\treturn perspObliqueToCamera(camera.box, camera.oblique, p);\n\t}\n\tconst x = p[0] - camera.box.w / 2;\n\tconst y = p[1] - camera.box.h / 2;\n\tconst z = p[2] - camera.box.d / 2;\n\tconst cy = Math.cos(camera.yaw);\n\tconst sy = Math.sin(camera.yaw);\n\tconst cp = Math.cos(camera.pitch);\n\tconst sp = Math.sin(camera.pitch);\n\tconst x1 = x * cy + z * sy;\n\tconst z1 = -x * sy + z * cy;\n\treturn [x1, y * cp + z1 * sp, z1 * cp - y * sp + camera.dist];\n}\n\n/** Chart px of a box point. */\nexport function perspToScreen(\n\tview: PerspView,\n\tp: readonly [number, number, number],\n): { x: number; y: number } {\n\tconst [X, Y, Z] = perspToCamera(view, p);\n\treturn { x: view.cx + (view.focal * X) / Z, y: view.cy - (view.focal * Y) / Z };\n}\n\n/** The camera for a box and its `c:view3D` angles (degrees), before scale and placement. */\nexport function perspCameraFor(\n\tbox: PerspBox,\n\trotXDeg: number,\n\trotYDeg: number,\n\tfovDeg: number = PERSP_DEFAULT_FOV,\n): PerspCamera {\n\tconst diagonal = Math.hypot(box.w, box.h, box.d);\n\tconst fov = Math.min(Math.max(fovDeg, 1), 170);\n\tconst dist = diagonal / (2 * Math.tan(((fov / 2) * Math.PI) / 180));\n\treturn {\n\t\tbox,\n\t\tyaw: (rotYDeg * Math.PI) / 180,\n\t\tpitch: (rotXDeg * PERSP_PITCH_PER_ROTX * Math.PI) / 180,\n\t\tdist,\n\t};\n}\n\n/** The box's eight corners. */\nfunction boxCorners(box: PerspBox): Array<[number, number, number]> {\n\treturn Array.from({ length: 8 }, (_, i): [number, number, number] => [\n\t\t(i & 1) * box.w,\n\t\t((i >> 1) & 1) * box.h,\n\t\t((i >> 2) & 1) * box.d,\n\t]);\n}\n\n/** Bounds of the projection of `points` (default: the box corners) at focal 1, box centre at (0, 0). */\nexport function perspUnitBounds(\n\tcamera: PerspCamera,\n\tpoints: ReadonlyArray<readonly [number, number, number]> = boxCorners(camera.box),\n): { minX: number; maxX: number; minY: number; maxY: number } {\n\tlet minX = Infinity;\n\tlet maxX = -Infinity;\n\tlet minY = Infinity;\n\tlet maxY = -Infinity;\n\tfor (const p of points) {\n\t\tconst [X, Y, Z] = perspToCamera(camera, p);\n\t\tminX = Math.min(minX, X / Z);\n\t\tmaxX = Math.max(maxX, X / Z);\n\t\tminY = Math.min(minY, -Y / Z);\n\t\tmaxY = Math.max(maxY, -Y / Z);\n\t}\n\treturn { minX, maxX, minY, maxY };\n}\n\n/**\n * Scale and place a camera so the projection of `points` (default: the box\n * corners) fits inside `rect` (chart px) as large as it can, centred in it\n * (`gt/chart-11`, a box too wide for its rect, sits midway down it).\n */\nexport function fitPerspView(\n\tcamera: PerspCamera,\n\trect: { left: number; top: number; right: number; bottom: number },\n\tpoints?: ReadonlyArray<readonly [number, number, number]>,\n): PerspView {\n\tconst b = perspUnitBounds(camera, points);\n\tconst focal = Math.min(\n\t\t(rect.right - rect.left) / (b.maxX - b.minX),\n\t\t(rect.bottom - rect.top) / (b.maxY - b.minY),\n\t);\n\treturn {\n\t\t...camera,\n\t\tfocal,\n\t\tcx: (rect.left + rect.right) / 2 - (focal * (b.minX + b.maxX)) / 2,\n\t\tcy: (rect.top + rect.bottom) / 2 - (focal * (b.minY + b.maxY)) / 2,\n\t};\n}\n\n/**\n * Where the view ray through chart px `(sx, sy)` meets the horizontal box\n * plane at height `y`, as box `(x, z)`; `null` when the ray runs parallel to\n * it or meets it behind the camera.\n */\nexport function perspScreenToPlaneY(\n\tview: PerspView,\n\tsx: number,\n\tsy: number,\n\ty: number,\n): { x: number; z: number } | null {\n\t// Ray direction in camera space (Z = 1), rotated back into box space.\n\tconst dx = (sx - view.cx) / view.focal;\n\tconst dy = (view.cy - sy) / view.focal;\n\tconst cp = Math.cos(view.pitch);\n\tconst sp = Math.sin(view.pitch);\n\tconst cyw = Math.cos(view.yaw);\n\tconst syw = Math.sin(view.yaw);\n\t// Inverse pitch: (x1, y, z1) from (X, Y, Z).\n\tconst invPitch = (X: number, Y: number, Z: number): [number, number, number] => [\n\t\tX,\n\t\tY * cp - Z * sp,\n\t\tY * sp + Z * cp,\n\t];\n\t// Inverse yaw: box-centred (x, z) from (x1, z1).\n\tconst invYaw = (x1: number, z1: number): [number, number] => [\n\t\tx1 * cyw - z1 * syw,\n\t\tx1 * syw + z1 * cyw,\n\t];\n\tconst [ox1, oy, oz1] = invPitch(0, 0, -view.dist);\n\tconst [dx1, dyb, dz1] = invPitch(dx, dy, 1);\n\tconst [ox, oz] = invYaw(ox1, oz1);\n\tconst [ddx, ddz] = invYaw(dx1, dz1);\n\tconst target = y - view.box.h / 2;\n\tif (Math.abs(dyb) < 1e-12) {\n\t\treturn null;\n\t}\n\tconst t = (target - oy) / dyb;\n\tif (t <= 0) {\n\t\treturn null;\n\t}\n\treturn { x: ox + ddx * t + view.box.w / 2, z: oz + ddz * t + view.box.d / 2 };\n}\n\n/**\n * A three.js camera that renders box-space geometry exactly where\n * {@link perspToScreen} puts it, on a canvas of `svgWidth x svgHeight` chart\n * px. It sits at the origin looking down -Z with an off-centre projection;\n * place the box group with {@link perspBoxMatrix}.\n */\nexport function buildPerspCamera(\n\tthree: ThreeModule,\n\tview: PerspView,\n\tsvgWidth: number,\n\tsvgHeight: number,\n): THREE.Camera {\n\tif (view.oblique) {\n\t\treturn buildPerspObliqueCamera(three, view, view.oblique, svgWidth, svgHeight);\n\t}\n\tconst reach = Math.hypot(view.box.w, view.box.h, view.box.d);\n\tconst near = Math.max(view.dist - reach, view.dist * 0.05);\n\tconst far = view.dist + reach;\n\tconst camera = new three.PerspectiveCamera(30, svgWidth / svgHeight, near, far);\n\tcamera.projectionMatrix.set(\n\t\t(2 * view.focal) / svgWidth,\n\t\t0,\n\t\t(2 * view.cx) / svgWidth - 1,\n\t\t0,\n\t\t0,\n\t\t(2 * view.focal) / svgHeight,\n\t\t1 - (2 * view.cy) / svgHeight,\n\t\t0,\n\t\t0,\n\t\t0,\n\t\t-(far + near) / (far - near),\n\t\t(-2 * far * near) / (far - near),\n\t\t0,\n\t\t0,\n\t\t-1,\n\t\t0,\n\t);\n\t// Three's view space looks down -Z, so the third column multiplies -Z:\n\t// negate it for the principal-point terms to add at positive depth.\n\tconst e = camera.projectionMatrix.elements;\n\te[8] = -e[8];\n\te[9] = -e[9];\n\tcamera.projectionMatrixInverse.copy(camera.projectionMatrix).invert();\n\treturn camera;\n}\n\n/** The matrix taking box space to the view space of {@link buildPerspCamera}. */\nexport function perspBoxMatrix(three: ThreeModule, view: PerspCamera): THREE.Matrix4 {\n\tif (view.oblique) {\n\t\treturn perspObliqueBoxMatrix(three, view.box);\n\t}\n\tconst { w, h, d } = view.box;\n\treturn new three.Matrix4()\n\t\t.makeScale(1, 1, -1)\n\t\t.multiply(new three.Matrix4().makeTranslation(0, 0, view.dist))\n\t\t.multiply(new three.Matrix4().makeRotationX(-view.pitch))\n\t\t.multiply(new three.Matrix4().makeRotationY(view.yaw))\n\t\t.multiply(new three.Matrix4().makeTranslation(-w / 2, -h / 2, -d / 2));\n}\n","/**\n * PowerPoint's 3-D Pie (`c:pie3DChart`) as a disc in the perspective chart\n * camera (`chart-3d-persp-view.ts`), fitted to `gt/chart-14,15`:\n *\n * - The pie is a puck of radius 1 and thickness `0.23` (box `2 x 0.23 x 2`,\n * scaled by `c:view3D/@hPercent`), pitched `0.91 * rotX` toward the viewer\n * (27.2 degrees fitted for rotX 30) and seen from `1.38` box diagonals: a\n * closer camera than the cartesian charts use, so the front of the pie is\n * visibly larger than the back.\n * - The first slice starts at 12 o'clock (plus `c:firstSliceAng`) and slices\n * run clockwise seen from above.\n * - The unexploded puck fits the plot rect; exploding shrinks the radius by\n * `1 / (1 + explosion)` and moves each slice out along its bisector by its\n * own explosion, so an exploded pie keeps the same footprint.\n *\n * @module chart-3d-pie-layout\n */\nimport type { PptxElement } from 'pptx-viewer-core';\n\nimport { fitPerspView, perspCameraFor } from './chart-3d-persp-view';\nimport type { PerspView } from './chart-3d-persp-view';\nimport type { ChartViewModel } from './chart-view-model-types';\n\n/** Points to chart px (96 dpi). */\nconst PT = 4 / 3;\n/** Puck thickness per unit radius. */\nconst PIE_THICKNESS = 0.23;\n/** Fitted pitch per degree of rotX. */\nconst PIE_PITCH_PER_ROTX = 0.91;\n/** Fitted camera distance, in box diagonals. */\nconst PIE_CAMERA_DIAGONALS = 1.38;\nconst RECT_MARGIN = 18 * PT;\nconst RECT_TOP_WITH_TITLE = 48 * PT;\nconst RECT_TOP_NO_TITLE = 14 * PT;\nconst RECT_BOTTOM_WITH_LEGEND = 44 * PT;\nconst RECT_BOTTOM_NO_LEGEND = 14 * PT;\n/** Rim samples used to fit the disc. */\nconst RIM_SAMPLES = 96;\n\nexport interface PieSlice {\n\tpointIndex: number;\n\tvalue: number;\n\tcolor: string;\n\t/** Clockwise from 12 o'clock, radians. */\n\tstartAngle: number;\n\tendAngle: number;\n\t/** Box-space offset of the exploded slice. */\n\toffset: { x: number; z: number };\n}\n\nexport interface PieChartLayout {\n\tview: PerspView;\n\t/** Box-space centre of the pie's top face (its bottom face sits on y = 0). */\n\tcenter: { x: number; y: number; z: number };\n\tradius: number;\n\tthickness: number;\n\tslices: PieSlice[];\n}\n\n/** Box (x, z) of the rim at `angle` (clockwise from 12 o'clock) for a pie centred at (cx, cz). */\nexport function pieRimPoint(\n\tcx: number,\n\tcz: number,\n\tradius: number,\n\tangle: number,\n): { x: number; z: number } {\n\treturn { x: cx + radius * Math.sin(angle), z: cz + radius * Math.cos(angle) };\n}\n\n/**\n * The flat pie's view model is square (its 2D render letterboxes a square\n * viewBox into the frame); the 3D scene draws across the whole frame, so\n * widen it to the element's own aspect, keeping the centred title and legend\n * centred.\n */\nexport function widenPieViewModel(vm: ChartViewModel, element: PptxElement): ChartViewModel {\n\tconst width = vm.svgHeight * (element.width / Math.max(element.height, 1));\n\tconst dx = (width - vm.svgWidth) / 2;\n\tif (Math.abs(dx) < 1e-6) {\n\t\treturn vm;\n\t}\n\treturn {\n\t\t...vm,\n\t\tsvgWidth: width,\n\t\ttitleX: vm.titleX + dx,\n\t\tlegendX: vm.legendAnchor === 'middle' ? vm.legendX + dx : vm.legendX,\n\t};\n}\n\n/** The 3-D pie layout of a `pie3D` chart element, or `null`. */\nexport function computePieChartLayout(\n\telement: PptxElement,\n\tvm: ChartViewModel,\n): PieChartLayout | null {\n\tif (element.type !== 'chart' || !element.chartData) {\n\t\treturn null;\n\t}\n\tconst chartData = element.chartData;\n\tconst series = chartData.series[0];\n\tif (!series || series.values.length === 0) {\n\t\treturn null;\n\t}\n\tconst view3D = chartData.view3D;\n\tconst thickness = PIE_THICKNESS * ((view3D?.hPercent ?? 100) / 100);\n\tconst box = { w: 2, h: thickness, d: 2 };\n\tconst camera = perspCameraFor(box, 0, view3D?.rotY ?? 0);\n\tcamera.pitch = ((view3D?.rotX ?? 30) * PIE_PITCH_PER_ROTX * Math.PI) / 180;\n\tcamera.dist = PIE_CAMERA_DIAGONALS * Math.hypot(box.w, box.h, box.d);\n\tconst rim: Array<[number, number, number]> = [];\n\tfor (let i = 0; i < RIM_SAMPLES; i++) {\n\t\tconst a = (i / RIM_SAMPLES) * Math.PI * 2;\n\t\tconst p = pieRimPoint(1, 1, 1, a);\n\t\trim.push([p.x, 0, p.z], [p.x, box.h, p.z]);\n\t}\n\tconst hasLegend =\n\t\tchartData.style?.hasLegend !== false && (chartData.style?.legendPosition ?? 'b') === 'b';\n\tconst view = fitPerspView(\n\t\tcamera,\n\t\t{\n\t\t\tleft: RECT_MARGIN,\n\t\t\tright: vm.svgWidth - RECT_MARGIN,\n\t\t\ttop: vm.title ? RECT_TOP_WITH_TITLE : RECT_TOP_NO_TITLE,\n\t\t\tbottom: vm.svgHeight - (hasLegend ? RECT_BOTTOM_WITH_LEGEND : RECT_BOTTOM_NO_LEGEND),\n\t\t},\n\t\trim,\n\t);\n\n\tconst explosionOf = (i: number): number =>\n\t\tMath.max(\n\t\t\t0,\n\t\t\t(series.dataPoints?.find((d) => d.idx === i)?.explosion ?? series.explosion ?? 0) / 100,\n\t\t);\n\tconst values = series.values.map((v) => (Number.isFinite(v) ? Math.abs(v) : 0));\n\tconst maxExplosion = values.reduce((m, _v, i) => Math.max(m, explosionOf(i)), 0);\n\tconst radius = 1 / (1 + maxExplosion);\n\tconst total = values.reduce((t, v) => t + v, 0) || 1;\n\tlet angle = ((chartData.firstSliceAngle ?? 0) * Math.PI) / 180;\n\tconst slices = values.map((value, i): PieSlice => {\n\t\tconst startAngle = angle;\n\t\tconst endAngle = angle + (value / total) * Math.PI * 2;\n\t\tangle = endAngle;\n\t\tconst mid = (startAngle + endAngle) / 2;\n\t\tconst out = explosionOf(i) * radius;\n\t\treturn {\n\t\t\tpointIndex: i,\n\t\t\tvalue: series.values[i],\n\t\t\tcolor: vm.legend[i]?.color ?? '#4472c4',\n\t\t\tstartAngle,\n\t\t\tendAngle,\n\t\t\toffset: { x: out * Math.sin(mid), z: out * Math.cos(mid) },\n\t\t};\n\t});\n\treturn {\n\t\tview,\n\t\tcenter: { x: 1, y: box.h * radius, z: 1 },\n\t\tradius,\n\t\tthickness: box.h * radius,\n\t\tslices,\n\t};\n}\n","/**\n * Pure raycast-hit -> hover-tooltip mapping for the interactive 3D bar chart\n * scene ({@link ./bar-chart-3d-scene.ts}).\n *\n * Unlike the surface chart's single continuous mesh (which recovers a grid\n * cell from a triangle `faceIndex`, see `surface-chart-3d-hit-test.ts`), each\n * bar3D data point is its OWN box mesh, so the scene controller tags every\n * box's `userData` with its (series, category) indices directly and a\n * `Raycaster.intersectObjects` hit reports them straight from the hit\n * object - no face-index arithmetic needed. This module only builds the\n * tooltip text from those indices, kept three-agnostic so it is unit-testable\n * without mocking WebGL.\n *\n * @module bar-chart-3d-hit-test\n */\nimport { buildMarkTooltip } from './chart-view-model';\n\n/** The (series, category) a raycast hit landed on, plus its authored value. */\nexport interface BarChart3DHit {\n\tseriesIndex: number;\n\tcategoryIndex: number;\n\tvalue: number;\n}\n\n/** The subset of {@link BarChart3DSceneOptions} the hover tooltip needs. */\nexport interface BarChart3DHoverTooltipData {\n\tcategoryLabels: ReadonlyArray<string>;\n\tseriesNames: ReadonlyArray<string>;\n\tnumberFormats?: ReadonlyArray<string | undefined>;\n}\n\n/**\n * Build the hover-tooltip text for a raycast hit on a bar3D box mesh, or\n * `undefined` when there is no hit.\n *\n * Mirrors `buildMarkTooltip`'s \"<series>, <category>: <value>\" text exactly,\n * so a bar3D box's tooltip reads identically to the flat SVG bar renderer's.\n */\nexport function buildBarChart3DHoverTooltip(\n\thit: BarChart3DHit | null | undefined,\n\tdata: BarChart3DHoverTooltipData,\n): string | undefined {\n\tif (!hit) {\n\t\treturn undefined;\n\t}\n\treturn buildMarkTooltip(\n\t\tdata.seriesNames[hit.seriesIndex],\n\t\tdata.categoryLabels[hit.categoryIndex],\n\t\thit.value,\n\t\tdata.numberFormats?.[hit.seriesIndex],\n\t);\n}\n"],"mappings":"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"}
|