pediatric-ai-scribe-v3/public/js/calculators.js
Daniel 2a2787c26d feat: Bedside clinical reference module + age→weight estimator + dose-math unit tests
Calculators:
- Bedside tab consolidating emergency protocols (Neonatal+Apgar+NRP, Airway/RSI,
  Cardiac Arrest/PALS, Respiratory, O2 & Ventilation, Status Epilepticus,
  Sepsis & Fever with PECARN/Aronson/Rochester/Step-by-Step, Anaphylaxis,
  Procedural Sedation, Agitation, Antiemetics, Antimicrobials, Burns with
  Lund-Browder body-parts TBSA + Parkland, Toxicology, Trauma).
- Global age→weight estimator at top of Calculators tab (APLS + Best Guess).
- Pressure-time waveform SVG teaching graphic for Ventilation.
- Algorithm image lightbox (fullscreen, Esc/tap-to-close).
- Every weight-based dose shows mg/kg inline for clinician verification.
- Drug tables wrapped in overflow-x:auto for mobile.

Infrastructure:
- Pure dose math extracted to public/js/calc-math.js (dual-export Node+browser).
- 36 unit tests in test/calc-math.test.js via node:test (zero new deps).
- "npm test" added to package.json.
2026-04-20 02:49:42 +02:00

3921 lines
323 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// ============================================================
// CALCULATORS.JS — Pediatric clinical calculators
// ============================================================
(function() {
var _inited = false;
document.addEventListener('tabChanged', function(e) {
if (e.detail.tab !== 'calculators' || _inited) return;
_inited = true;
initCalculators();
});
// ── Flexible age parser ─────────────────────────────────────────────
// Accepts: "3y", "3 years", "29m", "29 months", "2y5m", "2 years 5 months",
// "15d", "15 days", "3y 2m 10d", "36" (months), "3.5 years", etc.
// Returns age in months (may be fractional), or null if unparseable.
function parseAgeMonths(input) {
if (input == null) return null;
var s = String(input).toLowerCase().trim();
if (!s) return null;
// Plain number with no unit: if >= 24 assume years, else months. Matches
// common shorthand ("36" for 3y, "6" for 6 months).
if (/^[\d.]+$/.test(s)) {
var n = parseFloat(s);
if (isNaN(n)) return null;
return n >= 24 ? n : n; // keep as months; user can add unit if they meant years
}
var total = 0;
var matched = false;
// Use (?![a-z]) instead of \b so "2y5m" terminates "y" correctly.
// Order matters: longest-first alternations (years before yrs before y, etc.).
var my = s.match(/([\d.]+)\s*(?:years|year|yrs|yr|y)(?![a-z])/);
if (my) { total += parseFloat(my[1]) * 12; matched = true; }
var mm = s.match(/([\d.]+)\s*(?:months|month|mos|mo|m)(?![a-z])/);
if (mm) { total += parseFloat(mm[1]); matched = true; }
var mw = s.match(/([\d.]+)\s*(?:weeks|week|wks|wk|w)(?![a-z])/);
if (mw) { total += parseFloat(mw[1]) * 7 / 30.4375; matched = true; }
var md = s.match(/([\d.]+)\s*(?:days|day|d)(?![a-z])/);
if (md) { total += parseFloat(md[1]) / 30.4375; matched = true; }
return matched ? total : null;
}
function formatParsedAge(months) {
if (months < 1) {
var d = Math.round(months * 30.4375);
return '= ' + d + ' day' + (d === 1 ? '' : 's') + ' (' + months.toFixed(2) + ' mo)';
}
if (months < 24) {
return '= ' + (Math.round(months * 10) / 10) + ' months';
}
var yr = Math.floor(months / 12);
var mo = Math.round(months - yr * 12);
if (mo === 12) { yr += 1; mo = 0; }
return '= ' + yr + ' yr' + (mo ? ' ' + mo + ' mo' : '') + ' (' + Math.round(months) + ' mo total)';
}
// Expose for debugging / other modules
window._parseAgeMonths = parseAgeMonths;
function initCalculators() {
// ── Top-level pill navigation (scoped to .calc-nav-pill only) ──
document.querySelectorAll('.calc-nav-pill').forEach(function(pill) {
pill.addEventListener('click', function() {
document.querySelectorAll('.calc-nav-pill').forEach(function(p) { p.classList.remove('active'); });
document.querySelectorAll('.calc-panel').forEach(function(p) { p.classList.add('hidden'); });
pill.classList.add('active');
var panel = document.getElementById('calc-' + pill.dataset.calc);
if (panel) panel.classList.remove('hidden');
});
});
// ═══════════════════════════════════════════════════════════
// BP PERCENTILE — BCM/Rosner Quantile Spline Regression
// AAP 2017 classification with exact percentile computation
// ═══════════════════════════════════════════════════════════
// Height LMS parameters (218 entries, index 0 = month 24 / age 2y, index 217 = month 241)
var _htLMS_F_L=[1.07244896,1.051272912,1.041951175,1.012592236,0.970541909,0.921129988,0.868221392,0.81454413,0.761957977,0.711660228,0.664323379,0.620285102,0.57955631,0.54198094,0.511429832,0.482799937,0.455521041,0.429150288,0.403351725,0.377878239,0.352555862,0.327270297,0.301955463,0.276583851,0.251158446,0.225705996,0.20027145,0.174913356,0.149700081,0.12470671,0.100012514,0.075698881,0.051847635,0.02853967,0.005853853,-0.016133871,-0.037351181,-0.057729947,-0.077206672,-0.09572283,-0.113225128,-0.129665689,-0.145002179,-0.159197885,-0.172221748,-0.184048358,-0.194660215,-0.204030559,-0.212174408,-0.219069129,-0.224722166,-0.229140412,-0.232335686,-0.234324563,-0.235128195,-0.234772114,-0.233286033,-0.230703633,-0.227062344,-0.222403111,-0.216770161,-0.210210748,-0.202774891,-0.194515104,-0.185486099,-0.175744476,-0.165348396,-0.15435722,-0.142831123,-0.130830669,-0.118416354,-0.105648092,-0.092584657,-0.079283065,-0.065797888,-0.0521805,-0.03847825,-0.024733545,-0.010982868,0.002744306,0.016426655,0.030052231,0.043619747,0.05713988,0.070636605,0.08414848,0.097729873,0.111452039,0.125404005,0.13969316,0.154445482,0.169805275,0.185934346,0.203010488,0.2212252,0.240780542,0.261885086,0.284748919,0.309577733,0.336566048,0.365889711,0.397699038,0.432104409,0.46917993,0.508943272,0.551354277,0.596307363,0.643626542,0.693062173,0.744289752,0.79691098,0.85045728,0.904395871,0.958138449,1.011054559,1.062474568,1.111727029,1.158135105,1.201050821,1.239852328,1.274006058,1.303044695,1.326605954,1.344443447,1.356437773,1.362602695,1.363085725,1.358162799,1.348227142,1.333772923,1.315374704,1.293664024,1.269304678,1.242968236,1.21531127,1.186955477,1.158471522,1.130367088,1.103079209,1.076970655,1.052329922,1.029374161,1.008254396,0.989062282,0.971837799,0.95657215,0.94324228,0.931767062,0.922058291,0.914012643,0.907516917,0.902452436,0.898698641,0.896143482,0.894659668,0.89413892,0.894475371,0.895569834,0.897330209,0.899671635,0.902516442,0.905793969,0.909440266,0.913397733,0.91761471,0.922045055,0.926647697,0.931386217,0.93622842,0.941145943,0.94611388,0.95111043,0.956116576,0.961115792,0.966093766,0.971038162,0.975938391,0.980785418,0.985571579,0.99029042,0.994936555,0.999505539,1.003993753,1.0083983,1.012716921,1.016947912,1.021090055,1.025142554,1.029104983,1.032977233,1.036759475,1.040452117,1.044055774,1.047571238,1.050999451,1.054341482,1.057598512,1.060771808,1.063862715,1.066872639,1.069803036,1.072655401,1.075431258,1.078132156,1.080759655,1.083315329,1.085800751,1.088217496,1.090567133,1.092851222,1.095071313,1.097228939,1.099325619,1.101362852,1.103342119,1.105264876,1.107132561,1.108046193];
var _htLMS_F_M=[84.97555512,85.3973169,86.29026318,87.15714182,87.9960184,88.8055115,89.58476689,90.33341722,91.0515436,91.7396352,92.39854429,93.02945392,93.63382278,94.21335709,94.79643239,95.37391918,95.94692677,96.51644912,97.08337211,97.6484807,98.21246579,98.77593069,99.33939735,99.9033122,100.4680516,101.033927,101.6011898,102.1700358,102.7406094,103.3130077,103.8872839,104.4634511,105.0414853,105.6213287,106.2028921,106.7860583,107.3706841,107.9566031,108.5436278,109.1315521,109.7201531,110.3091934,110.8984228,111.4875806,112.0763967,112.6645943,113.2518902,113.8380006,114.4226317,115.0054978,115.5863089,116.1647782,116.7406221,117.3135622,117.8833259,118.4496481,119.0122722,119.5709513,120.1254495,120.6755427,121.22102,121.7616844,122.2973542,122.827864,123.3530652,123.8728276,124.38704,124.8956114,125.398472,125.895574,126.3868929,126.8724284,127.3522056,127.8262759,128.2947187,128.757642,129.2151839,129.6675143,130.1148354,130.5573839,130.995432,131.4292887,131.8593015,132.2858574,132.7093845,133.1303527,133.5492749,133.9667073,134.3832499,134.7995463,135.2162826,135.634186,136.0540223,136.4765925,136.9027281,137.3332846,137.7691339,138.2111552,138.6602228,139.1171933,139.5828898,140.0580848,140.5434787,141.0396832,141.5471945,142.0663731,142.59742,143.1403553,143.6949981,144.2609497,144.8375809,145.4240246,146.0191748,146.621692,147.2300177,147.8423918,148.4568879,149.0714413,149.6838943,150.2920328,150.8936469,151.4865636,152.0686985,152.6380955,153.1929631,153.7317031,154.2529332,154.755501,155.2384904,155.7012216,156.1432438,156.564323,156.9644258,157.3436995,157.7024507,158.0411233,158.3602756,158.6605588,158.9426964,159.2074654,159.455679,159.688172,159.9057871,160.1093647,160.299733,160.4776996,160.6440526,160.7995428,160.9448916,161.0807857,161.2078755,161.3267744,161.4380593,161.5422726,161.639917,161.7314645,161.8173534,161.8979913,161.9737558,162.0449969,162.1120386,162.17518,162.2346979,162.2908474,162.343864,162.3939652,162.4413513,162.4862071,162.5287029,162.5689958,162.6072309,162.6435418,162.6780519,162.7108751,162.7421168,162.7718741,162.8002371,162.8272889,162.8531067,162.8777619,162.9013208,162.9238449,162.9453912,162.9660131,162.9857599,163.0046776,163.0228094,163.0401953,163.0568727,163.0728768,163.0882404,163.1029943,163.1171673,163.1307866,163.1438776,163.1564644,163.1685697,163.1802146,163.1914194,163.202203,163.2125835,163.2225779,163.2322024,163.2414722,163.2504019,163.2590052,163.2672954,163.2752848,163.2829854,163.2904086,163.297565,163.304465,163.3111185,163.3175349,163.3237231,163.3296918,163.3354491,163.338251];
var _htLMS_F_S=[0.040791394,0.040859727,0.041142161,0.041349399,0.041500428,0.041610508,0.041691761,0.04175368,0.041803562,0.041846882,0.041887626,0.041928568,0.041971514,0.042017509,0.042104522,0.042199507,0.042300333,0.042405225,0.042512706,0.042621565,0.042730809,0.042839638,0.042947412,0.043053626,0.043157889,0.043259907,0.043359463,0.043456406,0.043550638,0.043642107,0.043730791,0.043816701,0.043899867,0.043980337,0.044058171,0.04413344,0.044206218,0.044276588,0.044344632,0.044410436,0.044474084,0.044535662,0.044595254,0.044652942,0.044708809,0.044762936,0.044815402,0.044866288,0.044915672,0.044963636,0.045010259,0.045055624,0.045099817,0.045142924,0.045185036,0.045226249,0.045266662,0.045306383,0.045345524,0.045384203,0.045422551,0.045460702,0.045498803,0.045537012,0.045575495,0.045614432,0.045654016,0.04569445,0.045735953,0.045778759,0.045823114,0.04586928,0.045917535,0.045968169,0.04602149,0.046077818,0.046137487,0.046200842,0.04626824,0.046340046,0.046416629,0.046498361,0.046585611,0.046678741,0.046778099,0.04688401,0.046996769,0.047116633,0.047243801,0.047378413,0.047520521,0.047670085,0.047826946,0.04799081,0.048161228,0.04833757,0.048519011,0.048704503,0.048892759,0.049082239,0.049271137,0.049457371,0.049638596,0.049812203,0.049975355,0.050125012,0.050257992,0.050371024,0.050460835,0.050524236,0.050558224,0.050560083,0.050527494,0.050458634,0.050352269,0.050207825,0.050025434,0.049805967,0.049551023,0.049262895,0.048944504,0.048599314,0.048231224,0.047844442,0.047443362,0.04703243,0.046616026,0.046198356,0.04578335,0.045374597,0.044975281,0.044588148,0.044215488,0.043859135,0.04352048,0.043200497,0.042899776,0.042618565,0.042356812,0.042114211,0.041890247,0.04168424,0.041495379,0.041322765,0.041165437,0.041022401,0.040892651,0.040775193,0.040669052,0.040573288,0.040487005,0.040409354,0.040339537,0.040276811,0.040220488,0.040169932,0.040124562,0.040083845,0.040047295,0.040014473,0.03998498,0.039958458,0.039934584,0.039913066,0.039893644,0.039876087,0.039860185,0.039845754,0.039832629,0.039820663,0.039809725,0.0397997,0.039790485,0.039781991,0.039774136,0.03976685,0.03976007,0.039753741,0.039747815,0.039742249,0.039737004,0.039732048,0.039727352,0.03972289,0.03971864,0.039714581,0.039710697,0.039706971,0.039703391,0.039699945,0.039696623,0.039693415,0.039690313,0.039687311,0.039684402,0.039681581,0.039678842,0.039676182,0.039673596,0.039671082,0.039668635,0.039666254,0.039663936,0.039661679,0.039659481,0.039657339,0.039655252,0.039653218,0.039651237,0.039649306,0.039647424,0.039645591,0.039643804,0.039642063,0.039640367,0.039638715,0.039637105,0.039636316];
var _htLMS_M_L=[0.941523967,1.00720807,0.837251351,0.681492975,0.538779654,0.407697153,0.286762453,0.174489485,0.069444521,-0.029720564,-0.124251789,-0.215288396,-0.30385434,-0.390918369,-0.254801167,-0.125654535,-0.00316735,0.11291221,0.222754969,0.326530126,0.42436156,0.516353108,0.602595306,0.683170764,0.758158406,0.827636736,0.891686306,0.95039153,1.003830006,1.05213569,1.0953669,1.133652119,1.167104213,1.195845353,1.220004233,1.239715856,1.255121285,1.266367398,1.273606657,1.276996893,1.276701119,1.272887366,1.265728536,1.255402281,1.242090871,1.225981067,1.207263978,1.186140222,1.162796198,1.137442868,1.110286487,1.081536236,1.05140374,1.020102497,0.987847213,0.954853043,0.921334742,0.887505723,0.85357703,0.819756239,0.786246296,0.753244292,0.720940222,0.689515708,0.659142731,0.629997853,0.602203984,0.575908038,0.55123134,0.528279901,0.507143576,0.487895344,0.470590753,0.455267507,0.441945241,0.430625458,0.421291648,0.413909588,0.408427813,0.404778262,0.402877077,0.402625561,0.40391127,0.406609232,0.410583274,0.415687443,0.421767514,0.428662551,0.436206531,0.44423,0.45256176,0.461030578,0.469466904,0.477704608,0.48558272,0.492947182,0.499652617,0.505564115,0.510559047,0.514528903,0.517381177,0.519041285,0.519454524,0.518588072,0.516433004,0.513006312,0.508352901,0.502547502,0.495696454,0.487939275,0.479449924,0.470437652,0.461147305,0.451858946,0.442886661,0.434576385,0.427302633,0.421464027,0.417477538,0.415771438,0.416777012,0.420919142,0.428606007,0.440218167,0.456097443,0.476536014,0.501766234,0.531951655,0.567179725,0.607456565,0.652704121,0.702759868,0.757379106,0.816239713,0.878947416,0.945053486,1.014046108,1.085383319,1.158487278,1.232768816,1.307628899,1.382473225,1.456720479,1.529810247,1.601219573,1.670433444,1.736995571,1.800483802,1.860518777,1.916765525,1.968934444,2.016781776,2.060109658,2.098765817,2.132642948,2.16167779,2.185849904,2.205180153,2.219728869,2.2295937,2.234907144,2.235833767,2.232567138,2.2253265,2.214353232,2.199905902,2.182262864,2.161704969,2.138524662,2.113023423,2.085490286,2.0562195,2.025496648,1.993598182,1.960789092,1.927320937,1.89343024,1.859337259,1.825245107,1.791339209,1.757787065,1.724738292,1.692324905,1.660661815,1.629847495,1.599964788,1.571081817,1.543252982,1.516519998,1.490912963,1.466451429,1.44314546,1.420996665,1.399999187,1.380140651,1.361403047,1.343763564,1.327195355,1.311668242,1.297149359,1.283603728,1.270994782,1.25928483,1.248435461,1.23840791,1.229163362,1.220663228,1.212869374,1.20574431,1.199251356,1.19335477,1.188019859,1.183213059,1.178901998,1.175055543,1.171643828,1.16863827,1.167279219];
var _htLMS_M_M=[86.45220101,86.86160934,87.65247282,88.42326434,89.17549228,89.91040853,90.62907762,91.33242379,92.02127167,92.69637946,93.35846546,94.00822923,94.64636981,95.27359106,95.91474929,96.54734328,97.17191309,97.78897727,98.3990283,99.00254338,99.599977,100.191764,100.7783198,101.3600411,101.9373058,102.5104735,103.0798852,103.645864,104.208713,104.7687256,105.3261638,105.8812823,106.4343146,106.9854769,107.534968,108.0829695,108.6296457,109.1751441,109.7195954,110.2631136,110.8057967,111.3477265,111.8889694,112.4295761,112.9695827,113.5090108,114.0478678,114.5861486,115.1238315,115.6608862,116.1972691,116.732925,117.2677879,117.8017819,118.3348215,118.8668123,119.397652,119.9272309,120.455433,120.9821362,121.5072136,122.0305342,122.5519634,123.0713645,123.588599,124.1035312,124.6160161,125.1259182,125.6331012,126.1374319,126.6387804,127.1370217,127.6320362,128.1237104,128.6119383,129.096622,129.5776723,130.0550101,130.5285669,130.9982857,131.4641218,131.9260439,132.3840348,132.838092,133.2882291,133.7344759,134.1768801,134.6155076,135.0504433,135.4817925,135.9096813,136.3342577,136.7556923,137.1741794,137.5899378,138.0032114,138.4142703,138.8234114,139.2309592,139.6372663,140.042714,140.4477127,140.8527022,141.2581515,141.6645592,142.072452,142.4823852,142.8949403,143.3107241,143.7303663,144.1545167,144.5838414,145.0190192,145.4607359,145.9096784,146.3665278,146.8319513,147.3065929,147.7910635,148.2859294,148.7917006,149.3088178,149.8376391,150.3784267,150.9313331,151.4963887,152.0734897,152.6623878,153.2626819,153.8738124,154.495058,155.1255365,155.7642086,156.4098858,157.0612415,157.7168289,158.3750929,159.034399,159.6930501,160.3493168,161.0014586,161.6477515,162.2865119,162.9161202,163.535045,164.1418486,164.7352199,165.3139755,165.8770715,166.4236087,166.9528354,167.4641466,167.9570814,168.4313175,168.8866644,169.3230548,169.7405351,170.139255,170.5194567,170.881464,171.2256717,171.5525345,171.8625576,172.1562865,172.4342983,172.6971935,172.9455898,173.180112,173.4013896,173.6100518,173.8067179,173.9919998,174.1664951,174.3307855,174.4854344,174.6309856,174.7679617,174.8968634,175.0181691,175.1323345,175.2397926,175.340954,175.4362071,175.5259191,175.6104358,175.690083,175.7651671,175.8359757,175.9027788,175.9658293,176.0253641,176.081605,176.1347593,176.1850208,176.2325707,176.2775781,176.3202008,176.3605864,176.3988725,176.4351874,176.469651,176.5023751,176.533464,176.5630153,176.5911197,176.6178621,176.6433219,176.6675729,176.6906844,176.712721,176.733743,176.753807,176.7729657,176.7912687,176.8087622,176.8254895,176.8414914,176.8492322];
var _htLMS_M_S=[0.040321528,0.040395626,0.040577525,0.040723122,0.040833194,0.040909059,0.040952433,0.04096533,0.040949976,0.040908737,0.040844062,0.040758431,0.040654312,0.04053412,0.040572876,0.04061691,0.040666414,0.040721467,0.040782045,0.040848042,0.040919281,0.040995524,0.041076485,0.041161838,0.041251224,0.041344257,0.041440534,0.041539635,0.041641136,0.041744602,0.041849607,0.041955723,0.042062532,0.042169628,0.042276619,0.042383129,0.042488804,0.042593311,0.042696342,0.042797615,0.042896877,0.042993904,0.043088503,0.043180513,0.043269806,0.043356287,0.043439893,0.043520597,0.043598407,0.043673359,0.043745523,0.043815003,0.043881929,0.043946461,0.044008785,0.044069112,0.044127675,0.044184725,0.044240532,0.044295379,0.044349559,0.044403374,0.04445713,0.044511135,0.044565693,0.044621104,0.044677662,0.044735646,0.044795322,0.044856941,0.04492073,0.044986899,0.045055632,0.045127088,0.045201399,0.045278671,0.045358979,0.045442372,0.045528869,0.045618459,0.045711105,0.045806742,0.045905281,0.046006604,0.046110573,0.046217028,0.04632579,0.046436662,0.04654943,0.046663871,0.046779748,0.046896817,0.047014827,0.047133525,0.047252654,0.047371961,0.047491194,0.047610108,0.047728463,0.04784603,0.047962592,0.048077942,0.048191889,0.048304259,0.048414893,0.048523648,0.048630402,0.04873505,0.048837504,0.048937694,0.049035564,0.049131073,0.049224189,0.049314887,0.049403145,0.049488934,0.049572216,0.049652935,0.049731004,0.0498063,0.04987865,0.049947823,0.050013518,0.050075353,0.050132858,0.050185471,0.050232532,0.050273285,0.050306885,0.050332406,0.05034886,0.050355216,0.050350423,0.050333444,0.050303283,0.050259018,0.050199837,0.050125062,0.05003418,0.049926861,0.049802977,0.04966261,0.049506051,0.049333801,0.049146553,0.04894519,0.048730749,0.048504404,0.048267442,0.04802123,0.047767192,0.047506783,0.047241456,0.04697265,0.046701759,0.046430122,0.046159004,0.045889585,0.045622955,0.045360101,0.045101913,0.044849174,0.044602566,0.044362674,0.044129985,0.043904897,0.043687723,0.043478698,0.043277987,0.043085685,0.042901835,0.042726424,0.042559396,0.042400652,0.042250063,0.042107465,0.041972676,0.041845488,0.041725679,0.041613015,0.041507249,0.041408129,0.041315398,0.041228796,0.04114806,0.041072931,0.04100315,0.040938463,0.040878617,0.040823368,0.040772475,0.040725706,0.040682834,0.04064364,0.040607913,0.040575448,0.040546051,0.040519532,0.040495713,0.040474421,0.040455493,0.040438773,0.040424111,0.040411366,0.040400405,0.040391101,0.040383334,0.04037699,0.040371962,0.040368149,0.040365456,0.040363795,0.04036308,0.040363233,0.040364179,0.04036585,0.04036818,0.040369574];
// BP Rosner spline coefficients (99 percentiles x 13 coefficients)
var _bpCoeff_F_SYS=[
[-7.4855,-1.2252,1.2643,-6.8797,20.4744,0.7114,-0.0066,-0.0667,0.3564,-0.0012,0.5278,-0.6927,0.1388],
[8.4462,-0.9598,0.9046,-5.1098,15.1548,0.5919,-0.0029,-0.065,0.2495,-0.003,0.4421,-0.5724,0.0997],
[26.6223,-1.1479,1.2134,-8.4665,28.0408,0.475,0.0001,-0.0643,0.2062,-0.023,0.5561,-0.7467,0.185],
[31.8947,-0.867,1.1693,-8.2932,26.0849,0.4251,-0.0002,-0.0535,0.1718,-0.008,0.3954,-0.5402,0.1473],
[30.9472,-1.1288,1.5926,-11.7371,34.5934,0.4578,-0.0019,-0.0341,0.1144,-0.0167,0.6897,-1.0025,0.3867],
[23.152,-1.1368,1.751,-13.8556,41.2104,0.527,-0.0048,-0.0149,0.0623,0.0062,0.4347,-0.6509,0.2798],
[19.3036,-0.923,1.6566,-14.2294,42.9522,0.5494,-0.0062,-0.0051,0.0555,0.0242,0.1295,-0.1986,0.0876],
[20.0191,-1.0378,1.6928,-13.6476,40.8615,0.5596,-0.0071,0.0146,-0.03,0.0135,0.1632,-0.2423,0.1013],
[21.6515,-0.9745,1.5964,-13.0096,38.8309,0.5462,-0.0063,0.0087,-0.0183,0.0093,0.2644,-0.3848,0.1477],
[22.6952,-0.8665,1.4799,-11.8203,34.2277,0.537,-0.0066,0.0176,-0.0648,0.0046,0.3226,-0.4689,0.1811],
[23.1615,-0.8132,1.4422,-11.8893,34.8542,0.5329,-0.0063,0.013,-0.0367,0.008,0.34,-0.5072,0.2171],
[27.9,-0.8288,1.4257,-11.5803,33.7393,0.4995,-0.0049,0.0013,0.0117,-0.0014,0.4954,-0.7333,0.3051],
[34.8678,-0.801,1.429,-11.2835,32.3656,0.4469,-0.0037,-0.0037,0.0274,-0.0004,0.3936,-0.5873,0.251],
[37.7557,-0.9638,1.5603,-11.545,31.5671,0.4392,-0.0035,0.0024,-0.0164,-0.0087,0.395,-0.575,0.2238],
[39.9509,-1.0185,1.6189,-11.6485,31.009,0.4284,-0.0032,0.0051,-0.0452,-0.0101,0.3516,-0.5073,0.1906],
[40.8576,-0.9313,1.5386,-11.5031,31.8413,0.418,-0.0029,0.0019,-0.0291,-0.0081,0.3507,-0.5094,0.1968],
[42.1455,-0.9104,1.5356,-11.4411,31.5567,0.4098,-0.0029,0.0038,-0.0368,-0.006,0.2848,-0.4155,0.1642],
[44.0009,-1.0103,1.6565,-11.8711,31.8672,0.4038,-0.0026,0.0007,-0.0172,-0.0017,0.1877,-0.2802,0.1211],
[42.9483,-0.9479,1.6532,-12.4439,34.3937,0.4097,-0.0029,0.0023,-0.0231,-0.0003,0.1892,-0.2761,0.1077],
[43.4489,-0.9355,1.5751,-11.4463,30.9525,0.4076,-0.0027,0,-0.0199,0.0013,0.1619,-0.2376,0.0949],
[42.0432,-0.9668,1.5892,-11.2769,29.6658,0.4235,-0.003,0.0009,-0.0194,0.0051,0.1181,-0.1781,0.0784],
[43.3921,-0.9251,1.5125,-10.669,27.8566,0.4122,-0.0025,-0.0008,-0.0269,-0.0003,0.178,-0.2571,0.0962],
[43.1823,-0.9153,1.5502,-11.2058,29.7148,0.4154,-0.0028,0.0025,-0.0386,0.0053,0.0679,-0.0977,0.0352],
[43.5111,-0.8427,1.4724,-10.8634,29.5168,0.4107,-0.0027,0.0019,-0.0416,-0.0023,0.1644,-0.2282,0.0711],
[44.8115,-0.9195,1.5496,-10.7815,27.8384,0.4087,-0.003,0.012,-0.0908,-0.0063,0.1451,-0.1957,0.053],
[45.1153,-0.8419,1.4685,-10.4821,27.7389,0.404,-0.003,0.0148,-0.1094,-0.0047,0.1524,-0.2131,0.0715],
[45.0184,-0.9109,1.4637,-9.8769,25.3956,0.4124,-0.0031,0.0163,-0.1196,-0.0095,0.2128,-0.3015,0.1084],
[46.8396,-0.9336,1.4913,-10.0409,25.5791,0.4004,-0.0025,0.0087,-0.0854,-0.0083,0.207,-0.2945,0.1065],
[46.3627,-1.0691,1.6403,-10.8997,27.3749,0.4156,-0.003,0.0128,-0.0892,-0.006,0.1891,-0.2783,0.1168],
[46.056,-1.0253,1.6174,-10.8914,27.6133,0.4169,-0.0032,0.0134,-0.0831,-0.0015,0.1168,-0.1751,0.0794],
[45.8707,-1.0687,1.6929,-11.5282,29.3823,0.4234,-0.0035,0.0189,-0.1052,-0.002,0.0549,-0.0766,0.0279],
[46.225,-1.0493,1.6305,-11.0002,28.295,0.4212,-0.0032,0.015,-0.0892,0.001,0.0192,-0.0279,0.014],
[49.7043,-1.1168,1.6687,-10.6909,26.5418,0.4005,-0.0027,0.0175,-0.1166,-0.0029,-0.0064,0.0124,-0.0056],
[52.501,-1.2283,1.7174,-10.288,24.6009,0.39,-0.0025,0.0229,-0.1413,-0.0055,-0.0773,0.1151,-0.0428],
[52.638,-1.2668,1.7982,-10.7251,24.8323,0.393,-0.0027,0.0233,-0.1352,-0.0037,-0.1218,0.1797,-0.0678],
[52.9451,-1.2987,1.8214,-10.8739,25.4383,0.3952,-0.0028,0.0249,-0.1365,-0.0026,-0.1753,0.2588,-0.1002],
[51.6977,-1.2275,1.7723,-10.6355,24.5465,0.4024,-0.0032,0.0273,-0.1377,0.0023,-0.2334,0.3428,-0.1327],
[51.5803,-1.1856,1.7323,-10.549,24.7169,0.4027,-0.0033,0.029,-0.1504,0.004,-0.2752,0.4081,-0.1658],
[52.5542,-1.1951,1.7357,-10.3953,23.5706,0.3978,-0.0032,0.0312,-0.1661,0.0005,-0.2249,0.34,-0.1482],
[54.7146,-1.2604,1.8028,-10.773,24.4075,0.3869,-0.0029,0.0332,-0.1862,-0.002,-0.2181,0.3306,-0.1449],
[56.735,-1.199,1.8011,-11.3328,26.8609,0.3684,-0.0025,0.0319,-0.1874,0.0002,-0.2443,0.3686,-0.1611],
[57.7385,-1.2515,1.8588,-11.3519,25.8098,0.3657,-0.0024,0.0287,-0.1704,-0.0009,-0.2306,0.3502,-0.1567],
[57.7098,-1.257,1.9037,-11.8077,27.0173,0.3677,-0.0024,0.0271,-0.1572,-0.0012,-0.1965,0.298,-0.1324],
[58.0736,-1.2363,1.9353,-12.317,28.6066,0.3643,-0.0024,0.0253,-0.1507,0.002,-0.178,0.2641,-0.1092],
[62.0223,-1.2128,1.9237,-12.157,27.903,0.3343,-0.0016,0.0242,-0.1555,-0.0004,-0.21,0.315,-0.136],
[62.1221,-1.1404,1.8555,-11.839,27.3698,0.3308,-0.0017,0.026,-0.1685,-0.0024,-0.1452,0.2208,-0.0993],
[62.7962,-1.113,1.8421,-11.7266,26.7715,0.3253,-0.0016,0.0282,-0.1884,-0.0019,-0.1808,0.2766,-0.1276],
[61.7073,-1.2183,1.9323,-12.0462,26.8742,0.3435,-0.0022,0.0321,-0.2009,-0.0018,-0.1943,0.2958,-0.1342],
[61.7636,-1.1885,1.9597,-12.4946,27.9124,0.342,-0.0022,0.0308,-0.1956,0.003,-0.234,0.3493,-0.149],
[63.7493,-1.2055,1.96,-12.5069,28.0089,0.3283,-0.0012,0.0195,-0.1595,-0.002,-0.1708,0.2634,-0.1258],
[62.2586,-1.077,1.8646,-12.2702,27.8184,0.3328,-0.0012,0.0137,-0.1292,-0.0024,-0.0705,0.1151,-0.0646],
[64.2911,-1.0805,1.8431,-11.8647,26.3816,0.3191,-0.0007,0.0088,-0.1057,-0.007,-0.0325,0.0621,-0.0471],
[68.9778,-1.2187,1.888,-11.2553,23.9127,0.294,0.0003,0.0053,-0.0991,-0.0123,-0.0668,0.1121,-0.0648],
[70.4806,-1.165,1.8218,-10.7395,22.4622,0.2801,0.0009,0.0001,-0.0853,-0.0136,-0.0702,0.1225,-0.0781],
[70.6109,-1.1182,1.8262,-11.2854,24.8046,0.2768,0.001,-0.0007,-0.084,-0.01,-0.1092,0.1806,-0.1041],
[69.8975,-1.1611,1.8731,-11.7046,26.3452,0.287,0.0007,0.0018,-0.0954,-0.0067,-0.1524,0.2386,-0.1185],
[69.191,-1.1401,1.9015,-12.217,27.9129,0.2928,0.0003,0.0055,-0.111,-0.0035,-0.2103,0.3262,-0.1586],
[69.9619,-1.1195,1.8816,-11.9235,26.817,0.2873,0.0005,0.0046,-0.1118,-0.0053,-0.1918,0.3015,-0.1525],
[68.3161,-1.0128,1.7759,-11.6001,26.6764,0.2951,0.0003,0.0028,-0.1008,-0.0022,-0.2321,0.3639,-0.1831],
[68.0555,-0.9162,1.6469,-10.7107,24.2868,0.2927,0.0006,-0.0014,-0.0813,-0.0004,-0.236,0.3707,-0.1882],
[65.6124,-0.7989,1.5036,-9.8072,21.9786,0.3055,0.0004,-0.0054,-0.0567,-0.0017,-0.1403,0.2328,-0.1369],
[65.1636,-0.7707,1.457,-9.5828,21.8374,0.3086,0.0005,-0.0086,-0.0391,-0.0024,-0.0941,0.1647,-0.109],
[66.6766,-0.913,1.5894,-9.8498,21.1477,0.3073,0.0008,-0.0116,-0.029,-0.0052,-0.0645,0.1189,-0.0865],
[65.4537,-0.895,1.5329,-9.3616,19.7235,0.3178,0.0007,-0.0136,-0.0176,-0.0044,-0.0173,0.0444,-0.0479],
[64.8596,-0.9404,1.6229,-9.8355,19.8054,0.3274,0.0002,-0.0077,-0.0396,-0.006,0.0077,0.0094,-0.0359],
[64.7808,-0.935,1.5826,-9.392,18.2771,0.3302,0.0002,-0.0082,-0.0324,-0.009,0.0629,-0.0712,-0.0032],
[65.5762,-0.9693,1.558,-8.833,16.6679,0.3289,0.0003,-0.009,-0.0304,-0.0092,0.0526,-0.0599,-0.0011],
[64.0451,-1.1203,1.7205,-9.4755,16.9051,0.3537,-0.0007,0.0019,-0.0701,-0.0041,-0.1202,0.1997,-0.1156],
[66.825,-1.1964,1.8333,-10.0226,17.9273,0.3397,-0.0006,0.0056,-0.0822,-0.0081,-0.1245,0.2047,-0.1138],
[65.6846,-1.2525,1.9018,-10.459,18.6882,0.3537,-0.0009,0.0036,-0.066,-0.0057,-0.113,0.1831,-0.0985],
[65.3052,-1.2617,1.9135,-10.5223,18.771,0.3604,-0.0013,0.0085,-0.0848,-0.0046,-0.1438,0.2265,-0.112],
[64.899,-1.2245,1.8584,-10.1192,17.7416,0.3641,-0.0016,0.0138,-0.1073,-0.0048,-0.1372,0.2161,-0.1063],
[65.3578,-1.2248,1.8289,-9.7674,16.8046,0.3627,-0.0014,0.0124,-0.1066,-0.0057,-0.1576,0.2502,-0.1263],
[64.5514,-1.1783,1.7442,-9.4075,16.9106,0.3687,-0.0013,0.0091,-0.0924,-0.0076,-0.0787,0.1365,-0.0847],
[66.0885,-1.1878,1.7936,-9.5264,16.3425,0.3605,-0.0016,0.0179,-0.1274,-0.0072,-0.185,0.2994,-0.1608],
[67.302,-1.1912,1.725,-8.4639,12.8607,0.3551,-0.0016,0.0212,-0.1358,-0.0076,-0.2055,0.3238,-0.1601],
[69.6151,-1.1726,1.7606,-8.9219,14.4437,0.3387,-0.0015,0.026,-0.1521,-0.0094,-0.1704,0.2659,-0.1257],
[70.5901,-1.2426,1.8162,-8.921,13.7988,0.3388,-0.0016,0.0283,-0.1619,-0.016,-0.066,0.1157,-0.069],
[74.0399,-1.3696,1.9736,-9.9705,16.4081,0.322,-0.001,0.0261,-0.1607,-0.0211,0.054,-0.068,0.017],
[78.1837,-1.4118,1.9659,-9.2285,13.6521,0.2962,-0.0004,0.0279,-0.176,-0.0236,0.0265,-0.035,0.0171],
[77.8733,-1.5496,2.1217,-10.0164,15.085,0.3117,-0.0013,0.041,-0.234,-0.0167,-0.141,0.2059,-0.0717],
[78.6258,-1.5819,2.1292,-10.2662,16.5876,0.311,-0.0011,0.0374,-0.2191,-0.0181,-0.0881,0.1294,-0.044],
[78.1114,-1.6551,2.2258,-11.1197,18.7127,0.3231,-0.0016,0.0421,-0.2369,-0.0174,-0.0626,0.0903,-0.0264],
[79.7562,-1.6836,2.2862,-11.9207,21.9312,0.3146,-0.0013,0.038,-0.2147,-0.0164,-0.0397,0.0537,-0.0083],
[81.1825,-1.7413,2.3012,-11.7683,21.4169,0.3106,-0.0011,0.0381,-0.2099,-0.0197,0.0394,-0.07,0.0551],
[82.4317,-1.7326,2.3369,-11.7377,20.8323,0.3043,-0.0014,0.0468,-0.2545,-0.0145,-0.1069,0.1451,-0.0329],
[83.4279,-1.7479,2.3341,-12.1336,23.8773,0.3009,-0.0009,0.0394,-0.2205,-0.0159,-0.0384,0.039,0.0189],
[87.5318,-1.8801,2.4042,-11.8201,21.5,0.2804,0,0.0344,-0.215,-0.0208,-0.0131,0.0053,0.0276],
[91.5471,-1.9424,2.5247,-12.4507,21.7964,0.2576,0.0005,0.0374,-0.2444,-0.0294,-0.0119,0.0227,-0.01],
[92.4497,-1.8508,2.5523,-13.6421,26.226,0.2495,0,0.0494,-0.305,-0.0184,-0.1813,0.2673,-0.1041],
[92.8328,-1.7523,2.5128,-13.17,23.6191,0.2436,0.0005,0.0322,-0.2188,-0.0162,-0.1657,0.2435,-0.0938],
[100.346,-1.9852,2.7015,-12.334,16.8429,0.2061,0.0016,0.0236,-0.1616,-0.0093,-0.4796,0.6954,-0.2616],
[106.8231,-1.8617,2.4704,-10.3756,11.994,0.1537,0.0038,0.0071,-0.1169,-0.0192,-0.4992,0.7439,-0.3113],
[111.3953,-1.9833,2.5967,-11.4122,16.0199,0.1324,0.0046,0.0068,-0.1417,-0.0242,-0.6418,0.9712,-0.431],
[117.6411,-2.0964,2.6981,-11.2572,13.4182,0.0991,0.0053,0.0132,-0.1836,-0.0338,-0.4799,0.719,-0.3037],
[121.3735,-2.3828,2.9534,-12.2263,14.8292,0.0974,0.0055,0.0085,-0.1487,-0.0205,-0.6271,0.9041,-0.3313],
[115.9126,-2.5317,3.2788,-15.2093,22.0287,0.1601,0.0028,0.0231,-0.181,0.0006,-0.7258,1.0194,-0.3341],
[125.5877,-1.6743,2.6055,-13.4481,23.2621,0.0405,0.006,-0.0009,-0.0707,0.0296,-1.1873,1.6794,-0.5743],
[135.675,-1.8473,2.0605,-8.0487,16.9201,-0.0112,0.0136,-0.0896,0.1678,-0.0337,0.3359,-0.5938,0.4196]
];
var _bpCoeff_F_DIA=[
[36.3363,-0.4513,-0.2328,28.8499,-129.833,-0.0182,0.0007,0.0464,-0.2691,-0.0622,-0.2979,0.6276,-0.5522],
[30.6534,-1.0645,-0.5369,30.836,-125.69,0.1058,0.0021,0.039,-0.2859,-0.0568,-0.8988,1.5116,-0.9035],
[46.6521,-0.8427,-0.8134,29.0051,-109.524,-0.0091,0.0049,0.0484,-0.379,-0.0684,-0.6066,1.0179,-0.5945],
[34.7995,-1.0943,-0.5132,24.8976,-93.9462,0.1143,0.0006,0.0856,-0.4757,-0.03,-0.9349,1.424,-0.6362],
[15.9095,-0.3518,-0.6484,19.5391,-72.0796,0.2253,-0.0045,0.1041,-0.5073,0.007,-1.3455,2.0777,-0.9953],
[12.8878,-0.0974,-1.0427,20.0319,-66.1203,0.2379,-0.002,0.0402,-0.2008,-0.0112,-0.4679,0.7618,-0.4226],
[3.2759,-0.1741,-0.7763,16.2511,-53.8662,0.3223,-0.0044,0.0485,-0.2089,-0.0061,-0.2448,0.4092,-0.2385],
[12.846,-0.0649,-0.8792,16.2183,-50.693,0.2474,-0.0022,0.0311,-0.123,-0.0255,0.239,-0.3265,0.1012],
[12.8668,0.1716,-1.0619,16.2814,-49.2028,0.2361,-0.002,0.0293,-0.1263,-0.0322,0.5303,-0.7561,0.2762],
[9.112,0.1408,-1.0811,16.1015,-48.0962,0.2737,-0.0032,0.0416,-0.1676,-0.0278,0.5837,-0.8523,0.3437],
[11.7225,-0.2667,-0.674,14.1978,-45.5872,0.284,-0.0034,0.0505,-0.203,-0.0368,0.5673,-0.8255,0.3314],
[19.5753,-0.4609,-0.4453,12.7133,-41.9359,0.2384,-0.002,0.0503,-0.2232,-0.0503,0.7475,-1.0987,0.4581],
[21.1297,-0.7489,-0.2784,12.1653,-40.6521,0.2491,-0.0015,0.0462,-0.2201,-0.0415,0.5736,-0.8537,0.3742],
[17.5087,-0.5589,-0.5804,13.6135,-42.3595,0.2699,-0.0017,0.0438,-0.2286,-0.0325,0.5451,-0.8138,0.3581],
[19.125,-0.6931,-0.358,11.3984,-35.5973,0.2679,-0.0009,0.0341,-0.1992,-0.0272,0.3386,-0.5034,0.2204],
[12.3312,-0.7307,-0.2314,9.1993,-27.9046,0.3246,-0.002,0.0272,-0.1474,-0.0218,0.4218,-0.6267,0.2695],
[8.7933,-0.5755,-0.2574,8.5358,-26.1118,0.3473,-0.0031,0.0313,-0.1447,-0.0249,0.4514,-0.6549,0.2572],
[6.8234,-0.7262,-0.0687,7.7821,-26.4927,0.3781,-0.0044,0.0462,-0.203,-0.0214,0.2612,-0.3714,0.1375],
[6.5708,-0.6226,-0.1738,8.0763,-26.5849,0.3759,-0.0041,0.0378,-0.1688,-0.0223,0.3339,-0.475,0.1725],
[12.4952,-0.781,0.0532,6.8239,-24.2698,0.3431,-0.0032,0.0368,-0.1732,-0.0262,0.1513,-0.1909,0.0331],
[16.8254,-0.4175,-0.2206,7.4894,-23.9702,0.2885,-0.0021,0.0295,-0.1608,-0.0154,-0.0241,0.0763,-0.095],
[17.8811,-0.4367,-0.1266,7.0389,-24.15,0.2868,-0.0028,0.0392,-0.1928,-0.0081,-0.278,0.4577,-0.2641],
[16.5734,-0.2666,-0.2542,7.0108,-22.3832,0.2899,-0.0032,0.0387,-0.1806,-0.0041,-0.2653,0.436,-0.2519],
[19.9011,-0.2317,-0.3427,7.6601,-23.4789,0.2636,-0.002,0.0303,-0.1519,-0.0146,-0.0788,0.162,-0.1394],
[21.7218,-0.2625,-0.2345,6.6903,-20.9185,0.2553,-0.0023,0.0347,-0.1547,-0.023,0.0302,0.0052,-0.0801],
[21.9955,-0.4947,-0.0505,6.3827,-21.7936,0.2719,-0.0028,0.0392,-0.1593,-0.0334,0.1394,-0.1536,-0.0152],
[25.2014,-0.5716,0.0877,5.7268,-21.1119,0.2566,-0.0032,0.0512,-0.2028,-0.0358,0.0855,-0.0747,-0.0456],
[24.9355,-0.6578,0.231,4.6551,-18.8514,0.2671,-0.0039,0.0592,-0.2224,-0.0268,-0.0489,0.114,-0.1096],
[23.5259,-0.5069,0.1119,4.7744,-18.0734,0.2698,-0.004,0.0557,-0.2087,-0.0263,0.0265,0.0098,-0.0803],
[22.6538,-0.3685,-0.0683,5.5225,-18.8175,0.2682,-0.0033,0.0439,-0.1629,-0.0299,0.2232,-0.2808,0.039],
[25.1343,-0.4732,0.0854,3.9605,-13.912,0.2571,-0.0028,0.0398,-0.1488,-0.038,0.4146,-0.5644,0.1571],
[26.0776,-0.4748,0.0973,4.2405,-15.6978,0.2526,-0.0028,0.0409,-0.1485,-0.0398,0.4214,-0.5758,0.1652],
[27.7828,-0.4017,0.07,4.258,-15.4754,0.2367,-0.0027,0.0432,-0.1635,-0.035,0.3149,-0.4222,0.1074],
[33.321,-0.5491,0.2782,3.9722,-17.4641,0.2081,-0.0028,0.0559,-0.2079,-0.0453,0.3091,-0.4165,0.114],
[34.8309,-0.6942,0.426,3.3318,-16.8497,0.2081,-0.003,0.0647,-0.2508,-0.0416,0.1445,-0.1779,0.0236],
[37.5926,-0.6443,0.3677,3.4067,-16.42,0.1823,-0.0015,0.0474,-0.1947,-0.0411,0.2234,-0.2936,0.0668],
[39.4412,-0.5625,0.2263,4.2984,-18.3087,0.1635,-0.0003,0.0348,-0.1585,-0.0452,0.3142,-0.4246,0.1158],
[40.6765,-0.6234,0.3141,3.8208,-17.9457,0.1599,-0.0002,0.0372,-0.1782,-0.041,0.1452,-0.1684,-0.0017],
[38.5263,-0.6294,0.3817,3.0897,-16.2418,0.1784,-0.0007,0.0354,-0.1608,-0.0439,0.2718,-0.3597,0.0853],
[38.8799,-0.7551,0.4856,2.734,-15.7989,0.186,-0.0008,0.037,-0.1615,-0.0449,0.292,-0.3993,0.1186],
[41.2743,-0.9011,0.6699,2.2512,-16.8137,0.1795,-0.0009,0.042,-0.1746,-0.0484,0.2216,-0.293,0.0726],
[42.2558,-1.0062,0.7158,2.6789,-19.1943,0.1817,-0.0009,0.0441,-0.1858,-0.0468,0.0978,-0.112,0.002],
[40.2612,-0.9872,0.7444,1.7973,-16.1566,0.1974,-0.0012,0.0445,-0.1857,-0.0476,0.1203,-0.1402,0.0055],
[43.6457,-1.0069,0.734,1.9082,-15.776,0.1751,-0.0005,0.0411,-0.1774,-0.054,0.2098,-0.2758,0.0684],
[37.4261,-1.0061,0.8119,0.7582,-12.6239,0.2262,-0.0023,0.0517,-0.2087,-0.0439,0.0866,-0.0919,-0.0122],
[39.6219,-1.2657,1.1924,-1.7105,-7.6258,0.228,-0.0027,0.0582,-0.2341,-0.047,-0.0208,0.0811,-0.1069],
[40.843,-1.2324,1.2238,-1.9885,-7.0689,0.2204,-0.0032,0.0673,-0.2749,-0.0429,-0.1374,0.2503,-0.1721],
[43.5592,-1.2444,1.2281,-1.7233,-8.2869,0.2012,-0.0024,0.0607,-0.2564,-0.0432,-0.1732,0.3033,-0.1943],
[44.6015,-1.2557,1.2143,-1.1069,-11.0077,0.197,-0.0025,0.062,-0.2557,-0.0368,-0.2817,0.4521,-0.2374],
[43.431,-1.4836,1.4844,-2.8301,-7.691,0.2221,-0.0031,0.0664,-0.2718,-0.0343,-0.3518,0.5529,-0.2744],
[40.2503,-1.5293,1.5113,-3.3498,-5.9574,0.2524,-0.0038,0.0674,-0.2644,-0.0307,-0.3766,0.5899,-0.2912],
[38.7912,-1.4248,1.4482,-3.6476,-4.2826,0.2581,-0.0037,0.0597,-0.2243,-0.033,-0.308,0.4967,-0.266],
[43.1602,-1.3762,1.3057,-2.4967,-6.1669,0.2217,-0.0018,0.0357,-0.1265,-0.0409,-0.031,0.0745,-0.0711],
[44.7535,-1.2714,1.1636,-1.6742,-7.0124,0.2031,-0.0006,0.0171,-0.0429,-0.0436,0.1573,-0.2169,0.0706],
[44.9528,-1.1354,1.0103,-0.6896,-9.5126,0.1953,-0.0005,0.0153,-0.0298,-0.0404,0.1044,-0.1372,0.0343],
[39.8113,-0.9011,0.8911,-1.1437,-6.6547,0.2237,-0.002,0.0227,-0.0406,-0.0358,0.093,-0.1099,0.0051],
[37.8989,-1.0051,1.0055,-1.5428,-6.9588,0.2482,-0.0029,0.031,-0.0735,-0.0328,-0.0609,0.1319,-0.119],
[35.1924,-0.8104,0.8253,-0.5962,-9.35,0.2601,-0.0037,0.0368,-0.0925,-0.0269,-0.1549,0.2764,-0.1888],
[35.6873,-0.7372,0.8448,-1.3541,-6.8503,0.254,-0.0041,0.0431,-0.1168,-0.023,-0.2589,0.4332,-0.2593],
[32.6133,-0.5491,0.7277,-1.3961,-5.5317,0.2691,-0.0053,0.0532,-0.1439,-0.0153,-0.3595,0.5813,-0.3205],
[34.8437,-0.4711,0.6905,-1.4542,-4.7991,0.2492,-0.0052,0.0579,-0.1655,-0.0189,-0.3396,0.557,-0.3175],
[35.5381,-0.4317,0.6593,-1.2682,-5.2622,0.2433,-0.0053,0.063,-0.1896,-0.0217,-0.3173,0.5302,-0.316],
[36.1777,-0.4466,0.641,-0.9947,-5.8087,0.2409,-0.0052,0.0631,-0.1933,-0.022,-0.1927,0.3323,-0.2121],
[41.2921,-0.4612,0.5856,-0.5033,-6.0372,0.2021,-0.0034,0.0497,-0.1573,-0.0331,0.0525,-0.035,-0.0513],
[43.0646,-0.3308,0.3256,1.3124,-9.9318,0.1798,-0.0016,0.0281,-0.0904,-0.0459,0.3232,-0.4202,0.0842],
[44.3551,-0.1948,0.1835,1.9859,-10.8501,0.1628,-0.0011,0.0241,-0.0832,-0.0524,0.5032,-0.684,0.19],
[41.152,0.0212,-0.0243,2.9817,-12.3905,0.1771,-0.0019,0.0273,-0.0838,-0.047,0.5514,-0.7673,0.2434],
[40.7747,0.1804,-0.1901,4.1333,-15.4608,0.1742,-0.0025,0.0343,-0.0976,-0.0441,0.5815,-0.8266,0.2933],
[42.6723,0.2057,-0.2093,4.492,-16.8094,0.1599,-0.0024,0.0353,-0.0956,-0.0449,0.6759,-0.9819,0.3834],
[44.4726,0.1842,-0.1287,4.2111,-17.151,0.1485,-0.0024,0.0365,-0.0871,-0.036,0.5025,-0.7363,0.2978],
[44.4307,0.0412,0.0455,3.5578,-17.0706,0.1602,-0.0031,0.0461,-0.1195,-0.0272,0.2636,-0.3881,0.1611],
[46.146,-0.1944,0.3303,2.0667,-14.4506,0.1634,-0.0032,0.0504,-0.1357,-0.0212,0.0591,-0.0927,0.0497],
[48.5522,-0.2845,0.4266,2.1896,-16.3502,0.1537,-0.0035,0.0626,-0.1955,-0.0152,-0.2111,0.308,-0.1179],
[47.5272,-0.3843,0.5027,1.5489,-14.8051,0.1683,-0.0032,0.0566,-0.179,-0.0162,-0.1752,0.2648,-0.1172],
[42.3688,-0.2544,0.359,1.5821,-13.3586,0.2003,-0.0031,0.0394,-0.1,-0.023,0.1762,-0.2505,0.0889],
[40.419,-0.1244,0.2024,2.2651,-13.8723,0.2085,-0.0028,0.0242,-0.027,-0.0263,0.4803,-0.717,0.3102],
[41.2786,-0.4001,0.5512,0.3246,-9.9661,0.2234,-0.0037,0.0333,-0.0397,-0.0258,0.411,-0.6274,0.2957],
[44.5475,-0.4095,0.5884,0.3313,-11.0779,0.202,-0.0036,0.0417,-0.0815,-0.024,0.2501,-0.3889,0.1968],
[48.1433,-0.5054,0.6845,0.6598,-14.3615,0.1854,-0.0038,0.0599,-0.1887,-0.0266,0.0236,-0.0355,0.0216],
[36.6027,-0.2846,0.4948,0.5126,-11.9027,0.2648,-0.0058,0.0611,-0.1823,-0.0318,0.3126,-0.4516,0.177],
[32.668,-0.2953,0.5385,-0.5236,-7.6933,0.2977,-0.0064,0.0584,-0.1674,-0.0333,0.4917,-0.7205,0.2953],
[34.2675,-0.3725,0.6712,-1.4456,-4.71,0.2927,-0.0065,0.0568,-0.1384,-0.0262,0.4807,-0.7367,0.354],
[34.5736,-0.5184,0.8798,-2.5558,-3.2479,0.3039,-0.0074,0.0666,-0.1528,-0.013,0.1827,-0.311,0.2009],
[38.2705,-0.8498,1.178,-3.1281,-5.8888,0.2993,-0.0068,0.0702,-0.2122,-0.0147,-0.202,0.2993,-0.1195],
[27.2619,-0.709,1.1524,-4.729,0.3025,0.3797,-0.0092,0.0796,-0.2446,-0.0222,0.1254,-0.163,0.0363],
[30.6429,-0.6031,1.1239,-5.8827,7.3287,0.3476,-0.0081,0.0684,-0.2186,-0.027,0.4252,-0.6274,0.2628],
[38.2584,-0.5815,1.057,-5.5212,7.7327,0.2884,-0.0057,0.0424,-0.1141,-0.0255,0.4732,-0.7143,0.3218],
[34.2063,-0.6992,1.3687,-7.5293,9.9367,0.33,-0.0072,0.0412,-0.0552,-0.0037,0.0265,-0.062,0.0645],
[28.3761,-0.5032,1.1656,-6.5035,7.3478,0.3702,-0.009,0.0557,-0.0992,0.0012,-0.2162,0.3295,-0.1511],
[31.5473,-0.191,0.8482,-4.995,5.5448,0.333,-0.0093,0.0772,-0.2338,-0.0012,-0.3665,0.5893,-0.3214],
[28.0599,-0.1241,0.7701,-4.7329,5.1931,0.3597,-0.0102,0.0796,-0.2161,-0.0098,0.0298,-0.0073,-0.0557],
[23.6587,0.3036,0.2722,-3.1305,5.7577,0.3693,-0.0097,0.0627,-0.1368,-0.0164,0.4595,-0.6438,0.21],
[30.6936,0.0131,0.6061,-3.5047,1.8377,0.3406,-0.0098,0.0776,-0.195,-0.0166,0.1956,-0.2534,0.0492],
[36.2121,-0.1094,0.7833,-3.9736,0.5351,0.3083,-0.0089,0.0774,-0.1975,-0.0148,0.091,-0.0977,-0.0189],
[42.9427,-0.2087,1.2659,-7.7504,8.427,0.2634,-0.0082,0.0706,-0.1836,0.0138,-0.4419,0.6751,-0.3217],
[35.6163,-0.3308,1.3791,-8.3941,8.0466,0.3365,-0.0098,0.0787,-0.2043,-0.0005,-0.1455,0.2492,-0.1613],
[52.6206,0.342,0.8903,-5.8391,3.6866,0.1778,-0.0082,0.0886,-0.2524,0.0117,-0.5949,0.9156,-0.4441],
[73.797,-0.1315,1.1805,-3.1333,-12.7158,0.0592,-0.0043,0.0809,-0.2789,-0.052,0.1674,-0.2079,0.0315],
[106.9205,-0.8638,1.9387,-5.949,-7.0235,-0.131,0.0011,0.064,-0.2761,-0.1211,0.5938,-0.7577,0.1352]
];
var _bpCoeff_M_SYS=[
[-15.1614,0.1585,0.7927,-16.2445,64.9588,0.7016,-0.0159,0.0803,-0.1501,0.0109,0.1002,-0.1603,0.0565],
[7.1181,0.1808,0.1658,-8.1838,41.4072,0.5512,-0.0095,0.054,-0.1228,0.0057,0.0042,0.0299,-0.0661],
[16.6833,-0.0164,0.2766,-6.0204,29.5897,0.5,-0.0072,0.037,-0.0808,-0.0092,0.0673,-0.0993,0.0246],
[4.2312,0.3344,0.0389,-4.8857,26.2991,0.583,-0.0104,0.0473,-0.0885,0.0009,0.0958,-0.155,0.0586],
[7.5365,-0.0042,0.4065,-5.8405,25.1459,0.5865,-0.0109,0.0523,-0.0938,0.001,0.0934,-0.1598,0.0738],
[9.1488,-0.3319,0.8441,-9.4288,35.3411,0.6019,-0.0121,0.0661,-0.1243,-0.0028,0.105,-0.187,0.0975],
[8.942,-0.0756,0.7374,-10.0163,38.7888,0.5921,-0.0126,0.0712,-0.1373,0.013,0.076,-0.1417,0.0814],
[7.6195,0.0671,0.6085,-8.8982,34.0775,0.5961,-0.0127,0.0706,-0.1365,0.0147,0.0961,-0.1812,0.1062],
[4.7191,0.0248,0.8039,-10.5118,37.6146,0.6241,-0.014,0.074,-0.1321,0.0285,0.0747,-0.1503,0.0994],
[-3.7807,0.2569,0.5926,-10.5763,40.4022,0.6754,-0.0144,0.0649,-0.1065,0.0265,0.1273,-0.2395,0.1377],
[-4.3588,0.5128,0.4441,-11.0057,43.9366,0.6643,-0.0141,0.0598,-0.0914,0.0297,0.1526,-0.2899,0.1703],
[0.9793,0.277,0.5168,-10.2491,40.6962,0.6426,-0.0127,0.0539,-0.0858,0.0133,0.1639,-0.2987,0.1604],
[4.1744,0.2919,0.5211,-10.2719,41.0334,0.6197,-0.0121,0.0528,-0.0869,0.0122,0.1661,-0.3033,0.1633],
[6.8468,0.1938,0.5369,-9.8873,39.859,0.6088,-0.0115,0.0517,-0.0889,0.0046,0.1768,-0.321,0.1715],
[11.1461,0.2378,0.3678,-8.151,35.8557,0.5761,-0.01,0.044,-0.0795,-0.0007,0.1778,-0.321,0.1698],
[12.4221,0.276,0.2488,-6.8316,31.9031,0.5662,-0.0092,0.0391,-0.073,-0.0089,0.2003,-0.3583,0.1859],
[10.6386,0.5028,0.0451,-6.0581,30.8189,0.5675,-0.0093,0.0395,-0.0789,-0.0048,0.1885,-0.3309,0.1625],
[11.895,0.4259,0.0403,-5.1913,27.4155,0.5654,-0.0088,0.0351,-0.0686,-0.0151,0.216,-0.3783,0.1854],
[15.6199,0.2947,0.1255,-4.8706,25.2474,0.5485,-0.0083,0.0349,-0.0709,-0.0153,0.1958,-0.3402,0.1631],
[19.1961,0.2043,0.1214,-4.058,22.8341,0.5297,-0.0074,0.031,-0.0656,-0.025,0.2093,-0.3615,0.171],
[24.9014,0.1164,0.1324,-3.0351,18.7307,0.4951,-0.0063,0.0283,-0.0649,-0.0265,0.1862,-0.3184,0.1463],
[27.7411,-0.0002,0.251,-3.251,17.9354,0.4835,-0.0062,0.0313,-0.073,-0.026,0.1667,-0.2835,0.1289],
[26.5408,-0.0132,0.3133,-3.6487,17.7499,0.4961,-0.0068,0.0361,-0.0837,-0.0188,0.1384,-0.2306,0.0976],
[24.9608,0.0679,0.2933,-3.7963,17.8167,0.5066,-0.0077,0.043,-0.0991,-0.0102,0.1136,-0.1873,0.0762],
[30.7628,-0.0404,0.3473,-3.514,16.9902,0.4711,-0.0065,0.0402,-0.0991,-0.0135,0.1043,-0.172,0.0705],
[32.9166,-0.0712,0.3957,-3.9,17.9467,0.4584,-0.0062,0.0397,-0.0994,-0.0111,0.0905,-0.1473,0.0576],
[35.8384,-0.154,0.4647,-4.0996,18.2022,0.4447,-0.0061,0.0445,-0.1155,-0.0116,0.0725,-0.1148,0.0406],
[35.8936,-0.2601,0.5885,-4.4079,17.6393,0.4551,-0.0069,0.0522,-0.1317,-0.0062,0.042,-0.0594,0.0107],
[35.6599,-0.2948,0.6396,-4.5403,17.3049,0.4616,-0.0074,0.0559,-0.1397,-0.0065,0.0482,-0.0732,0.0217],
[34.2326,-0.3816,0.7322,-4.795,17.0262,0.4801,-0.0079,0.0573,-0.1393,-0.0049,0.0527,-0.0851,0.0332],
[38.436,-0.518,0.8471,-5.2375,18.6249,0.4592,-0.0074,0.0594,-0.1493,-0.0109,0.0578,-0.0961,0.042],
[37.4759,-0.3108,0.6669,-4.487,17.3228,0.4543,-0.0072,0.0558,-0.1401,-0.0071,0.0668,-0.1148,0.0546],
[38.2626,-0.2565,0.595,-3.8813,15.733,0.4471,-0.0072,0.0565,-0.1436,-0.0047,0.058,-0.0993,0.0468],
[40.1654,-0.373,0.7286,-4.669,17.4341,0.4421,-0.0071,0.0576,-0.1469,-0.0005,0.0365,-0.0612,0.0272],
[42.9794,-0.5548,0.8878,-5.2907,18.8227,0.4348,-0.0069,0.0595,-0.1514,-0.0022,0.033,-0.0585,0.0309],
[45.6449,-0.6118,0.8823,-5.0487,18.8985,0.4196,-0.0061,0.0555,-0.1462,-0.0051,0.0381,-0.069,0.0387],
[46.6551,-0.5689,0.866,-5.0611,19.3856,0.41,-0.0059,0.0537,-0.1435,-0.0027,0.039,-0.0728,0.0431],
[47.5003,-0.5697,0.8793,-5.203,19.8144,0.4057,-0.0059,0.0563,-0.1527,-0.0019,0.0291,-0.0538,0.0314],
[45.403,-0.5065,0.8608,-5.5153,21.0092,0.4195,-0.0064,0.0585,-0.1569,0.0032,0.0197,-0.0361,0.0204],
[44.8971,-0.395,0.8017,-5.6222,21.9379,0.4168,-0.0064,0.0554,-0.147,0.0027,0.0376,-0.069,0.0382],
[47.5247,-0.4291,0.8436,-5.8317,22.6883,0.3999,-0.0058,0.0527,-0.1421,0.0015,0.0382,-0.0702,0.0389],
[46.463,-0.3679,0.8717,-6.4206,23.9766,0.4049,-0.006,0.0518,-0.1372,0.0093,0.0233,-0.0445,0.0258],
[43.9842,-0.1919,0.792,-6.7209,25.4109,0.4126,-0.0063,0.0508,-0.1325,0.0119,0.037,-0.0693,0.0383],
[43.2939,-0.2722,0.8627,-7.0319,25.6372,0.4253,-0.0066,0.052,-0.1346,0.0151,0.022,-0.0414,0.0222],
[44.9267,-0.3058,0.9029,-7.1291,25.4723,0.4173,-0.0066,0.054,-0.1396,0.0166,0.008,-0.0161,0.0087],
[45.3659,-0.1577,0.7596,-6.3854,23.8924,0.4047,-0.006,0.0477,-0.1258,0.015,0.0245,-0.0444,0.0212],
[45.5821,-0.0245,0.5923,-5.4731,22.294,0.3963,-0.0056,0.046,-0.1251,0.0164,0.0239,-0.0431,0.0201],
[47.1433,-0.0461,0.591,-5.2852,21.7529,0.3877,-0.0053,0.0449,-0.1222,0.0153,0.0223,-0.0412,0.0208],
[51.495,-0.1432,0.644,-5.3385,21.775,0.3619,-0.0042,0.0417,-0.1223,0.0089,0.0218,-0.0369,0.0143],
[49.2507,-0.0452,0.5634,-5.0092,21.3118,0.3735,-0.0044,0.0403,-0.1176,0.0104,0.0345,-0.0607,0.0278],
[48.723,-0.0088,0.5464,-5.0086,21.4246,0.3773,-0.0046,0.0403,-0.114,0.0144,0.0211,-0.0365,0.0147],
[46.2919,0.137,0.4328,-4.7097,21.0581,0.387,-0.0047,0.0368,-0.1041,0.0171,0.0335,-0.0595,0.027],
[47.5969,0.1489,0.3829,-4.2807,20.076,0.3772,-0.0039,0.0315,-0.0941,0.0134,0.0397,-0.0681,0.0283],
[48.5103,0.1248,0.3886,-4.0219,19.1219,0.3741,-0.0039,0.0318,-0.0943,0.0115,0.0417,-0.0714,0.03],
[47.0617,0.2003,0.3427,-3.9935,19.2648,0.3815,-0.0041,0.0313,-0.0915,0.0121,0.0505,-0.0878,0.0394],
[47.9002,0.1572,0.3732,-3.8154,17.8605,0.3802,-0.0041,0.032,-0.0944,0.0113,0.0408,-0.067,0.024],
[49.115,0.0782,0.4887,-4.5668,19.8764,0.3783,-0.0042,0.0339,-0.0974,0.0137,0.0304,-0.0508,0.019],
[49.9451,0.1037,0.4323,-3.9989,18.2108,0.3716,-0.0039,0.0318,-0.0942,0.0126,0.0354,-0.0602,0.0246],
[50.1287,0.2012,0.3324,-3.2058,15.608,0.3664,-0.0039,0.0327,-0.0981,0.0177,0.0133,-0.0189,0.0001],
[49.51,0.1993,0.3903,-3.8043,17.1157,0.3729,-0.0042,0.0344,-0.1008,0.0221,0.0041,-0.0038,-0.0061],
[47.0301,0.2961,0.3665,-3.9702,17.4284,0.3864,-0.0047,0.0328,-0.0906,0.0207,0.0246,-0.0408,0.0138],
[46.9571,0.2268,0.4324,-4.3249,18.4933,0.3932,-0.0048,0.0332,-0.0914,0.0225,0.0162,-0.0255,0.0051],
[45.7187,0.319,0.3143,-3.5355,16.3535,0.3986,-0.0048,0.0327,-0.0905,0.0195,0.039,-0.0672,0.0285],
[46.6338,0.3294,0.3122,-3.6994,16.9404,0.3928,-0.0047,0.0327,-0.0892,0.02,0.0422,-0.0754,0.036],
[46.796,0.2184,0.4173,-4.2913,18.3125,0.4005,-0.0048,0.0316,-0.0843,0.0138,0.0632,-0.1146,0.0591],
[45.6059,0.2609,0.3536,-3.7119,16.4744,0.409,-0.005,0.0313,-0.0814,0.0161,0.0671,-0.1239,0.0669],
[46.2843,0.1969,0.384,-3.6001,15.9912,0.4103,-0.005,0.0321,-0.0828,0.0153,0.0735,-0.139,0.08],
[42.7066,0.3391,0.2772,-3.5789,16.5957,0.4304,-0.0057,0.0333,-0.0798,0.0158,0.0981,-0.1852,0.1067],
[42.8015,0.3061,0.3293,-3.7417,16.4765,0.4348,-0.0061,0.0357,-0.0812,0.0203,0.0909,-0.1775,0.1098],
[44.6588,0.3589,0.2756,-3.1211,14.5181,0.4196,-0.0059,0.0374,-0.0881,0.0175,0.0943,-0.1832,0.1126],
[45.4978,0.2369,0.3198,-2.8753,12.9699,0.4238,-0.0058,0.0377,-0.09,0.0126,0.0997,-0.1911,0.1148],
[44.3791,0.247,0.2747,-2.2776,10.7861,0.4342,-0.0061,0.0387,-0.0918,0.0106,0.1113,-0.2121,0.1265],
[44.5213,0.3308,0.2335,-2.5761,12.6357,0.4295,-0.006,0.0393,-0.0953,0.015,0.1005,-0.192,0.1141],
[43.3339,0.3496,0.2289,-2.6952,12.6151,0.4397,-0.0064,0.0411,-0.0987,0.0118,0.1138,-0.2135,0.1223],
[45.7745,0.2806,0.323,-3.0124,12.5836,0.4279,-0.0062,0.0429,-0.1061,0.0132,0.0996,-0.1888,0.1104],
[46.2858,0.2501,0.3239,-2.6897,11.1237,0.4274,-0.0059,0.0399,-0.1008,0.0086,0.1214,-0.2293,0.1336],
[47.1461,0.0565,0.3804,-1.9028,7.5777,0.4368,-0.0058,0.0399,-0.1016,-0.0042,0.1495,-0.2777,0.1579],
[49.8411,-0.0213,0.4353,-2.2574,9.0572,0.4224,-0.0051,0.0374,-0.0989,-0.0067,0.1499,-0.2787,0.1591],
[54.41,-0.2754,0.6713,-3.3139,10.8614,0.4065,-0.0045,0.0392,-0.1059,-0.0134,0.1536,-0.2881,0.1687],
[59.0571,-0.3916,0.714,-3.2563,11.6335,0.3792,-0.0031,0.0313,-0.0925,-0.0235,0.1848,-0.3462,0.2023],
[61.5501,-0.4923,0.8257,-3.7049,12.2735,0.3688,-0.0028,0.0301,-0.0892,-0.0258,0.1974,-0.3735,0.2231],
[62.0991,-0.5602,0.8523,-3.3702,9.855,0.371,-0.0025,0.0277,-0.085,-0.0253,0.1895,-0.3572,0.2113],
[63.7402,-0.7486,1.0333,-4.0639,10.5288,0.3743,-0.0026,0.0296,-0.0853,-0.0264,0.1907,-0.3647,0.2234],
[63.1912,-0.7684,1.0572,-4.1343,10.1666,0.3825,-0.0028,0.0301,-0.0846,-0.0226,0.1752,-0.3347,0.204],
[65.29,-0.9003,1.2109,-4.7056,10.0344,0.3789,-0.0031,0.0353,-0.0982,-0.0171,0.1415,-0.2745,0.173],
[69.7586,-0.9059,1.1421,-3.8514,8.3464,0.3466,-0.0015,0.0272,-0.0852,-0.0254,0.1633,-0.3147,0.1963],
[68.7204,-0.7413,1.161,-4.8929,11.4709,0.347,-0.0023,0.0323,-0.0945,-0.0166,0.1384,-0.2677,0.1676],
[70.0709,-0.7105,1.1845,-4.9763,11.0263,0.3366,-0.0017,0.0271,-0.0857,-0.0132,0.1197,-0.2317,0.1451],
[71.2247,-0.6095,1.0475,-4.2244,9.2028,0.3239,-0.0008,0.022,-0.0796,-0.0212,0.1383,-0.2581,0.1496],
[71.0728,-0.5897,0.954,-3.2255,5.828,0.3275,-0.0005,0.0181,-0.0707,-0.02,0.1457,-0.2721,0.1573],
[70.0217,-0.3531,0.6571,-1.1748,0.806,0.3265,-0.0006,0.0201,-0.0785,-0.0091,0.1053,-0.1976,0.115],
[70.5203,-0.3866,0.7711,-1.2734,-1.0004,0.3319,-0.0017,0.0287,-0.092,0.009,0.0424,-0.0915,0.0678],
[76.3547,-0.7212,0.9341,-1.3303,-1.6526,0.314,-0.0002,0.0247,-0.0938,-0.0122,0.0896,-0.174,0.1101],
[90.6025,-1.3557,1.1746,0.1551,-7.729,0.2521,0.0034,0.0132,-0.0881,-0.0357,0.0885,-0.1674,0.1033],
[102.6662,-1.2263,0.8589,3.2534,-15.7885,0.1576,0.0072,-0.0076,-0.0516,-0.0325,0.0706,-0.1432,0.1009],
[102.9154,-1.5899,1.4523,-0.5061,-7.5933,0.1871,0.0055,0.002,-0.0596,-0.0411,0.1113,-0.2264,0.1604],
[125.2207,-3.3398,2.9466,-5.4863,-1.908,0.1438,0.0076,0.0111,-0.0959,-0.1006,0.1222,-0.2249,0.1376],
[125.8697,-3.2997,3.1051,-7.3155,3.4281,0.1505,0.0067,0.0193,-0.1148,-0.0879,0.0819,-0.1569,0.1076],
[99.6314,-2.8535,3.065,-6.4997,-4.9829,0.3473,-0.001,0.0499,-0.1346,-0.0354,-0.0379,0.0681,-0.0284]
];
var _bpCoeff_M_DIA=[
[-13.567,-1.1325,-1.7078,28.8607,-81.1719,0.4118,0.0003,-0.0263,0.0507,-0.0087,-0.1202,0.2977,-0.2691],
[-43.7777,1.9512,-3.8763,28.8717,-57.6407,0.4741,-0.0029,-0.0496,0.1518,-0.0191,0.1992,-0.2879,0.0508],
[-35.5221,1.6542,-3.2001,22.4882,-41.299,0.4425,-0.0025,-0.0428,0.1269,-0.0674,0.3133,-0.465,0.1062],
[-25.9772,2.0924,-3.8188,24.4956,-38.8551,0.3556,0.0003,-0.0543,0.1499,-0.0796,0.4423,-0.7299,0.2906],
[-16.9931,2.2497,-3.7873,23.1323,-35.1791,0.2916,0.0006,-0.0481,0.1416,-0.0641,0.3962,-0.6572,0.2638],
[-19.6683,2.3137,-3.7117,22.8638,-35.7152,0.3203,-0.0015,-0.0388,0.1406,-0.0689,0.4499,-0.7699,0.3469],
[-33.2858,2.7679,-4.0941,22.3138,-27.6548,0.3986,-0.0021,-0.0592,0.2053,-0.0938,0.6243,-1.0803,0.5056],
[-42.522,3.0229,-4.2155,22.1584,-27.6854,0.4632,-0.0051,-0.0392,0.1567,-0.0631,0.512,-0.8671,0.3759],
[-34.2517,2.7721,-3.6109,17.4453,-15.4161,0.4233,-0.0055,-0.0269,0.1286,-0.0371,0.366,-0.6077,0.2427],
[-42.4833,3.1554,-3.8233,16.9605,-12.0012,0.466,-0.0072,-0.0191,0.1105,-0.0294,0.3572,-0.5855,0.2225],
[-54.4375,3.0764,-3.5785,15.2542,-9.8518,0.569,-0.0112,-0.0014,0.0879,-0.034,0.4004,-0.6627,0.2631],
[-38.5925,2.3768,-3.1326,15.4931,-14.1216,0.5015,-0.0094,0.0059,0.0528,-0.0475,0.355,-0.5818,0.2245],
[-40.8119,2.5241,-3.3547,16.1453,-12.993,0.5119,-0.0092,0.0039,0.0554,-0.0504,0.3968,-0.6637,0.2771],
[-46.3014,2.6717,-3.5156,16.4588,-11.9729,0.5495,-0.0106,0.0106,0.0468,-0.0493,0.4299,-0.7314,0.3246],
[-47.6314,2.9586,-3.758,16.7192,-10.3567,0.5434,-0.0102,0.0067,0.0518,-0.0595,0.4837,-0.8241,0.3686],
[-41.6665,2.9392,-3.8754,17.5857,-10.8233,0.4983,-0.0073,-0.0149,0.0964,-0.0817,0.5737,-0.987,0.4563],
[-45.7369,2.9396,-3.8633,17.231,-10.561,0.5321,-0.008,-0.0146,0.1016,-0.0765,0.5824,-1.0084,0.4748],
[-51.929,2.9378,-3.7832,15.9238,-7.0752,0.586,-0.0101,-0.0013,0.0747,-0.0647,0.5498,-0.9515,0.4469],
[-45.8559,3.0516,-3.9216,17.0729,-10.1336,0.5356,-0.0086,-0.0063,0.0786,-0.0616,0.5196,-0.8956,0.415],
[-39.5605,2.8551,-3.5847,14.9465,-5.3128,0.5025,-0.0082,-0.003,0.0687,-0.0683,0.5134,-0.8848,0.4109],
[-33.7657,2.9223,-3.533,14.1257,-2.6863,0.4575,-0.0075,-0.0012,0.0596,-0.0664,0.4876,-0.8388,0.3872],
[-32.281,2.6018,-3.2278,12.8399,-0.8793,0.472,-0.0081,0.0063,0.0419,-0.062,0.4496,-0.7751,0.3605],
[-31.5797,2.3929,-2.9101,11.2038,1.5782,0.4845,-0.0091,0.0143,0.0265,-0.0586,0.4152,-0.712,0.3258],
[-32.2816,2.6349,-3.0487,11.5875,0.5188,0.4779,-0.0097,0.0203,0.0104,-0.044,0.3694,-0.6297,0.2818],
[-25.44,2.7183,-3.2535,13.5284,-4.0414,0.421,-0.007,0.0038,0.0396,-0.0469,0.3676,-0.6261,0.2792],
[-22.8873,2.5652,-3.2543,13.672,-3.1603,0.4141,-0.0056,-0.0066,0.0583,-0.0566,0.3787,-0.6382,0.2747],
[-20.7911,2.6849,-3.4699,14.9131,-5.2628,0.3921,-0.0042,-0.015,0.0686,-0.0663,0.3974,-0.6642,0.2789],
[-18.557,2.4292,-3.0989,12.2737,1.0228,0.3937,-0.0045,-0.0121,0.0655,-0.073,0.4005,-0.667,0.277],
[-17.5306,2.5085,-3.1093,11.7413,3.3022,0.3838,-0.0047,-0.009,0.0598,-0.0637,0.3744,-0.6243,0.2595],
[-14.3488,2.3673,-3.0068,11.4653,3.7471,0.3712,-0.004,-0.0129,0.0679,-0.0681,0.3759,-0.6244,0.2561],
[-16.6395,2.3516,-2.9622,11.2382,3.1551,0.3924,-0.0047,-0.0114,0.0678,-0.0675,0.3777,-0.6258,0.2543],
[-10.6475,2.2971,-2.8656,10.1755,7.4446,0.3509,-0.0034,-0.0169,0.0752,-0.0763,0.3958,-0.6548,0.2643],
[-10.0847,2.4662,-2.9361,10.2311,6.9534,0.3368,-0.0033,-0.0182,0.08,-0.073,0.3922,-0.6484,0.2607],
[-9.646,2.4037,-2.8587,10.171,5.6614,0.3398,-0.0036,-0.0141,0.0709,-0.0667,0.3688,-0.6116,0.2487],
[-5.5,2.2058,-2.7946,11.4006,-0.0691,0.3246,-0.003,-0.0129,0.0635,-0.0713,0.3492,-0.5757,0.231],
[-3.1184,2.0845,-2.7566,11.9122,-2.7527,0.3161,-0.0025,-0.0137,0.0596,-0.0779,0.347,-0.5661,0.2186],
[-1.8889,1.938,-2.5612,10.5284,0.4557,0.3178,-0.0027,-0.01,0.0505,-0.0868,0.3703,-0.6072,0.2401],
[1.3652,1.8159,-2.5509,11.3987,-2.5982,0.3031,-0.002,-0.0117,0.0496,-0.095,0.3856,-0.6354,0.2568],
[4.1129,1.8155,-2.5332,11.0415,-0.7368,0.2849,-0.0018,-0.0081,0.038,-0.0883,0.364,-0.6035,0.2493],
[1.4862,1.9999,-2.7504,12.2222,-3.4789,0.295,-0.0018,-0.0113,0.0461,-0.0881,0.3736,-0.6168,0.2503],
[-2.474,2.0859,-2.8319,12.5224,-3.8212,0.3229,-0.0028,-0.0094,0.0487,-0.086,0.392,-0.6551,0.2772],
[-0.415,1.9078,-2.6838,12.7489,-6.852,0.3217,-0.0029,-0.0082,0.0472,-0.0801,0.3635,-0.6077,0.2576],
[-0.0497,1.8113,-2.6253,12.8018,-7.7129,0.3277,-0.0029,-0.0071,0.0414,-0.0794,0.3497,-0.5807,0.2402],
[-1.5833,1.7827,-2.6894,13.4925,-9.1732,0.3439,-0.003,-0.0061,0.0371,-0.0845,0.3665,-0.6098,0.2548],
[1.209,1.7298,-2.6076,12.8518,-6.9268,0.3277,-0.0027,-0.0052,0.0323,-0.087,0.3703,-0.6203,0.2656],
[1.2834,1.6318,-2.5106,12.1368,-4.9164,0.335,-0.0025,-0.0086,0.0415,-0.0924,0.386,-0.6467,0.2773],
[-0.4438,1.6936,-2.4801,11.7414,-4.8147,0.3463,-0.0031,-0.0075,0.0435,-0.0895,0.3834,-0.6422,0.2749],
[-0.2325,1.613,-2.4272,12.1673,-8.1046,0.3529,-0.0033,-0.0065,0.0434,-0.0851,0.3606,-0.6019,0.2545],
[-2.1989,1.6982,-2.4926,12.7697,-10.7769,0.3643,-0.0037,-0.0061,0.0459,-0.0859,0.3821,-0.6441,0.2821],
[-0.8411,1.6919,-2.4301,12.0592,-8.667,0.3572,-0.004,-0.0005,0.0305,-0.0865,0.3748,-0.6317,0.2776],
[0.1678,1.6387,-2.3829,11.423,-6.0839,0.3552,-0.0038,-0.0004,0.0275,-0.0933,0.3894,-0.6552,0.2867],
[0.8079,1.7778,-2.4652,11.0582,-4.0097,0.3404,-0.0029,-0.0096,0.0477,-0.0928,0.4036,-0.6792,0.2963],
[-1.1219,1.8103,-2.4361,10.7708,-4.1791,0.3561,-0.0036,-0.0078,0.0484,-0.0819,0.3736,-0.6278,0.2717],
[-4.8133,1.8058,-2.331,9.8828,-2.9487,0.3871,-0.0049,-0.0019,0.0409,-0.0736,0.3513,-0.5879,0.2503],
[-8.1979,2.0298,-2.494,10.6089,-5.3076,0.4011,-0.0058,0.0028,0.0321,-0.0692,0.3504,-0.5851,0.247],
[-6.752,2.0613,-2.4814,10.131,-3.6573,0.3884,-0.0055,0.0002,0.0371,-0.0753,0.3769,-0.6294,0.2655],
[-3.566,1.8329,-2.2802,9.0883,-0.4962,0.3807,-0.005,-0.0007,0.0371,-0.081,0.3819,-0.6401,0.2738],
[1.0387,1.7975,-2.2844,9.2486,-0.6268,0.3494,-0.0037,-0.0064,0.0437,-0.0821,0.3621,-0.6004,0.2472],
[1.6962,1.5592,-2.1909,9.9497,-4.5187,0.3625,-0.0033,-0.0098,0.0505,-0.0904,0.364,-0.5976,0.2383],
[1.7174,1.6924,-2.3499,11.1189,-8.075,0.3556,-0.0029,-0.0144,0.0602,-0.0871,0.3514,-0.5716,0.2195],
[-1.1808,1.896,-2.4788,11.4555,-8.5302,0.3668,-0.0036,-0.0124,0.0586,-0.0775,0.3326,-0.5377,0.2006],
[-1.9286,1.8974,-2.4107,10.6569,-6.2357,0.3747,-0.0042,-0.0079,0.0509,-0.0731,0.3224,-0.5217,0.1951],
[-0.6762,1.6316,-2.0498,8.2301,-0.4293,0.3859,-0.0052,0.0017,0.0314,-0.0748,0.3067,-0.4907,0.1753],
[0.0177,1.3931,-1.7224,6.2104,3.67,0.398,-0.006,0.0074,0.0231,-0.0781,0.3064,-0.4907,0.1763],
[1.8242,1.4415,-1.8531,7.4867,0.3209,0.381,-0.0045,-0.0055,0.0517,-0.0808,0.3148,-0.504,0.181],
[3.3864,1.5296,-1.8957,8.1805,-2.714,0.3667,-0.0046,-0.0044,0.0516,-0.0669,0.2582,-0.4028,0.1272],
[1.4518,1.5557,-2.0588,9.891,-7.5275,0.3836,-0.0047,-0.0045,0.0515,-0.0676,0.2556,-0.3964,0.1218],
[-0.2228,1.7851,-2.3148,11.3445,-10.9345,0.3835,-0.0048,-0.0063,0.0572,-0.0663,0.2738,-0.4312,0.1425],
[-1.2686,1.848,-2.3626,11.0795,-8.9995,0.3885,-0.0049,-0.0053,0.0531,-0.0765,0.3143,-0.5003,0.1745],
[-1.1771,1.9498,-2.33,9.7844,-3.6954,0.382,-0.0052,-0.0022,0.0473,-0.0778,0.3354,-0.5421,0.202],
[-1.5905,1.9246,-2.2012,8.7588,-1.7051,0.39,-0.0063,0.0071,0.0279,-0.0723,0.315,-0.5067,0.1847],
[1.3907,1.7403,-1.9434,6.9646,2.6064,0.3789,-0.006,0.0072,0.0262,-0.0787,0.3279,-0.5282,0.1939],
[5.7059,1.724,-1.9265,7.7741,-2.061,0.3493,-0.0054,0.0068,0.0244,-0.0694,0.282,-0.4467,0.1515],
[12.6597,1.3459,-1.7148,8.837,-8.9553,0.3265,-0.0048,0.0144,-0.0045,-0.065,0.1958,-0.2892,0.0669],
[14.3993,1.3957,-1.9442,11.1527,-15.7051,0.3118,-0.0037,0.0089,-0.0004,-0.0745,0.2201,-0.3286,0.0822],
[17.6818,1.388,-1.9866,11.7883,-17.7697,0.2899,-0.0031,0.0095,-0.0089,-0.0708,0.1938,-0.2807,0.056],
[11.917,1.6817,-2.3045,13.3873,-21.1645,0.3206,-0.0046,0.0186,-0.0278,-0.0691,0.2114,-0.3145,0.0776],
[9.2777,1.6967,-2.2055,11.4045,-13.2029,0.3418,-0.0056,0.0253,-0.0412,-0.0758,0.2487,-0.3832,0.1165],
[5.8584,1.6874,-2.0515,9.5688,-8.1664,0.3719,-0.0073,0.0382,-0.0675,-0.0715,0.2508,-0.3923,0.1289],
[9.3245,1.5374,-1.8954,9.7989,-11.7858,0.3581,-0.0073,0.0413,-0.0754,-0.063,0.2057,-0.3147,0.0928],
[16.2286,1.2597,-1.7964,11.1013,-18.2966,0.3267,-0.0058,0.0385,-0.0835,-0.0656,0.1577,-0.2201,0.0326],
[15.2268,1.0841,-1.7857,12.168,-22.5467,0.3504,-0.0059,0.0373,-0.0777,-0.0718,0.1751,-0.253,0.0528],
[10.4724,1.4733,-2.2295,13.8392,-23.1801,0.3634,-0.0056,0.0276,-0.0497,-0.0848,0.2636,-0.4153,0.1436],
[5.2365,1.5165,-2.1802,12.4214,-17.9441,0.4039,-0.0071,0.0317,-0.0486,-0.0919,0.3179,-0.5147,0.1988],
[10.1259,1.4465,-1.9666,11.6878,-19.1724,0.3722,-0.0063,0.0273,-0.0379,-0.0743,0.2451,-0.3873,0.1349],
[8.7996,1.6042,-2.2123,13.8638,-26.1613,0.3767,-0.006,0.0209,-0.0216,-0.0624,0.2044,-0.3117,0.0907],
[7.3808,1.9753,-2.5467,14.6551,-24.7762,0.366,-0.0058,0.0184,-0.0173,-0.0685,0.2633,-0.4213,0.1535],
[8.2409,1.8093,-1.8703,8.5537,-10.4574,0.3742,-0.008,0.033,-0.0361,-0.0481,0.1904,-0.2951,0.0924],
[16.3443,1.4613,-1.5844,8.5531,-13.7014,0.3376,-0.0067,0.028,-0.0305,-0.0421,0.1473,-0.2208,0.0564],
[13.6814,1.7899,-2.0949,11.8906,-20.3017,0.3408,-0.0062,0.0239,-0.0268,-0.0499,0.1898,-0.2958,0.0953],
[-2.2305,2.0458,-2.0636,8.7608,-9.0684,0.4491,-0.0095,0.0277,-0.0118,-0.0522,0.2641,-0.4295,0.1659],
[7.1024,1.4245,-1.2884,5.4006,-5.1633,0.4266,-0.0107,0.0507,-0.0701,-0.0223,0.0801,-0.0982,-0.0105],
[22.5224,1.2411,-1.1587,5.4827,-6.229,0.3231,-0.008,0.0497,-0.0852,-0.035,0.0837,-0.1047,-0.0066],
[7.1688,2.0574,-2.1429,8.7073,-6.973,0.3913,-0.0079,0.0285,-0.027,-0.0746,0.3209,-0.5246,0.2072],
[10.9219,1.7121,-1.5447,6.0756,-5.588,0.3914,-0.0095,0.0458,-0.0634,-0.034,0.1515,-0.2269,0.0567],
[0.0292,1.3826,-1.5163,7.1831,-10.5716,0.5124,-0.0137,0.0821,-0.1555,-0.0443,0.1613,-0.2416,0.0645],
[-7.4708,1.924,-1.6304,5.8484,-7.4136,0.5394,-0.0152,0.0752,-0.1166,-0.0193,0.205,-0.3492,0.1599],
[17.4158,1.6902,-1.3304,3.6898,3.0431,0.3737,-0.0096,0.0478,-0.0772,-0.0183,0.131,-0.2054,0.0662],
[-2.725,3.8134,-2.3052,3.5243,8.0191,0.4042,-0.0133,0.0238,0.0586,0.0627,0.0422,-0.052,-0.018]
];
function calcHeightPctile(age, sex, heightCm) {
var idx = Math.max(0, Math.min(217, Math.round(age * 12) - 24));
var L, M, S;
if (sex === 'female') { L = _htLMS_F_L[idx]; M = _htLMS_F_M[idx]; S = _htLMS_F_S[idx]; }
else { L = _htLMS_M_L[idx]; M = _htLMS_M_M[idx]; S = _htLMS_M_S[idx]; }
var z = (Math.pow(heightCm / M, L) - 1) / (L * S);
return { z: z, percentile: normalCDF(z) * 100 };
}
function computeBPPercentile(age, sex, heightCm, bpType, bpValue) {
var t1, t2, t3, t4, t5, ta1, ta2, ta3, ta4, ta5, tb1, tb2, tb3, tb4, tb5, w;
if (sex === 'female') {
t1=106.7; t2=140.7; t3=154.0; t4=160.5; t5=168.9;
ta1=5.00; ta2=10.70; ta3=13.16; ta4=14.51; ta5=17.33;
tb1=6.701; tb2=16.438; tb3=46.80; tb4=84.46; tb5=203.608;
w = (age - 10) * (heightCm - 147);
} else {
t1=107.8; t2=140.0; t3=154.5; t4=166.4; t5=179.1;
ta1=5.06; ta2=10.79; ta3=13.22; ta4=14.51; ta5=17.30;
tb1=-15; tb2=8.9; tb3=50.375; tb4=112.684; tb5=250.04;
w = (age - 10) * (heightCm - 150);
}
var x = heightCm, y = age;
// Height restricted cubic splines
var x2a = Math.max(0, x - t1); var x2b = Math.max(0, x - t4); var x2c = Math.max(0, x - t5);
var x2 = Math.pow(x2a,3) - Math.pow(x2b,3)*(t5-t1)/(t5-t4) + Math.pow(x2c,3)*(t4-t1)/(t5-t4);
var x3a = Math.max(0, x - t2);
var x3 = Math.pow(x3a,3) - Math.pow(x2b,3)*(t5-t2)/(t5-t4) + Math.pow(x2c,3)*(t4-t2)/(t5-t4);
var x4a = Math.max(0, x - t3);
var x4 = Math.pow(x4a,3) - Math.pow(x2b,3)*(t5-t3)/(t5-t4) + Math.pow(x2c,3)*(t4-t3)/(t5-t4);
var x2s = x2/100, x3s = x3/100, x4s = x4/100;
// Age restricted cubic splines
var y2a = Math.max(0, y - ta1); var y2b = Math.max(0, y - ta4); var y2c = Math.max(0, y - ta5);
var y2 = Math.pow(y2a,3) - Math.pow(y2b,3)*(ta5-ta1)/(ta5-ta4) + Math.pow(y2c,3)*(ta4-ta1)/(ta5-ta4);
var y3a = Math.max(0, y - ta2);
var y3 = Math.pow(y3a,3) - Math.pow(y2b,3)*(ta5-ta2)/(ta5-ta4) + Math.pow(y2c,3)*(ta4-ta2)/(ta5-ta4);
var y4a = Math.max(0, y - ta3);
var y4 = Math.pow(y4a,3) - Math.pow(y2b,3)*(ta5-ta3)/(ta5-ta4) + Math.pow(y2c,3)*(ta4-ta3)/(ta5-ta4);
var y2s = y2/100, y3s = y3/100, y4s = y4/100;
// Interaction restricted cubic splines
var w2a = Math.max(0, w - tb1); var w2b = Math.max(0, w - tb4); var w2c = Math.max(0, w - tb5);
var w2 = Math.pow(w2a,3) - Math.pow(w2b,3)*(tb5-tb1)/(tb5-tb4) + Math.pow(w2c,3)*(tb4-tb1)/(tb5-tb4);
var w3a = Math.max(0, w - tb2);
var w3 = Math.pow(w3a,3) - Math.pow(w2b,3)*(tb5-tb2)/(tb5-tb4) + Math.pow(w2c,3)*(tb4-tb2)/(tb5-tb4);
var w4a = Math.max(0, w - tb3);
var w4 = Math.pow(w4a,3) - Math.pow(w2b,3)*(tb5-tb3)/(tb5-tb4) + Math.pow(w2c,3)*(tb4-tb3)/(tb5-tb4);
var w2s = w2/10000, w3s = w3/10000, w4s = w4/10000;
// Select coefficient array
var coeff;
if (sex === 'female') coeff = (bpType === 'sys') ? _bpCoeff_F_SYS : _bpCoeff_F_DIA;
else coeff = (bpType === 'sys') ? _bpCoeff_M_SYS : _bpCoeff_M_DIA;
// Compute predicted BP at each percentile and find closest match
var fxsys = new Array(99);
for (var i = 0; i < 99; i++) {
fxsys[i] = coeff[i][0] + coeff[i][5]*x + coeff[i][6]*x2s + coeff[i][7]*x3s + coeff[i][8]*x4s
+ coeff[i][1]*y + coeff[i][2]*y2s + coeff[i][3]*y3s + coeff[i][4]*y4s
+ coeff[i][9]*w + coeff[i][10]*w2s + coeff[i][11]*w3s + coeff[i][12]*w4s;
}
var minDiff = Infinity, percentile = 50;
for (var i = 0; i < 99; i++) {
var diff = Math.abs(bpValue - fxsys[i]);
if (diff < minDiff) { minDiff = diff; percentile = i + 1; }
}
return { percentile: percentile, predicted: fxsys };
}
function classifyBPFromPercentiles(age, sysPctile, diaPctile, sys, dia) {
var sysClass, diaClass;
if (age >= 13) {
// Ages >= 13: use absolute thresholds per AAP 2017
if (sys >= 140) sysClass = 'stage2';
else if (sys >= 130) sysClass = 'stage1';
else if (sys >= 120) sysClass = 'elevated';
else sysClass = 'normal';
if (dia >= 90) diaClass = 'stage2';
else if (dia >= 80) diaClass = 'stage1';
else diaClass = 'normal';
} else {
// Ages 1-<13: use percentile thresholds
if (sysPctile >= 95 + 12 || sys >= 140) sysClass = 'stage2';
else if (sysPctile >= 95 || sys >= 130) sysClass = 'stage1';
else if (sysPctile >= 90 || sys >= 120) sysClass = 'elevated';
else sysClass = 'normal';
if (diaPctile >= 95 + 12 || dia >= 90) diaClass = 'stage2';
else if (diaPctile >= 95 || dia >= 80) diaClass = 'stage1';
else if (diaPctile >= 90) diaClass = 'elevated';
else diaClass = 'normal';
}
var levels = { normal: 0, elevated: 1, stage1: 2, stage2: 3 };
var overall = levels[sysClass] >= levels[diaClass] ? sysClass : diaClass;
return { sysClass: sysClass, diaClass: diaClass, classification: overall };
}
var classLabels = {
normal: { text: 'Normal', color: '#10b981', bg: '#d1fae5' },
elevated: { text: 'Elevated', color: '#f59e0b', bg: '#fef3c7' },
stage1: { text: 'Stage 1 Hypertension', color: '#f97316', bg: '#ffedd5' },
stage2: { text: 'Stage 2 Hypertension', color: '#ef4444', bg: '#fee2e2' }
};
document.getElementById('btn-calc-bp').addEventListener('click', function() {
var age = parseFloat(document.getElementById('bp-age').value);
var sex = document.getElementById('bp-sex').value;
var sys = parseFloat(document.getElementById('bp-systolic').value);
var dia = parseFloat(document.getElementById('bp-diastolic').value);
var heightCm = parseFloat(document.getElementById('bp-height').value);
if (!age || !sex || !sys || !dia || !heightCm) { showToast('Fill in all fields including height', 'error'); return; }
if (age < 1 || age > 17) { showToast('Age must be 1-17 years', 'error'); return; }
var htResult = calcHeightPctile(age, sex, heightCm);
var sysResult = computeBPPercentile(age, sex, heightCm, 'sys', sys);
var diaResult = computeBPPercentile(age, sex, heightCm, 'dia', dia);
var bpClass = classifyBPFromPercentiles(age, sysResult.percentile, diaResult.percentile, sys, dia);
// Get 50th, 90th, 95th predicted values for display
var sys50 = sysResult.predicted[49].toFixed(0), sys90 = sysResult.predicted[89].toFixed(0), sys95 = sysResult.predicted[94].toFixed(0);
var dia50 = diaResult.predicted[49].toFixed(0), dia90 = diaResult.predicted[89].toFixed(0), dia95 = diaResult.predicted[94].toFixed(0);
var cl = classLabels[bpClass.classification];
var resultDiv = document.getElementById('bp-result');
resultDiv.classList.remove('hidden');
resultDiv.innerHTML =
'<div class="calc-result-header" style="background:' + cl.bg + ';border-color:' + cl.color + ';">' +
'<div style="font-size:18px;font-weight:700;color:' + cl.color + ';">' + cl.text + '</div>' +
'<div style="font-size:13px;color:var(--g600);margin-top:4px;">' + sys + '/' + dia + ' mmHg &mdash; ' + age + ' year old ' + sex + ', ' + heightCm + ' cm</div>' +
'</div>' +
'<div class="calc-result-grid">' +
'<div class="calc-result-item">' +
'<div class="calc-result-label">Systolic</div>' +
'<div class="calc-result-value">' + sysResult.percentile + '<span style="font-size:12px;">th %ile</span></div>' +
'<div class="calc-result-sub" style="color:' + classLabels[bpClass.sysClass].color + ';">' + classLabels[bpClass.sysClass].text + '</div>' +
'</div>' +
'<div class="calc-result-item">' +
'<div class="calc-result-label">Diastolic</div>' +
'<div class="calc-result-value">' + diaResult.percentile + '<span style="font-size:12px;">th %ile</span></div>' +
'<div class="calc-result-sub" style="color:' + classLabels[bpClass.diaClass].color + ';">' + classLabels[bpClass.diaClass].text + '</div>' +
'</div>' +
'<div class="calc-result-item">' +
'<div class="calc-result-label">Height</div>' +
'<div class="calc-result-value">' + Math.round(htResult.percentile) + '<span style="font-size:12px;">th %ile</span></div>' +
'<div class="calc-result-sub">Z = ' + htResult.z.toFixed(2) + '</div>' +
'</div>' +
'<div class="calc-result-item">' +
'<div class="calc-result-label">Reference (50th %ile)</div>' +
'<div class="calc-result-value" style="font-size:16px;">' + sys50 + '/' + dia50 + '</div>' +
'<div class="calc-result-sub">90th: ' + sys90 + '/' + dia90 + ' &bull; 95th: ' + sys95 + '/' + dia95 + '</div>' +
'</div>' +
'</div>' +
'<p style="font-size:11px;color:var(--g400);margin:12px 0 0;">BCM/Rosner quantile regression percentiles adjusted to patient height. AAP 2017 classification.</p>';
// Generate BP curves across ages 1-17 for this sex/height
renderBPChart(age, sex, heightCm, sys, dia);
});
function renderBPChart(patientAge, sex, heightCm, patientSys, patientDia) {
if (typeof Chart === 'undefined') return;
var container = document.getElementById('bp-chart-container');
if (!container) return;
container.classList.remove('hidden');
if (_chartInstances['bp-chart-canvas']) { _chartInstances['bp-chart-canvas'].destroy(); _chartInstances['bp-chart-canvas'] = null; }
// Generate percentile curves across ages 1-17
var sys50 = [], sys90 = [], sys95 = [], dia50 = [], dia90 = [], dia95 = [];
for (var a = 1; a <= 17; a++) {
var sr = computeBPPercentile(a, sex, heightCm, 'sys', 100);
var dr = computeBPPercentile(a, sex, heightCm, 'dia', 60);
sys50.push({x:a, y:Math.round(sr.predicted[49])}); sys90.push({x:a, y:Math.round(sr.predicted[89])}); sys95.push({x:a, y:Math.round(sr.predicted[94])});
dia50.push({x:a, y:Math.round(dr.predicted[49])}); dia90.push({x:a, y:Math.round(dr.predicted[89])}); dia95.push({x:a, y:Math.round(dr.predicted[94])});
}
var datasets = [
{ label: 'SBP 95th', data: sys95, borderColor: 'rgba(239,68,68,0.7)', borderWidth: 2, borderDash: [4,4], pointRadius: 0, fill: false, tension: 0.3 },
{ label: 'SBP 90th', data: sys90, borderColor: 'rgba(249,115,22,0.6)', borderWidth: 1.5, borderDash: [3,3], pointRadius: 0, fill: false, tension: 0.3 },
{ label: 'SBP 50th', data: sys50, borderColor: 'rgba(16,185,129,0.8)', borderWidth: 2, pointRadius: 0, fill: false, tension: 0.3 },
{ label: 'DBP 95th', data: dia95, borderColor: 'rgba(239,68,68,0.4)', borderWidth: 1.5, borderDash: [4,4], pointRadius: 0, fill: false, tension: 0.3 },
{ label: 'DBP 90th', data: dia90, borderColor: 'rgba(249,115,22,0.3)', borderWidth: 1, borderDash: [3,3], pointRadius: 0, fill: false, tension: 0.3 },
{ label: 'DBP 50th', data: dia50, borderColor: 'rgba(16,185,129,0.4)', borderWidth: 1.5, pointRadius: 0, fill: false, tension: 0.3 },
{ label: 'Patient SBP', data: [{x:patientAge, y:patientSys}], backgroundColor: '#2563eb', borderColor: '#1d4ed8', pointRadius: 8, pointHoverRadius: 10, showLine: false, type: 'scatter', order: 0 },
{ label: 'Patient DBP', data: [{x:patientAge, y:patientDia}], backgroundColor: '#7c3aed', borderColor: '#6d28d9', pointRadius: 8, pointHoverRadius: 10, pointStyle: 'triangle', showLine: false, type: 'scatter', order: 0 }
];
_chartInstances['bp-chart-canvas'] = new Chart(document.getElementById('bp-chart-canvas'), {
type: 'line',
data: { datasets: datasets },
options: {
responsive: true, maintainAspectRatio: true, aspectRatio: 1.6,
animation: { duration: 300 },
scales: {
x: { type: 'linear', title: { display: true, text: 'Age (years)', font: { size: 12, weight: 'bold' } }, min: 1, max: 17, ticks: { stepSize: 1 }, grid: { color: 'rgba(0,0,0,0.05)' } },
y: { title: { display: true, text: 'Blood Pressure (mmHg)', font: { size: 12, weight: 'bold' } }, min: 30, grid: { color: 'rgba(0,0,0,0.05)' } }
},
plugins: {
legend: { display: true, position: 'bottom', labels: { font: { size: 10 }, usePointStyle: true } },
tooltip: {
callbacks: {
label: function(ctx) {
if (ctx.dataset.label.indexOf('Patient') !== -1) return ctx.dataset.label + ': ' + ctx.parsed.y + ' mmHg';
return ctx.dataset.label + ': ' + ctx.parsed.y + ' mmHg at age ' + ctx.parsed.x;
}
}
}
}
}
});
}
document.getElementById('btn-clear-bp').addEventListener('click', function() {
['bp-age', 'bp-sex', 'bp-height', 'bp-systolic', 'bp-diastolic'].forEach(function(id) {
var el = document.getElementById(id); if (el) el.value = '';
});
document.getElementById('bp-result').classList.add('hidden');
var bpc = document.getElementById('bp-chart-container'); if (bpc) bpc.classList.add('hidden');
});
// ═══════════════════════════════════════════════════════════
// BMI PERCENTILE — CDC 2000
// ═══════════════════════════════════════════════════════════
// CDC BMI-for-Age 24-240mo (every 3 months, from CDC bmiagerev.csv)
var bmiLMS = {male:{24:{L:-1.982374,M:16.5478,S:0.080127},30:{L:-1.642107,M:16.2497,S:0.075499},36:{L:-1.419991,M:16.0003,S:0.072634},42:{L:-1.438165,M:15.7941,S:0.071495},48:{L:-1.714869,M:15.6282,S:0.071889},54:{L:-2.155348,M:15.5026,S:0.073491},60:{L:-2.615166,M:15.4191,S:0.075992},66:{L:-2.981797,M:15.3795,S:0.079211},72:{L:-3.211705,M:15.3835,S:0.083048},78:{L:-3.314769,M:15.429,S:0.0874},84:{L:-3.323189,M:15.5129,S:0.092131},90:{L:-3.270455,M:15.6317,S:0.097082},96:{L:-3.183058,M:15.7823,S:0.102091},102:{L:-3.079383,M:15.9617,S:0.107013},108:{L:-2.971148,M:16.1671,S:0.111721},114:{L:-2.865311,M:16.3961,S:0.116113},120:{L:-2.765648,M:16.6461,S:0.120112},126:{L:-2.673903,M:16.9151,S:0.123664},132:{L:-2.59056,M:17.2009,S:0.126735},138:{L:-2.51532,M:17.5014,S:0.129309},144:{L:-2.447426,M:17.8146,S:0.131389},150:{L:-2.385858,M:18.1387,S:0.132991},156:{L:-2.329457,M:18.4718,S:0.134141},162:{L:-2.277017,M:18.812,S:0.13488},168:{L:-2.227362,M:19.1576,S:0.135251},174:{L:-2.179426,M:19.5067,S:0.135309},180:{L:-2.132345,M:19.8577,S:0.13511},186:{L:-2.085574,M:20.2086,S:0.134718},192:{L:-2.039015,M:20.5576,S:0.134198},198:{L:-1.99315,M:20.9029,S:0.13362},204:{L:-1.949135,M:21.2425,S:0.133057},210:{L:-1.908831,M:21.5742,S:0.132585},216:{L:-1.87467,M:21.8959,S:0.132286},222:{L:-1.849323,M:22.2054,S:0.132249},228:{L:-1.835138,M:22.5007,S:0.132566},234:{L:-1.833401,M:22.7799,S:0.133339},240:{L:-1.843581,M:23.0414,S:0.134675}},female:{24:{L:-1.024497,M:16.388,S:0.085026},30:{L:-1.534542,M:16.0059,S:0.080932},36:{L:-2.096829,M:15.6992,S:0.078605},42:{L:-2.618733,M:15.4647,S:0.077904},48:{L:-3.018522,M:15.2985,S:0.078713},54:{L:-3.2593,M:15.1961,S:0.080904},60:{L:-3.350078,M:15.1519,S:0.0843},66:{L:-3.325522,M:15.1606,S:0.08868},72:{L:-3.225607,M:15.2169,S:0.093803},78:{L:-3.084291,M:15.3161,S:0.099427},84:{L:-2.926187,M:15.4536,S:0.105325},90:{L:-2.76731,M:15.6252,S:0.111295},96:{L:-2.617192,M:15.827,S:0.117159},102:{L:-2.480952,M:16.0552,S:0.122771},108:{L:-2.360921,M:16.3061,S:0.128014},114:{L:-2.257782,M:16.5763,S:0.132797},120:{L:-2.171296,M:16.8623,S:0.137057},126:{L:-2.100749,M:17.161,S:0.140754},132:{L:-2.045235,M:17.4691,S:0.143868},138:{L:-2.003802,M:17.7836,S:0.146399},144:{L:-1.975521,M:18.1015,S:0.148361},150:{L:-1.95952,M:18.42,S:0.149783},156:{L:-1.954978,M:18.7364,S:0.150705},162:{L:-1.9611,M:19.0481,S:0.151176},168:{L:-1.977074,M:19.3526,S:0.151256},174:{L:-2.002014,M:19.6475,S:0.15101},180:{L:-2.034893,M:19.9306,S:0.150512},186:{L:-2.07446,M:20.1998,S:0.149843},192:{L:-2.119157,M:20.4533,S:0.14909},198:{L:-2.167045,M:20.6891,S:0.148349},204:{L:-2.215738,M:20.9058,S:0.147723},210:{L:-2.262382,M:21.1016,S:0.147323},216:{L:-2.303688,M:21.2753,S:0.147269},222:{L:-2.336038,M:21.4255,S:0.147689},228:{L:-2.355678,M:21.5508,S:0.148724},234:{L:-2.35898,M:21.6501,S:0.150521},240:{L:-2.342797,M:21.7219,S:0.153241}}};
function calcBMIPercentile(bmi, L, M, S) {
// Z-score from LMS: Z = ((BMI/M)^L - 1) / (L * S)
var z;
if (Math.abs(L) < 0.001) {
z = Math.log(bmi / M) / S;
} else {
z = (Math.pow(bmi / M, L) - 1) / (L * S);
}
// Convert Z to percentile using standard normal CDF approximation
var p = normalCDF(z);
return { z: z, percentile: Math.round(p * 10000) / 100 };
}
function normalCDF(z) {
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;
z = Math.abs(z) / Math.sqrt(2);
var t = 1 / (1 + p * z);
var y = 1 - (((((a5*t+a4)*t)+a3)*t+a2)*t+a1)*t*Math.exp(-z*z);
return 0.5 * (1 + sign * y);
}
// ═══════════════════════════════════════════════════════════
// CHART.JS GROWTH CURVE RENDERING
// ═══════════════════════════════════════════════════════════
// Inverse LMS: given Z-score, return measurement value
function valueFromLMS(L, M, S, z) {
if (Math.abs(L) < 0.001) return M * Math.exp(S * z);
return M * Math.pow(1 + L * S * z, 1 / L);
}
// 7-line reference set: 3, 10, 25, 50, 75, 90, 97.
// Drops 5th and 95th (they crowded the 3rd/10th and 90th/97th labels
// on mobile without adding clinical value — 3rd/97th are the
// abnormal-threshold lines, the inner percentiles give the trend).
var PERCENTILE_LINES = [
{ p: 3, z: -1.88079, color: 'rgba(220,38,38,0.9)', dash: [6,4], width: 1.4 }, // red
{ p: 10, z: -1.28155, color: 'rgba(234,88,12,0.9)', dash: [], width: 1.2 }, // orange
{ p: 25, z: -0.67449, color: 'rgba(202,138,4,0.85)', dash: [], width: 1.1 }, // amber
{ p: 50, z: 0, color: 'rgba(22,163,74,0.95)', dash: [], width: 2.4 }, // green (center)
{ p: 75, z: 0.67449, color: 'rgba(37,99,235,0.85)', dash: [], width: 1.1 }, // blue
{ p: 90, z: 1.28155, color: 'rgba(124,58,237,0.9)', dash: [], width: 1.2 }, // violet
{ p: 97, z: 1.88079, color: 'rgba(219,39,119,0.9)', dash: [6,4], width: 1.4 } // pink
];
function generatePercentileCurves(lmsTable, percentileLines) {
var ages = Object.keys(lmsTable).map(Number).sort(function(a,b){return a-b;});
var datasets = [];
percentileLines.forEach(function(pl, idx) {
var points = [];
ages.forEach(function(age) {
var lms = lmsTable[age];
var val = valueFromLMS(lms.L, lms.M, lms.S, pl.z);
if (isFinite(val) && val > 0) points.push({ x: age, y: Math.round(val * 100) / 100 });
});
datasets.push({
label: pl.p + 'th',
data: points,
borderColor: pl.color,
borderWidth: pl.width,
borderDash: pl.dash,
pointRadius: 0,
pointHoverRadius: 0,
fill: false,
tension: 0.4,
order: 10
});
});
// Fill bands between symmetric percentile pairs.
// Indexes: 3=0, 10=1, 25=2, 50=3, 75=4, 90=5, 97=6
var fills = [
{ outer: 0, inner: 6, color: 'rgba(220,38,38,0.04)' }, // 3rd-97th (widest)
{ outer: 1, inner: 5, color: 'rgba(234,88,12,0.04)' }, // 10th-90th
{ outer: 2, inner: 4, color: 'rgba(163,163,163,0.05)' } // 25th-75th (IQR)
];
fills.forEach(function(f) {
if (datasets[f.outer] && datasets[f.inner]) {
datasets[f.outer].fill = { target: f.inner, above: f.color, below: f.color };
}
});
return datasets;
}
var _chartInstances = {};
// Chart.js plugin — labels each percentile curve at its right edge,
// spreads labels bidirectionally so top (97/95/90) and bottom (3/5/10)
// clusters both breathe, draws a thin leader from each label to the
// actual curve position when nudged, then repaints the patient dot
// ON TOP so it's never obscured by a label.
var percentileLabelPlugin = {
id: 'percentileLabels',
afterDatasetsDraw: function(chart) {
var ctx = chart.ctx;
var font = '700 11px -apple-system,BlinkMacSystemFont,"Segoe UI",Helvetica,Arial,sans-serif';
var MIN_GAP = 15;
// Collect percentile-line labels with native screen positions
var items = [];
chart.data.datasets.forEach(function(ds, i) {
if (!ds.label || !/^\d+th$/.test(ds.label)) return;
var meta = chart.getDatasetMeta(i);
if (!meta || meta.hidden || !meta.data || !meta.data.length) return;
var last = meta.data[meta.data.length - 1];
if (!last) return;
items.push({ label: ds.label, color: ds.borderColor, x: last.x, nativeY: last.y, targetY: last.y });
});
// Top to bottom (ascending canvas Y)
items.sort(function(a, b) { return a.nativeY - b.nativeY; });
// Forward pass — push items DOWN when crowded by item above
for (var k = 1; k < items.length; k++) {
if (items[k].targetY - items[k - 1].targetY < MIN_GAP) {
items[k].targetY = items[k - 1].targetY + MIN_GAP;
}
}
// Backward pass — pull items UP when still crowded by item below
for (var j = items.length - 2; j >= 0; j--) {
if (items[j + 1].targetY - items[j].targetY < MIN_GAP) {
items[j].targetY = items[j + 1].targetY - MIN_GAP;
}
}
// Clamp to chart area so nothing clips top/bottom
var area = chart.chartArea;
if (area) {
items.forEach(function(it) {
if (it.targetY < area.top + 6) it.targetY = area.top + 6;
if (it.targetY > area.bottom - 6) it.targetY = area.bottom - 6;
});
}
// Draw leader + label
items.forEach(function(it) {
var stroke = typeof it.color === 'string' ? it.color : '#555';
var m = stroke.match(/rgba?\((\d+),\s*(\d+),\s*(\d+)/);
if (m) stroke = 'rgb(' + m[1] + ',' + m[2] + ',' + m[3] + ')';
ctx.save();
// Leader — only if the label was nudged away from its native Y
if (Math.abs(it.targetY - it.nativeY) > 2) {
ctx.strokeStyle = stroke;
ctx.globalAlpha = 0.55;
ctx.lineWidth = 0.8;
ctx.beginPath();
ctx.moveTo(it.x, it.nativeY);
ctx.lineTo(it.x + 4, it.targetY);
ctx.stroke();
ctx.globalAlpha = 1;
}
// Label with white halo
ctx.font = font;
ctx.textAlign = 'left';
ctx.textBaseline = 'middle';
ctx.lineWidth = 3;
ctx.strokeStyle = 'rgba(255,255,255,0.92)';
ctx.strokeText(it.label, it.x + 5, it.targetY);
ctx.fillStyle = stroke;
ctx.fillText(it.label, it.x + 5, it.targetY);
ctx.restore();
});
// Repaint the patient dot ON TOP of the labels so it's never
// covered by a nearby percentile label.
chart.data.datasets.forEach(function(ds, i) {
if (ds.label !== 'Patient') return;
var meta = chart.getDatasetMeta(i);
if (!meta || !meta.data || !meta.data.length) return;
var pt = meta.data[0];
if (!pt) return;
ctx.save();
ctx.beginPath();
ctx.arc(pt.x, pt.y, 5, 0, Math.PI * 2);
ctx.fillStyle = '#2563eb';
ctx.fill();
ctx.lineWidth = 1.8;
ctx.strokeStyle = '#ffffff';
ctx.stroke();
ctx.restore();
});
}
};
function renderGrowthChart(canvasId, containerId, lmsTable, patientX, patientY, xLabel, yLabel, extraDatasets) {
if (typeof Chart === 'undefined') return; // Chart.js not loaded yet
var container = document.getElementById(containerId);
if (!container) return;
container.classList.remove('hidden');
if (_chartInstances[canvasId]) { _chartInstances[canvasId].destroy(); _chartInstances[canvasId] = null; }
var datasets = generatePercentileCurves(lmsTable, PERCENTILE_LINES);
// Patient data point — drawn on top of every curve. White ring so
// it reads cleanly even when it lands directly on a colored line.
datasets.push({
label: 'Patient',
data: [{ x: patientX, y: patientY }],
backgroundColor: '#2563eb',
borderColor: '#ffffff',
borderWidth: 1.8,
pointRadius: 5,
pointHoverRadius: 7,
pointStyle: 'circle',
showLine: false,
type: 'scatter',
order: -1
});
if (extraDatasets) extraDatasets.forEach(function(d) { datasets.push(d); });
_chartInstances[canvasId] = new Chart(document.getElementById(canvasId), {
type: 'line',
data: { datasets: datasets },
plugins: [percentileLabelPlugin],
options: {
responsive: true,
maintainAspectRatio: true,
aspectRatio: 1.6,
animation: { duration: 300 },
// Leave ~28px of padding on the right so the percentile labels
// ("50th", "95th", ...) drawn past the last data point are not
// clipped by the canvas edge.
layout: { padding: { right: 30 } },
scales: {
x: {
type: 'linear',
title: { display: true, text: xLabel, font: { size: 12, weight: 'bold' } },
grid: { color: 'rgba(0,0,0,0.05)' }
},
y: {
title: { display: true, text: yLabel, font: { size: 12, weight: 'bold' } },
grid: { color: 'rgba(0,0,0,0.05)' }
}
},
plugins: {
legend: { display: false },
tooltip: {
callbacks: {
label: function(ctx) {
if (ctx.dataset.label === 'Patient') return 'Patient: ' + ctx.parsed.y.toFixed(1) + ' ' + yLabel.split('(').pop().replace(')', '');
return ctx.dataset.label + ': ' + ctx.parsed.y.toFixed(1);
}
}
}
}
}
});
}
// Mid-parental height calculation
function calcMidParentalHeight(motherHt, fatherHt, sex) {
if (!motherHt || !fatherHt) return null;
var mph = sex === 'male' ? (motherHt + fatherHt + 13) / 2 : (motherHt + fatherHt - 13) / 2;
return { target: mph, low: mph - 8.5, high: mph + 8.5 };
}
// Extended BMI classification per CDC 2022
// Uses % of 95th percentile for severe obesity staging
function classifyBMI(percentile, bmi, lms) {
// Calculate 95th percentile BMI from LMS
var p95z = 1.645; // Z for 95th percentile
var bmi95;
if (Math.abs(lms.L) < 0.001) bmi95 = lms.M * Math.exp(lms.S * p95z);
else bmi95 = lms.M * Math.pow(1 + lms.L * lms.S * p95z, 1 / lms.L);
var pctOf95 = (bmi / bmi95) * 100;
if (percentile >= 95) {
if (pctOf95 >= 140) return { text: 'Class 3 Severe Obesity', color: '#7f1d1d', bg: '#fecaca', pctOf95: pctOf95, bmi95: bmi95 };
if (pctOf95 >= 120) return { text: 'Class 2 Severe Obesity', color: '#dc2626', bg: '#fee2e2', pctOf95: pctOf95, bmi95: bmi95 };
return { text: 'Obese (Class 1)', color: '#ef4444', bg: '#fee2e2', pctOf95: pctOf95, bmi95: bmi95 };
}
if (percentile >= 85) return { text: 'Overweight', color: '#f97316', bg: '#ffedd5', pctOf95: pctOf95, bmi95: bmi95 };
if (percentile >= 5) return { text: 'Healthy Weight', color: '#10b981', bg: '#d1fae5', pctOf95: pctOf95, bmi95: bmi95 };
return { text: 'Underweight', color: '#f59e0b', bg: '#fef3c7', pctOf95: pctOf95, bmi95: bmi95 };
}
document.getElementById('btn-calc-bmi').addEventListener('click', function() {
var ageYr = parseFloat(document.getElementById('bmi-age-yr').value) || 0;
var ageMo = parseInt(document.getElementById('bmi-age-mo').value) || 0;
var age = ageYr + ageMo / 12;
var sex = document.getElementById('bmi-sex').value;
var weight = parseFloat(document.getElementById('bmi-weight').value);
var height = parseFloat(document.getElementById('bmi-height').value);
if (!age || !sex || !weight || !height) { showToast('Fill in all fields', 'error'); return; }
if (age < 2 || age > 20) { showToast('Age must be 2-20 years', 'error'); return; }
var bmi = weight / Math.pow(height / 100, 2);
var ageMonths = Math.round(age * 12);
if (ageMonths < 24) ageMonths = 24;
if (ageMonths > 240) ageMonths = 240;
var lms = interpolateLMS(bmiLMS[sex], ageMonths);
if (!lms) { showToast('Invalid age/sex', 'error'); return; }
var result = calcBMIPercentile(bmi, lms.L, lms.M, lms.S);
var cl = classifyBMI(result.percentile, bmi, lms);
var extendedInfo = '';
if (result.percentile >= 85) {
extendedInfo = '<div class="calc-result-item"><div class="calc-result-label">% of 95th</div><div class="calc-result-value" style="font-size:16px;">' + cl.pctOf95.toFixed(0) + '%</div><div class="calc-result-sub">95th = ' + cl.bmi95.toFixed(1) + ' kg/m&sup2;</div></div>';
}
var resultDiv = document.getElementById('bmi-result');
resultDiv.classList.remove('hidden');
resultDiv.innerHTML =
'<div class="calc-result-header" style="background:' + cl.bg + ';border-color:' + cl.color + ';">' +
'<div style="font-size:18px;font-weight:700;color:' + cl.color + ';">' + cl.text + '</div>' +
'<div style="font-size:13px;color:var(--g600);margin-top:4px;">BMI ' + bmi.toFixed(1) + ' kg/m&sup2; &mdash; ' + result.percentile + 'th percentile' + (cl.pctOf95 && result.percentile >= 95 ? ' (' + cl.pctOf95.toFixed(0) + '% of 95th)' : '') + '</div>' +
'</div>' +
'<div class="calc-result-grid">' +
'<div class="calc-result-item"><div class="calc-result-label">BMI</div><div class="calc-result-value">' + bmi.toFixed(1) + '</div><div class="calc-result-sub">kg/m&sup2;</div></div>' +
'<div class="calc-result-item"><div class="calc-result-label">Percentile</div><div class="calc-result-value">' + result.percentile + '<span style="font-size:12px;">th</span></div></div>' +
'<div class="calc-result-item"><div class="calc-result-label">Z-Score</div><div class="calc-result-value" style="font-size:16px;">' + result.z.toFixed(2) + '</div></div>' +
extendedInfo +
'</div>';
var bmiYears = {}; Object.keys(bmiLMS[sex]).forEach(function(k) { bmiYears[+(k/12).toFixed(1)] = bmiLMS[sex][k]; });
renderGrowthChart('bmi-chart-canvas', 'bmi-chart-container', bmiYears, +(ageMonths/12).toFixed(1), bmi, 'Age (years)', 'BMI (kg/m2)');
});
document.getElementById('btn-clear-bmi').addEventListener('click', function() {
['bmi-age-yr', 'bmi-sex', 'bmi-weight', 'bmi-height'].forEach(function(id) {
var el = document.getElementById(id); if (el) el.value = '';
});
document.getElementById('bmi-result').classList.add('hidden');
});
// ═══════════════════════════════════════════════════════════
// BODY SURFACE AREA — Mosteller
// ═══════════════════════════════════════════════════════════
document.getElementById('btn-calc-bsa').addEventListener('click', function() {
var weight = parseFloat(document.getElementById('bsa-weight').value);
var height = parseFloat(document.getElementById('bsa-height').value);
if (!weight || !height) { showToast('Enter weight and height', 'error'); return; }
var bsa = Math.sqrt(height * weight / 3600);
var resultDiv = document.getElementById('bsa-result');
resultDiv.classList.remove('hidden');
resultDiv.innerHTML =
'<div class="calc-result-header" style="background:#e0f2fe;border-color:#0ea5e9;">' +
'<div style="font-size:18px;font-weight:700;color:#0369a1;">BSA: ' + bsa.toFixed(3) + ' m&sup2;</div>' +
'<div style="font-size:13px;color:var(--g600);margin-top:4px;">' + weight + ' kg, ' + height + ' cm (Mosteller formula)</div>' +
'</div>';
});
document.getElementById('btn-clear-bsa').addEventListener('click', function() {
['bsa-weight', 'bsa-height'].forEach(function(id) {
var el = document.getElementById(id); if (el) el.value = '';
});
document.getElementById('bsa-result').classList.add('hidden');
});
// ═══════════════════════════════════════════════════════════
// WEIGHT-BASED DOSING
// ═══════════════════════════════════════════════════════════
document.getElementById('btn-calc-dose').addEventListener('click', function() {
var weight = parseFloat(document.getElementById('dose-weight').value);
var dosePerKg = parseFloat(document.getElementById('dose-per-kg').value);
var freq = parseInt(document.getElementById('dose-freq').value);
var maxDose = parseFloat(document.getElementById('dose-max').value) || 0;
var conc = parseFloat(document.getElementById('dose-conc').value) || 0;
if (!weight || !dosePerKg) { showToast('Enter weight and dose', 'error'); return; }
var singleDose = weight * dosePerKg;
var capped = false;
if (maxDose > 0 && singleDose > maxDose) { singleDose = maxDose; capped = true; }
var dailyDose = singleDose * freq;
var rows = '<div class="calc-result-item"><div class="calc-result-label">Single Dose</div><div class="calc-result-value">' + singleDose.toFixed(1) + ' <span style="font-size:12px;">mg</span></div>'
+ (capped ? '<div class="calc-result-sub" style="color:var(--red);">Capped at max ' + maxDose + ' mg</div>' : '') + '</div>'
+ '<div class="calc-result-item"><div class="calc-result-label">Daily Total</div><div class="calc-result-value">' + dailyDose.toFixed(1) + ' <span style="font-size:12px;">mg/day</span></div>'
+ '<div class="calc-result-sub">' + singleDose.toFixed(1) + ' mg x ' + freq + '/day</div></div>';
if (conc > 0) {
var vol = singleDose / conc;
rows += '<div class="calc-result-item"><div class="calc-result-label">Volume per Dose</div><div class="calc-result-value">' + vol.toFixed(1) + ' <span style="font-size:12px;">mL</span></div>'
+ '<div class="calc-result-sub">at ' + conc + ' mg/mL</div></div>';
}
var resultDiv = document.getElementById('dose-result');
resultDiv.classList.remove('hidden');
resultDiv.innerHTML =
'<div class="calc-result-header" style="background:#ede9fe;border-color:#7c3aed;">' +
'<div style="font-size:18px;font-weight:700;color:#6d28d9;">' + singleDose.toFixed(1) + ' mg per dose</div>' +
'<div style="font-size:13px;color:var(--g600);margin-top:4px;">' + weight + ' kg x ' + dosePerKg + ' mg/kg' + (capped ? ' (max ' + maxDose + ' mg)' : '') + '</div>' +
'</div>' +
'<div class="calc-result-grid">' + rows + '</div>' +
'<p style="font-size:11px;color:var(--g400);margin:12px 0 0;">Always verify dosing against your formulary and institutional guidelines.</p>';
});
document.getElementById('btn-clear-dose').addEventListener('click', function() {
['dose-weight', 'dose-per-kg', 'dose-max', 'dose-conc'].forEach(function(id) {
var el = document.getElementById(id); if (el) el.value = '';
});
document.getElementById('dose-freq').value = '1';
document.getElementById('dose-result').classList.add('hidden');
});
// ═══════════════════════════════════════════════════════════
// GROWTH CHARTS — WHO 0-2y / CDC 2-20y + Fenton Preterm
// ═══════════════════════════════════════════════════════════
var currentGrowthType = 'wfa';
// WHO Weight-for-Age 0-60mo (monthly, from WHO Anthro daily LMS)
var wfaLMS = {male:{0:{L:0.3487,M:3.3464,S:0.14602},1:{L:0.2303,M:4.4525,S:0.13413},2:{L:0.1969,M:5.5714,S:0.12382},3:{L:0.174,M:6.369,S:0.11732},4:{L:0.1551,M:7.0069,S:0.11313},5:{L:0.1396,M:7.5077,S:0.11081},6:{L:0.1256,M:7.9389,S:0.10957},7:{L:0.1134,M:8.2963,S:0.10902},8:{L:0.1019,M:8.62,S:0.10882},9:{L:0.0917,M:8.9019,S:0.10881},10:{L:0.0821,M:9.1618,S:0.1089},11:{L:0.0729,M:9.4136,S:0.10906},12:{L:0.0645,M:9.646,S:0.10925},13:{L:0.0563,M:9.8772,S:0.10949},14:{L:0.0487,M:10.0944,S:0.10976},15:{L:0.0412,M:10.3139,S:0.11008},16:{L:0.0343,M:10.5228,S:0.11041},17:{L:0.0276,M:10.7289,S:0.11078},18:{L:0.021,M:10.9393,S:0.1112},19:{L:0.0149,M:11.1409,S:0.11163},20:{L:0.0087,M:11.3478,S:0.11212},21:{L:0.0029,M:11.5474,S:0.11261},22:{L:-0.0029,M:11.7528,S:0.11315},23:{L:-0.0083,M:11.951,S:0.11369},24:{L:-0.0136,M:12.1482,S:0.11425},25:{L:-0.0189,M:12.3506,S:0.11485},26:{L:-0.0239,M:12.5442,S:0.11544},27:{L:-0.0289,M:12.7413,S:0.11604},28:{L:-0.0337,M:12.9288,S:0.11663},29:{L:-0.0385,M:13.1188,S:0.11723},30:{L:-0.0431,M:13.2993,S:0.11781},31:{L:-0.0477,M:13.4824,S:0.1184},32:{L:-0.052,M:13.6567,S:0.11896},33:{L:-0.0563,M:13.8285,S:0.11952},34:{L:-0.0607,M:14.0038,S:0.12008},35:{L:-0.0648,M:14.1719,S:0.12062},36:{L:-0.0689,M:14.3443,S:0.12116},37:{L:-0.0729,M:14.5102,S:0.12168},38:{L:-0.0769,M:14.6811,S:0.12221},39:{L:-0.0808,M:14.8462,S:0.12271},40:{L:-0.0846,M:15.0167,S:0.12323},41:{L:-0.0883,M:15.1816,S:0.12373},42:{L:-0.092,M:15.3465,S:0.12424},43:{L:-0.0957,M:15.5168,S:0.12478},44:{L:-0.0992,M:15.6815,S:0.12531},45:{L:-0.1028,M:15.8514,S:0.12587},46:{L:-0.1063,M:16.0156,S:0.12642},47:{L:-0.1098,M:16.1851,S:0.12701},48:{L:-0.1131,M:16.3489,S:0.12759},49:{L:-0.1164,M:16.5126,S:0.12818},50:{L:-0.1198,M:16.6818,S:0.12881},51:{L:-0.123,M:16.8454,S:0.12942},52:{L:-0.1263,M:17.0145,S:0.13006},53:{L:-0.1294,M:17.1782,S:0.13068},54:{L:-0.1326,M:17.3473,S:0.13133},55:{L:-0.1356,M:17.5107,S:0.13196},56:{L:-0.1387,M:17.674,S:0.1326},57:{L:-0.1417,M:17.8425,S:0.13325},58:{L:-0.1447,M:18.0053,S:0.13389},59:{L:-0.1477,M:18.1732,S:0.13454},60:{L:-0.1506,M:18.3352,S:0.13517}},female:{0:{L:0.3809,M:3.2322,S:0.14171},1:{L:0.1727,M:4.1716,S:0.13738},2:{L:0.0959,M:5.1315,S:0.12998},3:{L:0.0407,M:5.8393,S:0.12622},4:{L:-0.0053,M:6.428,S:0.12401},5:{L:-0.0428,M:6.8959,S:0.12274},6:{L:-0.0759,M:7.3016,S:0.12204},7:{L:-0.1039,M:7.6416,S:0.12178},8:{L:-0.1292,M:7.9534,S:0.12181},9:{L:-0.1507,M:8.2259,S:0.12199},10:{L:-0.1698,M:8.4769,S:0.12222},11:{L:-0.1873,M:8.7207,S:0.12247},12:{L:-0.2022,M:8.9462,S:0.12267},13:{L:-0.216,M:9.1722,S:0.12283},14:{L:-0.2277,M:9.3861,S:0.12294},15:{L:-0.2385,M:9.6038,S:0.12299},16:{L:-0.2478,M:9.8124,S:0.12303},17:{L:-0.2561,M:10.0196,S:0.12305},18:{L:-0.2637,M:10.2324,S:0.12309},19:{L:-0.2702,M:10.4372,S:0.12315},20:{L:-0.2763,M:10.6481,S:0.12324},21:{L:-0.2814,M:10.8521,S:0.12335},22:{L:-0.2862,M:11.0633,S:0.12351},23:{L:-0.2903,M:11.2684,S:0.12369},24:{L:-0.294,M:11.4741,S:0.12389},25:{L:-0.2975,M:11.6868,S:0.12414},26:{L:-0.3005,M:11.8922,S:0.12441},27:{L:-0.3033,M:12.1028,S:0.12472},28:{L:-0.3057,M:12.3042,S:0.12506},29:{L:-0.308,M:12.5093,S:0.12545},30:{L:-0.3101,M:12.7047,S:0.12587},31:{L:-0.312,M:12.9033,S:0.12634},32:{L:-0.3138,M:13.093,S:0.12683},33:{L:-0.3155,M:13.2809,S:0.12736},34:{L:-0.3171,M:13.4739,S:0.12794},35:{L:-0.3186,M:13.6599,S:0.12854},36:{L:-0.3201,M:13.8518,S:0.1292},37:{L:-0.3216,M:14.0373,S:0.12987},38:{L:-0.323,M:14.2288,S:0.1306},39:{L:-0.3243,M:14.4136,S:0.13134},40:{L:-0.3257,M:14.6041,S:0.13214},41:{L:-0.327,M:14.7877,S:0.13294},42:{L:-0.3283,M:14.9704,S:0.13375},43:{L:-0.3296,M:15.1584,S:0.13461},44:{L:-0.3309,M:15.3395,S:0.13544},45:{L:-0.3322,M:15.5259,S:0.13631},46:{L:-0.3335,M:15.7056,S:0.13715},47:{L:-0.3348,M:15.8908,S:0.13801},48:{L:-0.3361,M:16.0697,S:0.13884},49:{L:-0.3374,M:16.2485,S:0.13967},50:{L:-0.3387,M:16.433,S:0.14051},51:{L:-0.34,M:16.6114,S:0.14132},52:{L:-0.3414,M:16.7957,S:0.14214},53:{L:-0.3427,M:16.9737,S:0.14292},54:{L:-0.344,M:17.1573,S:0.14372},55:{L:-0.3453,M:17.3344,S:0.14448},56:{L:-0.3466,M:17.5107,S:0.14524},57:{L:-0.3479,M:17.692,S:0.146},58:{L:-0.3492,M:17.8664,S:0.14674},59:{L:-0.3505,M:18.0456,S:0.14749},60:{L:-0.3518,M:18.2179,S:0.14821}}};
// CDC Weight-for-Age 24-240mo (every 6 months)
var cdcWfaLMS = {male:{24:{L:-0.216501,M:12.7415,S:0.108166},30:{L:-0.397568,M:13.5609,S:0.109378},36:{L:-0.62132,M:14.4026,S:0.111875},42:{L:-0.804515,M:15.3194,S:0.115493},48:{L:-0.915242,M:16.3168,S:0.119955},54:{L:-0.969633,M:17.3791,S:0.124879},60:{L:-1.000454,M:18.4859,S:0.129879},66:{L:-1.035044,M:19.6214,S:0.134676},72:{L:-1.087471,M:20.7777,S:0.139143},78:{L:-1.158132,M:21.9564,S:0.14331},84:{L:-1.236497,M:23.1674,S:0.147337},90:{L:-1.306268,M:24.4265,S:0.151472},96:{L:-1.351813,M:25.7526,S:0.155974},102:{L:-1.363458,M:27.1649,S:0.161026},108:{L:-1.339405,M:28.6813,S:0.166659},114:{L:-1.284375,M:30.3177,S:0.172729},120:{L:-1.206688,M:32.088,S:0.178929},126:{L:-1.115543,M:34.0036,S:0.184847},132:{L:-1.019277,M:36.0726,S:0.19003},138:{L:-0.92467,M:38.2978,S:0.194053},144:{L:-0.836962,M:40.6744,S:0.196592},150:{L:-0.760274,M:43.1883,S:0.197464},156:{L:-0.698166,M:45.8134,S:0.196662},162:{L:-0.654143,M:48.5111,S:0.194344},168:{L:-0.631877,M:51.231,S:0.190808},174:{L:-0.634919,M:53.9126,S:0.186442},180:{L:-0.665609,M:56.491,S:0.181666},186:{L:-0.723218,M:58.9029,S:0.176887},192:{L:-0.801993,M:61.0954,S:0.172459},198:{L:-0.890436,M:63.0323,S:0.168655},204:{L:-0.973245,M:64.6996,S:0.16564},210:{L:-1.035402,M:66.1075,S:0.163439},216:{L:-1.066224,M:67.2899,S:0.161923},222:{L:-1.061342,M:68.3,S:0.16087},228:{L:-1.023292,M:69.1947,S:0.160138},234:{L:-0.964377,M:69.9987,S:0.160007},240:{L:-0.916488,M:70.5976,S:0.161477}},female:{24:{L:-0.752207,M:12.1346,S:0.10774},30:{L:-0.914719,M:13.0436,S:0.113023},36:{L:-1.024471,M:13.9411,S:0.119492},42:{L:-1.107022,M:14.8812,S:0.125973},48:{L:-1.17703,M:15.8782,S:0.131802},54:{L:-1.238331,M:16.9283,S:0.136811},60:{L:-1.287692,M:18.0231,S:0.141191},66:{L:-1.318993,M:19.1583,S:0.145317},72:{L:-1.326764,M:20.3364,S:0.14959},78:{L:-1.308487,M:21.5675,S:0.154326},84:{L:-1.265549,M:22.868,S:0.159693},90:{L:-1.202884,M:24.2579,S:0.165689},96:{L:-1.127684,M:25.757,S:0.172147},102:{L:-1.047847,M:27.382,S:0.178774},108:{L:-0.970686,M:29.1429,S:0.185201},114:{L:-0.902198,M:31.0403,S:0.191041},120:{L:-0.846873,M:33.0639,S:0.195947},126:{L:-0.807873,M:35.1918,S:0.199648},132:{L:-0.787374,M:37.3909,S:0.201971},138:{L:-0.786904,M:39.6191,S:0.202848},144:{L:-0.8076,M:41.828,S:0.202299},150:{L:-0.850307,M:43.9661,S:0.200419},156:{L:-0.915514,M:45.9837,S:0.197363},162:{L:-1.003051,M:47.8366,S:0.19333},168:{L:-1.111606,M:49.4908,S:0.18856},174:{L:-1.238005,M:50.9254,S:0.183328},180:{L:-1.376478,M:52.1357,S:0.177947},186:{L:-1.518156,M:53.1333,S:0.172761},192:{L:-1.651248,M:53.9454,S:0.168125},198:{L:-1.762241,M:54.6122,S:0.164368},204:{L:-1.838092,M:55.1822,S:0.161753},210:{L:-1.868977,M:55.7062,S:0.160423},216:{L:-1.850946,M:56.2297,S:0.16037},222:{L:-1.787979,M:56.7803,S:0.161399},228:{L:-1.693267,M:57.3518,S:0.163138},234:{L:-1.589533,M:57.8833,S:0.165088},240:{L:-1.513362,M:58.219,S:0.166645}}};
// WHO Length/Height-for-Age 0-60mo (monthly)
var lfaLMS = {male:{0:{L:1.0,M:49.8842,S:0.03795},1:{L:1.0,M:54.6645,S:0.03559},2:{L:1.0,M:58.4384,S:0.03423},3:{L:1.0,M:61.4013,S:0.03329},4:{L:1.0,M:63.9041,S:0.03257},5:{L:1.0,M:65.8912,S:0.03204},6:{L:1.0,M:67.6435,S:0.03165},7:{L:1.0,M:69.1615,S:0.03139},8:{L:1.0,M:70.6224,S:0.03124},9:{L:1.0,M:71.9714,S:0.03117},10:{L:1.0,M:73.2653,S:0.03118},11:{L:1.0,M:74.5464,S:0.03125},12:{L:1.0,M:75.7391,S:0.03137},13:{L:1.0,M:76.9304,S:0.03154},14:{L:1.0,M:78.0451,S:0.03174},15:{L:1.0,M:79.1613,S:0.03197},16:{L:1.0,M:80.2113,S:0.03222},17:{L:1.0,M:81.234,S:0.03249},18:{L:1.0,M:82.2628,S:0.03279},19:{L:1.0,M:83.2318,S:0.0331},20:{L:1.0,M:84.2074,S:0.03342},21:{L:1.0,M:85.1291,S:0.03375},22:{L:1.0,M:86.0589,S:0.0341},23:{L:1.0,M:86.9392,S:0.03445},24:{L:1.0,M:87.8018,S:0.03479},25:{L:1.0,M:87.9737,S:0.03542},26:{L:1.0,M:88.7964,S:0.03576},27:{L:1.0,M:89.6247,S:0.0361},28:{L:1.0,M:90.4056,S:0.03642},29:{L:1.0,M:91.1906,S:0.03674},30:{L:1.0,M:91.9297,S:0.03704},31:{L:1.0,M:92.6735,S:0.03733},32:{L:1.0,M:93.3753,S:0.03761},33:{L:1.0,M:94.0612,S:0.03787},34:{L:1.0,M:94.7559,S:0.03812},35:{L:1.0,M:95.4168,S:0.03836},36:{L:1.0,M:96.0889,S:0.03858},37:{L:1.0,M:96.7298,S:0.03879},38:{L:1.0,M:97.3827,S:0.039},39:{L:1.0,M:98.006,S:0.03919},40:{L:1.0,M:98.6412,S:0.03937},41:{L:1.0,M:99.2471,S:0.03954},42:{L:1.0,M:99.8441,S:0.0397},43:{L:1.0,M:100.4522,S:0.03986},44:{L:1.0,M:101.0326,S:0.04002},45:{L:1.0,M:101.6246,S:0.04017},46:{L:1.0,M:102.191,S:0.04031},47:{L:1.0,M:102.7706,S:0.04045},48:{L:1.0,M:103.3273,S:0.04059},49:{L:1.0,M:103.8806,S:0.04073},50:{L:1.0,M:104.4496,S:0.04086},51:{L:1.0,M:104.9984,S:0.041},52:{L:1.0,M:105.5641,S:0.04113},53:{L:1.0,M:106.1104,S:0.04126},54:{L:1.0,M:106.6736,S:0.04139},55:{L:1.0,M:107.2176,S:0.04152},56:{L:1.0,M:107.7607,S:0.04165},57:{L:1.0,M:108.3209,S:0.04177},58:{L:1.0,M:108.8621,S:0.0419},59:{L:1.0,M:109.4203,S:0.04202},60:{L:1.0,M:109.9593,S:0.04214}},female:{0:{L:1.0,M:49.1477,S:0.0379},1:{L:1.0,M:53.6326,S:0.03641},2:{L:1.0,M:57.0796,S:0.03568},3:{L:1.0,M:59.7773,S:0.0352},4:{L:1.0,M:62.1071,S:0.03486},5:{L:1.0,M:64.019,S:0.03463},6:{L:1.0,M:65.751,S:0.03448},7:{L:1.0,M:67.2842,S:0.03441},8:{L:1.0,M:68.7732,S:0.0344},9:{L:1.0,M:70.1463,S:0.03444},10:{L:1.0,M:71.4656,S:0.03452},11:{L:1.0,M:72.7788,S:0.03464},12:{L:1.0,M:74.0049,S:0.03479},13:{L:1.0,M:75.2297,S:0.03496},14:{L:1.0,M:76.377,S:0.03514},15:{L:1.0,M:77.5258,S:0.03534},16:{L:1.0,M:78.6055,S:0.03555},17:{L:1.0,M:79.6559,S:0.03576},18:{L:1.0,M:80.7121,S:0.03598},19:{L:1.0,M:81.708,S:0.0362},20:{L:1.0,M:82.7116,S:0.03643},21:{L:1.0,M:83.6595,S:0.03665},22:{L:1.0,M:84.6154,S:0.03689},23:{L:1.0,M:85.5184,S:0.03711},24:{L:1.0,M:86.4008,S:0.03733},25:{L:1.0,M:86.5922,S:0.03786},26:{L:1.0,M:87.4358,S:0.03808},27:{L:1.0,M:88.2881,S:0.0383},28:{L:1.0,M:89.0938,S:0.03851},29:{L:1.0,M:89.9072,S:0.03872},30:{L:1.0,M:90.6765,S:0.03893},31:{L:1.0,M:91.4539,S:0.03913},32:{L:1.0,M:92.1906,S:0.03933},33:{L:1.0,M:92.9135,S:0.03952},34:{L:1.0,M:93.6473,S:0.03971},35:{L:1.0,M:94.346,S:0.03989},36:{L:1.0,M:95.0572,S:0.04007},37:{L:1.0,M:95.7356,S:0.04024},38:{L:1.0,M:96.427,S:0.04041},39:{L:1.0,M:97.0871,S:0.04057},40:{L:1.0,M:97.7601,S:0.04074},41:{L:1.0,M:98.4028,S:0.04089},42:{L:1.0,M:99.0369,S:0.04105},43:{L:1.0,M:99.6834,S:0.0412},44:{L:1.0,M:100.3007,S:0.04135},45:{L:1.0,M:100.9301,S:0.0415},46:{L:1.0,M:101.5312,S:0.04164},47:{L:1.0,M:102.1446,S:0.04179},48:{L:1.0,M:102.7312,S:0.04193},49:{L:1.0,M:103.3113,S:0.04206},50:{L:1.0,M:103.9045,S:0.0422},51:{L:1.0,M:104.4727,S:0.04233},52:{L:1.0,M:105.0541,S:0.04247},53:{L:1.0,M:105.6114,S:0.04259},54:{L:1.0,M:106.1817,S:0.04272},55:{L:1.0,M:106.7284,S:0.04285},56:{L:1.0,M:107.2698,S:0.04297},57:{L:1.0,M:107.8238,S:0.0431},58:{L:1.0,M:108.3547,S:0.04322},59:{L:1.0,M:108.8981,S:0.04335},60:{L:1.0,M:109.4189,S:0.04346}}};
// CDC Stature-for-Age 24-240mo (every 6 months)
var cdcLfaLMS = {male:{24:{L:1.007208,M:86.8616,S:0.040396},30:{L:0.174489,M:91.3324,S:0.040965},36:{L:-0.390918,M:95.2736,S:0.040534},42:{L:0.32653,M:99.0025,S:0.040848},48:{L:0.827637,M:102.5105,S:0.041344},54:{L:1.133652,M:105.8813,S:0.041956},60:{L:1.266367,M:109.1751,S:0.042593},66:{L:1.255402,M:112.4296,S:0.043181},72:{L:1.137443,M:115.6609,S:0.043673},78:{L:0.954853,M:118.8668,S:0.044069},84:{L:0.753244,M:122.0305,S:0.044403},90:{L:0.575908,M:125.1259,S:0.044736},96:{L:0.455268,M:128.1237,S:0.045127},102:{L:0.404778,M:130.9983,S:0.045618},108:{L:0.415687,M:133.7345,S:0.046217},114:{L:0.461031,M:136.3343,S:0.046897},120:{L:0.505564,M:138.8234,S:0.04761},126:{L:0.518588,M:141.2582,S:0.048304},132:{L:0.487939,M:143.7304,S:0.048938},138:{L:0.434576,M:146.3665,S:0.049489},144:{L:0.420919,M:149.3088,S:0.049948},150:{L:0.531952,M:152.6624,S:0.050273},156:{L:0.81624,M:156.4099,S:0.050333},162:{L:1.232769,M:160.3493,S:0.049927},168:{L:1.670433,M:164.1418,S:0.048945},174:{L:2.016782,M:167.4641,S:0.047507},180:{L:2.20518,M:170.1393,S:0.04589},186:{L:2.225326,M:172.1563,S:0.044363},192:{L:2.113023,M:173.6101,S:0.043086},198:{L:1.927321,M:174.631,S:0.042107},204:{L:1.724738,M:175.341,S:0.041408},210:{L:1.543253,M:175.836,S:0.040938},216:{L:1.399999,M:176.185,S:0.040644},222:{L:1.297149,M:176.4352,S:0.040474},228:{L:1.229163,M:176.6179,S:0.040391},234:{L:1.18802,M:176.7538,S:0.040364},240:{L:1.167279,M:176.8492,S:0.04037}},female:{24:{L:1.051273,M:85.3973,S:0.04086},30:{L:0.814544,M:90.3334,S:0.041754},36:{L:0.541981,M:94.2134,S:0.042018},42:{L:0.377878,M:97.6485,S:0.042622},48:{L:0.225706,M:101.0339,S:0.04326},54:{L:0.075699,M:104.4635,S:0.043817},60:{L:-0.05773,M:107.9566,S:0.044277},66:{L:-0.159198,M:111.4876,S:0.044653},72:{L:-0.219069,M:115.0055,S:0.044964},78:{L:-0.234772,M:118.4496,S:0.045226},84:{L:-0.210211,M:121.7617,S:0.045461},90:{L:-0.154357,M:124.8956,S:0.045694},96:{L:-0.079283,M:127.8263,S:0.045968},102:{L:0.002744,M:130.5574,S:0.04634},108:{L:0.084148,M:133.1304,S:0.046884},114:{L:0.169805,M:135.6342,S:0.04767},120:{L:0.284749,M:138.2112,S:0.048705},126:{L:0.46918,M:141.0397,S:0.049812},132:{L:0.74429,M:144.2609,S:0.050524},138:{L:1.062475,M:147.8424,S:0.050208},144:{L:1.303045,M:151.4866,S:0.048599},150:{L:1.358163,M:154.7555,S:0.046198},156:{L:1.242968,M:157.3437,S:0.043859},162:{L:1.076971,M:159.2075,S:0.042114},168:{L:0.956572,M:160.4777,S:0.041022},174:{L:0.902452,M:161.3268,S:0.040409},180:{L:0.89557,M:161.898,S:0.040084},186:{L:0.913398,M:162.2908,S:0.039913},192:{L:0.941146,M:162.569,S:0.039821},198:{L:0.971038,M:162.7719,S:0.039767},204:{L:0.999506,M:162.9238,S:0.039732},210:{L:1.025143,M:163.0402,S:0.039707},216:{L:1.047571,M:163.1308,S:0.039687},222:{L:1.066873,M:163.2022,S:0.039671},228:{L:1.083315,M:163.259,S:0.039657},234:{L:1.097229,M:163.3045,S:0.039646},240:{L:1.108046,M:163.3383,S:0.039636}}};
// WHO Head Circumference 0-60mo (monthly)
var hcfaLMS = {male:{0:{L:1.0,M:34.4618,S:0.03686},1:{L:1.0,M:37.2435,S:0.03135},2:{L:1.0,M:39.1349,S:0.02997},3:{L:1.0,M:40.5008,S:0.02918},4:{L:1.0,M:41.6401,S:0.02868},5:{L:1.0,M:42.5524,S:0.02837},6:{L:1.0,M:43.3393,S:0.02817},7:{L:1.0,M:43.9791,S:0.02804},8:{L:1.0,M:44.5384,S:0.02796},9:{L:1.0,M:45.0007,S:0.02792},10:{L:1.0,M:45.4004,S:0.0279},11:{L:1.0,M:45.7593,S:0.02789},12:{L:1.0,M:46.0637,S:0.02789},13:{L:1.0,M:46.3421,S:0.02789},14:{L:1.0,M:46.5834,S:0.02791},15:{L:1.0,M:46.809,S:0.02792},16:{L:1.0,M:47.0088,S:0.02795},17:{L:1.0,M:47.1936,S:0.02797},18:{L:1.0,M:47.3718,S:0.028},19:{L:1.0,M:47.5341,S:0.02803},20:{L:1.0,M:47.6931,S:0.02806},21:{L:1.0,M:47.8399,S:0.0281},22:{L:1.0,M:47.985,S:0.02814},23:{L:1.0,M:48.1198,S:0.02817},24:{L:1.0,M:48.2494,S:0.02821},25:{L:1.0,M:48.378,S:0.02825},26:{L:1.0,M:48.4974,S:0.0283},27:{L:1.0,M:48.6158,S:0.02834},28:{L:1.0,M:48.7255,S:0.02838},29:{L:1.0,M:48.8341,S:0.02843},30:{L:1.0,M:48.9347,S:0.02847},31:{L:1.0,M:49.0341,S:0.02851},32:{L:1.0,M:49.126,S:0.02855},33:{L:1.0,M:49.214,S:0.02859},34:{L:1.0,M:49.3011,S:0.02863},35:{L:1.0,M:49.3818,S:0.02867},36:{L:1.0,M:49.4619,S:0.02871},37:{L:1.0,M:49.5362,S:0.02875},38:{L:1.0,M:49.6101,S:0.02878},39:{L:1.0,M:49.679,S:0.02882},40:{L:1.0,M:49.7476,S:0.02886},41:{L:1.0,M:49.8117,S:0.02889},42:{L:1.0,M:49.8737,S:0.02893},43:{L:1.0,M:49.9357,S:0.02896},44:{L:1.0,M:49.9938,S:0.02899},45:{L:1.0,M:50.0518,S:0.02903},46:{L:1.0,M:50.1062,S:0.02906},47:{L:1.0,M:50.1606,S:0.02909},48:{L:1.0,M:50.2115,S:0.02912},49:{L:1.0,M:50.261,S:0.02915},50:{L:1.0,M:50.3107,S:0.02918},51:{L:1.0,M:50.3573,S:0.02921},52:{L:1.0,M:50.4043,S:0.02924},53:{L:1.0,M:50.4485,S:0.02927},54:{L:1.0,M:50.4931,S:0.0293},55:{L:1.0,M:50.5353,S:0.02932},56:{L:1.0,M:50.5766,S:0.02935},57:{L:1.0,M:50.6184,S:0.02938},58:{L:1.0,M:50.6582,S:0.0294},59:{L:1.0,M:50.6986,S:0.02943},60:{L:1.0,M:50.7372,S:0.02945}},female:{0:{L:1.0,M:33.8787,S:0.03496},1:{L:1.0,M:36.5163,S:0.03211},2:{L:1.0,M:38.258,S:0.03168},3:{L:1.0,M:39.521,S:0.0314},4:{L:1.0,M:40.5895,S:0.03119},5:{L:1.0,M:41.454,S:0.03102},6:{L:1.0,M:42.2079,S:0.03087},7:{L:1.0,M:42.8278,S:0.03075},8:{L:1.0,M:43.3753,S:0.03063},9:{L:1.0,M:43.8309,S:0.03053},10:{L:1.0,M:44.2273,S:0.03044},11:{L:1.0,M:44.5865,S:0.03035},12:{L:1.0,M:44.894,S:0.03027},13:{L:1.0,M:45.1779,S:0.03019},14:{L:1.0,M:45.4255,S:0.03012},15:{L:1.0,M:45.6582,S:0.03005},16:{L:1.0,M:45.865,S:0.02999},17:{L:1.0,M:46.0571,S:0.02993},18:{L:1.0,M:46.2431,S:0.02987},19:{L:1.0,M:46.4135,S:0.02982},20:{L:1.0,M:46.5814,S:0.02977},21:{L:1.0,M:46.7375,S:0.02972},22:{L:1.0,M:46.8931,S:0.02967},23:{L:1.0,M:47.0388,S:0.02962},24:{L:1.0,M:47.1799,S:0.02958},25:{L:1.0,M:47.3207,S:0.02953},26:{L:1.0,M:47.452,S:0.02949},27:{L:1.0,M:47.5825,S:0.02945},28:{L:1.0,M:47.7035,S:0.02941},29:{L:1.0,M:47.8231,S:0.02937},30:{L:1.0,M:47.9336,S:0.02933},31:{L:1.0,M:48.0425,S:0.02929},32:{L:1.0,M:48.1432,S:0.02926},33:{L:1.0,M:48.2395,S:0.02922},34:{L:1.0,M:48.3347,S:0.02919},35:{L:1.0,M:48.423,S:0.02916},36:{L:1.0,M:48.5106,S:0.02912},37:{L:1.0,M:48.5921,S:0.02909},38:{L:1.0,M:48.6732,S:0.02906},39:{L:1.0,M:48.7487,S:0.02903},40:{L:1.0,M:48.824,S:0.029},41:{L:1.0,M:48.8942,S:0.02897},42:{L:1.0,M:48.9621,S:0.02894},43:{L:1.0,M:49.0298,S:0.02891},44:{L:1.0,M:49.0932,S:0.02888},45:{L:1.0,M:49.1566,S:0.02886},46:{L:1.0,M:49.2162,S:0.02883},47:{L:1.0,M:49.2759,S:0.0288},48:{L:1.0,M:49.3321,S:0.02878},49:{L:1.0,M:49.3869,S:0.02875},50:{L:1.0,M:49.4421,S:0.02873},51:{L:1.0,M:49.4942,S:0.0287},52:{L:1.0,M:49.5468,S:0.02868},53:{L:1.0,M:49.5966,S:0.02866},54:{L:1.0,M:49.647,S:0.02863},55:{L:1.0,M:49.6946,S:0.02861},56:{L:1.0,M:49.7413,S:0.02859},57:{L:1.0,M:49.7886,S:0.02856},58:{L:1.0,M:49.8335,S:0.02854},59:{L:1.0,M:49.8791,S:0.02852},60:{L:1.0,M:49.9225,S:0.0285}}};
// WHO Weight-for-Length 45-110cm (every 1cm)
var wflLMS = {male:{45:{L:-0.3521,M:2.441,S:0.09182},46:{L:-0.3521,M:2.6077,S:0.09124},47:{L:-0.3521,M:2.7755,S:0.09065},48:{L:-0.3521,M:2.948,S:0.09007},49:{L:-0.3521,M:3.1308,S:0.08948},50:{L:-0.3521,M:3.3278,S:0.0889},51:{L:-0.3521,M:3.5376,S:0.08831},52:{L:-0.3521,M:3.762,S:0.08771},53:{L:-0.3521,M:4.006,S:0.08711},54:{L:-0.3521,M:4.2693,S:0.08651},55:{L:-0.3521,M:4.5467,S:0.08592},56:{L:-0.3521,M:4.8338,S:0.08535},57:{L:-0.3521,M:5.1259,S:0.08481},58:{L:-0.3521,M:5.418,S:0.0843},59:{L:-0.3521,M:5.7074,S:0.08383},60:{L:-0.3521,M:5.9907,S:0.08342},61:{L:-0.3521,M:6.2632,S:0.08308},62:{L:-0.3521,M:6.5251,S:0.08279},63:{L:-0.3521,M:6.7786,S:0.08255},64:{L:-0.3521,M:7.0255,S:0.08236},65:{L:-0.3521,M:7.2666,S:0.08223},66:{L:-0.3521,M:7.5034,S:0.08215},67:{L:-0.3521,M:7.737,S:0.08212},68:{L:-0.3521,M:7.9674,S:0.08214},69:{L:-0.3521,M:8.1955,S:0.08219},70:{L:-0.3521,M:8.4227,S:0.08229},71:{L:-0.3521,M:8.648,S:0.08241},72:{L:-0.3521,M:8.8697,S:0.08254},73:{L:-0.3521,M:9.0865,S:0.08269},74:{L:-0.3521,M:9.2974,S:0.08283},75:{L:-0.3521,M:9.5032,S:0.08295},76:{L:-0.3521,M:9.7033,S:0.08307},77:{L:-0.3521,M:9.8963,S:0.08314},78:{L:-0.3521,M:10.0827,S:0.08318},79:{L:-0.3521,M:10.2649,S:0.08316},80:{L:-0.3521,M:10.4475,S:0.08308},81:{L:-0.3521,M:10.6352,S:0.08293},82:{L:-0.3521,M:10.8321,S:0.08273},83:{L:-0.3521,M:11.0415,S:0.08246},84:{L:-0.3521,M:11.2651,S:0.08215},85:{L:-0.3521,M:11.5007,S:0.08181},86:{L:-0.3521,M:11.7444,S:0.08145},87:{L:-0.3521,M:11.9916,S:0.08111},88:{L:-0.3521,M:12.2382,S:0.08082},89:{L:-0.3521,M:12.4815,S:0.08058},90:{L:-0.3521,M:12.7209,S:0.08041},91:{L:-0.3521,M:12.9569,S:0.0803},92:{L:-0.3521,M:13.191,S:0.08025},93:{L:-0.3521,M:13.4239,S:0.08026},94:{L:-0.3521,M:13.6572,S:0.08034},95:{L:-0.3521,M:13.8928,S:0.08047},96:{L:-0.3521,M:14.1325,S:0.08067},97:{L:-0.3521,M:14.3782,S:0.08092},98:{L:-0.3521,M:14.6316,S:0.08122},99:{L:-0.3521,M:14.8934,S:0.08157},100:{L:-0.3521,M:15.1637,S:0.08198},101:{L:-0.3521,M:15.4419,S:0.08243},102:{L:-0.3521,M:15.7276,S:0.08292},103:{L:-0.3521,M:16.0206,S:0.08343},104:{L:-0.3521,M:16.3204,S:0.08397},105:{L:-0.3521,M:16.6268,S:0.08453},106:{L:-0.3521,M:16.9401,S:0.0851},107:{L:-0.3521,M:17.2607,S:0.08568},108:{L:-0.3521,M:17.5885,S:0.08629},109:{L:-0.3521,M:17.9242,S:0.08691},110:{L:-0.3521,M:18.2689,S:0.08755}},female:{45:{L:-0.3833,M:2.4607,S:0.09029},46:{L:-0.3833,M:2.6306,S:0.09037},47:{L:-0.3833,M:2.8007,S:0.09044},48:{L:-0.3833,M:2.9741,S:0.09052},49:{L:-0.3833,M:3.156,S:0.0906},50:{L:-0.3833,M:3.3518,S:0.09068},51:{L:-0.3833,M:3.5636,S:0.09076},52:{L:-0.3833,M:3.7911,S:0.09085},53:{L:-0.3833,M:4.0332,S:0.09093},54:{L:-0.3833,M:4.2875,S:0.09102},55:{L:-0.3833,M:4.5498,S:0.0911},56:{L:-0.3833,M:4.8162,S:0.09118},57:{L:-0.3833,M:5.0837,S:0.09125},58:{L:-0.3833,M:5.3507,S:0.0913},59:{L:-0.3833,M:5.6151,S:0.09134},60:{L:-0.3833,M:5.8742,S:0.09136},61:{L:-0.3833,M:6.127,S:0.09137},62:{L:-0.3833,M:6.3738,S:0.09135},63:{L:-0.3833,M:6.6144,S:0.09131},64:{L:-0.3833,M:6.8501,S:0.09126},65:{L:-0.3833,M:7.0812,S:0.09119},66:{L:-0.3833,M:7.3076,S:0.0911},67:{L:-0.3833,M:7.5288,S:0.09101},68:{L:-0.3833,M:7.7448,S:0.0909},69:{L:-0.3833,M:7.9559,S:0.09079},70:{L:-0.3833,M:8.163,S:0.09068},71:{L:-0.3833,M:8.3666,S:0.09056},72:{L:-0.3833,M:8.5679,S:0.09043},73:{L:-0.3833,M:8.7661,S:0.09031},74:{L:-0.3833,M:8.9601,S:0.09018},75:{L:-0.3833,M:9.149,S:0.09005},76:{L:-0.3833,M:9.3337,S:0.08992},77:{L:-0.3833,M:9.5166,S:0.08979},78:{L:-0.3833,M:9.7015,S:0.08965},79:{L:-0.3833,M:9.8915,S:0.08952},80:{L:-0.3833,M:10.0891,S:0.0894},81:{L:-0.3833,M:10.2965,S:0.08928},82:{L:-0.3833,M:10.514,S:0.08918},83:{L:-0.3833,M:10.741,S:0.0891},84:{L:-0.3833,M:10.9767,S:0.08903},85:{L:-0.3833,M:11.2198,S:0.08898},86:{L:-0.3833,M:11.4684,S:0.08895},87:{L:-0.3833,M:11.7201,S:0.08895},88:{L:-0.3833,M:11.972,S:0.08896},89:{L:-0.3833,M:12.2229,S:0.089},90:{L:-0.3833,M:12.4723,S:0.08906},91:{L:-0.3833,M:12.7205,S:0.08913},92:{L:-0.3833,M:12.9681,S:0.08923},93:{L:-0.3833,M:13.2158,S:0.08934},94:{L:-0.3833,M:13.4643,S:0.08948},95:{L:-0.3833,M:13.7146,S:0.08963},96:{L:-0.3833,M:13.9676,S:0.08981},97:{L:-0.3833,M:14.2239,S:0.09},98:{L:-0.3833,M:14.4848,S:0.09021},99:{L:-0.3833,M:14.7519,S:0.09044},100:{L:-0.3833,M:15.0267,S:0.09069},101:{L:-0.3833,M:15.3108,S:0.09096},102:{L:-0.3833,M:15.6046,S:0.09125},103:{L:-0.3833,M:15.9087,S:0.09155},104:{L:-0.3833,M:16.2229,S:0.09186},105:{L:-0.3833,M:16.547,S:0.09219},106:{L:-0.3833,M:16.8814,S:0.09254},107:{L:-0.3833,M:17.2269,S:0.09289},108:{L:-0.3833,M:17.5839,S:0.09326},109:{L:-0.3833,M:17.9526,S:0.09363},110:{L:-0.3833,M:18.3324,S:0.09401}}};
// Fenton Preterm Growth LMS (GA 22-50 weeks) — Weight in grams
var fentonLMS = {
male: {
22:{L:0.21,M:496,S:0.17},24:{L:0.21,M:660,S:0.17},26:{L:0.21,M:870,S:0.16},
28:{L:0.20,M:1124,S:0.15},30:{L:0.18,M:1430,S:0.14},32:{L:0.15,M:1795,S:0.14},
34:{L:0.12,M:2230,S:0.13},36:{L:0.08,M:2710,S:0.13},38:{L:0.04,M:3195,S:0.12},
40:{L:0.01,M:3530,S:0.12},42:{L:-0.02,M:3820,S:0.12},44:{L:-0.04,M:4200,S:0.12},
46:{L:-0.06,M:4680,S:0.12},48:{L:-0.07,M:5200,S:0.12},50:{L:-0.08,M:5760,S:0.12}
},
female: {
22:{L:0.23,M:474,S:0.17},24:{L:0.22,M:610,S:0.17},26:{L:0.22,M:810,S:0.16},
28:{L:0.21,M:1040,S:0.15},30:{L:0.19,M:1330,S:0.14},32:{L:0.16,M:1680,S:0.14},
34:{L:0.12,M:2090,S:0.13},36:{L:0.08,M:2540,S:0.13},38:{L:0.04,M:3000,S:0.12},
40:{L:0.01,M:3340,S:0.12},42:{L:-0.02,M:3630,S:0.12},44:{L:-0.04,M:4010,S:0.12},
46:{L:-0.06,M:4470,S:0.12},48:{L:-0.07,M:4970,S:0.12},50:{L:-0.08,M:5510,S:0.12}
}
};
// Growth sub-pill navigation
document.querySelectorAll('[data-growth]').forEach(function(pill) {
pill.addEventListener('click', function() {
document.querySelectorAll('[data-growth]').forEach(function(p) { p.classList.remove('active'); });
pill.classList.add('active');
currentGrowthType = pill.dataset.growth;
var isFenton = currentGrowthType === 'fenton';
var isHC = currentGrowthType === 'hcfa';
var isWFL = currentGrowthType === 'wfl';
document.getElementById('growth-age-field').style.display = (isFenton || isWFL) ? 'none' : '';
document.getElementById('growth-ga-field').style.display = isFenton ? '' : 'none';
document.getElementById('growth-hc-field').style.display = isHC ? '' : 'none';
document.getElementById('growth-weight-field').style.display = isHC ? 'none' : '';
document.getElementById('growth-length-field').style.display = (currentGrowthType === 'wfa') ? 'none' : (isFenton ? 'none' : '');
var src = document.getElementById('growth-source-text');
if (isFenton) src.textContent = 'Fenton 2013 preterm growth charts (22-50 weeks GA). Weight in grams.';
else if (isHC) src.textContent = 'WHO head circumference-for-age (0-36 months).';
else if (isWFL) src.textContent = 'WHO weight-for-length (45-110 cm, 0-2 years).';
else src.textContent = 'WHO growth standards (0-2y) / CDC 2000 (2-20y).';
document.getElementById('growth-result').classList.add('hidden');
var chartContainer = document.getElementById('growth-chart-container');
if (chartContainer) chartContainer.classList.add('hidden');
if (_chartInstances['growth-chart-canvas']) { _chartInstances['growth-chart-canvas'].destroy(); _chartInstances['growth-chart-canvas'] = null; }
// Show MPH section only for LFA
var mphSection = document.getElementById('growth-mph-section');
if (mphSection) mphSection.style.display = (currentGrowthType === 'lfa') ? '' : 'none';
});
});
function interpolateLMS(lmsTable, val) {
var keys = Object.keys(lmsTable).map(Number).sort(function(a,b){return a-b;});
if (val <= keys[0]) return lmsTable[keys[0]];
if (val >= keys[keys.length-1]) return lmsTable[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 = lmsTable[keys[i]], b = lmsTable[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 lmsTable[keys[0]];
}
function calcZFromLMS(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 renderGrowthResult(label, value, unit, z, percentile) {
var pctl = (Math.round(percentile * 100) / 100).toFixed(2);
var cl;
if (pctl >= 95 || pctl <= 5) cl = { color: '#f59e0b', bg: '#fef3c7', text: pctl <= 5 ? 'Below 5th percentile' : 'Above 95th percentile' };
else if (pctl >= 85 || pctl <= 15) cl = { color: '#f97316', bg: '#ffedd5', text: pctl + 'th percentile' };
else cl = { color: '#10b981', bg: '#d1fae5', text: pctl + 'th percentile' };
return '<div class="calc-result-header" style="background:' + cl.bg + ';border-color:' + cl.color + ';">' +
'<div style="font-size:18px;font-weight:700;color:' + cl.color + ';">' + cl.text + '</div>' +
'<div style="font-size:13px;color:var(--g600);margin-top:4px;">' + label + ': ' + value + ' ' + unit + '</div>' +
'</div>' +
'<div class="calc-result-grid">' +
'<div class="calc-result-item"><div class="calc-result-label">Percentile</div><div class="calc-result-value">' + pctl + '<span style="font-size:12px;">th</span></div></div>' +
'<div class="calc-result-item"><div class="calc-result-label">Z-Score</div><div class="calc-result-value" style="font-size:16px;">' + z.toFixed(2) + '</div></div>' +
'</div>';
}
document.getElementById('btn-calc-growth').addEventListener('click', function() {
var sex = document.getElementById('growth-sex').value;
if (!sex) { showToast('Select sex', 'error'); return; }
var resultDiv = document.getElementById('growth-result');
if (currentGrowthType === 'fenton') {
var ga = parseFloat(document.getElementById('growth-ga').value);
var wt = parseFloat(document.getElementById('growth-weight').value);
if (!ga || !wt) { showToast('Enter gestational age and weight', 'error'); return; }
var wtGrams = wt * 1000;
var lms = interpolateLMS(fentonLMS[sex], ga);
var z = calcZFromLMS(wtGrams, lms.L, lms.M, lms.S);
var p = normalCDF(z) * 100;
resultDiv.classList.remove('hidden');
resultDiv.innerHTML = renderGrowthResult('Weight at ' + ga + ' weeks GA', wt + ' kg (' + Math.round(wtGrams) + 'g)', '', z, p);
renderGrowthChart('growth-chart-canvas', 'growth-chart-container', fentonLMS[sex], ga, wtGrams, 'Gestational Age (weeks)', 'Weight (g)');
return;
}
var yrEl = document.getElementById('growth-age-yr');
var moEl = document.getElementById('growth-age-mo');
var dyEl = document.getElementById('growth-age-d');
var yrRaw = yrEl ? yrEl.value.trim() : '';
var moRaw = moEl ? moEl.value.trim() : '';
var dyRaw = dyEl ? dyEl.value.trim() : '';
// Treat blank fields as 0, but require at least ONE field to have any value.
// "0 days" (newborn at birth) is valid — explicit zero counts.
if (yrRaw === '' && moRaw === '' && dyRaw === '') {
showToast('Enter age (years, months, or days)', 'error'); return;
}
var yr = parseFloat(yrRaw) || 0;
var mo = parseFloat(moRaw) || 0;
var dy = parseFloat(dyRaw) || 0;
var age = yr * 12 + mo + dy / 30.4375; // age in months, fractional OK
if (age < 0) { showToast('Age cannot be negative', 'error'); return; }
if (currentGrowthType === 'wfa') {
var wt = parseFloat(document.getElementById('growth-weight').value);
if (!wt) { showToast('Enter weight', 'error'); return; }
// Use WHO for 0-60mo, CDC for >60mo
var wfaTable = (age > 24) ? cdcWfaLMS[sex] : wfaLMS[sex];
var wfaChartTable = (age > 24) ? cdcWfaLMS[sex] : wfaLMS[sex];
var lms = interpolateLMS(wfaTable, age);
var z = calcZFromLMS(wt, lms.L, lms.M, lms.S);
var p = normalCDF(z) * 100;
var src = (age > 24) ? 'CDC' : 'WHO';
resultDiv.classList.remove('hidden');
resultDiv.innerHTML = renderGrowthResult('Weight-for-Age (' + age + ' mo, ' + src + ')', wt, 'kg', z, p);
if (age > 24) {
var wfaYears = {}; Object.keys(wfaChartTable).forEach(function(k) { wfaYears[+(k/12).toFixed(2)] = wfaChartTable[k]; });
renderGrowthChart('growth-chart-canvas', 'growth-chart-container', wfaYears, +(age/12).toFixed(2), wt, 'Age (years)', 'Weight (kg)');
} else {
renderGrowthChart('growth-chart-canvas', 'growth-chart-container', wfaChartTable, age, wt, 'Age (months)', 'Weight (kg)');
}
}
else if (currentGrowthType === 'lfa') {
var len = parseFloat(document.getElementById('growth-length').value);
if (!len) { showToast('Enter length/height', 'error'); return; }
// Use WHO for 0-60mo, CDC for >60mo
var lfaTable = (age > 24) ? cdcLfaLMS[sex] : lfaLMS[sex];
var lms = interpolateLMS(lfaTable, age);
var z = calcZFromLMS(len, lms.L, lms.M, lms.S);
var p = normalCDF(z) * 100;
var src = (age > 24) ? 'CDC' : 'WHO';
resultDiv.classList.remove('hidden');
resultDiv.innerHTML = renderGrowthResult('Length/Height-for-Age (' + age + ' mo, ' + src + ')', len, 'cm', z, p);
// Mid-parental height
var mphDatasets = [];
var motherHt = parseFloat((document.getElementById('growth-mother-ht') || {}).value);
var fatherHt = parseFloat((document.getElementById('growth-father-ht') || {}).value);
var mph = calcMidParentalHeight(motherHt, fatherHt, sex);
if (mph) {
// Calculate what percentile the MPH corresponds to using adult height LMS (~18y = 216mo)
var adultLms = interpolateLMS(cdcLfaLMS[sex], 216);
var mphZ = calcZFromLMS(mph.target, adultLms.L, adultLms.M, adultLms.S);
var mphPctile = (Math.round(normalCDF(mphZ) * 10000) / 100).toFixed(2);
resultDiv.innerHTML += '<div style="margin-top:8px;padding:8px 12px;background:#ede9fe;border-radius:6px;font-size:13px;color:#6d28d9;"><strong>Mid-Parental Height:</strong> ' + mph.target.toFixed(1) + ' cm (' + mphPctile + 'th percentile) &mdash; target range: ' + mph.low.toFixed(1) + ' - ' + mph.high.toFixed(1) + ' cm</div>';
// MPH coordinates: use years if age > 24mo
var mphX1 = age > 24 ? 17 : 204;
var mphX2 = age > 24 ? 20 : 240;
mphDatasets.push({ label: 'MPH Range', data: [{x:mphX1,y:mph.low},{x:mphX2,y:mph.low}], borderColor:'rgba(139,92,246,0.3)', backgroundColor:'rgba(139,92,246,0.1)', fill:'+1', pointRadius:0, borderWidth:1, tension:0, order:5 });
mphDatasets.push({ label: 'MPH Upper', data: [{x:mphX1,y:mph.high},{x:mphX2,y:mph.high}], borderColor:'rgba(139,92,246,0.3)', fill:false, pointRadius:0, borderWidth:1, tension:0, order:5 });
mphDatasets.push({ label: 'MPH ' + mph.target.toFixed(0) + 'cm (' + mphPctile + 'th %ile)', data: [{x:mphX1,y:mph.target},{x:mphX2,y:mph.target}], borderColor:'rgba(139,92,246,0.8)', borderDash:[6,3], fill:false, pointRadius:3, pointHoverRadius:6, borderWidth:2, tension:0, order:5 });
}
if (age > 24) {
var lfaYears = {}; Object.keys(lfaTable).forEach(function(k) { lfaYears[+(k/12).toFixed(2)] = lfaTable[k]; });
renderGrowthChart('growth-chart-canvas', 'growth-chart-container', lfaYears, +(age/12).toFixed(2), len, 'Age (years)', 'Length/Height (cm)', mphDatasets);
} else {
renderGrowthChart('growth-chart-canvas', 'growth-chart-container', lfaTable, age, len, 'Age (months)', 'Length/Height (cm)', mphDatasets);
}
}
else if (currentGrowthType === 'hcfa') {
var hc = parseFloat(document.getElementById('growth-hc').value);
if (!hc) { showToast('Enter head circumference', 'error'); return; }
if (age > 60) { showToast('HC charts available 0-60 months only', 'error'); return; }
var lms = interpolateLMS(hcfaLMS[sex], age);
var z = calcZFromLMS(hc, lms.L, lms.M, lms.S);
var p = normalCDF(z) * 100;
resultDiv.classList.remove('hidden');
resultDiv.innerHTML = renderGrowthResult('Head Circumference (' + age + ' mo)', hc, 'cm', z, p);
if (age > 24) {
var hcYears = {}; Object.keys(hcfaLMS[sex]).forEach(function(k) { hcYears[+(k/12).toFixed(2)] = hcfaLMS[sex][k]; });
renderGrowthChart('growth-chart-canvas', 'growth-chart-container', hcYears, +(age/12).toFixed(2), hc, 'Age (years)', 'Head Circumference (cm)');
} else {
renderGrowthChart('growth-chart-canvas', 'growth-chart-container', hcfaLMS[sex], age, hc, 'Age (months)', 'Head Circumference (cm)');
}
}
else if (currentGrowthType === 'wfl') {
var wt = parseFloat(document.getElementById('growth-weight').value);
var len = parseFloat(document.getElementById('growth-length').value);
if (!wt || !len) { showToast('Enter weight and length', 'error'); return; }
// Use WHO Weight-for-Length if length is within 45-110cm range
if (len >= 45 && len <= 110 && wflLMS[sex]) {
var lms = interpolateLMS(wflLMS[sex], len);
var z = calcZFromLMS(wt, lms.L, lms.M, lms.S);
var p = normalCDF(z) * 100;
resultDiv.classList.remove('hidden');
resultDiv.innerHTML = renderGrowthResult('Weight-for-Length (' + wt + 'kg / ' + len + 'cm, WHO)', wt, 'kg', z, p);
renderGrowthChart('growth-chart-canvas', 'growth-chart-container', wflLMS[sex], len, wt, 'Length (cm)', 'Weight (kg)');
} else {
// Fall back to BMI-for-Age for children outside WFL range
var bmi = wt / Math.pow(len / 100, 2);
var ageMonths = Math.max(24, Math.min(240, Math.round(age)));
var lms = interpolateLMS(bmiLMS[sex], ageMonths);
var z = calcZFromLMS(bmi, lms.L, lms.M, lms.S);
var p = normalCDF(z) * 100;
resultDiv.classList.remove('hidden');
resultDiv.innerHTML = renderGrowthResult('Weight-for-Length (' + wt + 'kg / ' + len + 'cm, BMI proxy)', 'BMI ' + bmi.toFixed(1), 'kg/m2', z, p);
}
}
});
document.getElementById('btn-clear-growth').addEventListener('click', function() {
['growth-sex', 'growth-age-yr', 'growth-age-mo', 'growth-age-d', 'growth-ga', 'growth-weight', 'growth-length', 'growth-hc'].forEach(function(id) {
var el = document.getElementById(id); if (el) el.value = '';
});
var hint = document.getElementById('growth-age-parsed'); if (hint) hint.textContent = '';
document.getElementById('growth-result').classList.add('hidden');
});
// Live feedback as the age fields change
var ageHint = document.getElementById('growth-age-parsed');
function updateAgeHint() {
if (!ageHint) return;
var yrRaw = ((document.getElementById('growth-age-yr') || {}).value || '').trim();
var moRaw = ((document.getElementById('growth-age-mo') || {}).value || '').trim();
var dyRaw = ((document.getElementById('growth-age-d') || {}).value || '').trim();
if (yrRaw === '' && moRaw === '' && dyRaw === '') { ageHint.textContent = ''; return; }
var total = (parseFloat(yrRaw) || 0) * 12 + (parseFloat(moRaw) || 0) + (parseFloat(dyRaw) || 0) / 30.4375;
ageHint.style.color = 'var(--g500)';
ageHint.textContent = formatParsedAge(total);
}
['growth-age-yr', 'growth-age-mo', 'growth-age-d'].forEach(function(id) {
var el = document.getElementById(id);
if (el) el.addEventListener('input', updateAgeHint);
});
// ═══════════════════════════════════════════════════════════
// BILIRUBIN — AAP 2022 Phototherapy + Bhutani Nomogram
// ═══════════════════════════════════════════════════════════
// ── Bilirubin chart helpers ──
function generateThresholdCurve(table) {
var keys = Object.keys(table).map(Number).sort(function(a,b){return a-b;});
return keys.map(function(h) { return { x: h, y: table[h] }; });
}
function renderBiliChart(patientHours, patientTSB, curveDatasets) {
if (typeof Chart === 'undefined') return;
var container = document.getElementById('bili-chart-container');
if (!container) return;
container.classList.remove('hidden');
if (_chartInstances['bili-chart-canvas']) { _chartInstances['bili-chart-canvas'].destroy(); _chartInstances['bili-chart-canvas'] = null; }
var datasets = curveDatasets.map(function(ds) {
return Object.assign({ pointRadius: 0, pointHoverRadius: 0, tension: 0.3, order: 10 }, ds);
});
// Patient point
datasets.push({
label: 'Patient',
data: [{ x: patientHours, y: patientTSB }],
backgroundColor: '#2563eb',
borderColor: '#1d4ed8',
pointRadius: 8,
pointHoverRadius: 10,
showLine: false,
type: 'scatter',
order: 0
});
_chartInstances['bili-chart-canvas'] = new Chart(document.getElementById('bili-chart-canvas'), {
type: 'line',
data: { datasets: datasets },
options: {
responsive: true,
maintainAspectRatio: true,
aspectRatio: 1.6,
animation: { duration: 300 },
scales: {
x: { type: 'linear', title: { display: true, text: 'Age (hours)', font: { size: 12, weight: 'bold' } }, min: 12, max: 150, grid: { color: 'rgba(0,0,0,0.05)' } },
y: { title: { display: true, text: 'TSB (mg/dL)', font: { size: 12, weight: 'bold' } }, min: 0, grid: { color: 'rgba(0,0,0,0.05)' } }
},
plugins: {
legend: { display: true, position: 'bottom', labels: { font: { size: 11 }, usePointStyle: true, pointStyle: 'line' } },
tooltip: {
callbacks: {
label: function(ctx) {
if (ctx.dataset.label === 'Patient') return 'Patient: ' + ctx.parsed.y.toFixed(1) + ' mg/dL at ' + ctx.parsed.x + 'h';
return ctx.dataset.label + ': ' + ctx.parsed.y.toFixed(1) + ' mg/dL';
}
}
}
}
}
});
}
// AAP 2022 phototherapy thresholds (TSB in mg/dL) by hour of age
// Source: Kemper et al., Pediatrics 2022;150(3):e2022058859, Figures 2-3
// Values read from published nomogram curves at key time points
// NOTE: The AAP 2022 raised thresholds ~2 mg/dL above the 2004 guidelines
// AAP 2022 EXACT hour-by-hour phototherapy thresholds (extracted from PediTools API, validated against AAP nomograms)
// >= 38 weeks, no neurotoxicity risk factors
var photoThresholds38 = {12:10.1,13:10.3,14:10.5,15:10.7,16:10.8,17:11,18:11.2,19:11.4,20:11.6,21:11.7,22:11.9,23:12.1,24:12.3,25:12.4,26:12.6,27:12.8,28:12.9,29:13.1,30:13.3,31:13.4,32:13.6,33:13.8,34:13.9,35:14.1,36:14.2,37:14.4,38:14.5,39:14.7,40:14.8,41:15,42:15.1,43:15.3,44:15.4,45:15.6,46:15.7,47:15.8,48:16,49:16.1,50:16.2,51:16.4,52:16.5,53:16.6,54:16.8,55:16.9,56:17,57:17.1,58:17.3,59:17.4,60:17.5,61:17.6,62:17.7,63:17.8,64:17.9,65:18.1,66:18.2,67:18.3,68:18.4,69:18.5,70:18.6,71:18.7,72:18.8,73:18.9,74:19,75:19.1,76:19.2,77:19.3,78:19.4,79:19.5,80:19.5,81:19.6,82:19.7,83:19.8,84:19.9,85:20,86:20,87:20.1,88:20.2,89:20.3,90:20.3,91:20.4,92:20.5,93:20.6,94:20.6,95:20.7,96:20.7};
// >= 38 weeks, WITH neurotoxicity risk factors
var photoThresholds38risk = {12:8.5,13:8.6,14:8.8,15:9,16:9.2,17:9.4,18:9.5,19:9.7,20:9.9,21:10,22:10.2,23:10.4,24:10.5,25:10.7,26:10.8,27:11,28:11.2,29:11.3,30:11.5,31:11.6,32:11.8,33:11.9,34:12.1,35:12.2,36:12.4,37:12.5,38:12.7,39:12.8,40:12.9,41:13.1,42:13.2,43:13.3,44:13.5,45:13.6,46:13.7,47:13.9,48:14,49:14.1,50:14.2,51:14.4,52:14.5,53:14.6,54:14.7,55:14.8,56:14.9,57:15.1,58:15.2,59:15.3,60:15.4,61:15.5,62:15.6,63:15.7,64:15.8,65:15.9,66:16,67:16.1,68:16.2,69:16.3,70:16.4,71:16.5,72:16.6,73:16.6,74:16.7,75:16.8,76:16.9,77:17,78:17.1,79:17.1,80:17.2,81:17.3,82:17.4,83:17.4,84:17.5,85:17.6,86:17.6,87:17.7,88:17.8,89:17.8,90:17.9,91:18,92:18,93:18.1,94:18.1,95:18.2,96:18.2};
// 36-37 weeks, no neurotoxicity risk factors
var photoThresholds36 = {12:9,13:9.2,14:9.4,15:9.6,16:9.8,17:9.9,18:10.1,19:10.3,20:10.5,21:10.6,22:10.8,23:11,24:11.2,25:11.3,26:11.5,27:11.7,28:11.8,29:12,30:12.1,31:12.3,32:12.5,33:12.6,34:12.8,35:12.9,36:13.1,37:13.2,38:13.4,39:13.5,40:13.7,41:13.8,42:13.9,43:14.1,44:14.2,45:14.4,46:14.5,47:14.6,48:14.8,49:14.9,50:15,51:15.1,52:15.3,53:15.4,54:15.5,55:15.6,56:15.8,57:15.9,58:16,59:16.1,60:16.2,61:16.3,62:16.5,63:16.6,64:16.7,65:16.8,66:16.9,67:17,68:17.1,69:17.2,70:17.3,71:17.4,72:17.5,73:17.6,74:17.7,75:17.8,76:17.9,77:17.9,78:18,79:18.1,80:18.2,81:18.3,82:18.4,83:18.4,84:18.5,85:18.6,86:18.7,87:18.8,88:18.8,89:18.9,90:19,91:19,92:19.1,93:19.2,94:19.2,95:19.3,96:19.3};
// 36-37 weeks, WITH neurotoxicity risk factors
var photoThresholds36risk = {12:7.4,13:7.6,14:7.8,15:8,16:8.1,17:8.3,18:8.5,19:8.6,20:8.8,21:9,22:9.1,23:9.3,24:9.4,25:9.6,26:9.8,27:9.9,28:10.1,29:10.2,30:10.4,31:10.5,32:10.7,33:10.8,34:11,35:11.1,36:11.2,37:11.4,38:11.5,39:11.7,40:11.8,41:11.9,42:12.1,43:12.2,44:12.3,45:12.5,46:12.6,47:12.7,48:12.8,49:13,50:13.1,51:13.2,52:13.3,53:13.4,54:13.5,55:13.7,56:13.8,57:13.9,58:14,59:14.1,60:14.2,61:14.3,62:14.4,63:14.5,64:14.6,65:14.7,66:14.8,67:14.9,68:15,69:15.1,70:15.2,71:15.3,72:15.4,73:15.4,74:15.5,75:15.6,76:15.7,77:15.8,78:15.8,79:15.9,80:16,81:16.1,82:16.1,83:16.2,84:16.3,85:16.4,86:16.4,87:16.5,88:16.6,89:16.6,90:16.7,91:16.7,92:16.8,93:16.8,94:16.9,95:17,96:17};
// 35 weeks, no neurotoxicity risk factors
var photoThresholds35 = {12:8.5,13:8.7,14:8.9,15:9,16:9.2,17:9.4,18:9.6,19:9.8,20:9.9,21:10.1,22:10.3,23:10.4,24:10.6,25:10.8,26:10.9,27:11.1,28:11.3,29:11.4,30:11.6,31:11.7,32:11.9,33:12,34:12.2,35:12.3,36:12.5,37:12.6,38:12.8,39:12.9,40:13.1,41:13.2,42:13.4,43:13.5,44:13.6,45:13.8,46:13.9,47:14,48:14.2,49:14.3,50:14.4,51:14.5,52:14.7,53:14.8,54:14.9,55:15,56:15.1,57:15.3,58:15.4,59:15.5,60:15.6,61:15.7,62:15.8,63:15.9,64:16,65:16.1,66:16.2,67:16.3,68:16.4,69:16.5,70:16.6,71:16.7,72:16.8,73:16.9,74:17,75:17.1,76:17.2,77:17.3,78:17.4,79:17.5,80:17.5,81:17.6,82:17.7,83:17.8,84:17.8,85:17.9,86:18,87:18.1,88:18.1,89:18.2,90:18.3,91:18.3,92:18.4,93:18.5,94:18.5,95:18.6,96:18.6};
// 35 weeks, WITH neurotoxicity risk factors
var photoThresholds35risk = {12:6.9,13:7.1,14:7.2,15:7.4,16:7.6,17:7.7,18:7.9,19:8.1,20:8.2,21:8.4,22:8.6,23:8.7,24:8.9,25:9,26:9.2,27:9.3,28:9.5,29:9.6,30:9.8,31:9.9,32:10.1,33:10.2,34:10.3,35:10.5,36:10.6,37:10.8,38:10.9,39:11,40:11.2,41:11.3,42:11.4,43:11.5,44:11.7,45:11.8,46:11.9,47:12,48:12.2,49:12.3,50:12.4,51:12.5,52:12.6,53:12.7,54:12.8,55:13,56:13.1,57:13.2,58:13.3,59:13.4,60:13.5,61:13.6,62:13.7,63:13.8,64:13.9,65:14,66:14.1,67:14.2,68:14.2,69:14.3,70:14.4,71:14.5,72:14.6,73:14.7,74:14.8,75:14.8,76:14.9,77:15,78:15.1,79:15.1,80:15.2,81:15.3,82:15.3,83:15.4,84:15.5,85:15.5,86:15.6,87:15.7,88:15.7,89:15.8,90:15.8,91:15.9,92:15.9,93:16,94:16.1,95:16.1,96:16.1};
// Exchange transfusion thresholds (AAP 2022, hour-by-hour from PediTools)
var exchangeThresholds38 = {12:19.7,13:19.9,14:20,15:20.1,16:20.3,17:20.4,18:20.6,19:20.7,20:20.8,21:21,22:21.1,23:21.2,24:21.4,25:21.5,26:21.6,27:21.7,28:21.9,29:22,30:22.1,31:22.2,32:22.3,33:22.4,34:22.6,35:22.7,36:22.8,37:22.9,38:23,39:23.1,40:23.2,41:23.3,42:23.4,43:23.5,44:23.6,45:23.7,46:23.8,47:23.9,48:24,49:24.1,50:24.2,51:24.3,52:24.4,53:24.5,54:24.6,55:24.7,56:24.7,57:24.8,58:24.9,59:25,60:25.1,61:25.2,62:25.2,63:25.3,64:25.4,65:25.5,66:25.5,67:25.6,68:25.7,69:25.7,70:25.8,71:25.9,72:25.9,73:26,74:26,75:26.1,76:26.2,77:26.2,78:26.3,79:26.3,80:26.4,81:26.4,82:26.5,83:26.5,84:26.6,85:26.6,86:26.7,87:26.7,88:26.7,89:26.8,90:26.8,91:26.9,92:26.9,93:26.9,94:27,95:27,96:27};
var exchangeThresholds38risk = {12:16.3,13:16.4,14:16.5,15:16.6,16:16.7,17:16.9,18:17,19:17.1,20:17.2,21:17.3,22:17.4,23:17.6,24:17.7,25:17.8,26:17.9,27:18,28:18.1,29:18.2,30:18.3,31:18.4,32:18.5,33:18.7,34:18.8,35:18.9,36:19,37:19.1,38:19.2,39:19.3,40:19.4,41:19.5,42:19.6,43:19.7,44:19.8,45:19.9,46:19.9,47:20,48:20.1,49:20.2,50:20.3,51:20.4,52:20.5,53:20.6,54:20.7,55:20.8,56:20.8,57:20.9,58:21,59:21.1,60:21.2,61:21.3,62:21.3,63:21.4,64:21.5,65:21.6,66:21.7,67:21.7,68:21.8,69:21.9,70:22,71:22,72:22.1,73:22.2,74:22.2,75:22.3,76:22.4,77:22.5,78:22.5,79:22.6,80:22.7,81:22.7,82:22.8,83:22.8,84:22.9,85:23,86:23,87:23.1,88:23.1,89:23.2,90:23.3,91:23.3,92:23.4,93:23.4,94:23.5,95:23.5,96:23.5};
var exchangeThresholds36 = {12:17.5,13:17.7,14:17.8,15:17.9,16:18.1,17:18.2,18:18.3,19:18.5,20:18.6,21:18.7,22:18.9,23:19,24:19.1,25:19.2,26:19.4,27:19.5,28:19.6,29:19.7,30:19.9,31:20,32:20.1,33:20.2,34:20.4,35:20.5,36:20.6,37:20.7,38:20.8,39:20.9,40:21,41:21.2,42:21.3,43:21.4,44:21.5,45:21.6,46:21.7,47:21.8,48:21.9,49:22,50:22.1,51:22.2,52:22.3,53:22.4,54:22.5,55:22.6,56:22.7,57:22.8,58:22.9,59:23,60:23.1,61:23.2,62:23.2,63:23.3,64:23.4,65:23.5,66:23.6,67:23.7,68:23.8,69:23.8,70:23.9,71:24,72:24.1,73:24.1,74:24.2,75:24.3,76:24.4,77:24.4,78:24.5,79:24.6,80:24.6,81:24.7,82:24.8,83:24.8,84:24.9,85:25,86:25,87:25.1,88:25.2,89:25.2,90:25.3,91:25.3,92:25.4,93:25.4,94:25.5,95:25.5,96:25.5};
var exchangeThresholds36risk = {12:15.2,13:15.3,14:15.4,15:15.6,16:15.7,17:15.8,18:15.9,19:16.1,20:16.2,21:16.3,22:16.4,23:16.5,24:16.6,25:16.8,26:16.9,27:17,28:17.1,29:17.2,30:17.3,31:17.4,32:17.5,33:17.6,34:17.7,35:17.8,36:17.9,37:18,38:18.1,39:18.2,40:18.3,41:18.4,42:18.5,43:18.6,44:18.7,45:18.8,46:18.9,47:19,48:19.1,49:19.2,50:19.2,51:19.3,52:19.4,53:19.5,54:19.6,55:19.7,56:19.7,57:19.8,58:19.9,59:20,60:20.1,61:20.1,62:20.2,63:20.3,64:20.3,65:20.4,66:20.5,67:20.6,68:20.6,69:20.7,70:20.8,71:20.8,72:20.9,73:20.9,74:21,75:21.1,76:21.1,77:21.2,78:21.2,79:21.3,80:21.4,81:21.4,82:21.5,83:21.5,84:21.6,85:21.6,86:21.7,87:21.7,88:21.8,89:21.8,90:21.9,91:21.9,92:22,93:22,94:22,95:22.1,96:22.1};
var exchangeThresholds35 = {12:16.4,13:16.5,14:16.6,15:16.8,16:16.9,17:17,18:17.2,19:17.3,20:17.4,21:17.5,22:17.7,23:17.8,24:17.9,25:18,26:18.2,27:18.3,28:18.4,29:18.5,30:18.7,31:18.8,32:18.9,33:19,34:19.1,35:19.2,36:19.4,37:19.5,38:19.6,39:19.7,40:19.8,41:19.9,42:20,43:20.1,44:20.2,45:20.3,46:20.5,47:20.6,48:20.7,49:20.8,50:20.9,51:21,52:21.1,53:21.2,54:21.3,55:21.4,56:21.5,57:21.6,58:21.7,59:21.7,60:21.8,61:21.9,62:22,63:22.1,64:22.2,65:22.3,66:22.4,67:22.5,68:22.6,69:22.6,70:22.7,71:22.8,72:22.9,73:23,74:23.1,75:23.1,76:23.2,77:23.3,78:23.4,79:23.4,80:23.5,81:23.6,82:23.7,83:23.7,84:23.8,85:23.9,86:23.9,87:24,88:24.1,89:24.1,90:24.2,91:24.3,92:24.3,93:24.4,94:24.4,95:24.5,96:24.5};
var exchangeThresholds35risk = {12:14.6,13:14.8,14:14.9,15:15,16:15.1,17:15.3,18:15.4,19:15.5,20:15.6,21:15.8,22:15.9,23:16,24:16.1,25:16.2,26:16.3,27:16.4,28:16.5,29:16.6,30:16.8,31:16.9,32:17,33:17.1,34:17.2,35:17.3,36:17.4,37:17.5,38:17.6,39:17.7,40:17.7,41:17.8,42:17.9,43:18,44:18.1,45:18.2,46:18.3,47:18.4,48:18.5,49:18.5,50:18.6,51:18.7,52:18.8,53:18.9,54:18.9,55:19,56:19.1,57:19.2,58:19.2,59:19.3,60:19.4,61:19.4,62:19.5,63:19.6,64:19.6,65:19.7,66:19.8,67:19.8,68:19.9,69:19.9,70:20,71:20.1,72:20.1,73:20.2,74:20.2,75:20.3,76:20.3,77:20.4,78:20.4,79:20.5,80:20.5,81:20.6,82:20.6,83:20.6,84:20.7,85:20.7,86:20.8,87:20.8,88:20.8,89:20.9,90:20.9,91:20.9,92:21,93:21,94:21,95:21.1,96:21.1};
function interpolateThreshold(table, hours) {
var keys = Object.keys(table).map(Number).sort(function(a,b){return a-b;});
if (hours <= keys[0]) return table[keys[0]];
if (hours >= keys[keys.length-1]) return table[keys[keys.length-1]];
for (var i = 0; i < keys.length-1; i++) {
if (hours >= keys[i] && hours <= keys[i+1]) {
var t = (hours - keys[i]) / (keys[i+1] - keys[i]);
return table[keys[i]] + t * (table[keys[i+1]] - table[keys[i]]);
}
}
return table[keys[0]];
}
// Bili sub-pill nav
document.querySelectorAll('[data-bili]').forEach(function(pill) {
pill.addEventListener('click', function() {
document.querySelectorAll('[data-bili]').forEach(function(p) { p.classList.remove('active'); });
pill.classList.add('active');
document.getElementById('bili-aap-panel').style.display = pill.dataset.bili === 'aap' ? '' : 'none';
document.getElementById('bili-bhutani-panel').style.display = pill.dataset.bili === 'bhutani' ? '' : 'none';
document.getElementById('bili-result').classList.add('hidden');
var biliChartC = document.getElementById('bili-chart-container');
if (biliChartC) biliChartC.classList.add('hidden');
if (_chartInstances['bili-chart-canvas']) { _chartInstances['bili-chart-canvas'].destroy(); _chartInstances['bili-chart-canvas'] = null; }
});
});
document.getElementById('btn-calc-bili-aap').addEventListener('click', function() {
var ga = document.getElementById('bili-ga').value;
var hours = parseFloat(document.getElementById('bili-age-hours').value);
var tsb = parseFloat(document.getElementById('bili-tsb').value);
var risk = document.getElementById('bili-risk').value;
if (!ga || isNaN(hours) || isNaN(tsb)) { showToast('Fill in all fields', 'error'); return; }
var gaNum = parseInt(ga);
var table;
if (gaNum >= 38) table = risk === 'medium' ? photoThresholds38risk : photoThresholds38;
else if (gaNum === 36 || gaNum === 37) table = risk === 'medium' ? photoThresholds36risk : photoThresholds36;
else table = risk === 'medium' ? photoThresholds35risk : photoThresholds35;
var threshold = interpolateThreshold(table, hours);
var aboveThreshold = tsb >= threshold;
// Check exchange transfusion threshold too
var exchangeTable;
if (gaNum >= 38) exchangeTable = risk === 'medium' ? exchangeThresholds38risk : exchangeThresholds38;
else if (gaNum >= 36) exchangeTable = risk === 'medium' ? exchangeThresholds36risk : exchangeThresholds36;
else exchangeTable = risk === 'medium' ? exchangeThresholds35risk : exchangeThresholds35;
var exchangeThreshold = exchangeTable ? interpolateThreshold(exchangeTable, hours) : null;
var aboveExchange = exchangeThreshold && tsb >= exchangeThreshold;
var cl;
if (aboveExchange) cl = { text: 'ABOVE EXCHANGE TRANSFUSION THRESHOLD', color: '#7f1d1d', bg: '#fecaca' };
else if (aboveThreshold) cl = { text: 'Above Phototherapy Threshold', color: '#ef4444', bg: '#fee2e2' };
else cl = { text: 'Below Phototherapy Threshold', color: '#10b981', bg: '#d1fae5' };
var resultDiv = document.getElementById('bili-result');
resultDiv.classList.remove('hidden');
resultDiv.innerHTML =
'<div class="calc-result-header" style="background:' + cl.bg + ';border-color:' + cl.color + ';">' +
'<div style="font-size:18px;font-weight:700;color:' + cl.color + ';">' + cl.text + '</div>' +
'<div style="font-size:13px;color:var(--g600);margin-top:4px;">TSB ' + tsb + ' mg/dL at ' + hours + ' hours of life</div>' +
'</div>' +
'<div class="calc-result-grid">' +
'<div class="calc-result-item"><div class="calc-result-label">Patient TSB</div><div class="calc-result-value">' + tsb + '</div><div class="calc-result-sub">mg/dL</div></div>' +
'<div class="calc-result-item"><div class="calc-result-label">Photo Threshold</div><div class="calc-result-value">' + threshold.toFixed(1) + '</div><div class="calc-result-sub">mg/dL at ' + hours + 'h</div></div>' +
'<div class="calc-result-item"><div class="calc-result-label">Margin</div><div class="calc-result-value" style="color:' + cl.color + ';">' + (tsb >= threshold ? '+' : '') + (tsb - threshold).toFixed(1) + '</div><div class="calc-result-sub">mg/dL ' + (aboveThreshold ? 'above' : 'below') + ' photo</div></div>' +
(exchangeThreshold ? '<div class="calc-result-item"><div class="calc-result-label">Exchange Threshold</div><div class="calc-result-value" style="color:#7f1d1d;">' + exchangeThreshold.toFixed(1) + '</div><div class="calc-result-sub">mg/dL' + (aboveExchange ? ' — EXCEEDED' : '') + '</div></div>' : '') +
'</div>' +
'<p style="font-size:11px;color:var(--g400);margin:12px 0 0;">GA ' + ga + ' weeks, ' + (risk === 'medium' ? 'with' : 'without') + ' neurotoxicity risk factors. AAP 2022 CPG (exact values from published nomograms). Always use clinical judgment.</p>';
// Chart: phototherapy + exchange threshold lines vs patient
var chartDatasets = [
{ label: 'Phototherapy Threshold', data: generateThresholdCurve(table), borderColor: '#ef4444', borderWidth: 2, borderDash: [], fill: { target: 'origin', above: 'rgba(239,68,68,0.08)' } }
];
if (exchangeTable) {
chartDatasets.push({ label: 'Exchange Transfusion', data: generateThresholdCurve(exchangeTable), borderColor: '#7f1d1d', borderWidth: 2, borderDash: [6,3], fill: false });
}
renderBiliChart(hours, tsb, chartDatasets);
});
document.getElementById('btn-clear-bili-aap').addEventListener('click', function() {
['bili-ga', 'bili-age-hours', 'bili-tsb', 'bili-risk'].forEach(function(id) {
var el = document.getElementById(id); if (el) el.value = '';
});
document.getElementById('bili-result').classList.add('hidden');
var bc = document.getElementById('bili-chart-container'); if (bc) bc.classList.add('hidden');
});
// Bhutani 1999 hour-specific risk nomogram — 40th / 75th / 95th
// percentile TSB boundaries. Values are a pre-digitized transcription
// of the original Figure 2 (Bhutani VK et al., Pediatrics 1999;103(1):6-14),
// lifted verbatim from the JS data arrays used by the codingace.net
// Bhutani calculator:
// https://codingace.net/health/neonate_bilirubin_bhutani.html
// Cross-checked against the AAP 2004 CPG reproduction of the same chart:
// https://staffnet.southernhealth.ca/wp-content/uploads/Bhutani-Nomogram.pdf
// (Reproduced with AAP permission from Pediatrics 2004;114:297-316)
// 6-hour granularity through the first 72 h, 12-hour after.
//
// Zone semantics (per AAP 2004 reproduction legend):
// High-risk: TSB >= 95th percentile
// High-intermediate: 75th <= TSB < 95th
// Low-intermediate: 40th <= TSB < 75th
// Low-risk: TSB < 40th
//
// Clinical note: this nomogram is for RISK STRATIFICATION only.
// For phototherapy/exchange decisions use the AAP 2022 tab
// (which supersedes the 2004 treatment thresholds).
var bhutaniZones = {
p95: { 6:6.0, 12:7.2, 18:8.5, 24:9.6, 30:11.2, 36:12.8, 42:13.8, 48:14.8,
54:15.6, 60:16.2, 66:16.8, 72:17.4, 84:18.0, 96:18.4, 108:18.8, 120:19.0 },
p75: { 6:4.5, 12:5.5, 18:6.6, 24:7.8, 30:9.2, 36:10.6, 42:11.6, 48:12.6,
54:13.4, 60:14.0, 66:14.6, 72:15.0, 84:15.4, 96:15.6, 108:15.8, 120:16.0 },
p40: { 6:3.0, 12:4.0, 18:5.0, 24:6.2, 30:7.2, 36:8.4, 42:9.2, 48:10.0,
54:10.6, 60:11.2, 66:11.8, 72:12.2, 84:12.6, 96:12.8, 108:13.0, 120:13.2 }
};
document.getElementById('btn-calc-bhutani').addEventListener('click', function() {
var hours = parseFloat(document.getElementById('bhutani-age').value);
var tsb = parseFloat(document.getElementById('bhutani-tsb').value);
if (isNaN(hours) || isNaN(tsb)) { showToast('Fill in all fields', 'error'); return; }
var p95 = interpolateThreshold(bhutaniZones.p95, hours);
var p75 = interpolateThreshold(bhutaniZones.p75, hours);
var p40 = interpolateThreshold(bhutaniZones.p40, hours);
var zone, cl;
if (tsb >= p95) { zone = 'High-Risk Zone'; cl = { color: '#ef4444', bg: '#fee2e2' }; }
else if (tsb >= p75) { zone = 'High-Intermediate Zone'; cl = { color: '#f97316', bg: '#ffedd5' }; }
else if (tsb >= p40) { zone = 'Low-Intermediate Zone'; cl = { color: '#f59e0b', bg: '#fef3c7' }; }
else { zone = 'Low-Risk Zone'; cl = { color: '#10b981', bg: '#d1fae5' }; }
var resultDiv = document.getElementById('bili-result');
resultDiv.classList.remove('hidden');
resultDiv.innerHTML =
'<div class="calc-result-header" style="background:' + cl.bg + ';border-color:' + cl.color + ';">' +
'<div style="font-size:18px;font-weight:700;color:' + cl.color + ';">' + zone + '</div>' +
'<div style="font-size:13px;color:var(--g600);margin-top:4px;">TSB ' + tsb + ' mg/dL at ' + hours + ' hours of life</div>' +
'</div>' +
'<div class="calc-result-grid">' +
'<div class="calc-result-item"><div class="calc-result-label">95th %ile</div><div class="calc-result-value" style="font-size:16px;color:#ef4444;">' + p95.toFixed(1) + '</div><div class="calc-result-sub">High-risk</div></div>' +
'<div class="calc-result-item"><div class="calc-result-label">75th %ile</div><div class="calc-result-value" style="font-size:16px;color:#f97316;">' + p75.toFixed(1) + '</div><div class="calc-result-sub">High-intermediate</div></div>' +
'<div class="calc-result-item"><div class="calc-result-label">40th %ile</div><div class="calc-result-value" style="font-size:16px;color:#f59e0b;">' + p40.toFixed(1) + '</div><div class="calc-result-sub">Low-intermediate</div></div>' +
'</div>' +
'<p style="font-size:11px;color:var(--g400);margin:12px 0 0;">Bhutani hour-specific risk nomogram for infants &ge; 35 weeks GA. Digitized values from Bhutani et al., Pediatrics 1999 (cross-checked against the AAP 2004 CPG reproduction). For phototherapy decisions use the AAP 2022 tab.</p>';
// Chart: Bhutani zone curves with patient
renderBiliChart(hours, tsb, [
{ label: '95th (High-Risk)', data: generateThresholdCurve(bhutaniZones.p95), borderColor: '#ef4444', borderWidth: 2, fill: false, borderDash: [] },
{ label: '75th (High-Intermed)', data: generateThresholdCurve(bhutaniZones.p75), borderColor: '#f97316', borderWidth: 1.5, fill: { target: '-1', above: 'rgba(239,68,68,0.08)' }, borderDash: [3,3] },
{ label: '40th (Low-Intermed)', data: generateThresholdCurve(bhutaniZones.p40), borderColor: '#f59e0b', borderWidth: 1.5, fill: { target: '-1', above: 'rgba(249,115,22,0.08)' }, borderDash: [3,3] }
]);
});
document.getElementById('btn-clear-bhutani').addEventListener('click', function() {
['bhutani-age', 'bhutani-tsb'].forEach(function(id) {
var el = document.getElementById(id); if (el) el.value = '';
});
document.getElementById('bili-result').classList.add('hidden');
var bc = document.getElementById('bili-chart-container'); if (bc) bc.classList.add('hidden');
});
// ═══════════════════════════════════════════════════════════
// VITAL SIGNS — Interactive age selector
// Harriet Lane Handbook 23rd Edition reference values
// ═══════════════════════════════════════════════════════════
var VITALS_DATA = {
premie: {
label: 'Premie',
hr: { awake: '120-170', sleeping: '100-150' },
rr: '40-70',
sbp: '55-75', dbp: '35-45',
temp: '36.5-37.5',
weight: '0.5-2.5 kg',
spo2: '88-95% (target)',
notes: [
'HR and RR are highly variable and depend on gestational age',
'BP increases with gestational age and postnatal age',
'Target SpO2 88-95% to reduce retinopathy of prematurity risk',
'Temperature instability is common — use servo-controlled warmers',
'Bradycardia (<100 bpm) and apnea are common in premature infants'
]
},
'0-3mo': {
label: '0-3 Months',
hr: { awake: '100-150', sleeping: '85-135' },
rr: '35-55',
sbp: '65-85', dbp: '45-55',
temp: '36.5-37.5',
weight: '2.5-6 kg',
spo2: '>95%',
notes: [
'HR normally increases with crying (up to 180-190 bpm) — this is physiologic',
'Periodic breathing (pauses <10 sec) is normal in neonates',
'Acrocyanosis (blue hands/feet) is normal; central cyanosis is not',
'BP is best measured in the right arm (pre-ductal) in neonates',
'Normal weight loss of 5-7% in first 3-5 days; regain by 10-14 days'
]
},
'3-6mo': {
label: '3-6 Months',
hr: { awake: '90-120', sleeping: '75-110' },
rr: '30-45',
sbp: '70-90', dbp: '50-65',
temp: '36.5-37.5',
weight: '5-8 kg',
spo2: '>95%',
notes: [
'Expected weight gain: 20-30 g/day (150-200 g/week)',
'HR gradually decreases as vagal tone matures',
'RR >60 at rest may indicate lower respiratory tract disease',
'BP should be measured with appropriate cuff size (width 40% of arm circumference)'
]
},
'6-12mo': {
label: '6-12 Months',
hr: { awake: '80-120', sleeping: '70-110' },
rr: '25-40',
sbp: '80-100', dbp: '55-65',
temp: '36.0-37.5',
weight: '8-10 kg',
spo2: '>95%',
notes: [
'Expected weight: triple birth weight by 12 months (~10 kg average)',
'Weight gain slows to ~10-15 g/day',
'Sinus arrhythmia (HR varies with breathing) is normal',
'Febrile tachycardia: HR increases ~10 bpm per 1 degree C above 37'
]
},
'1-3yr': {
label: '1-3 Years',
hr: { awake: '70-110', sleeping: '60-100' },
rr: '20-30',
sbp: '90-105', dbp: '55-70',
temp: '36.0-37.5',
weight: '10-15 kg',
spo2: '>95%',
notes: [
'Expected weight gain: ~200-250 g/month (2-2.5 kg/year)',
'Tachycardia: HR >110 at rest warrants evaluation',
'Tachypnea: RR >30 at rest may indicate respiratory distress',
'BP screening begins at age 3 per AAP 2017 guidelines',
'Estimated weight: 2 x (age in years) + 8'
]
},
'3-6yr': {
label: '3-6 Years',
hr: { awake: '65-110', sleeping: '55-100' },
rr: '20-25',
sbp: '95-110', dbp: '60-75',
temp: '36.0-37.5',
weight: '14-20 kg',
spo2: '>95%',
notes: [
'Annual BP screening recommended from age 3',
'Normal BP <90th percentile for age, sex, and height',
'Elevated BP: 90th to <95th percentile (or 120/80 if lower)',
'Estimated weight: 2 x (age in years) + 8',
'ETT size (uncuffed): (age/4) + 4'
]
},
'6-12yr': {
label: '6-12 Years',
hr: { awake: '60-95', sleeping: '50-85' },
rr: '14-22',
sbp: '100-120', dbp: '60-75',
temp: '36.0-37.5',
weight: '20-40 kg',
spo2: '>95%',
notes: [
'Resting HR >95 or <60 warrants evaluation',
'BP should be measured at every clinical encounter',
'Stage 1 HTN: >=95th percentile on 3 separate occasions',
'Estimated weight: 3 x (age in years) + 7',
'ETT size (cuffed): (age/4) + 3.5'
]
},
'>12yr': {
label: '>12 Years',
hr: { awake: '55-85', sleeping: '45-75' },
rr: '12-18',
sbp: '110-135', dbp: '65-85',
temp: '36.0-37.5',
weight: '40-80 kg',
spo2: '>95%',
notes: [
'Vital signs approach adult values',
'From age 13: use adult BP thresholds (AAP 2017)',
'Normal: <120/<80 mmHg; Elevated: 120-129/<80 mmHg',
'Stage 1 HTN: 130-139/80-89 mmHg; Stage 2 HTN: >=140/>=90 mmHg',
'Orthostatic vitals: measure lying, sitting, standing if dizzy',
'Athletic bradycardia (HR 45-60) may be normal in trained adolescents'
]
}
};
// Use event delegation on the vitals panel so the listener works even
// when the panel is hidden at init time (hidden elements are still in the DOM,
// but a setTimeout-based approach can race with dynamic content loading).
var vitalsPanel = document.getElementById('calc-vitals');
if (vitalsPanel) {
vitalsPanel.addEventListener('change', function(e) {
if (e.target.id !== 'vitals-age-select') return;
var key = e.target.value;
var resultDiv = document.getElementById('vitals-result');
if (!key || !VITALS_DATA[key]) { resultDiv.classList.add('hidden'); return; }
var v = VITALS_DATA[key];
resultDiv.classList.remove('hidden');
resultDiv.innerHTML =
'<div class="calc-result-header" style="background:#eff6ff;border-color:#2563eb;">' +
'<div style="font-size:18px;font-weight:700;color:#1d4ed8;">' + v.label + '</div>' +
'</div>' +
'<div class="calc-result-grid" style="margin-top:12px;">' +
'<div class="calc-result-item"><div class="calc-result-label">Heart Rate (awake)</div><div class="calc-result-value" style="font-size:18px;color:#ef4444;">' + v.hr.awake + '</div><div class="calc-result-sub">bpm</div></div>' +
'<div class="calc-result-item"><div class="calc-result-label">Heart Rate (sleep)</div><div class="calc-result-value" style="font-size:18px;color:#8b5cf6;">' + v.hr.sleeping + '</div><div class="calc-result-sub">bpm</div></div>' +
'<div class="calc-result-item"><div class="calc-result-label">Respiratory Rate</div><div class="calc-result-value" style="font-size:18px;color:#0ea5e9;">' + v.rr + '</div><div class="calc-result-sub">breaths/min</div></div>' +
'<div class="calc-result-item"><div class="calc-result-label">Systolic BP</div><div class="calc-result-value" style="font-size:18px;color:#f97316;">' + v.sbp + '</div><div class="calc-result-sub">mmHg</div></div>' +
'<div class="calc-result-item"><div class="calc-result-label">Diastolic BP</div><div class="calc-result-value" style="font-size:18px;color:#f59e0b;">' + v.dbp + '</div><div class="calc-result-sub">mmHg</div></div>' +
'<div class="calc-result-item"><div class="calc-result-label">Temperature</div><div class="calc-result-value" style="font-size:18px;color:#10b981;">' + v.temp + '</div><div class="calc-result-sub">&deg;C</div></div>' +
'<div class="calc-result-item"><div class="calc-result-label">SpO2</div><div class="calc-result-value" style="font-size:18px;color:#06b6d4;">' + v.spo2 + '</div><div class="calc-result-sub"></div></div>' +
'<div class="calc-result-item"><div class="calc-result-label">Weight Range</div><div class="calc-result-value" style="font-size:18px;color:#6366f1;">' + v.weight + '</div><div class="calc-result-sub"></div></div>' +
'</div>' +
'<div style="margin-top:14px;padding:12px;background:var(--g50);border-radius:8px;">' +
'<div style="font-size:12px;font-weight:600;color:var(--g600);margin-bottom:6px;">Clinical Notes</div>' +
'<ul style="margin:0;padding-left:16px;font-size:12px;color:var(--g700);line-height:1.7;">' +
v.notes.map(function(n) { return '<li>' + n + '</li>'; }).join('') +
'</ul>' +
'</div>';
});
}
// ═══════════════════════════════════════════════════════════
// RESUSCITATION MEDICATIONS — Harriet Lane Handbook / AHA PALS 2020
// ═══════════════════════════════════════════════════════════
var RESUS_MEDS = [
{
name: 'Adenosine', indication: 'SVT', category: 'cardiac',
route: 'IV/IO rapid bolus',
calc: function(w) {
var d1 = +(w * 0.1).toFixed(2);
var d2 = +(w * 0.2).toFixed(2);
var d3 = +(w * 0.3).toFixed(2);
return {
dose: d1 + ' mg (0.1 mg/kg)',
extra: 'May repeat: ' + Math.min(d2, 12) + ' mg (0.2 mg/kg), then ' + Math.min(d3, 12) + ' mg (0.3 mg/kg)',
max: 'Max first dose 6 mg, max subsequent 12 mg'
};
}
},
{
name: 'Amiodarone', indication: 'VT / VF', category: 'cardiac',
route: 'IV/IO',
calc: function(w) {
var d = +(w * 5).toFixed(1);
return {
dose: Math.min(d, 300) + ' mg (5 mg/kg)',
extra: 'No pulse: push undiluted. Pulse: over 20-60 min. Subsequent max 150 mg.',
max: 'Max first 300 mg, max total 15 mg/kg/24hr or 2200 mg'
};
}
},
{
name: 'Atropine', indication: 'Bradycardia', category: 'cardiac',
route: 'IV/IO/IM',
calc: function(w) {
var d = +(w * 0.02).toFixed(3);
var ett = (w * 0.04).toFixed(3) + '-' + (w * 0.06).toFixed(3);
return {
dose: Math.min(d, 0.5) + ' mg (0.02 mg/kg)',
extra: 'ETT dose: ' + ett + ' mg (0.04-0.06 mg/kg)',
max: 'Max single 0.5 mg, max total 1 mg'
};
}
},
{
name: 'Calcium Chloride 10%', indication: 'Hypocalcemia / Hyperkalemia', category: 'metabolic',
route: 'IV/IO',
calc: function(w) {
var d = +(w * 20).toFixed(0);
return {
dose: Math.min(d, 1000) + ' mg (20 mg/kg)',
extra: 'Give slowly. Central line preferred.',
max: 'Max 1 g (1000 mg)'
};
}
},
{
name: 'Calcium Gluconate 10%', indication: 'Hypocalcemia / Hyperkalemia', category: 'metabolic',
route: 'IV/IO',
calc: function(w) {
var d = +(w * 60).toFixed(0);
return {
dose: Math.min(d, 3000) + ' mg (60 mg/kg)',
extra: 'Give slowly over 10-20 min with cardiac monitoring.',
max: 'Max 3 g (3000 mg)'
};
}
},
{
name: 'Dextrose', indication: 'Hypoglycemia', category: 'metabolic',
route: 'IV',
calc: function(w) {
var grams = +(w * 0.5).toFixed(1) + '-' + +(w * 1).toFixed(1);
var detail = '';
if (w < 5) {
var ml = (w * 5).toFixed(1) + '-' + (w * 10).toFixed(1);
detail = 'D10W: ' + ml + ' mL (5-10 mL/kg)';
} else if (w < 45) {
var ml = (w * 2).toFixed(1) + '-' + (w * 4).toFixed(1);
detail = 'D25W: ' + ml + ' mL (2-4 mL/kg)';
} else {
var ml = (w * 1).toFixed(1) + '-' + (w * 2).toFixed(1);
detail = 'D50W: ' + ml + ' mL (1-2 mL/kg)';
}
return {
dose: grams + ' g (0.5-1 g/kg)',
extra: detail,
max: 'Max 25 g'
};
}
},
{
name: 'Epinephrine', indication: 'Pulseless arrest / Anaphylaxis', category: 'cardiac',
route: 'IV/IO/IM/ETT',
calc: function(w) {
var iv = +(w * 0.01).toFixed(3);
var ivVol = +(w * 0.1).toFixed(2);
var ett = +(w * 0.1).toFixed(2);
var im = +(w * 0.01).toFixed(3);
return {
dose: Math.min(iv, 1) + ' mg IV/IO (0.01 mg/kg of 0.1 mg/mL = ' + Math.min(ivVol, 10) + ' mL) q3-5 min',
extra: 'ETT: ' + Math.min(ett, 2.5) + ' mg (0.1 mg/kg of 1 mg/mL). Anaphylaxis IM: ' + Math.min(im, 0.5) + ' mg (0.01 mg/kg)',
max: 'Max IV 1 mg, max ETT 2.5 mg, max IM 0.5 mg'
};
}
},
{
name: 'Hydrocortisone', indication: 'Adrenal crisis', category: 'metabolic',
route: 'IV/IM/IO',
calc: function(w) {
var d = +(w * 2).toFixed(1);
return {
dose: Math.min(d, 100) + ' mg (2 mg/kg)',
extra: 'Stress dosing for adrenal insufficiency.',
max: 'Max 100 mg'
};
}
},
{
name: 'Insulin (Regular)', indication: 'Hyperkalemia', category: 'metabolic',
route: 'IV',
calc: function(w) {
var d = +(w * 0.1).toFixed(2);
var dex = +(w * 0.5).toFixed(1);
return {
dose: Math.min(d, 5) + ' units (0.1 units/kg)',
extra: 'Give with ' + dex + ' g/kg dextrose (0.5 g/kg). Monitor glucose closely.',
max: 'Max 5 units'
};
}
},
{
name: 'Lidocaine', indication: 'Antiarrhythmic', category: 'cardiac',
route: 'IV/IO',
calc: function(w) {
var d = +(w * 1).toFixed(1);
var ett = (w * 2).toFixed(1) + '-' + (w * 3).toFixed(1);
return {
dose: Math.min(d, 100) + ' mg (1 mg/kg)',
extra: 'ETT: ' + ett + ' mg (2-3 mg/kg). May repeat q5 min.',
max: 'Max 100 mg/dose, max total 3 mg/kg'
};
}
},
{
name: 'Magnesium Sulfate', indication: 'Torsades de Pointes', category: 'cardiac',
route: 'IV/IO',
calc: function(w) {
var d = +(w * 50).toFixed(0);
return {
dose: Math.min(d, 2000) + ' mg (50 mg/kg)',
extra: 'Give over 10-20 min (faster if pulseless).',
max: 'Max 2 g (2000 mg)'
};
}
},
{
name: 'Naloxone', indication: 'Opioid overdose', category: 'reversal',
route: 'IV/IO/IM/IN/ETT',
calc: function(w) {
var partial = +(w * 0.001).toFixed(4) + '-' + +(w * 0.005).toFixed(4);
var full = +(w * 0.1).toFixed(3);
return {
dose: 'Partial: ' + partial + ' mg (0.001-0.005 mg/kg)',
extra: 'Full reversal: ' + Math.min(full, 2) + ' mg (0.1 mg/kg)',
max: 'Max partial first dose 0.1 mg, max full 2 mg'
};
}
},
{
name: 'Sodium Bicarbonate', indication: 'Metabolic acidosis', category: 'metabolic',
route: 'IV/IO',
calc: function(w) {
var d = +(w * 1).toFixed(1);
return {
dose: Math.min(d, 50) + ' mEq (1 mEq/kg)',
extra: w < 10 ? 'Dilute to 0.5 mEq/mL (use 4.2% solution) for neonates/small infants.' : 'Use 8.4% solution (1 mEq/mL).',
max: 'Max 50 mEq'
};
}
}
];
var categoryColors = { cardiac: '#ef4444', metabolic: '#3b82f6', reversal: '#10b981' };
var categoryLabels = { cardiac: 'Cardiac', metabolic: 'Metabolic', reversal: 'Reversal' };
// Use event delegation for resus panel
var resusPanel = document.getElementById('calc-resus');
if (resusPanel) {
resusPanel.addEventListener('click', function(e) {
var btn = e.target.closest('#btn-calc-resus, #btn-clear-resus');
if (!btn) return;
if (btn.id === 'btn-clear-resus') {
var wi = document.getElementById('resus-weight'); if (wi) wi.value = '';
var rd = document.getElementById('resus-result'); if (rd) { rd.classList.add('hidden'); rd.innerHTML = ''; }
return;
}
// Calculate
var weightEl = document.getElementById('resus-weight');
var resultDiv = document.getElementById('resus-result');
var w = parseFloat(weightEl.value);
if (!w || w <= 0) { alert('Please enter a valid weight.'); return; }
var html = '<div style="margin-bottom:12px;font-size:14px;font-weight:700;color:var(--g800);">Doses for ' + w + ' kg patient</div>';
html += '<div style="display:flex;gap:6px;flex-wrap:wrap;margin-bottom:14px;font-size:11px;">';
Object.keys(categoryColors).forEach(function(cat) {
html += '<span style="display:inline-flex;align-items:center;gap:4px;"><span style="width:10px;height:10px;border-radius:50%;background:' + categoryColors[cat] + ';display:inline-block;"></span>' + categoryLabels[cat] + '</span>';
});
html += '</div>';
html += '<div style="display:grid;grid-template-columns:repeat(auto-fill,minmax(300px,1fr));gap:12px;">';
RESUS_MEDS.forEach(function(med) {
var r = med.calc(w);
var color = categoryColors[med.category] || '#6b7280';
html += '<div style="border:1.5px solid ' + color + '33;border-radius:10px;overflow:hidden;background:#fff;">' +
'<div style="padding:10px 14px;background:' + color + '0d;border-bottom:1px solid ' + color + '22;">' +
'<div style="font-size:14px;font-weight:700;color:' + color + ';">' + med.name + '</div>' +
'<div style="font-size:11px;color:var(--g500);margin-top:2px;">' + med.indication + '</div>' +
'</div>' +
'<div style="padding:12px 14px;font-size:13px;">' +
'<div style="margin-bottom:6px;"><strong>Dose:</strong> ' + r.dose + '</div>' +
'<div style="margin-bottom:6px;font-size:12px;color:var(--g600);">' + r.extra + '</div>' +
'<div style="font-size:11px;color:var(--g500);"><strong>Max:</strong> ' + r.max + '</div>' +
'<div style="font-size:11px;color:var(--g400);margin-top:4px;"><strong>Route:</strong> ' + med.route + '</div>' +
'</div>' +
'</div>';
});
html += '</div>';
html += '<div style="margin-top:14px;padding:10px;background:#fef3c7;border-radius:8px;font-size:11px;color:#92400e;">' +
'<strong>Disclaimer:</strong> Always verify doses against institutional protocols and current guidelines. This tool is for educational reference only.' +
'</div>';
resultDiv.innerHTML = html;
resultDiv.classList.remove('hidden');
});
}
// ═══════════════════════════════════════════════════════════
// GLASGOW COMA SCALE
// ═══════════════════════════════════════════════════════════
// GCS sub-pill navigation
var gcsPanel = document.getElementById('calc-gcs');
if (gcsPanel) {
gcsPanel.addEventListener('click', function(e) {
var pill = e.target.closest('[data-gcs]');
if (!pill) return;
gcsPanel.querySelectorAll('[data-gcs]').forEach(function(p) { p.classList.remove('active'); });
pill.classList.add('active');
var isInfant = pill.dataset.gcs === 'infant';
var childP = document.getElementById('gcs-child-panel');
var infantP = document.getElementById('gcs-infant-panel');
if (childP) childP.style.display = isInfant ? 'none' : '';
if (infantP) infantP.style.display = isInfant ? '' : 'none';
updateGCS();
});
gcsPanel.addEventListener('change', function(e) {
if (e.target.tagName === 'SELECT') updateGCS();
});
}
function updateGCS() {
var isInfant = document.querySelector('[data-gcs="infant"].active') !== null;
var prefix = isInfant ? 'gcs-infant' : 'gcs-child';
var eye = parseInt(document.getElementById(prefix + '-eye').value) || 0;
var verbal = parseInt(document.getElementById(prefix + '-verbal').value) || 0;
var motor = parseInt(document.getElementById(prefix + '-motor').value) || 0;
var total = eye + verbal + motor;
var severity, color, bg;
if (total <= 8) { severity = 'Severe (Coma)'; color = '#ef4444'; bg = '#fee2e2'; }
else if (total <= 12) { severity = 'Moderate'; color = '#f59e0b'; bg = '#fef3c7'; }
else { severity = 'Mild'; color = '#10b981'; bg = '#d1fae5'; }
var resultDiv = document.getElementById('gcs-result');
if (resultDiv) {
resultDiv.innerHTML =
'<div class="calc-result-header" style="background:' + bg + ';border-color:' + color + ';">' +
'<div style="font-size:24px;font-weight:700;color:' + color + ';">GCS: ' + total + '/15</div>' +
'<div style="font-size:14px;color:var(--g600);margin-top:4px;">' + severity + '</div>' +
'</div>' +
'<div class="calc-result-grid" style="margin-top:12px;">' +
'<div class="calc-result-item"><div class="calc-result-label">Eye (E)</div><div class="calc-result-value">' + eye + '</div></div>' +
'<div class="calc-result-item"><div class="calc-result-label">Verbal (V)</div><div class="calc-result-value">' + verbal + '</div></div>' +
'<div class="calc-result-item"><div class="calc-result-label">Motor (M)</div><div class="calc-result-value">' + motor + '</div></div>' +
'</div>' +
'<div style="margin-top:12px;font-size:12px;color:var(--g500);">' +
'<strong>Interpretation:</strong> 13-15 Mild, 9-12 Moderate, 3-8 Severe/Coma. ' +
'Intubation typically considered at GCS &le; 8. ' +
(isInfant ? 'Using infant-modified verbal and motor scales.' : '') +
'</div>';
}
}
// Initial GCS render
setTimeout(updateGCS, 200);
// ═══════════════════════════════════════════════════════════
// EQUIPMENT SIZING — Harriet Lane Handbook
// ═══════════════════════════════════════════════════════════
var EQUIP_DATA = {
premie: {
label: 'Premie (1-3 kg)',
bvm: 'Infant', nasal: '12 Fr', oral: 'Infant', blade: 'Miller 0',
ett: '2.5-3.0', lma: '1', glidescope: '1',
iv: '22-24 ga', cvl: '3 Fr', ngt: '5 Fr', chest: '10-12 Fr', foley: '6 Fr'
},
newborn: {
label: 'Newborn (2-4 kg)',
bvm: 'Infant', nasal: '14-16 Fr', oral: 'Small 50 mm', blade: 'Miller 0',
ett: '3.0-3.5', lma: '1', glidescope: '1',
iv: '22-24 ga', cvl: '3-4 Fr', ngt: '5-8 Fr', chest: '10-12 Fr', foley: '6 Fr'
},
'6mo': {
label: '6 months (6-8 kg)',
bvm: 'Infant', nasal: '14-16 Fr', oral: 'Small 60 mm', blade: 'Miller 1',
ett: '3.5', lma: '1.5', glidescope: '2',
iv: '20-24 ga', cvl: '4 Fr', ngt: '8 Fr', chest: '12-18 Fr', foley: '8 Fr'
},
'1yr': {
label: '1 year (10 kg)',
bvm: 'Small child', nasal: '14-18 Fr', oral: 'Small 60 mm', blade: 'Miller 1 / MAC 2',
ett: '4.0', lma: '2', glidescope: '2',
iv: '20-24 ga', cvl: '4-5 Fr', ngt: '10 Fr', chest: '16-20 Fr', foley: '8 Fr'
},
'2-3yr': {
label: '2-3 years (12-16 kg)',
bvm: 'Small child', nasal: '14-18 Fr', oral: 'Small 70 mm', blade: 'Miller 1 / MAC 2',
ett: '4.0-4.5', lma: '2', glidescope: '2',
iv: '18-22 ga', cvl: '4-5 Fr', ngt: '10-12 Fr', chest: '16-24 Fr', foley: '8 Fr'
},
'4-6yr': {
label: '4-6 years (20-25 kg)',
bvm: 'Child', nasal: '16-20 Fr', oral: 'Small 70-80 mm', blade: 'Miller 2 / MAC 2',
ett: '4.5-5.0', lma: '2.5', glidescope: '3',
iv: '18-22 ga', cvl: '5 Fr', ngt: '12-14 Fr', chest: '20-28 Fr', foley: '8 Fr'
},
'7-10yr': {
label: '7-10 years (25-35 kg)',
bvm: 'Child / Small adult', nasal: '18-22 Fr', oral: 'Medium 80-90 mm', blade: 'Miller 2 / MAC 2',
ett: '5.5-6.0', lma: '2.5-3', glidescope: '3',
iv: '18-22 ga', cvl: '5 Fr', ngt: '12-14 Fr', chest: '20-32 Fr', foley: '8 Fr'
},
'11-15yr': {
label: '11-15 years (40-50 kg)',
bvm: 'Adult', nasal: '22-36 Fr', oral: 'Medium 90 mm', blade: 'Miller 2 / MAC 3',
ett: '6.0-6.5', lma: '3', glidescope: '3 or 4',
iv: '18-20 ga', cvl: '7 Fr', ngt: '14-18 Fr', chest: '28-38 Fr', foley: '10 Fr'
},
'16yr': {
label: '16+ years (>50 kg)',
bvm: 'Adult', nasal: '22-36 Fr', oral: 'Medium 90 mm', blade: 'Miller 2 / MAC 3',
ett: '7.0-8.0', lma: '4', glidescope: '3 or 4',
iv: '18-20 ga', cvl: '7 Fr', ngt: '14-18 Fr', chest: '28-42 Fr', foley: '12 Fr'
}
};
var equipPanel = document.getElementById('calc-equipment');
if (equipPanel) {
equipPanel.addEventListener('change', function(e) {
if (e.target.id !== 'equip-age-select') return;
var key = e.target.value;
var resultDiv = document.getElementById('equip-result');
if (!key || !EQUIP_DATA[key]) { resultDiv.classList.add('hidden'); return; }
var eq = EQUIP_DATA[key];
resultDiv.classList.remove('hidden');
resultDiv.innerHTML =
'<div class="calc-result-header" style="background:#eff6ff;border-color:#2563eb;">' +
'<div style="font-size:18px;font-weight:700;color:#1d4ed8;">' + eq.label + '</div>' +
'</div>' +
'<div style="margin-top:12px;overflow-x:auto;">' +
'<table class="admin-table" style="font-size:13px;width:100%;">' +
'<tbody>' +
'<tr><td style="font-weight:600;width:40%;">Bag-Valve Mask</td><td>' + eq.bvm + '</td></tr>' +
'<tr><td style="font-weight:600;">Oral Airway</td><td>' + eq.oral + '</td></tr>' +
'<tr><td style="font-weight:600;">Nasal Airway</td><td>' + eq.nasal + '</td></tr>' +
'<tr><td style="font-weight:600;">Laryngoscope Blade</td><td>' + eq.blade + '</td></tr>' +
'<tr><td style="font-weight:600;">ETT Size</td><td>' + eq.ett + '</td></tr>' +
'<tr><td style="font-weight:600;">LMA Size</td><td>' + eq.lma + '</td></tr>' +
'<tr><td style="font-weight:600;">Glidescope</td><td>' + eq.glidescope + '</td></tr>' +
'<tr><td style="font-weight:600;">IV Catheter</td><td>' + eq.iv + '</td></tr>' +
'<tr><td style="font-weight:600;">Central Line</td><td>' + eq.cvl + '</td></tr>' +
'<tr><td style="font-weight:600;">NGT / OGT</td><td>' + eq.ngt + '</td></tr>' +
'<tr><td style="font-weight:600;">Chest Tube</td><td>' + eq.chest + '</td></tr>' +
'<tr><td style="font-weight:600;">Foley Catheter</td><td>' + eq.foley + '</td></tr>' +
'</tbody>' +
'</table>' +
'</div>' +
'<div style="margin-top:10px;font-size:11px;color:var(--g400);">' +
'<strong>ETT Formulas:</strong> Uncuffed = (age/4)+4, Cuffed = (age/4)+3, Depth = ETT size x 3. ' +
'Source: Harriet Lane Handbook.' +
'</div>';
});
}
}
})();
// ============================================================
// NEONATAL ASSESSMENT
// ============================================================
(function() {
document.addEventListener('click', function(e) {
if (e.target.id === 'btn-neo-assess' || e.target.closest('#btn-neo-assess')) neoAssess();
});
// Fenton 2013 LMS data (weight in grams, GA in weeks)
var fentonLMS = {
male: {
22:{L:0.21,M:496,S:0.17},23:{L:0.21,M:575,S:0.17},24:{L:0.21,M:660,S:0.17},25:{L:0.21,M:762,S:0.16},
26:{L:0.21,M:870,S:0.16},27:{L:0.20,M:993,S:0.15},28:{L:0.20,M:1124,S:0.15},29:{L:0.19,M:1272,S:0.14},
30:{L:0.18,M:1430,S:0.14},31:{L:0.17,M:1607,S:0.14},32:{L:0.15,M:1795,S:0.14},33:{L:0.13,M:2008,S:0.13},
34:{L:0.12,M:2230,S:0.13},35:{L:0.10,M:2467,S:0.13},36:{L:0.08,M:2710,S:0.13},37:{L:0.06,M:2948,S:0.12},
38:{L:0.04,M:3195,S:0.12},39:{L:0.02,M:3380,S:0.12},40:{L:0.01,M:3530,S:0.12},41:{L:0.00,M:3660,S:0.12},
42:{L:-0.02,M:3820,S:0.12}
},
female: {
22:{L:0.23,M:474,S:0.17},23:{L:0.22,M:538,S:0.17},24:{L:0.22,M:610,S:0.17},25:{L:0.22,M:705,S:0.16},
26:{L:0.22,M:810,S:0.16},27:{L:0.21,M:920,S:0.15},28:{L:0.21,M:1040,S:0.15},29:{L:0.20,M:1178,S:0.14},
30:{L:0.19,M:1330,S:0.14},31:{L:0.18,M:1500,S:0.14},32:{L:0.16,M:1680,S:0.14},33:{L:0.14,M:1880,S:0.13},
34:{L:0.12,M:2090,S:0.13},35:{L:0.10,M:2310,S:0.13},36:{L:0.08,M:2540,S:0.13},37:{L:0.06,M:2766,S:0.12},
38:{L:0.04,M:3000,S:0.12},39:{L:0.02,M:3180,S:0.12},40:{L:0.01,M:3340,S:0.12},41:{L:0.00,M:3480,S:0.12},
42:{L:-0.02,M:3630,S:0.12}
}
};
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 = '<p style="color:var(--red);font-size:13px;">Enter GA and birth weight.</p>';
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 += '<div style="display:flex;gap:12px;flex-wrap:wrap;margin-bottom:12px;">';
html += '<div style="flex:1;min-width:200px;padding:14px;border-radius:10px;background:' + gaClass.color + '10;border:1.5px solid ' + gaClass.color + '30;">';
html += '<div style="font-size:12px;color:var(--g500);margin-bottom:4px;">Gestational Age Classification</div>';
html += '<div style="font-size:18px;font-weight:700;color:' + gaClass.color + ';"><i class="fas ' + gaClass.icon + '"></i> ' + gaClass.label + '</div>';
html += '<div style="font-size:13px;color:var(--g600);margin-top:4px;">' + weeks + ' weeks ' + days + ' days (' + gaDecimal.toFixed(1) + ' weeks)</div>';
html += '</div>';
// Weight Classification (AGA/SGA/LGA)
html += '<div style="flex:1;min-width:200px;padding:14px;border-radius:10px;background:' + wtClass.color + '10;border:1.5px solid ' + wtClass.color + '30;">';
html += '<div style="font-size:12px;color:var(--g500);margin-bottom:4px;">Weight for Gestational Age</div>';
html += '<div style="font-size:18px;font-weight:700;color:' + wtClass.color + ';">' + wtClass.label + '</div>';
html += '<div style="font-size:13px;color:var(--g600);margin-top:4px;">' + percentile.toFixed(1) + 'th percentile (' + wtClass.detail + ')</div>';
html += '</div>';
html += '</div>';
// Birth Weight Category
html += '<div style="display:flex;gap:12px;flex-wrap:wrap;margin-bottom:12px;">';
html += '<div style="flex:1;min-width:200px;padding:14px;border-radius:10px;background:' + bwClass.color + '10;border:1.5px solid ' + bwClass.color + '30;">';
html += '<div style="font-size:12px;color:var(--g500);margin-bottom:4px;">Birth Weight Category</div>';
html += '<div style="font-size:18px;font-weight:700;color:' + bwClass.color + ';">' + bwClass.label + '</div>';
html += '<div style="font-size:13px;color:var(--g600);margin-top:4px;">' + weight + 'g (' + (weight/1000).toFixed(2) + ' kg)</div>';
html += '</div>';
// Stats
html += '<div style="flex:1;min-width:200px;padding:14px;border-radius:10px;background:var(--g50);border:1.5px solid var(--g200);">';
html += '<div style="font-size:12px;color:var(--g500);margin-bottom:4px;">Fenton Growth Data (' + (sex === 'male' ? 'Male' : 'Female') + ')</div>';
html += '<div style="font-size:13px;color:var(--g700);line-height:1.8;">';
html += '<strong>Expected weight (50th %ile):</strong> ' + expectedWeight + 'g<br>';
html += '<strong>Z-score:</strong> ' + z.toFixed(2) + '<br>';
html += '<strong>Percentile:</strong> ' + percentile.toFixed(1) + '%';
html += '</div></div>';
html += '</div>';
// Reference
html += '<p style="font-size:11px;color:var(--g400);margin:8px 0 0;">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.</p>';
resultDiv.innerHTML = html;
}
})();
// ============================================================
// RESPIRATORY MANAGEMENT (Asthma, Croup, Bronchiolitis)
// ============================================================
(function() {
// Sub-pill navigation
document.addEventListener('click', function(e) {
var pill = e.target.closest('[data-resp]');
if (pill) {
document.querySelectorAll('[data-resp]').forEach(function(p) { p.classList.remove('active'); });
pill.classList.add('active');
['asthma','croup','bronchiolitis'].forEach(function(s) {
var el = document.getElementById('resp-' + s);
if (el) el.style.display = pill.dataset.resp === s ? '' : 'none';
});
}
if (e.target.closest('[data-asthma-severity]')) asthmaManagement(e.target.closest('[data-asthma-severity]').dataset.asthmaSeverity);
if (e.target.id === 'btn-pram-calc' || e.target.closest('#btn-pram-calc')) calcPRAM();
if (e.target.id === 'btn-croup-calc' || e.target.closest('#btn-croup-calc')) calcCroup();
if (e.target.id === 'btn-bronch-calc' || e.target.closest('#btn-bronch-calc')) calcBronchiolitis();
});
function dose(wt, mgPerKg, maxMg) { var d = Math.round(wt * mgPerKg * 10) / 10; return maxMg ? Math.min(d, maxMg) : d; }
// Delegates to the shared _EM.dStr so the per-kg math is visible to the prescriber.
function doseStr(wt, mgPerKg, maxMg, unit) {
return window._EM.dStr(wt, mgPerKg, maxMg, unit);
}
function drugRow(name, doseText, route, notes) {
return '<tr><td style="font-weight:600;">' + name + '</td><td>' + doseText + '</td><td>' + route + '</td><td style="font-size:12px;color:var(--g500);">' + (notes || '') + '</td></tr>';
}
function drugTable(rows) {
return '<div style="overflow-x:auto;-webkit-overflow-scrolling:touch;margin:8px 0;"><table style="width:100%;min-width:500px;border-collapse:collapse;font-size:13px;"><thead><tr style="background:var(--g100);"><th style="text-align:left;padding:6px 8px;">Drug</th><th style="padding:6px 8px;">Dose</th><th style="padding:6px 8px;">Route</th><th style="padding:6px 8px;">Notes</th></tr></thead><tbody>' + rows + '</tbody></table></div>';
}
function severityBadge(label, color) { return '<span style="display:inline-block;padding:4px 12px;border-radius:6px;background:' + color + '20;color:' + color + ';font-weight:700;font-size:14px;">' + label + '</span>'; }
function asthmaManagement(severity) {
var wt = parseFloat(document.getElementById('resp-weight').value);
var resultDiv = document.getElementById('asthma-result');
if (!wt) { resultDiv.innerHTML = '<p style="color:var(--red);font-size:13px;">Enter weight (kg).</p>'; return; }
var html = '';
if (severity === 'mild') {
html += severityBadge('Mild Exacerbation', '#10b981');
html += '<p style="font-size:13px;margin:8px 0;">Speaks in sentences, no accessory muscle use, SpO2 ≥94%</p>';
html += drugTable(
drugRow('Albuterol (MDI)', '4-8 puffs via spacer', 'Inhaled', 'q20min x 3 doses, then q1-4h') +
drugRow('Albuterol (neb)', doseStr(wt, 0.15, 5, ' mg') + ' (min 2.5 mg)', 'Nebulized', 'q20min x 3 doses') +
drugRow('Dexamethasone', doseStr(wt, 0.6, 16), 'PO/IV', 'Single dose, or 2 days') +
drugRow('Prednisolone', doseStr(wt, 1, 60) + '/day', 'PO', 'Alternative: 3-5 day course')
);
html += '<div style="margin-top:8px;padding:8px 12px;background:#d1fae5;border-radius:6px;font-size:12px;color:#065f46;"><strong>Reassess after 1 hour.</strong> If improving → discharge with albuterol MDI + spacer + oral steroid course. If not improving → escalate to moderate.</div>';
} else if (severity === 'moderate') {
html += severityBadge('Moderate Exacerbation', '#f59e0b');
html += '<p style="font-size:13px;margin:8px 0;">Speaks in phrases, some accessory muscle use, SpO2 90-93%</p>';
html += drugTable(
drugRow('Albuterol (neb)', doseStr(wt, 0.15, 5, ' mg') + ' (min 2.5 mg)', 'Nebulized', 'q20min x 3 doses, then continuous if needed') +
drugRow('Ipratropium', wt < 20 ? '250 mcg' : '500 mcg', 'Nebulized', 'q20min x 3 doses with albuterol') +
drugRow('Dexamethasone', doseStr(wt, 0.6, 16), 'PO/IV/IM', 'Single dose') +
drugRow('O2 supplemental', 'Target SpO2 ≥94%', 'Nasal cannula/mask', 'Titrate to effect')
);
html += '<div style="margin-top:8px;padding:8px 12px;background:#fef3c7;border-radius:6px;font-size:12px;color:#92400e;"><strong>Reassess after 1-2 hours.</strong> If improving → step down to mild protocol. If worsening or no improvement → escalate to severe.</div>';
} else {
html += severityBadge('Severe / Life-Threatening', '#ef4444');
html += '<p style="font-size:13px;margin:8px 0;">Speaks in words only, significant accessory muscle use, SpO2 &lt;90%. Consider ICU.</p>';
html += drugTable(
drugRow('Albuterol continuous', doseStr(wt, 0.5, 20, ' mg') + '/hr', 'Continuous neb', 'Or 0.15-0.3 mg/kg q20min') +
drugRow('Ipratropium', wt < 20 ? '250 mcg' : '500 mcg', 'Nebulized', 'q20min x 3 doses with albuterol') +
drugRow('Dexamethasone', doseStr(wt, 0.6, 16), 'IV', 'Or methylprednisolone 2 mg/kg IV (max 60 mg)') +
drugRow('Magnesium sulfate', doseStr(wt, 50, 2000) + ' IV over 20 min', 'IV', 'Single dose, monitor BP') +
drugRow('Epinephrine (IM)', doseStr(wt, 0.01, 0.5) + ' (1:1000)', 'IM', 'If impending arrest / no IV access') +
drugRow('Terbutaline', doseStr(wt, 0.01, 0.4) + ' SC/IV', 'SC or IV bolus', 'Then 0.1-10 mcg/kg/min infusion') +
drugRow('O2 supplemental', 'Target SpO2 ≥94%', 'High flow / NIPPV', 'Consider BiPAP/CPAP')
);
html += '<div style="margin-top:8px;padding:8px 12px;background:#fee2e2;border-radius:6px;font-size:12px;color:#991b1b;"><strong>Continuous monitoring.</strong> Consider ICU admission. If no response to magnesium → terbutaline infusion. If impending respiratory failure → intubation (ketamine preferred induction agent).</div>';
// Clinical decision points specific to severe asthma
html += '<div style="margin-top:10px;display:grid;grid-template-columns:repeat(auto-fit,minmax(260px,1fr));gap:8px;">';
// ABG
html += '<div style="padding:10px 12px;background:white;border:1px solid var(--g200);border-radius:8px;font-size:12px;line-height:1.5;">' +
'<div style="font-weight:700;color:var(--blue-dark);margin-bottom:4px;"><i class="fas fa-flask"></i> When to obtain a blood gas</div>' +
'&bull; Severe exacerbation <strong>not responding</strong> after 1-2 h aggressive therapy<br>' +
'&bull; Impending respiratory failure — altered mentation, fatigue, silent chest<br>' +
'&bull; SpO2 &lt;92% despite supplemental O2<br>' +
'&bull; Suspected CO2 retention (rising PCO2 in a previously tachypneic patient)<br>' +
'<strong style="color:#991b1b;">Interpretation:</strong> asthmatics hyperventilate → expect <em>low</em> PCO2. A <strong>"normal" or rising PCO2 = impending failure</strong>. Don\'t delay treatment for the gas.' +
'</div>';
// Intubation
html += '<div style="padding:10px 12px;background:white;border:1px solid var(--g200);border-radius:8px;font-size:12px;line-height:1.5;">' +
'<div style="font-weight:700;color:#dc2626;margin-bottom:4px;"><i class="fas fa-stethoscope"></i> When to intubate (mostly clinical)</div>' +
'&bull; <strong>Absolute:</strong> apnea, cardiac arrest, coma, inability to protect airway<br>' +
'&bull; Progressive fatigue despite maximal therapy (NIV, mag, terbutaline, heliox)<br>' +
'&bull; Refractory hypoxemia / hypercapnia with acidosis<br>' +
'&bull; Silent chest + deteriorating consciousness<br>' +
'<strong>RSI choice:</strong> <span style="color:#065f46;font-weight:600;">ketamine 1-2 mg/kg</span> (bronchodilator, preserves BP) + <span style="color:#065f46;font-weight:600;">rocuronium</span>. Avoid succs if hyperkalemic. Permissive hypercapnia after tube; allow expiration (low rate, I:E 1:3-4).' +
'</div>';
// Heliox
html += '<div style="padding:10px 12px;background:white;border:1px solid var(--g200);border-radius:8px;font-size:12px;line-height:1.5;">' +
'<div style="font-weight:700;color:#7c3aed;margin-bottom:4px;"><i class="fas fa-wind"></i> Heliox (He/O2)</div>' +
'&bull; Lower gas density → less turbulence → reduced work of breathing through narrowed airways.<br>' +
'&bull; <strong>Consider in:</strong> severe asthma not responding to max therapy (bridge), upper airway obstruction (croup, post-extubation stridor, FB partial).<br>' +
'&bull; Typical mix: <strong>70:30 He:O2</strong> (or 80:20). Delivered via tight non-rebreather or in-line with neb.<br>' +
'&bull; <strong>Limitation:</strong> requires FiO2 ≤ 30-40%. If patient needs higher FiO2, heliox can\'t help.<br>' +
'&bull; Evidence in asthma is mixed — use as adjunct, not substitute.' +
'</div>';
html += '</div>';
}
html += '<p style="font-size:11px;color:var(--g400);margin:12px 0 0;">NAEPP/GINA guidelines. Always use clinical judgment. Verify doses against institutional protocols.</p>';
resultDiv.innerHTML = html;
}
function calcPRAM() {
var total = ['pram-spo2','pram-retractions','pram-scalene','pram-air','pram-wheeze'].reduce(function(s, id) {
return s + parseInt(document.getElementById(id).value);
}, 0);
var severity = total <= 3 ? 'Mild' : total <= 7 ? 'Moderate' : 'Severe';
var color = total <= 3 ? '#10b981' : total <= 7 ? '#f59e0b' : '#ef4444';
document.getElementById('pram-result').innerHTML = '<div style="padding:10px 14px;border-radius:8px;background:' + color + '10;border:1.5px solid ' + color + '30;"><span style="font-size:18px;font-weight:700;color:' + color + ';">PRAM Score: ' + total + '/12 — ' + severity + '</span><p style="font-size:12px;color:var(--g600);margin:4px 0 0;">Mild (0-3): outpatient management. Moderate (4-7): consider oral steroids + frequent bronchodilators. Severe (8-12): aggressive treatment, consider ICU.</p></div>';
}
function calcCroup() {
var wt = parseFloat(document.getElementById('resp-weight').value) || 10;
var total = ['croup-conscious','croup-cyanosis','croup-stridor','croup-air','croup-retractions'].reduce(function(s, id) {
return s + parseInt(document.getElementById(id).value);
}, 0);
var severity, color, treatment;
if (total <= 2) { severity = 'Mild'; color = '#10b981'; treatment = drugTable(drugRow('Dexamethasone', doseStr(wt, 0.6, 16), 'PO (single dose)', 'Preferred corticosteroid') + drugRow('Supportive care', 'Cool mist, comfort measures', '', 'Discharge if tolerating PO')); }
else if (total <= 5) { severity = 'Moderate'; color = '#f59e0b'; treatment = drugTable(drugRow('Dexamethasone', doseStr(wt, 0.6, 16), 'PO/IM', 'Single dose') + drugRow('Racemic epinephrine', '0.5 mL of 2.25% solution', 'Nebulized', 'Observe 2-4 hrs after for rebound') + drugRow('Nebulized epinephrine', '0.5 mL/kg of 1:1000 (max 5 mL)', 'Nebulized', 'Alternative to racemic')); }
else if (total <= 11) { severity = 'Severe'; color = '#ef4444'; treatment = drugTable(drugRow('Dexamethasone', doseStr(wt, 0.6, 16), 'IV/IM', 'Immediate') + drugRow('Racemic epinephrine', '0.5 mL of 2.25% solution', 'Nebulized', 'May repeat q15-20min, observe 2-4 hrs') + drugRow('Nebulized epinephrine', '0.5 mL/kg of 1:1000 (max 5 mL)', 'Nebulized', 'Alternative') + drugRow('Heliox', '70:30 or 80:20', 'Face mask', 'Consider if not responding') + drugRow('O2 supplemental', 'Target SpO2 ≥94%', 'Blow-by preferred', 'Minimize agitation')); }
else { severity = 'Impending Respiratory Failure'; color = '#dc2626'; treatment = '<div style="padding:10px;background:#fee2e2;border-radius:6px;font-size:13px;color:#991b1b;font-weight:600;">Immediate airway management. Prepare for intubation (use ETT 0.5-1 size smaller than predicted). Call anesthesia/ENT. Continue nebulized epinephrine and dexamethasone IV.</div>'; }
document.getElementById('croup-result').innerHTML = '<div style="padding:10px 14px;border-radius:8px;background:' + color + '10;border:1.5px solid ' + color + '30;margin-bottom:12px;"><span style="font-size:18px;font-weight:700;color:' + color + ';">Westley Score: ' + total + '/17 — ' + severity + '</span></div>' + treatment + '<p style="font-size:11px;color:var(--g400);margin:8px 0 0;">Westley WJ et al. Nebulized racemic epinephrine by IPPB for the treatment of croup. Am J Dis Child 1978. Mild ≤2, Moderate 3-5, Severe 6-11, Impending failure ≥12.</p>';
}
function calcBronchiolitis() {
var wt = parseFloat(document.getElementById('resp-weight').value) || 5;
var age = document.getElementById('bronch-age').value;
var spo2 = document.getElementById('bronch-spo2').value;
var hydration = document.getElementById('bronch-hydration').value;
var distress = document.getElementById('bronch-distress').value;
var html = '<h4 style="font-size:15px;font-weight:700;color:var(--g800);margin:0 0 8px;">Bronchiolitis Management</h4>';
var admit = distress === 'severe' || spo2 === 'low' || hydration === 'poor' || age === '<12w';
if (admit) {
html += severityBadge('Admit / Observe', '#ef4444');
html += '<div style="margin:10px 0;">';
if (age === '<12w') html += '<p style="font-size:13px;color:var(--red);font-weight:600;">⚠ Age &lt;12 weeks — high risk for apnea. Monitor closely.</p>';
html += '</div>';
} else {
html += severityBadge('Likely Safe for Discharge', '#10b981');
}
html += '<div style="margin:12px 0;"><strong style="font-size:13px;">Supportive Care (evidence-based):</strong></div>';
html += drugTable(
drugRow('Nasal suctioning', 'Bulb suction or NasalClear', 'Nasal', 'Before feeds and as needed') +
drugRow('O2 supplemental', 'Target SpO2 ≥90%', 'NC / high flow', spo2 === 'low' ? 'Required' : 'If needed') +
drugRow('Hypertonic saline 3%', '4 mL nebulized', 'Nebulized', 'Consider in inpatients (AAP weak recommendation)') +
(hydration === 'poor' ? drugRow('IV fluids', 'NS/LR bolus ' + doseStr(wt, 20, null, ' mL'), 'IV', 'Then maintenance D5 0.45NS') + drugRow('NG feeds', 'If unable to feed orally', 'NG tube', 'Preferred over IV if gut functional') : '')
);
html += '<div style="margin:12px 0;padding:10px 12px;background:var(--amber-light);border-radius:6px;font-size:12px;color:#92400e;"><strong>NOT recommended (AAP 2014/2023):</strong> Albuterol/salbutamol (no benefit in bronchiolitis), epinephrine (no evidence of benefit), systemic corticosteroids (no benefit), antibiotics (unless secondary bacterial infection), chest physiotherapy.</div>';
html += '<p style="font-size:11px;color:var(--g400);margin:8px 0 0;">AAP Clinical Practice Guideline: Management of Bronchiolitis in Infants and Children (2014, reaffirmed 2023). RSV is the most common cause (50-80%).</p>';
document.getElementById('bronch-result').innerHTML = html;
}
})();
// ============================================================
// SEIZURE MANAGEMENT
// ============================================================
(function() {
document.addEventListener('click', function(e) {
if (e.target.id === 'btn-seizure-calc' || e.target.closest('#btn-seizure-calc')) calcSeizure();
});
function d(wt, mgPerKg, max) { var v = Math.round(wt * mgPerKg * 100) / 100; return max ? Math.min(v, max) : v; }
function row(phase, drug, dose, route, notes) {
return '<tr><td style="font-weight:600;color:var(--blue);">' + phase + '</td><td style="font-weight:600;">' + drug + '</td><td>' + dose + '</td><td>' + route + '</td><td style="font-size:12px;color:var(--g500);">' + notes + '</td></tr>';
}
// Visual pathway row — time badge + step card linked by vertical line
function stepRow(time, color, title, bodyHtml, isLast) {
return '<div style="display:flex;gap:12px;align-items:stretch;">' +
'<div style="flex:0 0 auto;width:70px;display:flex;flex-direction:column;align-items:center;">' +
'<div style="background:' + color + ';color:white;padding:6px 0;border-radius:20px;font-size:12px;font-weight:700;width:60px;text-align:center;box-shadow:0 1px 3px rgba(0,0,0,0.15);">' + time + '</div>' +
(isLast ? '' : '<div style="flex:1;width:3px;background:' + color + '40;margin:2px 0;"></div>') +
'</div>' +
'<div style="flex:1;padding:10px 14px;border-left:4px solid ' + color + ';background:' + color + '10;border-radius:0 8px 8px 0;margin-bottom:' + (isLast ? '4px' : '12px') + ';">' +
'<div style="font-weight:700;color:' + color + ';font-size:13px;margin-bottom:6px;text-transform:uppercase;letter-spacing:0.3px;">' + title + '</div>' +
'<div style="font-size:13px;color:var(--g700);line-height:1.55;">' + bodyHtml + '</div>' +
'</div>' +
'</div>';
}
function calcSeizure() {
var wt = parseFloat(document.getElementById('seizure-weight').value);
var resultDiv = document.getElementById('seizure-result');
if (!wt) { resultDiv.innerHTML = '<p style="color:var(--red);font-size:13px;">Enter weight (kg).</p>'; return; }
var S = window._EM;
var d10Low = Math.round(wt * 2 * 10) / 10;
var d10High = Math.round(wt * 5 * 10) / 10;
var html = '<div style="padding:10px 14px;border-radius:8px;background:#fee2e2;border:1.5px solid #ef4444;margin-bottom:14px;"><strong style="color:#dc2626;font-size:14px;"><i class="fas fa-bolt"></i> Status Epilepticus Pathway — ' + wt + ' kg</strong><div style="font-size:12px;color:var(--g600);margin-top:3px;">Time = 0 at seizure onset. Do not pause between steps for benzo to take effect — act on the clock.</div></div>';
// 0 min — STABILIZE
html += stepRow('0 min', '#3b82f6', 'Stabilize',
'<strong>ABCs</strong> — position, 100% O2 via NC / NRB, suction. <strong>IV or IO</strong> × 2. Continuous SpO2, ECG, BP. ' +
'<strong>POC glucose</strong> — if &lt;60 mg/dL: <strong>D10W ' + d10Low + '-' + d10High + ' mL IV</strong> (2-5 mL/kg). ' +
'<strong>Labs</strong>: CBC, CMP, Mg, Ca, Phos, VBG, lactate, AED levels, toxicology if unclear etiology. ' +
'<strong>Consider pyridoxine</strong> 100 mg IV in infants &lt;18 mo or INH ingestion. Temperature: treat hyperthermia aggressively.'
);
// 5 min — 1ST BENZO
html += stepRow('5 min', '#8b5cf6', '1st benzodiazepine (give once, pick by access)',
S.drugTable(
S.drugRow('Lorazepam <span style="color:#065f46;font-weight:600;">(IV preferred)</span>', S.dStr(wt, 0.1, 4), 'IV / IO', 'Slow push over 1-2 min.') +
S.drugRow('Midazolam', S.dStr(wt, 0.2, 10), 'IM / IN / buccal', 'Use 5 mg/mL concentrate for IN; split between nares.') +
S.drugRow('Diazepam', S.dStr(wt, 0.5, 20), 'PR', 'Only if no IV/IM/IN access.')
)
);
// 10 min — 2ND BENZO
html += stepRow('10 min', '#a855f7', '2nd benzodiazepine — if still seizing',
'Repeat same agent + dose <strong>once</strong>. Prepare 2nd-line now (don\'t wait to see if benzo works). If apnea/airway compromise: BVM, consider advanced airway.'
);
// 20 min — 2ND-LINE
html += stepRow('20 min', '#f59e0b', '2nd-line anti-epileptic — pick one (ESETT: equivalent efficacy)',
S.drugTable(
S.drugRow('Levetiracetam <span style="color:#065f46;font-weight:600;">(preferred)</span>', S.dStr(wt, 60, 4500), 'IV over 5-15 min', 'Best tolerability. No ECG monitoring needed.') +
S.drugRow('Fosphenytoin', S.dStr(wt, 20, 1500, ' mg PE'), 'IV over 10 min', 'Max rate 3 mg PE/kg/min. Monitor ECG, BP. Avoid if cardiac dysrhythmia.') +
S.drugRow('Valproic acid', S.dStr(wt, 40, 3000), 'IV over 10 min', '<strong>Avoid &lt;2 yr, hepatic / mitochondrial disease, pregnancy.</strong>') +
S.drugRow('Phenobarbital', S.dStr(wt, 20, 1000), 'IV over 20 min', 'Last-choice 2nd line. High risk of resp depression + hypotension.')
)
);
// 30 min — 2nd of 2nd-line (optional)
html += stepRow('30 min', '#ef4444', 'Still seizing? Consider 2nd agent from 2nd-line OR proceed to refractory',
'If the first 2nd-line drug failed, give a different 2nd-line agent <strong>OR</strong> move directly to refractory therapy. Activate ICU, prepare for intubation. Confirm etiology not reversible (electrolytes, glucose, fever, toxin).'
);
// 40 min — REFRACTORY
html += stepRow('40 min', '#dc2626', 'Refractory status — intubate + continuous infusion + continuous EEG',
S.drugTable(
S.drugRow('Midazolam <span style="color:#065f46;font-weight:600;">(1st-line infusion)</span>', 'Bolus ' + d(wt, 0.2, 10) + ' mg → gtt ' + d(wt, 0.05, 2) + '-' + d(wt, 0.5, 18) + ' mg/hr <span style="color:var(--g500);font-size:11px;">(bolus 0.2 mg/kg, gtt 0.05-0.5 mg/kg/hr)</span>', 'IV', 'Titrate to seizure control / burst suppression.') +
S.drugRow('Pentobarbital', 'Bolus ' + d(wt, 5, 200) + ' mg → gtt ' + d(wt, 1, null) + '-' + d(wt, 5, null) + ' mg/hr <span style="color:var(--g500);font-size:11px;">(bolus 5 mg/kg, gtt 1-5 mg/kg/hr)</span>', 'IV', 'Causes hypotension — often need pressors.') +
S.drugRow('Propofol', 'Bolus ' + d(wt, 2, 100) + ' mg → gtt ' + d(wt, 2, null) + '-' + d(wt, 5, null) + ' mg/hr <span style="color:var(--g500);font-size:11px;">(bolus 2 mg/kg, gtt 2-5 mg/kg/hr)</span>', 'IV', '<strong>PRIS risk in children</strong> — limit to &lt;4 mg/kg/hr and duration &lt;48 h.') +
S.drugRow('Ketamine', 'Bolus ' + d(wt, 2, 100) + ' mg → gtt ' + d(wt, 1, null) + '-' + d(wt, 5, null) + ' mg/hr <span style="color:var(--g500);font-size:11px;">(bolus 2 mg/kg, gtt 1-5 mg/kg/hr)</span>', 'IV', 'NMDA antagonist — rescue. Good BP profile; useful if refractory to GABAergics.')
) +
'<div style="margin-top:8px;font-size:12px;color:var(--g600);"><strong>Continuous EEG within 1 h</strong> — target electrographic seizure suppression × 24-48 h, then wean. Reassess etiology: CNS imaging, LP, expanded workup.</div>'
, true);
// Key points
html += '<div style="margin-top:16px;padding:10px 12px;background:#fef3c7;border-radius:6px;font-size:12px;color:#92400e;line-height:1.55;"><strong>Key points</strong><br>' +
'• Do <strong>NOT</strong> wait for benzo response before starting the 2nd-line — parallel preparation.<br>' +
'• Maximum <strong>2 benzo doses</strong> total (1 pre-hospital + 1 in ED, or 2 in ED).<br>' +
'• Respiratory depression is common — have BVM, airway equipment, naloxone, flumazenil accessible (but avoid flumazenil here).<br>' +
'• ESETT trial: levetiracetam = fosphenytoin = valproate for efficacy. Pick by tolerability / contraindications.<br>' +
'• Always reassess: ongoing seizure? Non-convulsive status? Pseudo-seizure? → continuous EEG if any doubt.</div>';
html += '<p style="font-size:11px;color:var(--g400);margin:8px 0 0;font-style:italic;">Based on AES Guidelines 2016 and ESETT (Kapur et al., NEJM 2019). Verify all doses against institutional protocols.</p>';
resultDiv.innerHTML = html;
}
})();
// ============================================================
// ANAPHYLAXIS MANAGEMENT
// ============================================================
(function() {
document.addEventListener('click', function(e) {
if (e.target.id === 'btn-anaph-calc' || e.target.closest('#btn-anaph-calc')) calcAnaphylaxis();
});
function d(wt, mgPerKg, max) { var v = Math.round(wt * mgPerKg * 100) / 100; return max ? Math.min(v, max) : v; }
function calcAnaphylaxis() {
var wt = parseFloat(document.getElementById('anaph-weight').value);
var age = document.getElementById('anaph-age').value;
var resultDiv = document.getElementById('anaph-result');
if (!wt) { resultDiv.innerHTML = '<p style="color:var(--red);font-size:13px;">Enter weight (kg).</p>'; return; }
var S = window._EM;
var epiDose = d(wt, 0.01, 0.5);
var epiVol = Math.round(epiDose * 10) / 10; // 1:1000 = 1 mg/mL
var autoInjector = wt < 10 ? 'Draw up manually' : wt <= 25 ? 'EpiPen Jr / Auvi-Q 0.15 mg' : 'EpiPen / Auvi-Q 0.3 mg';
var html = '<div style="padding:14px;border-radius:10px;background:#fee2e2;border:2px solid #ef4444;margin-bottom:16px;">';
html += '<div style="font-size:18px;font-weight:700;color:#dc2626;margin-bottom:6px;"><i class="fas fa-triangle-exclamation"></i> STEP 1: Epinephrine IM — GIVE IMMEDIATELY</div>';
html += '<div style="font-size:15px;font-weight:600;color:var(--g800);margin-bottom:4px;">Epinephrine 1:1000 (1 mg/mL): <span style="color:#dc2626;">' + epiDose + ' mg (' + epiVol + ' mL)</span> IM to lateral thigh</div>';
html += '<div style="font-size:13px;color:var(--g600);">0.01 mg/kg (max 0.5 mg) | Auto-injector: ' + autoInjector + '</div>';
html += '<div style="font-size:12px;color:#991b1b;margin-top:6px;">May repeat every 5-15 minutes if symptoms persist. No contraindications in anaphylaxis.</div>';
html += '</div>';
html += '<div style="overflow-x:auto;-webkit-overflow-scrolling:touch;margin-bottom:12px;"><table style="width:100%;min-width:560px;border-collapse:collapse;font-size:13px;"><thead><tr style="background:var(--g100);"><th style="text-align:left;padding:6px 8px;">Step</th><th style="padding:6px 8px;">Drug</th><th style="padding:6px 8px;">Dose</th><th style="padding:6px 8px;">Route</th><th style="padding:6px 8px;">Notes</th></tr></thead><tbody>';
html += '<tr><td style="font-weight:600;color:var(--blue);">STEP 2</td><td style="font-weight:600;">Position</td><td>Supine + legs elevated</td><td>—</td><td style="font-size:12px;color:var(--g500);">If dyspneic: sitting position. If vomiting: recovery position</td></tr>';
html += '<tr><td style="font-weight:600;color:var(--blue);">STEP 3</td><td style="font-weight:600;">O2</td><td>High flow 10-15 L/min</td><td>Face mask</td><td style="font-size:12px;color:var(--g500);">100% O2. Prepare for airway management</td></tr>';
html += '<tr><td style="font-weight:600;color:var(--blue);">STEP 4</td><td style="font-weight:600;">IV fluids</td><td>NS ' + S.dStr(wt, 20, null, ' mL') + ' bolus</td><td>IV/IO</td><td style="font-size:12px;color:var(--g500);">Repeat up to 60 mL/kg for hypotension</td></tr>';
html += '<tr><td style="font-weight:600;color:var(--blue);">STEP 5</td><td style="font-weight:600;">Diphenhydramine</td><td>' + S.dStr(wt, 1.25, 50) + '</td><td>IV/IM/PO</td><td style="font-size:12px;color:var(--g500);">H1 blocker. NOT first-line — adjunct only</td></tr>';
html += '<tr><td></td><td style="font-weight:600;">Ranitidine</td><td>' + S.dStr(wt, 1, 50) + '</td><td>IV over 5 min</td><td style="font-size:12px;color:var(--g500);">H2 blocker. Optional adjunct</td></tr>';
html += '<tr><td style="font-weight:600;color:var(--blue);">STEP 6</td><td style="font-weight:600;">Dexamethasone</td><td>' + S.dStr(wt, 0.6, 16) + '</td><td>IV/IM/PO</td><td style="font-size:12px;color:var(--g500);">Prevents biphasic reaction (4-6 hrs later)</td></tr>';
html += '<tr><td></td><td style="font-weight:600;">Methylprednisolone</td><td>' + S.dStr(wt, 2, 125) + '</td><td>IV</td><td style="font-size:12px;color:var(--g500);">Alternative steroid</td></tr>';
html += '<tr style="background:#fef3c7;"><td style="font-weight:600;color:#dc2626;">IF REFRACTORY</td><td style="font-weight:600;">Epinephrine gtt</td><td>0.1-1 mcg/kg/min</td><td>IV infusion</td><td style="font-size:12px;color:var(--g500);">For persistent hypotension despite fluids + IM epi</td></tr>';
html += '<tr style="background:#fef3c7;"><td></td><td style="font-weight:600;">Glucagon</td><td>' + S.dStr(wt, 0.02, 1) + '</td><td>IV/IM</td><td style="font-size:12px;color:var(--g500);">For patients on beta-blockers not responding to epi</td></tr>';
html += '</tbody></table></div>';
html += '<div style="padding:10px 12px;background:var(--amber-light);border-radius:6px;font-size:12px;color:#92400e;"><strong>Observe minimum 4-6 hours</strong> after last dose of epinephrine (biphasic reactions occur in 5-20% of cases). Discharge with EpiPen prescription and anaphylaxis action plan. Refer to allergist.</div>';
html += '<p style="font-size:11px;color:var(--g400);margin:8px 0 0;">ASCIA Anaphylaxis Guidelines 2021. WAO Anaphylaxis Guidance 2020. AAP/ACAAI Practice Parameters.</p>';
resultDiv.innerHTML = html;
}
})();
// ============================================================
// PROCEDURAL SEDATION
// ============================================================
(function() {
document.addEventListener('click', function(e) {
if (e.target.id === 'btn-sed-calc' || e.target.closest('#btn-sed-calc')) calcSedation();
});
function d(wt, mgPerKg, max) { var v = Math.round(wt * mgPerKg * 100) / 100; return max ? Math.min(v, max) : v; }
function calcSedation() {
var wt = parseFloat(document.getElementById('sed-weight').value);
var resultDiv = document.getElementById('sed-result');
if (!wt) { resultDiv.innerHTML = '<p style="color:var(--red);font-size:13px;">Enter weight (kg).</p>'; return; }
var html = '<div style="padding:10px 14px;border-radius:8px;background:var(--purple-light);border:1.5px solid var(--purple);margin-bottom:12px;"><span style="font-size:14px;font-weight:700;color:var(--purple);">Procedural Sedation — ' + wt + ' kg patient</span></div>';
// Sedation agents
html += '<h4 style="font-size:14px;font-weight:700;color:var(--g800);margin:0 0 8px;">Sedation Agents</h4>';
html += '<div style="overflow-x:auto;-webkit-overflow-scrolling:touch;margin-bottom:16px;"><table style="width:100%;min-width:640px;border-collapse:collapse;font-size:13px;"><thead><tr style="background:var(--g100);"><th style="text-align:left;padding:6px 8px;">Drug</th><th style="padding:6px 8px;">Dose</th><th style="padding:6px 8px;">Route</th><th style="padding:6px 8px;">Onset</th><th style="padding:6px 8px;">Duration</th><th style="padding:6px 8px;">Notes</th></tr></thead><tbody>';
// Small helper: display dose ranges with per-kg footer consistently.
var perKg = function(lo, hi, unit) {
unit = unit || 'mg';
return ' <span style="color:var(--g500);font-size:11px;">(' + lo + (hi != null ? '-' + hi : '') + ' ' + unit + '/kg)</span>';
};
html += '<tr><td style="font-weight:600;">Ketamine</td><td>' + d(wt, 1.5, 100) + '-' + d(wt, 2, 150) + ' mg' + perKg(1.5, 2) + '</td><td>IV</td><td>1 min</td><td>15-30 min</td><td style="font-size:12px;color:var(--g500);">Dissociative. Preserves airway reflexes.</td></tr>';
html += '<tr><td></td><td>' + d(wt, 4, 300) + '-' + d(wt, 5, 400) + ' mg' + perKg(4, 5) + '</td><td>IM</td><td>3-5 min</td><td>30-60 min</td><td style="font-size:12px;color:var(--g500);">Give atropine 0.01 mg/kg to reduce secretions.</td></tr>';
html += '<tr><td style="font-weight:600;">Midazolam</td><td>' + d(wt, 0.05, 2) + '-' + d(wt, 0.1, 5) + ' mg' + perKg(0.05, 0.1) + '</td><td>IV</td><td>2-3 min</td><td>30-60 min</td><td style="font-size:12px;color:var(--g500);">Anxiolysis. Titrate q3-5 min.</td></tr>';
html += '<tr><td></td><td>' + d(wt, 0.5, 20) + ' mg' + perKg(0.5, null) + '</td><td>IN/PO</td><td>10-15 min</td><td>30-60 min</td><td style="font-size:12px;color:var(--g500);">IN (max 10 mg / naris) or PO (max 20 mg).</td></tr>';
html += '<tr><td style="font-weight:600;">Propofol</td><td>' + d(wt, 1, 40) + ' mg' + perKg(1, null) + '</td><td>IV</td><td>30 sec</td><td>5-10 min</td><td style="font-size:12px;color:var(--g500);">Short procedures. Causes apnea — manage airway.</td></tr>';
html += '<tr><td style="font-weight:600;">Fentanyl</td><td>' + d(wt, 1, 100) + ' mcg' + perKg(1, null, 'mcg') + '</td><td>IV</td><td>2-3 min</td><td>30-60 min</td><td style="font-size:12px;color:var(--g500);">Analgesic. Often combined with midazolam.</td></tr>';
html += '<tr><td></td><td>' + d(wt, 2, 100) + ' mcg' + perKg(2, null, 'mcg') + '</td><td>IN</td><td>5-10 min</td><td>30-60 min</td><td style="font-size:12px;color:var(--g500);">Intranasal.</td></tr>';
html += '<tr><td style="font-weight:600;">Nitrous oxide</td><td>50:50 or 70:30 mix</td><td>Inhaled</td><td>2-5 min</td><td>5 min off</td><td style="font-size:12px;color:var(--g500);">Self-administered via demand valve. Anxiolysis + mild analgesia.</td></tr>';
html += '<tr><td style="font-weight:600;">Dexmedetomidine</td><td>' + d(wt, 2, 100) + ' mcg' + perKg(2, 3, 'mcg') + '</td><td>IN</td><td>15-30 min</td><td>60-90 min</td><td style="font-size:12px;color:var(--g500);">Intranasal. No respiratory depression. Good for imaging.</td></tr>';
html += '</tbody></table></div>';
// Reversal agents
html += '<h4 style="font-size:14px;font-weight:700;color:var(--red);margin:0 0 8px;"><i class="fas fa-rotate-left"></i> Reversal Agents</h4>';
html += '<div style="overflow-x:auto;-webkit-overflow-scrolling:touch;"><table style="width:100%;min-width:560px;border-collapse:collapse;font-size:13px;"><thead><tr style="background:#fee2e2;"><th style="text-align:left;padding:6px 8px;">Drug</th><th style="padding:6px 8px;">Dose</th><th style="padding:6px 8px;">Route</th><th style="padding:6px 8px;">Reverses</th><th style="padding:6px 8px;">Notes</th></tr></thead><tbody>';
html += '<tr><td style="font-weight:600;">Naloxone</td><td>' + d(wt, 0.1, 2) + ' mg' + perKg(0.1, null) + '</td><td>IV/IM/IN</td><td>Opioids (fentanyl, morphine)</td><td style="font-size:12px;color:var(--g500);">Max 2 mg. Repeat q2-3 min. Duration shorter than opioids — monitor for re-sedation.</td></tr>';
html += '<tr><td style="font-weight:600;">Flumazenil</td><td>' + d(wt, 0.01, 0.2) + ' mg' + perKg(0.01, null) + '</td><td>IV</td><td>Benzodiazepines (midazolam)</td><td style="font-size:12px;color:var(--g500);">Max 0.2 mg single dose. Repeat q1 min to max 1 mg total. Risk of seizures — use cautiously.</td></tr>';
html += '</tbody></table></div>';
html += '<div style="margin-top:12px;padding:10px 12px;background:var(--amber-light);border-radius:6px;font-size:12px;color:#92400e;"><strong>Pre-sedation checklist:</strong> NPO status (2h clear liquids, 6h solids), consent, monitoring equipment (pulse ox, capnography, BP), resuscitation equipment at bedside, suction ready, IV access. Minimum monitoring: continuous SpO2, HR, capnography. Provider capable of managing airway must be present.</div>';
html += '<p style="font-size:11px;color:var(--g400);margin:8px 0 0;">AAP Guidelines for Monitoring and Management of Pediatric Patients Before, During, and After Sedation. ASA Practice Guidelines for Sedation and Analgesia by Non-Anesthesiologists.</p>';
resultDiv.innerHTML = html;
}
})();
// ============================================================
// IMAGE LIGHTBOX — any element with data-img-src opens fullscreen
// ============================================================
(function() {
document.addEventListener('click', function(e) {
var opener = e.target.closest && e.target.closest('[data-img-src]');
if (opener) {
e.preventDefault();
var lb = document.getElementById('img-lightbox');
if (!lb) return;
var src = opener.dataset.imgSrc;
var title = opener.dataset.imgTitle || '';
document.getElementById('img-lightbox-img').src = src;
document.getElementById('img-lightbox-img').alt = title;
document.getElementById('img-lightbox-title').textContent = title;
document.getElementById('img-lightbox-open').href = src;
lb.style.display = 'flex';
return;
}
// Close on close button, on backdrop click (not on image), and on Escape (below)
var closeBtn = e.target.closest && e.target.closest('#img-lightbox-close');
var lb2 = document.getElementById('img-lightbox');
if (!lb2 || lb2.style.display !== 'flex') return;
if (closeBtn || e.target === lb2) {
lb2.style.display = 'none';
document.getElementById('img-lightbox-img').src = '';
}
});
document.addEventListener('keydown', function(e) {
if (e.key === 'Escape') {
var lb = document.getElementById('img-lightbox');
if (lb && lb.style.display === 'flex') {
lb.style.display = 'none';
document.getElementById('img-lightbox-img').src = '';
}
}
});
})();
// ============================================================
// EMERGENCIES SUB-NAV + SHARED HELPERS
// ============================================================
(function() {
document.addEventListener('click', function(e) {
var pill = e.target.closest('[data-em]');
if (!pill) return;
document.querySelectorAll('[data-em]').forEach(function(p) { p.classList.remove('active'); });
pill.classList.add('active');
var sections = ['neonatal','airway','cardiac','respiratory','ventilation','seizure','sepsis','anaphylaxis','sedation','agitation','antiemetics','antimicrobials','burns','toxicology','trauma'];
sections.forEach(function(s) {
var el = document.getElementById('em-' + s);
if (el) el.style.display = pill.dataset.em === s ? '' : 'none';
});
});
})();
// Shared helpers (attached to window for reuse across sections)
window._EM = {
d: function(wt, perKg, max) { var v = Math.round(wt * perKg * 100) / 100; return max ? Math.min(v, max) : v; },
// Dose string — always shows the per-kg used (and max when capped), so the
// prescriber can verify the math without opening a drug ref.
// S.dStr(30, 0.1, 4) → "3 mg (0.1 mg/kg, max 4 mg)"
// S.dStr(60, 0.1, 4) → "4 mg (0.1 mg/kg, max 4 mg · capped)"
// S.dStr(20, 2, 150, ' mcg') → "40 mcg (2 mcg/kg, max 150 mcg)"
dStr: function(wt, perKg, max, unit) {
unit = unit || ' mg';
var uTrim = unit.trim() || 'mg';
var raw = wt * perKg;
var v = Math.round(raw * 100) / 100;
var capped = max != null && v > max;
var val = capped ? max : v;
var perKgStr = '(' + perKg + ' ' + uTrim + '/kg';
if (max != null) perKgStr += ', max ' + max + ' ' + uTrim;
if (capped) perKgStr += ' · capped';
perKgStr += ')';
return val + unit + ' <span style="color:var(--g500);font-size:11px;font-weight:400;">' + perKgStr + '</span>';
},
drugTable: function(rows) {
return '<div style="overflow-x:auto;-webkit-overflow-scrolling:touch;margin:8px 0;"><table style="width:100%;min-width:500px;border-collapse:collapse;font-size:13px;"><thead><tr style="background:var(--g100);"><th style="text-align:left;padding:6px 8px;">Drug</th><th style="text-align:left;padding:6px 8px;">Dose</th><th style="text-align:left;padding:6px 8px;">Route</th><th style="text-align:left;padding:6px 8px;">Notes</th></tr></thead><tbody>' + rows + '</tbody></table></div>';
},
drugRow: function(name, dose, route, notes) {
return '<tr><td style="font-weight:600;padding:5px 8px;border-bottom:1px solid var(--g100);">' + name + '</td><td style="padding:5px 8px;border-bottom:1px solid var(--g100);">' + dose + '</td><td style="padding:5px 8px;border-bottom:1px solid var(--g100);">' + route + '</td><td style="padding:5px 8px;border-bottom:1px solid var(--g100);font-size:12px;color:var(--g500);">' + (notes || '') + '</td></tr>';
},
stepBox: function(color, title, body) {
return '<div style="border-left:4px solid ' + color + ';background:' + color + '10;padding:10px 14px;border-radius:6px;margin-bottom:10px;">' +
'<div style="font-weight:700;color:' + color + ';font-size:13px;margin-bottom:4px;">' + title + '</div>' +
'<div style="font-size:13px;color:var(--g700);line-height:1.5;">' + body + '</div></div>';
},
arrow: '<div style="text-align:center;color:var(--g400);font-size:16px;margin:-4px 0 6px;">↓</div>',
badge: function(label, color) { return '<span style="display:inline-block;padding:3px 10px;border-radius:6px;background:' + color + '20;color:' + color + ';font-weight:700;font-size:12px;">' + label + '</span>'; },
ref: function(text) { return '<p style="font-size:11px;color:var(--g400);margin:8px 0 0;font-style:italic;">' + text + '</p>'; }
};
// ============================================================
// BEDSIDE — AGE → WEIGHT (single source for all sub-sections)
// ============================================================
(function() {
document.addEventListener('input', function(e) {
if (e.target && e.target.id === 'bedside-age') recomputeFromAge();
if (e.target && e.target.id === 'bedside-weight') {
e.target.dataset.userTyped = '1';
}
});
document.addEventListener('change', function(e) {
if (e.target && e.target.id === 'bedside-formula') recomputeFromAge(true);
});
document.addEventListener('click', function(e) {
if (e.target.closest && e.target.closest('#btn-bedside-clear')) {
document.getElementById('bedside-age').value = '';
var wtField = document.getElementById('bedside-weight');
wtField.value = '';
delete wtField.dataset.userTyped;
var note = document.getElementById('bedside-estimate-note');
if (note) note.innerHTML = '';
}
});
// Recompute weight from age using the currently selected formula.
// If forceFromFormula is true (formula dropdown changed), overwrite even user-typed weight.
function recomputeFromAge(forceFromFormula) {
var raw = document.getElementById('bedside-age').value;
var note = document.getElementById('bedside-estimate-note');
if (!raw || !raw.trim()) { if (note) note.innerHTML = ''; return; }
var months = window._parseAgeMonths ? window._parseAgeMonths(raw) : null;
if (months == null || isNaN(months) || months < 0) {
if (note) note.innerHTML = '<span style="color:var(--red);">Could not parse age. Try "3y", "18 months", "15 days".</span>';
return;
}
var formula = document.getElementById('bedside-formula').value;
var est = window._PED_MATH.estimateWeightFromAgeMonths(months);
var pickedWeight = formula === 'bestguess' ? est.all.bestGuess : est.all.apls;
var pickedLabel = formula === 'bestguess' ? bestGuessBand(months) : aplsBand(months);
var wtField = document.getElementById('bedside-weight');
if (forceFromFormula || !wtField.dataset.userTyped) {
wtField.value = pickedWeight;
delete wtField.dataset.userTyped; // treat as computed again
}
var ageTxt = months < 12
? (Math.round(months * 10) / 10) + ' months'
: (Math.round(months / 12 * 10) / 10) + ' years';
if (note) note.innerHTML = '<strong>' + pickedWeight + ' kg</strong> ' +
'<span style="color:var(--g500);">(' + ageTxt + ', ' + pickedLabel + ')</span> · ' +
'APLS: ' + est.all.apls + ' kg · Best Guess: ' + est.all.bestGuess + ' kg. <em>You can override the weight field.</em>';
}
function aplsBand(m) {
if (m < 12) return 'APLS 0-12 mo';
var y = m / 12;
if (y <= 5) return 'APLS 1-5 yr';
return 'APLS 6-12 yr';
}
function bestGuessBand(m) {
if (m < 12) return 'Best Guess 1-11 mo';
var y = m / 12;
if (y <= 5) return 'Best Guess 1-4 yr';
return 'Best Guess 5-14 yr';
}
// Top bedside weight is estimator-only. Sections have their own weight fields and
// read them directly (no auto-propagation). No window globals needed here.
function flash(id) {
var el = document.getElementById(id);
if (!el) return;
var prev = el.style.background;
el.style.background = 'var(--green)';
setTimeout(function() { el.style.background = prev; }, 400);
}
})();
// PED_MATH pure functions now live in /js/calc-math.js (loaded before this file)
// and are available as window._PED_MATH. Sharing the math with Node unit tests.
// ============================================================
// SEPSIS
// ============================================================
(function() {
document.addEventListener('click', function(e) {
if (e.target.id === 'btn-sepsis-show' || e.target.closest('#btn-sepsis-show')) showSepsis();
});
function showSepsis() {
var wt = parseFloat(document.getElementById('sepsis-weight').value);
var age = document.getElementById('sepsis-age').value;
var el = document.getElementById('sepsis-result');
var S = window._EM;
var html = '';
var ageLbl = { neonate: 'Neonate (0-28 d)', infant: 'Young infant (29 d - 3 mo)', child: 'Older child / adolescent' }[age];
html += '<div style="padding:10px 14px;border-radius:8px;background:#fee2e2;border:1.5px solid #ef4444;margin-bottom:12px;"><strong style="color:#dc2626;">Sepsis approach — ' + ageLbl + (wt ? ', ' + wt + ' kg' : '') + '</strong></div>';
// Definition (Phoenix 2024)
html += '<h5 style="font-size:13px;font-weight:700;color:var(--g700);margin:0 0 6px;">Definition — Phoenix Sepsis Criteria (JAMA 2024)</h5>';
html += '<div style="padding:10px;background:var(--g50);border-radius:6px;font-size:12px;line-height:1.55;margin-bottom:12px;">';
html += '<strong>Sepsis</strong> = suspected or confirmed infection + Phoenix Score ≥2 (organ dysfunction across respiratory, cardiovascular, coagulation, neurological).<br>';
html += '<strong>Septic shock</strong> = sepsis + cardiovascular dysfunction (vasoactive support, or ↑lactate ≥5, or ↓MAP for age).<br>';
html += '<em style="color:var(--g500);">Previous SIRS-based criteria (Goldstein 2005) are now superseded. Still useful for quick clinical screening.</em>';
html += '</div>';
// Quick red flags
html += '<h5 style="font-size:13px;font-weight:700;color:var(--g700);margin:10px 0 6px;">Red flags (recognize early)</h5>';
html += '<div style="padding:10px;background:#fef2f2;border-radius:6px;font-size:12px;color:#991b1b;">Abnormal behavior / mentation • Fever + ill-appearance • Tachycardia out of proportion to fever • Prolonged cap refill (&gt;3 s) • Cold/mottled extremities • Weak pulses or wide pulse pressure (&quot;warm shock&quot;) • Hypotension is a <strong>LATE</strong> sign in children • Any immune compromise / indwelling line.</div>';
// Age-specific approach
html += '<h5 style="font-size:13px;font-weight:700;color:var(--g700);margin:14px 0 6px;">Evaluation &amp; empiric therapy — ' + ageLbl + '</h5>';
if (age === 'neonate') {
html += '<div style="padding:10px;background:var(--g50);border-radius:6px;font-size:12px;margin-bottom:10px;">';
html += '<strong>Workup (full sepsis eval):</strong> CBC + diff, CRP, blood culture, UA + urine culture (cath), <strong>lumbar puncture</strong> (CSF + HSV PCR), CXR if respiratory sx. Consider procalcitonin. Rapid viral panel if available.<br>';
html += '<strong>Early-onset (&lt;72 h):</strong> GBS, E. coli, Listeria. <strong>Late-onset (&gt;72 h):</strong> coag-neg staph, S. aureus, gram-negs, Candida.</div>';
html += S.drugTable(
S.drugRow('Ampicillin', wt ? S.dStr(wt, 100, 2000) : '50-100 mg/kg/dose', 'IV', 'q8-12h depending on age/weight. Covers GBS, Listeria, Enterococcus.') +
S.drugRow('Gentamicin', wt ? S.dStr(wt, 4, 120) : '4-5 mg/kg/dose', 'IV', 'q24-48h. Monitor levels. Peak 5-12, trough &lt;1.') +
S.drugRow('Cefotaxime (add)', wt ? S.dStr(wt, 50, 2000) : '50 mg/kg/dose', 'IV', 'If meningitis suspected or gram-neg concern. Ceftriaxone avoided in hyperbilirubinemia.') +
S.drugRow('Acyclovir', wt ? S.dStr(wt, 20, 1200) : '20 mg/kg/dose', 'IV q8h', 'If HSV risk: maternal genital lesions, vesicles, seizures, CSF pleocytosis, hypothermia, hepatitis.')
);
} else if (age === 'infant') {
html += '<div style="padding:10px;background:var(--g50);border-radius:6px;font-size:12px;margin-bottom:10px;">';
html += '<strong>Workup:</strong> Use validated rules — PECARN, Aronson, Rochester, Step-by-Step (see below). Most warrant CBC + ANC, procalcitonin and/or CRP, blood culture, UA + urine culture. Many warrant LP + admission + empiric abx.<br>';
html += '<strong>Coverage:</strong> GBS, E. coli, Listeria (up to ~6 wk), S. pneumoniae, N. meningitidis, H. influenzae, Salmonella.</div>';
// Febrile-infant rules — collapsible details
html += '<details style="margin-bottom:10px;border:1px solid var(--g200);border-radius:8px;padding:8px 10px;background:white;"><summary style="cursor:pointer;font-weight:600;font-size:13px;color:var(--blue-dark);"><i class="fas fa-list-check"></i> Validated febrile-infant rules (click to expand)</summary>';
html += '<div style="margin-top:10px;font-size:12px;line-height:1.55;">';
// PECARN 2019
html += '<div style="padding:10px 12px;background:#eff6ff;border-radius:6px;margin-bottom:8px;border-left:4px solid #3b82f6;">';
html += '<div style="font-weight:700;color:#1e40af;margin-bottom:4px;">PECARN febrile infant rule (Kuppermann et al., JAMA Pediatrics 2019)</div>';
html += '<strong>Age:</strong> 29-60 days, well-appearing, febrile. <strong>Low-risk if ALL:</strong><br>';
html += '&nbsp;&bull; Normal UA (no LE, no nitrite, &lt;5 WBC/hpf)<br>';
html += '&nbsp;&bull; ANC ≤4,090 /&mu;L<br>';
html += '&nbsp;&bull; Procalcitonin ≤0.5 ng/mL (if procal unavailable: use CRP &le;20 mg/L as proxy)<br>';
html += '<strong>Low-risk</strong> → may defer LP/abx, observe, close follow-up. <strong>Not low-risk</strong> → full workup + empiric abx.';
html += '</div>';
// Aronson 2019
html += '<div style="padding:10px 12px;background:#f0fdf4;border-radius:6px;margin-bottom:8px;border-left:4px solid #16a34a;">';
html += '<div style="font-weight:700;color:#166534;margin-bottom:4px;">Aronson rule (Aronson et al., PEDIATRICS 2019)</div>';
html += '<strong>Age:</strong> 8-60 days, febrile ≥38°C. Point-based score for invasive bacterial infection (IBI):<br>';
html += '&nbsp;&bull; Age 22-28 days: <strong>+1</strong><br>';
html += '&nbsp;&bull; Max temperature ≥38.5°C: <strong>+2</strong><br>';
html += '&nbsp;&bull; ANC ≥5,185 /&mu;L: <strong>+2</strong><br>';
html += '&nbsp;&bull; Abnormal UA: <strong>+3</strong><br>';
html += '<strong>Score 0-1</strong> → low risk. <strong>≥2</strong> → consider full workup + abx. Higher scores → higher IBI risk.';
html += '</div>';
// Rochester
html += '<div style="padding:10px 12px;background:#fffbeb;border-radius:6px;margin-bottom:8px;border-left:4px solid #f59e0b;">';
html += '<div style="font-weight:700;color:#92400e;margin-bottom:4px;">Rochester criteria (Jaskiewicz et al., Pediatrics 1994)</div>';
html += '<strong>Age:</strong> 0-60 days, febrile. <strong>Low-risk if ALL:</strong><br>';
html += '&nbsp;&bull; Previously healthy (term, no perinatal complications, no prior abx/hospitalization)<br>';
html += '&nbsp;&bull; Well-appearing, no focal infection (not skin/bone/joint/soft tissue)<br>';
html += '&nbsp;&bull; WBC 5,000-15,000 /&mu;L and absolute band count ≤1,500 /&mu;L<br>';
html += '&nbsp;&bull; UA ≤10 WBC/hpf<br>';
html += '&nbsp;&bull; If diarrhea: stool ≤5 WBC/hpf<br>';
html += '<strong>Low-risk</strong> → observation without abx possible (NPV &gt;98%). Does not include procal.';
html += '</div>';
// Step-by-Step
html += '<div style="padding:10px 12px;background:#fdf4ff;border-radius:6px;margin-bottom:4px;border-left:4px solid #a855f7;">';
html += '<div style="font-weight:700;color:#6b21a8;margin-bottom:4px;">Step-by-Step (Gomez et al., Pediatrics 2016 — European)</div>';
html += '<strong>Age:</strong> ≤90 days, febrile. Sequential triage; stop at first positive:<br>';
html += '&nbsp;<strong>1.</strong> Ill-appearing? → <em>high risk</em><br>';
html += '&nbsp;<strong>2.</strong> Age ≤21 days? → <em>high risk</em><br>';
html += '&nbsp;<strong>3.</strong> Leukocyturia (UA abnormal)? → <em>high risk</em><br>';
html += '&nbsp;<strong>4.</strong> Procalcitonin ≥0.5 ng/mL? → <em>high risk</em><br>';
html += '&nbsp;<strong>5.</strong> CRP &gt;20 mg/L AND/OR ANC &gt;10,000 /&mu;L? → <em>intermediate</em><br>';
html += '&nbsp;<strong>6.</strong> Otherwise → <em>low risk</em>';
html += '<div style="margin-top:4px;color:var(--g500);">Highest sensitivity for IBI among these rules when procal available.</div>';
html += '</div>';
html += '<div style="margin-top:8px;padding:8px 10px;background:var(--g50);border-radius:6px;font-size:11px;color:var(--g600);"><strong>Practical note:</strong> AAP 2021 Clinical Practice Guideline on the well-appearing febrile infant 8-60 days synthesizes these — ages 8-21 d full workup regardless, 22-28 d inflammatory markers guide LP, 29-60 d UA + markers guide LP/abx. Defer to your local institutional pathway if available.</div>';
html += '</div></details>';
html += S.drugTable(
S.drugRow('Ceftriaxone', wt ? S.dStr(wt, 75, 2000) : '50-75 mg/kg/dose', 'IV / IM', 'q24h (or 100 mg/kg/day divided q12h for meningitis). <strong>Avoid &lt;28 days</strong> if hyperbilirubinemia.') +
S.drugRow('Ampicillin', wt ? S.dStr(wt, 100, 2000) : '50-100 mg/kg/dose', 'IV', 'If &lt;6 wks: add for Listeria coverage.') +
S.drugRow('Vancomycin', wt ? S.dStr(wt, 15, 1000) : '15 mg/kg/dose', 'IV', 'If severe / MRSA risk / meningitis. Target trough 15-20.') +
S.drugRow('Acyclovir', wt ? S.dStr(wt, 20, 1200) : '20 mg/kg/dose', 'IV q8h', '&lt;6 weeks with suspicion of HSV.')
);
} else {
html += '<div style="padding:10px;background:var(--g50);border-radius:6px;font-size:12px;margin-bottom:10px;">';
html += '<strong>Recognition:</strong> Phoenix score or clinical concern + suspected infection. <strong>Workup:</strong> CBC, CRP, procalcitonin, blood cx (+ site-specific cx), lactate, blood gas, glucose, electrolytes, coags, LP if CNS concern. Source-directed imaging.<br>';
html += '<strong>Common sources:</strong> respiratory, UTI, CNS, skin/soft tissue, intra-abdominal, bone/joint, indwelling device.</div>';
html += S.drugTable(
S.drugRow('Ceftriaxone', wt ? S.dStr(wt, 50, 2000) : '50 mg/kg/dose', 'IV', 'q24h (or 100 mg/kg/day divided for meningitis).') +
S.drugRow('Vancomycin', wt ? S.dStr(wt, 15, 1000) : '15 mg/kg/dose', 'IV', 'q6h. If severe, indwelling line, or MRSA prevalence &gt;10%.') +
S.drugRow('Piperacillin-tazobactam', wt ? S.dStr(wt, 100, 4500) : '80-100 mg/kg/dose', 'IV', 'If intra-abdominal / neutropenic.') +
S.drugRow('Clindamycin', wt ? S.dStr(wt, 10, 900) : '10-13 mg/kg/dose', 'IV', 'Adjunct for toxic shock syndrome (toxin suppression).') +
S.drugRow('Acyclovir', wt ? S.dStr(wt, 20, 1200) : '10-20 mg/kg/dose', 'IV q8h', 'If HSV CNS concern.')
);
}
// First-hour bundle
html += '<h5 style="font-size:13px;font-weight:700;color:var(--g700);margin:14px 0 6px;">First-hour bundle (SSC Peds 2020)</h5>';
html += S.stepBox('#3b82f6', '0-5 min — Recognize', 'Screen for sepsis; sepsis huddle / activation. Assess ABCs. O2 to SpO2 &gt;94%. Warm patient.');
html += S.stepBox('#8b5cf6', '5-15 min — Access &amp; labs', 'Two IVs or IO. Draw: blood cx (ideally before abx), lactate, CBC, CMP, coags, blood gas, glucose. UA + culture. Source-specific cultures.');
html += S.stepBox('#f59e0b', '15-30 min — Fluids', (wt ? 'NS or LR <strong>' + S.d(wt, 20) + ' mL</strong> bolus over 5-10 min (20 mL/kg). ' : 'NS/LR 10-20 mL/kg bolus over 5-10 min. ') + 'Reassess after each bolus: HR, perfusion, lung sounds, liver size. Repeat up to 40-60 mL/kg; stop if crackles or hepatomegaly.');
html += S.stepBox('#10b981', '30-60 min — Antibiotics + reassess', 'Broad-spectrum empiric abx within 1 hour (ideally 3 hr in sepsis, &le;1 hr in septic shock). Recheck lactate, perfusion.');
html += S.stepBox('#ef4444', '&gt;60 min — Fluid-refractory shock', 'Start vasoactive (<strong>epinephrine 0.05-0.3 mcg/kg/min</strong> for cold shock or <strong>norepinephrine 0.05-0.3 mcg/kg/min</strong> for warm shock). Consider central/IO access. Stress-dose hydrocortisone ' + (wt ? '<strong>' + S.d(wt, 2, 100) + ' mg</strong> IV <span style="color:var(--g500);font-size:11px;">(2 mg/kg, max 100 mg)</span>' : '2 mg/kg IV (max 100 mg)') + ' if catecholamine-resistant. Consider ICU transfer.');
// Key targets
html += '<h5 style="font-size:13px;font-weight:700;color:var(--g700);margin:14px 0 6px;">Resuscitation targets</h5>';
html += '<div style="padding:10px;background:var(--g50);border-radius:6px;font-size:12px;">Normal mentation • Cap refill ≤2 s • Warm extremities • Strong peripheral pulses • UOP ≥1 mL/kg/hr • MAP ≥5th %ile for age (&gt;65 mmHg adolescent) • SpO2 ≥94% • Lactate trending down.</div>';
html += S.ref('Phoenix Sepsis Criteria (Schlapbach et al., JAMA 2024). Surviving Sepsis Campaign Pediatric 2020. AAP pediatric sepsis guidance.');
el.innerHTML = html;
}
})();
// ============================================================
// NEONATAL RESUSCITATION (NRP) — pathway + drug calc
// ============================================================
(function() {
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);
});
function renderPathway() {
var el = document.getElementById('nrp-pathway-static');
if (!el || el.dataset.rendered) return;
var S = window._EM;
var html = '';
html += S.stepBox('#3b82f6', 'BIRTH — ASSESS (first 30 sec)', 'Term? Tone? Breathing/crying? If <strong>all yes</strong> → routine care with mother. If <strong>any no</strong> → warm, dry, stimulate, position airway, clear airway PRN, evaluate HR & respirations.');
html += S.arrow;
html += S.stepBox('#8b5cf6', 'HR &lt; 100 OR apneic/gasping (60 sec)', '<strong>Start PPV</strong> 40-60 breaths/min, room air for term / 21-30% for preterm. Attach SpO2 (right hand) &plusmn; ECG. MR SOPA if ineffective: <em>M</em>ask adjust, <em>R</em>eposition, <em>S</em>uction, <em>O</em>pen mouth, <em>P</em>ressure increase, <em>A</em>lternative airway.');
html += S.arrow;
html += S.stepBox('#f59e0b', 'HR &lt; 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 &lt; 60 after 30 sec of effective PPV', '<strong>Intubate + Chest compressions</strong> — 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 &lt; 60 despite compressions + PPV x 60 sec', '<strong>Epinephrine</strong> 1:10,000 (0.1 mg/mL): <br>&bull; <strong>IV/IO:</strong> 0.01-0.03 mg/kg (0.1-0.3 mL/kg) — preferred<br>&bull; <strong>ETT:</strong> 0.05-0.1 mg/kg (0.5-1 mL/kg) — while IV being placed<br>Repeat q3-5 min. If hypovolemia: <strong>NS 10 mL/kg IV/IO</strong> over 5-10 min.');
html += '<div style="display:grid;grid-template-columns:repeat(auto-fit,minmax(160px,1fr));gap:8px;margin-top:14px;">';
html += '<div style="padding:10px;background:var(--g50);border-radius:6px;font-size:12px;"><strong>Target SpO2 (preductal):</strong><br>1 min: 60-65%<br>2 min: 65-70%<br>3 min: 70-75%<br>4 min: 75-80%<br>5 min: 80-85%<br>10 min: 85-95%</div>';
html += '<div style="padding:10px;background:var(--g50);border-radius:6px;font-size:12px;"><strong>Initial ETT size:</strong><br>&lt;1 kg / &lt;28 wk: <strong>2.5</strong><br>1-2 kg / 28-34 wk: <strong>3.0</strong><br>2-3 kg / 34-38 wk: <strong>3.5</strong><br>&gt;3 kg / &gt;38 wk: <strong>3.5-4.0</strong></div>';
html += '<div style="padding:10px;background:var(--g50);border-radius:6px;font-size:12px;"><strong>ETT depth (lip):</strong><br>~ 6 + weight(kg) cm</div>';
html += '</div>';
el.innerHTML = html;
el.dataset.rendered = '1';
}
function calcNRP() {
var wt = parseFloat(document.getElementById('nrp-weight').value);
var el = document.getElementById('nrp-result');
if (!wt) { el.innerHTML = '<p style="color:var(--red);font-size:13px;">Enter weight (kg).</p>'; return; }
var S = window._EM;
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 = '<div style="padding:10px 14px;border-radius:8px;background:var(--red)10;border:1.5px solid var(--red);margin-bottom:10px;"><strong style="color:var(--red);">NRP doses — ' + wt + ' kg</strong></div>';
var pk = function(txt) { return ' <span style="color:var(--g500);font-size:11px;">(' + txt + ')</span>'; };
html += S.drugTable(
S.drugRow('Epinephrine 1:10,000', epiIvLow + '-' + epiIvHigh + ' mg, ' + (Math.round(epiIvLow*10)/10) + '-' + (Math.round(epiIvHigh*10)/10) + ' mL' + pk('0.01-0.03 mg/kg = 0.1-0.3 mL/kg'), 'IV / IO', 'Preferred route. Repeat q3-5 min.') +
S.drugRow('Epinephrine 1:10,000', epiEtLow + '-' + epiEtHigh + ' mg, ' + (Math.round(epiEtLow*10)/10) + '-' + (Math.round(epiEtHigh*10)/10) + ' mL' + pk('0.05-0.1 mg/kg = 0.5-1 mL/kg'), 'ETT', 'While IV being placed.') +
S.drugRow('Normal saline', ns + ' mL' + pk('10 mL/kg'), 'IV / IO', 'Over 5-10 min for volume. Repeat PRN.') +
S.drugRow('Dextrose 10%', d10 + ' mL' + pk('2 mL/kg = 0.2 g/kg'), 'IV slow push', 'For documented hypoglycemia. Then D10 infusion 4-6 mg/kg/min.')
);
html += '<div style="padding:10px;background:#fef3c7;border-radius:6px;font-size:12px;color:#92400e;"><strong>Concentration note:</strong> NRP uses epinephrine <strong>1:10,000</strong> (0.1 mg/mL). NOT 1:1000 (1 mg/mL) — that is IM for anaphylaxis / older patients.</div>';
html += S.ref('AHA/AAP Neonatal Resuscitation Program (NRP) 8th edition, 2020.');
el.innerHTML = html;
}
})();
// ============================================================
// AIRWAY / RSI
// ============================================================
(function() {
document.addEventListener('click', function(e) {
if (e.target.id === 'btn-airway-calc' || e.target.closest('#btn-airway-calc')) calcAirway();
});
function calcAirway() {
var wt = parseFloat(document.getElementById('airway-weight').value);
var age = parseFloat(document.getElementById('airway-age').value);
var el = document.getElementById('airway-result');
if (!wt) { el.innerHTML = '<p style="color:var(--red);font-size:13px;">Enter weight (kg).</p>'; return; }
var S = window._EM;
// Equipment sizing
var ettUncuff = age ? Math.round(((age/4) + 4) * 2) / 2 : null;
var ettCuff = age ? Math.round(((age/4) + 3.5) * 2) / 2 : null;
var ettDepth = ettUncuff ? Math.round(ettUncuff * 3 * 10) / 10 : null;
var bladeSize = age != null ? (age < 1 ? 'Miller 0-1' : age < 2 ? 'Miller 1 / Mac 1' : age < 8 ? 'Miller 2 / Mac 2' : 'Miller/Mac 3') : '—';
var lmaSize = wt < 5 ? '1' : wt < 10 ? '1.5' : wt < 20 ? '2' : wt < 30 ? '2.5' : wt < 50 ? '3' : wt < 70 ? '4' : '5';
var html = '<div style="padding:10px 14px;border-radius:8px;background:var(--blue-light);border:1.5px solid var(--blue);margin-bottom:10px;"><strong style="color:var(--blue-dark);">RSI doses &amp; equipment — ' + wt + ' kg' + (age ? ', ~' + age + ' yr' : '') + '</strong></div>';
// Pre-medication
html += '<h5 style="font-size:13px;font-weight:700;color:var(--g700);margin:10px 0 4px;">Pre-medication (optional)</h5>';
html += S.drugTable(
S.drugRow('Atropine', S.dStr(wt, 0.02, 1, ' mg') + ' (min 0.1 mg)', 'IV', 'Consider &lt;1 yr or if using succinylcholine, or bradycardia risk') +
S.drugRow('Lidocaine 2%', S.dStr(wt, 1.5, 100, ' mg'), 'IV over 1 min', 'For ↑ICP, asthma; give 2-3 min pre-induction') +
S.drugRow('Fentanyl', S.dStr(wt, 2, 150, ' mcg') + ' (2-3 mcg/kg)', 'IV over 1 min', 'Blunts sympathetic response; avoid if hypotensive')
);
// Induction
html += '<h5 style="font-size:13px;font-weight:700;color:var(--g700);margin:14px 0 4px;">Induction</h5>';
html += S.drugTable(
S.drugRow('Ketamine', S.dStr(wt, 1.5, 150, ' mg') + ' (1-2 mg/kg)', 'IV', 'Preserves BP. First-line for shock, asthma, sepsis') +
S.drugRow('Etomidate', S.dStr(wt, 0.3, 30, ' mg'), 'IV', 'Hemodynamically neutral. Avoid in septic shock (adrenal suppression)') +
S.drugRow('Propofol', S.dStr(wt, 2, 200, ' mg') + ' (1-2 mg/kg)', 'IV', 'Causes hypotension. Avoid in shock') +
S.drugRow('Midazolam', S.dStr(wt, 0.2, 10, ' mg'), 'IV', 'Less optimal induction — slower onset')
);
// Paralytics
html += '<h5 style="font-size:13px;font-weight:700;color:var(--g700);margin:14px 0 4px;">Paralytics</h5>';
html += S.drugTable(
S.drugRow('Rocuronium', S.dStr(wt, 1.2, 100, ' mg') + ' (1-1.2 mg/kg)', 'IV', '30-60 sec onset; 30-45 min duration. First-line non-depolarizing.') +
S.drugRow('Succinylcholine', S.dStr(wt, (wt < 10 ? 2 : 1.5), 150, ' mg'), 'IV', '<10kg: 2 mg/kg; ≥10kg: 1.5 mg/kg. Avoid in burns/crush/hyperK/MH/NM dz. IM option: 4 mg/kg.') +
S.drugRow('Vecuronium', S.dStr(wt, 0.1, 10, ' mg'), 'IV', '2-3 min onset; longer duration than roc')
);
// Post-intubation sedation
html += '<h5 style="font-size:13px;font-weight:700;color:var(--g700);margin:14px 0 4px;">Maintenance sedation / analgesia</h5>';
html += S.drugTable(
S.drugRow('Midazolam gtt', S.dStr(wt, 0.05, 2, ' mg') + '-' + S.dStr(wt, 0.2, 10, ' mg') + '/hr', 'IV infusion', '0.05-0.2 mg/kg/hr') +
S.drugRow('Fentanyl gtt', S.dStr(wt, 1, 100, ' mcg') + '-' + S.dStr(wt, 4, 200, ' mcg') + '/hr', 'IV infusion', '1-4 mcg/kg/hr') +
S.drugRow('Ketamine gtt', S.dStr(wt, 0.5, 30, ' mg') + '-' + S.dStr(wt, 2, 100, ' mg') + '/hr', 'IV infusion', '0.5-2 mg/kg/hr. Good for asthma') +
S.drugRow('Dexmedetomidine gtt', '0.2-1.4 mcg/kg/hr', 'IV infusion', 'No resp depression; causes bradycardia + hypotension') +
S.drugRow('Rocuronium gtt', '10-12 mcg/kg/min', 'IV infusion', 'If continued paralysis needed — only with adequate sedation')
);
// Equipment
html += '<h5 style="font-size:13px;font-weight:700;color:var(--g700);margin:14px 0 4px;">Equipment sizing</h5>';
html += '<div style="display:grid;grid-template-columns:repeat(auto-fit,minmax(180px,1fr));gap:8px;font-size:12px;">';
if (age != null) {
html += '<div style="padding:10px;background:var(--g50);border-radius:6px;"><strong>ETT (uncuffed):</strong> ' + ettUncuff + ' mm<br><strong>ETT (cuffed):</strong> ' + ettCuff + ' mm<br><strong>Depth at lip:</strong> ~' + ettDepth + ' cm</div>';
html += '<div style="padding:10px;background:var(--g50);border-radius:6px;"><strong>Laryngoscope blade:</strong><br>' + bladeSize + '</div>';
} else {
html += '<div style="padding:10px;background:var(--g50);border-radius:6px;"><em>Enter age for ETT/blade sizing.</em><br>ETT (uncuffed) = (age/4) + 4<br>ETT (cuffed) = (age/4) + 3.5<br>Depth = ETT size &times; 3</div>';
}
html += '<div style="padding:10px;background:var(--g50);border-radius:6px;"><strong>LMA size:</strong> ' + lmaSize + '<br>OPA = corner mouth → angle mandible<br>NPA = tip nose → tragus</div>';
html += '<div style="padding:10px;background:var(--g50);border-radius:6px;"><strong>Suction catheter (Fr):</strong> ETT size &times; 2<br><strong>NG tube:</strong> ETT &times; 2<br><strong>Chest tube:</strong> 4 &times; ETT</div>';
html += '</div>';
// Ventilator starting settings
html += '<h5 style="font-size:13px;font-weight:700;color:var(--g700);margin:14px 0 4px;">Ventilator — starting settings</h5>';
html += '<div style="padding:10px;background:var(--blue-light);border-radius:6px;font-size:12px;color:var(--g700);">';
html += '<strong>Mode:</strong> Volume or pressure control<br>';
html += '<strong>Tidal volume:</strong> 6-8 mL/kg (= ' + S.d(wt, 6) + '-' + S.d(wt, 8) + ' mL). Use lower (4-6 mL/kg) for ARDS.<br>';
html += '<strong>Rate:</strong> Infant 25-30, Child 15-25, Adolescent 12-16<br>';
html += '<strong>PEEP:</strong> 5 cmH2O (↑ for oxygenation problems)<br>';
html += '<strong>FiO2:</strong> Start 100%, wean to SpO2 92-97%<br>';
html += '<strong>I:E ratio:</strong> 1:2 (1:3-4 for obstructive disease)';
html += '</div>';
html += S.ref('Harriet Lane Handbook 23rd ed / PALS 2020. Always confirm doses against institutional protocols.');
el.innerHTML = html;
}
})();
// ============================================================
// CARDIAC ARREST / PALS
// ============================================================
(function() {
document.addEventListener('click', function(e) {
var btn = e.target.closest('[data-cardiac]');
if (btn) cardiacShow(btn.dataset.cardiac);
});
function getWt() {
return parseFloat(document.getElementById('cardiac-weight').value) || 0;
}
function cardiacShow(kind) {
var wt = getWt();
var el = document.getElementById('cardiac-result');
if (!wt) { el.innerHTML = '<p style="color:var(--red);font-size:13px;">Enter weight (kg).</p>'; return; }
var S = window._EM;
var html = '<div style="padding:10px 14px;border-radius:8px;background:var(--red)10;border:1.5px solid var(--red);margin-bottom:10px;"><strong style="color:var(--red);">' + title(kind) + ' — ' + wt + ' kg</strong></div>';
if (kind === 'general') {
html += S.drugTable(
S.drugRow('Epinephrine 1:10,000', S.dStr(wt, 0.01, 1, ' mg') + ' (' + S.dStr(wt, 0.1, 10, ' mL') + ')', 'IV / IO', '0.01 mg/kg = 0.1 mL/kg of 1:10,000. Max single dose 1 mg. Repeat q3-5 min.') +
S.drugRow('Epinephrine ET', S.dStr(wt, 0.1, 2.5, ' mg'), 'ETT', '0.1 mg/kg (1 mL/kg of 1:10,000) if no IV/IO') +
S.drugRow('Amiodarone', S.dStr(wt, 5, 300, ' mg'), 'IV / IO bolus', '5 mg/kg for arrest. Max 300 mg. Repeat up to 2 times (max 15 mg/kg/day).') +
S.drugRow('Lidocaine', S.dStr(wt, 1, 100, ' mg'), 'IV / IO bolus', '1 mg/kg. Alternative to amiodarone for VF/VT.') +
S.drugRow('Atropine', S.dStr(wt, 0.02, 0.5, ' mg') + ' (min 0.1 mg)', 'IV / IO', '0.02 mg/kg. Bradycardia from ↑vagal tone or AV block.') +
S.drugRow('Adenosine (1st)', S.dStr(wt, 0.1, 6, ' mg'), 'IV push + flush', '0.1 mg/kg (max 6 mg). For SVT. Rapid push, double flush.') +
S.drugRow('Adenosine (2nd)', S.dStr(wt, 0.2, 12, ' mg'), 'IV push + flush', '0.2 mg/kg (max 12 mg). Second dose if first unsuccessful.') +
S.drugRow('Sodium bicarb 8.4%', S.dStr(wt, 1, 50, ' mEq'), 'IV / IO', '1 mEq/kg. ONLY if severe metabolic acidosis, hyperK, or TCA OD. Not routine.') +
S.drugRow('Calcium chloride 10%', S.dStr(wt, 20, 1000, ' mg') + ' (' + S.dStr(wt, 0.2, 10, ' mL') + ')', 'IV / IO (central preferred)', 'For hyperK, hypoCa, Mg OD, CCB OD. 20 mg/kg = 0.2 mL/kg.') +
S.drugRow('Calcium gluconate 10%', S.dStr(wt, 60, 3000, ' mg') + ' (' + S.dStr(wt, 0.6, 30, ' mL') + ')', 'IV / IO (peripheral OK)', '60 mg/kg = 0.6 mL/kg. Preferred peripherally.') +
S.drugRow('Magnesium sulfate', S.dStr(wt, 50, 2000, ' mg'), 'IV over 10-20 min', '25-50 mg/kg. Torsades, severe asthma. Max 2 g.') +
S.drugRow('Dextrose 10%', S.dStr(wt, 2, null, ' mL') + ' (0.2 g/kg)', 'IV push', 'For documented hypoglycemia') +
S.drugRow('Defibrillation', '2 J/kg → 4 J/kg → 10 J/kg (max 10 J/kg or adult dose)', 'Pad', 'For VF/pulseless VT. Resume CPR immediately after shock.') +
S.drugRow('Cardioversion (sync)', '0.5-1 J/kg → 2 J/kg', 'Pad', 'For unstable SVT/VT. Sedate if possible.')
);
html += '<div style="padding:10px;background:#fef3c7;border-radius:6px;font-size:12px;color:#92400e;margin-top:10px;"><strong>Concentrations:</strong> Epi 1:10,000 (0.1 mg/mL) for IV arrest. 1:1000 (1 mg/mL) for IM anaphylaxis. Atropine &lt;0.1 mg can cause paradoxical bradycardia.</div>';
} else if (kind === 'asystole') {
html += S.drugTable(
S.drugRow('CPR', '100-120/min, depth 1/3 AP', '—', '15:2 (2 rescuer) or 30:2 (single). Rotate every 2 min.') +
S.drugRow('Epinephrine', S.dStr(wt, 0.01, 1, ' mg') + ' IV/IO', 'IV / IO', '0.01 mg/kg 1:10,000 = 0.1 mL/kg. Q3-5 min. Start early.') +
S.drugRow('Epinephrine ETT', S.dStr(wt, 0.1, 2.5, ' mg'), 'ETT', '0.1 mg/kg if no IV access')
);
html += '<h5 style="font-size:13px;font-weight:700;color:var(--g700);margin:14px 0 6px;">Reversible causes (H\'s &amp; T\'s)</h5>';
html += '<div style="display:grid;grid-template-columns:repeat(auto-fit,minmax(160px,1fr));gap:6px;font-size:12px;">';
html += '<div style="padding:8px;background:var(--g50);border-radius:6px;"><strong>H\'s</strong><br>Hypoxia, Hypovolemia, H+ (acidosis), Hypo/hyperK, Hypoglycemia, Hypothermia</div>';
html += '<div style="padding:8px;background:var(--g50);border-radius:6px;"><strong>T\'s</strong><br>Tension PTX, Tamponade, Toxins, Thrombosis (MI/PE), Trauma</div>';
html += '</div>';
} else if (kind === 'brady') {
html += S.stepBox('#f59e0b', 'Bradycardia with poor perfusion (HR &lt; 60)', 'Start CPR if HR &lt; 60 with poor perfusion despite oxygenation and ventilation.');
html += S.arrow;
html += S.drugTable(
S.drugRow('Epinephrine', S.dStr(wt, 0.01, 1, ' mg'), 'IV / IO', 'First-line. Q3-5 min.') +
S.drugRow('Atropine', S.dStr(wt, 0.02, 0.5, ' mg') + ' (min 0.1 mg)', 'IV / IO', 'If ↑ vagal tone or AV block. Max 1 mg child / 0.5 mg infant.') +
S.drugRow('Transcutaneous pacing', '—', 'Pad', 'For refractory bradycardia not responsive to drugs.') +
S.drugRow('Consider', '—', '—', 'Hypoxia, tension pneumothorax, ↑ICP, toxic ingestion (organo, CCB, BB), heart block')
);
} else if (kind === 'svt') {
html += S.stepBox('#3b82f6', 'SVT — narrow complex, rate usually &gt;220 infant / &gt;180 child', 'Differentiate from sinus tach: abrupt onset/offset, no P waves or abnormal P axis, HR minimally variable.');
html += S.arrow;
html += '<h5 style="font-size:13px;font-weight:700;color:var(--g700);margin:6px 0;">If STABLE</h5>';
html += S.drugTable(
S.drugRow('Vagal maneuvers', 'Ice to face, blow into syringe, Valsalva', '—', 'Try first in stable patient') +
S.drugRow('Adenosine (1st)', S.dStr(wt, 0.1, 6, ' mg'), 'IV push (proximal) + flush', 'Rapid push, 3-way stopcock with NS flush') +
S.drugRow('Adenosine (2nd)', S.dStr(wt, 0.2, 12, ' mg'), 'IV push + flush', 'If first dose unsuccessful') +
S.drugRow('Procainamide', '15 mg/kg over 30-60 min', 'IV', 'Expert consult. Avoid with amiodarone.') +
S.drugRow('Amiodarone', '5 mg/kg over 20-60 min', 'IV', 'Expert consult.')
);
html += '<h5 style="font-size:13px;font-weight:700;color:var(--g700);margin:10px 0 4px;">If UNSTABLE</h5>';
html += S.drugTable(S.drugRow('Synchronized cardioversion', '0.5-1 J/kg → 2 J/kg', 'Pad', 'Sedate if possible. Pre-treat with adenosine if IV available.'));
} else if (kind === 'vfib') {
html += S.stepBox('#dc2626', 'VF / Pulseless VT', 'High-quality CPR + defibrillation are key. Minimize interruptions.');
html += S.arrow;
html += S.drugTable(
S.drugRow('Defibrillation (1st)', '2 J/kg', 'Pad', 'Resume CPR immediately after shock.') +
S.drugRow('Defibrillation (2nd)', '4 J/kg', 'Pad', 'After 2 min CPR.') +
S.drugRow('Defibrillation (3rd+)', '≥4 J/kg (max 10 J/kg or adult dose)', 'Pad', '') +
S.drugRow('Epinephrine', S.dStr(wt, 0.01, 1, ' mg'), 'IV / IO', 'After 2nd shock. Q3-5 min.') +
S.drugRow('Amiodarone', S.dStr(wt, 5, 300, ' mg'), 'IV / IO bolus', 'Refractory VF/VT. Max 15 mg/kg/day.') +
S.drugRow('Lidocaine', S.dStr(wt, 1, 100, ' mg'), 'IV / IO', 'Alternative to amiodarone. Then 20-50 mcg/kg/min gtt.') +
S.drugRow('Mg sulfate', S.dStr(wt, 50, 2000, ' mg'), 'IV over 1-2 min', 'For torsades or hypoMg.')
);
} else if (kind === 'vt') {
html += S.stepBox('#f59e0b', 'Stable monomorphic VT', 'Expert consult. Avoid combining QT-prolonging agents.');
html += S.arrow;
html += S.drugTable(
S.drugRow('Amiodarone', '5 mg/kg over 20-60 min', 'IV', '= ' + S.d(wt, 5, 300) + ' mg over 20-60 min') +
S.drugRow('Procainamide', '15 mg/kg over 30-60 min', 'IV', 'Do not combine with amiodarone') +
S.drugRow('Sync cardioversion', '0.5-1 → 2 J/kg', 'Pad', 'If becomes unstable. Sedate.')
);
}
html += S.ref('AHA PALS Guidelines 2020. Always verify against institutional protocols.');
el.innerHTML = html;
}
function title(k) {
return { general: 'PALS General Doses', asystole: 'Asystole / PEA', brady: 'Bradycardia', svt: 'SVT', vfib: 'VF / Pulseless VT', vt: 'Stable VT' }[k] || k;
}
})();
// ============================================================
// AGITATION
// ============================================================
(function() {
document.addEventListener('click', function(e) {
if (e.target.id === 'btn-agit-calc' || e.target.closest('#btn-agit-calc')) calcAgit();
});
function calcAgit() {
var wt = parseFloat(document.getElementById('agit-weight').value);
var el = document.getElementById('agit-result');
if (!wt) { el.innerHTML = '<p style="color:var(--red);font-size:13px;">Enter weight (kg).</p>'; return; }
var S = window._EM;
var html = '<div style="padding:10px 14px;border-radius:8px;background:var(--purple-light);border:1.5px solid var(--purple);margin-bottom:10px;"><strong style="color:var(--purple);">Agitation management — ' + wt + ' kg</strong></div>';
html += S.stepBox('#10b981', 'Step 1 — Non-pharmacologic', 'Dim lights, quiet room, familiar caregiver present, reduce stimulation. Rule out hypoglycemia, hypoxia, pain, ↑ICP, toxic ingestion, infection.');
html += S.stepBox('#3b82f6', 'Step 2 — Oral / intranasal (cooperative)', 'First-line for moderate agitation if the patient will accept PO/IN.');
html += S.drugTable(
S.drugRow('Lorazepam', S.dStr(wt, 0.05, 2, ' mg'), 'PO', '0.05 mg/kg. May repeat in 30 min.') +
S.drugRow('Midazolam', S.dStr(wt, 0.5, 10, ' mg'), 'PO', '0.5 mg/kg (max 10 mg)') +
S.drugRow('Midazolam', S.dStr(wt, 0.3, 10, ' mg'), 'IN (5 mg/mL)', '0.3 mg/kg split between nares (max 10 mg)') +
S.drugRow('Olanzapine (ODT)', wt < 30 ? '2.5-5 mg' : '5-10 mg', 'PO / ODT', 'Age ≥6 yr. Avoid IM + benzo combo (risk of resp depression).') +
S.drugRow('Diphenhydramine', S.dStr(wt, 1, 50, ' mg'), 'PO', '1 mg/kg. Adjunct only; sedating.')
);
html += S.stepBox('#f59e0b', 'Step 3 — IM / IV (severe, uncooperative, or safety risk)', 'Require continuous monitoring. Consider restraints only as last resort.');
html += S.drugTable(
S.drugRow('Midazolam', S.dStr(wt, 0.1, 5, ' mg'), 'IV / IM', '0.05-0.1 mg/kg IV, 0.1-0.15 mg/kg IM (max 10 mg)') +
S.drugRow('Lorazepam', S.dStr(wt, 0.1, 4, ' mg'), 'IV / IM', '0.05-0.1 mg/kg (max 4 mg). May cause resp depression.') +
S.drugRow('Haloperidol', wt < 40 ? '0.025-0.075 mg/kg = ' + S.d(wt, 0.05) + ' mg' : '2.5-5 mg', 'IM / IV', 'Avoid &lt;3 yr. Risk: QT, EPS, NMS. ECG if repeated.') +
S.drugRow('Olanzapine', wt < 40 ? '2.5-5 mg' : '5-10 mg', 'IM', 'Avoid benzo co-administration (resp depression, hypotension)') +
S.drugRow('Ketamine', S.dStr(wt, 4, 500, ' mg'), 'IM', '4-5 mg/kg IM (rescue for severe excited delirium). Monitor airway.') +
S.drugRow('Droperidol', '0.03-0.07 mg/kg = ' + S.d(wt, 0.05) + ' mg', 'IM / IV', 'Effective but QT concern — get ECG.')
);
html += '<div style="padding:10px;background:#fef3c7;border-radius:6px;font-size:12px;color:#92400e;margin-top:10px;"><strong>Monitoring:</strong> Continuous SpO2 + HR after parenteral sedation. Have airway equipment, flumazenil, naloxone, and IV access ready.</div>';
html += S.ref('AAP Clinical Report on Pediatric Agitation. ACEP Guidelines for Acute Agitation.');
el.innerHTML = html;
}
})();
// ============================================================
// ANTIEMETICS
// ============================================================
(function() {
document.addEventListener('click', function(e) {
if (e.target.id === 'btn-emet-calc' || e.target.closest('#btn-emet-calc')) calcEmet();
});
function calcEmet() {
var wt = parseFloat(document.getElementById('emet-weight').value);
var el = document.getElementById('emet-result');
if (!wt) { el.innerHTML = '<p style="color:var(--red);font-size:13px;">Enter weight (kg).</p>'; return; }
var S = window._EM;
// Ondansetron weight bands
var ondWt = wt < 15 ? '2 mg' : wt < 30 ? '4 mg' : '8 mg';
var html = '<div style="padding:10px 14px;border-radius:8px;background:var(--blue-light);border:1.5px solid var(--blue);margin-bottom:10px;"><strong style="color:var(--blue-dark);">Antiemetic doses — ' + wt + ' kg</strong></div>';
html += S.drugTable(
S.drugRow('Ondansetron', ondWt + ' (weight band) OR ' + S.dStr(wt, 0.15, 8, ' mg') + ' (0.15 mg/kg)', 'PO / ODT / IV', 'First-line. Max single 8 mg. Repeat q8h. QT prolongation — avoid with other QT drugs. &lt;6 mo: limited data.') +
S.drugRow('Metoclopramide', S.dStr(wt, 0.15, 10, ' mg'), 'IV / IM / PO', '0.1-0.15 mg/kg (max 10 mg). Give with diphenhydramine to prevent EPS / dystonia.') +
S.drugRow('Dimenhydrinate', S.dStr(wt, 1.25, 50, ' mg'), 'PO / IV / IM / PR', '1.25 mg/kg (max 50 mg) q6h. ≥2 yr.') +
S.drugRow('Diphenhydramine', S.dStr(wt, 1, 50, ' mg'), 'PO / IV / IM', '1 mg/kg (max 50 mg) q6h. Adjunct, sedating.') +
S.drugRow('Promethazine', S.dStr(wt, 0.25, 25, ' mg'), 'PO / IV / IM', '0.25-1 mg/kg. <strong>CONTRAINDICATED &lt;2 yr</strong> (resp depression). Tissue injury if IV extrav.') +
S.drugRow('Dexamethasone', S.dStr(wt, 0.15, 10, ' mg'), 'IV / PO', 'Adjunct, esp. chemo-induced. 0.15 mg/kg (max 10 mg).') +
S.drugRow('Scopolamine patch', '1.5 mg patch', 'Transdermal', '≥12 yr. Motion sickness. Apply 4h before exposure.')
);
html += '<div style="padding:10px;background:#fef3c7;border-radius:6px;font-size:12px;color:#92400e;margin-top:10px;"><strong>Pearls:</strong> Ondansetron is first-line in ED for acute gastroenteritis vomiting — single PO/ODT dose increases oral rehydration success. Avoid anticholinergics + opioid combinations. Check QTc if stacking ondansetron + other QT drugs.</div>';
html += S.ref('AAP gastroenteritis guidance; WHO essential medicines; Lexicomp.');
el.innerHTML = html;
}
})();
// ============================================================
// ANTIMICROBIALS (empiric, by age + infection type)
// ============================================================
(function() {
document.addEventListener('click', function(e) {
if (e.target.id === 'btn-abx-lookup' || e.target.closest('#btn-abx-lookup')) lookupAbx();
});
var REG = {
neonate: {
sepsis: { first: 'Ampicillin + gentamicin', alt: 'Add cefotaxime if meningitis suspected or gram-neg concern', duration: '7-10 days; 21 days if confirmed meningitis', notes: 'Cover GBS, E. coli, Listeria. Add acyclovir if HSV risk (maternal lesions, vesicles, seizures).' },
meningitis: { first: 'Ampicillin + cefotaxime (or gentamicin) + acyclovir', alt: 'Add vancomycin if gram-positive cocci', duration: '14-21 days depending on organism', notes: 'HSV coverage essential. LP + HSV PCR.' },
pna: { first: 'Ampicillin + gentamicin', alt: 'Add cefotaxime for gram-neg', duration: '7-10 days', notes: 'Same as sepsis coverage.' },
uti: { first: 'Ampicillin + gentamicin', alt: 'Cefotaxime if sensitivities known', duration: '10-14 days', notes: 'Evaluate for sepsis. Renal US and VCUG workup.' },
skin: { first: 'Ampicillin + gentamicin', alt: 'Add vancomycin if MRSA risk', duration: '7-10 days', notes: 'Omphalitis, mastitis — broad coverage.' },
ent: { first: 'Discuss with infectious diseases', alt: '—', duration: '—', notes: 'Rare in neonates. Any ear/throat infection warrants sepsis eval.' },
neutropenic: { first: 'Cefepime or piperacillin-tazobactam', alt: 'Add vancomycin if indwelling line, severe mucositis, or MRSA', duration: 'Until ANC recovery + afebrile ≥48h', notes: 'Oncology/ID consult.' },
ic: { first: 'Ampicillin + gentamicin + metronidazole', alt: 'Or piperacillin-tazobactam', duration: '7-14 days', notes: 'NEC: add metronidazole/clindamycin for anaerobes.' },
bone: { first: 'Ampicillin + gentamicin', alt: 'Vancomycin if MRSA risk', duration: '3-6 weeks (IV then PO)', notes: 'Usually hematogenous. S. aureus, GBS, E. coli.' }
},
infant: {
sepsis: { first: 'Ampicillin + ceftriaxone (or gentamicin)', alt: '+ vancomycin if MRSA / severe', duration: '7-10 days', notes: 'Add acyclovir if HSV suspected (<6 wks). Fever in <90 days requires workup.' },
meningitis: { first: 'Ceftriaxone + vancomycin (± ampicillin if &lt;6 wks for Listeria)', alt: '+ acyclovir if HSV', duration: '10-14 days (longer for Listeria/gram-neg)', notes: 'Dexamethasone if H. influenzae suspected.' },
pna: { first: 'Ampicillin (or ceftriaxone)', alt: 'Add azithromycin if atypical', duration: '7-10 days', notes: 'S. pneumoniae most common. RSV/viral often primary.' },
uti: { first: 'Ceftriaxone or cefotaxime', alt: 'Ampicillin + gentamicin', duration: '10-14 days', notes: 'US kidney/bladder if first febrile UTI.' },
skin: { first: 'Cefazolin or clindamycin', alt: 'Vancomycin if MRSA risk', duration: '7-10 days', notes: 'Consider MRSA if purulent or local resistance >10%.' },
ent: { first: 'Amoxicillin (90 mg/kg/day) for AOM', alt: 'Amox-clav if recent abx/treatment failure', duration: 'AOM 10 days &lt;2 yr; 7 days ≥2 yr', notes: 'Observe mild AOM if &gt;6 mo and no severe features.' },
neutropenic: { first: 'Cefepime or piperacillin-tazobactam', alt: '+ vancomycin for severe/mucositis/line', duration: 'Until ANC recovery + afebrile', notes: 'Oncology/ID consult.' },
ic: { first: 'Ceftriaxone + metronidazole', alt: 'Piperacillin-tazobactam', duration: '5-7 days (uncomplicated), longer for complicated', notes: 'Appendicitis — surgical consult.' },
bone: { first: 'Cefazolin ± vancomycin', alt: 'Clindamycin', duration: '3-4 weeks (IV then PO transition)', notes: 'S. aureus most common. Kingella in &lt;4 yr.' }
},
child: {
sepsis: { first: 'Ceftriaxone + vancomycin', alt: 'Piperacillin-tazobactam if intra-abdominal', duration: '7-14 days', notes: 'Expand if specific source. Add antifungal if prolonged neutropenia.' },
meningitis: { first: 'Ceftriaxone + vancomycin', alt: '+ dexamethasone (Hib coverage)', duration: '10-14 days', notes: 'Lumbar puncture. Dexamethasone 0.15 mg/kg q6h x 4 days.' },
pna: { first: 'Ampicillin OR amoxicillin (high dose)', alt: 'Ceftriaxone if hospitalized; add azithromycin for atypical', duration: '5-7 days (uncomplicated)', notes: 'Mycoplasma if &gt;5 yr. Consider viral causes.' },
uti: { first: 'Cephalexin or TMP-SMX (PO)', alt: 'Ceftriaxone if ill', duration: '7-10 days (10-14 if pyelo)', notes: 'Culture-guided de-escalation.' },
skin: { first: 'Cephalexin or clindamycin', alt: 'TMP-SMX or doxycycline if MRSA', duration: '5-10 days', notes: 'Abscess — incision &amp; drainage primary tx.' },
ent: { first: 'Amoxicillin 90 mg/kg/day (AOM); Penicillin V for strep pharyngitis', alt: 'Amox-clav; cephalexin if non-anaphylactic PCN allergy', duration: 'AOM 5-10 days; strep 10 days', notes: 'Strep pharyngitis dose: PCN V 250 mg BID-TID (&lt;27 kg) or 500 mg BID (≥27 kg).' },
neutropenic: { first: 'Cefepime OR piperacillin-tazobactam', alt: '+ vancomycin', duration: 'Until ANC recovery + afebrile', notes: 'Add empiric antifungal if fever &gt;4-7 days.' },
ic: { first: 'Ceftriaxone + metronidazole', alt: 'Piperacillin-tazobactam', duration: '5-7 days (uncomplicated appendicitis)', notes: 'Surgical consult.' },
bone: { first: 'Cefazolin ± vancomycin', alt: 'Clindamycin', duration: '3-4 weeks total', notes: 'S. aureus, group A strep. Consider MRSA if severe.' }
}
};
function lookupAbx() {
var age = document.getElementById('abx-age').value;
var inf = document.getElementById('abx-infection').value;
var el = document.getElementById('abx-result');
var r = REG[age] && REG[age][inf];
if (!r) { el.innerHTML = '<p style="color:var(--red);font-size:13px;">No regimen found.</p>'; return; }
var S = window._EM;
var ageLbl = { neonate: 'Neonate (0-28 d)', infant: 'Infant (1-3 mo)', child: 'Child (>3 mo)' }[age];
var infLbl = document.querySelector('#abx-infection option[value="' + inf + '"]').textContent;
var html = '<div style="padding:10px 14px;border-radius:8px;background:var(--blue-light);border:1.5px solid var(--blue);margin-bottom:10px;"><strong style="color:var(--blue-dark);">' + ageLbl + ' — ' + infLbl + '</strong></div>';
html += '<div style="padding:12px;background:#d1fae5;border-radius:6px;margin-bottom:10px;"><strong style="color:#065f46;">First-line:</strong> ' + r.first + '</div>';
html += '<div style="padding:12px;background:var(--g50);border-radius:6px;margin-bottom:10px;"><strong>Alternative / add:</strong> ' + r.alt + '</div>';
html += '<div style="padding:12px;background:var(--g50);border-radius:6px;margin-bottom:10px;"><strong>Duration:</strong> ' + r.duration + '</div>';
html += '<div style="padding:10px;background:#fef3c7;border-radius:6px;font-size:12px;color:#92400e;"><strong>Notes:</strong> ' + r.notes + '</div>';
html += S.ref('AAP Red Book, IDSA guidelines, Harriet Lane. Always tailor to local resistance patterns and culture results.');
el.innerHTML = html;
}
})();
// ============================================================
// BURNS — Lund-Browder body parts + Parkland
// ============================================================
(function() {
// Lund-Browder age-adjusted region percentages. Regions marked "*" change with age.
// Column order: infant, young (1-5), child (5-10), adol (10-15), adult (>15).
var LB = {
head: { label: 'Head', vals: [18, 13, 11, 9, 7], ageSensitive: true },
neck: { label: 'Neck', vals: [2, 2, 2, 2, 2] },
ant_trunk: { label: 'Anterior trunk', vals: [13, 13, 13, 13, 13] },
post_trunk:{ label: 'Posterior trunk', vals: [13, 13, 13, 13, 13] },
r_buttock: { label: 'Right buttock', vals: [2.5, 2.5, 2.5, 2.5, 2.5] },
l_buttock: { label: 'Left buttock', vals: [2.5, 2.5, 2.5, 2.5, 2.5] },
genital: { label: 'Genitalia', vals: [1, 1, 1, 1, 1] },
r_uparm: { label: 'R upper arm', vals: [4, 4, 4, 4, 4] },
l_uparm: { label: 'L upper arm', vals: [4, 4, 4, 4, 4] },
r_forearm: { label: 'R forearm', vals: [3, 3, 3, 3, 3] },
l_forearm: { label: 'L forearm', vals: [3, 3, 3, 3, 3] },
r_hand: { label: 'R hand', vals: [2.5, 2.5, 2.5, 2.5, 2.5] },
l_hand: { label: 'L hand', vals: [2.5, 2.5, 2.5, 2.5, 2.5] },
r_thigh: { label: 'R thigh', vals: [5.5, 8, 8.5, 9, 9.5], ageSensitive: true },
l_thigh: { label: 'L thigh', vals: [5.5, 8, 8.5, 9, 9.5], ageSensitive: true },
r_leg: { label: 'R lower leg', vals: [5, 5.5, 6, 6.5, 7], ageSensitive: true },
l_leg: { label: 'L lower leg', vals: [5, 5.5, 6, 6.5, 7], ageSensitive: true },
r_foot: { label: 'R foot', vals: [3.5, 3.5, 3.5, 3.5, 3.5] },
l_foot: { label: 'L foot', vals: [3.5, 3.5, 3.5, 3.5, 3.5] }
};
var AGE_KEYS = ['infant','young','child','adol','adult'];
document.addEventListener('click', function(e) {
if (e.target.id === 'btn-burn-calc' || e.target.closest('#btn-burn-calc')) calcBurn();
if (e.target.id === 'btn-burn-reset' || e.target.closest('#btn-burn-reset')) resetParts();
// Render body-parts table the first (or any) time the Burns sub-pill is activated
var bp = e.target.closest && e.target.closest('[data-em="burns"]');
if (bp) setTimeout(renderBodyParts, 0);
// Also render if the top-level Bedside tab is clicked (ensures table ready before user navigates)
var nav = e.target.closest && e.target.closest('[data-calc="bedside"]');
if (nav) setTimeout(renderBodyParts, 50);
});
document.addEventListener('change', function(e) {
if (e.target && e.target.id === 'burn-age') renderBodyParts();
});
document.addEventListener('input', function(e) {
if (e.target && e.target.dataset && e.target.dataset.burnRegion) updateLive();
});
// Also attempt render on these events in case component mounts later
document.addEventListener('DOMContentLoaded', renderBodyParts);
document.addEventListener('tabChanged', function() { setTimeout(renderBodyParts, 100); });
if (document.readyState !== 'loading') setTimeout(renderBodyParts, 0);
function ageIdx() { return Math.max(0, AGE_KEYS.indexOf(document.getElementById('burn-age').value)); }
function renderBodyParts() {
var wrap = document.getElementById('burn-bodyparts-wrapper');
if (!wrap) return;
var idx = ageIdx();
var html = '<div style="background:var(--g50);border-radius:8px;padding:10px 12px;">';
html += '<div style="font-size:12px;color:var(--g600);margin-bottom:8px;line-height:1.4;">For each involved body region, enter <strong>% of that region burned (2° or deeper)</strong>. Leave 0 if uninvolved. TBSA = sum of (region size × % involvement).</div>';
html += '<div style="display:grid;grid-template-columns:repeat(auto-fit,minmax(220px,1fr));gap:6px;">';
Object.keys(LB).forEach(function(key) {
var r = LB[key];
var max = r.vals[idx];
var isAgeDep = r.ageSensitive;
html += '<div style="display:flex;align-items:center;gap:8px;padding:4px 8px;background:white;border-radius:6px;border:1px solid var(--g200);">' +
'<label style="flex:1;font-size:12px;color:var(--g700);">' + r.label + ' <span style="color:var(--g400);">(' + max + '%' + (isAgeDep ? '<span title="age-adjusted">*</span>' : '') + ')</span></label>' +
'<input type="number" min="0" max="100" step="5" value="0" data-burn-region="' + key + '" data-burn-max="' + max + '" style="width:68px;padding:3px 6px;border:1px solid var(--g300);border-radius:4px;font-size:12px;text-align:right;"> %' +
'</div>';
});
html += '</div></div>';
wrap.innerHTML = html;
updateLive();
}
function resetParts() {
var inputs = document.querySelectorAll('[data-burn-region]');
inputs.forEach(function(i) { i.value = 0; });
document.getElementById('burn-tbsa').value = '';
updateLive();
}
function computeTbsa() {
var idx = ageIdx();
var total = 0;
Object.keys(LB).forEach(function(key) {
var el = document.querySelector('[data-burn-region="' + key + '"]');
if (!el) return;
var pct = parseFloat(el.value) || 0;
if (pct < 0) pct = 0; if (pct > 100) pct = 100;
total += LB[key].vals[idx] * (pct / 100);
});
return Math.round(total * 10) / 10;
}
function updateLive() {
var t = computeTbsa();
var live = document.getElementById('burn-tbsa-live');
if (live) live.textContent = t > 0 ? 'Computed TBSA: ' + t + '%' : '';
}
function calcBurn() {
var wt = parseFloat(document.getElementById('burn-weight').value);
var override = document.getElementById('burn-tbsa').value;
var tbsa = override !== '' ? parseFloat(override) : computeTbsa();
var el = document.getElementById('burn-result');
if (!wt) { el.innerHTML = '<p style="color:var(--red);font-size:13px;">Enter weight (kg).</p>'; return; }
if (!tbsa || tbsa <= 0) { el.innerHTML = '<p style="color:var(--red);font-size:13px;">Enter % involvement per region, or override TBSA.</p>'; return; }
var S = window._EM;
var total = Math.round(4 * wt * tbsa);
var first8 = Math.round(total / 2);
var rateFirst = Math.round(first8 / 8);
var next16 = total - first8;
var rateNext = Math.round(next16 / 16);
var maint = wt <= 10 ? wt * 4 : wt <= 20 ? 40 + (wt - 10) * 2 : 60 + (wt - 20);
maint = Math.round(maint);
var html = '<div style="padding:10px 14px;border-radius:8px;background:#fee2e2;border:1.5px solid #ef4444;margin-bottom:10px;"><strong style="color:#dc2626;">Burn fluid resuscitation — ' + wt + ' kg, ' + tbsa + '% TBSA (2° or deeper)</strong></div>';
html += '<div style="padding:12px;background:#fef2f2;border-radius:6px;margin-bottom:10px;"><strong>Parkland formula:</strong> 4 mL × kg × %TBSA = <strong>' + total + ' mL LR over 24 hours</strong>' +
'<br>&nbsp;&nbsp;<strong>First 8 h</strong> (from time of burn): ' + first8 + ' mL (~<strong>' + rateFirst + ' mL/hr</strong>)' +
'<br>&nbsp;&nbsp;<strong>Next 16 h</strong>: ' + next16 + ' mL (~<strong>' + rateNext + ' mL/hr</strong>)</div>';
html += '<div style="padding:12px;background:var(--g50);border-radius:6px;margin-bottom:10px;"><strong>Plus maintenance fluids (4-2-1):</strong> ' + maint + ' mL/hr (D5 1/2NS ± 20 mEq KCl/L once UOP established). Consider dextrose in children &lt;30 kg.</div>';
html += '<div style="padding:12px;background:var(--g50);border-radius:6px;margin-bottom:10px;"><strong>Titrate to UOP:</strong> target 1-2 mL/kg/hr (infants / children), 0.5-1 mL/kg/hr (adolescents). <strong>Clinical response trumps formula.</strong></div>';
// Breakdown of what regions contributed
var idx = ageIdx();
var breakdown = '';
Object.keys(LB).forEach(function(key) {
var el = document.querySelector('[data-burn-region="' + key + '"]');
if (!el) return;
var pct = parseFloat(el.value) || 0;
if (pct > 0) {
var contrib = Math.round(LB[key].vals[idx] * pct / 100 * 10) / 10;
breakdown += '<div>' + LB[key].label + ': ' + pct + '% of ' + LB[key].vals[idx] + '% = ' + contrib + '%</div>';
}
});
if (breakdown) {
html += '<details style="margin-bottom:10px;"><summary style="cursor:pointer;font-size:13px;font-weight:600;color:var(--g700);">Region breakdown</summary><div style="padding:10px;background:var(--g50);border-radius:6px;font-size:12px;margin-top:6px;">' + breakdown + '</div></details>';
}
html += '<h5 style="font-size:13px;font-weight:700;color:var(--g700);margin:14px 0 6px;">Other pearls</h5>';
html += '<div style="padding:10px;background:var(--g50);border-radius:6px;font-size:12px;">';
html += '<strong>Rule of palm:</strong> Patient\'s palm + fingers ≈ 1% TBSA — good for scattered burns.<br>';
html += '<strong>First-degree burns DO NOT count</strong> toward TBSA or Parkland.<br>';
html += '<strong>Analgesia:</strong> Morphine 0.05-0.1 mg/kg IV q2h, or fentanyl 1-2 mcg/kg IV q30-60 min.<br>';
html += '<strong>Tetanus</strong> prophylaxis if indicated. Tdap/Td ± tetanus immunoglobulin.';
html += '</div>';
html += '<h5 style="font-size:13px;font-weight:700;color:var(--g700);margin:14px 0 6px;">Burn center referral (ABA)</h5>';
html += '<div style="padding:10px;background:#fef3c7;border-radius:6px;font-size:12px;color:#92400e;">Partial-thickness &gt;10% TBSA; any full-thickness; face/hands/feet/genital/perineum/major joints; electrical/chemical/inhalation; associated trauma; significant comorbidities; pediatric burns in non-pediatric center.</div>';
html += S.ref('ABA Advanced Burn Life Support (ABLS) 2018. Parkland formula: Baxter 1968. Lund-Browder 1944 chart (age-adjusted regions).');
el.innerHTML = html;
}
})();
// ============================================================
// TOXICOLOGY
// ============================================================
(function() {
document.addEventListener('click', function(e) {
if (e.target.id === 'btn-tox-lookup' || e.target.closest('#btn-tox-lookup')) lookupTox();
});
function lookupTox() {
var wt = parseFloat(document.getElementById('tox-weight').value);
var topic = document.getElementById('tox-topic').value;
var el = document.getElementById('tox-result');
var S = window._EM;
var html = '';
if (topic === 'approach') {
html += S.stepBox('#3b82f6', '1. Stabilize (ABCDE)', 'Airway, breathing, circulation, disability (glucose, pupils, GCS), exposure. Naloxone if depressed LOC + resp depression. Dextrose if hypoglycemic. Thiamine in select cases.');
html += S.stepBox('#8b5cf6', '2. Identify toxidrome', '<strong>Sympathomimetic:</strong> HTN, tachy, mydriasis, diaphoresis (cocaine, meth). <strong>Anticholinergic:</strong> hot/dry, mydriasis, tachy, delirium (antihistamines, TCAs). <strong>Cholinergic:</strong> SLUDGE-M, miosis (organophosphates). <strong>Opioid:</strong> miosis, resp depression, ↓LOC. <strong>Sedative-hypnotic:</strong> ↓LOC, normal/low vitals.');
html += S.stepBox('#f59e0b', '3. Decontamination', '<strong>Activated charcoal</strong> 1 g/kg PO (max 50 g): within 1h of ingestion, intact airway, ingestion adsorbed (not Li, metals, alcohols). Avoid caustics/hydrocarbons. <strong>Whole bowel irrigation:</strong> PEG for metals/iron/lithium/sustained release. <strong>Gastric lavage:</strong> rarely indicated. <strong>Ipecac:</strong> no longer recommended.');
html += S.stepBox('#10b981', '4. Enhance elimination', '<strong>Urinary alkalinization</strong> (salicylates, phenobarbital). <strong>Hemodialysis</strong> (see ISTUMBLE). <strong>Lipid emulsion</strong> for lipid-soluble drug toxicity (LA, CCB, TCA).');
html += S.stepBox('#ef4444', '5. Antidotes', 'See topic list. <strong>Contact Poison Center</strong> (US: 1-800-222-1222) early for any significant exposure.');
} else if (topic === 'acetaminophen') {
html += '<div style="padding:10px 14px;border-radius:8px;background:var(--blue-light);border:1.5px solid var(--blue);margin-bottom:10px;"><strong>Acetaminophen overdose</strong></div>';
html += '<p style="font-size:13px;">Acute toxic dose: &gt;150 mg/kg (or 7.5 g total) single ingestion. Hepatotoxic after 24h; AST/ALT peak day 3-4.</p>';
html += '<p style="font-size:13px;"><strong>Diagnosis:</strong> Draw level at 4h post-ingestion (or on arrival if &gt;4h). Plot on <strong>Rumack-Matthew nomogram</strong> (treatment line at 150 mcg/mL at 4h).</p>';
html += S.drugTable(
S.drugRow('N-acetylcysteine (NAC) — IV', '150 mg/kg over 1h → 50 mg/kg over 4h → 100 mg/kg over 16h (21h total)', 'IV', 'Total 300 mg/kg. Most effective if started &lt;8h post-ingestion.') +
S.drugRow('N-acetylcysteine — PO', '140 mg/kg load, then 70 mg/kg q4h × 17 doses', 'PO', 'Alternative to IV. Unpleasant taste — often with juice.') +
S.drugRow('Activated charcoal', '1 g/kg (max 50 g)', 'PO', 'If within 1-2h of ingestion and airway protected.')
);
if (wt) html += '<div style="padding:10px;background:var(--g50);border-radius:6px;font-size:12px;"><strong>For ' + wt + ' kg:</strong> IV loading = ' + S.d(wt, 150) + ' mg over 1h <span style="color:var(--g500);font-size:11px;">(150 mg/kg)</span>; 2nd bag = ' + S.d(wt, 50) + ' mg over 4h <span style="color:var(--g500);font-size:11px;">(50 mg/kg)</span>; 3rd bag = ' + S.d(wt, 100) + ' mg over 16h <span style="color:var(--g500);font-size:11px;">(100 mg/kg)</span>. <em>Total 300 mg/kg.</em></div>';
} else if (topic === 'opioids') {
html += '<div style="padding:10px 14px;border-radius:8px;background:var(--blue-light);border:1.5px solid var(--blue);margin-bottom:10px;"><strong>Opioid overdose</strong></div>';
html += '<p style="font-size:13px;">Triad: <strong>miosis + respiratory depression + ↓ LOC</strong>. Fentanyl / synthetics may require repeated/higher doses.</p>';
html += S.drugTable(
S.drugRow('Naloxone (initial)', '0.01-0.1 mg/kg' + (wt ? ' = ' + S.d(wt, 0.01) + '-' + S.d(wt, 0.1) + ' mg' : ''), 'IV / IM / IN / IO', 'Start low if chronic opioid use (avoid withdrawal). Titrate to respiratory effort, not consciousness.') +
S.drugRow('Naloxone (full reversal)', '2 mg IV/IM/IN', 'IV / IM / IN', 'If no chronic use and severe resp depression. Repeat q2-3 min.') +
S.drugRow('Naloxone infusion', '2/3 of effective bolus per hour', 'IV', 'For long-acting opioids (methadone, fentanyl patch, sustained release)')
);
html += '<div style="padding:10px;background:#fef3c7;border-radius:6px;font-size:12px;color:#92400e;margin-top:10px;">Observe ≥4h after last dose; longer for long-acting agents. Duration of naloxone (30-90 min) is shorter than most opioids — <strong>re-sedation is common</strong>.</div>';
} else if (topic === 'iron') {
html += '<div style="padding:10px 14px;border-radius:8px;background:var(--blue-light);border:1.5px solid var(--blue);margin-bottom:10px;"><strong>Iron overdose</strong></div>';
html += '<p style="font-size:13px;">Toxic dose: elemental Fe ≥20 mg/kg. Severe ≥60 mg/kg. <strong>Charcoal does NOT bind iron.</strong></p>';
html += '<p style="font-size:13px;"><strong>Stages:</strong> 1) GI (0-6h: vomiting, bloody diarrhea); 2) Latent (6-24h: deceptive improvement); 3) Shock/metabolic acidosis (12-24h); 4) Hepatotoxicity (2-5d); 5) Gastric scarring (2-8 wk).</p>';
html += S.drugTable(
S.drugRow('Whole bowel irrigation', 'PEG-ES 25-40 mL/kg/hr', 'NG', 'For radiopaque pills on KUB or ingested sustained-release iron.') +
S.drugRow('Deferoxamine', '15 mg/kg/hr IV infusion', 'IV', 'Max 6-8 g/day. Indications: shock, metabolic acidosis, Fe level &gt;500 mcg/dL, or severe symptoms. Urine turns "vin rosé" color.')
);
html += '<div style="padding:10px;background:#fef3c7;border-radius:6px;font-size:12px;color:#92400e;margin-top:10px;">Iron level at 4-6h. &lt;350 usually asymptomatic; 350-500 mild; &gt;500 severe. Consider KUB for radiopaque pills.</div>';
} else if (topic === 'tca') {
html += '<div style="padding:10px 14px;border-radius:8px;background:var(--blue-light);border:1.5px solid var(--blue);margin-bottom:10px;"><strong>TCA overdose</strong></div>';
html += '<p style="font-size:13px;">Anticholinergic + Na-channel blockade. <strong>Risks:</strong> seizure, VT/VF, hypotension, coma. ECG: QRS &gt;100 ms or R in aVR &gt;3 mm predicts toxicity.</p>';
html += S.drugTable(
S.drugRow('Sodium bicarbonate 8.4%', '1-2 mEq/kg IV bolus → infusion', 'IV', 'Goal pH 7.45-7.55 and narrowing QRS. Repeat bolus for QRS widening, hypotension, or arrhythmia.') +
S.drugRow('Mg sulfate', S.dStr(wt || 30, 50, 2000, ' mg'), 'IV over 10 min', 'For torsades.') +
S.drugRow('IV lipid emulsion 20%', '1.5 mL/kg bolus → 0.25 mL/kg/min × 30-60 min', 'IV', 'If refractory shock/arrest. Consult toxicology.')
);
html += '<div style="padding:10px;background:#fef3c7;border-radius:6px;font-size:12px;color:#92400e;margin-top:10px;"><strong>Avoid</strong> Class IA/IC antiarrhythmics, beta-blockers, physostigmine (risk of asystole with TCAs).</div>';
} else if (topic === 'bbccb') {
html += '<div style="padding:10px 14px;border-radius:8px;background:var(--blue-light);border:1.5px solid var(--blue);margin-bottom:10px;"><strong>β-blocker / Calcium-channel blocker overdose</strong></div>';
html += '<p style="font-size:13px;">Bradycardia + hypotension. CCBs (esp. verapamil, diltiazem, amlodipine) can be lethal in small pediatric doses.</p>';
html += S.drugTable(
S.drugRow('IV fluids', '20 mL/kg NS bolus', 'IV', 'Cautious — avoid volume overload') +
S.drugRow('Calcium chloride 10% or gluconate', 'CaCl 20 mg/kg / Ca-glu 60 mg/kg', 'IV', 'First-line for CCB. Repeat q15-20 min.') +
S.drugRow('Glucagon', '50 mcg/kg IV bolus → 50-150 mcg/kg/hr', 'IV', 'β-blocker antidote. GI side effects common.') +
S.drugRow('High-dose insulin (HIE)', 'Regular insulin 1 U/kg bolus → 0.5-2 U/kg/hr + D25% infusion', 'IV', 'Hyperinsulinemic euglycemia therapy. Monitor K+ and glucose closely.') +
S.drugRow('Vasopressors', 'Epi / norepi infusion', 'IV', 'Titrate to MAP.') +
S.drugRow('Lipid emulsion 20%', '1.5 mL/kg → 0.25 mL/kg/min', 'IV', 'For lipid-soluble CCBs (verapamil) if refractory.') +
S.drugRow('Methylene blue / ECMO', '—', '—', 'Rescue therapy — toxicology/ICU consult.')
);
} else if (topic === 'benzo') {
html += '<div style="padding:10px 14px;border-radius:8px;background:var(--blue-light);border:1.5px solid var(--blue);margin-bottom:10px;"><strong>Benzodiazepine overdose</strong></div>';
html += '<p style="font-size:13px;">Sedation + resp depression. Usually supportive — intubation rarely needed alone. <strong>Flumazenil caution.</strong></p>';
html += S.drugTable(
S.drugRow('Flumazenil', '0.01 mg/kg (max 0.2 mg) IV, may repeat q1 min to max 1 mg', 'IV', 'Only for iatrogenic reversal in a benzo-naive patient with no TCAs, seizure disorder, or chronic benzo use. <strong>Can precipitate seizures.</strong>')
);
html += '<div style="padding:10px;background:#fef3c7;border-radius:6px;font-size:12px;color:#92400e;margin-top:10px;">In real-world ingestion, <strong>supportive care (airway, monitoring)</strong> is usually safer than flumazenil.</div>';
} else if (topic === 'organo') {
html += '<div style="padding:10px 14px;border-radius:8px;background:var(--blue-light);border:1.5px solid var(--blue);margin-bottom:10px;"><strong>Organophosphate / carbamate poisoning</strong></div>';
html += '<p style="font-size:13px;">Cholinergic toxidrome: <strong>SLUDGE-M</strong> (salivation, lacrimation, urination, defecation, GI distress, emesis, miosis) + muscle fasciculation, bradycardia, bronchorrhea. Decontamination critical (PPE for providers).</p>';
html += S.drugTable(
S.drugRow('Atropine', '0.05 mg/kg IV, double q3-5 min until bronchial secretions dry', 'IV', 'Endpoint = dry lungs, not dry mouth or heart rate. Can require huge doses.') +
S.drugRow('Pralidoxime (2-PAM)', '25-50 mg/kg IV over 30 min (max 2 g) → 10-20 mg/kg/hr', 'IV', 'Only for organophosphates (not carbamates). Regenerates acetylcholinesterase.') +
S.drugRow('Diazepam / midazolam', 'Standard seizure doses', 'IV', 'For seizures or severe fasciculations.')
);
} else if (topic === 'salicylate') {
html += '<div style="padding:10px 14px;border-radius:8px;background:var(--blue-light);border:1.5px solid var(--blue);margin-bottom:10px;"><strong>Salicylate overdose</strong></div>';
html += '<p style="font-size:13px;">Mixed respiratory alkalosis + anion gap metabolic acidosis. Tinnitus, tachypnea, diaphoresis, hyperthermia. Severe: CNS depression, seizures, pulmonary edema, cerebral edema.</p>';
html += S.drugTable(
S.drugRow('Fluids', 'Aggressive resuscitation', 'IV', 'Dehydration common. Avoid fluid overload (risk of pulmonary edema).') +
S.drugRow('Sodium bicarb', '1-2 mEq/kg IV bolus → drip', 'IV', 'Urinary alkalinization (goal urine pH &gt;7.5). Prevents CNS entry.') +
S.drugRow('Glucose', 'Maintain euglycemia even if BG normal', 'IV', 'CNS hypoglycemia despite normal serum glucose.') +
S.drugRow('Hemodialysis', '—', '—', 'For severe: altered MS, pulmonary edema, renal failure, refractory acidosis, or level &gt;100 mg/dL acute / &gt;60 chronic.')
);
} else if (topic === 'etoh') {
html += '<div style="padding:10px 14px;border-radius:8px;background:var(--blue-light);border:1.5px solid var(--blue);margin-bottom:10px;"><strong>Toxic alcohols (methanol / ethylene glycol)</strong></div>';
html += '<p style="font-size:13px;">Anion gap metabolic acidosis + osmolar gap. Methanol → visual changes, blindness. Ethylene glycol → calcium oxalate crystals in urine, renal failure.</p>';
html += S.drugTable(
S.drugRow('Fomepizole', '15 mg/kg IV load → 10 mg/kg q12h × 4 → 15 mg/kg q12h', 'IV', 'First-line. Inhibits alcohol dehydrogenase.') +
S.drugRow('Ethanol (alternative)', 'Load 600 mg/kg → maintain level 100-150 mg/dL', 'IV / PO', 'If fomepizole unavailable. Monitor closely.') +
S.drugRow('Hemodialysis', '—', '—', 'For severe acidosis, end-organ damage, or high levels.') +
S.drugRow('Folate / thiamine / pyridoxine', 'Standard doses', 'IV', 'Methanol: folate. EG: thiamine + pyridoxine (divert to non-toxic metabolites).')
);
} else if (topic === 'dialyzable') {
html += '<div style="padding:10px 14px;border-radius:8px;background:var(--blue-light);border:1.5px solid var(--blue);margin-bottom:10px;"><strong>Dialyzable drugs (ISTUMBLE)</strong></div>';
html += '<p style="font-size:13px;">Commonly dialyzable in overdose:</p>';
html += '<div style="display:grid;grid-template-columns:repeat(auto-fit,minmax(200px,1fr));gap:6px;font-size:13px;">';
[['I','Isopropyl alcohol, INH'],['S','Salicylates'],['T','Theophylline, Toxic alcohols'],['U','Uremia-related drugs'],['M','Methanol, Metformin, Methotrexate'],['B','Barbiturates (long-acting)'],['L','Lithium'],['E','Ethylene glycol']].forEach(function(x) {
html += '<div style="padding:8px 10px;background:var(--g50);border-radius:6px;"><strong>' + x[0] + ':</strong> ' + x[1] + '</div>';
});
html += '</div>';
html += '<div style="padding:10px;background:#fef3c7;border-radius:6px;font-size:12px;color:#92400e;margin-top:10px;"><strong>Poor candidates for HD:</strong> Large Vd (TCAs, digoxin, BBs), highly protein-bound (benzos, CCBs), lipid-soluble (opioids, phenothiazines). EXTRIP recommendations are evidence-based — consult toxicology.</div>';
}
html += S.ref('Call Poison Control early: 1-800-222-1222 (US). Refs: Goldfrank\'s Toxicologic Emergencies, EXTRIP workgroup.');
el.innerHTML = html;
}
})();
// ============================================================
// TRAUMA
// ============================================================
(function() {
document.addEventListener('click', function(e) {
if (e.target.id === 'btn-trauma-show' || e.target.closest('#btn-trauma-show')) showTrauma();
});
function showTrauma() {
var wt = parseFloat(document.getElementById('trauma-weight').value);
var el = document.getElementById('trauma-result');
var S = window._EM;
var html = '';
html += '<h5 style="font-size:13px;font-weight:700;color:var(--g700);margin:0 0 6px;">Primary Survey — ABCDE</h5>';
html += S.stepBox('#ef4444', 'A — Airway + c-spine', 'Maintain airway (jaw thrust, suction). <strong>Manual inline stabilization</strong>; apply collar. Intubate if GCS ≤8, inadequate airway, or impending compromise. Avoid succinylcholine if burn/crush/prolonged immobilization.');
html += S.stepBox('#f59e0b', 'B — Breathing', 'SpO2, bilateral breath sounds, chest wall integrity. Identify tension PTX (needle decompression), open PTX (3-sided dressing), flail chest, massive hemothorax.');
html += S.stepBox('#10b981', 'C — Circulation', 'Two large-bore IVs / IO. Control hemorrhage (direct pressure, tourniquet, pelvic binder). ' + (wt ? 'NS or LR 20 mL/kg = ' + S.d(wt, 20) + ' mL bolus.' : 'NS/LR 20 mL/kg bolus.') + ' Consider blood after 40-60 mL/kg crystalloid or in Class III shock.');
html += S.stepBox('#3b82f6', 'D — Disability', 'GCS, pupils, glucose, gross motor. Consider ↑ICP (head up 30°, mannitol 0.5-1 g/kg or hypertonic saline 3% 3-5 mL/kg).');
html += S.stepBox('#8b5cf6', 'E — Exposure + environment', 'Fully expose; prevent hypothermia (warm blankets, fluids).');
html += '<h5 style="font-size:13px;font-weight:700;color:var(--g700);margin:16px 0 6px;">Massive Transfusion Protocol (MTP)</h5>';
html += S.drugTable(
S.drugRow('Ratio', '1:1:1 (pRBC : FFP : platelets)', '—', 'Activate early if ≥40 mL/kg transfused or ongoing hemorrhage. Avoid excessive crystalloid.') +
S.drugRow('Tranexamic acid (TXA)', '15 mg/kg IV (max 1 g) over 10 min → 2 mg/kg/hr × 8h', 'IV', 'Within 3 hr of injury. CRASH-2 / MATIC.') +
S.drugRow('Calcium', '20 mg/kg CaCl or 60 mg/kg Ca-gluconate IV per unit citrated blood', 'IV', 'Citrated blood chelates calcium.')
);
html += '<h5 style="font-size:13px;font-weight:700;color:var(--g700);margin:16px 0 6px;">C-spine clearance (NEXUS / CCR)</h5>';
html += '<div style="padding:10px;background:var(--g50);border-radius:6px;font-size:12px;">Pediatric c-spine decision tools are imperfect. <strong>Imaging if any:</strong> focal neurologic deficit, altered mental status, neck pain / tenderness, torticollis, substantial torso injury, high-risk mechanism (diving, MVC &gt;55 mph, fall &gt;10 ft). Plain films + CT if positive or equivocal.</div>';
html += '<h5 style="font-size:13px;font-weight:700;color:var(--g700);margin:16px 0 6px;">Pediatric shock — signs</h5>';
html += '<div style="padding:10px;background:#fee2e2;border-radius:6px;font-size:12px;color:#991b1b;">Children compensate well — <strong>hypotension is a late finding</strong>. Early signs: tachycardia, cool extremities, weak peripheral pulses, prolonged cap refill (&gt;3 sec), narrowed pulse pressure, altered mentation. Minimum SBP = 70 + (2 × age in years) for ages 1-10.</div>';
html += '<h5 style="font-size:13px;font-weight:700;color:var(--g700);margin:16px 0 6px;">Secondary survey — AMPLE + head-to-toe</h5>';
html += '<div style="padding:10px;background:var(--g50);border-radius:6px;font-size:12px;"><strong>AMPLE:</strong> Allergies, Medications, Past history, Last meal, Events of injury. Head-to-toe exam; log-roll for back; digital rectal; neurovascular checks of all extremities.</div>';
html += S.ref('ATLS 10th ed; PALS 2020; PECARN c-spine rule; CRASH-2 trial (TXA).');
el.innerHTML = html;
}
})();
// ============================================================
// APGAR SCORE (inside Neonatal)
// ============================================================
(function() {
document.addEventListener('click', function(e) {
if (e.target.id === 'btn-apgar-calc' || e.target.closest('#btn-apgar-calc')) calcApgar();
});
function calcApgar() {
var keys = ['appearance','pulse','grimace','activity','respiration'];
var total = keys.reduce(function(s, k) {
return s + (parseInt(document.getElementById('apgar-' + k).value) || 0);
}, 0);
var el = document.getElementById('apgar-result');
var color, severity, guidance;
if (total >= 7) {
color = '#10b981'; severity = 'Reassuring';
guidance = 'Routine newborn care. Continue reassessment. Repeat at 5 min.';
} else if (total >= 4) {
color = '#f59e0b'; severity = 'Moderately depressed';
guidance = 'Stimulate, clear airway, warm. Give O2 if cyanotic. Ventilate with PPV if HR &lt;100 or apneic/gasping. Reassess q30 sec.';
} else {
color = '#ef4444'; severity = 'Severely depressed';
guidance = 'Full NRP pathway — PPV immediately. Intubate if PPV ineffective. Chest compressions if HR &lt;60. Epinephrine and volume per NRP.';
}
var html = '<div style="padding:10px 14px;border-radius:8px;background:' + color + '10;border:1.5px solid ' + color + ';">';
html += '<strong style="color:' + color + ';font-size:16px;">Apgar: ' + total + '/10 — ' + severity + '</strong>';
html += '<div style="font-size:12px;color:var(--g700);margin-top:6px;line-height:1.5;">' + guidance + '</div></div>';
html += '<p style="font-size:11px;color:var(--g400);margin-top:8px;font-style:italic;">Apgar is a description of status — <strong>never</strong> delay resuscitation while scoring. Follow NRP algorithm based on HR and breathing. Apgar &lt;7 at 5 min: repeat q5 min up to 20 min.</p>';
el.innerHTML = html;
}
})();
// ============================================================
// O2 & VENTILATION (teaching reference)
// ============================================================
(function() {
document.addEventListener('click', function(e) {
if (e.target.id === 'btn-vent-show' || e.target.closest('#btn-vent-show')) showVent();
});
function showVent() {
var wt = parseFloat(document.getElementById('vent-weight').value);
var age = parseFloat(document.getElementById('vent-age').value);
var el = document.getElementById('vent-result');
var S = window._EM;
var html = '';
// ── Target SpO2 quick reference ──
html += '<h5 style="font-size:13px;font-weight:700;color:var(--g700);margin:0 0 6px;">Target SpO2</h5>';
html += '<div style="overflow-x:auto;-webkit-overflow-scrolling:touch;margin-bottom:14px;"><table style="width:100%;min-width:460px;border-collapse:collapse;font-size:12px;">';
html += '<thead><tr style="background:var(--g100);"><th style="text-align:left;padding:5px 8px;">Patient</th><th style="text-align:left;padding:5px 8px;">Target</th><th style="text-align:left;padding:5px 8px;">Notes</th></tr></thead><tbody>';
html += '<tr><td style="padding:5px 8px;border-bottom:1px solid var(--g100);">Most children</td><td style="padding:5px 8px;border-bottom:1px solid var(--g100);"><strong>94-98%</strong></td><td style="padding:5px 8px;border-bottom:1px solid var(--g100);">Normal</td></tr>';
html += '<tr><td style="padding:5px 8px;border-bottom:1px solid var(--g100);">Bronchiolitis (AAP 2014/2023)</td><td style="padding:5px 8px;border-bottom:1px solid var(--g100);"><strong>≥90%</strong></td><td style="padding:5px 8px;border-bottom:1px solid var(--g100);">Don\'t chase higher saturations</td></tr>';
html += '<tr><td style="padding:5px 8px;border-bottom:1px solid var(--g100);">Chronic lung disease / CF</td><td style="padding:5px 8px;border-bottom:1px solid var(--g100);"><strong>90-94%</strong></td><td style="padding:5px 8px;border-bottom:1px solid var(--g100);">Avoid hyperoxia in CO2 retainers</td></tr>';
html += '<tr><td style="padding:5px 8px;border-bottom:1px solid var(--g100);">Preterm neonate</td><td style="padding:5px 8px;border-bottom:1px solid var(--g100);"><strong>90-95%</strong></td><td style="padding:5px 8px;border-bottom:1px solid var(--g100);">Minimize ROP risk</td></tr>';
html += '<tr><td style="padding:5px 8px;border-bottom:1px solid var(--g100);">Term neonate (min of life)</td><td style="padding:5px 8px;border-bottom:1px solid var(--g100);"><strong>Per NRP ladder</strong></td><td style="padding:5px 8px;border-bottom:1px solid var(--g100);">1 min 60-65%, 10 min 85-95%</td></tr>';
html += '</tbody></table></div>';
// ── Escalation ladder ──
html += '<h5 style="font-size:13px;font-weight:700;color:var(--g700);margin:14px 0 6px;">Escalation ladder (step up when target not reached / work of breathing)</h5>';
html += S.stepBox('#10b981',
'1. Nasal cannula (low-flow)',
'<strong>0.5-6 L/min</strong> &nbsp;·&nbsp; FiO2 ~24-40% (rough: room air 21% + 4% per L/min) &nbsp;·&nbsp; comfortable, no humidification needed. Good for mild hypoxia or baseline support.');
html += S.stepBox('#3b82f6',
'2. Simple face mask',
'<strong>6-10 L/min</strong> &nbsp;·&nbsp; FiO2 35-60%. Must keep flow &gt;6 L/min to flush CO2. Tolerated less well than NC.');
html += S.stepBox('#8b5cf6',
'3. Non-rebreather mask',
'<strong>10-15 L/min</strong> &nbsp;·&nbsp; FiO2 60-90%. Reservoir bag must stay inflated. For severe hypoxia with intact breathing.');
html += S.stepBox('#f59e0b',
'4. High-flow nasal cannula (HFNC)',
'<strong>' + (wt ? '1-2 L/kg/min = ' + S.d(wt, 1) + '-' + S.d(wt, 2) + ' L/min' : '1-2 L/kg/min') + '</strong> (max ~50-60 L/min adults) &nbsp;·&nbsp; heated + humidified &nbsp;·&nbsp; FiO2 30-100% titratable &nbsp;·&nbsp; generates ~2-5 cmH2O PEEP &nbsp;·&nbsp; works for bronchiolitis, early resp failure. Reassess at 1-2 h — no improvement → step up.');
html += S.stepBox('#ef4444',
'5. Non-invasive ventilation (CPAP / BiPAP)',
'<strong>CPAP</strong> 5-10 cmH2O (pure PEEP) &nbsp;·&nbsp; <strong>BiPAP</strong> IPAP 10-14 / EPAP 5 (adds pressure support) &nbsp;·&nbsp; FiO2 as needed. Needs cooperative patient, intact airway reflexes, no copious secretions. Contraindicated: coma, apnea, unstable hemodynamics, facial trauma.');
html += S.stepBox('#dc2626',
'6. Intubate + mechanical ventilation',
'When NIV fails, airway compromised, apnea, or GCS ≤8. See RSI under the Airway tab for drugs.');
// ── BVM how-to ──
html += '<h5 style="font-size:13px;font-weight:700;color:var(--g700);margin:14px 0 6px;">Bag-Valve-Mask (BVM)</h5>';
html += '<div style="padding:10px 12px;background:var(--blue-light);border-radius:6px;font-size:12px;line-height:1.6;">';
html += '<strong>When:</strong> apnea, bradycardia (HR &lt;60 in neonate; inadequate breathing at any age), during resuscitation.<br>';
html += '<strong>Rate:</strong> Newborn 40-60 /min &nbsp;·&nbsp; Infant-child 20-30 /min &nbsp;·&nbsp; Adolescent 10-12 /min (1 breath q5-6 sec).<br>';
html += '<strong>Tidal volume:</strong> 6-8 mL/kg — only enough to see <strong>gentle chest rise</strong>. Avoid over-ventilation (gastric distension, ↓venous return, lung injury).<br>';
html += '<strong>Technique:</strong> head tilt / jaw thrust, proper mask seal (E-C grip or 2-thumb), squeeze 1 sec, release fully before next breath. Attach O2 at 10-15 L/min + reservoir.<br>';
html += '<strong>If not ventilating:</strong> MR SOPA — <u>M</u>ask reseal, <u>R</u>eposition airway, <u>S</u>uction mouth+nose, <u>O</u>pen mouth, <u>P</u>ressure ↑, <u>A</u>lternative airway (LMA or ETT).';
html += '</div>';
// ── Mechanical vent settings ──
html += '<h5 style="font-size:13px;font-weight:700;color:var(--g700);margin:14px 0 6px;">Mechanical ventilator — starting settings</h5>';
var rate = age == null ? '' : (age < 0.1 ? '30-40' : age < 1 ? '25-35' : age < 5 ? '20-25' : age < 12 ? '16-20' : '12-16');
html += '<div style="padding:10px 12px;background:var(--g50);border-radius:6px;font-size:12px;line-height:1.65;">';
html += '<strong>Mode:</strong> Volume-control (set TV, get pressure) OR Pressure-control (set pressure, get TV). PRVC / SIMV-PS are hybrids. Pick what your unit uses.<br>';
html += '<strong>Tidal volume:</strong> <strong>' + (wt ? S.d(wt, 6) + '-' + S.d(wt, 8) + ' mL' : '6-8 mL/kg') + '</strong> <span style="color:var(--g500);font-size:11px;">(6-8 mL/kg)</span>. Use lower (4-6 mL/kg) for ARDS.<br>';
html += '<strong>Rate:</strong> ' + (rate ? rate + ' /min (for age ' + age + ' yr)' : 'Newborn 30-40 · Infant 25-35 · Child 16-20 · Adolescent 12-16') + '.<br>';
html += '<strong>PEEP:</strong> start <strong>5 cmH2O</strong> (routine). Increase to 8-12+ for refractory hypoxia (ARDS).<br>';
html += '<strong>FiO2:</strong> start 100%, wean rapidly to lowest that maintains target SpO2 (usually &lt;60%).<br>';
html += '<strong>I:E ratio:</strong> 1:2 normally. 1:3-4 for obstructive disease (asthma, bronchiolitis) to allow exhalation.<br>';
html += '<strong>Inspiratory time:</strong> 0.5 s infant &nbsp;·&nbsp; 0.7-1 s child &nbsp;·&nbsp; 1-1.2 s adolescent.<br>';
html += '<strong>Pressure limits:</strong> keep plateau &lt;30 cmH2O (ideally &lt;28) to avoid barotrauma.';
html += '</div>';
// ── Pressure-time waveform ──
html += '<h5 style="font-size:13px;font-weight:700;color:var(--g700);margin:14px 0 6px;">Pressure-time waveform (what the monitor shows)</h5>';
html += '<div style="padding:10px;background:white;border:1px solid var(--g200);border-radius:8px;margin-bottom:14px;">';
html += '<svg viewBox="0 0 540 260" xmlns="http://www.w3.org/2000/svg" style="width:100%;max-width:640px;display:block;margin:0 auto;">' +
// grid lines
'<line x1="60" y1="60" x2="500" y2="60" stroke="#f3f4f6"/>' +
'<line x1="60" y1="100" x2="500" y2="100" stroke="#f3f4f6"/>' +
'<line x1="60" y1="140" x2="500" y2="140" stroke="#f3f4f6"/>' +
'<line x1="60" y1="180" x2="500" y2="180" stroke="#f3f4f6"/>' +
// axes
'<line x1="60" y1="220" x2="500" y2="220" stroke="#374151" stroke-width="1.5"/>' +
'<line x1="60" y1="20" x2="60" y2="220" stroke="#374151" stroke-width="1.5"/>' +
// y-axis tick labels (cmH2O)
'<text x="55" y="64" font-size="10" text-anchor="end" fill="#6b7280">30</text>' +
'<text x="55" y="104" font-size="10" text-anchor="end" fill="#6b7280">20</text>' +
'<text x="55" y="144" font-size="10" text-anchor="end" fill="#6b7280">10</text>' +
'<text x="55" y="184" font-size="10" text-anchor="end" fill="#6b7280">5</text>' +
'<text x="55" y="224" font-size="10" text-anchor="end" fill="#6b7280">0</text>' +
// axis titles
'<text x="275" y="250" font-size="11" text-anchor="middle" fill="#374151">Time (seconds)</text>' +
'<text x="18" y="120" font-size="11" text-anchor="middle" fill="#374151" transform="rotate(-90 18 120)">Pressure (cmH₂O)</text>' +
// x-axis time markers
'<text x="60" y="238" font-size="10" text-anchor="middle" fill="#6b7280">0</text>' +
'<text x="200" y="238" font-size="10" text-anchor="middle" fill="#6b7280">2</text>' +
'<text x="340" y="238" font-size="10" text-anchor="middle" fill="#6b7280">4</text>' +
'<text x="480" y="238" font-size="10" text-anchor="middle" fill="#6b7280">6</text>' +
// PEEP reference dashed line (y=180 = 5 cmH2O)
'<line x1="60" y1="180" x2="500" y2="180" stroke="#10b981" stroke-width="1" stroke-dasharray="4,3" opacity="0.5"/>' +
// Pressure curve — 3 breaths, each 2s (Ti=0.8s, Te=1.2s); 70px/sec; PEEP=5→y=180, PIP=25→y=80, Plateau=22→y=88
'<path d="M 60 180 L 80 180 L 90 80 L 145 88 L 155 180 L 200 180 L 210 80 L 265 88 L 275 180 L 340 180 L 350 80 L 405 88 L 415 180 L 480 180" fill="none" stroke="#3b82f6" stroke-width="2.5" stroke-linejoin="round"/>' +
// PIP label
'<line x1="120" y1="50" x2="92" y2="78" stroke="#ef4444"/>' +
'<text x="125" y="48" font-size="11" font-weight="bold" fill="#ef4444">PIP</text>' +
'<text x="125" y="60" font-size="9" fill="#6b7280">peak inspiratory</text>' +
// Plateau label
'<line x1="230" y1="50" x2="145" y2="88" stroke="#a855f7"/>' +
'<text x="235" y="48" font-size="11" font-weight="bold" fill="#a855f7">Plateau</text>' +
'<text x="235" y="60" font-size="9" fill="#6b7280">reflects alveolar pressure</text>' +
// PEEP label
'<line x1="380" y1="208" x2="345" y2="182" stroke="#10b981"/>' +
'<text x="385" y="208" font-size="11" font-weight="bold" fill="#10b981">PEEP</text>' +
// Ti bracket (x=90 to 155)
'<line x1="90" y1="32" x2="155" y2="32" stroke="#f59e0b" stroke-width="1"/>' +
'<line x1="90" y1="28" x2="90" y2="36" stroke="#f59e0b"/>' +
'<line x1="155" y1="28" x2="155" y2="36" stroke="#f59e0b"/>' +
'<text x="122" y="25" font-size="10" font-weight="bold" text-anchor="middle" fill="#f59e0b">Ti</text>' +
// Te bracket (x=155 to 200)
'<line x1="155" y1="202" x2="200" y2="202" stroke="#f59e0b" stroke-width="1"/>' +
'<line x1="155" y1="198" x2="155" y2="206" stroke="#f59e0b"/>' +
'<line x1="200" y1="198" x2="200" y2="206" stroke="#f59e0b"/>' +
'<text x="177" y="215" font-size="10" font-weight="bold" text-anchor="middle" fill="#f59e0b">Te</text>' +
'</svg>';
html += '<div style="font-size:11px;color:var(--g500);margin-top:8px;line-height:1.5;"><strong style="color:#ef4444;">PIP</strong> = peak pressure during inspiration (depends on TV, airway resistance, lung compliance). <strong style="color:#a855f7;">Plateau</strong> = static pressure at end-inspiration with brief breath-hold (reflects alveolar pressure — keep &lt;30). <strong style="color:#10b981;">PEEP</strong> = baseline end-expiratory pressure keeping alveoli open. <strong style="color:#f59e0b;">Ti / Te</strong> = inspiratory / expiratory time. Rate &times; (Ti+Te) = 60 s.</div>';
html += '</div>';
// ── Troubleshooting: "if this, change that" ──
html += '<h5 style="font-size:13px;font-weight:700;color:var(--g700);margin:14px 0 6px;">Adjusting for gas exchange</h5>';
html += '<div style="overflow-x:auto;-webkit-overflow-scrolling:touch;"><table style="width:100%;min-width:480px;border-collapse:collapse;font-size:12px;">';
html += '<thead><tr style="background:var(--g100);"><th style="text-align:left;padding:5px 8px;">Problem</th><th style="text-align:left;padding:5px 8px;">First lever</th><th style="text-align:left;padding:5px 8px;">Second lever</th></tr></thead><tbody>';
html += '<tr><td style="padding:5px 8px;border-bottom:1px solid var(--g100);"><strong>Low SpO2</strong> (oxygenation)</td><td style="padding:5px 8px;border-bottom:1px solid var(--g100);">↑ FiO2</td><td style="padding:5px 8px;border-bottom:1px solid var(--g100);">↑ PEEP (recruits collapsed alveoli)</td></tr>';
html += '<tr><td style="padding:5px 8px;border-bottom:1px solid var(--g100);"><strong>↑ PCO2</strong> (ventilation)</td><td style="padding:5px 8px;border-bottom:1px solid var(--g100);">↑ Rate</td><td style="padding:5px 8px;border-bottom:1px solid var(--g100);">↑ Tidal volume</td></tr>';
html += '<tr><td style="padding:5px 8px;border-bottom:1px solid var(--g100);"><strong>↓ PCO2</strong> (over-ventilating)</td><td style="padding:5px 8px;border-bottom:1px solid var(--g100);">↓ Rate</td><td style="padding:5px 8px;border-bottom:1px solid var(--g100);">↓ Tidal volume</td></tr>';
html += '<tr><td style="padding:5px 8px;border-bottom:1px solid var(--g100);"><strong>High peak pressure</strong></td><td style="padding:5px 8px;border-bottom:1px solid var(--g100);">Check tube (kink, mucus plug), compliance, bronchospasm</td><td style="padding:5px 8px;border-bottom:1px solid var(--g100);">Suction, bronchodilator, lower TV</td></tr>';
html += '<tr><td style="padding:5px 8px;border-bottom:1px solid var(--g100);"><strong>Auto-PEEP</strong> (asthma, bronchiolitis)</td><td style="padding:5px 8px;border-bottom:1px solid var(--g100);">↓ Rate, ↑ expiratory time</td><td style="padding:5px 8px;border-bottom:1px solid var(--g100);">Disconnect + bag briefly if critical</td></tr>';
html += '</tbody></table></div>';
// ── Mental model summary ──
html += '<div style="margin-top:14px;padding:10px 12px;background:#d1fae5;border-radius:6px;font-size:12px;color:#065f46;line-height:1.55;"><strong>Mental model:</strong> Oxygenation is mostly <strong>FiO2 + PEEP</strong>. Ventilation (CO2) is mostly <strong>rate + tidal volume</strong>. Match mode to disease: obstructive (asthma, bronchiolitis) → long expiratory time, permissive hypercapnia. Restrictive (ARDS) → low TV, high PEEP, permissive hypercapnia + hypoxia.</div>';
html += S.ref('Based on AAP / PALS / AARC guidance. Tailor to individual patient and institutional protocols.');
el.innerHTML = html;
}
})();