@pimia/design-tokens 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.
package/README.md ADDED
@@ -0,0 +1,77 @@
1
+ # @pimia/design-tokens
2
+
3
+ El sistema de diseño de Pimia («los números en limpio») como paquete
4
+ **opcional** para apps de partner: tokens tipados, variables CSS y un preset de
5
+ Tailwind. Licencia MIT.
6
+
7
+ **El white-label es poder no usarlo.** Tu app vertical puede traer tu marca, tu
8
+ tipografía y tu paleta — este paquete existe para el partner que quiera el
9
+ aspecto Pimia (o su chasis) sin copiarlo a mano, y para que «powered by Pimia»
10
+ pueda verse, no solo leerse.
11
+
12
+ Fuente de verdad: el `DESIGN.md` de la plataforma (snapshot 2026-07-30). Si
13
+ diverge, gana la plataforma y este paquete se actualiza — no al revés.
14
+
15
+ ## Uso
16
+
17
+ **Variables CSS (sin build, sin framework):**
18
+
19
+ ```css
20
+ @import '@pimia/design-tokens/pimia.css';
21
+
22
+ .mi-boton {
23
+ background: var(--pimia-color-primary);
24
+ border-radius: var(--pimia-radius-control);
25
+ }
26
+ ```
27
+
28
+ **Preset de Tailwind:**
29
+
30
+ ```js
31
+ // tailwind.config.js
32
+ import pimiaPreset from '@pimia/design-tokens/tailwind'
33
+
34
+ export default {
35
+ presets: [pimiaPreset],
36
+ content: ['./src/**/*.{ts,tsx,vue}'],
37
+ }
38
+ ```
39
+
40
+ Da `bg-primary`, `text-ink-muted`, `bg-success-container`, `rounded-card`,
41
+ `font-display`, `p-md`… siempre por `theme.extend` (no borra la paleta por
42
+ defecto; la disciplina de no usar `purple-*` es tuya si adoptas el sistema).
43
+
44
+ **Tokens en JS/TS:**
45
+
46
+ ```ts
47
+ import { colors, typography, namedRules } from '@pimia/design-tokens'
48
+ ```
49
+
50
+ Las fuentes (Plus Jakarta Sans + Inter) no van en el paquete: cárgalas
51
+ self-hosted o desde tu proveedor; los stacks declaran los fallbacks.
52
+
53
+ ## Las reglas que hacen que parezca Pimia
54
+
55
+ Si adoptas el sistema, estas cinco reglas son el 90 % del resultado (el
56
+ detalle narrativo vive en el DESIGN.md de la plataforma; aquí van como
57
+ `namedRules` consultables):
58
+
59
+ 1. **Una sola voz** — el violeta OKLCH 278 es la única voz de marca; nada de
60
+ `purple-*`/`violet-*` de serie.
61
+ 2. **El semáforo contable** — `success`/`warning`/`danger` hablan SOLO de
62
+ estado de dinero y cumplimiento; el violeta jamás comunica estado.
63
+ 3. **El límite del slate** — el texto legible nunca baja de `ink-muted`
64
+ (`#475569`); `ink-subtle` es solo decorativo (no cumple AA).
65
+ 4. **Plano por defecto** — profundidad por hairlines de 1 px y contraste de
66
+ superficie; sombra máxima `shadow-sm` y siempre con borde.
67
+ 5. **Números tabulares** — todo dato financiero en mono con `tabular-nums` y,
68
+ en tablas, alineado a la derecha.
69
+
70
+ Y una prohibición sin matices: **cero emojis en la UI**.
71
+
72
+ ## Qué NO es
73
+
74
+ - No es una librería de componentes (los recetarios de `components` son la
75
+ forma canónica de botón/input/card/badge, para que montes los tuyos).
76
+ - No es obligatorio: ninguna invariante de la plataforma depende de él — las
77
+ reglas legales y de cumplimiento viven server-side, no en el CSS.
package/dist/css.d.ts ADDED
@@ -0,0 +1 @@
1
+ export declare function cssVariables(): string;
package/dist/css.js ADDED
@@ -0,0 +1,25 @@
1
+ /**
2
+ * Variables CSS a partir de los tokens: la vía de adopción sin build ni
3
+ * framework. `cssVariables()` devuelve el bloque `:root`; el build lo vuelca
4
+ * además a `dist/pimia.css` para importarlo tal cual.
5
+ */
6
+ import { colors, fontFamilies, radius, spacing } from './tokens.js';
7
+ const kebab = (name) => name.replace(/([a-z0-9])([A-Z])/g, '$1-$2').toLowerCase();
8
+ export function cssVariables() {
9
+ const lines = [':root {'];
10
+ for (const [name, value] of Object.entries(colors)) {
11
+ lines.push(` --pimia-color-${kebab(name)}: ${value};`);
12
+ }
13
+ for (const [name, value] of Object.entries(fontFamilies)) {
14
+ const stack = value.map((f) => (f.includes(' ') ? `'${f}'` : f)).join(', ');
15
+ lines.push(` --pimia-font-${kebab(name)}: ${stack};`);
16
+ }
17
+ for (const [name, value] of Object.entries(radius)) {
18
+ lines.push(` --pimia-radius-${kebab(name)}: ${value};`);
19
+ }
20
+ for (const [name, value] of Object.entries(spacing)) {
21
+ lines.push(` --pimia-space-${name}: ${value};`);
22
+ }
23
+ lines.push('}');
24
+ return lines.join('\n') + '\n';
25
+ }
@@ -0,0 +1,4 @@
1
+ export { colors, components, fontFamilies, forbiddenFonts, namedRules, radius, spacing, tokens, typography, } from './tokens.js';
2
+ export type { PimiaTokens, TypeStyle } from './tokens.js';
3
+ export { cssVariables } from './css.js';
4
+ export { default as tailwindPreset } from './tailwind.js';
package/dist/index.js ADDED
@@ -0,0 +1,3 @@
1
+ export { colors, components, fontFamilies, forbiddenFonts, namedRules, radius, spacing, tokens, typography, } from './tokens.js';
2
+ export { cssVariables } from './css.js';
3
+ export { default as tailwindPreset } from './tailwind.js';
package/dist/pimia.css ADDED
@@ -0,0 +1,33 @@
1
+ /* @pimia/design-tokens — variables CSS del sistema de diseño de Pimia.
2
+ * Generado del build; no editar a mano. Fuente: src/tokens.ts. */
3
+ :root {
4
+ --pimia-color-primary: oklch(48% 0.20 278);
5
+ --pimia-color-primary-hover: oklch(44% 0.22 278);
6
+ --pimia-color-primary-container: oklch(96% 0.04 278);
7
+ --pimia-color-primary-container-subtle: oklch(95% 0.018 278);
8
+ --pimia-color-ink: #1e293b;
9
+ --pimia-color-muted-ink: #475569;
10
+ --pimia-color-subtle-ink: #94a3b8;
11
+ --pimia-color-surface: #ffffff;
12
+ --pimia-color-surface-muted: #f8fafc;
13
+ --pimia-color-border: #e2e8f0;
14
+ --pimia-color-border-subtle: #f1f5f9;
15
+ --pimia-color-success: oklch(52% 0.18 155);
16
+ --pimia-color-success-container: oklch(97% 0.03 155);
17
+ --pimia-color-warning: oklch(62% 0.18 75);
18
+ --pimia-color-warning-container: oklch(98% 0.02 75);
19
+ --pimia-color-danger: oklch(54% 0.22 25);
20
+ --pimia-color-danger-container: oklch(98% 0.02 25);
21
+ --pimia-font-display: 'Plus Jakarta Sans', system-ui, sans-serif;
22
+ --pimia-font-body: Inter, system-ui, sans-serif;
23
+ --pimia-font-mono: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
24
+ --pimia-radius-control: 0.5rem;
25
+ --pimia-radius-card: 0.75rem;
26
+ --pimia-radius-badge: 0.375rem;
27
+ --pimia-radius-pill: 9999px;
28
+ --pimia-space-xs: 0.375rem;
29
+ --pimia-space-sm: 0.625rem;
30
+ --pimia-space-md: 1rem;
31
+ --pimia-space-lg: 1.25rem;
32
+ --pimia-space-xl: 2.5rem;
33
+ }
@@ -0,0 +1,57 @@
1
+ declare const preset: {
2
+ theme: {
3
+ extend: {
4
+ colors: {
5
+ primary: {
6
+ DEFAULT: "oklch(48% 0.20 278)";
7
+ hover: "oklch(44% 0.22 278)";
8
+ container: "oklch(96% 0.04 278)";
9
+ 'container-subtle': "oklch(95% 0.018 278)";
10
+ };
11
+ ink: {
12
+ DEFAULT: "#1e293b";
13
+ muted: "#475569";
14
+ subtle: "#94a3b8";
15
+ };
16
+ surface: {
17
+ DEFAULT: "#ffffff";
18
+ muted: "#f8fafc";
19
+ };
20
+ line: {
21
+ DEFAULT: "#e2e8f0";
22
+ subtle: "#f1f5f9";
23
+ };
24
+ success: {
25
+ DEFAULT: "oklch(52% 0.18 155)";
26
+ container: "oklch(97% 0.03 155)";
27
+ };
28
+ warning: {
29
+ DEFAULT: "oklch(62% 0.18 75)";
30
+ container: "oklch(98% 0.02 75)";
31
+ };
32
+ danger: {
33
+ DEFAULT: "oklch(54% 0.22 25)";
34
+ container: "oklch(98% 0.02 25)";
35
+ };
36
+ };
37
+ fontFamily: {
38
+ display: ("Plus Jakarta Sans" | "system-ui" | "sans-serif")[];
39
+ body: ("system-ui" | "sans-serif" | "Inter")[];
40
+ mono: ("ui-monospace" | "SFMono-Regular" | "Menlo" | "Monaco" | "Consolas" | "monospace")[];
41
+ };
42
+ borderRadius: {
43
+ control: "0.5rem";
44
+ card: "0.75rem";
45
+ badge: "0.375rem";
46
+ };
47
+ spacing: {
48
+ xs: "0.375rem";
49
+ sm: "0.625rem";
50
+ md: "1rem";
51
+ lg: "1.25rem";
52
+ xl: "2.5rem";
53
+ };
54
+ };
55
+ };
56
+ };
57
+ export default preset;
@@ -0,0 +1,63 @@
1
+ /**
2
+ * Preset de Tailwind con los tokens de Pimia. Uso:
3
+ *
4
+ * // tailwind.config.js
5
+ * import pimiaPreset from '@pimia/design-tokens/tailwind'
6
+ * export default { presets: [pimiaPreset], content: [...] }
7
+ *
8
+ * Va por `theme.extend`: no borra la paleta por defecto de Tailwind — las
9
+ * reglas del sistema (nada de purple-* ni violet-*) son disciplina de uso, y
10
+ * el partner que no quiera el sistema sencillamente no monta el preset.
11
+ */
12
+ import { colors, fontFamilies, radius, spacing } from './tokens.js';
13
+ const preset = {
14
+ theme: {
15
+ extend: {
16
+ colors: {
17
+ primary: {
18
+ DEFAULT: colors.primary,
19
+ hover: colors.primaryHover,
20
+ container: colors.primaryContainer,
21
+ 'container-subtle': colors.primaryContainerSubtle,
22
+ },
23
+ ink: {
24
+ DEFAULT: colors.ink,
25
+ muted: colors.mutedInk,
26
+ subtle: colors.subtleInk,
27
+ },
28
+ surface: {
29
+ DEFAULT: colors.surface,
30
+ muted: colors.surfaceMuted,
31
+ },
32
+ line: {
33
+ DEFAULT: colors.border,
34
+ subtle: colors.borderSubtle,
35
+ },
36
+ success: {
37
+ DEFAULT: colors.success,
38
+ container: colors.successContainer,
39
+ },
40
+ warning: {
41
+ DEFAULT: colors.warning,
42
+ container: colors.warningContainer,
43
+ },
44
+ danger: {
45
+ DEFAULT: colors.danger,
46
+ container: colors.dangerContainer,
47
+ },
48
+ },
49
+ fontFamily: {
50
+ display: [...fontFamilies.display],
51
+ body: [...fontFamilies.body],
52
+ mono: [...fontFamilies.mono],
53
+ },
54
+ borderRadius: {
55
+ control: radius.control,
56
+ card: radius.card,
57
+ badge: radius.badge,
58
+ },
59
+ spacing: { ...spacing },
60
+ },
61
+ },
62
+ };
63
+ export default preset;
@@ -0,0 +1,208 @@
1
+ /**
2
+ * Tokens del sistema de diseño de Pimia («los números en limpio»).
3
+ *
4
+ * Fuente de verdad: DESIGN.md del repo de la plataforma (frontmatter + reglas
5
+ * con nombre), snapshot del 2026-07-30. Este paquete NO inventa valores: los
6
+ * transcribe para que una app de partner pueda adoptarlos — o ignorarlos por
7
+ * completo, que es exactamente lo que significa white-label.
8
+ *
9
+ * Los canónicos de marca y semáforo van en OKLCH (matiz 278 para la marca);
10
+ * los `hex` que aparecen en comentarios son equivalencias orientativas.
11
+ */
12
+ export declare const colors: {
13
+ /** La única voz de marca: acciones primarias, enlaces, navegación activa, foco. */
14
+ readonly primary: "oklch(48% 0.20 278)";
15
+ readonly primaryHover: "oklch(44% 0.22 278)";
16
+ /** Fondos de estado activo, badges de marca. */
17
+ readonly primaryContainer: "oklch(96% 0.04 278)";
18
+ /** Fondo de avatares de iniciales (texto en `primary`). */
19
+ readonly primaryContainerSubtle: "oklch(95% 0.018 278)";
20
+ /** Texto principal (slate-800). */
21
+ readonly ink: "#1e293b";
22
+ /** Texto secundario y cuerpo de lectura (slate-600) — el LÍMITE legible. */
23
+ readonly mutedInk: "#475569";
24
+ /** SOLO decorativo (slate-400): iconos de apoyo, placeholders, disabled. ~3:1 sobre blanco, no cumple AA para texto. */
25
+ readonly subtleInk: "#94a3b8";
26
+ /** Cards y formularios. */
27
+ readonly surface: "#ffffff";
28
+ /** Fondo de página y sidebar (slate-50). */
29
+ readonly surfaceMuted: "#f8fafc";
30
+ /** Bordes de card y panel (slate-200). */
31
+ readonly border: "#e2e8f0";
32
+ /** Separadores internos de card (slate-100). */
33
+ readonly borderSubtle: "#f1f5f9";
34
+ readonly success: "oklch(52% 0.18 155)";
35
+ readonly successContainer: "oklch(97% 0.03 155)";
36
+ readonly warning: "oklch(62% 0.18 75)";
37
+ readonly warningContainer: "oklch(98% 0.02 75)";
38
+ readonly danger: "oklch(54% 0.22 25)";
39
+ readonly dangerContainer: "oklch(98% 0.02 25)";
40
+ };
41
+ export declare const fontFamilies: {
42
+ /** Titulares y superficies comerciales (login, landing). */
43
+ readonly display: readonly ["Plus Jakarta Sans", "system-ui", "sans-serif"];
44
+ /** El trabajo: tablas, formularios, lectura funcional. */
45
+ readonly body: readonly ["Inter", "system-ui", "sans-serif"];
46
+ /** Montos, NIFs, IBANs, códigos — SIEMPRE con `tabular-nums` y, en tablas, a la derecha. */
47
+ readonly mono: readonly ["ui-monospace", "SFMono-Regular", "Menlo", "Monaco", "Consolas", "monospace"];
48
+ };
49
+ export type TypeStyle = {
50
+ fontFamily: readonly string[];
51
+ fontSize: string;
52
+ fontWeight: number;
53
+ lineHeight: number;
54
+ letterSpacing: string;
55
+ };
56
+ export declare const typography: Record<string, TypeStyle>;
57
+ /** Radios por rol — controles, cards, badges, pills. */
58
+ export declare const radius: {
59
+ readonly control: "0.5rem";
60
+ readonly card: "0.75rem";
61
+ readonly badge: "0.375rem";
62
+ readonly pill: "9999px";
63
+ };
64
+ export declare const spacing: {
65
+ readonly xs: "0.375rem";
66
+ readonly sm: "0.625rem";
67
+ readonly md: "1rem";
68
+ readonly lg: "1.25rem";
69
+ readonly xl: "2.5rem";
70
+ };
71
+ /**
72
+ * Recetas de componente del frontmatter, con las referencias resueltas.
73
+ * Son la forma canónica, no una imposición: una app de partner puede montar
74
+ * sus propios componentes con los tokens de arriba.
75
+ */
76
+ export declare const components: {
77
+ readonly buttonPrimary: {
78
+ readonly backgroundColor: "oklch(48% 0.20 278)";
79
+ readonly textColor: "#ffffff";
80
+ readonly rounded: "0.5rem";
81
+ readonly padding: "0.5rem 1rem";
82
+ };
83
+ readonly buttonSecondary: {
84
+ readonly backgroundColor: "#ffffff";
85
+ readonly textColor: "#1e293b";
86
+ readonly rounded: "0.5rem";
87
+ readonly padding: "0.5rem 1rem";
88
+ };
89
+ readonly input: {
90
+ readonly backgroundColor: "#ffffff";
91
+ readonly textColor: "#1e293b";
92
+ readonly rounded: "0.5rem";
93
+ readonly padding: "0.5rem 0.75rem";
94
+ };
95
+ readonly card: {
96
+ readonly backgroundColor: "#ffffff";
97
+ readonly textColor: "#1e293b";
98
+ readonly rounded: "0.75rem";
99
+ readonly padding: "1.25rem";
100
+ };
101
+ readonly badge: {
102
+ readonly backgroundColor: "oklch(96% 0.04 278)";
103
+ readonly textColor: "oklch(48% 0.20 278)";
104
+ readonly rounded: "0.375rem";
105
+ readonly padding: "0.125rem 0.5rem";
106
+ };
107
+ };
108
+ /**
109
+ * Las reglas con nombre del sistema, en forma consultable (para linters de
110
+ * partner, documentación generada o simple lectura). El detalle narrativo
111
+ * vive en DESIGN.md; esto es el resumen operativo.
112
+ */
113
+ export declare const namedRules: {
114
+ readonly unaSolaVoz: "El violeta OKLCH 278 es la única voz de marca; purple-*/violet-* de Tailwind quedan prohibidos.";
115
+ readonly semaforoContable: "success/warning/danger hablan SOLO de estado de dinero y cumplimiento; el violeta jamás comunica estado.";
116
+ readonly limiteDelSlate: "El texto legible nunca baja de mutedInk (#475569); subtleInk es solo decorativo (no cumple AA).";
117
+ readonly planoPorDefecto: "Profundidad por hairlines de 1px y contraste de superficie; sombra máxima shadow-sm y siempre con borde.";
118
+ readonly numerosTabulares: "Todo dato financiero o estructurado va en mono con tabular-nums y, en tablas, alineado a la derecha.";
119
+ readonly sinEmojis: "Nada de emojis en la UI: StatusBadge, iconos o puntos de color.";
120
+ };
121
+ /** Fuentes vetadas y jubiladas por DESIGN.md §3 — no reintroducir. */
122
+ export declare const forbiddenFonts: readonly ["Sora", "DM Sans", "Space Mono", "IBM Plex", "Outfit", "Nunito", "Raleway", "Lato", "Poppins", "Lexend", "Source Sans 3", "Bricolage Grotesque", "Hanken Grotesk"];
123
+ export declare const tokens: {
124
+ readonly colors: {
125
+ /** La única voz de marca: acciones primarias, enlaces, navegación activa, foco. */
126
+ readonly primary: "oklch(48% 0.20 278)";
127
+ readonly primaryHover: "oklch(44% 0.22 278)";
128
+ /** Fondos de estado activo, badges de marca. */
129
+ readonly primaryContainer: "oklch(96% 0.04 278)";
130
+ /** Fondo de avatares de iniciales (texto en `primary`). */
131
+ readonly primaryContainerSubtle: "oklch(95% 0.018 278)";
132
+ /** Texto principal (slate-800). */
133
+ readonly ink: "#1e293b";
134
+ /** Texto secundario y cuerpo de lectura (slate-600) — el LÍMITE legible. */
135
+ readonly mutedInk: "#475569";
136
+ /** SOLO decorativo (slate-400): iconos de apoyo, placeholders, disabled. ~3:1 sobre blanco, no cumple AA para texto. */
137
+ readonly subtleInk: "#94a3b8";
138
+ /** Cards y formularios. */
139
+ readonly surface: "#ffffff";
140
+ /** Fondo de página y sidebar (slate-50). */
141
+ readonly surfaceMuted: "#f8fafc";
142
+ /** Bordes de card y panel (slate-200). */
143
+ readonly border: "#e2e8f0";
144
+ /** Separadores internos de card (slate-100). */
145
+ readonly borderSubtle: "#f1f5f9";
146
+ readonly success: "oklch(52% 0.18 155)";
147
+ readonly successContainer: "oklch(97% 0.03 155)";
148
+ readonly warning: "oklch(62% 0.18 75)";
149
+ readonly warningContainer: "oklch(98% 0.02 75)";
150
+ readonly danger: "oklch(54% 0.22 25)";
151
+ readonly dangerContainer: "oklch(98% 0.02 25)";
152
+ };
153
+ readonly fontFamilies: {
154
+ /** Titulares y superficies comerciales (login, landing). */
155
+ readonly display: readonly ["Plus Jakarta Sans", "system-ui", "sans-serif"];
156
+ /** El trabajo: tablas, formularios, lectura funcional. */
157
+ readonly body: readonly ["Inter", "system-ui", "sans-serif"];
158
+ /** Montos, NIFs, IBANs, códigos — SIEMPRE con `tabular-nums` y, en tablas, a la derecha. */
159
+ readonly mono: readonly ["ui-monospace", "SFMono-Regular", "Menlo", "Monaco", "Consolas", "monospace"];
160
+ };
161
+ readonly typography: Record<string, TypeStyle>;
162
+ readonly radius: {
163
+ readonly control: "0.5rem";
164
+ readonly card: "0.75rem";
165
+ readonly badge: "0.375rem";
166
+ readonly pill: "9999px";
167
+ };
168
+ readonly spacing: {
169
+ readonly xs: "0.375rem";
170
+ readonly sm: "0.625rem";
171
+ readonly md: "1rem";
172
+ readonly lg: "1.25rem";
173
+ readonly xl: "2.5rem";
174
+ };
175
+ readonly components: {
176
+ readonly buttonPrimary: {
177
+ readonly backgroundColor: "oklch(48% 0.20 278)";
178
+ readonly textColor: "#ffffff";
179
+ readonly rounded: "0.5rem";
180
+ readonly padding: "0.5rem 1rem";
181
+ };
182
+ readonly buttonSecondary: {
183
+ readonly backgroundColor: "#ffffff";
184
+ readonly textColor: "#1e293b";
185
+ readonly rounded: "0.5rem";
186
+ readonly padding: "0.5rem 1rem";
187
+ };
188
+ readonly input: {
189
+ readonly backgroundColor: "#ffffff";
190
+ readonly textColor: "#1e293b";
191
+ readonly rounded: "0.5rem";
192
+ readonly padding: "0.5rem 0.75rem";
193
+ };
194
+ readonly card: {
195
+ readonly backgroundColor: "#ffffff";
196
+ readonly textColor: "#1e293b";
197
+ readonly rounded: "0.75rem";
198
+ readonly padding: "1.25rem";
199
+ };
200
+ readonly badge: {
201
+ readonly backgroundColor: "oklch(96% 0.04 278)";
202
+ readonly textColor: "oklch(48% 0.20 278)";
203
+ readonly rounded: "0.375rem";
204
+ readonly padding: "0.125rem 0.5rem";
205
+ };
206
+ };
207
+ };
208
+ export type PimiaTokens = typeof tokens;
package/dist/tokens.js ADDED
@@ -0,0 +1,188 @@
1
+ /**
2
+ * Tokens del sistema de diseño de Pimia («los números en limpio»).
3
+ *
4
+ * Fuente de verdad: DESIGN.md del repo de la plataforma (frontmatter + reglas
5
+ * con nombre), snapshot del 2026-07-30. Este paquete NO inventa valores: los
6
+ * transcribe para que una app de partner pueda adoptarlos — o ignorarlos por
7
+ * completo, que es exactamente lo que significa white-label.
8
+ *
9
+ * Los canónicos de marca y semáforo van en OKLCH (matiz 278 para la marca);
10
+ * los `hex` que aparecen en comentarios son equivalencias orientativas.
11
+ */
12
+ export const colors = {
13
+ /** La única voz de marca: acciones primarias, enlaces, navegación activa, foco. */
14
+ primary: 'oklch(48% 0.20 278)', // ≈ #4b44ca
15
+ primaryHover: 'oklch(44% 0.22 278)', // ≈ #422fc7
16
+ /** Fondos de estado activo, badges de marca. */
17
+ primaryContainer: 'oklch(96% 0.04 278)', // ≈ #ebf0ff
18
+ /** Fondo de avatares de iniciales (texto en `primary`). */
19
+ primaryContainerSubtle: 'oklch(95% 0.018 278)',
20
+ /** Texto principal (slate-800). */
21
+ ink: '#1e293b',
22
+ /** Texto secundario y cuerpo de lectura (slate-600) — el LÍMITE legible. */
23
+ mutedInk: '#475569',
24
+ /** SOLO decorativo (slate-400): iconos de apoyo, placeholders, disabled. ~3:1 sobre blanco, no cumple AA para texto. */
25
+ subtleInk: '#94a3b8',
26
+ /** Cards y formularios. */
27
+ surface: '#ffffff',
28
+ /** Fondo de página y sidebar (slate-50). */
29
+ surfaceMuted: '#f8fafc',
30
+ /** Bordes de card y panel (slate-200). */
31
+ border: '#e2e8f0',
32
+ /** Separadores internos de card (slate-100). */
33
+ borderSubtle: '#f1f5f9',
34
+ // El semáforo contable: habla SOLO de estado de dinero y cumplimiento,
35
+ // nunca de marca. Cada estado con su `-container` pastel para badges.
36
+ success: 'oklch(52% 0.18 155)', // ≈ #008435
37
+ successContainer: 'oklch(97% 0.03 155)', // ≈ #e6fcec
38
+ warning: 'oklch(62% 0.18 75)', // ≈ #c37000
39
+ warningContainer: 'oklch(98% 0.02 75)', // ≈ #fff7ea
40
+ danger: 'oklch(54% 0.22 25)', // ≈ #d00021
41
+ dangerContainer: 'oklch(98% 0.02 25)', // ≈ #fff4f2
42
+ };
43
+ export const fontFamilies = {
44
+ /** Titulares y superficies comerciales (login, landing). */
45
+ display: ['Plus Jakarta Sans', 'system-ui', 'sans-serif'],
46
+ /** El trabajo: tablas, formularios, lectura funcional. */
47
+ body: ['Inter', 'system-ui', 'sans-serif'],
48
+ /** Montos, NIFs, IBANs, códigos — SIEMPRE con `tabular-nums` y, en tablas, a la derecha. */
49
+ mono: ['ui-monospace', 'SFMono-Regular', 'Menlo', 'Monaco', 'Consolas', 'monospace'],
50
+ };
51
+ export const typography = {
52
+ /** Hero comercial (Jakarta). Techo duro: 48px. */
53
+ display: {
54
+ fontFamily: fontFamilies.display,
55
+ fontSize: 'clamp(2.25rem, 5vw, 3rem)',
56
+ fontWeight: 800,
57
+ lineHeight: 1.05,
58
+ letterSpacing: '-0.025em',
59
+ },
60
+ /** h1 de página. */
61
+ headline: {
62
+ fontFamily: fontFamilies.display,
63
+ fontSize: '1.5rem',
64
+ fontWeight: 700,
65
+ lineHeight: 1.2,
66
+ letterSpacing: 'normal',
67
+ },
68
+ /** h2 de sección y cabeceras de card grandes. */
69
+ title: {
70
+ fontFamily: fontFamilies.display,
71
+ fontSize: '1.125rem',
72
+ fontWeight: 600,
73
+ lineHeight: 1.3,
74
+ letterSpacing: 'normal',
75
+ },
76
+ /** Celdas, formularios, lectura funcional. */
77
+ body: {
78
+ fontFamily: fontFamilies.body,
79
+ fontSize: '0.875rem',
80
+ fontWeight: 400,
81
+ lineHeight: 1.5,
82
+ letterSpacing: 'normal',
83
+ },
84
+ /** Metadatos y filas secundarias (DESIGN.md §3, escala de trabajo). */
85
+ bodySm: {
86
+ fontFamily: fontFamilies.body,
87
+ fontSize: '0.75rem',
88
+ fontWeight: 400,
89
+ lineHeight: 1.5,
90
+ letterSpacing: 'normal',
91
+ },
92
+ /** Leyendas de campo y cabeceras de tabla: MAYÚSCULAS + tracking. */
93
+ label: {
94
+ fontFamily: fontFamilies.body,
95
+ fontSize: '0.6875rem',
96
+ fontWeight: 600,
97
+ lineHeight: 1.4,
98
+ letterSpacing: '0.05em',
99
+ },
100
+ };
101
+ /** Radios por rol — controles, cards, badges, pills. */
102
+ export const radius = {
103
+ control: '0.5rem', // botones e inputs (rounded-lg)
104
+ card: '0.75rem', // cards, panels, secciones (rounded-xl)
105
+ badge: '0.375rem', // StatusBadge
106
+ pill: '9999px',
107
+ };
108
+ export const spacing = {
109
+ xs: '0.375rem',
110
+ sm: '0.625rem',
111
+ md: '1rem',
112
+ lg: '1.25rem',
113
+ xl: '2.5rem',
114
+ };
115
+ /**
116
+ * Recetas de componente del frontmatter, con las referencias resueltas.
117
+ * Son la forma canónica, no una imposición: una app de partner puede montar
118
+ * sus propios componentes con los tokens de arriba.
119
+ */
120
+ export const components = {
121
+ buttonPrimary: {
122
+ backgroundColor: colors.primary,
123
+ textColor: colors.surface,
124
+ rounded: radius.control,
125
+ padding: '0.5rem 1rem',
126
+ },
127
+ buttonSecondary: {
128
+ backgroundColor: colors.surface,
129
+ textColor: colors.ink,
130
+ rounded: radius.control,
131
+ padding: '0.5rem 1rem',
132
+ },
133
+ input: {
134
+ backgroundColor: colors.surface,
135
+ textColor: colors.ink,
136
+ rounded: radius.control,
137
+ padding: '0.5rem 0.75rem',
138
+ },
139
+ card: {
140
+ backgroundColor: colors.surface,
141
+ textColor: colors.ink,
142
+ rounded: radius.card,
143
+ padding: '1.25rem',
144
+ },
145
+ badge: {
146
+ backgroundColor: colors.primaryContainer,
147
+ textColor: colors.primary,
148
+ rounded: radius.badge,
149
+ padding: '0.125rem 0.5rem',
150
+ },
151
+ };
152
+ /**
153
+ * Las reglas con nombre del sistema, en forma consultable (para linters de
154
+ * partner, documentación generada o simple lectura). El detalle narrativo
155
+ * vive en DESIGN.md; esto es el resumen operativo.
156
+ */
157
+ export const namedRules = {
158
+ unaSolaVoz: 'El violeta OKLCH 278 es la única voz de marca; purple-*/violet-* de Tailwind quedan prohibidos.',
159
+ semaforoContable: 'success/warning/danger hablan SOLO de estado de dinero y cumplimiento; el violeta jamás comunica estado.',
160
+ limiteDelSlate: 'El texto legible nunca baja de mutedInk (#475569); subtleInk es solo decorativo (no cumple AA).',
161
+ planoPorDefecto: 'Profundidad por hairlines de 1px y contraste de superficie; sombra máxima shadow-sm y siempre con borde.',
162
+ numerosTabulares: 'Todo dato financiero o estructurado va en mono con tabular-nums y, en tablas, alineado a la derecha.',
163
+ sinEmojis: 'Nada de emojis en la UI: StatusBadge, iconos o puntos de color.',
164
+ };
165
+ /** Fuentes vetadas y jubiladas por DESIGN.md §3 — no reintroducir. */
166
+ export const forbiddenFonts = [
167
+ 'Sora',
168
+ 'DM Sans',
169
+ 'Space Mono',
170
+ 'IBM Plex',
171
+ 'Outfit',
172
+ 'Nunito',
173
+ 'Raleway',
174
+ 'Lato',
175
+ 'Poppins',
176
+ 'Lexend',
177
+ 'Source Sans 3',
178
+ 'Bricolage Grotesque',
179
+ 'Hanken Grotesk',
180
+ ];
181
+ export const tokens = {
182
+ colors,
183
+ fontFamilies,
184
+ typography,
185
+ radius,
186
+ spacing,
187
+ components,
188
+ };
package/package.json ADDED
@@ -0,0 +1,55 @@
1
+ {
2
+ "name": "@pimia/design-tokens",
3
+ "version": "0.1.0",
4
+ "description": "Sistema de diseño de Pimia como paquete OPCIONAL para apps de partner: tokens tipados, variables CSS y preset de Tailwind. El white-label es poder no usarlo.",
5
+ "license": "MIT",
6
+ "author": "Pimia (https://pimia.es)",
7
+ "homepage": "https://github.com/Pimia-AI/pimia-sdks/tree/main/design-tokens#readme",
8
+ "repository": {
9
+ "type": "git",
10
+ "url": "git+https://github.com/Pimia-AI/pimia-sdks.git",
11
+ "directory": "design-tokens"
12
+ },
13
+ "bugs": {
14
+ "url": "https://github.com/Pimia-AI/pimia-sdks/issues"
15
+ },
16
+ "publishConfig": {
17
+ "access": "public"
18
+ },
19
+ "type": "module",
20
+ "main": "./dist/index.js",
21
+ "types": "./dist/index.d.ts",
22
+ "exports": {
23
+ ".": {
24
+ "types": "./dist/index.d.ts",
25
+ "import": "./dist/index.js"
26
+ },
27
+ "./tailwind": {
28
+ "types": "./dist/tailwind.d.ts",
29
+ "import": "./dist/tailwind.js"
30
+ },
31
+ "./pimia.css": "./dist/pimia.css"
32
+ },
33
+ "files": [
34
+ "dist",
35
+ "README.md"
36
+ ],
37
+ "engines": {
38
+ "node": ">=20"
39
+ },
40
+ "scripts": {
41
+ "build": "tsc -p tsconfig.json && node scripts/emit-css.mjs",
42
+ "typecheck": "tsc -p tsconfig.json --noEmit",
43
+ "test": "node --test test/*.test.js",
44
+ "prepublishOnly": "npm run build"
45
+ },
46
+ "devDependencies": {
47
+ "typescript": "^5.7.2"
48
+ },
49
+ "keywords": [
50
+ "pimia",
51
+ "design-tokens",
52
+ "design-system",
53
+ "tailwind"
54
+ ]
55
+ }