@jjlmoya/utils-developer 1.11.0 → 1.13.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 (100) hide show
  1. package/package.json +7 -4
  2. package/scripts/postinstall.mjs +27 -0
  3. package/src/entries.ts +74 -0
  4. package/src/tool/aspectRatio/aspect-ratio-calculator.css +276 -0
  5. package/src/tool/aspectRatio/component.astro +0 -278
  6. package/src/tool/aspectRatio/entry.ts +30 -0
  7. package/src/tool/aspectRatio/index.ts +2 -32
  8. package/src/tool/calculadoraTiempoDatos/component.astro +0 -524
  9. package/src/tool/calculadoraTiempoDatos/data-time-calculator-web-speed-impact.css +522 -0
  10. package/src/tool/calculadoraTiempoDatos/entry.ts +29 -0
  11. package/src/tool/calculadoraTiempoDatos/index.ts +2 -31
  12. package/src/tool/colorConverter/color-converter-rgb-hex-hsl.css +262 -0
  13. package/src/tool/colorConverter/component.astro +0 -264
  14. package/src/tool/colorConverter/entry.ts +29 -0
  15. package/src/tool/colorConverter/index.ts +2 -31
  16. package/src/tool/conversorExcelCsvHtml/component.astro +0 -360
  17. package/src/tool/conversorExcelCsvHtml/entry.ts +29 -0
  18. package/src/tool/conversorExcelCsvHtml/excel-csv-html-table-converter.css +358 -0
  19. package/src/tool/conversorExcelCsvHtml/index.ts +2 -31
  20. package/src/tool/cronGenerator/component.astro +0 -317
  21. package/src/tool/cronGenerator/cron.css +315 -0
  22. package/src/tool/cronGenerator/entry.ts +30 -0
  23. package/src/tool/cronGenerator/index.ts +2 -32
  24. package/src/tool/cssSpecificityCalculator/component.astro +0 -205
  25. package/src/tool/cssSpecificityCalculator/css-specificity-calculator.css +203 -0
  26. package/src/tool/cssSpecificityCalculator/entry.ts +30 -0
  27. package/src/tool/cssSpecificityCalculator/index.ts +2 -32
  28. package/src/tool/cssToInlineConverter/component.astro +0 -150
  29. package/src/tool/cssToInlineConverter/css-to-inline-converter.css +148 -0
  30. package/src/tool/cssToInlineConverter/entry.ts +30 -0
  31. package/src/tool/cssToInlineConverter/index.ts +2 -32
  32. package/src/tool/duplicateCssRemover/component.astro +0 -197
  33. package/src/tool/duplicateCssRemover/duplicate-css-remover.css +195 -0
  34. package/src/tool/duplicateCssRemover/entry.ts +30 -0
  35. package/src/tool/duplicateCssRemover/index.ts +2 -32
  36. package/src/tool/generadorSecurityTxt/component.astro +0 -231
  37. package/src/tool/generadorSecurityTxt/entry.ts +29 -0
  38. package/src/tool/generadorSecurityTxt/index.ts +2 -31
  39. package/src/tool/generadorSecurityTxt/security-txt-generator-rfc-9116.css +229 -0
  40. package/src/tool/hashGenerator/component.astro +0 -229
  41. package/src/tool/hashGenerator/entry.ts +29 -0
  42. package/src/tool/hashGenerator/hash-generator.css +227 -0
  43. package/src/tool/hashGenerator/index.ts +2 -31
  44. package/src/tool/inspectorCertificadosSsl/component.astro +0 -261
  45. package/src/tool/inspectorCertificadosSsl/entry.ts +45 -0
  46. package/src/tool/inspectorCertificadosSsl/index.ts +2 -47
  47. package/src/tool/inspectorCertificadosSsl/ssl-tls-certificate-inspector.css +259 -0
  48. package/src/tool/jsonFormatter/component.astro +0 -346
  49. package/src/tool/jsonFormatter/entry.ts +30 -0
  50. package/src/tool/jsonFormatter/index.ts +2 -32
  51. package/src/tool/jsonFormatter/json-formatter.css +344 -0
  52. package/src/tool/keycode/component.astro +0 -298
  53. package/src/tool/keycode/entry.ts +30 -0
  54. package/src/tool/keycode/index.ts +2 -32
  55. package/src/tool/keycode/keycode.css +296 -0
  56. package/src/tool/llmCostCalculator/component.astro +0 -253
  57. package/src/tool/llmCostCalculator/entry.ts +46 -0
  58. package/src/tool/llmCostCalculator/index.ts +2 -48
  59. package/src/tool/llmCostCalculator/llm-cost-calculator.css +251 -0
  60. package/src/tool/mobileMockupGenerator/component.astro +0 -906
  61. package/src/tool/mobileMockupGenerator/entry.ts +45 -0
  62. package/src/tool/mobileMockupGenerator/index.ts +2 -47
  63. package/src/tool/mobileMockupGenerator/mobile-mockup-generator.css +904 -0
  64. package/src/tool/musicalTypography/component.astro +0 -291
  65. package/src/tool/musicalTypography/entry.ts +29 -0
  66. package/src/tool/musicalTypography/index.ts +2 -31
  67. package/src/tool/musicalTypography/musical-typography.css +289 -0
  68. package/src/tool/placeholderGenerator/component.astro +0 -255
  69. package/src/tool/placeholderGenerator/entry.ts +46 -0
  70. package/src/tool/placeholderGenerator/index.ts +2 -48
  71. package/src/tool/placeholderGenerator/placeholder-image-generator.css +253 -0
  72. package/src/tool/promptLibrary/component.astro +0 -689
  73. package/src/tool/promptLibrary/entry.ts +45 -0
  74. package/src/tool/promptLibrary/index.ts +2 -47
  75. package/src/tool/promptLibrary/prompt-library.css +687 -0
  76. package/src/tool/readabilityCalculator/component.astro +0 -322
  77. package/src/tool/readabilityCalculator/entry.ts +45 -0
  78. package/src/tool/readabilityCalculator/index.ts +2 -47
  79. package/src/tool/readabilityCalculator/visual-readability-calculator-wcag-apca.css +320 -0
  80. package/src/tool/svgSanitizer/component.astro +0 -289
  81. package/src/tool/svgSanitizer/entry.ts +45 -0
  82. package/src/tool/svgSanitizer/index.ts +2 -47
  83. package/src/tool/svgSanitizer/svg-sanitizer.css +287 -0
  84. package/src/tool/svgToCss/component.astro +0 -196
  85. package/src/tool/svgToCss/entry.ts +30 -0
  86. package/src/tool/svgToCss/index.ts +2 -32
  87. package/src/tool/svgToCss/svg-to-css-converter.css +194 -0
  88. package/src/tool/urlCleaner/component.astro +0 -282
  89. package/src/tool/urlCleaner/entry.ts +45 -0
  90. package/src/tool/urlCleaner/index.ts +2 -47
  91. package/src/tool/urlCleaner/url-tracking-cleaner.css +280 -0
  92. package/src/tool/urlEncoderDecoder/component.astro +0 -168
  93. package/src/tool/urlEncoderDecoder/entry.ts +30 -0
  94. package/src/tool/urlEncoderDecoder/index.ts +2 -32
  95. package/src/tool/urlEncoderDecoder/url-encoder-decoder.css +166 -0
  96. package/src/tool/utmGenerator/component.astro +0 -156
  97. package/src/tool/utmGenerator/entry.ts +29 -0
  98. package/src/tool/utmGenerator/index.ts +2 -31
  99. package/src/tool/utmGenerator/utm-generator.css +154 -0
  100. package/src/tools.ts +1 -1
