Biochemical changes of body all values normal and abnormal values with reason of abnormality

Reading File
Finding Sources
Finding Sources
Finding Sources
Finding Sources
Finding Sources
Finding Sources
Finding Sources
Finding Sources
Finding Sources
Reading File
Reading File
I now have excellent, comprehensive data from Guyton's physiology tables and Goldman-Cecil Medicine's reference intervals. I have enough to produce a thorough, well-organized answer. Let me compile this now.

Biochemical Changes of the Body: Normal & Abnormal Values with Reasons for Abnormality

Sources: Guyton and Hall Textbook of Medical Physiology, Goldman-Cecil Medicine (Reference Intervals Appendix), Harrison's Principles of Internal Medicine 22e

1. ELECTROLYTES

Sodium (Na⁺)

StatusValue
Normal135-145 mmol/L (avg 142)
Hyponatremia< 135 mmol/L
Hypernatremia> 145 mmol/L
Causes of Hyponatremia (low Na): Excessive water intake, SIADH (Syndrome of Inappropriate ADH secretion), heart failure, cirrhosis, nephrotic syndrome, hypothyroidism, adrenal insufficiency, diuretic use.
Causes of Hypernatremia (high Na): Dehydration/inadequate water intake, diabetes insipidus (central or nephrogenic), excessive Na intake, Conn's syndrome (primary hyperaldosteronism).

Potassium (K⁺)

StatusValue
Normal3.5-5.3 mmol/L (avg 4.2)
Hypokalemia< 3.5 mmol/L
Hyperkalemia> 5.3 mmol/L
Causes of Hypokalemia: Diuretics (thiazides, loop diuretics), vomiting/diarrhea, hyperaldosteronism, Cushing's syndrome, insulin excess, alkalosis (intracellular shift), poor dietary intake.
Causes of Hyperkalemia: Renal failure (impaired excretion), Addison's disease (low aldosterone), ACE inhibitors/ARBs, acidosis (extracellular shift), crush injuries/rhabdomyolysis, excessive K supplementation, hemolysis (spurious).

Chloride (Cl⁻)

StatusValue
Normal98-108 mmol/L (avg 106)
Hypochloremia< 98 mmol/L
Hyperchloremia> 108 mmol/L
Causes of Hypochloremia: Vomiting (loss of HCl), metabolic alkalosis, diuretics, Addison's disease.
Causes of Hyperchloremia: Hyperchloremic metabolic acidosis (e.g., diarrhea losing bicarbonate), renal tubular acidosis, excessive saline infusion.

Bicarbonate (HCO₃⁻)

StatusValue
Normal22-29 mmol/L (avg 24)
Low< 22 mmol/L
High> 29 mmol/L
Low HCO₃ (Metabolic acidosis): Diabetic ketoacidosis, lactic acidosis, renal failure, diarrhea, renal tubular acidosis, ingestion of acids (methanol, salicylates).
High HCO₃ (Metabolic alkalosis): Vomiting, excessive antacids, hyperaldosteronism, loop/thiazide diuretics, Cushing's syndrome.

Calcium (Ca²⁺)

StatusValue
Normal (total)8.5-10.5 mg/dL (avg 10.0)
Normal (ionized)4.65-5.28 mg/dL
Hypocalcemia< 8.5 mg/dL (total)
Hypercalcemia> 10.5 mg/dL (total)
Causes of Hypocalcemia: Hypoparathyroidism, vitamin D deficiency (rickets, osteomalacia), chronic renal failure (reduced 1,25-OH D3), pancreatitis, hypomagnesemia, hypoalbuminemia (apparent only).
Causes of Hypercalcemia: Hyperparathyroidism (most common outpatient), malignancy (PTHrP secretion, lytic bone mets), vitamin D toxicity, sarcoidosis, Paget's disease, thiazide diuretics, milk-alkali syndrome.

Magnesium (Mg²⁺)

StatusValue
Normal (total)1.3-2.4 mEq/L (avg 1.8)
Normal (ionized)0.6-1.1 mEq/L
Hypomagnesemia< 1.3 mEq/L
Hypermagnesemia> 2.4 mEq/L
Causes of Hypomagnesemia: Malabsorption, chronic alcoholism, loop/thiazide diuretics, diarrhea, poorly controlled diabetes, proton pump inhibitors (long-term use).
Causes of Hypermagnesemia: Renal failure, excessive Mg antacid/laxative use, Mg-containing IV infusion.

Phosphate

StatusValue
Normal2.5-4.5 mg/dL (avg 3.5)
Hypophosphatemia< 2.5 mg/dL
Hyperphosphatemia> 4.5 mg/dL
Causes of Hypophosphatemia: Malnutrition, refeeding syndrome, hyperparathyroidism, vitamin D deficiency, antacid overuse (phosphate binding), alcoholism.
Causes of Hyperphosphatemia: Renal failure, hypoparathyroidism, rhabdomyolysis, vitamin D toxicity, excessive dietary phosphate.

2. BLOOD GLUCOSE

StatusValue
Fasting (normal)70-100 mg/dL (3.9-5.5 mmol/L)
Pre-diabetes (IFG)100-125 mg/dL
Diabetes mellitus≥ 126 mg/dL (fasting)
Hypoglycemia< 70 mg/dL
HbA1c (normal)< 5.7%
HbA1c (diabetes)≥ 6.5%
Causes of Hyperglycemia: Type 1 DM (absolute insulin deficiency), Type 2 DM (insulin resistance + relative deficiency), Cushing's syndrome (cortisol antagonizes insulin), acromegaly (GH excess), pancreatitis/pancreatectomy, stress hyperglycemia (catecholamines), drugs (corticosteroids, thiazides, atypical antipsychotics).
Causes of Hypoglycemia: Insulin overdose, sulfonylurea use, prolonged fasting, Addison's disease (cortisol deficiency), insulinoma, liver failure (impaired gluconeogenesis), alcohol (blocks gluconeogenesis), reactive hypoglycemia.

3. LIVER FUNCTION TESTS (LFTs)

ALT (Alanine Aminotransferase / SGPT)

StatusValue
Normal7-56 U/L (M: up to 45; F: up to 34 per Goldman-Cecil)
Elevated> 56 U/L
Causes of elevation: Viral hepatitis (very high, >500), alcoholic hepatitis, NAFLD/NASH, drug-induced liver injury (paracetamol, isoniazid), autoimmune hepatitis, ischemic hepatitis (>1000 - "shock liver"), celiac disease.

AST (Aspartate Aminotransferase / SGOT)

StatusValue
Normal10-40 U/L
Elevated> 40 U/L
AST:ALT ratio > 2:1 strongly suggests alcoholic liver disease (alcohol damages mitochondria, releasing mitochondrial AST; also alcohol depletes pyridoxine needed for ALT synthesis).

Alkaline Phosphatase (ALP)

StatusValue
Normal44-147 U/L
Elevated> 147 U/L
Causes of elevation: Cholestasis (biliary obstruction - most common), Paget's disease of bone, liver metastases, pregnancy (placental isoenzyme), healing fractures, hyperparathyroidism.

Gamma-GT (GGT)

Normal (M)Normal (F)Elevated
8-61 U/L5-36 U/L> upper limit
Elevated in: Alcohol use (most sensitive marker), cholestasis, fatty liver, enzyme-inducing drugs (phenytoin, rifampicin).

Bilirubin

StatusValue
Total (normal)0.2-1.2 mg/dL (3-21 μmol/L)
Direct (conjugated)0-0.3 mg/dL
Indirect (unconjugated)0.2-0.9 mg/dL
Jaundice> 2.5-3.0 mg/dL (clinically visible)
High Unconjugated (Indirect) Bilirubin: Hemolysis, Gilbert's syndrome, Crigler-Najjar syndrome, neonatal jaundice (physiological or pathological), ineffective erythropoiesis.
High Conjugated (Direct) Bilirubin: Hepatocellular damage (hepatitis, cirrhosis), biliary obstruction (gallstones, cholangiocarcinoma, pancreatic head cancer), Dubin-Johnson syndrome, Rotor syndrome.

Serum Albumin

StatusValue
Normal3.5-5.0 g/dL
Hypoalbuminemia< 3.5 g/dL
Causes of Low Albumin (synthesized in liver): Chronic liver disease (cirrhosis), malnutrition/malabsorption, nephrotic syndrome (urinary losses), chronic inflammation/acute phase response (negative acute-phase protein), protein-losing enteropathy.

Serum Total Protein

StatusValue
Normal6.4-8.3 g/dL
Low< 6.4 g/dL
High> 8.3 g/dL
High total protein with low albumin (elevated globulin fraction) suggests: Multiple myeloma, chronic infections (HIV, TB, viral hepatitis), autoimmune disease (SLE, rheumatoid arthritis), sarcoidosis.

4. KIDNEY FUNCTION TESTS

Blood Urea Nitrogen (BUN)

StatusValue
Normal8-25 mg/dL (2.9-8.9 mmol/L)
Elevated (azotemia)> 25 mg/dL
Causes of Elevated BUN:
  • Pre-renal: Dehydration, heart failure, GI bleeding (blood protein digested to urea), high protein diet
  • Renal: Acute kidney injury, chronic kidney disease, glomerulonephritis
  • Post-renal: Urinary tract obstruction (BPH, stones, tumor)
Low BUN: Liver failure (urea synthesis impaired), malnutrition, SIADH (dilutional).

Serum Creatinine

StatusValue
Normal (M)0.7-1.3 mg/dL
Normal (F)0.6-1.1 mg/dL
ElevatedAbove upper limit
Causes of Elevated Creatinine: Acute/chronic kidney disease (most important - reflects GFR reduction), rhabdomyolysis (muscle breakdown), high meat diet, drugs (trimethoprim, cimetidine block tubular secretion - spurious elevation), very muscular individuals.
BUN:Creatinine Ratio:
  • Normal: 10:1 to 20:1
  • 20:1 → Pre-renal azotemia or GI bleeding
  • < 10:1 → Liver failure, malnutrition, SIADH

eGFR (Estimated GFR)

CategoryValue
Normal≥ 90 mL/min/1.73m²
Mild CKD (G2)60-89
Moderate CKD (G3)30-59
Severe CKD (G4)15-29
Kidney failure (G5)< 15

Uric Acid

StatusValue
Normal (M)3.5-7.2 mg/dL
Normal (F)2.6-6.0 mg/dL
Hyperuricemia> 7.0 mg/dL (M), > 6.0 mg/dL (F)
Causes of Hyperuricemia (Gout): Purine-rich diet (red meat, shellfish), alcohol (inhibits urate excretion), diuretics, renal failure, leukemia/lymphoma (high cell turnover), Lesch-Nyhan syndrome, chemotherapy (tumor lysis).
Low uric acid: Xanthine oxidase inhibitors (allopurinol), Wilson's disease, SIADH.

5. LIPID PROFILE

ParameterDesirableBorderlineHigh Risk
Total cholesterol< 200 mg/dL200-239≥ 240 mg/dL
LDL cholesterol< 100 mg/dL (optimal)130-159≥ 160 mg/dL
HDL cholesterol≥ 60 mg/dL (protective)40-59< 40 mg/dL (M), < 50 (F)
Triglycerides< 150 mg/dL150-199≥ 200 mg/dL; Very high ≥ 500
Causes of High LDL/Total Cholesterol: Familial hypercholesterolemia (LDL receptor defect), hypothyroidism, nephrotic syndrome, cholestasis, diabetes, high saturated fat diet, obesity.
Causes of High Triglycerides: Type 2 DM, obesity, metabolic syndrome, alcohol excess, hypothyroidism, nephrotic syndrome, familial hypertriglyceridemia, estrogens, beta-blockers.
Causes of Low HDL: Smoking, obesity, physical inactivity, type 2 DM, metabolic syndrome, hypertriglyceridemia, androgenic steroids, beta-blockers.

6. THYROID FUNCTION TESTS (TFTs)

TestNormalHypothyroidHyperthyroid
TSH0.4-4.0 mIU/LHigh (↑↑)Low (↓)
Free T40.8-1.8 ng/dLLowHigh
Free T32.3-4.2 pg/mLLowHigh
Hypothyroidism: Hashimoto's thyroiditis (autoimmune), iodine deficiency, post-thyroidectomy, radioiodine therapy, medications (amiodarone, lithium). Biochemically: high TSH, low fT4. Metabolic effects: elevated cholesterol, hyponatremia, elevated CK (myopathy), anemia.
Hyperthyroidism: Graves' disease (TSH receptor antibodies), toxic multinodular goitre, thyroiditis, iodine excess. Biochemically: low TSH, high fT4/fT3. Metabolic effects: low cholesterol, elevated LFTs (mild), elevated glucose.

