@jjlmoya/utils-cooking 1.2.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 (130) hide show
  1. package/package.json +60 -0
  2. package/src/category/i18n/en.ts +24 -0
  3. package/src/category/i18n/es.ts +208 -0
  4. package/src/category/i18n/fr.ts +24 -0
  5. package/src/category/index.ts +37 -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 +32 -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/i18n-titles.test.ts +66 -0
  18. package/src/tests/locale_completeness.test.ts +42 -0
  19. package/src/tests/mocks/astro_mock.js +2 -0
  20. package/src/tests/no_h1_in_components.test.ts +48 -0
  21. package/src/tests/seo_length.test.ts +22 -0
  22. package/src/tests/tool_validation.test.ts +17 -0
  23. package/src/tool/american-kitchen-converter/AmericanKitchenEngine.ts +259 -0
  24. package/src/tool/american-kitchen-converter/bibliography.astro +6 -0
  25. package/src/tool/american-kitchen-converter/component.astro +838 -0
  26. package/src/tool/american-kitchen-converter/i18n/en.ts +282 -0
  27. package/src/tool/american-kitchen-converter/i18n/es.ts +281 -0
  28. package/src/tool/american-kitchen-converter/i18n/fr.ts +292 -0
  29. package/src/tool/american-kitchen-converter/index.ts +24 -0
  30. package/src/tool/american-kitchen-converter/seo.astro +8 -0
  31. package/src/tool/banana-ripeness/BananaCare.css +587 -0
  32. package/src/tool/banana-ripeness/BananaEngine.ts +79 -0
  33. package/src/tool/banana-ripeness/bibliography.astro +6 -0
  34. package/src/tool/banana-ripeness/component.astro +285 -0
  35. package/src/tool/banana-ripeness/i18n/en.ts +177 -0
  36. package/src/tool/banana-ripeness/i18n/es.ts +177 -0
  37. package/src/tool/banana-ripeness/i18n/fr.ts +177 -0
  38. package/src/tool/banana-ripeness/index.ts +24 -0
  39. package/src/tool/banana-ripeness/seo.astro +8 -0
  40. package/src/tool/brine/bibliography.astro +6 -0
  41. package/src/tool/brine/component.astro +884 -0
  42. package/src/tool/brine/i18n/en.ts +221 -0
  43. package/src/tool/brine/i18n/es.ts +222 -0
  44. package/src/tool/brine/i18n/fr.ts +221 -0
  45. package/src/tool/brine/index.ts +26 -0
  46. package/src/tool/brine/seo.astro +8 -0
  47. package/src/tool/cookware-guide/CookwareGuide.css +487 -0
  48. package/src/tool/cookware-guide/bibliography.astro +6 -0
  49. package/src/tool/cookware-guide/component.astro +164 -0
  50. package/src/tool/cookware-guide/i18n/en.ts +163 -0
  51. package/src/tool/cookware-guide/i18n/es.ts +163 -0
  52. package/src/tool/cookware-guide/i18n/fr.ts +164 -0
  53. package/src/tool/cookware-guide/index.ts +24 -0
  54. package/src/tool/cookware-guide/init.ts +174 -0
  55. package/src/tool/cookware-guide/seo.astro +8 -0
  56. package/src/tool/egg-timer/EggTimer.css +503 -0
  57. package/src/tool/egg-timer/bibliography.astro +14 -0
  58. package/src/tool/egg-timer/component.astro +281 -0
  59. package/src/tool/egg-timer/i18n/en.ts +230 -0
  60. package/src/tool/egg-timer/i18n/es.ts +222 -0
  61. package/src/tool/egg-timer/i18n/fr.ts +121 -0
  62. package/src/tool/egg-timer/index.ts +27 -0
  63. package/src/tool/egg-timer/seo.astro +39 -0
  64. package/src/tool/ingredient-rescaler/IngredientRescaler.css +308 -0
  65. package/src/tool/ingredient-rescaler/bibliography.astro +6 -0
  66. package/src/tool/ingredient-rescaler/component.astro +107 -0
  67. package/src/tool/ingredient-rescaler/i18n/en.ts +265 -0
  68. package/src/tool/ingredient-rescaler/i18n/es.ts +268 -0
  69. package/src/tool/ingredient-rescaler/i18n/fr.ts +207 -0
  70. package/src/tool/ingredient-rescaler/index.ts +24 -0
  71. package/src/tool/ingredient-rescaler/init.ts +200 -0
  72. package/src/tool/ingredient-rescaler/seo.astro +8 -0
  73. package/src/tool/kitchen-timer/KitchenTimer.css +325 -0
  74. package/src/tool/kitchen-timer/bibliography.astro +6 -0
  75. package/src/tool/kitchen-timer/component.astro +341 -0
  76. package/src/tool/kitchen-timer/i18n/en.ts +154 -0
  77. package/src/tool/kitchen-timer/i18n/es.ts +154 -0
  78. package/src/tool/kitchen-timer/i18n/fr.ts +154 -0
  79. package/src/tool/kitchen-timer/index.ts +26 -0
  80. package/src/tool/kitchen-timer/init.ts +55 -0
  81. package/src/tool/kitchen-timer/lib/AudioHelper.ts +27 -0
  82. package/src/tool/kitchen-timer/lib/DockManager.ts +97 -0
  83. package/src/tool/kitchen-timer/lib/KitchenTimer.ts +264 -0
  84. package/src/tool/kitchen-timer/seo.astro +8 -0
  85. package/src/tool/meringue-peak/MeringueCalculator.css +298 -0
  86. package/src/tool/meringue-peak/bibliography.astro +6 -0
  87. package/src/tool/meringue-peak/component.astro +169 -0
  88. package/src/tool/meringue-peak/i18n/en.ts +257 -0
  89. package/src/tool/meringue-peak/i18n/es.ts +234 -0
  90. package/src/tool/meringue-peak/i18n/fr.ts +234 -0
  91. package/src/tool/meringue-peak/index.ts +24 -0
  92. package/src/tool/meringue-peak/seo.astro +8 -0
  93. package/src/tool/mold-scaler/MoldScaler.css +406 -0
  94. package/src/tool/mold-scaler/bibliography.astro +6 -0
  95. package/src/tool/mold-scaler/component.astro +126 -0
  96. package/src/tool/mold-scaler/i18n/en.ts +268 -0
  97. package/src/tool/mold-scaler/i18n/es.ts +269 -0
  98. package/src/tool/mold-scaler/i18n/fr.ts +276 -0
  99. package/src/tool/mold-scaler/index.ts +26 -0
  100. package/src/tool/mold-scaler/init.ts +264 -0
  101. package/src/tool/mold-scaler/seo.astro +8 -0
  102. package/src/tool/pizza/Pizza.css +569 -0
  103. package/src/tool/pizza/bibliography.astro +6 -0
  104. package/src/tool/pizza/calculator.ts +143 -0
  105. package/src/tool/pizza/component.astro +237 -0
  106. package/src/tool/pizza/i18n/en.ts +288 -0
  107. package/src/tool/pizza/i18n/es.ts +289 -0
  108. package/src/tool/pizza/i18n/fr.ts +288 -0
  109. package/src/tool/pizza/index.ts +27 -0
  110. package/src/tool/pizza/seo.astro +8 -0
  111. package/src/tool/roux-guide/RouxGuide.css +483 -0
  112. package/src/tool/roux-guide/bibliography.astro +6 -0
  113. package/src/tool/roux-guide/component.astro +194 -0
  114. package/src/tool/roux-guide/i18n/en.ts +233 -0
  115. package/src/tool/roux-guide/i18n/es.ts +225 -0
  116. package/src/tool/roux-guide/i18n/fr.ts +225 -0
  117. package/src/tool/roux-guide/index.ts +24 -0
  118. package/src/tool/roux-guide/init.ts +187 -0
  119. package/src/tool/roux-guide/seo.astro +8 -0
  120. package/src/tool/sourdough-calculator/SourdoughCalculator.css +369 -0
  121. package/src/tool/sourdough-calculator/bibliography.astro +6 -0
  122. package/src/tool/sourdough-calculator/component.astro +198 -0
  123. package/src/tool/sourdough-calculator/i18n/en.ts +242 -0
  124. package/src/tool/sourdough-calculator/i18n/es.ts +243 -0
  125. package/src/tool/sourdough-calculator/i18n/fr.ts +248 -0
  126. package/src/tool/sourdough-calculator/index.ts +24 -0
  127. package/src/tool/sourdough-calculator/init.ts +131 -0
  128. package/src/tool/sourdough-calculator/seo.astro +8 -0
  129. package/src/tools.ts +29 -0
  130. package/src/types.ts +73 -0
