@motir/design-system 0.1.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 (107) hide show
  1. package/README.md +126 -0
  2. package/dist/appearance.d.ts +47 -0
  3. package/dist/appearance.js +3 -0
  4. package/dist/appearance.js.map +1 -0
  5. package/dist/components/theme/AppearancePickers.d.ts +97 -0
  6. package/dist/components/theme/AppearancePickers.js +542 -0
  7. package/dist/components/theme/AppearancePickers.js.map +1 -0
  8. package/dist/components/theme/HandDrawnFilter.d.ts +23 -0
  9. package/dist/components/theme/HandDrawnFilter.js +41 -0
  10. package/dist/components/theme/HandDrawnFilter.js.map +1 -0
  11. package/dist/components/theme/ImmersiveTilt.d.ts +3 -0
  12. package/dist/components/theme/ImmersiveTilt.js +113 -0
  13. package/dist/components/theme/ImmersiveTilt.js.map +1 -0
  14. package/dist/components/theme/StyleVignette.d.ts +60 -0
  15. package/dist/components/theme/StyleVignette.js +382 -0
  16. package/dist/components/theme/StyleVignette.js.map +1 -0
  17. package/dist/components/ui/Button.d.ts +32 -0
  18. package/dist/components/ui/Button.js +92 -0
  19. package/dist/components/ui/Button.js.map +1 -0
  20. package/dist/components/ui/Card.d.ts +33 -0
  21. package/dist/components/ui/Card.js +64 -0
  22. package/dist/components/ui/Card.js.map +1 -0
  23. package/dist/components/ui/ColorSwatchPicker.d.ts +19 -0
  24. package/dist/components/ui/ColorSwatchPicker.js +71 -0
  25. package/dist/components/ui/ColorSwatchPicker.js.map +1 -0
  26. package/dist/components/ui/Combobox.d.ts +84 -0
  27. package/dist/components/ui/Combobox.js +374 -0
  28. package/dist/components/ui/Combobox.js.map +1 -0
  29. package/dist/components/ui/EmptyState.d.ts +38 -0
  30. package/dist/components/ui/EmptyState.js +73 -0
  31. package/dist/components/ui/EmptyState.js.map +1 -0
  32. package/dist/components/ui/ErrorState.d.ts +43 -0
  33. package/dist/components/ui/ErrorState.js +169 -0
  34. package/dist/components/ui/ErrorState.js.map +1 -0
  35. package/dist/components/ui/FormField.d.ts +31 -0
  36. package/dist/components/ui/FormField.js +43 -0
  37. package/dist/components/ui/FormField.js.map +1 -0
  38. package/dist/components/ui/Input.d.ts +29 -0
  39. package/dist/components/ui/Input.js +105 -0
  40. package/dist/components/ui/Input.js.map +1 -0
  41. package/dist/components/ui/Modal.d.ts +84 -0
  42. package/dist/components/ui/Modal.js +153 -0
  43. package/dist/components/ui/Modal.js.map +1 -0
  44. package/dist/components/ui/MultiSelectPicker.d.ts +73 -0
  45. package/dist/components/ui/MultiSelectPicker.js +358 -0
  46. package/dist/components/ui/MultiSelectPicker.js.map +1 -0
  47. package/dist/components/ui/Pill.d.ts +49 -0
  48. package/dist/components/ui/Pill.js +107 -0
  49. package/dist/components/ui/Pill.js.map +1 -0
  50. package/dist/components/ui/Popover.d.ts +65 -0
  51. package/dist/components/ui/Popover.js +57 -0
  52. package/dist/components/ui/Popover.js.map +1 -0
  53. package/dist/components/ui/SectionLabel.d.ts +28 -0
  54. package/dist/components/ui/SectionLabel.js +27 -0
  55. package/dist/components/ui/SectionLabel.js.map +1 -0
  56. package/dist/components/ui/Segmented.d.ts +30 -0
  57. package/dist/components/ui/Segmented.js +65 -0
  58. package/dist/components/ui/Segmented.js.map +1 -0
  59. package/dist/components/ui/Spinner.d.ts +22 -0
  60. package/dist/components/ui/Spinner.js +39 -0
  61. package/dist/components/ui/Spinner.js.map +1 -0
  62. package/dist/components/ui/Switch.d.ts +34 -0
  63. package/dist/components/ui/Switch.js +50 -0
  64. package/dist/components/ui/Switch.js.map +1 -0
  65. package/dist/components/ui/Textarea.d.ts +19 -0
  66. package/dist/components/ui/Textarea.js +72 -0
  67. package/dist/components/ui/Textarea.js.map +1 -0
  68. package/dist/components/ui/Toast.d.ts +45 -0
  69. package/dist/components/ui/Toast.js +116 -0
  70. package/dist/components/ui/Toast.js.map +1 -0
  71. package/dist/components/ui/Tooltip.d.ts +25 -0
  72. package/dist/components/ui/Tooltip.js +43 -0
  73. package/dist/components/ui/Tooltip.js.map +1 -0
  74. package/dist/contexts/theme-context.d.ts +95 -0
  75. package/dist/contexts/theme-context.js +561 -0
  76. package/dist/contexts/theme-context.js.map +1 -0
  77. package/dist/index.d.ts +41 -0
  78. package/dist/index.js +67 -0
  79. package/dist/specimen/TokensSpecimen.d.ts +13 -0
  80. package/dist/specimen/TokensSpecimen.js +1090 -0
  81. package/dist/specimen/TokensSpecimen.js.map +1 -0
  82. package/dist/theme/appearance-resolution.d.ts +59 -0
  83. package/dist/theme/appearance-resolution.js +379 -0
  84. package/dist/theme/appearance-resolution.js.map +1 -0
  85. package/dist/theme/init-script.d.ts +48 -0
  86. package/dist/theme/init-script.js +391 -0
  87. package/dist/theme/init-script.js.map +1 -0
  88. package/dist/theme/palettes.d.ts +146 -0
  89. package/dist/theme/palettes.js +85 -0
  90. package/dist/theme/palettes.js.map +1 -0
  91. package/dist/theme/styles.d.ts +351 -0
  92. package/dist/theme/styles.js +264 -0
  93. package/dist/theme/styles.js.map +1 -0
  94. package/dist/theme/tilt.d.ts +41 -0
  95. package/dist/theme/tilt.js +18 -0
  96. package/dist/theme/tilt.js.map +1 -0
  97. package/dist/theme/types.d.ts +61 -0
  98. package/dist/theme/types.js +234 -0
  99. package/dist/theme/types.js.map +1 -0
  100. package/dist/theme/typography.d.ts +144 -0
  101. package/dist/theme/typography.js +57 -0
  102. package/dist/theme/typography.js.map +1 -0
  103. package/dist/utils/cn.d.ts +16 -0
  104. package/dist/utils/cn.js +11 -0
  105. package/dist/utils/cn.js.map +1 -0
  106. package/package.json +60 -0
  107. package/theme.css +3924 -0