7. ARTERIAL BLOOD GAS (ABG)

ParameterNormalAcidoticAlkalotic
pH7.35-7.45< 7.35> 7.45
PaCO₂35-45 mmHg> 45 (resp. acidosis)< 35 (resp. alkalosis)
PaO₂75-100 mmHg--
HCO₃22-26 mEq/L< 22 (met. acidosis)> 26 (met. alkalosis)
O₂ Sat95-100%--
Respiratory Acidosis (↑CO₂): COPD, asthma (acute severe), respiratory muscle weakness (GBS, myasthenia), opioid overdose, obesity hypoventilation.
Respiratory Alkalosis (↓CO₂): Hyperventilation (anxiety, pain), high altitude, sepsis, pregnancy (progesterone stimulates respiration), mechanical over-ventilation.
Metabolic Acidosis (↓HCO₃): DKA, lactic acidosis, renal failure, methanol/ethylene glycol ingestion, diarrhea (bicarbonate loss), renal tubular acidosis.
Metabolic Alkalosis (↑HCO₃): Vomiting, NG tube suction (HCl loss), diuretics, Cushing's, Conn's syndrome, antacid overuse.

8. COMPLETE BLOOD COUNT - KEY BIOCHEMICAL CORRELATES

ParameterNormalAbnormal
Hemoglobin (M)13.5-17.5 g/dL< 13.5 = anemia
Hemoglobin (F)12.0-15.5 g/dL< 12.0 = anemia
Serum Iron60-170 mcg/dLLow = IDA; High = hemochromatosis
TIBC240-450 mcg/dLHigh in IDA; Low in ACD/iron overload
Serum Ferritin12-300 ng/mL (M)Low = IDA; High = iron overload, inflammation
Vitamin B12200-900 pg/mL< 200 = megaloblastic anemia
Folate2.7-17.0 ng/mLLow in alcohol, malabsorption, folate-poor diet
Iron Deficiency Anemia (IDA): Low ferritin (depleted stores), low serum iron, high TIBC (liver upregulates transferrin), low MCV (microcytic). Causes: chronic blood loss (GI, menstrual), poor dietary intake, malabsorption (celiac).
Megaloblastic Anemia: Low B12 or folate → impaired DNA synthesis → macrocytic (large) RBCs, hypersegmented neutrophils. B12 deficiency also causes subacute combined degeneration of spinal cord.

9. CARDIAC BIOMARKERS

BiomarkerNormalElevated atPeak atSignificance
Troponin I/T (high-sensitivity)< 0.04 ng/mL3-6 hrs12-24 hrsMI, myocarditis, PE
CK-MB< 5 ng/mL3-6 hrs12-24 hrsMI (more cardiac-specific than total CK)
BNP (B-type natriuretic peptide)< 100 pg/mLChronicPersistentHeart failure
NT-proBNP< 125 pg/mLChronicPersistentHeart failure
High Troponin causes: MI (most important), myocarditis, pulmonary embolism (right heart strain), sepsis, renal failure (impaired clearance), cardiac contusion, cardioversion.
High BNP/NT-proBNP: Left ventricular dysfunction/heart failure, pulmonary hypertension, renal failure. Used to distinguish cardiac vs non-cardiac dyspnea.

10. INFLAMMATORY/ACUTE PHASE MARKERS

MarkerNormalElevated
CRP (C-reactive protein)< 1.0 mg/dL (<10 mg/L)> 1.0 mg/dL
ESRM: < 15 mm/hr; F: < 20 mm/hr> 20-30 mm/hr
Fibrinogen200-400 mg/dLRaised in inflammation
Procalcitonin (PCT)< 0.1 ng/mL> 0.5 = bacterial sepsis likely
Causes of High CRP: Bacterial infections (very high, >100 mg/L), autoimmune disease (RA, SLE, vasculitis), tissue necrosis (MI, surgery), malignancy. CRP is a more sensitive and rapid marker than ESR.
High ESR: Multiple myeloma (paraprotein - highest ESR levels), chronic infection (TB, endocarditis), autoimmune diseases, malignancy, pregnancy, anemia.
Low ESR: Polycythemia vera, sickle cell disease, hypofibrinogenemia, heart failure.

11. HORMONAL / SPECIAL BIOCHEMISTRY

HormoneNormalLowHigh
Cortisol (AM)6-23 mcg/dLAddison's, hypopituitarismCushing's, stress, depression
ACTH7-63 pg/mL (AM)Secondary adrenal insufficiency (pituitary)Primary adrenal insufficiency, Cushing's (pituitary/ectopic)
Growth Hormone (GH)< 1 ng/mL (adult)GH deficiencyAcromegaly (adult), gigantism (child)
Insulin (fasting)2-25 mIU/LType 1 DMInsulinoma, metabolic syndrome, Type 2 DM (early)
Serum Ferritin12-300 ng/mLIDAHemochromatosis, ferritin-related inflammation
Parathyroid hormone (PTH)15-65 pg/mLHypoparathyroidismPrimary hyperparathyroidism, renal failure (secondary)

Summary Quick Reference Table

TestNormal RangeLow = SuggestsHigh = Suggests
Na⁺135-145 mmol/LSIADH, heart failure, cirrhosisDehydration, DI, Conn's
K⁺3.5-5.3 mmol/LDiuretics, vomiting, alkalosisRenal failure, Addison's, acidosis
Glucose (fasting)70-100 mg/dLInsulinoma, Addison's, liver failureDM, Cushing's, steroids
Creatinine0.6-1.3 mg/dLMalnutrition, low muscle massKidney disease, rhabdomyolysis
ALT< 56 U/L-Hepatitis, liver damage
Total cholesterol< 200 mg/dLMalnutrition, hyperthyroidismCAD risk, hypothyroidism
Troponin< 0.04 ng/mL-MI, myocarditis, PE
TSH0.4-4.0 mIU/LHyperthyroidism, pituitary failureHypothyroidism
HCO₃22-26 mEq/LMetabolic acidosis, diarrheaMetabolic alkalosis, vomiting
Albumin3.5-5.0 g/dLCirrhosis, malnutrition, nephroticDehydration (hemoconcentration)

Key Clinical Principles:
  1. No lab value is interpreted in isolation - always correlate with clinical context.
  2. Many conditions cause multiple simultaneous biochemical abnormalities (e.g., DKA causes hyperglycemia, metabolic acidosis, hypokalemia, high anion gap, and ketonemia all together).
  3. Reference ranges vary by lab, method, and population (age, sex, pregnancy).
  4. "Normal" range typically covers the middle 95% of a healthy reference population - 5% of healthy people will have "abnormal" values.
Sources: Guyton and Hall Textbook of Medical Physiology (Elsevier, 14e), Goldman-Cecil Medicine Reference Intervals Appendix, Harrison's Principles of Internal Medicine 22e (2025)

Create a clinical interpretation guide PDF with flowcharts for abnormal labs

Reading File
Running Command

mkdir -p /home/daytona/workspace/clinical-lab-guide && ls /home/daytona/workspace/clinical-lab-guide && python3 -c "import reportlab; import matplotlib; print('reportlab:', reportlab.Version); print('matplotlib OK')"

Writing File

~/clinical-lab-guide/generate_guide.py

"""
Clinical Laboratory Interpretation Guide with Flowcharts
Generates a comprehensive PDF using ReportLab + Matplotlib
"""

import os
import io
import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import matplotlib.patches as mpatches
from matplotlib.patches import FancyBboxPatch, FancyArrowPatch
import numpy as np

from reportlab.lib.pagesizes import A4
from reportlab.lib import colors
from reportlab.lib.units import cm, mm
from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
from reportlab.lib.enums import TA_CENTER, TA_LEFT, TA_JUSTIFY
from reportlab.platypus import (
    SimpleDocTemplate, Paragraph, Spacer, Table, TableStyle,
    PageBreak, Image as RLImage, HRFlowable, KeepTogether
)
from reportlab.graphics.shapes import Drawing, Rect, String, Line, Polygon
from reportlab.graphics import renderPDF

OUTPUT_PATH = "/home/daytona/workspace/clinical-lab-guide/Clinical_Lab_Interpretation_Guide.pdf"

# ── Color palette ──────────────────────────────────────────────────────────────
NAVY     = colors.HexColor('#1A2B5C')
TEAL     = colors.HexColor('#006D77')
GREEN    = colors.HexColor('#2D6A4F')
RED      = colors.HexColor('#C62828')
ORANGE   = colors.HexColor('#E65100')
GOLD     = colors.HexColor('#F9A825')
LAVENDER = colors.HexColor('#E8EAF6')
LIGHT_BG = colors.HexColor('#F0F4F8')
MINT     = colors.HexColor('#E0F2F1')
WHITE    = colors.white
GRAY     = colors.HexColor('#607D8B')
DARKGRAY = colors.HexColor('#37474F')

# ── Styles ─────────────────────────────────────────────────────────────────────
def build_styles():
    styles = getSampleStyleSheet()
    custom = {}

    custom['CoverTitle'] = ParagraphStyle('CoverTitle',
        fontName='Helvetica-Bold', fontSize=28, textColor=WHITE,
        alignment=TA_CENTER, spaceAfter=8, leading=34)

    custom['CoverSub'] = ParagraphStyle('CoverSub',
        fontName='Helvetica', fontSize=13, textColor=colors.HexColor('#BBDEFB'),
        alignment=TA_CENTER, spaceAfter=4, leading=18)

    custom['SectionHeader'] = ParagraphStyle('SectionHeader',
        fontName='Helvetica-Bold', fontSize=15, textColor=WHITE,
        alignment=TA_LEFT, spaceAfter=6, spaceBefore=4, leading=20,
        leftIndent=10)

    custom['SubHeader'] = ParagraphStyle('SubHeader',
        fontName='Helvetica-Bold', fontSize=11, textColor=NAVY,
        alignment=TA_LEFT, spaceAfter=4, spaceBefore=6, leading=14)

    custom['Body'] = ParagraphStyle('Body',
        fontName='Helvetica', fontSize=9, textColor=DARKGRAY,
        alignment=TA_JUSTIFY, spaceAfter=4, leading=13, leftIndent=4)

    custom['Bullet'] = ParagraphStyle('Bullet',
        fontName='Helvetica', fontSize=9, textColor=DARKGRAY,
        alignment=TA_LEFT, spaceAfter=2, leading=13, leftIndent=14,
        firstLineIndent=-10)

    custom['Caption'] = ParagraphStyle('Caption',
        fontName='Helvetica-Oblique', fontSize=8, textColor=GRAY,
        alignment=TA_CENTER, spaceAfter=2, leading=11)

    custom['TableHeader'] = ParagraphStyle('TableHeader',
        fontName='Helvetica-Bold', fontSize=8, textColor=WHITE,
        alignment=TA_CENTER, leading=10)

    custom['TableCell'] = ParagraphStyle('TableCell',
        fontName='Helvetica', fontSize=8, textColor=DARKGRAY,
        alignment=TA_LEFT, leading=11)

    custom['NormalRange'] = ParagraphStyle('NormalRange',
        fontName='Helvetica-Bold', fontSize=8, textColor=GREEN,
        alignment=TA_CENTER, leading=11)

    custom['Warning'] = ParagraphStyle('Warning',
        fontName='Helvetica-BoldOblique', fontSize=8, textColor=RED,
        alignment=TA_LEFT, leading=11, leftIndent=6)

    return custom

