<!-- 04_VISUAL/xwui/xwui-lib/xwui-lib-super/src/charts/XWUIBarPlot/XWUIBarPlot.md -->
# XWUIBarPlot

One bar engine for buckets of segments: stacked columns with capacity (one line or one per bucket), over and under
states, a dashed "before" ghost and status-toned buckets; histograms from pre-binned counts with tone bands, a
cumulative overlay on a percent scale, percentile and reference markers and a draggable, keyboard-operable target that
reports the probability at or below it; diverging rows (tornado, variance) from a shared zero; and share bars whose
legend percentages sum to 100. Every bar is reachable with a roving tab stop, every drawing has a text summary and a
table twin. Engine-switchable: native DOM, React, Vue and Preact render the same tree (`native-baseline.json`).

Spec: plnx `REF_06_GAPS.md` section 2.2, C08. Absorbs P-G12 `XWUIStackedColumns`, W:CapacityHistogram,
W:DistributionChart, C-G8 `XWUIDistributionPlot`, C-G7 `XWUIImpactBars` (+C-W7), W:ShareBar, the `bars` kind of
W:MicroChart and S-W10.

## Basic Usage

```example
file: examples/BasicUsage.ts
html: examples/BasicUsage.html
title: Basic Usage
description: Runs per hour stacked by outcome, the last hour partial.
```

Scenario examples: `MonteCarloHistogram`, `CapacityVsDemand`, `TopDrivers`, `ShareBar` (see `SCENARIOS.md`).

## Data

```ts
data: {
  buckets: Array<{
    id: string;                        // unique; a repeated id is suffixed (k~1) so events name one bar
    label?: string; code?: string; sub?: string;
    segments?: Array<{ key: string; value: number; hue?: string; pattern?: 'solid' | 'hatch' | 'outline'; label?: string }>;
    value?: number;                    // one-segment shorthand (histogram bins)
    low?: number; high?: number;       // diverging rows, sign kept
    ghost?: number | Segment[];        // dashed "before" / "if everything ran" outline
    partial?: boolean; dimmed?: boolean;
    total?: string;                    // own total text ("22 / 26"), printed under the label
    tone?: string; note?: string;      // status colouring: the whole bar in one tone, and its word
  }>;
  series?: Array<{ key: string; label: string; hue?: string; pattern?: Pattern }>;   // legend order, labels, hues
  capacity?: number | number[]; capacityLabel?: string;
  overlay?: { values: number[]; label: string; area?: boolean };   // 0..100; one value per bucket = far edge
  markers?: Array<{ id: string; at: number; label: string; kind: 'percentile' | 'reference' | 'data-date' | 'target'; hue?: string }>;
  bands?: Array<{ from: number; to: number; tone: string }>;
  axis?: Array<{ at: number; label: string }>;          // domain ticks
  valueAxis?: Array<{ at: number; label: string }>;     // value gridlines
  domain?: [number, number];                            // default 0 .. bucket count
  selectedId?: string | null;
  status?: 'ready' | 'loading' | 'error' | 'stale';
}
```

Colours are token NAMES, never values: a hue (`indigo`, `teal`, `rose`, ... resolved by the style tier's `hueVar` to
`var(--xwui-hue-<name>)`, so a host may add names), a status tone (`ok`, `info`, `warn`, `error`, `neutral`) or a
health state (`on-track`, `at-risk`, `off-track`, `none`). Anything that is not a plain identifier is refused.

## Options (`conf_comp`)

