Please make and interpretation and how to make diagnosis throw many blood reports in simple hindi english language

Reading File
Finding Sources
Finding Sources
Searching the Web

blood test interpretation guide CBC LFT KFT complete diagnosis

Reading File
Reading Web Page

https://zelifehealthcare.com/common-blood-tests-explained-cb…

Yahan aapke liye ek simple aur detailed guide hai - sabse common blood tests ki interpretation aur diagnosis kaise hoti hai, simple Hindi-English mein.

🩸 Blood Reports Kaise Padhein - Simple Hindi-English Guide


1. CBC - Complete Blood Count (Khoon ki Poori Jaanch)

CBC sabse zyada order hone wala blood test hai. Isme 3 main cheezein dekhi jaati hain:

A) RBC / Hemoglobin (Lal Khoon ke Kankad)

ValueNormal RangeMatlab
Hemoglobin (Hb)Men: 13-17 g/dL, Women: 12-15 g/dLOxygen carry karta hai
RBC Count4 to 6 million/Β΅LRed blood cells ki sankhya
Hematocrit (HCT)36-45%Blood mein RBC ka percentage
Agar Hb Kam Hai (Anemia):
  • Doctor pehle MCV (Mean Corpuscular Volume) dekhte hain:
    • MCV < 80 fL (Microcytic) = Iron ki kami ya Thalassemia
    • MCV 80-100 fL (Normocytic) = Chronic disease, kidney problem, blood loss
    • MCV > 100 fL (Macrocytic) = Vitamin B12 ya Folic Acid ki kami
  • RDW bhi important hai - agar RDW high + MCV low = Iron deficiency confirm hoti hai
Agar Hb Zyada Hai: Dehydration, smoking, lung disease (Polycythemia)

B) WBC - White Blood Cells (Safed Khoon ke Kankad / Immunity Cells)

Normal RangeMatlab
4,000 - 11,000 /Β΅LInfection se ladne wale cells
WBC HIGH (Leukocytosis) = Kya hua?
  • Bacterial infection - Neutrophils badhte hain (zyada common)
  • Viral infection - Lymphocytes badhte hain
  • Allergies / Parasites - Eosinophils badhte hain
  • Blood cancer (Leukemia) - bahut zyada WBC
WBC LOW (Leukopenia) = Kya hua?
  • Viral infection (dengue, typhoid)
  • Bone marrow problem
  • Chemotherapy ka asar
Differential Count - WBC ke types:
CellNormal %Badhne par
Neutrophils50-70%Bacterial infection
Lymphocytes20-40%Viral infection
Eosinophils1-4%Allergy, worms
Monocytes2-8%TB, fungal infection
Basophils0-1%Allergy, blood disorders

C) Platelets (Khoon ka Thakka Banane wale Cells)

ValueMatlab
Normal: 1.5 to 4 lakh /Β΅L
< 1.5 lakh = ThrombocytopeniaDengue, liver problem, Vitamin B12 kami
< 20,000 = EmergencyBleeding ka zyada risk
> 4 lakh = ThrombocytosisIron deficiency, infection, cancer

2. LFT - Liver Function Test (Liver ki Jaanch)

TestNormalAgar Badha?
SGPT / ALTUpto 40 U/LLiver cells damage - Hepatitis, fatty liver, alcohol
SGOT / ASTUpto 40 U/LLiver + Heart damage (heart attack mein bhi badh sakta hai)
ALP40-130 U/LBile blockage, bone disease
Total Bilirubin0.2 - 1.2 mg/dLJaundice ka marker
Albumin3.5 - 5.0 g/dLAgar kam = Liver weak hai
Total Protein6 - 8.3 g/dLNutrition aur liver function
Doctor kya sochte hain?
  • SGPT 3 guna se zyada badha + Bilirubin > 2 + Peeli skin = Hepatitis ya Jaundice - turant doctor se milein
  • SGOT bada + SGPT normal = Heart problem bhi possible
  • Albumin kam + Bilirubin zyada = Advanced liver disease

3. KFT - Kidney Function Test (Gurde ki Jaanch)

TestNormalAgar Badha?
Creatinine0.6-1.2 mg/dLKidney kaam kam kar rahi hai
Urea / BUN7-20 mg/dLProtein zyada ya kidney weak
Uric AcidMen: 3.5-7.2, Women: 2.6-6.0 mg/dLGout (Gathiya) ka risk
eGFR> 60 mL/minAgar < 60 = Kidney disease
ElectrolytesSodium 135-145, Potassium 3.5-5.0 mEq/LBalance bigda = Hospital admission zaruri
Diagnosis guide:
  • Creatinine thoda badha + Protein in urine = Early kidney damage (Diabetic Nephropathy)
  • Creatinine bahut zyada badha = Acute Kidney Injury (Emergency)

4. Blood Sugar Tests (Diabetes ki Jaanch)

TestNormalPre-DiabetesDiabetes
Fasting Blood Sugar< 100 mg/dL100-125> 126
PP Sugar (2 hr after meal)< 140 mg/dL140-199> 200
HbA1c< 5.7%5.7-6.4%> 6.5%
Random Blood Sugar< 140 mg/dL-> 200 with symptoms
HbA1c sabse reliable hai - pichle 3 mahine ka average blood sugar batata hai

5. Lipid Profile (Cholesterol / Dil ki Jaanch)

TestIdeal LevelDanger Level
Total Cholesterol< 200 mg/dL> 240 = High
LDL ("Bura" cholesterol)< 100 mg/dL> 160 = High risk
HDL ("Achha" cholesterol)Men > 40, Women > 50Kam hona bura hai
Triglycerides< 150 mg/dL> 200 = High
Diagnosis guide:
  • High LDL + Low HDL + High TG = Heart attack ka risk zyada
  • Fasting zaroori hai is test ke liye (8-10 ghante kuch nahi khana)

6. Thyroid Tests (TSH, T3, T4)

TestNormalAgar Badha/Ghata?
TSH0.4 - 4.0 mIU/LBadhna = Hypothyroidism; Ghata = Hyperthyroidism
Free T40.8 - 1.8 ng/dLGhata = Thyroid weak
Free T32.3 - 4.2 pg/mLBadhna = Thyroid overactive
Simple Rule:
  • TSH HIGH + T4 LOW = Hypothyroidism (weight gain, fatigue, thandi lagti hai)
  • TSH LOW + T4 HIGH = Hyperthyroidism (weight loss, palpitations, anxiety)

7. Inflammation Markers (Sujan ke Tests)

TestNormalMatlab
ESRMen < 15, Women < 20 mm/hrSujan, infection, TB mein badh jaata hai
CRP< 5 mg/LAcute infection ya inflammation mein bahut zyada badh jaata hai
Procalcitonin< 0.25 ng/mLSirf bacterial infection mein bahut badh jaata hai

⚠️ Diagnosis Kaise Hoti Hai - 5 Golden Rules

  1. Ek test se koi diagnosis NAHI hoti - Doctor symptoms + examination + multiple tests mika ke sochte hain
  2. Red/High/Low mark = Ghabrana mat - Mildly abnormal values aksar dehydration, dawaon ya temporary bimari se hoti hain
  3. Trend dekhna zaroori hai - Ek baar ka creatinine 1.5 alag baat hai, har baar badhta creatinine alag baat hai
  4. Reference ranges lab se lab alag hoti hain - Apne report ki reference range use karein jo print par di hoti hai
  5. Doctor ko puri history batayein - Koi bhi blood report sirf doctor ko milkar interpret karein - woh aapki age, weight, dawayein aur symptoms sabko saath mein consider karte hain

πŸ“‹ Quick Reference Card - Ek Nazar Mein

ReportKya DekheinAgar Abnormal
CBCHb, WBC, PlateletsAnemia / Infection / Bleeding
LFTSGPT, Bilirubin, AlbuminLiver damage / Jaundice
KFTCreatinine, eGFRKidney function
HbA1c% valueDiabetes control
Lipid ProfileLDL, HDLHeart disease risk
ThyroidTSHThyroid disorder

Important: Yeh guide samajhne ke liye hai. Diagnosis sirf qualified doctor hi kar sakta/sakti hai. Koi bhi report agar concern kar rahi hai toh doctor se milein - report ki photocopy, purani reports aur dawaaon ki list saath leke jaayein.

Icu ke investigation bhi bata do

Finding Sources
Finding Sources
Searching the Web

ICU critical care investigations ABG lactate troponin interpretation guide

Finding Sources
Finding Sources
Finding Sources
Reading File
Finding Sources
Finding Sources
Ab poori jankari aa gayi hai. Yahan ICU ki sabse important investigations ka complete guide hai:

πŸ₯ ICU Investigations - Complete Guide (Simple Hindi-English)


1. ABG - Arterial Blood Gas (Sabse Important ICU Test)

Kya hai: Artery se khoon nikaalkar oxygen, CO2 aur acid-base balance check kiya jaata hai. ICU mein yeh din mein kai baar hota hai.

Normal Values (Yaad kar lo!)

ParameterNormal ValueRange
pH7.407.35 - 7.45
PaCO240 mmHg38 - 42 mmHg
PO2100 mmHg75 - 100 mmHg
HCO3-24 mEq/L22 - 26 mEq/L
SpO298-100%> 95% normal
Base Excess0-4 to +4

ABG Padhne ke 5 Steps (Current Surgical Therapy):

Step 1 - pH dekho:
  • pH < 7.35 = Acidemia (Khoon zyada tezaab)
  • pH > 7.45 = Alkalemia (Khoon zyada khaari)
Step 2 - PaCO2 dekho (Respiratory component):
  • PaCO2 HIGH + pH LOW = Respiratory Acidosis (CO2 nahi nikla - lungs fail)
  • PaCO2 LOW + pH HIGH = Respiratory Alkalosis (zyada saans - hyperventilation)
Step 3 - HCO3 dekho (Metabolic component):
  • HCO3 LOW + pH LOW = Metabolic Acidosis (kidney fail, DKA, lactic acidosis)
  • HCO3 HIGH + pH HIGH = Metabolic Alkalosis (vomiting, diuretics)
Step 4 - Base Excess dekho:
  • < -4 = Base Deficit = Acidosis hai
  • +4 = Alkalosis hai
Step 5 - PO2 dekho:
  • PO2 < 60 = Hypoxemia - oxygen dena padega

4 Main ABG Disorders - Quick Table

DisorderpHPaCO2HCO3ICU mein Kab
Respiratory Acidosis↓↑↑ (compensate)Ventilator fail, COPD, drowning
Respiratory Alkalosis↑↓↓ (compensate)Anxiety, sepsis early stage, fever
Metabolic Acidosis↓↓ (compensate)↓DKA, kidney fail, shock, poisoning
Metabolic Alkalosis↑↑ (compensate)↑Zyada vomiting, NGT suction, diuretics

Winter's Formula (Metabolic Acidosis mein compensation check karna):

Expected PaCO2 = (1.5 Γ— HCO3) + 8 Β± 2
  • Agar actual PaCO2 = expected β†’ sirf metabolic acidosis
  • Agar actual PaCO2 > expected β†’ Mixed: Respiratory acidosis bhi hai
  • Agar actual PaCO2 < expected β†’ Mixed: Respiratory alkalosis bhi hai

2. Lactate (Tissue Hypoxia / Shock ka Marker)

LevelMatlabICU Action
< 2 mmol/LNormal
2-4 mmol/LMild elevationConcern - fluids, monitoring
> 4 mmol/LSevereShock - aggressive resuscitation
Badhta ja raha haiVery bad signOrgan failure ho rahi hai
Lactate kya batata hai:
  • Tissues ko oxygen nahi mil raha (anaerobic metabolism)
  • Septic shock, hemorrhagic shock, cardiac shock mein zyada badh jaata hai
  • Lactate clear ho raha hai = treatment kaam kar rahi hai βœ…
  • Lactate badhta ja raha hai = patient worse ho raha hai ❌

3. Troponin (Dil ke Damage ka Marker)

