Genarate handwritten notes of cardiovascular system

Asking for Preferences
Reading File
Finding Sources
Finding Sources
Finding Sources
Finding Sources
Finding Sources
Finding Sources
Finding Sources
Reading File
Finding Sources
Reading File
Finding Sources
Running Command

mkdir -p /tmp/workspace/cvs-notes && ls /tmp/workspace/cvs-notes/

Writing File

~/cvs-notes/generate_cvs_notes.py

"""
Cardiovascular System - Handwritten-Style Notes PDF Generator
For MBBS/MD Medical Students
"""

from reportlab.lib.pagesizes import A4
from reportlab.lib import colors
from reportlab.lib.units import mm, cm
from reportlab.pdfgen import canvas
from reportlab.lib.colors import HexColor
from reportlab.platypus import SimpleDocTemplate, Paragraph, Spacer, Table, TableStyle, HRFlowable
from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
from reportlab.lib.enums import TA_LEFT, TA_CENTER, TA_JUSTIFY
from reportlab.pdfbase import pdfmetrics
from reportlab.pdfbase.ttfonts import TTFont
import os, math, random

OUTPUT = "/tmp/workspace/cvs-notes/CVS_Handwritten_Notes_MBBS.pdf"

# ── colour palette (notebook feel) ──────────────────────────────────────────
BG          = HexColor("#FFFEF7")      # cream paper
LINE_COLOR  = HexColor("#C8DCEF")      # faint blue ruled lines
HEADING1    = HexColor("#1A237E")      # deep navy (main title)
HEADING2    = HexColor("#0D47A1")      # medium blue (chapter heading)
HEADING3    = HexColor("#1565C0")      # slightly lighter (sub-heading)
HEADING4    = HexColor("#1976D2")      # section heading
BODY_INK    = HexColor("#1C1C1C")      # near-black ink
HIGHLIGHT   = HexColor("#FFF176")      # yellow highlight
BOX_BORDER  = HexColor("#0D47A1")
BOX_BG      = HexColor("#E3F2FD")
WARNING_BG  = HexColor("#FFF3E0")
WARNING_BOR = HexColor("#E65100")
MNEMONIC_BG = HexColor("#F3E5F5")
MNEMONIC_B  = HexColor("#6A1B9A")
TABLE_HEAD  = HexColor("#1565C0")
TABLE_ALT   = HexColor("#E8F4FD")
RULE_COLOR  = HexColor("#90CAF9")
RED_PEN     = HexColor("#C62828")      # important / exam tip
GREEN_PEN   = HexColor("#2E7D32")      # clinical pearl
STAMP_COLOR = HexColor("#E3F2FD")

W, H = A4  # 595 x 842 pt

# ── helper: ruled-paper background ──────────────────────────────────────────
def draw_background(c, w, h):
    c.setFillColor(BG)
    c.rect(0, 0, w, h, fill=1, stroke=0)
    c.setStrokeColor(LINE_COLOR)
    c.setLineWidth(0.4)
    line_spacing = 18
    y = h - 30
    while y > 20:
        c.line(15, y, w - 15, y)
        y -= line_spacing
    # left margin red line
    c.setStrokeColor(HexColor("#FFCDD2"))
    c.setLineWidth(0.8)
    c.line(45, h - 10, 45, 10)

def draw_page_number(c, page_num, w):
    c.setFont("Helvetica", 8)
    c.setFillColor(HexColor("#90A4AE"))
    c.drawCentredString(w / 2, 12, f"— {page_num} —")

def draw_header_banner(c, text, w, h, page_num):
    # top banner
    c.setFillColor(HexColor("#1A237E"))
    c.rect(0, h - 22, w, 22, fill=1, stroke=0)
    c.setFillColor(colors.white)
    c.setFont("Helvetica-Bold", 9)
    c.drawString(50, h - 14, "CARDIOVASCULAR SYSTEM — MBBS/MD NOTES")
    c.setFont("Helvetica", 8)
    c.drawRightString(w - 10, h - 14, text)

# ── canvas-based page callback ───────────────────────────────────────────────
class PageTemplate:
    def __init__(self, section_name=""):
        self.section_name = section_name
        self.page_num = [0]

    def __call__(self, canvas_obj, doc):
        self.page_num[0] += 1
        canvas_obj.saveState()
        draw_background(canvas_obj, W, H)
        draw_header_banner(canvas_obj, self.section_name, W, H, self.page_num[0])
        draw_page_number(canvas_obj, self.page_num[0], W)
        canvas_obj.restoreState()


# ── paragraph styles ─────────────────────────────────────────────────────────
def make_styles():
    styles = getSampleStyleSheet()

    base = dict(fontName="Helvetica", fontSize=10, leading=15,
                textColor=BODY_INK, spaceAfter=4,
                leftIndent=10, rightIndent=10)

    s = {}

    s['chapter_title'] = ParagraphStyle('chapter_title',
        fontName="Helvetica-Bold", fontSize=22, leading=28,
        textColor=HEADING1, spaceAfter=6, spaceBefore=12,
        alignment=TA_CENTER)

    s['chapter_sub'] = ParagraphStyle('chapter_sub',
        fontName="Helvetica-Oblique", fontSize=11, leading=15,
        textColor=HexColor("#3949AB"), spaceAfter=10,
        alignment=TA_CENTER)

    s['h1'] = ParagraphStyle('h1',
        fontName="Helvetica-Bold", fontSize=16, leading=20,
        textColor=HEADING2, spaceAfter=6, spaceBefore=14,
        leftIndent=8, borderPad=4,
        borderColor=HEADING2, borderWidth=0)

    s['h2'] = ParagraphStyle('h2',
        fontName="Helvetica-Bold", fontSize=13, leading=17,
        textColor=HEADING3, spaceAfter=4, spaceBefore=10,
        leftIndent=12)

    s['h3'] = ParagraphStyle('h3',
        fontName="Helvetica-BoldOblique", fontSize=11, leading=15,
        textColor=HEADING4, spaceAfter=3, spaceBefore=8,
        leftIndent=16)

    s['body'] = ParagraphStyle('body', **base)

    s['bullet'] = ParagraphStyle('bullet',
        fontName="Helvetica", fontSize=10, leading=15,
        textColor=BODY_INK, spaceAfter=3,
        leftIndent=28, firstLineIndent=-14,
        bulletIndent=16, rightIndent=10)

    s['subbullet'] = ParagraphStyle('subbullet',
        fontName="Helvetica", fontSize=9.5, leading=14,
        textColor=BODY_INK, spaceAfter=2,
        leftIndent=44, firstLineIndent=-14,
        bulletIndent=32, rightIndent=10)

    s['important'] = ParagraphStyle('important',
        fontName="Helvetica-Bold", fontSize=10, leading=15,
        textColor=RED_PEN, spaceAfter=4,
        leftIndent=10, rightIndent=10)

    s['clinical'] = ParagraphStyle('clinical',
        fontName="Helvetica-Oblique", fontSize=10, leading=15,
        textColor=GREEN_PEN, spaceAfter=4,
        leftIndent=14, rightIndent=10)

    s['mnemonic'] = ParagraphStyle('mnemonic',
        fontName="Helvetica-Bold", fontSize=11, leading=16,
        textColor=MNEMONIC_B, spaceAfter=4,
        leftIndent=14, rightIndent=10)

    s['box_head'] = ParagraphStyle('box_head',
        fontName="Helvetica-Bold", fontSize=10.5, leading=15,
        textColor=HEADING2, spaceAfter=3, leftIndent=6)

    s['box_body'] = ParagraphStyle('box_body',
        fontName="Helvetica", fontSize=9.5, leading=14,
        textColor=BODY_INK, spaceAfter=3, leftIndent=6, rightIndent=6)

    s['table_head'] = ParagraphStyle('table_head',
        fontName="Helvetica-Bold", fontSize=9, leading=13,
        textColor=colors.white, alignment=TA_CENTER)

    s['table_cell'] = ParagraphStyle('table_cell',
        fontName="Helvetica", fontSize=9, leading=13,
        textColor=BODY_INK, alignment=TA_LEFT)

    s['exam_tip'] = ParagraphStyle('exam_tip',
        fontName="Helvetica-Bold", fontSize=9.5, leading=14,
        textColor=HexColor("#B71C1C"), spaceAfter=3,
        leftIndent=10, rightIndent=10)

    return s


