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

"This record lives in another tool." A square mark (one or two letters on a hue token), an optional key ("ENG-151"), a label and an
optional sync state drawn as a shape (a different shape per state) with its word available as text. One look in every view (plnx UX-017):
the Home briefing source chips, the board name cell, the triage row, linked work, the sync center conflict header and the Connections
state. Static by default; interactive it is a real `button` (an `a` when the record has an `href`) that reports `activate`.

It composes no other component: the badge is one element, a few spans and CSS. It is the plnx spec C05 (REF_06 section 2.2) and absorbs
A-G3 `XWUISourceBadge`, B-W1 (`ToolMark`, `SourceChip`) and the colour need behind B-E8 (a solid brand tile that `XWUIAvatar` cannot paint).

## Basic Usage

```example
file: examples/BasicUsage.ts
html: examples/BasicUsage.html
title: Basic Usage
description: The Home briefing source chip: tile, name and a health dot as a button.
```

```example
file: examples/ConflictHeader.ts
html: examples/ConflictHeader.html
title: Sync center conflict header
description: A medium tile and the record key, static.
```

```example
file: examples/ConnectionStates.ts
html: examples/ConnectionStates.html
title: Connection states
description: Six states, six shapes, each with its word; setSyncState changes one badge in place.
```

## Data

| Field | Type | Meaning |
| --- | --- | --- |
| `label` | `string` | The other tool's name ("Jira"). Also the accessible name. Empty: the locale word "Unknown source". |
| `mark` | `string` | One or two letters on the tile ("J", "Az"); longer text is cut at two code points. Empty: the first letter of the label. |
| `markHue` | `string?` | A hue token NAME, never a colour. A plain name (`teal`, `indigo`) reads `--xwui-hue-<name>`; a host token (`--tool-jira`) is used as written; anything else resolves to slate. See "Hues". |
| `key` | `string?` | The record's id in that tool ("ENG-151"). Drawn in a left-to-right isolate. |
| `state` | `ok`, `syncing`, `auth`, `rate`, `paused` or `error` | Sync health. Unset: no state is drawn. |
| `stateLabel` | `string?` | The state word of this badge ("Syncing - 38 left"). Unset: the locale word for the state. |
| `title` | `string?` | Tooltip. Unset: the accessible name. |
| `href` | `string?` | Where the record lives. Used only when `interactive`; http(s), mailto and relative links only, anything else is dropped. |

## Options