@@ -0,0 +1,315 @@
1
+ .cron-root {
2
+ --cron-primary: #8b5cf6;
3
+ --cron-success: #10b981;
4
+ --cron-card-bg: #fff;
5
+ --cron-bg: #f8fafc;
6
+ --cron-text: #0f172a;
7
+ --cron-text-muted: #64748b;
8
+ --cron-border: #e2e8f0;
9
+
10
+ max-width: 900px;
11
+ margin: 2rem auto;
12
+ color: var(--cron-text);
13
+ }
14
+
15
+ :global(.theme-dark) .cron-root {
16
+ --cron-card-bg: #1e293b;
17
+ --cron-bg: #0f172a;
18
+ --cron-text: #f1f5f9;
19
+ --cron-text-muted: #94a3b8;
20
+ --cron-border: #334155;
21
+ }
22
+
23
+ .cron-outer-card {
24
+ background: var(--cron-card-bg);
25
+ border: 1px solid var(--cron-border);
26
+ border-radius: 1.5rem;
27
+ box-shadow: 0 4px 24px rgba(0, 0, 0, 0.07);
28
+ overflow: hidden;
29
+ }
30
+
31
+ .cron-hero {
32
+ background: #0f172a;
33
+ padding: 2.25rem 2rem 1.75rem;
34
+ display: flex;
35
+ flex-direction: column;
36
+ align-items: center;
37
+ gap: 1.25rem;
38
+ }
39
+
40
+ .cron-expr-row {
41
+ display: flex;
42
+ align-items: flex-start;
43
+ gap: 1.25rem;
44
+ flex-wrap: wrap;
45
+ justify-content: center;
46
+ }
47
+
48
+ .cron-part-wrapper {
49
+ display: flex;
50
+ flex-direction: column;
51
+ align-items: center;
52
+ gap: 0.375rem;
53
+ }
54
+
55
+ .cron-disp-part {
56
+ font-size: 3rem;
57
+ font-weight: 800;
58
+ color: #a78bfa;
59
+ line-height: 1;
60
+ font-variant-numeric: tabular-nums;
61
+ transition: color 0.2s;
62
+ }
63
+
64
+ .cron-part-label {
65
+ font-size: 0.65rem;
66
+ font-weight: 600;
67
+ color: #475569;
68
+ text-transform: uppercase;
69
+ letter-spacing: 0.08em;
70
+ white-space: nowrap;
71
+ }
72
+
73
+ .cron-human-wrap {
74
+ background: rgba(255, 255, 255, 0.06);
75
+ border: 1px solid rgba(255, 255, 255, 0.1);
76
+ border-radius: 0.75rem;
77
+ padding: 0.5rem 1.25rem;
78
+ }
79
+
80
+ .cron-human-text {
81
+ color: #cbd5e1;
82
+ font-size: 0.925rem;
83
+ font-weight: 500;
84
+ }
85
+
86
+ .cron-human-text[data-error] {
87
+ color: #f87171;
88
+ }
89
+
90
+ .cron-body {
91
+ padding: 1.5rem;
92
+ display: flex;
93
+ flex-direction: column;
94
+ gap: 1.25rem;
95
+ }
96
+
97
+ .cron-grid {
98
+ display: grid;
99
+ grid-template-columns: 1fr 1fr;
100
+ gap: 1.25rem;
101
+ }
102
+
103
+ @media (max-width: 700px) {
104
+ .cron-grid {
105
+ grid-template-columns: 1fr;
106
+ }
107
+ }
108
+
109
+ .cron-controls {
110
+ background: var(--cron-bg);
111
+ border: 1px solid var(--cron-border);
112
+ border-radius: 1rem;
113
+ padding: 1.125rem;
114
+ }
115
+
116
+ .cron-tabs {
117
+ display: flex;
118
+ gap: 0.5rem;
119
+ margin-bottom: 1.125rem;
120
+ border-bottom: 1px solid var(--cron-border);
121
+ padding-bottom: 0.875rem;
122
+ }
123
+
124
+ .cron-tab-btn {
125
+ padding: 0.375rem 1rem;
126
+ border-radius: 0.5rem;
127
+ border: none;
128
+ background: transparent;
129
+ color: var(--cron-text-muted);
130
+ font-size: 0.875rem;
131
+ font-weight: 600;
132
+ cursor: pointer;
133
+ transition: background 0.15s, color 0.15s;
134
+ }
135
+
136
+ .cron-tab-btn[data-active] {
137
+ background: rgba(139, 92, 246, 0.12);
138
+ color: var(--cron-primary);
139
+ }
140
+
141
+ .cron-presets {
142
+ display: grid;
143
+ grid-template-columns: 1fr 1fr;
144
+ gap: 0.5rem;
145
+ }
146
+
147
+ .cron-preset-btn {
148
+ display: flex;
149
+ flex-direction: column;
150
+ align-items: flex-start;
151
+ gap: 0.2rem;
152
+ padding: 0.75rem;
153
+ background: var(--cron-card-bg);
154
+ border: 1px solid var(--cron-border);
155
+ border-radius: 0.75rem;
156
+ cursor: pointer;
157
+ text-align: left;
158
+ transition: border-color 0.15s, background 0.15s;
159
+ }
160
+
161
+ .cron-preset-btn:hover {
162
+ border-color: var(--cron-primary);
163
+ background: rgba(139, 92, 246, 0.06);
164
+ }
165
+
166
+ .cron-preset-label {
167
+ font-size: 0.825rem;
168
+ font-weight: 700;
169
+ color: var(--cron-text);
170
+ }
171
+
172
+ .cron-preset-expr {
173
+ font-size: 0.72rem;
174
+ color: var(--cron-text-muted);
175
+ }
176
+
177
+ .cron-field {
178
+ display: flex;
179
+ flex-direction: column;
180
+ gap: 0.3rem;
181
+ margin-bottom: 0.75rem;
182
+ }
183
+
184
+ .cron-field:last-child {
185
+ margin-bottom: 0;
186
+ }
187
+
188
+ .cron-field-label {
189
+ font-size: 0.78rem;
190
+ font-weight: 600;
191
+ color: var(--cron-text-muted);
192
+ }
193
+
194
+ .cron-input {
195
+ width: 100%;
196
+ padding: 0.45rem 0.75rem;
197
+ font-size: 0.875rem;
198
+ background: var(--cron-card-bg);
199
+ border: 1px solid var(--cron-border);
200
+ border-radius: 0.5rem;
201
+ color: var(--cron-text);
202
+ outline: none;
203
+ box-sizing: border-box;
204
+ transition: border-color 0.2s, box-shadow 0.2s;
205
+ }
206
+
207
+ .cron-input:focus {
208
+ border-color: var(--cron-primary);
209
+ box-shadow: 0 0 0 3px rgba(139, 92, 246, 0.14);
210
+ }
211
+
212
+ .cron-field-hint {
213
+ font-size: 0.7rem;
214
+ color: var(--cron-text-muted);
215
+ }
216
+
217
+ .cron-runs-section {
218
+ background: var(--cron-bg);
219
+ border: 1px solid var(--cron-border);
220
+ border-radius: 1rem;
221
+ padding: 1.125rem;
222
+ display: flex;
223
+ flex-direction: column;
224
+ }
225
+
226
+ .cron-runs-title {
227
+ font-size: 0.8rem;
228
+ font-weight: 700;
229
+ color: var(--cron-text-muted);
230
+ text-transform: uppercase;
231
+ letter-spacing: 0.06em;
232
+ margin: 0 0 0.75rem;
233
+ }
234
+
235
+ .cron-runs-list {
236
+ list-style: none;
237
+ margin: 0;
238
+ padding: 0;
239
+ display: flex;
240
+ flex-direction: column;
241
+ gap: 0.4rem;
242
+ flex: 1;
243
+ }
244
+
245
+ .cron-run-skeleton {
246
+ height: 2.25rem;
247
+ background: var(--cron-card-bg);
248
+ border-radius: 0.5rem;
249
+ border: 1px solid var(--cron-border);
250
+ }
251
+
252
+ :global(.cron-run-item) {
253
+ display: flex;
254
+ align-items: center;
255
+ justify-content: space-between;
256
+ padding: 0.5rem 0.75rem;
257
+ background: var(--cron-card-bg);
258
+ border: 1px solid var(--cron-border);
259
+ border-radius: 0.5rem;
260
+ font-size: 0.825rem;
261
+ }
262
+
263
+ :global(.cron-run-date) {
264
+ font-weight: 600;
265
+ color: var(--cron-text);
266
+ text-transform: capitalize;
267
+ }
268
+
269
+ :global(.cron-run-rel) {
270
+ font-size: 0.72rem;
271
+ color: var(--cron-text-muted);
272
+ }
273
+
274
+ :global(.cron-no-runs) {
275
+ padding: 1rem;
276
+ text-align: center;
277
+ color: var(--cron-text-muted);
278
+ font-size: 0.825rem;
279
+ font-style: italic;
280
+ }
281
+
282
+ .cron-copy-btn {
283
+ width: 100%;
284
+ padding: 0.8rem;
285
+ background: var(--cron-primary);
286
+ color: #fff;
287
+ border: none;
288
+ border-radius: 0.875rem;
289
+ font-size: 0.925rem;
290
+ font-weight: 700;
291
+ cursor: pointer;
292
+ transition: background 0.2s, transform 0.1s;
293
+ }
294
+
295
+ .cron-copy-btn:hover {
296
+ background: #7c3aed;
297
+ }
298
+
299
+ .cron-copy-btn:active {
300
+ transform: scale(0.98);
301
+ }
302
+
303
+ .cron-copy-btn[data-copied] {
304
+ background: var(--cron-success);
305
+ }
306
+
307
+ @media (max-width: 480px) {
308
+ .cron-disp-part {
309
+ font-size: 2rem;
310
+ }
311
+
312
+ .cron-presets {
313
+ grid-template-columns: 1fr;
314
+ }
315
+ }
@@ -0,0 +1,30 @@
1
+ import type { DeveloperToolEntry, ToolLocaleContent } from '../../types';
2
+
3
+ import type { CronGeneratorUI } from './ui';
4
+
5
+ export type CronGeneratorLocaleContent = ToolLocaleContent<CronGeneratorUI>;
6
+
7
+ export const cronGenerator: DeveloperToolEntry<CronGeneratorUI> = {
8
+ id: 'cron-generator',
9
+ icons: {
10
+ bg: 'mdi:clock-outline',
11
+ fg: 'mdi:code-braces',
12
+ },
13
+ i18n: {
14
+ de: async () => (await import('./i18n/de')).content,
15
+ en: async () => (await import('./i18n/en')).content,
16
+ es: async () => (await import('./i18n/es')).content,
17
+ fr: async () => (await import('./i18n/fr')).content,
18
+ id: async () => (await import('./i18n/id')).content,
19
+ it: async () => (await import('./i18n/it')).content,
20
+ ja: async () => (await import('./i18n/ja')).content,
21
+ ko: async () => (await import('./i18n/ko')).content,
22
+ nl: async () => (await import('./i18n/nl')).content,
23
+ pl: async () => (await import('./i18n/pl')).content,
24
+ pt: async () => (await import('./i18n/pt')).content,
25
+ ru: async () => (await import('./i18n/ru')).content,
26
+ sv: async () => (await import('./i18n/sv')).content,
27
+ tr: async () => (await import('./i18n/tr')).content,
28
+ zh: async () => (await import('./i18n/zh')).content,
29
+ },
30
+ };
@@ -1,35 +1,5 @@
1
- import type { DeveloperToolEntry, ToolLocaleContent, ToolDefinition } from '../../types';
2
-
3
- import type { CronGeneratorUI } from './ui';
4
-
5
- export type CronGeneratorLocaleContent = ToolLocaleContent<CronGeneratorUI>;
6
-
7
- export const cronGenerator: DeveloperToolEntry<CronGeneratorUI> = {
8
- id: 'cron-generator',
9
- icons: {
10
- bg: 'mdi:clock-outline',
11
- fg: 'mdi:code-braces',
12
- },
13
- i18n: {
14
- de: async () => (await import('./i18n/de')).content,
15
- en: async () => (await import('./i18n/en')).content,
16
- es: async () => (await import('./i18n/es')).content,
17
- fr: async () => (await import('./i18n/fr')).content,
18
- id: async () => (await import('./i18n/id')).content,
19
- it: async () => (await import('./i18n/it')).content,
20
- ja: async () => (await import('./i18n/ja')).content,
21
- ko: async () => (await import('./i18n/ko')).content,
22
- nl: async () => (await import('./i18n/nl')).content,
23
- pl: async () => (await import('./i18n/pl')).content,
24
- pt: async () => (await import('./i18n/pt')).content,
25
- ru: async () => (await import('./i18n/ru')).content,
26
- sv: async () => (await import('./i18n/sv')).content,
27
- tr: async () => (await import('./i18n/tr')).content,
28
- zh: async () => (await import('./i18n/zh')).content,
29
- },
30
- };
31
-
32
-
1
+ import { cronGenerator } from './entry';
2
+ export * from './entry';
33
3
  export const CRON_GENERATOR_TOOL: ToolDefinition = {
34
4
  entry: cronGenerator,
35
5
  Component: () => import('./component.astro'),
@@ -79,211 +79,6 @@ const t = (ui ?? {}) as CssSpecificityCalculatorUI;
79
79
  </div>
80
80
  </div>
81
81
 
82
- <style>
83
- .spec-root {
84
- --spec-primary: #8b5cf6;
85
- --spec-primary-dark: #7c3aed;
86
- --spec-success: #10b981;
87
- --spec-card-bg: #fff;
88
- --spec-bg: #f8fafc;
89
- --spec-text: #0f172a;
90
- --spec-text-muted: #64748b;
91
- --spec-border: #e2e8f0;
92
-
93
- max-width: 900px;
94
- margin: 2rem auto;
95
- color: var(--spec-text);
96
- }
97
-
98
- :global(.theme-dark) .spec-root {
99
- --spec-card-bg: #1e293b;
100
- --spec-bg: #0f172a;
101
- --spec-text: #f1f5f9;
102
- --spec-text-muted: #94a3b8;
103
- --spec-border: #334155;
104
- }
105
-
106
- .spec-card {
107
- background: var(--spec-card-bg);
108
- border: 1px solid var(--spec-border);
109
- border-radius: 1.25rem;
110
- box-shadow: 0 4px 24px rgba(0, 0, 0, 0.06);
111
- padding: 1.75rem;
112
- display: flex;
113
- flex-direction: column;
114
- gap: 1.25rem;
115
- }
116
-
117
- .spec-comparison {
118
- display: grid;
119
- grid-template-columns: 1fr 1fr;
120
- gap: 1.5rem;
121
- position: relative;
122
- }
123
-
124
- @media (max-width: 768px) {
125
- .spec-comparison {
126
- grid-template-columns: 1fr;
127
- }
128
- }
129
-
130
- .spec-vs {
131
- position: absolute;
132
- top: 50%;
133
- left: 50%;
134
- transform: translate(-50%, -50%);
135
- background: var(--spec-primary);
136
- color: #fff;
137
- font-weight: 800;
138
- width: 2.75rem;
139
- height: 2.75rem;
140
- display: flex;
141
- align-items: center;
142
- justify-content: center;
143
- border-radius: 50%;
144
- border: 3px solid var(--spec-card-bg);
145
- z-index: 10;
146
- font-size: 0.85rem;
147
- box-shadow: 0 4px 12px rgba(139, 92, 246, 0.4);
148
- }
149
-
150
- @media (max-width: 768px) {
151
- .spec-vs {
152
- display: none;
153
- }
154
- }
155
-
156
- .spec-block {
157
- background: var(--spec-bg);
158
- border: 2px solid var(--spec-border);
159
- border-radius: 1rem;
160
- padding: 1.25rem;
161
- display: flex;
162
- flex-direction: column;
163
- gap: 1rem;
164
- position: relative;
165
- overflow: hidden;
166
- transition: border-color 0.25s, box-shadow 0.25s, padding-top 0.25s;
167
- }
168
-
169
- .spec-winner-banner {
170
- position: absolute;
171
- top: 0;
172
- left: 0;
173
- right: 0;
174
- background: var(--spec-success);
175
- color: #fff;
176
- text-align: center;
177
- font-weight: 700;
178
- padding: 0.3rem;
179
- font-size: 0.8rem;
180
- transform: translateY(-100%);
181
- transition: transform 0.25s;
182
- }
183
-
184
- .spec-field {
185
- display: flex;
186
- flex-direction: column;
187
- gap: 0.4rem;
188
- }
189
-
190
- .spec-field-label {
191
- font-size: 0.8rem;
192
- font-weight: 700;
193
- color: var(--spec-text-muted);
194
- text-transform: uppercase;
195
- letter-spacing: 0.06em;
196
- }
197
-
198
- .spec-input {
199
- width: 100%;
200
- padding: 0.75rem 1rem;
201
- font-size: 1rem;
202
- color: var(--spec-text);
203
- background: var(--spec-card-bg);
204
- border: 1px solid var(--spec-border);
205
- border-radius: 0.75rem;
206
- outline: none;
207
- transition: border-color 0.2s, box-shadow 0.2s;
208
- box-sizing: border-box;
209
- }
210
-
211
- .spec-input:focus {
212
- border-color: var(--spec-primary);
213
- box-shadow: 0 0 0 3px rgba(139, 92, 246, 0.15);
214
- }
215
-
216
- .spec-counters {
217
- display: grid;
218
- grid-template-columns: repeat(3, 1fr);
219
- gap: 0.625rem;
220
- }
221
-
222
- .spec-counter {
223
- background: var(--spec-card-bg);
224
- border: 1px solid var(--spec-border);
225
- border-radius: 0.75rem;
226
- padding: 0.875rem 0.5rem;
227
- text-align: center;
228
- display: flex;
229
- flex-direction: column;
230
- align-items: center;
231
- gap: 0.375rem;
232
- }
233
-
234
- .spec-counter-ids {
235
- border-bottom: 3px solid #ef4444;
236
- }
237
-
238
- .spec-counter-cls {
239
- border-bottom: 3px solid #3b82f6;
240
- }
241
-
242
- .spec-counter-els {
243
- border-bottom: 3px solid #10b981;
244
- }
245
-
246
- .spec-counter-value {
247
- font-size: 2.25rem;
248
- font-weight: 800;
249
- line-height: 1;
250
- font-variant-numeric: tabular-nums;
251
- }
252
-
253
- .spec-counter-ids .spec-counter-value {
254
- color: #ef4444;
255
- }
256
-
257
- .spec-counter-cls .spec-counter-value {
258
- color: #3b82f6;
259
- }
260
-
261
- .spec-counter-els .spec-counter-value {
262
- color: #10b981;
263
- }
264
-
265
- .spec-counter-label {
266
- font-size: 0.68rem;
267
- text-transform: uppercase;
268
- letter-spacing: 0.05em;
269
- font-weight: 700;
270
- color: var(--spec-text-muted);
271
- }
272
-
273
- .spec-tie-msg {
274
- text-align: center;
275
- padding: 0.875rem 1.25rem;
276
- background: var(--spec-bg);
277
- border: 1px solid var(--spec-border);
278
- border-radius: 0.875rem;
279
- color: var(--spec-text);
280
- font-weight: 600;
281
- font-size: 0.9rem;
282
- opacity: 0;
283
- transform: translateY(6px);
284
- transition: opacity 0.25s, transform 0.25s;
285
- }
286
- </style>
287
82
 
288
83
  <script>
289
84
  import { setupCalculator } from './ui-controller';