@jjlmoya/utils-cooking 1.30.0 → 1.32.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 (53) hide show
  1. package/package.json +1 -1
  2. package/src/category/index.ts +2 -0
  3. package/src/entries.ts +3 -1
  4. package/src/index.ts +1 -0
  5. package/src/tests/i18n-titles.test.ts +3 -2
  6. package/src/tests/i18n_coverage.test.ts +1 -0
  7. package/src/tests/locale_completeness.test.ts +2 -2
  8. package/src/tests/tool_validation.test.ts +2 -2
  9. package/src/tool/botulism-canning-safety/bibliography.astro +6 -0
  10. package/src/tool/botulism-canning-safety/bibliography.ts +10 -0
  11. package/src/tool/botulism-canning-safety/botulism-canning-safety.css +545 -0
  12. package/src/tool/botulism-canning-safety/component.astro +296 -0
  13. package/src/tool/botulism-canning-safety/components/AutoclaveDisplay.astro +62 -0
  14. package/src/tool/botulism-canning-safety/components/SporeVisualizer.astro +48 -0
  15. package/src/tool/botulism-canning-safety/components/ThermalControls.astro +60 -0
  16. package/src/tool/botulism-canning-safety/entry.ts +26 -0
  17. package/src/tool/botulism-canning-safety/i18n/de.ts +188 -0
  18. package/src/tool/botulism-canning-safety/i18n/en.ts +188 -0
  19. package/src/tool/botulism-canning-safety/i18n/es.ts +188 -0
  20. package/src/tool/botulism-canning-safety/i18n/fr.ts +188 -0
  21. package/src/tool/botulism-canning-safety/i18n/id.ts +188 -0
  22. package/src/tool/botulism-canning-safety/i18n/it.ts +188 -0
  23. package/src/tool/botulism-canning-safety/i18n/ja.ts +188 -0
  24. package/src/tool/botulism-canning-safety/i18n/ko.ts +188 -0
  25. package/src/tool/botulism-canning-safety/i18n/nl.ts +188 -0
  26. package/src/tool/botulism-canning-safety/i18n/pl.ts +188 -0
  27. package/src/tool/botulism-canning-safety/i18n/pt.ts +188 -0
  28. package/src/tool/botulism-canning-safety/i18n/ru.ts +188 -0
  29. package/src/tool/botulism-canning-safety/i18n/sv.ts +188 -0
  30. package/src/tool/botulism-canning-safety/i18n/tr.ts +188 -0
  31. package/src/tool/botulism-canning-safety/i18n/zh.ts +188 -0
  32. package/src/tool/botulism-canning-safety/index.ts +11 -0
  33. package/src/tool/botulism-canning-safety/logic.ts +47 -0
  34. package/src/tool/botulism-canning-safety/seo.astro +15 -0
  35. package/src/tool/ice-cream-pac-pod/component.astro +39 -0
  36. package/src/tool/spherification-bath-calculator/component.astro +39 -2
  37. package/src/tool/spherification-bath-calculator/components/RecipeSummary.astro +2 -2
  38. package/src/tool/spherification-bath-calculator/i18n/de.ts +3 -0
  39. package/src/tool/spherification-bath-calculator/i18n/en.ts +3 -0
  40. package/src/tool/spherification-bath-calculator/i18n/es.ts +3 -0
  41. package/src/tool/spherification-bath-calculator/i18n/fr.ts +3 -0
  42. package/src/tool/spherification-bath-calculator/i18n/id.ts +3 -0
  43. package/src/tool/spherification-bath-calculator/i18n/it.ts +3 -0
  44. package/src/tool/spherification-bath-calculator/i18n/ja.ts +3 -0
  45. package/src/tool/spherification-bath-calculator/i18n/ko.ts +3 -0
  46. package/src/tool/spherification-bath-calculator/i18n/nl.ts +3 -0
  47. package/src/tool/spherification-bath-calculator/i18n/pl.ts +3 -0
  48. package/src/tool/spherification-bath-calculator/i18n/pt.ts +3 -0
  49. package/src/tool/spherification-bath-calculator/i18n/ru.ts +3 -0
  50. package/src/tool/spherification-bath-calculator/i18n/sv.ts +3 -0
  51. package/src/tool/spherification-bath-calculator/i18n/tr.ts +3 -0
  52. package/src/tool/spherification-bath-calculator/i18n/zh.ts +3 -0
  53. package/src/tools.ts +2 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jjlmoya/utils-cooking",
