Context
apps/loopover-ui/src/components/site/app-panels/analytics-card-shell.tsx is the documented (#2200) shared "titled card with loading/empty/ready" treatment. Five sibling analytics cards in the same folder never adopted it, instead hand-rolling the same <section className="rounded-token border-hairline..."> header/title markup: cycle-time-card.tsx, gate-precision-card.tsx, reversal-health-card.tsx, gate-outcome-card.tsx, slop-duplicate-trend-card.tsx. This is the root cause of a real, user-visible bug: cycle-time-card.tsx:55-60 renders a bare <p> for its no-data case instead of the shared EmptyState component every properly-adopted sibling (acceptance-rate-card.tsx:31-42, queue-health-card.tsx:45-60, findings-breakdown-card.tsx, slop-band-calibration-card.tsx) gets for free from AnalyticsCardShell's state="empty".
Requirements
- Migrate
cycle-time-card.tsx, gate-precision-card.tsx, reversal-health-card.tsx, gate-outcome-card.tsx, and slop-duplicate-trend-card.tsx to render through AnalyticsCardShell, following exactly how acceptance-rate-card.tsx/queue-health-card.tsx already use it (loading/empty/ready states, title/chrome).
- After migration,
cycle-time-card.tsx's no-data case must show the shared EmptyState, not its old bare <p>.
- Do not change any card's actual data-fetching logic or the shape of its ready-state content — only the chrome/state-handling wrapper.
- This is a UI-only change under
apps/**.
Deliverables
Expected Outcome
All analytics cards in this folder share one loading/empty/ready implementation, and the previously-broken CycleTimeCard empty state is fixed as a natural consequence.
Links & Resources
apps/loopover-ui/src/components/site/app-panels/analytics-card-shell.tsx (#2200)
apps/loopover-ui/src/components/site/app-panels/cycle-time-card.tsx:55-60, gate-precision-card.tsx, reversal-health-card.tsx:78-83, gate-outcome-card.tsx:91-96, slop-duplicate-trend-card.tsx
acceptance-rate-card.tsx:31-42, queue-health-card.tsx:45-60 (already-correct pattern to match)
Context
apps/loopover-ui/src/components/site/app-panels/analytics-card-shell.tsxis the documented (#2200) shared "titled card with loading/empty/ready" treatment. Five sibling analytics cards in the same folder never adopted it, instead hand-rolling the same<section className="rounded-token border-hairline...">header/title markup:cycle-time-card.tsx,gate-precision-card.tsx,reversal-health-card.tsx,gate-outcome-card.tsx,slop-duplicate-trend-card.tsx. This is the root cause of a real, user-visible bug:cycle-time-card.tsx:55-60renders a bare<p>for its no-data case instead of the sharedEmptyStatecomponent every properly-adopted sibling (acceptance-rate-card.tsx:31-42,queue-health-card.tsx:45-60,findings-breakdown-card.tsx,slop-band-calibration-card.tsx) gets for free fromAnalyticsCardShell'sstate="empty".Requirements
cycle-time-card.tsx,gate-precision-card.tsx,reversal-health-card.tsx,gate-outcome-card.tsx, andslop-duplicate-trend-card.tsxto render throughAnalyticsCardShell, following exactly howacceptance-rate-card.tsx/queue-health-card.tsxalready use it (loading/empty/ready states, title/chrome).cycle-time-card.tsx's no-data case must show the sharedEmptyState, not its old bare<p>.apps/**.Deliverables
AnalyticsCardShell.cycle-time-card.tsx's empty state now showsEmptyState, matching its siblings.Expected Outcome
All analytics cards in this folder share one loading/empty/ready implementation, and the previously-broken
CycleTimeCardempty state is fixed as a natural consequence.Links & Resources
apps/loopover-ui/src/components/site/app-panels/analytics-card-shell.tsx(#2200)apps/loopover-ui/src/components/site/app-panels/cycle-time-card.tsx:55-60,gate-precision-card.tsx,reversal-health-card.tsx:78-83,gate-outcome-card.tsx:91-96,slop-duplicate-trend-card.tsxacceptance-rate-card.tsx:31-42,queue-health-card.tsx:45-60(already-correct pattern to match)