# ── box helpers ───────────────────────────────────────────────────────────────
def info_box(content_paragraphs, bg=BOX_BG, border=BOX_BORDER, pad=6):
    """Wrap paragraphs in a coloured box table."""
    data = [[p] for p in content_paragraphs]
    t = Table(data, colWidths=[W - 80])
    t.setStyle(TableStyle([
        ('BACKGROUND', (0, 0), (-1, -1), bg),
        ('BOX',        (0, 0), (-1, -1), 1.2, border),
        ('TOPPADDING',    (0, 0), (-1, -1), pad),
        ('BOTTOMPADDING', (0, 0), (-1, -1), pad),
        ('LEFTPADDING',   (0, 0), (-1, -1), pad + 2),
        ('RIGHTPADDING',  (0, 0), (-1, -1), pad),
        ('ROWBACKGROUNDS', (0, 0), (-1, -1), [bg]),
    ]))
    return t


def two_col_table(headers, rows, s):
    """Simple two-column comparison table."""
    head_row = [Paragraph(h, s['table_head']) for h in headers]
    data = [head_row]
    for i, row in enumerate(rows):
        data.append([Paragraph(cell, s['table_cell']) for cell in row])
    col_w = (W - 90) / len(headers)
    t = Table(data, colWidths=[col_w] * len(headers))
    style = [
        ('BACKGROUND', (0, 0), (-1, 0), TABLE_HEAD),
        ('BOX',        (0, 0), (-1, -1), 0.8, BOX_BORDER),
        ('INNERGRID',  (0, 0), (-1, -1), 0.4, RULE_COLOR),
        ('TOPPADDING',    (0, 0), (-1, -1), 4),
        ('BOTTOMPADDING', (0, 0), (-1, -1), 4),
        ('LEFTPADDING',   (0, 0), (-1, -1), 5),
        ('VALIGN',        (0, 0), (-1, -1), 'MIDDLE'),
    ]
    for i in range(1, len(data)):
        if i % 2 == 0:
            style.append(('BACKGROUND', (0, i), (-1, i), TABLE_ALT))
    t.setStyle(TableStyle(style))
    return t