TestLevelMatlab
hs-Troponin I/T< 14 ng/L (lab-dependent)Normal
14-50 ng/LMildly elevatedMyocardial injury - non-cardiac cause possible
> 50 ng/L risingSignificantAcute MI - cardiology bulao
ICU mein Troponin kab badhta hai (Harrison's):
  • Heart attack (most common)
  • Sepsis mein bhi badhta hai (cardiac injury from toxins)
  • Pulmonary embolism (PE)
  • Myocarditis
  • Renal failure
  • Mechanical ventilation (high pressure)
⚠️ Important: ICU mein troponin positive = sirf heart attack nahi - full clinical picture dekho
Serial Troponin rule:
  • 0 hr + 3 hr + 6 hr repeat karo
  • Agar rise ho raha hai (delta troponin) = Active MI

4. Procalcitonin (PCT) - Infection vs Non-Infection

LevelMatlab
< 0.1 ng/mLNormal - No infection
0.1 - 0.5 ng/mLMild increase - local infection possible
0.5 - 2 ng/mLModerate - systemic infection
> 2 ng/mLSepsis likely
> 10 ng/mLSevere sepsis / Septic shock
PCT vs CRP:
  • PCT = Bacterial infection specific hai, viral mein zyada nahi badhta
  • CRP = Any inflammation mein badh jaata hai (infection, surgery, trauma)
  • ICU mein PCT se antibiotic start/stop decide karte hain

5. Coagulation Tests (Khoon Jamne ki Jaanch)

TestNormalICU Importance
PT (Prothrombin Time)11-13 secondsLiver function + clotting
INR0.8 - 1.2> 1.5 = Bleeding risk zyada
aPTT25-35 seconds> 45 = Heparin overdose or DIC
Fibrinogen200-400 mg/dL< 100 = DIC - emergency
D-Dimer< 500 ng/mLBadhna = DVT, PE, DIC
Platelet Count1.5 - 4 lakh< 50,000 = Transfusion consider

DIC (Disseminated Intravascular Coagulation) - Emergency:

  • INR HIGH + aPTT HIGH + Platelets LOW + Fibrinogen LOW + D-Dimer HIGH
  • Sepsis, trauma, burns, obstetric emergencies mein hota hai
  • Patient ek saath blood clot bhi bana raha hai aur bleed bhi kar raha hai

6. Electrolytes (ICU mein Roz Check hote hain)

ElectrolyteNormalDanger Signs
Sodium (Na)135-145 mEq/L< 120 = Seizures; > 155 = Brain shrinkage
Potassium (K)3.5-5.0 mEq/L< 3.0 = Arrhythmia; > 6.0 = Cardiac arrest
Calcium (Ca)8.5-10.5 mg/dL< 7 = Tetany; > 13 = Coma
Magnesium (Mg)1.7-2.2 mg/dL< 1.2 = Arrhythmia, seizures
Phosphate2.5-4.5 mg/dLBadhna = Kidney fail
Chloride98-106 mEq/LImbalance = Acid-base disorder

7. Renal Markers (Kidney ka ICU Monitoring)

TestCritical ValueMatlab
CreatinineRoz checkRoz > 0.3 mg rise = Acute Kidney Injury
BUN/UreaRising trendDialysis ka indication
Urine Output< 0.5 mL/kg/hr for 6 hrsOliguria = AKI Stage 1
eGFR< 30 = Severe damageDose adjustment zaroori
AKI (Acute Kidney Injury) - ICU Classification:
  • Stage 1: Creatinine 1.5x baseline ya urine output < 0.5 mL/kg/hr x 6 hrs
  • Stage 2: Creatinine 2x baseline
  • Stage 3: Creatinine 3x baseline - Dialysis consider karo

8. Liver Function (Critical Care mein)

TestCritical LevelMatlab
Bilirubin> 2 mg/dL + risingLiver failure ya bile duct problem
ALT/SGPT> 1000 U/LAcute liver necrosis (drug toxicity, ischemia)
Ammonia> 100 Β΅mol/LHepatic encephalopathy
Albumin< 2 g/dLCritical malnutrition, liver failure

9. Inflammatory / Sepsis Markers

TestNormalElevated Mein
WBC4,000-11,000> 12,000 ya < 4,000 = Sepsis criteria
CRP< 5 mg/L> 100 = Severe infection/inflammation
PCT< 0.1 ng/mL> 2 = Sepsis
ESR< 20 mm/hrChronic inflammation, TB
IL-6< 7 pg/mLCytokine storm (COVID, Sepsis) mein bahut badh jaata
Ferritin< 300 ng/mL> 1000 = Macrophage activation, Severe sepsis

10. Cardiac Monitoring Tests

TestNormalKab Order
BNP / NT-proBNP< 100 pg/mLHeart failure ki severity
Troponin (serial)Lab-dependentChest pain, ECG changes
CK-MB< 5%Old MI marker (ab troponin preferred)
Myoglobin< 90 ng/mLRhabdomyolysis (muscle crush injury)
NT-proBNP:
  • < 300 = Heart failure unlikely
  • 900 = Heart failure likely
  • 4500 = Severe heart failure

11. Glucose Monitoring (ICU mein Har 4-6 ghante)

LevelAction
< 70 mg/dLHypoglycemia - D50 dena = Emergency
70-180 mg/dLTarget range ICU mein
> 180 mg/dLInsulin infusion start karo
> 400 mg/dLDKA ya HHS check karo
ICU mein tight glucose control (target 140-180) mortality kam karta hai

12. Special ICU Tests

Cultures (Infection Source Dhundne ke liye):

CultureKabKya Batata Hai
Blood Culture x 2Fever spike ya sepsis mein - antibiotics se PEHLEBacteremia - kaunsa bacteria, kaunsi antibiotic
Urine CultureCatheter patients, UTI suspicionUrinary infection
Sputum CultureVentilated patients, pneumoniaLung infection
BAL (Bronchoalveolar Lavage)Ventilator-associated pneumoniaDeep lung infection
Wound SwabPost-op infectionSurgical site infection

Other Important Tests:

TestMatlab
Thyroid (TSH)Thyroid storm ya myxedema coma ICU admission mein
CortisolAdrenal insufficiency (Septic shock jo fluids se nahi sudhar raha)
Serum Osmolality275-295 mOsm/kg - Hypo/Hypernatremia management
Toxicology ScreenDrug overdose, poisoning cases
AmmoniaLiver failure, AMS cases

πŸ“Š ICU Daily Monitoring Checklist

TimeTests
Every 4-6 hrsBlood glucose, ABG (ventilated patients)
Every 8 hrsUrine output, vitals charting
Daily (Morning)CBC, Electrolytes, Creatinine, LFT, Coagulation
As neededBlood cultures, Troponin, PCT, Lactate
WeeklyThyroid, Nutritional markers (Albumin, Pre-albumin)

🚨 ICU Emergency Values - Turant Action Required!

TestPanic ValueAction
pH< 7.20 ya > 7.60Immediate ventilator change / bicarb
PO2< 50 mmHgOxygen/Intubation
Potassium< 2.5 ya > 6.5 mEq/LCardiac monitoring, correction
Glucose< 40 mg/dLD50 IV stat
Lactate> 8 mmol/LAggressive resuscitation
Platelet< 20,000Transfusion
INR> 5Vitamin K / FFP
CreatinineRoz double ho rahaNephrology consult / Dialysis
TroponinHigh + ECG changesCardiology consult stat

Yaad rakho: ICU mein ek akela test nahi, pattern + trend + clinical picture sab milake diagnosis hoti hai. Saari values ko ek saath dekho - yahi ICU medicine hai! πŸ₯

Explain ECG changes in ICU patients - ST elevation, arrhythmias

Reading File
Finding Sources
Finding Sources
Searching the Web

ICU ECG changes ST elevation arrhythmias interpretation guide critical care

Finding Sources
Finding Sources
Reading File
Reading File
Finding Sources
Reading File
Finding Sources
Excellent! Sari information aa gayi hai - textbooks se direct data hai. Ab ek comprehensive guide likhta hoon:

❀️ ICU mein ECG Changes - Complete Guide (Simple Hindi-English)


Pehle - ECG Basics Yaad Karo (Quick Recap)

P wave   = Atria ka activation (sinus node se)
PR interval = AV node se signal jaane ka time (Normal: 0.12-0.20 sec)
QRS complex = Ventricles ka activation (Normal: < 0.12 sec / 3 small boxes)
ST segment  = Ventricles repolarize ho rahe hain - YAHAN ISCHEMIA DIKHTI HAI
T wave   = Ventricle recovery
QT interval = Arrhythmia ka risk dikhaata hai (Normal: < 440ms men, < 460ms women)

PART 1 - ST CHANGES (Sabse Important ICU ECG Finding)


A) ST Elevation - Kab Hota Hai?

STEMI Criteria (Washington Manual / Rosen's):
PatientLead V2-V3Baaki Sabhi Leads
Men > 40 yrβ‰₯ 2 mmβ‰₯ 1 mm
Men < 40 yrβ‰₯ 2.5 mmβ‰₯ 1 mm
Womenβ‰₯ 1.5 mmβ‰₯ 1 mm
Rule: 2 ya zyada contiguous (saath wale) leads mein ST elevation = STEMI jab tak prove na ho otherwise

B) Konsi Leads = Konsi Wall = Konsi Artery?

STEMI LocationLeads Mein ChangesArtery Block
Anterior STEMIV1 - V4 elevationLAD (Left Anterior Descending)
Lateral STEMII, aVL, V5, V6 elevationLCX (Left Circumflex)
AnterolateralV1-V6 + I, aVLLAD proximal
Inferior STEMIII, III, aVF elevationRCA (Right Coronary Artery)
Right VentricularV3R, V4R elevationProximal RCA
Posterior STEMIV1-V3 mein ST DEPRESSIONLCX - missed hoti hai!
⚠️ Posterior STEMI - V1-V3 mein tall R waves + ST depression = Posterior leads (V7-V9) lagao - ST elevation milegi

C) Reciprocal Changes - Confirmation ka Sign

  • Anterior STEMI β†’ II, III, aVF mein ST depression
  • Inferior STEMI β†’ I, aVL mein ST depression
  • Reciprocal change milna = STEMI ki specificity badhti hai

D) ST Elevation Sirf STEMI nahi hota - Differential Diagnosis

ConditionECG PatternKaise Alag karein
STEMILocalized leads, reciprocal changesTroponin rise, symptoms
PericarditisDiffuse ST elevation - saari leads meinSaddle-shaped, PR depression, no reciprocal
Early RepolarizationV2-V4 mein, J-point notchingYoung healthy patients, no symptoms
LVHV5-V6 mein mild ST elevationVoltage criteria bhi hoga
LBBB (New)Pseudo-ST elevationWide QRS, Sgarbossa criteria use karo
Aortic DissectionIf coronary involved - localizedSudden severe tearing chest/back pain
Vasospasm (Prinzmetal)Transient elevation - comes and goesNo plaque, young, smoker

E) ST Depression - Kya Matlab?

PatternMatlab
Horizontal / Downsloping ST depressionNSTEMI / Unstable Angina - active ischemia
Upsloping ST depressionLess specific, but monitor
ST depression V1-V3 onlyPosterior MI rule out karo
Widespread ST depression + aVR elevationLeft main coronary stenosis - very dangerous

F) T Wave Changes

ChangeMatlab
Hyperacute T waves (tall, peaked, symmetric)Very early STEMI - first minutes
T wave inversionIschemia, PE, RVH, post-STEMI
Wellens' PatternBiphasic / deep T inversion V2-V3 = LAD stenosis - "LAD warning"
PseudonormalizationPreviously inverted T becomes "normal" during chest pain = Ischemia!
CVA T-wavesDeep wide T inversion - subarachnoid hemorrhage mein

PART 2 - ICU ARRHYTHMIAS


Arrhythmia Samajhne ka Framework

Pehle poochhte hain:
1. Rate kitna hai? (Tachy >100 / Brady <60)
2. Rhythm regular hai ya irregular?
3. QRS narrow hai (<0.12s) ya wide (>0.12s)?
4. P waves hain? PR normal hai?
5. Patient stable hai ya unstable?

TACHYARRHYTHMIAS (HR > 100)

1. Sinus Tachycardia

  • ECG: Normal P wave before every QRS, HR 100-150
  • ICU mein cause: Pain, fever, sepsis, hypovolemia, anxiety, PE, hyperthyroidism
  • Treatment: Cause treat karo - yeh secondary response hai, arrhythmia nahi

2. Atrial Fibrillation (AF) - ICU mein Most Common Arrhythmia

ECG Pattern:
- Irregularly IRREGULAR rhythm (sabase important feature)
- No visible P waves - sirf chaotic baseline
- QRS narrow (jab tak aberrant conduction na ho)
- Variable R-R intervals
Ventricular RateNaamICU Action
100-150 bpmAF with rapid ventricular responseRate control + anticoagulation
> 150 bpmHemodynamically unstable possibleConsider cardioversion
< 100 bpmAF with controlled rateMonitor
ICU mein AF kyun hota hai:
  • Sepsis (most common in ICU)
  • Post-cardiac surgery
  • Electrolyte imbalance (K+, Mg2+ low)
  • PE
  • Hyperthyroidism
