@photon-ai/pho-ui 4.8.0 → 4.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/chunks/bar-chart-ht70KKj3.js +19 -0
- package/dist/chunks/bar-chart-ht70KKj3.js.map +1 -0
- package/dist/chunks/{basic-page-BqfpJgAj.js → basic-page-DzT8yecB.js} +176 -175
- package/dist/chunks/basic-page-DzT8yecB.js.map +1 -0
- package/dist/chunks/chart-B5c8gmlj.js +1338 -0
- package/dist/chunks/chart-B5c8gmlj.js.map +1 -0
- package/dist/chunks/code-block-CbcE994O.js +516 -0
- package/dist/chunks/code-block-CbcE994O.js.map +1 -0
- package/dist/chunks/line-chart-Cm_Ac7f4.js +22 -0
- package/dist/chunks/line-chart-Cm_Ac7f4.js.map +1 -0
- package/dist/components/bar-chart.js +1 -1
- package/dist/components/chart.js +8 -5
- package/dist/components/code-block.js +12 -3
- package/dist/components/line-chart.js +1 -1
- package/dist/index.js +175 -162
- package/dist/motion.js +14 -13
- package/dist/motion.js.map +1 -1
- package/dist/primitives.js +1 -1
- package/dist/sections/basic-page.js +1 -1
- package/dist/src/components/bar-chart/bar-chart.d.ts +9 -1
- package/dist/src/components/chart/chart.d.ts +25 -0
- package/dist/src/components/chart/format.d.ts +9 -5
- package/dist/src/components/chart/index.d.ts +7 -4
- package/dist/src/components/chart/scale.d.ts +2 -2
- package/dist/src/components/chart/shell.d.ts +20 -13
- package/dist/src/components/chart/skeleton.d.ts +11 -0
- package/dist/src/components/chart/theme.d.ts +8 -0
- package/dist/src/components/chart/types.d.ts +39 -2
- package/dist/src/components/chart/use-measure.d.ts +2 -1
- package/dist/src/components/code-block/code-block.d.ts +23 -11
- package/dist/src/components/code-block/highlight.d.ts +24 -0
- package/dist/src/components/code-block/index.d.ts +4 -1
- package/dist/src/components/code-block/languages.d.ts +64 -0
- package/dist/src/components/code-block/pho-theme.d.ts +18 -0
- package/dist/src/components/code-block/tokens.d.ts +14 -0
- package/dist/src/components/line-chart/line-chart.d.ts +12 -3
- package/dist/src/motion/index.d.ts +6 -0
- package/dist/src/sections/basic-page/basic-page.d.ts +2 -0
- package/package.json +4 -1
- package/src/styles/theme.css +17 -4
- package/dist/chunks/IconArrowsMinimize-BfPUGuCB.js +0 -75
- package/dist/chunks/IconArrowsMinimize-BfPUGuCB.js.map +0 -1
- package/dist/chunks/bar-chart-DIALC2_z.js +0 -190
- package/dist/chunks/bar-chart-DIALC2_z.js.map +0 -1
- package/dist/chunks/basic-page-BqfpJgAj.js.map +0 -1
- package/dist/chunks/code-block-BuFfh0zH.js +0 -197
- package/dist/chunks/code-block-BuFfh0zH.js.map +0 -1
- package/dist/chunks/legend-C0mU7dqd.js +0 -60
- package/dist/chunks/legend-C0mU7dqd.js.map +0 -1
- package/dist/chunks/line-chart-VuMYKzW3.js +0 -453
- package/dist/chunks/line-chart-VuMYKzW3.js.map +0 -1
- package/dist/chunks/use-measure-C-i54AC6.js +0 -629
- package/dist/chunks/use-measure-C-i54AC6.js.map +0 -1
- package/dist/src/components/chart/axes.d.ts +0 -22
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"basic-page-DzT8yecB.js","names":[],"sources":["../../src/sections/basic-page/basic-page.tsx"],"sourcesContent":["import {\n Children,\n createContext,\n Fragment,\n isValidElement,\n useCallback,\n useContext,\n useEffect,\n useId,\n useLayoutEffect,\n useMemo,\n useRef,\n useState,\n useSyncExternalStore,\n type AnchorHTMLAttributes,\n type ComponentProps,\n type ReactNode,\n type Ref,\n type RefObject,\n} from \"react\";\nimport {\n AnimatePresence,\n motion,\n useIsPresent,\n useReducedMotion,\n} from \"motion/react\";\nimport { createPortal } from \"react-dom\";\nimport { Dialog as BaseDialog } from \"@base-ui/react/dialog\";\nimport {\n IconArrowsMaximize,\n IconArrowsMinimize,\n IconChevronLeft,\n IconChevronRight,\n IconSearch,\n IconX,\n} from \"@tabler/icons-react\";\nimport {\n Button,\n ButtonLink,\n type ButtonLinkProps,\n type ButtonProps,\n} from \"../../components/button\";\nimport { DrawnCheckGlyph } from \"../../components/checkbox/check-glyph\";\nimport { Error as ErrorLine } from \"../../components/error\";\nimport { Form as FormElement } from \"../../components/form\";\nimport { Menu } from \"../../components/menu\";\nimport {\n createTableSearchStore,\n DataTable,\n GhostSearch,\n TableHostContext,\n TableSearchContext,\n} from \"../../components/data-table\";\nimport { CodeBlock } from \"../../components/code-block\";\nimport { DescriptionList } from \"../../components/description-list\";\nimport { InputGroup } from \"../../components/input-group\";\nimport { Tooltip } from \"../../components/tooltip\";\nimport {\n BAR_RISE_PX,\n FADE_ENTRANCE,\n FADE_SWAP,\n RISE_PX,\n SPRING_ENTRANCE,\n TRAVEL_LINEAR,\n fadeThroughBlur,\n} from \"../../motion\";\nimport { BLUR_MAX_PX, ScrollArea } from \"../../components/scroll-area\";\nimport { Toast } from \"../../components/toast\";\nimport { AnimatedHeight } from \"../../utils/animated-height\";\nimport { cn } from \"../../utils/cn\";\nimport { useLinkComponent } from \"../../utils/link-provider\";\n\n/**\n * BasicPage — Pho's standard content page: a page title, section titles, and\n * bordered cards of label/control rows. Settings, billing, members — any\n * single-column management surface. A wide page that is two things at once\n * (traffic and facts) uses `Columns` on a `Root width=\"wide\"`.\n *\n * Spacing: wrap the page in `Root` (a 42rem column with `px-5` gutters,\n * vertical padding). `Stack` separates blocks (`gap-10`). Inside an\n * untitled wrapper, children share `gap-3`. A self-contained surface\n * (`Card`, `Callout`, `Fields`, `Onboard`, `Header`, `Columns`, `Table`,\n * `Code`) placed as a Stack child keeps its own internal rhythm — do not\n * wrap a Card just to protect its rows.\n * Wrap a section title + description in `Header` (no gap — title and\n * description sit flush) so that pair stays tight — don't put them as\n * loose siblings. Parts already carry `px-5`.\n *\n * Navigation: pages may drill into subpages. `RowLink` is a whole-row link\n * (trailing chevron) and `Back` returns to the parent — both render through\n * the host's `LinkProvider`; the URL itself stays the router's job. `Back`\n * floats in `Root`'s top padding, so `Title` never moves between pages that\n * have a back link and pages that don't.\n */\n\n/* ------------------------------- class map ------------------------------- */\n\n/** Card surface — border, corner, fill; no divider rules. */\nconst BASIC_PAGE_CARD_SURFACE =\n \"rounded-base border border-pho-secondary bg-pho-primary\";\n\n/**\n * Card divider rules — hairlines between direct children. A row followed by\n * an `Alert` drops its divider (the `:has()` rule) so the error line reads\n * as part of the row it belongs to — the alert's own bottom divider takes\n * over toward whatever follows. Kept separate from the surface so\n * `animateHeight` can move the dividers onto the measured content wrapper.\n */\nconst BASIC_PAGE_CARD_DIVIDERS =\n \"divide-y divide-pho-secondary [&>:has(+[data-basic-page-alert])]:border-b-0\";\n\n/**\n * Bordered card that stacks rows with hairline dividers. `gap-0` is the\n * card's own: Stack used to force `gap-3` onto a bare Card and open 12px\n * bands between `divide-y` rows. The marker below lets Stack skip it.\n */\nexport const BASIC_PAGE_CARD = `${BASIC_PAGE_CARD_SURFACE} ${BASIC_PAGE_CARD_DIVIDERS} gap-0`;\n\n/**\n * Standalone callout surface — featured block (invite form, notice, etc.).\n * Don't wrap in `Card`; this is the outer chrome.\n */\nexport const BASIC_PAGE_CALLOUT =\n \"flex min-w-0 flex-col gap-3 rounded-base border border-pho-secondary bg-pho-page p-5\";\n\n/**\n * One row — label (+ optional description) left, control right.\n * `min-h-[4.25rem]` (68px) keeps avatar/control rows from collapsing shorter\n * than a comfortable touch target.\n */\nexport const BASIC_PAGE_ROW =\n \"flex min-h-[4.25rem] min-w-0 flex-col gap-3 px-5 py-4 sm:flex-row sm:items-center sm:justify-between sm:gap-6\";\n\n/**\n * One card row that can host subviews. Same padding rhythm as a plain row —\n * an optional trailing `ItemPanel` breaks out of it on its own.\n */\nexport const BASIC_PAGE_ITEM = \"flex flex-col gap-3 px-5 py-4\";\n\n/**\n * Secondary strip closing an `Item` that is last in its card. Negative\n * margins escape the item's `px-5 pb-4` so the gray sheet runs edge-to-edge\n * and owns the row's bottom padding. The body above stays square and the\n * sheet's top is flush against it; only the bottom rounds, nesting into the\n * card's 12px corner (11px inside the 1px border). Content lands back on the\n * item's left gutter.\n */\nexport const BASIC_PAGE_ITEM_PANEL =\n \"-mx-5 -mb-4 flex items-center rounded-b-[calc(0.75rem-1px)] bg-pho-secondary py-1 pr-3 pl-5\";\n\n/**\n * Mid-list variant — the full-bleed sheet only reads well against the card's\n * bottom corner, so when later rows follow, the panel becomes an inset chip\n * instead: fully rounded at the small-control radius, overhanging the text\n * gutter by 8px per side (content stays aligned with the body above), and\n * leaving the row's own bottom padding and the card's hairline divider alone.\n * `-mt-1.5` collapses the item's `gap-3` (12px) to an effective `gap-1.5` (6px).\n */\nexport const BASIC_PAGE_ITEM_PANEL_DIVIDED =\n \"-mx-2 -mt-1.5 flex items-center rounded-sm bg-pho-secondary px-2 py-0.5\";\n\n/* --------------------------------- motion -------------------------------- */\n\n/**\n * One spring for every BasicPage motion — the `Stack` entrance, `Title` /\n * `Header` enter, `Reveal`, the Title ↔ Back morph, and the `Alert` /\n * `Footer` height reveals. Measured off a 60fps iOS push: ~330ms with a\n * long, gentle glide, everything co-landing. Essentially critically damped\n * (an overshooting edge would show clipped content).\n */\nconst ENTRANCE_SPRING = SPRING_ENTRANCE;\n\n/** Fade paired with the spring — spans most of the glide. */\nconst ENTRANCE_FADE = FADE_ENTRANCE;\n\n/**\n * Rise distance for the `Reveal` / `Stack` / `enter` entrances — small\n * travel; the content surfaces, it doesn't slide in.\n */\nconst REVEAL_RISE_PX = RISE_PX;\n\n/* --------------------------------- parts --------------------------------- */\n\n/**\n * Page chrome — centered column at the standard content width. Hosts\n * `Title` + `Stack` (and any route-level siblings). Prefer this over\n * ad-hoc `max-w-*` wrappers in the app shell.\n *\n * `44.5rem` = the 42rem (`2xl`) content column plus the two `px-5` gutters,\n * so wide viewports render exactly as before while narrow ones keep a 20px\n * breathing edge instead of running content into the viewport.\n *\n * `relative` anchors `Back`, which floats in the top padding. The top zone\n * is conditional (`:has()`): pages carrying a `Back` reserve 64px for it;\n * pages without one keep the tighter 48px so the title doesn't sit low.\n *\n * The column is also a `min-h-full` flex stack: when the host gives it a\n * height context (an app shell's scroll pane), a full-page state can claim\n * the leftover viewport with `flex-1` — `ErrorView className=\"flex-1\"`\n * centers itself vertically below the title. Hosts without a height context\n * see a normal column; regular pages are unaffected.\n *\n * Root itself never animates — the page entrance lives on `Stack`, so\n * `Title` and `Back` (the page chrome) stay put while the body below rises\n * in.\n */\nexport interface BasicPageRootProps extends ComponentProps<\"div\"> {\n ref?: Ref<HTMLDivElement>;\n /**\n * Condense on scroll — on by default. Once the title has scrolled out of\n * the pane, a sticky bar pins to the top with the way back and the page\n * name: the large title collapsing into its bar. It assembles itself\n * from `Title` and the trail's tail crumb; nothing to wire. Pass `false`\n * for a page that should scroll away whole.\n *\n * `\"pinned\"` makes the condensed state the page's only state: the bar\n * is up from the first paint, with no entrance, and never dissolves —\n * nothing is observed. The heading block leaves the flow: `Title` still\n * names the page (its `h1` stays, visually hidden) and still hands the\n * bar its words; the trail in the flow hides, and the bar's tail crumb\n * is the way back. The column starts right under the bar — its top seat\n * is the bar's height, nothing more — and `Stack` sits at the untitled\n * rhythm, 12px below it. For a page that is one surface (an inbox, a\n * board) and has no room for a title block. A shell adopting the bar\n * reads `condensed: true` from the start, as it does after a scroll.\n */\n condense?: boolean | \"pinned\";\n /**\n * The content column's cap. `base` is the 42rem reading column every\n * settings page uses; `wide` opens it to 80rem for a page that is a\n * list first — rows with several columns. Left unsaid, the page sizes\n * itself: `base`, until it carries a `Table` — records in columns run\n * wide on their own. Forms stay on `base`: across a wide row a label\n * and its control drift out of one glance. Either width can host an\n * `Aside` — the column keeps its cap beside the panel, and leftover\n * space is margin, not content width.\n *\n * `full` takes the cap and the gutters off: the column is the pane, edge\n * to edge, with no trim under it. For a page that is one surface filling\n * the pane (an inbox, a board) — pair it with `condense=\"pinned\"`, and\n * `Stack` sits flush under the bar. Its content brings its own padding.\n */\n width?: \"base\" | \"wide\" | \"full\";\n /**\n * This page was painted before React — rendered to a string and inlined\n * ahead of the bundle (a boot skeleton), or the React twin re-rendering\n * that markup as-is on its first commit. Marks the root with\n * `data-basic-page-prerendered`. Nothing inside it plays the entrance,\n * an explicit `enter` included: the page is already on screen, and\n * starting values would blink it out. The React page taking over from\n * it stays put too — it finds the marker in the document at its first\n * render, while the twin is still there.\n *\n * Not needed for markup React hydrates in place (a server-rendered\n * page): the parts know a hydration pass from a mount and stay at rest\n * on their own. This is for the twin that mounts fresh, beside or over\n * markup it does not hydrate.\n */\n prerendered?: boolean;\n}\n\n/**\n * What `useEntrance` reads to place a part in its page: the page's root\n * (whose node is what a part scans for a loading part it may be taking\n * over from) and whether the page was painted before React. `null` outside\n * a `Root`, where a part falls back to scanning the whole document.\n */\ninterface EntranceScope {\n ref: RefObject<HTMLDivElement | null>;\n prerendered: boolean;\n}\n\nconst EntranceScopeContext = createContext<EntranceScope | null>(null);\n\n/** Below this pane width (Tailwind's `md`) an `Aside` is the page, not a panel beside it. */\nconst ASIDE_PANE_MIN_PX = 768;\n\n/** How wide the panel is, once the pane is wide enough to host it. */\nexport type BasicPageAsideWidth = \"default\" | \"wide\";\n\n/**\n * The panel's width. Default is two fifths of a small pane, floored at\n * 20rem and capped at 28rem — a subpage that is a reading column. `wide`\n * is two thirds of the pane, floored at 28rem and capped at 48rem, for a\n * subpage that is a waterfall or a JSON body. Both sides keep their own\n * measure: the page beside the panel holds its column cap, and leftover\n * space is margin, not content width. Below `ASIDE_PANE_MIN_PX` this is\n * unused: the subpage is the page.\n */\nfunction asideWidth(pane: number, size: BasicPageAsideWidth = \"default\") {\n return size === \"wide\"\n ? Math.round(Math.min(Math.max(pane * (2 / 3), 448), 768))\n : Math.round(Math.min(Math.max(pane * 0.4, 320), 448));\n}\n\n/**\n * How an open `Aside` shows its subpage: a `panel` beside the page, or as\n * the `page` itself, the list stepping aside.\n */\nexport type BasicPageAsidePresentation = \"panel\" | \"page\";\n\ninterface AsideHost {\n /** Where the panel mounts — a cell after the page's column. */\n slot: HTMLElement | null;\n /** The pane is too narrow for two columns: an `Aside` can only be the page. */\n paneNarrow: boolean;\n /** The scroll pane's width, px — what `asideWidth` reads. */\n paneWidth: number;\n /** The scroll pane's height, px — null while the document itself scrolls. */\n paneHeight: number | null;\n setOpen: (open: boolean) => void;\n /** The `Aside` reports how it presents — `Root` hides the list while it is the page. */\n setAsPage: (asPage: boolean) => void;\n /** An `Aside` announces itself — measuring idles until one is mounted. */\n setPresent: (present: boolean) => void;\n}\n\nconst AsideHostContext = createContext<AsideHost | null>(null);\n\n/** Handed down by the panel to the page inside it. */\ninterface AsidePanelController {\n setBack: (back: CondenseTail | null) => void;\n}\n\nconst AsidePanelContext = createContext<AsidePanelController | null>(null);\n\n/**\n * A page hosts its `Aside`: it measures the pane it lives in — how wide\n * (which decides the presentation and the panel's width), how tall (the\n * panel's height) — and keeps a cell after its column for the panel to\n * mount into. Everything idles until an `Aside` is actually mounted.\n */\nfunction useAsideHost(rootRef: RefObject<HTMLDivElement | null>) {\n const [slot, setSlot] = useState<HTMLElement | null>(null);\n const [present, setPresent] = useState(false);\n const [open, setOpen] = useState(false);\n const [asPage, setAsPage] = useState(false);\n const [pane, setPane] = useState<{ width: number; height: number | null }>(\n () => ({\n width: typeof window === \"undefined\" ? 0 : window.innerWidth,\n height: null,\n }),\n );\n useLayoutEffect(() => {\n const el = rootRef.current;\n if (!present || el == null) return;\n const scroller = findScrollParent(el);\n const measure = () => {\n const width = el.offsetWidth;\n const height = scroller?.clientHeight ?? null;\n setPane((prev) =>\n prev.width === width && prev.height === height\n ? prev\n : { width, height },\n );\n };\n measure();\n if (typeof ResizeObserver === \"undefined\") return;\n const observer = new ResizeObserver(measure);\n observer.observe(el);\n if (scroller != null) observer.observe(scroller);\n return () => observer.disconnect();\n }, [rootRef, present]);\n const host = useMemo<AsideHost>(\n () => ({\n slot,\n paneNarrow: pane.width < ASIDE_PANE_MIN_PX,\n paneWidth: pane.width,\n paneHeight: pane.height,\n setOpen,\n setAsPage,\n setPresent,\n }),\n [slot, pane],\n );\n return { host, setSlot, open, asPage };\n}\n\nfunction scrollTopOf(scroller: Element | null) {\n return scroller == null ? window.scrollY : scroller.scrollTop;\n}\n\nfunction scrollTo(scroller: Element | null, top: number) {\n if (scroller == null) window.scrollTo({ top });\n else scroller.scrollTop = top;\n}\n\nfunction Root({\n condense = true,\n width,\n prerendered = false,\n className,\n children,\n ref,\n ...props\n}: BasicPageRootProps) {\n // While an app shell adopts the bar (CondenseScope), the way back lives\n // there from the start — the page's own corner trail hides and the\n // column keeps its tighter top. Inside an `Aside`'s panel likewise: the\n // close in the panel's corner is the way back.\n const adopted = useContext(CondenseScopeContext)?.adopt ?? false;\n const panel = useContext(AsidePanelContext);\n // Born condensed and staying so: the bar is the page's heading.\n const pinned = condense === \"pinned\";\n // A page that carries a table is a wide page — tables announce\n // themselves, so `width` can stay unsaid. Saying it wins either way.\n const [hasTable, setHasTable] = useState(false);\n const tableCount = useRef(0);\n const announceTable = useCallback((present: boolean) => {\n tableCount.current += present ? 1 : -1;\n setHasTable(tableCount.current > 0);\n }, []);\n // Inside an `Aside`'s panel the sheet is the pane and keeps its own\n // padding: `full` there is the panel's default, not a second layout. Said\n // once here so the column and the root's attribute (which `Stack` reads\n // for its seat under a pinned bar) can never disagree.\n const full = width === \"full\" && panel == null;\n const wide = width === \"wide\" || (width == null && hasTable);\n // The channel between a searchable table and a `Search` in a header.\n const [tableSearch] = useState(createTableSearchStore);\n const rootRef = useRef<HTMLDivElement | null>(null);\n // The parts inside decide their entrance against this page alone (see\n // `useEntrance`): a loading part in another page on screen is not theirs.\n const entranceScope = useMemo<EntranceScope>(\n () => ({ ref: rootRef, prerendered }),\n [prerendered],\n );\n const [title, setTitle] = useState<{\n label: ReactNode;\n el: HTMLElement | null;\n } | null>(null);\n const [tail, setTail] = useState<CondenseTail | null>(null);\n useEffect(() => {\n if (panel == null) return;\n panel.setBack(tail);\n return () => panel.setBack(null);\n }, [panel, tail]);\n const {\n host,\n setSlot,\n open: asideOpen,\n asPage: asideAsPage,\n } = useAsideHost(rootRef);\n // While the aside is the page (a narrow pane, an entry by URL, or the\n // reader expanded it): the pane starts at its top, and when the aside\n // closes, returns to where the list was.\n const asideIsPage = asideOpen && asideAsPage;\n const registry = useMemo<CondenseRegistry>(\n () => ({ setTitle, setTail, pinned }),\n [pinned],\n );\n // What a pinned `Title` needs for the bar it mounts itself — kept off\n // `registry` on purpose: `Breadcrumbs` reads `registry` too, and folding\n // a value it *writes* (`tail`) into the same memo would change the\n // object its own effect depends on every time that effect runs,\n // resetting it forever (an infinite loop, not just a wasted render).\n const pinnedBar = useMemo<CondensePinnedBar>(\n () => ({\n tail: panel == null ? tail : null,\n silent: asideIsPage || panel != null,\n }),\n [tail, panel, asideIsPage],\n );\n const wasPage = useRef(false);\n const listScroll = useRef(0);\n useLayoutEffect(() => {\n const el = rootRef.current;\n if (asideIsPage === wasPage.current || el == null) return;\n wasPage.current = asideIsPage;\n const scroller = findScrollParent(el);\n if (asideIsPage) {\n listScroll.current = scrollTopOf(scroller);\n scrollTo(scroller, 0);\n } else {\n scrollTo(scroller, listScroll.current);\n }\n }, [asideIsPage]);\n // The page is a full-width shell that owns the chrome — the trail in its\n // top-left corner, the condensing bar across its top — around a centered\n // content column. The chrome belongs to the pane, not the column: on a\n // wide pane the way back stays at the corner while the column centers.\n // Pinned, `Title` mounts the bar itself instead (see its doc) — a second\n // copy here would double it, and could only ever learn the label a\n // commit late from `setTitle`, forever empty in a render that never gets\n // a second one.\n const bar =\n condense && !pinned ? (\n <CondenseBar\n title={title}\n tail={panel == null ? tail : null}\n silent={asideIsPage || panel != null}\n />\n ) : null;\n const column = (\n <div\n data-basic-page-column=\"\"\n className={cn(\n \"mx-auto flex w-full min-w-0 flex-1 flex-col px-5 pt-12 pb-12 *:min-w-0\",\n // A host page keeps its reading or list cap. A subpage inside the\n // panel fills the sheet — the 44.5rem column is wider than a\n // default panel and would scroll the pane sideways.\n panel == null &&\n (full\n ? \"px-0 pb-0\"\n : wide\n ? \"max-w-[84rem] md:px-8\"\n : \"max-w-[44.5rem]\"),\n // Pinned, the trail lives in the bar and the column reserves no\n // seat of its own: `Title` mounts the bar as a real 48px block at\n // the head of the flow (see there), so content starts right under\n // it. A negative margin on a zero-height bar would not do — in a\n // flex column margins do not collapse, and every sibling after it\n // would climb the same 48px, under the bar. Adopted, the shell's\n // bar sits above the pane and the column starts at its top too.\n pinned\n ? \"pt-0 [&_[data-basic-page-back]]:hidden\"\n : adopted || panel != null\n ? \"[&_[data-basic-page-back]]:hidden\"\n : \"has-[[data-basic-page-back]]:pt-16\",\n )}\n >\n {condense ? (\n <CondenseContext.Provider value={registry}>\n <CondensePinnedBarContext.Provider value={pinnedBar}>\n {children}\n </CondensePinnedBarContext.Provider>\n </CondenseContext.Provider>\n ) : (\n children\n )}\n </div>\n );\n return (\n <div\n data-basic-page-root=\"\"\n data-basic-page-width={full ? \"full\" : wide ? \"wide\" : undefined}\n data-basic-page-prerendered={prerendered ? \"\" : undefined}\n data-basic-page-pinned={pinned ? \"\" : undefined}\n className={cn(\n \"relative flex min-h-full w-full min-w-0 flex-row\",\n className,\n )}\n {...props}\n ref={(node) => {\n rootRef.current = node;\n if (typeof ref === \"function\") ref(node);\n else if (ref != null) ref.current = node;\n }}\n >\n <EntranceScopeContext.Provider value={entranceScope}>\n <AsideHostContext.Provider value={host}>\n <TableHostContext.Provider value={announceTable}>\n <TableSearchContext.Provider value={tableSearch}>\n <div\n data-basic-page-main=\"\"\n className={cn(\n \"flex min-w-0 flex-1 flex-col\",\n asideIsPage && \"hidden\",\n )}\n >\n {bar}\n {column}\n </div>\n <div ref={setSlot} className=\"contents\" />\n </TableSearchContext.Provider>\n </TableHostContext.Provider>\n </AsideHostContext.Provider>\n </EntranceScopeContext.Provider>\n </div>\n );\n}\n\n/**\n * Pages whose heading has left the pane — one entry per condensed bar,\n * kept in a layout effect so the set is exact within a commit: a departing\n * page's cleanup and an arriving page's mount land in the same flush.\n * Read at render by an arriving bar. During a route swap the page being\n * left is still mounted at that moment, so the comer knows a bar is on\n * screen and takes it over in place — first painted already condensed,\n * with no entrance — instead of letting it vanish with the old page and\n * fade back in a frame later. Its own observation then has the last word:\n * a page that starts at its top dissolves the inherited bar with the usual\n * fade. A shell adopting the bar reads the same continuity through the\n * scope store, so its one bar never dips between pages either.\n */\nconst condensedPages = new Set<string>();\n\n/**\n * The condensed header — hidden until the whole heading has left the\n * scrollport (observed against the nearest scrollable ancestor), then fades\n * in pinned to the top: the tail crumb as the way back at the left, the\n * page name rising into the center. Unmounted while hidden so it never catches focus or\n * clicks meant for the trail beneath it. It stacks above a scroll area's\n * own top edge (`z-20` over its `z-10`), whose gradient blur would\n * otherwise sit on the title text. A page arriving under a bar another\n * page was showing keeps that bar up (see `condensedPages`); only its\n * contents — the way back, the page name — change. A `pinned` bar is up\n * from the first paint and stays: nothing is observed, and its first\n * frame is its resting one, as for a bar handed over.\n *\n * `Root` mounts this for every mode but `pinned`; there, `Title` mounts it\n * instead, handing it its own words directly rather than through\n * `setTitle`. `Root`'s own render always happens before `children`'s —\n * sibling order, not timing — so a `title` read from `Root`'s state is only\n * ever what the *previous* commit learned; a static render\n * (`renderToStaticMarkup`, a boot skeleton) never gets a second one, and\n * the bar would stay empty forever. `Title` already has its words at\n * render, before any effect: letting it own the pinned instance is what\n * makes the first frame the right one.\n */\nfunction CondenseBar({\n title,\n tail,\n silent = false,\n pinned = false,\n className,\n}: {\n title: { label: ReactNode; el: HTMLElement | null } | null;\n tail: CondenseTail | null;\n /** A page hidden behind its aside says nothing to the scope. */\n silent?: boolean;\n /** The bar is the page's heading: condensed from the start, never let go. */\n pinned?: boolean;\n /** `Title`'s pinned instance gives the bar its height in the flow — see there. */\n className?: string;\n}) {\n const reduceMotion = useReducedMotion();\n // Born condensed when pinned, or when another page's bar is up as this\n // one renders: the bar is handed over rather than re-entered. A silent\n // page (one inside an aside's panel) neither inherits nor hands over —\n // its bar is not the pane's.\n const [condensed, setCondensed] = useState(\n () => pinned || (!silent && condensedPages.size > 0),\n );\n const scope = useContext(CondenseScopeContext);\n const owner = useId();\n useLayoutEffect(() => {\n if (!condensed || silent) return;\n condensedPages.add(owner);\n return () => {\n condensedPages.delete(owner);\n };\n }, [owner, condensed, silent]);\n useEffect(() => {\n if (scope == null) return;\n if (silent) {\n scope.store.clear(owner);\n return;\n }\n scope.store.set(owner, {\n condensed,\n title: title?.label ?? null,\n back: tail,\n });\n }, [scope, owner, condensed, title, tail, silent]);\n useEffect(() => {\n if (scope == null) return;\n return () => scope.store.clear(owner);\n }, [scope, owner]);\n const el = title?.el ?? null;\n useEffect(() => {\n // Pinned, the heading never comes back into the pane: nothing to watch.\n if (pinned) return;\n if (el == null || typeof IntersectionObserver === \"undefined\") {\n // Nothing to watch: an inherited bar has no heading to keep it up, so\n // it dissolves on the next frame — unless a heading registers first\n // (a `Title`'s layout effect lands before paint) and cancels this.\n if (typeof requestAnimationFrame === \"undefined\") return;\n const frame = requestAnimationFrame(() => setCondensed(false));\n return () => cancelAnimationFrame(frame);\n }\n const observer = new IntersectionObserver(\n ([entry]) => setCondensed(entry != null && !entry.isIntersecting),\n { root: findScrollParent(el) },\n );\n observer.observe(el);\n return () => observer.disconnect();\n }, [el, pinned]);\n // The page name follows the scroll: the title left upward, so its bar\n // form rises in from `CONDENSE_BAR_RISE_PX` below (and sinks back the\n // same way) — the move a shell adopting the bar plays on narrow\n // viewports, so both widths read as one motion. The bar itself only\n // fades, in place. Under reduced motion neither travels nor softens.\n const titleRise = reduceMotion ? 0 : -CONDENSE_BAR_RISE_PX;\n const titleBlurAway = reduceMotion ? \"blur(0px)\" : `blur(${BLUR_MAX_PX}px)`;\n return (\n <div\n data-basic-page-condense=\"\"\n className={cn(\"sticky top-0 z-20 h-0 overflow-visible\", className)}\n >\n {/* `initial={false}`: a bar present at the first render was handed\n over from the page before — it stays put, its contents in place,\n no fade and no rise. A bar that appears later enters as usual. */}\n <AnimatePresence initial={false}>\n {condensed && !(scope?.adopt ?? false) && (\n <motion.div\n initial={{ opacity: 0 }}\n animate={{ opacity: 1 }}\n exit={{ opacity: 0 }}\n transition={CONDENSE_BAR_ENTER}\n // Three columns, the outer two equal, so the page name sits at\n // the bar's center whatever the way back is wide, never under it;\n // a long name truncates in its own cell. A name that is itself a\n // flex row (a word and a badge) centers as a block, which\n // text-align alone would not do.\n className=\"border-pho-secondary bg-pho-page/85 relative grid h-12 grid-cols-[1fr_minmax(0,auto)_1fr] items-center border-b px-3 backdrop-blur\"\n >\n <div className=\"flex min-w-0 items-center justify-start\">\n {tail != null && (\n <ButtonLink\n variant=\"ghost\"\n size=\"sm\"\n href={tail.href}\n onClick={tail.onClick}\n prefix={\n <span className=\"inline-flex [&>svg]:size-[1.125em] [&>svg]:shrink-0\">\n <IconChevronLeft />\n </span>\n }\n className=\"min-w-max\"\n >\n {tail.label}\n </ButtonLink>\n )}\n </div>\n <motion.span\n initial={{ opacity: 0, y: titleRise, filter: titleBlurAway }}\n animate={{ opacity: 1, y: 0, filter: \"blur(0px)\" }}\n exit={{ opacity: 0, y: titleRise, filter: titleBlurAway }}\n transition={{ ...CONDENSE_BAR_ENTER, y: CONDENSE_BAR_TRAVEL }}\n className=\"text-pho-primary block max-w-full min-w-0 truncate text-center text-base font-medium\"\n >\n {title?.label}\n </motion.span>\n </motion.div>\n )}\n </AnimatePresence>\n </div>\n );\n}\n\n/**\n * Slug for hash targets — \"Danger zone\" → `danger-zone`. Empty / non-string\n * children yield no id; pass an explicit `id` to override or `id=\"\"` to opt out.\n */\nfunction slugifyHeading(value: string): string {\n return value\n .normalize(\"NFKD\")\n .replace(/[\\u0300-\\u036f]/g, \"\")\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, \"-\")\n .replace(/^-+|-+$/g, \"\");\n}\n\nfunction headingIdFromChildren(children: ReactNode): string | undefined {\n if (typeof children !== \"string\" && typeof children !== \"number\") {\n return undefined;\n }\n const slug = slugifyHeading(String(children));\n return slug || undefined;\n}\n\n/** Resolve `id`: explicit wins; `\"\"` opts out; else slug from plain-text children. */\nfunction resolveHeadingId(\n id: string | undefined,\n children: ReactNode,\n): string | undefined {\n if (id === \"\") return undefined;\n if (id != null) return id;\n return headingIdFromChildren(children);\n}\n\n/**\n * Namespaced Motion `layoutId` for the Title ↔ Back shared-element morph —\n * give a parent page's `Title` and its subpage's `Back` the same `morphId`\n * and the word itself travels between the two: the large title shrinks into\n * the back link on drill-in, and grows back on return.\n */\nconst morphLayoutId = (id: string) => `basic-page-morph-${id}`;\n\n/** The morph rides the page-tier entrance spring — one glide, everywhere. */\nconst MORPH_TRANSITION = { layout: ENTRANCE_SPRING } as const;\n\n/**\n * Chevron entrance for a morphing `Back`, measured off a 60fps iOS push\n * (sub-pixel tracking of the recording): the arrow emerges from under the\n * left edge of the arriving word at ~62% of the flight — sliding left by\n * ~2/3 of its own width with a strong ease-out while fading in over ~120ms\n * — and lands together with the word, which is still gliding its last few\n * pixels the whole time. Nothing is sequential.\n */\nconst MORPH_CHEVRON_RISE_X = 10;\nconst MORPH_CHEVRON_ENTER = {\n delay: 0.2,\n duration: 0.12,\n ease: \"easeOut\",\n} as const;\n\n/**\n * Ink crossfade for the morphing word — iOS redraws the word in the\n * destination's ink and fades the origin-ink rendition out over the first\n * half of the flight, so the word takes off in the color it had and lands\n * in the color it gets. `MorphLabel` mounts the ghost only while a layout\n * animation is actually running, so static renders never see it.\n */\nconst MORPH_INK_FADE = { duration: 0.18, ease: \"easeOut\" } as const;\n\n/**\n * Deeper than one level, the back link's slot is already occupied when a\n * navigation happens, and iOS treats the chevron as furniture: it stays put\n * across pushes and pops between subpages, and only the label changes.\n * Measured off the WLAN → Succade push and its pop in the same recording:\n *\n * - **Push** — the outgoing back label leaves as the old title shrinks\n * into its place: iOS slides it the whole way under the chevron in\n * ~130ms; here it fades out with a short drift in that direction — the\n * full slide read as a whoosh next to a word that is still arriving.\n * - **Pop** — the incoming back label slides right out from under the\n * chevron, starting ~40% into the title's return flight, ~150ms.\n * - **Pop to the root** — no back link remains; the chevron fades out in\n * place over the first frames while the word grows into the title.\n */\nconst BACK_LABEL_LEAVE_X = -8;\nconst BACK_LABEL_LEAVE = { duration: 0.16, ease: \"easeOut\" } as const;\nconst BACK_LABEL_ARRIVE = {\n delay: 0.14,\n duration: 0.16,\n ease: \"easeOut\",\n} as const;\nconst BACK_CHEVRON_LEAVE = { duration: 0.12, ease: \"easeOut\" } as const;\n\n/**\n * Trails (breadcrumb navs) currently mounted — one per page. Read at render\n * by an arriving `Breadcrumbs` or morphing `Title`: the outgoing page's\n * trail is still mounted at that moment, so the arriving side knows one is\n * on its way out, and how long it was, and can play the depth transition —\n * hold the chevron, see the old label off, fade a separator, or fade the\n * chevron when no trail returns. `useLayoutEffect` keeps the list exact\n * within a commit: an outgoing trail's cleanup runs before an incoming\n * trail's mount effect.\n */\nconst mountedTrails: { labels: ReactNode[] }[] = [];\n\nfunction useTrailPresence(labels: ReactNode[]) {\n const entry = useRef({ labels });\n entry.current.labels = labels;\n useLayoutEffect(() => {\n const self = entry.current;\n mountedTrails.push(self);\n return () => {\n mountedTrails.splice(mountedTrails.indexOf(self), 1);\n };\n }, []);\n}\n\n/** The trail on its way out at this render, if any — snapshot at mount. */\nfunction useDepartingTrail() {\n const [departing] = useState<{ labels: ReactNode[] } | null>(() => {\n const last = mountedTrails[mountedTrails.length - 1];\n return last ? { labels: [...last.labels] } : null;\n });\n return departing;\n}\n\n/**\n * Condensing header — the page's way back once the title has scrolled away.\n * `Root condense` renders a sticky bar in the reserved top zone; `Title` and\n * `Breadcrumbs` report what belongs in it (the heading, the tail crumb)\n * through this context, so the bar assembles itself and consumers only set\n * the flag. The bar stays out of the way until the whole heading has left\n * the scrollport, then fades in pinned to the top. `condense=\"pinned\"` is\n * the one exception: there, `Title` mounts the bar itself instead of\n * reporting to it — see `CondenseBar`'s doc.\n */\ninterface CondenseTail {\n label: ReactNode;\n href: string;\n onClick?: ComponentProps<\"a\">[\"onClick\"];\n}\n\ninterface CondenseRegistry {\n setTitle: (\n title: { label: ReactNode; el: HTMLElement | null } | null,\n ) => void;\n setTail: (tail: CondenseTail | null) => void;\n /** The bar is the page's heading (`Root condense=\"pinned\"`): the flow's title steps aside for it. */\n pinned: boolean;\n}\n\nconst CondenseContext = createContext<CondenseRegistry | null>(null);\n\n/**\n * The way back and quiet-flag a pinned `Title` needs for the bar it mounts\n * itself (see `CondenseBar`'s doc) — the same two things `Root` hands its\n * own instance. A separate context from `CondenseRegistry` on purpose:\n * `Breadcrumbs` writes the tail through `registry.setTail`, and folding its\n * *current* value into the same memo `Breadcrumbs` also reads would change\n * the object its effect depends on every time that effect runs — resetting\n * it forever, an infinite loop rather than a wasted render.\n */\ninterface CondensePinnedBar {\n tail: CondenseTail | null;\n silent: boolean;\n}\n\nconst CONDENSE_PINNED_BAR_IDLE: CondensePinnedBar = {\n tail: null,\n silent: false,\n};\n\nconst CondensePinnedBarContext = createContext<CondensePinnedBar>(\n CONDENSE_PINNED_BAR_IDLE,\n);\n\n/**\n * What the condensed bar would show, for an app shell that shows it\n * itself: whether the title has left the pane, the page name, the way\n * back. Idle (`condensed: false`, both null) outside any `CondenseScope`.\n */\nexport interface BasicPageCondense {\n condensed: boolean;\n title: ReactNode | null;\n back: CondenseTail | null;\n}\n\nconst CONDENSE_IDLE: BasicPageCondense = {\n condensed: false,\n title: null,\n back: null,\n};\n\ninterface CondenseStore {\n get: () => BasicPageCondense;\n set: (owner: string, next: BasicPageCondense) => void;\n clear: (owner: string) => void;\n subscribe: (listener: () => void) => () => void;\n}\n\nconst CondenseScopeContext = createContext<{\n store: CondenseStore;\n adopt: boolean;\n} | null>(null);\n\nconst subscribeToNothing = () => () => {};\nconst getIdle = () => CONDENSE_IDLE;\n\n/**\n * Hands the condensed bar to the app shell. On a narrow viewport the shell\n * already has a bar of its own; two stacked bars is one too many. Wrap the\n * shell (its bar and the routed pages) in `CondenseScope` and read\n * `useCondense()` where the bar is: while `condensed`, show `title` in the\n * middle and `back` as a plain chevron beside the menu button. While\n * `adopt` is true the page renders no bar of its own; pass `adopt={false}`\n * on viewports where the shell bar does not exist (desktop) and the page's\n * bar returns. State still tracks either way — `useCondense()` always\n * answers.\n */\nfunction CondenseScope({\n adopt = true,\n children,\n}: {\n adopt?: boolean;\n children?: ReactNode;\n}) {\n const [store] = useState<CondenseStore>(() => {\n let snapshot = CONDENSE_IDLE;\n let owner: string | null = null;\n const listeners = new Set<() => void>();\n const emit = () => {\n for (const listener of listeners) listener();\n };\n return {\n get: () => snapshot,\n set(id, next) {\n owner = id;\n snapshot = next;\n emit();\n },\n // Only the last writer clears — during a page swap the departing\n // page unmounts after the arriving one has already spoken.\n clear(id) {\n if (owner !== id) return;\n owner = null;\n snapshot = CONDENSE_IDLE;\n emit();\n },\n subscribe(listener) {\n listeners.add(listener);\n return () => listeners.delete(listener);\n },\n };\n });\n const value = useMemo(() => ({ store, adopt }), [store, adopt]);\n return (\n <CondenseScopeContext.Provider value={value}>\n {children}\n </CondenseScopeContext.Provider>\n );\n}\n\n/** The nearest scope's condense state — see `CondenseScope`. */\nexport function useCondense(): BasicPageCondense {\n const scope = useContext(CondenseScopeContext);\n return useSyncExternalStore(\n scope?.store.subscribe ?? subscribeToNothing,\n scope?.store.get ?? getIdle,\n scope?.store.get ?? getIdle,\n );\n}\n\n/**\n * The condensed bar's motion, exported for a shell that adopts the bar\n * (`CondenseScope`) so its swap moves the same way: 0.2s ease-out. The bar\n * fades in place; its page name rises in from 8px below and leaves the\n * same way.\n */\nexport const CONDENSE_BAR_ENTER = FADE_SWAP;\n/**\n * The displacement channel of the same move: travel is linear, like the\n * library's other linear transitions (the 100ms control inks), while the\n * fade and the soft focus keep the ease-out. Spread it per axis:\n * `transition={{ ...CONDENSE_BAR_ENTER, y: CONDENSE_BAR_TRAVEL }}`.\n */\nexport const CONDENSE_BAR_TRAVEL = TRAVEL_LINEAR;\n/**\n * The bar's rise distance, signed as \"from above\": the page name comes\n * from below, so it starts at `-CONDENSE_BAR_RISE_PX`.\n */\nexport const CONDENSE_BAR_RISE_PX = BAR_RISE_PX;\n\n/** Nearest scrollable ancestor — the observer root; `null` means viewport. */\nfunction findScrollParent(el: HTMLElement): Element | null {\n if (typeof getComputedStyle !== \"function\") return null;\n for (\n let node = el.parentElement;\n node != null && node !== document.body;\n node = node.parentElement\n ) {\n const { overflowY } = getComputedStyle(node);\n if (overflowY === \"auto\" || overflowY === \"scroll\") return node;\n }\n return null;\n}\n\n/**\n * A shared element can only fly between two points the user has seen. Each\n * morph word tracks whether it is on screen (keyed by `morphId`); when the\n * other end mounts, it flies only if the word it continues was visible.\n * A title scrolled out of view yields a plain fade at the destination\n * instead of a dive in from off-screen.\n */\nconst morphWordSeen = new Map<string, { visible: boolean; el: Element }>();\n\n/**\n * A flight is worth it only over a short distance. The title sits at the\n * column's left edge, the crumb in the page's top-left corner, so the\n * distance between the two ends is the column's inset from the page's\n * edge. Up to a short word's width the morph reads as one word moving\n * up; on a wide pane the column centers far from the corner, the flight\n * becomes a long streak across empty space, and the word fades across\n * instead (the same arrival it plays when the other end was never seen).\n * Measured when the flight is decided, against the page the word is\n * leaving (still mounted at that render), so a window resized since that\n * page loaded is judged as it is now, not as it was.\n */\nconst MORPH_FLIGHT_MAX_INSET = 96;\n\n/** The column's inset from the page's left edge, for a word inside a `Root`. */\nfunction columnInset(el: Element): number {\n const root = el.closest(\"[data-basic-page-root]\");\n const column = root?.querySelector(\"[data-basic-page-column]\");\n if (!root || !column) return 0;\n return (\n column.getBoundingClientRect().left - root.getBoundingClientRect().left\n );\n}\n\n/**\n * Mount-locked flight decision + live visibility tracking for a morph word.\n * `fly` is read from the registry once at mount (was the other end on\n * screen?); the ref then feeds this word's own visibility back for the next\n * navigation. No-ops without `IntersectionObserver` (jsdom, SSR).\n */\nfunction useMorphFlight(morphId: string | undefined) {\n const [fly] = useState(() => {\n if (morphId == null) return false;\n const seen = morphWordSeen.get(morphId);\n return (\n seen != null &&\n seen.visible &&\n seen.el.isConnected &&\n columnInset(seen.el) <= MORPH_FLIGHT_MAX_INSET\n );\n });\n const ref = useRef<HTMLSpanElement | null>(null);\n useEffect(() => {\n if (morphId == null || typeof IntersectionObserver === \"undefined\") return;\n const el = ref.current;\n if (!el) return;\n const observer = new IntersectionObserver(([entry]) => {\n if (entry) {\n morphWordSeen.set(morphId, { visible: entry.isIntersecting, el });\n }\n });\n observer.observe(el);\n return () => {\n observer.disconnect();\n // The other end reads the registry while rendering — before this\n // cleanup runs in the same commit — so clearing here keeps a page-swap\n // flight intact while a later, unrelated mount (the list re-entered\n // from the sidebar) starts fresh instead of trusting stale sight.\n morphWordSeen.delete(morphId);\n };\n }, [morphId]);\n return { fly, ref };\n}\n\n/** How a morph word shows up when it is not flying in. */\ntype MorphArrival = \"fade\" | \"rise\" | \"slide\";\n\nconst MORPH_ARRIVALS = {\n // Back label with nothing to fly from — a plain fade.\n fade: {\n initial: { opacity: 0 },\n animate: { opacity: 1 },\n transition: { opacity: ENTRANCE_FADE },\n },\n // Subpage title behind a departing morph — rises from just below.\n rise: {\n initial: { opacity: 0, y: REVEAL_RISE_PX },\n animate: { opacity: 1, y: 0 },\n transition: { y: ENTRANCE_SPRING, opacity: ENTRANCE_FADE },\n },\n // Back label on a pop between subpages — out from under the chevron.\n slide: {\n initial: { x: \"-100%\" },\n animate: { x: 0 },\n transition: { x: BACK_LABEL_ARRIVE },\n },\n} as const;\n\n/**\n * The shared-element word of a Title ↔ Back morph. While the box flies, an\n * origin-ink copy of the word sits on top and fades out (the iOS snapshot\n * crossfade); the copy only exists during a real layout animation. When the\n * flight is skipped (`fly` false — the other end wasn't on screen, or there\n * is no other end yet), the layout snap is instant and the word appears in\n * place, or plays its `arrival` instead: a fade, a rise on the entrance\n * spring (`Title`'s `enter`), or a slide out from under the back chevron.\n */\nfunction MorphLabel({\n morphId,\n fromClassName,\n fly,\n morphRef,\n arrival,\n className,\n children,\n}: {\n morphId: string;\n /** Ink the word arrives FROM (the other end's text color). */\n fromClassName: string;\n /** Fly the layout box — the other end was on screen at navigation. */\n fly: boolean;\n morphRef: React.Ref<HTMLSpanElement>;\n /** Entrance to play when not flying; omit to appear in place. */\n arrival?: MorphArrival;\n /** Extra classes on the flying span (Title's ellipsis lives here). */\n className?: string;\n children: ReactNode;\n}) {\n const [crossfading, setCrossfading] = useState(false);\n const arriving = !fly && arrival != null ? MORPH_ARRIVALS[arrival] : null;\n return (\n <motion.span\n ref={morphRef}\n layoutId={morphLayoutId(morphId)}\n initial={arriving?.initial}\n animate={arriving?.animate}\n transition={\n fly\n ? MORPH_TRANSITION\n : { layout: { duration: 0 }, ...arriving?.transition }\n }\n onLayoutAnimationStart={() => {\n if (fly) setCrossfading(true);\n }}\n onLayoutAnimationComplete={() => setCrossfading(false)}\n className={cn(\"relative inline-block\", className)}\n >\n {children}\n {crossfading && (\n <motion.span\n aria-hidden\n initial={{ opacity: 1 }}\n animate={{ opacity: 0 }}\n transition={MORPH_INK_FADE}\n // The ghost retires itself: a zero-distance \"flight\" (a crumb that\n // stays put between pages) starts a layout animation that never\n // reports completion.\n onAnimationComplete={() => setCrossfading(false)}\n className={cn(\"absolute inset-0\", fromClassName)}\n >\n {children}\n </motion.span>\n )}\n </motion.span>\n );\n}\n\nexport interface BasicPageTitleProps extends ComponentProps<\"h1\"> {\n /**\n * Shared-element key. Pair with the same `morphId` on the subpage's\n * `Back` and the word morphs between title and back link across the\n * navigation. Skipped under reduced motion.\n */\n morphId?: string;\n /**\n * Rise this title into its line on mount — for a subpage title whose line\n * an inbound Title ↔ Back morph departs from. The moment the word lifts\n * off, this title floats up from just below it (the Stack physics), so\n * the two form one upward stream and never overlap. Combines with\n * `morphId` for a mid-level page (a list that is itself a subpage): the\n * word rises in when the page is entered from its parent and flies in\n * from the back link when returned to from its own subpage. Played once\n * per visit: a title taking over from a loading part in this page's\n * `Root` (its skeleton's), or from a prerendered page anywhere (the one\n * painted before React), stays put. Skipped under reduced motion.\n */\n enter?: boolean;\n /**\n * A trailing accessory — a status badge, a word in its own color — at\n * the label's end, centered on its line. It stands outside the word: it\n * neither flies with a morph nor goes into the condensed bar's label,\n * and the label still ellipsizes beside it. When the word arrives in\n * motion — flying in from a back link, or rising on `enter` — the\n * accessory rises into place beside it on the same spring, so the two\n * land together.\n */\n trailing?: ReactNode;\n ref?: Ref<HTMLHeadingElement>;\n}\n\n/**\n * Ellipsis for a title word that moves. A morphing word flies in from the\n * back link's line above, and an entering word rises from below the\n * baseline: both spend part of the animation outside the heading's box, so\n * the heading itself must not clip — the `overflow: hidden` that\n * `truncate` brings lives on the moving span instead. `align-top` keeps an\n * `inline-block` with hidden overflow from taking its baseline at the\n * bottom edge, which would push the line box (and everything under the\n * title) down by the descender.\n */\nconst TITLE_MOTION_LABEL = \"max-w-full min-w-0 truncate align-top\";\n\n/**\n * The accessory slot beside the title word. A plain inline span inherits\n * the heading's `text-display-base` line box (~31px); a 20px Badge then\n * sits on that baseline and reads high or low. Making the slot a flex\n * row shrinks it to the accessory so the title's `items-center` can\n * center it on the word.\n */\nconst TITLE_TRAILING = \"flex shrink-0 items-center\";\n\n/**\n * Page title — largest heading on the surface. Plain-text children get a slug\n * `id` for hash targets (`#profile`); the heading itself is not a link.\n * Long names ellipsize; keep trailing accessories (`Badge`, status) as\n * `shrink-0` siblings of a `min-w-0 truncate` label inside a `flex min-w-0`\n * row so they stay visible.\n */\nfunction Title({\n id,\n morphId,\n enter: enterProp,\n trailing,\n className,\n children,\n ...props\n}: BasicPageTitleProps) {\n const headingId = resolveHeadingId(id, children);\n const reduceMotion = useReducedMotion();\n // The rise is the subpage's entrance: a title taking over from a loading\n // part in this page's Root (its skeleton), or from a prerendered page\n // (the one painted before React), stays put.\n const enter = useEntrance(enterProp === true);\n const flight = useMorphFlight(morphId);\n const departingTrail = useDepartingTrail();\n const moving = !reduceMotion && (morphId != null || enter === true);\n // How the word shows up when it is not flying in: `enter` rises it from\n // below; so does a pop (a trail on its way out) whose flight was declined\n // for distance, rather than letting the title simply appear.\n const arrival: MorphArrival | undefined =\n enter || departingTrail != null ? \"rise\" : undefined;\n // Under `Root condense`, hand the bar this heading — its words and its\n // element, so the bar knows what to say and when the heading is gone.\n // Pinned, the bar is the heading: the `h1` stays for the document and\n // assistive tech, and leaves the eye to the bar.\n const condense = useContext(CondenseContext);\n const pinned = condense?.pinned ?? false;\n // Pinned, this title mounts the bar itself (below) with its own words\n // directly, instead of handing them to `Root` through `setTitle` — see\n // `CondenseBar`'s doc for why. The bar is then a real block in the flow,\n // its own 48px tall, and the column keeps `pt-0`: the seat is the bar.\n // Adopted, the shell shows the bar above the pane and this instance\n // renders nothing to see, so it takes no height either.\n const adopted = useContext(CondenseScopeContext)?.adopt ?? false;\n const pinnedBar = useContext(CondensePinnedBarContext);\n const headingRef = useRef<HTMLHeadingElement | null>(null);\n useLayoutEffect(() => {\n if (condense == null || pinned) return;\n condense.setTitle({ label: children, el: headingRef.current });\n return () => condense.setTitle(null);\n }, [condense, pinned, children]);\n // A word flying in from a trail while that trail's page leaves: if no\n // trail takes over the slot (a pop to the root), its chevron is left to\n // this title to fade out. Decided after the commit's mount effects, so a\n // page that brings its own trail (a pop between subpages) keeps the\n // chevron still instead of ghosting one under it.\n const [chevronGhost, setChevronGhost] = useState(\n flight.fly && departingTrail != null,\n );\n useLayoutEffect(() => {\n if (mountedTrails.length > 0) setChevronGhost(false);\n }, []);\n const hasTrailing = trailing != null && trailing !== false;\n // The accessory moves when the word does: an inbound flight or a rise.\n const trailingMoves =\n !reduceMotion &&\n (morphId != null ? flight.fly || arrival != null : enter === true);\n const label =\n morphId != null && !reduceMotion ? (\n <MorphLabel\n morphId={morphId}\n fromClassName=\"text-pho-secondary\"\n fly={flight.fly}\n morphRef={flight.ref}\n arrival={arrival}\n className={TITLE_MOTION_LABEL}\n >\n {children}\n </MorphLabel>\n ) : enter && !reduceMotion ? (\n <motion.span\n initial={{ opacity: 0, y: REVEAL_RISE_PX }}\n animate={{ opacity: 1, y: 0 }}\n transition={{ y: ENTRANCE_SPRING, opacity: ENTRANCE_FADE }}\n className={cn(\"inline-block\", TITLE_MOTION_LABEL)}\n >\n {children}\n </motion.span>\n ) : hasTrailing ? (\n // Beside an accessory the ellipsis lives on the label, as it does for\n // a moving word; the heading's own `truncate` is a block's.\n <span className=\"min-w-0 truncate\">{children}</span>\n ) : (\n children\n );\n return (\n <>\n {pinned && condense != null && (\n // Its own words, at render — see `CondenseBar`'s doc for why this\n // can't wait for `setTitle` and a second commit.\n <CondenseBar\n title={{ label: children, el: headingRef.current }}\n tail={pinnedBar.tail}\n silent={pinnedBar.silent}\n pinned\n className={adopted ? undefined : \"h-12 shrink-0\"}\n />\n )}\n <h1\n id={headingId}\n data-basic-page-title=\"\"\n className={cn(\n \"text-display-base text-pho-primary max-w-full min-w-0 scroll-mt-12 px-5 font-medium\",\n // A static title ellipsizes on the heading; a moving one hands the\n // clip to its span so the flight / rise is never cut off.\n moving ? \"whitespace-nowrap\" : \"truncate\",\n pinned && \"sr-only\",\n className,\n )}\n {...props}\n ref={(node: HTMLHeadingElement | null) => {\n headingRef.current = node;\n const forwarded = (props as { ref?: Ref<HTMLHeadingElement> }).ref;\n if (typeof forwarded === \"function\") forwarded(node);\n else if (forwarded != null) forwarded.current = node;\n }}\n >\n {hasTrailing ? (\n // The label and its accessory on one line: the label takes the\n // squeeze and ellipsizes, the accessory keeps its size.\n <span className=\"flex max-w-full min-w-0 items-center gap-2\">\n {label}\n {trailingMoves ? (\n <motion.span\n data-basic-page-title-trailing=\"\"\n initial={{ opacity: 0, y: REVEAL_RISE_PX }}\n animate={{ opacity: 1, y: 0 }}\n transition={{ y: ENTRANCE_SPRING, opacity: ENTRANCE_FADE }}\n className={TITLE_TRAILING}\n >\n {trailing}\n </motion.span>\n ) : (\n <span\n data-basic-page-title-trailing=\"\"\n className={TITLE_TRAILING}\n >\n {trailing}\n </span>\n )}\n </span>\n ) : (\n label\n )}\n {chevronGhost && (\n <motion.span\n aria-hidden\n initial={{ opacity: 1 }}\n animate={{ opacity: 0 }}\n transition={BACK_CHEVRON_LEAVE}\n onAnimationComplete={() => setChevronGhost(false)}\n className={cn(\n \"text-pho-secondary pointer-events-none absolute inline-flex items-center\",\n BACK_CHEVRON_GHOST_POSITION,\n )}\n >\n <IconChevronLeft />\n </motion.span>\n )}\n </h1>\n </>\n );\n}\n\n/**\n * Arrival — content that replaces a skeleton reveals on its own. `Stack`\n * watches its `aria-busy`: the render in which it flips from true to false\n * is an arrival, and the rows and items mounting in that render rise in,\n * each on its own, dividers intact. Nothing else counts as arriving: a\n * remount under a new `key`, a row the user toggled on, a page's first\n * render (the stack's entrance covers that) all appear plainly. The\n * declaration is the `aria-busy` a loading page carries anyway.\n */\nconst ArrivalContext = createContext(false);\n\nfunction useArrival() {\n const arriving = useContext(ArrivalContext);\n const reduceMotion = useReducedMotion();\n const [arrives] = useState(() => arriving && !reduceMotion);\n return arrives;\n}\n\n/**\n * Leaving — a row removed from a `Card` collapses and fades out on its own.\n * `Card` keeps departing children around until their exit has played; a\n * row knows it is leaving through presence and clips itself meanwhile.\n * Padding and the divider's border go to zero with the height, so the rows\n * below close up smoothly. Under reduced motion both moments are instant.\n */\nconst ROW_EXIT = {\n height: 0,\n opacity: 0,\n paddingTop: 0,\n paddingBottom: 0,\n borderTopWidth: 0,\n} as const;\nconst ROW_TRANSITION = {\n y: ENTRANCE_SPRING,\n opacity: ENTRANCE_FADE,\n height: ENTRANCE_SPRING,\n paddingTop: ENTRANCE_SPRING,\n paddingBottom: ENTRANCE_SPRING,\n borderTopWidth: ENTRANCE_SPRING,\n} as const;\n\nfunction useRowMotion() {\n const arrives = useArrival();\n const isPresent = useIsPresent();\n const reduceMotion = useReducedMotion();\n return {\n initial: arrives ? { opacity: 0, y: REVEAL_RISE_PX } : false,\n animate: { opacity: 1, y: 0 },\n exit: ROW_EXIT,\n transition: reduceMotion ? { duration: 0 } : ROW_TRANSITION,\n leaving: !isPresent,\n } as const;\n}\n\n/**\n * Development only: the rhythm is the system's, and a wrapper that brings\n * its own gap is the one mistake that keeps recurring. After mount, a\n * container looks at what it got and says so in the console when a block\n * is spaced by some other number. Lint catches the classes; this catches\n * what lint cannot see (a className built at runtime, a host component's\n * own wrapper). Silent where no stylesheet applies (tests, SSR).\n */\n// Guarded: the browser has no `process` global, and this runs at import.\nconst RHYTHM_CHECK =\n typeof process !== \"undefined\" && process.env?.NODE_ENV !== \"production\";\n\nfunction useRhythmCheck(\n ref: RefObject<HTMLElement | null>,\n part: string,\n own: number,\n child: (el: Element) => number | null,\n) {\n useEffect(() => {\n if (!RHYTHM_CHECK || ref.current == null) return;\n if (typeof getComputedStyle !== \"function\") return;\n const gapOf = (el: Element) => {\n const value = getComputedStyle(el).rowGap;\n return value === \"\" || value === \"normal\" ? null : parseFloat(value);\n };\n const ownGap = gapOf(ref.current);\n if (ownGap != null && ownGap !== own) {\n console.warn(\n `[BasicPage.${part}] spaced at ${ownGap}px instead of ${own}px. Spacing is the system's: Stack gap-10 between blocks, a block gap-3, Fields gap-5. Remove the class and move the wrapper instead.`,\n ref.current,\n );\n }\n for (const el of Array.from(ref.current.children)) {\n const expected = child(el);\n if (expected == null) continue;\n if (getComputedStyle(el).display === \"contents\") continue;\n const gap = gapOf(el);\n if (gap != null && gap !== expected) {\n console.warn(\n `[BasicPage.${part}] a child is spaced at ${gap}px instead of ${expected}px. Spacing is the system's: Stack gap-10 between blocks, a block gap-3, Fields gap-5. Remove the class and move the wrapper instead.`,\n el,\n );\n }\n }\n });\n}\n\nexport interface BasicPageStackProps extends Omit<\n ComponentProps<\"div\">,\n RevealMotionConflicts\n> {\n /**\n * Whether mounting plays the page entrance. Left unset, the stack decides\n * from what is on screen: it enters unless it is taking over from a\n * loading part in this page's `Root` — a stack marked `aria-busy`, or\n * inside an `aria-busy` region — or a prerendered page is anywhere in\n * the document. In the first case the skeleton was the page's entrance\n * and this stack takes its place at rest, values filling in; in the\n * second the page was painted before React and is already there. A\n * loading part in some other page (one still on screen while this one\n * mounts) does not count. `true` always enters, except inside a\n * `Root prerendered` or while hydrating server markup (the page is on\n * screen either way); `false` never does.\n */\n enter?: boolean;\n ref?: Ref<HTMLDivElement>;\n}\n\n/**\n * Whether a loading part is in `scope` right now: a `Title`, `Header` or\n * `Stack` marked `aria-busy`, or one inside an `aria-busy` region. Read at\n * a part's first render, while whatever it replaces is still in the\n * document — the swap happens at commit. The scope is the part's own\n * `Root`, so a skeleton still on screen in another page (a route swap\n * away from a page whose data never came) is not mistaken for this page's.\n */\nfunction loadingPageIn(scope: ParentNode): boolean {\n return Array.from(\n scope.querySelectorAll(\n \"[data-basic-page-stack], [data-basic-page-title], [data-basic-page-header]\",\n ),\n ).some((part) => part.closest('[aria-busy=\"true\"]') != null);\n}\n\nconst paintedByReact = () => false;\nconst paintedBeforeReact = () => true;\n\n/**\n * Whether this render is markup painted before React: the server pass\n * itself, and the client's hydration of what the server sent. The two have\n * to agree with each other, and a render-time probe (`typeof document`)\n * is exactly what tells them apart: the hydrating client has a document,\n * so it would render an entrance the server did not, React would find two\n * different trees in one markup and refuse to patch either, and the page\n * would blink out and rise in again after the reader had already seen it.\n * `useSyncExternalStore` is the hook React reserves for this question: the\n * server snapshot on the server and again on the client while it hydrates,\n * the client snapshot on any mount after that, and the hydrated part\n * re-rendered once with the client's answer when hydration is over. Read\n * into a mount-time `useState`, the value is the pass's own, and that\n * re-render leaves it alone.\n */\nfunction usePaintedBeforeReact(): boolean {\n return useSyncExternalStore(\n subscribeToNothing,\n paintedByReact,\n paintedBeforeReact,\n );\n}\n\n/**\n * Whether a part plays its entrance, decided once at the first render:\n * `initial` only counts on mount, and the loading part this one may be\n * taking over from is only in the document until the commit. `wanted` is\n * the part's own answer. Overridden, in order:\n *\n * - Markup painted before React never enters, `insists` or not: rendered\n * to a string, the part has nothing to arrive from, and starting values\n * would paint it invisible until a bundle picked the animation up. The\n * client hydrating that markup is the same page, already on screen, so\n * it renders the same thing and stays put. The entrance is for a page\n * React puts on screen itself.\n * - Inside a `Root prerendered` nothing enters, `insists` or not — the\n * page is the one painted before React, already on screen.\n * - A caller that `insists` (an explicit `enter`) enters.\n * - A prerendered page anywhere in the document means this part is the\n * React page taking over from the boot skeleton: at rest.\n * - A loading part in this page's `Root` means this part is the loaded\n * half of a skeleton → data swap: at rest. At a new page's first render\n * its `Root` has not committed yet (the ref is null), so other pages'\n * skeletons are out of sight and the page enters — every sibling part\n * in it together. Outside any `Root` the whole document is the scope.\n */\nfunction useEntrance(wanted: boolean, insists = false): boolean {\n const scope = useContext(EntranceScopeContext);\n const painted = usePaintedBeforeReact();\n const [enters] = useState(() => {\n if (painted || !wanted) return false;\n if (scope?.prerendered) return false;\n if (insists) return true;\n if (document.querySelector(\"[data-basic-page-prerendered]\") != null) {\n return false;\n }\n const own = scope ? scope.ref.current : document;\n return own == null || !loadingPageIn(own);\n });\n return enters;\n}\n\n/**\n * Vertical stack under the page title. Blocks (forms / sections) use `gap-10`;\n * each block lays out its children with `gap-3`.\n *\n * Mounting plays the page entrance: the stack rises 12px and fades in on the\n * Card-shell / Command spring while `Title` / `Back` above stay put. The\n * entrance is the page's, played once per visit by whatever the page first\n * shows; a stack that takes over from a loading one appears at rest. What\n * that means per state:\n *\n * - **Entering the page** — whatever the page first shows (skeleton\n * included) rides in with its stack.\n * - **Skeleton, then the data** — a skeleton is a stack under `aria-busy`\n * (its own, or a wrapper's). The loaded stack mounting in its place, in\n * the same `Root`, finds it there and renders at rest: the shape was\n * already there, the values fill in. Whether the skeleton is a separate\n * component (swapped for the loaded return) or one stack branching its\n * children (`{pending ? bones : content}`) makes no difference to the\n * motion. Only this page's `Root` counts: a skeleton still on screen in\n * the page being left does not hold the next page at rest.\n * - **Skeleton that is already on screen before React** (rendered to a\n * string, painted before the bundle, re-rendered as-is on React's first\n * commit) — its `Root` says `prerendered`: static markup never enters,\n * nothing inside that root does either, and the React page taking over\n * finds the marker in the document and stays put on its own;\n * `enter={false}` says so outright for markup that must never move.\n * - **A page the server rendered and React hydrates** stays put with no\n * flag at all: the hydration pass renders what the server did, at rest,\n * and the entrance waits for a page React mounts itself (a navigation).\n * An `enter` on a hydrating stack does not override this either: the\n * page is on screen, and starting values would blink it out.\n * - **A region the skeleton couldn't predict** (a list of unknown length)\n * — `Reveal` rises that region in once its shape is known.\n *\n * Static under reduced motion.\n */\nfunction Stack({\n enter,\n className,\n children,\n // Pulled out so the spread below can't hand `ref` to motion.div a second\n // time — a later duplicate would replace the composite callback and both\n // the rhythm check and the forwarded ref would silently lose the node.\n ref: forwardedRef,\n ...props\n}: BasicPageStackProps) {\n const reduceMotion = useReducedMotion();\n const stackRef = useRef<HTMLDivElement | null>(null);\n // Untitled wrappers run at gap-3. Surfaces that own their rhythm are\n // skipped (Card / Onboard: divide-y; Fields is checked at 20).\n useRhythmCheck(stackRef, \"Stack\", 40, (el) => {\n if (el.hasAttribute(\"data-basic-page-fields\")) return 20;\n if (\n el.hasAttribute(\"data-basic-page-card\") ||\n el.hasAttribute(\"data-basic-page-onboard\") ||\n el.hasAttribute(\"data-basic-page-header\") ||\n el.hasAttribute(\"data-basic-page-columns\") ||\n el.hasAttribute(\"data-data-table\") ||\n el.hasAttribute(\"data-code-block\")\n ) {\n return null;\n }\n return 12;\n });\n // Unset: enter, unless taking over from a loading part in this Root or a\n // prerendered page. Set: as told (a prerendered Root still wins).\n const enters = useEntrance(enter ?? true, enter === true);\n // The render in which `aria-busy` goes from true to false is an arrival:\n // what mounts in it reveals. Compared against the previous render, so a\n // page that never loads never arrives, and a later remount does not.\n const busy = props[\"aria-busy\"];\n const isBusy = busy === true || busy === \"true\";\n const wasBusy = useRef(isBusy);\n const arriving = wasBusy.current && !isBusy;\n useEffect(() => {\n wasBusy.current = isBusy;\n });\n return (\n <motion.div\n ref={(node: HTMLDivElement | null) => {\n stackRef.current = node;\n if (typeof forwardedRef === \"function\") forwardedRef(node);\n else if (forwardedRef != null) forwardedRef.current = node;\n }}\n data-basic-page-stack=\"\"\n initial={\n reduceMotion || !enters ? false : { opacity: 0, y: REVEAL_RISE_PX }\n }\n animate={{ opacity: 1, y: 0 }}\n transition={{ y: ENTRANCE_SPRING, opacity: ENTRANCE_FADE }}\n className={cn(\n \"mt-7 flex min-w-0 flex-col gap-10\",\n // Under the page title, what the first block leads with decides the\n // seat. Bare surface first (callout, table, card) takes the full\n // block rhythm — title mb-3 + 28 = 40px, the same 40 as `gap-10`\n // between blocks. A first block leading with its own heading\n // (SectionTitle / Header) reads text-under-text and keeps the\n // tighter 36px. A callout stays a surface even when a heading sits\n // directly inside it.\n \"[&:has(>*:first-child:not([data-basic-page-callout])>[data-basic-page-header]:first-child)]:mt-6 [&:has(>*:first-child:not([data-basic-page-callout])>h2:first-child)]:mt-6 [&:has(>[data-basic-page-header]:first-child)]:mt-6 [&:has(>h2:first-child)]:mt-6\",\n // Under a pinned bar (`Root condense=\"pinned\"`) no title stands\n // above the stack — the bar is the heading — so the seat is the\n // untitled rhythm, 12px, the same `gap-3` an untitled wrapper keeps\n // between its children. Scoped through the column so it outranks\n // the `:has()` seats above whatever the first block leads with. A\n // `width=\"full\"` page is one surface: it sits flush under the bar.\n \"[[data-basic-page-pinned]:not([data-basic-page-width=full])_[data-basic-page-column]_&]:mt-3 [[data-basic-page-pinned][data-basic-page-width=full]_[data-basic-page-column]_&]:mt-0\",\n // Untitled wrappers (`div`, `form`, `Reveal`) become a flex column\n // at gap-3. Surfaces that already own their display and rhythm are\n // skipped: Card / Onboard / DataTable (divide-y, no gap), Fields\n // (gap-5), Callout (its own gap-3), Header / Columns (grids),\n // Code (a title row flush on its body).\n // Forcing gap-3 onto a Card opens 12px bands between hairline rows.\n // The selector is one static string so Tailwind sees the utility.\n \"*:min-w-0 [&>*:not([data-basic-page-fields]):not([data-basic-page-card]):not([data-basic-page-callout]):not([data-basic-page-onboard]):not([data-basic-page-header]):not([data-basic-page-columns]):not([data-data-table]):not([data-code-block])]:flex [&>*:not([data-basic-page-fields]):not([data-basic-page-card]):not([data-basic-page-callout]):not([data-basic-page-onboard]):not([data-basic-page-header]):not([data-basic-page-columns]):not([data-data-table]):not([data-code-block])]:flex-col [&>*:not([data-basic-page-fields]):not([data-basic-page-card]):not([data-basic-page-callout]):not([data-basic-page-onboard]):not([data-basic-page-header]):not([data-basic-page-columns]):not([data-data-table]):not([data-code-block])]:gap-3\",\n className,\n )}\n {...props}\n >\n <ArrivalContext.Provider value={arriving}>\n {children}\n </ArrivalContext.Provider>\n </motion.div>\n );\n}\n\n/**\n * Title + optional description pair. No gap between them — the block's\n * `gap-3` only applies between this header and the card.\n */\nexport interface BasicPageHeaderProps extends Omit<\n ComponentProps<\"div\">,\n RevealMotionConflicts\n> {\n /**\n * Rise this header into place on mount — the Header flavor of `Title`'s\n * `enter`, for a subpage title that carries a description: the pair\n * floats up from below the departing morph word as one block. Put `enter`\n * here and NOT on the `Title` inside. As for `Title`, stays put when it\n * takes over from a loading part in this page's `Root`, or from a\n * prerendered page anywhere. Skipped under reduced motion.\n */\n enter?: boolean;\n ref?: Ref<HTMLDivElement>;\n}\n\n/**\n * Title + description as one block, spaced from the card below like a\n * title is. A three-column grid so a `Search` and a `HeaderAction` can\n * stand at the row's end: text stacks in the first column, the search in\n * the second, the action in the third, both seats spanning the text's two\n * rows with their top on the header's top. Unoccupied end columns are\n * empty and nothing changes.\n *\n * The text meets a seat by height: taller than it, the text sets the rows\n * and the seat sits at the top; shorter, the text centers against the seat.\n * A lone text child spans both rows and centers itself. A pair shares the\n * seat's extra height equally between its rows — the grid's own rule for a\n * spanning item over two `auto` rows already full — so the first sits at\n * its row's foot and the second at its row's head, and the pair stays one\n * block, centered.\n */\nconst BASIC_PAGE_HEADER =\n \"@container grid min-w-0 grid-cols-[minmax(0,1fr)_auto_auto] mb-3 gap-y-0 [&>:not([data-basic-page-search]):not([data-basic-page-header-action])]:col-start-1 [&>:nth-child(1_of_:not([data-basic-page-search]):not([data-basic-page-header-action])):nth-last-child(1_of_:not([data-basic-page-search]):not([data-basic-page-header-action]))]:row-span-2 [&>:nth-child(1_of_:not([data-basic-page-search]):not([data-basic-page-header-action])):nth-last-child(1_of_:not([data-basic-page-search]):not([data-basic-page-header-action]))]:self-center [&>:nth-child(1_of_:not([data-basic-page-search]):not([data-basic-page-header-action])):not(:nth-last-child(1_of_:not([data-basic-page-search]):not([data-basic-page-header-action])))]:self-end [&>:not([data-basic-page-search]):not([data-basic-page-header-action]):not(:nth-child(1_of_:not([data-basic-page-search]):not([data-basic-page-header-action])))]:self-start [[data-basic-page-callout]_&]:mb-0 [[data-basic-page-stack]>*>&]:mb-0\";\n\nfunction Header({\n enter: enterProp,\n className,\n ...props\n}: BasicPageHeaderProps) {\n const reduceMotion = useReducedMotion();\n // As for `Title`: no rise over a loading part in this page's Root, or a\n // prerendered page anywhere.\n const enter = useEntrance(enterProp === true);\n if (enter && !reduceMotion) {\n return (\n <motion.div\n initial={{ opacity: 0, y: REVEAL_RISE_PX }}\n animate={{ opacity: 1, y: 0 }}\n transition={{ y: ENTRANCE_SPRING, opacity: ENTRANCE_FADE }}\n className={cn(BASIC_PAGE_HEADER, className)}\n {...props}\n data-basic-page-header=\"\"\n />\n );\n }\n return (\n <div\n className={cn(BASIC_PAGE_HEADER, className)}\n {...props}\n data-basic-page-header=\"\"\n />\n );\n}\n\n/**\n * An action at the header row's end — a small button (or two) seated in\n * the `Header` grid the way `Search` is: top-right of the block, its top\n * edge on the header's top, its right edge on the title / card-content\n * inset (`mr-5` matching `SectionTitle`'s `px-5`). A callout already\n * carries `p-5` and its title has no `px-5`, so the inset drops there.\n * Text shorter than the seat centers against it. Put it inside `Header`\n * after the text; with a `Search` present it stands to the search's right.\n */\nfunction HeaderAction({\n className,\n ...props\n}: ComponentProps<\"div\"> & { ref?: Ref<HTMLDivElement> }) {\n return (\n <div\n data-basic-page-header-action=\"\"\n className={cn(\n \"flex items-center gap-2\",\n // Its seat in a `Header`'s grid — inert anywhere else. No\n // min-w-0: the title column takes the squeeze and truncates.\n \"[[data-basic-page-header]>&]:col-start-3 [[data-basic-page-header]>&]:row-span-2 [[data-basic-page-header]>&]:row-start-1 [[data-basic-page-header]>&]:mr-5 [[data-basic-page-header]>&]:ml-4 [[data-basic-page-header]>&]:self-start [[data-basic-page-header]>&]:justify-self-end\",\n \"[[data-basic-page-callout]_[data-basic-page-header]>&]:mr-0\",\n className,\n )}\n {...props}\n />\n );\n}\n\n/**\n * Section heading — same padding as the page title, smaller type. Hashable via\n * slug `id` (not a link).\n */\nfunction SectionTitle({\n id,\n className,\n children,\n ...props\n}: ComponentProps<\"h2\"> & { ref?: Ref<HTMLHeadingElement> }) {\n const headingId = resolveHeadingId(id, children);\n return (\n <h2\n id={headingId}\n className={cn(\n \"text-display-xs text-pho-primary max-w-full min-w-0 scroll-mt-12 truncate px-5 font-medium\",\n // The gap to the card is the title's own, so a wrapper between the\n // Stack and the block (a form, a Reveal) never loses it. As a Stack\n // block's direct child the block's gap-3 already spaces it; inside\n // a Header the pair's own gap does.\n \"mb-3 [[data-basic-page-callout]_&]:mb-0 [[data-basic-page-header]>&]:mb-0 [[data-basic-page-stack]>*>&]:mb-0\",\n className,\n )}\n {...props}\n >\n {children}\n </h2>\n );\n}\n\n/**\n * Supporting copy under a section title. Same display step as the title;\n * color + normal weight keep it secondary. Always wrap with `Header`.\n */\nfunction Description({\n className,\n ...props\n}: ComponentProps<\"p\"> & { ref?: Ref<HTMLParagraphElement> }) {\n return (\n <p\n className={cn(\n \"text-display-xs text-pho-description px-5 font-normal\",\n className,\n )}\n {...props}\n />\n );\n}\n\n/**\n * How many rows the searchable table is showing — a `Description` that\n * reads the table's search. Idle: \"12 people.\" A query: \"3 of 12.\"\n * Renders nothing until a table with `search` is on the page. Put it in\n * the `Header` under the section title.\n */\nfunction TableCount({\n one,\n other,\n ...props\n}: ComponentProps<\"p\"> & {\n /** Singular noun — \"1 person.\" */\n one: string;\n /** Plural noun — \"12 people.\" */\n other: string;\n ref?: Ref<HTMLParagraphElement>;\n}) {\n const store = useContext(TableSearchContext);\n const api = useSyncExternalStore(\n store?.subscribe ?? subscribeToNothing,\n () => store?.get().api ?? null,\n () => null,\n );\n if (api == null) return null;\n const text =\n api.query.trim() !== \"\"\n ? `${api.matched} of ${api.total}.`\n : `${api.total} ${api.total === 1 ? one : other}.`;\n return <Description {...props}>{text}</Description>;\n}\n\n/**\n * Optional caption below a section's `Card` (outside the card). One step\n * smaller than `Description` (`text-xs`). Not the card-internal dirty-state\n * `Footer`.\n */\nfunction SectionFooter({\n className,\n ...props\n}: ComponentProps<\"p\"> & { ref?: Ref<HTMLParagraphElement> }) {\n return (\n <p\n className={cn(\n \"text-pho-description px-5 text-xs font-normal\",\n \"mt-3 [[data-basic-page-callout]_&]:mt-0 [[data-basic-page-stack]>*>&]:mt-0\",\n className,\n )}\n {...props}\n />\n );\n}\n\nexport interface BasicPageCardProps extends ComponentProps<\"div\"> {\n /**\n * Glide the card's height when its content swaps — bones becoming a\n * different number of rows, a row created or revoked, an inline state\n * change. The height follows the content on the page spring instead of\n * jumping. Reserve it for cards whose contents change while mounted.\n */\n animateHeight?: boolean;\n ref?: Ref<HTMLDivElement>;\n}\n\n/** Bordered card that stacks rows with hairline dividers. */\nfunction Card({\n animateHeight,\n className,\n children,\n ...props\n}: BasicPageCardProps) {\n // Departing rows stay until their exit has played. `toArray` keys static\n // children by their position, so a conditional row that goes away is\n // seen as itself leaving, not as the last row; list rows bring their own\n // keys (by data id, never by index). Presence never blocks an entrance:\n // rows decide that themselves (only an arrival plays one), so bones and\n // the rows replacing them may even share a position.\n const rows = <AnimatePresence>{Children.toArray(children)}</AnimatePresence>;\n if (animateHeight) {\n return (\n <div\n // No permanent clip, same as the static card: AnimatedHeight clips\n // for the spring's duration, rows round their own outer corners, and\n // a control on the last row (an ItemPanel's copy button) keeps its\n // focus ring and rim at rest.\n className={cn(BASIC_PAGE_CARD_SURFACE, \"min-h-0 gap-0\", className)}\n {...props}\n data-basic-page-card=\"\"\n >\n <AnimatedHeight\n transition={ENTRANCE_SPRING}\n className={BASIC_PAGE_CARD_DIVIDERS}\n >\n {rows}\n </AnimatedHeight>\n </div>\n );\n }\n return (\n <div\n className={cn(BASIC_PAGE_CARD, className)}\n {...props}\n // After `{...props}` so a host spread cannot drop the marker Stack\n // uses to skip this surface. Empty string matches the other parts.\n data-basic-page-card=\"\"\n >\n {rows}\n </div>\n );\n}\n\n/**\n * One card row that can host subviews. Padding matches a plain row, so use it\n * for any row that may grow an `ItemPanel` — primary content goes straight in\n * as children; the panel, when present, is the last child.\n *\n * ```tsx\n * <BasicPage.Card>\n * <BasicPage.Item>\n * …name, meta, actions…\n * <BasicPage.ItemPanel divided>…secret / expanded content…</BasicPage.ItemPanel>\n * </BasicPage.Item>\n * …later siblings (pass `divided` on the panel above)…\n * </BasicPage.Card>\n * ```\n */\nfunction Item({\n className,\n ...props\n}: Omit<ComponentProps<\"div\">, RevealMotionConflicts> & {\n ref?: Ref<HTMLDivElement>;\n}) {\n const { leaving, ...rowMotion } = useRowMotion();\n return (\n <motion.div\n {...rowMotion}\n className={cn(BASIC_PAGE_ITEM, leaving && \"overflow-hidden\", className)}\n {...props}\n />\n );\n}\n\nexport interface BasicPageItemPanelProps extends ComponentProps<\"div\"> {\n /**\n * Set when later card rows follow this item. The panel then renders as an\n * inset rounded chip (keeping the card's own divider) instead of the\n * full-bleed bottom sheet, which only reads well against the card's corner.\n * @default false\n */\n divided?: boolean;\n ref?: Ref<HTMLDivElement>;\n}\n\n/**\n * Secondary strip at the end of an `Item`. When the item closes the card,\n * it's a gray sheet flush under the body, full-bleed and owning the row's\n * bottom padding, rounding only into the card's bottom corner. Pass `divided`\n * when later card rows follow — the panel becomes an inset rounded chip and\n * the card's hairline divider stays in charge. Content is already a centered\n * flex row either way.\n */\nfunction ItemPanel({\n divided = false,\n className,\n ...props\n}: BasicPageItemPanelProps) {\n return (\n <div\n className={cn(\n divided ? BASIC_PAGE_ITEM_PANEL_DIVIDED : BASIC_PAGE_ITEM_PANEL,\n className,\n )}\n {...props}\n />\n );\n}\n\n/**\n * Standalone callout. Pair with `CalloutTitle` / `CalloutDescription` (and\n * optional actions) for a featured block — e.g. an invite form. Do not wrap\n * in `Card`; this is already the outer surface.\n *\n * Pass `icon` for a decorative glyph anchored to the header block (first\n * child) — typically a Tabler outline icon. The icon is aria-hidden; keep\n * meaning in the title/description.\n */\nfunction Callout({\n className,\n icon,\n children,\n ...props\n}: ComponentProps<\"div\"> & {\n ref?: Ref<HTMLDivElement>;\n /** Decorative icon, top-right of the header (first child). */\n icon?: ReactNode;\n}) {\n // Treat boolean false (and other empty values) as absent — `icon={cond &&\n // <Icon />}` is a common pattern and must not reserve header padding.\n if (icon == null || icon === false || icon === true) {\n return (\n <div\n className={cn(BASIC_PAGE_CALLOUT, className)}\n {...props}\n data-basic-page-callout=\"\"\n >\n {children}\n </div>\n );\n }\n\n const [header, ...rest] = Children.toArray(children);\n\n return (\n <div\n className={cn(BASIC_PAGE_CALLOUT, className)}\n {...props}\n data-basic-page-callout=\"\"\n >\n <div className=\"relative\">\n <div className=\"min-w-0 pr-16\">{header}</div>\n <div\n aria-hidden\n // Always the top-right corner, its top on the first line's top —\n // not centered, so it holds still as the callout grows.\n className=\"text-pho-primary pointer-events-none absolute top-0 right-0 size-14 opacity-[0.275] [&>svg]:size-full\"\n >\n {icon}\n </div>\n </div>\n {rest}\n </div>\n );\n}\n\n/** Callout heading — same type as `SectionTitle`. Hashable via slug `id`. */\nfunction CalloutTitle({\n id,\n className,\n children,\n ...props\n}: ComponentProps<\"h2\"> & { ref?: Ref<HTMLHeadingElement> }) {\n const headingId = resolveHeadingId(id, children);\n return (\n <h2\n id={headingId}\n className={cn(\n \"text-display-xs text-pho-primary max-w-full min-w-0 scroll-mt-12 truncate font-medium\",\n className,\n )}\n {...props}\n >\n {children}\n </h2>\n );\n}\n\n/** Supporting copy under a callout title. */\nfunction CalloutDescription({\n className,\n ...props\n}: ComponentProps<\"p\"> & { ref?: Ref<HTMLParagraphElement> }) {\n return (\n <p\n className={cn(\n \"text-display-xs text-pho-description font-normal\",\n className,\n )}\n {...props}\n />\n );\n}\n\n/* ------------------------------- onboarding ------------------------------ */\n\nexport interface BasicPageOnboardProps extends ComponentProps<\"ol\"> {\n ref?: Ref<HTMLOListElement>;\n}\n\n/** Where a step stands in its `Onboard` — the list decides. */\ntype StepState = \"done\" | \"working\" | \"pending\" | \"current\" | \"upcoming\";\n\ninterface StepSeat {\n /** 1-based position — the number in the ring. */\n number: number;\n state: StepState;\n}\n\nconst StepContext = createContext<StepSeat | null>(null);\n/** Inside a step, where a `Value` wears the section's type. */\nconst StepTypeContext = createContext(false);\n\n/**\n * The service's setup, before the page: an ordered card of `Step`s under\n * the page's `Header`, for a service that needs something done before it\n * can be used — a number chosen, a business registered. Steps are\n * `Onboard`'s direct children, in the order they are done, and the list\n * decides the rest: it numbers them by position and finds the one at\n * hand (the first not `done`). That step is open — its line and its\n * button under the title; the others fold to their title, the done ones\n * with a check and what they came to, the waiting ones muted. A step\n * finishing folds closed as the next opens, on the Accordion's spring.\n * When the last step is done the service is on — render the page in its\n * place.\n */\nfunction Onboard({ className, children, ...props }: BasicPageOnboardProps) {\n let seated = false;\n const steps = Children.toArray(children).map((child, index) => {\n if (\n !isValidElement<{ done?: boolean; working?: boolean; pending?: boolean }>(\n child,\n )\n ) {\n return child;\n }\n let state: StepState;\n if (child.props.done) state = \"done\";\n else if (seated) state = \"upcoming\";\n else {\n seated = true;\n state = child.props.working\n ? \"working\"\n : child.props.pending\n ? \"pending\"\n : \"current\";\n }\n return (\n <StepContext.Provider\n key={child.key ?? index}\n value={{ number: index + 1, state }}\n >\n {child}\n </StepContext.Provider>\n );\n });\n return (\n <ol\n // A real list, with none of a host's list styling: no marker, no\n // indent, and the steps carry no margin of their own (see `Step`).\n className={cn(BASIC_PAGE_CARD, \"m-0 list-none p-0\", className)}\n {...props}\n data-basic-page-onboard=\"\"\n >\n {steps}\n </ol>\n );\n}\n\nexport interface BasicPageStepProps extends Omit<\n ComponentProps<\"li\">,\n \"title\"\n> {\n /**\n * Decorative glyph for the step at hand, top-right of its body the way a\n * `Callout`'s is — typically a Tabler outline icon at stroke 1.25. It is\n * aria-hidden (keep the meaning in the title) and folds away with the\n * body: a done or waiting step shows none.\n */\n icon?: ReactNode;\n /**\n * Something to look at beside the step at hand — a code to scan, with\n * its caption — in the corner where the `icon` would be, its top on the\n * title's, holding still as the fold opens beside it. It takes the\n * icon's place when both are given, and folds away with the body.\n */\n aside?: ReactNode;\n /** The title: a verb and its object — \"Choose a number\". */\n title: ReactNode;\n /**\n * The line under the title while the step is at hand: what it involves,\n * or, while it waits, how long. Folded away with the rest once the step\n * is done or before its turn.\n */\n description?: ReactNode;\n /**\n * Set once the step is done — its ring draws a check, its body folds\n * closed, and the next step opens.\n */\n done?: boolean;\n /**\n * Set while Photon itself is at work on the step — a number being\n * allocated, a machine's task of a minute or less. It stays at hand and\n * open, and its ring spins around the number. Waiting on someone else\n * is `pending` instead.\n */\n working?: boolean;\n /**\n * Set while the step waits on someone else — a carrier's review, a\n * teammate's approval, anything that takes minutes or days. It stays at\n * hand and open, its ring dashed; say how long in the description. A\n * step Photon itself is at work on is `working`, not pending.\n */\n pending?: boolean;\n /**\n * At hand: the step's action — a small `Button` or `ButtonLink` — under\n * its line. Done: what it came to — a `Value` — at the title's end.\n * Waiting its turn: not shown.\n */\n children?: ReactNode;\n ref?: Ref<HTMLLIElement>;\n}\n\n/**\n * The ring — solid ink with the number while the step is at hand, an ink\n * ring with a drawn check once done, a faint ring while it waits its\n * turn, dashed while it waits on someone else, and, while Photon works\n * on it, a faint track with an ink arc spinning around the number (the\n * `Spinner`'s arc and pace, at the ring's own size). A grid cell so the\n * number and the check crossfade in place.\n */\nconst STEP_RING =\n \"relative grid size-5 shrink-0 place-items-center rounded-full border text-xs font-medium tabular-nums transition-[background-color,border-color,color] duration-200 ease-out *:[grid-area:1/1]\";\n\nconst STEP_RING_STATES: Record<StepState, string> = {\n done: \"border-pho-ink text-pho-primary\",\n current: \"bg-pho-brand-solid text-pho-on-brand border-transparent\",\n working: \"border-transparent text-pho-primary\",\n pending: \"border-pho-ink text-pho-primary border-dashed\",\n upcoming: \"border-pho-primary text-pho-description\",\n};\n\n/**\n * The working ring, drawn as the `Spinner` is: a track of ink at 30% over\n * the ring's own edge — legible on the page's ground, where a hairline\n * would fade — and a quarter turn of full ink spinning over it.\n */\nconst STEP_RING_TRACK =\n \"pointer-events-none absolute -inset-px rounded-full border border-pho-ink opacity-30\";\nconst STEP_RING_ARC =\n \"pointer-events-none absolute -inset-px rounded-full border border-pho-ink border-r-transparent border-b-transparent border-l-transparent animate-pho-spinner\";\n\n/** Said with the title, since the ring only draws its standing. */\nconst STEP_SPOKEN: Partial<Record<StepState, string>> = {\n done: \"Done.\",\n working: \"In progress.\",\n pending: \"Waiting.\",\n};\n\n/**\n * One step of an `Onboard`, left to right: the ring, the words, the\n * corner. The ring and the title share one row and center on each\n * other's midline; while the step is at hand, the line sits flush under\n * the title (as a Header's description sits under its title) with the\n * button below, folded open in the title's own column by `Reveal` — the\n * page spring, the `Footer` grammar: never clipped, the button whole\n * from the first frame, fading in as the space opens. The corner holds\n * the icon at hand and what the step came to once done. The step at hand sits on the page's ground, the way a `Callout`\n * does; the others stay on the card's white. The title and the line wear the\n * section's type — `SectionTitle` over `Description`, both\n * `text-display-xs`. Its standing comes from the list; on its own it is\n * the step at hand.\n */\nfunction Step({\n icon,\n aside,\n title,\n description,\n done,\n working,\n pending,\n className,\n children,\n ...props\n}: BasicPageStepProps) {\n const seat = useContext(StepContext);\n const state: StepState =\n seat?.state ??\n (done ? \"done\" : working ? \"working\" : pending ? \"pending\" : \"current\");\n const reduceMotion = useReducedMotion();\n const atHand =\n state === \"current\" || state === \"working\" || state === \"pending\";\n const waiting = state === \"upcoming\";\n const spoken = STEP_SPOKEN[state];\n const hasChildren = children != null && children !== false;\n const hasIcon = icon != null && icon !== false;\n const hasAside = aside != null && aside !== false;\n return (\n <li\n data-basic-page-step={state}\n aria-current={atHand ? \"step\" : undefined}\n className={cn(\n // A grid: the ring and the title share the first row and center\n // on each other's midline, whatever their heights; the fold takes\n // the second row under the title; the corner — an icon at hand,\n // what the step came to once done — takes a third column that\n // exists only while something sits in it. The fold's row is the\n // flexible one, so an aside spanning both rows grows it alone and\n // the title's row keeps the title's height, its top the aside's.\n \"relative m-0 grid min-w-0 grid-cols-[auto_minmax(0,1fr)] grid-rows-[auto_minmax(0,1fr)] items-center gap-x-3 px-5 py-4\",\n // The step at hand on the page's ground, the tint coming and going\n // the way the ring's ink does. It rounds into the card's corners\n // when the step is first or last (11px inside the 1px border).\n \"transition-[background-color] duration-200 ease-out first:rounded-t-[calc(0.75rem-1px)] last:rounded-b-[calc(0.75rem-1px)] motion-reduce:transition-none\",\n atHand && \"bg-pho-page\",\n className,\n )}\n {...props}\n >\n <StepTypeContext.Provider value>\n <span\n aria-hidden\n className={cn(\n STEP_RING,\n STEP_RING_STATES[state],\n \"col-start-1 row-start-1\",\n )}\n >\n <AnimatePresence initial={false}>\n {state === \"done\" ? (\n <motion.span\n key=\"check\"\n {...fadeThroughBlur(reduceMotion)}\n className=\"flex\"\n >\n <DrawnCheckGlyph className=\"size-3\" />\n </motion.span>\n ) : (\n <motion.span key=\"number\" {...fadeThroughBlur(reduceMotion)}>\n {seat?.number ?? 1}\n </motion.span>\n )}\n </AnimatePresence>\n {state === \"working\" ? (\n <>\n <span className={STEP_RING_TRACK} />\n <span className={STEP_RING_ARC} />\n </>\n ) : null}\n </span>\n <div\n data-basic-page-step-title=\"\"\n className={cn(\n \"text-display-xs col-start-2 row-start-1 min-w-0 font-medium transition-colors duration-200 ease-out\",\n waiting ? \"text-pho-description\" : \"text-pho-primary\",\n )}\n >\n {spoken ? <span className=\"sr-only\">{spoken} </span> : null}\n {title}\n </div>\n {/* The fold, flush under the title in its column — as a Header's\n description sits under its title — with the line and the\n button. No gap to compensate: it is a grid row of its own, and\n the fold fills it: when an aside grows the row, the line stays\n under the title and the button goes to the foot, level with the\n aside's bottom — the room opens between them. */}\n <Reveal\n show={atHand}\n gap=\"none\"\n clip={false}\n className=\"col-start-2 row-start-2 flex min-w-0 flex-col self-stretch\"\n >\n <div\n data-basic-page-step-body=\"\"\n className=\"flex min-w-0 flex-1 flex-col\"\n >\n {description ? (\n <div className=\"text-display-xs text-pho-description font-normal\">\n {description}\n </div>\n ) : null}\n {hasChildren ? (\n <div className=\"mt-auto flex flex-wrap items-center gap-2 pt-3\">\n {children}\n </div>\n ) : null}\n </div>\n </Reveal>\n {state === \"done\" && hasChildren ? (\n <div className=\"col-start-3 row-start-1 flex min-w-0 items-center gap-2\">\n {children}\n </div>\n ) : hasAside ? (\n <AnimatePresence initial={false}>\n {atHand ? (\n <motion.div\n key=\"aside\"\n {...fadeThroughBlur(reduceMotion)}\n // The icon's corner, for something to look at: its top on\n // the title row's top, holding still as the fold opens.\n className=\"col-start-3 row-span-2 row-start-1 self-start\"\n >\n {aside}\n </motion.div>\n ) : null}\n </AnimatePresence>\n ) : hasIcon ? (\n <AnimatePresence initial={false}>\n {atHand ? (\n <motion.div\n key=\"icon\"\n aria-hidden\n {...fadeThroughBlur(reduceMotion)}\n // The Callout's corner: its top on the title row's top,\n // holding still as the fold opens beside it.\n className=\"pointer-events-none col-start-3 row-span-2 row-start-1 size-14 self-start\"\n >\n <div className=\"text-pho-primary size-full opacity-[0.275] [&>svg]:size-full\">\n {icon}\n </div>\n </motion.div>\n ) : null}\n </AnimatePresence>\n ) : null}\n </StepTypeContext.Provider>\n </li>\n );\n}\n\nexport interface BasicPageRowProps extends Omit<\n ComponentProps<\"div\">,\n \"title\" | RevealMotionConflicts\n> {\n /** Left-side field name — plain text, or compose with a trailing hint. */\n label: ReactNode;\n /** Optional helper under the label. */\n description?: ReactNode;\n /** Associates the label with a control id. When omitted, the label is not a `<label>`. */\n htmlFor?: string;\n /**\n * Stack the label above a full-width control instead of the default\n * label-left / control-right layout at `sm+`. Keeps the compact `gap-3`\n * rhythm — the default row's `justify-between` would otherwise stretch\n * label and control apart under `min-h-[4.25rem]`.\n */\n stacked?: boolean;\n ref?: Ref<HTMLDivElement>;\n}\n\n/**\n * One row: label (+ optional description) left, control right.\n * Pass `htmlFor` when the row wraps a labelled input; omit it for display/\n * action rows (avatar, danger-zone delete). Pass `stacked` for full-width\n * controls that sit under the label.\n */\nfunction Row({\n label,\n description,\n htmlFor,\n stacked = false,\n className,\n children,\n ...props\n}: BasicPageRowProps) {\n const { leaving, ...rowMotion } = useRowMotion();\n return (\n <motion.div\n {...rowMotion}\n className={cn(\n BASIC_PAGE_ROW,\n stacked && \"sm:flex-col sm:items-stretch sm:justify-start sm:gap-3\",\n leaving && \"overflow-hidden\",\n className,\n )}\n {...props}\n >\n <div className=\"min-w-0\">\n {htmlFor ? (\n <label\n htmlFor={htmlFor}\n className=\"text-pho-primary block text-base font-normal\"\n >\n {label}\n </label>\n ) : (\n // A div, not a p: the label slot takes composed content (an\n // identity with its avatar, a loading bone) as well as a name.\n <div className=\"text-pho-primary text-base font-normal\">{label}</div>\n )}\n {description ? (\n <p className=\"text-pho-description text-xs\">{description}</p>\n ) : null}\n </div>\n <div\n className={cn(\n \"flex w-full min-w-0 items-center gap-2 sm:w-auto\",\n stacked && \"sm:w-full\",\n )}\n >\n {children}\n </div>\n </motion.div>\n );\n}\n\n/** Read-only value on the right side of a row (email, etc.). */\nfunction Value({\n className,\n ...props\n}: ComponentProps<\"p\"> & { ref?: Ref<HTMLParagraphElement> }) {\n // A value wears the type of what it sits beside: a row's, or, at a\n // step's title's end, the section's — the line's size and weight.\n const inStep = useContext(StepTypeContext);\n return (\n <p\n className={cn(\n \"text-pho-description max-w-full min-w-0 truncate\",\n inStep ? \"text-display-xs font-normal\" : \"text-base\",\n className,\n )}\n {...props}\n />\n );\n}\n\nexport interface BasicPageAlertProps extends Omit<\n ComponentProps<\"div\">,\n \"children\"\n> {\n /** The caught value — a problem body, an `Error` wrapping one, or unknown. */\n error?: unknown;\n /** Override the derived message. */\n children?: ReactNode;\n /**\n * Explicit presence override — defaults to whether there is anything to\n * show, so the reveal plays as the mutation's error comes and goes.\n */\n show?: boolean;\n ref?: Ref<HTMLDivElement>;\n}\n\n/**\n * Server error under a row, still inside the card — the partial failure\n * (\"Couldn't update your name\"), rendered by `Error` from the problem body.\n * Keep it mounted and pass the mutation's error: the line reveals and\n * collapses on `Footer`'s height spring + fade. The card drops its divider\n * above the line so it reads as part of the row it belongs to. Matches card\n * horizontal padding — don't re-apply `px-5`.\n *\n * For a page that failed to load outright, swap the stack for an `ErrorView`\n * instead.\n */\nfunction Alert({\n error: errorProp,\n show,\n className,\n children,\n ...props\n}: BasicPageAlertProps) {\n const reduceMotion = useReducedMotion();\n // Inside `Form`, with no `error` of its own, the alert shows the form's.\n const form = useContext(FormContext);\n const error = errorProp ?? form?.error ?? undefined;\n const hasContent = error != null || children != null;\n // Explicit `show` cannot force an empty animated slot — ErrorLine returns\n // null when there is nothing to render.\n const visible = (show ?? true) && hasContent;\n return (\n <AnimatePresence initial={false}>\n {visible ? (\n <motion.div\n data-basic-page-alert=\"\"\n className=\"overflow-hidden\"\n initial={{ height: 0, opacity: 0 }}\n animate={{ height: \"auto\", opacity: 1 }}\n exit={{ height: 0, opacity: 0 }}\n transition={\n reduceMotion\n ? { duration: 0 }\n : { height: ENTRANCE_SPRING, opacity: ENTRANCE_FADE }\n }\n >\n <ErrorLine\n error={error}\n className={cn(\"px-5 pb-3\", className)}\n {...props}\n >\n {children}\n </ErrorLine>\n </motion.div>\n ) : null}\n </AnimatePresence>\n );\n}\n\n/* ------------------------------- forms ---------------------------------- */\n\ninterface FormContextValue {\n pending: boolean;\n dirty: boolean;\n error: unknown;\n /** Auto-save lifecycle: which field asked, and where the save stands. */\n auto: { field: string | null; phase: \"saving\" | \"saved\" } | null;\n /** Schedules an auto-save (the same typing-pause debounce); null unless `autoSave`. */\n requestSave: ((field?: string) => void) | null;\n}\n\n/**\n * The nearest `Form autoSave`'s trigger, for controls whose changes never\n * bubble as native events (a Base UI checkbox, a select): call it in the\n * control's own onChange and the save runs after the usual pause. Null\n * outside an auto-saving form.\n */\nexport function useAutoSave() {\n return useContext(FormContext)?.requestSave ?? null;\n}\n\n/** Typing pause before an auto-save fires; blur flushes it immediately. */\nexport const AUTO_SAVE_DELAY_MS = 800;\n\n/**\n * The toast lane auto-save failures speak through. Host it once in the app\n * shell — `<Toast.Provider toastManager={formToasts}>` around a viewport —\n * and every `Form autoSave` reaches it without wiring. A failure toast\n * carries Retry and stays until the save lands (the next success closes it).\n */\nexport const formToasts = Toast.createToastManager();\n\nconst FormContext = createContext<FormContextValue | null>(null);\n\n/** Field errors keyed by `name`, the shape Base UI `Form` maps onto fields. */\nexport type BasicPageFormErrors = Record<string, string | string[]>;\n\nexport interface BasicPageFormProps<\n Values extends Record<string, unknown> = Record<string, unknown>,\n> extends Omit<\n ComponentProps<typeof FormElement>,\n // autoSave shadows a legacy DOM string attribute of the same name.\n \"onFormSubmit\" | \"errors\" | \"action\" | \"autoSave\"\n> {\n /**\n * Documents save themselves; transactions submit. With `autoSave`, the\n * form runs `action` on its own — after a typing pause, immediately on\n * blur — once native validation passes, and skips quietly while it does\n * not. Controls stay enabled throughout; put a `Saved` in the field's\n * hint for the inline Saving…/Saved word. A failure keeps the value in\n * place and raises a Retry toast on `formToasts` that stays until a\n * save lands. Keep the explicit `Submit` for creations and anything\n * paid or irreversible.\n */\n autoSave?: boolean;\n /**\n * The save. Receives the field values keyed by `name`, after native\n * validation passed. Resolve to finish; return `{ errors }` to put\n * messages on fields; throw (a `Problem`, an `Error`) for the form's\n * `Alert`. While it runs, every control and the submit are disabled.\n */\n action?: (\n values: Values,\n ) =>\n | void\n | { errors?: BasicPageFormErrors }\n | Promise<void | { errors?: BasicPageFormErrors }>;\n /** Field errors to start with — from a previous round trip. */\n errors?: BasicPageFormErrors;\n}\n\n/**\n * The form. A `<form>` that owns the save lifecycle so the page parts can\n * read it: `Submit` shows pending, `Footer show=\"dirty\"` appears after the\n * first edit and leaves when the action lands, `Alert` shows what the\n * action threw, and field errors the action returns land under their\n * fields. Uncontrolled by design — give fields `defaultValue` and a `name`,\n * and remount with `key` when the record changes; there is no state to\n * seed. Lay the fields out in `Fields` (the form card, its `Footer` inside\n * at the bottom), or keep a `Card` of `Row`s for a settings page that\n * saves, its `Footer` following the card one block gap below.\n *\n * The form adds no spacing. Inside a `Stack`, one form around a card and\n * its footer is one block; a form that spans several blocks goes around\n * the `Stack` instead, and the blocks keep the Stack's rhythm.\n */\nfunction Form<Values extends Record<string, unknown>>({\n action,\n errors: initialErrors,\n autoSave = false,\n className,\n children,\n onChange,\n onBlur,\n ...props\n}: BasicPageFormProps<Values>) {\n const [pending, setPending] = useState(false);\n const [dirty, setDirty] = useState(false);\n const [error, setError] = useState<unknown>(null);\n const [errors, setErrors] = useState<BasicPageFormErrors>(\n initialErrors ?? {},\n );\n const [auto, setAuto] = useState<FormContextValue[\"auto\"]>(null);\n const formRef = useRef<HTMLFormElement | null>(null);\n const autoTimer = useRef<ReturnType<typeof setTimeout> | null>(null);\n const lastField = useRef<string | null>(null);\n const inFlight = useRef(false);\n const queued = useRef(false);\n const failToast = useRef<string | null>(null);\n const latestRun = useRef<() => Promise<void>>(async () => {});\n useEffect(\n () => () => {\n if (autoTimer.current != null) clearTimeout(autoTimer.current);\n },\n [],\n );\n\n const runAutoSave = async () => {\n const form = formRef.current;\n if (form == null || action == null) return;\n if (inFlight.current) {\n queued.current = true;\n return;\n }\n // Quiet while a field is still invalid — the next pause tries again.\n if (!form.checkValidity()) return;\n const values = Object.fromEntries(new FormData(form).entries());\n const field = lastField.current;\n inFlight.current = true;\n setAuto({ field, phase: \"saving\" });\n setError(null);\n try {\n const result = await action(values as Values);\n const fieldErrors = result?.errors;\n if (fieldErrors != null && Object.keys(fieldErrors).length > 0) {\n setErrors(fieldErrors);\n setAuto(null);\n return;\n }\n setErrors({});\n setDirty(false);\n setAuto({ field, phase: \"saved\" });\n if (failToast.current != null) {\n formToasts.close(failToast.current);\n failToast.current = null;\n }\n } catch (caught) {\n setAuto(null);\n setError(caught);\n // The value stays in the field; the toast stays until a save lands.\n if (failToast.current != null) formToasts.close(failToast.current);\n failToast.current = formToasts.add({\n type: \"error\",\n title: \"Couldn't save\",\n description:\n caught instanceof Error && caught.message !== \"\"\n ? caught.message\n : \"The change is still here — try again.\",\n timeout: 0,\n actionProps: {\n children: \"Retry\",\n onClick: () => {\n void latestRun.current();\n },\n },\n });\n } finally {\n inFlight.current = false;\n if (queued.current) {\n queued.current = false;\n void latestRun.current();\n }\n }\n };\n latestRun.current = runAutoSave;\n\n const scheduleAutoSave = () => {\n if (autoTimer.current != null) clearTimeout(autoTimer.current);\n autoTimer.current = setTimeout(() => {\n autoTimer.current = null;\n void latestRun.current();\n }, AUTO_SAVE_DELAY_MS);\n };\n\n const requestSave = useMemo(\n () =>\n autoSave\n ? (field?: string) => {\n if (field != null) lastField.current = field;\n setDirty(true);\n scheduleAutoSave();\n }\n : null,\n // eslint-disable-next-line react-hooks/exhaustive-deps -- schedule fn is stable per instance\n [autoSave],\n );\n const context = useMemo(\n () => ({ pending, dirty, error, auto, requestSave }),\n [pending, dirty, error, auto, requestSave],\n );\n return (\n <FormContext.Provider value={context}>\n <FormElement\n errors={errors}\n onFormSubmit={async (values) => {\n if (action == null) return;\n setPending(true);\n setError(null);\n try {\n const result = await action(values as Values);\n const fieldErrors = result?.errors;\n if (fieldErrors != null && Object.keys(fieldErrors).length > 0) {\n setErrors(fieldErrors);\n return;\n }\n setErrors({});\n setDirty(false);\n } catch (caught) {\n setError(caught);\n } finally {\n setPending(false);\n }\n }}\n onChange={(event) => {\n setDirty(true);\n setError(null);\n // A field edited after a round trip drops the message it came back\n // with; the next submit validates it fresh.\n const name = (event.target as { name?: string }).name;\n if (name && name in errors) {\n setErrors((current) => {\n const { [name]: _dropped, ...rest } = current;\n return rest;\n });\n }\n if (autoSave) {\n if (name) lastField.current = name;\n scheduleAutoSave();\n }\n onChange?.(event);\n }}\n onBlur={(event) => {\n // Leaving a field flushes the pending pause — the edit lands\n // before attention moves on.\n if (autoSave && dirty && autoTimer.current != null) {\n clearTimeout(autoTimer.current);\n autoTimer.current = null;\n void latestRun.current();\n }\n onBlur?.(event);\n }}\n // No spacing of its own. Transparent to layout, so whatever the form\n // wraps keeps the rhythm of where it sits: several blocks inside a\n // Stack stay Stack blocks, a card and its footer inside a block stay\n // that block's children. As a Stack's direct child it is one block\n // itself (a card and its footer), spaced by the Stack's block rule.\n className={cn(\n \"contents [[data-basic-page-stack]>&]:flex [[data-basic-page-stack]>&]:min-w-0 [[data-basic-page-stack]>&]:flex-col\",\n className,\n )}\n {...props}\n ref={(node: HTMLFormElement | null) => {\n formRef.current = node;\n const forwarded = (props as { ref?: Ref<HTMLFormElement> }).ref;\n if (typeof forwarded === \"function\") forwarded(node);\n else if (forwarded != null) forwarded.current = node;\n }}\n >\n <fieldset\n disabled={pending}\n aria-busy={pending || undefined}\n className=\"contents\"\n >\n {children}\n </fieldset>\n </FormElement>\n </FormContext.Provider>\n );\n}\n\n/**\n * The inline word for an auto-saving field — put it inside the field at\n * its trailing edge (`Input trailing`), where the eye already is while\n * typing. Quiet gray, never colored, so it cannot be read as validation:\n * \"Saving…\" while the save runs, \"Saved\" for a breath after it lands,\n * then nothing at all — idle it renders nothing and reserves nothing.\n * Words fade through the system's 1px soft focus — no travel — and\n * carry their own surface wash, so long\n * input text fades beneath them instead of colliding. With `name` it\n * speaks only for that field; without, for the whole form.\n */\nfunction Saved({\n name,\n className,\n ...props\n}: Omit<ComponentProps<\"output\">, RevealMotionConflicts> & { name?: string }) {\n const form = useContext(FormContext);\n const reduceMotion = useReducedMotion();\n const auto = form?.auto ?? null;\n const mine = auto != null && (name == null || auto.field === name);\n const [linger, setLinger] = useState(false);\n const phase = mine ? auto.phase : null;\n useEffect(() => {\n if (phase !== \"saved\") return;\n setLinger(true);\n const timer = setTimeout(() => setLinger(false), 1800);\n return () => clearTimeout(timer);\n }, [phase, auto]);\n const word =\n phase === \"saving\"\n ? \"Saving…\"\n : phase === \"saved\" && linger\n ? \"Saved\"\n : null;\n const blurAway = reduceMotion ? \"blur(0px)\" : `blur(${BLUR_MAX_PX}px)`;\n return (\n // Both words share one grid cell, right-aligned: the goer fades out\n // exactly where the comer fades in, overlapping by stacking — never\n // by Motion absolutely positioning the goer (which misplaces against\n // a right-anchored container).\n <span className=\"grid justify-items-end\">\n <AnimatePresence initial={false}>\n {word != null && (\n <motion.output\n key={word}\n initial={{ opacity: 0, filter: blurAway }}\n animate={{ opacity: 1, filter: \"blur(0px)\" }}\n exit={{ opacity: 0, filter: blurAway }}\n transition={CONDENSE_BAR_ENTER}\n className={cn(\n \"text-pho-description pl-8 [grid-area:1/1]\",\n className,\n )}\n // The word's own wash: the field surface ramping in from the\n // left — the scroll edge's fade turned sideways.\n style={{\n background:\n \"linear-gradient(to left, var(--background-color-pho-primary) calc(100% - 2rem), transparent)\",\n }}\n {...props}\n >\n {word}\n </motion.output>\n )}\n </AnimatePresence>\n </span>\n );\n}\n\n/** The card's field padding, matched to `Row` (`px-5 py-4`). */\nconst BASIC_PAGE_FIELDS =\n \"flex min-w-0 flex-col gap-5 p-5 [&>[data-basic-page-alert]]:-mx-5 [&>[data-basic-page-alert]]:-mt-2 [&>[data-basic-page-alert]]:-mb-5 [&>[data-basic-page-footer]]:pr-0 [&>[data-basic-page-reveal]]:flex [&>[data-basic-page-reveal]]:flex-col [&>[data-basic-page-reveal]]:gap-5\";\n\n/**\n * The form card: labelled fields stacked, label above control, one rhythm\n * (`gap-5`). Where a `Card` of `Row`s is a table of settings, this is a\n * sheet to fill in — a create page, a long edit. `Input` brings its own\n * label and hint; wrap other controls in `Field`. `Alert` and `Footer`\n * sit inside, at the bottom — unlike a `Card` of rows, a sheet keeps its\n * submit: the button's box lines up with the fields' edge.\n */\nfunction Fields({\n className,\n ...props\n}: ComponentProps<\"div\"> & { ref?: Ref<HTMLDivElement> }) {\n const fieldsRef = useRef<HTMLDivElement | null>(null);\n // Only the sheet's own rhythm: a field's internal gap is the field's.\n useRhythmCheck(fieldsRef, \"Fields\", 20, () => null);\n return (\n <div\n className={cn(BASIC_PAGE_CARD_SURFACE, BASIC_PAGE_FIELDS, className)}\n {...props}\n ref={(node: HTMLDivElement | null) => {\n fieldsRef.current = node;\n const forwarded = props.ref;\n if (typeof forwarded === \"function\") forwarded(node);\n else if (forwarded != null) forwarded.current = node;\n }}\n data-basic-page-fields=\"\"\n />\n );\n}\n\n/** Fields side by side from `sm` (a first and last name), stacked below. */\nfunction Inline({\n className,\n ...props\n}: ComponentProps<\"div\"> & { ref?: Ref<HTMLDivElement> }) {\n return (\n <div\n className={cn(\n \"flex min-w-0 flex-col gap-5 *:min-w-0 sm:flex-row sm:gap-3 sm:*:flex-1\",\n className,\n )}\n {...props}\n />\n );\n}\n\n/** The submit. A small effect `Button`, pending while the action runs. */\nfunction Submit({\n children = \"Save changes\",\n ...props\n}: Omit<ButtonProps, \"type\">) {\n const form = useContext(FormContext);\n return (\n <Button\n type=\"submit\"\n variant=\"effect\"\n size=\"sm\"\n loading={form?.pending}\n {...props}\n >\n {children}\n </Button>\n );\n}\n\nexport interface BasicPageFooterProps extends ComponentProps<\"div\"> {\n /**\n * Animated presence for the dirty-state action: the card glides\n * open/closed on a height spring while the button fades. Omit for a\n * static, always-visible footer (no animation). No reveal plays on first\n * mount — only on flips.\n */\n show?: boolean | \"dirty\";\n ref?: Ref<HTMLDivElement>;\n}\n\n/**\n * Save action for a card. After a `Card` of rows it sits outside, below the\n * surface, its trailing edge on the rows' text edge, so the card\n * holds only rows; inside `Fields` it sits at the bottom of the sheet.\n * Typically a submit button that appears after the form is dirty; pass\n * `show` (instead of conditional rendering) to animate it in and out\n * following the onboarding card's motion language.\n */\nfunction Footer({ show: showProp, className, ...props }: BasicPageFooterProps) {\n // `show=\"dirty\"`: inside `Form`, present once something was edited, gone\n // again once the action lands.\n const form = useContext(FormContext);\n const show = showProp === \"dirty\" ? (form?.dirty ?? false) : showProp;\n const bar = (\n <div\n data-basic-page-footer=\"\"\n // The button's trailing edge lines up with the card's text, not its\n // border: the card's 1px border and `px-5` put the text edge 21px\n // in, and the effect button's 1.5px rim is a box-shadow outside its\n // box — so the box sits 22.5px in and the rim's outer edge meets the\n // text edge.\n className={cn(\n \"flex items-center justify-end gap-3 pr-[calc(1.25rem+2.5px)]\",\n className,\n )}\n {...props}\n />\n );\n if (show === undefined) return bar;\n // A block below the card: the reveal compensates the block gap above it,\n // so the card's bottom edge does not move while the footer is away.\n // Never clipped: the button shows whole from the first frame and fades\n // in as the space below the card opens.\n return (\n <Reveal show={show} gap=\"block\" clip={false}>\n {bar}\n </Reveal>\n );\n}\n\n/**\n * DOM handlers whose React signatures clash with Motion's gesture props of\n * the same name on `motion.*` elements — excluded from `Reveal`'s public API\n * (same policy as Button).\n */\ntype RevealMotionConflicts =\n | \"onAnimationStart\"\n | \"onAnimationEnd\"\n | \"onAnimationIteration\"\n | \"onDrag\"\n | \"onDragStart\"\n | \"onDragEnd\"\n | \"onDragEnter\"\n | \"onDragExit\"\n | \"onDragLeave\"\n | \"onDragOver\"\n | \"onDrop\";\n\nexport interface BasicPageRevealProps extends Omit<\n ComponentProps<\"div\">,\n RevealMotionConflicts\n> {\n /**\n * Animated presence for a `Stack` block that comes and goes: keep the\n * block mounted and drive it with `show` — it glides open and closed\n * (height + fade) on the page spring, with the Stack's `gap-10`\n * compensated so nothing jumps when it fully collapses. Omit `show` for\n * the one-shot data-arrival entrance.\n */\n show?: boolean;\n /**\n * Clip the block while its height animates (the default). Pass `false`\n * for a block whose content must show whole from the first frame — a\n * button with a rim, a shadow — and let it fade in as the space opens.\n */\n clip?: boolean;\n /**\n * Which gap the presence variant compensates while collapsing —\n * `\"stack\"` for a Stack block (`gap-10`), `\"fields\"` for a field in a\n * `Fields` sheet (`gap-5`), `\"block\"` for an element\n * inside a block (`gap-3`), `\"none\"` for a region with no gap around\n * it (a grid row of its own). @default \"stack\"\n */\n gap?: \"stack\" | \"block\" | \"fields\" | \"none\";\n /**\n * Set when this wraps multiple `Card` rows — the extra element Reveal\n * needs for `AnimatePresence` sits between them and the card's own\n * `divide-y`, so the hairlines between the wrapped rows disappear unless\n * this restores them. Leave off for content that isn't a run of rows.\n */\n dividers?: boolean;\n ref?: Ref<HTMLDivElement>;\n}\n\n/**\n * Exactly one surrounding flex gap — the presence variant trades this much\n * margin against its height so neighbours glide to their final positions\n * instead of snapping by a gap when the block unmounts. `dividers` rows sit\n * in a `divide-y` card with no flex `gap` at all, so they get no\n * compensation — `gap` would otherwise overshoot into the next row's padding\n * as the block collapses.\n */\nconst GAP_COMPENSATION = {\n stack: \"-2.5rem\",\n block: \"-0.75rem\",\n fields: \"-1.25rem\",\n none: \"0px\",\n} as const;\n\n/**\n * Data-arrival entrance for regions whose shape the skeleton couldn't\n * predict — a list of unknown length, a region that depends on the data.\n * Wrap that region (keeping `Title` and 1:1 chrome outside): once the shape\n * is known it rises 12px and fades in on the Card-shell / Command spring,\n * the same physics as the `Footer` / `Alert` reveals. When the skeleton\n * mirrors the loaded layout element for element, skip the reveal — values\n * fill into a shape that never moves. The page *entrance* is separate and\n * already built into `Stack`: whatever the page first shows (including the\n * skeleton) rides that. Static under reduced motion.\n *\n * With `show`, Reveal becomes an animated-presence block instead (the\n * `Footer` grammar): a whole section of the Stack that appears or leaves at\n * runtime glides open/closed while its neighbours follow.\n */\nfunction Reveal({\n show,\n clip = true,\n gap = \"stack\",\n dividers,\n className,\n ...props\n}: BasicPageRevealProps) {\n const reduceMotion = useReducedMotion();\n // Card rows carry their own padding and a divide-y border, not a flex\n // gap — dividers always means zero gap to compensate for.\n const gapCompensation = GAP_COMPENSATION[dividers ? \"none\" : gap];\n const nodeRef = useRef<HTMLDivElement | null>(null);\n // The first render with `show` plays no animation (AnimatePresence\n // `initial={false}`); any later mount does.\n const animatesOnMount = useRef(show !== true);\n useEffect(() => {\n animatesOnMount.current = true;\n }, []);\n const clipOn = () => {\n if (clip && nodeRef.current) nodeRef.current.style.overflow = \"hidden\";\n };\n const clipOff = () => {\n if (nodeRef.current) nodeRef.current.style.overflow = \"\";\n };\n\n if (show === undefined) {\n return (\n <motion.div\n initial={reduceMotion ? false : { opacity: 0, y: REVEAL_RISE_PX }}\n animate={{ opacity: 1, y: 0 }}\n transition={{ y: ENTRANCE_SPRING, opacity: ENTRANCE_FADE }}\n className={cn(dividers && BASIC_PAGE_CARD_DIVIDERS, className)}\n {...props}\n />\n );\n }\n\n // Clip only while the height animates. At rest the block is unclipped, so\n // a button's rim, a focus ring, or a shadow at its edge shows whole. The\n // toggle goes through the DOM: on exit AnimatePresence keeps a frozen\n // clone whose props no longer update, but its handlers still reach the\n // node. A block mounting with the animation (a later `show`) starts\n // clipped; the first render with `show` plays no animation and stays open.\n return (\n <AnimatePresence initial={false}>\n {show ? (\n <motion.div\n data-basic-page-reveal=\"\"\n ref={(node: HTMLDivElement | null) => {\n nodeRef.current = node;\n if (clip && node && animatesOnMount.current) {\n node.style.overflow = \"hidden\";\n }\n }}\n onAnimationStart={clipOn}\n onAnimationComplete={clipOff}\n initial={{\n height: 0,\n opacity: 0,\n marginTop: gapCompensation,\n }}\n animate={{ height: \"auto\", opacity: 1, marginTop: 0 }}\n exit={{ height: 0, opacity: 0, marginTop: gapCompensation }}\n transition={\n reduceMotion\n ? { duration: 0 }\n : {\n height: ENTRANCE_SPRING,\n marginTop: ENTRANCE_SPRING,\n opacity: ENTRANCE_FADE,\n }\n }\n className={cn(dividers && BASIC_PAGE_CARD_DIVIDERS, className)}\n {...props}\n />\n ) : null}\n </AnimatePresence>\n );\n}\n\n/* ------------------------------- navigation ------------------------------ */\n\n/**\n * Where the trail's chevron sits, in `Root` coordinates, for the ghost a\n * root `Title` fades out on a pop: the nav's `top-4 left-3` plus the\n * button's 8px icon-side padding, centred in the 32px control; the glyph\n * is 1.125em of the `sm` button's 14px type. Kept next to the trail's own\n * offset.\n */\nconst BACK_CHEVRON_GHOST_POSITION =\n \"top-4 left-5 h-8 text-base [&>svg]:size-[1.125em] [&>svg]:shrink-0\";\n\n/** Tailwind's `sm` — below it the trail collapses to its last crumb. */\nconst TRAIL_WIDE_QUERY = \"(min-width: 40rem)\";\n\nfunction isNarrowViewport() {\n return (\n typeof window !== \"undefined\" &&\n typeof window.matchMedia === \"function\" &&\n !window.matchMedia(TRAIL_WIDE_QUERY).matches\n );\n}\n\ninterface TrailItemContextValue {\n index: number;\n count: number;\n /** The trail on its way out at this render, if any. */\n departing: { labels: ReactNode[] } | null;\n /** Below `sm` — only the last crumb shows, with the chevron; decided at mount. */\n narrow: boolean;\n}\n\nconst TrailItemContext = createContext<TrailItemContextValue | null>(null);\n\nexport interface BasicPageBreadcrumbsProps extends ComponentProps<\"nav\"> {\n /** `Crumb`s, root-most first; the last one is the immediate parent. */\n children: ReactNode;\n}\n\n/**\n * The trail above the title — where this page sits, root-most crumb first,\n * ending with the immediate parent; the current page is the `Title` below.\n * Place inside `Root`, before `Title`. It floats in the page's top-left\n * corner instead of taking layout space, and the column reserves a 64px\n * top zone for it, so `Title` sits at the same position whether or not a\n * page has one.\n *\n * One form at every depth: `‹ parent / parent / parent` — the chevron opens\n * the trail (it is the way up), slashes separate the crumbs (they are the\n * path), one crumb or many. Below `sm` the path collapses to `‹ parent` —\n * the last crumb alone. Crumbs render through the host's `LinkProvider`.\n *\n * Four crumbs or more, the middle folds: `‹ root / … / parent / parent`,\n * with the folded pages behind the ellipsis as a menu. The trail keeps a\n * width ceiling at any depth, and the fold never touches the tail, so the\n * title morph is unaffected.\n *\n * It sits in the page's top-left corner — `top-4 left-3`, the chevron ink\n * 20px from the edge, the column gutter's width — as chrome of the pane,\n * not of the column: on a wide pane it stays at the corner while the\n * column centers. `top-4` centers the 32px buttons in the 64px reserved\n * zone; the ghost hover pills hang in the corner padding.\n *\n * Motion between pages: the tail crumb is the morph partner of the child\n * page's `Title` (pair their `morphId`s); everything before it holds still.\n * On a push the trail grows by one — a separator emerges from under the\n * arriving word; on a pop it loses its tail — the word grows back into the\n * title and the spare separator fades. Collapsed, it behaves as `Back`.\n */\nfunction Breadcrumbs({\n className,\n children,\n ...props\n}: BasicPageBreadcrumbsProps) {\n const items = Children.toArray(children).filter(isValidElement);\n const labels = items.map(\n (item) => (item.props as { children?: ReactNode }).children ?? null,\n );\n const departing = useDepartingTrail();\n useTrailPresence(labels);\n const [narrow] = useState(isNarrowViewport);\n const reduceMotion = useReducedMotion();\n const count = items.length;\n const Link = useLinkComponent();\n // Wide trails fold: first crumb, an ellipsis holding the middle, the last\n // two. The trail keeps a width ceiling at any depth, and the morph always\n // involves the tail, which the fold never touches. Collapsed (below sm)\n // the whole path is already one crumb — nothing to fold.\n const folded = !narrow && count >= TRAIL_FOLD_AT;\n // Under `Root condense`, the bar borrows the tail crumb as its way back.\n const condense = useContext(CondenseContext);\n const tailProps =\n count > 0 ? (items[count - 1]?.props as BasicPageCrumbProps) : null;\n const tailLabel = tailProps?.children ?? \"Back\";\n const tailHref = tailProps?.href;\n const tailClick = tailProps?.onClick;\n useLayoutEffect(() => {\n if (condense == null || tailHref == null) return;\n condense.setTail({ label: tailLabel, href: tailHref, onClick: tailClick });\n return () => condense.setTail(null);\n }, [condense, tailLabel, tailHref, tailClick]);\n // A pop, wide: the trail lost its tail — the separator that stood before\n // it has nothing to precede any more and fades where it was.\n const [spareSeparator, setSpareSeparator] = useState(\n !reduceMotion &&\n !narrow &&\n departing != null &&\n departing.labels.length > count,\n );\n return (\n <nav\n aria-label=\"Breadcrumb\"\n data-basic-page-back=\"\"\n className={cn(\n \"absolute top-4 left-3 flex min-w-max items-center\",\n className,\n )}\n {...props}\n >\n <ol className=\"m-0 flex list-none items-center p-0\">\n {items.map((item, index) => {\n if (folded && index > 0 && index < count - 2) return null;\n return (\n <Fragment key={item.key ?? index}>\n {folded && index === count - 2 && (\n <li className=\"m-0 flex items-center max-sm:hidden\">\n <span aria-hidden className={TRAIL_SEPARATOR}>\n {TRAIL_SEPARATOR_GLYPH}\n </span>\n <Menu.Root>\n <Menu.Trigger\n render={\n <Button\n variant=\"ghost\"\n size=\"sm\"\n aria-label=\"Hidden pages\"\n className=\"px-2.5\"\n >\n {TRAIL_FOLD_GLYPH}\n </Button>\n }\n />\n <Menu.Portal>\n <Menu.Positioner align=\"start\" sideOffset={4}>\n <Menu.Popup>\n {items.slice(1, count - 2).map((hidden, i) => {\n const crumb = hidden.props as BasicPageCrumbProps;\n return (\n <Menu.LinkItem\n key={hidden.key ?? i}\n render={\n <Link\n href={crumb.href}\n onClick={crumb.onClick}\n />\n }\n >\n {crumb.children ?? \"Back\"}\n </Menu.LinkItem>\n );\n })}\n </Menu.Popup>\n </Menu.Positioner>\n </Menu.Portal>\n </Menu.Root>\n </li>\n )}\n <li\n className={cn(\n \"m-0 flex items-center\",\n index < count - 1 && \"max-sm:hidden\",\n )}\n >\n <TrailItemContext.Provider\n value={{ index, count, departing, narrow }}\n >\n {item}\n </TrailItemContext.Provider>\n </li>\n </Fragment>\n );\n })}\n {spareSeparator && (\n <li aria-hidden className=\"m-0 flex items-center max-sm:hidden\">\n <motion.span\n initial={{ opacity: 1 }}\n animate={{ opacity: 0 }}\n transition={BACK_CHEVRON_LEAVE}\n onAnimationComplete={() => setSpareSeparator(false)}\n className={TRAIL_SEPARATOR}\n >\n {TRAIL_SEPARATOR_GLYPH}\n </motion.span>\n </li>\n )}\n </ol>\n </nav>\n );\n}\n\n/**\n * `/` between crumbs — description ink, tucked into the buttons' padding.\n * A slash, not a chevron: the trail opens with `‹`, and a `›` after it read\n * as two directions at once. The `‹` is the way up; the slashes are the\n * path.\n */\nconst TRAIL_SEPARATOR =\n \"text-pho-description -mx-1 inline-flex shrink-0 text-base select-none\";\nconst TRAIL_SEPARATOR_GLYPH = \"/\";\n\n/**\n * Wide trails fold at this many crumbs: the first stays (it opens the\n * trail), the middle collapses into an ellipsis menu, the last two stay\n * (where you are, and the step above). Four 160px crumbs and their slashes\n * would pass the 672px content column; the fold caps the trail's width at\n * any depth.\n */\nconst TRAIL_FOLD_AT = 4;\nconst TRAIL_FOLD_GLYPH = \"…\";\n\nexport interface BasicPageCrumbProps extends Omit<\n ButtonLinkProps,\n \"variant\" | \"size\" | \"shape\" | \"prefix\" | \"suffix\" | \"svgOnly\" | \"href\"\n> {\n /** Destination — rendered through the host's `LinkProvider`. */\n href: string;\n /** Label — name the page. @default \"Back\" */\n children?: ReactNode;\n /**\n * Shared-element key. Pair with the same `morphId` on that page's `Title`\n * and the word morphs between title and crumb across the navigation.\n * Skipped under reduced motion.\n */\n morphId?: string;\n}\n\n/**\n * One step of the trail — a small ghost `ButtonLink`. Only meaningful\n * inside `Breadcrumbs`, which decides what shows at which width and which\n * crumb is the tail; `Back` is the one-crumb shorthand.\n */\nfunction Crumb({\n href,\n className,\n morphId,\n children = \"Back\",\n ...props\n}: BasicPageCrumbProps) {\n const trail = useContext(TrailItemContext);\n const reduceMotion = useReducedMotion();\n const morphing = morphId != null && !reduceMotion;\n const flight = useMorphFlight(morphing ? morphId : undefined);\n if (trail == null) {\n throw new Error(\n \"BasicPage.Crumb must be rendered inside BasicPage.Breadcrumbs\",\n );\n }\n const { index, count, departing, narrow } = trail;\n const first = index === 0;\n const last = index === count - 1;\n const grew = departing != null && departing.labels.length < count;\n const shrank = departing != null && departing.labels.length > count;\n // Is this crumb new on screen? Wide: only a tail the trail just grew by\n // (or any tail with no trail before it — a cold mount, the first push).\n // Collapsed: the tail is always the one visible crumb, so a change of\n // trail always changes what shows.\n const newHere = last && (departing == null || grew || narrow);\n // Wide, the chevron opens the trail (first crumb); collapsed, it leads\n // the tail (the only crumb). Both, when they are the same crumb.\n const chevron = first || last;\n const chevronClass =\n first && last ? \"\" : first ? \"max-sm:hidden\" : \"sm:hidden\";\n // Between subpages the chevron is already there — it holds still. Only\n // the first push (no trail on the way out) brings it in with the word.\n const chevronHolds = departing != null;\n // How the label shows up when nothing flies in. Collapsed and a pop: out\n // from under the chevron; a crumb that was already there: no entrance.\n const arrival: MorphArrival | undefined = !last\n ? undefined\n : narrow\n ? shrank\n ? \"slide\"\n : \"fade\"\n : newHere\n ? \"fade\"\n : undefined;\n // Collapsed and a push: the old tail label leaves as the new one arrives\n // in the same slot. Wide, the old tail simply stays as the crumb before.\n const [leavingLabel, setLeavingLabel] = useState<ReactNode>(\n morphing && narrow && flight.fly && departing != null && !shrank\n ? departing.labels[departing.labels.length - 1]\n : null,\n );\n const animateChevron = morphing && chevron && !chevronHolds;\n const animateSeparator =\n morphing && !first && last && (departing == null || grew);\n\n return (\n <>\n {!first && (\n <span aria-hidden className={cn(TRAIL_SEPARATOR, \"max-sm:hidden\")}>\n {animateSeparator ? (\n <motion.span\n initial={\n flight.fly\n ? { opacity: 0, x: MORPH_CHEVRON_RISE_X }\n : { opacity: 0 }\n }\n animate={flight.fly ? { opacity: 1, x: 0 } : { opacity: 1 }}\n transition={flight.fly ? MORPH_CHEVRON_ENTER : ENTRANCE_FADE}\n className=\"inline-flex\"\n >\n {TRAIL_SEPARATOR_GLYPH}\n </motion.span>\n ) : (\n TRAIL_SEPARATOR_GLYPH\n )}\n </span>\n )}\n <ButtonLink\n variant=\"ghost\"\n size=\"sm\"\n href={href}\n prefix={\n chevron ? (\n animateChevron ? (\n // Mirrors the slot's direct-child svg sizing — the fade\n // wrapper sits between the slot and the icon.\n <motion.span\n initial={\n flight.fly\n ? { opacity: 0, x: MORPH_CHEVRON_RISE_X }\n : { opacity: 0 }\n }\n animate={flight.fly ? { opacity: 1, x: 0 } : { opacity: 1 }}\n transition={flight.fly ? MORPH_CHEVRON_ENTER : ENTRANCE_FADE}\n className={cn(\n \"inline-flex [&>svg]:size-[1.125em] [&>svg]:shrink-0\",\n chevronClass,\n )}\n >\n <IconChevronLeft />\n </motion.span>\n ) : (\n <span\n className={cn(\n \"inline-flex [&>svg]:size-[1.125em] [&>svg]:shrink-0\",\n chevronClass,\n )}\n >\n <IconChevronLeft />\n </span>\n )\n ) : (\n // An empty slot keeps every crumb on the icon-side padding, so a\n // crumb measures the same whether or not it is showing a chevron\n // — a label must not shift by 2px when it changes role.\n <span className=\"hidden\" />\n )\n }\n className={cn(\"min-w-max\", className)}\n {...props}\n >\n {morphing && morphId != null ? (\n // The word's box: unclipped while a flight is possible, clipped at\n // its left edge while the label slides out from under the chevron.\n // The departing label sits on top as its own layer so the arriving\n // word is never affected by it. A block, not an inline-block: hidden\n // overflow on an inline-block moves its baseline to the bottom edge\n // and would grow the button by the descender. Crumbs before the tail\n // ellipsize; the tail stays whole so its flight is never clipped.\n <span\n className={cn(\n \"relative block\",\n !flight.fly && arrival === \"slide\" && \"overflow-hidden\",\n !last && \"max-w-40 truncate\",\n )}\n >\n <MorphLabel\n morphId={morphId}\n fromClassName=\"text-pho-primary\"\n fly={flight.fly}\n morphRef={flight.ref}\n arrival={arrival}\n >\n {children}\n </MorphLabel>\n {leavingLabel != null && (\n <motion.span\n aria-hidden\n initial={{ x: 0, opacity: 1 }}\n animate={{ x: BACK_LABEL_LEAVE_X, opacity: 0 }}\n transition={BACK_LABEL_LEAVE}\n onAnimationComplete={() => setLeavingLabel(null)}\n className=\"pointer-events-none absolute inset-y-0 left-0 whitespace-nowrap\"\n >\n {leavingLabel}\n </motion.span>\n )}\n </span>\n ) : (\n <span className={cn(\"block\", !last && \"max-w-40 truncate\")}>\n {children}\n </span>\n )}\n </ButtonLink>\n </>\n );\n}\n\nexport type BasicPageBackProps = BasicPageCrumbProps;\n\n/**\n * Back link for a subpage one level down — the one-crumb `Breadcrumbs`:\n * `‹ parent`, floating in `Root`'s reserved top padding, morphing with the\n * parent's `Title` when they share a `morphId`. Deeper pages list the whole\n * path with `Breadcrumbs` + `Crumb` instead.\n */\nfunction Back({ className, ...props }: BasicPageBackProps) {\n return (\n <Breadcrumbs className={className}>\n <Crumb {...props} />\n </Breadcrumbs>\n );\n}\n\nexport interface BasicPageRowLinkProps extends Omit<\n AnchorHTMLAttributes<HTMLAnchorElement>,\n \"href\" | \"title\" | RevealMotionConflicts\n> {\n /** Left-side field name — plain text, or compose with a trailing badge. */\n label: ReactNode;\n /** Optional helper under the label. */\n description?: ReactNode;\n /** Optional media left of the label (e.g. project avatar). */\n leading?: ReactNode;\n /** Subpage destination — rendered through the host's `LinkProvider`. */\n href: string;\n /** Optional trailing value before the chevron (compose with `Value`). */\n children?: ReactNode;\n ref?: Ref<HTMLAnchorElement>;\n}\n\n/**\n * A row that navigates — the whole row is one link into a subpage, with a\n * trailing chevron cue. Always horizontal: a column stack would park the\n * chevron under the label on narrow viewports. Hover lifts the row, and\n * first/last rows follow the card's corner radius.\n */\nfunction RowLink({\n label,\n description,\n leading,\n href,\n className,\n children,\n ...props\n}: BasicPageRowLinkProps) {\n const Link = useLinkComponent();\n const MotionLink = useMemo(() => motion.create(Link), [Link]);\n const { leaving, ...rowMotion } = useRowMotion();\n return (\n <MotionLink\n href={href}\n {...rowMotion}\n {...props}\n className={cn(\n // Same padding / min-height as `BASIC_PAGE_ROW`, but never `flex-col`\n // — navigation rows keep label left and chevron right at every width.\n \"flex min-h-[4.25rem] min-w-0 flex-row items-center justify-between gap-6 px-5 py-4\",\n \"group outline-pho-brand hover:bg-pho-primary-hover cursor-pointer transition-colors focus-visible:outline-2 focus-visible:-outline-offset-2\",\n // The row whose page is open beside the list keeps the wash.\n \"aria-[current=page]:bg-pho-primary-hover\",\n // Hover wash follows the card's rounding (minus the 1px border).\n \"first:rounded-t-[calc(var(--radius-base)-1px)] last:rounded-b-[calc(var(--radius-base)-1px)]\",\n leaving && \"overflow-hidden\",\n className,\n )}\n >\n <div\n className={cn(\n \"flex min-w-0 flex-1 items-center\",\n leading != null && \"gap-3\",\n )}\n >\n {leading}\n <div className=\"min-w-0\">\n <div className=\"flex min-w-0 items-center gap-1\">\n {typeof label === \"string\" || typeof label === \"number\" ? (\n <p className=\"text-pho-primary truncate text-base font-medium\">\n {label}\n </p>\n ) : (\n label\n )}\n </div>\n {description ? (\n <div className=\"text-pho-description truncate text-xs\">\n {description}\n </div>\n ) : null}\n </div>\n </div>\n <div className=\"flex min-w-0 items-center justify-end gap-2\">\n {children != null ? <div className=\"min-w-0\">{children}</div> : null}\n <IconChevronRight\n aria-hidden\n className=\"text-pho-secondary group-hover:text-pho-secondary-hover size-4 shrink-0 transition-colors\"\n />\n </div>\n </MotionLink>\n );\n}\n\n/* -------------------------------- assembly ------------------------------- */\n\n/**\n * Basic page layout. One stack, one gap rhythm — only title scale differs:\n *\n * ```tsx\n * <BasicPage.Root>\n * <BasicPage.Title>Profile</BasicPage.Title>\n * <BasicPage.Stack>\n * <form>\n * <BasicPage.Card>\n * <BasicPage.Row label=\"Name\" htmlFor=\"first-name\">\n * <Input id=\"first-name\" size=\"sm\" />\n * </BasicPage.Row>\n * </BasicPage.Card>\n * </form>\n * <form>\n * <BasicPage.Header>\n * <BasicPage.SectionTitle>Agent profile</BasicPage.SectionTitle>\n * <BasicPage.Description>…</BasicPage.Description>\n * </BasicPage.Header>\n * <BasicPage.Card>…</BasicPage.Card>\n * </form>\n * <div>\n * <BasicPage.SectionTitle>Danger zone</BasicPage.SectionTitle>\n * <BasicPage.Card>\n * <BasicPage.Row label=\"Delete account\" description=\"…\">\n * <Button color=\"destructive\" size=\"sm\">Delete</Button>\n * </BasicPage.Row>\n * </BasicPage.Card>\n * </div>\n * <BasicPage.Callout icon={<IconMail stroke={1.25} />}>\n * <BasicPage.Header>\n * <BasicPage.CalloutTitle>Invitations</BasicPage.CalloutTitle>\n * <BasicPage.CalloutDescription>…</BasicPage.CalloutDescription>\n * </BasicPage.Header>\n * …invite form…\n * </BasicPage.Callout>\n * </BasicPage.Stack>\n * </BasicPage.Root>\n * ```\n *\n * Subpage — `Back` above the title, `RowLink` rows to drill in:\n *\n * ```tsx\n * <BasicPage.Root>\n * <BasicPage.Back href=\"/settings\">Settings</BasicPage.Back>\n * <BasicPage.Title>Billing</BasicPage.Title>\n * <BasicPage.Stack>\n * <div>\n * <BasicPage.Card>\n * <BasicPage.RowLink label=\"Invoices\" href=\"/settings/invoices\">\n * <BasicPage.Value>12 documents</BasicPage.Value>\n * </BasicPage.RowLink>\n * </BasicPage.Card>\n * </div>\n * </BasicPage.Stack>\n * </BasicPage.Root>\n * ```\n */\nexport interface BasicPageAsideProps {\n /**\n * Whether a page is in it. Defaults to whether there are children — hand\n * it the router's outlet element (`useOutlet()` in React Router), `null`\n * while no subpage route matches, and the aside opens and closes with\n * the URL.\n */\n open?: boolean;\n /**\n * How the panel meets the page on a wide pane. `overlay`, the default,\n * floats over the page's right edge: it takes no ground, surfaces when\n * a subpage opens and leaves with it, and the page beneath stays live.\n * `inline` docks it: the panel's ground is reserved from the first\n * paint, the page beside it never reflows as subpages open and close,\n * and `placeholder` wears the empty panel.\n */\n variant?: \"overlay\" | \"inline\";\n /**\n * For an overlay: dim the page behind and keep interaction in the panel.\n * Focus stays inside, the backdrop is a way out, Escape still closes.\n * Off by default, so the page stays live under the panel and opening\n * another row swaps the panel's page.\n */\n modal?: boolean;\n /**\n * The empty inline panel's face — a quiet line that says what opens\n * here. Optional; without it the reserved panel stands empty. An\n * overlay has no empty face: closed, it is not there.\n */\n placeholder?: ReactNode;\n /**\n * The way out for a page that carries no `Back` — the close in the\n * panel's corner calls it. A page with a `Back` closes through that link.\n */\n onClose?: () => void;\n /**\n * How wide the panel is on a pane that can host it. `default` (unsaid)\n * is two fifths of the pane, 20–28rem. `wide` is two thirds of the pane,\n * 28–48rem — a request body or a waterfall. Below `md` the subpage is\n * the page and this does not apply.\n */\n width?: BasicPageAsideWidth;\n /**\n * How the open subpage shows, controlled: `panel` beside the page, or\n * `page` — the list steps aside and the subpage takes the pane, the way\n * it does on a narrow pane. Pair with `onPresentationChange`; the\n * panel's Expand and the page's Show as panel ask through it. A narrow\n * pane (under `md`) is the page whatever this says.\n */\n presentation?: BasicPageAsidePresentation;\n /**\n * The presentation the subpage opens with, when uncontrolled. Unsaid,\n * the aside decides from how it was reached: a subpage already open\n * when the aside mounts arrived by URL — a deep link, a refresh — and\n * is the page; one that opens later was opened from the list and is a\n * panel. The choice resets each time the aside closes.\n */\n defaultPresentation?: BasicPageAsidePresentation;\n /** The reader pressed Expand or Show as panel. */\n onPresentationChange?: (presentation: BasicPageAsidePresentation) => void;\n /**\n * Whether the panel wears an Expand beside its close, and the expanded\n * page a Show as panel in its corner. On by default; `false` leaves the\n * presentation to the pane and to whoever controls it.\n */\n expandable?: boolean;\n children?: ReactNode;\n}\n\n/**\n * A subpage beside the page. On a pane wide enough for two columns (48rem,\n * Tailwind's `md`) it is a panel at the right edge. By default the panel\n * floats: it takes no ground, surfaces over the page's edge when a\n * subpage opens and leaves with it, and the page beneath stays live\n * unless `modal` dims it. `variant=\"inline\"` docks it: the panel holds\n * its ground from the first paint, the page beside it never reflows as\n * subpages open and close — only the panel's face changes, `placeholder`\n * while empty, the subpage while one is open. Either way the subpage\n * scrolls on its own, its `Back` is the close in the corner, Escape\n * closes too. On a narrower pane the same subpage is the page — the list\n * steps aside, the subpage takes the pane with its own `Back` — so one\n * subpage component serves both. Works under either `Root` width: the\n * page keeps its own column cap beside the panel, and leftover space is\n * margin. `width=\"wide\"` opens the panel itself (two thirds of the pane,\n * up to 48rem); the page's column cap does not follow.\n *\n * Panel or page is presentation, not routing: the URL is the subpage's\n * either way. Left to itself the aside reads how it was reached — a\n * subpage open at mount arrived by URL (deep link, refresh) and is the\n * page; one that opens later was opened from the list and is a panel —\n * and the panel's Expand turns it into the page at the same URL. The\n * page's own `Back` is the way to the list; Show as panel in its corner\n * folds it back beside the list. `presentation` / `onPresentationChange`\n * take the choice over; `defaultPresentation` seeds it.\n */\nfunction Aside({\n open,\n variant = \"overlay\",\n modal = false,\n placeholder,\n onClose,\n width = \"default\",\n presentation,\n defaultPresentation,\n onPresentationChange,\n expandable = true,\n children,\n}: BasicPageAsideProps) {\n const host = useContext(AsideHostContext);\n const panelWidth = host != null ? asideWidth(host.paneWidth, width) : 0;\n // `Children.toArray` drops `null` / `false` / `true`, so `{ok && <Page/>}`\n // does not count as open the way `children != null` would (`false != null`).\n const isOpen = open ?? Children.toArray(children).length > 0;\n const {\n presentation: resolved,\n setPresentation,\n canChoose,\n } = useAsidePresentation({\n isOpen,\n paneNarrow: host?.paneNarrow ?? false,\n presentation,\n defaultPresentation,\n onPresentationChange,\n });\n const setOpen = host?.setOpen;\n const setAsPage = host?.setAsPage;\n const setPresent = host?.setPresent;\n useLayoutEffect(() => {\n if (setPresent == null) return;\n setPresent(true);\n return () => setPresent(false);\n }, [setPresent]);\n useLayoutEffect(() => {\n if (setOpen == null) return;\n setOpen(isOpen);\n return () => setOpen(false);\n }, [setOpen, isOpen]);\n useLayoutEffect(() => {\n if (setAsPage == null) return;\n setAsPage(resolved === \"page\");\n return () => setAsPage(false);\n }, [setAsPage, resolved]);\n useEffect(() => {\n if (\n host == null &&\n typeof process !== \"undefined\" &&\n process.env?.NODE_ENV !== \"production\"\n ) {\n console.warn(\"BasicPage.Aside: needs a `BasicPage.Root` around it.\");\n }\n }, [host]);\n if (host == null || host.slot == null) return null;\n const onExpand =\n expandable && canChoose ? () => setPresentation(\"page\") : undefined;\n if (resolved === \"page\") {\n // Show as panel only where a panel is possible — a wide pane whose\n // reader (or app) chose the page — never on a pane that can only be\n // the page.\n const onCollapse =\n expandable && canChoose && !host.paneNarrow\n ? () => setPresentation(\"panel\")\n : undefined;\n return createPortal(\n isOpen ? (\n <div\n data-basic-page-aside=\"page\"\n data-basic-page-aside-expanded={host.paneNarrow ? undefined : \"\"}\n className=\"relative flex min-w-0 flex-1 flex-col\"\n >\n {onCollapse != null ? (\n <span className=\"absolute top-2 right-2 z-30\">\n <Tooltip.Provider>\n <AsideCornerButton\n label=\"Show as panel\"\n icon={<IconArrowsMinimize />}\n onClick={onCollapse}\n />\n </Tooltip.Provider>\n </span>\n ) : null}\n {children}\n </div>\n ) : null,\n host.slot,\n );\n }\n if (variant === \"inline\") {\n return createPortal(\n <AsideInline\n width={panelWidth}\n paneHeight={host.paneHeight}\n onClose={onClose}\n onExpand={onExpand}\n open={isOpen}\n placeholder={placeholder}\n >\n {children}\n </AsideInline>,\n host.slot,\n );\n }\n return (\n <AsideOverlay\n container={host.slot}\n width={panelWidth}\n paneHeight={host.paneHeight}\n onClose={onClose}\n onExpand={onExpand}\n open={isOpen}\n modal={modal}\n >\n {children}\n </AsideOverlay>\n );\n}\n\n/**\n * The aside's presentation, resolved. A narrow pane is always the page.\n * Otherwise `presentation` (controlled) wins, then the reader's choice\n * through Expand / Show as panel, then `defaultPresentation`, then how the\n * subpage was reached: open at mount means it arrived by URL and is the\n * page; opening later means the list opened it and it is a panel. The\n * reader's choice and the arrival both reset when the aside closes, so\n * the next subpage decides afresh.\n */\nfunction useAsidePresentation({\n isOpen,\n paneNarrow,\n presentation,\n defaultPresentation,\n onPresentationChange,\n}: {\n isOpen: boolean;\n paneNarrow: boolean;\n presentation: BasicPageAsidePresentation | undefined;\n defaultPresentation: BasicPageAsidePresentation | undefined;\n onPresentationChange:\n ((presentation: BasicPageAsidePresentation) => void) | undefined;\n}) {\n // Open at mount — the subpage arrived with the aside, by URL.\n const [arrivedOpen, setArrivedOpen] = useState(isOpen);\n const [chosen, setChosen] = useState<BasicPageAsidePresentation | null>(null);\n useLayoutEffect(() => {\n if (isOpen) return;\n setArrivedOpen(false);\n setChosen(null);\n }, [isOpen]);\n const controlled = presentation != null;\n const uncontrolled =\n chosen ?? defaultPresentation ?? (arrivedOpen ? \"page\" : \"panel\");\n const resolved: BasicPageAsidePresentation = paneNarrow\n ? \"page\"\n : (presentation ?? uncontrolled);\n const setPresentation = useCallback(\n (next: BasicPageAsidePresentation) => {\n if (!controlled) setChosen(next);\n onPresentationChange?.(next);\n },\n [controlled, onPresentationChange],\n );\n // A controlled aside with no listener has nowhere to send the choice.\n const canChoose = !controlled || onPresentationChange != null;\n return { presentation: resolved, setPresentation, canChoose };\n}\n\n/**\n * The way out of a panel: the subpage's `Back`, handed up through\n * `AsidePanelContext`, or the host's `onClose`. Whoever closes the panel\n * from outside (Escape, a backdrop) clicks it, so a route-driven aside\n * leaves through the router like any other navigation. It is mounted\n * only while a subpage is open; an empty panel leaves the close request\n * to whoever else wants it.\n */\nfunction useAsideWayOut() {\n const [back, setBack] = useState<CondenseTail | null>(null);\n const panel = useMemo<AsidePanelController>(() => ({ setBack }), []);\n const closeRef = useRef<HTMLSpanElement | null>(null);\n const leave = useCallback(() => {\n const way = closeRef.current?.querySelector<HTMLElement>(\"a, button\");\n if (way == null) return false;\n way.click();\n return true;\n }, []);\n return { back, panel, closeRef, leave };\n}\n\nconst ASIDE_CLOSE = {\n variant: \"ghost\",\n size: \"sm\",\n svgOnly: true,\n \"aria-label\": \"Close\",\n children: <IconX />,\n} as const;\n\n/**\n * An icon button in the aside's corner — Expand beside the panel's close,\n * Show as panel on the expanded page — named by a tooltip as well as its\n * label, since the glyph alone is a guess.\n */\nfunction AsideCornerButton({\n label,\n icon,\n onClick,\n}: {\n label: string;\n icon: ReactNode;\n onClick: () => void;\n}) {\n return (\n <Tooltip.Root>\n <Tooltip.Trigger\n render={\n <Button\n variant=\"ghost\"\n size=\"sm\"\n svgOnly\n aria-label={label}\n onClick={onClick}\n >\n {icon}\n </Button>\n }\n />\n <Tooltip.Portal>\n <Tooltip.Positioner>\n <Tooltip.Popup>{label}</Tooltip.Popup>\n </Tooltip.Positioner>\n </Tooltip.Portal>\n </Tooltip.Root>\n );\n}\n\n/**\n * A panel's subpage face: the corner controls — Expand, then the close\n * (the subpage's `Back`, or `onClose`) — over the page in its own scroll\n * area. `closeRef` wraps the close alone, so Escape and the backdrop find\n * the way out and never the Expand.\n */\nfunction AsideSubpage({\n back,\n onClose,\n onExpand,\n closeRef,\n panel,\n children,\n}: {\n back: CondenseTail | null;\n onClose?: () => void;\n onExpand?: () => void;\n closeRef: RefObject<HTMLSpanElement | null>;\n panel: AsidePanelController;\n children?: ReactNode;\n}) {\n return (\n <>\n <span className=\"absolute top-2 right-2 z-30 flex items-center gap-0.5\">\n {onExpand != null ? (\n <Tooltip.Provider>\n <AsideCornerButton\n label=\"Expand\"\n icon={<IconArrowsMaximize />}\n onClick={onExpand}\n />\n </Tooltip.Provider>\n ) : null}\n <span ref={closeRef} className=\"contents\">\n {back != null ? (\n <ButtonLink\n {...ASIDE_CLOSE}\n href={back.href}\n onClick={back.onClick}\n />\n ) : onClose != null ? (\n <Button {...ASIDE_CLOSE} onClick={onClose} />\n ) : null}\n </span>\n </span>\n <ScrollArea.Root className=\"min-h-0 min-w-0 flex-1\">\n <ScrollArea.Viewport\n className=\"overflow-x-hidden\"\n style={{ overflowX: \"hidden\" }}\n >\n <ScrollArea.Content\n className=\"flex min-h-full w-full min-w-0 flex-col\"\n // Base UI sets `minWidth: fit-content` on Content. A pretty-printed\n // JSON line would then grow the sheet past the panel measure.\n style={{ minWidth: 0, width: \"100%\", maxWidth: \"100%\" }}\n >\n <AsidePanelContext.Provider value={panel}>\n {children}\n </AsidePanelContext.Provider>\n </ScrollArea.Content>\n </ScrollArea.Viewport>\n <ScrollArea.Scrollbar>\n <ScrollArea.Thumb />\n </ScrollArea.Scrollbar>\n </ScrollArea.Root>\n </>\n );\n}\n\n/**\n * The docked panel — reserved ground, never a layout event. The cell\n * keeps the panel's width whether or not a subpage is open, so the page\n * beside it never reflows: a form row stretching wide and snapping back\n * on every open is exactly the disturbance this buys out. The sheet is\n * sticky at the pane's top and as tall as the pane; its two faces — the\n * placeholder and the subpage — crossfade in one grid cell (fade and a\n * breath of blur), and the page inside scrolls in its own scroll area.\n */\nfunction AsideInline({\n width,\n paneHeight,\n onClose,\n onExpand,\n open,\n placeholder,\n children,\n}: {\n width: number;\n paneHeight: number | null;\n onClose?: () => void;\n onExpand?: () => void;\n open: boolean;\n placeholder?: ReactNode;\n children?: ReactNode;\n}) {\n const reduceMotion = useReducedMotion();\n const { back, panel, closeRef, leave } = useAsideWayOut();\n const blurAway = reduceMotion ? \"blur(0px)\" : `blur(${BLUR_MAX_PX}px)`;\n const height = paneHeight ?? \"100dvh\";\n // Escape is the close even when focus is still on the list (a RowLink\n // with aria-current), not only when it is inside the panel.\n useEffect(() => {\n const onKeyDown = (event: KeyboardEvent) => {\n if (event.key !== \"Escape\" || event.defaultPrevented) return;\n if (leave()) event.preventDefault();\n };\n document.addEventListener(\"keydown\", onKeyDown);\n return () => document.removeEventListener(\"keydown\", onKeyDown);\n }, [leave]);\n const face = {\n initial: { opacity: 0, filter: blurAway },\n animate: { opacity: 1, filter: \"blur(0px)\" },\n exit: { opacity: 0, filter: blurAway },\n transition: reduceMotion ? { duration: 0 } : CONDENSE_BAR_ENTER,\n } as const;\n return (\n <aside\n data-basic-page-aside=\"panel\"\n data-basic-page-aside-variant=\"inline\"\n className=\"relative flex min-w-0 shrink-0 flex-col\"\n style={{ width, minWidth: 0, maxWidth: width, minHeight: height }}\n >\n {/* Both faces share one grid cell — the swap measures nothing. Part\n of the layout, not a floating layer: a hairline edge, no\n elevation shadow. */}\n <div\n className=\"border-pho-secondary bg-pho-primary sticky top-0 grid min-w-0 overflow-hidden border-l *:min-h-0 *:[grid-area:1/1]\"\n style={{ height }}\n >\n <AnimatePresence initial={false}>\n {open ? (\n <motion.div\n key=\"page\"\n {...face}\n className=\"relative flex min-w-0 flex-col\"\n >\n <AsideSubpage\n back={back}\n onClose={onClose}\n onExpand={onExpand}\n closeRef={closeRef}\n panel={panel}\n >\n {children}\n </AsideSubpage>\n </motion.div>\n ) : (\n <motion.div key=\"empty\" {...face} className=\"flex flex-col\">\n {placeholder}\n </motion.div>\n )}\n </AnimatePresence>\n </div>\n </aside>\n );\n}\n\n/**\n * The floating panel — a layer over the page's right edge, not a cell in\n * it. It takes no ground: the page keeps its full width, the sheet\n * surfaces from the edge when a subpage opens and leaves with it, and\n * under it the page stays live unless `modal` says otherwise. Built on\n * Base UI's Dialog for what a floating layer owes: Escape from anywhere,\n * and for a modal the focus trap, the return of focus on close, and the\n * page marked hidden behind it. Positioned in the page's own frame and\n * sticky at the pane's top, so it floats inside whatever pane hosts the\n * page, as tall as that pane.\n */\nfunction AsideOverlay({\n container,\n width,\n paneHeight,\n onClose,\n onExpand,\n open,\n modal,\n children,\n}: {\n container: HTMLElement;\n width: number;\n paneHeight: number | null;\n onClose?: () => void;\n onExpand?: () => void;\n open: boolean;\n modal: boolean;\n children?: ReactNode;\n}) {\n const { back, panel, closeRef, leave } = useAsideWayOut();\n const height = paneHeight ?? \"100dvh\";\n return (\n <BaseDialog.Root\n open={open}\n modal={modal ? \"trap-focus\" : false}\n // The page beneath stays live: no close on an outside press, none\n // on focus leaving. A modal's backdrop closes on its own click.\n disablePointerDismissal\n onOpenChange={(next, details) => {\n if (next) return;\n // The route owns `open`. A close request means leave through the\n // way out; the panel then follows the URL.\n details.cancel();\n leave();\n }}\n >\n <BaseDialog.Portal container={container} className=\"contents\">\n {modal ? (\n <BaseDialog.Backdrop\n data-basic-page-aside-backdrop=\"\"\n className={cn(\n \"bg-pho-overlay absolute inset-0 z-30 transition-opacity duration-200 ease-out motion-reduce:transition-none\",\n \"data-[ending-style]:opacity-0 data-[starting-style]:opacity-0\",\n )}\n onClick={leave}\n />\n ) : null}\n <BaseDialog.Popup\n data-basic-page-aside=\"panel\"\n data-basic-page-aside-variant=\"overlay\"\n // A live page keeps its focus where it was; a modal takes it.\n initialFocus={modal ? undefined : false}\n finalFocus={modal ? undefined : false}\n className={cn(\n \"absolute inset-y-0 right-0 z-30 flex min-w-0 flex-col outline-none\",\n // Arrives the way content does: a short rise from the edge\n // with the ink, and leaves the same way.\n \"transition-[translate,opacity] duration-250 ease-out motion-reduce:transition-none\",\n \"data-[ending-style]:translate-x-3 data-[ending-style]:opacity-0 data-[ending-style]:duration-200 data-[starting-style]:translate-x-3 data-[starting-style]:opacity-0\",\n )}\n style={{ width, minWidth: 0, maxWidth: width }}\n >\n {/* A floating layer: the elevation shadow over the hairline. */}\n <div\n className=\"border-pho-secondary bg-pho-primary shadow-pho-xl sticky top-0 flex min-w-0 flex-col overflow-hidden border-l\"\n style={{ height }}\n >\n <AsideSubpage\n back={back}\n onClose={onClose}\n onExpand={onExpand}\n closeRef={closeRef}\n panel={panel}\n >\n {children}\n </AsideSubpage>\n </div>\n </BaseDialog.Popup>\n </BaseDialog.Portal>\n </BaseDialog.Root>\n );\n}\n\n/** The open search box's width. */\nconst SEARCH_OPEN_W = \"14rem\";\n\n/** The box's width travels on the page spring — what Menu and Popover open on. */\nconst SEARCH_GLIDE =\n \"transition-[width] duration-[330ms] ease-pho-spring motion-reduce:transition-none\";\n/**\n * The two faces trade places on the swap fade; visibility follows at the\n * fade's end, so the face going away drops out of the tab order and the\n * accessibility tree without a timer deciding when.\n */\nconst SEARCH_FACE =\n \"transition-[opacity,visibility] duration-200 ease-out motion-reduce:transition-none\";\n\n/**\n * Controlled, the query and its setter come together: a `value` with no\n * way to change it would be a field that silently ignores typing.\n */\ntype BasicPageSearchControl =\n | { value: string; onValueChange: (value: string) => void }\n | { value?: undefined; onValueChange?: undefined };\n\nexport type BasicPageSearchProps = BasicPageSearchOwnProps &\n BasicPageSearchControl;\n\ninterface BasicPageSearchOwnProps extends ComponentProps<\"div\"> {\n /**\n * The face. `box` (default) is the bordered field beside a section\n * title — open on a wide header, a round button that glides it open on\n * a narrow one. `ghost` is the table-chrome face: a magnifier and a\n * bare field on the text line, no box — for a toolbar band or anywhere\n * a boxed control would be noise; it flexes instead of folding.\n */\n variant?: \"box\" | \"ghost\";\n /**\n * When the box folds to its round button. `auto` (default): a header at\n * least 36rem wide shows the box open, a narrower one the button.\n * `always`: the button at every width, the box gliding open from it on\n * click — for a list whose header has the room but wants the lighter\n * face.\n */\n fold?: \"auto\" | \"always\";\n /**\n * The field's placeholder in the controlled mode (`value` with\n * `onValueChange`: the page searches its own list rather than a table,\n * the Search shows `placeholder`, reports typing through `onValueChange`,\n * and clears through it on Escape; without `value` it adopts the\n * searchable table on the page). About twenty characters fit the open box.\n */\n placeholder?: string;\n /**\n * The accessible name of the button and the field — the placeholder\n * unless said otherwise, for a placeholder too short to say what the\n * search covers.\n */\n label?: string;\n}\n\n/**\n * A search standing at the end of a section header. Put it in the\n * `Header` beside the title and it adopts the searchable table's box (the\n * table then renders none of its own); give it `value` and it searches\n * the page's own list of rows, no table needed. On a header at least\n * 36rem wide the box simply stands open: the header is a container, CSS\n * decides, nothing is measured. On a narrower one — or at every width\n * with `fold=\"always\"` — a round button holds the place; clicking it\n * glides the box open on the page spring, the two faces crossfading, with\n * focus landing inside. The box stays while it holds a query; emptied and\n * blurred it glides shut and the button returns, and Escape clears,\n * blurs, and shuts. Without `value`, renders nothing until a table with\n * `search` is on the page.\n */\nfunction Search({\n variant = \"box\",\n fold = \"auto\",\n value,\n onValueChange,\n placeholder,\n label,\n className,\n ...props\n}: BasicPageSearchProps) {\n const store = useContext(TableSearchContext);\n const tableApi = useSyncExternalStore(\n store?.subscribe ?? subscribeToNothing,\n () => store?.get().api ?? null,\n () => null,\n );\n // Controlled, the page's list is the subject and the table (if any) keeps\n // its own box; otherwise the table's box is adopted and it yields.\n const controlled = value != null;\n useEffect(() => {\n if (store == null || controlled) return;\n store.adopt(true);\n return () => store.adopt(false);\n }, [store, controlled]);\n const api = controlled\n ? {\n query: value,\n setQuery: onValueChange,\n placeholder: placeholder ?? \"Search\",\n label: label ?? placeholder ?? \"Search\",\n }\n : tableApi == null\n ? null\n : {\n query: tableApi.query,\n setQuery: tableApi.setQuery,\n placeholder: tableApi.placeholder,\n label: label ?? tableApi.placeholder,\n };\n // `open` is the button's click; the box also stays while it holds a query.\n const [open, setOpen] = useState(false);\n const inputRef = useRef<HTMLInputElement | null>(null);\n const showBox = open || (api?.query ?? \"\") !== \"\";\n // Focus once the box can take it. Its visibility is transitioning, and a\n // transition computes its start value — hidden — at its very first\n // instant, so a field asked to focus on that frame refuses; the next\n // frame it is visible. Try a frame at a time until focus lands.\n useEffect(() => {\n if (!open) return;\n let frame = 0;\n let tries = 0;\n const attempt = () => {\n const input = inputRef.current;\n if (input == null) return;\n input.focus();\n if (document.activeElement !== input && tries++ < 5) {\n frame = requestAnimationFrame(attempt);\n }\n };\n frame = requestAnimationFrame(attempt);\n return () => cancelAnimationFrame(frame);\n }, [open]);\n if (variant === \"ghost\") {\n return (\n <div\n data-basic-page-search=\"\"\n data-variant=\"ghost\"\n className={cn(\n \"flex min-w-0 flex-1\",\n api == null && \"hidden\",\n className,\n )}\n {...props}\n >\n {api != null && (\n <GhostSearch\n value={api.query}\n onChange={api.setQuery}\n placeholder={api.placeholder}\n aria-label={api.label}\n onKeyDown={(event) => {\n if (event.key !== \"Escape\") return;\n // Ours — not the aside's close.\n event.preventDefault();\n api.setQuery(\"\");\n event.currentTarget.blur();\n }}\n />\n )}\n </div>\n );\n }\n const auto = fold === \"auto\";\n return (\n <div\n data-basic-page-search=\"\"\n data-expanded={showBox || undefined}\n className={cn(\n \"grid min-w-0 content-center\",\n // Its seat in a `Header`'s grid — inert anywhere else. Top on the\n // header's top, level with a `HeaderAction` beside it; the header\n // centers text shorter than the search against it.\n \"[[data-basic-page-header]>&]:col-start-2 [[data-basic-page-header]>&]:row-span-2 [[data-basic-page-header]>&]:row-start-1 [[data-basic-page-header]>&]:ml-4 [[data-basic-page-header]>&]:justify-items-end [[data-basic-page-header]>&]:self-start\",\n api == null && \"hidden\",\n className,\n )}\n {...props}\n >\n {api != null && (\n <div\n className={cn(\n \"grid w-9 max-w-full justify-items-end *:[grid-area:1/1]\",\n SEARCH_GLIDE,\n auto && \"@[36rem]:w-56\",\n )}\n style={showBox ? { width: SEARCH_OPEN_W } : undefined}\n >\n {/* Visibility follows the fade to its end, so the face going away\n also drops out of the tab order and hit-testing at once. On a\n wide `auto` header the button never shows; CSS keeps it out. */}\n <Button\n variant=\"outlined\"\n size=\"sm\"\n shape=\"circle\"\n svgOnly\n aria-label={api.label}\n aria-hidden={showBox || undefined}\n tabIndex={showBox ? -1 : undefined}\n onClick={() => setOpen(true)}\n className={cn(\n SEARCH_FACE,\n showBox\n ? \"pointer-events-none invisible opacity-0\"\n : \"visible opacity-100\",\n auto &&\n \"@[36rem]:pointer-events-none @[36rem]:invisible @[36rem]:opacity-0\",\n )}\n >\n <IconSearch />\n </Button>\n <div\n inert={!auto && !showBox}\n className={cn(\n \"w-full min-w-0\",\n SEARCH_FACE,\n showBox\n ? \"visible opacity-100\"\n : \"pointer-events-none invisible opacity-0\",\n auto &&\n \"@[36rem]:pointer-events-auto @[36rem]:visible @[36rem]:opacity-100\",\n )}\n >\n <InputGroup.Root size=\"sm\" className=\"w-full\">\n <InputGroup.Addon>\n <IconSearch />\n </InputGroup.Addon>\n <InputGroup.Input\n ref={inputRef}\n type=\"search\"\n value={api.query}\n onChange={(event) => api.setQuery(event.target.value)}\n onBlur={() => {\n if (api.query === \"\") setOpen(false);\n }}\n onKeyDown={(event) => {\n if (event.key !== \"Escape\") return;\n // Ours — not the aside's close.\n event.preventDefault();\n api.setQuery(\"\");\n setOpen(false);\n event.currentTarget.blur();\n }}\n placeholder={api.placeholder}\n aria-label={api.label}\n />\n </InputGroup.Root>\n </div>\n </div>\n )}\n </div>\n );\n}\n\n/**\n * Two-column body on a wide page. The side column is floored at 29rem —\n * a `pho_res_` + 26-character resource id sits whole beside its label in\n * a card row — and capped at 32rem so it stays a facts column, not a\n * second reading measure. The main column takes the rest.\n *\n * Pair with `Root width=\"wide\"` so the canvas can host both columns.\n * `Columns` brings its own `@container`: two columns only when the\n * container can hold the 42rem reading column, a 2.5rem gutter, and the\n * 29rem side (73.5rem). Below that the page is one 42rem reading column,\n * source order main → side → foot. Leave `side` out and it stays that\n * reading column at every width.\n *\n * Each slot is a `Stack`. The grid owns the seams between them (16px\n * row gap + a 24px stack seat = 40px, the block rhythm), so hosts never\n * put `mt-*` on a stack. `enter` is the stacks' — see `Stack`.\n */\nexport interface BasicPageColumnsProps {\n /** The page's `Title` or `Header`, across the top of both columns. */\n header?: ReactNode;\n /** The primary column. Left; first in one column. */\n main: ReactNode;\n /**\n * The facts and offers. Right, 29–32rem; first after `main` in one\n * column. Left out, the page stays one reading column.\n */\n side?: ReactNode;\n /** What ends the page. Under `side` on the right; last in one column. */\n foot?: ReactNode;\n /** Whether the stacks play the page entrance — see `Stack`. */\n enter?: boolean;\n}\n\nfunction Columns({ header, main, side, foot, enter }: BasicPageColumnsProps) {\n const twoColumns = side != null;\n return (\n <div data-basic-page-columns=\"\" className=\"@container w-full min-w-0\">\n <div\n className={cn(\n \"mx-auto w-full max-w-[42rem]\",\n twoColumns && \"@min-[73.5rem]:max-w-none\",\n )}\n >\n {header}\n <div\n className={cn(\n \"grid gap-x-10 gap-y-4\",\n twoColumns &&\n \"@min-[73.5rem]:grid-cols-[minmax(42rem,1fr)_minmax(29rem,32rem)] @min-[73.5rem]:grid-rows-[auto_minmax(0,1fr)]\",\n // The seam under `main` in one column: the grid owns its row\n // gaps, and this is the one it cannot express as a single\n // `gap-y` — a stack's `mt` is the seat it takes under the\n // title, not a seam between stacks. `side` keeps that seat\n // once it sits under the title again.\n twoColumns &&\n \"[&>[data-basic-page-columns-side]]:mt-6 @min-[73.5rem]:[&>[data-basic-page-columns-side]]:mt-7\",\n // `foot` is never under the title (it follows `side`, or\n // `main` when there is no side), so its seat stays the seam.\n foot != null && \"[&>[data-basic-page-columns-foot]]:mt-6\",\n )}\n >\n <Stack\n enter={enter}\n data-basic-page-columns-main=\"\"\n className={cn(\n // The outer Stack already seated Columns; don't add another mt.\n \"[[data-basic-page-stack]>[data-basic-page-columns]_&]:mt-0\",\n twoColumns &&\n \"@min-[73.5rem]:col-start-1 @min-[73.5rem]:row-span-2 @min-[73.5rem]:row-start-1\",\n )}\n >\n {main}\n </Stack>\n {twoColumns ? (\n <Stack\n enter={enter}\n data-basic-page-columns-side=\"\"\n className={cn(\n \"[[data-basic-page-stack]>[data-basic-page-columns]_&]:mt-0\",\n \"@min-[73.5rem]:col-start-2 @min-[73.5rem]:row-start-1\",\n )}\n >\n {side}\n </Stack>\n ) : null}\n {foot != null ? (\n <Stack\n enter={enter}\n data-basic-page-columns-foot=\"\"\n className={cn(\n \"[[data-basic-page-stack]>[data-basic-page-columns]_&]:mt-0\",\n twoColumns &&\n \"@min-[73.5rem]:col-start-2 @min-[73.5rem]:row-start-2 @min-[73.5rem]:self-start\",\n )}\n >\n {foot}\n </Stack>\n ) : null}\n </div>\n </div>\n </div>\n );\n}\n\nexport const BasicPage = {\n Root,\n Aside,\n Search,\n // The data table under the page's name — records in columns, rows that\n // open in the aside. Same component as `components/data-table`; import\n // from there where a bundle wants the table without the page.\n Table: DataTable,\n // A body on the page — an event's JSON, a request as sent, the command\n // that installs the SDK — as a block, colored by `language`. Same\n // component as `components/code-block`; import from there where a\n // bundle wants the panel without the page.\n Code: CodeBlock,\n CondenseScope,\n Breadcrumbs,\n Crumb,\n Back,\n Title,\n Stack,\n Columns,\n Header,\n HeaderAction,\n SectionTitle,\n Description,\n TableCount,\n SectionFooter,\n Card,\n Item,\n ItemPanel,\n Callout,\n CalloutTitle,\n CalloutDescription,\n Onboard,\n Step,\n Row,\n RowLink,\n Value,\n // One record's metadata — label beside value, dense lines of text\n // inside a Card Item, where `Row` is a 68px row built for a control on\n // its right. Same component as `components/description-list`; import\n // from there where a bundle wants the list without the page.\n Meta: DescriptionList.Root,\n MetaItem: DescriptionList.Item,\n Alert,\n Footer,\n Form,\n Saved,\n Fields,\n Inline,\n Submit,\n Reveal,\n};\n"],"mappings":"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"}
|