@@ -0,0 +1,146 @@
1
+ /**
2
+ * The Motir PALETTE LIBRARY — the named-colour registry (Subtask 7.3.48).
3
+ *
4
+ * A "palette" is a named COLOUR scheme the whole UI can swap to at runtime —
5
+ * the second half of the two-axis contract the style schema (7.3.32) wrote but
6
+ * did not implement. It is the COLOUR/hue axis, and it is deliberately
7
+ * INDEPENDENT of the SHAPE axis (`data-style` — see ./styles.ts): a palette
8
+ * decides what colours the product WEARS (surfaces, ink, accent, tints,
9
+ * semantic hues); a style decides how it FEELS (silhouette, elevation,
10
+ * density, motion). Picking a palette never changes a radius, and picking a
11
+ * style never changes a hue.
12
+ *
13
+ * ── The two-axis runtime contract ───────────────────────────────────────
14
+ * data-palette="<palette-id>" — THIS axis. Layers per-palette `--el-*`
15
+ * element-token overrides over the Tier-3
16
+ * base in app/globals.css.
17
+ * data-style="<style-id>" — the INDEPENDENT shape/feel axis.
18
+ * data-theme="light|dark" — the light/dark base WITHIN a palette
19
+ * (`--color-*`); orthogonal to the palette.
20
+ *
21
+ * A `[data-palette='…']` block in globals.css MUST override ONLY `--el-*`
22
+ * element colour tokens — NEVER a shape/feel token (radius / spacing / shadow
23
+ * / sizing / motion / type). That is the style axis's job, and keeping the two
24
+ * disjoint is what makes "style × palette" a true product of two independent
25
+ * choices rather than N×M hand-tuned combinations.
26
+ *
27
+ * ── v1 — Motir's own palette ─────────────────────────────────────────────
28
+ * v1 ships exactly ONE registered palette: **Motir** — the warm, Notion-warm
29
+ * scheme the product already wears (cream surfaces, charcoal ink, purple
30
+ * primary, pastel feature tints). It is the Tier-0/Tier-3 BASE, so — exactly
31
+ * like the `warm-editorial` base style — it needs NO `[data-palette]` override
32
+ * block; the base `--el-*` tokens already are it. (Per Yue, 2026-06-17: "use
33
+ * Motir's colour palette for the v1.") Each later "Palette: …" subtask ADDS its
34
+ * entry here, ships a `[data-palette='<id>']` block in globals.css overriding
35
+ * the `--el-*` layer, and authors its `docs/palettes/<id>.md` doc — exactly the
36
+ * shape the per-style subtasks (7.3.33+) follow on the other axis.
37
+ */
38
+ /** A registered, runtime-selectable colour palette. */
39
+ interface PaletteDefinition {
40
+ /** The `data-palette` attribute value. Stable; used as the localStorage value. */
41
+ id: string;
42
+ /** Display name shown in the gallery / `/tokens` toggle. */
43
+ name: string;
44
+ /** One-line characterization of the colour mood. */
45
+ tagline: string;
46
+ /** Where the colours are drawn from (credit / mood anchor). */
47
+ inspiration: string;
48
+ /**
49
+ * Repo-relative path to this palette's doc — the colour-role reference a
50
+ * later getdesign-style swap or the `/tokens` composer reads. Every
51
+ * registered palette maps to exactly one.
52
+ */
53
+ designDoc: string;
54
+ }
55
+ /**
56
+ * The registry. Insertion order is the gallery order. Each `id` matches a
57
+ * `[data-palette='<id>']` block in app/globals.css (Motir is the base, so its
58
+ * block is the Tier-3 defaults — no override block needed).
59
+ */
60
+ declare const PALETTE_REGISTRY: {
61
+ motir: {
62
+ id: string;
63
+ name: string;
64
+ tagline: string;
65
+ inspiration: string;
66
+ designDoc: string;
67
+ };
68
+ cobalt: {
69
+ id: string;
70
+ name: string;
71
+ tagline: string;
72
+ inspiration: string;
73
+ designDoc: string;
74
+ };
75
+ graphite: {
76
+ id: string;
77
+ name: string;
78
+ tagline: string;
79
+ inspiration: string;
80
+ designDoc: string;
81
+ };
82
+ evergreen: {
83
+ id: string;
84
+ name: string;
85
+ tagline: string;
86
+ inspiration: string;
87
+ designDoc: string;
88
+ };
89
+ spectrum: {
90
+ id: string;
91
+ name: string;
92
+ tagline: string;
93
+ inspiration: string;
94
+ designDoc: string;
95
+ };
96
+ amber: {
97
+ id: string;
98
+ name: string;
99
+ tagline: string;
100
+ inspiration: string;
101
+ designDoc: string;
102
+ };
103
+ sienna: {
104
+ id: string;
105
+ name: string;
106
+ tagline: string;
107
+ inspiration: string;
108
+ designDoc: string;
109
+ };
110
+ garnet: {
111
+ id: string;
112
+ name: string;
113
+ tagline: string;
114
+ inspiration: string;
115
+ designDoc: string;
116
+ };
117
+ citrine: {
118
+ id: string;
119
+ name: string;
120
+ tagline: string;
121
+ inspiration: string;
122
+ designDoc: string;
123
+ };
124
+ candy: {
125
+ id: string;
126
+ name: string;
127
+ tagline: string;
128
+ inspiration: string;
129
+ designDoc: string;
130
+ };
131
+ };
132
+ /** The id of every registered palette — `data-palette` value space. */
133
+ type PaletteId = keyof typeof PALETTE_REGISTRY;
134
+ /** All registered palette ids, in gallery order. */
135
+ declare const PALETTE_IDS: PaletteId[];
136
+ /**
137
+ * The default palette a fresh install / unset preference resolves to. Motir is
138
+ * the house palette and the Tier-3 base.
139
+ */
140
+ declare const DEFAULT_PALETTE_ID: PaletteId;
141
+ /** Narrowing guard — is an arbitrary string a registered palette id? */
142
+ declare function isPaletteId(value: unknown): value is PaletteId;
143
+ /** Resolve a (possibly stale / unknown) value to a valid palette definition. */
144
+ declare function resolvePalette(value: unknown): PaletteDefinition;
145
+
146
+ export { DEFAULT_PALETTE_ID, PALETTE_IDS, PALETTE_REGISTRY, type PaletteDefinition, type PaletteId, isPaletteId, resolvePalette };
@@ -0,0 +1,85 @@
1
+ // src/theme/palettes.ts
2
+ var PALETTE_REGISTRY = {
3
+ motir: {
4
+ id: "motir",
5
+ name: "Motir",
6
+ tagline: "Warm and editorial \u2014 cream surfaces, charcoal ink, a purple primary, pastel tints.",
7
+ inspiration: "Notion's warm marketing palette \u2014 the product's house colours.",
8
+ designDoc: "docs/palettes/motir.md"
9
+ },
10
+ cobalt: {
11
+ id: "cobalt",
12
+ name: "Cobalt",
13
+ tagline: "Cool and institutional \u2014 slate-cool surfaces, a confident cobalt primary, cooled tints.",
14
+ inspiration: "Coinbase's clean institutional blue + IBM's structured blue, on Radix Blue/Indigo/Slate scales.",
15
+ designDoc: "docs/palettes/cobalt.md"
16
+ },
17
+ graphite: {
18
+ id: "graphite",
19
+ name: "Graphite",
20
+ tagline: "Stark and editorial \u2014 cool greyscale surfaces + ink, an ink CTA, a single restrained cool-blue accent.",
21
+ inspiration: "Vercel's black-and-white precision + Linear's ultra-minimal, on Radix Slate/Blue scales.",
22
+ designDoc: "docs/palettes/graphite.md"
23
+ },
24
+ evergreen: {
25
+ id: "evergreen",
26
+ name: "Evergreen",
27
+ tagline: "Fresh and technical \u2014 an emerald primary over cooled forest neutrals, a green-leaning UI.",
28
+ inspiration: "getdesign.md \u2014 Supabase (dark emerald) / Spotify (vibrant green) / MongoDB (spring green), on Radix green/jade ramps.",
29
+ designDoc: "docs/palettes/evergreen.md"
30
+ },
31
+ spectrum: {
32
+ id: "spectrum",
33
+ name: "Spectrum",
34
+ tagline: "Vibrant and playful \u2014 crisp cool surfaces, a bright violet primary, a candy-bright multi-hue accent & tint set.",
35
+ inspiration: "Figma's vibrant multi-colour brand + Airtable's colourful, friendly palette, on Radix Violet/Iris/Pink/Blue scales.",
36
+ designDoc: "docs/palettes/spectrum.md"
37
+ },
38
+ amber: {
39
+ id: "amber",
40
+ name: "Amber",
41
+ tagline: "Warm and electric \u2014 Binance trading-floor gold over the exchange\u2019s graphite near-blacks; dark labels on the gold.",
42
+ inspiration: "Binance \u2014 its whole documented palette: the bold gold #F0B90B/#FCD535 over cool graphite trading-floor blacks (#0B0E11/#1E2329) + greys, with the buy-green/sell-red semantics.",
43
+ designDoc: "docs/palettes/amber.md"
44
+ },
45
+ sienna: {
46
+ id: "sienna",
47
+ name: "Sienna",
48
+ tagline: "Warm and vivid \u2014 Mistral flame-orange over the Mediterranean warm-cream surfaces; dark labels on the flame.",
49
+ inspiration: "Mistral AI \u2014 its whole documented palette (getdesign.md/mistral.ai): the flame #fa520f + Block-gradient + Sunshine ambers over Warm-Ivory cream surfaces (#fffaeb) and Mistral-Black ink.",
50
+ designDoc: "docs/palettes/sienna.md"
51
+ },
52
+ garnet: {
53
+ id: "garnet",
54
+ name: "Garnet",
55
+ tagline: "Rich and bold \u2014 Pinterest Pushpin red over the brand\u2019s neutral greys; white labels on the red.",
56
+ inspiration: "Pinterest \u2014 its whole documented palette: Pushpin red #E60023/#BD081C over Cod-Gray ink (#111111) and neutral greys (#767676/#EFEFEF), with Gestalt \u201CSkycicle\u201D blue links.",
57
+ designDoc: "docs/palettes/garnet.md"
58
+ },
59
+ citrine: {
60
+ id: "citrine",
61
+ name: "Citrine",
62
+ tagline: "Bright and collaborative \u2014 Miro\u2019s Sunglow yellow over the whiteboard greys, with the Miro action-blue accent.",
63
+ inspiration: "Miro \u2014 its whole Mirotone palette (every value a documented Mirotone step): Sunglow yellow #FFD02F (primary) + the action-blue #3859FF over the gray ramp + Stratos ink #050038, with the green/red semantic ramps.",
64
+ designDoc: "docs/palettes/citrine.md"
65
+ },
66
+ candy: {
67
+ id: "candy",
68
+ name: "Candy",
69
+ tagline: "Sweet and playful \u2014 a light bubblegum-pink primary over candy-paper pinks, with a full pastel-candy rainbow.",
70
+ inspiration: "A candy concept grounded entirely in documented Radix Colors scales (every value a Radix step): Pink primary + Mauve neutrals + a Sky/Jade/Violet/Amber/Crimson candy rainbow; Glossier Pink #F5DADF as the pastel-pink mood reference.",
71
+ designDoc: "docs/palettes/candy.md"
72
+ }
73
+ };
74
+ var PALETTE_IDS = Object.keys(PALETTE_REGISTRY);
75
+ var DEFAULT_PALETTE_ID = "motir";
76
+ function isPaletteId(value) {
77
+ return typeof value === "string" && Object.prototype.hasOwnProperty.call(PALETTE_REGISTRY, value);
78
+ }
79
+ function resolvePalette(value) {
80
+ return PALETTE_REGISTRY[isPaletteId(value) ? value : DEFAULT_PALETTE_ID];
81
+ }
82
+
83
+ export { DEFAULT_PALETTE_ID, PALETTE_IDS, PALETTE_REGISTRY, isPaletteId, resolvePalette };
84
+ //# sourceMappingURL=palettes.js.map
85
+ //# sourceMappingURL=palettes.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/theme/palettes.ts"],"names":[],"mappings":";AA6DO,IAAM,gBAAA,GAAmB;AAAA,EAC9B,KAAA,EAAO;AAAA,IACL,EAAA,EAAI,OAAA;AAAA,IACJ,IAAA,EAAM,OAAA;AAAA,IACN,OAAA,EAAS,yFAAA;AAAA,IACT,WAAA,EAAa,qEAAA;AAAA,IACb,SAAA,EAAW;AAAA,GACb;AAAA,EACA,MAAA,EAAQ;AAAA,IACN,EAAA,EAAI,QAAA;AAAA,IACJ,IAAA,EAAM,QAAA;AAAA,IACN,OAAA,EACE,8FAAA;AAAA,IACF,WAAA,EACE,iGAAA;AAAA,IACF,SAAA,EAAW;AAAA,GACb;AAAA,EACA,QAAA,EAAU;AAAA,IACR,EAAA,EAAI,UAAA;AAAA,IACJ,IAAA,EAAM,UAAA;AAAA,IACN,OAAA,EACE,6GAAA;AAAA,IACF,WAAA,EACE,0FAAA;AAAA,IACF,SAAA,EAAW;AAAA,GACb;AAAA,EACA,SAAA,EAAW;AAAA,IACT,EAAA,EAAI,WAAA;AAAA,IACJ,IAAA,EAAM,WAAA;AAAA,IACN,OAAA,EACE,gGAAA;AAAA,IACF,WAAA,EACE,4HAAA;AAAA,IACF,SAAA,EAAW;AAAA,GACb;AAAA,EACA,QAAA,EAAU;AAAA,IACR,EAAA,EAAI,UAAA;AAAA,IACJ,IAAA,EAAM,UAAA;AAAA,IACN,OAAA,EACE,sHAAA;AAAA,IACF,WAAA,EACE,qHAAA;AAAA,IACF,SAAA,EAAW;AAAA,GACb;AAAA,EACA,KAAA,EAAO;AAAA,IACL,EAAA,EAAI,OAAA;AAAA,IACJ,IAAA,EAAM,OAAA;AAAA,IACN,OAAA,EACE,6HAAA;AAAA,IACF,WAAA,EACE,sLAAA;AAAA,IACF,SAAA,EAAW;AAAA,GACb;AAAA,EACA,MAAA,EAAQ;AAAA,IACN,EAAA,EAAI,QAAA;AAAA,IACJ,IAAA,EAAM,QAAA;AAAA,IACN,OAAA,EACE,kHAAA;AAAA,IACF,WAAA,EACE,gMAAA;AAAA,IACF,SAAA,EAAW;AAAA,GACb;AAAA,EACA,MAAA,EAAQ;AAAA,IACN,EAAA,EAAI,QAAA;AAAA,IACJ,IAAA,EAAM,QAAA;AAAA,IACN,OAAA,EACE,0GAAA;AAAA,IACF,WAAA,EACE,2LAAA;AAAA,IACF,SAAA,EAAW;AAAA,GACb;AAAA,EACA,OAAA,EAAS;AAAA,IACP,EAAA,EAAI,SAAA;AAAA,IACJ,IAAA,EAAM,SAAA;AAAA,IACN,OAAA,EACE,yHAAA;AAAA,IACF,WAAA,EACE,0NAAA;AAAA,IACF,SAAA,EAAW;AAAA,GACb;AAAA,EACA,KAAA,EAAO;AAAA,IACL,EAAA,EAAI,OAAA;AAAA,IACJ,IAAA,EAAM,OAAA;AAAA,IACN,OAAA,EACE,mHAAA;AAAA,IACF,WAAA,EACE,yOAAA;AAAA,IACF,SAAA,EAAW;AAAA;AAEf;AAMO,IAAM,WAAA,GAAc,MAAA,CAAO,IAAA,CAAK,gBAAgB;AAMhD,IAAM,kBAAA,GAAgC;AAGtC,SAAS,YAAY,KAAA,EAAoC;AAC9D,EAAA,OAAO,OAAO,UAAU,QAAA,IAAY,MAAA,CAAO,UAAU,cAAA,CAAe,IAAA,CAAK,kBAAkB,KAAK,CAAA;AAClG;AAGO,SAAS,eAAe,KAAA,EAAmC;AAChE,EAAA,OAAO,gBAAA,CAAiB,WAAA,CAAY,KAAK,CAAA,GAAI,QAAQ,kBAAkB,CAAA;AACzE","file":"palettes.js","sourcesContent":["/**\n * The Motir PALETTE LIBRARY — the named-colour registry (Subtask 7.3.48).\n *\n * A \"palette\" is a named COLOUR scheme the whole UI can swap to at runtime —\n * the second half of the two-axis contract the style schema (7.3.32) wrote but\n * did not implement. It is the COLOUR/hue axis, and it is deliberately\n * INDEPENDENT of the SHAPE axis (`data-style` — see ./styles.ts): a palette\n * decides what colours the product WEARS (surfaces, ink, accent, tints,\n * semantic hues); a style decides how it FEELS (silhouette, elevation,\n * density, motion). Picking a palette never changes a radius, and picking a\n * style never changes a hue.\n *\n * ── The two-axis runtime contract ───────────────────────────────────────\n * data-palette=\"<palette-id>\" — THIS axis. Layers per-palette `--el-*`\n * element-token overrides over the Tier-3\n * base in app/globals.css.\n * data-style=\"<style-id>\" — the INDEPENDENT shape/feel axis.\n * data-theme=\"light|dark\" — the light/dark base WITHIN a palette\n * (`--color-*`); orthogonal to the palette.\n *\n * A `[data-palette='…']` block in globals.css MUST override ONLY `--el-*`\n * element colour tokens — NEVER a shape/feel token (radius / spacing / shadow\n * / sizing / motion / type). That is the style axis's job, and keeping the two\n * disjoint is what makes \"style × palette\" a true product of two independent\n * choices rather than N×M hand-tuned combinations.\n *\n * ── v1 — Motir's own palette ─────────────────────────────────────────────\n * v1 ships exactly ONE registered palette: **Motir** — the warm, Notion-warm\n * scheme the product already wears (cream surfaces, charcoal ink, purple\n * primary, pastel feature tints). It is the Tier-0/Tier-3 BASE, so — exactly\n * like the `warm-editorial` base style — it needs NO `[data-palette]` override\n * block; the base `--el-*` tokens already are it. (Per Yue, 2026-06-17: \"use\n * Motir's colour palette for the v1.\") Each later \"Palette: …\" subtask ADDS its\n * entry here, ships a `[data-palette='<id>']` block in globals.css overriding\n * the `--el-*` layer, and authors its `docs/palettes/<id>.md` doc — exactly the\n * shape the per-style subtasks (7.3.33+) follow on the other axis.\n */\n\n/** A registered, runtime-selectable colour palette. */\nexport interface PaletteDefinition {\n /** The `data-palette` 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 colour mood. */\n tagline: string;\n /** Where the colours are drawn from (credit / mood anchor). */\n inspiration: string;\n /**\n * Repo-relative path to this palette's doc — the colour-role reference a\n * later getdesign-style swap or the `/tokens` composer reads. Every\n * registered palette maps to exactly one.\n */\n designDoc: string;\n}\n\n/**\n * The registry. Insertion order is the gallery order. Each `id` matches a\n * `[data-palette='<id>']` block in app/globals.css (Motir is the base, so its\n * block is the Tier-3 defaults — no override block needed).\n */\nexport const PALETTE_REGISTRY = {\n motir: {\n id: 'motir',\n name: 'Motir',\n tagline: 'Warm and editorial — cream surfaces, charcoal ink, a purple primary, pastel tints.',\n inspiration: \"Notion's warm marketing palette — the product's house colours.\",\n designDoc: 'docs/palettes/motir.md',\n },\n cobalt: {\n id: 'cobalt',\n name: 'Cobalt',\n tagline:\n 'Cool and institutional — slate-cool surfaces, a confident cobalt primary, cooled tints.',\n inspiration:\n \"Coinbase's clean institutional blue + IBM's structured blue, on Radix Blue/Indigo/Slate scales.\",\n designDoc: 'docs/palettes/cobalt.md',\n },\n graphite: {\n id: 'graphite',\n name: 'Graphite',\n tagline:\n 'Stark and editorial — cool greyscale surfaces + ink, an ink CTA, a single restrained cool-blue accent.',\n inspiration:\n \"Vercel's black-and-white precision + Linear's ultra-minimal, on Radix Slate/Blue scales.\",\n designDoc: 'docs/palettes/graphite.md',\n },\n evergreen: {\n id: 'evergreen',\n name: 'Evergreen',\n tagline:\n 'Fresh and technical — an emerald primary over cooled forest neutrals, a green-leaning UI.',\n inspiration:\n 'getdesign.md — Supabase (dark emerald) / Spotify (vibrant green) / MongoDB (spring green), on Radix green/jade ramps.',\n designDoc: 'docs/palettes/evergreen.md',\n },\n spectrum: {\n id: 'spectrum',\n name: 'Spectrum',\n tagline:\n 'Vibrant and playful — crisp cool surfaces, a bright violet primary, a candy-bright multi-hue accent & tint set.',\n inspiration:\n \"Figma's vibrant multi-colour brand + Airtable's colourful, friendly palette, on Radix Violet/Iris/Pink/Blue scales.\",\n designDoc: 'docs/palettes/spectrum.md',\n },\n amber: {\n id: 'amber',\n name: 'Amber',\n tagline:\n 'Warm and electric — Binance trading-floor gold over the exchange’s graphite near-blacks; dark labels on the gold.',\n inspiration:\n 'Binance — its whole documented palette: the bold gold #F0B90B/#FCD535 over cool graphite trading-floor blacks (#0B0E11/#1E2329) + greys, with the buy-green/sell-red semantics.',\n designDoc: 'docs/palettes/amber.md',\n },\n sienna: {\n id: 'sienna',\n name: 'Sienna',\n tagline:\n 'Warm and vivid — Mistral flame-orange over the Mediterranean warm-cream surfaces; dark labels on the flame.',\n inspiration:\n 'Mistral AI — its whole documented palette (getdesign.md/mistral.ai): the flame #fa520f + Block-gradient + Sunshine ambers over Warm-Ivory cream surfaces (#fffaeb) and Mistral-Black ink.',\n designDoc: 'docs/palettes/sienna.md',\n },\n garnet: {\n id: 'garnet',\n name: 'Garnet',\n tagline:\n 'Rich and bold — Pinterest Pushpin red over the brand’s neutral greys; white labels on the red.',\n inspiration:\n 'Pinterest — its whole documented palette: Pushpin red #E60023/#BD081C over Cod-Gray ink (#111111) and neutral greys (#767676/#EFEFEF), with Gestalt “Skycicle” blue links.',\n designDoc: 'docs/palettes/garnet.md',\n },\n citrine: {\n id: 'citrine',\n name: 'Citrine',\n tagline:\n 'Bright and collaborative — Miro’s Sunglow yellow over the whiteboard greys, with the Miro action-blue accent.',\n inspiration:\n 'Miro — its whole Mirotone palette (every value a documented Mirotone step): Sunglow yellow #FFD02F (primary) + the action-blue #3859FF over the gray ramp + Stratos ink #050038, with the green/red semantic ramps.',\n designDoc: 'docs/palettes/citrine.md',\n },\n candy: {\n id: 'candy',\n name: 'Candy',\n tagline:\n 'Sweet and playful — a light bubblegum-pink primary over candy-paper pinks, with a full pastel-candy rainbow.',\n inspiration:\n 'A candy concept grounded entirely in documented Radix Colors scales (every value a Radix step): Pink primary + Mauve neutrals + a Sky/Jade/Violet/Amber/Crimson candy rainbow; Glossier Pink #F5DADF as the pastel-pink mood reference.',\n designDoc: 'docs/palettes/candy.md',\n },\n} satisfies Record<string, PaletteDefinition>;\n\n/** The id of every registered palette — `data-palette` value space. */\nexport type PaletteId = keyof typeof PALETTE_REGISTRY;\n\n/** All registered palette ids, in gallery order. */\nexport const PALETTE_IDS = Object.keys(PALETTE_REGISTRY) as PaletteId[];\n\n/**\n * The default palette a fresh install / unset preference resolves to. Motir is\n * the house palette and the Tier-3 base.\n */\nexport const DEFAULT_PALETTE_ID: PaletteId = 'motir';\n\n/** Narrowing guard — is an arbitrary string a registered palette id? */\nexport function isPaletteId(value: unknown): value is PaletteId {\n return typeof value === 'string' && Object.prototype.hasOwnProperty.call(PALETTE_REGISTRY, value);\n}\n\n/** Resolve a (possibly stale / unknown) value to a valid palette definition. */\nexport function resolvePalette(value: unknown): PaletteDefinition {\n return PALETTE_REGISTRY[isPaletteId(value) ? value : DEFAULT_PALETTE_ID];\n}\n"]}
@@ -0,0 +1,351 @@
1
+ import { TypeId } from './typography.js';
2
+
3
+ /**
4
+ * The Motir STYLE LIBRARY — the named-aesthetic registry (Subtask 7.3.32).
5
+ *
6
+ * A "style" is a named, end-to-end AESTHETIC the whole UI can swap to at
7
+ * runtime — the foundation the onboarding design wizard (7.3.27) and the
8
+ * `/tokens` composer (7.3.30) build on. It is the SHAPE/feel axis, and it is
9
+ * deliberately INDEPENDENT of the COLOR axis (`data-palette` — see below): a
10
+ * style decides how the product FEELS (silhouette, stroke, elevation, surface
11
+ * treatment, density, motion, typography, component silhouettes); a palette
12
+ * decides what colours it WEARS. Picking a style never changes a hue, and
13
+ * picking a palette never changes a radius.
14
+ *
15
+ * ── The two-axis runtime contract ───────────────────────────────────────
16
+ * data-style="<style-id>" — THIS axis. Layers per-style shape/feel
17
+ * tokens (+ component-variant overrides) over
18
+ * the Tier-0 base scale in app/globals.css.
19
+ * data-palette="<palette-id>" — the INDEPENDENT colour axis (re-skins the
20
+ * `--el-*` layer). Orthogonal to data-style.
21
+ * data-theme="light|dark" — the light/dark base within a palette.
22
+ *
23
+ * A `[data-style='…']` TOKEN block in globals.css MUST override ONLY shape/feel
24
+ * tokens (radius / spacing / shadow / sizing / transition / type) — NEVER a
25
+ * `--color-*` or `--el-*` colour token. That is the palette axis's job, and
26
+ * keeping the two disjoint is what makes "style × palette" a true product of
27
+ * two independent choices rather than 2×N hand-tuned combinations.
28
+ *
29
+ * A SURFACE-MATERIAL style (glassmorphism, 7.3.35; later cybercore, aurora,
30
+ * neumorphism …) owns a richer surface — translucency, a gradient canvas,
31
+ * frosted backdrop-blur — that the token block cannot express. It adds a
32
+ * palette-DERIVED MATERIAL LAYER: style-scoped component rules
33
+ * (`[data-style='id'] [data-surface='…'] { … }`) whose colour comes ONLY from
34
+ * `color-mix()`/`var(--color-*|--el-*)` over the ACTIVE palette, never a raw
35
+ * hue — so the two axes stay disjoint (a palette swap re-tints the material; a
36
+ * style swap leaves hues untouched). Surfaces opt in via the `data-surface`
37
+ * hook the shared primitives emit. Both rules are enforced by
38
+ * tests/theme/styleRegistry.test.ts.
39
+ *
40
+ * ── Why a style is MORE than a token swap ───────────────────────────────
41
+ * The feel-bearing DIMENSIONS below are the axes a pure token swap ignores:
42
+ * two styles can share the Tier-0 scale yet feel utterly different because
43
+ * their silhouette, elevation philosophy, surface treatment, and component
44
+ * silhouettes diverge. The registry names those dimensions so each style (and
45
+ * its DESIGN.md) is authored against the same rubric.
46
+ *
47
+ * This module is the schema + the registration of the styles. Each "Style: …"
48
+ * subtask (7.3.33–7.3.42) ADDS its entry here, ships a `[data-style='<id>']`
49
+ * token block in globals.css (plus, for a surface-material style, the
50
+ * palette-derived material layer above), and authors its `docs/styles/<id>.md`
51
+ * DESIGN.md.
52
+ */
53
+
54
+ /**
55
+ * The feel-bearing axes a named style controls. A token-only swap reaches the
56
+ * first few; the rest (surface treatment, motion, typography, component
57
+ * silhouettes) are what give a style its identity and must be authored, not
58
+ * derived. The order here is the canonical presentation order (the `/tokens`
59
+ * page + each style's DESIGN.md walk them in this sequence).
60
+ */
61
+ declare const STYLE_DIMENSIONS: readonly [{
62
+ readonly key: "silhouette";
63
+ readonly label: "Shape / silhouette";
64
+ readonly description: "Corner-radius personality — sober rectangles vs. soft pills vs. hard right angles.";
65
+ }, {
66
+ readonly key: "stroke";
67
+ readonly label: "Border / stroke";
68
+ readonly description: "Hairline vs. heavy outline; whether structure is drawn with borders at all.";
69
+ }, {
70
+ readonly key: "elevation";
71
+ readonly label: "Elevation philosophy";
72
+ readonly description: "How depth is expressed — soft diffuse shadows, hard offset shadows, or flat.";
73
+ }, {
74
+ readonly key: "surface";
75
+ readonly label: "Surface / background treatment";
76
+ readonly description: "Opaque cards vs. translucent glass vs. tinted washes — the material of a surface.";
77
+ }, {
78
+ readonly key: "density";
79
+ readonly label: "Density rhythm";
80
+ readonly description: "Padding/sizing cadence — compact and efficient vs. roomy and relaxed.";
81
+ }, {
82
+ readonly key: "motion";
83
+ readonly label: "Motion";
84
+ readonly description: "Transition speed and easing — snappy, gentle, or springy.";
85
+ }, {
86
+ readonly key: "typography";
87
+ readonly label: "Typography";
88
+ readonly description: "The style's DEFAULT type pairing — type is the independent `data-type` axis now (see ./typography.ts + `defaultTypeId`); this describes the pairing the style ships with: editorial serif, all-sans, or mono headlines.";
89
+ }, {
90
+ readonly key: "components";
91
+ readonly label: "Component silhouettes";
92
+ readonly description: "Per-component shape overrides beyond tokens (e.g. a pill button vs. a square one).";
93
+ }];
94
+ type StyleDimensionKey = (typeof STYLE_DIMENSIONS)[number]['key'];
95
+ /** A registered, runtime-selectable style. */
96
+ interface StyleDefinition {
97
+ /** The `data-style` attribute value. Stable; used as the localStorage value. */
98
+ id: string;
99
+ /** Display name shown in the gallery / `/tokens` toggle. */
100
+ name: string;
101
+ /** One-line characterization of the feel. */
102
+ tagline: string;
103
+ /** Where the look is drawn from (credit / mood anchor). */
104
+ inspiration: string;
105
+ /** One line per feel-bearing dimension — the authored rubric for this style. */
106
+ dimensions: Record<StyleDimensionKey, string>;
107
+ /**
108
+ * Repo-relative path to this style's DESIGN.md — the doc the `/tokens` page
109
+ * composes (and a later getdesign-style swap reads). Every registered style
110
+ * maps to exactly one.
111
+ */
112
+ designDoc: string;
113
+ /**
114
+ * The type pairing (`data-type`, see ./typography.ts) this style applies when
115
+ * the user has NOT pinned an explicit type — the style's curated default,
116
+ * overridable. Type is its own axis now; this is how a style keeps its
117
+ * out-of-the-box typographic feel (e.g. swiss → `motir-sans`, neo-brutalism /
118
+ * cybercore-y2k → `motir-mono`) without owning `--font-*` in its own block.
119
+ */
120
+ defaultTypeId: TypeId;
121
+ }
122
+ /**
123
+ * The registry. Insertion order is the gallery order. Each `id` matches a
124
+ * `[data-style='<id>']` block in app/globals.css (Warm Editorial is the base,
125
+ * so its block is the Tier-0 defaults — no override block needed).
126
+ */
127
+ declare const STYLE_REGISTRY: {
128
+ 'warm-editorial': {
129
+ id: string;
130
+ name: string;
131
+ tagline: string;
132
+ inspiration: string;
133
+ designDoc: string;
134
+ defaultTypeId: "motir";
135
+ dimensions: {
136
+ silhouette: string;
137
+ stroke: string;
138
+ elevation: string;
139
+ surface: string;
140
+ density: string;
141
+ motion: string;
142
+ typography: string;
143
+ components: string;
144
+ };
145
+ };
146
+ 'soft-playful': {
147
+ id: string;
148
+ name: string;
149
+ tagline: string;
150
+ inspiration: string;
151
+ designDoc: string;
152
+ defaultTypeId: "motir";
153
+ dimensions: {
154
+ silhouette: string;
155
+ stroke: string;
156
+ elevation: string;
157
+ surface: string;
158
+ density: string;
159
+ motion: string;
160
+ typography: string;
161
+ components: string;
162
+ };
163
+ };
164
+ 'swiss-minimal-flat': {
165
+ id: string;
166
+ name: string;
167
+ tagline: string;
168
+ inspiration: string;
169
+ designDoc: string;
170
+ defaultTypeId: "motir-sans";
171
+ dimensions: {
172
+ silhouette: string;
173
+ stroke: string;
174
+ elevation: string;
175
+ surface: string;
176
+ density: string;
177
+ motion: string;
178
+ typography: string;
179
+ components: string;
180
+ };
181
+ };
182
+ 'neo-brutalism': {
183
+ id: string;
184
+ name: string;
185
+ tagline: string;
186
+ inspiration: string;
187
+ designDoc: string;
188
+ defaultTypeId: "motir-mono";
189
+ dimensions: {
190
+ silhouette: string;
191
+ stroke: string;
192
+ elevation: string;
193
+ surface: string;
194
+ density: string;
195
+ motion: string;
196
+ typography: string;
197
+ components: string;
198
+ };
199
+ };
200
+ glassmorphism: {
201
+ id: string;
202
+ name: string;
203
+ tagline: string;
204
+ inspiration: string;
205
+ designDoc: string;
206
+ defaultTypeId: "motir";
207
+ dimensions: {
208
+ silhouette: string;
209
+ stroke: string;
210
+ elevation: string;
211
+ surface: string;
212
+ density: string;
213
+ motion: string;
214
+ typography: string;
215
+ components: string;
216
+ };
217
+ };
218
+ 'cybercore-y2k': {
219
+ id: string;
220
+ name: string;
221
+ tagline: string;
222
+ inspiration: string;
223
+ designDoc: string;
224
+ defaultTypeId: "motir-mono";
225
+ dimensions: {
226
+ silhouette: string;
227
+ stroke: string;
228
+ elevation: string;
229
+ surface: string;
230
+ density: string;
231
+ motion: string;
232
+ typography: string;
233
+ components: string;
234
+ };
235
+ };
236
+ aurora: {
237
+ id: string;
238
+ name: string;
239
+ tagline: string;
240
+ inspiration: string;
241
+ designDoc: string;
242
+ defaultTypeId: "motir";
243
+ dimensions: {
244
+ silhouette: string;
245
+ stroke: string;
246
+ elevation: string;
247
+ surface: string;
248
+ density: string;
249
+ motion: string;
250
+ typography: string;
251
+ components: string;
252
+ };
253
+ };
254
+ '3d-immersive': {
255
+ id: string;
256
+ name: string;
257
+ tagline: string;
258
+ inspiration: string;
259
+ designDoc: string;
260
+ defaultTypeId: "motir";
261
+ dimensions: {
262
+ silhouette: string;
263
+ stroke: string;
264
+ elevation: string;
265
+ surface: string;
266
+ density: string;
267
+ motion: string;
268
+ typography: string;
269
+ components: string;
270
+ };
271
+ };
272
+ neumorphism: {
273
+ id: string;
274
+ name: string;
275
+ tagline: string;
276
+ inspiration: string;
277
+ designDoc: string;
278
+ defaultTypeId: "motir";
279
+ dimensions: {
280
+ silhouette: string;
281
+ stroke: string;
282
+ elevation: string;
283
+ surface: string;
284
+ density: string;
285
+ motion: string;
286
+ typography: string;
287
+ components: string;
288
+ };
289
+ };
290
+ 'hand-drawn-indie': {
291
+ id: string;
292
+ name: string;
293
+ tagline: string;
294
+ inspiration: string;
295
+ designDoc: string;
296
+ defaultTypeId: "editorial";
297
+ dimensions: {
298
+ silhouette: string;
299
+ stroke: string;
300
+ elevation: string;
301
+ surface: string;
302
+ density: string;
303
+ motion: string;
304
+ typography: string;
305
+ components: string;
306
+ };
307
+ };
308
+ retrofuturism: {
309
+ id: string;
310
+ name: string;
311
+ tagline: string;
312
+ inspiration: string;
313
+ designDoc: string;
314
+ defaultTypeId: "grotesk";
315
+ dimensions: {
316
+ silhouette: string;
317
+ stroke: string;
318
+ elevation: string;
319
+ surface: string;
320
+ density: string;
321
+ motion: string;
322
+ typography: string;
323
+ components: string;
324
+ };
325
+ };
326
+ };
327
+ /** The id of every registered style — `data-style` value space. */
328
+ type StyleId = keyof typeof STYLE_REGISTRY;
329
+ /** All registered style ids, in gallery order. */
330
+ declare const STYLE_IDS: StyleId[];
331
+ /**
332
+ * The default style a fresh install / unset preference resolves to. Warm
333
+ * Editorial is Motir's house style and the Tier-0 base.
334
+ */
335
+ declare const DEFAULT_STYLE_ID: StyleId;
336
+ /** Narrowing guard — is an arbitrary string a registered style id? */
337
+ declare function isStyleId(value: unknown): value is StyleId;
338
+ /** Resolve a (possibly stale / unknown) value to a valid style definition. */
339
+ declare function resolveStyle(value: unknown): StyleDefinition;
340
+ /**
341
+ * styleId → its `defaultTypeId` — the type pairing applied when the user has
342
+ * not pinned an explicit `data-type`. Baked into the FOUC init script (so the
343
+ * pre-hydration pass can resolve the right type for the active style) and used
344
+ * by the theme context's effective-type derivation. `resolveType` (the
345
+ * registry) supplies the ultimate fallback, so every value here is a real id.
346
+ */
347
+ declare const STYLE_DEFAULT_TYPE: Record<StyleId, TypeId>;
348
+ /** The default type for a (possibly unknown) style value — the fallback chain. */
349
+ declare function defaultTypeForStyle(styleValue: unknown): TypeId;
350
+
351
+ export { DEFAULT_STYLE_ID, STYLE_DEFAULT_TYPE, STYLE_DIMENSIONS, STYLE_IDS, STYLE_REGISTRY, type StyleDefinition, type StyleDimensionKey, type StyleId, defaultTypeForStyle, isStyleId, resolveStyle };