Treatment (Rosen's):
  1. Unstable (BP low, chest pain, altered sensorium) β†’ DC Cardioversion stat
  2. Stable β†’ Rate control: Beta-blocker (metoprolol) ya Diltiazem
  3. Anticoagulation agar AF > 48 hrs (stroke risk)

3. Atrial Flutter

ECG Pattern:
- Regular "sawtooth" waves - flutter waves 300/min
- Ventricular rate typically 150 bpm (2:1 block)
- Regular rhythm
  • Treatment: AF jaise hi - rate control ya cardioversion

4. SVT - Supraventricular Tachycardia

ECG Pattern:
- Sudden onset narrow QRS tachycardia - HR 150-250
- P waves hidden in QRS ya uske baad
- Regular rhythm
- "Paroxysmal" - achanak shuru, achanak band
Treatment (Miller's Anesthesia):
  1. Vagal maneuvers (carotid sinus massage, Valsalva)
  2. Adenosine 6 mg IV rapid push - first line
  3. Diltiazem / Metoprolol agar adenosine fail
  4. Unstable β†’ DC Cardioversion
⚠️ Adenosine WPW ya AF mein avoid karo - AF with rapid response trigger ho sakti hai

5. Ventricular Tachycardia (VT) - ICU Emergency

ECG Pattern:
- Wide QRS (> 0.12 sec) tachycardia, HR > 100
- AV dissociation (P waves and QRS independent)
- Fusion beats / Capture beats - VT ka confirmation
- Monomorphic: Same shape QRS
- Polymorphic: Different shape QRS
TypeECGTreatment
VT Pulse hai, StableWide complex tachycardiaAmiodarone 150 mg IV
VT Pulse hai, UnstableSame + BP lowSynchronized Cardioversion
Pulseless VTWide complex, no pulseDefibrillation (unsynchronized) + CPR
Torsades de PointesTwisting QRS patternMgSO4 2g IV stat

6. Torsades de Pointes (TdP) - ICU Specific

ECG Pattern:
- Polymorphic VT
- QRS amplitude "twists" around baseline - helix shape
- Always with PROLONGED QT interval
- May degenerate to VF
ICU mein QT prolongation cause:
  • Hypokalemia, Hypomagnesemia (most common ICU cause)
  • Drugs: Amiodarone, haloperidol, methadone, azithromycin, ondansetron, many antibiotics
  • Hypothermia
  • Subarachnoid hemorrhage
Treatment:
  • MgSO4 2g IV over 5 min (even if Mg normal!)
  • Offending drug band karo
  • K+ correct karo (> 4.5 mEq/L target)
  • Temporary pacing agar bradycardia-dependent TdP

7. Ventricular Fibrillation (VF) - Cardiac Arrest

ECG Pattern:
- Chaotic, irregular, no recognizable QRS
- No P waves, no T waves
- No pulse - cardiac arrest
Treatment: Immediate Defibrillation (200J biphasic) + CPR
  • VF = Shockable rhythm

BRADYARRHYTHMIAS (HR < 60)

1. Sinus Bradycardia

  • HR < 60, normal P-QRS-T, regular
  • ICU causes: Hypothermia, hypothyroidism, raised ICP, beta-blocker overdose, vagal reflex
  • Treatment: If stable β†’ observe; Symptomatic β†’ Atropine 0.5 mg IV

2. AV Blocks - 3 Types (Harrison's / Goldman-Cecil)

BlockECG FindingICU SignificanceTreatment
1st DegreePR > 0.20 sec (5 small boxes) - every P conductsBenign, no treatmentMonitor, check drugs
2nd Degree Mobitz I (Wenckebach)PR gradually lengthens then P drops (no QRS)Usually benign, may progressAtropine if symptomatic
2nd Degree Mobitz IIPR fixed, suddenly P drops - no QRSDangerous - can go to complete blockPacing ready karo
3rd Degree (Complete Heart Block)P waves aur QRS completely independent - dissociationEmergency - very low HR, no cardiac outputEmergency pacing
Mobitz II + Complete Block = Pacemaker indication - cardiology bulao stat!

ICU mein Electrolytes aur ECG Changes (Harrison's)

Hyperkalemia (K+ > 5.5) - Progressive ECG Changes:

Early:   Tall PEAKED (tented) T waves ← Pehla sign
↓
Moderate: PR prolongation + P wave flattening
↓
Severe:  Wide QRS (sine wave pattern)
↓
Critical: Asystole / VF β†’ Cardiac arrest
Treatment sequence: Calcium gluconate β†’ Insulin+Dextrose β†’ Salbutamol β†’ Kayexalate / Dialysis

Hypokalemia (K+ < 3.5) - ECG Changes:

- ST depression
- T wave flattening / inversion
- Prominent U waves (after T wave)
- QT prolongation β†’ Torsades risk
ICU mein K+ target: > 4.0 mEq/L (especially in cardiac patients)

Hypocalcemia:

  • QT prolongation (specifically QTc lengthening)
  • Risk of Torsades

Hypercalcemia:

  • QT shortening
  • J-point elevation

Hypothermia (Temp < 32Β°C):

  • Osborn Wave (J wave) - characteristic notch at J point
  • Bradycardia
  • QT prolongation
  • Risk of VF

PART 3 - Special ICU ECG Patterns


1. Pericarditis

ECG:
- Diffuse ST elevation - SAARI leads mein (not localized)
- Saddle-shaped ST segment
- PR depression (pathognomonic)
- No reciprocal changes

2. Pulmonary Embolism (PE)

Classic Pattern: S1Q3T3
- S wave in Lead I
- Q wave in Lead III
- T inversion in Lead III
(Present sirf 20% mein - low sensitivity)

Common findings:
- Sinus tachycardia (most common)
- New RBBB
- Right heart strain: T inversion V1-V4
- AF

3. Digoxin Effect vs Toxicity

Effect (therapeutic):
- "Scooped" / Salvador Dali moustache ST depression
- QT shortening

Toxicity:
- Bradycardia + AV blocks
- VT / VF
- "Bidirectional VT" - digoxin toxicity pathognomonic

4. Cardiac Tamponade

ECG:
- Low voltage (small QRS everywhere)
- Electrical alternans - QRS size beat to beat change karta hai
- Sinus tachycardia
- Confirm with Echo
Emergency pericardiocentesis

🚨 ICU ECG Emergency Decision Tree

ECG Abnormal hai?
        |
   ______|______
  |             |
Patient       Patient
UNSTABLE      STABLE
  |               |
Immediate      Diagnose
DC Shock /     aur treat
Defib / CPR    cause

UNSTABLE = Low BP + Chest pain + Altered sensorium + Low SpO2

πŸ“‹ Quick Reference Card - ICU ECG at a Glance

FindingThinkAction
ST elevation 2+ contiguous leadsSTEMICath lab activate - Door to balloon < 90 min
Diffuse ST elevation + PR depressionPericarditisEcho, NSAIDs/Colchicine
Irregular irregular + no P wavesAtrial FibrillationRate control, anticoag
Wide QRS tachycardiaVTAmiodarone / Cardioversion
Chaotic baseline, no QRSVFDefibrillate immediately!
Tall peaked T wavesHyperkalemiaCalcium gluconate stat
Prominent U wavesHypokalemiaK+ replacement
QT > 500msTorsades riskStop offending drugs, give Mg
P-QRS dissociationComplete heart blockEmergency pacing
Low voltage + Electrical alternansCardiac tamponadePericardiocentesis
S1Q3T3 + tachycardiaPECT-PA, anticoagulation
J-wave (Osborn wave)HypothermiaRewarm

Golden Rule: ICU mein ECG sirf monitor nahi, diagnostic tool hai. Har nayi ECG ko pehli wali se compare karo. "New changes" = "New problem" - always investigate! - Rosen's Emergency Medicine

Create a visual ECG pattern reference PDF for quick ICU bedside use

Reading File
Running Command

mkdir -p /home/daytona/workspace/ecg-reference && ls /home/daytona/workspace/

Writing File

~/ecg-reference/generate_ecg_pdf.py

#!/usr/bin/env python3
"""
ICU ECG Pattern Reference PDF Generator
Visual quick-reference for bedside use
"""

from reportlab.lib.pagesizes import A4
from reportlab.lib import colors
from reportlab.lib.units import cm, mm
from reportlab.platypus import (
    SimpleDocTemplate, Paragraph, Spacer, Table, TableStyle,
    HRFlowable, KeepTogether, PageBreak
)
from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
from reportlab.lib.enums import TA_CENTER, TA_LEFT, TA_RIGHT
from reportlab.graphics.shapes import (
    Drawing, PolyLine, Rect, String, Line, Circle, Group
)
from reportlab.graphics import renderPDF
from reportlab.platypus import Flowable
import math

# ── Color Palette ────────────────────────────────────────────────────────────
RED       = colors.HexColor('#C0392B')
DARK_RED  = colors.HexColor('#7B241C')
GREEN     = colors.HexColor('#1E8449')
DARK_GREEN= colors.HexColor('#145A32')
BLUE      = colors.HexColor('#1A5276')
LIGHT_BLUE= colors.HexColor('#2E86C1')
ORANGE    = colors.HexColor('#D35400')
PURPLE    = colors.HexColor('#6C3483')
DARK_GRAY = colors.HexColor('#2C3E50')
MID_GRAY  = colors.HexColor('#7F8C8D')
LIGHT_GRAY= colors.HexColor('#F2F3F4')
ECG_BG    = colors.HexColor('#FFF9F9')
ECG_GRID  = colors.HexColor('#FFCCCC')
ECG_LINE  = colors.HexColor('#C0392B')
WHITE     = colors.white
BLACK     = colors.black
YELLOW_BG = colors.HexColor('#FDFEFE')
HEADER_BG = colors.HexColor('#1A5276')
ALERT_BG  = colors.HexColor('#FDEDEC')
INFO_BG   = colors.HexColor('#EBF5FB')
WARN_BG   = colors.HexColor('#FEF9E7')
GOOD_BG   = colors.HexColor('#EAFAF1')

# ── ECG Waveform Drawing Flowable ────────────────────────────────────────────

class ECGWaveform(Flowable):
    """Draw an ECG waveform with grid background and labeling."""

    def __init__(self, width, height, points, label="", color=None,
                 show_grid=True, label_points=None, bg_color=None):
        Flowable.__init__(self)
        self.width = width
        self.height = height
        self.points = points          # list of (x, y) in 0-1 space
        self.label = label
        self.color = color or ECG_LINE
        self.show_grid = show_grid
        self.label_points = label_points or []   # [(x, y, text), ...]
        self.bg_color = bg_color or ECG_BG

    def draw(self):
        c = self.canv
        w, h = self.width, self.height
        pad = 4

        # Background
        c.setFillColor(self.bg_color)
        c.roundRect(0, 0, w, h, 3, fill=1, stroke=0)

        # Grid lines
        if self.show_grid:
            c.setStrokeColor(ECG_GRID)
            c.setLineWidth(0.3)
            # Vertical grid every ~5mm
            step = w / 20
            for i in range(1, 20):
                c.line(i * step, pad, i * step, h - pad)
            # Horizontal grid every 25% height
            for frac in [0.25, 0.5, 0.75]:
                y = pad + frac * (h - 2 * pad)
                c.line(pad, y, w - pad, y)

        # Border
        c.setStrokeColor(colors.HexColor('#DDDDDD'))
        c.setLineWidth(0.5)
        c.roundRect(0, 0, w, h, 3, fill=0, stroke=1)

        # Waveform
        if len(self.points) >= 2:
            c.setStrokeColor(self.color)
            c.setLineWidth(1.8)
            path = c.beginPath()
            x0 = pad + self.points[0][0] * (w - 2 * pad)
            y0 = pad + self.points[0][1] * (h - 2 * pad)
            path.moveTo(x0, y0)
            for px, py in self.points[1:]:
                x = pad + px * (w - 2 * pad)
                y = pad + py * (h - 2 * pad)
                path.lineTo(x, y)
            c.drawPath(path, stroke=1, fill=0)

        # Baseline reference (dotted)
        c.setStrokeColor(MID_GRAY)
        c.setLineWidth(0.4)
        c.setDash([2, 3])
        mid_y = pad + 0.35 * (h - 2 * pad)
        c.line(pad, mid_y, w - pad, mid_y)
        c.setDash([])

        # Annotation labels on waveform
        c.setFont("Helvetica-Bold", 6.5)
        for lx, ly, lt in self.label_points:
            x = pad + lx * (w - 2 * pad)
            y = pad + ly * (h - 2 * pad)
            c.setFillColor(DARK_GRAY)
            c.drawCentredString(x, y, lt)

        # Label bottom-left
        if self.label:
            c.setFont("Helvetica-Bold", 7.5)
            c.setFillColor(DARK_GRAY)
            c.drawString(5, 4, self.label)


def make_ecg(width, height, pattern_type, **kwargs):
    """Factory – returns an ECGWaveform for the named pattern."""

    baseline = 0.35   # y-fraction for isoelectric line
    top = 0.92
    peak_qrs = 0.95
    trough_qrs = 0.02
    mid = 0.5

    # ── helpers ────────────────────────────────────────────────────────
    def segment(x0, y0, x1, y1, n=2):
        """Straight segment as list of points."""
        return [(x0 + (x1 - x0) * i / (n - 1),
                 y0 + (y1 - y0) * i / (n - 1)) for i in range(n)]

    def p_wave(cx, amp=0.12, w=0.06):
        """Smooth P wave (half-sine)."""
        pts = []
        for i in range(12):
            t = i / 11
            pts.append((cx - w / 2 + t * w, baseline + amp * math.sin(math.pi * t)))
        return pts

    def normal_beat(offset=0.0, scale=1.0):
        """One normal PQRST beat."""
        b = baseline
        pts = []
        # Baseline approach
        pts += segment(offset + 0.00, b, offset + 0.05, b)
        # P wave
        pts += p_wave(offset + 0.09, amp=0.10 * scale)
        # PR segment
        pts += segment(offset + 0.12, b, offset + 0.17, b)
        # Q
        pts += segment(offset + 0.17, b, offset + 0.19, b - 0.06 * scale)
        # R
        pts += segment(offset + 0.19, b - 0.06 * scale, offset + 0.21, b + 0.55 * scale)
        # S
        pts += segment(offset + 0.21, b + 0.55 * scale, offset + 0.23, b - 0.08 * scale)
        # Return to baseline
        pts += segment(offset + 0.23, b - 0.08 * scale, offset + 0.26, b)
        # ST segment (flat at baseline)
        pts += segment(offset + 0.26, b, offset + 0.32, b)
        # T wave
        pts += p_wave(offset + 0.37, amp=0.13 * scale, w=0.10)
        # Return to baseline
        pts += segment(offset + 0.43, b, offset + 0.50, b)
        return pts

    def st_elevation_beat(offset=0.0, elev=0.15):
        """Beat with ST elevation."""
        b = baseline
        pts = []
        pts += segment(offset + 0.00, b, offset + 0.05, b)
        pts += p_wave(offset + 0.09, amp=0.10)
        pts += segment(offset + 0.12, b, offset + 0.17, b)
        pts += segment(offset + 0.17, b, offset + 0.19, b - 0.06)
        pts += segment(offset + 0.19, b - 0.06, offset + 0.21, b + 0.55)
        pts += segment(offset + 0.21, b + 0.55, offset + 0.24, b - 0.04)
        # ST elevated & straight/oblique
        pts += segment(offset + 0.24, b - 0.04, offset + 0.26, b + elev)
        pts += segment(offset + 0.26, b + elev, offset + 0.33, b + elev)
        # T wave (tall hyperacute-ish)
        pts += p_wave(offset + 0.38, amp=0.18, w=0.10)
        pts += segment(offset + 0.43, b, offset + 0.50, b)
        return pts

    def st_depression_beat(offset=0.0, dep=0.12):
        """Beat with horizontal ST depression."""
        b = baseline
        pts = []
        pts += segment(offset + 0.00, b, offset + 0.05, b)
        pts += p_wave(offset + 0.09, amp=0.10)
        pts += segment(offset + 0.12, b, offset + 0.17, b)
        pts += segment(offset + 0.17, b, offset + 0.19, b - 0.06)
        pts += segment(offset + 0.19, b - 0.06, offset + 0.21, b + 0.55)
        pts += segment(offset + 0.21, b + 0.55, offset + 0.24, b - 0.04)
        pts += segment(offset + 0.24, b - 0.04, offset + 0.26, b - dep)
        pts += segment(offset + 0.26, b - dep, offset + 0.33, b - dep)
        pts += p_wave(offset + 0.37, amp=0.10, w=0.10)
        pts += segment(offset + 0.43, b, offset + 0.50, b)
        return pts

    def t_inversion_beat(offset=0.0):
        """Beat with inverted T wave."""
        b = baseline
        pts = []
        pts += segment(offset + 0.00, b, offset + 0.05, b)
        pts += p_wave(offset + 0.09, amp=0.10)
        pts += segment(offset + 0.12, b, offset + 0.17, b)
        pts += segment(offset + 0.17, b, offset + 0.19, b - 0.06)
        pts += segment(offset + 0.19, b - 0.06, offset + 0.21, b + 0.55)
        pts += segment(offset + 0.21, b + 0.55, offset + 0.24, b - 0.04)
        pts += segment(offset + 0.24, b - 0.04, offset + 0.26, b)
        pts += segment(offset + 0.26, b, offset + 0.33, b)
        # Inverted T
        for i in range(12):
            t = i / 11
            cx = offset + 0.37
            w2 = 0.10
            x = cx - w2 / 2 + t * w2
            y = b - 0.13 * math.sin(math.pi * t)
            pts.append((x, y))
        pts += segment(offset + 0.43, b, offset + 0.50, b)
        return pts

    def af_beat(offset=0.0):
        """Irregular AF-like beat (no P, narrow QRS, irregular baseline)."""
        b = baseline
        pts = []
        # Fibrillatory baseline
        for i in range(30):
            x = offset + i * 0.006
            y = b + 0.03 * math.sin(i * 1.8) + 0.02 * math.sin(i * 3.5)
            pts.append((x, y))
        # QRS at irregular position
        qrs_x = offset + 0.18
        pts += segment(qrs_x, b, qrs_x + 0.01, b - 0.04)
        pts += segment(qrs_x + 0.01, b - 0.04, qrs_x + 0.03, b + 0.55)
        pts += segment(qrs_x + 0.03, b + 0.55, qrs_x + 0.05, b - 0.06)
        pts += segment(qrs_x + 0.05, b - 0.06, qrs_x + 0.07, b)
        # More fibbrillation
        for i in range(18):
            x = offset + 0.26 + i * 0.006
            y = b + 0.025 * math.sin(i * 2.1) + 0.015 * math.sin(i * 4.0)
            pts.append((x, y))
        # Another QRS at different spacing
        qrs2 = offset + 0.38
        pts += segment(qrs2, b, qrs2 + 0.01, b - 0.04)
        pts += segment(qrs2 + 0.01, b - 0.04, qrs2 + 0.03, b + 0.52)
        pts += segment(qrs2 + 0.03, b + 0.52, qrs2 + 0.05, b - 0.05)
        pts += segment(qrs2 + 0.05, b - 0.05, qrs2 + 0.07, b)
        # Tail
        for i in range(10):
            x = offset + 0.46 + i * 0.004
            y = b + 0.02 * math.sin(i * 2.5)
            pts.append((x, y))
        return pts

    def vt_beat(offset=0.0, n=2):
        """Wide complex VT beats."""
        b = baseline
        pts = []
        for beat in range(n):
            o = offset + beat * 0.45
            pts += segment(o + 0.00, b, o + 0.03, b)
            # Wide bizarre QRS
            pts += segment(o + 0.03, b, o + 0.06, b + 0.20)
            pts += segment(o + 0.06, b + 0.20, o + 0.10, b + 0.65)
            pts += segment(o + 0.10, b + 0.65, o + 0.14, b - 0.05)
            pts += segment(o + 0.14, b - 0.05, o + 0.20, b + 0.08)
            pts += segment(o + 0.20, b + 0.08, o + 0.24, b - 0.03)
            pts += segment(o + 0.24, b - 0.03, o + 0.28, b)
            pts += segment(o + 0.28, b, o + 0.32, b)
            # Discordant T
            for i in range(8):
                t = i / 7
                cx = o + 0.37
                x = cx - 0.06 + t * 0.12
                y = b - 0.10 * math.sin(math.pi * t)
                pts.append((x, y))
            pts += segment(o + 0.44, b, o + 0.45, b)
        return pts

    def vf_wave(offset=0.0):
        """VF - chaotic undulation."""
        b = baseline
        pts = []
        for i in range(120):
            x = offset + i * 0.008
            if x > 1.0:
                break
            amp = 0.25 + 0.10 * math.sin(i * 0.7)
            y = b + amp * math.sin(i * 0.9 + 1.2) * math.cos(i * 0.4)
            pts.append((x, y))
        return pts

    def flutter_wave(offset=0.0):
        """Atrial flutter sawtooth."""
        b = baseline
        pts = []
        # Regular sawtooth flutter waves
        for wave in range(6):
            o = offset + wave * 0.12
            pts += segment(o + 0.00, b, o + 0.07, b + 0.22)
            pts += segment(o + 0.07, b + 0.22, o + 0.12, b)
        # One QRS (2:1)
        qrs_x = offset + 0.24
        pts += segment(qrs_x, b, qrs_x + 0.01, b - 0.03)
        pts += segment(qrs_x + 0.01, b - 0.03, qrs_x + 0.025, b + 0.55)
        pts += segment(qrs_x + 0.025, b + 0.55, qrs_x + 0.04, b - 0.05)
        pts += segment(qrs_x + 0.04, b - 0.05, qrs_x + 0.06, b)
        # More flutter
        for wave in range(5):
            o = offset + 0.31 + wave * 0.12
            pts += segment(o + 0.00, b, o + 0.07, b + 0.22)
            pts += segment(o + 0.07, b + 0.22, o + 0.12, b)
        # Second QRS
        qrs2 = offset + 0.61
        pts += segment(qrs2, b, qrs2 + 0.01, b - 0.03)
        pts += segment(qrs2 + 0.01, b - 0.03, qrs2 + 0.025, b + 0.55)
        pts += segment(qrs2 + 0.025, b + 0.55, qrs2 + 0.04, b - 0.05)
        pts += segment(qrs2 + 0.04, b - 0.05, qrs2 + 0.06, b)
        for i in range(15):
            o2 = offset + 0.68 + i * 0.02
            pts.append((o2, b + 0.18 * math.sin(i * 1.6)))
        return pts

    def heart_block_3rd(offset=0.0):
        """3rd degree heart block - P waves marching through, QRS escape."""
        b = baseline
        pts = []
        pts += segment(offset + 0.00, b, offset + 0.03, b)
        # P wave 1
        pts += p_wave(offset + 0.06, amp=0.10)
        pts += segment(offset + 0.10, b, offset + 0.15, b)
        # QRS escape (narrow, slow)
        pts += segment(offset + 0.15, b, offset + 0.17, b - 0.04)
        pts += segment(offset + 0.17, b - 0.04, offset + 0.19, b + 0.45)
        pts += segment(offset + 0.19, b + 0.45, offset + 0.21, b - 0.05)
        pts += segment(offset + 0.21, b - 0.05, offset + 0.23, b)
        pts += segment(offset + 0.23, b, offset + 0.28, b)
        # P wave 2 (different timing from QRS)
        pts += p_wave(offset + 0.31, amp=0.10)
        pts += segment(offset + 0.35, b, offset + 0.38, b)
        # P wave 3
        pts += p_wave(offset + 0.44, amp=0.10)
        pts += segment(offset + 0.48, b, offset + 0.50, b)
        # Another escape QRS
        pts += segment(offset + 0.50, b, offset + 0.52, b - 0.04)
        pts += segment(offset + 0.52, b - 0.04, offset + 0.54, b + 0.45)
        pts += segment(offset + 0.54, b + 0.45, offset + 0.56, b - 0.05)
        pts += segment(offset + 0.56, b - 0.05, offset + 0.58, b)
        # P wave 4
        pts += segment(offset + 0.58, b, offset + 0.64, b)
        pts += p_wave(offset + 0.67, amp=0.10)
        pts += segment(offset + 0.72, b, offset + 0.80, b)
        # P wave 5
        pts += p_wave(offset + 0.83, amp=0.10)
        pts += segment(offset + 0.87, b, offset + 1.00, b)
        return pts

    def hyperkalemia_ecg(offset=0.0):
        """Tall tented T waves + wide QRS (moderate hyperK)."""
        b = baseline
        pts = []
        pts += segment(offset + 0.00, b, offset + 0.05, b)
        # Flat/absent P
        pts += segment(offset + 0.05, b, offset + 0.11, b + 0.03)
        pts += segment(offset + 0.11, b + 0.03, offset + 0.15, b)
        pts += segment(offset + 0.15, b, offset + 0.18, b)
        # Wide QRS
        pts += segment(offset + 0.18, b, offset + 0.20, b - 0.04)
        pts += segment(offset + 0.20, b - 0.04, offset + 0.23, b + 0.52)
        pts += segment(offset + 0.23, b + 0.52, offset + 0.29, b - 0.06)
        pts += segment(offset + 0.29, b - 0.06, offset + 0.33, b)
        pts += segment(offset + 0.33, b, offset + 0.36, b)
        # Tall symmetric (tented) T wave
        for i in range(16):
            t = i / 15
            cx = offset + 0.43
            x = cx - 0.07 + t * 0.14
            y = b + 0.42 * math.sin(math.pi * t)  # Very tall!
            pts.append((x, y))
        pts += segment(offset + 0.50, b, offset + 0.55, b)
        return pts

    def hypokalemia_ecg(offset=0.0):
        """Flat T + prominent U wave."""
        b = baseline
        pts = []
        pts += segment(offset + 0.00, b, offset + 0.05, b)
        pts += p_wave(offset + 0.09, amp=0.10)
        pts += segment(offset + 0.12, b, offset + 0.17, b)
        pts += segment(offset + 0.17, b, offset + 0.19, b - 0.04)
        pts += segment(offset + 0.19, b - 0.04, offset + 0.21, b + 0.50)
        pts += segment(offset + 0.21, b + 0.50, offset + 0.23, b - 0.05)
        pts += segment(offset + 0.23, b - 0.05, offset + 0.26, b)
        pts += segment(offset + 0.26, b, offset + 0.30, b)
        # Flat/small T
        for i in range(8):
            t = i / 7
            cx = offset + 0.33
            x = cx - 0.04 + t * 0.08
            y = b + 0.04 * math.sin(math.pi * t)
            pts.append((x, y))
        # U wave
        pts += segment(offset + 0.38, b, offset + 0.40, b)
        for i in range(10):
            t = i / 9
            cx = offset + 0.44
            x = cx - 0.04 + t * 0.08
            y = b + 0.11 * math.sin(math.pi * t)
            pts.append((x, y))
        pts += segment(offset + 0.49, b, offset + 0.55, b)
        return pts

    def pericarditis_ecg(offset=0.0):
        """Diffuse saddle-shaped ST elevation + PR depression."""
        b = baseline
        pts = []
        pts += segment(offset + 0.00, b, offset + 0.05, b)
        pts += p_wave(offset + 0.09, amp=0.10)
        # PR depression
        pts += segment(offset + 0.12, b, offset + 0.13, b - 0.04)
        pts += segment(offset + 0.13, b - 0.04, offset + 0.17, b - 0.04)
        pts += segment(offset + 0.17, b - 0.04, offset + 0.19, b - 0.04)
        pts += segment(offset + 0.19, b - 0.04, offset + 0.21, b + 0.48)
        pts += segment(offset + 0.21, b + 0.48, offset + 0.23, b - 0.02)
        # Saddle-shaped ST elevation (curved upward)
        for i in range(12):
            t = i / 11
            x = offset + 0.24 + t * 0.12
            # Saddle = concave upward
            y = b + 0.12 - 0.04 * math.cos(math.pi * t)
            pts.append((x, y))
        # T wave (upright, following ST)
        pts += p_wave(offset + 0.40, amp=0.16, w=0.10)
        pts += segment(offset + 0.46, b, offset + 0.55, b)
        return pts

    def torsades_ecg(offset=0.0):
        """Torsades de pointes - twisting QRS."""
        b = baseline
        pts = []
        for beat in range(5):
            o = offset + beat * 0.19
            phase = beat * math.pi * 0.7
            amp = 0.55 * math.sin(phase + 0.5)
            sign = 1 if amp > 0 else -1
            amp = max(0.25, abs(amp)) * sign
            # Brief QRS
            pts += segment(o, b, o + 0.02, b + amp * 0.3)
            pts += segment(o + 0.02, b + amp * 0.3, o + 0.05, b + amp)
            pts += segment(o + 0.05, b + amp, o + 0.08, b - amp * 0.2)
            pts += segment(o + 0.08, b - amp * 0.2, o + 0.10, b)
            # Discordant T
            for i in range(6):
                t2 = i / 5
                x = o + 0.12 + t2 * 0.06
                y = b - amp * 0.3 * math.sin(math.pi * t2)
                pts.append((x, y))
            pts += segment(o + 0.18, b, o + 0.19, b)
        return pts

    def prolonged_qt(offset=0.0):
        """Normal QRS, prolonged QT interval."""
        b = baseline
        pts = []
        pts += segment(offset + 0.00, b, offset + 0.04, b)
        pts += p_wave(offset + 0.08, amp=0.10)
        pts += segment(offset + 0.11, b, offset + 0.15, b)
        pts += segment(offset + 0.15, b, offset + 0.17, b - 0.04)
        pts += segment(offset + 0.17, b - 0.04, offset + 0.19, b + 0.52)
        pts += segment(offset + 0.19, b + 0.52, offset + 0.21, b - 0.05)
        pts += segment(offset + 0.21, b - 0.05, offset + 0.24, b)
        # Very prolonged ST before T wave
        pts += segment(offset + 0.24, b, offset + 0.42, b)
        # T wave
        pts += p_wave(offset + 0.47, amp=0.12, w=0.10)
        pts += segment(offset + 0.53, b, offset + 0.60, b)
        return pts

    def wenckebach_ecg(offset=0.0):
        """Mobitz I - PR progressively lengthens, then dropped beat."""
        b = baseline
        pts = []
        pr_delays = [0.04, 0.06, 0.09]  # Increasing PR
        beat_starts = [0.00, 0.22, 0.46]
        for i, (bs, pr) in enumerate(zip(beat_starts, pr_delays)):
            o = offset + bs
            pts += segment(o, b, o + 0.02, b)
            pts += p_wave(o + 0.03, amp=0.09)
            pts += segment(o + 0.06, b, o + 0.06 + pr, b)
            qrs_start = o + 0.06 + pr
            pts += segment(qrs_start, b, qrs_start + 0.01, b - 0.03)
            pts += segment(qrs_start + 0.01, b - 0.03, qrs_start + 0.03, b + 0.45)
            pts += segment(qrs_start + 0.03, b + 0.45, qrs_start + 0.05, b - 0.04)
            pts += segment(qrs_start + 0.05, b - 0.04, qrs_start + 0.07, b)
            pts += segment(qrs_start + 0.07, b, qrs_start + 0.10, b)
            pts += p_wave(qrs_start + 0.12, amp=0.09, w=0.05)
            pts += segment(qrs_start + 0.16, b, qrs_start + 0.20, b)
        # Dropped beat - just P wave, no QRS
        o_drop = offset + 0.73
        pts += p_wave(o_drop, amp=0.09)
        pts += segment(o_drop + 0.04, b, o_drop + 0.27, b)
        return pts

    # ── Pattern dispatch ────────────────────────────────────────────────
    patterns = {
        'normal':        (normal_beat(0.05) + normal_beat(0.55),
                          [(0.26, 0.96, 'P'), (0.31, 0.98, 'Q'), (0.33, 0.99, 'R'),
                           (0.35, 0.97, 'S'), (0.44, 0.93, 'T')]),
        'st_elevation':  (st_elevation_beat(0.05) + st_elevation_beat(0.55),
                          [(0.36, 0.97, 'ST↑')]),
        'st_depression': (st_depression_beat(0.05) + st_depression_beat(0.55),
                          [(0.36, 0.97, 'ST↓')]),
        't_inversion':   (t_inversion_beat(0.05) + t_inversion_beat(0.55),
                          [(0.44, 0.97, '-T')]),
        'af':            (af_beat(0.00), [(0.15, 0.97, 'No P')]),
        'flutter':       (flutter_wave(0.00), [(0.07, 0.96, 'Sawtooth')]),
        'vt':            (vt_beat(0.02, n=2), [(0.15, 0.97, 'Wide QRS')]),
        'vf':            (vf_wave(0.00), [(0.50, 0.97, 'Chaotic')]),
        'chb':           (heart_block_3rd(0.00), [(0.50, 0.97, 'P≠QRS')]),
        'hyperkalemia':  (hyperkalemia_ecg(0.05), [(0.43, 0.97, 'Tall T')]),
        'hypokalemia':   (hypokalemia_ecg(0.05), [(0.44, 0.97, 'U wave')]),
        'pericarditis':  (pericarditis_ecg(0.05), [(0.30, 0.97, 'Saddle ST↑')]),
        'torsades':      (torsades_ecg(0.00), [(0.50, 0.97, 'Twisting')]),
        'prolonged_qt':  (prolonged_qt(0.05), [(0.38, 0.97, 'Long QT')]),
        'wenckebach':    (wenckebach_ecg(0.00), [(0.88, 0.97, 'Drop')]),
    }

    pts_data, lp = patterns.get(pattern_type, patterns['normal'])
    color = kwargs.pop('color', ECG_LINE)
    label = kwargs.pop('label', '')
    return ECGWaveform(width, height, pts_data, label=label, color=color,
                       label_points=lp, **kwargs)


# ── Styled helpers ────────────────────────────────────────────────────────────

def build_styles():
    styles = getSampleStyleSheet()

    styles.add(ParagraphStyle('DocTitle',
        fontSize=22, fontName='Helvetica-Bold',
        textColor=WHITE, alignment=TA_CENTER, spaceAfter=2))
    styles.add(ParagraphStyle('DocSubtitle',
        fontSize=11, fontName='Helvetica',
        textColor=colors.HexColor('#AED6F1'), alignment=TA_CENTER, spaceAfter=0))
    styles.add(ParagraphStyle('SectionHeader',
        fontSize=12, fontName='Helvetica-Bold',
        textColor=WHITE, alignment=TA_LEFT, spaceAfter=3,
        leftIndent=4))
    styles.add(ParagraphStyle('CardTitle',
        fontSize=9.5, fontName='Helvetica-Bold',
        textColor=DARK_GRAY, spaceAfter=1, leftIndent=2))
    styles.add(ParagraphStyle('CardBody',
        fontSize=7.5, fontName='Helvetica',
        textColor=DARK_GRAY, spaceAfter=1, leftIndent=2, leading=10))
    styles.add(ParagraphStyle('AlertText',
        fontSize=7.5, fontName='Helvetica-Bold',
        textColor=RED, spaceAfter=1, leftIndent=2))
    styles.add(ParagraphStyle('GoodText',
        fontSize=7.5, fontName='Helvetica-Bold',
        textColor=DARK_GREEN, spaceAfter=1, leftIndent=2))
    styles.add(ParagraphStyle('TableHeader',
        fontSize=8, fontName='Helvetica-Bold',
        textColor=WHITE, alignment=TA_CENTER))
    styles.add(ParagraphStyle('TableCell',
        fontSize=7.5, fontName='Helvetica',
        textColor=DARK_GRAY, alignment=TA_LEFT, leading=10))
    styles.add(ParagraphStyle('TableCellBold',
        fontSize=7.5, fontName='Helvetica-Bold',
        textColor=DARK_GRAY, alignment=TA_LEFT))
    styles.add(ParagraphStyle('FooterText',
        fontSize=6.5, fontName='Helvetica',
        textColor=MID_GRAY, alignment=TA_CENTER))
    styles.add(ParagraphStyle('PageTitle',
        fontSize=13, fontName='Helvetica-Bold',
        textColor=WHITE, alignment=TA_LEFT, spaceAfter=2, leftIndent=6))
    return styles


def section_header(title, styles, bg=HEADER_BG):
    """Colored section header bar."""
    return Table(
        [[Paragraph(title, styles['SectionHeader'])]],
        colWidths=[17.5 * cm],
        style=TableStyle([
            ('BACKGROUND', (0, 0), (-1, -1), bg),
            ('TOPPADDING', (0, 0), (-1, -1), 5),
            ('BOTTOMPADDING', (0, 0), (-1, -1), 5),
            ('LEFTPADDING', (0, 0), (-1, -1), 6),
            ('ROUNDEDCORNERS', [4, 4, 4, 4]),
        ])
    )


def ecg_card(waveform, title, bullets, styles, bg=ECG_BG, alert=False):
    """A single ECG pattern card: waveform + description."""
    title_color = RED if alert else BLUE
    title_style = ParagraphStyle('_ct', fontSize=9, fontName='Helvetica-Bold',
                                 textColor=title_color, spaceAfter=2, leftIndent=2)
    bullet_style = ParagraphStyle('_cb', fontSize=7.2, fontName='Helvetica',
                                  textColor=DARK_GRAY, leftIndent=4, leading=9.5)
    content = [Paragraph(title, title_style)]
    for b in bullets:
        content.append(Paragraph(f"β€’ {b}", bullet_style))

    # Build inner table: waveform | text
    inner = Table(
        [[waveform, [c for c in content]]],
        colWidths=[6.8 * cm, 9.5 * cm],
        style=TableStyle([
            ('VALIGN', (0, 0), (-1, -1), 'TOP'),
            ('LEFTPADDING', (0, 0), (0, 0), 3),
            ('RIGHTPADDING', (0, 0), (0, 0), 4),
            ('LEFTPADDING', (1, 0), (1, 0), 3),
            ('TOPPADDING', (0, 0), (-1, -1), 4),
            ('BOTTOMPADDING', (0, 0), (-1, -1), 4),
        ])
    )
    wrapper = Table(
        [[inner]],
        colWidths=[17.0 * cm],
        style=TableStyle([
            ('BACKGROUND', (0, 0), (-1, -1), bg),
            ('BOX', (0, 0), (-1, -1), 0.6, colors.HexColor('#CCCCCC')),
            ('ROUNDEDCORNERS', [4, 4, 4, 4]),
            ('TOPPADDING', (0, 0), (-1, -1), 0),
            ('BOTTOMPADDING', (0, 0), (-1, -1), 0),
        ])
    )
    return wrapper


# ── Cover Page ───────────────────────────────────────────────────────────────

def build_cover(styles):
    elems = []

    # Large colored banner
    banner = Table(
        [[Paragraph("πŸ«€  ICU ECG REFERENCE", styles['DocTitle']),
          Paragraph("Quick Pattern Guide for Bedside Use", styles['DocSubtitle'])]],
        colWidths=[17.5 * cm],
        style=TableStyle([
            ('BACKGROUND', (0, 0), (-1, -1), HEADER_BG),
            ('TOPPADDING', (0, 0), (-1, -1), 14),
            ('BOTTOMPADDING', (0, 0), (-1, -1), 14),
            ('SPAN', (0, 0), (0, 1)),
        ])
    )

    # Re-do as single-column
    banner = Table(
        [[Paragraph("ICU ECG PATTERN REFERENCE", styles['DocTitle'])],
         [Paragraph("Quick Visual Guide for Bedside Use  |  Hindi-English", styles['DocSubtitle'])]],
        colWidths=[17.5 * cm],
        style=TableStyle([
            ('BACKGROUND', (0, 0), (-1, -1), HEADER_BG),
            ('TOPPADDING', (0, 0), (-1, -1), 12),
            ('BOTTOMPADDING', (0, 0), (-1, -1), 12),
            ('LEFTPADDING', (0, 0), (-1, -1), 10),
        ])
    )
    elems.append(banner)
    elems.append(Spacer(1, 0.3 * cm))

    # Contents overview table
    contents_data = [
        [Paragraph("SECTION", styles['TableHeader']),
         Paragraph("TOPICS", styles['TableHeader'])],
        ["Page 1", "Normal ECG + ECG Basics (PQRST)"],
        ["Page 2", "ST Elevation - STEMI Patterns & Localization"],
        ["Page 3", "ST Depression, T-wave Changes, Pericarditis"],
        ["Page 4", "Supraventricular Arrhythmias (AF, Flutter, SVT)"],
        ["Page 5", "Ventricular Arrhythmias (VT, VF, Torsades)"],
        ["Page 6", "Bradyarrhythmias & Heart Blocks"],
        ["Page 7", "Electrolyte ECG Changes (HyperK, HypoK, Ca, Mg)"],
        ["Page 8", "Special Patterns (PE, Tamponade, Hypothermia, Digoxin)"],
        ["Page 9", "ICU Emergency Quick-Action Table"],
    ]
    t_style = TableStyle([
        ('BACKGROUND', (0, 0), (-1, 0), HEADER_BG),
        ('BACKGROUND', (0, 1), (-1, 1), INFO_BG),
        ('BACKGROUND', (0, 2), (-1, 2), LIGHT_GRAY),
        ('BACKGROUND', (0, 3), (-1, 3), INFO_BG),
        ('BACKGROUND', (0, 4), (-1, 4), LIGHT_GRAY),
        ('BACKGROUND', (0, 5), (-1, 5), INFO_BG),
        ('BACKGROUND', (0, 6), (-1, 6), LIGHT_GRAY),
        ('BACKGROUND', (0, 7), (-1, 7), INFO_BG),
        ('BACKGROUND', (0, 8), (-1, 8), LIGHT_GRAY),
        ('BACKGROUND', (0, 9), (-1, 9), INFO_BG),
        ('FONTNAME', (0, 1), (-1, -1), 'Helvetica'),
        ('FONTSIZE', (0, 1), (-1, -1), 9),
        ('TEXTCOLOR', (0, 1), (-1, -1), DARK_GRAY),
        ('FONTNAME', (0, 1), (0, -1), 'Helvetica-Bold'),
        ('TEXTCOLOR', (0, 1), (0, -1), BLUE),
        ('GRID', (0, 0), (-1, -1), 0.4, colors.HexColor('#CCCCCC')),
        ('TOPPADDING', (0, 0), (-1, -1), 5),
        ('BOTTOMPADDING', (0, 0), (-1, -1), 5),
        ('LEFTPADDING', (0, 0), (-1, -1), 8),
    ])
    tbl = Table(contents_data, colWidths=[3 * cm, 14.5 * cm], style=t_style)
    elems.append(tbl)
    elems.append(Spacer(1, 0.3 * cm))

    # How to use box
    how_data = [[
        Paragraph(
            "<b>HOW TO USE THIS REFERENCE / Kaise Use Karein:</b><br/>"
            "1. ECG dekho β†’ pattern identify karo β†’ iss guide mein match karo<br/>"
            "2. Diagnosis confirm karo β†’ Emergency Action Table (Page 9) dekho<br/>"
            "3. Patient stable hai ya nahi - PEHLE yeh decide karo<br/>"
            "4. Unstable = SHOCK / DEFIB / CPR pehle, phir diagnosis<br/>"
            "<i>Note: Ye guide clinical judgment ki jagah nahi le sakti. Doctor se confirm karo.</i>",
            ParagraphStyle('hw', fontSize=8, fontName='Helvetica',
                           textColor=DARK_GRAY, leading=12))
    ]]
    how_tbl = Table(how_data, colWidths=[17.5 * cm], style=TableStyle([
        ('BACKGROUND', (0, 0), (-1, -1), WARN_BG),
        ('BOX', (0, 0), (-1, -1), 1, ORANGE),
        ('TOPPADDING', (0, 0), (-1, -1), 8),
        ('BOTTOMPADDING', (0, 0), (-1, -1), 8),
        ('LEFTPADDING', (0, 0), (-1, -1), 8),
    ]))
    elems.append(how_tbl)
    return elems


# ── Page builders ─────────────────────────────────────────────────────────────

def page_normal_ecg(styles):
    elems = [section_header("PAGE 1 β€” NORMAL ECG & BASICS", styles), Spacer(1, 0.2 * cm)]

    # Normal ECG card (wide)
    normal_wf = make_ecg(16 * cm, 3.2 * cm, 'normal', label='Normal Sinus Rhythm')
    elems.append(normal_wf)
    elems.append(Spacer(1, 0.2 * cm))

    # PQRST explanation table
    pq_data = [
        [Paragraph("WAVE", styles['TableHeader']),
         Paragraph("NORMAL VALUE", styles['TableHeader']),
         Paragraph("MEANING", styles['TableHeader'])],
        ["P Wave", "< 0.12 sec, < 2.5 mm", "Atria ka depolarization (SA node se)"],
        ["PR Interval", "0.12 – 0.20 sec (3-5 boxes)", "AV node delay – agar > 0.20 = 1st degree block"],
        ["QRS Complex", "< 0.12 sec (< 3 boxes)", "Ventricles ka depolarization – agar wide = BBB ya VT"],
        ["ST Segment", "Isoelectric (flat, at baseline)", "STEMI = elevation; NSTEMI/Ischemia = depression"],
        ["T Wave", "Upright in most leads", "Repolarization – inversion = ischemia"],
        ["QT Interval", "< 440 ms men / < 460 ms women", "Lamba = Torsades risk (drugs, hypoK, hypoMg)"],
        ["QTc (corrected)", "Bazett: QT / √RR", "Correct for heart rate"],
    ]
    pq_style = TableStyle([
        ('BACKGROUND', (0, 0), (-1, 0), HEADER_BG),
        ('BACKGROUND', (0, 1), (-1, 1), INFO_BG),
        ('BACKGROUND', (0, 2), (-1, 2), LIGHT_GRAY),
        ('BACKGROUND', (0, 3), (-1, 3), INFO_BG),
        ('BACKGROUND', (0, 4), (-1, 4), LIGHT_GRAY),
        ('BACKGROUND', (0, 5), (-1, 5), INFO_BG),
        ('BACKGROUND', (0, 6), (-1, 6), LIGHT_GRAY),
        ('BACKGROUND', (0, 7), (-1, 7), INFO_BG),
        ('FONTNAME', (0, 1), (-1, -1), 'Helvetica'),
        ('FONTNAME', (0, 1), (0, -1), 'Helvetica-Bold'),
        ('TEXTCOLOR', (0, 1), (0, -1), BLUE),
        ('FONTSIZE', (0, 1), (-1, -1), 8),
        ('TEXTCOLOR', (0, 1), (-1, -1), DARK_GRAY),
        ('GRID', (0, 0), (-1, -1), 0.4, colors.HexColor('#CCCCCC')),
        ('TOPPADDING', (0, 0), (-1, -1), 4),
        ('BOTTOMPADDING', (0, 0), (-1, -1), 4),
        ('LEFTPADDING', (0, 0), (-1, -1), 6),
    ])
    pq_tbl = Table(pq_data, colWidths=[3.5 * cm, 5.0 * cm, 9.0 * cm], style=pq_style)
    elems.append(pq_tbl)
    elems.append(Spacer(1, 0.2 * cm))

    # Heart rate calculation box
    hr_data = [[
        Paragraph(
            "<b>HEART RATE CALCULATION:</b>  300 Γ· (number of large boxes between R-R)  "
            "| 1 large box = 0.20 sec | 1 small box = 0.04 sec<br/>"
            "<b>Speed memory:</b>  1 box=300 | 2=150 | 3=100 | 4=75 | 5=60 | 6=50",
            ParagraphStyle('hr', fontSize=8, fontName='Helvetica',
                           textColor=DARK_GRAY, leading=12))
    ]]
    hr_tbl = Table(hr_data, colWidths=[17.5 * cm], style=TableStyle([
        ('BACKGROUND', (0, 0), (-1, -1), GOOD_BG),
        ('BOX', (0, 0), (-1, -1), 0.8, GREEN),
        ('TOPPADDING', (0, 0), (-1, -1), 6),
        ('BOTTOMPADDING', (0, 0), (-1, -1), 6),
        ('LEFTPADDING', (0, 0), (-1, -1), 8),
    ]))
    elems.append(hr_tbl)
    return elems


def page_stemi(styles):
    elems = [section_header("PAGE 2 β€” ST ELEVATION (STEMI)", styles, RED), Spacer(1, 0.15 * cm)]

    # STEMI criteria
    crit_data = [[
        Paragraph(
            "<b>STEMI CRITERIA (Washington Manual):</b>  2+ contiguous leads mein ST elevation needed<br/>"
            "Men >40 yr: β‰₯2mm in V2-V3, β‰₯1mm others  |  Men <40 yr: β‰₯2.5mm in V2-V3  |  Women: β‰₯1.5mm in V2-V3, β‰₯1mm others<br/>"
            "<b>DOOR-TO-BALLOON TARGET: &lt; 90 minutes  β†’  Activate Cath Lab IMMEDIATELY</b>",
            ParagraphStyle('cr', fontSize=8, fontName='Helvetica',
                           textColor=DARK_GRAY, leading=12))
    ]]
    crit_tbl = Table(crit_data, colWidths=[17.5 * cm], style=TableStyle([
        ('BACKGROUND', (0, 0), (-1, -1), ALERT_BG),
        ('BOX', (0, 0), (-1, -1), 1.2, RED),
        ('TOPPADDING', (0, 0), (-1, -1), 6),
        ('BOTTOMPADDING', (0, 0), (-1, -1), 6),
        ('LEFTPADDING', (0, 0), (-1, -1), 8),
    ]))
    elems.append(crit_tbl)
    elems.append(Spacer(1, 0.2 * cm))

    # ST elevation waveform
    wf = make_ecg(7 * cm, 2.6 * cm, 'st_elevation', color=RED, label='ST Elevation (STEMI)')
    normal = make_ecg(7 * cm, 2.6 * cm, 'normal', label='Normal (compare)')

    side_tbl = Table([[wf, Spacer(0.3 * cm, 1), normal]],
                     colWidths=[7.2 * cm, 0.3 * cm, 7.2 * cm],
                     style=TableStyle([('VALIGN', (0, 0), (-1, -1), 'TOP')]))
    elems.append(side_tbl)
    elems.append(Spacer(1, 0.2 * cm))

    # Localization table
    loc_data = [
        [Paragraph("LOCATION", styles['TableHeader']),
         Paragraph("LEADS", styles['TableHeader']),
         Paragraph("ARTERY (Rosen's)", styles['TableHeader']),
         Paragraph("RECIPROCAL CHANGES", styles['TableHeader'])],
        ["Anterior STEMI", "V1 – V4", "LAD (Left Anterior Descending)", "ST↓ in II, III, aVF"],
        ["Lateral STEMI", "I, aVL, V5, V6", "LCX (Left Circumflex)", "ST↓ in inferior leads"],
        ["Anterolateral", "V1–V6, I, aVL", "Proximal LAD / Left Main", "ST↓ inferior + right"],
        ["Inferior STEMI", "II, III, aVF", "RCA (Right Coronary Artery)", "ST↓ in I, aVL"],
        ["Right Ventricular", "V3R, V4R elevation", "Proximal RCA", "Check if Inferior STEMI"],
        ["Posterior STEMI", "V7-V9 elevation", "LCX (often missed!)", "ST↓ + Tall R in V1-V3"],
        ["aVR elevation", "aVR ↑ + diffuse ST↓", "Left Main / Proximal LAD", "Global subendocardial"],
    ]
    loc_style = TableStyle([
        ('BACKGROUND', (0, 0), (-1, 0), RED),
        ('BACKGROUND', (0, 1), (-1, 1), colors.HexColor('#FDEDEC')),
        ('BACKGROUND', (0, 2), (-1, 2), LIGHT_GRAY),
        ('BACKGROUND', (0, 3), (-1, 3), colors.HexColor('#FDEDEC')),
        ('BACKGROUND', (0, 4), (-1, 4), LIGHT_GRAY),
        ('BACKGROUND', (0, 5), (-1, 5), colors.HexColor('#FDEDEC')),
        ('BACKGROUND', (0, 6), (-1, 6), LIGHT_GRAY),
        ('BACKGROUND', (0, 7), (-1, 7), ALERT_BG),
        ('FONTNAME', (0, 1), (-1, -1), 'Helvetica'),
        ('FONTNAME', (0, 1), (0, -1), 'Helvetica-Bold'),
        ('TEXTCOLOR', (0, 1), (0, -1), RED),
        ('FONTSIZE', (0, 0), (-1, -1), 7.5),
        ('TEXTCOLOR', (0, 1), (-1, -1), DARK_GRAY),
        ('GRID', (0, 0), (-1, -1), 0.4, colors.HexColor('#CCCCCC')),
        ('TOPPADDING', (0, 0), (-1, -1), 4),
        ('BOTTOMPADDING', (0, 0), (-1, -1), 4),
        ('LEFTPADDING', (0, 0), (-1, -1), 5),
    ])
    loc_tbl = Table(loc_data,
                    colWidths=[3.8 * cm, 3.0 * cm, 5.5 * cm, 5.2 * cm],
                    style=loc_style)
    elems.append(loc_tbl)
    elems.append(Spacer(1, 0.15 * cm))

    # LBBB note
    lbbb_data = [[
        Paragraph(
            "<b>NEW LBBB + Chest Pain = Treat as STEMI (Sgarbossa Criteria)</b><br/>"
            "Concordant ST↑ >1mm | Discordant ST↑ >5mm | ST↓ >1mm in V1-V3",
            ParagraphStyle('lb', fontSize=8, fontName='Helvetica',
                           textColor=DARK_GRAY, leading=11))
    ]]
    lbbb_tbl = Table(lbbb_data, colWidths=[17.5 * cm], style=TableStyle([
        ('BACKGROUND', (0, 0), (-1, -1), WARN_BG),
        ('BOX', (0, 0), (-1, -1), 0.8, ORANGE),
        ('TOPPADDING', (0, 0), (-1, -1), 5),
        ('BOTTOMPADDING', (0, 0), (-1, -1), 5),
        ('LEFTPADDING', (0, 0), (-1, -1), 8),
    ]))
    elems.append(lbbb_tbl)
    return elems


def page_st_depression_t(styles):
    elems = [section_header("PAGE 3 β€” ST DEPRESSION, T-WAVE CHANGES & PERICARDITIS", styles, PURPLE), Spacer(1, 0.15 * cm)]

    wf_dep  = make_ecg(5.3 * cm, 2.5 * cm, 'st_depression', color=ORANGE, label='ST Depression')
    wf_tinv = make_ecg(5.3 * cm, 2.5 * cm, 't_inversion',  color=PURPLE, label='T Inversion')
    wf_peri = make_ecg(5.3 * cm, 2.5 * cm, 'pericarditis', color=BLUE,   label='Pericarditis')

    row_tbl = Table([[wf_dep, Spacer(0.2*cm,1), wf_tinv, Spacer(0.2*cm,1), wf_peri]],
                    colWidths=[5.5*cm, 0.2*cm, 5.5*cm, 0.2*cm, 5.5*cm],
                    style=TableStyle([('VALIGN',(0,0),(-1,-1),'TOP')]))
    elems.append(row_tbl)
    elems.append(Spacer(1, 0.2 * cm))

    changes_data = [
        [Paragraph("FINDING", styles['TableHeader']),
         Paragraph("PATTERN", styles['TableHeader']),
         Paragraph("THINK", styles['TableHeader']),
         Paragraph("ACTION", styles['TableHeader'])],
        ["Horizontal ST↓", "Flat depression β‰₯1mm", "NSTEMI / Unstable Angina", "Troponin, heparin, cardiology"],
        ["Downsloping ST↓", "ST slopes down", "Significant ischemia", "Urgent cardiology review"],
        ["ST↓ V1-V3 only", "Isolated posterior", "Posterior STEMI!", "Add V7-V9 leads"],
        ["T inversion", "Inverted T wave", "Ischemia, PE, post-MI", "Echo, troponin, CTPA"],
        ["Wellens' Pattern", "Biphasic/deep T↓ V2-V3", "LAD critical stenosis", "Urgent angiography"],
        ["Hyperacute T", "Tall, peaked, symmetric", "Very early STEMI (mins)", "Serial ECG, troponin"],
        ["Diffuse ST↑ all leads", "Saddle-shaped + PR↓", "Pericarditis", "Echo, NSAIDs, colchicine"],
        ["CVA T-waves", "Deep wide T inversion", "Subarachnoid hemorrhage", "CT head, neurosurgery"],
    ]
    ch_style = TableStyle([
        ('BACKGROUND', (0, 0), (-1, 0), PURPLE),
        ('FONTNAME', (0, 1), (-1, -1), 'Helvetica'),
        ('FONTNAME', (0, 1), (0, -1), 'Helvetica-Bold'),
        ('TEXTCOLOR', (0, 1), (0, -1), PURPLE),
        ('FONTSIZE', (0, 0), (-1, -1), 7.5),
        ('TEXTCOLOR', (0, 1), (-1, -1), DARK_GRAY),
        ('ROWBACKGROUNDS', (0, 1), (-1, -1), [LIGHT_GRAY, WHITE]),
        ('GRID', (0, 0), (-1, -1), 0.4, colors.HexColor('#CCCCCC')),
        ('TOPPADDING', (0, 0), (-1, -1), 4),
        ('BOTTOMPADDING', (0, 0), (-1, -1), 4),
        ('LEFTPADDING', (0, 0), (-1, -1), 5),
    ])
    ch_tbl = Table(changes_data, colWidths=[4.0*cm, 3.8*cm, 5.0*cm, 4.7*cm], style=ch_style)
    elems.append(ch_tbl)
    return elems


def page_supra_arrhythmias(styles):
    elems = [section_header("PAGE 4 β€” SUPRAVENTRICULAR ARRHYTHMIAS (SVT, AF, FLUTTER)", styles, BLUE), Spacer(1, 0.15 * cm)]

    wf_af  = make_ecg(8.0*cm, 2.6*cm, 'af',      color=BLUE,   label='Atrial Fibrillation')
    wf_fl  = make_ecg(8.0*cm, 2.6*cm, 'flutter',  color=PURPLE, label='Atrial Flutter')

    row = Table([[wf_af, Spacer(0.3*cm,1), wf_fl]],
                colWidths=[8.3*cm, 0.3*cm, 8.3*cm],
                style=TableStyle([('VALIGN',(0,0),(-1,-1),'TOP')]))
    elems.append(row)
    elems.append(Spacer(1, 0.2*cm))

    arr_data = [
        [Paragraph("ARRHYTHMIA", styles['TableHeader']),
         Paragraph("ECG FINDINGS", styles['TableHeader']),
         Paragraph("STABLE TREATMENT", styles['TableHeader']),
         Paragraph("UNSTABLE TREATMENT", styles['TableHeader'])],
        ["Sinus Tachycardia", "Normal P before QRS\nHR 100-150, regular", "Treat CAUSE (sepsis/fever/pain)\nNO specific antiarrhythmic", "β€”"],
        ["Atrial Fibrillation", "Irregularly irregular\nNo P waves, chaotic baseline\nVariable R-R intervals", "Rate control:\nMetoprolol 5mg IV\nor Diltiazem 0.25mg/kg IV\nAnticoag if >48hrs", "DC Cardioversion\n100-200J sync\nStat"],
        ["Atrial Flutter", "Regular sawtooth P waves\n300/min flutter, 150 ventricular\n2:1 or 4:1 block", "Rate control same as AF\nCardioversion 50-100J", "DC Cardioversion\n50-100J sync"],
        ["SVT (AVNRT)", "Narrow QRS tachycardia\nHR 150-250\nNo visible P waves", "Vagal maneuvers first\nAdenosine 6mg rapid IV\n(warn patient!)", "DC Cardioversion\n50-100J sync"],
        ["Sinus Bradycardia", "Normal P-QRS-T, HR<60\nRegular rhythm", "If asymptomatic: observe\nAtropine 0.5mg IV if symptomatic", "Pacing if refractory"],
    ]
    arr_style = TableStyle([
        ('BACKGROUND', (0, 0), (-1, 0), BLUE),
        ('FONTNAME', (0, 1), (-1, -1), 'Helvetica'),
        ('FONTNAME', (0, 1), (0, -1), 'Helvetica-Bold'),
        ('TEXTCOLOR', (0, 1), (0, -1), BLUE),
        ('FONTSIZE', (0, 0), (-1, -1), 7.5),
        ('TEXTCOLOR', (0, 1), (-1, -1), DARK_GRAY),
        ('ROWBACKGROUNDS', (0, 1), (-1, -1), [INFO_BG, WHITE]),
        ('GRID', (0, 0), (-1, -1), 0.4, colors.HexColor('#CCCCCC')),
        ('TOPPADDING', (0, 0), (-1, -1), 4),
        ('BOTTOMPADDING', (0, 0), (-1, -1), 4),
        ('LEFTPADDING', (0, 0), (-1, -1), 5),
        ('VALIGN', (0, 0), (-1, -1), 'TOP'),
    ])
    arr_tbl = Table(arr_data, colWidths=[3.5*cm, 5.0*cm, 5.0*cm, 4.0*cm], style=arr_style)
    elems.append(arr_tbl)
    elems.append(Spacer(1, 0.15*cm))

    # Adenosine warning
    aden_data = [[
        Paragraph(
            "<b>⚠ ADENOSINE WARNING:</b>  WPW (Wolff-Parkinson-White) mein AVOID karo β€” AF with rapid conduction trigger ho sakti hai  |  "
            "Always with crash cart ready  |  Central line se better, peripheral IV se bhi hota hai (rapid flush ke saath)",
            ParagraphStyle('aw', fontSize=8, fontName='Helvetica', textColor=DARK_GRAY, leading=11))
    ]]
    aden_tbl = Table(aden_data, colWidths=[17.5*cm], style=TableStyle([
        ('BACKGROUND', (0, 0), (-1, -1), WARN_BG),
        ('BOX', (0, 0), (-1, -1), 0.8, ORANGE),
        ('TOPPADDING', (0, 0), (-1, -1), 5),
        ('BOTTOMPADDING', (0, 0), (-1, -1), 5),
        ('LEFTPADDING', (0, 0), (-1, -1), 8),
    ]))
    elems.append(aden_tbl)
    return elems


def page_ventricular_arrhythmias(styles):
    elems = [section_header("PAGE 5 β€” VENTRICULAR ARRHYTHMIAS (VT, VF, TORSADES) β€” HIGH ALERT!", styles, RED), Spacer(1, 0.15*cm)]

    wf_vt  = make_ecg(5.3*cm, 2.6*cm, 'vt',      color=RED,    label='Ventricular Tachycardia (VT)')
    wf_vf  = make_ecg(5.3*cm, 2.6*cm, 'vf',      color=DARK_RED,label='Ventricular Fibrillation (VF)')
    wf_tor = make_ecg(5.3*cm, 2.6*cm, 'torsades', color=PURPLE, label='Torsades de Pointes')

    row = Table([[wf_vt, Spacer(0.2*cm,1), wf_vf, Spacer(0.2*cm,1), wf_tor]],
                colWidths=[5.5*cm,0.2*cm,5.5*cm,0.2*cm,5.5*cm],
                style=TableStyle([('VALIGN',(0,0),(-1,-1),'TOP')]))
    elems.append(row)
    elems.append(Spacer(1, 0.2*cm))

    v_data = [
        [Paragraph("RHYTHM", styles['TableHeader']),
         Paragraph("ECG PATTERN", styles['TableHeader']),
         Paragraph("PULSE?", styles['TableHeader']),
         Paragraph("TREATMENT", styles['TableHeader'])],
        ["Monomorphic VT", "Wide QRS >0.12s\nRegular rate >100\nAV dissociation\nFusion/capture beats", "YES - Stable", "Amiodarone 150mg IV over 10min\nthen 1mg/min infusion"],
        ["Monomorphic VT", "Same wide QRS", "YES - Unstable\n(BP↓, syncope)", "SYNCHRONIZED DC Cardioversion\n100-200J biphasic"],
        ["Pulseless VT", "Wide complex, NO PULSE", "NO", "DEFIBRILLATE (unsynchronized)\n200J β†’ CPR β†’ 300J β†’ CPR β†’ 360J"],
        ["Ventricular Fibrillation", "Chaotic, no QRS\nNO PULSE", "NO", "DEFIBRILLATE 200J β†’ CPR\nEpinephrine 1mg IV q3-5min\nAmiodarone 300mg IV"],
        ["Torsades de Pointes", "Twisting QRS amplitude\nPolymorphic, QT prolonged", "Usually YES", "MgSO4 2g IV over 5min STAT\nStop QT-prolonging drugs\nK+ >4.5 mEq/L target"],
        ["Accelerated Idioventricular", "Wide QRS, HR 60-100\nPost-MI reperfusion", "YES", "Usually benign\nReperfusion rhythm β€” observe"],
    ]
    v_style = TableStyle([
        ('BACKGROUND', (0, 0), (-1, 0), RED),
        ('FONTNAME', (0, 1), (-1, -1), 'Helvetica'),
        ('FONTNAME', (0, 1), (0, -1), 'Helvetica-Bold'),
        ('TEXTCOLOR', (0, 1), (0, -1), RED),
        ('FONTSIZE', (0, 0), (-1, -1), 7.5),
        ('TEXTCOLOR', (0, 1), (-1, -1), DARK_GRAY),
        ('ROWBACKGROUNDS', (0, 1), (-1, -1), [colors.HexColor('#FDEDEC'), WHITE]),
        ('GRID', (0, 0), (-1, -1), 0.4, colors.HexColor('#CCCCCC')),
        ('TOPPADDING', (0, 0), (-1, -1), 4),
        ('BOTTOMPADDING', (0, 0), (-1, -1), 4),
        ('LEFTPADDING', (0, 0), (-1, -1), 5),
        ('VALIGN', (0, 0), (-1, -1), 'TOP'),
    ])
    v_tbl = Table(v_data, colWidths=[3.8*cm, 5.0*cm, 2.8*cm, 5.9*cm], style=v_style)
    elems.append(v_tbl)
    elems.append(Spacer(1, 0.15*cm))

    # QT prolonging drugs
    qt_data = [[
        Paragraph(
            "<b>COMMON QT-PROLONGING DRUGS IN ICU (Torsades Risk):</b><br/>"
            "Amiodarone | Haloperidol | Methadone | Azithromycin | Fluconazole | Ondansetron | "
            "Ciprofloxacin | Metronidazole | Quetiapine | TCA antidepressants | Hydroxychloroquine<br/>"
            "<b>QTc >500ms = Stop offending drug + MgSO4 + K⁺ correction</b>",
            ParagraphStyle('qt', fontSize=8, fontName='Helvetica', textColor=DARK_GRAY, leading=11))
    ]]
    qt_tbl = Table(qt_data, colWidths=[17.5*cm], style=TableStyle([
        ('BACKGROUND', (0, 0), (-1, -1), ALERT_BG),
        ('BOX', (0, 0), (-1, -1), 1.0, RED),
        ('TOPPADDING', (0, 0), (-1, -1), 6),
        ('BOTTOMPADDING', (0, 0), (-1, -1), 6),
        ('LEFTPADDING', (0, 0), (-1, -1), 8),
    ]))
    elems.append(qt_tbl)
    return elems


def page_bradyarrhythmias(styles):
    elems = [section_header("PAGE 6 β€” BRADYARRHYTHMIAS & HEART BLOCKS", styles, DARK_GREEN), Spacer(1, 0.15*cm)]

    wf_chb = make_ecg(8.0*cm, 2.6*cm, 'chb',       color=DARK_GREEN, label='Complete Heart Block (3rd Degree)')
    wf_wen = make_ecg(8.0*cm, 2.6*cm, 'wenckebach', color=GREEN,      label='Mobitz I (Wenckebach)')

    row = Table([[wf_chb, Spacer(0.3*cm,1), wf_wen]],
                colWidths=[8.3*cm, 0.3*cm, 8.3*cm],
                style=TableStyle([('VALIGN',(0,0),(-1,-1),'TOP')]))
    elems.append(row)
    elems.append(Spacer(1, 0.2*cm))

    hb_data = [
        [Paragraph("BLOCK TYPE", styles['TableHeader']),
         Paragraph("ECG FINDING", styles['TableHeader']),
         Paragraph("RISK", styles['TableHeader']),
         Paragraph("ICU ACTION", styles['TableHeader'])],
        ["1st Degree AV Block", "PR >0.20s (>5 small boxes)\nEvery P conducts normally", "Low\nUsually benign", "Monitor, check drugs\n(digoxin, beta-blockers)"],
        ["2nd Degree - Mobitz I (Wenckebach)", "PR progressively lengthens\nthen P wave drops (no QRS)\nPattern repeats", "Low-Moderate\nRarely progresses", "Observe, atropine if symptomatic\nCheck inferior MI"],
        ["2nd Degree - Mobitz II", "Fixed PR interval\nSuddenly P wave drops β€” no QRS\nNo warning!", "HIGH β€” can progress to CHB\nUnpredictable", "Transcutaneous pacing ready\nPermanent pacemaker indication\nCardiology STAT"],
        ["3rd Degree (Complete Heart Block)", "P waves & QRS completely INDEPENDENT\nP rate > QRS rate (dissociation)\nEscape rhythm: 30-50 bpm", "CRITICAL\nLow cardiac output", "Emergency pacing STAT\nAtropine 0.5-1mg IV (temp)\nDopamine/Epinephrine if needed"],
        ["Sinus Node Dysfunction", "Sinus pause >3s\nor HR <40 consistently", "Symptomatic bradycardia", "Atropine β†’ pacing\nCheck hypothyroidism, drugs"],
    ]
    hb_style = TableStyle([
        ('BACKGROUND', (0, 0), (-1, 0), DARK_GREEN),
        ('FONTNAME', (0, 1), (-1, -1), 'Helvetica'),
        ('FONTNAME', (0, 1), (0, -1), 'Helvetica-Bold'),
        ('TEXTCOLOR', (0, 1), (0, -1), DARK_GREEN),
        ('FONTSIZE', (0, 0), (-1, -1), 7.5),
        ('TEXTCOLOR', (0, 1), (-1, -1), DARK_GRAY),
        ('ROWBACKGROUNDS', (0, 1), (-1, -1), [GOOD_BG, WHITE]),
        ('GRID', (0, 0), (-1, -1), 0.4, colors.HexColor('#CCCCCC')),
        ('TOPPADDING', (0, 0), (-1, -1), 4),
        ('BOTTOMPADDING', (0, 0), (-1, -1), 4),
        ('LEFTPADDING', (0, 0), (-1, -1), 5),
        ('VALIGN', (0, 0), (-1, -1), 'TOP'),
        # Highlight Mobitz II and CHB rows
        ('BACKGROUND', (0, 3), (-1, 3), colors.HexColor('#FEF5E7')),
        ('BACKGROUND', (0, 4), (-1, 4), ALERT_BG),
    ])
    hb_tbl = Table(hb_data, colWidths=[4.0*cm, 5.0*cm, 3.5*cm, 5.0*cm], style=hb_style)
    elems.append(hb_tbl)
    elems.append(Spacer(1, 0.15*cm))

    causes_data = [[
        Paragraph(
            "<b>ICU CAUSES OF BRADYCARDIA:</b>  Beta-blocker/CCB overdose | Digoxin toxicity | "
            "Inferior STEMI (RCA β†’ SA/AV node ischemia) | Hypothyroidism | Hypothermia | "
            "Raised ICP (Cushing reflex) | Vasovagal | Hyperkalemia | Post-cardiac surgery",
            ParagraphStyle('bc', fontSize=8, fontName='Helvetica', textColor=DARK_GRAY, leading=11))
    ]]
    causes_tbl = Table(causes_data, colWidths=[17.5*cm], style=TableStyle([
        ('BACKGROUND', (0, 0), (-1, -1), GOOD_BG),
        ('BOX', (0, 0), (-1, -1), 0.8, GREEN),
        ('TOPPADDING', (0, 0), (-1, -1), 6),
        ('BOTTOMPADDING', (0, 0), (-1, -1), 6),
        ('LEFTPADDING', (0, 0), (-1, -1), 8),
    ]))
    elems.append(causes_tbl)
    return elems


def page_electrolytes(styles):
    elems = [section_header("PAGE 7 β€” ELECTROLYTE ECG CHANGES (Harrison's Principles)", styles, ORANGE), Spacer(1, 0.15*cm)]

    wf_hik = make_ecg(5.3*cm, 2.5*cm, 'hyperkalemia', color=RED,   label='Hyperkalemia (K⁺ >5.5)')
    wf_lok = make_ecg(5.3*cm, 2.5*cm, 'hypokalemia',  color=BLUE,  label='Hypokalemia (K⁺ <3.5)')
    wf_qtl = make_ecg(5.3*cm, 2.5*cm, 'prolonged_qt', color=PURPLE,label='Prolonged QT (Ca↓/Mg↓/Drugs)')

    row = Table([[wf_hik, Spacer(0.2*cm,1), wf_lok, Spacer(0.2*cm,1), wf_qtl]],
                colWidths=[5.5*cm,0.2*cm,5.5*cm,0.2*cm,5.5*cm],
                style=TableStyle([('VALIGN',(0,0),(-1,-1),'TOP')]))
    elems.append(row)
    elems.append(Spacer(1, 0.2*cm))

    el_data = [
        [Paragraph("ELECTROLYTE", styles['TableHeader']),
         Paragraph("ECG CHANGES (Sequence)", styles['TableHeader']),
         Paragraph("TREATMENT", styles['TableHeader'])],
        ["Hyperkalemia K⁺ >5.5\n(CRITICAL >6.5)", "Early: Tall PEAKED (tented) T waves ← FIRST SIGN\nModerate: PR↑, P wave flat/absent, wide QRS\nSevere: Sine wave pattern β†’ Asystole / VF",
         "1. Calcium gluconate 10% 10ml IV (membrane stabilize)\n2. Insulin 10U + Dextrose 50% 50ml IV\n3. Salbutamol nebulizer\n4. Kayexalate / Dialysis"],
        ["Hypokalemia K⁺ <3.5", "ST depression, T wave flat/inverted\nProminent U wave (after T wave)\nQT prolongation β†’ Torsades risk\nPR prolongation",
         "IV KCl: Max 10 mEq/hr peripheral\n20 mEq/hr central line\nTarget K⁺ >4.0 in cardiac patients\nAlways correct Mg2+ together"],
        ["Hypocalcemia Ca <8.5", "QT prolongation (ST segment lengthens)\nNo QRS change\nSevere: Cardiac arrest risk",
         "IV Calcium gluconate 10ml 10%\nor Calcium chloride 5-10ml 10%\n(Central line preferred for CaCl)"],
        ["Hypercalcemia Ca >10.5", "QT shortening\nOsborn-like J point changes\nBradycardia, AV blocks\nBundle branch blocks",
         "IV saline hydration\nFurosemide\nBisphosphonates\nDialysis if severe"],
        ["Hypomagnesemia Mg <1.7", "QT prolongation\nTorsades de Pointes\nFlattened T waves\nU waves",
         "MgSO4 1-2g IV over 15-60min\nReplace K⁺ simultaneously\n(HypoMg causes refractory hypoK)"],
        ["Hypothermia Temp <32Β°C", "Osborn wave (J wave) β€” notch at J point\nBradycardia, QT prolongation\nPR/QRS widening\nVF risk at <28Β°C",
         "Rewarm (active external/internal)\nManage VF with defibrillation\n(May need repeated shocks)"],
    ]
    el_style = TableStyle([
        ('BACKGROUND', (0, 0), (-1, 0), ORANGE),
        ('FONTNAME', (0, 1), (-1, -1), 'Helvetica'),
        ('FONTNAME', (0, 1), (0, -1), 'Helvetica-Bold'),
        ('TEXTCOLOR', (0, 1), (0, -1), ORANGE),
        ('FONTSIZE', (0, 0), (-1, -1), 7.5),
        ('TEXTCOLOR', (0, 1), (-1, -1), DARK_GRAY),
        ('ROWBACKGROUNDS', (0, 1), (-1, -1), [WARN_BG, WHITE]),
        ('GRID', (0, 0), (-1, -1), 0.4, colors.HexColor('#CCCCCC')),
        ('TOPPADDING', (0, 0), (-1, -1), 4),
        ('BOTTOMPADDING', (0, 0), (-1, -1), 4),
        ('LEFTPADDING', (0, 0), (-1, -1), 5),
        ('VALIGN', (0, 0), (-1, -1), 'TOP'),
        # Highlight hyperkalemia (most critical)
        ('BACKGROUND', (0, 1), (-1, 1), ALERT_BG),
    ])
    el_tbl = Table(el_data, colWidths=[3.5*cm, 7.2*cm, 6.8*cm], style=el_style)
    elems.append(el_tbl)
    return elems


def page_special_patterns(styles):
    elems = [section_header("PAGE 8 β€” SPECIAL ICU PATTERNS (PE, TAMPONADE, DIGOXIN, HYPOTHERMIA)", styles, DARK_GRAY), Spacer(1, 0.15*cm)]

    sp_data = [
        [Paragraph("CONDITION", styles['TableHeader']),
         Paragraph("ECG FINDINGS", styles['TableHeader']),
         Paragraph("KEY DIFFERENTIATOR", styles['TableHeader']),
         Paragraph("ACTION", styles['TableHeader'])],
        ["Pulmonary Embolism (PE)", "Sinus tachycardia (most common!)\nS1Q3T3 pattern (only 20%)\nNew RBBB\nT inversion V1-V4 (RV strain)\nAF (new onset)",
         "S1Q3T3 = S wave in I\nQ wave in III, T inversion III",
         "CTPA (gold standard)\nEchocardiography\nAnticoagulation\n(Thrombolysis if massive)"],
        ["Cardiac Tamponade", "Sinus tachycardia\nLow voltage (small QRS all leads)\nElectrical alternans (QRS size alternates beat-to-beat)\nPR segment flattening",
         "Electrical alternans = highly specific\nConfirm with ECHO\nPulsus paradoxus clinically",
         "Emergency pericardiocentesis\nEcho-guided preferred"],
        ["Digoxin Effect (Therapeutic)", "Scooped/Salvador Dali moustache ST↓\nQT shortening\nT wave flattening/inversion\nBradycardia",
         "Scooped ST = therapeutic\nNOT toxicity per se",
         "Monitor digoxin level\nMaintain K⁺ >3.5"],
        ["Digoxin Toxicity", "Bradycardia + AV blocks\nBidirectional VT (pathognomonic!)\nPAT with block\nVT / VF",
         "Bidirectional VT = digoxin until proven otherwise",
         "Digoxin-Fab (Digibind) STAT\nNo cardioversion!\nPotassium correction"],
        ["Pericarditis", "Diffuse saddle-shaped ST↑ ALL leads\nPR depression (pathognomonic)\nNo reciprocal changes\nNo Q waves",
         "Diffuse (not localized) ST↑\nPR depression key!",
         "NSAIDs + Colchicine\nEchocardiography\nRule out STEMI"],
        ["LVH (Left Ventricular Hypertrophy)", "Tall R in V5-V6 (>25mm)\nDeep S in V1-V2\nST↓ and T inversion V4-V6 (strain pattern)\nLAD (Left Axis Deviation)",
         "Strain pattern mimics ischemia\nVoltage criteria needed",
         "Echo for confirmation\nBP control\nMonitor for LBBB"],
        ["Early Repolarization", "J-point elevation V2-V5\nNotching at J-point\nConcave ST elevation\nNormal T waves",
         "Young healthy patients\nAsymptomatic\nSt concave (vs STEMI oblique/convex)",
         "Usually benign\nSerial ECG if symptoms\nRule out STEMI"],
        ["WPW (Wolff-Parkinson-White)", "Short PR (<0.12s)\nDelta wave (slurred QRS onset)\nWide QRS\nST/T changes secondary",
         "Delta wave = key finding\nAF with WPW very dangerous",
         "Avoid adenosine/digoxin/beta-blockers!\nProcainamide if AF+WPW\nRFA ablation"],
    ]
    sp_style = TableStyle([
        ('BACKGROUND', (0, 0), (-1, 0), DARK_GRAY),
        ('FONTNAME', (0, 1), (-1, -1), 'Helvetica'),
        ('FONTNAME', (0, 1), (0, -1), 'Helvetica-Bold'),
        ('TEXTCOLOR', (0, 1), (0, -1), DARK_GRAY),
        ('FONTSIZE', (0, 0), (-1, -1), 7.2),
        ('TEXTCOLOR', (0, 1), (-1, -1), DARK_GRAY),
        ('ROWBACKGROUNDS', (0, 1), (-1, -1), [LIGHT_GRAY, WHITE]),
        ('GRID', (0, 0), (-1, -1), 0.4, colors.HexColor('#CCCCCC')),
        ('TOPPADDING', (0, 0), (-1, -1), 4),
        ('BOTTOMPADDING', (0, 0), (-1, -1), 4),
        ('LEFTPADDING', (0, 0), (-1, -1), 5),
        ('VALIGN', (0, 0), (-1, -1), 'TOP'),
    ])
    sp_tbl = Table(sp_data, colWidths=[3.3*cm, 5.2*cm, 4.5*cm, 4.5*cm], style=sp_style)
    elems.append(sp_tbl)
    return elems


def page_emergency_table(styles):
    elems = [section_header("PAGE 9 β€” ICU ECG EMERGENCY QUICK-ACTION TABLE", styles, RED), Spacer(1, 0.15*cm)]

    # UNSTABLE vs STABLE banner
    us_data = [[
        Paragraph(
            "<b>FIRST QUESTION ALWAYS: Patient STABLE hai ya UNSTABLE?</b><br/>"
            "UNSTABLE = ANY of: BP &lt;90/60 | Active chest pain | Altered sensorium | SpO2 &lt;90% | Signs of shock<br/>"
            "<b>If UNSTABLE β†’ DC SHOCK / DEFIB / CPR PEHLE β€” phir diagnosis!</b>",
            ParagraphStyle('us', fontSize=9, fontName='Helvetica', textColor=WHITE, leading=13))
    ]]
    us_tbl = Table(us_data, colWidths=[17.5*cm], style=TableStyle([
        ('BACKGROUND', (0, 0), (-1, -1), RED),
        ('TOPPADDING', (0, 0), (-1, -1), 8),
        ('BOTTOMPADDING', (0, 0), (-1, -1), 8),
        ('LEFTPADDING', (0, 0), (-1, -1), 10),
        ('ROUNDEDCORNERS', [4,4,4,4]),
    ]))
    elems.append(us_tbl)
    elems.append(Spacer(1, 0.2*cm))

    em_data = [
        [Paragraph("ECG FINDING", styles['TableHeader']),
         Paragraph("DIAGNOSIS", styles['TableHeader']),
         Paragraph("IMMEDIATE ACTION", styles['TableHeader']),
         Paragraph("TIME TARGET", styles['TableHeader'])],
        ["VF / Pulseless VT", "Cardiac Arrest\n(Shockable rhythm)", "CPR + DEFIBRILLATE 200J\nEpinephrine 1mg q3-5min\nAmiodarone 300mg IV", "< 2 min"],
        ["STEMI (ST↑ β‰₯2 leads)", "Acute MI\nCoronary occlusion", "Activate Cath Lab\nAspirin 300mg + Heparin\nMorphine / O2 / Nitrates", "Door-to-balloon < 90 min"],
        ["VT with pulse, UNSTABLE", "Hemodynamic compromise", "SYNCHRONIZED cardioversion\n100-200J biphasic", "< 5 min"],
        ["VT with pulse, STABLE", "Ventricular tachycardia", "Amiodarone 150mg IV over 10min\nIdentify & treat cause", "< 30 min"],
        ["Torsades de Pointes", "Polymorphic VT\n(Long QT)", "MgSO4 2g IV over 5 min STAT\nStop QT drugs, correct K⁺", "< 10 min"],
        ["AF/Flutter UNSTABLE", "Rapid ventricular response\nHemodynamic compromise", "DC CARDIOVERSION\n100-200J (AF) / 50J (Flutter)", "< 5 min"],
        ["Complete Heart Block", "AV nodal failure\nEscape rhythm <50 bpm", "Atropine 0.5-1mg IV\nTranscutaneous pacing STAT\nCardiology consult", "< 5 min"],
        ["Tall peaked T waves", "Hyperkalemia\n(Cardiac arrest risk)", "Calcium gluconate 10ml 10% IV\nInsulin + Dextrose\nSalbutamol", "< 10 min"],
        ["Wide QRS + Bradycardia", "Hyperkalemia / Drug toxicity\nComplete heart block", "Calcium gluconate (if HyperK)\nStop offending drugs\nPacing if needed", "< 10 min"],
        ["S1Q3T3 + Tachycardia", "Pulmonary Embolism", "CTPA or Echo\nAnticoagulation (heparin)\nThrombolysis if massive", "< 60 min"],
        ["Low voltage + Electrical alternans", "Cardiac Tamponade", "Emergency pericardiocentesis\nEcho-guided\nVolume + vasopressors temp", "< 30 min"],
        ["Osborn (J) waves + Bradycardia", "Hypothermia", "Active rewarming\nVF β†’ defibrillation\nHandle gently (VF risk)", "Continuous"],
    ]
    em_style = TableStyle([
        ('BACKGROUND', (0, 0), (-1, 0), RED),
        ('FONTNAME', (0, 1), (-1, -1), 'Helvetica'),
        ('FONTNAME', (0, 1), (0, -1), 'Helvetica-Bold'),
        ('TEXTCOLOR', (0, 1), (0, -1), RED),
        ('FONTSIZE', (0, 0), (-1, -1), 7.5),
        ('TEXTCOLOR', (0, 1), (-1, -1), DARK_GRAY),
        # Alternate rows
        ('ROWBACKGROUNDS', (0, 1), (-1, -1), [ALERT_BG, WHITE]),
        # Very critical rows brighter
        ('BACKGROUND', (0, 1), (-1, 1), colors.HexColor('#FADBD8')),  # VF
        ('BACKGROUND', (0, 2), (-1, 2), colors.HexColor('#FADBD8')),  # STEMI
        ('GRID', (0, 0), (-1, -1), 0.4, colors.HexColor('#CCCCCC')),
        ('TOPPADDING', (0, 0), (-1, -1), 4),
        ('BOTTOMPADDING', (0, 0), (-1, -1), 4),
        ('LEFTPADDING', (0, 0), (-1, -1), 5),
        ('VALIGN', (0, 0), (-1, -1), 'TOP'),
    ])
    em_tbl = Table(em_data, colWidths=[4.0*cm, 3.5*cm, 6.3*cm, 3.0*cm], style=em_style)
    elems.append(em_tbl)
    elems.append(Spacer(1, 0.15*cm))

    # Footer
    foot_data = [[
        Paragraph(
            "Sources: Rosen's Emergency Medicine | Washington Manual of Medical Therapeutics | "
            "Harrison's Principles of Internal Medicine 22e | Current Surgical Therapy 14e | "
            "Miller's Anesthesia 10e  |  For educational use only β€” always confirm with supervising physician.",
            ParagraphStyle('ft', fontSize=7, fontName='Helvetica', textColor=MID_GRAY,
                           alignment=TA_CENTER, leading=9))
    ]]
    foot_tbl = Table(foot_data, colWidths=[17.5*cm], style=TableStyle([
        ('BACKGROUND', (0, 0), (-1, -1), LIGHT_GRAY),
        ('BOX', (0, 0), (-1, -1), 0.4, MID_GRAY),
        ('TOPPADDING', (0, 0), (-1, -1), 4),
        ('BOTTOMPADDING', (0, 0), (-1, -1), 4),
        ('LEFTPADDING', (0, 0), (-1, -1), 6),
    ]))
    elems.append(foot_tbl)
    return elems


# ── Header / Footer callback ─────────────────────────────────────────────────

def on_page(canvas, doc):
    """Draw page header and footer on every page."""
    canvas.saveState()
    w, h = A4

    # Top strip
    canvas.setFillColor(HEADER_BG)
    canvas.rect(0, h - 0.55*cm, w, 0.55*cm, fill=1, stroke=0)
    canvas.setFont('Helvetica-Bold', 7.5)
    canvas.setFillColor(WHITE)
    canvas.drawString(1.5*cm, h - 0.40*cm, "ICU ECG PATTERN REFERENCE")
    canvas.drawRightString(w - 1.5*cm, h - 0.40*cm, f"Page {doc.page}")

    # Bottom strip
    canvas.setFillColor(colors.HexColor('#EAECEE'))
    canvas.rect(0, 0, w, 0.45*cm, fill=1, stroke=0)
    canvas.setFont('Helvetica', 6.5)
    canvas.setFillColor(MID_GRAY)
    canvas.drawCentredString(w/2, 0.14*cm,
        "Educational Reference Only | Confirm with Supervising Physician | Sources: Rosen's EM, Harrison's, Washington Manual")

    canvas.restoreState()


# ── Main builder ─────────────────────────────────────────────────────────────

def build_pdf(output_path):
    doc = SimpleDocTemplate(
        output_path,
        pagesize=A4,
        leftMargin=1.2*cm, rightMargin=1.2*cm,
        topMargin=1.0*cm,  bottomMargin=0.8*cm,
        title="ICU ECG Pattern Reference",
        author="Orris Medical AI",
        subject="Critical Care ECG Quick Reference"
    )

    styles = build_styles()

    story = []

    # Cover
    story += build_cover(styles)
    story.append(PageBreak())

    # Page 1 - Normal ECG
    story += page_normal_ecg(styles)
    story.append(PageBreak())

    # Page 2 - STEMI
    story += page_stemi(styles)
    story.append(PageBreak())

    # Page 3 - ST depression / T changes
    story += page_st_depression_t(styles)
    story.append(PageBreak())

    # Page 4 - Supraventricular
    story += page_supra_arrhythmias(styles)
    story.append(PageBreak())

    # Page 5 - Ventricular arrhythmias
    story += page_ventricular_arrhythmias(styles)
    story.append(PageBreak())

    # Page 6 - Bradyarrhythmias
    story += page_bradyarrhythmias(styles)
    story.append(PageBreak())

    # Page 7 - Electrolytes
    story += page_electrolytes(styles)
    story.append(PageBreak())

    # Page 8 - Special patterns
    story += page_special_patterns(styles)
    story.append(PageBreak())

    # Page 9 - Emergency table
    story += page_emergency_table(styles)

    doc.build(story, onFirstPage=on_page, onLaterPages=on_page)
    print(f"PDF created: {output_path}")


if __name__ == "__main__":
    build_pdf("/home/daytona/workspace/ecg-reference/ICU_ECG_Reference.pdf")
Running Command

cd /home/daytona/workspace/ecg-reference && python3 generate_ecg_pdf.py 2>&1

Editing File

~/ecg-reference/generate_ecg_pdf.py

Successfully replaced 1 instance(s) of the string in '/home/daytona/workspace/ecg-reference/generate_ecg_pdf.py'
Running Command

cd /home/daytona/workspace/ecg-reference && python3 generate_ecg_pdf.py 2>&1

Running Command

cd /home/daytona/workspace/ecg-reference && python3 -c " import traceback from generate_ecg_pdf import * styles = build_styles() # Test each page function for fn_name, fn in [('cover', build_cover), ('normal', page_normal_ecg), ('stemi', page_stemi), ('st_dep', page_st_depression_t), ('supra', page_supra_arrhythmias), ('vent', page_ventricular_arrhythmias), ('brady', page_bradyarrhythmias), ('elec', page_electrolytes), ('special', page_special_patterns), ('emergency', page_emergency_table)]: try: elems = fn(styles) print(f'OK: {fn_name} -> {len(elems)} elements') except Exception as e: print(f'ERROR in {fn_name}: {e}') traceback.print_exc() " 2>&1

Running Command

cd /home/daytona/workspace/ecg-reference && python3 -c " from generate_ecg_pdf import * from reportlab.lib.pagesizes import A4 from reportlab.platypus import SimpleDocTemplate, PageBreak styles = build_styles() doc = SimpleDocTemplate('/tmp/test_ecg.pdf', pagesize=A4, leftMargin=1.2*cm, rightMargin=1.2*cm, topMargin=1.0*cm, bottomMargin=0.8*cm) story = [] story += build_cover(styles) story.append(PageBreak()) # Test page by page pages = [page_normal_ecg, page_stemi, page_st_depression_t, page_supra_arrhythmias, page_ventricular_arrhythmias, page_bradyarrhythmias, page_electrolytes, page_special_patterns, page_emergency_table] for i, page_fn in enumerate(pages): print(f'Adding page {i+1}: {page_fn.__name__}') story += page_fn(styles) story.append(PageBreak()) print('Building PDF...') doc.build(story, onFirstPage=on_page, onLaterPages=on_page) print('Done!') " 2>&1

Running Command

cd /home/daytona/workspace/ecg-reference && python3 -c " from generate_ecg_pdf import * from reportlab.lib.pagesizes import A4 from reportlab.platypus import SimpleDocTemplate, PageBreak styles = build_styles() # Test just cover doc = SimpleDocTemplate('/tmp/test1.pdf', pagesize=A4, leftMargin=1.2*cm, rightMargin=1.2*cm, topMargin=1.0*cm, bottomMargin=0.8*cm) story = build_cover(styles) try: doc.build(story, onFirstPage=on_page, onLaterPages=on_page) print('Cover OK') except Exception as e: print(f'Cover FAIL: {e}') # Test just cover + page_normal doc2 = SimpleDocTemplate('/tmp/test2.pdf', pagesize=A4, leftMargin=1.2*cm, rightMargin=1.2*cm, topMargin=1.0*cm, bottomMargin=0.8*cm) story2 = build_cover(styles) + [PageBreak()] + page_normal_ecg(styles) try: doc2.build(story2, onFirstPage=on_page, onLaterPages=on_page) print('Normal ECG page OK') except Exception as e: print(f'Normal ECG page FAIL: {e}') " 2>&1

Running Command

cd /home/daytona/workspace/ecg-reference && python3 -c " from generate_ecg_pdf import * from reportlab.lib.pagesizes import A4 from reportlab.platypus import SimpleDocTemplate, PageBreak styles = build_styles() pages = [page_stemi, page_st_depression_t, page_supra_arrhythmias, page_ventricular_arrhythmias, page_bradyarrhythmias, page_electrolytes, page_special_patterns, page_emergency_table] for page_fn in pages: doc = SimpleDocTemplate('/tmp/test_p.pdf', pagesize=A4, leftMargin=1.2*cm, rightMargin=1.2*cm, topMargin=1.0*cm, bottomMargin=0.8*cm) try: doc.build(page_fn(styles), onFirstPage=on_page, onLaterPages=on_page) print(f'OK: {page_fn.__name__}') except Exception as e: print(f'FAIL: {page_fn.__name__}: {e}') " 2>&1

Editing File

~/ecg-reference/generate_ecg_pdf.py

Successfully replaced 1 instance(s) of the string in '/home/daytona/workspace/ecg-reference/generate_ecg_pdf.py'
Editing File

~/ecg-reference/generate_ecg_pdf.py

Successfully replaced 1 instance(s) of the string in '/home/daytona/workspace/ecg-reference/generate_ecg_pdf.py'
Editing File

~/ecg-reference/generate_ecg_pdf.py

Successfully replaced 1 instance(s) of the string in '/home/daytona/workspace/ecg-reference/generate_ecg_pdf.py'
Editing File

~/ecg-reference/generate_ecg_pdf.py

Successfully replaced 1 instance(s) of the string in '/home/daytona/workspace/ecg-reference/generate_ecg_pdf.py'
Editing File

~/ecg-reference/generate_ecg_pdf.py

Successfully replaced 1 instance(s) of the string in '/home/daytona/workspace/ecg-reference/generate_ecg_pdf.py'
Editing File

~/ecg-reference/generate_ecg_pdf.py

Successfully replaced 1 instance(s) of the string in '/home/daytona/workspace/ecg-reference/generate_ecg_pdf.py'
Running Command

cd /home/daytona/workspace/ecg-reference && python3 generate_ecg_pdf.py 2>&1

Running Command

ls -lh /home/daytona/workspace/ecg-reference/ICU_ECG_Reference.pdf

Model call limits exceeded: run limit (20/20)
This is a shared conversation. Sign in to Orris to start your own chat.