Accessibility
TokenizedText, TokenizedTextSegmentKind from @prepared911/ui/tokenized-text.
The body is one run of text in order. Plain text, links, mentions and highlights are read where they sit; there is no region, role or live announcement of its own. The scroll container that holds the transcript owns the log role (ChatScroll).
Each link is a Link: a real anchor with its text as the name. A link with an unsafe protocol is plain text, so no control in the tab order does nothing.
The visible text is aria-hidden and name is read in its place, as a visually hidden run. A mention is therefore read once, with the name the caller chose ("Mentioned: Medic 7"), not twice.
A redaction is a fill with no visible text. Its label ("Redacted", or the field name such as "Phone number") is the accessible text, in a visually hidden run, so a screen reader says it once in place of the removed words. A second copy of the label sets the fill's width; it is aria-hidden and visibility: hidden, so it is neither painted nor announced. The original words are not in the value, so they cannot be read, selected, copied or found, by anyone or anything.
A highlight is a mark, underlined (dashed, or solid for the current match) in addition to its fill, so it is marked without color. The current match carries aria-current.
The mention wash sits under the default foreground, highlights use Message's fills, and redactions use the status fills, which paint no text: the fill is measured at 3:1 or more against the canvas in light and dark (WCAG 1.4.11), and the hidden sizing copy keeps the fill's on-solid color; the page clears WCAG 2.2 AA in light and dark inside a plain line and both bubbles (checked with axe). Under forced-colors: active a redaction becomes a Canvas fill with a CanvasText outline (dashed when automated), so its extent stays visible; the mention takes LinkText with an underline, and highlights keep their underline.
A mention's visible handle is translate="no", so a browser translator leaves "@Medic 4" as written (ADR 0019 §7). Its spoken name is localized copy and stays translatable.