Build the M4 label experience on top of the #43 label API.
- shared: `flattenLabelTree` (tree → depth-first list) for chip lookup,
filtering, and the picker; `PageListItemView` adds each page's `labelIds`
to the sidebar list response.
- api: `GET /ponds/:id/pages` now includes `labelIds` per page (one grouped
query), so the sidebar can render chips and filter without extra calls.
- web:
- Pond settings page (`/p/:pondSlug/settings`) with a `LabelManager`
tree: inline create, rename, recolour (`<input type=color>`), move via a
parent picker that excludes the label's own subtree, and delete that
confirms then force-detaches assigned pages. Every control is a native
button/input/select — the tree is fully keyboard-operable.
- `LabelPicker` panel on the page editor: searchable, hierarchy-indented
multi-select that assigns/unassigns immediately and refreshes the page's
labels and the sidebar.
- Sidebar: colored label chips on page entries (readable text via a
luminance-based contrast helper) and a descendant-inclusive label filter
(selecting a parent matches pages tagged with its children, via the
shared `collectSubtreeIds`). Owner link to pond settings.
- i18n `labels` namespace (de + en).
- e2e `labels.spec.ts` (new CI pack): full lifecycle from the settings UI
and picker-assign + parent-filter-includes-child. Selectors are
language-independent because the UI language follows the user's locale.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PGdhRiwU1WRL4XxJfZYipY