@rainersoft/design-tokens 2.0.0 → 2.3.1
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 +167 -519
- package/dist/index.d.mts +8485 -0
- package/dist/index.d.ts +1052 -31
- package/dist/index.js +44 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +16 -2
- package/dist/index.mjs.map +1 -1
- package/formats/tokens.json +7 -4
- package/package.json +38 -86
- package/themes/dark.ts +0 -89
- package/themes/index.ts +0 -99
- package/themes/light.ts +0 -88
- package/tokens/accessibility.ts +0 -280
- package/tokens/animations.json +0 -142
- package/tokens/breakpoints.json +0 -30
- package/tokens/colors/dark.json +0 -296
- package/tokens/colors/light.json +0 -272
- package/tokens/components/celestial-background.json +0 -106
- package/tokens/effects.json +0 -125
- package/tokens/hero.json +0 -69
- package/tokens/index.ts +0 -443
- package/tokens/motion.json +0 -33
- package/tokens/radius.json +0 -16
- package/tokens/shadows.json +0 -33
- package/tokens/spacing.json +0 -42
- package/tokens/typography.json +0 -264
- package/tokens/utilities.ts +0 -594
- package/tokens/z-index.json +0 -27
package/tokens/accessibility.ts
DELETED
|
@@ -1,280 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @fileoverview Utilitários de Acessibilidade - Verificação de Contraste WCAG
|
|
3
|
-
*
|
|
4
|
-
* @description
|
|
5
|
-
* Utilitários para verificar e garantir conformidade com padrões WCAG AA/AAA
|
|
6
|
-
* de contraste de cores. Essas funções são agnósticas e podem ser usadas em
|
|
7
|
-
* qualquer ambiente (web, mobile, desktop).
|
|
8
|
-
*
|
|
9
|
-
* @module tokens/accessibility
|
|
10
|
-
* @version 2.0.0
|
|
11
|
-
* @author Rainer Teixeira
|
|
12
|
-
* @since 1.0.0
|
|
13
|
-
*/
|
|
14
|
-
|
|
15
|
-
/**
|
|
16
|
-
* Converte cor hexadecimal para RGB
|
|
17
|
-
*
|
|
18
|
-
* @param {string} hex - Cor em formato hexadecimal (#RRGGBB ou RRGGBB)
|
|
19
|
-
* @returns {Object} Objeto com valores RGB { r, g, b }
|
|
20
|
-
*
|
|
21
|
-
* @example
|
|
22
|
-
* ```typescript
|
|
23
|
-
* const rgb = hexToRgb('#0891b2');
|
|
24
|
-
* // { r: 8, g: 145, b: 178 }
|
|
25
|
-
* ```
|
|
26
|
-
*/
|
|
27
|
-
export function hexToRgb(hex: string): { r: number; g: number; b: number } {
|
|
28
|
-
const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
|
|
29
|
-
if (!result) {
|
|
30
|
-
throw new Error(`Invalid hex color: ${hex}`);
|
|
31
|
-
}
|
|
32
|
-
return {
|
|
33
|
-
r: parseInt(result[1], 16),
|
|
34
|
-
g: parseInt(result[2], 16),
|
|
35
|
-
b: parseInt(result[3], 16),
|
|
36
|
-
};
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
/**
|
|
40
|
-
* Calcula a luminância relativa de uma cor RGB
|
|
41
|
-
*
|
|
42
|
-
* @param {number} r - Componente vermelho (0-255)
|
|
43
|
-
* @param {number} g - Componente verde (0-255)
|
|
44
|
-
* @param {number} b - Componente azul (0-255)
|
|
45
|
-
* @returns {number} Luminância relativa (0-1)
|
|
46
|
-
*
|
|
47
|
-
* @description
|
|
48
|
-
* Fórmula baseada na recomendação WCAG 2.1 para cálculo de luminância.
|
|
49
|
-
*
|
|
50
|
-
* @example
|
|
51
|
-
* ```typescript
|
|
52
|
-
* const luminance = getLuminance(8, 145, 178);
|
|
53
|
-
* // 0.234
|
|
54
|
-
* ```
|
|
55
|
-
*/
|
|
56
|
-
export function getLuminance(r: number, g: number, b: number): number {
|
|
57
|
-
const [rs, gs, bs] = [r, g, b].map((val) => {
|
|
58
|
-
const v = val / 255;
|
|
59
|
-
return v <= 0.03928 ? v / 12.92 : Math.pow((v + 0.055) / 1.055, 2.4);
|
|
60
|
-
});
|
|
61
|
-
return 0.2126 * rs + 0.7152 * gs + 0.0722 * bs;
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
/**
|
|
65
|
-
* Calcula o contraste entre duas cores
|
|
66
|
-
*
|
|
67
|
-
* @param {string} color1 - Primeira cor em hexadecimal
|
|
68
|
-
* @param {string} color2 - Segunda cor em hexadecimal
|
|
69
|
-
* @returns {number} Razão de contraste (1-21)
|
|
70
|
-
*
|
|
71
|
-
* @description
|
|
72
|
-
* Retorna a razão de contraste entre duas cores conforme WCAG 2.1.
|
|
73
|
-
* Valores mínimos recomendados:
|
|
74
|
-
* - WCAG AA (normal): 4.5:1 para texto normal, 3:1 para texto grande
|
|
75
|
-
* - WCAG AAA (melhor): 7:1 para texto normal, 4.5:1 para texto grande
|
|
76
|
-
*
|
|
77
|
-
* @example
|
|
78
|
-
* ```typescript
|
|
79
|
-
* const contrast = getContrast('#ffffff', '#000000');
|
|
80
|
-
* // 21 (máximo contraste)
|
|
81
|
-
*
|
|
82
|
-
* const contrast2 = getContrast('#0891b2', '#ffffff');
|
|
83
|
-
* // 3.2 (atende WCAG AA para texto grande)
|
|
84
|
-
* ```
|
|
85
|
-
*/
|
|
86
|
-
export function getContrast(
|
|
87
|
-
color1: string,
|
|
88
|
-
color2: string
|
|
89
|
-
): number {
|
|
90
|
-
const rgb1 = hexToRgb(color1);
|
|
91
|
-
const rgb2 = hexToRgb(color2);
|
|
92
|
-
|
|
93
|
-
const lum1 = getLuminance(rgb1.r, rgb1.g, rgb1.b);
|
|
94
|
-
const lum2 = getLuminance(rgb2.r, rgb2.g, rgb2.b);
|
|
95
|
-
|
|
96
|
-
const lighter = Math.max(lum1, lum2);
|
|
97
|
-
const darker = Math.min(lum1, lum2);
|
|
98
|
-
|
|
99
|
-
return (lighter + 0.05) / (darker + 0.05);
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
/**
|
|
103
|
-
* Verifica se o contraste atende ao padrão WCAG AA
|
|
104
|
-
*
|
|
105
|
-
* @param {string} foreground - Cor do texto (hexadecimal)
|
|
106
|
-
* @param {string} background - Cor de fundo (hexadecimal)
|
|
107
|
-
* @param {boolean} [largeText=false] - Se o texto é grande (>=18pt ou >=14pt bold)
|
|
108
|
-
* @returns {boolean} true se atende WCAG AA, false caso contrário
|
|
109
|
-
*
|
|
110
|
-
* @description
|
|
111
|
-
* WCAG AA requer:
|
|
112
|
-
* - Texto normal: contraste mínimo de 4.5:1
|
|
113
|
-
* - Texto grande: contraste mínimo de 3:1
|
|
114
|
-
*
|
|
115
|
-
* @example
|
|
116
|
-
* ```typescript
|
|
117
|
-
* const meetsAA = meetsWCAGAA('#0891b2', '#ffffff', false);
|
|
118
|
-
* // true (contraste 3.2:1, mas texto normal precisa 4.5:1)
|
|
119
|
-
*
|
|
120
|
-
* const meetsAALarge = meetsWCAGAA('#0891b2', '#ffffff', true);
|
|
121
|
-
* // true (contraste 3.2:1, texto grande precisa 3:1)
|
|
122
|
-
* ```
|
|
123
|
-
*/
|
|
124
|
-
export function meetsWCAGAA(
|
|
125
|
-
foreground: string,
|
|
126
|
-
background: string,
|
|
127
|
-
largeText: boolean = false
|
|
128
|
-
): boolean {
|
|
129
|
-
const contrast = getContrast(foreground, background);
|
|
130
|
-
return largeText ? contrast >= 3 : contrast >= 4.5;
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
/**
|
|
134
|
-
* Verifica se o contraste atende ao padrão WCAG AAA
|
|
135
|
-
*
|
|
136
|
-
* @param {string} foreground - Cor do texto (hexadecimal)
|
|
137
|
-
* @param {string} background - Cor de fundo (hexadecimal)
|
|
138
|
-
* @param {boolean} [largeText=false] - Se o texto é grande (>=18pt ou >=14pt bold)
|
|
139
|
-
* @returns {boolean} true se atende WCAG AAA, false caso contrário
|
|
140
|
-
*
|
|
141
|
-
* @description
|
|
142
|
-
* WCAG AAA requer:
|
|
143
|
-
* - Texto normal: contraste mínimo de 7:1
|
|
144
|
-
* - Texto grande: contraste mínimo de 4.5:1
|
|
145
|
-
*
|
|
146
|
-
* @example
|
|
147
|
-
* ```typescript
|
|
148
|
-
* const meetsAAA = meetsWCAGAAA('#000000', '#ffffff', false);
|
|
149
|
-
* // true (contraste 21:1)
|
|
150
|
-
* ```
|
|
151
|
-
*/
|
|
152
|
-
export function meetsWCAGAAA(
|
|
153
|
-
foreground: string,
|
|
154
|
-
background: string,
|
|
155
|
-
largeText: boolean = false
|
|
156
|
-
): boolean {
|
|
157
|
-
const contrast = getContrast(foreground, background);
|
|
158
|
-
return largeText ? contrast >= 4.5 : contrast >= 7;
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
/**
|
|
162
|
-
* Retorna informações completas de contraste entre duas cores
|
|
163
|
-
*
|
|
164
|
-
* @param {string} foreground - Cor do texto (hexadecimal)
|
|
165
|
-
* @param {string} background - Cor de fundo (hexadecimal)
|
|
166
|
-
* @returns {Object} Objeto com informações de contraste
|
|
167
|
-
*
|
|
168
|
-
* @example
|
|
169
|
-
* ```typescript
|
|
170
|
-
* const info = getContrastInfo('#0891b2', '#ffffff');
|
|
171
|
-
* // {
|
|
172
|
-
* // contrast: 3.2,
|
|
173
|
-
* // meetsAA: false,
|
|
174
|
-
* // meetsAALarge: true,
|
|
175
|
-
* // meetsAAA: false,
|
|
176
|
-
* // meetsAAALarge: false,
|
|
177
|
-
* // level: 'AA Large'
|
|
178
|
-
* // }
|
|
179
|
-
* ```
|
|
180
|
-
*/
|
|
181
|
-
export function getContrastInfo(
|
|
182
|
-
foreground: string,
|
|
183
|
-
background: string
|
|
184
|
-
): {
|
|
185
|
-
contrast: number;
|
|
186
|
-
meetsAA: boolean;
|
|
187
|
-
meetsAALarge: boolean;
|
|
188
|
-
meetsAAA: boolean;
|
|
189
|
-
meetsAAALarge: boolean;
|
|
190
|
-
level: 'Fail' | 'AA Large' | 'AA' | 'AAA Large' | 'AAA';
|
|
191
|
-
} {
|
|
192
|
-
const contrast = getContrast(foreground, background);
|
|
193
|
-
const meetsAA = contrast >= 4.5;
|
|
194
|
-
const meetsAALarge = contrast >= 3;
|
|
195
|
-
const meetsAAA = contrast >= 7;
|
|
196
|
-
const meetsAAALarge = contrast >= 4.5;
|
|
197
|
-
|
|
198
|
-
let level: 'Fail' | 'AA Large' | 'AA' | 'AAA Large' | 'AAA' = 'Fail';
|
|
199
|
-
if (meetsAAA) {
|
|
200
|
-
level = 'AAA';
|
|
201
|
-
} else if (meetsAAALarge) {
|
|
202
|
-
level = 'AAA Large';
|
|
203
|
-
} else if (meetsAA) {
|
|
204
|
-
level = 'AA';
|
|
205
|
-
} else if (meetsAALarge) {
|
|
206
|
-
level = 'AA Large';
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
return {
|
|
210
|
-
contrast,
|
|
211
|
-
meetsAA,
|
|
212
|
-
meetsAALarge,
|
|
213
|
-
meetsAAA,
|
|
214
|
-
meetsAAALarge,
|
|
215
|
-
level,
|
|
216
|
-
};
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
/**
|
|
220
|
-
* Valida se uma combinação de cores atende aos padrões de acessibilidade
|
|
221
|
-
*
|
|
222
|
-
* @param {string} foreground - Cor do texto (hexadecimal)
|
|
223
|
-
* @param {string} background - Cor de fundo (hexadecimal)
|
|
224
|
-
* @param {Object} options - Opções de validação
|
|
225
|
-
* @param {boolean} [options.requireAAA=false] - Se deve requerer WCAG AAA
|
|
226
|
-
* @param {boolean} [options.largeText=false] - Se o texto é grande
|
|
227
|
-
* @returns {Object} Resultado da validação
|
|
228
|
-
*
|
|
229
|
-
* @example
|
|
230
|
-
* ```typescript
|
|
231
|
-
* const validation = validateContrast('#0891b2', '#ffffff', {
|
|
232
|
-
* largeText: true
|
|
233
|
-
* });
|
|
234
|
-
* // {
|
|
235
|
-
* // valid: true,
|
|
236
|
-
* // level: 'AA Large',
|
|
237
|
-
* // contrast: 3.2,
|
|
238
|
-
* // message: 'Contraste válido para texto grande (WCAG AA)'
|
|
239
|
-
* // }
|
|
240
|
-
* ```
|
|
241
|
-
*/
|
|
242
|
-
export function validateContrast(
|
|
243
|
-
foreground: string,
|
|
244
|
-
background: string,
|
|
245
|
-
options: {
|
|
246
|
-
requireAAA?: boolean;
|
|
247
|
-
largeText?: boolean;
|
|
248
|
-
} = {}
|
|
249
|
-
): {
|
|
250
|
-
valid: boolean;
|
|
251
|
-
level: string;
|
|
252
|
-
contrast: number;
|
|
253
|
-
message: string;
|
|
254
|
-
} {
|
|
255
|
-
const { requireAAA = false, largeText = false } = options;
|
|
256
|
-
const info = getContrastInfo(foreground, background);
|
|
257
|
-
|
|
258
|
-
let valid = false;
|
|
259
|
-
let message = '';
|
|
260
|
-
|
|
261
|
-
if (requireAAA) {
|
|
262
|
-
valid = largeText ? info.meetsAAALarge : info.meetsAAA;
|
|
263
|
-
message = valid
|
|
264
|
-
? `Contraste válido (WCAG AAA${largeText ? ' - Texto Grande' : ''})`
|
|
265
|
-
: `Contraste insuficiente para WCAG AAA${largeText ? ' - Texto Grande' : ''}. Requerido: ${largeText ? '4.5:1' : '7:1'}, atual: ${info.contrast.toFixed(2)}:1`;
|
|
266
|
-
} else {
|
|
267
|
-
valid = largeText ? info.meetsAALarge : info.meetsAA;
|
|
268
|
-
message = valid
|
|
269
|
-
? `Contraste válido (WCAG AA${largeText ? ' - Texto Grande' : ''})`
|
|
270
|
-
: `Contraste insuficiente para WCAG AA${largeText ? ' - Texto Grande' : ''}. Requerido: ${largeText ? '3:1' : '4.5:1'}, atual: ${info.contrast.toFixed(2)}:1`;
|
|
271
|
-
}
|
|
272
|
-
|
|
273
|
-
return {
|
|
274
|
-
valid,
|
|
275
|
-
level: info.level,
|
|
276
|
-
contrast: info.contrast,
|
|
277
|
-
message,
|
|
278
|
-
};
|
|
279
|
-
}
|
|
280
|
-
|
package/tokens/animations.json
DELETED
|
@@ -1,142 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"animations": {
|
|
3
|
-
"accordion-down": {
|
|
4
|
-
"name": "accordion-down",
|
|
5
|
-
"duration": "0.2s",
|
|
6
|
-
"timingFunction": "ease-out",
|
|
7
|
-
"keyframes": {
|
|
8
|
-
"from": {
|
|
9
|
-
"height": "0"
|
|
10
|
-
},
|
|
11
|
-
"to": {
|
|
12
|
-
"height": "var(--radix-accordion-content-height)"
|
|
13
|
-
}
|
|
14
|
-
}
|
|
15
|
-
},
|
|
16
|
-
"accordion-up": {
|
|
17
|
-
"name": "accordion-up",
|
|
18
|
-
"duration": "0.2s",
|
|
19
|
-
"timingFunction": "ease-out",
|
|
20
|
-
"keyframes": {
|
|
21
|
-
"from": {
|
|
22
|
-
"height": "var(--radix-accordion-content-height)"
|
|
23
|
-
},
|
|
24
|
-
"to": {
|
|
25
|
-
"height": "0"
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
},
|
|
29
|
-
"slide-in": {
|
|
30
|
-
"name": "slide-in",
|
|
31
|
-
"duration": "0.3s",
|
|
32
|
-
"timingFunction": "ease-out",
|
|
33
|
-
"keyframes": {
|
|
34
|
-
"0%": {
|
|
35
|
-
"transform": "translateY(-10px)",
|
|
36
|
-
"opacity": "0"
|
|
37
|
-
},
|
|
38
|
-
"100%": {
|
|
39
|
-
"transform": "translateY(0)",
|
|
40
|
-
"opacity": "1"
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
},
|
|
44
|
-
"fade-in": {
|
|
45
|
-
"name": "fade-in",
|
|
46
|
-
"duration": "0.5s",
|
|
47
|
-
"timingFunction": "ease-in",
|
|
48
|
-
"keyframes": {
|
|
49
|
-
"0%": {
|
|
50
|
-
"opacity": "0"
|
|
51
|
-
},
|
|
52
|
-
"100%": {
|
|
53
|
-
"opacity": "1"
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
},
|
|
57
|
-
"glitch": {
|
|
58
|
-
"name": "glitch",
|
|
59
|
-
"duration": "4s",
|
|
60
|
-
"timingFunction": "linear",
|
|
61
|
-
"iterationCount": "infinite",
|
|
62
|
-
"keyframes": {
|
|
63
|
-
"0%, 100%": {
|
|
64
|
-
"transform": "translate(0)"
|
|
65
|
-
},
|
|
66
|
-
"10%": {
|
|
67
|
-
"transform": "translate(-2px, 2px)"
|
|
68
|
-
},
|
|
69
|
-
"20%": {
|
|
70
|
-
"transform": "translate(2px, -2px)"
|
|
71
|
-
},
|
|
72
|
-
"30%, 50%, 70%, 90%": {
|
|
73
|
-
"transform": "translate(0)"
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
},
|
|
77
|
-
"neon-pulse": {
|
|
78
|
-
"name": "neon-pulse",
|
|
79
|
-
"duration": "2s",
|
|
80
|
-
"timingFunction": "ease-in-out",
|
|
81
|
-
"iterationCount": "infinite",
|
|
82
|
-
"direction": "alternate",
|
|
83
|
-
"keyframes": {
|
|
84
|
-
"0%, 100%": {
|
|
85
|
-
"filter": "brightness(1) saturate(1)"
|
|
86
|
-
},
|
|
87
|
-
"50%": {
|
|
88
|
-
"filter": "brightness(1.3) saturate(1.2)"
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
},
|
|
92
|
-
"flicker": {
|
|
93
|
-
"name": "flicker",
|
|
94
|
-
"duration": "2s",
|
|
95
|
-
"timingFunction": "linear",
|
|
96
|
-
"iterationCount": "infinite",
|
|
97
|
-
"keyframes": {
|
|
98
|
-
"0%, 19.999%, 22%, 62.999%, 64%, 64.999%, 70%, 100%": {
|
|
99
|
-
"opacity": "1",
|
|
100
|
-
"filter": "brightness(1.2)"
|
|
101
|
-
},
|
|
102
|
-
"20%, 21.999%, 63%, 63.999%, 65%, 69.999%": {
|
|
103
|
-
"opacity": "0.85",
|
|
104
|
-
"filter": "brightness(0.9)"
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
},
|
|
108
|
-
"scan-line": {
|
|
109
|
-
"name": "scan-line",
|
|
110
|
-
"duration": "4s",
|
|
111
|
-
"timingFunction": "linear",
|
|
112
|
-
"iterationCount": "infinite",
|
|
113
|
-
"keyframes": {
|
|
114
|
-
"0%": {
|
|
115
|
-
"top": "0"
|
|
116
|
-
},
|
|
117
|
-
"100%": {
|
|
118
|
-
"top": "100%"
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
|
-
},
|
|
122
|
-
"glitch-after": {
|
|
123
|
-
"name": "glitch-after",
|
|
124
|
-
"duration": "3s",
|
|
125
|
-
"timingFunction": "linear",
|
|
126
|
-
"iterationCount": "infinite",
|
|
127
|
-
"keyframes": {
|
|
128
|
-
"0%, 100%": {
|
|
129
|
-
"opacity": "0"
|
|
130
|
-
},
|
|
131
|
-
"5%, 10%": {
|
|
132
|
-
"opacity": "0.8",
|
|
133
|
-
"transform": "translate(-3px, 3px)"
|
|
134
|
-
},
|
|
135
|
-
"15%, 95%": {
|
|
136
|
-
"opacity": "0"
|
|
137
|
-
}
|
|
138
|
-
}
|
|
139
|
-
}
|
|
140
|
-
}
|
|
141
|
-
}
|
|
142
|
-
|
package/tokens/breakpoints.json
DELETED
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"$schema": "https://json.schemastore.org/theme.json",
|
|
3
|
-
"$description": "Responsive breakpoints - Mobile-first approach",
|
|
4
|
-
"breakpoints": {
|
|
5
|
-
"xs": "0px",
|
|
6
|
-
"sm": "640px",
|
|
7
|
-
"md": "768px",
|
|
8
|
-
"lg": "1024px",
|
|
9
|
-
"xl": "1280px",
|
|
10
|
-
"2xl": "1536px",
|
|
11
|
-
"3xl": "1920px"
|
|
12
|
-
},
|
|
13
|
-
"container": {
|
|
14
|
-
"sm": "640px",
|
|
15
|
-
"md": "768px",
|
|
16
|
-
"lg": "1024px",
|
|
17
|
-
"xl": "1280px",
|
|
18
|
-
"2xl": "1536px",
|
|
19
|
-
"3xl": "1920px"
|
|
20
|
-
},
|
|
21
|
-
"mediaQueries": {
|
|
22
|
-
"xs": "@media (min-width: 0px)",
|
|
23
|
-
"sm": "@media (min-width: 640px)",
|
|
24
|
-
"md": "@media (min-width: 768px)",
|
|
25
|
-
"lg": "@media (min-width: 1024px)",
|
|
26
|
-
"xl": "@media (min-width: 1280px)",
|
|
27
|
-
"2xl": "@media (min-width: 1536px)",
|
|
28
|
-
"3xl": "@media (min-width: 1920px)"
|
|
29
|
-
}
|
|
30
|
-
}
|