Each list page restyled DataTable on top of the shared look: fourteen
re-skin classes, filled grey headers, padded cards inside padded pages
and nth-child column widths (which put Docker's Name column 300px in
once the checkbox column existed). The table wrap is now the only
frame, the header is unfilled, column widths come from the column
definition, and raw tables and ui Table uses render through DataTable.
scripts/check-tables.mjs holds it in lint.
Page bodies drop the 1400px reading column (and the per-page caps on
Domains, Deployments, Dashboard, detail pages and Recipes) for one
20px gutter everywhere; Settings caps only its form column. The top
bar gets the sidebar's surface and edge so the chrome reads apart from
the canvas, and the bulk-selection pill clears the status bar.
Also removes decorative chrome: gradient letter avatars and tinted
stat icons become neutral, Domains rows lose the icon tile and the
"Registrar -" sub-line, and destructive row actions are quiet ghost
buttons that turn red on hover (.btn-ghost.is-danger).
Second geometry pass, over every stylesheet: control heights are 28,
32 or 40; tables have a 32px header and 40px rows (the databases grid
stays compact at 32); cards use one radius and 16px padding; about 30
page-specific pill classes follow the 20px badge spec; and shadows are
only on things that float (menus raised, modals and drawers overlay),
with focus as one ring. Glows, hover lifts and card shadows are gone,
and page overrides of the shared primitives are removed.
Sign-in and setup screens use the 40px size. Fixed chrome (status bar,
icons, avatars, chart boxes) is marked // geometry: and exempt.
Measured: distinct button heights 25 -> 13, table headers 8 -> 3,
badges 7 -> 3. check-geometry ceilings are now zero for raw shadows
and control heights.
The three remaining catalogs each had their own card: a 140px cover
banner with source, category, first-party and trust badges on
Extensions, a legacy SharedCard on Server Templates, and a bespoke
button card in the engine drawer. All three now use the shared
CatalogCard: one tag, author and trust as plain text, an outline
action, and a flat surface. Server-template facts also get singular
forms ("1 package", not "1 packages").
Plan 79 §H + ratchet 7.
<html dir> already follows the language manifest and the locale probe asserts
it. What was missing is a stylesheet that could follow it: 468
direction-anchored declarations (margin/padding/border-left|right, bare
left:/right:, text-align and float) against 5 logical properties. An RTL
locale today would render a mirrored language inside an unmirrored layout, so
the plan ships plumbing and a ratchet, not a locale. The count is 468 rather
than the plan's grepped 412 because float and text-align are equally anchored.
Also splits `src/i18n/t.js` out of the i18n barrel. The API client's error
mapper imports the bare `t`, and the client is reachable from a node test --
which then loaded i18n/index.js and its `import.meta.glob`, a Vite
compile-time transform that throws under plain node. The obvious fix was the
runtime guard that had just been removed for silently discarding every locale,
so the module is split instead: t.js touches only the i18next singleton, and
index.js keeps initialisation and the glob for browser-only callers.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>