@jjlmoya/utils-cooking 1.37.0 → 1.39.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 (59) hide show
  1. package/package.json +1 -1
  2. package/src/category/index.ts +4 -0
  3. package/src/entries.ts +5 -1
  4. package/src/index.ts +2 -0
  5. package/src/tests/i18n-titles.test.ts +1 -1
  6. package/src/tests/leavener-acid-neutralizer.test.ts +42 -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/leavener-acid-neutralizer/bibliography.astro +6 -0
  10. package/src/tool/leavener-acid-neutralizer/bibliography.ts +10 -0
  11. package/src/tool/leavener-acid-neutralizer/component.astro +335 -0
  12. package/src/tool/leavener-acid-neutralizer/entry.ts +26 -0
  13. package/src/tool/leavener-acid-neutralizer/i18n/de.ts +279 -0
  14. package/src/tool/leavener-acid-neutralizer/i18n/en.ts +279 -0
  15. package/src/tool/leavener-acid-neutralizer/i18n/es.ts +275 -0
  16. package/src/tool/leavener-acid-neutralizer/i18n/fr.ts +279 -0
  17. package/src/tool/leavener-acid-neutralizer/i18n/id.ts +279 -0
  18. package/src/tool/leavener-acid-neutralizer/i18n/it.ts +275 -0
  19. package/src/tool/leavener-acid-neutralizer/i18n/ja.ts +279 -0
  20. package/src/tool/leavener-acid-neutralizer/i18n/ko.ts +279 -0
  21. package/src/tool/leavener-acid-neutralizer/i18n/nl.ts +279 -0
  22. package/src/tool/leavener-acid-neutralizer/i18n/pl.ts +279 -0
  23. package/src/tool/leavener-acid-neutralizer/i18n/pt.ts +279 -0
  24. package/src/tool/leavener-acid-neutralizer/i18n/ru.ts +279 -0
  25. package/src/tool/leavener-acid-neutralizer/i18n/sv.ts +279 -0
  26. package/src/tool/leavener-acid-neutralizer/i18n/tr.ts +279 -0
  27. package/src/tool/leavener-acid-neutralizer/i18n/zh.ts +279 -0
  28. package/src/tool/leavener-acid-neutralizer/index.ts +10 -0
  29. package/src/tool/leavener-acid-neutralizer/leavener-acid-neutralizer.css +424 -0
  30. package/src/tool/leavener-acid-neutralizer/logic.ts +57 -0
  31. package/src/tool/leavener-acid-neutralizer/seo.astro +15 -0
  32. package/src/tool/pectin-jam-setting-calculator/bibliography.astro +6 -0
  33. package/src/tool/pectin-jam-setting-calculator/bibliography.ts +10 -0
  34. package/src/tool/pectin-jam-setting-calculator/component.astro +170 -0
  35. package/src/tool/pectin-jam-setting-calculator/components/CalculatorInputs.astro +44 -0
  36. package/src/tool/pectin-jam-setting-calculator/components/DropTestVisualizer.astro +40 -0
  37. package/src/tool/pectin-jam-setting-calculator/components/FruitSelector.astro +38 -0
  38. package/src/tool/pectin-jam-setting-calculator/components/RecipeResults.astro +72 -0
  39. package/src/tool/pectin-jam-setting-calculator/entry.ts +26 -0
  40. package/src/tool/pectin-jam-setting-calculator/i18n/de.ts +248 -0
  41. package/src/tool/pectin-jam-setting-calculator/i18n/en.ts +248 -0
  42. package/src/tool/pectin-jam-setting-calculator/i18n/es.ts +248 -0
  43. package/src/tool/pectin-jam-setting-calculator/i18n/fr.ts +248 -0
  44. package/src/tool/pectin-jam-setting-calculator/i18n/id.ts +248 -0
  45. package/src/tool/pectin-jam-setting-calculator/i18n/it.ts +248 -0
  46. package/src/tool/pectin-jam-setting-calculator/i18n/ja.ts +248 -0
  47. package/src/tool/pectin-jam-setting-calculator/i18n/ko.ts +248 -0
  48. package/src/tool/pectin-jam-setting-calculator/i18n/nl.ts +248 -0
  49. package/src/tool/pectin-jam-setting-calculator/i18n/pl.ts +248 -0
  50. package/src/tool/pectin-jam-setting-calculator/i18n/pt.ts +248 -0
  51. package/src/tool/pectin-jam-setting-calculator/i18n/ru.ts +248 -0
  52. package/src/tool/pectin-jam-setting-calculator/i18n/sv.ts +248 -0
  53. package/src/tool/pectin-jam-setting-calculator/i18n/tr.ts +248 -0
  54. package/src/tool/pectin-jam-setting-calculator/i18n/zh.ts +248 -0
  55. package/src/tool/pectin-jam-setting-calculator/index.ts +11 -0
  56. package/src/tool/pectin-jam-setting-calculator/logic.ts +96 -0
  57. package/src/tool/pectin-jam-setting-calculator/pectin-jam-setting-calculator.css +730 -0
  58. package/src/tool/pectin-jam-setting-calculator/seo.astro +15 -0
  59. package/src/tools.ts +4 -0
