@jjlmoya/utils-diy 1.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 (135) hide show
  1. package/package.json +60 -0
  2. package/src/category/i18n/en.ts +110 -0
  3. package/src/category/i18n/es.ts +110 -0
  4. package/src/category/i18n/fr.ts +101 -0
  5. package/src/category/index.ts +25 -0
  6. package/src/category/seo.astro +15 -0
  7. package/src/components/PreviewNavSidebar.astro +116 -0
  8. package/src/components/PreviewToolbar.astro +143 -0
  9. package/src/data.ts +11 -0
  10. package/src/env.d.ts +5 -0
  11. package/src/index.ts +57 -0
  12. package/src/layouts/PreviewLayout.astro +117 -0
  13. package/src/pages/[locale]/[slug].astro +146 -0
  14. package/src/pages/[locale].astro +251 -0
  15. package/src/pages/index.astro +4 -0
  16. package/src/tests/faq_count.test.ts +19 -0
  17. package/src/tests/locale_completeness.test.ts +42 -0
  18. package/src/tests/mocks/astro_mock.js +2 -0
  19. package/src/tests/no_h1_in_components.test.ts +48 -0
  20. package/src/tests/schemas_fulfillment.test.ts +23 -0
  21. package/src/tests/seo_length.test.ts +22 -0
  22. package/src/tests/title_quality.test.ts +55 -0
  23. package/src/tests/tool_validation.test.ts +17 -0
  24. package/src/tool/balusterCalculator/bibliography.astro +14 -0
  25. package/src/tool/balusterCalculator/component.astro +605 -0
  26. package/src/tool/balusterCalculator/i18n/en.ts +264 -0
  27. package/src/tool/balusterCalculator/i18n/es.ts +264 -0
  28. package/src/tool/balusterCalculator/i18n/fr.ts +264 -0
  29. package/src/tool/balusterCalculator/index.ts +33 -0
  30. package/src/tool/balusterCalculator/seo.astro +15 -0
  31. package/src/tool/balusterCalculator/ui.ts +15 -0
  32. package/src/tool/clayCalculator/bibliography.astro +14 -0
  33. package/src/tool/clayCalculator/component.astro +731 -0
  34. package/src/tool/clayCalculator/i18n/en.ts +183 -0
  35. package/src/tool/clayCalculator/i18n/es.ts +183 -0
  36. package/src/tool/clayCalculator/i18n/fr.ts +183 -0
  37. package/src/tool/clayCalculator/index.ts +33 -0
  38. package/src/tool/clayCalculator/seo.astro +15 -0
  39. package/src/tool/clayCalculator/ui.ts +19 -0
  40. package/src/tool/concreteCalculator/bibliography.astro +13 -0
  41. package/src/tool/concreteCalculator/component.astro +1089 -0
  42. package/src/tool/concreteCalculator/i18n/en.ts +201 -0
  43. package/src/tool/concreteCalculator/i18n/es.ts +201 -0
  44. package/src/tool/concreteCalculator/i18n/fr.ts +201 -0
  45. package/src/tool/concreteCalculator/index.ts +28 -0
  46. package/src/tool/concreteCalculator/seo.astro +14 -0
  47. package/src/tool/concreteCalculator/ui.ts +35 -0
  48. package/src/tool/cutOptimizer/bibliography.astro +13 -0
  49. package/src/tool/cutOptimizer/component.astro +825 -0
  50. package/src/tool/cutOptimizer/i18n/en.ts +178 -0
  51. package/src/tool/cutOptimizer/i18n/es.ts +178 -0
  52. package/src/tool/cutOptimizer/i18n/fr.ts +178 -0
  53. package/src/tool/cutOptimizer/index.ts +28 -0
  54. package/src/tool/cutOptimizer/optimizer.ts +199 -0
  55. package/src/tool/cutOptimizer/seo.astro +14 -0
  56. package/src/tool/cutOptimizer/ui.ts +25 -0
  57. package/src/tool/drillCalculator/bibliography.astro +13 -0
  58. package/src/tool/drillCalculator/component.astro +1210 -0
  59. package/src/tool/drillCalculator/engine.ts +63 -0
  60. package/src/tool/drillCalculator/i18n/en.ts +137 -0
  61. package/src/tool/drillCalculator/i18n/es.ts +137 -0
  62. package/src/tool/drillCalculator/i18n/fr.ts +137 -0
  63. package/src/tool/drillCalculator/index.ts +28 -0
  64. package/src/tool/drillCalculator/seo.astro +14 -0
  65. package/src/tool/drillCalculator/ui.ts +41 -0
  66. package/src/tool/drillSharpener/bibliography.astro +13 -0
  67. package/src/tool/drillSharpener/component.astro +712 -0
  68. package/src/tool/drillSharpener/engine.ts +42 -0
  69. package/src/tool/drillSharpener/i18n/en.ts +121 -0
  70. package/src/tool/drillSharpener/i18n/es.ts +121 -0
  71. package/src/tool/drillSharpener/i18n/fr.ts +121 -0
  72. package/src/tool/drillSharpener/index.ts +31 -0
  73. package/src/tool/drillSharpener/seo.astro +14 -0
  74. package/src/tool/drillSharpener/ui.ts +53 -0
  75. package/src/tool/epoxyCalculator/bibliography.astro +14 -0
  76. package/src/tool/epoxyCalculator/component.astro +888 -0
  77. package/src/tool/epoxyCalculator/i18n/en.ts +195 -0
  78. package/src/tool/epoxyCalculator/i18n/es.ts +195 -0
  79. package/src/tool/epoxyCalculator/i18n/fr.ts +195 -0
  80. package/src/tool/epoxyCalculator/index.ts +33 -0
  81. package/src/tool/epoxyCalculator/seo.astro +15 -0
  82. package/src/tool/epoxyCalculator/ui.ts +22 -0
  83. package/src/tool/furnitureFit/bibliography.astro +13 -0
  84. package/src/tool/furnitureFit/component.astro +552 -0
  85. package/src/tool/furnitureFit/engine.ts +51 -0
  86. package/src/tool/furnitureFit/i18n/en.ts +152 -0
  87. package/src/tool/furnitureFit/i18n/es.ts +152 -0
  88. package/src/tool/furnitureFit/i18n/fr.ts +152 -0
  89. package/src/tool/furnitureFit/index.ts +28 -0
  90. package/src/tool/furnitureFit/seo.astro +14 -0
  91. package/src/tool/furnitureFit/ui.ts +21 -0
  92. package/src/tool/mortarCalculator/bibliography.astro +13 -0
  93. package/src/tool/mortarCalculator/component.astro +1139 -0
  94. package/src/tool/mortarCalculator/i18n/en.ts +219 -0
  95. package/src/tool/mortarCalculator/i18n/es.ts +205 -0
  96. package/src/tool/mortarCalculator/i18n/fr.ts +220 -0
  97. package/src/tool/mortarCalculator/index.ts +24 -0
  98. package/src/tool/mortarCalculator/seo.astro +14 -0
  99. package/src/tool/mortarCalculator/ui.ts +37 -0
  100. package/src/tool/passepartoutCalculator/bibliography.astro +13 -0
  101. package/src/tool/passepartoutCalculator/component.astro +741 -0
  102. package/src/tool/passepartoutCalculator/i18n/en.ts +178 -0
  103. package/src/tool/passepartoutCalculator/i18n/es.ts +178 -0
  104. package/src/tool/passepartoutCalculator/i18n/fr.ts +178 -0
  105. package/src/tool/passepartoutCalculator/index.ts +28 -0
  106. package/src/tool/passepartoutCalculator/seo.astro +14 -0
  107. package/src/tool/passepartoutCalculator/ui.ts +17 -0
  108. package/src/tool/stairCalculator/bibliography.astro +52 -0
  109. package/src/tool/stairCalculator/component.astro +766 -0
  110. package/src/tool/stairCalculator/engine.ts +128 -0
  111. package/src/tool/stairCalculator/i18n/en.ts +149 -0
  112. package/src/tool/stairCalculator/i18n/es.ts +149 -0
  113. package/src/tool/stairCalculator/i18n/fr.ts +149 -0
  114. package/src/tool/stairCalculator/index.ts +31 -0
  115. package/src/tool/stairCalculator/seo.astro +211 -0
  116. package/src/tool/stairCalculator/ui.ts +109 -0
  117. package/src/tool/thermalExpansionCalculator/bibliography.astro +13 -0
  118. package/src/tool/thermalExpansionCalculator/component.astro +771 -0
  119. package/src/tool/thermalExpansionCalculator/engine.ts +23 -0
  120. package/src/tool/thermalExpansionCalculator/i18n/en.ts +174 -0
  121. package/src/tool/thermalExpansionCalculator/i18n/es.ts +174 -0
  122. package/src/tool/thermalExpansionCalculator/i18n/fr.ts +174 -0
  123. package/src/tool/thermalExpansionCalculator/index.ts +28 -0
  124. package/src/tool/thermalExpansionCalculator/seo.astro +14 -0
  125. package/src/tool/thermalExpansionCalculator/ui.ts +41 -0
  126. package/src/tool/voltageDropCalculator/bibliography.astro +13 -0
  127. package/src/tool/voltageDropCalculator/component.astro +1022 -0
  128. package/src/tool/voltageDropCalculator/i18n/en.ts +155 -0
  129. package/src/tool/voltageDropCalculator/i18n/es.ts +155 -0
  130. package/src/tool/voltageDropCalculator/i18n/fr.ts +148 -0
  131. package/src/tool/voltageDropCalculator/index.ts +28 -0
  132. package/src/tool/voltageDropCalculator/seo.astro +14 -0
  133. package/src/tool/voltageDropCalculator/ui.ts +22 -0
  134. package/src/tools.ts +16 -0
  135. package/src/types.ts +72 -0