# ── Flowchart builder (matplotlib) ─────────────────────────────────────────────
def make_flowchart(title, nodes, arrows, figsize=(8, 9), colors_map=None):
    """
    nodes: list of dicts {id, label, x, y, shape, color, fontsize}
    arrows: list of (from_id, to_id, label)
    Returns PNG bytes
    """
    fig, ax = plt.subplots(figsize=figsize)
    ax.set_xlim(0, 10)
    ax.set_ylim(0, 10)
    ax.axis('off')

    # Title
    ax.text(5, 9.6, title, ha='center', va='center', fontsize=13,
            fontweight='bold', color='#1A2B5C',
            bbox=dict(boxstyle='round,pad=0.4', facecolor='#E8EAF6', edgecolor='#1A2B5C', lw=1.5))

    node_centers = {}
    for n in nodes:
        x, y = n['x'], n['y']
        w = n.get('w', 3.2)
        h = n.get('h', 0.65)
        color = n.get('color', '#006D77')
        shape = n.get('shape', 'round')
        fc = n.get('fc', '#E0F2F1')
        fs = n.get('fontsize', 8)
        node_centers[n['id']] = (x, y)

        if shape == 'diamond':
            dx, dy = w/2, h*1.1
            diamond = plt.Polygon(
                [[x, y+dy], [x+dx*0.85, y], [x, y-dy], [x-dx*0.85, y]],
                closed=True, facecolor=fc, edgecolor=color, lw=1.5)
            ax.add_patch(diamond)
            ax.text(x, y, n['label'], ha='center', va='center',
                    fontsize=fs, color=color, fontweight='bold',
                    wrap=True, multialignment='center')
        elif shape == 'oval':
            ellipse = mpatches.Ellipse((x, y), w, h*1.3,
                facecolor=fc, edgecolor=color, lw=1.5)
            ax.add_patch(ellipse)
            ax.text(x, y, n['label'], ha='center', va='center',
                    fontsize=fs, color=color, fontweight='bold')
        else:  # rectangle / rounded
            box = FancyBboxPatch((x - w/2, y - h/2), w, h,
                boxstyle='round,pad=0.08',
                facecolor=fc, edgecolor=color, lw=1.5)
            ax.add_patch(box)
            ax.text(x, y, n['label'], ha='center', va='center',
                    fontsize=fs, color=color, fontweight='bold',
                    multialignment='center')

    for (src, dst, lbl) in arrows:
        x1, y1 = node_centers[src]
        x2, y2 = node_centers[dst]
        ax.annotate('', xy=(x2, y2+0.35), xytext=(x1, y1-0.35),
                    arrowprops=dict(arrowstyle='->', color='#607D8B',
                                   lw=1.4, connectionstyle='arc3,rad=0.0'))
        if lbl:
            mx = (x1+x2)/2 + 0.15
            my = (y1+y2)/2
            ax.text(mx, my, lbl, fontsize=7, color='#E65100',
                    fontstyle='italic', ha='left', va='center')

    plt.tight_layout(pad=0.3)
    buf = io.BytesIO()
    plt.savefig(buf, format='png', dpi=150, bbox_inches='tight')
    plt.close(fig)
    buf.seek(0)
    return buf

# ── Individual flowcharts ───────────────────────────────────────────────────────

def fc_sodium():
    nodes = [
        {'id':'start','label':'Serum Sodium Result','x':5,'y':9.0,'shape':'oval','color':'#1A2B5C','fc':'#E8EAF6','w':3.5,'h':0.7},
        {'id':'check','label':'Is Na⁺ < 135 or > 145?','x':5,'y':7.8,'shape':'diamond','color':'#006D77','fc':'#E0F2F1','w':3.6,'h':0.8,'fontsize':8},
        {'id':'normal','label':'NORMAL (135-145 mmol/L)\nNo action needed','x':8.2,'y':7.8,'shape':'round','color':'#2D6A4F','fc':'#C8E6C9','w':3.0,'h':0.7,'fontsize':7},
        {'id':'hypo','label':'HYPONATREMIA\n< 135 mmol/L','x':2,'y':6.4,'shape':'round','color':'#C62828','fc':'#FFCDD2','w':2.8,'h':0.7,'fontsize':8},
        {'id':'hyper','label':'HYPERNATREMIA\n> 145 mmol/L','x':7.5,'y':6.4,'shape':'round','color':'#E65100','fc':'#FFE0B2','w':2.8,'h':0.7,'fontsize':8},
        {'id':'osm','label':'Check serum osmolality\n& urine osmolality','x':2,'y':5.1,'shape':'round','color':'#006D77','fc':'#E0F2F1','w':2.8,'h':0.7,'fontsize':7},
        {'id':'hyper_cause','label':'Water loss > Na loss?\nOr Na gain?','x':7.5,'y':5.1,'shape':'diamond','color':'#006D77','fc':'#E0F2F1','w':2.8,'h':0.75,'fontsize':7},
        {'id':'dilutional','label':'Dilutional:\nSIADH / Heart failure\nCirrhosis / Nephrotic','x':0.8,'y':3.7,'shape':'round','color':'#7B1FA2','fc':'#F3E5F5','w':2.5,'h':0.85,'fontsize':7},
        {'id':'depletional','label':'Depletional:\nDiuretics / Vomiting\nAdrenal insufficiency','x':3.2,'y':3.7,'shape':'round','color':'#C62828','fc':'#FFCDD2','w':2.5,'h':0.85,'fontsize':7},
        {'id':'water_loss','label':'Water loss:\nDiabetes insipidus\nInsensible losses','x':6.5,'y':3.7,'shape':'round','color':'#E65100','fc':'#FFE0B2','w':2.5,'h':0.85,'fontsize':7},
        {'id':'na_gain','label':'Na gain:\nConn\'s syndrome\nHypertonic saline','x':9.0,'y':3.7,'shape':'round','color':'#F57F17','fc':'#FFF9C4','w':2.4,'h':0.85,'fontsize':7},
        {'id':'rx_hypo','label':'Rx: Fluid restrict / treat cause\nSevere: hypertonic saline\n(correct slowly: 0.5 mEq/hr)','x':2,'y':2.2,'shape':'round','color':'#1A2B5C','fc':'#E8EAF6','w':3.2,'h':0.85,'fontsize':7},
        {'id':'rx_hyper','label':'Rx: Free water replacement\nDI: Desmopressin\n(correct slowly: 0.5 mEq/hr)','x':7.5,'y':2.2,'shape':'round','color':'#1A2B5C','fc':'#E8EAF6','w':3.2,'h':0.85,'fontsize':7},
    ]
    arrows = [
        ('start','check',''),
        ('check','normal','Normal'),
        ('check','hypo','< 135'),
        ('check','hyper','> 145'),
        ('hypo','osm',''),
        ('hyper','hyper_cause',''),
        ('osm','dilutional','Low osm'),
        ('osm','depletional','Low osm + UNa<20'),
        ('hyper_cause','water_loss','Water loss'),
        ('hyper_cause','na_gain','Na gain'),
        ('dilutional','rx_hypo',''),
        ('depletional','rx_hypo',''),
        ('water_loss','rx_hyper',''),
        ('na_gain','rx_hyper',''),
    ]
    return make_flowchart('Sodium (Na⁺) Interpretation Flowchart', nodes, arrows, figsize=(10,10))

def fc_potassium():
    nodes = [
        {'id':'start','label':'Serum Potassium Result','x':5,'y':9.2,'shape':'oval','color':'#1A2B5C','fc':'#E8EAF6','w':3.5,'h':0.7},
        {'id':'check','label':'K⁺ < 3.5 or > 5.3?','x':5,'y':8.0,'shape':'diamond','color':'#006D77','fc':'#E0F2F1','w':3.2,'h':0.8},
        {'id':'normal','label':'NORMAL (3.5-5.3 mmol/L)','x':8.3,'y':8.0,'shape':'round','color':'#2D6A4F','fc':'#C8E6C9','w':2.8,'h':0.65,'fontsize':7},
        {'id':'hypo','label':'HYPOKALEMIA < 3.5','x':2.2,'y':6.7,'shape':'round','color':'#C62828','fc':'#FFCDD2','w':2.8,'h':0.65},
        {'id':'hyper','label':'HYPERKALEMIA > 5.3','x':7.5,'y':6.7,'shape':'round','color':'#E65100','fc':'#FFE0B2','w':2.8,'h':0.65},
        {'id':'hypo_cause','label':'GI loss or renal loss?','x':2.2,'y':5.4,'shape':'diamond','color':'#006D77','fc':'#E0F2F1','w':2.8,'h':0.8,'fontsize':7},
        {'id':'hyper_cause','label':'Real or spurious?','x':7.5,'y':5.4,'shape':'diamond','color':'#006D77','fc':'#E0F2F1','w':2.8,'h':0.8,'fontsize':7},
        {'id':'gi_loss','label':'GI loss:\nVomiting / Diarrhea\nNG suction / Laxatives','x':1.0,'y':4.0,'shape':'round','color':'#C62828','fc':'#FFCDD2','w':2.4,'h':0.9,'fontsize':7},
        {'id':'renal_loss','label':'Renal loss:\nDiuretics / Aldosteronism\nMg deficiency / Alkalosis','x':3.5,'y':4.0,'shape':'round','color':'#7B1FA2','fc':'#F3E5F5','w':2.6,'h':0.9,'fontsize':7},
        {'id':'spurious','label':'Spurious:\nHemolysis / High WBC\nDelayed sample processing','x':6.2,'y':4.0,'shape':'round','color':'#F57F17','fc':'#FFF9C4','w':2.6,'h':0.9,'fontsize':7},
        {'id':'real_hyper','label':'Real Hyperkalemia:\nRenal failure / Addison\'s\nACEi/ARBs / Acidosis\nRhabdomyolysis','x':8.8,'y':4.0,'shape':'round','color':'#C62828','fc':'#FFCDD2','w':2.4,'h':1.0,'fontsize':7},
        {'id':'rx_hypo','label':'Rx: Oral/IV KCl replacement\nTreat cause; monitor ECG\nCorrect Mg deficiency','x':2.2,'y':2.4,'shape':'round','color':'#1A2B5C','fc':'#E8EAF6','w':3.0,'h':0.9,'fontsize':7},
        {'id':'rx_hyper','label':'Rx: Calcium gluconate (cardioprotect)\nInsulin + glucose (shift K⁺ in)\nSalbutamol / Kayexalate\nDialysis if severe','x':7.5,'y':2.4,'shape':'round','color':'#1A2B5C','fc':'#E8EAF6','w':3.2,'h':1.0,'fontsize':7},
        {'id':'ecg','label':'⚠ URGENT ECG:\nTall T-waves → Sine wave → VF','x':7.5,'y':0.9,'shape':'round','color':'#C62828','fc':'#FFCDD2','w':3.2,'h':0.75,'fontsize':7},
    ]
    arrows = [
        ('start','check',''),
        ('check','normal','Normal'),
        ('check','hypo','< 3.5'),
        ('check','hyper','> 5.3'),
        ('hypo','hypo_cause',''),
        ('hyper','hyper_cause',''),
        ('hypo_cause','gi_loss','GI'),
        ('hypo_cause','renal_loss','Renal'),
        ('hyper_cause','spurious','Spurious?'),
        ('hyper_cause','real_hyper','Real'),
        ('gi_loss','rx_hypo',''),
        ('renal_loss','rx_hypo',''),
        ('real_hyper','rx_hyper',''),
        ('rx_hyper','ecg',''),
    ]
    return make_flowchart('Potassium (K⁺) Interpretation Flowchart', nodes, arrows, figsize=(10,10))

