@jjlmoya/utils-health 1.16.0 → 1.18.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 (56) hide show
  1. package/package.json +1 -1
  2. package/src/category/index.ts +3 -1
  3. package/src/data.ts +1 -1
  4. package/src/entries.ts +5 -1
  5. package/src/index.ts +1 -1
  6. package/src/tests/locale_completeness.test.ts +2 -3
  7. package/src/tests/tool_validation.test.ts +2 -2
  8. package/src/tool/bodyAdiposityIndexCalculator/bibliography.astro +14 -0
  9. package/src/tool/bodyAdiposityIndexCalculator/bibliography.ts +24 -0
  10. package/src/tool/bodyAdiposityIndexCalculator/body-adiposity-index-calculator.css +547 -0
  11. package/src/tool/bodyAdiposityIndexCalculator/component.astro +288 -0
  12. package/src/tool/bodyAdiposityIndexCalculator/entry.ts +27 -0
  13. package/src/tool/bodyAdiposityIndexCalculator/i18n/de.ts +301 -0
  14. package/src/tool/bodyAdiposityIndexCalculator/i18n/en.ts +301 -0
  15. package/src/tool/bodyAdiposityIndexCalculator/i18n/es.ts +301 -0
  16. package/src/tool/bodyAdiposityIndexCalculator/i18n/fr.ts +301 -0
  17. package/src/tool/bodyAdiposityIndexCalculator/i18n/id.ts +301 -0
  18. package/src/tool/bodyAdiposityIndexCalculator/i18n/it.ts +301 -0
  19. package/src/tool/bodyAdiposityIndexCalculator/i18n/ja.ts +301 -0
  20. package/src/tool/bodyAdiposityIndexCalculator/i18n/ko.ts +301 -0
  21. package/src/tool/bodyAdiposityIndexCalculator/i18n/nl.ts +301 -0
  22. package/src/tool/bodyAdiposityIndexCalculator/i18n/pl.ts +301 -0
  23. package/src/tool/bodyAdiposityIndexCalculator/i18n/pt.ts +301 -0
  24. package/src/tool/bodyAdiposityIndexCalculator/i18n/ru.ts +301 -0
  25. package/src/tool/bodyAdiposityIndexCalculator/i18n/sv.ts +301 -0
  26. package/src/tool/bodyAdiposityIndexCalculator/i18n/tr.ts +301 -0
  27. package/src/tool/bodyAdiposityIndexCalculator/i18n/zh.ts +301 -0
  28. package/src/tool/bodyAdiposityIndexCalculator/index.ts +12 -0
  29. package/src/tool/bodyAdiposityIndexCalculator/logic.ts +39 -0
  30. package/src/tool/bodyAdiposityIndexCalculator/seo.astro +15 -0
  31. package/src/tool/bodyAdiposityIndexCalculator/ui.ts +35 -0
  32. package/src/tool/leanBodyMassCalculator/bibliography.astro +14 -0
  33. package/src/tool/leanBodyMassCalculator/bibliography.ts +20 -0
  34. package/src/tool/leanBodyMassCalculator/component.astro +240 -0
  35. package/src/tool/leanBodyMassCalculator/entry.ts +27 -0
  36. package/src/tool/leanBodyMassCalculator/i18n/de.ts +333 -0
  37. package/src/tool/leanBodyMassCalculator/i18n/en.ts +333 -0
  38. package/src/tool/leanBodyMassCalculator/i18n/es.ts +333 -0
  39. package/src/tool/leanBodyMassCalculator/i18n/fr.ts +333 -0
  40. package/src/tool/leanBodyMassCalculator/i18n/id.ts +333 -0
  41. package/src/tool/leanBodyMassCalculator/i18n/it.ts +333 -0
  42. package/src/tool/leanBodyMassCalculator/i18n/ja.ts +333 -0
  43. package/src/tool/leanBodyMassCalculator/i18n/ko.ts +333 -0
  44. package/src/tool/leanBodyMassCalculator/i18n/nl.ts +333 -0
  45. package/src/tool/leanBodyMassCalculator/i18n/pl.ts +333 -0
  46. package/src/tool/leanBodyMassCalculator/i18n/pt.ts +333 -0
  47. package/src/tool/leanBodyMassCalculator/i18n/ru.ts +333 -0
  48. package/src/tool/leanBodyMassCalculator/i18n/sv.ts +333 -0
  49. package/src/tool/leanBodyMassCalculator/i18n/tr.ts +333 -0
  50. package/src/tool/leanBodyMassCalculator/i18n/zh.ts +333 -0
  51. package/src/tool/leanBodyMassCalculator/index.ts +12 -0
  52. package/src/tool/leanBodyMassCalculator/lean-body-mass-calculator.css +391 -0
  53. package/src/tool/leanBodyMassCalculator/logic.ts +55 -0
  54. package/src/tool/leanBodyMassCalculator/seo.astro +15 -0
  55. package/src/tool/leanBodyMassCalculator/ui.ts +30 -0
  56. package/src/tools.ts +3 -2
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jjlmoya/utils-health",
3
- "version": "1.16.0",
3
+ "version": "1.18.0",
4
4
  "type": "module",