@@ -0,0 +1,24 @@
1
+ import type { CookingToolEntry, ToolDefinition } from '../../types';
2
+ import RouxGuideComponent from './component.astro';
3
+ import RouxGuideSEO from './seo.astro';
4
+ import RouxGuideBibliography from './bibliography.astro';
5
+
6
+ export const rouxGuide: CookingToolEntry = {
7
+ id: 'roux-guide',
8
+ icons: {
9
+ bg: 'mdi:chef-hat',
10
+ fg: 'mdi:pot-mix',
11
+ },
12
+ i18n: {
13
+ es: () => import('./i18n/es').then((m) => m.content),
14
+ en: () => import('./i18n/en').then((m) => m.content),
15
+ fr: () => import('./i18n/fr').then((m) => m.content),
16
+ },
17
+ };
18
+
19
+ export const ROUX_GUIDE_TOOL: ToolDefinition = {
20
+ entry: rouxGuide,
21
+ Component: RouxGuideComponent,
22
+ SEOComponent: RouxGuideSEO,
23
+ BibliographyComponent: RouxGuideBibliography,
24
+ };
@@ -0,0 +1,187 @@
1
+ type LiquidType = 'milk' | 'lightStock' | 'darkStock' | 'tomato';
2
+ type TextureLevel = 1 | 2 | 3 | 4;
3
+
4
+ interface LiquidConfig {
5
+ name: string;
6
+ rouxType: 'white' | 'blond' | 'brown';
7
+ tip: string;
8
+ }
9
+
10
+ interface RouxInfo {
11
+ label: string;
12
+ time: string;
13
+ description: string;
14
+ }
15
+
16
+ interface State {
17
+ volume: number;
18
+ liquid: LiquidType;
19
+ level: TextureLevel;
20
+ }
21
+
22
+ const VISCOSITY_RATIOS: Record<TextureLevel, number> = {
23
+ 1: 50,
24
+ 2: 90,
25
+ 3: 130,
26
+ 4: 185,
27
+ };
28
+
29
+ const LIQUID_CONFIG: Record<LiquidType, LiquidConfig> = {
30
+ milk: {
31
+ name: 'Béchamel',
32
+ rouxType: 'white',
33
+ tip: 'Usa leche fría. Añádela gradualmente al principio o de golpe si bates fuerte.',
34
+ },
35
+ lightStock: {
36
+ name: 'Velouté',
37
+ rouxType: 'blond',
38
+ tip: 'Usa fondo de ave o pescado. Deja que el roux huela a galleta antes de ligar.',
39
+ },
40
+ darkStock: {
41
+ name: 'Espagnole',
42
+ rouxType: 'brown',
43
+ tip: 'Para salsas oscuras potentes. El roux debe estar color chocolate, pero sin quemarse.',
44
+ },
45
+ tomato: {
46
+ name: 'Salsa de Tomate',
47
+ rouxType: 'blond',
48
+ tip: 'El roux ayudará a dar cuerpo y suavidad a la textura final del tomate.',
49
+ },
50
+ };
51
+
52
+ const ROUX_INFO: Record<'white' | 'blond' | 'brown', RouxInfo> = {
53
+ white: {
54
+ label: 'Blanco',
55
+ time: '2-3 min',
56
+ description: 'Cocina solo hasta perder el olor a harina cruda. Sin color.',
57
+ },
58
+ blond: {
59
+ label: 'Rubio',
60
+ time: '5-8 min',
61
+ description: 'Busca un color de mantequilla tostada y un aroma a nueces.',
62
+ },
63
+ brown: {
64
+ label: 'Oscuro',
65
+ time: '15-20 min',
66
+ description: 'Fuego muy suave. Color chocolate. Nota: requiere un 10% más de peso.',
67
+ },
68
+ };
69
+
70
+ interface RouxElements {
71
+ volumeInput: HTMLInputElement;
72
+ liquidBtns: NodeListOf<Element>;
73
+ textureBtns: NodeListOf<Element>;
74
+ progressBar: HTMLElement;
75
+ butterOut: HTMLElement;
76
+ flourOut: HTMLElement;
77
+ rouxLabel: HTMLElement;
78
+ cookInst: HTMLElement;
79
+ sauceName: HTMLElement;
80
+ ratioDisp: HTMLElement;
81
+ chefTip: HTMLElement;
82
+ }
83
+
84
+ function getRequiredElements(): Record<string, HTMLElement | null> {
85
+ return {
86
+ volumeInput: document.getElementById('volume-input'),
87
+ progressBar: document.getElementById('progress-bar'),
88
+ butterOut: document.getElementById('butter-output'),
89
+ flourOut: document.getElementById('flour-output'),
90
+ rouxLabel: document.getElementById('roux-type-label'),
91
+ cookInst: document.getElementById('cooking-instructions'),
92
+ sauceName: document.getElementById('sauce-name'),
93
+ ratioDisp: document.getElementById('ratio-display'),
94
+ chefTip: document.getElementById('chef-tip'),
95
+ };
96
+ }
97
+
98
+ function validateElements(els: Record<string, HTMLElement | null>): boolean {
99
+ const requiredKeys = ['volumeInput', 'progressBar', 'butterOut', 'flourOut', 'rouxLabel', 'cookInst', 'sauceName', 'ratioDisp', 'chefTip'];
100
+ return requiredKeys.every((key) => els[key]);
101
+ }
102
+
103
+ function setupElements(): RouxElements | null {
104
+ const els = getRequiredElements();
105
+ if (!validateElements(els)) return null;
106
+
107
+ const volumeInput = els.volumeInput as HTMLInputElement;
108
+ return {
109
+ volumeInput,
110
+ liquidBtns: document.querySelectorAll('.liquid-btn'),
111
+ textureBtns: document.querySelectorAll('.texture-btn'),
112
+ progressBar: els.progressBar as HTMLElement,
113
+ butterOut: els.butterOut as HTMLElement,
114
+ flourOut: els.flourOut as HTMLElement,
115
+ rouxLabel: els.rouxLabel as HTMLElement,
116
+ cookInst: els.cookInst as HTMLElement,
117
+ sauceName: els.sauceName as HTMLElement,
118
+ ratioDisp: els.ratioDisp as HTMLElement,
119
+ chefTip: els.chefTip as HTMLElement,
120
+ };
121
+ }
122
+
123
+ function setupLiquidButtons(els: RouxElements, state: State, updateCalculations: () => void): void {
124
+ els.liquidBtns.forEach((btn) => {
125
+ btn.addEventListener('click', () => {
126
+ els.liquidBtns.forEach((b) => {
127
+ b.classList.remove('active', 'bg-white', 'dark:bg-slate-700', 'shadow-md', 'ring-2', 'ring-indigo-500/20');
128
+ });
129
+ btn.classList.add('active', 'bg-white', 'dark:bg-slate-700', 'shadow-md', 'ring-2', 'ring-indigo-500/20');
130
+ state.liquid = (btn as HTMLElement).dataset.type as LiquidType || 'milk';
131
+ updateCalculations();
132
+ });
133
+ });
134
+ }
135
+
136
+ function setupTextureButtons(els: RouxElements, state: State, updateCalculations: () => void): void {
137
+ els.textureBtns.forEach((btn) => {
138
+ btn.addEventListener('click', () => {
139
+ els.textureBtns.forEach((b) => {
140
+ b.classList.remove('active', 'border-amber-500/50', 'bg-amber-50', 'dark:bg-amber-900/10');
141
+ b.classList.add('border-slate-100', 'dark:border-slate-800', 'bg-white', 'dark:bg-slate-900');
142
+ });
143
+
144
+ btn.classList.remove('border-slate-100', 'dark:border-slate-800', 'bg-white', 'dark:bg-slate-900');
145
+ btn.classList.add('active', 'border-amber-500/50', 'bg-amber-50', 'dark:bg-amber-900/10');
146
+ state.level = parseInt((btn as HTMLElement).dataset.level || '2') as TextureLevel;
147
+ updateCalculations();
148
+ });
149
+ });
150
+ }
151
+
152
+ function updateDisplay(els: RouxElements, state: State): void {
153
+ const config = LIQUID_CONFIG[state.liquid];
154
+ const baseRatio = VISCOSITY_RATIOS[state.level];
155
+ const liters = state.volume / 1000;
156
+ const correctionFactor = config.rouxType === 'brown' ? 1.15 : 1.0;
157
+ const totalRoux = Math.round(baseRatio * liters * correctionFactor);
158
+ const each = Math.round(totalRoux / 2);
159
+
160
+ els.butterOut.textContent = each.toString();
161
+ els.flourOut.textContent = each.toString();
162
+
163
+ const info = ROUX_INFO[config.rouxType];
164
+ els.rouxLabel.textContent = info.label;
165
+ els.cookInst.textContent = `${info.description} (${info.time})`;
166
+ els.sauceName.textContent = config.name;
167
+ els.ratioDisp.textContent = `${totalRoux}g/L`;
168
+ els.chefTip.textContent = `"${config.tip}"`;
169
+ els.progressBar.style.width = `${(state.level / 4) * 100}%`;
170
+ }
171
+
172
+ export function initRouxGuide(): void {
173
+ const els = setupElements();
174
+ if (!els) return;
175
+
176
+ const state: State = { volume: 1000, liquid: 'milk', level: 2 };
177
+ const updateCalculations = () => updateDisplay(els, state);
178
+
179
+ els.volumeInput.addEventListener('input', (e) => {
180
+ state.volume = parseInt((e.target as HTMLInputElement).value) || 0;
181
+ updateCalculations();
182
+ });
183
+
184
+ setupLiquidButtons(els, state, updateCalculations);
185
+ setupTextureButtons(els, state, updateCalculations);
186
+ updateCalculations();
187
+ }
@@ -0,0 +1,8 @@
1
+ ---
2
+ import { SEORenderer } from "@jjlmoya/utils-shared";
3
+ import { content } from "./i18n/es";
4
+
5
+ const locale = "es";
6
+ ---
7
+
8
+ <SEORenderer content={{ sections: content.seo, locale }} />
@@ -0,0 +1,369 @@
1
+ :root {
2
+ --sc-primary: hsl(38deg, 92%, 50%);
3
+ --sc-primary-light: hsl(38deg, 92%, 90%);
4
+ --sc-success: hsl(142deg, 72%, 45%);
5
+ --sc-bg-card: hsl(0deg, 0%, 100%);
6
+ --sc-bg-app: hsl(210deg, 20%, 98%);
7
+ --sc-border: hsl(210deg, 20%, 90%);
8
+ --sc-text-main: hsl(210deg, 30%, 20%);
9
+ --sc-text-muted: hsl(210deg, 15%, 50%);
10
+ --sc-text-disabled: hsl(210deg, 15%, 75%);
11
+ --sc-shadow-md: 0 4px 6px -1px rgb(0, 0, 0, 0.1);
12
+ --sc-shadow-lg: 0 10px 15px -3px rgb(0, 0, 0, 0.1);
13
+ --sc-radius: 1rem;
14
+ --sc-transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
15
+ }
16
+
17
+ .theme-dark {
18
+ --sc-bg-card: hsl(220deg, 25%, 12%);
19
+ --sc-bg-app: hsl(220deg, 30%, 7%);
20
+ --sc-border: hsl(220deg, 20%, 20%);
21
+ --sc-text-main: hsl(210deg, 20%, 95%);
22
+ --sc-text-muted: hsl(210deg, 15%, 70%);
23
+ --sc-text-disabled: hsl(210deg, 15%, 50%);
24
+ --sc-primary-light: hsl(38deg, 92%, 12%);
25
+ }
26
+
27
+ .sourdough-calculator {
28
+ width: 100%;
29
+ max-width: 100%;
30
+ padding: 2rem;
31
+ background: var(--sc-bg-card);
32
+ border: 1px solid var(--sc-border);
33
+ border-radius: var(--sc-radius);
34
+ box-shadow: var(--sc-shadow-lg);
35
+ }
36
+
37
+ .sc-header {
38
+ width: 100%;
39
+ height: 0.5rem;
40
+ background: var(--sc-primary);
41
+ border-radius: var(--sc-radius) var(--sc-radius) 0 0;
42
+ margin: -2rem -2rem 2rem;
43
+ }
44
+
45
+ .sc-grid {
46
+ display: grid;
47
+ grid-template-columns: 1fr;
48
+ gap: 3rem;
49
+ }
50
+
51
+ @media (min-width: 1024px) {
52
+ .sc-grid {
53
+ grid-template-columns: 2fr 3fr;
54
+ }
55
+
56
+ .sc-grid > * {
57
+ min-width: 0;
58
+ }
59
+ }
60
+
61
+ .sc-section {
62
+ display: flex;
63
+ flex-direction: column;
64
+ gap: 2.5rem;
65
+ }
66
+
67
+ .sc-control-group {
68
+ display: flex;
69
+ flex-direction: column;
70
+ gap: 1rem;
71
+ }
72
+
73
+ .sc-label {
74
+ font-size: 0.875rem;
75
+ font-weight: 700;
76
+ color: var(--sc-text-muted);
77
+ text-transform: uppercase;
78
+ letter-spacing: 0.05em;
79
+ display: flex;
80
+ align-items: center;
81
+ gap: 0.5rem;
82
+ }
83
+
84
+ .sc-input {
85
+ width: 100%;
86
+ padding: 1rem;
87
+ border: 2px solid var(--sc-border);
88
+ border-radius: 0.75rem;
89
+ background: var(--sc-bg-app);
90
+ color: var(--sc-text-main);
91
+ font-weight: 600;
92
+ font-size: 2rem;
93
+ text-align: center;
94
+ transition: var(--sc-transition);
95
+ }
96
+
97
+ .sc-input:focus {
98
+ outline: none;
99
+ border-color: var(--sc-primary);
100
+ box-shadow: 0 0 0 3px hsl(38deg, 92%, 50%, 0.1);
101
+ }
102
+
103
+ .sc-input::placeholder {
104
+ color: var(--sc-text-disabled);
105
+ }
106
+
107
+ input[type='number']::-webkit-outer-spin-button,
108
+ input[type='number']::-webkit-inner-spin-button {
109
+ -webkit-appearance: none;
110
+ margin: 0;
111
+ }
112
+
113
+ .sc-ratio-buttons {
114
+ display: grid;
115
+ grid-template-columns: repeat(3, 1fr);
116
+ gap: 0.75rem;
117
+ }
118
+
119
+ .ratio-btn {
120
+ display: flex;
121
+ flex-direction: column;
122
+ align-items: center;
123
+ justify-content: center;
124
+ padding: 0.75rem 0.5rem;
125
+ border-radius: 0.75rem;
126
+ border: 2px solid var(--sc-border);
127
+ background: var(--sc-bg-app);
128
+ color: var(--sc-text-muted);
129
+ font-weight: 600;
130
+ cursor: pointer;
131
+ transition: var(--sc-transition);
132
+ }
133
+
134
+ .ratio-btn:hover {
135
+ border-color: var(--sc-primary);
136
+ color: var(--sc-primary);
137
+ }
138
+
139
+ .ratio-btn.ratio-active {
140
+ background: var(--sc-primary-light);
141
+ border-color: var(--sc-primary);
142
+ color: var(--sc-primary);
143
+ box-shadow: var(--sc-shadow-md);
144
+ }
145
+
146
+ .ratio-btn.ratio-inactive {
147
+ background: var(--sc-bg-app);
148
+ border-color: var(--sc-border);
149
+ color: var(--sc-text-muted);
150
+ }
151
+
152
+ .sc-ratio-label {
153
+ font-size: 0.625rem;
154
+ text-transform: uppercase;
155
+ opacity: 0.75;
156
+ margin-bottom: 0.25rem;
157
+ }
158
+
159
+ .sc-ratio-value {
160
+ font-size: 1.125rem;
161
+ font-weight: 700;
162
+ }
163
+
164
+ .sc-custom-inputs {
165
+ display: none;
166
+ gap: 1.5rem;
167
+ padding: 1.5rem;
168
+ background: var(--sc-bg-app);
169
+ border-radius: 0.75rem;
170
+ border: 1px solid var(--sc-border);
171
+ }
172
+
173
+ .sc-custom-inputs.visible {
174
+ display: flex;
175
+ justify-content: space-around;
176
+ align-items: flex-end;
177
+ }
178
+
179
+ .sc-custom-input-group {
180
+ display: flex;
181
+ flex-direction: column;
182
+ align-items: center;
183
+ gap: 0.5rem;
184
+ }
185
+
186
+ .custom-input {
187
+ padding: 0.75rem;
188
+ border: 1px solid var(--sc-border);
189
+ border-radius: 0.5rem;
190
+ background: var(--sc-bg-card);
191
+ color: var(--sc-text-main);
192
+ width: 80px;
193
+ text-align: center;
194
+ font-weight: 600;
195
+ font-size: 1rem;
196
+ transition: var(--sc-transition);
197
+ }
198
+
199
+ .custom-input:focus {
200
+ outline: none;
201
+ border-color: var(--sc-primary);
202
+ }
203
+
204
+ .sc-custom-label {
205
+ font-size: 0.625rem;
206
+ text-transform: uppercase;
207
+ font-weight: 700;
208
+ color: var(--sc-text-muted);
209
+ margin-bottom: 0.25rem;
210
+ display: block;
211
+ text-align: center;
212
+ }
213
+
214
+ .sc-results {
215
+ display: flex;
216
+ flex-direction: column;
217
+ gap: 1rem;
218
+ }
219
+
220
+ .sc-results-header {
221
+ padding: 1rem;
222
+ background: var(--sc-bg-app);
223
+ border: 1px solid var(--sc-border);
224
+ border-radius: 0.75rem;
225
+ display: flex;
226
+ justify-content: space-between;
227
+ align-items: center;
228
+ }
229
+
230
+ .sc-results-title {
231
+ font-size: 0.75rem;
232
+ font-weight: 700;
233
+ color: var(--sc-text-muted);
234
+ text-transform: uppercase;
235
+ letter-spacing: 0.05em;
236
+ }
237
+
238
+ .sc-hydration-badge {
239
+ font-size: 0.75rem;
240
+ font-weight: 600;
241
+ color: var(--sc-primary);
242
+ background: var(--sc-primary-light);
243
+ padding: 0.25rem 0.75rem;
244
+ border-radius: 9999px;
245
+ }
246
+
247
+ .sc-result-rows {
248
+ display: flex;
249
+ flex-direction: column;
250
+ gap: 0;
251
+ border: 1px solid var(--sc-border);
252
+ border-radius: 0.75rem;
253
+ overflow: hidden;
254
+ }
255
+
256
+ .sc-result-row {
257
+ display: flex;
258
+ justify-content: space-between;
259
+ align-items: center;
260
+ padding: 1rem;
261
+ border-bottom: 1px solid var(--sc-border);
262
+ transition: var(--sc-transition);
263
+ }
264
+
265
+ .sc-result-row:last-child {
266
+ border-bottom: none;
267
+ }
268
+
269
+ .sc-result-row:hover {
270
+ background: var(--sc-primary-light);
271
+ }
272
+
273
+ .sc-result-content {
274
+ display: flex;
275
+ align-items: center;
276
+ gap: 1rem;
277
+ flex: 1;
278
+ }
279
+
280
+ .sc-result-icon {
281
+ width: 3rem;
282
+ height: 3rem;
283
+ border-radius: 0.5rem;
284
+ display: flex;
285
+ align-items: center;
286
+ justify-content: center;
287
+ font-size: 1.5rem;
288
+ }
289
+
290
+ .sc-result-icon.starter {
291
+ background: hsl(38deg, 92%, 90%);
292
+ color: var(--sc-primary);
293
+ }
294
+
295
+ .theme-dark .sc-result-icon.starter {
296
+ background: hsl(38deg, 92%, 15%);
297
+ }
298
+
299
+ .sc-result-icon.flour {
300
+ background: hsl(45deg, 93%, 90%);
301
+ color: hsl(45deg, 93%, 50%);
302
+ }
303
+
304
+ .theme-dark .sc-result-icon.flour {
305
+ background: hsl(45deg, 93%, 15%);
306
+ }
307
+
308
+ .sc-result-icon.water {
309
+ background: hsl(196deg, 95%, 90%);
310
+ color: hsl(196deg, 95%, 50%);
311
+ }
312
+
313
+ .theme-dark .sc-result-icon.water {
314
+ background: hsl(196deg, 95%, 15%);
315
+ }
316
+
317
+ .sc-result-name {
318
+ font-weight: 700;
319
+ color: var(--sc-text-main);
320
+ font-size: 1.125rem;
321
+ }
322
+
323
+ .sc-result-desc {
324
+ font-size: 0.875rem;
325
+ color: var(--sc-text-muted);
326
+ }
327
+
328
+ .sc-result-value {
329
+ display: flex;
330
+ flex-direction: column;
331
+ align-items: flex-end;
332
+ gap: 0.25rem;
333
+ }
334
+
335
+ .sc-result-amount {
336
+ font-size: 1.875rem;
337
+ font-weight: 800;
338
+ color: var(--sc-text-main);
339
+ line-height: 1;
340
+ }
341
+
342
+ .sc-result-unit {
343
+ font-size: 0.875rem;
344
+ color: var(--sc-text-muted);
345
+ font-weight: 600;
346
+ }
347
+
348
+ .sc-total {
349
+ display: flex;
350
+ justify-content: flex-end;
351
+ align-items: center;
352
+ gap: 1rem;
353
+ padding: 1rem;
354
+ margin-top: 1rem;
355
+ opacity: 0.75;
356
+ }
357
+
358
+ .sc-total-label {
359
+ font-size: 0.875rem;
360
+ font-weight: 600;
361
+ color: var(--sc-text-muted);
362
+ text-transform: uppercase;
363
+ }
364
+
365
+ .sc-total-value {
366
+ font-size: 1.25rem;
367
+ font-weight: 700;
368
+ color: var(--sc-text-main);
369
+ }
@@ -0,0 +1,6 @@
1
+ ---
2
+ import { Bibliography } from '@jjlmoya/utils-shared';
3
+ import { content } from './i18n/es';
4
+ ---
5
+
6
+ <Bibliography links={content.bibliography} />