def fc_glucose():
    nodes = [
        {'id':'start','label':'Fasting Blood Glucose','x':5,'y':9.2,'shape':'oval','color':'#1A2B5C','fc':'#E8EAF6','w':3.5,'h':0.7},
        {'id':'check','label':'Glucose level?','x':5,'y':8.0,'shape':'diamond','color':'#006D77','fc':'#E0F2F1','w':3.0,'h':0.8},
        {'id':'normal','label':'NORMAL: 70-100 mg/dL','x':5,'y':6.5,'shape':'round','color':'#2D6A4F','fc':'#C8E6C9','w':2.8,'h':0.65,'fontsize':7},
        {'id':'low','label':'HYPOGLYCEMIA < 70','x':1.5,'y':6.5,'shape':'round','color':'#C62828','fc':'#FFCDD2','w':2.6,'h':0.65},
        {'id':'prediab','label':'PRE-DIABETES 100-125','x':5,'y':5.2,'shape':'round','color':'#E65100','fc':'#FFE0B2','w':2.8,'h':0.65,'fontsize':7},
        {'id':'dm','label':'DIABETES ≥ 126 mg/dL','x':8.3,'y':6.5,'shape':'round','color':'#C62828','fc':'#FFCDD2','w':2.8,'h':0.65},
        {'id':'low_cause','label':'Cause of hypoglycemia?','x':1.5,'y':5.2,'shape':'diamond','color':'#006D77','fc':'#E0F2F1','w':2.8,'h':0.8,'fontsize':7},
        {'id':'dm_type','label':'Type 1 or Type 2 DM?','x':8.3,'y':5.2,'shape':'diamond','color':'#006D77','fc':'#E0F2F1','w':2.8,'h':0.8,'fontsize':7},
        {'id':'low_drug','label':'Drug-induced:\nInsulin / Sulfonylurea\nAlcohol','x':0.4,'y':3.8,'shape':'round','color':'#7B1FA2','fc':'#F3E5F5','w':2.2,'h':0.9,'fontsize':7},
        {'id':'low_other','label':'Non-drug:\nInsulinoma / Addison\'s\nLiver failure / Fasting','x':2.6,'y':3.8,'shape':'round','color':'#C62828','fc':'#FFCDD2','w':2.4,'h':0.9,'fontsize':7},
        {'id':'t1','label':'Type 1 DM:\nAutoimmune / Anti-GAD\nInsulin required','x':7.2,'y':3.8,'shape':'round','color':'#006D77','fc':'#E0F2F1','w':2.4,'h':0.9,'fontsize':7},
        {'id':'t2','label':'Type 2 DM:\nInsulin resistance\nOral agents / Lifestyle','x':9.4,'y':3.8,'shape':'round','color':'#E65100','fc':'#FFE0B2','w':2.2,'h':0.9,'fontsize':7},
        {'id':'rx_low','label':'Rx: 15g fast carbs (Rule of 15)\nSevere: IV Dextrose 50% or Glucagon\nFind & treat underlying cause','x':1.5,'y':2.2,'shape':'round','color':'#1A2B5C','fc':'#E8EAF6','w':3.0,'h':0.9,'fontsize':7},
        {'id':'hba1c','label':'Check HbA1c (3 month glucose average)\nTarget: < 7.0% (most patients)\nCheck for complications','x':5,'y':3.8,'shape':'round','color':'#1A2B5C','fc':'#FFF9C4','w':2.8,'h':0.9,'fontsize':7},
        {'id':'rx_dm','label':'Rx: Lifestyle + Metformin (T2)\nInsulin (T1 and advanced T2)\nMonitor HbA1c, renal function, lipids','x':8.3,'y':2.2,'shape':'round','color':'#1A2B5C','fc':'#E8EAF6','w':3.0,'h':0.9,'fontsize':7},
    ]
    arrows = [
        ('start','check',''),
        ('check','low','< 70'),
        ('check','normal','70-100'),
        ('check','dm','≥ 126'),
        ('normal','prediab','Recheck\n100-125'),
        ('low','low_cause',''),
        ('dm','dm_type',''),
        ('low_cause','low_drug','Drug'),
        ('low_cause','low_other','Other'),
        ('dm_type','t1','T1'),
        ('dm_type','t2','T2'),
        ('low_drug','rx_low',''),
        ('low_other','rx_low',''),
        ('prediab','hba1c',''),
        ('t1','rx_dm',''),
        ('t2','rx_dm',''),
    ]
    return make_flowchart('Blood Glucose Interpretation Flowchart', nodes, arrows, figsize=(10,11))

def fc_liver():
    nodes = [
        {'id':'start','label':'Abnormal Liver Enzymes','x':5,'y':9.3,'shape':'oval','color':'#1A2B5C','fc':'#E8EAF6','w':3.5,'h':0.7},
        {'id':'pattern','label':'Hepatocellular or Cholestatic?','x':5,'y':8.1,'shape':'diamond','color':'#006D77','fc':'#E0F2F1','w':3.8,'h':0.85},
        {'id':'hep','label':'HEPATOCELLULAR\nALT/AST elevated\n(ALT > AST typical)','x':2.2,'y':6.7,'shape':'round','color':'#C62828','fc':'#FFCDD2','w':2.8,'h':0.85,'fontsize':7},
        {'id':'chol','label':'CHOLESTATIC\nALP + GGT elevated\nBilirubin raised','x':7.8,'y':6.7,'shape':'round','color':'#E65100','fc':'#FFE0B2','w':2.8,'h':0.85,'fontsize':7},
        {'id':'ratio','label':'AST:ALT ratio?','x':2.2,'y':5.3,'shape':'diamond','color':'#006D77','fc':'#E0F2F1','w':2.8,'h':0.8,'fontsize':8},
        {'id':'chol_cause','label':'Intrahepatic or\nExtrahepatic?','x':7.8,'y':5.3,'shape':'diamond','color':'#006D77','fc':'#E0F2F1','w':2.8,'h':0.8,'fontsize':7},
        {'id':'alcoholic','label':'AST:ALT > 2:1\nAlcoholic hepatitis\n+ GGT elevated','x':0.8,'y':3.9,'shape':'round','color':'#7B1FA2','fc':'#F3E5F5','w':2.4,'h':0.9,'fontsize':7},
        {'id':'viral','label':'AST:ALT < 1:1\nViral hepatitis\nNAFLD / Drug-induced','x':3.5,'y':3.9,'shape':'round','color':'#C62828','fc':'#FFCDD2','w':2.6,'h':0.9,'fontsize':7},
        {'id':'intra','label':'Intrahepatic:\nPBC / PSC / Drugs\nInfiltrative disease','x':6.5,'y':3.9,'shape':'round','color':'#E65100','fc':'#FFE0B2','w':2.4,'h':0.9,'fontsize':7},
        {'id':'extra','label':'Extrahepatic:\nGallstones / Stricture\nPancreatic Ca / CBD','x':9.0,'y':3.9,'shape':'round','color':'#F57F17','fc':'#FFF9C4','w':2.4,'h':0.9,'fontsize':7},
        {'id':'severity','label':'Check severity:\nBilirubin / PT / Albumin\n(Child-Pugh / MELD)','x':2.2,'y':2.4,'shape':'round','color':'#1A2B5C','fc':'#E8EAF6','w':3.0,'h':0.9,'fontsize':7},
        {'id':'imaging','label':'Imaging: Ultrasound\nMRCP / ERCP\nTumour markers (CA19-9)','x':7.8,'y':2.4,'shape':'round','color':'#1A2B5C','fc':'#E8EAF6','w':3.0,'h':0.9,'fontsize':7},
        {'id':'biopsy','label':'Consider: Liver biopsy\nViral serology / Autoimmune\nHaemochromatosis screen','x':2.2,'y':0.9,'shape':'round','color':'#37474F','fc':'#ECEFF1','w':3.2,'h':0.85,'fontsize':7},
    ]
    arrows = [
        ('start','pattern',''),
        ('pattern','hep','ALT/AST ↑↑'),
        ('pattern','chol','ALP ↑↑'),
        ('hep','ratio',''),
        ('chol','chol_cause',''),
        ('ratio','alcoholic','> 2:1'),
        ('ratio','viral','< 1:1'),
        ('chol_cause','intra','Intra'),
        ('chol_cause','extra','Extra'),
        ('alcoholic','severity',''),
        ('viral','severity',''),
        ('intra','imaging',''),
        ('extra','imaging',''),
        ('severity','biopsy',''),
    ]
    return make_flowchart('Liver Function Tests Interpretation Flowchart', nodes, arrows, figsize=(10,11))

def fc_renal():
    nodes = [
        {'id':'start','label':'Elevated Creatinine / BUN','x':5,'y':9.3,'shape':'oval','color':'#1A2B5C','fc':'#E8EAF6','w':3.5,'h':0.7},
        {'id':'ratio','label':'BUN:Creatinine Ratio?','x':5,'y':8.1,'shape':'diamond','color':'#006D77','fc':'#E0F2F1','w':3.3,'h':0.8},
        {'id':'pre','label':'PRE-RENAL\nBUN:Cr > 20:1\nFractional Na < 1%','x':1.5,'y':6.7,'shape':'round','color':'#E65100','fc':'#FFE0B2','w':2.8,'h':0.85,'fontsize':7},
        {'id':'renal','label':'INTRINSIC RENAL\nBUN:Cr 10-20:1\nFractional Na > 2%','x':5,'y':6.7,'shape':'round','color':'#C62828','fc':'#FFCDD2','w':2.8,'h':0.85,'fontsize':7},
        {'id':'post','label':'POST-RENAL\nBUN:Cr > 20:1\nHydronephrosis on USS','x':8.5,'y':6.7,'shape':'round','color':'#7B1FA2','fc':'#F3E5F5','w':2.8,'h':0.85,'fontsize':7},
        {'id':'pre_cause','label':'Cause?','x':1.5,'y':5.3,'shape':'diamond','color':'#006D77','fc':'#E0F2F1','w':2.0,'h':0.75,'fontsize':8},
        {'id':'renal_cause','label':'Glomerular or Tubular\nor Vascular?','x':5,'y':5.3,'shape':'diamond','color':'#006D77','fc':'#E0F2F1','w':3.0,'h':0.8,'fontsize':7},
        {'id':'post_cause','label':'Obstruction level?','x':8.5,'y':5.3,'shape':'diamond','color':'#006D77','fc':'#E0F2F1','w':2.6,'h':0.75,'fontsize':7},
        {'id':'vol_dep','label':'Volume depletion:\nDehydration\nHeart failure\nHemorrhage','x':0.4,'y':3.8,'shape':'round','color':'#E65100','fc':'#FFE0B2','w':2.2,'h':1.0,'fontsize':7},
        {'id':'glom','label':'Glomerular:\nGlomerulonephritis\nNephrotic syndrome\nLupus nephritis','x':3.5,'y':3.8,'shape':'round','color':'#C62828','fc':'#FFCDD2','w':2.4,'h':1.0,'fontsize':7},
        {'id':'tubular','label':'Tubular (ATN):\nIschaemia / Sepsis\nNephrotoxins (contrast\nAminoglycosides)','x':6.1,'y':3.8,'shape':'round','color':'#F57F17','fc':'#FFF9C4','w':2.4,'h':1.0,'fontsize':7},
        {'id':'obstr','label':'Obstruction:\nBPH / Stones\nRetroperitoneal\nmalignancy','x':8.8,'y':3.8,'shape':'round','color':'#7B1FA2','fc':'#F3E5F5','w':2.4,'h':1.0,'fontsize':7},
        {'id':'rx_pre','label':'IV fluids / Treat HF\nACEi/ARBs hold\nMonitor urine output','x':1.5,'y':2.2,'shape':'round','color':'#1A2B5C','fc':'#E8EAF6','w':2.8,'h':0.9,'fontsize':7},
        {'id':'rx_renal','label':'Biopsy if glomerular\nStop nephrotoxins\nCheck ANA/ANCA/Anti-GBM','x':5,'y':2.2,'shape':'round','color':'#1A2B5C','fc':'#E8EAF6','w':2.8,'h':0.9,'fontsize':7},
        {'id':'rx_post','label':'Urinary catheter / Stent\nUrology referral\nNephrostomy if needed','x':8.5,'y':2.2,'shape':'round','color':'#1A2B5C','fc':'#E8EAF6','w':2.8,'h':0.9,'fontsize':7},
    ]
    arrows = [
        ('start','ratio',''),
        ('ratio','pre','> 20:1'),
        ('ratio','renal','10-20:1'),
        ('ratio','post','Obstruction'),
        ('pre','pre_cause',''),
        ('renal','renal_cause',''),
        ('post','post_cause',''),
        ('pre_cause','vol_dep',''),
        ('renal_cause','glom','Glom'),
        ('renal_cause','tubular','ATN'),
        ('post_cause','obstr',''),
        ('vol_dep','rx_pre',''),
        ('glom','rx_renal',''),
        ('tubular','rx_renal',''),
        ('obstr','rx_post',''),
    ]
    return make_flowchart('Renal Function (Creatinine/BUN) Interpretation Flowchart', nodes, arrows, figsize=(10,11))

