Replace the hand-rolled SVG Sankey on the Cashflow page with a
concentric multi-level donut (recharts), aimed at working on both
desktop and mobile where the Sankey was wide and hard to use.
- Backend: `sankey?nested=1` returns the full nested Income/Expense
tree (up to MAX_DEPTH) via a new `CategoryTree::nest()`, strictly by
category type so its totals match the summary and breakdown cards
(savings, investments and transfers excluded). A synthetic "Direct"
child keeps each node's children summing to the node total.
- Frontend: `MultiLevelDonut` renders concentric rings — income grows
toward the centre, expense toward the rim — with a `showIncome` prop
exposed as a Combined / Expenses-only toggle for comparison. Inside
labels on the innermost ring; leader-line labels (name + share) on the
outermost ring with per-side vertical collision avoidance on wide
screens, suppressed below 480px where the outer ring is read on tap.
- Pure ring-building logic lives in `lib/donut-utils` with unit tests;
the nested endpoint has a feature test.
Prototype for comparing the Combined vs Expenses-only layouts before
picking a final direction; the old SankeyChart component is kept but no
longer rendered on this page.