Build motir.co/design — a PUBLIC page that demonstrates Motir's design ability by letting a visitor switch Style × Palette × Type and watch the whole site restyle live. It ships in motir-marketing, not motir-core.
This card was authored on 2026-06-17 as a motir-core surface, when Motir's public front door was motir-core's app/page.tsx. The 8.3 re-plan of 2026-06-30 moved the public marketing surface into the new motir-marketing repo (MOTIR-656) and this card was never swept. Its premise — a public marketing / credibility surface — now resolves to motir.co.
What the re-plan changed: the repo pin (motir-core → motir-marketing), the route (/tokens → /design), the substrate (motir-core's lib/theme/* + components/ui/* → the published @motir/design-system), the PARENT — this card was moved out of 8.8 (launch-readiness polish) into 8.3, the marketing-site story, where the rest of the motir.co work lives — and three deliverables the old card did not carry (a design asset, the nav entrance, the missing typefaces). It also GAINED a design blocker and a copy blocker, which is what the planning-time design gate should have produced in June.
What it did NOT change: motir-core's /tokens stays exactly as it is. It is the internal living spec (docs/DESIGN.md, docs/design-system.md; docs/a11y/shell-audit.md calls it "a dev-only specimen") and it still has real callers — tests/e2e/shell-a11y-tokens.spec.ts, plus app/tokens/ allowlists in tests/theme/shapeSwapLint.test.ts and tests/theme/swapLayerLint.test.ts. Nothing is being migrated and no path is being abandoned, so this card owes no deletion sibling: it adds a NEW public surface on a DIFFERENT host. (Measured: git grep "'/tokens'\|app/tokens" origin/main → 27 hits in motir-core, every one an internal spec, test, lint-allowlist or doc reference.)
/design and not /tokens/tokens would name the same route as motir-core's dev specimen while meaning something else, and on a marketing host it reads as API tokens — a real collision, since app.motir.co/settings/account/tokens is exactly that. /design names what the page is about.
Nothing has to be extracted, packaged or published. motir-marketing's package.json already depends on @motir/design-system@0.1.0 and @motir/brand@0.1.0; app/globals.css already @imports @motir/design-system/theme.css and @sources the package dist (without which Tailwind generates none of the package's classes and the page paints unstyled with no error); app/layout.tsx already runs the package's themeInitScript blocking in <head>.
The published tarball (npm pack @motir/design-system@0.1.0, shasum ed10ed8db66eb09d34d062b0b4bad878c8509fed, pulled anonymously — the consumer's own route) exports everything this page needs: ThemeProvider · useTheme · StylePicker · PalettePicker · TypePicker · ThemeSegmentedControl · AxisField / AxisNote / AxisRadioGroup · StyleVignette · TokensSpecimen · cn · the primitives · and the three registries at 9 styles · 10 palettes · 6 type pairings — the same membership as motir-core origin/main, so the showcase is not a stale copy of the system.
How the whole page restyles: ThemeProvider writes data-theme / data-style / data-palette / data-type onto document.documentElement and persists each to localStorage. The attributes therefore drive theme.css's 35 [data-palette], 109 [data-style] and 9 [data-type] blocks for the entire document — header and footer included — which is exactly the whole-self styling this card is for. It also means the choice PERSISTS across motir.co; the design card decides and draws that (it is drawn as KEPT, with a Reset to default control).
app/layout.tsx loads Inter + Source Serif 4 + JetBrains Mono only, and says so deliberately: "this site has no picker, so it loads the default pairing's three and nothing else." Three of the six pairings need faces that are not loaded, and two of them fail hard rather than degrading, read from the published theme.css:
| pairing | reads | face | today |
|---|---|---|---|
grotesk | var(--font-grotesk-source) — no in-var fallback | Space Grotesk | declaration invalid ⇒ role falls back |
editorial | var(--font-editorial-source) — no in-var fallback | Fraunces | declaration invalid ⇒ role falls back |
mono-technical | var(--font-mono-technical-source, ui-monospace) | IBM Plex Mono | degrades to ui-monospace |
⚠️ The loader variable MUST be the -source name. theme.css declares the ROLE tokens as --font-sans: var(--font-sans-source, …) and the [data-type] blocks re-point the roles; naming a next/font variable --font-sans directly leaves every var(--font-*-source) unresolved and silently disables the whole type axis. app/layout.tsx's own header says this — follow it.
Add the three with preload: false, so the landing's first paint is unchanged: only a visitor who actually picks one of those pairings pays for the face.
One repository, one pull request, motir-marketing. It does not touch motir-core — not app/tokens/, not the package source, not theme.css. It ships no new design token and no new primitive: everything it renders comes from @motir/design-system, and where a primitive is missing the answer is to compose, never to hand-roll a container, a radius or a colour. It writes no copy — the copy card owns the strings and this card reads them from copy.designShowcase.* / copy.nav.*.
/design is publicly reachable with no sign-in on motir.co and renders the page the design asset draws. (motir-marketing has no auth of any kind, so this is a property of the route existing — not a gate to remove.)data-style / data-palette / data-type attributes on <html> after each control is operated.system resolves through prefers-color-scheme.app/layout.tsx loads Space Grotesk as --font-grotesk-source, Fraunces as --font-editorial-source and IBM Plex Mono as --font-mono-technical-source, each with preload: false; a test asserts each of the six TYPOGRAPHY ids maps to a -source variable the layout defines.@motir/design-system and declares no --el-*, no --color-*, and no raw rounded-* / p-* / h-* where a shape token exists.app/_components/SiteHeader.tsx (desktop bar + md:hidden panel) with the current-page treatment the design specifies, as a next/link — it is the site's first internal second route. No accent-coloured text in the bar (MOTIR-3745).app/sitemap.ts gains the /design line in this same change — the file's own comment asks for exactly that: "When a second page lands it adds its line here, in the same change that adds the route."vitest, the repo's tests/*.test.tsx pattern, per the code-and-tests-are-one-deliverable floor): the page renders, each control writes the expected <html> attribute, the type-pairing ↔ font-variable map is total, and the AA matrix passes. There is no separate test card and no E2E lane in this repository — ci.yml runs lint · typecheck · build · test, and its own header says not to declare a gate before its job exists.pnpm lint, pnpm format:check, pnpm typecheck, pnpm build and pnpm test all pass.validate_work_item, projected over this re-plan, raised two advisories against this card. Neither applies, and here is the check rather than the agreement.
subsumption · likely-already-shipped — app/page.tsx, moooon-B-V/motir-marketing#5 (MOTIR-1152), merged 2026-08-28. DOES NOT APPLY — and it fired for a good reason worth recording. The detector matched because this card was re-pinned to motir-marketing in the same act, and the most recent pull request touching that repository's app/ is 1152's. The path is the disproof: 1152 shipped app/page.tsx, and this card's only page deliverable is app/design/page.tsx, which does not exist on origin/main (git ls-tree -r --name-only origin/main lists 52 files in motir-marketing and no app/design/ among them). What 1152 genuinely did ship — the chrome, both package imports, the two @source lines, the theme init script — is not duplicated here; it is this card's SUBSTRATE, which is exactly why 1152 is wired as a blocked_by rather than ignored.reference · advisory — this card names MOTIR-656. DOES NOT APPLY, and it is now the card's own PARENT. It is cited in the re-plan banner to explain WHY the card moved repositories — a historical pointer, not a consumption — and a parent is never a blocked_by. 656 is a container story that produces no output this card reads, and its own deliverables here (the landing, the brand, the SEO root) are all done; the two children of it that are still open, MOTIR-1156 (directory listings) and MOTIR-2267 (trademark clearance), are unrelated to this page and are named here only as the reason a story-level edge would have been wrong.A note on the numbers. This card and its two new siblings were re-numbered 8.8.x → 8.3.x when the set moved from story 8.8 to story 8.3. Sibling cards are therefore cited by CHIP throughout, never by number — a number in prose is exactly what a move like this invalidates.
@source lines and the font loading this page extends. Now a SAME-PARENT sibling, since this card moved into 8.3. · MOTIR-1456 — @motir/brandmotir-marketing app/layout.tsx (the three loaded faces and the -source naming rule) · app/globals.css · app/_components/SiteHeader.tsx · app/sitemap.ts (its hand-off to this card) · lib/copy.ts · .github/workflows/ci.yml@motir/design-system@0.1.0 — npm pack @motir/design-system@0.1.0, shasum ed10ed8db66eb09d34d062b0b4bad878c8509fed; read dist/index.js for the barrel and theme.css for the [data-type] blocks quoted above. Read the PUBLISHED package, not motir-core's packages/design-system/ source — this repository installs the registry copy.done. MOTIR-1061 (the onboarding-flow design) was DROPPED as a blocker by this re-plan: it drew motir-core's onboarding journey and is not a prerequisite of a motir.co marketing page.app/tokens/page.tsx — the internal specimen this does not replace, kept for reference on section composition only (its Sidebar, CommandPalette, chart and IssueTypeIcon sections are motir-core-only and are out of reach here)