def fc_abg():
    nodes = [
        {'id':'start','label':'Arterial Blood Gas (ABG)','x':5,'y':9.3,'shape':'oval','color':'#1A2B5C','fc':'#E8EAF6','w':3.5,'h':0.7},
        {'id':'ph','label':'Check pH first','x':5,'y':8.2,'shape':'diamond','color':'#006D77','fc':'#E0F2F1','w':3.0,'h':0.8},
        {'id':'acid','label':'ACIDOSIS\npH < 7.35','x':2,'y':6.9,'shape':'round','color':'#C62828','fc':'#FFCDD2','w':2.6,'h':0.7},
        {'id':'alk','label':'ALKALOSIS\npH > 7.45','x':8,'y':6.9,'shape':'round','color':'#E65100','fc':'#FFE0B2','w':2.6,'h':0.7},
        {'id':'normal_ph','label':'NORMAL pH 7.35-7.45\nCheck for compensation','x':5,'y':6.9,'shape':'round','color':'#2D6A4F','fc':'#C8E6C9','w':2.8,'h':0.7,'fontsize':7},
        {'id':'acid_co2','label':'Check PaCO₂','x':2,'y':5.6,'shape':'diamond','color':'#006D77','fc':'#E0F2F1','w':2.6,'h':0.75,'fontsize':8},
        {'id':'alk_co2','label':'Check PaCO₂','x':8,'y':5.6,'shape':'diamond','color':'#006D77','fc':'#E0F2F1','w':2.6,'h':0.75,'fontsize':8},
        {'id':'resp_acid','label':'RESPIRATORY ACIDOSIS\nPaCO₂ > 45\nCOPD / Opioids\nRespiratory failure','x':0.8,'y':4.2,'shape':'round','color':'#C62828','fc':'#FFCDD2','w':2.6,'h':1.0,'fontsize':7},
        {'id':'met_acid','label':'METABOLIC ACIDOSIS\nHCO₃ < 22\nDKA / Lactic acidosis\nRenal failure / Diarrhea','x':3.3,'y':4.2,'shape':'round','color':'#7B1FA2','fc':'#F3E5F5','w':2.6,'h':1.0,'fontsize':7},
        {'id':'resp_alk','label':'RESPIRATORY ALKALOSIS\nPaCO₂ < 35\nHyperventilation\nSepsis / Anxiety','x':6.5,'y':4.2,'shape':'round','color':'#E65100','fc':'#FFE0B2','w':2.6,'h':1.0,'fontsize':7},
        {'id':'met_alk','label':'METABOLIC ALKALOSIS\nHCO₃ > 26\nVomiting / Diuretics\nCushing\'s / Conn\'s','x':9.2,'y':4.2,'shape':'round','color':'#F57F17','fc':'#FFF9C4','w':2.6,'h':1.0,'fontsize':7},
        {'id':'anion','label':'ANION GAP = Na - (Cl + HCO₃)\nNormal: 7-16 mEq/L\nHigh AG: DKA, Lactic, Uremia,\nMethanol, Salicylates\nNormal AG: RTA, Diarrhea','x':2,'y':2.5,'shape':'round','color':'#1A2B5C','fc':'#FFFDE7','w':3.2,'h':1.1,'fontsize':7},
        {'id':'rx_resp','label':'Rx resp acidosis:\nO₂ / Ventilation support\nBronchodilators / Naloxone','x':0.8,'y':2.5,'shape':'round','color':'#1A2B5C','fc':'#E8EAF6','w':2.4,'h':0.9,'fontsize':6},
        {'id':'compensation','label':'Check compensation:\nMetabolic acidosis → PaCO₂ ↓\nMetabolic alkalosis → PaCO₂ ↑\nRespiratory → HCO₃ changes','x':7.5,'y':2.5,'shape':'round','color':'#37474F','fc':'#ECEFF1','w':3.2,'h':1.0,'fontsize':7},
    ]
    arrows = [
        ('start','ph',''),
        ('ph','acid','< 7.35'),
        ('ph','alk','> 7.45'),
        ('ph','normal_ph','7.35-7.45'),
        ('acid','acid_co2',''),
        ('alk','alk_co2',''),
        ('acid_co2','resp_acid','↑ CO₂'),
        ('acid_co2','met_acid','↓ HCO₃'),
        ('alk_co2','resp_alk','↓ CO₂'),
        ('alk_co2','met_alk','↑ HCO₃'),
        ('met_acid','anion','AG check'),
        ('resp_acid','rx_resp',''),
        ('met_alk','compensation',''),
        ('resp_alk','compensation',''),
    ]
    return make_flowchart('Arterial Blood Gas (ABG) Interpretation Flowchart', nodes, arrows, figsize=(10,11))

# ── Reference table helper ──────────────────────────────────────────────────────
def ref_table(styles, data, col_widths, header_color=NAVY):
    th = styles['TableHeader']
    tc = styles['TableCell']
    formatted = []
    for i, row in enumerate(data):
        if i == 0:
            formatted.append([Paragraph(str(c), th) for c in row])
        else:
            formatted.append([Paragraph(str(c), tc) for c in row])
    t = Table(formatted, colWidths=col_widths)
    style = TableStyle([
        ('BACKGROUND', (0,0), (-1,0), header_color),
        ('TEXTCOLOR',  (0,0), (-1,0), colors.white),
        ('ROWBACKGROUNDS', (0,1), (-1,-1), [LIGHT_BG, colors.white]),
        ('GRID',       (0,0), (-1,-1), 0.4, colors.HexColor('#B0BEC5')),
        ('VALIGN',     (0,0), (-1,-1), 'MIDDLE'),
        ('TOPPADDING', (0,0), (-1,-1), 4),
        ('BOTTOMPADDING',(0,0),(-1,-1), 4),
        ('LEFTPADDING',(0,0), (-1,-1), 5),
    ])
    t.setStyle(style)
    return t

# ── Section banner ──────────────────────────────────────────────────────────────
def section_banner(text, color, styles):
    banner_style = ParagraphStyle('Banner',
        fontName='Helvetica-Bold', fontSize=13, textColor=WHITE,
        alignment=TA_LEFT, leftIndent=12, leading=18,
        spaceAfter=6, spaceBefore=10)
    p = Paragraph(text, banner_style)
    t = Table([[p]], colWidths=[17*cm])
    t.setStyle(TableStyle([
        ('BACKGROUND', (0,0), (-1,-1), color),
        ('TOPPADDING', (0,0), (-1,-1), 6),
        ('BOTTOMPADDING',(0,0),(-1,-1), 6),
        ('LEFTPADDING',(0,0), (-1,-1), 8),
        ('ROUNDEDCORNERS', [4]),
    ]))
    return t

def info_box(text, styles, bg=MINT, border=TEAL):
    p = Paragraph(text, styles['Body'])
    t = Table([[p]], colWidths=[17*cm])
    t.setStyle(TableStyle([
        ('BACKGROUND', (0,0), (-1,-1), bg),
        ('BOX', (0,0), (-1,-1), 1, border),
        ('TOPPADDING', (0,0), (-1,-1), 6),
        ('BOTTOMPADDING',(0,0),(-1,-1), 6),
        ('LEFTPADDING',(0,0), (-1,-1), 8),
    ]))
    return t

def img_from_buf(buf, width=17*cm):
    img = RLImage(buf, width=width, height=width*1.05)
    return img