# ── CONTENT BUILDER ───────────────────────────────────────────────────────────
def build_content(s):
    story = []
    SP = Spacer
    HR = HRFlowable

    def h(text, level=1):
        story.append(Paragraph(text, s[f'h{level}']))

    def p(text):
        story.append(Paragraph(text, s['body']))

    def b(text):
        story.append(Paragraph(f"• {text}", s['bullet']))

    def sb(text):
        story.append(Paragraph(f"◦ {text}", s['subbullet']))

    def imp(text):
        story.append(Paragraph(f"★ {text}", s['important']))

    def clin(text):
        story.append(Paragraph(f"🩺 {text}", s['clinical']))

    def tip(text):
        story.append(Paragraph(f"📝 EXAM TIP: {text}", s['exam_tip']))

    def spacer(n=6):
        story.append(SP(1, n))

    def rule():
        story.append(HR(width="100%", thickness=0.6, color=RULE_COLOR, spaceAfter=4, spaceBefore=4))

    def box(title, items, bg=BOX_BG, bor=BOX_BORDER):
        inner = [Paragraph(title, s['box_head'])]
        for it in items:
            inner.append(Paragraph(f"• {it}", s['box_body']))
        story.append(info_box(inner, bg=bg, border=bor))
        spacer(4)

    def mnemonic(title, text):
        inner = [
            Paragraph(f"🔤 MNEMONIC: {title}", s['mnemonic']),
            Paragraph(text, s['box_body'])
        ]
        story.append(info_box(inner, bg=MNEMONIC_BG, border=MNEMONIC_B))
        spacer(4)

    def warning(title, text):
        inner = [
            Paragraph(f"⚠️ {title}", ParagraphStyle('wh', fontName="Helvetica-Bold",
                fontSize=10, textColor=WARNING_BOR, leading=14, leftIndent=4)),
            Paragraph(text, s['box_body'])
        ]
        story.append(info_box(inner, bg=WARNING_BG, border=WARNING_BOR))
        spacer(4)

    # ══════════════════════════════════════════════════════════════════════════
    # COVER / TITLE PAGE
    # ══════════════════════════════════════════════════════════════════════════
    story.append(SP(1, 30))
    story.append(Paragraph("CARDIOVASCULAR SYSTEM", s['chapter_title']))
    story.append(Paragraph("Complete Handwritten-Style Notes for MBBS/MD", s['chapter_sub']))
    spacer(8)
    story.append(HR(width="80%", thickness=2, color=HEADING1, spaceAfter=6, spaceBefore=6))
    story.append(Paragraph(
        "Covering: Anatomy • Physiology • Pathology • Pharmacology",
        ParagraphStyle('cover_sub', fontName="Helvetica-Oblique", fontSize=11,
                       textColor=HEADING3, alignment=TA_CENTER, leading=16)
    ))
    spacer(10)
    box("📚 Topics Covered", [
        "Section 1 — Anatomy of the Heart & Great Vessels",
        "Section 2 — Cardiac Physiology & the Cardiac Cycle",
        "Section 3 — Pathology: Heart Failure, IHD, Valvular Disease, Arrhythmias",
        "Section 4 — Cardiovascular Pharmacology",
        "Section 5 — High-Yield Summary & Mnemonics",
    ])
    spacer(20)
    story.append(Paragraph(
        "Sources: Braunwald's Heart Disease | Robbins & Kumar Basic Pathology | ROSEN's Emergency Medicine | Goldman-Cecil Medicine",
        ParagraphStyle('src', fontName="Helvetica-Oblique", fontSize=8,
                       textColor=HexColor("#78909C"), alignment=TA_CENTER)
    ))
    story.append(SP(1, 50))

    # ══════════════════════════════════════════════════════════════════════════
    # SECTION 1 — ANATOMY
    # ══════════════════════════════════════════════════════════════════════════
    story.append(HR(width="100%", thickness=2.5, color=HEADING1))
    story.append(Paragraph("SECTION 1: ANATOMY OF THE HEART & GREAT VESSELS", s['chapter_title']))
    story.append(HR(width="100%", thickness=1, color=RULE_COLOR))
    spacer(8)

    h("1.1  Overview & Position", 1)
    p("The heart is a hollow, muscular, cone-shaped organ located in the <b>middle mediastinum</b>. It weighs ~250–350 g (♀) and ~300–400 g (♂). It sits obliquely — 2/3 lies to the LEFT of the midline.")
    spacer(4)
    b("Borders of the heart:")
    sb("RIGHT border — Right atrium")
    sb("LEFT border — Left ventricle (mainly) + left auricle")
    sb("SUPERIOR border — Right + Left atria, great vessels")
    sb("INFERIOR border — Right ventricle (mainly)")
    spacer(4)
    b("Apex: Formed by left ventricle, located at the 5th intercostal space, mid-clavicular line (left side)")
    b("Base: Posterior surface — mainly left atrium")
    spacer(6)

    h("1.2  Layers of the Heart Wall", 1)
    data = [
        ["Layer", "Description", "Key Points"],
        ["Epicardium", "Visceral pericardium, outer layer", "Coronary vessels run here"],
        ["Myocardium", "Cardiac muscle; thickest layer", "LV wall thicker than RV (3:1 ratio)"],
        ["Endocardium", "Inner endothelial lining", "Lines chambers & valves"],
        ["Pericardium", "Fibroserous sac around heart", "Fibrous + serous layers; ~50 mL fluid normally"],
    ]
    story.append(two_col_table(data[0], data[1:], s))
    spacer(6)

    h("1.3  Cardiac Chambers", 1)
    h("Right Atrium (RA)", 2)
    b("Receives deoxygenated blood from SVC, IVC, and coronary sinus")
    b("Contains the <b>Sinoatrial (SA) node</b> — pacemaker — in the sulcus terminalis near SVC opening")
    b("Fossa ovalis — remnant of foramen ovale (fetal circulation)")
    b("Crista terminalis divides smooth vs. trabeculated (musculi pectinati) portions")
    spacer(4)
    h("Right Ventricle (RV)", 2)
    b("Crescent-shaped in cross-section; pumps blood into pulmonary circulation")
    b("Has coarse trabeculae carneae; moderator band carries right bundle branch")
    b("Normal RV pressure: <b>25/5 mmHg</b>")
    b("Separated from LV by interventricular septum")
    spacer(4)
    h("Left Atrium (LA)", 2)
    b("Receives oxygenated blood from 4 pulmonary veins")
    b("Thicker wall than RA; left auricle prone to thrombus in AF")
    b("Forms most of the posterior surface of the heart (base)")
    spacer(4)
    h("Left Ventricle (LV)", 2)
    b("Elliptical; wall ~8–12 mm thick at end-diastole (vs. RV ~3 mm)")
    b("Normal LV pressure: <b>120/8 mmHg</b>; Normal LVEDP ≤ 12 mmHg")
    b("Fine trabeculae carneae; papillary muscles (anterior + posterior) attached to mitral valve leaflets via chordae tendineae")
    spacer(4)
    imp("LV:RV wall thickness ratio ~3:1. LV must overcome systemic vascular resistance (~800–1200 dyn·s·cm⁻⁵)")
    spacer(6)

    h("1.4  Cardiac Valves", 1)
    story.append(two_col_table(
        ["Valve", "Location", "Cusps", "Opens When", "Closes When"],
        [
            ["Tricuspid (TV)", "Right AV", "3 (ant, post, septal)", "Diastole (filling RV)", "Systole"],
            ["Pulmonary (PV)", "RVOT", "3 semilunar", "RV systole", "RV diastole"],
            ["Mitral (MV)", "Left AV", "2 (ant, post)", "Diastole (filling LV)", "Systole"],
            ["Aortic (AoV)", "LVOT", "3 semilunar", "LV systole", "LV diastole"],
        ], s
    ))
    spacer(4)
    mnemonic("Valve positions (Auscultation)",
             "A2P2T1M1 — (Aortic 2nd ICS right, Pulmonary 2nd ICS left, Tricuspid lower left sternal border, Mitral 5th ICS MCL)\n"
             "All Physicians Take Money → Aortic, Pulmonary, Tricuspid, Mitral")
    spacer(6)

    h("1.5  Coronary Circulation", 1)
    h("Left Coronary Artery (LCA)", 2)
    b("Arises from <b>left coronary sinus</b> of aorta")
    b("Left Main (LMCA) → divides into:")
    sb("Left Anterior Descending (LAD): Supplies anterior LV wall, anterior IVS, apex — '\"widow maker\"'")
    sb("Left Circumflex (LCx): Supplies lateral + posterior LV wall, LA; gives SA nodal artery in ~40%")
    spacer(4)
    h("Right Coronary Artery (RCA)", 2)
    b("Arises from <b>right coronary sinus</b>")
    b("Supplies RA, RV, inferior LV wall, SA node (60%), AV node (85–90%), posterior IVS (in RCA-dominant)")
    b("RCA-dominant circulation present in ~70% of people")
    spacer(4)
    box("Coronary Dominance", [
        "RCA dominant (70%): RCA gives posterior descending artery (PDA)",
        "LCx dominant (10%): LCx gives PDA",
        "Co-dominant (20%): Both RCA and LCx give PDA",
        "Clinical: RCA occlusion → inferior MI + AV block; LAD occlusion → anterior MI + LV dysfunction",
    ])

    h("1.6  Cardiac Conduction System", 1)
    b("<b>SA node</b>: Right atrium near SVC; intrinsic rate 60–100 bpm; supplied by RCA (60%)")
    b("<b>AV node</b>: Floor of RA near coronary sinus ostium; rate 40–60 bpm; delay ~0.1 s")
    b("<b>Bundle of His</b>: Passes through membranous IVS; bifurcates at IVS")
    b("<b>Right Bundle Branch (RBB)</b>: Runs in moderator band to anterior papillary muscle")
    b("<b>Left Bundle Branch (LBB)</b>: Divides into anterior + posterior fascicles")
    b("<b>Purkinje fibres</b>: Fastest conduction in heart (~4 m/s); intrinsic rate 20–40 bpm")
    spacer(4)
    tip("SA node → AV node → Bundle of His → L+R bundles → Purkinje fibres. AV node has the SLOWEST conduction velocity (0.05 m/s) — allows time for atrial filling of ventricles.")
    rule()
    spacer(6)

    # ══════════════════════════════════════════════════════════════════════════
    # SECTION 2 — PHYSIOLOGY
    # ══════════════════════════════════════════════════════════════════════════
    story.append(HR(width="100%", thickness=2.5, color=HEADING1))
    story.append(Paragraph("SECTION 2: CARDIAC PHYSIOLOGY & THE CARDIAC CYCLE", s['chapter_title']))
    story.append(HR(width="100%", thickness=1, color=RULE_COLOR))
    spacer(8)

    h("2.1  Cardiac Output (CO) & Determinants", 1)
    p("Cardiac Output (CO) = the volume of blood ejected by each ventricle per minute.")
    spacer(4)
    story.append(info_box([
        Paragraph("CO = HR × SV", ParagraphStyle('formula', fontName="Helvetica-Bold",
            fontSize=14, textColor=HEADING1, alignment=TA_CENTER, leading=20)),
        Paragraph("Normal CO = 4–8 L/min | Cardiac Index (CI) = CO / BSA = 2.2–4.0 L/min/m²",
            ParagraphStyle('fml2', fontName="Helvetica", fontSize=10, textColor=BODY_INK,
            alignment=TA_CENTER, leading=15)),
    ]))
    spacer(6)

    h("4 Determinants of CO", 2)
    story.append(two_col_table(
        ["Parameter", "Definition", "Normal Value", "↑ by", "↓ by"],
        [
            ["Heart Rate (HR)", "Beats per min (chronotropy)", "60–100 bpm", "Sympathetic, exercise, fever", "Vagal, β-blockers, hypothyroidism"],
            ["Preload", "EDV / ventricular filling (lusitropy)", "LVEDP 6–12 mmHg", "IV fluids, leg raise, exercise", "Diuretics, nitrates, dehydration"],
            ["Afterload", "Resistance LV must overcome", "SVR 800–1200 dyn·s", "HTN, aortic stenosis, vasoconstrictors", "Vasodilators, ACE inhibitors"],
            ["Contractility", "Intrinsic myocardial force (inotropy)", "EF 55–70%", "Sympathomimetics, digoxin, Ca²⁺", "β-blockers, heart failure, acidosis"],
        ], s
    ))
    spacer(6)

    h("Frank-Starling Mechanism", 2)
    p("Increased ventricular filling (preload) → stretches sarcomeres → greater overlap of actin-myosin → stronger contraction → increased SV. This continues up to a physiological limit (sarcomere length ~2.2 μm optimal).")
    b("Clinical application: IV fluids in septic shock temporarily improve CO by raising preload")
    b("In severe heart failure: Starling curve is flat or depressed — further fluid loading can worsen pulmonary oedema")
    imp("Frank-Starling law = heart pumps whatever blood returns to it (venous return = CO in steady state)")
    spacer(6)

    h("2.2  The Cardiac Cycle", 1)
    p("The cardiac cycle has two main phases: <b>Systole</b> (contraction & ejection) and <b>Diastole</b> (relaxation & filling). Duration: ~0.8 s at 75 bpm.")
    spacer(4)
    story.append(two_col_table(
        ["Phase", "Event", "Valves", "Pressure Change"],
        [
            ["1. Isovolumetric Contraction", "Ventricle contracts; no ejection yet", "All closed", "LV pressure rises rapidly"],
            ["2. Rapid Ejection", "AoV/PV open; blood ejected", "AoV + PV open", "LV > Aortic; SV ejected"],
            ["3. Reduced Ejection", "Slower ejection; pressure falls", "AoV + PV open", "Aortic > LV"],
            ["4. Isovolumetric Relaxation", "Ventricle relaxes; no filling", "All closed", "LV pressure drops fast"],
            ["5. Rapid Filling", "MV/TV open; passive filling", "MV + TV open", "LA/RA → Ventricles"],
            ["6. Diastasis", "Slow filling phase", "MV + TV open", "Equalization of pressures"],
            ["7. Atrial Kick (Presystole)", "'Atrial systole'; adds ~20–25% filling", "MV + TV open", "Final boost to LVEDV"],
        ], s
    ))
    spacer(4)
    warning("Lost Atrial Kick in AF",
            "In atrial fibrillation, atrial contraction (kick) is lost → reduced LVEDV by ~20–25% → reduced CO. This is clinically significant in patients with diastolic dysfunction (e.g., hypertensive heart disease, hypertrophic cardiomyopathy).")
    spacer(4)

    h("Heart Sounds", 2)
    b("<b>S1 (lub)</b>: Closure of MV + TV at start of systole; best heard at apex/LLSB")
    b("<b>S2 (dub)</b>: Closure of AoV + PV at start of diastole; A2 heard 2nd ICS right, P2 heard 2nd ICS left")
    sb("Physiological split of S2: A2 before P2; widens on inspiration (↑ venous return to RV)")
    sb("Fixed split: ASD — equal RV/LV filling delay")
    sb("Paradoxical split: P2 before A2; in LBBB, aortic stenosis")
    b("<b>S3 (pathological in adults)</b>: Early diastole; 'ventricular gallop'; indicates high LVEDP / heart failure")
    b("<b>S4</b>: Late diastole (presystole); 'atrial gallop'; stiff ventricle — HTN, HCM, aortic stenosis")
    spacer(4)
    mnemonic("S3 vs S4",
             "S3 — 3 letters = 3 letters in 'ken-TU-cky' (ken-TU-cky rhythm) — pathological, heart failure\n"
             "S4 — 'TEN-nes-see' rhythm — stiff ventricle, atrial kick against non-compliant LV")
    spacer(4)

    h("2.3  Action Potential & Electrophysiology", 1)
    h("Ventricular Myocyte AP (Fast response)", 2)
    b("Phase 0 — Rapid depolarisation: Fast Na⁺ channels open → upstroke")
    b("Phase 1 — Early repolarisation: Na⁺ channels inactivate; K⁺ (Ito) efflux → notch")
    b("Phase 2 — Plateau: Ca²⁺ influx (L-type VGCC) = K⁺ efflux — <b>unique to cardiac cells!</b>")
    b("Phase 3 — Rapid repolarisation: K⁺ (IKr, IKs) efflux > Ca²⁺ influx")
    b("Phase 4 — Resting membrane potential: −90 mV (maintained by K⁺ leak + Na-K ATPase)")
    spacer(4)
    h("SA Node AP (Slow response / pacemaker)", 2)
    b("Phase 4 — Funny current (If): slow Na⁺ influx → spontaneous depolarisation (automaticity)")
    b("Phase 0 — Slow upstroke: Ca²⁺ channels (not Na⁺)")
    b("No true resting potential — spontaneous depolarisation is hallmark of pacemaker cells")
    imp("No Phase 1 or 2 in SA/AV node. Upstroke by Ca²⁺ channels (target of CCBs: verapamil, diltiazem).")
    spacer(4)
    tip("Refractory period prevents re-entrant circuits in healthy myocardium. Absolute refractory period corresponds to Phase 0–2 (no new AP possible). Relative refractory period = Phase 3 (suprathreshold stimulus can trigger AP — vulnerable period for VF if R-on-T phenomenon occurs).")
    rule()
    spacer(6)

    # ══════════════════════════════════════════════════════════════════════════
    # SECTION 3 — PATHOLOGY
    # ══════════════════════════════════════════════════════════════════════════
    story.append(HR(width="100%", thickness=2.5, color=HEADING1))
    story.append(Paragraph("SECTION 3: CARDIOVASCULAR PATHOLOGY", s['chapter_title']))
    story.append(HR(width="100%", thickness=1, color=RULE_COLOR))
    spacer(8)

    h("3.1  Ischaemic Heart Disease (IHD)", 1)
    p("<b>IHD</b> is the most common cause of death in developed countries. It results from an imbalance between myocardial oxygen <b>demand</b> and <b>supply</b>, most commonly due to atherosclerosis of coronary arteries.")
    spacer(4)
    h("Pathophysiology", 2)
    b("Endothelial injury → lipid accumulation (foam cells) → fatty streak → fibrous plaque → vulnerable plaque → plaque rupture → thrombus → coronary occlusion")
    b("Risk factors: Hypertension, Dyslipidaemia, Diabetes, Smoking, Family history, Obesity, Sedentary lifestyle")
    spacer(4)
    h("ACS Spectrum", 2)
    story.append(two_col_table(
        ["Type", "Mechanism", "ECG", "Troponin", "Management"],
        [
            ["Unstable Angina (UA)", "Plaque rupture; partial occlusion; no necrosis", "ST depression / T-wave inv", "Normal", "DAPT, heparin, PCI"],
            ["NSTEMI", "Partial occlusion; subendocardial infarction", "ST depression / T-wave inv", "Elevated", "DAPT, anticoagulant, early PCI"],
            ["STEMI", "Complete occlusion; transmural infarction", "ST elevation; Q waves later", "Markedly elevated", "Immediate reperfusion (PCI < 90 min or thrombolysis)"],
        ], s
    ))
    spacer(4)
    box("LAD vs RCA Occlusion Territories", [
        "LAD: Anterior wall + anterior IVS + apex → Anterior MI (V1–V4)",
        "LCx: Lateral wall → Lateral MI (I, aVL, V5–V6)",
        "RCA: Inferior wall + posterior IVS + RV → Inferior MI (II, III, aVF)",
        "Right-sided leads (V3R–V4R) needed to detect RV infarction",
    ])
    imp("Door-to-balloon time (D2B) < 90 min for primary PCI in STEMI. If PCI unavailable < 120 min, give thrombolysis (streptokinase / tPA).")
    spacer(4)
    h("Complications of MI", 2)
    b("Early (<24 h): Arrhythmias (VF most common cause of death in 1st hour), cardiogenic shock")
    b("1–4 days: Fibrinous pericarditis (pleuritic chest pain), AV block (inferior MI)")
    b("5–10 days: Free wall rupture (haemopericardium, tamponade), papillary muscle rupture (acute MR), VSD")
    b("Weeks–months: Dressler's syndrome (autoimmune pericarditis), LV aneurysm, chronic heart failure")
    spacer(6)

    h("3.2  Heart Failure (HF)", 1)
    p("HF = inability of the heart to pump sufficient CO to meet metabolic demands, or only at elevated filling pressures.")
    spacer(4)
    story.append(two_col_table(
        ["Feature", "HFrEF (Systolic)", "HFpEF (Diastolic)"],
        [
            ["Definition", "EF < 40%", "EF ≥ 50% with symptoms of HF"],
            ["Mechanism", "Impaired contractility (inotropy↓)", "Impaired relaxation (lusitropy↓)"],
            ["Causes", "IHD, dilated CMP, myocarditis", "HTN, HCM, aortic stenosis, ageing"],
            ["LV appearance", "Dilated, thin-walled", "Normal size or concentric hypertrophy"],
            ["Natriuretic peptides", "Markedly elevated BNP/NT-proBNP", "Elevated (less so)"],
            ["Treatment", "ACE-I/ARB, BB, MRA, SGLT2i, ARNI", "Treat cause; diuretics for congestion"],
        ], s
    ))
    spacer(4)
    h("Neurohormonal Activation in HF", 2)
    b("↓ CO → baroreceptor activation → ↑ SNS + ↑ RAAS + ↑ ADH")
    b("SNS: ↑HR, ↑contractility, vasoconstriction → short-term compensation")
    b("RAAS: Angiotensin II → aldosterone → Na⁺/H₂O retention → ↑ preload & afterload → worsens LV remodelling")
    b("Long-term: Cardiac fibrosis, hypertrophy, β-receptor downregulation, oxidative stress → progressive LV dysfunction")
    spacer(4)
    h("Clinical Features", 2)
    b("<b>Left HF</b>: Dyspnoea (orthopnoea, PND), cough, pink frothy sputum, S3 gallop, lung crackles, elevated PCWP")
    b("<b>Right HF</b>: Peripheral oedema, JVP elevation, hepatomegaly, ascites, fatigue")
    b("<b>Biventricular (congestive) HF</b>: Features of both")
    mnemonic("NYHA Functional Classification",
             "Class I — No symptoms with ordinary activity\n"
             "Class II — Slight limitation; symptoms with moderate exertion\n"
             "Class III — Marked limitation; symptoms with minimal exertion\n"
             "Class IV — Symptoms at rest")
    spacer(6)

    h("3.3  Hypertension & Hypertensive Heart Disease", 1)
    b("HTN = sustained BP ≥ 130/80 mmHg (ACC/AHA 2017) or ≥ 140/90 mmHg (JNC 7/ESC)")
    b("Primary (essential) HTN: ~95% of cases; multifactorial (genetic + environmental)")
    b("Secondary HTN: Renal artery stenosis, primary hyperaldosteronism, phaeochromocytoma, coarctation of aorta")
    spacer(4)
    h("Cardiac Effects of Chronic HTN", 2)
    b("Pressure overload → concentric LV hypertrophy (LVH) → diastolic dysfunction → HFpEF")
    b("LVH increases myocardial oxygen demand → subendocardial ischaemia")
    b("Accelerates coronary atherosclerosis → IHD")
    b("LA enlargement → AF → stroke risk")
    imp("Hypertensive emergency: BP > 180/120 with target organ damage → IV labetalol / nicardipine / sodium nitroprusside. Reduce MAP by ≤25% in 1st hour, then gradually over 24–48 h.")
    spacer(6)

    h("3.4  Valvular Heart Disease", 1)
    story.append(two_col_table(
        ["Valve Lesion", "Common Cause", "Murmur", "Key Features", "Surgery Threshold"],
        [
            ["Aortic Stenosis (AS)", "Age-related calcification, bicuspid AoV", "Ejection systolic (2nd ICS right) → carotids", "SAD triad: Syncope, Angina, Dyspnoea; slow rising pulse; narrow pulse pressure", "AVA < 1 cm² or symptomatic"],
            ["Aortic Regurgitation (AR)", "Bicuspid AoV, infective endocarditis, aortic dissection, Marfan", "Early diastolic (left sternal edge)", "Wide pulse pressure; Corrigan's pulse; Austin Flint murmur; head bobbing (de Musset)", "EF < 50% or severe symptoms"],
            ["Mitral Stenosis (MS)", "Rheumatic fever (most common)", "Mid-diastolic rumble (apex); opening snap", "Malar flush; AF; pulmonary HTN; LA enlargement on CXR", "MVA < 1.5 cm² or symptoms"],
            ["Mitral Regurgitation (MR)", "MVP, IHD, rheumatic fever, IE", "Holosystolic (apex → axilla)", "Volume overload → LV dilatation; S3 gallop; wide split S2", "EF < 60%, ESD > 40 mm"],
        ], s
    ))
    spacer(6)

    h("3.5  Cardiomyopathies", 1)
    story.append(two_col_table(
        ["Type", "Anatomy", "Mechanism", "Cause", "Key Feature"],
        [
            ["Dilated CMP (DCM)", "Dilated LV ± RV, ↓ EF", "Systolic dysfunction", "Idiopathic, alcohol, viral, peripartum, Chagas", "Eccentric hypertrophy; 'balloon' heart"],
            ["Hypertrophic CMP (HCM)", "Asymmetric septal hypertrophy, normal/small LV cavity", "Diastolic dysfunction, LVOTO", "Autosomal dominant; β-myosin heavy chain mutation", "LVOTO; dynamic obstruction; ↑ obstruction on Valsalva/standing"],
            ["Restrictive CMP (RCM)", "Normal LV size, stiff ventricle", "Infiltration/fibrosis → ↑ filling pressures", "Amyloidosis, sarcoidosis, haemochromatosis, radiation", "Kussmaul's sign; square root sign on catheterisation"],
            ["Arrhythmogenic RV CMP", "RV fibrofatty replacement", "RV systolic failure + arrhythmias", "Desmosomal gene mutations (desmoplakin, plakophilin)", "Epsilon wave on ECG; SCD in young athletes"],
        ], s
    ))
    spacer(4)
    imp("HCM: Most common cause of sudden cardiac death (SCD) in young athletes (<35 years). LVOTO worsens with ↓ preload (dehydration, Valsalva, standing) and ↑ contractility. Avoid: nitrates, diuretics, digoxin.")
    rule()
    spacer(6)

    h("3.6  Arrhythmias", 1)
    h("Atrial Fibrillation (AF)", 2)
    b("Most common sustained cardiac arrhythmia; prevalence increases with age")
    b("ECG: Irregularly irregular rhythm; absent P waves; fibrillatory baseline")
    b("Mechanism: Multiple chaotic re-entrant circuits in atria (often from pulmonary vein foci)")
    b("Risk factors: Hypertension, valvular disease (MS), HF, thyrotoxicosis, alcohol, OSA, post-cardiac surgery")
    spacer(4)
    mnemonic("CHA₂DS₂-VASc Score (stroke risk in AF)",
             "C — Congestive HF (1 pt)\n"
             "H — Hypertension (1 pt)\n"
             "A₂ — Age ≥75 (2 pts)\n"
             "D — Diabetes (1 pt)\n"
             "S₂ — Stroke/TIA/thromboembolism (2 pts)\n"
             "V — Vascular disease (1 pt)\n"
             "A — Age 65–74 (1 pt)\n"
             "Sc — Sex category (female = 1 pt)\n"
             "Score ≥2 (♂) or ≥3 (♀) → anticoagulate (DOAC preferred)")
    spacer(4)
    h("Ventricular Tachycardia (VT)", 2)
    b("≥3 consecutive ventricular beats at rate > 100 bpm; wide complex (QRS > 120 ms)")
    b("Sustained VT (>30 s) or haemodynamically unstable → DC cardioversion")
    b("Pulseless VT → treat as VF (defibrillation + CPR)")
    b("Causes: Ischaemia, cardiomyopathy, electrolyte disturbance (↓K⁺, ↓Mg²⁺), long QT syndrome")
    spacer(4)
    h("AV Blocks", 2)
    story.append(two_col_table(
        ["Type", "ECG Finding", "Level of Block", "Management"],
        [
            ["1st Degree", "PR interval > 200 ms; all P waves conducted", "AV node (delay)", "None; reassure"],
            ["2nd Degree Mobitz I (Wenckebach)", "Progressive PR lengthening → dropped QRS", "AV node", "Usually benign; atropine if symptomatic"],
            ["2nd Degree Mobitz II", "Fixed PR; sudden dropped QRS (no warning)", "Bundle of His/below", "Pacemaker (high risk of progressing to 3rd degree)"],
            ["3rd Degree (Complete)", "P and QRS dissociated; escape rhythm (junctional or ventricular)", "Complete AV dissociation", "Permanent pacemaker"],
        ], s
    ))
    rule()
    spacer(6)

    # ══════════════════════════════════════════════════════════════════════════
    # SECTION 4 — PHARMACOLOGY
    # ══════════════════════════════════════════════════════════════════════════
    story.append(HR(width="100%", thickness=2.5, color=HEADING1))
    story.append(Paragraph("SECTION 4: CARDIOVASCULAR PHARMACOLOGY", s['chapter_title']))
    story.append(HR(width="100%", thickness=1, color=RULE_COLOR))
    spacer(8)

    h("4.1  Antihypertensive Drugs", 1)
    story.append(two_col_table(
        ["Class", "Examples", "Mechanism", "Indications", "Key Side Effects"],
        [
            ["ACE Inhibitors", "Ramipril, Lisinopril, Enalapril", "Block ACE → ↓ Ang II → vasodilation + ↓ aldosterone", "HTN, HFrEF, post-MI, CKD (diabetic nephropathy)", "Dry cough (bradykinin↑), hyperkalaemia, angioedema (CI in pregnancy)"],
            ["ARBs", "Losartan, Valsartan, Candesartan", "Block AT1 receptor → ↓ Ang II effects", "HTN, HFrEF (ACE-I intolerant), diabetic nephropathy", "Hyperkalaemia (no cough); CI in pregnancy"],
            ["β-Blockers", "Atenolol, Metoprolol, Carvedilol, Bisoprolol", "Block β1 receptors → ↓ HR, ↓ CO, ↓ renin", "HTN, IHD, HFrEF, arrhythmias, post-MI", "Bradycardia, bronchospasm (CI in asthma), fatigue, sexual dysfunction"],
            ["Calcium Channel Blockers (CCBs)", "Amlodipine (DHP); Verapamil, Diltiazem (non-DHP)", "Block L-type Ca²⁺ channels → vasodilation or ↓ HR", "HTN (DHP); AF rate control, angina (non-DHP)", "Peripheral oedema (DHP); constipation, bradycardia (Verapamil)"],
            ["Thiazide Diuretics", "Hydrochlorothiazide, Chlorthalidone, Indapamide", "Block Na-Cl co-transporter in DCT → Na⁺/H₂O excretion", "HTN (1st line elderly/AfroCaribbean)", "Hypokalaemia, hyperuricaemia, hyperglycaemia, dyslipidaemia"],
            ["Loop Diuretics", "Furosemide, Bumetanide, Torasemide", "Block NKCC2 in Loop of Henle", "HF with fluid overload, HTN (renal failure)", "Hypokalaemia, hyponatraemia, ototoxicity, hypomagnesaemia"],
            ["K⁺-sparing Diuretics / MRA", "Spironolactone, Eplerenone, Amiloride", "Block aldosterone receptor (MRA) or ENaC (amiloride)", "HFrEF (with ACE-I/BB), hyperaldosteronism", "Hyperkalaemia; gynaecomastia (spironolactone)"],
        ], s
    ))
    spacer(6)

    h("4.2  Antiarrhythmic Drugs (Vaughan Williams Classification)", 1)
    story.append(two_col_table(
        ["Class", "Mechanism", "Drugs", "Used For"],
        [
            ["Class Ia", "Na⁺ channel block (intermediate kinetics) + K⁺ block → ↑ AP duration", "Quinidine, Procainamide, Disopyramide", "AF, VT; now rarely used (pro-arrhythmic)"],
            ["Class Ib", "Na⁺ channel block (fast dissociation) → ↓ AP duration", "Lidocaine, Mexiletine", "VT (especially post-MI); IV lidocaine for acute VT"],
            ["Class Ic", "Na⁺ channel block (slow kinetics); minimal effect on AP duration", "Flecainide, Propafenone", "AF/flutter cardioversion (structurally normal heart only — CI in IHD/HF)"],
            ["Class II", "β-receptor blockade → ↓ HR, ↓ AV conduction", "Metoprolol, Atenolol, Esmolol, Propranolol", "Rate control in AF, SVT, post-MI, VT (adrenergic)"],
            ["Class III", "K⁺ channel block → ↑ AP duration + refractoriness", "Amiodarone, Sotalol, Dofetilide, Ibutilide", "AF/flutter (cardioversion/maintenance), VT; Amiodarone = broadest spectrum"],
            ["Class IV", "Ca²⁺ channel block (non-DHP) → ↓ AV conduction", "Verapamil, Diltiazem", "SVT (rate control), AF rate control"],
        ], s
    ))
    spacer(4)
    warning("Amiodarone Toxicity (PITS)",
            "P — Pulmonary toxicity (interstitial pneumonitis — most serious)\n"
            "I — Increased LFTs / hepatotoxicity\n"
            "T — Thyroid dysfunction (both hyper- and hypothyroidism)\n"
            "S — Skin (photosensitivity; grey-blue discolouration)\n"
            "Also: Corneal microdeposits (99% reversible); peripheral neuropathy; check TFTs, LFTs, CXR every 6 months")
    spacer(6)

    h("4.3  Heart Failure Pharmacology", 1)
    h("HFrEF (EF < 40%) — Disease-Modifying Therapy", 2)
    story.append(two_col_table(
        ["Drug Class", "Examples", "Mechanism", "Mortality Benefit", "Key Notes"],
        [
            ["ACE Inhibitor / ARB", "Ramipril; Valsartan", "↓ RAAS → ↓ afterload + ↓ LV remodelling", "↓ mortality ~20%", "1st line; monitor K⁺ + creatinine"],
            ["β-Blocker", "Carvedilol, Bisoprolol, Metoprolol succinate", "Counteract SNS; ↓ HR; ↓ LV remodelling", "↓ mortality ~30%", "Start low, go slow; do NOT use in decompensated HF"],
            ["MRA (Aldosterone antagonist)", "Spironolactone, Eplerenone", "↓ cardiac fibrosis + aldosterone effects", "↓ mortality 30% (RALES trial)", "EF < 35%; K⁺ < 5.0; eGFR > 30"],
            ["ARNI", "Sacubitril/Valsartan (Entresto)", "Neprilysin inhibition (↑ BNP) + ARB", "↓ mortality vs enalapril (PARADIGM-HF)", "Replace ACE-I/ARB; 36h washout from ACE-I"],
            ["SGLT2 Inhibitor", "Dapagliflozin, Empagliflozin", "Glucosuria; ↓ preload + afterload; cardioprotective", "↓ CV death/HF hospitalisation (DAPA-HF, EMPEROR-Reduced)", "Benefit regardless of diabetes status"],
            ["Ivabradine", "Ivabradine", "If channel block → ↓ HR only", "↓ HF hospitalisation (SHIFT trial)", "Use if HR ≥ 75 on max tolerated β-blocker, sinus rhythm only"],
        ], s
    ))
    spacer(4)
    tip("4 pillars of HFrEF therapy: ACE-I/ARB/ARNI + BB + MRA + SGLT2i. Each independently reduces mortality. ARNI replaces ACE-I/ARB. Target resting HR < 70 bpm with β-blocker + ivabradine if needed.")
    spacer(6)

    h("4.4  Lipid-Lowering Therapy", 1)
    story.append(two_col_table(
        ["Class", "Drugs", "Mechanism", "LDL Reduction", "Key Notes"],
        [
            ["Statins", "Atorvastatin, Rosuvastatin, Simvastatin", "HMG-CoA reductase inhibition → ↓ hepatic cholesterol synthesis → ↑ LDL receptors", "30–55%", "1st line; myopathy/rhabdomyolysis (esp. simvastatin 80 mg); check CK if muscle pain"],
            ["Ezetimibe", "Ezetimibe", "Blocks NPC1L1 → ↓ intestinal cholesterol absorption", "+15–25% on top of statin", "Used with statin in high-risk; IMPROVE-IT trial"],
            ["PCSK9 Inhibitors", "Evolocumab, Alirocumab", "Monoclonal Ab against PCSK9 → ↑ LDL receptor recycling", "+45–65% on top of statin", "Familial hypercholesterolaemia; very high risk; injectable (biweekly/monthly)"],
            ["Fibrates", "Fenofibrate, Gemfibrozil", "PPARα activation → ↑ lipoprotein lipase → ↓ TG", "TG ↓↓; modest HDL↑", "Hypertriglyceridaemia; avoid with statins (↑ myopathy risk — esp. gemfibrozil)"],
        ], s
    ))
    spacer(4)
    box("LDL-C Targets (ESC 2021)", [
        "Very high risk (ACS, established CVD, DM with end-organ damage): LDL < 1.4 mmol/L AND ≥50% reduction",
        "High risk (markedly elevated risk factors, DM, moderate CKD): LDL < 1.8 mmol/L AND ≥50% reduction",
        "Moderate risk: LDL < 2.6 mmol/L",
        "Low risk: LDL < 3.0 mmol/L",
    ])
    rule()
    spacer(6)

    h("4.5  Antiplatelet & Anticoagulant Therapy", 1)
    h("Antiplatelets", 2)
    b("<b>Aspirin</b>: Irreversible COX-1 inhibition → ↓ TXA₂ → ↓ platelet aggregation. Dose: 75–100 mg daily")
    b("<b>Clopidogrel/Ticagrelor/Prasugrel</b>: P2Y12 receptor blockers → ↓ ADP-mediated platelet activation")
    b("DAPT (Aspirin + P2Y12 blocker): 12 months after ACS; minimum 1–6 months after stent (depending on stent type and bleeding risk)")
    spacer(4)
    h("Anticoagulants", 2)
    story.append(two_col_table(
        ["Drug", "Class", "Mechanism", "Use", "Reversal Agent"],
        [
            ["Warfarin", "VKA", "Inhibits Vit K-dependent factors (II, VII, IX, X, Protein C & S)", "AF (valvular), mechanical prosthetic valves, DVT/PE", "Vit K (slow); 4-factor PCC or FFP (rapid)"],
            ["Heparin (UFH)", "Anticoagulant", "Activates antithrombin → inhibits IIa + Xa", "ACS (acute), bridging, PE/DVT", "Protamine sulphate"],
            ["LMWH", "Anticoagulant", "Activates antithrombin → mainly anti-Xa", "DVT/PE treatment & prophylaxis, ACS, pregnancy (safe)", "Protamine (partial)"],
            ["Dabigatran", "DOAC (Direct thrombin inhibitor)", "Direct IIa inhibition", "AF, VTE treatment/prevention", "Idarucizumab (Praxbind)"],
            ["Rivaroxaban/Apixaban", "DOAC (Factor Xa inhibitor)", "Direct Xa inhibition", "AF, VTE, post-ACS (rivaroxaban)", "Andexanet alfa"],
        ], s
    ))
    rule()
    spacer(6)

    # ══════════════════════════════════════════════════════════════════════════
    # SECTION 5 — HIGH-YIELD SUMMARY
    # ══════════════════════════════════════════════════════════════════════════
    story.append(HR(width="100%", thickness=2.5, color=HEADING1))
    story.append(Paragraph("SECTION 5: HIGH-YIELD SUMMARY & MNEMONICS", s['chapter_title']))
    story.append(HR(width="100%", thickness=1, color=RULE_COLOR))
    spacer(8)

    h("5.1  Must-Know Normal Values", 1)
    story.append(two_col_table(
        ["Parameter", "Normal Value"],
        [
            ["Heart Rate", "60–100 bpm"],
            ["Cardiac Output (CO)", "4–8 L/min"],
            ["Cardiac Index (CI)", "2.2–4.0 L/min/m²"],
            ["Ejection Fraction (EF)", "55–70%"],
            ["LV systolic pressure", "~120 mmHg"],
            ["LV end-diastolic pressure (LVEDP)", "6–12 mmHg"],
            ["PCWP (pulmonary capillary wedge pressure)", "6–12 mmHg (>18 → pulmonary oedema)"],
            ["Aortic pressure", "120/80 mmHg"],
            ["PA pressure", "25/10 mmHg (mean <25)"],
            ["RV pressure", "25/5 mmHg"],
            ["SVR (systemic vascular resistance)", "800–1200 dyn·s·cm⁻⁵"],
            ["PVR (pulmonary vascular resistance)", "60–120 dyn·s·cm⁻⁵"],
        ], s
    ))
    spacer(6)

    h("5.2  Key ECG Findings", 1)
    story.append(two_col_table(
        ["ECG Finding", "Diagnosis"],
        [
            ["Delta wave (slurred upstroke) + short PR", "Wolff-Parkinson-White (WPW)"],
            ["Epsilon wave + T-wave inversions V1–V3", "Arrhythmogenic RV cardiomyopathy (ARVC)"],
            ["J-waves (Osborn waves)", "Hypothermia"],
            ["Diffuse ST elevation + PR depression", "Acute pericarditis"],
            ["ST elevation in aVR + diffuse ST depression", "Left main / proximal LAD occlusion"],
            ["Saddle-shaped ST elevation + no reciprocal changes", "Pericarditis (vs STEMI)"],
            ["Long QTc (>440 ms ♂, >460 ms ♀)", "Long QT syndrome → Torsades de Pointes risk"],
            ["Alternating QRS height (electrical alternans)", "Cardiac tamponade"],
            ["p-pulmonale (peaked P > 2.5 mm in II)", "Right atrial enlargement (cor pulmonale)"],
            ["p-mitrale (broad notched P in II)", "Left atrial enlargement (mitral stenosis)"],
        ], s
    ))
    spacer(6)

    h("5.3  Top Mnemonics", 1)
    mnemonic("HF drugs that ↑ survival in HFrEF — 'ABMS'",
             "A — ACE Inhibitor (or ARNI)\nB — Beta-blocker\nM — MRA (Mineralocorticoid receptor antagonist)\nS — SGLT2 inhibitor")
    mnemonic("Causes of AF — PIRATES",
             "P — Pulmonary disease (PE, COPD)\nI — Ischaemia (MI, IHD)\nR — Rheumatic heart disease (Mitral stenosis)\nA — Anaemia / Alcohol\nT — Thyrotoxicosis\nE — Electrolyte disturbance (↓K⁺, ↓Mg²⁺)\nS — Sepsis / Surgery (post-cardiac)")
    mnemonic("Signs of Aortic Regurgitation — 3 W's + Corrigan",
             "W — Wide pulse pressure\nW — Watson's water-hammer pulse (Corrigan's pulse)\nW — Head bobbing (de Musset's sign)\nAustin Flint murmur = relative MS at the mitral valve from AR jet")
    mnemonic("STEMI territories",
             "V1–V4 → Anterior (LAD)\nI, aVL, V5–V6 → Lateral (LCx)\nII, III, aVF → Inferior (RCA)\nV7–V9 → Posterior (LCx/RCA)\nV3R, V4R → Right ventricular (RCA)")
    mnemonic("Causes of LVH on ECG (Sokolov-Lyon criteria)",
             "S in V1 + R in V5 or V6 > 35 mm → LVH\nCauses: HTN (most common), HCM, aortic stenosis, athlete's heart")
    spacer(6)

    h("5.4  Final Exam-Critical Points", 1)
    imp("1. Most common cause of SCD in young athletes: HCM")
    imp("2. Most common arrhythmia: AF")
    imp("3. Most common valvular lesion in developed world: Aortic stenosis (age-related calcification)")
    imp("4. Most common valvular lesion in developing world: Mitral stenosis (rheumatic fever)")
    imp("5. SA node blood supply: RCA in 60%, LCx in 40%")
    imp("6. AV node blood supply: RCA in 85–90%")
    imp("7. Atrial kick lost in AF → up to 25% reduction in CO")
    imp("8. LMCA occlusion = 'widow maker'; often fatal without immediate PCI")
    imp("9. Hypertensive emergency: Reduce MAP by ≤25% in 1st hour only")
    imp("10. Pulseless VT/VF → Defibrillation immediately + CPR; do NOT give adenosine")
    imp("11. Mobitz II → Immediate pacemaker referral (risk of sudden complete AV block)")
    imp("12. DOACs preferred over warfarin in non-valvular AF (lower intracranial bleeding risk)")
    spacer(6)

    story.append(HR(width="100%", thickness=2, color=HEADING1))
    story.append(Paragraph(
        "END OF NOTES — Cardiovascular System | MBBS/MD Level",
        ParagraphStyle('end', fontName="Helvetica-Bold", fontSize=11,
                       textColor=HEADING1, alignment=TA_CENTER, leading=18)
    ))
    story.append(Paragraph(
        "Compiled from: Braunwald's Heart Disease | Robbins & Kumar Basic Pathology | ROSEN's Emergency Medicine | Goldman-Cecil Medicine",
        ParagraphStyle('end2', fontName="Helvetica-Oblique", fontSize=8,
                       textColor=HexColor("#78909C"), alignment=TA_CENTER, leading=14)
    ))

    return story