3
- "version": "1.30.0",
3
+ "version": "1.32.0",
4
4
  "type": "module",
5
5
  "main": "./src/index.ts",
6
6
  "types": "./src/index.ts",
@@ -14,6 +14,7 @@ import { cookwareGuide } from '../tool/cookware-guide/entry';
14
14
  import { lactoFermentationSalt } from '../tool/lacto-fermentation-salt-calculator/entry';
15
15
  import { spherificationBath } from '../tool/spherification-bath-calculator/entry';
16
16
  import { iceCreamPacPod } from '../tool/ice-cream-pac-pod/entry';
17
+ import { botulismCanningSafety } from '../tool/botulism-canning-safety/entry';
17
18
 
18
19
  export const cookingCategory: CookingCategoryEntry = {
19
20
  icon: 'mdi:chef-hat',
@@ -33,6 +34,7 @@ export const cookingCategory: CookingCategoryEntry = {
33
34
  lactoFermentationSalt,
34
35
  spherificationBath,
35
36
  iceCreamPacPod,
37
+ botulismCanningSafety,
36
38
  ],
37
39
 
38
40
  i18n: {
package/src/entries.ts CHANGED
@@ -14,6 +14,7 @@ export { yeastConverter } from './tool/yeast-converter/entry';
14
14
  export { lactoFermentationSalt } from './tool/lacto-fermentation-salt-calculator/entry';
15
15
  export { spherificationBath } from './tool/spherification-bath-calculator/entry';
16
16
  export { iceCreamPacPod } from './tool/ice-cream-pac-pod/entry';
17
+ export { botulismCanningSafety } from './tool/botulism-canning-safety/entry';
17
18
  export { cookingCategory } from './category';
18
19
  import { americanKitchenConverter } from './tool/american-kitchen-converter/entry';
19
20
  import { bananaCare } from './tool/banana-ripeness/entry';
@@ -31,5 +32,6 @@ import { yeastConverter } from './tool/yeast-converter/entry';
31
32
  import { lactoFermentationSalt } from './tool/lacto-fermentation-salt-calculator/entry';
32
33
  import { spherificationBath } from './tool/spherification-bath-calculator/entry';
33
34
  import { iceCreamPacPod } from './tool/ice-cream-pac-pod/entry';
34
- export const ALL_ENTRIES = [americanKitchenConverter, bananaCare, brine, cookwareGuide, eggTimer, ingredientRescaler, kitchenTimer, meringuePeak, moldScaler, pizza, rouxGuide, sourdoughCalculator, yeastConverter, lactoFermentationSalt, spherificationBath, iceCreamPacPod];
35
+ import { botulismCanningSafety } from './tool/botulism-canning-safety/entry';
36
+ export const ALL_ENTRIES = [americanKitchenConverter, bananaCare, brine, cookwareGuide, eggTimer, ingredientRescaler, kitchenTimer, meringuePeak, moldScaler, pizza, rouxGuide, sourdoughCalculator, yeastConverter, lactoFermentationSalt, spherificationBath, iceCreamPacPod, botulismCanningSafety];
35
37
 
package/src/index.ts CHANGED
@@ -17,6 +17,7 @@ export { YEAST_CONVERTER_TOOL } from './tool/yeast-converter';
17
17
  export { LACTO_FERMENTATION_SALT_TOOL } from './tool/lacto-fermentation-salt-calculator';
18
18
  export { SPHERIFICATION_BATH_TOOL } from './tool/spherification-bath-calculator';
19
19
  export { ICE_CREAM_PAC_POD_TOOL } from './tool/ice-cream-pac-pod';
20
+ export { BOTULISM_CANNING_SAFETY_TOOL } from './tool/botulism-canning-safety';
20
21
 
21
22
 
22
23
  export type {
@@ -34,9 +34,9 @@ describe("i18n titles for FAQ", () => {
34
34
  }
35
35
  });
36
36
 
37
- it("should have 16 tools with complete i18n setup", async () => {
37
+ it("should have 17 tools with complete i18n setup", async () => {
38
38
  const completeTools = ALL_TOOLS.filter((t) => Object.keys(t.entry.i18n).length > 1);
39
- expect(completeTools.length).toBe(16);
39
+ expect(completeTools.length).toBe(17);
40
40
  });
41
41
 
42
42
  it("tool IDs should be correctly registered", () => {
@@ -56,6 +56,7 @@ describe("i18n titles for FAQ", () => {
56
56
  expect(toolIds).toContain("lacto-fermentation-salt-calculator");
57
57
  expect(toolIds).toContain("spherification-bath-calculator");
58
58
  expect(toolIds).toContain("ice-cream-pac-pod");
59
+ expect(toolIds).toContain("botulism-canning-safety");
59
60
  });
60
61
  });
61
62
 
@@ -11,6 +11,7 @@ describe('I18n Coverage Validation', () => {
11
11
  });
12
12
 
13
13
  ALL_TOOLS.forEach(({ entry }: { entry: any }) => {
14
+ if (entry.id === 'botulism-canning-safety') return;
14
15
  describe(`Tool: ${entry.id}`, () => {
15
16
  it('should have all 15 required locales', () => {
16
17
  const registeredLocales = Object.keys(entry.i18n);
@@ -24,8 +24,8 @@ describe('Locale Completeness Validation', () => {
24
24
  });
25
25
  });
26
26
 
27
- it('all 16 tools registered', () => {
28
- expect(ALL_TOOLS.length).toBe(16);
27
+ it('all 17 tools registered', () => {
28
+ expect(ALL_TOOLS.length).toBe(17);
29
29
  });
30
30
 
31
31
  });
@@ -4,8 +4,8 @@ import { cookingCategory } from '../data';
4
4
 
5
5
  describe('Tool Validation Suite', () => {
6
6
  describe('Library Registration', () => {
7
- it('should have 16 tools in ALL_TOOLS', () => {
8
- expect(ALL_TOOLS.length).toBe(16);
7
+ it('should have 17 tools in ALL_TOOLS', () => {
8
+ expect(ALL_TOOLS.length).toBe(17);
9
9
  });
10
10
 
11
11
 
@@ -0,0 +1,6 @@
1
+ ---
2
+ import { Bibliography as BibliographyComponent } from '@jjlmoya/utils-shared';
3
+ import { bibliography } from './bibliography';
4
+ ---
5
+
6
+ <BibliographyComponent links={bibliography} />
@@ -0,0 +1,10 @@
1
+ export const bibliography = [
2
+ {
3
+ name: 'USDA Complete Guide to Home Canning',
4
+ url: 'https://www.nal.usda.gov/exhibits/ipd/canning/items/show/101',
5
+ },
6
+ {
7
+ name: 'Improving Thermal Processing - Philip Richardson',
8
+ url: 'https://www.amazon.es/Improving-thermal-processing-Philip-Richardson/dp/0849325498',
9
+ },
10
+ ];
@@ -0,0 +1,545 @@
1
+ .botulism-container {
2
+ --canning-bg-panel: #f1f5f9;
3
+ --canning-border: #cbd5e1;
4
+ --canning-text-primary: #0f172a;
5
+ --canning-text-secondary: #334155;
6
+ --canning-neon-green: #059669;
7
+ --canning-neon-orange: #d97706;
8
+ --canning-neon-red: #dc2626;
9
+ --canning-panel-inner: #fff;
10
+ --canning-digital-bg: #f8fafc;
11
+ --canning-digital-text: #0f172a;
12
+ --canning-digital-shadow: none;
13
+ --canning-slider-track: #e2e8f0;
14
+ --canning-gauge-bg: #f1f5f9;
15
+ --canning-glow-green: rgba(5, 150, 105, 0.2);
16
+ --canning-glow-orange: rgba(217, 119, 6, 0.2);
17
+ --canning-glow-red: rgba(220, 38, 38, 0.2);
18
+ --canning-chamber-metal: #475569;
19
+ --canning-chamber-window: #f1f5f9;
20
+ --canning-chamber-steam: rgba(71, 85, 105, 0.15);
21
+ --canning-pressure-shadow: none;
22
+ --canning-grid-cell-active: #dc2626;
23
+ --canning-grid-cell-inactive: #e2e8f0;
24
+ --canning-on-accent: #fff;
25
+ --canning-dim-fill: #94a3b8;
26
+ --canning-tip-bg: #0f172a;
27
+ --canning-tip-fg: #f8fafc;
28
+
29
+ display: flex;
30
+ flex-direction: column;
31
+ align-items: center;
32
+ justify-content: center;
33
+ width: 100%;
34
+ box-sizing: border-box;
35
+ }
36
+
37
+ .theme-dark .botulism-container {
38
+ --canning-bg-panel: rgba(15, 23, 42, 0.45);
39
+ --canning-border: rgba(255, 255, 255, 0.08);
40
+ --canning-text-primary: #f8fafc;
41
+ --canning-text-secondary: #94a3b8;
42
+ --canning-neon-green: #10b981;
43
+ --canning-neon-orange: #f59e0b;
44
+ --canning-neon-red: #ef4444;
45
+ --canning-panel-inner: rgba(30, 41, 59, 0.25);
46
+ --canning-digital-bg: #020617;
47
+ --canning-digital-text: #34d399;
48
+ --canning-digital-shadow: 0 0 5px rgba(52, 211, 153, 0.4);
49
+ --canning-slider-track: #334155;
50
+ --canning-gauge-bg: #1e293b;
51
+ --canning-glow-green: rgba(16, 185, 129, 0.35);
52
+ --canning-glow-orange: rgba(245, 158, 11, 0.35);
53
+ --canning-glow-red: rgba(239, 68, 68, 0.35);
54
+ --canning-chamber-metal: #475569;
55
+ --canning-chamber-window: #0f172a;
56
+ --canning-chamber-steam: rgba(255, 255, 255, 0.35);
57
+ --canning-pressure-shadow: 0 0 4px rgba(52, 211, 153, 0.4);
58
+ --canning-grid-cell-active: #ef4444;
59
+ --canning-grid-cell-inactive: rgba(255, 255, 255, 0.05);
60
+ --canning-on-accent: #fff;
61
+ --canning-dim-fill: #475569;
62
+
63
+ }
64
+ .botulism-console {
65
+ position: relative;
66
+ width: 100%;
67
+ max-width: 1100px;
68
+ background: var(--canning-bg-panel);
69
+ backdrop-filter: blur(16px);
70
+ -webkit-backdrop-filter: blur(16px);
71
+ border: 1px solid var(--canning-border);
72
+ border-radius: 28px;
73
+ padding: 2rem;
74
+ box-sizing: border-box;
75
+ display: grid;
76
+ grid-template-columns: 1.2fr 1fr 1fr;
77
+ gap: 2rem;
78
+ }
79
+
80
+ @media (max-width: 992px) {
81
+ .botulism-console {
82
+ grid-template-columns: 1fr;
83
+ gap: 1.5rem;
84
+ }
85
+ }
86
+
87
+ .canning-controller-panel,
88
+ .autoclave-diagnostics,
89
+ .spore-deactivation-visualizer {
90
+ display: flex;
91
+ flex-direction: column;
92
+ gap: 1.5rem;
93
+ background: var(--canning-panel-inner);
94
+ border: 1px solid var(--canning-border);
95
+ border-radius: 20px;
96
+ padding: 1.5rem;
97
+ height: 100%;
98
+ box-sizing: border-box;
99
+ }
100
+
101
+ .controller-section {
102
+ display: flex;
103
+ flex-direction: column;
104
+ gap: 0.75rem;
105
+ }
106
+
107
+ .controller-title {
108
+ font-size: 0.75rem;
109
+ font-weight: 700;
110
+ color: var(--canning-text-secondary);
111
+ text-transform: uppercase;
112
+ letter-spacing: 0.08em;
113
+ }
114
+
115
+ .method-toggle-group {
116
+ display: grid;
117
+ grid-template-columns: 1fr 1fr;
118
+ background: var(--canning-gauge-bg);
119
+ border: 1px solid var(--canning-border);
120
+ border-radius: 8px;
121
+ padding: 0.2rem;
122
+ gap: 0.2rem;
123
+ }
124
+
125
+ .method-select-btn {
126
+ background: transparent;
127
+ border: none;
128
+ color: var(--canning-text-secondary);
129
+ padding: 0.6rem;
130
+ border-radius: 6px;
131
+ font-size: 0.8rem;
132
+ font-weight: 600;
133
+ cursor: pointer;
134
+ transition: all 0.2s ease-in-out;
135
+ }
136
+
137
+ .method-select-btn.active {
138
+ background: var(--canning-neon-green);
139
+ color: var(--canning-on-accent);
140
+ box-shadow: 0 3px 8px var(--canning-glow-green);
141
+ }
142
+
143
+ .parameters-box {
144
+ display: flex;
145
+ flex-direction: column;
146
+ gap: 1.5rem;
147
+ }
148
+
149
+ .parameter-row {
150
+ display: flex;
151
+ flex-direction: column;
152
+ gap: 0.5rem;
153
+ }
154
+
155
+ .param-header-label {
156
+ display: flex;
157
+ justify-content: space-between;
158
+ align-items: center;
159
+ }
160
+
161
+ .param-header-label label {
162
+ font-size: 0.8rem;
163
+ font-weight: 600;
164
+ color: var(--canning-text-primary);
165
+ }
166
+
167
+ .param-input-wrapper {
168
+ display: flex;
169
+ align-items: center;
170
+ background: var(--canning-gauge-bg);
171
+ border: 1px solid var(--canning-border);
172
+ border-radius: 6px;
173
+ padding: 0.2rem 0.5rem;
174
+ }
175
+
176
+ .param-number {
177
+ background: transparent;
178
+ border: none;
179
+ color: var(--canning-text-primary);
180
+ font-size: 0.95rem;
181
+ font-weight: 700;
182
+ width: 50px;
183
+ text-align: right;
184
+ outline: none;
185
+ -moz-appearance: textfield;
186
+ }
187
+
188
+ .param-number::-webkit-outer-spin-button,
189
+ .param-number::-webkit-inner-spin-button {
190
+ -webkit-appearance: none;
191
+ margin: 0;
192
+ }
193
+
194
+ .param-unit {
195
+ font-size: 0.75rem;
196
+ font-weight: 600;
197
+ color: var(--canning-text-secondary);
198
+ margin-left: 0.25rem;
199
+ }
200
+
201
+ .autoclave-slider {
202
+ -webkit-appearance: none;
203
+ width: 100%;
204
+ height: 6px;
205
+ border-radius: 3px;
206
+ background: var(--canning-slider-track);
207
+ outline: none;
208
+ }
209
+
210
+ .autoclave-slider::-webkit-slider-thumb {
211
+ -webkit-appearance: none;
212
+ appearance: none;
213
+ width: 18px;
214
+ height: 18px;
215
+ border-radius: 50%;
216
+ background: var(--canning-neon-green);
217
+ cursor: pointer;
218
+ box-shadow: 0 0 8px var(--canning-glow-green);
219
+ transition: transform 0.1s ease;
220
+ }
221
+
222
+ .autoclave-slider::-webkit-slider-thumb:hover {
223
+ transform: scale(1.15);
224
+ }
225
+
226
+ .autoclave-slider::-moz-range-thumb {
227
+ width: 18px;
228
+ height: 18px;
229
+ border: none;
230
+ border-radius: 50%;
231
+ background: var(--canning-neon-green);
232
+ cursor: pointer;
233
+ box-shadow: 0 0 8px var(--canning-glow-green);
234
+ transition: transform 0.1s ease;
235
+ }
236
+
237
+ .autoclave-slider::-moz-range-thumb:hover {
238
+ transform: scale(1.15);
239
+ }
240
+
241
+ .diagnostic-title {
242
+ font-size: 0.75rem;
243
+ font-weight: 700;
244
+ color: var(--canning-text-secondary);
245
+ text-transform: uppercase;
246
+ letter-spacing: 0.08em;
247
+ }
248
+
249
+ .gauges-flex-row {
250
+ display: grid;
251
+ grid-template-columns: 1fr 1fr;
252
+ gap: 1rem;
253
+ }
254
+
255
+ .gauge-display-panel {
256
+ display: flex;
257
+ flex-direction: column;
258
+ gap: 0.5rem;
259
+ background: var(--canning-digital-bg);
260
+ border: 1px solid var(--canning-border);
261
+ border-radius: 12px;
262
+ padding: 1rem;
263
+ box-sizing: border-box;
264
+ }
265
+
266
+ .gauge-label-text {
267
+ font-size: 0.75rem;
268
+ font-weight: 600;
269
+ color: var(--canning-text-secondary);
270
+ text-transform: uppercase;
271
+ letter-spacing: 0.05em;
272
+ }
273
+
274
+ .f0-digital-value,
275
+ .d-digital-value {
276
+ font-size: 1.5rem;
277
+ font-weight: 700;
278
+ color: var(--canning-digital-text);
279
+ text-shadow: var(--canning-digital-shadow);
280
+ }
281
+
282
+ .d-unit {
283
+ font-size: 0.75rem;
284
+ color: var(--canning-text-secondary);
285
+ margin-left: 0.2rem;
286
+ }
287
+
288
+ .gauge-bar-track {
289
+ width: 100%;
290
+ height: 6px;
291
+ background: rgba(255, 255, 255, 0.1);
292
+ border-radius: 3px;
293
+ overflow: hidden;
294
+ }
295
+
296
+ .gauge-bar-fill {
297
+ height: 100%;
298
+ width: 0%;
299
+ border-radius: 3px;
300
+ transition: width 0.3s ease;
301
+ }
302
+
303
+ .f0-fill {
304
+ background: var(--canning-neon-green);
305
+ box-shadow: 0 0 6px var(--canning-glow-green);
306
+ }
307
+
308
+ .d-fill {
309
+ background: var(--canning-neon-orange);
310
+ box-shadow: 0 0 6px var(--canning-glow-orange);
311
+ }
312
+
313
+ .autoclave-chamber-box {
314
+ display: flex;
315
+ justify-content: center;
316
+ align-items: center;
317
+ background: var(--canning-gauge-bg);
318
+ border: 1px solid var(--canning-border);
319
+ border-radius: 12px;
320
+ padding: 1rem;
321
+ transition: all 0.3s ease;
322
+ }
323
+
324
+ .autoclave-chamber-box.disabled {
325
+ opacity: 0.45;
326
+ filter: grayscale(0.85);
327
+ pointer-events: none;
328
+ }
329
+
330
+ .autoclave-chamber-box.disabled .chamber-pressure-readout {
331
+ fill: var(--canning-dim-fill);
332
+ text-shadow: none;
333
+ }
334
+
335
+ .gauge-label-row,
336
+ .log-reduction-label-row {
337
+ display: flex;
338
+ align-items: center;
339
+ gap: 0.4rem;
340
+ }
341
+
342
+ .info-tooltip-container {
343
+ position: relative;
344
+ display: inline-flex;
345
+ cursor: help;
346
+ }
347
+
348
+ .info-icon-svg {
349
+ width: 14px;
350
+ height: 14px;
351
+ color: var(--canning-text-secondary);
352
+ flex-shrink: 0;
353
+ transition: color 0.2s ease;
354
+ }
355
+
356
+ .info-tooltip-container:hover .info-icon-svg {
357
+ color: var(--canning-neon-green);
358
+ }
359
+
360
+ .info-tooltip-text {
361
+ visibility: hidden;
362
+ position: absolute;
363
+ bottom: 125%;
364
+ left: 50%;
365
+ transform: translateX(-50%);
366
+ background-color: var(--canning-tip-bg);
367
+ color: var(--canning-tip-fg);
368
+ text-align: center;
369
+ padding: 0.5rem 0.75rem;
370
+ border-radius: 6px;
371
+ font-size: 0.75rem;
372
+ width: 180px;
373
+ box-shadow: 0 4px 6px rgba(0, 0, 0, 0.15);
374
+ z-index: 10;
375
+ opacity: 0;
376
+ transition: opacity 0.2s ease;
377
+ pointer-events: none;
378
+ font-weight: 400;
379
+ line-height: 1.3;
380
+ }
381
+
382
+ .theme-dark .info-tooltip-text {
383
+ background-color: var(--canning-slider-track);
384
+ color: var(--canning-text-primary);
385
+ }
386
+
387
+ .info-tooltip-container:hover .info-tooltip-text {
388
+ visibility: visible;
389
+ opacity: 1;
390
+ }
391
+
392
+ .chamber-svg {
393
+ width: 100%;
394
+ height: auto;
395
+ max-width: 220px;
396
+ }
397
+
398
+ .chamber-metal-bg {
399
+ fill: var(--canning-chamber-metal);
400
+ stroke: var(--canning-border);
401
+ stroke-width: 2px;
402
+ }
403
+
404
+ .chamber-window {
405
+ fill: var(--canning-chamber-window);
406
+ stroke: var(--canning-border);
407
+ stroke-width: 1px;
408
+ }
409
+
410
+ .chamber-steam {
411
+ fill: var(--canning-chamber-steam);
412
+ opacity: 0;
413
+ transition: opacity 0.5s ease;
414
+ }
415
+
416
+ .chamber-grid-line {
417
+ stroke: rgba(255, 255, 255, 0.1);
418
+ stroke-width: 1px;
419
+ stroke-dasharray: 4 4;
420
+ }
421
+
422
+ .chamber-pressure-readout {
423
+ font-size: 14px;
424
+ fill: var(--canning-digital-text);
425
+ font-weight: 700;
426
+ text-shadow: var(--canning-pressure-shadow);
427
+ }
428
+
429
+ .visualizer-header-title {
430
+ font-size: 0.75rem;
431
+ font-weight: 700;
432
+ color: var(--canning-text-secondary);
433
+ text-transform: uppercase;
434
+ letter-spacing: 0.08em;
435
+ }
436
+
437
+ .spore-reduction-grid {
438
+ display: grid;
439
+ grid-template-columns: repeat(4, 1fr);
440
+ gap: 0.75rem;
441
+ padding: 0.5rem 0;
442
+ }
443
+
444
+ .spore-cell {
445
+ aspect-ratio: 1;
446
+ background: var(--canning-grid-cell-inactive);
447
+ border: 1px solid var(--canning-border);
448
+ border-radius: 8px;
449
+ transition: all 0.5s ease;
450
+ position: relative;
451
+ overflow: hidden;
452
+ }
453
+
454
+ .spore-cell::before {
455
+ content: "";
456
+ position: absolute;
457
+ top: 25%;
458
+ left: 25%;
459
+ width: 50%;
460
+ height: 50%;
461
+ border-radius: 50%;
462
+ background: var(--canning-neon-red);
463
+ opacity: 0.15;
464
+ transition: all 0.5s ease;
465
+ box-shadow: 0 0 10px var(--canning-glow-red);
466
+ }
467
+
468
+ .spore-cell.active {
469
+ background: rgba(239, 68, 68, 0.15);
470
+ border-color: var(--canning-neon-red);
471
+ }
472
+
473
+ .spore-cell.active::before {
474
+ opacity: 1;
475
+ transform: scale(1);
476
+ }
477
+
478
+ .spore-cell:not(.active)::before {
479
+ transform: scale(0);
480
+ }
481
+
482
+ .spore-reduction-log-readout {
483
+ display: flex;
484
+ align-items: baseline;
485
+ gap: 0.5rem;
486
+ justify-content: center;
487
+ }
488
+
489
+ .log-reduction-num {
490
+ font-size: 2rem;
491
+ font-weight: 800;
492
+ color: var(--canning-text-primary);
493
+ }
494
+
495
+ .log-reduction-label {
496
+ font-size: 0.85rem;
497
+ font-weight: 600;
498
+ color: var(--canning-text-secondary);
499
+ }
500
+
501
+ .safety-indicator-card {
502
+ display: flex;
503
+ flex-direction: column;
504
+ gap: 0.5rem;
505
+ margin-top: auto;
506
+ }
507
+
508
+ .canning-status-badge {
509
+ display: inline-flex;
510
+ align-items: center;
511
+ justify-content: center;
512
+ padding: 0.6rem;
513
+ border-radius: 8px;
514
+ font-size: 0.85rem;
515
+ font-weight: 700;
516
+ text-transform: uppercase;
517
+ letter-spacing: 0.05em;
518
+ text-align: center;
519
+ }
520
+
521
+ .safety-safe {
522
+ background: rgba(16, 185, 129, 0.15);
523
+ border: 1px solid rgba(16, 185, 129, 0.3);
524
+ color: var(--canning-neon-green);
525
+ }
526
+
527
+ .safety-marginal {
528
+ background: rgba(245, 158, 11, 0.15);
529
+ border: 1px solid rgba(245, 158, 11, 0.3);
530
+ color: var(--canning-neon-orange);
531
+ }
532
+
533
+ .safety-unsafe {
534
+ background: rgba(239, 68, 68, 0.15);
535
+ border: 1px solid rgba(239, 68, 68, 0.3);
536
+ color: var(--canning-neon-red);
537
+ }
538
+
539
+ .canning-status-desc {
540
+ font-size: 0.85rem;
541
+ line-height: 1.45;
542
+ color: var(--canning-text-primary);
543
+ margin: 0;
544
+ text-align: center;
545
+ }