5
5
  "main": "./src/index.ts",
6
6
  "types": "./src/index.ts",
@@ -1,5 +1,6 @@
1
1
  import type { HealthCategoryEntry } from '../types';
2
2
  import { bmiCalculator } from '../tool/bmiCalculator/entry';
3
+ import { bodyAdiposityIndexCalculator } from '../tool/bodyAdiposityIndexCalculator/entry';
3
4
  import { daltonismSimulator } from '../tool/daltonismSimulator/entry';
4
5
  import { tinnitusReliever } from '../tool/tinnitusReliever/entry';
5
6
  import { breathingVisualizer } from '../tool/breathingVisualizer/entry';
@@ -10,10 +11,11 @@ import { binauralTuner } from '../tool/binauralTuner/entry';
10
11
  import { pelliRobsonTest } from '../tool/pelliRobsonTest/entry';
11
12
  import { peripheralVisionTrainer } from '../tool/peripheralVisionTrainer/entry';
12
13
  import { epworthSleepinessScale } from '../tool/epworthSleepinessScale/entry';
14
+ import { leanBodyMassCalculator } from '../tool/leanBodyMassCalculator/entry';
13
15
 
14
16
  export const healthCategory: HealthCategoryEntry = {
15
17
  icon: 'mdi:heart-pulse',
16
- tools: [bmiCalculator, daltonismSimulator, tinnitusReliever, breathingVisualizer, caffeineTracker, waterPurifier, digestionStopwatch, binauralTuner, pelliRobsonTest, peripheralVisionTrainer, epworthSleepinessScale],
18
+ tools: [bmiCalculator, bodyAdiposityIndexCalculator, leanBodyMassCalculator, daltonismSimulator, tinnitusReliever, breathingVisualizer, caffeineTracker, waterPurifier, digestionStopwatch, binauralTuner, pelliRobsonTest, peripheralVisionTrainer, epworthSleepinessScale],
17
19
  i18n: {
18
20
  en: () => import('./i18n/en').then((m) => m.content),
19
21
  es: () => import('./i18n/es').then((m) => m.content),
package/src/data.ts CHANGED
@@ -14,6 +14,7 @@ export { screenDecompressionTime } from './tool/screenDecompressionTime';
14
14
  export { bloodUnitConverter } from './tool/bloodUnitConverter';
15
15
  export { readingDistanceCalculator } from './tool/readingDistanceCalculator';
16
16
  export { hydrationCalculator } from './tool/hydrationCalculator';
17
+ export { leanBodyMassCalculator } from './tool/leanBodyMassCalculator';
17
18
 
18
19
  export { healthCategory } from './category';
19
20
 
@@ -25,4 +26,3 @@ export type {
25
26
  HealthToolEntry,
26
27
  HealthCategoryEntry,
27
28
  } from './types';
28
-
package/src/entries.ts CHANGED
@@ -1,12 +1,14 @@
1
1
  export { binauralTuner } from './tool/binauralTuner/entry';
2
2
  export { bloodUnitConverter } from './tool/bloodUnitConverter/entry';
3
3
  export { bmiCalculator } from './tool/bmiCalculator/entry';
4
+ export { bodyAdiposityIndexCalculator } from './tool/bodyAdiposityIndexCalculator/entry';
4
5
  export { breathingVisualizer } from './tool/breathingVisualizer/entry';
5
6
  export { caffeineTracker } from './tool/caffeineTracker/entry';
6
7
  export { daltonismSimulator } from './tool/daltonismSimulator/entry';
7
8
  export { digestionStopwatch } from './tool/digestionStopwatch/entry';
8
9
  export { epworthSleepinessScale } from './tool/epworthSleepinessScale/entry';
9
10
  export { hydrationCalculator } from './tool/hydrationCalculator/entry';
11
+ export { leanBodyMassCalculator } from './tool/leanBodyMassCalculator/entry';
10
12
  export { pelliRobsonTest } from './tool/pelliRobsonTest/entry';
11
13
  export { peripheralVisionTrainer } from './tool/peripheralVisionTrainer/entry';
12
14
  export { readingDistanceCalculator } from './tool/readingDistanceCalculator/entry';
@@ -18,12 +20,14 @@ export { healthCategory } from './category';
18
20
  import { binauralTuner } from './tool/binauralTuner/entry';
19
21
  import { bloodUnitConverter } from './tool/bloodUnitConverter/entry';
20
22
  import { bmiCalculator } from './tool/bmiCalculator/entry';
23
+ import { bodyAdiposityIndexCalculator } from './tool/bodyAdiposityIndexCalculator/entry';
21
24
  import { breathingVisualizer } from './tool/breathingVisualizer/entry';
22
25
  import { caffeineTracker } from './tool/caffeineTracker/entry';
23
26
  import { daltonismSimulator } from './tool/daltonismSimulator/entry';
24
27
  import { digestionStopwatch } from './tool/digestionStopwatch/entry';
25
28
  import { epworthSleepinessScale } from './tool/epworthSleepinessScale/entry';
26
29
  import { hydrationCalculator } from './tool/hydrationCalculator/entry';
30
+ import { leanBodyMassCalculator } from './tool/leanBodyMassCalculator/entry';
27
31
  import { pelliRobsonTest } from './tool/pelliRobsonTest/entry';
28
32
  import { peripheralVisionTrainer } from './tool/peripheralVisionTrainer/entry';
29
33
  import { readingDistanceCalculator } from './tool/readingDistanceCalculator/entry';
@@ -31,4 +35,4 @@ import { screenDecompressionTime } from './tool/screenDecompressionTime/entry';
31
35
  import { tinnitusReliever } from './tool/tinnitusReliever/entry';
32
36
  import { ubeCalculator } from './tool/ubeCalculator/entry';
33
37
  import { waterPurifier } from './tool/waterPurifier/entry';
34
- export const ALL_ENTRIES = [binauralTuner, bloodUnitConverter, bmiCalculator, breathingVisualizer, caffeineTracker, daltonismSimulator, digestionStopwatch, epworthSleepinessScale, hydrationCalculator, pelliRobsonTest, peripheralVisionTrainer, readingDistanceCalculator, screenDecompressionTime, tinnitusReliever, ubeCalculator, waterPurifier];
38
+ export const ALL_ENTRIES = [binauralTuner, bloodUnitConverter, bmiCalculator, bodyAdiposityIndexCalculator, breathingVisualizer, caffeineTracker, daltonismSimulator, digestionStopwatch, epworthSleepinessScale, hydrationCalculator, leanBodyMassCalculator, pelliRobsonTest, peripheralVisionTrainer, readingDistanceCalculator, screenDecompressionTime, tinnitusReliever, ubeCalculator, waterPurifier];
package/src/index.ts CHANGED
@@ -14,6 +14,7 @@ export * from './tool/screenDecompressionTime';
14
14
  export * from './tool/bloodUnitConverter';
15
15
  export * from './tool/readingDistanceCalculator';
16
16
  export * from './tool/hydrationCalculator';
17
+ export * from './tool/bodyAdiposityIndexCalculator';
17
18
 
18
19
  export { healthCategory } from './category';
19
20
  export const healthCategorySEO = () => import('./category/seo.astro').then((m) => m.default);
@@ -33,4 +34,3 @@ export type {
33
34
  } from './types';
34
35
 
35
36
  export { ALL_ENTRIES, ALL_TOOLS } from './tools';
36
-
@@ -35,8 +35,7 @@ describe('Locale Completeness Validation', () => {
35
35
  });
36
36
  });
