@motir/design-system 0.20.0 → 0.21.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.
Files changed (36) hide show
  1. package/README.md +150 -5
  2. package/dist/components/theme/AppearancePickers.js +30 -2
  3. package/dist/components/theme/AppearancePickers.js.map +1 -1
  4. package/dist/components/ui/DatePicker.d.ts +31 -0
  5. package/dist/components/ui/DatePicker.js +442 -0
  6. package/dist/components/ui/DatePicker.js.map +1 -0
  7. package/dist/components/ui/DatePickerFormatContext.d.ts +26 -0
  8. package/dist/components/ui/DatePickerFormatContext.js +58 -0
  9. package/dist/components/ui/DatePickerFormatContext.js.map +1 -0
  10. package/dist/components/ui/datePickerFormat.d.ts +40 -0
  11. package/dist/components/ui/datePickerFormat.js +30 -0
  12. package/dist/components/ui/datePickerFormat.js.map +1 -0
  13. package/dist/contexts/theme-context.js +30 -2
  14. package/dist/contexts/theme-context.js.map +1 -1
  15. package/dist/index.d.ts +3 -0
  16. package/dist/index.js +5 -0
  17. package/dist/mock/index.js +30 -2
  18. package/dist/mock/index.js.map +1 -1
  19. package/dist/mock/renderMock.js +30 -2
  20. package/dist/mock/renderMock.js.map +1 -1
  21. package/dist/specimen/TokensSpecimen.js +2 -2
  22. package/dist/specimen/TokensSpecimen.js.map +1 -1
  23. package/dist/theme/appearance-resolution.js +30 -2
  24. package/dist/theme/appearance-resolution.js.map +1 -1
  25. package/dist/theme/init-script.js +30 -2
  26. package/dist/theme/init-script.js.map +1 -1
  27. package/dist/theme/styles.d.ts +1 -1
  28. package/dist/theme/styles.js +2 -2
  29. package/dist/theme/styles.js.map +1 -1
  30. package/dist/theme/types.js +2 -2
  31. package/dist/theme/types.js.map +1 -1
  32. package/dist/theme/typography.d.ts +46 -3
  33. package/dist/theme/typography.js +28 -0
  34. package/dist/theme/typography.js.map +1 -1
  35. package/package.json +1 -1
  36. package/theme.css +105 -1
@@ -41,6 +41,34 @@ var TYPE_REGISTRY = {
41
41
  tagline: "IBM Plex Mono throughout \u2014 a precise, developer-grade UI.",
42
42
  faces: "IBM Plex Mono headlines + body/UI + meta/code.",
43
43
  designDoc: "docs/typography/mono-technical.md"
44
+ },
45
+ marker: {
46
+ id: "marker",
47
+ name: "Marker",
48
+ tagline: "Hand-lettered marker headlines over a clean sans body \u2014 sketchy, friendly, human.",
49
+ faces: "Caveat marker headlines \xB7 Inter body \xB7 JetBrains Mono meta.",
50
+ designDoc: "docs/typography/marker.md"
51
+ },
52
+ rounded: {
53
+ id: "rounded",
54
+ name: "Rounded",
55
+ tagline: "A soft rounded sans across the whole UI \u2014 friendly and approachable.",
56
+ faces: "Nunito headlines + body/UI \xB7 JetBrains Mono meta.",
57
+ designDoc: "docs/typography/rounded.md"
58
+ },
59
+ slab: {
60
+ id: "slab",
61
+ name: "Slab",
62
+ tagline: "Sturdy slab-serif headlines over a clean sans body \u2014 confident, print-like.",
63
+ faces: "Roboto Slab headlines \xB7 Inter body \xB7 JetBrains Mono meta.",
64
+ designDoc: "docs/typography/slab.md"
65
+ },
66
+ humanist: {
67
+ id: "humanist",
68
+ name: "Humanist",
69
+ tagline: "A warm humanist sans across the whole UI \u2014 open and readable.",
70
+ faces: "Fira Sans headlines + body/UI \xB7 JetBrains Mono meta.",
71
+ designDoc: "docs/typography/humanist.md"
44
72
  }
45
73
  };
