pediatric-ai-scribe-v3/public/js/peGuide.js
Daniel 33bfc0bfbc feat(pe-guide): teaching-focused redesign — grading scales, pearls, significance
User feedback: the exam steps were too generic (e.g. "Shoulder abduction
— 5/5 bilaterally" never explained what 5/5 means or HOW to test it).
The guide needs to serve as a teaching tool, not just a checkbox list.

Three changes:

1. GRADING SCALES reference card (new). Collapsible panel at the top of
   each system showing the relevant scales:
   - Neuro: MRC strength (0-5), DTR (0-4+), Plantar response
   - MSK: Scoliometer ATR, Beighton hypermobility score
   Each scale shows the grade AND its clinical meaning in a compact
   table. No more orphan "5/5 bilaterally" without definition.

2. Per-component SIGNIFICANCE + PEARL fields (optional). Adolescent
   neuro components enriched with:
   - Significance: one-line clinical relevance (what this component is
     actually for — what pathologies it detects)
   - Teaching pearl: a Hutchison/Bates/Nelson-style tip that helps the
     learner see past the mechanics to the reasoning
   Visually distinct — pearl gets a warm amber accent, significance is
   a crosshair icon under the name.

3. Method strings REWRITTEN for every adolescent strength step. Before:
   "Shoulder abduction — 5/5 bilaterally". After: "Patient abducts both
   arms to 90°. Examiner pushes down on each arm just above the elbow
   while patient resists. Compare sides. — Holds against full resistance
   — MRC 5/5 bilaterally". Same treatment for all 14 strength steps,
   all 8 DTR steps, and tone/pronator-drift.

UI redesign:
- Accent bars on cards (cyan for MSK, purple for neuro) for visual
  anchor
- Numbered step circles instead of "1." prefix
- HOW / NORMAL label badges on each step
- Watch-for block with red left-border for red-flag grouping
- System-level header with icon (bone for MSK, brain for neuro)

Other age groups (newborn through school-age) keep the old data shape
(steps without pearls) — they still render correctly, just without the
pearl/significance blocks. Enriching them is an incremental follow-up.
2026-04-22 19:35:03 +02:00

960 lines
79 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.

// ============================================================
// PHYSICAL EXAM GUIDE — step-by-step OSCE reference + report generator
// ============================================================
// Sources for the exam content:
// - Bates' Guide to Physical Examination, 13th edition (technique)
// - Nelson Textbook of Pediatrics, 22nd edition (age-specific content)
// - Hutchison's Clinical Methods, 25th edition (systematic approach)
// - Developmental reflex timing: Fenichel Clinical Pediatric Neurology, 8th ed
//
// Data model:
// PE_DATA[ageGroup][system] = { overview, components: [{ name, steps: [{label, method, normal}], abnormalHints }] }
// Each step has its own Normal / Abnormal / Skip toggle so the physician
// ticks the exam off step-by-step and flags specific abnormal findings.
// Report generation (POST /api/generate-pe-narrative) receives the flat
// step array and produces a Technique + Findings narrative.
// ============================================================
(function () {
// ────────────────────────────────────────────────────────────
// GRADING SCALES — universal reference shown at top of each system
// ────────────────────────────────────────────────────────────
var SCALES = {
mrc: {
title: 'MRC strength grade (05)',
icon: 'fa-hand-fist',
rows: [
['5', 'Normal power — holds against full resistance'],
['4', 'Reduced — moves against gravity + some resistance'],
['3', 'Moves against gravity only (no added resistance)'],
['2', 'Full range with gravity eliminated (horizontal plane)'],
['1', 'Flicker / trace contraction, no joint movement'],
['0', 'No contraction']
]
},
dtr: {
title: 'Deep-tendon reflex grade (04+)',
icon: 'fa-circle-dot',
rows: [
['0', 'Absent'],
['1+', 'Hypoactive — trace, only with reinforcement'],
['2+', 'Normal'],
['3+', 'Brisk — may still be normal in anxious patients'],
['4+', 'Hyperactive with sustained clonus — always abnormal']
]
},
plantar: {
title: 'Plantar response (Babinski)',
icon: 'fa-shoe-prints',
rows: [
['Down-going', 'Normal in anyone ≥ 2 years'],
['Up-going', 'Normal < 2 years; abnormal after — UMN lesion'],
['Asymmetric', 'Always abnormal at any age']
]
},
beighton: {
title: 'Beighton hypermobility score (09)',
icon: 'fa-hands',
rows: [
['≤ 3', 'Normal flexibility'],
['4', 'Borderline — consider in context'],
['≥ 5', 'Hypermobility spectrum; screen for hEDS if other features present']
]
},
atr: {
title: 'Scoliometer — angle of trunk rotation',
icon: 'fa-ruler',
rows: [
['< 5°', 'Normal, no follow-up'],
['56°', 'Borderline — re-check at each visit'],
['≥ 7°', 'Refer for PA/lateral spine x-ray + orthopedic evaluation']
]
}
};
// Which scales are relevant per system
var SYSTEM_SCALES = {
msk: ['atr', 'beighton'],
neuro: ['mrc', 'dtr', 'plantar']
};
// ────────────────────────────────────────────────────────────
// DATA
// ────────────────────────────────────────────────────────────
var PE_DATA = {
newborn: {
label: 'Newborn (028 days)',
msk: {
overview: 'Exam done warm, quiet, undressed. Focus: birth injury, DDH, congenital anomaly. All steps symmetric.',
components: [
{ name: 'Resting posture', steps: [
{ label: 'Observe posture', method: 'Place supine and undisturbed for 30s', normal: 'Symmetric flexion at hips, knees, elbows' },
{ label: 'Hand position', method: 'Inspect resting hands', normal: 'Loosely fisted; opens intermittently' },
{ label: 'Symmetry', method: 'Compare left vs right side at rest', normal: 'Mirror-image posture' }
], abnormalHints: ['Frog-leg (hypotonia)', 'Asymmetric arm (brachial plexus/clavicle fx)', 'Opisthotonos (CNS)', 'Persistent fisting with thumb in palm'] },
{ name: 'Clavicles', steps: [
{ label: 'Palpate right clavicle', method: 'Trace from sternoclavicular joint to acromion with index finger', normal: 'Smooth, continuous, no step-off' },
{ label: 'Palpate left clavicle', method: 'Same technique on left side', normal: 'Smooth, continuous' },
{ label: 'Crepitus check', method: 'Light pressure along length of clavicle while gently abducting arm', normal: 'No crepitus, no pain response' }
], abnormalHints: ['Palpable step-off or callus (fracture — LGA, shoulder dystocia)', 'Asymmetric Moro on affected side'] },
{ name: 'Hips — DDH screen', steps: [
{ label: 'Thigh/gluteal folds', method: 'Undress completely; compare skin-fold symmetry', normal: 'Symmetric thigh and gluteal folds' },
{ label: 'Abduction', method: 'Flex hips 90°, abduct simultaneously', normal: 'Both hips abduct to ≥75° symmetrically' },
{ label: 'Barlow maneuver', method: 'Thumb on medial thigh, flex hip 90°, adduct, apply gentle posterior pressure', normal: 'No clunk or movement felt (negative)' },
{ label: 'Ortolani maneuver', method: 'From Barlow position: abduct and lift with fingers on greater trochanter', normal: 'No clunk as hip returns (negative)' },
{ label: 'Galeazzi sign', method: 'Knees flexed together with feet on table; compare knee heights', normal: 'Knees level — no leg-length discrepancy' }
], abnormalHints: ['Palpable Ortolani clunk (dislocated, reducible)', 'Barlow clunk (dislocatable)', 'Limited abduction', 'Positive Galeazzi (shortened femur)'] },
{ name: 'Spine and back', steps: [
{ label: 'Position prone', method: 'Turn infant prone, support chest', normal: 'Tolerates position, lifts head briefly' },
{ label: 'Palpate midline', method: 'Run finger from C-spine to coccyx', normal: 'Straight midline, no step-offs or gaps' },
{ label: 'Sacral inspection', method: 'Inspect sacral dimple if present; measure depth, distance from anus', normal: 'No dimple, or dimple <5mm deep and <2.5cm from anus' },
{ label: 'Cutaneous markers', method: 'Inspect midline skin from neck to coccyx', normal: 'No hair tuft, hemangioma, lipoma, or sinus tract' }
], abnormalHints: ['Deep sacral dimple (>5mm) or >2.5cm from anus — imaging', 'Hair tuft, hemangioma, lipoma (occult dysraphism)', 'Palpable defect'] },
{ name: 'Upper extremities', steps: [
{ label: 'Spontaneous movement', method: 'Observe both arms for 30s', normal: 'Symmetric antigravity movement' },
{ label: 'Digits', method: 'Count and inspect fingers both hands', normal: '5 digits each, no webbing or duplication' },
{ label: 'Palmar creases', method: 'Inspect palmar creases', normal: 'Normal triradiate creases' }
], abnormalHints: ['Erb/Klumpke palsy (paucity of movement)', 'Polydactyly, syndactyly', 'Single transverse (simian) palmar crease'] },
{ name: 'Lower extremities / feet', steps: [
{ label: 'Hip and knee range', method: 'Gently flex, extend, internally/externally rotate each', normal: 'Full symmetric range, no contracture' },
{ label: 'Foot alignment', method: 'Inspect resting foot position', normal: 'Midline or mildly adducted forefoot' },
{ label: 'Passive correction', method: 'Gently attempt to bring foot to neutral', normal: 'Fully correctable to neutral' },
{ label: 'Stroke test', method: 'Stroke lateral border of foot', normal: 'Foot dorsiflexes and everts reflexively' }
], abnormalHints: ['Rigid clubfoot (non-correctable talipes equinovarus)', 'Fixed metatarsus adductus', 'Rocker-bottom foot (trisomy 18)', 'Calcaneovalgus'] }
]
},
neuro: {
overview: 'Primitive reflexes present and symmetric. Tone assessed passively and actively. Full exam 35 min on a quiet, fed infant.',
components: [
{ name: 'Alertness and behavior', steps: [
{ label: 'State cycling', method: 'Observe over 12 min for alert periods', normal: 'Alert periods with spontaneous eye opening' },
{ label: 'Response to voice', method: 'Speak softly near ear', normal: 'Quiets to voice or turns toward sound' },
{ label: 'Consolability', method: 'If crying, attempt to soothe with swaddling or voice', normal: 'Consolable within 12 min' }
], abnormalHints: ['Lethargy', 'Jitteriness not stopped by passive flexion', 'Irritability unrelieved by feeding'] },
{ name: 'Cranial nerves', steps: [
{ label: 'CN II — pupil response', method: 'Shine light in each eye', normal: 'Pupils equal, reactive to light, direct and consensual' },
{ label: 'CN II — blink to light', method: 'Bright light in the line of sight', normal: 'Reflex blink' },
{ label: 'CN VII — facial symmetry at rest', method: 'Observe resting face', normal: 'Symmetric nasolabial folds' },
{ label: 'CN VII — facial symmetry with cry', method: 'Note face during a cry', normal: 'Symmetric grimace' },
{ label: 'CN IX, X, XII — suck and swallow', method: 'Offer clean gloved finger, pacifier, or during feed', normal: 'Strong coordinated suck-swallow, no choking' }
], abnormalHints: ['Asymmetric face (CN VII injury — usually forceps)', 'Poor suck or uncoordinated swallow', 'Fixed or unequal pupil'] },
{ name: 'Tone — passive', steps: [
{ label: 'Pull-to-sit', method: 'Grasp hands/wrists, pull smoothly to sit', normal: 'Brief head lag at term; not dramatic' },
{ label: 'Ventral suspension', method: 'Suspend prone over hand at chest', normal: 'Head briefly lifts to horizontal; extremities flexed' },
{ label: 'Arm recoil', method: 'Extend both arms fully at elbows, release', normal: 'Rapid return to flexion' },
{ label: 'Popliteal angle', method: 'Hip flexed 90°, extend knee maximally', normal: '≤110°' }
], abnormalHints: ['Marked head lag (hypotonia)', 'Slip-through on vertical suspension', 'Hypertonia / scissoring', 'Floppy limbs with no recoil'] },
{ name: 'Spontaneous movement', steps: [
{ label: 'Observe limbs', method: 'Undisturbed over 1 min, note movement', normal: 'Symmetric antigravity movement of all 4 limbs' },
{ label: 'Quality of movement', method: 'Note smoothness vs jitteriness', normal: 'Smooth, mildly variable movements' }
], abnormalHints: ['Paucity of movement in one limb', 'Coarse jitteriness', 'Clonic jerks', 'Tonic posturing'] },
{ name: 'Primitive reflexes', steps: [
{ label: 'Moro', method: 'Support head; allow 30° head drop or loud clap', normal: 'Symmetric arm abduction then flexion, often cry' },
{ label: 'Rooting', method: 'Stroke cheek at corner of mouth', normal: 'Turns head toward stroke and opens mouth' },
{ label: 'Palmar grasp', method: 'Press into palm with finger', normal: 'Strong, symmetric finger flexion' },
{ label: 'Plantar grasp', method: 'Press ball of foot below toes', normal: 'Toes flex around finger symmetrically' },
{ label: 'Stepping', method: 'Hold upright with feet touching surface', normal: 'Alternating stepping movements' },
{ label: 'Tonic neck (fencing)', method: 'Turn head to one side with infant supine', normal: 'Same-side arm extends, opposite flexes (not obligate)' },
{ label: 'Galant', method: 'Stroke paravertebrally from shoulder to buttock, one side', normal: 'Trunk curves toward stroked side' }
], abnormalHints: ['Absent or asymmetric Moro — CNS injury, brachial plexus, clavicle fx', 'Absent grasps — CNS depression', 'Obligate tonic neck is abnormal'] },
{ name: 'Babinski (plantar response)', steps: [
{ label: 'Stroke lateral sole', method: 'Firm stroke from heel toward toes along lateral plantar border', normal: 'Up-going great toe with fanning (normal in newborn)' },
{ label: 'Symmetry check', method: 'Repeat opposite foot', normal: 'Symmetric response' }
], abnormalHints: ['Asymmetric response is always abnormal'] }
]
}
},
infant: {
label: 'Infant (112 months)',
msk: {
overview: 'Continued DDH screen through 6 months. Watch motor progression and symmetry of tone/movement.',
components: [
{ name: 'Hips — continued DDH screen', steps: [
{ label: 'Thigh-fold symmetry', method: 'Inspect with infant supine, thighs flexed', normal: 'Symmetric folds' },
{ label: 'Barlow/Ortolani (through 3mo)', method: 'As in newborn — thumb medial, flex 90°, adduct+push then abduct+lift', normal: 'Negative bilaterally' },
{ label: 'Abduction (any age)', method: 'Flex 90°, abduct simultaneously', normal: '≥70° symmetric abduction' },
{ label: 'Galeazzi', method: 'Knees flexed feet flat on exam table', normal: 'Knees equal height' }
], abnormalHints: ['Clunk on Barlow/Ortolani (<3mo)', 'Limited abduction', 'Asymmetric folds', 'Positive Galeazzi'] },
{ name: 'Gross-motor milestones (age-appropriate)', steps: [
{ label: 'Head control', method: 'Prone, pull-to-sit, held upright', normal: 'Age-appropriate: 2mo lifts head 45°; 4mo no head lag' },
{ label: 'Rolling', method: 'Observe on flat surface', normal: 'Rolls back-to-front by 56mo' },
{ label: 'Sitting', method: 'Place in sitting position', normal: 'Tripod sit by 6mo; sits without support by 78mo' },
{ label: 'Standing', method: 'Support under arms', normal: 'Bears weight by 6mo; pulls to stand by 9mo' }
], abnormalHints: ['Milestone delay by ≥2mo', 'Loss of previously attained milestone', 'Asymmetric use of limbs'] },
{ name: 'Spine', steps: [
{ label: 'Palpate seated', method: 'Run finger along spine with infant sitting or held upright', normal: 'Midline, no step-offs' },
{ label: 'Back curvature', method: 'Inspect sitting and lying', normal: 'Physiologic gentle kyphosis in early infancy; lumbar lordosis as sitting develops' }
], abnormalHints: ['Fixed kyphoscoliosis', 'Sacral dimple with cutaneous marker', 'Step-off'] },
{ name: 'Extremities', steps: [
{ label: 'Passive range', method: 'Through each major joint', normal: 'Full symmetric range' },
{ label: 'Joint inspection', method: 'Inspect for swelling, warmth, effusion', normal: 'No swelling, warmth, or effusion' },
{ label: 'Feet alignment', method: 'Observe standing if pulling up, else passive positioning', normal: 'Correctable or aligned feet; flexible' }
], abnormalHints: ['Joint swelling/warmth (septic vs reactive arthritis)', 'Rigid clubfoot', 'Persistent asymmetric tone'] }
]
},
neuro: {
overview: 'Primitive reflexes fading on schedule; protective reflexes emerging; gross motor and tone interlinked.',
components: [
{ name: 'Alertness and social engagement', steps: [
{ label: 'Social smile', method: 'Face-to-face interaction', normal: 'Social smile by 68 weeks' },
{ label: 'Tracking', method: 'Move object across visual field', normal: '180° horizontal tracking by 3mo' },
{ label: 'Engagement', method: 'Face-to-face, voice, toys', normal: 'Age-appropriate reciprocal interaction' }
], abnormalHints: ['No social smile by 3mo', 'Absent tracking past 3mo', 'Poor engagement (developmental concern)'] },
{ name: 'Cranial nerves', steps: [
{ label: 'Pupils', method: 'Light response each eye', normal: 'Equal reactive' },
{ label: 'Eye alignment', method: 'Inspect with gaze forward and in all directions', normal: 'No strabismus past 4mo' },
{ label: 'Facial symmetry', method: 'Observe smile and cry', normal: 'Symmetric' },
{ label: 'Suck and swallow', method: 'Observe feeding', normal: 'Coordinated, no choking' }
], abnormalHints: ['Persistent nystagmus', 'Strabismus past 4mo', 'Asymmetric face'] },
{ name: 'Tone', steps: [
{ label: 'Pull-to-sit', method: 'Gently pull wrists/hands', normal: 'No head lag by 4mo' },
{ label: 'Ventral suspension', method: 'Support prone, observe', normal: 'Head above horizontal, extremities actively flexed (age-dependent)' },
{ label: 'Vertical suspension', method: 'Support under arms, lift', normal: 'Does not slip through hands' }
], abnormalHints: ['Persistent head lag past 4mo (hypotonia)', 'Hypertonia / scissoring (UMN)', 'Slip-through on vertical suspension'] },
{ name: 'Primitive reflex integration', steps: [
{ label: 'Moro', method: 'Head drop or clap', normal: 'Absent by 6mo' },
{ label: 'Palmar grasp', method: 'Press into palm', normal: 'Integrated by 56mo; replaced by voluntary grasp' },
{ label: 'Tonic neck', method: 'Turn head to side', normal: 'Absent by 6mo' },
{ label: 'Rooting', method: 'Stroke cheek', normal: 'Absent by 34mo' }
], abnormalHints: ['Persistence of any primitive reflex past 6mo warrants eval (CP, CNS injury)'] },
{ name: 'Protective and postural reflexes', steps: [
{ label: 'Parachute', method: 'Held prone, tilt head downward suddenly', normal: 'Symmetric arm extension protectively by 9mo (emerges 69mo)' },
{ label: 'Lateral propping', method: 'Seated infant, gentle tilt to one side', normal: 'Arm extends to catch by 67mo' },
{ label: 'Landau', method: 'Suspend prone', normal: 'Extends head, spine, legs by 6mo' }
], abnormalHints: ['Absent parachute after 12mo (concerning)', 'Asymmetric lateral propping', 'Absent Landau'] }
]
}
},
toddler: {
label: 'Toddler (13 years)',
msk: {
overview: 'Gait, physiologic alignment changes, in-toeing, joint range. Cooperation unpredictable — use play.',
components: [
{ name: 'Gait', steps: [
{ label: 'Base of support', method: 'Have child walk ~10 feet', normal: 'Wide-based initially, narrowing by 2y' },
{ label: 'Heel-strike', method: 'Observe foot contact pattern', normal: 'Heel-strike developing by 18mo, consistent by 2y' },
{ label: 'Arm swing', method: 'Observe reciprocal arm swing', normal: 'Reciprocal arm swing by 18mo' },
{ label: 'Symmetry', method: 'Watch both sides in stance and swing', normal: 'Symmetric stride length and cadence' }
], abnormalHints: ['Toe-walking past 2y (idiopathic vs CP vs DMD)', 'Limp (Legg-Calvé-Perthes, transient synovitis, trauma)', 'Wide-based ataxia'] },
{ name: 'Knee alignment', steps: [
{ label: 'Stand feet together', method: 'Feet/medial malleoli touching; inspect knees', normal: 'Genu varum resolving by 1824mo; mild genu valgum common by 23y' },
{ label: 'Intercondylar or intermalleolar distance', method: 'Measure if alignment appears abnormal', normal: '<5cm intercondylar (varum) or <8cm intermalleolar (valgum)' },
{ label: 'Symmetry', method: 'Compare sides', normal: 'Symmetric' }
], abnormalHints: ['Persistent varum past 2y', 'Severe valgum >8cm', 'Unilateral (Blount disease, rickets)'] },
{ name: 'Feet alignment', steps: [
{ label: 'In-toeing / out-toeing', method: 'Observe foot angle during gait', normal: 'Mild in-toeing common (tibial torsion, femoral anteversion)' },
{ label: 'Arch during stance', method: 'Stand flat, then on tiptoes', normal: 'Flexible flat foot that forms arch on tiptoe' },
{ label: 'Heel alignment', method: 'View from behind standing', normal: 'Neutral or mildly valgus heel' }
], abnormalHints: ['Rigid flat foot (tarsal coalition)', 'Fixed metatarsus adductus', 'Severe in-toeing >15°'] },
{ name: 'Joint range', steps: [
{ label: 'Hips', method: 'Flex, abduct, rotate each hip', normal: 'Full symmetric range, no pain' },
{ label: 'Knees', method: 'Flex, extend; palpate for effusion', normal: 'Full range, no effusion, stable' },
{ label: 'Ankles', method: 'Dorsiflex, plantarflex, invert, evert', normal: 'Full range' },
{ label: 'Shoulders, elbows, wrists', method: 'Through full range each', normal: 'Full symmetric range' }
], abnormalHints: ['Joint effusion (septic vs reactive)', 'Guarded or painful motion', 'Asymmetric limitation'] },
{ name: 'Spine', steps: [
{ label: 'Inspect standing', method: 'View spine from behind', normal: 'Midline, no prominent curve' },
{ label: 'Palpate midline', method: 'Run finger along spinous processes', normal: 'Midline, no step-off, no tenderness' },
{ label: 'Shoulder/hip symmetry', method: 'Compare shoulder and hip heights', normal: 'Symmetric' }
], abnormalHints: ['Fixed scoliosis', 'Abnormal kyphosis', 'Asymmetric shoulder/hip', 'Midline tenderness'] }
]
},
neuro: {
overview: 'Shifting to adult-pattern exam. Primitive reflexes should be absent. Use play-based techniques.',
components: [
{ name: 'Mental status and language', steps: [
{ label: 'Engagement', method: 'Interaction with examiner/parent', normal: 'Alert, interactive, age-appropriate' },
{ label: 'Language — expressive', method: 'Note spontaneous utterances', normal: '1y: 13 words; 2y: 2-word phrases; 3y: short sentences' },
{ label: 'Language — receptive', method: 'Ask to point to body parts or follow simple commands', normal: 'Follows age-appropriate commands' }
], abnormalHints: ['Language regression (autism, epileptic encephalopathy)', 'Poor engagement', 'No 2-word phrases by 2y'] },
{ name: 'Cranial nerves', steps: [
{ label: 'CN II — pupil response', method: 'Shine light each eye', normal: 'Pupils equal reactive' },
{ label: 'CN III, IV, VI — EOM', method: 'Follow toy in H pattern', normal: 'Full smooth tracking, no strabismus' },
{ label: 'CN V — facial sensation', method: 'Light touch on forehead, cheek, jaw', normal: 'Responds to touch, symmetric' },
{ label: 'CN VII — face', method: 'Elicit smile, watch eye closure during cry', normal: 'Symmetric face' },
{ label: 'CN IX, X, XII — mouth', method: 'Say "ahh"; stick out tongue', normal: 'Palate rises symmetrically; tongue midline' }
], abnormalHints: ['Strabismus', 'Facial asymmetry', 'Tongue deviation', 'Absent palate elevation'] },
{ name: 'Motor — tone and bulk', steps: [
{ label: 'Passive tone', method: 'Move each limb through full range', normal: 'Normal resistance throughout' },
{ label: 'Bulk inspection', method: 'Inspect muscle bulk of thighs, calves, glutes', normal: 'Symmetric, age-appropriate bulk' },
{ label: 'Contracture check', method: 'Test for heel-cord tightness, hamstring tightness', normal: 'No contractures' }
], abnormalHints: ['Spasticity (especially catch in ankles)', 'Hypotonia', 'Calf pseudo-hypertrophy (DMD)'] },
{ name: 'Motor — functional strength', steps: [
{ label: 'Rising from floor', method: 'Place flat on back; ask to stand up', normal: 'Rises without using hands to push off thighs (no Gowers)' },
{ label: 'Climbing stairs', method: 'Observe or history', normal: 'Climbs holding rail' },
{ label: 'Squatting/getting up', method: 'Encourage via play', normal: 'Squats and rises without help' }
], abnormalHints: ['Gowers sign (proximal weakness — DMD)', 'Unable to climb stairs at age expected', 'Calf pain on walking (myositis)'] },
{ name: 'Deep tendon reflexes', steps: [
{ label: 'Patellar', method: 'Sitting or supine with distraction (toy)', normal: '2+ symmetric' },
{ label: 'Biceps', method: 'Arm at rest, strike thumb on tendon', normal: '2+ symmetric' },
{ label: 'Achilles', method: 'With distraction', normal: '2+ symmetric' }
], abnormalHints: ['Hyperreflexia or clonus (UMN, CP)', 'Absent reflexes (LMN, neuropathy)', 'Asymmetry'] },
{ name: 'Coordination and gait', steps: [
{ label: 'Run', method: 'Watch run ~10 feet', normal: 'Runs with reciprocal arm swing by 2y' },
{ label: 'Stairs', method: 'Observe', normal: 'Climbs with rail' },
{ label: 'Kick ball', method: 'Place ball; observe kick', normal: 'Kicks by 2y' },
{ label: 'Ataxia check', method: 'Watch for fluency of movement', normal: 'Smooth, no tremor' }
], abnormalHints: ['Ataxic gait', 'Intention tremor', 'Clumsiness beyond age'] },
{ name: 'Plantar response', steps: [
{ label: 'Stroke lateral sole', method: 'Firm stroke from heel to toes', normal: 'Down-going great toe (plantar flexion) by age 2' }
], abnormalHints: ['Up-going toe after age 2 = UMN sign (Babinski positive)'] }
]
}
},
preschool: {
label: 'Preschool (35 years)',
msk: {
overview: 'Functional gait maneuvers, scoliosis screen, resolving physiologic alignment.',
components: [
{ name: 'Gait — multiple patterns', steps: [
{ label: 'Normal gait', method: 'Walk ~15 feet barefoot', normal: 'Symmetric, smooth, reciprocal arm swing' },
{ label: 'Heel walking', method: 'Walk on heels only', normal: 'Able by 4y' },
{ label: 'Toe walking', method: 'Walk on toes only', normal: 'Able by 4y' },
{ label: 'Tandem walking', method: 'Heel-to-toe along a line for 5 steps', normal: 'Able by 4y with minimal deviation' },
{ label: 'Hopping', method: 'Hop on one foot', normal: '35 hops on preferred foot by 4y' }
], abnormalHints: ['Persistent toe-walking', 'Asymmetric stance/stride', 'Difficulty with any pattern'] },
{ name: 'Alignment', steps: [
{ label: 'Knee alignment', method: 'Stand feet together', normal: 'Mild residual valgus resolving; neutral by 67y' },
{ label: 'Foot arch', method: 'Standing, then tiptoe', normal: 'Arch forms on tiptoe (flexible flat foot)' },
{ label: 'Heel position', method: 'View from behind standing', normal: 'Neutral or mild valgus' }
], abnormalHints: ['Persistent unilateral varum', 'Rigid flat foot (no arch on tiptoe)', 'Pes cavus'] },
{ name: 'Scoliosis screen (Adam forward-bend)', steps: [
{ label: 'Position', method: 'Feet together, bend forward at waist, arms hanging, palms together', normal: 'Arms and head relaxed' },
{ label: 'View from behind', method: 'Examiner at same height; look along back', normal: 'Symmetric paraspinal contour' },
{ label: 'View from side', method: 'Side view for kyphosis', normal: 'Smooth thoracic curve' }
], abnormalHints: ['Rib hump (thoracic scoliosis)', 'Lumbar prominence', 'Asymmetric scapular height'] },
{ name: 'Joint range and stability', steps: [
{ label: 'Active range', method: 'Ask to perform full range at hips, knees, ankles, shoulders, elbows, wrists', normal: 'Full symmetric range, no pain' },
{ label: 'Knee stability', method: 'Palpate for effusion; assess stability if complaint', normal: 'Stable, no effusion' },
{ label: 'Carrying angle (elbows)', method: 'Arms at sides, palms forward', normal: 'Normal valgus carrying angle' }
], abnormalHints: ['Joint hypermobility (Beighton score)', 'Effusion', 'Pain with motion', 'Valgus >15°'] },
{ name: 'Feet', steps: [
{ label: 'Standing inspection', method: 'View from front and behind', normal: 'Symmetric feet, neutral heel, flexible flat feet common' },
{ label: 'Tiptoe', method: 'Stand on tiptoes', normal: 'Arch forms, symmetric' },
{ label: 'Pes planus vs cavus', method: 'Note arch height', normal: 'Flexible flat foot or mild arch' }
], abnormalHints: ['Rigid flat foot', 'Pes cavus (Charcot-Marie-Tooth)', 'Pain'] }
]
},
neuro: {
overview: 'Formal pediatric neuro exam now feasible — most 4- and 5-year-olds cooperate with structured testing.',
components: [
{ name: 'Mental status and language', steps: [
{ label: 'Orientation (age-appropriate)', method: 'Ask name, age, where you are', normal: 'Knows name and age by 3y; location by 45y' },
{ label: 'Speech intelligibility', method: 'Listen to spontaneous speech', normal: 'Strangers understand by 4y' },
{ label: 'Receptive language', method: '2- and 3-step commands', normal: 'Follows 3-step commands by 45y' }
], abnormalHints: ['Dysarthria', 'Expressive or receptive language delay', 'Inattention'] },
{ name: 'Cranial nerves (IIXII)', steps: [
{ label: 'CN II — visual acuity', method: 'HOTV chart or pictures at 10ft, each eye', normal: '20/30 or better by 4y; 20/25 by 5y' },
{ label: 'CN II — visual fields', method: 'Confrontation with toys from periphery', normal: 'Full fields' },
{ label: 'CN II — pupils', method: 'Light response each eye', normal: 'PERRL' },
{ label: 'CN III, IV, VI — EOM', method: 'Follow toy in H pattern; include convergence', normal: 'Full EOM, convergence present' },
{ label: 'CN V — sensation', method: 'Light touch forehead, cheek, jaw each side', normal: 'Intact, symmetric' },
{ label: 'CN V — motor', method: 'Clench teeth, palpate masseter', normal: 'Symmetric strong bulk' },
{ label: 'CN VII — face', method: 'Smile, wrinkle forehead, close eyes, puff cheeks', normal: 'Symmetric movement of all regions' },
{ label: 'CN VIII — hearing', method: 'Finger rub each ear or whispered words', normal: 'Intact bilaterally' },
{ label: 'CN IX, X — palate', method: 'Open mouth, say "ahh"', normal: 'Palate rises symmetrically, uvula midline' },
{ label: 'CN XI — SCM/trapezius', method: 'Shrug shoulders, turn head against resistance', normal: 'Symmetric strength' },
{ label: 'CN XII — tongue', method: 'Stick tongue out, move side to side', normal: 'Midline, no atrophy, full movement' }
], abnormalHints: ['Strabismus (amblyopia risk)', 'Facial weakness', 'Tongue deviation/fasciculations', 'Uvula off-midline'] },
{ name: 'Motor — tone, bulk, strength', steps: [
{ label: 'Tone inspection', method: 'Passive range all four limbs', normal: 'Normal tone throughout' },
{ label: 'Bulk inspection', method: 'Observe muscle bulk symmetry', normal: 'Symmetric, age-appropriate' },
{ label: 'Strength — shoulder abduction', method: 'Arms out, push down against resistance', normal: '5/5 bilaterally' },
{ label: 'Strength — elbow flexion', method: 'Flex elbow against resistance', normal: '5/5 bilaterally' },
{ label: 'Strength — grip', method: 'Squeeze examiner\'s fingers', normal: '5/5 symmetric' },
{ label: 'Strength — hip flexion', method: 'Lift leg off table against resistance', normal: '5/5 bilaterally' },
{ label: 'Strength — knee extension', method: 'Straighten knee against resistance', normal: '5/5 bilaterally' },
{ label: 'Strength — dorsiflexion', method: 'Pull toes up against resistance', normal: '5/5 bilaterally' }
], abnormalHints: ['Focal weakness', 'Gowers sign', 'Pseudohypertrophy (DMD)', 'Atrophy'] },
{ name: 'Deep tendon reflexes', steps: [
{ label: 'Biceps', method: 'Thumb on biceps tendon, strike', normal: '2+ symmetric' },
{ label: 'Patellar', method: 'Knees hanging, strike patellar tendon', normal: '2+ symmetric' },
{ label: 'Achilles', method: 'Slight dorsiflexion, strike Achilles tendon', normal: '2+ symmetric' },
{ label: 'Plantar response', method: 'Stroke lateral sole heel-to-toes', normal: 'Down-going great toe' }
], abnormalHints: ['Hyperreflexia or clonus (UMN)', 'Hyporeflexia (LMN)', 'Up-going plantar (Babinski — abnormal past 2y)', 'Asymmetry'] },
{ name: 'Coordination', steps: [
{ label: 'Finger-to-nose', method: 'Touch examiner\'s finger then own nose, repeat', normal: 'Smooth, no dysmetria' },
{ label: 'Heel-to-shin', method: 'Run heel down opposite shin', normal: 'Smooth bilaterally' },
{ label: 'Rapid alternating movements', method: 'Tap palm with opposite hand alternating palm/back', normal: 'Rhythmic, symmetric' },
{ label: 'Tandem walk', method: 'Heel-to-toe for 5 steps', normal: 'Minimal deviation' }
], abnormalHints: ['Dysmetria', 'Dysdiadochokinesia', 'Intention tremor', 'Ataxic tandem'] },
{ name: 'Sensory', steps: [
{ label: 'Light touch — hands', method: 'Cotton wisp on palm/dorsum, eyes closed', normal: 'Feels each touch' },
{ label: 'Light touch — feet', method: 'Same on dorsum of foot bilaterally', normal: 'Feels each touch' }
], abnormalHints: ['Focal sensory loss', 'Stocking-glove loss'] },
{ name: 'Gait and Romberg', steps: [
{ label: 'Normal gait', method: 'Walk ~20 feet', normal: 'Smooth, symmetric' },
{ label: 'Heel walk', method: 'Walk on heels', normal: 'Able without difficulty' },
{ label: 'Toe walk', method: 'Walk on toes', normal: 'Able without difficulty' },
{ label: 'Tandem', method: 'Heel-to-toe', normal: 'Intact' },
{ label: 'Romberg (5y+)', method: 'Feet together, eyes closed, stand 10s', normal: 'Stable without sway' }
], abnormalHints: ['Ataxic gait (cerebellar)', 'Romberg positive (dorsal column)', 'Circumduction (UMN)'] }
]
}
},
school: {
label: 'School-age (611 years)',
msk: {
overview: 'Scoliosis screening peri-puberty, sports overuse injuries, resolving alignment.',
components: [
{ name: 'Scoliosis screen (forward-bend + scoliometer)', steps: [
{ label: 'Standing inspection', method: 'Shoulders and iliac crest heights', normal: 'Symmetric shoulder and pelvic heights' },
{ label: 'Forward bend (Adam test)', method: 'Feet together, bend forward at waist, arms hanging palms together', normal: 'Symmetric paraspinal contour' },
{ label: 'Rib hump', method: 'View tangentially from behind at level of curve', normal: 'No rib hump' },
{ label: 'Lumbar prominence', method: 'Same view at lumbar level', normal: 'No prominence' },
{ label: 'Scoliometer (if available)', method: 'Place scoliometer across rib hump, read angle of trunk rotation', normal: 'ATR < 5°; ≥7° → refer' }
], abnormalHints: ['Rib hump', 'ATR ≥7°', 'Asymmetric shoulders or pelvis', 'Decompensation (plumb line offset)'] },
{ name: 'Back and spine', steps: [
{ label: 'Posture inspection', method: 'Standing, view front/back/side', normal: 'Normal spinal curves; plumb line centered' },
{ label: 'Palpate spinous processes', method: 'From C2 to S1', normal: 'No tenderness, no step-off' },
{ label: 'Range of motion', method: 'Flex, extend, lateral bend, rotate', normal: 'Full painless range' }
], abnormalHints: ['Midline tenderness', 'Step-off (spondylolisthesis)', 'Limited motion with pain'] },
{ name: 'Alignment', steps: [
{ label: 'Knees', method: 'Feet together, inspect', normal: 'Neutral alignment by 67y' },
{ label: 'Feet', method: 'Stand, then tiptoes', normal: 'Medial arch present, symmetric' },
{ label: 'Leg lengths', method: 'Supine, measure ASIS to medial malleolus if asymmetric', normal: 'Equal within 1cm' }
], abnormalHints: ['Residual valgum', 'Pes cavus', 'Leg-length discrepancy >1cm'] },
{ name: 'Joint stability and sports exam (if active)', steps: [
{ label: 'Active range all joints', method: 'Through full range', normal: 'Full symmetric range, no pain or crepitus' },
{ label: 'Knee — Lachman (if sports-active)', method: 'Knee 20° flexion, stabilize femur, pull tibia forward', normal: 'Firm endpoint, no laxity' },
{ label: 'Knee — McMurray', method: 'Flexed knee, rotate tibia while extending', normal: 'No pain or click' },
{ label: 'Shoulder — impingement (Neer/Hawkins)', method: 'Passive shoulder flexion with arm in internal rotation', normal: 'No pain' },
{ label: 'Ankle stability', method: 'Anterior drawer and talar tilt', normal: 'No laxity' }
], abnormalHints: ['ACL laxity (positive Lachman)', 'Meniscal click', 'Shoulder impingement', 'Ankle instability'] },
{ name: 'Gait and functional movement', steps: [
{ label: 'Normal gait', method: 'Walk 20 feet', normal: 'Smooth, symmetric' },
{ label: 'Single-leg stance', method: 'Stand on one foot 10s each side', normal: 'Stable without Trendelenburg drop' },
{ label: 'Squat', method: 'Full squat and rise', normal: 'Full squat without pain or asymmetry' },
{ label: 'Hop on one foot', method: '5 hops each side', normal: 'Able and symmetric' }
], abnormalHints: ['Trendelenburg sign (hip abductor weakness)', 'Antalgic gait', 'Asymmetric squat', 'Pain with hop'] }
]
},
neuro: {
overview: 'Adult-pattern six-component exam: mental status, CN, motor, reflexes, sensory, coordination/gait.',
components: [
{ name: 'Mental status', steps: [
{ label: 'Orientation', method: 'Name, age, school, city, day of week', normal: 'Oriented x 4' },
{ label: 'Attention', method: 'Count backward from 20; days of week backward', normal: 'Intact' },
{ label: '3-item recall', method: 'Ball-flag-tree; ask at 3 and 5 min', normal: '3/3 recall at 5 min' },
{ label: 'Language', method: 'Name common objects; repeat a sentence', normal: 'Fluent, no paraphasia' }
], abnormalHints: ['Inattention (ADHD features)', 'Memory deficits', 'Word-finding difficulty', 'Perseveration'] },
{ name: 'Cranial nerves (IIXII)', steps: [
{ label: 'CN II — acuity', method: 'Snellen at 20ft each eye with corrective lenses if worn', normal: '20/20 or baseline' },
{ label: 'CN II — fields', method: 'Confrontation, 4 quadrants each eye', normal: 'Full fields' },
{ label: 'CN II — fundoscopy (if indicated)', method: 'Direct ophthalmoscopy — disc, vessels, macula', normal: 'Sharp disc, normal cup-disc ratio, no papilledema' },
{ label: 'CN II, III — pupils', method: 'Direct and consensual light, accommodation', normal: 'PERRLA' },
{ label: 'CN III, IV, VI — EOM', method: 'Follow finger in H pattern; convergence', normal: 'Full EOM, no nystagmus, convergence intact' },
{ label: 'CN V — sensation', method: 'Light touch V1 (forehead), V2 (cheek), V3 (jaw) each side', normal: 'Intact, symmetric' },
{ label: 'CN V — motor', method: 'Clench teeth, palpate masseter/temporalis; jaw opening', normal: 'Symmetric strength' },
{ label: 'CN VII', method: 'Raise eyebrows, close eyes tight, smile/show teeth, puff cheeks', normal: 'Symmetric movement, all regions' },
{ label: 'CN VIII', method: 'Finger rub each ear; Weber/Rinne if deficit', normal: 'Hears bilaterally' },
{ label: 'CN IX, X', method: 'Palate elevation with "ahh"; uvula midline; voice quality', normal: 'Symmetric elevation, uvula midline, normal voice' },
{ label: 'CN XI', method: 'Shrug shoulders against resistance; head turn against resistance', normal: '5/5 SCM and trapezius' },
{ label: 'CN XII', method: 'Stick tongue out; side-to-side', normal: 'Midline, no atrophy or fasciculations' }
], abnormalHints: ['Papilledema (increased ICP)', 'Focal cranial nerve deficit — any warrants workup', 'Tongue fasciculations (LMN/MND)'] },
{ name: 'Motor — bulk, tone, strength', steps: [
{ label: 'Bulk inspection', method: 'Shoulders, thighs, calves, intrinsic hand muscles', normal: 'Symmetric, no atrophy' },
{ label: 'Tone', method: 'Passive range at elbows, wrists, knees, ankles', normal: 'Normal resistance throughout' },
{ label: 'Strength — deltoids', method: 'Shoulder abduction against resistance', normal: '5/5 bilaterally' },
{ label: 'Strength — biceps', method: 'Elbow flexion against resistance', normal: '5/5' },
{ label: 'Strength — triceps', method: 'Elbow extension against resistance', normal: '5/5' },
{ label: 'Strength — grip', method: 'Squeeze 2 fingers', normal: '5/5 symmetric' },
{ label: 'Strength — finger abduction', method: 'Spread fingers against resistance', normal: '5/5' },
{ label: 'Strength — hip flexion', method: 'Lift leg supine against resistance', normal: '5/5' },
{ label: 'Strength — knee extension', method: 'Straighten knee against resistance', normal: '5/5' },
{ label: 'Strength — dorsiflexion', method: 'Pull toes up against resistance', normal: '5/5' },
{ label: 'Strength — plantarflexion', method: 'Push foot down against resistance', normal: '5/5' }
], abnormalHints: ['Focal weakness (localize)', 'Spasticity (UMN)', 'Atrophy', 'Fasciculations'] },
{ name: 'Deep tendon reflexes', steps: [
{ label: 'Biceps (C5-C6)', method: 'Thumb on tendon, strike', normal: '2+ symmetric' },
{ label: 'Triceps (C7-C8)', method: 'Strike triceps tendon', normal: '2+ symmetric' },
{ label: 'Brachioradialis (C5-C6)', method: 'Strike distal radius', normal: '2+ symmetric' },
{ label: 'Patellar (L3-L4)', method: 'Knees hanging, strike tendon', normal: '2+ symmetric' },
{ label: 'Achilles (S1)', method: 'Slight dorsiflexion, strike tendon', normal: '2+ symmetric' },
{ label: 'Plantar response', method: 'Stroke lateral sole heel-to-toes', normal: 'Down-going bilaterally' },
{ label: 'Clonus', method: 'Rapid dorsiflexion at ankle', normal: 'No sustained clonus' }
], abnormalHints: ['Hyperreflexia with clonus (UMN: stroke, MS, cord lesion)', 'Hyporeflexia (LMN, neuropathy, myopathy)', 'Asymmetry', 'Up-going Babinski', 'Sustained clonus'] },
{ name: 'Sensory', steps: [
{ label: 'Light touch — upper', method: 'Cotton wisp dorsum of hands, eyes closed', normal: 'Intact, symmetric' },
{ label: 'Light touch — lower', method: 'Same on dorsum of feet', normal: 'Intact, symmetric' },
{ label: 'Pain — upper', method: 'Broken Q-tip or pin on hands', normal: 'Intact, symmetric' },
{ label: 'Pain — lower', method: 'Same on feet', normal: 'Intact, symmetric' },
{ label: 'Vibration', method: '128 Hz tuning fork at distal IP joint of great toes', normal: 'Feels vibration; counts down seconds' },
{ label: 'Proprioception', method: 'Move great toe up/down with eyes closed', normal: 'Identifies direction correctly' }
], abnormalHints: ['Dermatomal loss (nerve root)', 'Stocking-glove (neuropathy)', 'Loss of vibration/proprioception (dorsal column — B12, tabes, MS)'] },
{ name: 'Coordination', steps: [
{ label: 'Finger-nose-finger', method: 'Touch examiner finger then own nose, examiner moves target', normal: 'Smooth, accurate, no dysmetria' },
{ label: 'Heel-to-shin', method: 'Supine: heel down opposite shin', normal: 'Smooth, on-target' },
{ label: 'Rapid alternating movements', method: 'Supinate/pronate hand on knee rapidly', normal: 'Rhythmic, symmetric' },
{ label: 'Fine motor', method: 'Finger tapping (thumb to each finger in sequence)', normal: 'Rhythmic, accurate' }
], abnormalHints: ['Dysmetria (past-pointing, overshoot)', 'Intention tremor', 'Dysdiadochokinesia'] },
{ name: 'Gait and Romberg', steps: [
{ label: 'Normal gait', method: 'Walk 20 feet', normal: 'Narrow-based, smooth, reciprocal arm swing' },
{ label: 'Heel walk', method: 'Walk on heels', normal: 'Able without difficulty' },
{ label: 'Toe walk', method: 'Walk on toes', normal: 'Able without difficulty' },
{ label: 'Tandem', method: 'Heel-to-toe along a line', normal: 'Minimal deviation, 10+ steps' },
{ label: 'Romberg', method: 'Feet together, eyes closed, 30s', normal: 'Stable without fall or significant sway' }
], abnormalHints: ['Wide-based (cerebellar)', 'Steppage (peripheral neuropathy)', 'Scissoring (UMN)', 'Romberg positive (dorsal column)', 'Circumduction'] }
]
}
},
adolescent: {
label: 'Adolescent (1221 years)',
msk: {
overview: 'Sports-related injuries, adolescent scoliosis, apophyseal overuse, hypermobility screening.',
components: [
{ name: 'Scoliosis screen', steps: [
{ label: 'Standing inspection', method: 'Patient undressed to waist (keep privacy); compare shoulders, iliac crests, scapular heights', normal: 'Symmetric shoulders and pelvis' },
{ label: 'Forward bend (Adam)', method: 'Feet together, bend forward, arms hanging palms together', normal: 'Symmetric paraspinal contour' },
{ label: 'Scoliometer', method: 'Place across thoracic and lumbar regions at maximum prominence', normal: 'ATR <5°; 56° monitor; ≥7° refer' },
{ label: 'Plumb line check', method: 'Drop plumb from C7; note where it falls', normal: 'Passes through gluteal cleft (compensated)' },
{ label: 'Leg lengths', method: 'Supine; ASIS to medial malleolus each side', normal: 'Within 1cm' }
], abnormalHints: ['Rib/lumbar hump', 'ATR ≥7°', 'Decompensation (plumb off gluteal cleft)', 'Leg-length discrepancy driving apparent curve'] },
{ name: 'Back pain evaluation (if complaint)', steps: [
{ label: 'Inspect and palpate', method: 'Spinous processes, paraspinal muscles, SI joints', normal: 'Non-tender' },
{ label: 'Range of motion', method: 'Flex, extend, lateral bend, rotate', normal: 'Full painless range' },
{ label: 'Single-leg hyperextension (stork)', method: 'Stand on one foot, extend back — each side', normal: 'No pain (negative for spondylolysis)' },
{ label: 'Straight-leg raise', method: 'Supine, lift straight leg to 70°+', normal: 'No radicular pain to 70°' },
{ label: 'SI joint tests', method: 'FABER, SI compression', normal: 'No pain' }
], abnormalHints: ['Spondylolysis (positive stork test)', 'Radicular pain (disc herniation)', 'SI joint pathology', 'Inflammatory back pain pattern'] },
{ name: 'Joint stability — sports-specific', steps: [
{ label: 'Knee — Lachman', method: 'Knee 20° flexion, stabilize femur, pull tibia anteriorly', normal: 'Firm endpoint, no laxity (ACL intact)' },
{ label: 'Knee — anterior drawer', method: 'Knee 90°, pull tibia forward', normal: 'No excess anterior translation' },
{ label: 'Knee — varus/valgus stress', method: 'Stress at 0 and 30° flexion', normal: 'No gap opening (LCL/MCL intact)' },
{ label: 'Knee — McMurray', method: 'Flex, rotate tibia while extending', normal: 'No pain or click' },
{ label: 'Shoulder — apprehension', method: 'Abduct and externally rotate', normal: 'No apprehension' },
{ label: 'Shoulder — Neer/Hawkins', method: 'Passive flexion with internal rotation', normal: 'No pain' },
{ label: 'Ankle — anterior drawer', method: 'Pull heel forward with tibia stabilized', normal: 'No laxity' },
{ label: 'Ankle — talar tilt', method: 'Invert heel with tibia stabilized', normal: 'No excess tilt' }
], abnormalHints: ['ACL/PCL tear', 'MCL/LCL laxity', 'Meniscal injury', 'Shoulder instability/impingement', 'Ankle ligament laxity'] },
{ name: 'Apophysitis and overuse screen', steps: [
{ label: 'Tibial tubercle', method: 'Palpate with knee flexed', normal: 'Non-tender' },
{ label: 'Calcaneal apophysis', method: 'Palpate posterior calcaneus', normal: 'Non-tender' },
{ label: 'Iliac apophyses', method: 'Palpate ASIS, AIIS, iliac crest', normal: 'Non-tender' },
{ label: 'Rotator cuff', method: 'Empty-can (Jobe) test', normal: 'No pain or weakness' }
], abnormalHints: ['Osgood-Schlatter (tibial tubercle tender)', 'Sever (calcaneal tender)', 'Iliac apophysitis', 'Rotator cuff tendinopathy'] },
{ name: 'Hypermobility screen (Beighton)', steps: [
{ label: 'Fifth finger extension', method: 'Passive extension of fifth MCP to >90°', normal: 'No hyperextension (1 pt each side if positive)' },
{ label: 'Thumb to forearm', method: 'Passive flexion of thumb to touch forearm', normal: 'Does not reach (1 pt each side if positive)' },
{ label: 'Elbow hyperextension', method: 'Hyperextension >10°', normal: 'No hyperextension (1 pt each side if positive)' },
{ label: 'Knee hyperextension', method: 'Hyperextension >10°', normal: 'No hyperextension (1 pt each side if positive)' },
{ label: 'Palms to floor', method: 'Feet together, bend forward, palms flat on floor with knees straight', normal: 'Cannot reach (1 pt if positive)' }
], abnormalHints: ['Beighton ≥5/9 suggests hypermobility spectrum (hEDS workup if with other features)'] },
{ name: 'Alignment and gait', steps: [
{ label: 'Standing alignment', method: 'View knees, feet', normal: 'Neutral alignment, medial arch' },
{ label: 'Normal gait', method: 'Walk 20 feet', normal: 'Symmetric, smooth' },
{ label: 'Functional movements', method: 'Squat, single-leg stance, hop', normal: 'Full symmetric function' }
], abnormalHints: ['Antalgic gait', 'Trendelenburg', 'Asymmetric squat'] }
]
},
neuro: {
overview: 'Full adult-pattern neuro exam across six pillars: mental status, cranial nerves, motor, reflexes, sensory, coordination/gait. In adolescents, screen concussion sequelae if sports-active; frontal release signs must be absent.',
components: [
{ name: 'Mental status',
significance: 'Detects cognitive change (concussion, substance use, mood disorder, rare neurodegenerative disease).',
pearl: 'Attention precedes memory. A patient who can\'t attend (serial 7s, months backward) will fail memory even with intact hippocampus — distinguish before calling it a memory problem.',
steps: [
{ label: 'Orientation', method: 'Name, age, date, location, situation', normal: 'Oriented x 4' },
{ label: 'Attention', method: 'Count backward from 100 by 7s (serial 7s) or months of year backward', normal: 'Intact' },
{ label: 'Short-term memory', method: '3-item registration and recall at 5 min', normal: '3/3 recall' },
{ label: 'Language', method: 'Object naming; sentence repetition; reading; writing', normal: 'Fluent, no paraphasia, comprehends written and spoken' },
{ label: 'Executive function', method: 'Similarities (apple/orange); interpret proverb', normal: 'Abstract, age-appropriate' }
], abnormalHints: ['Post-concussion cognitive changes', 'Mood or personality changes', 'Subtle executive dysfunction', 'Word-finding difficulty'] },
{ name: 'Cranial nerves (IIXII, full formal exam)',
significance: 'Localises brainstem, base-of-skull, and specific nerve pathology. Subtle deficits (RAPD, mild facial weakness, Horner) are easily missed — exam discipline matters.',
pearl: 'The fastest screen for a CN deficit is asking the patient to speak, smile, look around, and swallow water. What\'s preserved in everyday function tells you what\'s likely intact — then examine formally to confirm and to catch the subtle.',
steps: [
{ label: 'CN I (if indicated)', method: 'Coffee or cinnamon each nostril separately', normal: 'Identifies both' },
{ label: 'CN II — acuity', method: 'Snellen at 20ft each eye; corrective lenses if worn', normal: '20/20 or baseline' },
{ label: 'CN II — fields', method: 'Confrontation, 4 quadrants each eye', normal: 'Full fields' },
{ label: 'CN II — fundoscopy', method: 'Direct ophthalmoscopy — disc, vessels, macula', normal: 'Sharp disc, normal cup/disc, no papilledema' },
{ label: 'CN II, III — pupils', method: 'Direct, consensual, swinging flashlight, accommodation', normal: 'PERRLA, no RAPD' },
{ label: 'CN III, IV, VI — EOM', method: 'H pattern, convergence, note nystagmus or ptosis', normal: 'Full conjugate movement, no nystagmus, convergence intact' },
{ label: 'CN V — sensation', method: 'Light touch V1, V2, V3 each side', normal: 'Intact, symmetric' },
{ label: 'CN V — motor', method: 'Clench jaw, palpate masseter/temporalis; lateral jaw movement', normal: 'Symmetric strength and bulk' },
{ label: 'CN V — corneal reflex (if indicated)', method: 'Cotton wisp to cornea', normal: 'Blinks bilaterally' },
{ label: 'CN VII', method: 'Wrinkle forehead, close eyes against resistance, smile/bare teeth, puff cheeks', normal: 'Symmetric all four movements' },
{ label: 'CN VIII — hearing', method: 'Finger rub each ear; Weber (midline) + Rinne (air > bone) if deficit', normal: 'Equal bilaterally' },
{ label: 'CN IX, X', method: 'Palate elevation with "ahh"; uvula midline; voice; gag (if indicated)', normal: 'Symmetric palate, uvula midline, normal voice' },
{ label: 'CN XI', method: 'Shoulder shrug and head turn against resistance', normal: '5/5 SCM and trapezius bilaterally' },
{ label: 'CN XII', method: 'Tongue protrusion, side to side; inspect for fasciculations/atrophy', normal: 'Midline, no atrophy or fasciculations, full movement' }
], abnormalHints: ['Any focal cranial nerve deficit', 'Papilledema', 'RAPD', 'Nystagmus', 'Facial asymmetry', 'Tongue deviation'] },
{ name: 'Motor — bulk, tone, strength',
significance: 'Localises lesion to UMN vs LMN vs muscle vs junction. Pattern of weakness (proximal vs distal, symmetric vs focal) narrows differential.',
pearl: 'Pronator drift is the most sensitive screen for subtle UMN weakness — a normal-feeling arm that drifts down with eyes closed still has corticospinal tract dysfunction. Always do it even when formal strength is 5/5.',
steps: [
{ label: 'Bulk inspection', method: 'Inspect shoulders, biceps, thighs, calves, dorsal interossei (between metacarpals) of hands.', normal: 'Symmetric bulk; no atrophy, no pseudohypertrophy' },
{ label: 'Tone — upper', method: 'Passive flex-extend elbow and pronate-supinate wrist at slow then quick speeds. Then pronator drift: arms outstretched, palms up, eyes closed for 10 s.', normal: 'Smooth passive range; no drift, no pronation of the outstretched hand' },
{ label: 'Tone — lower', method: 'Passive knee flexion-extension; quick ankle dorsiflexion to check for catch. Heel-slap test: roll thigh and watch for ankle swing.', normal: 'Normal resistance, no catch, symmetric' },
{ label: 'Strength — deltoid (C5)', method: 'Patient abducts both arms to 90°. Examiner pushes down on each arm just above the elbow while patient resists. Compare sides.', normal: 'Holds against full resistance — MRC 5/5 bilaterally' },
{ label: 'Strength — biceps (C5C6)', method: 'Elbow flexed 90°, supinated. Examiner grasps wrist and pulls to extend while patient resists.', normal: 'Holds against full resistance — 5/5' },
{ label: 'Strength — triceps (C7)', method: 'Elbow flexed 90°. Examiner pushes wrist toward shoulder while patient extends against resistance.', normal: 'Extends against full resistance — 5/5' },
{ label: 'Strength — wrist extension (C6C7)', method: 'Patient makes fist, extends wrist. Examiner pushes down on knuckles while patient holds wrist up.', normal: 'Holds against full resistance — 5/5' },
{ label: 'Strength — finger flexion / grip (C8)', method: 'Patient grips two of examiner\'s crossed fingers as hard as possible. Compare sides.', normal: 'Strong symmetric grip — 5/5' },
{ label: 'Strength — finger abduction (T1)', method: 'Patient spreads fingers wide. Examiner squeezes index and little fingers together while patient resists.', normal: 'Holds fingers apart — 5/5' },
{ label: 'Strength — hip flexion (L2L3)', method: 'Supine. Patient lifts straight leg 30° off table. Examiner pushes down on thigh just above knee while patient resists.', normal: 'Holds thigh up against full resistance — 5/5' },
{ label: 'Strength — knee extension (L3L4)', method: 'Sitting, knee 90°. Patient straightens knee while examiner pushes distal shin down.', normal: 'Extends against full resistance — 5/5' },
{ label: 'Strength — ankle dorsiflexion (L4L5)', method: 'Patient pulls toes and foot up toward shin. Examiner pushes foot down at the dorsum.', normal: 'Holds dorsiflexion against full resistance — 5/5; preserved heel-walk' },
{ label: 'Strength — great toe extension (L5)', method: 'Patient extends great toe up while examiner pushes it down with thumb.', normal: 'Holds against full resistance — 5/5 (classic L5 test)' },
{ label: 'Strength — ankle plantarflexion (S1)', method: 'Patient pushes foot down against examiner\'s hand at the ball. OR ask patient to toe-walk 10 steps (more sensitive — unilateral plantarflexion weakness shows immediately).', normal: 'Full power; toe-walks symmetrically — 5/5' }
], abnormalHints: ['Focal weakness → localise by myotome', 'Pronator drift (subtle UMN, always check even with 5/5)', 'Spasticity / catch (UMN)', 'Atrophy (LMN, disuse)', 'Fasciculations (MND, ALS)', 'Pseudohypertrophy of calves (DMD in a young male)'] },
{ name: 'Deep tendon reflexes',
significance: 'Reflex pattern (increased, decreased, asymmetric) localises UMN vs LMN vs root vs peripheral nerve. Inexpensive and fast, but asymmetry is the most informative finding.',
pearl: 'A reinforced reflex is still a reflex. If you can\'t elicit it initially, use Jendrassik (teeth clench or pull interlocked fingers apart) to boost — absent reflexes without reinforcement aren\'t truly absent.',
steps: [
{ label: 'Biceps (C5C6)', method: 'Patient\'s arm relaxed across lap. Examiner places thumb firmly on biceps tendon at the cubital fossa, strikes thumb with reflex hammer. Compare both sides sequentially.', normal: '2+ symmetric — visible contraction of biceps, slight elbow flexion' },
{ label: 'Brachioradialis (C5C6)', method: 'Arm relaxed. Strike the distal radius about 3 cm proximal to the wrist, on its radial (thumb) side.', normal: '2+ symmetric — elbow flexion and slight forearm supination' },
{ label: 'Triceps (C7)', method: 'Support the patient\'s arm at the wrist with elbow at 90°. Strike the triceps tendon just above the olecranon.', normal: '2+ symmetric — triceps contraction, slight elbow extension' },
{ label: 'Finger flexors — Hoffmann sign', method: 'Grasp the middle finger\'s distal phalanx, flick it downward quickly and release. Watch the thumb and index finger.', normal: 'Negative — no thumb flexion, no index flexion (positive = corticospinal tract dysfunction)' },
{ label: 'Patellar (L3L4)', method: 'Patient sits with knees hanging freely off the table. Strike the patellar tendon just below the patella.', normal: '2+ symmetric — quadriceps contraction with knee extension' },
{ label: 'Achilles (S1)', method: 'Patient\'s knee slightly flexed and leg externally rotated, or kneeling on a chair. Slightly dorsiflex the foot and strike the Achilles tendon.', normal: '2+ symmetric — plantar flexion of the foot' },
{ label: 'Plantar response (Babinski)', method: 'Stroke the lateral aspect of the sole firmly from the heel toward the little toe, then curve across the ball of the foot.', normal: 'Toes flex downward (plantar flexion, "down-going") bilaterally in anyone ≥ 2 years' },
{ label: 'Ankle clonus', method: 'Knee slightly bent. Support the shin with one hand, quickly and sharply dorsiflex the foot with the other, hold in dorsiflexion.', normal: '≤ 3 non-sustained beats is acceptable; sustained rhythmic oscillation = pathological clonus (UMN)' }
], abnormalHints: ['Hyperreflexia + sustained clonus = UMN (MS, myelopathy, cord lesion, stroke)', 'Symmetric hyporeflexia = peripheral polyneuropathy, GBS, myopathy, hypothyroid, B12 deficiency', 'Asymmetric hyporeflexia = radiculopathy at that segment', 'Hoffmann positive = corticospinal tract dysfunction at cervical cord or above', 'Up-going Babinski after age 2 = UMN (always abnormal)'] },
{ name: 'Sensory', steps: [
{ label: 'Light touch — upper', method: 'Cotton wisp, dorsum of hands, eyes closed', normal: 'Intact, symmetric' },
{ label: 'Light touch — lower', method: 'Dorsum of feet', normal: 'Intact, symmetric' },
{ label: 'Pain — upper', method: 'Broken Q-tip sharp end, hands', normal: 'Intact, symmetric' },
{ label: 'Pain — lower', method: 'Same on feet', normal: 'Intact, symmetric' },
{ label: 'Temperature (if indicated)', method: 'Cold tuning fork each area', normal: 'Intact' },
{ label: 'Vibration', method: '128 Hz tuning fork at distal IP of great toes; count seconds to fade', normal: 'Feels vibration; appropriate duration' },
{ label: 'Proprioception', method: 'Move great toe up/down with eyes closed', normal: 'Identifies direction correctly' },
{ label: 'Two-point discrimination (if indicated)', method: 'Blunt calipers on fingertip', normal: '<5mm on fingertip' },
{ label: 'Stereognosis (if indicated)', method: 'Identify coin/key in hand with eyes closed', normal: 'Correct identification' }
], abnormalHints: ['Dermatomal loss (nerve root)', 'Stocking-glove loss (length-dependent neuropathy)', 'Dorsal column loss (B12, tabes, MS — positive Romberg, vibration loss)', 'Cortical deficit (astereognosis, impaired 2-pt)'] },
{ name: 'Coordination', steps: [
{ label: 'Finger-nose-finger', method: 'Alternate examiner\'s finger and own nose; examiner moves target', normal: 'Smooth, accurate bilaterally' },
{ label: 'Heel-to-shin', method: 'Supine: heel down opposite shin and back', normal: 'Smooth, accurate' },
{ label: 'Rapid alternating (Dysdiadochokinesis)', method: 'Supinate/pronate hand rapidly on thigh', normal: 'Rhythmic, symmetric' },
{ label: 'Finger tapping', method: 'Thumb to each finger in sequence rapidly', normal: 'Rhythmic, smooth, symmetric' }
], abnormalHints: ['Dysmetria (cerebellar)', 'Intention tremor', 'Dysdiadochokinesia', 'Decomposed movement'] },
{ name: 'Gait and Romberg', steps: [
{ label: 'Normal gait', method: 'Walk 20 feet', normal: 'Narrow-based, smooth, reciprocal arm swing' },
{ label: 'Heel walk', method: 'Walk on heels only', normal: 'Able without difficulty' },
{ label: 'Toe walk', method: 'Walk on toes only', normal: 'Able without difficulty' },
{ label: 'Tandem', method: 'Heel-to-toe along a line, 10+ steps', normal: 'Minimal deviation' },
{ label: 'Romberg', method: 'Feet together, eyes open then closed, 30s', normal: 'Stable — no significant sway or fall with eyes closed' },
{ label: 'Single-leg stance', method: '10s each side, eyes open', normal: 'Stable without drift' }
], abnormalHints: ['Ataxic (wide-based — cerebellar)', 'Steppage (peripheral neuropathy / foot drop)', 'Circumduction (UMN hemiparesis)', 'Scissoring', 'Romberg positive (dorsal column)'] },
{ name: 'Frontal release / primitive reflexes', steps: [
{ label: 'Grasp reflex', method: 'Stroke palm', normal: 'Absent' },
{ label: 'Snout reflex', method: 'Tap upper lip', normal: 'No lip pucker' },
{ label: 'Glabellar tap', method: 'Tap between eyebrows — should habituate after 34 taps', normal: 'Habituates (no sustained blink)' },
{ label: 'Palmomental', method: 'Stroke thenar eminence', normal: 'No ipsilateral chin twitch' }
], abnormalHints: ['Presence suggests frontal lobe pathology, neurodegenerative disease, or severe TBI — rare in adolescence but relevant in post-concussion workup'] }
]
}
}
};
// ────────────────────────────────────────────────────────────
// STATE + RENDER
// ────────────────────────────────────────────────────────────
var _inited = false;
// state keyed as 'system-componentIdx-stepIdx' → { label, method, normal, status, note }
var state = {};
var currentSystem = 'msk';
var currentAgeGroup = '';
document.addEventListener('tabChanged', function (e) {
if (e.detail.tab !== 'peguide' || _inited) return;
_inited = true;
init();
});
function init() {
var ageSelect = document.getElementById('pe-age-group');
var content = document.getElementById('pe-content');
var actions = document.getElementById('pe-actions');
ageSelect.addEventListener('change', function () {
currentAgeGroup = ageSelect.value;
state = {};
document.getElementById('pe-output').classList.add('hidden');
if (!currentAgeGroup || !PE_DATA[currentAgeGroup]) {
content.innerHTML = '<p style="text-align:center;color:#9ca3af;padding:40px;">Select an age group above.</p>';
actions.style.display = 'none';
return;
}
renderSystem();
actions.style.display = 'flex';
});
document.querySelectorAll('[data-pesystem]').forEach(function (btn) {
btn.addEventListener('click', function () {
document.querySelectorAll('[data-pesystem]').forEach(function (b) { b.classList.remove('active'); });
btn.classList.add('active');
currentSystem = btn.dataset.pesystem;
state = {};
document.getElementById('pe-output').classList.add('hidden');
if (currentAgeGroup) renderSystem();
});
});
document.getElementById('pe-all-normal').addEventListener('click', setAllNormal);
document.getElementById('pe-all-clear').addEventListener('click', clearAll);
document.getElementById('pe-generate-btn').addEventListener('click', generate);
}
function renderSystem() {
var content = document.getElementById('pe-content');
var group = PE_DATA[currentAgeGroup];
if (!group || !group[currentSystem]) {
content.innerHTML = '<p style="text-align:center;color:#9ca3af;padding:40px;">No data for this combination.</p>';
return;
}
var section = group[currentSystem];
var accent = currentSystem === 'msk' ? '#0891b2' : '#7c3aed'; // cyan for MSK, purple for neuro
var accentTint = currentSystem === 'msk' ? '#ecfeff' : '#f5f3ff';
var html = '';
// ─ Overview banner ─
html += '<div class="card" style="margin-bottom:14px;border-left:4px solid ' + accent + ';">';
html += ' <div class="card-header" style="border:0;padding:14px 16px 6px;"><h3 style="margin:0;font-size:16px;color:' + accent + ';"><i class="fas fa-' + (currentSystem === 'msk' ? 'bone' : 'brain') + '"></i> ' + esc(group.label) + ' — ' + (currentSystem === 'msk' ? 'Musculoskeletal' : 'Neurologic') + '</h3></div>';
html += ' <div style="padding:0 16px 14px;font-size:13px;line-height:1.65;color:var(--g700);">' + esc(section.overview) + '</div>';
html += '</div>';
// ─ Grading scales reference (collapsible) ─
var scaleKeys = SYSTEM_SCALES[currentSystem] || [];
if (scaleKeys.length) {
html += '<details class="card" style="margin-bottom:14px;background:' + accentTint + ';border:1px solid ' + accent + '33;">';
html += ' <summary style="padding:10px 16px;cursor:pointer;font-weight:600;font-size:13px;color:' + accent + ';list-style:none;display:flex;align-items:center;gap:8px;"><i class="fas fa-book-medical"></i> Grading scales &amp; reference <span style="font-weight:400;color:var(--g500);font-size:11px;">(click to expand)</span></summary>';
html += ' <div style="padding:0 16px 14px;display:grid;grid-template-columns:repeat(auto-fit,minmax(280px,1fr));gap:14px;">';
scaleKeys.forEach(function (sk) {
var sc = SCALES[sk]; if (!sc) return;
html += '<div style="background:#fff;border:1px solid var(--g200);border-radius:8px;padding:10px 12px;">';
html += ' <div style="font-weight:600;font-size:12px;color:var(--g800);margin-bottom:6px;"><i class="fas ' + sc.icon + '" style="color:' + accent + ';margin-right:6px;"></i>' + esc(sc.title) + '</div>';
html += ' <table style="width:100%;font-size:11px;line-height:1.5;border-collapse:collapse;">';
sc.rows.forEach(function (row) {
html += '<tr><td style="padding:2px 0;white-space:nowrap;color:' + accent + ';font-weight:600;font-family:ui-monospace,monospace;">' + esc(row[0]) + '</td><td style="padding:2px 0 2px 10px;color:var(--g700);">' + esc(row[1]) + '</td></tr>';
});
html += ' </table>';
html += '</div>';
});
html += ' </div>';
html += '</details>';
}
// ─ Components ─
section.components.forEach(function (c, ci) {
html += '<div class="card" style="margin-bottom:12px;border-left:3px solid ' + accent + ';">';
// Header
html += ' <div style="padding:12px 16px 8px;display:flex;align-items:center;justify-content:space-between;gap:10px;">';
html += ' <h3 style="margin:0;font-size:15px;color:var(--g800);">' + esc(c.name) + '</h3>';
html += ' <span style="font-size:10px;font-weight:600;padding:3px 8px;border-radius:10px;background:' + accent + '22;color:' + accent + ';text-transform:uppercase;letter-spacing:0.5px;white-space:nowrap;">' + c.steps.length + ' steps</span>';
html += ' </div>';
// Significance line
if (c.significance) {
html += ' <div style="padding:0 16px 6px;font-size:12px;color:var(--g600);line-height:1.55;"><i class="fas fa-bullseye" style="color:' + accent + ';margin-right:6px;font-size:11px;"></i>' + esc(c.significance) + '</div>';
}
// Teaching pearl
if (c.pearl) {
html += ' <div style="margin:6px 16px 10px;padding:10px 12px;background:#fef7e7;border-left:3px solid #f59e0b;border-radius:0 6px 6px 0;font-size:12px;line-height:1.6;color:#78350f;"><i class="fas fa-lightbulb" style="color:#f59e0b;margin-right:6px;"></i><em>' + esc(c.pearl) + '</em></div>';
}
// Steps
html += ' <div style="padding:4px 12px 10px;">';
c.steps.forEach(function (s, si) {
var key = currentSystem + '-' + ci + '-' + si;
if (!state[key]) state[key] = { component: c.name, label: s.label, method: s.method, normal: s.normal, status: null, note: '' };
var st = state[key].status;
var rowBg = st === 'normal' ? '#ecfdf5' : st === 'abnormal' ? '#fef2f2' : 'transparent';
var rowBorder = st === 'normal' ? '#a7f3d0' : st === 'abnormal' ? '#fecaca' : 'var(--g200)';
html += '<div class="pe-step" data-pe-key="' + key + '" style="padding:10px 12px;border:1px solid ' + rowBorder + ';border-radius:8px;margin-bottom:6px;background:' + rowBg + ';transition:background 0.12s,border-color 0.12s;">';
html += ' <div style="display:flex;align-items:flex-start;gap:10px;">';
html += ' <div style="flex-shrink:0;width:22px;height:22px;border-radius:50%;background:' + accent + '22;color:' + accent + ';font-size:11px;font-weight:700;display:flex;align-items:center;justify-content:center;line-height:1;">' + (si + 1) + '</div>';
html += ' <div style="flex:1;min-width:0;">';
html += ' <div style="font-weight:600;font-size:13px;color:var(--g800);">' + esc(s.label) + '</div>';
html += ' <div style="font-size:12px;color:var(--g600);margin-top:3px;line-height:1.55;"><span style="color:var(--g500);font-weight:600;text-transform:uppercase;letter-spacing:0.5px;font-size:10px;">How</span> &nbsp;' + esc(s.method) + '</div>';
html += ' <div style="font-size:12px;color:var(--g600);margin-top:2px;line-height:1.55;"><span style="color:#059669;font-weight:600;text-transform:uppercase;letter-spacing:0.5px;font-size:10px;">Normal</span> &nbsp;' + esc(s.normal) + '</div>';
html += ' </div>';
html += ' <div style="display:flex;gap:3px;flex-shrink:0;">';
html += ' <button class="visit-status-btn ' + (st === 'normal' ? 'done' : '') + '" data-pe-status="normal" data-pe-key="' + key + '" title="Normal">✓</button>';
html += ' <button class="visit-status-btn ' + (st === 'abnormal' ? 'refused' : '') + '" data-pe-status="abnormal" data-pe-key="' + key + '" title="Abnormal">✗</button>';
html += ' <button class="visit-status-btn ' + (st === null ? 'not-due' : '') + '" data-pe-status="skip" data-pe-key="' + key + '" title="Skip">—</button>';
html += ' </div>';
html += ' </div>';
html += ' <div class="pe-abnormal-detail" style="margin-top:8px;' + (st === 'abnormal' ? '' : 'display:none;') + '">';
html += ' <input type="text" class="pe-note" data-pe-key="' + key + '" placeholder="Describe the abnormal finding (e.g., 4/5 strength, left pronator drift)" value="' + esc(state[key].note || '') + '" style="width:100%;padding:6px 10px;font-size:12px;border:1px solid #fecaca;border-radius:6px;background:#fff;">';
html += ' </div>';
html += '</div>';
});
html += ' </div>';
// Watch-for
if (c.abnormalHints && c.abnormalHints.length) {
html += '<div style="margin:0 12px 12px;padding:10px 12px;background:#fef2f2;border-left:3px solid #ef4444;border-radius:0 6px 6px 0;font-size:11px;line-height:1.7;color:#7f1d1d;">';
html += '<div style="font-weight:600;text-transform:uppercase;letter-spacing:0.5px;color:#991b1b;margin-bottom:4px;font-size:10px;"><i class="fas fa-triangle-exclamation"></i> Watch for</div>';
html += c.abnormalHints.map(esc).join(' &nbsp;·&nbsp; ');
html += '</div>';
}
html += '</div>';
});
content.innerHTML = html;
content.querySelectorAll('[data-pe-status]').forEach(function (btn) {
btn.addEventListener('click', function () { handleStatus(btn); });
});
content.querySelectorAll('.pe-note').forEach(function (inp) {
inp.addEventListener('input', function () {
var key = inp.dataset.peKey;
if (state[key]) state[key].note = inp.value;
});
});
}
function handleStatus(btn) {
var key = btn.dataset.peKey;
var status = btn.dataset.peStatus;
if (!state[key]) return;
state[key].status = (status === 'skip') ? null : status;
var row = btn.closest('.pe-step');
if (row) {
var s = state[key].status;
row.style.background = s === 'normal' ? '#ecfdf5' : s === 'abnormal' ? '#fef2f2' : 'transparent';
row.style.borderColor = s === 'normal' ? '#a7f3d0' : s === 'abnormal' ? '#fecaca' : 'var(--g200)';
row.querySelectorAll('[data-pe-status]').forEach(function (b) {
b.classList.remove('done', 'refused', 'not-due');
if (b.dataset.peStatus === 'normal' && state[key].status === 'normal') b.classList.add('done');
if (b.dataset.peStatus === 'abnormal' && state[key].status === 'abnormal') b.classList.add('refused');
if (b.dataset.peStatus === 'skip' && state[key].status === null) b.classList.add('not-due');
});
var detail = row.querySelector('.pe-abnormal-detail');
if (detail) detail.style.display = (state[key].status === 'abnormal') ? '' : 'none';
}
}
function setAllNormal() {
Object.keys(state).forEach(function (k) { if (k.indexOf(currentSystem + '-') === 0) state[k].status = 'normal'; });
renderSystem();
}
function clearAll() {
Object.keys(state).forEach(function (k) { if (k.indexOf(currentSystem + '-') === 0) { state[k].status = null; state[k].note = ''; } });
renderSystem();
}
function generate() {
if (!currentAgeGroup || !PE_DATA[currentAgeGroup]) return;
var steps = Object.keys(state)
.filter(function (k) { return k.indexOf(currentSystem + '-') === 0; })
.map(function (k) { return state[k]; });
var assessed = steps.filter(function (s) { return s.status !== null; });
if (assessed.length === 0) { showToast('Mark at least one step Normal or Abnormal', 'error'); return; }
var btn = document.getElementById('pe-generate-btn');
btn.disabled = true; btn.innerHTML = '<i class="fas fa-spinner fa-spin"></i> Generating...';
var modelSel = document.querySelector('#peguide-tab .tab-model-select');
var model = modelSel ? modelSel.value : '';
var format = document.getElementById('pe-format').value;
fetch('/api/generate-pe-narrative', {
method: 'POST',
headers: getAuthHeaders(),
body: JSON.stringify({
steps: steps,
ageGroup: PE_DATA[currentAgeGroup].label,
system: currentSystem,
patientAge: document.getElementById('pe-age').value,
patientGender: document.getElementById('pe-gender').value,
model: model,
format: format
})
})
.then(function (r) { return r.json(); })
.then(function (data) {
if (!data.success) { showToast(data.error || 'Generation failed', 'error'); return; }
var out = document.getElementById('pe-output');
out.classList.remove('hidden');
document.getElementById('pe-narrative-text').textContent = data.narrative;
var tag = document.getElementById('pe-model-tag');
if (tag) tag.textContent = data.model || '';
var bar = document.getElementById('pe-summary-bar');
if (bar && data.summary) {
bar.classList.remove('hidden');
bar.innerHTML = '<span style="color:#10b981;">' + data.summary.normal + ' normal</span> · <span style="color:#ef4444;">' + data.summary.abnormal + ' abnormal</span> · <span style="color:#9ca3af;">' + data.summary.notAssessed + ' skipped</span>';
}
})
.catch(function (err) { console.error('[PEGuide] generate error', err); showToast('Request failed', 'error'); })
.finally(function () {
btn.disabled = false; btn.innerHTML = '<i class="fas fa-wand-magic-sparkles"></i> Generate Exam Report';
});
}
function esc(s) {
if (s == null) return '';
return String(s).replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;');
}
})();