<!-- 04_VISUAL/xwui/xwui-lib/xwui-lib-super/src/tables/XWUICellMatrix/XWUICellMatrix.md -->
# XWUICellMatrix

Rows by columns of typed cells for matrices that are not spreadsheets: heat maps with a tone scale and a hatched
limit, risk grids with item chips, dot stacks, signed coverage grids with totals, permission matrices (tick, toggle,
locked), rosters (two-line cells, off days) and grouped comparison tables (collapsible groups, column emphasis,
search, differences only, a one-column phone mode). Static use is a real `<table>`; interactive use is the same table
as an ARIA grid with a roving tab stop, selection by cell, row or column, editing and toggling. Large matrices
(12 by 168 and up) render only the visible window.

## Basic Usage

```example
file: examples/BasicUsage.ts
html: examples/BasicUsage.html
title: Basic Usage
description: Shift coverage preview, three shifts by five days, banded by health tone.
```

```example
file: examples/RiskMatrix.ts
html: examples/RiskMatrix.html
title: Risk Matrix
description: Likelihood by impact with risk chips and heat bands.
```

```example
file: examples/ComparisonMatrix.ts
html: examples/ComparisonMatrix.html
title: Comparison Matrix
description: Grouped plan comparison with toolbar, column emphasis and one-column phone mode.
```

```example
file: examples/PermissionMatrix.ts
html: examples/PermissionMatrix.html
title: Permission Matrix
description: Roles by rights as toggles with locked cells.
```

## Data

| Field | Shape | Notes |
| --- | --- | --- |
| `columns` | `{ id, label, sub?, align?: 'start' \| 'end', state?: 'current' \| 'emphasis' }[]` | Column order is draw order (mirrored under RTL unless `ltrColumns`). |
| `rows` | `{ id, label, sub?, lead?: { dot?, avatar? }, kind?: 'item' \| 'total', cells, state?: 'flash' \| 'hit' \| 'dim' }[]` | Ignored when `groups` is set. |
| `groups` | `{ id, label, open?, rows }[]` | Collapsed rows stay in the DOM with `hidden`. |
| `totals` | `cell[]` | A `tfoot` totals row. |
| `spans` | `{ row, from, to, label, hue? }[]` | Labelled bars laid over a row (`to` exclusive). |
| `selected` | `{ row?, col? }` | Host-owned; `cellActivate` reports a change. |
| `query`, `diffOnly` | `string`, `boolean` | Search (case, accent and Arabic letter folding) and differences only. |
| `status`, `errorText` | `'ready' \| 'loading' \| 'error'` | Skeleton, or an alert with a retry button (`retry` event). |
| `preset` | `'basic' \| 'permissions'` | Loads a vetted data set; explicit fields win. |

A cell: `{ value?, text?, sub?, kind?, tone?, items?, stack?, state?, peer?, locked?, on?, note? }`. `kind` is one of
`value` (default), `count`, `items`, `dots`, `tick`, `toggle`, `bar` (0 to 100), `text`, `two-line`, `placeholder`,
`addon`, `status`. `tone` is a token NAME: `heat-1` .. `heat-5`, `on-track`, `at-risk`, `off-track`, `none`, or a hue
name (`violet`, `sky`, a host hue); unset, the scale bins `value`. `state` flags: `selected`, `flash`, `comment`,
`changed`, `applied`, `formula`, `negative`, `hot`, `bad`, `fixed`, `off`, `hit`, `dim`.

## Options

| Option | Default | What it does |
| --- | --- | --- |
| `interaction` | `'cell'` | `'none'` static table; `'cell'`, `'row'`, `'column'` grid selection. |
| `scale` | none | `{ kind, stops: [{ upTo, tone, label? }], hatchAbove? }`; also draws the legend. |
| `rowAxisTitle`, `colAxisTitle` | none | Words in cell names ("Likelihood 4, Impact 3: 2 risks") and the axis captions. |
| `ltrColumns` | `false` | Time columns stay left to right under RTL (an LTR island; arrows do not swap). |
| `stickyHeader`, `stickyFirstColumn` | `true` | Sticky inside the scroller. |
| `scroll` | `'x'` | The grid scrolls sideways inside the component. |
| `compact`, `compactBelow` | `'none'`, none | `'one-column'` (a column picker) or `'list'` below a container width in CSS px. |
| `toolbar` | none | `{ search, diffOnly, expandAll }`. |
| `columnEmphasis` | `false` | Column headers are `aria-pressed` buttons. |
| `editable` | `false` | Value, count and text cells edit with Enter, F2 or a double click. |
| `signed`, `hideZero` | `false` | `+2` / `-3` for diverging values; blank zero cells. |
| `cellSize` | `'md'` | `'sm'` hour grids, `'lg'` chips and long text. |
| `virtualize` | `'auto'` | Windowing above 400 cells; `'off'` draws everything. |
| `maxBlockSize` | none | Bounded scroller (a CSS length): rows window too and the header sticks inside. |
| `pageSize`, `maxItems`, `flashMs` | `5`, `6`, `1200` | PageUp/PageDown rows, chips before "+N", flash duration. |
| `labels` | none | Copy overrides keyed like `xwui.cell_matrix.*` without the prefix (`items_one`, `yes`, `search`, ...). |
| `title`, `ariaLabel`, `emptyText`, `density`, `locale`, `numberingSystem`, `className` | | As every XWUI component. |

CSS knobs: `--xwui-cell-matrix-surface`, `-cell-size`, `-row-size`, `-row-head-size`, `-gap`, `-sticky-offset`.

## Events and methods

Events: `onCellActivate(row, col, colIndex)`, `onCellChange(row, col, value)`, `onItemActivate(id, row, col)`,
`onGroupToggle(id, open)`, `onColumnEmphasis(id | null)`, `onQueryChange(query)`, `onRetry()`; the logic also emits
`diffOnlyChange`.

Methods: `setCell(rowId, col, patch)` (targeted: only that cell is patched), `flash(rowId, col?)`, `select(rowId, colId)`,
`getSelected()`, `setQuery()`, `setDiffOnly()`, `toggleGroup(id, open?)`, `setAllGroups(open)`, `emphasize(id | null)`,
`toText()` (tab separated text twin), `updateData()`, `updateConfig()`, `getElement()`, `destroy()`.
Static: `XWUICellMatrix.projectView(data, config)` for a still render inside a parent view tree.

## Accessibility and RTL

- Static: `<table>` with `th scope="col"` and `th scope="row"`; icon cells carry hidden words ("Included").
- Interactive: `role="grid"`, gridcells with `aria-selected` and full names, one tab stop. Keys: arrows (Left and Right
  swap under RTL unless `ltrColumns`), Home/End (row), Ctrl+Home/Ctrl+End (grid), PageUp/PageDown, Enter (activate,
  enter a chip cell, edit), Space (select, toggle), F2 (edit), Escape (leave a chip cell, cancel an edit). Group lines
  are buttons with `aria-expanded` on the same roving path.
- Colour is never the only signal: heat and health tones add the ramp glyph from `theme/viz-tokens.css`, cells above
  `hatchAbove` add the hatch and the words "Over the limit", dot states add triangle and diamond shapes, states add
  outlines and hidden words, a cell that prints its own number needs no glyph.
- Windowed grids set `aria-rowcount`/`aria-colcount` and per-cell indexes; a hidden summary is the text twin and
  `toText()` gives every cell.
- Logical properties only; the table mirrors under a parent `dir="rtl"`; Western digits unless `numberingSystem`.
- Reduced motion: the flash becomes a still dashed outline (JS and CSS); the skeleton stops.

```api
```
