Closes#363 (frontend half of milestone #361). Consumes the
`ContainerView.parent: Option<String>` field landing in damocles'
backend slice — when present, the container list renders depth-first
with sibling-position tree glyphs (├─ / └─ joints + │ continuation
columns). When absent (pre-#361 state — every container's `parent` is
None) the tree collapses to a flat list with no glyphs and no indent
— bit-identical to the legacy render.
## Tree shape
- Roots: containers whose `parent` is None OR whose parent name isn't
in the current container set (orphan tolerance).
- Sibling ordering: alphabetical by name within each level (matches
damocles' wire spec at #363#issuecomment-3356).
- Cycle safety: any container not reached via the root-walk gets
emitted as a root at the end — no agent ever silently disappears
from the list when the topology is malformed.
- Tree glyphs: ancestor at depth d contributes a │ continuation column
when that ancestor has more siblings below; otherwise a 3-space gap.
The joint is ├─ for non-last siblings, └─ for the last child.
- Depth-0 ancestor column is suppressed: roots already separate
visually as top-level rows, no need for a column 0 vertical line.
## DOM / CSS
- New `buildAgentTree(containers)` + `treePrefix(node)` helpers in
app.js. The render loop walks the tree-ordered list instead of the
legacy alphabetical containers array.
- Each container row gets `data-depth=N` (only when N > 0) and a
`<span class="tree-prefix">…</span>` prepended (absolute-positioned
into the row's left margin so the existing flex icon/body layout
isn't disrupted).
- CSS: per-depth `margin-left` step rules for depths 1-6 (hardcoded
rather than typed-attr() because CSS Values 5 is Chromium-only as
of 2026). 6 depths cover any reasonable hive topology with
headroom; deeper agents render at depth 6 indent without further
step — visually clamps gracefully.
- `.tree-prefix` rendered with `var(--purple-dim)` so the structural
lines read as supporting chrome, not as content.
## Validation
- `npm run build` clean. Bundle deltas: dashboard app.js
+1.8kb (tree builder + treePrefix + render-loop tweak),
dashboard.css +0.4kb (tree-prefix + per-depth indent rules).
- The render is a no-op until `ContainerView.parent` is populated —
validation in production deferred to once damocles' meta-topology
field lands. The pre-#361 path (every parent=None) is exercised
by every existing dashboard load.
- Forward-compatible with damocles' design pivot at #364 (topology
source moved from agent.nix to meta/topology.json). The wire shape
on ContainerView is unchanged from the frontend's perspective — the
field is just sourced from a different backend store.