Mobile adaptation An on-call engineer at 3 a.m. holding a phone. Reflow to one column is the easy half; the hard half is deciding which two panels come first, and a phone layout that is the desktop order squeezed is a decision nobody made. Tokens this needs: --card, --card-foreground, --foreground, --muted-foreground, --border, --status-critical The status, chart, scale, state and direction names are an extension, not a rename. shadcn has --destructive and five --chart-* and nothing else in this territory. ──────────────────────────────────────────────────────────────────────── // TriagePage.tsx ──────────────────────────────────────────────────────────────────────── import { cn } from "@/lib/utils"; /** * The phone version, designed for triage rather than reflowed from the grid. * * Three questions and a way out. Is it real, how bad, can it wait, then a * route to the full dashboard for the case where the answer is "open the * laptop". Every answer is a prop the caller has to supply, so a page that * cannot answer one of them is a page that should not have a phone version. * Nothing lives in a tooltip, because there is no hover, and the one target * is tall enough for a thumb. */ type Props = { title: string; /** Has the alert been corroborated by a second signal? A single rule * firing is a claim; two is a fact. */ real: boolean; /** How bad, as a share of a named thing. Rendered as "4.1% of checkouts", * computed here so the page and the source cannot disagree. */ affected: number; total: number; of: string; /** Whether it can wait until morning. The rule that decides lives with * the alert, not here. */ canWait: boolean; /** The full desktop page. Required: a summary with no way past it is a * dead end at 3 a.m. */ fullHref: string; onOpenFull?: () => void; }; const yesNo = (b: boolean) => (b ? "yes" : "no"); export function TriagePage({ title, real, affected, total, of, canWait, fullHref, onOpenFull }: Props) { const share = `${((affected / total) * 100).toFixed(1)}% of ${of}`; return (
{title}