diff --git a/.gitignore b/.gitignore
index 723bf9f..e224646 100644
--- a/.gitignore
+++ b/.gitignore
@@ -3,6 +3,7 @@ node_modules/
.env.local
.env.production
data/
+!public/data/
*.db
*.db-journal
*.db-wal
diff --git a/public/data/drugs.json b/public/data/drugs.json
new file mode 100644
index 0000000..0c888ed
--- /dev/null
+++ b/public/data/drugs.json
@@ -0,0 +1,498 @@
+{
+ "version": "1.0",
+ "last_reviewed": "2026-04-20",
+ "sections": {
+ "anaphylaxis": {
+ "drugs": [
+ {
+ "name": "Epinephrine IM",
+ "dose_mg_per_kg": 0.01,
+ "max_mg": 0.5,
+ "unit": "mg",
+ "route": "IM",
+ "notes": "1:1000 (1 mg/mL), lateral thigh. May repeat q5-15 min.",
+ "concentration": "1:1000",
+ "source": "ASCIA 2021"
+ },
+ {
+ "name": "Normal saline bolus",
+ "dose_mg_per_kg": 20,
+ "max_mg": null,
+ "unit": "mL",
+ "route": "IV/IO",
+ "notes": "Repeat up to 60 mL/kg for hypotension",
+ "source": "ASCIA 2021"
+ },
+ {
+ "name": "Diphenhydramine",
+ "dose_mg_per_kg": 1.25,
+ "max_mg": 50,
+ "unit": "mg",
+ "route": "IV/IM/PO",
+ "notes": "H1 blocker. NOT first-line — adjunct only",
+ "source": "AAP/ACAAI"
+ },
+ {
+ "name": "Ranitidine",
+ "dose_mg_per_kg": 1,
+ "max_mg": 50,
+ "unit": "mg",
+ "route": "IV over 5 min",
+ "notes": "H2 blocker. Optional adjunct",
+ "source": "AAP/ACAAI"
+ },
+ {
+ "name": "Dexamethasone",
+ "dose_mg_per_kg": 0.6,
+ "max_mg": 16,
+ "unit": "mg",
+ "route": "IV/IM/PO",
+ "notes": "Prevents biphasic reaction (4-6 hrs later)",
+ "source": "AAP/ACAAI"
+ },
+ {
+ "name": "Methylprednisolone",
+ "dose_mg_per_kg": 2,
+ "max_mg": 125,
+ "unit": "mg",
+ "route": "IV",
+ "notes": "Alternative steroid",
+ "source": "AAP/ACAAI"
+ },
+ {
+ "name": "Glucagon",
+ "dose_mg_per_kg": 0.02,
+ "max_mg": 1,
+ "unit": "mg",
+ "route": "IV/IM",
+ "notes": "For patients on beta-blockers not responding to epi",
+ "source": "ASCIA 2021"
+ }
+ ]
+ },
+ "sedation": {
+ "drugs": [
+ {
+ "name": "Ketamine IV",
+ "display": "Ketamine",
+ "dose_mg_per_kg_low": 1.5,
+ "dose_mg_per_kg_high": 2,
+ "max_mg_low": 100,
+ "max_mg_high": 150,
+ "unit": "mg",
+ "route": "IV",
+ "onset": "1 min",
+ "duration": "15-30 min",
+ "notes": "Dissociative. Preserves airway reflexes.",
+ "source": "AAP sedation guideline"
+ },
+ {
+ "name": "Ketamine IM",
+ "display": "",
+ "dose_mg_per_kg_low": 4,
+ "dose_mg_per_kg_high": 5,
+ "max_mg_low": 300,
+ "max_mg_high": 400,
+ "unit": "mg",
+ "route": "IM",
+ "onset": "3-5 min",
+ "duration": "30-60 min",
+ "notes": "Give atropine 0.01 mg/kg to reduce secretions.",
+ "source": "AAP sedation guideline"
+ },
+ {
+ "name": "Midazolam IV",
+ "display": "Midazolam",
+ "dose_mg_per_kg_low": 0.05,
+ "dose_mg_per_kg_high": 0.1,
+ "max_mg_low": 2,
+ "max_mg_high": 5,
+ "unit": "mg",
+ "route": "IV",
+ "onset": "2-3 min",
+ "duration": "30-60 min",
+ "notes": "Anxiolysis. Titrate q3-5 min.",
+ "source": "AAP sedation guideline"
+ },
+ {
+ "name": "Midazolam IN/PO",
+ "display": "",
+ "dose_mg_per_kg": 0.5,
+ "max_mg": 20,
+ "unit": "mg",
+ "route": "IN/PO",
+ "onset": "10-15 min",
+ "duration": "30-60 min",
+ "notes": "IN (max 10 mg / naris) or PO (max 20 mg).",
+ "source": "AAP sedation guideline"
+ },
+ {
+ "name": "Propofol",
+ "display": "Propofol",
+ "dose_mg_per_kg": 1,
+ "max_mg": 40,
+ "unit": "mg",
+ "route": "IV",
+ "onset": "30 sec",
+ "duration": "5-10 min",
+ "notes": "Short procedures. Causes apnea — manage airway.",
+ "source": "AAP sedation guideline"
+ },
+ {
+ "name": "Fentanyl IV",
+ "display": "Fentanyl",
+ "dose_mg_per_kg": 1,
+ "max_mg": 100,
+ "unit": "mcg",
+ "route": "IV",
+ "onset": "2-3 min",
+ "duration": "30-60 min",
+ "notes": "Analgesic. Often combined with midazolam.",
+ "source": "AAP sedation guideline"
+ },
+ {
+ "name": "Fentanyl IN",
+ "display": "",
+ "dose_mg_per_kg": 2,
+ "max_mg": 100,
+ "unit": "mcg",
+ "route": "IN",
+ "onset": "5-10 min",
+ "duration": "30-60 min",
+ "notes": "Intranasal.",
+ "source": "AAP sedation guideline"
+ },
+ {
+ "name": "Nitrous oxide",
+ "display": "Nitrous oxide",
+ "dose_mg_per_kg": null,
+ "max_mg": null,
+ "unit": "mix",
+ "dose_display": "50:50 or 70:30 mix",
+ "route": "Inhaled",
+ "onset": "2-5 min",
+ "duration": "5 min off",
+ "notes": "Self-administered via demand valve. Anxiolysis + mild analgesia.",
+ "source": "AAP sedation guideline"
+ },
+ {
+ "name": "Dexmedetomidine IN",
+ "display": "Dexmedetomidine",
+ "dose_mg_per_kg_low": 2,
+ "dose_mg_per_kg_high": 3,
+ "max_mg_low": 100,
+ "max_mg_high": null,
+ "unit": "mcg",
+ "route": "IN",
+ "onset": "15-30 min",
+ "duration": "60-90 min",
+ "notes": "Intranasal. No respiratory depression. Good for imaging.",
+ "source": "AAP sedation guideline"
+ },
+ {
+ "name": "Naloxone",
+ "display": "Naloxone",
+ "dose_mg_per_kg": 0.1,
+ "max_mg": 2,
+ "unit": "mg",
+ "route": "IV/IM/IN",
+ "reverses": "Opioids (fentanyl, morphine)",
+ "notes": "Max 2 mg. Repeat q2-3 min. Duration shorter than opioids — monitor for re-sedation.",
+ "source": "AAP sedation guideline"
+ },
+ {
+ "name": "Flumazenil",
+ "display": "Flumazenil",
+ "dose_mg_per_kg": 0.01,
+ "max_mg": 0.2,
+ "unit": "mg",
+ "route": "IV",
+ "reverses": "Benzodiazepines (midazolam)",
+ "notes": "Max 0.2 mg single dose. Repeat q1 min to max 1 mg total. Risk of seizures — use cautiously.",
+ "source": "AAP sedation guideline"
+ }
+ ]
+ },
+ "agitation": {
+ "drugs": [
+ {
+ "name": "Lorazepam PO",
+ "display": "Lorazepam",
+ "step": 2,
+ "dose_mg_per_kg": 0.05,
+ "max_mg": 2,
+ "unit": "mg",
+ "route": "PO",
+ "notes": "0.05 mg/kg. May repeat in 30 min.",
+ "source": "AAP/ACEP agitation"
+ },
+ {
+ "name": "Midazolam PO",
+ "display": "Midazolam",
+ "step": 2,
+ "dose_mg_per_kg": 0.5,
+ "max_mg": 10,
+ "unit": "mg",
+ "route": "PO",
+ "notes": "0.5 mg/kg (max 10 mg)",
+ "source": "AAP/ACEP agitation"
+ },
+ {
+ "name": "Midazolam IN",
+ "display": "Midazolam",
+ "step": 2,
+ "dose_mg_per_kg": 0.3,
+ "max_mg": 10,
+ "unit": "mg",
+ "route": "IN (5 mg/mL)",
+ "notes": "0.3 mg/kg split between nares (max 10 mg)",
+ "source": "AAP/ACEP agitation"
+ },
+ {
+ "name": "Olanzapine (ODT)",
+ "display": "Olanzapine (ODT)",
+ "step": 2,
+ "dose_mg_per_kg": null,
+ "max_mg": null,
+ "unit": "mg",
+ "route": "PO / ODT",
+ "dose_display_if_under_30kg": "2.5-5 mg",
+ "dose_display_if_30kg_or_more": "5-10 mg",
+ "notes": "Age ≥6 yr. Avoid IM + benzo combo (risk of resp depression).",
+ "source": "AAP/ACEP agitation"
+ },
+ {
+ "name": "Diphenhydramine PO",
+ "display": "Diphenhydramine",
+ "step": 2,
+ "dose_mg_per_kg": 1,
+ "max_mg": 50,
+ "unit": "mg",
+ "route": "PO",
+ "notes": "1 mg/kg. Adjunct only; sedating.",
+ "source": "AAP/ACEP agitation"
+ },
+ {
+ "name": "Midazolam IV/IM",
+ "display": "Midazolam",
+ "step": 3,
+ "dose_mg_per_kg": 0.1,
+ "max_mg": 5,
+ "unit": "mg",
+ "route": "IV / IM",
+ "notes": "0.05-0.1 mg/kg IV, 0.1-0.15 mg/kg IM (max 10 mg)",
+ "source": "AAP/ACEP agitation"
+ },
+ {
+ "name": "Lorazepam IV/IM",
+ "display": "Lorazepam",
+ "step": 3,
+ "dose_mg_per_kg": 0.1,
+ "max_mg": 4,
+ "unit": "mg",
+ "route": "IV / IM",
+ "notes": "0.05-0.1 mg/kg (max 4 mg). May cause resp depression.",
+ "source": "AAP/ACEP agitation"
+ },
+ {
+ "name": "Haloperidol",
+ "display": "Haloperidol",
+ "step": 3,
+ "dose_mg_per_kg": 0.05,
+ "max_mg": null,
+ "unit": "mg",
+ "route": "IM / IV",
+ "dose_display_if_under_40kg": "0.025-0.075 mg/kg",
+ "dose_display_if_40kg_or_more": "2.5-5 mg",
+ "notes": "Avoid <3 yr. Risk: QT, EPS, NMS. ECG if repeated.",
+ "source": "AAP/ACEP agitation"
+ },
+ {
+ "name": "Olanzapine IM",
+ "display": "Olanzapine",
+ "step": 3,
+ "dose_mg_per_kg": null,
+ "max_mg": null,
+ "unit": "mg",
+ "route": "IM",
+ "dose_display_if_under_40kg": "2.5-5 mg",
+ "dose_display_if_40kg_or_more": "5-10 mg",
+ "notes": "Avoid benzo co-administration (resp depression, hypotension)",
+ "source": "AAP/ACEP agitation"
+ },
+ {
+ "name": "Ketamine IM",
+ "display": "Ketamine",
+ "step": 3,
+ "dose_mg_per_kg": 4,
+ "max_mg": 500,
+ "unit": "mg",
+ "route": "IM",
+ "notes": "4-5 mg/kg IM (rescue for severe excited delirium). Monitor airway.",
+ "source": "AAP/ACEP agitation"
+ },
+ {
+ "name": "Droperidol",
+ "display": "Droperidol",
+ "step": 3,
+ "dose_mg_per_kg": 0.05,
+ "max_mg": null,
+ "unit": "mg",
+ "route": "IM / IV",
+ "dose_display_prefix": "0.03-0.07 mg/kg",
+ "notes": "Effective but QT concern — get ECG.",
+ "source": "AAP/ACEP agitation"
+ }
+ ]
+ },
+ "antiemetics": {
+ "drugs": [
+ {
+ "name": "Ondansetron",
+ "dose_mg_per_kg": 0.15,
+ "max_mg": 8,
+ "unit": "mg",
+ "route": "PO / ODT / IV",
+ "weight_band_dose": {
+ "under_15kg": "2 mg",
+ "15_to_30kg": "4 mg",
+ "30kg_or_more": "8 mg"
+ },
+ "notes": "First-line. Max single 8 mg. Repeat q8h. QT prolongation — avoid with other QT drugs. <6 mo: limited data.",
+ "source": "AAP gastroenteritis; Lexicomp"
+ },
+ {
+ "name": "Metoclopramide",
+ "dose_mg_per_kg": 0.15,
+ "max_mg": 10,
+ "unit": "mg",
+ "route": "IV / IM / PO",
+ "notes": "0.1-0.15 mg/kg (max 10 mg). Give with diphenhydramine to prevent EPS / dystonia.",
+ "source": "Lexicomp"
+ },
+ {
+ "name": "Dimenhydrinate",
+ "dose_mg_per_kg": 1.25,
+ "max_mg": 50,
+ "unit": "mg",
+ "route": "PO / IV / IM / PR",
+ "notes": "1.25 mg/kg (max 50 mg) q6h. ≥2 yr.",
+ "source": "Lexicomp"
+ },
+ {
+ "name": "Diphenhydramine",
+ "dose_mg_per_kg": 1,
+ "max_mg": 50,
+ "unit": "mg",
+ "route": "PO / IV / IM",
+ "notes": "1 mg/kg (max 50 mg) q6h. Adjunct, sedating.",
+ "source": "Lexicomp"
+ },
+ {
+ "name": "Promethazine",
+ "dose_mg_per_kg": 0.25,
+ "max_mg": 25,
+ "unit": "mg",
+ "route": "PO / IV / IM",
+ "notes": "0.25-1 mg/kg. CONTRAINDICATED <2 yr (resp depression). Tissue injury if IV extrav.",
+ "source": "Lexicomp"
+ },
+ {
+ "name": "Dexamethasone",
+ "dose_mg_per_kg": 0.15,
+ "max_mg": 10,
+ "unit": "mg",
+ "route": "IV / PO",
+ "notes": "Adjunct, esp. chemo-induced. 0.15 mg/kg (max 10 mg).",
+ "source": "Lexicomp"
+ },
+ {
+ "name": "Scopolamine patch",
+ "dose_mg_per_kg": null,
+ "max_mg": null,
+ "unit": "mg",
+ "dose_display": "1.5 mg patch",
+ "route": "Transdermal",
+ "notes": "≥12 yr. Motion sickness. Apply 4h before exposure.",
+ "source": "Lexicomp"
+ }
+ ]
+ },
+ "seizure": {
+ "drugs": [
+ {
+ "name": "Lorazepam",
+ "phase": "1st benzo",
+ "dose_mg_per_kg": 0.1,
+ "max_mg": 4,
+ "unit": "mg",
+ "route": "IV / IO",
+ "label_suffix": " (IV preferred)",
+ "notes": "Slow push over 1-2 min.",
+ "source": "AES 2016; ESETT 2019"
+ },
+ {
+ "name": "Midazolam",
+ "phase": "1st benzo",
+ "dose_mg_per_kg": 0.2,
+ "max_mg": 10,
+ "unit": "mg",
+ "route": "IM / IN / buccal",
+ "notes": "Use 5 mg/mL concentrate for IN; split between nares.",
+ "source": "AES 2016; ESETT 2019"
+ },
+ {
+ "name": "Diazepam",
+ "phase": "1st benzo",
+ "dose_mg_per_kg": 0.5,
+ "max_mg": 20,
+ "unit": "mg",
+ "route": "PR",
+ "notes": "Only if no IV/IM/IN access.",
+ "source": "AES 2016"
+ },
+ {
+ "name": "Levetiracetam",
+ "phase": "2nd-line",
+ "dose_mg_per_kg": 60,
+ "max_mg": 4500,
+ "unit": "mg",
+ "route": "IV over 5-15 min",
+ "label_suffix": " (preferred)",
+ "notes": "Best tolerability. No ECG monitoring needed.",
+ "source": "ESETT 2019"
+ },
+ {
+ "name": "Fosphenytoin",
+ "phase": "2nd-line",
+ "dose_mg_per_kg": 20,
+ "max_mg": 1500,
+ "unit": "mg PE",
+ "route": "IV over 10 min",
+ "notes": "Max rate 3 mg PE/kg/min. Monitor ECG, BP. Avoid if cardiac dysrhythmia.",
+ "source": "ESETT 2019"
+ },
+ {
+ "name": "Valproic acid",
+ "phase": "2nd-line",
+ "dose_mg_per_kg": 40,
+ "max_mg": 3000,
+ "unit": "mg",
+ "route": "IV over 10 min",
+ "notes": "Avoid <2 yr, hepatic / mitochondrial disease, pregnancy.",
+ "source": "ESETT 2019"
+ },
+ {
+ "name": "Phenobarbital",
+ "phase": "2nd-line",
+ "dose_mg_per_kg": 20,
+ "max_mg": 1000,
+ "unit": "mg",
+ "route": "IV over 20 min",
+ "notes": "Last-choice 2nd line. High risk of resp depression + hypotension.",
+ "source": "AES 2016"
+ }
+ ]
+ }
+ }
+}
diff --git a/public/e2e-harness.html b/public/e2e-harness.html
index e1aa96b..d109f19 100644
--- a/public/e2e-harness.html
+++ b/public/e2e-harness.html
@@ -16,6 +16,7 @@
+