import type { ReactNode } from 'react'; /** * The primitives a written page is built from. * * `/parity?tab=findings` is a document rather than a gallery — 888 lines of * argument, evidence tables and hex values — and it grew these five inline. On * its own that was fine; nothing was duplicated. But they are the generic parts * of *any* such page, and the second one would have copied them, which is the * shape `narrow`/`Field` had already reached across five gallery pages before * `chrome/ui/axis-filter.tsx` gave them one home. * * The names are longer here than they were as file-locals. `P` and `H3` read * fine next to their only caller; imported into a page that also renders kit * components they read as nothing at all, and `Table` would have collided with * what `chrome/ui/tables.tsx` exports. */ /** A numbered section: heading, one line of provenance, then the argument. */ export function Finding({ n, title, meta, children, }: { n: number; title: string; meta: ReactNode; children: ReactNode; }) { return (

{n}. {title}

{meta}

{children}
); } /** Body copy, held to a readable measure. */ export function Paragraph({ children }: { children: ReactNode }) { return

{children}

; } /** A heading inside a finding. */ export function SubHeading({ children }: { children: ReactNode }) { return

{children}

; } export function ProseTable({ head, rows, }: { head: readonly string[]; rows: readonly (readonly ReactNode[])[]; }) { return ( /* Its own scroll container: the palette table is seven columns of hex and variable paths, and the page body must never scroll sideways. */
{head.map((h) => ( ))} {rows.map((row, i) => ( {row.map((cell, j) => ( ))} ))}
{h}
{cell}
); } /** A hex with the colour itself beside it — a colour argument needs the colour. */ export function Hex({ value }: { value: string }) { return ( ); }