/* * Main column plus a fixed support rail. * * The rail is what stops a page being empty and the main column is what stops * it being thin: an account with one instance used to render a third of a row * of summary and nothing else. The rail carries what is true regardless of how * many instances exist, so the page has a floor. * * It collapses below lg in source order, which puts the main column first on a * phone. Nothing is hidden at any width if content only fits on a desktop it * does not belong in the rail. */ export function PageFrame({ children, aside }: { children: React.ReactNode; aside?: React.ReactNode }) { if (!aside) return
{children}
; return (
{children}
); } /** One card in the rail. Title is a label, not a heading you read for pleasure. */ export function RailCard({ title, count, children }: { title: string; count?: number | string; children: React.ReactNode }) { return (

{title}

{count !== undefined && {count}}
{children}
); } /** Key/value rows for the rail. Values are mono so numbers line up. */ export function RailFacts({ rows }: { rows: { label: string; value: React.ReactNode }[] }) { return (
{rows.map((r) => (
{r.label}
{r.value}
))}
); }