# ── Main builder ────────────────────────────────────────────────────────────────
def build_pdf():
    doc = SimpleDocTemplate(
        OUTPUT_PATH,
        pagesize=A4,
        leftMargin=2*cm, rightMargin=2*cm,
        topMargin=2.2*cm, bottomMargin=2.2*cm,
        title='Clinical Laboratory Interpretation Guide',
        author='Orris Clinical Reference',
    )

    styles = build_styles()
    W = 17*cm
    story = []

    # ═══════════════════════════════════════════════════════
    # COVER PAGE
    # ═══════════════════════════════════════════════════════
    cover_bg = Table(
        [[Paragraph('', styles['Body'])]],
        colWidths=[W], rowHeights=[25*cm]
    )
    cover_bg.setStyle(TableStyle([('BACKGROUND',(0,0),(-1,-1), NAVY)]))
    story.append(cover_bg)
    story.append(Spacer(1, -25*cm))

    story.append(Spacer(1, 3.5*cm))
    story.append(Paragraph('🔬 Clinical Laboratory', styles['CoverTitle']))
    story.append(Paragraph('Interpretation Guide', styles['CoverTitle']))
    story.append(Spacer(1, 0.5*cm))
    story.append(Paragraph('with Diagnostic Flowcharts', styles['CoverSub']))
    story.append(Spacer(1, 0.4*cm))
    story.append(Paragraph('Normal Values · Abnormal Patterns · Differential Diagnoses', styles['CoverSub']))
    story.append(Spacer(1, 1.5*cm))

    cover_info = Table([
        [Paragraph('<b>Electrolytes</b><br/>Na · K · Cl · HCO₃ · Ca · Mg · Phosphate', styles['CoverSub'])],
        [Paragraph('<b>Metabolic</b><br/>Blood Glucose · HbA1c · Lipids · Uric Acid', styles['CoverSub'])],
        [Paragraph('<b>Organ Function</b><br/>Liver (LFTs) · Kidneys (Creatinine/BUN) · Thyroid', styles['CoverSub'])],
        [Paragraph('<b>Critical Values</b><br/>ABG · Cardiac Biomarkers · Inflammatory Markers', styles['CoverSub'])],
    ], colWidths=[W*0.75])
    cover_info.setStyle(TableStyle([
        ('ALIGN', (0,0), (-1,-1), 'CENTER'),
        ('TOPPADDING', (0,0), (-1,-1), 5),
        ('BOTTOMPADDING', (0,0), (-1,-1), 5),
        ('BOX', (0,0), (-1,0), 0.5, colors.HexColor('#90CAF9')),
        ('BOX', (0,1), (-1,1), 0.5, colors.HexColor('#90CAF9')),
        ('BOX', (0,2), (-1,2), 0.5, colors.HexColor('#90CAF9')),
        ('BOX', (0,3), (-1,3), 0.5, colors.HexColor('#90CAF9')),
        ('LEFTPADDING', (0,0), (-1,-1), 30),
    ]))
    story.append(cover_info)
    story.append(Spacer(1, 2.0*cm))
    story.append(Paragraph('Sources: Guyton & Hall Physiology · Goldman-Cecil Medicine · Harrison\'s Principles 22e', styles['CoverSub']))
    story.append(Paragraph('July 2026', styles['CoverSub']))
    story.append(PageBreak())

    # ═══════════════════════════════════════════════════════
    # PAGE 2: QUICK REFERENCE TABLE
    # ═══════════════════════════════════════════════════════
    story.append(section_banner('📊  Quick Reference: Normal Lab Values', NAVY, styles))
    story.append(Spacer(1, 0.3*cm))
    story.append(info_box(
        '<b>Clinical note:</b> Reference ranges cover the middle 95% of healthy adults. '
        'Always correlate with clinical context. Ranges may vary by laboratory method, '
        'patient age, sex, and pregnancy status.',
        styles))
    story.append(Spacer(1, 0.4*cm))

    qr_data = [
        ['Test', 'Normal Range', 'Low Suggests', 'High Suggests'],
        ['Sodium (Na⁺)', '135-145 mmol/L', 'SIADH, HF, cirrhosis, vomiting', 'Dehydration, DI, Conn\'s'],
        ['Potassium (K⁺)', '3.5-5.3 mmol/L', 'Diuretics, vomiting, alkalosis', 'Renal failure, Addison\'s, acidosis'],
        ['Chloride (Cl⁻)', '98-108 mmol/L', 'Metabolic alkalosis, vomiting', 'Hyperchloremic acidosis, RTA'],
        ['Bicarbonate (HCO₃⁻)', '22-26 mEq/L', 'Metabolic acidosis (DKA, diarrhea)', 'Metabolic alkalosis, Cushing\'s'],
        ['Calcium (total)', '8.5-10.5 mg/dL', 'Hypoparathyroid, Vit D def., CKD', 'Hyperparathyroid, malignancy'],
        ['Magnesium', '1.3-2.4 mEq/L', 'Alcoholism, diuretics, malabsorption', 'Renal failure, excess Mg intake'],
        ['Phosphate', '2.5-4.5 mg/dL', 'Hyperparathyroid, malnutrition, refeeding', 'Renal failure, hypoparathyroid'],
        ['Blood Glucose (fast)', '70-100 mg/dL', 'Insulinoma, Addison\'s, liver failure', 'Diabetes, Cushing\'s, stress'],
        ['HbA1c', '< 5.7%', 'Hemolytic anemia (falsely low)', 'Pre-DM 5.7-6.4%; DM ≥ 6.5%'],
        ['Creatinine (M)', '0.7-1.3 mg/dL', 'Low muscle mass, malnutrition', 'CKD, AKI, rhabdomyolysis'],
        ['Creatinine (F)', '0.6-1.1 mg/dL', 'Low muscle mass, malnutrition', 'CKD, AKI, rhabdomyolysis'],
        ['BUN', '8-25 mg/dL', 'Liver failure, overhydration', 'Pre-renal, AKI, CKD, GI bleed'],
        ['Uric acid (M)', '3.5-7.2 mg/dL', 'Allopurinol, Wilson\'s, SIADH', 'Gout, CKD, diuretics, leukemia'],
        ['ALT (SGPT)', '7-56 U/L', '—', 'Hepatitis, liver damage, NAFLD'],
        ['AST (SGOT)', '10-40 U/L', '—', 'Liver disease, MI, rhabdomyolysis'],
        ['ALP', '44-147 U/L', '—', 'Cholestasis, bone disease, pregnancy'],
        ['GGT', 'M:8-61; F:5-36 U/L', '—', 'Alcohol, cholestasis, enzyme induction'],
        ['Total Bilirubin', '0.2-1.2 mg/dL', '—', 'Jaundice > 2.5 mg/dL'],
        ['Albumin', '3.5-5.0 g/dL', 'Cirrhosis, malnutrition, nephrotic', 'Dehydration (relative)'],
        ['Total Protein', '6.4-8.3 g/dL', 'Malnutrition, liver disease', 'Myeloma, chronic infection'],
        ['Total Cholesterol', '< 200 mg/dL', 'Malnutrition, hyperthyroid', 'CVD risk, hypothyroid'],
        ['LDL Cholesterol', '< 100 mg/dL (optimal)', 'Over-treated, malnutrition', 'CVD risk, FH, nephrotic'],
        ['HDL Cholesterol', '≥ 60 mg/dL (protective)', 'CVD risk, obesity, DM', 'Exercise, statin therapy'],
        ['Triglycerides', '< 150 mg/dL', '—', 'DM, obesity, alcohol, hypothyroid'],
        ['TSH', '0.4-4.0 mIU/L', 'Hyperthyroid, pituitary failure', 'Hypothyroid (primary)'],
        ['Free T4', '0.8-1.8 ng/dL', 'Hypothyroid', 'Hyperthyroid'],
        ['Troponin I/T (hs)', '< 0.04 ng/mL', '—', 'MI, myocarditis, PE, sepsis'],
        ['BNP', '< 100 pg/mL', '—', 'Heart failure, pulmonary HTN'],
        ['CRP', '< 1.0 mg/dL', '—', 'Bacterial infection, inflammation'],
        ['Procalcitonin (PCT)', '< 0.1 ng/mL', '—', '> 0.5 = bacterial sepsis likely'],
        ['pH (arterial)', '7.35-7.45', 'Acidosis', 'Alkalosis'],
        ['PaCO₂', '35-45 mmHg', 'Resp. alkalosis / Compensation', 'Resp. acidosis / Compensation'],
        ['PaO₂', '75-100 mmHg', 'Hypoxemia / Type 1 resp failure', '—'],
    ]
    story.append(ref_table(styles, qr_data, [3.5*cm, 3.2*cm, 5.2*cm, 5.1*cm]))
    story.append(PageBreak())

    # ═══════════════════════════════════════════════════════
    # ELECTROLYTES SECTION
    # ═══════════════════════════════════════════════════════
    story.append(section_banner('💧  Electrolytes: Sodium & Potassium', TEAL, styles))
    story.append(Spacer(1, 0.3*cm))

    # Sodium flowchart
    story.append(Paragraph('Sodium (Na⁺) Interpretation Algorithm', styles['SubHeader']))
    buf_na = fc_sodium()
    story.append(img_from_buf(buf_na, width=W))
    story.append(Paragraph('Fig 1. Systematic approach to hypo- and hypernatremia. Correction rate must not exceed 0.5 mEq/L/hr to prevent osmotic demyelination syndrome.', styles['Caption']))
    story.append(Spacer(1, 0.3*cm))

    na_detail = [
        ['Condition', 'Key Lab Findings', 'Common Causes', 'Treatment'],
        ['Hyponatremia\n< 135 mmol/L', 'Low Na, check Uosm\nand UNa', 'SIADH, HF, cirrhosis,\ndiuretics, Addison\'s', 'Fluid restriction; hypertonic\nNaCl if symptomatic'],
        ['Hypernatremia\n> 145 mmol/L', 'High Na, check urine\nosmolality and volume', 'Dehydration, DI,\nConn\'s syndrome', 'Free water orally or IV\n5% dextrose; correct slowly'],
        ['SIADH', 'Low Na, Low osm,\nUrine Na > 20, Uosm > 100', 'Malignancy, CNS disease,\nPneumonia, drugs (SSRIs)', 'Fluid restrict, Tolvaptan,\nDemeclocycline'],
        ['Diabetes insipidus', 'High Na, dilute urine\n(Uosm < 300)', 'Central (ADH def) or\nNephrogenic (ADH resistance)', 'Central: Desmopressin\nNephrogenic: Thiazide, low Na diet'],
    ]
    story.append(ref_table(styles, na_detail, [3.0*cm, 3.8*cm, 5.0*cm, 5.2*cm], TEAL))
    story.append(PageBreak())

    # Potassium flowchart
    story.append(Paragraph('Potassium (K⁺) Interpretation Algorithm', styles['SubHeader']))
    buf_k = fc_potassium()
    story.append(img_from_buf(buf_k, width=W))
    story.append(Paragraph('Fig 2. Potassium disorders. Hyperkalemia is a medical emergency - obtain ECG immediately. Classic ECG progression: peaked T → PR prolongation → wide QRS → sine wave → VF.', styles['Caption']))
    story.append(Spacer(1, 0.3*cm))

    k_detail = [
        ['Condition', 'ECG Changes', 'Common Causes', 'Treatment Priority'],
        ['Hypokalemia\n< 3.5 mmol/L', 'Flat/inverted T, U waves,\nST depression', 'Diuretics, vomiting,\ndiarrhea, Cushing\'s', 'Oral KCl (mild)\nIV KCl (< 2.5 or symptomatic)'],
        ['Hyperkalemia\n> 5.3 mmol/L', 'Peaked T waves → wide QRS\n→ Sine wave → VF', 'CKD, Addison\'s, ACEi,\nRhabdomyolysis, acidosis', '1st: Ca gluconate (cardioprotect)\n2nd: Insulin+glucose\n3rd: Dialysis'],
        ['Hypokalemic\nperiodic paralysis', 'Flaccid paralysis,\nno ECG changes initially', 'Thyrotoxicosis, exercise,\nhigh carbs, familial', 'IV KCl + treat thyroid\nAvoid glucose/insulin'],
    ]
    story.append(ref_table(styles, k_detail, [3.0*cm, 3.5*cm, 5.0*cm, 5.5*cm], TEAL))
    story.append(PageBreak())

    # ═══════════════════════════════════════════════════════
    # GLUCOSE SECTION
    # ═══════════════════════════════════════════════════════
    story.append(section_banner('🩸  Blood Glucose & Diabetes Interpretation', colors.HexColor('#AD1457'), styles))
    story.append(Spacer(1, 0.3*cm))
    buf_gluc = fc_glucose()
    story.append(img_from_buf(buf_gluc, width=W))
    story.append(Paragraph('Fig 3. Blood glucose interpretation. Rule of 15 for hypoglycemia: 15g carbs → wait 15 min → recheck. Repeat × 3 if still < 70 mg/dL. Then give meal/snack.', styles['Caption']))
    story.append(Spacer(1, 0.3*cm))

    gluc_detail = [
        ['Condition', 'Glucose', 'HbA1c', 'Other Findings', 'Management'],
        ['Normal', '70-100 mg/dL', '< 5.7%', 'Normal insulin, no proteinuria', 'Healthy lifestyle'],
        ['Pre-diabetes (IFG)', '100-125 mg/dL', '5.7-6.4%', 'OGTT 2hr: 140-199 mg/dL', 'Lifestyle mod, monitor annually'],
        ['Type 2 DM', '≥ 126 mg/dL', '≥ 6.5%', 'Overweight, acanthosis nigricans,\nhigh insulin, insulin resistance', 'Metformin + GLP-1 RA or SGLT2i\nLifestyle, CVD risk reduction'],
        ['Type 1 DM', '≥ 126 mg/dL', '≥ 6.5%', 'Anti-GAD, IA-2, ZnT8 antibodies\nLow C-peptide, thin young patient', 'Insulin (basal-bolus regimen)\nCarb counting, CGM'],
        ['DKA', '> 250 mg/dL', 'High', 'pH < 7.3, HCO₃ < 15\nKetones ++, raised anion gap', 'IV fluids + Insulin infusion\nK⁺ replacement, monitor closely'],
        ['Hypoglycemia', '< 70 mg/dL', 'Low if recurrent', 'Whipple\'s triad: symptoms +\nlow glucose + relief with glucose', 'Oral dextrose/glucose tablets\nSevere: IV D50 or Glucagon 1mg IM'],
    ]
    story.append(ref_table(styles, gluc_detail, [2.8*cm, 2.5*cm, 1.8*cm, 4.7*cm, 5.2*cm], colors.HexColor('#AD1457')))
    story.append(PageBreak())

    # ═══════════════════════════════════════════════════════
    # LIVER FUNCTION
    # ═══════════════════════════════════════════════════════
    story.append(section_banner('🫀  Liver Function Tests (LFTs)', colors.HexColor('#2E7D32'), styles))
    story.append(Spacer(1, 0.3*cm))
    buf_liver = fc_liver()
    story.append(img_from_buf(buf_liver, width=W))
    story.append(Paragraph('Fig 4. LFT interpretation algorithm. AST:ALT > 2:1 strongly suggests alcoholic hepatitis. Isolated ALP rise = bone or liver; confirm with GGT (elevated = liver source).', styles['Caption']))
    story.append(Spacer(1, 0.3*cm))

    liver_detail = [
        ['Condition', 'ALT/AST', 'ALP', 'Bilirubin', 'Albumin/PT', 'Key Tests'],
        ['Viral hepatitis\n(acute)', 'Very high\n(> 500 U/L)', 'Normal/mild ↑', 'Elevated\n(conjugated)', 'Usually normal', 'HBsAg, HCV RNA,\nHAV IgM'],
        ['Alcoholic\nhepatitis', 'Moderate ↑\nAST:ALT > 2:1', 'Mild-moderate ↑', 'Elevated', 'Low albumin\nHigh PT', 'GGT very high\nMDF score'],
        ['NAFLD/NASH', 'Mild ↑\nALT > AST', 'Normal/mild ↑', 'Usually normal', 'Usually normal', 'Liver USS, BMI\nFibroscan'],
        ['Biliary\nobstruction', 'Mild ↑', 'Very high\n(> 3× ULN)', 'Conjugated ↑↑\nDark urine, pale stools', 'Low if chronic', 'USS/MRCP\nCA 19-9'],
        ['Cirrhosis\n(chronic)', 'Mild-moderate ↑\nor normal', 'Elevated', 'Elevated\n(late)', 'Low albumin\nHigh PT, low PLT', 'Child-Pugh, MELD\nVarices screen'],
        ['Drug-induced\n(e.g. paracetamol)', 'Very high\n(> 1000 if OD)', 'Normal/mild ↑', 'Elevated', 'High PT/INR', 'Drug history\nParacetamol level'],
        ['Gilbert\'s\nsyndrome', 'Normal', 'Normal', 'Unconjugated ↑\n(isolated)', 'Normal', 'No treatment needed\nBenign condition'],
    ]
    story.append(ref_table(styles, liver_detail, [2.5*cm, 2.2*cm, 2.0*cm, 2.8*cm, 2.5*cm, 5.0*cm], colors.HexColor('#2E7D32')))
    story.append(PageBreak())

    # ═══════════════════════════════════════════════════════
    # RENAL FUNCTION
    # ═══════════════════════════════════════════════════════
    story.append(section_banner('🔵  Renal Function Tests', colors.HexColor('#1565C0'), styles))
    story.append(Spacer(1, 0.3*cm))
    buf_renal = fc_renal()
    story.append(img_from_buf(buf_renal, width=W))
    story.append(Paragraph('Fig 5. Acute kidney injury (AKI) classification using BUN:Creatinine ratio and fractional excretion of sodium (FENa). FENa < 1% = pre-renal; FENa > 2% = intrinsic renal.', styles['Caption']))
    story.append(Spacer(1, 0.3*cm))

    ckd_stages = [
        ['CKD Stage', 'eGFR (mL/min/1.73m²)', 'Description', 'Key Actions'],
        ['G1', '≥ 90', 'Normal/High', 'Treat cause, CV risk reduction'],
        ['G2', '60-89', 'Mildly decreased', 'Monitor annually, control BP/DM'],
        ['G3a', '45-59', 'Mildly-moderately decreased', 'Nephrology review if needed'],
        ['G3b', '30-44', 'Moderately-severely decreased', 'Avoid nephrotoxins, adjust doses'],
        ['G4', '15-29', 'Severely decreased', 'Prepare for renal replacement therapy'],
        ['G5', '< 15', 'Kidney failure', 'Dialysis or transplantation'],
    ]
    story.append(Paragraph('CKD Staging (KDIGO 2022)', styles['SubHeader']))
    story.append(ref_table(styles, ckd_stages, [1.8*cm, 4.0*cm, 5.0*cm, 6.2*cm], colors.HexColor('#1565C0')))
    story.append(Spacer(1, 0.4*cm))

    aki_table = [
        ['AKI Stage', 'Creatinine Criteria', 'Urine Output Criteria', 'Management Focus'],
        ['Stage 1', '1.5-1.9× baseline\nor ≥ 0.3 mg/dL rise', '< 0.5 mL/kg/hr for 6-12 hrs', 'Remove nephrotoxins, optimize fluids'],
        ['Stage 2', '2.0-2.9× baseline', '< 0.5 mL/kg/hr for ≥ 12 hrs', 'ICU/HDU monitoring, renal consult'],
        ['Stage 3', '≥ 3× baseline\nor ≥ 4.0 mg/dL', '< 0.3 mL/kg/hr for ≥ 24 hrs\nor anuria ≥ 12 hrs', 'Dialysis if: fluid overload, severe\nhyperK, acidosis, uremia'],
    ]
    story.append(Paragraph('AKI Staging (KDIGO Criteria)', styles['SubHeader']))
    story.append(ref_table(styles, aki_table, [2.2*cm, 4.0*cm, 4.2*cm, 6.6*cm], colors.HexColor('#1565C0')))
    story.append(PageBreak())

    # ═══════════════════════════════════════════════════════
    # ABG SECTION
    # ═══════════════════════════════════════════════════════
    story.append(section_banner('💨  Arterial Blood Gas (ABG) Interpretation', colors.HexColor('#4A148C'), styles))
    story.append(Spacer(1, 0.3*cm))
    buf_abg = fc_abg()
    story.append(img_from_buf(buf_abg, width=W))
    story.append(Paragraph('Fig 6. ABG interpretation algorithm. Always: (1) Check pH, (2) Identify primary disorder, (3) Assess compensation, (4) Calculate anion gap if metabolic acidosis.', styles['Caption']))
    story.append(Spacer(1, 0.3*cm))

    abg_table = [
        ['Disorder', 'pH', 'PaCO₂', 'HCO₃', 'Expected Compensation', 'Common Causes'],
        ['Resp. Acidosis\n(Acute)', '↓', '↑ > 45', 'Normal\n(+1 per 10 CO₂)', 'HCO₃ ↑ by 1 mEq/L\nper 10 mmHg CO₂ ↑', 'COPD exac., opioid OD,\napnea, NM weakness'],
        ['Resp. Acidosis\n(Chronic)', '↓ (mild)', '↑ > 45', '↑ significantly\n(+3.5 per 10 CO₂)', 'HCO₃ ↑ by 3.5 mEq/L\nper 10 mmHg CO₂ ↑', 'Chronic COPD,\nobesity hypoventilation'],
        ['Resp. Alkalosis', '↑', '↓ < 35', 'Normal/↓', 'HCO₃ ↓ by 2 mEq/L\nper 10 mmHg CO₂ ↓', 'Anxiety, sepsis,\npregnancy, altitude'],
        ['Met. Acidosis', '↓', 'Normal/↓', '↓ < 22', 'CO₂ = 1.5×(HCO₃)+8±2\n(Winter\'s formula)', 'DKA, lactic acidosis,\nrenal failure, diarrhea'],
        ['Met. Alkalosis', '↑', 'Normal/↑', '↑ > 26', 'CO₂ ↑ by 0.7×\n(HCO₃ - 24)', 'Vomiting, diuretics,\nCushing\'s, Conn\'s'],
    ]
    story.append(ref_table(styles, abg_table, [2.8*cm, 1.2*cm, 2.0*cm, 2.5*cm, 3.5*cm, 5.0*cm], colors.HexColor('#4A148C')))
    story.append(Spacer(1, 0.4*cm))

    anion_gap = [
        ['Anion Gap Status', 'Causes (MUDPILES mnemonic)'],
        ['High Anion Gap\nMetabolic Acidosis\n(AG > 16)', 'M - Methanol\nU - Uremia (renal failure)\nD - Diabetic ketoacidosis (DKA)\nP - Propylene glycol / Paracetamol\nI - Isoniazid / Iron toxicity\nL - Lactic acidosis\nE - Ethylene glycol\nS - Salicylates'],
        ['Normal Anion Gap\nMetabolic Acidosis\n(Hyperchloremic)', 'D - Diarrhea (bicarbonate loss)\nU - Ureteral diversion\nR - Renal tubular acidosis (RTA)\nA - Acetazolamide\nG - GI fistulas\nS - Saline infusion (excess)'],
    ]
    story.append(Paragraph('Anion Gap in Metabolic Acidosis (Normal AG = 7-16 mEq/L)', styles['SubHeader']))
    story.append(ref_table(styles, anion_gap, [4.5*cm, 12.5*cm], colors.HexColor('#4A148C')))
    story.append(PageBreak())

    # ═══════════════════════════════════════════════════════
    # LIPIDS & CARDIAC
    # ═══════════════════════════════════════════════════════
    story.append(section_banner('❤️   Lipid Profile & Cardiac Biomarkers', RED, styles))
    story.append(Spacer(1, 0.3*cm))

    story.append(Paragraph('Lipid Profile Interpretation', styles['SubHeader']))
    lipid_data = [
        ['Parameter', 'Optimal', 'Borderline', 'High Risk', 'Very High / Critical'],
        ['Total Cholesterol', '< 200 mg/dL', '200-239 mg/dL', '≥ 240 mg/dL', '—'],
        ['LDL Cholesterol', '< 70 (very high CVD risk)\n< 100 (high risk)\n< 130 (moderate)', '130-159 mg/dL', '160-189 mg/dL', '≥ 190 (FH likely)'],
        ['HDL Cholesterol', '≥ 60 mg/dL\n(protective)', '40-59 mg/dL', '< 40 (men)\n< 50 (women)', '—'],
        ['Triglycerides', '< 150 mg/dL', '150-199 mg/dL', '200-499 mg/dL', '≥ 500 (pancreatitis risk)'],
        ['Non-HDL Cholesterol', '< 130 mg/dL', '130-159 mg/dL', '≥ 160 mg/dL', '—'],
    ]
    story.append(ref_table(styles, lipid_data, [3.0*cm, 3.5*cm, 3.0*cm, 3.0*cm, 4.5*cm], RED))
    story.append(Spacer(1, 0.4*cm))

    story.append(info_box(
        '<b>Causes of secondary dyslipidemia:</b> Hypothyroidism (↑LDL) · Nephrotic syndrome (↑LDL, ↑TG) · '
        'Diabetes (↑TG, ↓HDL) · Chronic kidney disease · Alcoholism (↑TG) · Cushing\'s syndrome · '
        'Drugs: corticosteroids, thiazides, beta-blockers, retinoids, antipsychotics.',
        styles, bg=colors.HexColor('#FFEBEE'), border=RED))
    story.append(Spacer(1, 0.4*cm))

    story.append(Paragraph('Cardiac Biomarkers', styles['SubHeader']))
    cardiac_data = [
        ['Biomarker', 'Normal', 'Rise After MI', 'Peak', 'Returns Normal', 'Key Uses'],
        ['Troponin I/T (hs)', '< 0.04 ng/mL', '3-6 hours', '12-24 hrs', '5-14 days', 'Diagnosis of MI, myocarditis,\nPE risk stratification'],
        ['CK-MB', '< 5 ng/mL', '3-6 hours', '12-24 hrs', '48-72 hrs', 'Reinfarction detection\n(returns to normal faster)'],
        ['Myoglobin', '< 90 ng/mL', '1-3 hours', '6-12 hrs', '24-36 hrs', 'Early marker (non-specific)\nAlso raised in rhabdomyolysis'],
        ['BNP', '< 100 pg/mL', 'Chronic ↑', 'Persistent', 'Improves with Rx', 'Heart failure diagnosis\nDyspnea differentiation'],
        ['NT-proBNP', '< 125 pg/mL', 'Chronic ↑', 'Persistent', 'Improves with Rx', 'HF diagnosis (adjust\ncutoff > 75 yrs: < 450)'],
        ['LDH', '140-280 U/L', '12-24 hours', '48-72 hrs', '7-10 days', 'Late MI marker, hemolysis,\ntumor lysis syndrome'],
    ]
    story.append(ref_table(styles, cardiac_data, [2.8*cm, 2.2*cm, 2.0*cm, 1.8*cm, 2.0*cm, 6.2*cm], RED))
    story.append(PageBreak())

    # ═══════════════════════════════════════════════════════
    # THYROID & INFLAMMATORY MARKERS
    # ═══════════════════════════════════════════════════════
    story.append(section_banner('🦋  Thyroid Function & Inflammatory Markers', ORANGE, styles))
    story.append(Spacer(1, 0.3*cm))

    story.append(Paragraph('Thyroid Function Test Interpretation', styles['SubHeader']))
    thyroid_data = [
        ['TSH', 'Free T4', 'Free T3', 'Diagnosis', 'Common Causes', 'Management'],
        ['High', 'Low', 'Low', 'Primary\nHypothyroidism', 'Hashimoto\'s, iodine deficiency,\npost-thyroidectomy, amiodarone, lithium', 'Levothyroxine\n(target TSH 0.5-2.5)'],
        ['Low', 'High', 'High', 'Primary\nHyperthyroidism', 'Graves\' disease, toxic MNG,\nsolitary toxic adenoma, thyroiditis', 'Carbimazole/PTU,\nbeta-blockers, radioiodine'],
        ['High', 'Normal', 'Normal', 'Subclinical\nHypothyroid', 'Early Hashimoto\'s,\npost-RAI treatment', 'Treat if TSH > 10\nor symptoms present'],
        ['Low', 'Normal', 'Normal', 'Subclinical\nHyperthyroid', 'Early Graves\', over-replacement,\nsolitary toxic adenoma', 'Monitor; treat if\nAF risk or osteoporosis'],
        ['Low', 'Low', 'Low', 'Central\nHypothyroid', 'Pituitary adenoma,\nSheehan\'s syndrome, pituitary surgery', 'Treat pituitary cause;\nLevothyroxine'],
        ['Normal', 'Low/Normal', 'Low', 'Non-thyroidal\nIllness (Sick euthyroid)', 'Severe illness, starvation,\nICU patients', 'Treat underlying illness;\ndo NOT give T4'],
    ]
    story.append(ref_table(styles, thyroid_data, [1.5*cm, 1.5*cm, 1.5*cm, 2.5*cm, 4.5*cm, 5.5*cm], ORANGE))
    story.append(Spacer(1, 0.4*cm))

    story.append(Paragraph('Inflammatory & Acute Phase Markers', styles['SubHeader']))
    inflam_data = [
        ['Marker', 'Normal', 'Mildly Elevated', 'Markedly Elevated', 'Clinical Use'],
        ['CRP (C-Reactive\nProtein)', '< 1.0 mg/dL\n(< 10 mg/L)', '1-10 mg/dL\n(mild inflammation)', '> 10 mg/dL\nBacterial infection', 'Monitor infection, inflammation\nhi-sCRP for CVD risk (< 3 mg/L)'],
        ['ESR (Erythrocyte\nSedimen. Rate)', 'M: < 15 mm/hr\nF: < 20 mm/hr', '20-50 mm/hr\n(non-specific)', '> 100 mm/hr\nMyeloma, TB, endocarditis', 'Non-specific; useful in myeloma,\npolymyalgia rheumatica'],
        ['Procalcitonin\n(PCT)', '< 0.1 ng/mL', '0.1-0.5 (viral/local\nbacterial possible)', '> 0.5 bacterial sepsis\n> 2 severe sepsis\n> 10 septic shock', 'Guide antibiotic initiation\nand de-escalation'],
        ['Ferritin', 'M: 12-300 ng/mL\nF: 12-150 ng/mL', '—', '> 500 in inflammation\n> 1000 HLH, ferritinemia', 'Iron deficiency (low)\nHemochromatosis (very high)'],
        ['D-dimer', '< 0.5 µg/mL FEU', '—', '> 0.5 = VTE possible\n(high sensitivity, low spec)', 'Rule out DVT/PE;\nnot useful to rule in'],
        ['Fibrinogen', '200-400 mg/dL', '—', '> 400 = acute phase\n< 100 = DIC/severe liver', 'DIC: low + prolonged PT/aPTT\n+ low platelets'],
    ]
    story.append(ref_table(styles, inflam_data, [2.8*cm, 2.8*cm, 3.0*cm, 3.5*cm, 5.0*cm], ORANGE))
    story.append(PageBreak())

    # ═══════════════════════════════════════════════════════
    # CALCIUM, ANEMIA, CRITICAL VALUES
    # ═══════════════════════════════════════════════════════
    story.append(section_banner('⚡  Calcium Disorders, Anemia & Critical Lab Values', colors.HexColor('#00695C'), styles))
    story.append(Spacer(1, 0.3*cm))

    story.append(Paragraph('Calcium Disorder Differential', styles['SubHeader']))
    calcium_data = [
        ['Condition', 'Ca', 'PTH', 'Phosphate', 'Vitamin D', 'Causes'],
        ['Primary\nHyperparathyroidism', '↑', '↑↑', '↓', 'Normal/↓', 'Parathyroid adenoma (85%),\nhyperplasia, carcinoma'],
        ['Malignancy\n(hypercalcemia)', '↑', '↓ (suppressed)', 'Normal/↑', 'Normal', 'PTHrP secretion,\nlytic bone mets, lymphoma (1,25-D3)'],
        ['Sarcoidosis', '↑', '↓', 'Normal', 'High 1,25-D3', 'Granuloma converts 25-D3\nto active 1,25-D3'],
        ['Primary\nHypoparathyroidism', '↓', '↓↓', '↑', 'Normal', 'Post-thyroid surgery,\nautoimmune, DiGeorge'],
        ['Vitamin D\nDeficiency', '↓ (mild)', '↑ (2° HPT)', '↓ or normal', 'Low 25-D3', 'Poor sunlight, malabsorption,\nchronic liver/renal disease'],
        ['CKD (2° HPT)', '↓ or normal', '↑↑', '↑', 'Low 1,25-D3', 'Impaired renal 1-alpha\nhydroxylase; phosphate retention'],
        ['Pseudohypo-\nparathyroidism', '↓', '↑↑', '↑', 'Normal', 'PTH resistance (Albright\nosteodystrophy), GNAS mutation'],
    ]
    story.append(ref_table(styles, calcium_data, [2.8*cm, 1.0*cm, 1.2*cm, 2.0*cm, 2.2*cm, 7.8*cm], colors.HexColor('#00695C')))
    story.append(Spacer(1, 0.4*cm))

    story.append(Paragraph('Anemia - Biochemical Classification', styles['SubHeader']))
    anemia_data = [
        ['Type', 'Hb', 'MCV', 'Serum Iron', 'Ferritin', 'TIBC', 'Other', 'Causes'],
        ['Iron Deficiency\nAnemia (IDA)', '↓', '↓\n(< 80 fL)', '↓', '↓↓', '↑', 'Low reticulocytes\nHypochromic RBCs', 'GI blood loss, menorrhagia,\nmalabsorption (celiac)'],
        ['Anemia of Chronic\nDisease (ACD)', '↓\n(mild)', 'Normal/↓', '↓', 'Normal/↑\n(key diff)', '↓', 'High CRP,\nhigh hepcidin', 'Chronic infection, malignancy,\nautoimmune diseases'],
        ['Megaloblastic\n(B12/Folate def.)', '↓', '↑\n(> 100 fL)', 'Normal', 'Normal', 'Normal', 'Hypersegmented\nneutrophils, oval macrocytes', 'B12: pernicious anemia,\nvegetarians, gastrectomy\nFolate: alcohol, pregnancy'],
        ['Haemolytic\nAnemia', '↓', 'Normal/↑', 'Normal/↑', '↑', 'Normal/↓', '↑LDH, ↑Indirect bili,\n↓Haptoglobin', 'AIHA, hereditary spherocytosis,\nG6PD def., sickle cell, TTP'],
        ['Aplastic Anemia', '↓↓', 'Normal', 'Normal/↑', '↑', 'Normal', 'Pancytopenia,\nhypocellular marrow', 'Idiopathic, drugs, radiation,\nparoxysmal nocturnal hemoglobinuria'],
    ]
    story.append(ref_table(styles, anemia_data, [2.2*cm, 0.8*cm, 1.0*cm, 1.5*cm, 1.5*cm, 1.0*cm, 3.0*cm, 5.5*cm], colors.HexColor('#00695C')))
    story.append(Spacer(1, 0.4*cm))

    story.append(Paragraph('Critical (Panic) Laboratory Values - Require Immediate Action', styles['SubHeader']))
    critical_data = [
        ['Test', 'Critical Low', 'Critical High', 'Immediate Action'],
        ['Sodium', '< 120 mmol/L', '> 160 mmol/L', 'Medical emergency - slow correction\nMax rate 0.5 mEq/L/hr'],
        ['Potassium', '< 2.5 mmol/L', '> 6.5 mmol/L', 'URGENT ECG; IV KCl (low)\nCalcium gluconate + insulin/glucose (high)'],
        ['Glucose', '< 40 mg/dL', '> 500 mg/dL', 'IV D50 or glucagon (low)\nInsulin drip + fluids (high - DKA/HHS)'],
        ['Calcium (total)', '< 6.5 mg/dL', '> 13.0 mg/dL', 'IV calcium gluconate (low)\nIV saline + bisphosphonates (high)'],
        ['Creatinine', '—', '> 10 mg/dL\n(new/acute)', 'Nephrology consult; consider dialysis\nCheck K⁺, fluid status'],
        ['Troponin', '—', 'Any elevation\n+ chest pain', 'STEMI protocol: ECG + cath lab\nNon-STEMI: ASA, anticoag, cath'],
        ['pH (arterial)', '< 7.20', '> 7.60', 'ICU admission; treat underlying cause\nConsider NaHCO₃ if pH < 7.10'],
        ['Hemoglobin', '< 7.0 g/dL', '—', 'Transfuse if symptomatic\nFind source of blood loss'],
        ['PT/INR', '—', '> 3.0 (not on\nwarfarin)', 'Vitamin K IV; FFP if bleeding\nCheck liver function'],
    ]
    story.append(ref_table(styles, critical_data, [3.0*cm, 3.0*cm, 3.5*cm, 7.5*cm], colors.HexColor('#B71C1C')))
    story.append(PageBreak())

    # ═══════════════════════════════════════════════════════
    # FINAL PAGE: KEY CLINICAL PRINCIPLES
    # ═══════════════════════════════════════════════════════
    story.append(section_banner('📋  Key Clinical Principles & Interpretation Rules', DARKGRAY, styles))
    story.append(Spacer(1, 0.3*cm))

    principles = [
        ('Never interpret a lab in isolation',
         'Always correlate with clinical history, symptoms, physical examination, and other labs. '
         'A troponin of 0.1 ng/mL means very different things in a chest-pain patient vs. a CKD patient.'),
        ('Reference ranges are population-based, not diagnostic cutoffs',
         'They represent the middle 95% of healthy adults. 5% of healthy people will have "abnormal" values. '
         'Age, sex, ethnicity, medications, and laboratory methods all affect reference ranges.'),
        ('Trend matters as much as the value',
         'A creatinine rising from 0.8 to 1.3 mg/dL is more significant than a stable 1.5 mg/dL. '
         'Serial troponins (0h, 3h, 6h) are more informative than a single measurement.'),
        ('Confirm unexpected critical values before acting',
         'Always repeat unexpected critical values (except troponin, potassium in symptomatic patients). '
         'Check for sample hemolysis, contamination, and collection errors first.'),
        ('Understand compensatory changes',
         'A low pH + low HCO₃ + low CO₂ = metabolic acidosis with appropriate respiratory compensation. '
         'The compensation is expected - it does not mean two separate disorders unless it is excessive.'),
        ('Multiple abnormalities often cluster in syndromes',
         'DKA: high glucose + metabolic acidosis + high anion gap + ketones + high K⁺ (apparent) + high BUN. '
         'Nephrotic: low albumin + edema + high cholesterol + proteinuria + normal/low Na.'),
        ('Pseudo-abnormalities exist',
         'Pseudohyponatremia (hyperlipidemia, hyperproteinemia) · Pseudohyperkalemia (hemolysis, thrombocytosis) · '
         'Pseudohypoglycemia (high WBC count consuming glucose in tube) · Spurious low creatinine (low muscle mass).'),
    ]

    for title_p, body_p in principles:
        story.append(KeepTogether([
            Paragraph(f'• {title_p}', styles['SubHeader']),
            Paragraph(body_p, styles['Body']),
            Spacer(1, 0.2*cm),
        ]))

    story.append(Spacer(1, 0.5*cm))
    story.append(HRFlowable(width=W, thickness=1, color=GRAY))
    story.append(Spacer(1, 0.3*cm))

    sources_text = (
        '<b>Sources:</b> Guyton and Hall Textbook of Medical Physiology, 14th Ed (Elsevier) · '
        'Goldman-Cecil Medicine, International Edition, 2-Volume Set (Elsevier) · '
        'Harrison\'s Principles of Internal Medicine, 22nd Ed (McGraw Hill, 2025) · '
        'KDIGO Clinical Practice Guidelines for Acute Kidney Injury (2012) · '
        'ADA Standards of Medical Care in Diabetes (2024) · '
        'ACC/AHA Guideline on Dyslipidemia Management (2019)'
    )
    story.append(Paragraph(sources_text, styles['Caption']))

    # ── Build ──────────────────────────────────────────────────────────────────
    def on_first_page(canvas, doc):
        pass

    def on_later_pages(canvas, doc):
        canvas.saveState()
        canvas.setFont('Helvetica', 8)
        canvas.setFillColor(GRAY)
        canvas.drawString(2*cm, 1.3*cm, 'Clinical Laboratory Interpretation Guide · Orris Clinical Reference')
        canvas.drawRightString(A4[0]-2*cm, 1.3*cm, f'Page {doc.page}')
        canvas.restoreState()

    doc.build(story, onFirstPage=on_first_page, onLaterPages=on_later_pages)
    print(f"PDF successfully created: {OUTPUT_PATH}")

