32ee00178e1b31bd8031391c3a804ebd3b29d21f
Add `SelectableRichText`, a custom iced widget that mirrors `rich_text` (linkified spans + A13 link clicks) and adds per-message drag selection, Ctrl/Cmd+C copy, and Ctrl/Cmd+A select-all. Swap it in for the chat body element; the chat row and attachment layout are unchanged. Selection offsets are paragraph-global byte offsets (matching cosmic-text's hit_test), which equals a single global range because sanitize_chat keeps every message on one logical line. Pure seam `selected_substring` / `select_all` is unit-tested incl. unicode/emoji byte boundaries. Highlight quads are computed from public Paragraph primitives, falling back to a whole-message span_bounds union if sub-range rects can't be derived. Only one message holds a selection at a time: each widget clears its own selection on a left-press that lands outside its bounds. Right-click menu (Part B) intentionally deferred — native Ctrl/Cmd+C/A is the path. Implemented by Codex on branch, reviewed/committed by Claude. 464 lib tests, clippy --all-targets clean, release green. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>