# ── MAIN ─────────────────────────────────────────────────────────────────────
def main():
    pt = PageTemplate(section_name="CVS Notes")

    doc = SimpleDocTemplate(
        OUTPUT,
        pagesize=A4,
        leftMargin=50, rightMargin=25,
        topMargin=30, bottomMargin=25,
        title="Cardiovascular System — MBBS/MD Handwritten Notes",
        author="Orris Medical",
        subject="Cardiovascular System",
    )

    styles = make_styles()
    story = build_content(styles)

    doc.build(story, onFirstPage=pt, onLaterPages=pt)
    print(f"PDF generated: {OUTPUT}")


if __name__ == "__main__":
    main()
Running Command

cd /tmp/workspace/cvs-notes && python generate_cvs_notes.py

Running Command

ls -lh /tmp/workspace/cvs-notes/CVS_Handwritten_Notes_MBBS.pdf

Your handwritten-style CVS notes PDF is ready! Here's your download link:

CVS Handwritten Notes MBBS

PDF Document · PDF


What's Inside the Notes

The PDF is designed with a cream ruled-paper background, navy/blue ink headings, coloured info boxes, yellow highlights, and mnemonic boxes — mimicking the feel of real handwritten notes.

5 Full Sections:

SectionTopics Covered
1 — AnatomyHeart position, chambers (RA/RV/LA/LV), layers, 4 valves, coronary circulation (LAD/LCx/RCA), conduction system
2 — PhysiologyCardiac output formula, Frank-Starling, cardiac cycle (all 7 phases), heart sounds (S1–S4), action potential (ventricular vs. SA node)
3 — PathologyIHD/ACS (UA/NSTEMI/STEMI), Heart failure (HFrEF vs HFpEF), Hypertensive heart disease, Valvular disease (AS/AR/MS/MR), Cardiomyopathies (DCM/HCM/RCM/ARVC), Arrhythmias (AF, VT, AV blocks)
4 — PharmacologyAntihypertensives (ACE-I, ARB, BB, CCB, diuretics), Antiarrhythmics (Vaughan Williams I–IV), HF drugs (4 pillars + ARNI + ivabradine), Lipid therapy, Antiplatelets/Anticoagulants
5 — High-Yield SummaryNormal values table, ECG findings, 6 key mnemonics (PIRATES, CHA₂DS₂-VASc, ABMS, etc.), 12 exam-critical points
Sources: Braunwald's Heart Disease, Robbins & Kumar Basic Pathology, ROSEN's Emergency Medicine, Goldman-Cecil Medicine.
This is a shared conversation. Sign in to Orris to start your own chat.