// ============================================================ // bedside/neonatal.js // NEONATAL ASSESSMENT (Fenton growth) + NRP pathway + Apgar. // ============================================================ import { S } from './shared.js'; // Fenton 2013 LMS data (weight in grams, GA in weeks). // // LMS parameters derived empirically from peditools.org/fenton2013 — // peditools is widely used and consistent with the published // Fenton TR, Kim JH. BMC Pediatrics 2013;13:59 reference. Each week's // triple was fit against 6 probe weights per week (RMSE < 0.005 z-score // units). Replaces an earlier hand-rounded table whose z-scores drifted // ~0.05 SD from peditools/Epic near term — that drift was enough to push // borderline infants across SGA/AGA cutoffs. // // Validated test cases: // 40 5/7 wk male, 3070g → z = -1.42 (Epic: -1.43, peditools: -1.42) var fentonLMS = { male: { 22:{L:0.5885,M:496,S:0.12802},23:{L:0.7565,M:571,S:0.14547},24:{L:0.9128,M:651,S:0.16235},25:{L:1.0544,M:741,S:0.17765}, 26:{L:1.1862,M:841,S:0.19029},27:{L:1.3051,M:953,S:0.19989},28:{L:1.3699,M:1079,S:0.20777},29:{L:1.4165,M:1223,S:0.21163}, 30:{L:1.4172,M:1388,S:0.21185},31:{L:1.3755,M:1578,S:0.20785},32:{L:1.2952,M:1790,S:0.20112},33:{L:1.1974,M:2018,S:0.19143}, 34:{L:1.0743,M:2255,S:0.18119},35:{L:0.9583,M:2493,S:0.16992},36:{L:0.8460,M:2726,S:0.16001},37:{L:0.7543,M:2947,S:0.15072}, 38:{L:0.6650,M:3156,S:0.14304},39:{L:0.5881,M:3360,S:0.13641},40:{L:0.5237,M:3568,S:0.13173},41:{L:0.4691,M:3785,S:0.12863}, 42:{L:0.4216,M:4014,S:0.12735} }, female: { 22:{L:-0.0868,M:481,S:0.13605},23:{L:0.2119,M:537,S:0.14635},24:{L:0.5281,M:606,S:0.16134},25:{L:0.8258,M:694,S:0.18077}, 26:{L:1.0501,M:792,S:0.19889},27:{L:1.2084,M:899,S:0.21323},28:{L:1.2599,M:1017,S:0.22437},29:{L:1.2539,M:1152,S:0.22982}, 30:{L:1.2262,M:1306,S:0.23082},31:{L:1.1223,M:1482,S:0.22733},32:{L:1.0122,M:1681,S:0.21846},33:{L:0.8746,M:1897,S:0.20681}, 34:{L:0.7299,M:2126,S:0.19407},35:{L:0.5929,M:2362,S:0.18059},36:{L:0.4534,M:2602,S:0.17028},37:{L:0.3462,M:2835,S:0.16139}, 38:{L:0.2636,M:3050,S:0.15513},39:{L:0.2069,M:3239,S:0.15004},40:{L:0.1670,M:3415,S:0.14649},41:{L:0.1517,M:3596,S:0.14359}, 42:{L:0.1308,M:3787,S:0.14127} } }; function interpolateLMS(table, val) { var keys = Object.keys(table).map(Number).sort(function(a,b){return a-b;}); if (val <= keys[0]) return table[keys[0]]; if (val >= keys[keys.length-1]) return table[keys[keys.length-1]]; for (var i = 0; i < keys.length - 1; i++) { if (val >= keys[i] && val <= keys[i+1]) { var t = (val - keys[i]) / (keys[i+1] - keys[i]); var a = table[keys[i]], b = table[keys[i+1]]; return { L: a.L + t*(b.L-a.L), M: a.M + t*(b.M-a.M), S: a.S + t*(b.S-a.S) }; } } return table[keys[0]]; } function calcZ(value, L, M, S) { if (Math.abs(L) < 0.001) return Math.log(value / M) / S; return (Math.pow(value / M, L) - 1) / (L * S); } function zToPercentile(z) { // Approximation of the standard normal CDF var a1=0.254829592, a2=-0.284496736, a3=1.421413741, a4=-1.453152027, a5=1.061405429, p=0.3275911; var sign = z < 0 ? -1 : 1; var x = Math.abs(z) / Math.sqrt(2); var t = 1 / (1 + p * x); var y = 1 - (((((a5*t + a4)*t) + a3)*t + a2)*t + a1)*t * Math.exp(-x*x); return Math.round(((1 + sign * y) / 2) * 1000) / 10; } function classifyGA(weeks, days) { var total = weeks + (days || 0) / 7; if (total < 28) return { label: 'Extremely Preterm', color: '#dc2626', icon: 'fa-triangle-exclamation' }; if (total < 32) return { label: 'Very Preterm', color: '#ea580c', icon: 'fa-triangle-exclamation' }; if (total < 34) return { label: 'Moderate Preterm', color: '#d97706', icon: 'fa-circle-exclamation' }; if (total < 37) return { label: 'Late Preterm', color: '#ca8a04', icon: 'fa-circle-info' }; if (total < 39) return { label: 'Early Term', color: '#2563eb', icon: 'fa-circle-info' }; if (total < 41) return { label: 'Full Term', color: '#16a34a', icon: 'fa-circle-check' }; if (total < 42) return { label: 'Late Term', color: '#d97706', icon: 'fa-circle-info' }; return { label: 'Post Term', color: '#dc2626', icon: 'fa-triangle-exclamation' }; } function classifyWeight(percentile) { if (percentile < 3) return { label: 'Severely SGA', color: '#dc2626', detail: '<3rd percentile' }; if (percentile < 10) return { label: 'SGA', color: '#ea580c', detail: '<10th percentile' }; if (percentile > 97) return { label: 'Severely LGA', color: '#dc2626', detail: '>97th percentile' }; if (percentile > 90) return { label: 'LGA', color: '#ea580c', detail: '>90th percentile' }; return { label: 'AGA', color: '#16a34a', detail: '10th-90th percentile' }; } function classifyBirthWeight(grams) { if (grams < 1000) return { label: 'Extremely Low Birth Weight (ELBW)', color: '#dc2626' }; if (grams < 1500) return { label: 'Very Low Birth Weight (VLBW)', color: '#ea580c' }; if (grams < 2500) return { label: 'Low Birth Weight (LBW)', color: '#d97706' }; if (grams <= 4000) return { label: 'Normal Birth Weight', color: '#16a34a' }; return { label: 'Macrosomia (>4000g)', color: '#ea580c' }; } function neoAssess() { var weeks = parseInt(document.getElementById('neo-ga-weeks').value); var days = parseInt(document.getElementById('neo-ga-days').value) || 0; var weight = parseFloat(document.getElementById('neo-weight').value); var sex = document.getElementById('neo-sex').value; var resultDiv = document.getElementById('neo-result'); if (!weeks || !weight) { resultDiv.innerHTML = '
Enter GA and birth weight.
'; return; } var gaDecimal = weeks + days / 7; var gaClass = classifyGA(weeks, days); var bwClass = classifyBirthWeight(weight); // Calculate percentile using Fenton LMS var lms = interpolateLMS(fentonLMS[sex], gaDecimal); var z = calcZ(weight, lms.L, lms.M, lms.S); var percentile = zToPercentile(z); var wtClass = classifyWeight(percentile); var expectedWeight = Math.round(lms.M); var html = ''; // GA Classification html += 'Fenton TR, Kim JH. A systematic review and meta-analysis to revise the Fenton growth chart for preterm infants. BMC Pediatrics 2013;13:59. GA classification per ACOG/AAP definitions.
'; resultDiv.innerHTML = html; } // ---- NRP pathway + drug calc ----------------------------------------- function renderPathway() { var el = document.getElementById('nrp-pathway-static'); if (!el || el.dataset.rendered) return; var html = ''; html += S.stepBox('#3b82f6', 'BIRTH — ASSESS (first 30 sec)', 'Term? Tone? Breathing/crying? If all yes → routine care with mother. If any no → warm, dry, stimulate, position airway, clear airway PRN, evaluate HR & respirations.'); html += S.arrow; html += S.stepBox('#8b5cf6', 'HR < 100 OR apneic/gasping (60 sec)', 'Start PPV 40-60 breaths/min, room air for term / 21-30% for preterm. Attach SpO2 (right hand) ± ECG. MR SOPA if ineffective: Mask adjust, Reposition, Suction, Open mouth, Pressure increase, Alternative airway.'); html += S.arrow; html += S.stepBox('#f59e0b', 'HR < 100 after 30 sec effective PPV', 'Reassess ventilation — ensure chest rise. Consider increasing FiO2, intubation, or LMA. Continue PPV.'); html += S.arrow; html += S.stepBox('#ef4444', 'HR < 60 after 30 sec of effective PPV', 'Intubate + Chest compressions — 3:1 ratio (90 compressions + 30 breaths per minute), FiO2 100%, lower 1/3 sternum, depth 1/3 AP chest.'); html += S.arrow; html += S.stepBox('#dc2626', 'HR < 60 despite compressions + PPV x 60 sec', 'Epinephrine 1:10,000 (0.1 mg/mL):Enter weight (kg).
'; return; } var epiIvLow = Math.round(wt * 0.01 * 100) / 100; var epiIvHigh = Math.round(wt * 0.03 * 100) / 100; var epiEtLow = Math.round(wt * 0.05 * 100) / 100; var epiEtHigh = Math.round(wt * 0.1 * 100) / 100; var ns = Math.round(wt * 10); var d10 = Math.round(wt * 2 * 10) / 10; var html = 'Apgar is a description of status — never delay resuscitation while scoring. Follow NRP algorithm based on HR and breathing. Apgar <7 at 5 min: repeat q5 min up to 20 min.
'; el.innerHTML = html; } export function init() { // Neonatal assessment document.addEventListener('click', function(e) { if (e.target.id === 'btn-neo-assess' || e.target.closest('#btn-neo-assess')) neoAssess(); }); // NRP pathway render + calc document.addEventListener('DOMContentLoaded', renderPathway); document.addEventListener('tabChanged', function() { setTimeout(renderPathway, 100); }); if (document.readyState !== 'loading') setTimeout(renderPathway, 0); document.addEventListener('click', function(e) { if (e.target.id === 'btn-nrp-calc' || e.target.closest('#btn-nrp-calc')) calcNRP(); // Render NRP pathway when Neonatal sub-pill is clicked (in case component loaded late) var np = e.target.closest && e.target.closest('[data-em="neonatal"]'); if (np) setTimeout(renderPathway, 0); var nav = e.target.closest && e.target.closest('[data-calc="bedside"]'); if (nav) setTimeout(renderPathway, 50); }); // Apgar document.addEventListener('click', function(e) { if (e.target.id === 'btn-apgar-calc' || e.target.closest('#btn-apgar-calc')) calcApgar(); }); }