37
37
 
38
- it('all 16 tools registered', () => {
39
- expect(ALL_TOOLS.length).toBe(16);
38
+ it('all 18 tools registered', () => {
39
+ expect(ALL_TOOLS.length).toBe(18);
40
40
  });
41
41
  });
42
-
@@ -4,8 +4,8 @@ import { healthCategory } 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 18 tools in ALL_TOOLS', () => {
8
+ expect(ALL_TOOLS.length).toBe(18);
9
9
  });
10
10
 
11
11
  it('healthCategory should be defined', () => {
@@ -0,0 +1,14 @@
1
+ ---
2
+ import { Bibliography } from '@jjlmoya/utils-shared';
3
+ import { bodyAdiposityIndexCalculator } from './index';
4
+ import type { KnownLocale } from '../../types';
5
+
6
+ interface Props {
7
+ locale?: KnownLocale;
8
+ }
9
+
10
+ const { locale = 'en' } = Astro.props;
11
+ const content = await bodyAdiposityIndexCalculator.i18n[locale]?.();
12
+ ---
13
+
14
+ {content && <Bibliography links={content.bibliography} />}
@@ -0,0 +1,24 @@
1
+ import type { BibliographyEntry } from '../../types';
2
+
3
+ export const bibliography: BibliographyEntry[] = [
4
+ {
5
+ name: 'Bergman et al.: A better index of body adiposity',
6
+ url: 'https://doi.org/10.1038/oby.2011.38',
7
+ },
8
+ {
9
+ name: 'WHO: Obesity and overweight fact sheet',
10
+ url: 'https://www.who.int/news-room/fact-sheets/detail/obesity-and-overweight',
11
+ },
12
+ {
13
+ name: 'CDC: About adult BMI',
14
+ url: 'https://www.cdc.gov/bmi/adult-calculator/index.html',
15
+ },
16
+ {
17
+ name: 'NIH MedlinePlus: Body weight and body fat',
18
+ url: 'https://medlineplus.gov/ency/patientinstructions/000348.htm',
19
+ },
20
+ {
21
+ name: 'Wikipedia: Body adiposity index',
22
+ url: 'https://en.wikipedia.org/wiki/Body_adiposity_index',
23
+ },
24
+ ];
@@ -0,0 +1,547 @@
1
+ .bai {
2
+ --bai-paper: #fbfaf7;
3
+ --bai-panel: #fff;
4
+ --bai-ink: #20242b;
5
+ --bai-muted: #69707d;
6
+ --bai-line: #d9dde3;
7
+ --bai-line-strong: #bfc6d0;
8
+ --bai-blue: #2f63c7;
9
+ --bai-green: #2f8a58;
10
+ --bai-amber: #b46b1f;
11
+ --bai-red: #bd3b3b;
12
+ --bai-shadow: rgba(32, 36, 43, 0.08);
13
+
14
+ width: 100%;
15
+ }
16
+
17
+ .theme-dark .bai {
18
+ --bai-paper: #12161d;
19
+ --bai-panel: #191f28;
20
+ --bai-ink: #f3f5f7;
21
+ --bai-muted: #a9b0bd;
22
+ --bai-line: #323a47;
23
+ --bai-line-strong: #465263;
24
+ --bai-shadow: rgba(0, 0, 0, 0.28);
25
+ }
26
+
27
+ .bai__shell {
28
+ position: relative;
29
+ overflow: hidden;
30
+ border: 1px solid var(--bai-line);
31
+ border-radius: 8px;
32
+ background: var(--bai-paper);
33
+ color: var(--bai-ink);
34
+ box-shadow: 0 18px 42px var(--bai-shadow);
35
+ }
36
+
37
+ .bai__shell::before {
38
+ content: "";
39
+ position: absolute;
40
+ inset: 0;
41
+ pointer-events: none;
42
+ background-image:
43
+ linear-gradient(to right, color-mix(in srgb, var(--bai-line) 38%, transparent) 1px, transparent 1px),
44
+ linear-gradient(to bottom, color-mix(in srgb, var(--bai-line) 32%, transparent) 1px, transparent 1px);
45
+ background-size: 26px 26px;
46
+ opacity: 0.28;
47
+ }
48
+
49
+ .bai__shell--changed .bai__scoreline strong {
50
+ animation: bai-score-pop 260ms ease-out;
51
+ }
52
+
53
+ .bai__shell--changed .bai__marker {
54
+ animation: bai-marker-settle 360ms ease-out;
55
+ }
56
+
57
+ .bai__workbench {
58
+ position: relative;
59
+ z-index: 1;
60
+ display: grid;
61
+ gap: 0;
62
+ }
63
+
64
+ .bai__controls,
65
+ .bai__result {
66
+ padding: clamp(1rem, 3vw, 1.5rem);
67
+ }
68
+
69
+ .bai__controls {
70
+ display: grid;
71
+ gap: 0.85rem;
72
+ background: var(--bai-panel);
73
+ border-bottom: 1px solid var(--bai-line);
74
+ }
75
+
76
+ .bai__figure {
77
+ position: relative;
78
+ height: 8.25rem;
79
+ overflow: hidden;
80
+ border: 1px solid var(--bai-line);
81
+ border-radius: 8px;
82
+ background:
83
+ radial-gradient(circle at 50% 28%, color-mix(in srgb, var(--bai-blue) 12%, transparent), transparent 24%),
84
+ var(--bai-paper);
85
+ }
86
+
87
+ .bai__figure-head,
88
+ .bai__figure-body,
89
+ .bai__figure-hip,
90
+ .bai__figure-line {
91
+ position: absolute;
92
+ left: 50%;
93
+ }
94
+
95
+ .bai__figure-head {
96
+ top: 0.8rem;
97
+ width: 1.8rem;
98
+ height: 1.8rem;
99
+ border: 2px solid var(--bai-ink);
100
+ border-radius: 999px;
101
+ transform: translateX(-50%);
102
+ }
103
+
104
+ .bai__figure-body {
105
+ top: 2.75rem;
106
+ width: 3rem;
107
+ height: 4.25rem;
108
+ border: 2px solid var(--bai-ink);
109
+ border-bottom-width: 0;
110
+ border-radius: 1.6rem 1.6rem 0.7rem 0.7rem;
111
+ transform: translateX(-50%);
112
+ }
113
+
114
+ .bai__figure-hip {
115
+ top: 5.55rem;
116
+ width: 4.75rem;
117
+ height: 1.35rem;
118
+ border: 2px solid var(--bai-amber);
119
+ border-radius: 999px;
120
+ transform: translateX(-50%);
121
+ transform-origin: 50% 50%;
122
+ transition: transform 180ms ease;
123
+ }
124
+
125
+ .bai__figure-line {
126
+ background: var(--bai-line-strong);
127
+ }
128
+
129
+ .bai__figure-line--height {
130
+ top: 0.8rem;
131
+ left: 1rem;
132
+ width: 1px;
133
+ height: 6.6rem;
134
+ }
135
+
136
+ .bai__figure-line--height::before,
137
+ .bai__figure-line--height::after,
138
+ .bai__figure-line--hip::before,
139
+ .bai__figure-line--hip::after {
140
+ content: "";
141
+ position: absolute;
142
+ background: var(--bai-line-strong);
143
+ }
144
+
145
+ .bai__figure-line--height::before,
146
+ .bai__figure-line--height::after {
147
+ left: -0.25rem;
148
+ width: 0.5rem;
149
+ height: 1px;
150
+ }
151
+
152
+ .bai__figure-line--height::before { top: 0; }
153
+ .bai__figure-line--height::after { bottom: 0; }
154
+
155
+ .bai__figure-line--hip {
156
+ top: 6.2rem;
157
+ width: 5.8rem;
158
+ height: 1px;
159
+ transform: translateX(-50%);
160
+ }
161
+
162
+ .bai__figure-line--hip::before,
163
+ .bai__figure-line--hip::after {
164
+ top: -0.25rem;
165
+ width: 1px;
166
+ height: 0.5rem;
167
+ }
168
+
169
+ .bai__figure-line--hip::before { left: 0; }
170
+ .bai__figure-line--hip::after { right: 0; }
171
+
172
+ .bai__switch-row {
173
+ display: grid;
174
+ grid-template-columns: 1fr auto;
175
+ gap: 0.75rem;
176
+ align-items: center;
177
+ }
178
+
179
+ .bai__unit,
180
+ .bai__sex {
181
+ display: inline-grid;
182
+ grid-auto-flow: column;
183
+ gap: 0.25rem;
184
+ padding: 0.25rem;
185
+ border: 1px solid var(--bai-line);
186
+ border-radius: 8px;
187
+ background: var(--bai-paper);
188
+ }
189
+
190
+ .bai__unit {
191
+ grid-template-columns: repeat(2, minmax(0, 1fr));
192
+ }
193
+
194
+ .bai__unit-btn,
195
+ .bai__sex-btn {
196
+ height: 2.35rem;
197
+ border: 0;
198
+ border-radius: 6px;
199
+ background: transparent;
200
+ color: var(--bai-muted);
201
+ font: inherit;
202
+ font-size: 0.84rem;
203
+ font-weight: 800;
204
+ cursor: pointer;
205
+ transition: background-color 0.16s ease, color 0.16s ease, box-shadow 0.16s ease;
206
+ }
207
+
208
+ .bai__sex-btn {
209
+ width: 2.35rem;
210
+ display: inline-grid;
211
+ place-items: center;
212
+ }
213
+
214
+ .bai__sex-btn svg {
215
+ width: 1.15rem;
216
+ height: 1.15rem;
217
+ }
218
+
219
+ .bai__unit-btn:hover,
220
+ .bai__sex-btn:hover {
221
+ color: var(--bai-ink);
222
+ box-shadow: 0 0 0 1px var(--bai-line-strong) inset;
223
+ }
224
+
225
+ .bai__unit-btn:active,
226
+ .bai__sex-btn:active {
227
+ transform: translateY(1px);
228
+ }
229
+
230
+ .bai__unit-btn--active,
231
+ .bai__sex-btn--active {
232
+ background: var(--bai-ink);
233
+ color: var(--bai-panel);
234
+ box-shadow: 0 1px 0 rgba(255, 255, 255, 0.16) inset;
235
+ }
236
+
237
+ .theme-dark .bai__unit-btn--active,
238
+ .theme-dark .bai__sex-btn--active {
239
+ background: #eef2f7;
240
+ color: #161b22;
241
+ }
242
+
243
+ .bai__field {
244
+ display: grid;
245
+ gap: 0.65rem;
246
+ padding: 0.8rem 0.85rem;
247
+ border: 1px solid var(--bai-line);
248
+ border-radius: 8px;
249
+ background: var(--bai-paper);
250
+ transition: border-color 0.16s ease, box-shadow 0.16s ease, transform 0.16s ease;
251
+ }
252
+
253
+ .bai__field:focus-within {
254
+ border-color: var(--bai-line-strong);
255
+ box-shadow: 0 0 0 3px color-mix(in srgb, var(--bai-blue) 14%, transparent);
256
+ transform: translateY(-1px);
257
+ }
258
+
259
+ .bai__field-top {
260
+ display: flex;
261
+ align-items: baseline;
262
+ justify-content: space-between;
263
+ gap: 1rem;
264
+ color: var(--bai-muted);
265
+ font-size: 0.82rem;
266
+ font-weight: 800;
267
+ }
268
+
269
+ .bai__field-top strong {
270
+ color: var(--bai-ink);
271
+ font-size: clamp(1.3rem, 5vw, 1.75rem);
272
+ line-height: 1;
273
+ }
274
+
275
+ .bai__range {
276
+ --track-color: color-mix(in srgb, var(--bai-ink) 18%, transparent);
277
+
278
+ width: 100%;
279
+ height: 1.4rem;
280
+ margin: 0;
281
+ accent-color: var(--bai-ink);
282
+ cursor: ew-resize;
283
+ }
284
+
285
+ .bai__range::-webkit-slider-runnable-track {
286
+ height: 0.42rem;
287
+ border-radius: 999px;
288
+ background: var(--track-color);
289
+ }
290
+
291
+ .bai__range::-webkit-slider-thumb {
292
+ margin-top: -0.44rem;
293
+ width: 1.28rem;
294
+ height: 1.28rem;
295
+ border: 2px solid var(--bai-panel);
296
+ border-radius: 999px;
297
+ background: var(--bai-ink);
298
+ box-shadow: 0 3px 12px var(--bai-shadow);
299
+ }
300
+
301
+ .bai__range::-moz-range-track {
302
+ height: 0.42rem;
303
+ border-radius: 999px;
304
+ background: var(--track-color);
305
+ }
306
+
307
+ .bai__range::-moz-range-thumb {
308
+ width: 1.28rem;
309
+ height: 1.28rem;
310
+ border: 2px solid var(--bai-panel);
311
+ border-radius: 999px;
312
+ background: var(--bai-ink);
313
+ box-shadow: 0 3px 12px var(--bai-shadow);
314
+ }
315
+
316
+ .bai__result {
317
+ display: grid;
318
+ gap: 1rem;
319
+ align-content: center;
320
+ }
321
+
322
+ .bai__scoreline {
323
+ display: grid;
324
+ grid-template-columns: auto 1fr auto;
325
+ gap: 0.65rem;
326
+ align-items: baseline;
327
+ color: var(--bai-muted);
328
+ font-size: 0.78rem;
329
+ font-weight: 900;
330
+ text-transform: uppercase;
331
+ }
332
+
333
+ .bai__scoreline strong {
334
+ color: var(--bai-ink);
335
+ font-size: clamp(4.1rem, 18vw, 7.5rem);
336
+ font-weight: 950;
337
+ line-height: 0.86;
338
+ letter-spacing: 0;
339
+ text-align: center;
340
+ font-variant-numeric: tabular-nums;
341
+ transition: color 0.16s ease;
342
+ }
343
+
344
+ .bai__scale {
345
+ display: grid;
346
+ gap: 0.55rem;
347
+ }
348
+
349
+ .bai__scale-track {
350
+ position: relative;
351
+ display: grid;
352
+ grid-template-columns: 21fr 29fr 15fr 35fr;
353
+ height: 1.1rem;
354
+ overflow: visible;
355
+ border: 1px solid var(--bai-line-strong);
356
+ border-radius: 999px;
357
+ background: var(--bai-panel);
358
+ box-shadow: 0 1px 0 rgba(255, 255, 255, 0.18) inset;
359
+ }
360
+
361
+ .bai__band {
362
+ min-width: 0;
363
+ }
364
+
365
+ .bai__band--low { background: color-mix(in srgb, var(--bai-blue) 72%, transparent); }
366
+ .bai__band--healthy { background: color-mix(in srgb, var(--bai-green) 72%, transparent); }
367
+ .bai__band--elevated { background: color-mix(in srgb, var(--bai-amber) 78%, transparent); }
368
+ .bai__band--high { background: color-mix(in srgb, var(--bai-red) 74%, transparent); }
369
+
370
+ .bai__marker {
371
+ position: absolute;
372
+ top: 50%;
373
+ left: 50%;
374
+ width: 0.9rem;
375
+ height: 2.15rem;
376
+ border: 2px solid var(--bai-paper);
377
+ border-radius: 999px;
378
+ background: var(--bai-ink);
379
+ box-shadow: 0 0 0 1px var(--bai-line-strong), 0 8px 18px var(--bai-shadow);
380
+ transform: translate(-50%, -50%);
381
+ transition: left 0.18s ease;
382
+ }
383
+
384
+ .bai__ticks {
385
+ display: grid;
386
+ grid-template-columns: repeat(4, 1fr);
387
+ gap: 0.25rem;
388
+ color: var(--bai-muted);
389
+ font-size: 0.68rem;
390
+ font-weight: 850;
391
+ text-transform: uppercase;
392
+ }
393
+
394
+ .bai__ticks span:nth-child(2),
395
+ .bai__ticks span:nth-child(3) {
396
+ text-align: center;
397
+ }
398
+
399
+ .bai__ticks span:last-child {
400
+ text-align: right;
401
+ }
402
+
403
+ .bai__readout {
404
+ min-height: 6.7rem;
405
+ padding: 0.95rem;
406
+ border: 1px solid var(--bai-line);
407
+ border-radius: 8px;
408
+ background: var(--bai-panel);
409
+ transition: border-color 0.16s ease;
410
+ }
411
+
412
+ .bai__readout strong {
413
+ display: block;
414
+ margin-bottom: 0.4rem;
415
+ color: var(--bai-ink);
416
+ font-size: clamp(1.2rem, 4vw, 1.65rem);
417
+ line-height: 1.1;
418
+ }
419
+
420
+ .bai__readout p {
421
+ margin: 0;
422
+ color: var(--bai-muted);
423
+ font-size: 0.94rem;
424
+ line-height: 1.5;
425
+ }
426
+
427
+ .bai__result[data-level="low"] .bai__readout strong { color: var(--bai-blue); }
428
+ .bai__result[data-level="healthy"] .bai__readout strong { color: var(--bai-green); }
429
+ .bai__result[data-level="elevated"] .bai__readout strong { color: var(--bai-amber); }
430
+ .bai__result[data-level="high"] .bai__readout strong { color: var(--bai-red); }
431
+ .bai__result[data-level="low"] .bai__scoreline strong { color: var(--bai-blue); }
432
+ .bai__result[data-level="healthy"] .bai__scoreline strong { color: var(--bai-green); }
433
+ .bai__result[data-level="elevated"] .bai__scoreline strong { color: var(--bai-amber); }
434
+ .bai__result[data-level="high"] .bai__scoreline strong { color: var(--bai-red); }
435
+
436
+ .bai__notes {
437
+ position: relative;
438
+ z-index: 1;
439
+ display: grid;
440
+ gap: 0;
441
+ border-top: 1px solid var(--bai-line);
442
+ }
443
+
444
+ .bai__info {
445
+ display: grid;
446
+ grid-template-columns: 1.45rem 1fr;
447
+ gap: 0.7rem;
448
+ align-items: start;
449
+ padding: 0.78rem 0.95rem;
450
+ border-bottom: 1px solid var(--bai-line);
451
+ background: var(--bai-panel);
452
+ color: var(--bai-muted);
453
+ transition: background-color 0.16s ease;
454
+ }
455
+
456
+ .bai__info:hover {
457
+ background: var(--bai-paper);
458
+ }
459
+
460
+ .bai__info:last-child {
461
+ border-bottom: 0;
462
+ }
463
+
464
+ .bai__info span {
465
+ display: grid;
466
+ place-items: center;
467
+ width: 1.45rem;
468
+ height: 1.45rem;
469
+ color: var(--bai-blue);
470
+ }
471
+
472
+ .bai__info svg {
473
+ width: 1.15rem;
474
+ height: 1.15rem;
475
+ }
476
+
477
+ .bai__info p {
478
+ margin: 0;
479
+ font-size: 0.86rem;
480
+ line-height: 1.45;
481
+ }
482
+
483
+ .bai__info strong {
484
+ color: var(--bai-ink);
485
+ }
486
+
487
+ .bai__info--warning span,
488
+ .bai__info--warning strong {
489
+ color: var(--bai-amber);
490
+ }
491
+
492
+ @media (max-width: 420px) {
493
+ .bai__switch-row {
494
+ grid-template-columns: 1fr;
495
+ }
496
+
497
+ .bai__sex {
498
+ width: max-content;
499
+ }
500
+
501
+ .bai__scoreline {
502
+ grid-template-columns: 1fr;
503
+ justify-items: center;
504
+ gap: 0.15rem;
505
+ }
506
+ }
507
+
508
+ @media (min-width: 780px) {
509
+ .bai__workbench {
510
+ grid-template-columns: minmax(300px, 0.78fr) minmax(360px, 1fr);
511
+ }
512
+
513
+ .bai__controls {
514
+ border-right: 1px solid var(--bai-line);
515
+ border-bottom: 0;
516
+ }
517
+
518
+ .bai__result {
519
+ padding: clamp(1.25rem, 3vw, 2rem);
520
+ }
521
+
522
+ .bai__notes {
523
+ grid-template-columns: repeat(3, 1fr);
524
+ }
525
+
526
+ .bai__info {
527
+ border-right: 1px solid var(--bai-line);
528
+ border-bottom: 0;
529
+ }
530
+
531
+ .bai__info:last-child {
532
+ border-right: 0;
533
+ }
534
+ }
535
+
536
+ @keyframes bai-score-pop {
537
+ 0% { transform: translateY(0) scale(1); }
538
+ 45% { transform: translateY(-2px) scale(1.025); }
539
+ 100% { transform: translateY(0) scale(1); }
540
+ }
541
+
542
+ @keyframes bai-marker-settle {
543
+ 0% { transform: translate(-50%, -50%) scaleY(0.82); }
544
+ 55% { transform: translate(-50%, -50%) scaleY(1.08); }
545
+ 100% { transform: translate(-50%, -50%) scaleY(1); }
546
+ }
547
+