{greet}, {S.doc.child.parent || 'there'}.}
sub={Here's where {S.doc.child.name}'s plan stands today, {fmtDate(TODAY)}. A few small things need you — nothing urgent.}
/>
{/* quick actions */}
{quick.map((q) => (
))}
{/* money at a glance */}
remaining{fmtMoney(remaining)}of {fmtMoney(plan.total)}{PLAN_DAYS_LEFT} days left in plan
{c.name}
{over && {Math.round(c.pct * 100)}% used}
{fmtMoney(c.remaining)} left
);
})}
0.05 ? 'amber' : 'good'} icon={pacing > 0.05 ? 'info' : 'checkCircle'}>
{pacing > 0.05
? <>You're spending a little faster than the calendar — you've used {Math.round(plan.pct * 100)}% of funds and {Math.round(PLAN_TIME_PCT * 100)}% of the plan year has passed. The marker line shows where you'd be "on pace". Worth a glance, not a worry.>
: <>You're tracking nicely — spending is roughly in step with how much of the plan year has gone by.>}
{/* two columns: needs you + activity */}
Needs you
{S.reminders.map((r) => )}
Recent activity
{S.doc.activity.length === 0 &&
Nothing yet — what you do in Haven will show up here.
}
{S.doc.activity.map((a, i, arr) => {
const tone = { paid: 'var(--good)', claim: 'var(--primary)', invoice: 'var(--amber-ink)', pay: 'var(--core)' }[a.type];
const ic = { paid: 'checkCircle', claim: 'send', invoice: 'receipt', pay: 'people' }[a.type];
const I = Icons[ic];
return (
}
{S.doc.budget.map((c) => {
const v = m.perCat[c.key] || 0;
if (!v) return null;
return ;
})}
))}
{months.map((m) =>
{m.label}
)}
{S.doc.budget.map((c) => (
{c.name}
))}
)}
);
}
function Budget() {
const S = useHaven();
const plan = S.plan;
const [open, setOpen] = useS2('capacity');
return (
How {S.doc.child.name}'s funding is split, what's left, and whether you're on pace. The faint line on each bar is where you'd be if you spent evenly across the year.>} />
{/* summary strip */}
);
}
// ══════════════════════════════════════════════════════════════════
// PROVIDERS
// ══════════════════════════════════════════════════════════════════
function Providers() {
const S = useHaven();
return (
Everyone you buy supports from, their rates, and when each needs renewing.>} />
{S.doc.providers.length === 0 && No providers yet — add your therapists, programs and suppliers in Settings and they'll appear here and in the claim form.}
{S.doc.providers.map((p) => {
const days = p.agreementEnds ? daysBetween(TODAY, new Date(p.agreementEnds)) : null;
const soon = days != null && days <= 21;
const cat = S.doc.budget.find((b) => b.key === p.cat);
return (