if __name__ == '__main__':
    build_pdf()
Running Command

cd /home/daytona/workspace/clinical-lab-guide && python3 generate_guide.py 2>&1

Editing File

~/clinical-lab-guide/generate_guide.py

Successfully replaced 1 instance(s) of the string in '/home/daytona/workspace/clinical-lab-guide/generate_guide.py'
Running Command

cd /home/daytona/workspace/clinical-lab-guide && python3 generate_guide.py 2>&1

Running Command

ls -lh /home/daytona/workspace/clinical-lab-guide/Clinical_Lab_Interpretation_Guide.pdf

Your PDF is ready - 1.3 MB, generated successfully.

Clinical Lab Interpretation Guide

PDF Document · PDF


Here's what's inside the guide (8 sections, color-coded throughout):
Cover Page - Full-color navy cover with topic overview
Section 1 - Quick Reference Table
  • All 34 key lab values with normal ranges, low/high interpretations in a single master table
Section 2 - Electrolytes (with Flowcharts)
  • Flowchart 1: Sodium (Na⁺) - hyponatremia vs hypernatremia algorithm, including SIADH, DI, Conn's
  • Flowchart 2: Potassium (K⁺) - hypo/hyperkalemia with ECG urgency indicators and treatment ladder
  • Detailed differential tables for each