| Option | Default | What it does |
| --- | --- | --- |
| `mode` | `'stacked'` | `stacked`, `histogram`, `diverging`, `share` |
| `orientation` | `'vertical'` | stacked and histogram plots; diverging and share are rows |
| `split` | none | `{ by: 'target' \| 'markers', tones, labels? }`: bin colour before and after the target, or per marker region |
| `target` | not editable | `{ editable, step, tag }`; `tag` takes `{name}`, `{at}`, `{p}` |
| `overStyle` | `'segment'` | over capacity drawn hatched (`segment`), tinted (`tint`) or outlined (`outline`) |
| `shortfall` | `false` | draw the gap under capacity as a dashed box and say it |
| `legend` | `'below'` | `'none'` hides it |
| `showTotals` | `false` | the number on each bar (a bucket's `total` text always shows under its label) |
| `rounding` | `'largest-remainder'` | share percentages; `'round'` may not sum to 100 |
| `progress` | `'final'` | `'live'` while counts grow: `aria-busy`, heights transition |
| `height` | `'md'` | size name `xs`, `sm` (spark), `md`, `lg`, `xl` |
| `mirrorInRtl` | by mode | rows mirror; vertical number and time axes stay an LTR island |
| `transitionMs` | `180` | 0 under `prefers-reduced-motion` whatever is set |
| `tableTwin` | `true` | visually hidden table of every value |
| `maxBars` | `500` | newest buckets kept (1 to 500); pass 24 for the XWUIBucketBars window |
| `ticks` | auto | label every n-th bucket from the newest; unset = all when 16 or fewer |
| `percentiles` | none | automatic markers from the counts, e.g. `[50, 80, 95]` |
| `headroom`, `valueMax` | `0`, none | free space above the tallest bar; a fixed top of the scale |
| `unit` | `''` | suffix after every value in text |
| `ariaLabel`, `emptyText`, `labels` | locale pack | copy; `labels` overrides any `xwui.bar_plot.*` word |
| `locale`, `numberingSystem` | page, `'latn'` | number formatting; Western digits by default |

## Events and methods

Events (on the logic, and as DOM `CustomEvent`s on the host): `bucketSelect { id, selected }`,
`targetChange { at, p }`, `targetCommit { at, p }`, `markerSelect { id }`.

Methods: `select(id)` (picking the selected one releases it), `getSelectedId()`, `appendCounts(delta, withData?)` and
`setCounts(counts, withData?)` (live fill by index array or id map; `withData` such as the overlay lands in the same
commit), `setStatus(status)`, `setFormatAt(fn)` (text of a domain value: dates, money; trusted host code),
`onBucketSelect`, `onTargetChange`, `onTargetCommit`, `onMarkerSelect`, `updateData`, `updateConfig`, `getElement`,
`destroy` (idempotent; releases the view mount, the reduced-motion listener, a pointer capture and the logic).
`XWUIBarPlot.projectView(data, config, ctx)` composes a still render into another component's tree.

Pure helpers (exported): `binValues` (raw observations to counts), `percentileAt`, `probabilityAt`,
`cumulativePercents`, `sharePercents`, `xOf`, `toneRef`, `buildBarPlotModel`.

## Accessibility and RTL

- The root is a `figure role="group"` named by `ariaLabel`. The drawing (bands, gridlines, capacity, curve) is one
  `role="img"` whose name is the summary: bar count and peak, results and bins with every marker, over-capacity count,
  the target's probability, "Stale".
- Each bar is `role="img"` with its full text (`Q1 2027: Total 32, ERP rollout 18, ..., Capacity 30 (over capacity by 2)`).
  One bar owns the tab stop (the selected one, else the newest column or the first row). Columns: Left and Right (they
  follow the bar they point at when the axis is mirrored); rows: Up and Down; Home and End; Enter and Space select.
- The target handle is a `role="slider"` with `aria-valuetext` ("Target 31 Mar: 54 percent"); arrows step one bin
  (or `target.step`), Page keys ten, Home and End the domain ends. Pointer drag works anywhere in the plot; vertical
  swipes still scroll the page (`touch-action: pan-y` on the plot, `none` only on the small handle).
- Marker tags are buttons (`markerSelect`). Over capacity, partial, notes and shortfall are words in the bar name and
  the twin's State column, and hatched or outlined in the drawing: never colour alone.
- Direction comes from the parent `dir`. Text inside the LTR island reads in the page direction (an inner span carries
  it, because logical insets resolve against the element's own direction). Western digits unless `numberingSystem`.

## Styling

Classes `.xwui-bar-plot`, `.xwui-bar-plot__<part>`, modifiers `--<mode>`, `--rows`/`--columns`, `--h-<size>`,
`--live`, `--stale`, `--still`, `--mirrored`. Knobs: `--xwui-bar-plot-h-<size>`, `--xwui-bar-plot-gap`,
`--xwui-bar-plot-bar-max`, `--xwui-bar-plot-radius`, `--xwui-bar-plot-default`, `--xwui-bar-plot-over`,
`--xwui-bar-plot-under`, `--xwui-bar-plot-overlay`, `--xwui-bar-plot-target`, `--xwui-bar-plot-row-h`. Hues need
`theme/viz-tokens.css` (style tier); without it a named hue falls back to the accent.

## Provenance

Promoted from the app-owned `03_BASE/xwflow/xwflow-web/src/components/XWUIBucketBars` (xwflow-web, 18-Oct-2026 state:
`state.ts` 453 lines, `view.ts` 296, adapter 246, tests 985). Kept: the series catalogue, raw-count normalisation,
newest-`maxBars` window, repeated-key suffixing, status-toned whole bars with `note`, partial wording, roving tab stop
with clamped arrows, the tick thinning from the newest bar, the LTR time island and the table twin; its state and
view tests are ported as the "promoted floor" blocks of `XWUIBarPlot.test.ts`. Changed: `key` became `id`, `values`
became `segments`, `numberLocale` became `locale` + `numberingSystem`, gradient tone pairs and the rem `gap`/`radius`
config became CSS knobs, one in-tree readout replaced one `XWUIOverlayTooltip` per bar. xwflow-web keeps its copy and
switches its import when it adopts this one (no shim).

```api
```
