<!-- 04_VISUAL/xwui/xwui-lib/xwui-lib-super/src/display/XWUINodeGraph/XWUINodeGraph.md -->
# XWUINodeGraph

Node cards and links laid out by pure layout functions, with pan, zoom and fit. Five layouts: `tree-down`, `radial` and
`mind-map` read each node's `parent` and morph into each other; `layered` ranks the links by longest path with barycentre
ordering, for activity-on-node precedence networks with ES, EF, LS, LF corners and FS, SS, FF, SF links with lag labels;
`bands` places nodes in swimlane bands with capacity and an inline add, for cause and effect maps. Collapse with hidden
counts, a best or critical path highlight that dims the rest, ghost (suggested) nodes and links, a value flash, keyboard tree
navigation and an outline or table text twin. The component only draws: every value is computed and formatted by the host.

## Basic Usage

```example
file: examples/BasicUsage.ts
html: examples/BasicUsage.html
title: Basic Usage
description: A small work breakdown: three branches, budgets rolled up by the host, top-down.
```

## Decision Tree

```example
file: examples/DecisionTree.ts
html: examples/DecisionTree.html
title: Decision Tree
description: Expected values computed by the host, the best path highlighted and the rest dimmed; switch between top-down, radial and mind map.
```

## Precedence Network

```example
file: examples/PrecedenceNetwork.ts
html: examples/PrecedenceNetwork.html
title: Precedence Network
description: Activity-on-node cards with ES, EF, LS, LF and float from the host schedule, the critical path, and a start-to-start link with a lag.
```

## Strategy Map

```example
file: examples/StrategyMap.ts
html: examples/StrategyMap.html
title: Strategy Map
description: Objectives in perspective bands with capacity, cause and effect links flowing upward, and an inline add per band.
```

## Data

| Field | Shape |
| --- | --- |
| `nodes[]` | `{ id, title, parent?, band?, kind?, value?, sub?, glyph?, badge?, owner?: { name, initials? }, progress? (0..1), status? ('ok' \| 'warn' \| 'bad' \| 'none'), collapsed?, ghost?, critical?, hue? (token NAME), corners?: { tl, tr, bl, br, centre? } }` |
| `links[]` | `{ from, to, type? ('FS' \| 'SS' \| 'FF' \| 'SF' \| 'tree' \| 'cause'), label?, critical?, ghost?, added? }`. In tree layouts a link between a parent and its child carries that edge's label and state; other links are drawn as cross links. |
| `bands[]` | `{ id, label, icon?, capacity? }` (bands layout; without a list one band per distinct `node.band`) |
| `highlightPath[]` | ids of the best or critical path, in order |
| `flash[]` | ids whose value just changed: each flashes once per new list |
| `selectedId` | the selected node or null (host-owned; `select` reports a change) |

Bad entries (no id, no title, a duplicate id, a link to an unknown node, a parent cycle) are dropped or cut; the component
never throws on data.

## Options

| Option | Default | What it does |
| --- | --- | --- |
| `layout` | `'tree-down'` | `'tree-down' \| 'radial' \| 'mind-map' \| 'layered' \| 'bands'`; a change morphs the same cards |
| `link` | `'curve'` | `'curve' \| 'elbow'` |
| `pan` | `true` | the canvas scrolls (touch, trackpad, drag with a mouse or pen, Ctrl or Cmd plus wheel zooms); `false` always fits |
| `zoom` | `'fit'` | a scale (1 = 100%) or `'fit'` (never above 100%) |
| `nodeSize` | `'auto'` | px per `kind`, `'*'` for every kind |
| `dimOutsidePath` | `true` | dims nodes and links off `highlightPath` |
| `flow` | `false` | a dash flows along every link (critical and ghost links always carry a dash) |
| `addMode` | `'none'` | `'inline'`: an Add control and input per band |
| `ltrWorld` | layered: `true`, others: `false` | keep the drawing left to right under RTL (time runs left to right); labels always follow the page |
| `scrollWhenNarrow` | `true` | fit stops at 60%; below that the canvas scrolls |
| `twin` | tree layouts: `'outline'`, others: `'table'` | the text twin |
| `controls` | `true` | zoom out, zoom level, zoom in, fit |
| `layouts` | `[]` | two or more layouts: a switch beside the zoom controls |
| `labels` | | copy overrides by key (see the schema); unset keys use `xwui.node_graph.<snake_key>` |
| `ariaLabel`, `emptyText`, `locale`, `numberingSystem`, `className` | | as every super component |

CSS knob: `--xwui-node-graph-block-size` (viewport height, default 28rem; 22rem in a container under 30rem).

## Events and methods

Logic events (also re-dispatched on the host element as bubbling DOM events): `select { id }` (`node-select`),
`toggle { id, collapsed }` (`node-toggle`), `activate { id }` (`node-activate`, Enter or double click), `addRequest { band }`
(`add-request`), `addCommit { band, title }` (`add-commit`), `pan { x, y }` (`graph-pan`), `zoom { zoom, mode }`
(`graph-zoom`), `layoutChange { layout }` (`layout-change`).

Methods: `select(id)`, `getSelectedId()`, `toggle(id, collapsed?)`, `setLayout(layout)`, `zoomIn()`, `zoomOut()`,
`zoomTo(scale)`, `fit()`, `getZoom()`, `focusNodeById(id)`, `remeasure()`, `pause()`, `play()`, `updateData(patch)`,
`updateConfig(patch)`, `getElement()`, `destroy()`, and `onSelect`, `onToggle`, `onActivate`, `onAddRequest`, `onAddCommit`,
`onPan`, `onZoom`, `onLayoutChange`. `XWUINodeGraph.projectView(data, config)` composes a still graph into a parent's view.

## Accessibility and RTL

- Tree layouts: the cards are an ARIA `tree` of `treeitem`s (`aria-level`, `aria-posinset`, `aria-setsize`,
  `aria-expanded`, `aria-selected`) with one tab stop. Down and Up move in reading order, Right opens a branch then enters
  it, Left closes it then moves to the parent (Right and Left swap on a right-to-left page), Home and End jump, Space
  selects, Enter activates. The collapse pill is a pointer affordance only (`aria-hidden`).
- Layered and bands: the cards are buttons (`aria-pressed`) in a labelled group; the arrow keys move to the nearest card in
  that direction on the drawing; a visually hidden table twin lists name, value, the corner values, the links in and the
  state words.
- Every card's name carries its value, corners, status, owner, and the words critical, on path, suggested and "n hidden";
  colour is never the only signal (health uses the viz ramp shapes).
- The viewport is `dir="ltr"`: the world's x axis and scroll offsets never flip. A tree or band world mirrors as one unit
  under RTL; a layered world stays left to right with its corner rows in `dir="ltr"` while titles follow the page.
- Reduced motion (CSS and the shared playback rule in JS) stops the morph and the flowing dash; the flash is a colour fade.

```api
```