Section 3 - Blood Glucose (with Flowchart)
  • Flowchart 3: Fasting glucose algorithm - normal → pre-DM → DM → hypoglycemia, with Type 1 vs Type 2 branching
  • DKA, HHS, insulinoma differentials
Section 4 - Liver Function (with Flowchart)
  • Flowchart 4: Hepatocellular vs cholestatic pattern, AST:ALT ratio, causes, biopsy indications
  • 7-condition LFT pattern table
Section 5 - Renal Function (with Flowchart)
  • Flowchart 5: Pre-renal / Intrinsic renal / Post-renal classification using BUN:Cr ratio and FENa
  • KDIGO AKI staging (Stages 1-3) and CKD staging (G1-G5)
Section 6 - ABG (with Flowchart)
  • Flowchart 6: pH → identify disorder → compensation → anion gap
  • MUDPILES mnemonic for high anion gap metabolic acidosis
  • Winter's formula, compensation equations
Section 7 - Lipids & Cardiac Biomarkers
  • ATP III lipid targets by risk category
  • Cardiac biomarker timeline table (Troponin, CK-MB, BNP, LDH)
Section 8 - Thyroid, Inflammatory, Calcium, Anemia & Critical Values
  • 7-pattern thyroid interpretation grid
  • Calcium disorder differential (PTH/Vitamin D pattern recognition)
  • Anemia biochemical classification (IDA vs ACD vs Megaloblastic vs Hemolytic)
  • Critical/Panic values table with immediate actions for each
This is a shared conversation. Sign in to Orris to start your own chat.