46
74
  var TYPE_IDS = Object.keys(TYPE_REGISTRY);
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/theme/typography.ts"],"names":[],"mappings":";AAuFO,IAAM,aAAA,GAAgB;AAAA,EAC3B,KAAA,EAAO;AAAA,IACL,EAAA,EAAI,OAAA;AAAA,IACJ,IAAA,EAAM,OAAA;AAAA,IACN,OAAA,EAAS,4EAAA;AAAA,IACT,KAAA,EAAO,oEAAA;AAAA,IACP,SAAA,EAAW;AAAA,GACb;AAAA,EACA,YAAA,EAAc;AAAA,IACZ,EAAA,EAAI,YAAA;AAAA,IACJ,IAAA,EAAM,YAAA;AAAA,IACN,OAAA,EAAS,qEAAA;AAAA,IACT,KAAA,EAAO,kDAAA;AAAA,IACP,SAAA,EAAW;AAAA,GACb;AAAA,EACA,YAAA,EAAc;AAAA,IACZ,EAAA,EAAI,YAAA;AAAA,IACJ,IAAA,EAAM,YAAA;AAAA,IACN,OAAA,EAAS,wEAAA;AAAA,IACT,KAAA,EAAO,4CAAA;AAAA,IACP,SAAA,EAAW;AAAA,GACb;AAAA,EACA,OAAA,EAAS;AAAA,IACP,EAAA,EAAI,SAAA;AAAA,IACJ,IAAA,EAAM,SAAA;AAAA,IACN,OAAA,EAAS,iFAAA;AAAA,IACT,KAAA,EAAO,6DAAA;AAAA,IACP,SAAA,EAAW;AAAA,GACb;AAAA,EACA,SAAA,EAAW;AAAA,IACT,EAAA,EAAI,WAAA;AAAA,IACJ,IAAA,EAAM,WAAA;AAAA,IACN,OAAA,EAAS,gFAAA;AAAA,IACT,KAAA,EAAO,sEAAA;AAAA,IACP,SAAA,EAAW;AAAA,GACb;AAAA,EACA,gBAAA,EAAkB;AAAA,IAChB,EAAA,EAAI,gBAAA;AAAA,IACJ,IAAA,EAAM,gBAAA;AAAA,IACN,OAAA,EAAS,gEAAA;AAAA,IACT,KAAA,EAAO,gDAAA;AAAA,IACP,SAAA,EAAW;AAAA;AAEf;AAMO,IAAM,QAAA,GAAW,MAAA,CAAO,IAAA,CAAK,aAAa;AAM1C,IAAM,eAAA,GAA0B;AAGhC,SAAS,SAAS,KAAA,EAAiC;AACxD,EAAA,OAAO,OAAO,UAAU,QAAA,IAAY,MAAA,CAAO,UAAU,cAAA,CAAe,IAAA,CAAK,eAAe,KAAK,CAAA;AAC/F;AAGO,SAAS,YAAY,KAAA,EAAsC;AAChE,EAAA,OAAO,aAAA,CAAc,QAAA,CAAS,KAAK,CAAA,GAAI,QAAQ,eAAe,CAAA;AAChE","file":"typography.js","sourcesContent":["/**\n * The Motir TYPOGRAPHY LIBRARY — the named-pairing registry (Subtask 7.3.53).\n *\n * A \"type pairing\" is a named TYPOGRAPHY scheme the whole UI can swap to at\n * runtime — the THIRD design axis, completing the token decomposition\n * (Colour `data-palette` · Type `data-type` · Shape/feel `data-style`). It is\n * deliberately INDEPENDENT of the other two: a pairing decides which TYPEFACES\n * the product wears (the headline / body / mono role mapping); it never touches\n * a hue (palette axis) or a radius (style axis).\n *\n * ── The three-axis runtime contract ─────────────────────────────────────\n * data-type=\"<type-id>\" — THIS axis. A `[data-type='<id>']` block in\n * app/globals.css re-points the `--font-*`\n * role tokens (sans / serif / mono) — and ONLY\n * font tokens, never colour or shape.\n * data-palette=\"<palette-id>\" — the INDEPENDENT colour axis (`--el-*`).\n * data-style=\"<style-id>\" — the INDEPENDENT shape/feel axis.\n *\n * The shared `--font-size-*` SCALE stays common across pairings — sizes are\n * layout, not brand; a pairing remaps the FACES, not the type scale.\n *\n * ── A style declares a DEFAULT pairing (overridable) ────────────────────\n * Typography used to be BUNDLED into the style axis: `swiss-minimal-flat`,\n * `neo-brutalism` and `cybercore-y2k` each re-pointed `--font-serif` inside\n * their own `[data-style]` block. That is now a disjointness violation (two\n * axes setting `--font-*`). The fix: each style declares a `defaultTypeId`\n * (see ./styles.ts) — the pairing applied when the user has NOT pinned an\n * explicit type — and the per-style font overrides move here, as pairings.\n * So out-of-the-box looks are UNCHANGED; the new freedom is that type is now\n * independently overridable (e.g. Swiss shape + a serif pairing).\n *\n * ── v1 — the base faces only (no new payload) ───────────────────────────\n * v1 registered three pairings built from the THREE already-loaded next/font\n * faces (Inter · Source Serif 4 · JetBrains Mono) — so they add ZERO font\n * payload and carry NO new-typeface design decision:\n * - `motir` — the base: editorial serif headlines over a sans body.\n * - `motir-sans` — all-sans (Inter headlines); reproduces the Swiss look.\n * - `motir-mono` — mono THROUGHOUT (headlines + body/UI); a code-native UI.\n * `motir` is the base — like the `motir` palette / `warm-editorial` style it\n * needs NO `[data-type]` override block; the base `--font-*` tokens already are\n * it.\n *\n * ── New-typeface pairings (Grotesk / Editorial / Mono-Technical, 7.3.54–56) ──\n * Each adds a real type-design decision and loads its own next/font face(s),\n * re-pointing a role in its own `[data-type]` block:\n * - `grotesk` (7.3.54) — Space Grotesk THROUGHOUT (headlines + body/UI).\n * - `editorial` (7.3.55) — Fraunces display-serif headlines over the Inter\n * body; a magazine, considered pairing (one new face — Inter + JetBrains reused).\n * Body STAYS Inter — a display serif is unreadable as UI, so this pairing\n * re-types headlines only (the legibility exception to whole-UI re-typing).\n * - `mono-technical` (7.3.56) — IBM Plex Mono THROUGHOUT (headlines + body/UI +\n * meta); a precise, developer-grade UI (one new face — Inter reused for nothing\n * now, kept as the ultimate fallback).\n *\n * ── Whole-UI re-typing (Yue, 2026-06-19) ────────────────────────────────\n * A type pairing re-types the WHOLE app, chrome included (nav, header, buttons),\n * not just headlines: a pairing whose signature face reads as a UI sans/mono\n * (`grotesk`, `motir-mono`, `mono-technical`) ALSO re-points the body/UI role\n * (`--font-sans`) in its `[data-type]` block. The display-serif `editorial` and\n * the all-Inter `motir` / `motir-sans` keep the Inter body for legibility.\n * Each later \"Type: …\" subtask ADDS its entry here + a `[data-type]` block (its\n * face loaded in `app/layout.tsx`) + its `docs/typography/<id>.md`.\n */\n\n/** A registered, runtime-selectable type pairing. */\nexport interface TypographyDefinition {\n /** The `data-type` attribute value. Stable; used as the localStorage value. */\n id: string;\n /** Display name shown in the gallery / `/tokens` toggle. */\n name: string;\n /** One-line characterization of the typographic feel. */\n tagline: string;\n /** The headline / body / mono face mapping (credit / what it loads). */\n faces: string;\n /**\n * Repo-relative path to this pairing's doc — the type-role reference a later\n * getdesign-style swap or the `/tokens` composer reads. Every registered\n * pairing maps to exactly one.\n */\n designDoc: string;\n}\n\n/**\n * The registry. Insertion order is the gallery order. Each non-base `id`\n * matches a `[data-type='<id>']` block in app/globals.css (`motir` is the base,\n * so its block is the Tier-0 `--font-*` defaults — no override block needed).\n */\nexport const TYPE_REGISTRY = {\n motir: {\n id: 'motir',\n name: 'Motir',\n tagline: 'Editorial serif headlines over a clean sans body — the house pairing.',\n faces: 'Source Serif 4 headlines · Inter body · JetBrains Mono meta.',\n designDoc: 'docs/typography/motir.md',\n },\n 'motir-sans': {\n id: 'motir-sans',\n name: 'Motir Sans',\n tagline: 'All-sans — Inter for headlines and body; structural, no serif.',\n faces: 'Inter headlines + body · JetBrains Mono meta.',\n designDoc: 'docs/typography/motir-sans.md',\n },\n 'motir-mono': {\n id: 'motir-mono',\n name: 'Motir Mono',\n tagline: 'Monospace throughout — a code-native UI, headlines, body and all.',\n faces: 'JetBrains Mono headlines + body/UI + meta.',\n designDoc: 'docs/typography/motir-mono.md',\n },\n grotesk: {\n id: 'grotesk',\n name: 'Grotesk',\n tagline: 'Geometric neo-grotesque across the whole UI — tight, confident, product-y.',\n faces: 'Space Grotesk headlines + body/UI · JetBrains Mono meta.',\n designDoc: 'docs/typography/grotesk.md',\n },\n editorial: {\n id: 'editorial',\n name: 'Editorial',\n tagline: 'A characterful display serif over a humanist sans — magazine, considered.',\n faces: 'Fraunces display headlines · Inter body · JetBrains Mono meta.',\n designDoc: 'docs/typography/editorial.md',\n },\n 'mono-technical': {\n id: 'mono-technical',\n name: 'Mono-Technical',\n tagline: 'IBM Plex Mono throughout — a precise, developer-grade UI.',\n faces: 'IBM Plex Mono headlines + body/UI + meta/code.',\n designDoc: 'docs/typography/mono-technical.md',\n },\n} satisfies Record<string, TypographyDefinition>;\n\n/** The id of every registered pairing — `data-type` value space. */\nexport type TypeId = keyof typeof TYPE_REGISTRY;\n\n/** All registered pairing ids, in gallery order. */\nexport const TYPE_IDS = Object.keys(TYPE_REGISTRY) as TypeId[];\n\n/**\n * The default pairing a fresh install / unset preference resolves to when the\n * active style declares none. Motir is the house pairing and the Tier-0 base.\n */\nexport const DEFAULT_TYPE_ID: TypeId = 'motir';\n\n/** Narrowing guard — is an arbitrary string a registered pairing id? */\nexport function isTypeId(value: unknown): value is TypeId {\n return typeof value === 'string' && Object.prototype.hasOwnProperty.call(TYPE_REGISTRY, value);\n}\n\n/** Resolve a (possibly stale / unknown) value to a valid pairing definition. */\nexport function resolveType(value: unknown): TypographyDefinition {\n return TYPE_REGISTRY[isTypeId(value) ? value : DEFAULT_TYPE_ID];\n}\n"]}
1
+ {"version":3,"sources":["../../src/theme/typography.ts"],"names":[],"mappings":";AAsGO,IAAM,aAAA,GAAgB;AAAA,EAC3B,KAAA,EAAO;AAAA,IACL,EAAA,EAAI,OAAA;AAAA,IACJ,IAAA,EAAM,OAAA;AAAA,IACN,OAAA,EAAS,4EAAA;AAAA,IACT,KAAA,EAAO,oEAAA;AAAA,IACP,SAAA,EAAW;AAAA,GACb;AAAA,EACA,YAAA,EAAc;AAAA,IACZ,EAAA,EAAI,YAAA;AAAA,IACJ,IAAA,EAAM,YAAA;AAAA,IACN,OAAA,EAAS,qEAAA;AAAA,IACT,KAAA,EAAO,kDAAA;AAAA,IACP,SAAA,EAAW;AAAA,GACb;AAAA,EACA,YAAA,EAAc;AAAA,IACZ,EAAA,EAAI,YAAA;AAAA,IACJ,IAAA,EAAM,YAAA;AAAA,IACN,OAAA,EAAS,wEAAA;AAAA,IACT,KAAA,EAAO,4CAAA;AAAA,IACP,SAAA,EAAW;AAAA,GACb;AAAA,EACA,OAAA,EAAS;AAAA,IACP,EAAA,EAAI,SAAA;AAAA,IACJ,IAAA,EAAM,SAAA;AAAA,IACN,OAAA,EAAS,iFAAA;AAAA,IACT,KAAA,EAAO,6DAAA;AAAA,IACP,SAAA,EAAW;AAAA,GACb;AAAA,EACA,SAAA,EAAW;AAAA,IACT,EAAA,EAAI,WAAA;AAAA,IACJ,IAAA,EAAM,WAAA;AAAA,IACN,OAAA,EAAS,gFAAA;AAAA,IACT,KAAA,EAAO,sEAAA;AAAA,IACP,SAAA,EAAW;AAAA,GACb;AAAA,EACA,gBAAA,EAAkB;AAAA,IAChB,EAAA,EAAI,gBAAA;AAAA,IACJ,IAAA,EAAM,gBAAA;AAAA,IACN,OAAA,EAAS,gEAAA;AAAA,IACT,KAAA,EAAO,gDAAA;AAAA,IACP,SAAA,EAAW;AAAA,GACb;AAAA,EACA,MAAA,EAAQ;AAAA,IACN,EAAA,EAAI,QAAA;AAAA,IACJ,IAAA,EAAM,QAAA;AAAA,IACN,OAAA,EAAS,wFAAA;AAAA,IACT,KAAA,EAAO,mEAAA;AAAA,IACP,SAAA,EAAW;AAAA,GACb;AAAA,EACA,OAAA,EAAS;AAAA,IACP,EAAA,EAAI,SAAA;AAAA,IACJ,IAAA,EAAM,SAAA;AAAA,IACN,OAAA,EAAS,2EAAA;AAAA,IACT,KAAA,EAAO,sDAAA;AAAA,IACP,SAAA,EAAW;AAAA,GACb;AAAA,EACA,IAAA,EAAM;AAAA,IACJ,EAAA,EAAI,MAAA;AAAA,IACJ,IAAA,EAAM,MAAA;AAAA,IACN,OAAA,EAAS,kFAAA;AAAA,IACT,KAAA,EAAO,iEAAA;AAAA,IACP,SAAA,EAAW;AAAA,GACb;AAAA,EACA,QAAA,EAAU;AAAA,IACR,EAAA,EAAI,UAAA;AAAA,IACJ,IAAA,EAAM,UAAA;AAAA,IACN,OAAA,EAAS,oEAAA;AAAA,IACT,KAAA,EAAO,yDAAA;AAAA,IACP,SAAA,EAAW;AAAA;AAEf;AAMO,IAAM,QAAA,GAAW,MAAA,CAAO,IAAA,CAAK,aAAa;AAM1C,IAAM,eAAA,GAA0B;AAGhC,SAAS,SAAS,KAAA,EAAiC;AACxD,EAAA,OAAO,OAAO,UAAU,QAAA,IAAY,MAAA,CAAO,UAAU,cAAA,CAAe,IAAA,CAAK,eAAe,KAAK,CAAA;AAC/F;AAGO,SAAS,YAAY,KAAA,EAAsC;AAChE,EAAA,OAAO,aAAA,CAAc,QAAA,CAAS,KAAK,CAAA,GAAI,QAAQ,eAAe,CAAA;AAChE","file":"typography.js","sourcesContent":["/**\n * The Motir TYPOGRAPHY LIBRARY — the named-pairing registry (Subtask 7.3.53).\n *\n * A \"type pairing\" is a named TYPOGRAPHY scheme the whole UI can swap to at\n * runtime — the THIRD design axis, completing the token decomposition\n * (Colour `data-palette` · Type `data-type` · Shape/feel `data-style`). It is\n * deliberately INDEPENDENT of the other two: a pairing decides which TYPEFACES\n * the product wears (the headline / body / mono role mapping); it never touches\n * a hue (palette axis) or a radius (style axis).\n *\n * ── The three-axis runtime contract ─────────────────────────────────────\n * data-type=\"<type-id>\" — THIS axis. A `[data-type='<id>']` block in\n * app/globals.css re-points the `--font-*`\n * role tokens (sans / serif / mono) — and ONLY\n * font tokens, never colour or shape.\n * data-palette=\"<palette-id>\" — the INDEPENDENT colour axis (`--el-*`).\n * data-style=\"<style-id>\" — the INDEPENDENT shape/feel axis.\n *\n * The shared `--font-size-*` SCALE stays common across pairings — sizes are\n * layout, not brand; a pairing remaps the FACES, not the type scale.\n *\n * ── A style declares a DEFAULT pairing (overridable) ────────────────────\n * Typography used to be BUNDLED into the style axis: `swiss-minimal-flat`,\n * `neo-brutalism` and `cybercore-y2k` each re-pointed `--font-serif` inside\n * their own `[data-style]` block. That is now a disjointness violation (two\n * axes setting `--font-*`). The fix: each style declares a `defaultTypeId`\n * (see ./styles.ts) — the pairing applied when the user has NOT pinned an\n * explicit type — and the per-style font overrides move here, as pairings.\n * So out-of-the-box looks are UNCHANGED; the new freedom is that type is now\n * independently overridable (e.g. Swiss shape + a serif pairing).\n *\n * ── v1 — the base faces only (no new payload) ───────────────────────────\n * v1 registered three pairings built from the THREE already-loaded next/font\n * faces (Inter · Source Serif 4 · JetBrains Mono) — so they add ZERO font\n * payload and carry NO new-typeface design decision:\n * - `motir` — the base: editorial serif headlines over a sans body.\n * - `motir-sans` — all-sans (Inter headlines); reproduces the Swiss look.\n * - `motir-mono` — mono THROUGHOUT (headlines + body/UI); a code-native UI.\n * `motir` is the base — like the `motir` palette / `warm-editorial` style it\n * needs NO `[data-type]` override block; the base `--font-*` tokens already are\n * it.\n *\n * ── New-typeface pairings (Grotesk / Editorial / Mono-Technical, 7.3.54–56) ──\n * Each adds a real type-design decision and loads its own next/font face(s),\n * re-pointing a role in its own `[data-type]` block:\n * - `grotesk` (7.3.54) — Space Grotesk THROUGHOUT (headlines + body/UI).\n * - `editorial` (7.3.55) — Fraunces display-serif headlines over the Inter\n * body; a magazine, considered pairing (one new face — Inter + JetBrains reused).\n * Body STAYS Inter — a display serif is unreadable as UI, so this pairing\n * re-types headlines only (the legibility exception to whole-UI re-typing).\n * - `mono-technical` (7.3.56) — IBM Plex Mono THROUGHOUT (headlines + body/UI +\n * meta); a precise, developer-grade UI (one new face — Inter reused for nothing\n * now, kept as the ultimate fallback).\n *\n * ── New-typeface pairings (Story MOTIR-10548) ─────────────────────────────\n * - `marker` (MOTIR-10553) — Caveat hand-lettered marker headlines over the\n * Inter body; Hand-Drawn / Indie's default. Display-only, like `editorial`: a\n * marker hand is unreadable as UI text, so only the headline role is re-typed.\n * - `rounded` (MOTIR-10554) — Nunito THROUGHOUT (headlines + body/UI); a\n * soft, friendly rounded sans that reads cleanly as UI text, so it re-types\n * the whole UI like `grotesk`.\n * - `slab` (MOTIR-10555) — Roboto Slab headlines over the Inter body;\n * sturdy and print-like. Display-only, like `editorial`: heavy slab serifs\n * crowd UI text, so only the headline role is re-typed.\n * - `humanist` (MOTIR-10556) — Fira Sans THROUGHOUT (headlines + body/UI); a\n * warm humanist sans drawn as a screen UI face, so it re-types the whole UI\n * like `grotesk`.\n *\n * ── Whole-UI re-typing (Yue, 2026-06-19) ────────────────────────────────\n * A type pairing re-types the WHOLE app, chrome included (nav, header, buttons),\n * not just headlines: a pairing whose signature face reads as a UI sans/mono\n * (`grotesk`, `motir-mono`, `mono-technical`, `rounded`, `humanist`) ALSO\n * re-points the body/UI role (`--font-sans`) in its `[data-type]` block. The\n * display-serif `editorial` and `slab`, the display-only `marker` and the\n * all-Inter `motir` / `motir-sans` keep the Inter body for legibility.\n * Each later \"Type: …\" subtask ADDS its entry here + a `[data-type]` block (its\n * face loaded in `app/layout.tsx`) + its `docs/typography/<id>.md`.\n */\n\n/** A registered, runtime-selectable type pairing. */\nexport interface TypographyDefinition {\n /** The `data-type` attribute value. Stable; used as the localStorage value. */\n id: string;\n /** Display name shown in the gallery / `/tokens` toggle. */\n name: string;\n /** One-line characterization of the typographic feel. */\n tagline: string;\n /** The headline / body / mono face mapping (credit / what it loads). */\n faces: string;\n /**\n * Repo-relative path to this pairing's doc — the type-role reference a later\n * getdesign-style swap or the `/tokens` composer reads. Every registered\n * pairing maps to exactly one.\n */\n designDoc: string;\n}\n\n/**\n * The registry. Insertion order is the gallery order. Each non-base `id`\n * matches a `[data-type='<id>']` block in app/globals.css (`motir` is the base,\n * so its block is the Tier-0 `--font-*` defaults — no override block needed).\n */\nexport const TYPE_REGISTRY = {\n motir: {\n id: 'motir',\n name: 'Motir',\n tagline: 'Editorial serif headlines over a clean sans body — the house pairing.',\n faces: 'Source Serif 4 headlines · Inter body · JetBrains Mono meta.',\n designDoc: 'docs/typography/motir.md',\n },\n 'motir-sans': {\n id: 'motir-sans',\n name: 'Motir Sans',\n tagline: 'All-sans — Inter for headlines and body; structural, no serif.',\n faces: 'Inter headlines + body · JetBrains Mono meta.',\n designDoc: 'docs/typography/motir-sans.md',\n },\n 'motir-mono': {\n id: 'motir-mono',\n name: 'Motir Mono',\n tagline: 'Monospace throughout — a code-native UI, headlines, body and all.',\n faces: 'JetBrains Mono headlines + body/UI + meta.',\n designDoc: 'docs/typography/motir-mono.md',\n },\n grotesk: {\n id: 'grotesk',\n name: 'Grotesk',\n tagline: 'Geometric neo-grotesque across the whole UI — tight, confident, product-y.',\n faces: 'Space Grotesk headlines + body/UI · JetBrains Mono meta.',\n designDoc: 'docs/typography/grotesk.md',\n },\n editorial: {\n id: 'editorial',\n name: 'Editorial',\n tagline: 'A characterful display serif over a humanist sans — magazine, considered.',\n faces: 'Fraunces display headlines · Inter body · JetBrains Mono meta.',\n designDoc: 'docs/typography/editorial.md',\n },\n 'mono-technical': {\n id: 'mono-technical',\n name: 'Mono-Technical',\n tagline: 'IBM Plex Mono throughout — a precise, developer-grade UI.',\n faces: 'IBM Plex Mono headlines + body/UI + meta/code.',\n designDoc: 'docs/typography/mono-technical.md',\n },\n marker: {\n id: 'marker',\n name: 'Marker',\n tagline: 'Hand-lettered marker headlines over a clean sans body — sketchy, friendly, human.',\n faces: 'Caveat marker headlines · Inter body · JetBrains Mono meta.',\n designDoc: 'docs/typography/marker.md',\n },\n rounded: {\n id: 'rounded',\n name: 'Rounded',\n tagline: 'A soft rounded sans across the whole UI — friendly and approachable.',\n faces: 'Nunito headlines + body/UI · JetBrains Mono meta.',\n designDoc: 'docs/typography/rounded.md',\n },\n slab: {\n id: 'slab',\n name: 'Slab',\n tagline: 'Sturdy slab-serif headlines over a clean sans body — confident, print-like.',\n faces: 'Roboto Slab headlines · Inter body · JetBrains Mono meta.',\n designDoc: 'docs/typography/slab.md',\n },\n humanist: {\n id: 'humanist',\n name: 'Humanist',\n tagline: 'A warm humanist sans across the whole UI — open and readable.',\n faces: 'Fira Sans headlines + body/UI · JetBrains Mono meta.',\n designDoc: 'docs/typography/humanist.md',\n },\n} satisfies Record<string, TypographyDefinition>;\n\n/** The id of every registered pairing — `data-type` value space. */\nexport type TypeId = keyof typeof TYPE_REGISTRY;\n\n/** All registered pairing ids, in gallery order. */\nexport const TYPE_IDS = Object.keys(TYPE_REGISTRY) as TypeId[];\n\n/**\n * The default pairing a fresh install / unset preference resolves to when the\n * active style declares none. Motir is the house pairing and the Tier-0 base.\n */\nexport const DEFAULT_TYPE_ID: TypeId = 'motir';\n\n/** Narrowing guard — is an arbitrary string a registered pairing id? */\nexport function isTypeId(value: unknown): value is TypeId {\n return typeof value === 'string' && Object.prototype.hasOwnProperty.call(TYPE_REGISTRY, value);\n}\n\n/** Resolve a (possibly stale / unknown) value to a valid pairing definition. */\nexport function resolveType(value: unknown): TypographyDefinition {\n return TYPE_REGISTRY[isTypeId(value) ? value : DEFAULT_TYPE_ID];\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@motir/design-system",
3
- "version": "0.20.0",
3
+ "version": "0.21.0",
4
4
  "description": "Motir's 3-axis design system (colour · style · type): distributable token CSS, the axis registries, the theme-apply API, and framework-agnostic React primitives. Shared by motir-core and planner-scaffolded products.",
5
5
  "license": "GPL-3.0-only",
6
6
  "repository": {
package/theme.css CHANGED
@@ -189,6 +189,12 @@
189
189
  --shadow-elevated: 0 8px 24px rgba(15, 15, 15, 0.12);
190
190
  --shadow-modal: 0 16px 48px -8px rgba(15, 15, 15, 0.16);
191
191
  --shadow-hero-mockup: 0 24px 48px -8px rgba(15, 15, 15, 0.2);
192
+ /* How far the SOLID edge of `--shadow-elevated` falls below the box that casts
193
+ it. A soft, blurred lift has none (0); a hard-offset style sets its Y offset.
194
+ A control hung over other content (the canvas card's next-action button,
195
+ MOTIR-10631) lifts itself by this much more, so its shadow clears what it
196
+ floats above as its box does. */
197
+ --spacing-shadow-elevated-drop: 0px;
192
198
 
193
199
  /* ── Spacing ────────────────────────────────────────────────────── */
194
200
  --spacing-xxs: 4px;
@@ -481,6 +487,7 @@
481
487
  --shadow-subtle: 0 1px 2px rgba(15, 15, 15, 0.04);
482
488
  --shadow-card: 0 4px 12px rgba(15, 15, 15, 0.08);
483
489
  --shadow-elevated: 0 8px 24px rgba(15, 15, 15, 0.12);
490
+ --spacing-shadow-elevated-drop: 0px;
484
491
  --shadow-modal: 0 16px 48px -8px rgba(15, 15, 15, 0.16);
485
492
  --shadow-hero-mockup: 0 24px 48px -8px rgba(15, 15, 15, 0.2);
486
493
  --spacing-xxs: 4px;
@@ -897,6 +904,7 @@
897
904
  --shadow-subtle: 2px 2px 0 0 rgba(15, 15, 15, 1);
898
905
  --shadow-card: 4px 4px 0 0 rgba(15, 15, 15, 1);
899
906
  --shadow-elevated: 6px 6px 0 0 rgba(15, 15, 15, 1);
907
+ --spacing-shadow-elevated-drop: 6px; /* the Y offset of --shadow-elevated above */
900
908
  --shadow-modal: 8px 8px 0 0 rgba(15, 15, 15, 1);
901
909
  --shadow-hero-mockup: 12px 12px 0 0 rgba(15, 15, 15, 1);
902
910
 
@@ -1994,7 +2002,7 @@
1994
2002
  hover/press bounce. Colour stays the palette axis: the token block sets no
1995
2003
  `--color-` / `--el-` colour token (AA preserved), and the rough-border rule
1996
2004
  takes its ink from the palette (var(--el-border-strong)). Out-of-the-box type
1997
- is the characterful Editorial (Fraunces) pairing via `defaultTypeId`. See
2005
+ is the hand-lettered Marker (Caveat) pairing via `defaultTypeId`. See
1998
2006
  docs/styles/hand-drawn-indie.md. */
1999
2007
  [data-style='hand-drawn-indie'] {
2000
2008
  /* Silhouette — WONKY hand-drawn corners. The slash splits horizontal /
@@ -6224,6 +6232,102 @@
6224
6232
  --font-sans-tail: monospace;
6225
6233
  }
6226
6234
 
6235
+ [data-type='marker'] {
6236
+ /* Marker (MOTIR-10553) — hand-lettered marker headlines over the Inter body.
6237
+ Adds one new face: Caveat, loaded in app/fonts.ts as --font-marker-source.
6238
+ Re-point the headline (serif) role at it; body (Inter, --font-sans) and meta
6239
+ (JetBrains, --font-mono) keep the base roles. Display-only, like editorial:
6240
+ a marker hand is unreadable as UI or body text, so only headlines re-type.
6241
+ The pairing chain names no generic keyword (the FONT SETS rule below slots
6242
+ the CJK face between it and the `cursive` tail). ONLY --font-* role tokens
6243
+ here (the disjointness guard): no colour (--el/--color) or shape
6244
+ (--radius/--spacing/--shadow) token. */
6245
+ --font-serif-pairing: var(--font-marker-source), 'Caveat';
6246
+ --font-serif-tail: cursive;
6247
+ /* Re-asserted at the BASE value, not omitted (MOTIR-3933). An omitted role
6248
+ inherits the ANCESTOR's, which is invisible on `<html>` and wrong in a
6249
+ nested scope: this pairing under a mono ancestor rendered mono. Unlike the
6250
+ colour axis there is no `[data-appearance-scope]` layer to fall back
6251
+ through — `--font-*` are role tokens, not `--el-*` — so every
6252
+ `[data-type]` block must be TOTAL over the three roles. */
6253
+ --font-sans-pairing: var(--font-sans-source, 'Segoe UI'), 'Segoe UI', Roboto;
6254
+ --font-sans-tail: -apple-system, BlinkMacSystemFont, sans-serif;
6255
+ --font-mono-pairing: var(--font-mono-source, 'SF Mono'), 'SF Mono', Menlo;
6256
+ --font-mono-tail: monospace;
6257
+ }
6258
+
6259
+ [data-type='rounded'] {
6260
+ /* Rounded (MOTIR-10554) — a soft rounded sans across headlines AND body/UI.
6261
+ Re-point BOTH the headline (serif) role AND the body/UI (sans) role at
6262
+ Nunito (loaded in app/fonts.ts as --font-rounded-source), so the WHOLE app
6263
+ (nav, header, buttons, content) re-types — Nunito reads cleanly as a UI sans
6264
+ (Yue, 2026-06-19: the type axis must re-type the whole UI, chrome included).
6265
+ Meta stays JetBrains Mono (--font-mono). The pairing chains name no generic
6266
+ keyword, so the FONT SETS rule below slots the CJK face behind Nunito. ONLY
6267
+ font tokens here (the disjointness guard): no colour (--el / --color) or
6268
+ shape token. */
6269
+ --font-serif-pairing: var(--font-rounded-source), 'Nunito';
6270
+ --font-serif-tail: ui-sans-serif, system-ui, sans-serif;
6271
+ --font-sans-pairing: var(--font-rounded-source), 'Nunito';
6272
+ --font-sans-tail: ui-sans-serif, system-ui, sans-serif;
6273
+ /* Re-asserted at the BASE value, not omitted (MOTIR-3933). An omitted role
6274
+ inherits the ANCESTOR's, which is invisible on `<html>` and wrong in a
6275
+ nested scope: this pairing under a mono ancestor rendered mono. Unlike the
6276
+ colour axis there is no `[data-appearance-scope]` layer to fall back
6277
+ through — `--font-*` are role tokens, not `--el-*` — so every
6278
+ `[data-type]` block must be TOTAL over the three roles. */
6279
+ --font-mono-pairing: var(--font-mono-source, 'SF Mono'), 'SF Mono', Menlo;
6280
+ --font-mono-tail: monospace;
6281
+ }
6282
+
6283
+ [data-type='slab'] {
6284
+ /* Slab (MOTIR-10555) — sturdy slab-serif headlines over the Inter body. Adds
6285
+ one new face: Roboto Slab, loaded in app/fonts.ts as --font-slab-source.
6286
+ Re-point the headline (serif) role at it; body (Inter, --font-sans) and meta
6287
+ (JetBrains, --font-mono) keep the base roles. Display-only, like editorial:
6288
+ heavy rectangular serifs crowd dense UI text at 12–14px, so only headlines
6289
+ re-type. The pairing chain names no generic keyword (the FONT SETS rule
6290
+ below slots the CJK face between it and the `serif` tail). ONLY --font-*
6291
+ role tokens here (the disjointness guard): no colour (--el/--color) or shape
6292
+ (--radius/--spacing/--shadow) token. */
6293
+ --font-serif-pairing: var(--font-slab-source), 'Roboto Slab', Rockwell;
6294
+ --font-serif-tail: serif;
6295
+ /* Re-asserted at the BASE value, not omitted (MOTIR-3933). An omitted role
6296
+ inherits the ANCESTOR's, which is invisible on `<html>` and wrong in a
6297
+ nested scope: this pairing under a mono ancestor rendered mono. Unlike the
6298
+ colour axis there is no `[data-appearance-scope]` layer to fall back
6299
+ through — `--font-*` are role tokens, not `--el-*` — so every
6300
+ `[data-type]` block must be TOTAL over the three roles. */
6301
+ --font-sans-pairing: var(--font-sans-source, 'Segoe UI'), 'Segoe UI', Roboto;
6302
+ --font-sans-tail: -apple-system, BlinkMacSystemFont, sans-serif;
6303
+ --font-mono-pairing: var(--font-mono-source, 'SF Mono'), 'SF Mono', Menlo;
6304
+ --font-mono-tail: monospace;
6305
+ }
6306
+
6307
+ [data-type='humanist'] {
6308
+ /* Humanist (MOTIR-10556) — a warm humanist sans across headlines AND body/UI.
6309
+ Re-point BOTH the headline (serif) role AND the body/UI (sans) role at Fira
6310
+ Sans (loaded in app/fonts.ts as --font-humanist-source), so the WHOLE app
6311
+ (nav, header, buttons, content) re-types — Fira Sans was drawn as a screen UI
6312
+ face (Yue, 2026-06-19: the type axis must re-type the whole UI, chrome
6313
+ included). Meta stays JetBrains Mono (--font-mono). The pairing chains name
6314
+ no generic keyword, so the FONT SETS rule below slots the CJK face behind
6315
+ Fira Sans. ONLY font tokens here (the disjointness guard): no colour
6316
+ (--el / --color) or shape token. */
6317
+ --font-serif-pairing: var(--font-humanist-source), 'Fira Sans';
6318
+ --font-serif-tail: ui-sans-serif, system-ui, sans-serif;
6319
+ --font-sans-pairing: var(--font-humanist-source), 'Fira Sans';
6320
+ --font-sans-tail: ui-sans-serif, system-ui, sans-serif;
6321
+ /* Re-asserted at the BASE value, not omitted (MOTIR-3933). An omitted role
6322
+ inherits the ANCESTOR's, which is invisible on `<html>` and wrong in a
6323
+ nested scope: this pairing under a mono ancestor rendered mono. Unlike the
6324
+ colour axis there is no `[data-appearance-scope]` layer to fall back
6325
+ through — `--font-*` are role tokens, not `--el-*` — so every
6326
+ `[data-type]` block must be TOTAL over the three roles. */
6327
+ --font-mono-pairing: var(--font-mono-source, 'SF Mono'), 'SF Mono', Menlo;
6328
+ --font-mono-tail: monospace;
6329
+ }
6330
+
6227
6331
  /* ═══════════════════════════════════════════════════════════════════════
6228
6332
  FONT SETS — the script face behind the pairing (Story MOTIR-7733 · MOTIR-7845)
6229
6333
  A Type pairing (the [data-type] blocks above) decides each role's LATIN