@@ -0,0 +1,279 @@
1
+ import type { ToolLocaleContent } from '../../../types';
2
+ import { bibliography } from '../bibliography';
3
+
4
+ const title = "小苏打与泡打粉计算器:膨松剂和酸的中和平衡";
5
+ const description = "计算配方中精确的小苏打与泡打粉比例。中和酪乳、酸奶等酸性食材,避免金属余味,每次都能完美膨胀。";
6
+ const faq = [
7
+ {
8
+ question: "为什么用小苏打代替泡打粉需要加酸?",
9
+ answer: "小苏打是纯碱。它需要酸来激活并释放二氧化碳。酸不足时,小苏打无法完全反应,会在烘焙品中留下苦涩的金属味。"
10
+ },
11
+ {
12
+ question: "小苏打和泡打粉有什么区别?",
13
+ answer: "小苏打是100%碳酸氢钠,一种碱。泡打粉是完整的膨松剂,含有小苏打加上干燥酸化剂(如塔塔粉)和淀粉。泡打粉可自行中和。"
14
+ },
15
+ {
16
+ question: "1茶匙小苏打相当于多少泡打粉?",
17
+ answer: "小苏打的强度大约是泡打粉的3-4倍。替代1茶匙小苏打大约需要3-4茶匙泡打粉。但这种替换也会增加酸盐,可能改变风味,建议使用本计算器进行精确换算。"
18
+ },
19
+ {
20
+ question: "为什么我的蛋糕有肥皂味或金属味?",
21
+ answer: "肥皂味或金属余味是未反应小苏打的典型标志。面糊中没有足够的酸来完全中和碳酸氢钠时,碱性残留物会在烘焙后留存,产生令人不快的化学味。请使用本计算器确保完全中和。"
22
+ },
23
+ {
24
+ question: "碱化可可粉可以作为酸来使用吗?",
25
+ answer: "不能。碱化可可粉(Dutch-process)经过碱化处理,天然酸度已降低(pH约7-8)。只有天然可可粉(pH约5-6)呈酸性,才能中和小苏打。"
26
+ },
27
+ {
28
+ question: "小苏打如何影响烘焙品的上色?",
29
+ answer: "小苏打会提高面糊的pH值,使其更偏碱性。较高的pH值会加速美拉德褐变反应,使饼干和蛋糕的表皮颜色更深、风味更浓郁。"
30
+ }
31
+ ];
32
+
33
+ const howTo = [
34
+ {
35
+ name: "输入面粉重量",
36
+ text: "以克或盎司为单位输入配方中面粉的总重量,计算所需的整体膨松力。"
37
+ },
38
+ {
39
+ name: "添加酸性食材",
40
+ text: "选择配方中的酸性食材(如酪乳、酸奶或柠檬汁)并输入它们的重量。"
41
+ },
42
+ {
43
+ name: "检查pH平衡",
44
+ text: "观察虚拟pH天平。天平平衡表示中和状态最佳,没有金属余味。"
45
+ },
46
+ {
47
+ name: "量取膨松剂",
48
+ text: "读取中和小苏打的推荐用量,以及达到目标膨胀度所需的额外泡打粉助推量。"
49
+ }
50
+ ];
51
+
52
+ const faqSchema = {
53
+ '@context': 'https://schema.org' as const,
54
+ '@type': 'FAQPage' as const,
55
+ mainEntity: faq.map((item) => ({
56
+ '@type': 'Question' as const,
57
+ name: item.question,
58
+ acceptedAnswer: { '@type': 'Answer' as const, text: item.answer },
59
+ })),
60
+ };
61
+
62
+ const howToSchema = {
63
+ '@context': 'https://schema.org' as const,
64
+ '@type': 'HowTo' as const,
65
+ name: title,
66
+ description,
67
+ step: howTo.map((step) => ({
68
+ '@type': 'HowToStep' as const,
69
+ name: step.name,
70
+ text: step.text,
71
+ })),
72
+ };
73
+
74
+ const appSchema = {
75
+ '@context': 'https://schema.org' as const,
76
+ '@type': 'SoftwareApplication' as const,
77
+ name: title,
78
+ description,
79
+ applicationCategory: 'UtilitiesApplication',
80
+ operatingSystem: 'Web',
81
+ offers: { '@type': 'Offer' as const, price: '0', priceCurrency: 'CNY' },
82
+ };
83
+
84
+ export const content: ToolLocaleContent = {
85
+ slug: 'leavener-acid-neutralizer',
86
+ title: '膨松剂与酸的中和计算',
87
+ description: '计算配方中精确的小苏打与泡打粉比例。中和酪乳、酸奶等酸性食材,避免金属余味,每次都能完美膨胀。',
88
+ faqTitle: '常见问题',
89
+ ui: {
90
+ title: "膨松剂酸中和计算器",
91
+ subtitle: "用化学计量学优化烘焙的膨胀与风味",
92
+ flourLabel: "面粉重量",
93
+ addAcidLabel: "添加酸性食材",
94
+ weightLabel: "重量",
95
+ removeButton: "移除",
96
+ bakingSodaNeeded: "中和用小苏打",
97
+ requiredBakingPowder: "目标膨松力",
98
+ providedBakingPowderEquivalent: "小苏打贡献的膨松力",
99
+ boosterBakingPowder: "额外泡打粉助推",
100
+ resultsTitle: "计算出的膨松剂",
101
+ statusBalanced: "平衡良好",
102
+ statusAcidic: "酸过量",
103
+ statusAlkaline: "碱过量",
104
+ gramsUnit: "g",
105
+ ouncesUnit: "oz",
106
+ teaspoonsUnit: "茶匙",
107
+ scaleBalanceTitle: "虚拟pH天平",
108
+ acidListTitle: "酸性食材",
109
+ unitLabel: "计量单位",
110
+ metricUnit: "公制 (g)",
111
+ imperialUnit: "英制 (oz)",
112
+ acid_buttermilk: "酪乳",
113
+ acid_yogurt: "酸奶",
114
+ acid_sour_cream: "酸奶油",
115
+ acid_honey: "蜂蜜",
116
+ acid_molasses: "糖蜜",
117
+ acid_cocoa: "天然可可粉",
118
+ acid_lemon_juice: "柠檬汁",
119
+ acid_vinegar: "醋",
120
+ stoichiometryBadge: "pH化学计量",
121
+ simulateSodaLabel: "模拟添加小苏打",
122
+ autoBalanceBtn: "自动平衡",
123
+ sodaAddedLabel: "已添加小苏打"
124
+ },
125
+ faq,
126
+ howTo,
127
+ seo: [
128
+ {
129
+ type: 'summary',
130
+ title: '完美膨胀的关键要点',
131
+ items: [
132
+ '小苏打需要酸才能激活,否则烘焙品会有肥皂味和金属味',
133
+ '泡打粉可自行中和,作为助推器提供额外膨松力',
134
+ '标准目标为面粉重量的4%(泡打粉当量)以获得良好膨胀',
135
+ '使用下方的中和表,为你的酸性食材匹配正确的小苏打用量'
136
+ ]
137
+ },
138
+ {
139
+ type: 'title',
140
+ text: '烘焙中化学膨松剂的科学原理',
141
+ level: 2
142
+ },
143
+ {
144
+ type: 'paragraph',
145
+ html: '化学膨松依靠<strong>酸碱中和反应</strong>产生二氧化碳(CO2)气体,气体被困在面糊基质中,在烘焙时使其膨胀。小苏打(碳酸氢钠)与酸性食材的正确比例至关重要。<strong>小苏打过多</strong>会导致未反应的碱性残留,产生肥皂味、金属味和黄色变色。<strong>酸过多</strong>则会导致烘焙品密实、扁平,体积不足。'
146
+ },
147
+ {
148
+ type: 'stats',
149
+ columns: 4,
150
+ items: [
151
+ {
152
+ value: '3-4倍',
153
+ label: '小苏打比泡打粉更强',
154
+ icon: 'mdi:flash'
155
+ },
156
+ {
157
+ value: '4%',
158
+ label: '目标膨松力(面粉重量比)',
159
+ icon: 'mdi:target'
160
+ },
161
+ {
162
+ value: '1/4茶匙',
163
+ label: '每120g酪乳/酸奶所需小苏打',
164
+ icon: 'mdi:spoon-sugar'
165
+ },
166
+ {
167
+ value: '0.0125',
168
+ label: '中和比率(乳酸性食材)',
169
+ icon: 'mdi:scale-balance'
170
+ }
171
+ ]
172
+ },
173
+ {
174
+ type: 'title',
175
+ text: '小苏打 vs 泡打粉:完整对比',
176
+ level: 3
177
+ },
178
+ {
179
+ type: 'comparative',
180
+ columns: 2,
181
+ items: [
182
+ {
183
+ title: '小苏打',
184
+ icon: 'mdi:flask-outline',
185
+ description: '纯碳酸氢钠(NaHCO3)。一种强碱性碱,需要外部酸来激活并产生CO2。',
186
+ points: [
187
+ '比泡打粉强3-4倍',
188
+ '需要酸(酪乳、酸奶、柠檬汁)才能反应',
189
+ '过量会导致肥皂味、金属味和黄色内瓤',
190
+ '提高pH值,增强饼干的梅拉德褐变',
191
+ '单效型:混合后立即释放CO2'
192
+ ]
193
+ },
194
+ {
195
+ title: '泡打粉',
196
+ icon: 'mdi:flask-round-bottom-outline',
197
+ description: '完整的膨松系统,包含小苏打+干燥酸盐+淀粉。自行中和,可靠稳定。',
198
+ highlight: true,
199
+ points: [
200
+ '自带酸性成分(磷酸一钙、SAP等)',
201
+ '双效型:混合时和加热时分两阶段释放CO2',
202
+ '无金属余味,pH已平衡',
203
+ '每克强度较弱,需要3-4倍才能匹敌小苏打的功效',
204
+ '当小苏打单独无法拉起全部面粉时,最适合作为助推器'
205
+ ]
206
+ }
207
+ ]
208
+ },
209
+ {
210
+ type: 'table',
211
+ headers: ['酸性食材', '标准用量', '中和用小苏打', '中和比率'],
212
+ rows: [
213
+ ['酪乳 / 酸奶 / 酸奶油', '120g (1/2杯)', '1.5g (1/4茶匙)', '0.0125'],
214
+ ['柠檬汁 / 醋', '15g (1汤匙)', '1.5g (1/4茶匙)', '0.1000'],
215
+ ['天然可可粉', '80g (1杯)', '3.0g (1/2茶匙)', '0.0375'],
216
+ ['蜂蜜', '340g (1杯)', '3.0g (1/2茶匙)', '0.0088'],
217
+ ['糖蜜', '328g (1杯)', '3.0g (1/2茶匙)', '0.0091']
218
+ ]
219
+ },
220
+ {
221
+ type: 'diagnostic',
222
+ variant: 'warning',
223
+ title: '故障排查:你的膨松是否失衡?',
224
+ badge: '快速检查',
225
+ html: '<strong>如果蛋糕塌陷:</strong>酸太多或整体膨松剂不足,CO2在结构定型前就逃逸了。<br/><br/><strong>如果蛋糕密实扁平:</strong>酸量超过了小苏打的中和能力,或者面粉重量对应的总膨松力不足。<br/><br/><strong>如果有肥皂味或金属味:</strong>未反应的小苏打过量,增加酸性食材或减少小苏打用量。<br/><br/><strong>如果有黄色斑点:</strong>未溶解、未反应的小苏打结块的典型症状。下次请将小苏打与面粉一起过筛。'
226
+ },
227
+ {
228
+ type: 'title',
229
+ text: '如何平衡膨松剂并避免金属味',
230
+ level: 3
231
+ },
232
+ {
233
+ type: 'paragraph',
234
+ html: '要达到最佳风味和膨胀效果,请遵循以下步骤:<strong>首先</strong>,参考上方表格确定完全中和面糊中酸性成分所需的小苏打量。<strong>然后</strong>,将该小苏打量转换为泡打粉当量(乘以4),并与面粉所需的总膨松力进行比较;标准为面粉重量的<strong>4%</strong>(泡打粉当量)。<strong>如有不足</strong>,以中性泡打粉作为助推器补充剩余膨松力。本计算器会自动完成所有这些步骤。'
235
+ },
236
+ {
237
+ type: 'list',
238
+ icon: 'mdi:alert-circle-outline',
239
+ items: [
240
+ '切勿将小苏打与泡打粉 1:1 替换,小苏打强度是泡打粉的 3-4 倍且需要酸',
241
+ '小苏打务必与干性材料一起过筛,防止产生苦味结块',
242
+ '碱化可可粉(Dutch-process)不具有酸性,如需可可提供酸请使用天然可可粉',
243
+ '蜂蜜和糖蜜属弱酸性,每克所需的小苏打远少于柠檬汁',
244
+ '混合后请快速操作:化学膨松剂接触液体后立即开始反应'
245
+ ]
246
+ },
247
+ {
248
+ type: 'glossary',
249
+ items: [
250
+ {
251
+ term: '中和比率',
252
+ definition: '完全中和一定重量酸性食材所需的小苏打比例。比率越低,表示该食材每克的酸性越弱。'
253
+ },
254
+ {
255
+ term: '膨松力',
256
+ definition: '膨松剂能够产生的CO2气体总量。以泡打粉当量衡量,面粉重量的4%是蛋糕和松饼的标准目标。'
257
+ },
258
+ {
259
+ term: '双效泡打粉',
260
+ definition: '分两阶段释放CO2的泡打粉:首先在室温下与液体混合时,然后在烤箱加热时。能够提供更可靠的膨胀效果。'
261
+ },
262
+ {
263
+ term: '梅拉德反应',
264
+ definition: '氨基酸与还原糖之间发生的化学反应,使食物褐变并产生复杂风味。小苏打过量导致的高pH值会促进此反应。对饼干而言是理想效果,但对精致蛋糕则希望避免。'
265
+ },
266
+ {
267
+ term: 'pH平衡',
268
+ definition: '面糊酸碱度的衡量。中性pH(约7)表示所有小苏打已与所有酸完全反应。微碱性有利于上色,酸性有利于松软口感。'
269
+ }
270
+ ]
271
+ },
272
+ {
273
+ type: 'tip',
274
+ html: '<strong>上色与pH值:</strong>完全中和对风味至关重要,但在巧克力蛋糕和饼干中,略微过量的小苏打使面糊呈微碱性可能是理想的选择。较高的pH值会促进梅拉德褐变,产生更深的颜色、更脆的边缘和更浓郁的焦糖风味。对于精致的香草蛋糕,请力求精确中和,以保持纯净清爽的口感。'
275
+ }
276
+ ],
277
+ bibliography,
278
+ schemas: [faqSchema, howToSchema, appSchema]
279
+ };
@@ -0,0 +1,10 @@
1
+ import { leavenerAcidNeutralizer } from './entry';
2
+ import type { ToolDefinition } from '../../types';
3
+
4
+ export * from './entry';
5
+ export const LEAVENER_ACID_NEUTRALIZER_TOOL: ToolDefinition = {
6
+ entry: leavenerAcidNeutralizer,
7
+ Component: () => import('./component.astro'),
8
+ SEOComponent: () => import('./seo.astro'),
9
+ BibliographyComponent: () => import('./bibliography.astro'),
10
+ };
@@ -0,0 +1,424 @@
1
+ .leavener-container {
2
+ --lan-bg-card: rgba(255, 255, 255, 0.75);
3
+ --lan-bg-solid: rgba(255, 255, 255, 0.95);
4
+ --lan-border: rgba(0, 0, 0, 0.1);
5
+ --lan-border-active: #10b981;
6
+ --lan-text: #111827;
7
+ --lan-text-muted: #4b5563;
8
+ --lan-primary: #10b981;
9
+ --lan-acid: #ec4899;
10
+ --lan-alkaline: #3b82f6;
11
+ --lan-shadow: 0 15px 45px rgba(0, 0, 0, 0.05);
12
+
13
+ max-width: 1000px;
14
+ margin: 1rem auto;
15
+ padding: 0.5rem;
16
+ color: var(--lan-text);
17
+ }
18
+
19
+ .theme-dark .leavener-container {
20
+ --lan-bg-card: rgba(18, 18, 20, 0.6);
21
+ --lan-bg-solid: rgba(24, 24, 28, 0.9);
22
+ --lan-border: rgba(255, 255, 255, 0.12);
23
+ --lan-text: #f9fafb;
24
+ --lan-text-muted: #9ca3af;
25
+ --lan-primary: #34d399;
26
+ --lan-shadow: 0 15px 45px rgba(0, 0, 0, 0.45);
27
+ }
28
+
29
+ .leavener-card {
30
+ background: var(--lan-bg-card);
31
+ backdrop-filter: blur(24px);
32
+ border: 1px solid var(--lan-border);
33
+ border-radius: 1.75rem;
34
+ padding: 1.25rem;
35
+ box-shadow: var(--lan-shadow);
36
+ display: flex;
37
+ flex-direction: column;
38
+ gap: 1.5rem;
39
+ }
40
+
41
+ .recipe-setup-card {
42
+ background: var(--lan-bg-solid);
43
+ border: 1px solid var(--lan-border);
44
+ border-radius: 1.5rem;
45
+ padding: 1.75rem;
46
+ display: flex;
47
+ flex-direction: column;
48
+ gap: 1.5rem;
49
+ }
50
+
51
+ .top-row {
52
+ display: flex;
53
+ justify-content: space-between;
54
+ align-items: center;
55
+ flex-wrap: wrap;
56
+ gap: 0.75rem;
57
+ }
58
+
59
+ .luxury-badge {
60
+ font-size: 0.875rem;
61
+ font-weight: 950;
62
+ text-transform: uppercase;
63
+ letter-spacing: 0.1em;
64
+ background: rgba(16, 185, 129, 0.12);
65
+ color: var(--lan-primary);
66
+ padding: 0.5rem 1.25rem;
67
+ border-radius: 9999px;
68
+ border: 1px solid rgba(16, 185, 129, 0.2);
69
+ }
70
+
71
+ .unit-selector {
72
+ display: flex;
73
+ background: rgba(0, 0, 0, 0.05);
74
+ border-radius: 0.875rem;
75
+ padding: 0.25rem;
76
+ border: 1px solid var(--lan-border);
77
+ }
78
+
79
+ .theme-dark .unit-selector {
80
+ background: rgba(255, 255, 255, 0.05);
81
+ }
82
+
83
+ .unit-btn {
84
+ border: none;
85
+ background: none;
86
+ padding: 0.5rem 1.25rem;
87
+ font-size: 0.95rem;
88
+ font-weight: 900;
89
+ border-radius: 0.625rem;
90
+ color: var(--lan-text-muted);
91
+ cursor: pointer;
92
+ transition: all 0.2s;
93
+ }
94
+
95
+ .unit-btn.active {
96
+ background: var(--lan-bg-solid);
97
+ color: var(--lan-text);
98
+ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
99
+ }
100
+
101
+ .flour-slider-group {
102
+ display: flex;
103
+ flex-direction: column;
104
+ gap: 1rem;
105
+ }
106
+
107
+ .flour-header {
108
+ display: flex;
109
+ justify-content: space-between;
110
+ align-items: baseline;
111
+ }
112
+
113
+ .flour-title-label {
114
+ font-size: 1.1rem;
115
+ font-weight: 900;
116
+ text-transform: uppercase;
117
+ letter-spacing: 0.05em;
118
+ color: var(--lan-text-muted);
119
+ }
120
+
121
+ .flour-val-num {
122
+ font-size: 2.75rem;
123
+ font-weight: 950;
124
+ letter-spacing: -0.03em;
125
+ }
126
+
127
+ .premium-range-slider {
128
+ width: 100%;
129
+ height: 0.75rem;
130
+ border-radius: 9999px;
131
+ background: rgba(0, 0, 0, 0.08);
132
+ outline: none;
133
+ cursor: pointer;
134
+ appearance: none;
135
+ }
136
+
137
+ .theme-dark .premium-range-slider {
138
+ background: rgba(255, 255, 255, 0.08);
139
+ }
140
+
141
+ .premium-range-slider::-webkit-slider-thumb {
142
+ appearance: none;
143
+ width: 32px;
144
+ height: 32px;
145
+ background: var(--lan-text);
146
+ border-radius: 50%;
147
+ border: 4px solid var(--lan-bg-solid);
148
+ cursor: pointer;
149
+ box-shadow: 0 6px 16px rgba(0, 0, 0, 0.2);
150
+ }
151
+
152
+ .dashboard-grid {
153
+ display: grid;
154
+ grid-template-columns: 1fr;
155
+ gap: 1.5rem;
156
+ }
157
+
158
+ @media (min-width: 768px) {
159
+ .dashboard-grid {
160
+ grid-template-columns: 1fr 1fr;
161
+ }
162
+ }
163
+
164
+ .control-panel-card, .analysis-panel-card {
165
+ background: var(--lan-bg-solid);
166
+ border: 1px solid var(--lan-border);
167
+ border-radius: 1.75rem;
168
+ padding: 1.75rem;
169
+ display: flex;
170
+ flex-direction: column;
171
+ gap: 1.5rem;
172
+ }
173
+
174
+ .panel-subtitle {
175
+ font-size: 1.1rem;
176
+ font-weight: 900;
177
+ text-transform: uppercase;
178
+ letter-spacing: 0.08em;
179
+ color: var(--lan-text-muted);
180
+ margin: 0;
181
+ }
182
+
183
+ .ingredients-pills {
184
+ display: flex;
185
+ flex-wrap: wrap;
186
+ gap: 0.625rem;
187
+ }
188
+
189
+ .pill-btn {
190
+ border: 2px solid var(--lan-border);
191
+ background: none;
192
+ padding: 0.625rem 1.25rem;
193
+ border-radius: 9999px;
194
+ font-size: 1rem;
195
+ font-weight: 800;
196
+ color: var(--lan-text);
197
+ cursor: pointer;
198
+ transition: all 0.2s;
199
+ }
200
+
201
+ .pill-btn.active {
202
+ background: var(--lan-text);
203
+ color: var(--lan-bg-solid);
204
+ border-color: var(--lan-text);
205
+ box-shadow: 0 4px 12px rgba(0,0,0,0.1);
206
+ }
207
+
208
+ .active-sliders-list {
209
+ display: flex;
210
+ flex-direction: column;
211
+ gap: 1.25rem;
212
+ margin-top: 0.5rem;
213
+ }
214
+
215
+ .slider-wrapper-card {
216
+ background: rgba(0, 0, 0, 0.03);
217
+ border: 1px solid var(--lan-border);
218
+ border-radius: 1.25rem;
219
+ padding: 1.25rem;
220
+ display: flex;
221
+ flex-direction: column;
222
+ gap: 1rem;
223
+ }
224
+
225
+ .theme-dark .slider-wrapper-card {
226
+ background: rgba(255, 255, 255, 0.03);
227
+ }
228
+
229
+ .slider-header-row {
230
+ display: flex;
231
+ justify-content: space-between;
232
+ align-items: baseline;
233
+ }
234
+
235
+ .slider-label-name {
236
+ font-size: 1.25rem;
237
+ font-weight: 900;
238
+ }
239
+
240
+ .slider-value-num {
241
+ font-size: 1.75rem;
242
+ font-weight: 950;
243
+ letter-spacing: -0.02em;
244
+ }
245
+
246
+ .linear-ph-scale-card {
247
+ background: rgba(0, 0, 0, 0.03);
248
+ border: 1px solid var(--lan-border);
249
+ border-radius: 1.25rem;
250
+ padding: 1.75rem;
251
+ display: flex;
252
+ flex-direction: column;
253
+ gap: 1.25rem;
254
+ }
255
+
256
+ .theme-dark .linear-ph-scale-card {
257
+ background: rgba(255, 255, 255, 0.03);
258
+ }
259
+
260
+ .ph-track {
261
+ height: 1.25rem;
262
+ border-radius: 9999px;
263
+ display: flex;
264
+ position: relative;
265
+ overflow: visible;
266
+ }
267
+
268
+ .ph-zone {
269
+ height: 100%;
270
+ }
271
+
272
+ .acid-zone {
273
+ flex: 2;
274
+ background: linear-gradient(90deg, var(--lan-acid) 0%, #fda4af 100%);
275
+ border-top-left-radius: 9999px;
276
+ border-bottom-left-radius: 9999px;
277
+ }
278
+
279
+ .neutral-zone {
280
+ flex: 1;
281
+ background: #10b981;
282
+ }
283
+
284
+ .alkaline-zone {
285
+ flex: 2;
286
+ background: linear-gradient(90deg, #93c5fd 0%, var(--lan-alkaline) 100%);
287
+ border-top-right-radius: 9999px;
288
+ border-bottom-right-radius: 9999px;
289
+ }
290
+
291
+ .ph-pointer-orb {
292
+ position: absolute;
293
+ top: 50%;
294
+ transform: translate(-50%, -50%);
295
+ width: 2.25rem;
296
+ height: 2.25rem;
297
+ border-radius: 50%;
298
+ border: 4px solid var(--lan-cream);
299
+ background-color: var(--lan-primary);
300
+ box-shadow: 0 6px 15px rgba(0, 0, 0, 0.25);
301
+ transition: left 0.4s cubic-bezier(0.175, 0.885, 0.32, 1.275), background-color 0.2s;
302
+ z-index: 10;
303
+ }
304
+
305
+ .ph-labels {
306
+ display: flex;
307
+ justify-content: space-between;
308
+ font-size: 0.95rem;
309
+ font-weight: 900;
310
+ text-transform: uppercase;
311
+ letter-spacing: 0.05em;
312
+ color: var(--lan-text-muted);
313
+ }
314
+
315
+ .neutral-label {
316
+ color: var(--lan-primary);
317
+ }
318
+
319
+ .simulation-adjuster {
320
+ border: 2px solid var(--lan-border);
321
+ border-radius: 1.5rem;
322
+ padding: 1.25rem 1.5rem;
323
+ display: flex;
324
+ flex-direction: column;
325
+ gap: 0.75rem;
326
+ }
327
+
328
+ .adjuster-controls {
329
+ display: flex;
330
+ align-items: center;
331
+ gap: 0.75rem;
332
+ }
333
+
334
+ .btn-auto-balance {
335
+ background: var(--lan-primary);
336
+ color: var(--lan-cream);
337
+ border: none;
338
+ padding: 0.25rem 0.75rem;
339
+ border-radius: 0.5rem;
340
+ font-size: 0.8125rem;
341
+ font-weight: 800;
342
+ cursor: pointer;
343
+ transition: all 0.2s;
344
+ }
345
+
346
+ .btn-auto-balance:hover {
347
+ filter: brightness(1.1);
348
+ }
349
+
350
+ .adjuster-label {
351
+ font-size: 1.1rem;
352
+ font-weight: 900;
353
+ text-transform: uppercase;
354
+ color: var(--lan-text-muted);
355
+ }
356
+
357
+ .adjuster-val {
358
+ font-size: 2.25rem;
359
+ font-weight: 950;
360
+ letter-spacing: -0.02em;
361
+ }
362
+
363
+ .perfect-recipe-card {
364
+ display: flex;
365
+ flex-direction: column;
366
+ gap: 1.25rem;
367
+ }
368
+
369
+ .recipe-title {
370
+ font-size: 1.1rem;
371
+ font-weight: 950;
372
+ text-transform: uppercase;
373
+ letter-spacing: 0.08em;
374
+ margin: 0;
375
+ color: var(--lan-text-muted);
376
+ }
377
+
378
+ .recipe-stat-row {
379
+ display: flex;
380
+ justify-content: space-between;
381
+ align-items: center;
382
+ border-bottom: 2px dashed var(--lan-border);
383
+ padding-bottom: 1rem;
384
+ }
385
+
386
+ .recipe-stat-row:last-child {
387
+ border-bottom: none;
388
+ padding-bottom: 0;
389
+ }
390
+
391
+ .recipe-stat-info {
392
+ display: flex;
393
+ flex-direction: column;
394
+ gap: 0.25rem;
395
+ }
396
+
397
+ .stat-main-label {
398
+ font-size: 1.25rem;
399
+ font-weight: 900;
400
+ }
401
+
402
+ .stat-sub-label {
403
+ font-size: 0.95rem;
404
+ color: var(--lan-text-muted);
405
+ }
406
+
407
+ .recipe-stat-numbers {
408
+ display: flex;
409
+ flex-direction: column;
410
+ align-items: flex-end;
411
+ }
412
+
413
+ .num-large {
414
+ font-size: 2.5rem;
415
+ font-weight: 950;
416
+ letter-spacing: -0.03em;
417
+ }
418
+
419
+ .num-small {
420
+ font-size: 0.95rem;
421
+ font-weight: 900;
422
+ color: var(--lan-text-muted);
423
+ text-transform: uppercase;
424
+ }