@@ -0,0 +1,731 @@
1
+ ---
2
+ import type { KnownLocale } from '../../types';
3
+ import type { ClayCalculatorUI } from './ui';
4
+
5
+ interface Props {
6
+ locale?: KnownLocale;
7
+ ui?: Record<string, unknown>;
8
+ }
9
+
10
+ const { ui } = Astro.props;
11
+ const t = (ui ?? {}) as ClayCalculatorUI;
12
+ ---
13
+
14
+ <div class="cc-root">
15
+ <div class="cc-grid">
16
+ <div class="cc-panel-left">
17
+ <div class="cc-controls">
18
+ <div class="cc-field">
19
+ <label class="cc-label" for="cc-initial-size">{t.labelInitialSize}</label>
20
+ <input
21
+ type="number"
22
+ id="cc-initial-size"
23
+ value="100"
24
+ min="1"
25
+ step="0.1"
26
+ class="cc-input"
27
+ />
28
+ </div>
29
+
30
+ <div class="cc-field">
31
+ <label class="cc-label">{t.labelShrinkage}</label>
32
+ <div class="cc-slider-row">
33
+ <input
34
+ type="range"
35
+ id="cc-shrinkage-slider"
36
+ min="0"
37
+ max="20"
38
+ value="12"
39
+ step="0.5"
40
+ class="cc-slider"
41
+ />
42
+ <span id="cc-shrinkage-display" class="cc-slider-val">12.0</span>
43
+ </div>
44
+ <div class="cc-slider-labels">
45
+ <span>{t.labelLow}</span>
46
+ <span>{t.labelMedium}</span>
47
+ <span>{t.labelHigh}</span>
48
+ </div>
49
+ </div>
50
+
51
+ <div class="cc-presets">
52
+ <button id="cc-preset-low" class="cc-preset cc-preset-terracota">{t.presetTerracota}</button>
53
+ <button id="cc-preset-medium" class="cc-preset cc-preset-gres">{t.presetGres}</button>
54
+ <button id="cc-preset-high" class="cc-preset cc-preset-porcelana">{t.presetPorcelana}</button>
55
+ </div>
56
+ </div>
57
+
58
+ <div class="cc-result-box">
59
+ <h3 class="cc-result-title">{t.labelResult}</h3>
60
+ <div class="cc-result-rows">
61
+ <div class="cc-result-row">
62
+ <span class="cc-result-label">{t.labelFinalSize}</span>
63
+ <span id="cc-final-size" class="cc-result-value cc-value-final">88.0 mm</span>
64
+ </div>
65
+ <div class="cc-result-row">
66
+ <span class="cc-result-label">{t.labelLoss}</span>
67
+ <span id="cc-loss-amount" class="cc-result-value cc-value-loss">-12.0 mm</span>
68
+ </div>
69
+ </div>
70
+ </div>
71
+
72
+ <div class="cc-tip">
73
+ <svg class="cc-tip-icon" viewBox="0 0 24 24" fill="currentColor" width="16" height="16">
74
+ <path d="M13 9h-2V7h2m0 10h-2v-6h2m-1-9A10 10 0 0 0 2 12a10 10 0 0 0 10 10 10 10 0 0 0 10-10A10 10 0 0 0 12 2z"/>
75
+ </svg>
76
+ <span>{t.tipText}</span>
77
+ </div>
78
+ </div>
79
+
80
+ <div class="cc-panel-right">
81
+ <div class="cc-blob cc-blob-top"></div>
82
+ <div class="cc-blob cc-blob-bottom"></div>
83
+
84
+ <div class="cc-viz-wrapper">
85
+ <div class="cc-viz-aspect">
86
+ <div id="cc-circle-initial" class="cc-circle-initial">
87
+ <div class="cc-badge-initial">
88
+ {t.labelInitialBadge} <span id="cc-viz-initial">100.0</span> mm
89
+ </div>
90
+ </div>
91
+
92
+ <div id="cc-circle-final" class="cc-circle-final">
93
+ <div class="cc-circle-inner">
94
+ <div id="cc-viz-final" class="cc-viz-number">88.0</div>
95
+ <div class="cc-viz-unit">{t.labelFinalBadge}</div>
96
+ </div>
97
+ </div>
98
+
99
+ <div class="cc-badge-loss">
100
+ {t.labelLossBadge} <span id="cc-viz-loss">12.0</span>%
101
+ </div>
102
+ </div>
103
+
104
+ <div class="cc-areas">
105
+ <div class="cc-area-item">
106
+ <div class="cc-area-label">{t.labelInitialArea}</div>
107
+ <div id="cc-area-initial" class="cc-area-value cc-area-initial">31.416 mm²</div>
108
+ </div>
109
+ <div class="cc-area-item">
110
+ <div class="cc-area-label">{t.labelFinalArea}</div>
111
+ <div id="cc-area-final" class="cc-area-value cc-area-final">24.328 mm²</div>
112
+ </div>
113
+ </div>
114
+ </div>
115
+ </div>
116
+ </div>
117
+ </div>
118
+
119
+ <script>
120
+ let ccInputSize: HTMLInputElement | null = null;
121
+ let ccSlider: HTMLInputElement | null = null;
122
+ let ccSliderDisplay: HTMLElement | null = null;
123
+ let ccFinalSize: HTMLElement | null = null;
124
+ let ccLoss: HTMLElement | null = null;
125
+ let ccVizInitial: HTMLElement | null = null;
126
+ let ccVizFinal: HTMLElement | null = null;
127
+ let ccVizLoss: HTMLElement | null = null;
128
+ let ccCircleFinal: HTMLElement | null = null;
129
+ let ccAreaInitial: HTMLElement | null = null;
130
+ let ccAreaFinal: HTMLElement | null = null;
131
+
132
+ function setText(el: HTMLElement | null, text: string) {
133
+ if (el) el.innerText = text;
134
+ }
135
+
136
+ function updateCircle(scale: number) {
137
+ if (!ccCircleFinal) return;
138
+ const pct = (scale * 100).toFixed(1);
139
+ ccCircleFinal.style.width = `${pct}%`;
140
+ ccCircleFinal.style.height = `${pct}%`;
141
+ }
142
+
143
+ function calculate() {
144
+ const initialSize = parseFloat(ccInputSize?.value ?? '0') || 0;
145
+ const shrinkage = parseFloat(ccSlider?.value ?? '0') || 0;
146
+ const finalSize = initialSize * (1 - shrinkage / 100);
147
+ const loss = initialSize - finalSize;
148
+ const scale = initialSize > 0 ? finalSize / initialSize : 0;
149
+ const areaInitial = Math.PI * (initialSize / 2) ** 2;
150
+ const areaFinal = Math.PI * (finalSize / 2) ** 2;
151
+ const fmt = { maximumFractionDigits: 0 };
152
+
153
+ setText(ccSliderDisplay, shrinkage.toFixed(1));
154
+ setText(ccFinalSize, `${finalSize.toFixed(1)} mm`);
155
+ setText(ccLoss, `-${loss.toFixed(1)} mm`);
156
+ setText(ccVizInitial, initialSize.toFixed(1));
157
+ setText(ccVizFinal, finalSize.toFixed(1));
158
+ setText(ccVizLoss, shrinkage.toFixed(1));
159
+ setText(ccAreaInitial, `${areaInitial.toLocaleString(undefined, fmt)} mm²`);
160
+ setText(ccAreaFinal, `${areaFinal.toLocaleString(undefined, fmt)} mm²`);
161
+ updateCircle(scale);
162
+ }
163
+
164
+ function setShrinkage(value: number) {
165
+ if (ccSlider) ccSlider.value = value.toString();
166
+ calculate();
167
+ }
168
+
169
+ function initClayCalculator(root: HTMLElement) {
170
+ ccInputSize = root.querySelector<HTMLInputElement>('#cc-initial-size');
171
+ ccSlider = root.querySelector<HTMLInputElement>('#cc-shrinkage-slider');
172
+ ccSliderDisplay = root.querySelector<HTMLElement>('#cc-shrinkage-display');
173
+ ccFinalSize = root.querySelector<HTMLElement>('#cc-final-size');
174
+ ccLoss = root.querySelector<HTMLElement>('#cc-loss-amount');
175
+ ccVizInitial = root.querySelector<HTMLElement>('#cc-viz-initial');
176
+ ccVizFinal = root.querySelector<HTMLElement>('#cc-viz-final');
177
+ ccVizLoss = root.querySelector<HTMLElement>('#cc-viz-loss');
178
+ ccCircleFinal = root.querySelector<HTMLElement>('#cc-circle-final');
179
+ ccAreaInitial = root.querySelector<HTMLElement>('#cc-area-initial');
180
+ ccAreaFinal = root.querySelector<HTMLElement>('#cc-area-final');
181
+
182
+ if (!ccInputSize || !ccSlider) return;
183
+
184
+ ccInputSize.addEventListener('input', calculate);
185
+ ccSlider.addEventListener('input', calculate);
186
+ root.querySelector('#cc-preset-low')?.addEventListener('click', () => setShrinkage(8));
187
+ root.querySelector('#cc-preset-medium')?.addEventListener('click', () => setShrinkage(12));
188
+ root.querySelector('#cc-preset-high')?.addEventListener('click', () => setShrinkage(15));
189
+ calculate();
190
+ }
191
+
192
+ function init() {
193
+ document.querySelectorAll<HTMLElement>('.cc-root').forEach(initClayCalculator);
194
+ }
195
+
196
+ document.addEventListener('astro:page-load', init);
197
+ init();
198
+ </script>
199
+
200
+ <style>
201
+ .cc-root {
202
+ width: 100%;
203
+ max-width: 64rem;
204
+ margin: 0 auto;
205
+ background: linear-gradient(135deg, #fffbeb, #fff7ed);
206
+ border-radius: 1.5rem;
207
+ box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.15);
208
+ overflow: hidden;
209
+ border: 1px solid #fde68a;
210
+ }
211
+
212
+ .cc-grid {
213
+ display: grid;
214
+ grid-template-columns: 1fr;
215
+ }
216
+
217
+ @media (min-width: 1024px) {
218
+ .cc-grid {
219
+ grid-template-columns: 1fr 1fr;
220
+ }
221
+ }
222
+
223
+ .cc-panel-left {
224
+ padding: 2rem;
225
+ display: flex;
226
+ flex-direction: column;
227
+ gap: 2rem;
228
+ }
229
+
230
+ @media (min-width: 768px) {
231
+ .cc-panel-left {
232
+ padding: 3rem;
233
+ }
234
+ }
235
+
236
+ .cc-controls {
237
+ display: flex;
238
+ flex-direction: column;
239
+ gap: 1.5rem;
240
+ }
241
+
242
+ .cc-field {
243
+ display: flex;
244
+ flex-direction: column;
245
+ gap: 0.75rem;
246
+ }
247
+
248
+ .cc-label {
249
+ font-size: 0.75rem;
250
+ font-weight: 700;
251
+ text-transform: uppercase;
252
+ letter-spacing: 0.08em;
253
+ color: #92400e;
254
+ }
255
+
256
+ .cc-input {
257
+ width: 100%;
258
+ background: #fff;
259
+ border: 2px solid #fcd34d;
260
+ border-radius: 0.75rem;
261
+ padding: 0.75rem 1rem;
262
+ font-size: 1.5rem;
263
+ font-weight: 700;
264
+ color: #1e293b;
265
+ outline: none;
266
+ transition: border-color 0.2s, box-shadow 0.2s;
267
+ box-sizing: border-box;
268
+ }
269
+
270
+ .cc-input:focus {
271
+ border-color: #f59e0b;
272
+ box-shadow: 0 0 0 3px rgba(245, 158, 11, 0.2);
273
+ }
274
+
275
+ .cc-slider-row {
276
+ display: flex;
277
+ align-items: center;
278
+ gap: 1rem;
279
+ }
280
+
281
+ .cc-slider {
282
+ flex: 1;
283
+ height: 0.75rem;
284
+ background: #fde68a;
285
+ border-radius: 999px;
286
+ appearance: none;
287
+ cursor: pointer;
288
+ accent-color: #d97706;
289
+ outline: none;
290
+ }
291
+
292
+ .cc-slider::-webkit-slider-thumb {
293
+ appearance: none;
294
+ width: 20px;
295
+ height: 20px;
296
+ background: #d97706;
297
+ border-radius: 50%;
298
+ cursor: pointer;
299
+ border: 3px solid #fff;
300
+ box-shadow: 0 0 8px rgba(217, 119, 6, 0.4);
301
+ }
302
+
303
+ .cc-slider-val {
304
+ font-size: 1.875rem;
305
+ font-weight: 900;
306
+ color: #b45309;
307
+ width: 5rem;
308
+ text-align: right;
309
+ flex-shrink: 0;
310
+ }
311
+
312
+ .cc-slider-labels {
313
+ display: flex;
314
+ justify-content: space-between;
315
+ font-size: 0.7rem;
316
+ color: #d97706;
317
+ }
318
+
319
+ .cc-presets {
320
+ display: grid;
321
+ grid-template-columns: 1fr 1fr;
322
+ gap: 0.75rem;
323
+ padding-top: 0.5rem;
324
+ }
325
+
326
+ .cc-preset {
327
+ padding: 0.5rem 1rem;
328
+ border-radius: 0.5rem;
329
+ border: 2px solid;
330
+ font-weight: 700;
331
+ font-size: 0.875rem;
332
+ cursor: pointer;
333
+ transition: background 0.15s;
334
+ }
335
+
336
+ .cc-preset-terracota {
337
+ background: #ffedd5;
338
+ border-color: #fdba74;
339
+ color: #9a3412;
340
+ }
341
+
342
+ .cc-preset-terracota:hover {
343
+ background: #fed7aa;
344
+ }
345
+
346
+ .cc-preset-gres {
347
+ background: #fef3c7;
348
+ border-color: #fcd34d;
349
+ color: #92400e;
350
+ }
351
+
352
+ .cc-preset-gres:hover {
353
+ background: #fde68a;
354
+ }
355
+
356
+ .cc-preset-porcelana {
357
+ grid-column: span 2;
358
+ background: #fee2e2;
359
+ border-color: #fca5a5;
360
+ color: #991b1b;
361
+ }
362
+
363
+ .cc-preset-porcelana:hover {
364
+ background: #fecaca;
365
+ }
366
+
367
+ .cc-result-box {
368
+ background: #fff;
369
+ border-radius: 1rem;
370
+ padding: 1.5rem;
371
+ border: 2px solid #fcd34d;
372
+ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
373
+ }
374
+
375
+ .cc-result-title {
376
+ font-size: 0.7rem;
377
+ font-weight: 700;
378
+ text-transform: uppercase;
379
+ letter-spacing: 0.08em;
380
+ color: #92400e;
381
+ margin: 0 0 1rem;
382
+ }
383
+
384
+ .cc-result-rows {
385
+ display: flex;
386
+ flex-direction: column;
387
+ gap: 0.75rem;
388
+ }
389
+
390
+ .cc-result-row {
391
+ display: flex;
392
+ justify-content: space-between;
393
+ align-items: baseline;
394
+ }
395
+
396
+ .cc-result-label {
397
+ color: #64748b;
398
+ font-size: 0.9rem;
399
+ }
400
+
401
+ .cc-result-value {
402
+ font-weight: 900;
403
+ }
404
+
405
+ .cc-value-final {
406
+ font-size: 1.875rem;
407
+ color: #059669;
408
+ }
409
+
410
+ .cc-value-loss {
411
+ font-size: 1.125rem;
412
+ color: #dc2626;
413
+ }
414
+
415
+ .cc-tip {
416
+ background: #fef3c7;
417
+ border-radius: 0.75rem;
418
+ padding: 1rem;
419
+ border: 1px solid #fde68a;
420
+ display: flex;
421
+ align-items: flex-start;
422
+ gap: 0.5rem;
423
+ font-size: 0.75rem;
424
+ color: #92400e;
425
+ line-height: 1.5;
426
+ }
427
+
428
+ .cc-tip-icon {
429
+ flex-shrink: 0;
430
+ margin-top: 1px;
431
+ }
432
+
433
+ .cc-panel-right {
434
+ background: linear-gradient(135deg, #f1f5f9, #e2e8f0);
435
+ padding: 2rem;
436
+ display: flex;
437
+ align-items: center;
438
+ justify-content: center;
439
+ position: relative;
440
+ overflow: hidden;
441
+ min-height: 400px;
442
+ }
443
+
444
+ @media (min-width: 768px) {
445
+ .cc-panel-right {
446
+ padding: 3rem;
447
+ }
448
+ }
449
+
450
+ .cc-blob {
451
+ position: absolute;
452
+ border-radius: 50%;
453
+ filter: blur(60px);
454
+ opacity: 0.12;
455
+ pointer-events: none;
456
+ }
457
+
458
+ .cc-blob-top {
459
+ top: 2.5rem;
460
+ left: 2.5rem;
461
+ width: 8rem;
462
+ height: 8rem;
463
+ background: #f59e0b;
464
+ }
465
+
466
+ .cc-blob-bottom {
467
+ bottom: 2.5rem;
468
+ right: 2.5rem;
469
+ width: 10rem;
470
+ height: 10rem;
471
+ background: #f97316;
472
+ }
473
+
474
+ .cc-viz-wrapper {
475
+ position: relative;
476
+ z-index: 1;
477
+ width: 100%;
478
+ max-width: 24rem;
479
+ }
480
+
481
+ .cc-viz-aspect {
482
+ aspect-ratio: 1 / 1;
483
+ position: relative;
484
+ display: flex;
485
+ align-items: center;
486
+ justify-content: center;
487
+ }
488
+
489
+ .cc-circle-initial {
490
+ position: absolute;
491
+ border-radius: 50%;
492
+ border: 4px dashed #fbbf24;
493
+ background: rgba(253, 230, 138, 0.2);
494
+ transition: width 0.7s ease, height 0.7s ease;
495
+ display: flex;
496
+ align-items: center;
497
+ justify-content: center;
498
+ width: 100%;
499
+ height: 100%;
500
+ }
501
+
502
+ .cc-badge-initial {
503
+ position: absolute;
504
+ top: -2rem;
505
+ left: 50%;
506
+ transform: translateX(-50%);
507
+ background: #d97706;
508
+ color: #fff;
509
+ padding: 0.25rem 0.75rem;
510
+ border-radius: 999px;
511
+ font-size: 0.75rem;
512
+ font-weight: 700;
513
+ white-space: nowrap;
514
+ }
515
+
516
+ .cc-circle-final {
517
+ position: absolute;
518
+ border-radius: 50%;
519
+ border: 4px solid #059669;
520
+ background: rgba(16, 185, 129, 0.3);
521
+ transition: width 0.7s ease, height 0.7s ease;
522
+ display: flex;
523
+ align-items: center;
524
+ justify-content: center;
525
+ box-shadow: 0 10px 40px rgba(5, 150, 105, 0.3);
526
+ width: 88%;
527
+ height: 88%;
528
+ }
529
+
530
+ .cc-circle-inner {
531
+ text-align: center;
532
+ }
533
+
534
+ .cc-viz-number {
535
+ font-size: 3rem;
536
+ font-weight: 900;
537
+ color: #065f46;
538
+ line-height: 1;
539
+ margin-bottom: 0.25rem;
540
+ }
541
+
542
+ .cc-viz-unit {
543
+ font-size: 0.875rem;
544
+ font-weight: 700;
545
+ color: #047857;
546
+ }
547
+
548
+ .cc-badge-loss {
549
+ position: absolute;
550
+ bottom: -3rem;
551
+ left: 50%;
552
+ transform: translateX(-50%);
553
+ background: #dc2626;
554
+ color: #fff;
555
+ padding: 0.5rem 1rem;
556
+ border-radius: 999px;
557
+ font-size: 0.875rem;
558
+ font-weight: 700;
559
+ box-shadow: 0 4px 12px rgba(220, 38, 38, 0.3);
560
+ white-space: nowrap;
561
+ }
562
+
563
+ .cc-areas {
564
+ margin-top: 4.5rem;
565
+ display: grid;
566
+ grid-template-columns: 1fr 1fr;
567
+ gap: 1rem;
568
+ text-align: center;
569
+ }
570
+
571
+ .cc-area-item {
572
+ background: rgba(255, 255, 255, 0.6);
573
+ border-radius: 0.75rem;
574
+ padding: 0.75rem;
575
+ backdrop-filter: blur(4px);
576
+ }
577
+
578
+ .cc-area-label {
579
+ font-size: 0.7rem;
580
+ color: #475569;
581
+ margin-bottom: 0.25rem;
582
+ }
583
+
584
+ .cc-area-value {
585
+ font-size: 1rem;
586
+ font-weight: 700;
587
+ }
588
+
589
+ .cc-area-initial {
590
+ color: #b45309;
591
+ }
592
+
593
+ .cc-area-final {
594
+ color: #047857;
595
+ }
596
+
597
+ :global(.theme-dark) .cc-root {
598
+ background: linear-gradient(135deg, #0f172a, #1e293b);
599
+ border-color: #334155;
600
+ }
601
+
602
+ :global(.theme-dark) .cc-label {
603
+ color: #fbbf24;
604
+ }
605
+
606
+ :global(.theme-dark) .cc-input {
607
+ background: #1e293b;
608
+ border-color: #b45309;
609
+ color: #f8fafc;
610
+ }
611
+
612
+ :global(.theme-dark) .cc-input:focus {
613
+ border-color: #f59e0b;
614
+ box-shadow: 0 0 0 3px rgba(245, 158, 11, 0.15);
615
+ }
616
+
617
+ :global(.theme-dark) .cc-slider {
618
+ background: rgba(180, 83, 9, 0.3);
619
+ }
620
+
621
+ :global(.theme-dark) .cc-slider-val {
622
+ color: #fbbf24;
623
+ }
624
+
625
+ :global(.theme-dark) .cc-slider-labels {
626
+ color: #d97706;
627
+ }
628
+
629
+ :global(.theme-dark) .cc-preset-terracota {
630
+ background: rgba(249, 115, 22, 0.15);
631
+ border-color: #c2410c;
632
+ color: #fb923c;
633
+ }
634
+
635
+ :global(.theme-dark) .cc-preset-terracota:hover {
636
+ background: rgba(249, 115, 22, 0.25);
637
+ }
638
+
639
+ :global(.theme-dark) .cc-preset-gres {
640
+ background: rgba(245, 158, 11, 0.15);
641
+ border-color: #b45309;
642
+ color: #fbbf24;
643
+ }
644
+
645
+ :global(.theme-dark) .cc-preset-gres:hover {
646
+ background: rgba(245, 158, 11, 0.25);
647
+ }
648
+
649
+ :global(.theme-dark) .cc-preset-porcelana {
650
+ background: rgba(220, 38, 38, 0.15);
651
+ border-color: #991b1b;
652
+ color: #f87171;
653
+ }
654
+
655
+ :global(.theme-dark) .cc-preset-porcelana:hover {
656
+ background: rgba(220, 38, 38, 0.25);
657
+ }
658
+
659
+ :global(.theme-dark) .cc-result-box {
660
+ background: #1e293b;
661
+ border-color: #b45309;
662
+ }
663
+
664
+ :global(.theme-dark) .cc-result-title {
665
+ color: #fbbf24;
666
+ }
667
+
668
+ :global(.theme-dark) .cc-result-label {
669
+ color: #94a3b8;
670
+ }
671
+
672
+ :global(.theme-dark) .cc-value-final {
673
+ color: #34d399;
674
+ }
675
+
676
+ :global(.theme-dark) .cc-value-loss {
677
+ color: #f87171;
678
+ }
679
+
680
+ :global(.theme-dark) .cc-tip {
681
+ background: rgba(180, 83, 9, 0.15);
682
+ border-color: rgba(180, 83, 9, 0.4);
683
+ color: #fbbf24;
684
+ }
685
+
686
+ :global(.theme-dark) .cc-panel-right {
687
+ background: linear-gradient(135deg, #1e293b, #0f172a);
688
+ }
689
+
690
+ :global(.theme-dark) .cc-circle-initial {
691
+ border-color: #b45309;
692
+ background: rgba(180, 83, 9, 0.1);
693
+ }
694
+
695
+ :global(.theme-dark) .cc-badge-initial {
696
+ background: #d97706;
697
+ }
698
+
699
+ :global(.theme-dark) .cc-circle-final {
700
+ border-color: #10b981;
701
+ background: rgba(16, 185, 129, 0.2);
702
+ }
703
+
704
+ :global(.theme-dark) .cc-viz-number {
705
+ color: #6ee7b7;
706
+ }
707
+
708
+ :global(.theme-dark) .cc-viz-unit {
709
+ color: #34d399;
710
+ }
711
+
712
+ :global(.theme-dark) .cc-badge-loss {
713
+ background: #ef4444;
714
+ }
715
+
716
+ :global(.theme-dark) .cc-area-item {
717
+ background: rgba(30, 41, 59, 0.6);
718
+ }
719
+
720
+ :global(.theme-dark) .cc-area-label {
721
+ color: #94a3b8;
722
+ }
723
+
724
+ :global(.theme-dark) .cc-area-initial {
725
+ color: #fbbf24;
726
+ }
727
+
728
+ :global(.theme-dark) .cc-area-final {
729
+ color: #34d399;
730
+ }
731
+ </style>