@jjlmoya/utils-alcohol 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 (62) hide show
  1. package/package.json +60 -0
  2. package/src/category/i18n/en.ts +19 -0
  3. package/src/category/i18n/es.ts +28 -0
  4. package/src/category/i18n/fr.ts +19 -0
  5. package/src/category/index.ts +12 -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 +19 -0
  12. package/src/layouts/PreviewLayout.astro +117 -0
  13. package/src/pages/[locale]/[slug].astro +155 -0
  14. package/src/pages/[locale].astro +271 -0
  15. package/src/pages/index.astro +4 -0
  16. package/src/tests/content_mandatory.test.ts +32 -0
  17. package/src/tests/faq_count.test.ts +17 -0
  18. package/src/tests/mocks/astro_mock.js +2 -0
  19. package/src/tests/seo_length.test.ts +39 -0
  20. package/src/tests/tool_validation.test.ts +17 -0
  21. package/src/tool/alcoholClearance/component.astro +219 -0
  22. package/src/tool/alcoholClearance/component.css +369 -0
  23. package/src/tool/alcoholClearance/i18n/en.ts +172 -0
  24. package/src/tool/alcoholClearance/i18n/es.ts +181 -0
  25. package/src/tool/alcoholClearance/i18n/fr.ts +163 -0
  26. package/src/tool/alcoholClearance/index.ts +50 -0
  27. package/src/tool/alcoholClearance/logic.ts +59 -0
  28. package/src/tool/beerCooler/component.astro +236 -0
  29. package/src/tool/beerCooler/component.css +381 -0
  30. package/src/tool/beerCooler/i18n/en.ts +168 -0
  31. package/src/tool/beerCooler/i18n/es.ts +181 -0
  32. package/src/tool/beerCooler/i18n/fr.ts +168 -0
  33. package/src/tool/beerCooler/index.ts +49 -0
  34. package/src/tool/beerCooler/logic.ts +34 -0
  35. package/src/tool/carbonationCalculator/component.astro +225 -0
  36. package/src/tool/carbonationCalculator/component.css +483 -0
  37. package/src/tool/carbonationCalculator/i18n/en.ts +175 -0
  38. package/src/tool/carbonationCalculator/i18n/es.ts +179 -0
  39. package/src/tool/carbonationCalculator/i18n/fr.ts +175 -0
  40. package/src/tool/carbonationCalculator/index.ts +48 -0
  41. package/src/tool/carbonationCalculator/logic.ts +40 -0
  42. package/src/tool/cocktailBalancer/bibliography.astro +14 -0
  43. package/src/tool/cocktailBalancer/component.astro +396 -0
  44. package/src/tool/cocktailBalancer/component.css +1218 -0
  45. package/src/tool/cocktailBalancer/data/IngredientRepository.ts +83 -0
  46. package/src/tool/cocktailBalancer/data/Presets.ts +122 -0
  47. package/src/tool/cocktailBalancer/domain/Ingredient.ts +29 -0
  48. package/src/tool/cocktailBalancer/i18n/en.ts +193 -0
  49. package/src/tool/cocktailBalancer/i18n/es.ts +193 -0
  50. package/src/tool/cocktailBalancer/i18n/fr.ts +193 -0
  51. package/src/tool/cocktailBalancer/index.ts +68 -0
  52. package/src/tool/cocktailBalancer/logic.ts +118 -0
  53. package/src/tool/cocktailBalancer/seo.astro +53 -0
  54. package/src/tool/partyKeg/component.astro +269 -0
  55. package/src/tool/partyKeg/component.css +660 -0
  56. package/src/tool/partyKeg/i18n/en.ts +162 -0
  57. package/src/tool/partyKeg/i18n/es.ts +166 -0
  58. package/src/tool/partyKeg/i18n/fr.ts +162 -0
  59. package/src/tool/partyKeg/index.ts +46 -0
  60. package/src/tool/partyKeg/logic.ts +36 -0
  61. package/src/tools.ts +14 -0
  62. package/src/types.ts +72 -0