| Option | Default | What it does |
| --- | --- | --- |
| `size` | `'sm'` | `sm`: 24 px high, 16 px tile (a table cell, a chip row). `md`: 32 px high, 20 px tile (a card header). |
| `show` | `'full'` | `mark`: the tile only. `mark-key`: tile and key (the label when there is no key, in the key's weight). `full`: tile, label and key. |
| `showState` | `'dot'` | `dot`: the state shape. `text`: shape and word. `none`: no state is drawn, and none is named. |
| `interactive` | `false` | A `button` (an `a` with an href) that emits `activate`. Static: a `span role="img"`, so a click reaches the row that holds it. |
| `maxWidth` | none | Longest inline size, a plain CSS length (px, rem, em, ch, %). The label gives way first, then the state word, then the key. |
| `className` | none | Extra class. |

## Events and methods

`onActivate(handler)` returns an unsubscribe function; the detail is `{ label, key?, href? }`. A static badge never emits.
`activate()` presses it as a click does (false when static or destroyed). `setSyncState(state, stateLabel?)` changes the state in place
(a connection monitor calls it). `updateData(patch)`, `updateConfig(patch)`, `getElement()`, `destroy()`.
Static `XWUISourceBadge.projectView(data, config)` returns the view tree for composition into a parent (a grid cell, a card header).

`<xwui-source-badge>` takes `label mark mark-hue key state state-label href` and `size show show-state interactive max-width class-name`
as attributes (`title` stays a property so the host does not carry a second tooltip).

## States

Static, interactive (button), link (an href), every one of the six sync states, with and without the word, the unknown source (no data),
a truncated badge, reduced motion (the syncing disc stops turning), forced colours (system colours). There is no loading or error state of
its own: `syncing` is the loading state of a connection and `error` its failure.

| State | Shape | Colour token | Word (locale key) |
| --- | --- | --- | --- |
| `ok` | filled circle | `--xwui-health-on-track` | Healthy (`state_ok`) |
| `syncing` | half-filled disc in a ring, turning slowly | accent mixed toward the page ink | Syncing (`state_syncing`) |
| `auth` | diamond | `--xwui-health-off-track` | Access expired (`state_auth`) |
| `rate` | triangle | `--xwui-health-at-risk` | Rate limited (`state_rate`) |
| `paused` | two bars | `--xwui-health-none` | Paused (`state_paused`) |
| `error` | cross | `--xwui-health-off-track` | Sync error (`state_error`) |

Measured contrast of the shapes against the card (light / dark): ok 5.2 / 10.0, syncing 9.4 / 5.7, auth 5.6 / 5.9, rate 5.2 / 10.5,
paused 7.1 / 6.3, error 5.6 / 5.9 (WCAG 1.4.11 asks 3:1); state words 6.9 / 11.2.

## Hues

The tile is 80 percent of the hue token mixed with 20 percent of the page ink, with the card colour as letter ink, so the letters keep
4.5:1 on every hue: measured 4.74 light and 6.63 dark across the nine named hues and the 16 plnx tool tokens.
A product's identity colours live in the product's tokens, never in data or in this component: declare `--tool-jira: var(--xwui-hue-sky)`
(or any colour) in the app's tokens and pass `markHue: '--tool-jira'`.
The nine core hue names (`blue green red orange amber violet pink lime cyan`) exist only in xwflow-neon; elsewhere `--xwui-hue-blue`
is undeclared and the library's `hueVar` would paint slate. The badge keeps the core token first and falls back to the nearest extended
hue (`blue` to `sky`, `green` to `teal`, `red` to `rose`, `orange` and `amber` to `yellow`, `violet` to `purple`, `pink` to `fuchsia`,
`cyan` to `sky`, `lime` to `teal`): recorded as a library defect below, not a feature.

## Accessibility and RTL

- Accessible name: label, key and, when the state is drawn, its word, joined by the locale list separator (`xwui.source_badge.separator`)
  with the label and key in bidi isolates. A static badge is `role="img"` with that name; an interactive one is a native `button` or `a`
  with the same `aria-label`, so Enter and Space come from the browser. The tooltip repeats the name unless `data.title` says otherwise.
- The tile is `aria-hidden` and `dir="ltr"` (a logo, not text). The key is `dir="ltr"` (an isolate under RTL). The label and the state
  word are `dir="auto"`.
- Colour is never the only signal: six different shapes, plus the word in the name (and on screen with `showState: 'text'`).
- Targets: an interactive badge is 24 px high at `sm` and 32 px at `md`, at least 24 px wide even as a tile alone (WCAG 2.5.8); the
  focus ring is the shared `--focus-ring-*` token; no pointer-only action exists.
- Logical properties only: the badge mirrors under a parent `dir="rtl"` (the tile moves to the inline start, the state to the end).
  Numbers: none are drawn, so digits follow the host's text.
- Reduced motion: the syncing disc stops turning (CSS; the badge owns no timer, observer or JS animation). Forced colours: the tile
  and every shape draw in system colours.

## Layering (HEADLESS.md)

`XWUISourceBadge.json` schema, `.types.ts`, `.calc.ts` (pure: mark, hue reference, href and length sanitising, layout, name),
`.logic.ts` (the press rule, `setSyncState`, a destroyed badge reports nothing), `.view.ts` (`projectSourceBadgeView`), `.ts` (thin
persistent mount, `destroy()` also calls `logic.destroy()`), `index.ts` (custom element and presets).

## Locale keys

`xwui.source_badge.unknown`, `.separator`, `.state_ok`, `.state_syncing`, `.state_auth`, `.state_rate`, `.state_paused`, `.state_error`
(English fallbacks are in the view, so the badge reads correctly before a pack registers).

## Library defects found

- `hueVar` and the viz tokens: the nine core hue names are undeclared outside xwflow-neon, so a name from the documented core list paints
  slate in every other theme. Either declare them in `theme/viz-tokens.css` or drop them from `XWUI_HUES_CORE`.
- The scaffolded tester HTML omits `core/sizes.css`, `style/modern/focus.css` and `style/modern/motion.css`: the badge has no height, no
  focus ring and no hover transition without them. The scaffold should link them.
- `core/reset.css` pins `html` and `body` to the viewport with `overflow: hidden`, so a tall tester page cannot scroll or be captured
  unless the tester overrides it.
- `XWUIComponent.destroy()` does not call `logic.destroy()`; the logic's `emit` listeners also survive `logic.destroy()` (only the state
  subscribers are cleared). The badge guards with its own `released` flag.

```api
```
