Redesign the setup flow and consolidate the CSS into one primitives layer

Onboarding asks explicitly for one or two parents and shows one card per
parent for balances; the balance form is per parent with inline
validation; the partner can be filled from the FK deduction or added
from it. Settings and Dashboard reuse the same form.

CSS: bare buttons carry no colour any more; buttons, cards, choice
cards, fields, alerts, badges, eyebrow and modal chrome are defined once
in primitives.css. Media queries live only in responsive.css. A style
guard test blocks hex, !important and stray media queries. Bilingual
fixes: calendar selects size by content, header no longer wraps. Vitest
is capped at four workers.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
2026-09-19 12:27:29 +02:00
parent e4719cb9ae
commit ae6db7e16f
105 changed files with 5683 additions and 3690 deletions
+8 -1
View File
@@ -1,6 +1,7 @@
import { useState, useEffect, useCallback } from 'react'
import * as api from '@/services/api'
import { useLatestRequest } from './useLatestRequest'
import { useWorkspace } from '@/context'
import type { WorkspaceOverview } from '@/types'
interface UseAnalyticsResult {
@@ -15,6 +16,7 @@ export function useAnalytics(workspaceId: string | null, childId?: string): UseA
const [isLoading, setIsLoading] = useState(false)
const [error, setError] = useState<string | null>(null)
const { start, isCurrent } = useLatestRequest()
const { planVersion } = useWorkspace()
const fetch = useCallback(async () => {
const requestId = start()
@@ -43,9 +45,14 @@ export function useAnalytics(workspaceId: string | null, childId?: string): UseA
}
}, [workspaceId, childId, start, isCurrent])
// `planVersion` (bumped by usePlannedDays/useDayOverrides mutations) is
// included so a plan edit made through a different hook instance — e.g.
// the Calendar's `usePlannedDays` — refreshes the at-risk figures here
// too, without this hook knowing anything about who mutated. See
// `WorkspaceContext.planVersion`.
useEffect(() => {
fetch()
}, [fetch])
}, [fetch, planVersion])
return { data, isLoading, error, refresh: fetch }
}