+ Neonatal Assessment + NRP + Apgar
+
+ {/* Assessment */}
+ Gestational age + size assessment (Fenton 2013)
+
+
GA weeks setWeeks(e.target.value)} data-testid="neo-weeks" />
+
GA days (0-6) setDays(e.target.value)} data-testid="neo-days" />
+
Birth wt (g) setWtG(e.target.value)} data-testid="neo-weight" />
+
Sex setSex(e.target.value as Sex)} data-testid="neo-sex">Male Female
+
+ {assess && (
+
+
+
Gestational Age
+
{assess.gaClass.label}
+
{weeksNum} wk {daysNum} d ({assess.gaDecimal.toFixed(1)} wk)
+
+
+
Weight for Gestational Age
+
{assess.weightClass.label}
+
{assess.percentile.toFixed(1)}th percentile · {assess.weightClass.detail}
+
+
+
Birth Weight Category
+
{assess.bwClass.label}
+
{wtNum} g ({(wtNum / 1000).toFixed(2)} kg)
+
+
+
Fenton ({sex})
+
+
Expected weight (M): {assess.expectedWeight} g
+
Z-score: {assess.z.toFixed(2)}
+
Percentile: {assess.percentile.toFixed(1)}%
+
+
+
+ )}
+
+ {/* NRP pathway */}
+ NRP pathway (AHA/AAP 8th ed 2020)
+
+
BIRTH — ASSESS (first 30 sec)
Term? Tone? Breathing/crying? All yes → routine care. Any no → warm, dry, stimulate, clear airway PRN, evaluate HR + resp.
+
HR <100 OR apneic/gasping (60 s)
Start PPV 40-60 breaths/min, room air for term / 21-30% for preterm. Attach SpO₂ (right hand) ± ECG. MR SOPA if ineffective.
+
HR <100 after 30 s effective PPV
Reassess ventilation — ensure chest rise. Consider increasing FiO₂, intubation, or LMA. Continue PPV.
+
HR <60 after 30 s effective PPV
Intubate + chest compressions — 3:1 ratio (90 compressions + 30 breaths/min), FiO₂ 100%, lower 1/3 sternum, depth 1/3 AP chest.
+
HR <60 despite compressions + PPV × 60 s
Epinephrine 1:10,000 (0.1 mg/mL): IV/IO 0.01-0.03 mg/kg (0.1-0.3 mL/kg) — preferred. ETT 0.05-0.1 mg/kg. Repeat q3-5 min. Hypovolemia: NS 10 mL/kg IV/IO over 5-10 min .
+
+
+
Target SpO₂ (preductal): 1 min 60-65% · 2 min 65-70% · 3 min 70-75% · 4 min 75-80% · 5 min 80-85% · 10 min 85-95%
+
Initial ETT size: <1 kg / <28 wk: 2.5 · 1-2 kg / 28-34 wk: 3.0 · 2-3 kg / 34-38 wk: 3.5 · >3 kg / >38 wk: 3.5-4.0
+
ETT depth (lip): ~6 + weight(kg) cm
+
+
+ NRP drug doses
+ Weight (kg) setKgForNrp(e.target.value)} data-testid="nrp-weight" />
+ {validKg ? (
+
+
} route="IV / IO" notes="Preferred route. Repeat q3-5 min." />
+
} route="ETT" notes="While IV being placed." />
+
} route="IV / IO" notes="Over 5-10 min for volume. Repeat PRN." />
+
} route="IV slow push" notes="For documented hypoglycemia. Then D10 infusion 4-6 mg/kg/min." />
+
+ ) : Enter weight (kg) to see NRP doses.
}
+
+ Concentration note: NRP uses epinephrine 1:10,000 (0.1 mg/mL). NOT 1:1000 (1 mg/mL) — that is IM for anaphylaxis / older patients.
+
+
+ {/* Apgar */}
+ Apgar score
+
+ {[
+ ['appearance', 'Appearance', ['Blue/pale', 'Body pink, extremities blue', 'All pink']],
+ ['pulse', 'Pulse', ['Absent', '<100 bpm', '≥100 bpm']],
+ ['grimace', 'Grimace', ['No response', 'Grimace', 'Cough/sneeze']],
+ ['activity', 'Activity', ['Limp', 'Some flexion', 'Active motion']],
+ ['respiration', 'Respiration', ['Absent', 'Slow/irregular', 'Good/crying']],
+ ].map(([key, lab, options]) => (
+
+ {lab}
+ setApgarScores({ ...apgarScores, [key as string]: Number(e.target.value) })} data-testid={'apgar-' + key}>
+ {(options as string[]).map((o, i) => {i} — {o} )}
+
+
+ ))}
+
+
+
Apgar: {apgarTotal}/10 — {apgarSeverity}
+
{apgarGuidance}
+
+
+ Fenton TR, Kim JH. BMC Pediatr 2013;13:59 · NRP 8th ed (AHA/AAP 2020) · Apgar is a description of status — never delay resuscitation while scoring.
+
+
+ );
+}
+
+// ── Respiratory ─────────────────────────────────────────────
+export function RespiratoryPanel() {
+ const [mode, setMode] = useState<'asthma' | 'pram' | 'croup' | 'bronch'>('asthma');
+ const [weight, setWeight] = useState('');
+ const wt = Number.parseFloat(weight);
+ const valid = Number.isFinite(wt) && wt > 0;
+ const f = (perKg: number, max: number | null, unit = 'mg') => (valid ? formatDose(wt, perKg, max, unit) : null);
+ const [asthmaSev, setAsthmaSev] = useState<'mild' | 'moderate' | 'severe' | null>(null);
+
+ // PRAM inputs (0-12 total)
+ const [pram, setPram] = useState({ spo2: 0, retractions: 0, scalene: 0, air: 0, wheeze: 0 });
+ const pramTotal = Object.values(pram).reduce((s, v) => s + v, 0);
+ const pramSev = pramTotal <= 3 ? 'Mild' : pramTotal <= 7 ? 'Moderate' : 'Severe';
+ const pramColor = pramTotal <= 3 ? 'text-green-600 bg-green-50' : pramTotal <= 7 ? 'text-amber-600 bg-amber-50' : 'text-destructive bg-red-50';
+
+ // Croup / Westley (0-17)
+ const [croup, setCroup] = useState({ conscious: 0, cyanosis: 0, stridor: 0, air: 0, retractions: 0 });
+ const croupTotal = Object.values(croup).reduce((s, v) => s + v, 0);
+ const croupSev = croupTotal <= 2 ? 'Mild' : croupTotal <= 5 ? 'Moderate' : croupTotal <= 11 ? 'Severe' : 'Impending Respiratory Failure';
+ const croupColor = croupTotal <= 2 ? 'text-green-600 bg-green-50' : croupTotal <= 5 ? 'text-amber-600 bg-amber-50' : croupTotal <= 11 ? 'text-destructive bg-red-50' : 'text-red-900 bg-red-100';
+
+ // Bronchiolitis inputs
+ const [bronch, setBronch] = useState({ age: 'gte12w', spo2: 'ok', hydration: 'ok', distress: 'mild' });
+ const bronchAdmit = bronch.distress === 'severe' || bronch.spo2 === 'low' || bronch.hydration === 'poor' || bronch.age === 'lt12w';
+
+ return (
+
+ Respiratory
+
+ {(['asthma', 'pram', 'croup', 'bronch'] as const).map((m) => (
+ setMode(m)} className={'px-3 py-1 rounded-full text-xs font-medium border ' + (mode === m ? 'bg-primary text-primary-foreground border-primary' : 'bg-muted border-border')} data-testid={'resp-mode-' + m}>
+ {m === 'asthma' ? 'Asthma' : m === 'pram' ? 'PRAM' : m === 'croup' ? 'Croup (Westley)' : 'Bronchiolitis'}
+
+ ))}
+
+
+ {mode !== 'pram' && mode !== 'bronch' && (
+ Weight (kg) setWeight(e.target.value)} data-testid="resp-weight" />
+ )}
+
+ {/* ASTHMA */}
+ {mode === 'asthma' && (
+ <>
+
+ {(['mild', 'moderate', 'severe'] as const).map((s) => (
+ setAsthmaSev(s)} className={'px-3 py-1 rounded text-xs font-medium border ' + (asthmaSev === s ? (s === 'mild' ? 'bg-green-600 text-white' : s === 'moderate' ? 'bg-amber-500 text-white' : 'bg-destructive text-white') : 'bg-muted')}>
+ {s.charAt(0).toUpperCase() + s.slice(1)}
+
+ ))}
+
+ {asthmaSev && !valid && Enter weight (kg) to see doses.
}
+ {asthmaSev === 'mild' && valid && (
+ <>
+ Speaks in sentences, no accessory muscle use, SpO₂ ≥94%
+
+
+
} route="Nebulized" notes="q20min × 3 doses" />
+
} route="PO/IV" notes="Single dose, or 2 days" />
+
} route="PO" notes="Alternative: 3-5 day course" />
+
+ >
+ )}
+ {asthmaSev === 'moderate' && valid && (
+ <>
+ Speaks in phrases, some accessory muscle use, SpO₂ 90-93%
+
+
} route="Nebulized" notes="q20min × 3 doses, then continuous if needed" />
+
+
} route="PO/IV/IM" notes="Single dose" />
+
+
+ >
+ )}
+ {asthmaSev === 'severe' && valid && (
+ <>
+ Speaks in words only, significant accessory muscle use, SpO₂ <90%. Consider ICU.
+
+
} route="Continuous neb" notes="Or 0.15-0.3 mg/kg q20min" />
+
+
} route="IV" notes="Or methylprednisolone 2 mg/kg IV (max 60 mg)" />
+
} route="IV" notes="Single dose, monitor BP" />
+
} route="IM" notes="If impending arrest / no IV access" />
+
} route="SC/IV" notes="Then 0.1-10 mcg/kg/min infusion" />
+
+
+
+ Continuous monitoring. Consider ICU admission. If no response to magnesium → terbutaline infusion. If impending respiratory failure → intubation (ketamine preferred induction agent).
+
+ >
+ )}
+ NAEPP/GINA guidelines. Always use clinical judgment.
+ >
+ )}
+
+ {/* PRAM */}
+ {mode === 'pram' && (
+ <>
+ Pediatric Respiratory Assessment Measure (PRAM) — for asthma exacerbation severity (0-12).
+
+ {[
+ ['spo2', 'SpO₂', ['≥95% (0)', '92-94% (1)', '<92% (2)']],
+ ['retractions', 'Suprasternal retractions', ['Absent (0)', 'Present (2)']],
+ ['scalene', 'Scalene muscle use', ['Absent (0)', 'Present (2)']],
+ ['air', 'Air entry', ['Normal (0)', 'Mild ↓ at bases (1)', 'Widespread ↓ (2)', 'Absent/minimal (3)']],
+ ['wheeze', 'Wheezing', ['Absent (0)', 'Expiratory only (1)', 'Ins+exp (2)', 'Audible without stethoscope/silent chest (3)']],
+ ].map(([key, lab, options]) => (
+
+ {lab}
+ setPram({ ...pram, [key as string]: Number(e.target.value) })} data-testid={'pram-' + key}>
+ {(options as string[]).map((o, i) => {o} )}
+
+
+ ))}
+
+
+
PRAM Score: {pramTotal}/12 — {pramSev}
+
Mild (0-3): outpatient management. Moderate (4-7): consider oral steroids + frequent bronchodilators. Severe (8-12): aggressive treatment, consider ICU.
+
+ >
+ )}
+
+ {/* CROUP */}
+ {mode === 'croup' && (
+ <>
+ Westley croup score (0-17).
+
+ {[
+ ['conscious', 'Level of consciousness', ['Normal (0)', 'Disoriented (5)']],
+ ['cyanosis', 'Cyanosis', ['None (0)', 'With agitation (4)', 'At rest (5)']],
+ ['stridor', 'Stridor', ['None (0)', 'With agitation (1)', 'At rest (2)']],
+ ['air', 'Air entry', ['Normal (0)', 'Decreased (1)', 'Severely decreased (2)']],
+ ['retractions', 'Retractions', ['None (0)', 'Mild (1)', 'Moderate (2)', 'Severe (3)']],
+ ].map(([key, lab, options]) => (
+
+ {lab}
+ setCroup({ ...croup, [key as string]: Number(e.target.value) })} data-testid={'croup-' + key}>
+ {(options as string[]).map((o, i) => {o} )}
+
+
+ ))}
+
+
+
Westley: {croupTotal}/17 — {croupSev}
+
Mild ≤2 · Moderate 3-5 · Severe 6-11 · Impending failure ≥12.
+
+ {valid && (
+
+
} route={croupTotal <= 2 ? 'PO' : croupTotal <= 5 ? 'PO/IM' : 'IV/IM'} notes="Preferred corticosteroid; single dose" />
+ {croupTotal > 2 &&
}
+ {croupTotal > 2 &&
}
+ {croupTotal > 5 &&
}
+
+ )}
+ >
+ )}
+
+ {/* BRONCHIOLITIS */}
+ {mode === 'bronch' && (
+ <>
+
+
Age setBronch({ ...bronch, age: e.target.value })}><12 weeks (high risk) ≥12 weeks
+
SpO₂ setBronch({ ...bronch, spo2: e.target.value })}>≥90% <90%
+
Hydration setBronch({ ...bronch, hydration: e.target.value })}>Adequate Poor oral intake
+
Distress setBronch({ ...bronch, distress: e.target.value })}>Mild Moderate Severe
+
+
+
{bronchAdmit ? 'Admit / Observe' : 'Likely Safe for Discharge'}
+ {bronch.age === 'lt12w' &&
⚠ Age <12 weeks — high risk for apnea. Monitor closely.
}
+
+
+ NOT recommended (AAP 2014/2023): Albuterol/salbutamol (no benefit), epinephrine (no evidence), systemic corticosteroids (no benefit), antibiotics (unless bacterial co-infection), chest physiotherapy.
+
+ AAP Clinical Practice Guideline: Management of Bronchiolitis in Infants and Children (2014, reaffirmed 2023). RSV most common (50-80%).
+ >
+ )}
+
+ );
+}
+
+// ── Ventilation (O₂ escalation + vent settings reference) ───
+export function VentilationPanel() {
+ const [weight, setWeight] = useState('');
+ const [age, setAge] = useState('');
+ const wt = Number.parseFloat(weight);
+ const ageY = Number.parseFloat(age);
+ const validWt = Number.isFinite(wt) && wt > 0;
+ const hfLow = validWt ? Math.round(wt * 1 * 10) / 10 : 0;
+ const hfHigh = validWt ? Math.round(wt * 2 * 10) / 10 : 0;
+ const tvLow = validWt ? Math.round(wt * 6 * 10) / 10 : 0;
+ const tvHigh = validWt ? Math.round(wt * 8 * 10) / 10 : 0;
+ const hasAge = Number.isFinite(ageY) && ageY >= 0;
+ const rate = hasAge
+ ? ageY < 0.1 ? '30-40'
+ : ageY < 1 ? '25-35'
+ : ageY < 5 ? '20-25'
+ : ageY < 12 ? '16-20'
+ : '12-16'
+ : '';
+
+ return (
+
+ O₂ & Ventilation
+
+
+ Target SpO₂
+
+
+
+
+
+
+
+
+ Escalation ladder
+
+
1. Nasal cannula (low-flow)
0.5-6 L/min · FiO₂ ~24-40% · comfortable, no humidification. Good for mild hypoxia.
+
2. Simple face mask
6-10 L/min · FiO₂ 35-60%. Must keep flow >6 L/min to flush CO₂.
+
3. Non-rebreather mask
10-15 L/min · FiO₂ 60-90%. Reservoir bag must stay inflated.
+
4. High-flow nasal cannula (HFNC)
{validWt ? `1-2 L/kg/min = ${hfLow}-${hfHigh} L/min` : '1-2 L/kg/min'} · heated + humidified · FiO₂ 30-100% titratable · generates ~2-5 cmH₂O PEEP. Reassess at 1-2 h.
+
5. Non-invasive (CPAP / BiPAP)
CPAP 5-10 cmH₂O · BiPAP IPAP 10-14 / EPAP 5. Needs cooperative patient, intact airway reflexes, no copious secretions.
+
6. Intubate + mechanical ventilation
When NIV fails, airway compromised, apnea, or GCS ≤8. See Airway tab for RSI drugs.
+
+
+ Bag-Valve-Mask (BVM)
+
+
When: apnea, bradycardia (HR <60 neonate; inadequate breathing at any age), during resuscitation.
+
Rate: Newborn 40-60/min · Infant-child 20-30/min · Adolescent 10-12/min (1 breath q5-6 sec).
+
Tidal volume: 6-8 mL/kg — gentle chest rise only. Avoid over-ventilation.
+
Technique: head tilt / jaw thrust, E-C or 2-thumb mask seal, squeeze 1 sec, release fully.
+
Not ventilating? MR SOPA — Mask reseal, Reposition airway, Suction, Open mouth, Pressure ↑, Alternative airway.
+
+
+ Mechanical vent — starting settings
+
+
Mode: Volume-control OR Pressure-control. PRVC / SIMV-PS hybrids.
+
Tidal volume: {validWt ? `${tvLow}-${tvHigh} mL` : '6-8 mL/kg'} (6-8 mL/kg). Use 4-6 mL/kg for ARDS.
+
Rate: {rate ? `${rate}/min (age ${ageY} yr)` : 'Newborn 30-40 · Infant 25-35 · Child 16-20 · Adolescent 12-16'}.
+
PEEP: start 5 cmH₂O. Increase to 8-12+ for refractory hypoxia.
+
FiO₂: start 100%, wean rapidly to lowest that maintains target SpO₂.
+
I:E ratio: 1:2 normally; 1:3-4 for obstructive disease.
+
Plateau pressure: keep <30 cmH₂O (ideally <28).
+
+
+ Adjusting for gas exchange
+
+
+
+
+
+
+
+
+ Mental model: Oxygenation is mostly FiO₂ + PEEP . Ventilation (CO₂) is mostly rate + tidal volume . Obstructive (asthma, bronchiolitis) → long expiratory time, permissive hypercapnia. Restrictive (ARDS) → low TV, high PEEP, permissive hypercapnia + hypoxia.
+
+ AAP / PALS / AARC guidance.
+
+ );
+}
+
+// ── Sepsis ──────────────────────────────────────────────────
+export function SepsisPanel() {
+ const [weight, setWeight] = useState('');
+ const [age, setAge] = useState<'neonate' | 'infant' | 'child'>('child');
+ const wt = Number.parseFloat(weight);
+ const valid = Number.isFinite(wt) && wt > 0;
+ const f = (perKg: number, max: number | null, unit = 'mg') => (valid ? formatDose(wt, perKg, max, unit) : null);
+ const ageLbl = age === 'neonate' ? 'Neonate (0-28 d)' : age === 'infant' ? 'Young infant (29 d - 3 mo)' : 'Older child / adolescent';
+ const bolus = valid ? Math.round(wt * 20) : null;
+
+ return (
+
+ Sepsis & Fever
+
+
Weight (kg) setWeight(e.target.value)} data-testid="sepsis-weight" />
+
Age band setAge(e.target.value as typeof age)} data-testid="sepsis-age">Neonate (0-28 d) Infant (29 d - 3 mo) Older child / adolescent
+
+
+
+ Sepsis approach — {ageLbl}{valid ? `, ${wt} kg` : ''}
+
+
+ Definition — Phoenix Sepsis Criteria (JAMA 2024)
+
+
Sepsis = suspected or confirmed infection + Phoenix Score ≥2 (organ dysfunction across respiratory, cardiovascular, coagulation, neurological).
+
Septic shock = sepsis + cardiovascular dysfunction (vasoactive support, or ↑lactate ≥5, or ↓MAP for age).
+
Previous SIRS-based criteria (Goldstein 2005) are now superseded.
+
+
+ Red flags
+
+ Abnormal behavior / mentation · Fever + ill-appearance · Tachycardia out of proportion to fever · Prolonged cap refill (>3 s) · Cold/mottled extremities · Weak pulses or wide pulse pressure ("warm shock") · Hypotension is a LATE sign · Any immune compromise / indwelling line.
+
+
+ Empirical therapy — {ageLbl}
+
+ {age === 'neonate' && <>Workup (full sepsis eval): CBC+diff, CRP, blood culture, UA+urine culture (cath), LP (CSF+HSV PCR), CXR if respiratory sx, procalcitonin. Early-onset (<72 h): GBS, E. coli, Listeria. Late-onset (>72 h): CoNS, S. aureus, gram-negs, Candida.>}
+ {age === 'infant' && <>Workup: Use validated rules — PECARN, Aronson, Rochester, Step-by-Step. CBC+ANC, procalcitonin/CRP, blood culture, UA+urine culture. Many warrant LP + admission + empiric abx. Coverage: GBS, E. coli, Listeria (up to ~6 wk), S. pneumo, N. meningitidis, H. flu, Salmonella.>}
+ {age === 'child' && <>Recognition: Phoenix score or clinical concern + suspected infection. Workup: CBC, CRP, procalcitonin, blood cx (+site-specific), lactate, blood gas, glucose, electrolytes, coags, LP if CNS concern. Source-directed imaging.>}
+
+
+ {valid && (
+
+ {age === 'neonate' && <>
+
} route="IV" notes="q8-12h. Covers GBS, Listeria, Enterococcus." />
+
} route="IV" notes="q24-48h. Monitor levels." />
+
} route="IV" notes="If meningitis or gram-neg concern." />
+
} route="IV q8h" notes="HSV risk: maternal lesions, vesicles, seizures, CSF pleocytosis." />
+ >}
+ {age === 'infant' && <>
+
} route="IV / IM" notes="q24h (100 mg/kg/day divided q12h for meningitis). Avoid <28 d if hyperbilirubinemia." />
+
} route="IV" notes="If <6 wk: add for Listeria coverage." />
+
} route="IV" notes="If severe / MRSA risk / meningitis." />
+
} route="IV q8h" notes="<6 wk with suspicion of HSV." />
+ >}
+ {age === 'child' && <>
+
} route="IV" notes="q24h (100 mg/kg/day divided for meningitis)." />
+
} route="IV" notes="q6h. If severe, indwelling line, or MRSA prevalence >10%." />
+
} route="IV" notes="If intra-abdominal / neutropenic." />
+
} route="IV" notes="Adjunct for toxic shock syndrome (toxin suppression)." />
+
} route="IV q8h" notes="If HSV CNS concern." />
+ >}
+
+ )}
+
+ First-hour bundle (SSC Peds 2020)
+
+
0-5 min — Recognize
Screen, sepsis huddle/activation, ABCs, O₂ to SpO₂ >94%, warm.
+
5-15 min — Access & labs
Two IVs or IO. Draw blood cx (ideally before abx), lactate, CBC, CMP, coags, blood gas, glucose. UA + culture. Source-specific cultures.
+
15-30 min — Fluids
{valid ? <>NS or LR {bolus} mL bolus (20 mL/kg) over 5-10 min.> : <>NS/LR 10-20 mL/kg bolus over 5-10 min.>} Reassess HR, perfusion, lungs, liver. Repeat up to 40-60 mL/kg; stop if crackles/hepatomegaly.
+
30-60 min — Antibiotics + reassess
Broad-spectrum empiric abx within 1 hour (≤1 h in septic shock). Recheck lactate, perfusion.
+
>60 min — Fluid-refractory shock
Start vasoactive (epinephrine 0.05-0.3 mcg/kg/min cold / norepinephrine 0.05-0.3 mcg/kg/min warm). Central/IO access. Stress-dose hydrocortisone {valid ? <>{f(2, 100)!.value} mg IV (2 mg/kg, max 100 mg)> : '2 mg/kg IV (max 100 mg)'} if catecholamine-resistant. ICU.
+
+
+ Resuscitation targets
+
+ Normal mentation · Cap refill ≤2 s · Warm extremities · Strong peripheral pulses · UOP ≥1 mL/kg/hr · MAP ≥5th %ile for age (>65 mmHg adolescent) · SpO₂ ≥94% · Lactate trending down.
+
+ Phoenix Sepsis Criteria (Schlapbach et al., JAMA 2024) · Surviving Sepsis Campaign Pediatric 2020 · AAP pediatric sepsis guidance.
+
+ );
+}
+
+// ── Burns ───────────────────────────────────────────────────
+// Lund-Browder age-adjusted region percentages ported VERBATIM from
+// public/js/bedside/burns.js:10-30.
+const LUND_BROWDER: Array<{ key: string; label: string; vals: [number, number, number, number, number]; ageSensitive?: boolean }> = [
+ { key: 'head', label: 'Head', vals: [18, 13, 11, 9, 7], ageSensitive: true },
+ { key: 'neck', label: 'Neck', vals: [2, 2, 2, 2, 2] },
+ { key: 'ant_trunk', label: 'Anterior trunk', vals: [13, 13, 13, 13, 13] },
+ { key: 'post_trunk', label: 'Posterior trunk', vals: [13, 13, 13, 13, 13] },
+ { key: 'r_buttock', label: 'Right buttock', vals: [2.5, 2.5, 2.5, 2.5, 2.5] },
+ { key: 'l_buttock', label: 'Left buttock', vals: [2.5, 2.5, 2.5, 2.5, 2.5] },
+ { key: 'genital', label: 'Genitalia', vals: [1, 1, 1, 1, 1] },
+ { key: 'r_uparm', label: 'R upper arm', vals: [4, 4, 4, 4, 4] },
+ { key: 'l_uparm', label: 'L upper arm', vals: [4, 4, 4, 4, 4] },
+ { key: 'r_forearm', label: 'R forearm', vals: [3, 3, 3, 3, 3] },
+ { key: 'l_forearm', label: 'L forearm', vals: [3, 3, 3, 3, 3] },
+ { key: 'r_hand', label: 'R hand', vals: [2.5, 2.5, 2.5, 2.5, 2.5] },
+ { key: 'l_hand', label: 'L hand', vals: [2.5, 2.5, 2.5, 2.5, 2.5] },
+ { key: 'r_thigh', label: 'R thigh', vals: [5.5, 8, 8.5, 9, 9.5], ageSensitive: true },
+ { key: 'l_thigh', label: 'L thigh', vals: [5.5, 8, 8.5, 9, 9.5], ageSensitive: true },
+ { key: 'r_leg', label: 'R lower leg', vals: [5, 5.5, 6, 6.5, 7], ageSensitive: true },
+ { key: 'l_leg', label: 'L lower leg', vals: [5, 5.5, 6, 6.5, 7], ageSensitive: true },
+ { key: 'r_foot', label: 'R foot', vals: [3.5, 3.5, 3.5, 3.5, 3.5] },
+ { key: 'l_foot', label: 'L foot', vals: [3.5, 3.5, 3.5, 3.5, 3.5] },
+];
+const AGE_BANDS: Array<{ id: 'infant' | 'young' | 'child' | 'adol' | 'adult'; label: string }> = [
+ { id: 'infant', label: 'Infant (<1 y)' },
+ { id: 'young', label: 'Young child (1-5 y)' },
+ { id: 'child', label: 'Child (5-10 y)' },
+ { id: 'adol', label: 'Adolescent (10-15 y)' },
+ { id: 'adult', label: 'Adult (>15 y)' },
+];
+
+export function BurnsPanel() {
+ const [weight, setWeight] = useState('');
+ const [ageBand, setAgeBand] = useState<'infant' | 'young' | 'child' | 'adol' | 'adult'>('young');
+ const [override, setOverride] = useState('');
+ const [pct, setPct] = useState