@@ -0,0 +1,219 @@
1
+ ---
2
+ import { Icon } from "astro-icon/components";
3
+ import type { AlcoholClearanceUI } from "./index";
4
+ import './component.css';
5
+
6
+ interface Props {
7
+ ui: AlcoholClearanceUI;
8
+ }
9
+
10
+ const { ui } = Astro.props;
11
+ ---
12
+
13
+ <div class="alc-app" id="alcohol-app">
14
+ <div class="alc-card">
15
+ <div class="alc-grid">
16
+ <div class="alc-inputs-panel">
17
+ <div class="alc-sec">
18
+ <div class="alc-sex-weight">
19
+ <div class="alc-field">
20
+ <label class="field-label">
21
+ <Icon name="mdi:gender-male-female" class="field-label-icon" />
22
+ {ui.biologicalSexLabel}
23
+ </label>
24
+ <div class="sex-toggle">
25
+ <button class="sex-btn selected" data-r="0.68">
26
+ <Icon name="mdi:gender-male" class="sex-icon" />
27
+ </button>
28
+ <button class="sex-btn" data-r="0.55">
29
+ <Icon name="mdi:gender-female" class="sex-icon" />
30
+ </button>
31
+ </div>
32
+ </div>
33
+ <div class="alc-field">
34
+ <label class="field-label">
35
+ <Icon name="mdi:weight-kilogram" class="field-label-icon" />
36
+ {ui.weightLabel}
37
+ </label>
38
+ <div class="weight-input-wrap">
39
+ <input type="number" id="weight" value="75" class="weight-input" />
40
+ <span class="weight-unit">{ui.kgUnit}</span>
41
+ </div>
42
+ </div>
43
+ </div>
44
+ </div>
45
+
46
+ <div class="alc-sec">
47
+ <label class="field-label">{ui.addDrinkLabel}</label>
48
+ <div class="drink-btns">
49
+ {[
50
+ { type: 'beer', icon: 'mdi:beer' },
51
+ { type: 'wine', icon: 'mdi:glass-wine' },
52
+ { type: 'spirit', icon: 'mdi:glass-cocktail' },
53
+ { type: 'shot', icon: 'mdi:glass-mug-variant' }
54
+ ].map(d => (
55
+ <button class="drink-add-btn" data-type={d.type}>
56
+ <Icon name={d.icon} class="drink-icon" />
57
+ </button>
58
+ ))}
59
+ </div>
60
+ </div>
61
+
62
+ <div class="alc-sec">
63
+ <div class="list-header">
64
+ <label class="field-label">{ui.accumulatedLabel}</label>
65
+ <span id="items-count" class="items-count">0 {ui.drinksUnit}</span>
66
+ </div>
67
+ <div id="drinks-list" class="drinks-list custom-scroll">
68
+ <div class="list-empty">
69
+ <Icon name="mdi:glass-cocktail-off" class="list-empty-icon" />
70
+ <p class="list-empty-text">{ui.emptyListLabel}</p>
71
+ </div>
72
+ </div>
73
+ </div>
74
+ </div>
75
+
76
+ <div class="alc-results-panel">
77
+ <div class="bac-section">
78
+ <div class="bac-bg-icon">
79
+ <Icon name="mdi:account-alert" class="bac-bg-icon-svg" />
80
+ </div>
81
+ <div class="bac-content">
82
+ <div class="bac-label">{ui.estimatedBacLabel}</div>
83
+ <div class="bac-value-row">
84
+ <span class="bac-number" id="res-bac">0.00</span>
85
+ <span class="bac-unit">% {ui.bacUnit}</span>
86
+ </div>
87
+ <div id="time-box" class="time-box">
88
+ <Icon name="mdi:clock-outline" class="time-icon" />
89
+ <span id="res-time" class="time-text">--</span>
90
+ </div>
91
+ </div>
92
+ </div>
93
+
94
+ <div class="alc-sec alc-advice-sec">
95
+ <div class="advice-row">
96
+ <div class="advice-icon advice-icon-blue">
97
+ <Icon name="mdi:water" class="advice-icon-svg" />
98
+ </div>
99
+ <div>
100
+ <p class="advice-label">{ui.waterAdviceLabel}</p>
101
+ <p class="advice-value" id="res-water">0 ml</p>
102
+ </div>
103
+ </div>
104
+ <div class="advice-row">
105
+ <div class="advice-icon advice-icon-amber">
106
+ <Icon name="mdi:pill" class="advice-icon-svg" />
107
+ </div>
108
+ <div>
109
+ <p class="advice-label">{ui.pillAdviceLabel}</p>
110
+ <p class="advice-value advice-value-sm" id="res-pill">--</p>
111
+ </div>
112
+ </div>
113
+ </div>
114
+
115
+ <div class="alc-sec alc-disclaimer-sec">
116
+ <div class="disclaimer">
117
+ <Icon name="mdi:alert-circle" class="disclaimer-icon" />
118
+ <p class="disclaimer-text">{ui.disclaimerText}</p>
119
+ </div>
120
+ </div>
121
+ </div>
122
+ </div>
123
+ </div>
124
+
125
+ <div style="display:none" id="ui-labels" data-ui={JSON.stringify(ui)}></div>
126
+ </div>
127
+
128
+
129
+ <script>
130
+ import { calculateAlcoholClearance, getAlcoholGrams, DRINK_TEMPLATES } from "./logic";
131
+ import type { AlcoholClearanceUI } from "./index";
132
+
133
+ interface DrinkEntry { id: string; name: string; size: number; abv: number; }
134
+
135
+ class AlcoholClearanceApp {
136
+ state = { weight: 75, r: 0.68, drinks: [] as DrinkEntry[] };
137
+ ui = {} as AlcoholClearanceUI;
138
+
139
+ constructor() {
140
+ const uiEl = document.getElementById("ui-labels");
141
+ if (uiEl) this.ui = JSON.parse(uiEl.dataset.ui || "{}") as AlcoholClearanceUI;
142
+ this.init();
143
+ }
144
+
145
+ init() {
146
+ document.querySelectorAll<HTMLButtonElement>(".sex-btn").forEach(btn => {
147
+ btn.onclick = () => this.onSexSelect(btn);
148
+ });
149
+ const weightEl = document.getElementById("weight") as HTMLInputElement | null;
150
+ if (weightEl) weightEl.oninput = () => { this.state.weight = parseFloat(weightEl.value) || 75; this.update(); };
151
+ document.querySelectorAll<HTMLButtonElement>(".drink-add-btn").forEach(btn => {
152
+ btn.onclick = () => this.addDrink(btn.dataset.type ?? '');
153
+ });
154
+ this.update();
155
+ }
156
+
157
+ onSexSelect(btn: HTMLButtonElement) {
158
+ document.querySelectorAll(".sex-btn").forEach(b => b.classList.remove("selected"));
159
+ btn.classList.add("selected");
160
+ this.state.r = parseFloat(btn.dataset.r ?? '0.68');
161
+ this.update();
162
+ }
163
+
164
+ addDrink(type: string) {
165
+ const tpl = DRINK_TEMPLATES[type as keyof typeof DRINK_TEMPLATES];
166
+ if (!tpl) return;
167
+ this.state.drinks.push({ id: Math.random().toString(36).substr(2, 9), ...tpl });
168
+ this.renderList();
169
+ }
170
+
171
+ buildDrinkRow(name: string, qty: number): HTMLElement {
172
+ const row = document.createElement("div");
173
+ row.className = "drink-list-row";
174
+ row.innerHTML = `<div class="drink-row-info"><span class="drink-row-name">${this.ui[name + 'Label']}</span><span class="drink-row-qty">x${qty}</span></div>`;
175
+ const del = document.createElement("button");
176
+ del.className = "drink-row-del";
177
+ del.innerHTML = '<svg width="18" height="18" viewBox="0 0 24 24" fill="currentColor"><path d="M19,4H15.5L14.5,3H9.5L8.5,4H5V6H19V4M6,19A2,2 0 0,0 8,21H16A2,2 0 0,0 18,19V7H6V19Z"/></svg>';
178
+ del.onclick = () => {
179
+ const idx = this.state.drinks.findIndex(d => d.name === name);
180
+ this.state.drinks.splice(idx, 1);
181
+ this.renderList();
182
+ };
183
+ row.appendChild(del);
184
+ return row;
185
+ }
186
+
187
+ renderList() {
188
+ const container = document.getElementById("drinks-list");
189
+ const count = document.getElementById("items-count");
190
+ if (!container || !count) return;
191
+ if (this.state.drinks.length === 0) {
192
+ container.innerHTML = `<div class="list-empty"><p class="list-empty-text">${this.ui.emptyListLabel}</p></div>`;
193
+ count.innerText = `0 ${this.ui.drinksUnit}`;
194
+ this.update();
195
+ return;
196
+ }
197
+ container.innerHTML = "";
198
+ const grouped = this.state.drinks.reduce((acc: Record<string, number>, d) => { acc[d.name] = (acc[d.name] || 0) + 1; return acc; }, {});
199
+ Object.entries(grouped).forEach(([name, qty]) => container.appendChild(this.buildDrinkRow(name, qty)));
200
+ const len = this.state.drinks.length;
201
+ count.innerText = `${len} ${len > 1 ? this.ui.drinksUnit : this.ui.drinkUnit}`;
202
+ this.update();
203
+ }
204
+
205
+ update() {
206
+ const totalGrams = this.state.drinks.reduce((sum, d) => sum + getAlcoholGrams(d.size, d.abv), 0);
207
+ const res = calculateAlcoholClearance(totalGrams, this.state.weight, this.state.r, this.state.drinks.length);
208
+ const bacEl = document.getElementById("res-bac");
209
+ const timeEl = document.getElementById("res-time");
210
+ const waterEl = document.getElementById("res-water");
211
+ const pillEl = document.getElementById("res-pill");
212
+ if (bacEl) bacEl.innerText = res.bacPercent.toFixed(3);
213
+ if (timeEl) timeEl.innerText = res.bacPercent > 0 ? `${res.hoursToZero}h ${res.minutesToZero}m ${this.ui.timeToZeroLabel}` : "--";
214
+ if (waterEl) waterEl.innerText = res.waterMl + " ml";
215
+ if (pillEl) pillEl.innerText = this.ui[res.advice + 'Advice'] || "--";
216
+ }
217
+ }
218
+ new AlcoholClearanceApp();
219
+ </script>
@@ -0,0 +1,369 @@
1
+ .alc-app {
2
+ width: 100%;
3
+ max-width: 56rem;
4
+ margin: 0 auto;
5
+ padding: 0.5rem;
6
+ }
7
+
8
+ .alc-card {
9
+ background: #fff;
10
+ border: 1px solid #e2e8f0;
11
+ border-radius: 1.25rem;
12
+ overflow: clip;
13
+ box-shadow: 0 4px 20px rgba(0,0,0,0.06);
14
+ color: #1e293b;
15
+ }
16
+ .theme-dark .alc-card {
17
+ background: #0f172a;
18
+ border-color: #1e293b;
19
+ color: #f1f5f9;
20
+ }
21
+
22
+ .alc-grid { display: grid; }
23
+
24
+ @media (min-width: 768px) {
25
+ .alc-grid {
26
+ grid-template-columns: 1fr 1fr;
27
+ align-items: stretch;
28
+ }
29
+ }
30
+
31
+ .alc-inputs-panel {
32
+ display: flex;
33
+ flex-direction: column;
34
+ }
35
+
36
+ @media (min-width: 768px) { .alc-inputs-panel { border-right: 1px solid #e2e8f0; } }
37
+ .theme-dark .alc-inputs-panel { border-color: #1e293b; }
38
+
39
+ .alc-sec {
40
+ padding: 1.25rem 1.5rem;
41
+ border-bottom: 1px solid #e2e8f0;
42
+ }
43
+ .theme-dark .alc-sec { border-color: #1e293b; }
44
+ .alc-sec:last-child { border-bottom: none; }
45
+
46
+ .alc-sex-weight {
47
+ display: grid;
48
+ grid-template-columns: 1fr 1fr;
49
+ gap: 1.25rem;
50
+ }
51
+ .alc-field {
52
+ display: flex;
53
+ flex-direction: column;
54
+ gap: 0.75rem;
55
+ }
56
+
57
+ .field-label {
58
+ font-size: 0.75rem;
59
+ font-weight: 700;
60
+ text-transform: uppercase;
61
+ letter-spacing: 0.1em;
62
+ color: #94a3b8;
63
+ display: flex;
64
+ align-items: center;
65
+ gap: 0.5rem;
66
+ }
67
+ .field-label-icon {
68
+ width: 1rem;
69
+ height: 1rem;
70
+ }
71
+
72
+ .sex-toggle {
73
+ display: flex;
74
+ gap: 0.5rem;
75
+ padding: 0.25rem;
76
+ background: #f1f5f9;
77
+ border-radius: 0.75rem;
78
+ }
79
+ .theme-dark .sex-toggle { background: #1e293b; }
80
+
81
+ .sex-btn {
82
+ flex: 1;
83
+ padding: 0.75rem;
84
+ border-radius: 0.5rem;
85
+ border: none;
86
+ cursor: pointer;
87
+ display: flex;
88
+ align-items: center;
89
+ justify-content: center;
90
+ color: #94a3b8;
91
+ background: transparent;
92
+ transition: all 0.2s;
93
+ }
94
+ .sex-btn:hover { color: #64748b; }
95
+ .sex-btn.selected {
96
+ background: #fff;
97
+ color: #4f46e5;
98
+ box-shadow: 0 1px 3px rgba(0,0,0,0.1);
99
+ }
100
+ .theme-dark .sex-btn.selected {
101
+ background: #334155;
102
+ color: #818cf8;
103
+ }
104
+ .sex-icon {
105
+ width: 1.5rem;
106
+ height: 1.5rem;
107
+ }
108
+
109
+ .weight-input-wrap { position: relative; }
110
+ .weight-input {
111
+ width: 100%;
112
+ background: #f8fafc;
113
+ border: 2px solid #e2e8f0;
114
+ border-radius: 0.75rem;
115
+ padding: 0.75rem 3rem 0.75rem 1rem;
116
+ font-weight: 700;
117
+ font-size: 1.125rem;
118
+ outline: none;
119
+ transition: border-color 0.2s;
120
+ box-sizing: border-box;
121
+ }
122
+ .theme-dark .weight-input {
123
+ background: rgba(0,0,0,0.2);
124
+ border-color: #334155;
125
+ color: #f1f5f9;
126
+ }
127
+ .weight-input:focus { border-color: #6366f1; }
128
+ .weight-unit {
129
+ position: absolute;
130
+ right: 1rem;
131
+ top: 50%;
132
+ transform: translateY(-50%);
133
+ color: #94a3b8;
134
+ font-weight: 700;
135
+ font-size: 0.75rem;
136
+ text-transform: uppercase;
137
+ }
138
+
139
+ .drink-btns {
140
+ display: grid;
141
+ grid-template-columns: repeat(4, 1fr);
142
+ gap: 0.75rem;
143
+ margin-top: 0.75rem;
144
+ }
145
+ .drink-add-btn {
146
+ display: flex;
147
+ flex-direction: column;
148
+ align-items: center;
149
+ gap: 0.5rem;
150
+ padding: 1rem;
151
+ border-radius: 0.75rem;
152
+ border: none;
153
+ cursor: pointer;
154
+ background: #f1f5f9;
155
+ color: #475569;
156
+ transition: all 0.15s;
157
+ }
158
+ .theme-dark .drink-add-btn {
159
+ background: #1e293b;
160
+ color: #94a3b8;
161
+ }
162
+ .drink-add-btn:hover {
163
+ background: #e0e7ff;
164
+ color: #6366f1;
165
+ transform: scale(1.05);
166
+ }
167
+ .drink-add-btn:active { transform: scale(0.95); }
168
+ .drink-icon {
169
+ width: 2rem;
170
+ height: 2rem;
171
+ }
172
+
173
+ .list-header {
174
+ display: flex;
175
+ justify-content: space-between;
176
+ align-items: center;
177
+ margin-bottom: 0.75rem;
178
+ }
179
+ .items-count {
180
+ font-size: 0.75rem;
181
+ font-weight: 900;
182
+ color: #6366f1;
183
+ text-transform: uppercase;
184
+ }
185
+
186
+ .drinks-list {
187
+ max-height: 250px;
188
+ overflow-y: auto;
189
+ display: flex;
190
+ flex-direction: column;
191
+ gap: 0.5rem;
192
+ padding-right: 0.5rem;
193
+ }
194
+ .list-empty {
195
+ text-align: center;
196
+ padding: 2rem 0;
197
+ color: #cbd5e1;
198
+ display: flex;
199
+ flex-direction: column;
200
+ align-items: center;
201
+ gap: 0.75rem;
202
+ }
203
+ .theme-dark .list-empty { color: #334155; }
204
+ .list-empty-icon {
205
+ width: 2.5rem;
206
+ height: 2.5rem;
207
+ opacity: 0.2;
208
+ }
209
+ .list-empty-text {
210
+ font-size: 0.875rem;
211
+ font-weight: 500;
212
+ }
213
+
214
+ .custom-scroll::-webkit-scrollbar { width: 4px; }
215
+ .custom-scroll::-webkit-scrollbar-track { background: transparent; }
216
+ .custom-scroll::-webkit-scrollbar-thumb {
217
+ background: #e2e8f0;
218
+ border-radius: 10px;
219
+ }
220
+
221
+ .alc-results-panel {
222
+ display: flex;
223
+ flex-direction: column;
224
+ background: #f8fafc;
225
+ }
226
+ .theme-dark .alc-results-panel { background: rgba(0,0,0,0.2); }
227
+
228
+ .bac-section {
229
+ background: #4f46e5;
230
+ color: #fff;
231
+ padding: 1.5rem;
232
+ position: relative;
233
+ overflow: hidden;
234
+ flex-shrink: 0;
235
+ }
236
+ .theme-dark .bac-section { background: #4338ca; }
237
+ .bac-bg-icon {
238
+ position: absolute;
239
+ top: 0;
240
+ right: 0;
241
+ padding: 1.5rem;
242
+ opacity: 0.1;
243
+ }
244
+ .bac-bg-icon-svg {
245
+ width: 5rem;
246
+ height: 5rem;
247
+ transform: rotate(12deg);
248
+ }
249
+ .bac-content {
250
+ position: relative;
251
+ z-index: 1;
252
+ display: flex;
253
+ flex-direction: column;
254
+ gap: 1rem;
255
+ }
256
+ .bac-label {
257
+ font-size: 0.75rem;
258
+ font-weight: 700;
259
+ text-transform: uppercase;
260
+ letter-spacing: 0.2em;
261
+ opacity: 0.6;
262
+ }
263
+ .bac-value-row {
264
+ display: flex;
265
+ align-items: baseline;
266
+ gap: 0.5rem;
267
+ }
268
+ .bac-number {
269
+ font-size: 3.5rem;
270
+ font-weight: 900;
271
+ letter-spacing: -0.05em;
272
+ line-height: 1;
273
+ font-variant-numeric: tabular-nums;
274
+ }
275
+ .bac-unit {
276
+ font-size: 1rem;
277
+ font-weight: 700;
278
+ opacity: 0.6;
279
+ }
280
+
281
+ .time-box {
282
+ display: flex;
283
+ align-items: center;
284
+ gap: 0.75rem;
285
+ background: rgba(255,255,255,0.1);
286
+ border-radius: 0.75rem;
287
+ padding: 0.75rem;
288
+ border: 1px solid rgba(255,255,255,0.1);
289
+ }
290
+ .time-icon {
291
+ width: 1.25rem;
292
+ height: 1.25rem;
293
+ flex-shrink: 0;
294
+ }
295
+ .time-text {
296
+ font-weight: 700;
297
+ font-size: 0.875rem;
298
+ }
299
+
300
+ .alc-advice-sec {
301
+ display: flex;
302
+ flex-direction: column;
303
+ gap: 1rem;
304
+ }
305
+ .advice-row {
306
+ display: flex;
307
+ align-items: center;
308
+ gap: 1rem;
309
+ }
310
+ .advice-icon {
311
+ width: 2.25rem;
312
+ height: 2.25rem;
313
+ border-radius: 0.6rem;
314
+ display: flex;
315
+ align-items: center;
316
+ justify-content: center;
317
+ flex-shrink: 0;
318
+ }
319
+ .advice-icon-blue {
320
+ background: #dbeafe;
321
+ color: #3b82f6;
322
+ }
323
+ .theme-dark .advice-icon-blue { background: rgba(59,130,246,0.2); }
324
+ .advice-icon-amber {
325
+ background: #fef3c7;
326
+ color: #f59e0b;
327
+ }
328
+ .theme-dark .advice-icon-amber { background: rgba(245,158,11,0.2); }
329
+ .advice-icon-svg {
330
+ width: 1.25rem;
331
+ height: 1.25rem;
332
+ }
333
+ .advice-label {
334
+ font-size: 0.75rem;
335
+ font-weight: 700;
336
+ color: #94a3b8;
337
+ text-transform: uppercase;
338
+ margin: 0 0 0.2rem;
339
+ }
340
+ .advice-value {
341
+ font-size: 1.125rem;
342
+ font-weight: 900;
343
+ margin: 0;
344
+ }
345
+ .advice-value-sm { font-size: 0.875rem; }
346
+
347
+ .alc-disclaimer-sec { margin-top: auto; }
348
+ .disclaimer {
349
+ background: #fffbeb;
350
+ border-radius: 0.75rem;
351
+ padding: 0.875rem;
352
+ display: flex;
353
+ gap: 0.75rem;
354
+ color: #92400e;
355
+ font-size: 0.75rem;
356
+ line-height: 1.6;
357
+ border: 1px solid #fde68a;
358
+ }
359
+ .theme-dark .disclaimer {
360
+ background: rgba(120,53,15,0.2);
361
+ border-color: rgba(120,53,15,0.5);
362
+ color: #f59e0b;
363
+ }
364
+ .disclaimer-icon {
365
+ width: 1.5rem;
366
+ height: 1.5rem;
367
+ flex-shrink: 0;
368
+ }
369
+ .disclaimer-text { margin: 0; }