Hypertension case proforma general medicine

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

ls -la /home/daytona/workspace/ 2>/dev/null || echo "workspace empty or missing"

Writing File

~/hypertension-proforma/generate_proforma.py

#!/usr/bin/env python3
"""
Hypertension Case Proforma - General Medicine (MBBS Level)
Generates a comprehensive PDF case proforma using ReportLab.
"""

from reportlab.lib.pagesizes import A4
from reportlab.lib import colors
from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
from reportlab.lib.units import cm, mm
from reportlab.platypus import (
    SimpleDocTemplate, Paragraph, Spacer, Table, TableStyle,
    HRFlowable, KeepTogether
)
from reportlab.lib.enums import TA_CENTER, TA_LEFT, TA_RIGHT
from reportlab.pdfgen import canvas

OUTPUT_PATH = "/home/daytona/workspace/hypertension-proforma/Hypertension_Case_Proforma.pdf"

W, H = A4  # 595.28 x 841.89 points

# ── Colour palette ──────────────────────────────────────────────────────────
DARK_BLUE   = colors.HexColor("#1A3A5C")
MED_BLUE    = colors.HexColor("#2E6DA4")
LIGHT_BLUE  = colors.HexColor("#D6E4F0")
ACCENT      = colors.HexColor("#C0392B")
GREY_BG     = colors.HexColor("#F2F4F6")
LINE_GREY   = colors.HexColor("#BDC3C7")
WHITE       = colors.white
BLACK       = colors.black

# ── Helper: dotted answer line ───────────────────────────────────────────────
def line(n=1, width="100%"):
    """Return a series of underline tables acting as blank fill lines."""
    rows = []
    for _ in range(n):
        t = Table([["_" * 90]], colWidths=["100%"])
        t.setStyle(TableStyle([
            ("TEXTCOLOR", (0, 0), (-1, -1), LINE_GREY),
            ("FONTSIZE",  (0, 0), (-1, -1), 7),
            ("TOPPADDING",  (0, 0), (-1, -1), 0),
            ("BOTTOMPADDING", (0, 0), (-1, -1), 2),
            ("LEFTPADDING",  (0, 0), (-1, -1), 0),
        ]))
        rows.append(t)
        rows.append(Spacer(1, 1*mm))
    return rows

def field_row(label, n_lines=1, label_width=5*cm):
    """Label + dotted line(s) as a two-column table."""
    line_str = "_" * 70
    lines_text = ("<br/>".join([line_str] * n_lines))
    data = [[label, lines_text]]
    t = Table(data, colWidths=[label_width, None])
    t.setStyle(TableStyle([
        ("VALIGN", (0, 0), (-1, -1), "BOTTOM"),
        ("FONTSIZE", (0, 0), (-1, -1), 9),
        ("TEXTCOLOR", (0, 0), (0, -1), DARK_BLUE),
        ("TEXTCOLOR", (1, 0), (1, -1), LINE_GREY),
        ("BOTTOMPADDING", (0, 0), (-1, -1), 2),
        ("TOPPADDING",    (0, 0), (-1, -1), 4),
        ("LEFTPADDING",   (0, 0), (-1, -1), 0),
    ]))
    return t


# ── Page template with header/footer ────────────────────────────────────────
class HeaderFooterCanvas(canvas.Canvas):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self._saved_page_states = []

    def showPage(self):
        self._saved_page_states.append(dict(self.__dict__))
        self._startPage()

    def save(self):
        page_count = len(self._saved_page_states)
        for state in self._saved_page_states:
            self.__dict__.update(state)
            self.draw_page(page_count)
            canvas.Canvas.showPage(self)
        canvas.Canvas.save(self)

    def draw_page(self, page_count):
        self.saveState()
        pg = self._pageNumber
        # Header bar
        self.setFillColor(DARK_BLUE)
        self.rect(0, H - 1.2*cm, W, 1.2*cm, fill=1, stroke=0)
        self.setFillColor(WHITE)
        self.setFont("Helvetica-Bold", 11)
        self.drawString(1.5*cm, H - 0.85*cm, "HYPERTENSION CASE PROFORMA")
        self.setFont("Helvetica", 8)
        self.drawRightString(W - 1.5*cm, H - 0.85*cm, "General Medicine | MBBS")
        # Footer
        self.setFillColor(DARK_BLUE)
        self.rect(0, 0, W, 0.8*cm, fill=1, stroke=0)
        self.setFillColor(WHITE)
        self.setFont("Helvetica", 7.5)
        self.drawString(1.5*cm, 0.28*cm, "Department of General Medicine")
        self.drawCentredString(W/2, 0.28*cm, "CONFIDENTIAL - For Academic Use Only")
        self.drawRightString(W - 1.5*cm, 0.28*cm, f"Page {pg} of {page_count}")
        self.restoreState()


# ── Style helpers ────────────────────────────────────────────────────────────
styles = getSampleStyleSheet()

def S(name, **kw):
    base = styles["Normal"]
    return ParagraphStyle(name, parent=base, **kw)

TITLE   = S("TITLE",  fontSize=15, textColor=DARK_BLUE, fontName="Helvetica-Bold",
             spaceAfter=2, alignment=TA_CENTER)
SEC     = S("SEC",    fontSize=10.5, textColor=WHITE,  fontName="Helvetica-Bold",
             spaceAfter=2, leading=14)
SUBSEC  = S("SUBSEC", fontSize=9.5,  textColor=DARK_BLUE, fontName="Helvetica-Bold",
             spaceBefore=4, spaceAfter=2)
BODY    = S("BODY",   fontSize=9,    textColor=BLACK, leading=13)
SMALL   = S("SMALL",  fontSize=8,    textColor=colors.HexColor("#555555"), leading=11)
NOTE    = S("NOTE",   fontSize=8,    textColor=ACCENT, fontName="Helvetica-Oblique")
LABEL   = S("LABEL",  fontSize=9,    textColor=DARK_BLUE, fontName="Helvetica-Bold")


def section_header(text):
    """Blue banner heading."""
    data = [[Paragraph(text, SEC)]]
    t = Table(data, colWidths=[W - 3*cm])
    t.setStyle(TableStyle([
        ("BACKGROUND",    (0, 0), (-1, -1), MED_BLUE),
        ("TOPPADDING",    (0, 0), (-1, -1), 5),
        ("BOTTOMPADDING", (0, 0), (-1, -1), 5),
        ("LEFTPADDING",   (0, 0), (-1, -1), 8),
        ("ROUNDEDCORNERS", [3]),
    ]))
    return KeepTogether([Spacer(1, 4*mm), t, Spacer(1, 2*mm)])


def checkbox_row(items, cols=4):
    """Row of checkbox items."""
    padded = items + [""] * (cols - len(items) % cols if len(items) % cols else 0)
    rows = []
    for i in range(0, len(padded), cols):
        chunk = padded[i:i+cols]
        row_data = [["☐  " + c if c else ""] for c in chunk]
        flat = [["☐  " + c if c else "" for c in chunk]]
        rows.append(flat[0])
    t = Table(rows, colWidths=[(W - 3*cm) / cols] * cols)
    t.setStyle(TableStyle([
        ("FONTSIZE",      (0, 0), (-1, -1), 9),
        ("TEXTCOLOR",     (0, 0), (-1, -1), BLACK),
        ("TOPPADDING",    (0, 0), (-1, -1), 3),
        ("BOTTOMPADDING", (0, 0), (-1, -1), 3),
        ("LEFTPADDING",   (0, 0), (-1, -1), 4),
    ]))
    return t


def two_col_checklist(left_items, right_items, header_left="", header_right=""):
    """Two-column checklist table."""
    max_len = max(len(left_items), len(right_items))
    left_items  = left_items  + [""] * (max_len - len(left_items))
    right_items = right_items + [""] * (max_len - len(right_items))
    data = []
    if header_left or header_right:
        data.append([
            Paragraph(header_left, SUBSEC),
            Paragraph(header_right, SUBSEC)
        ])
    for l, r in zip(left_items, right_items):
        data.append([
            ("☐  " + l) if l else "",
            ("☐  " + r) if r else ""
        ])
    half = (W - 3*cm) / 2
    t = Table(data, colWidths=[half, half])
    t.setStyle(TableStyle([
        ("FONTSIZE",      (0, 0), (-1, -1), 9),
        ("TOPPADDING",    (0, 0), (-1, -1), 3),
        ("BOTTOMPADDING", (0, 0), (-1, -1), 3),
        ("LEFTPADDING",   (0, 0), (-1, -1), 4),
        ("LINEAFTER",     (0, 0), (0, -1), 0.5, LINE_GREY),
        ("FONTNAME",      (0, 0), (-1, 0), "Helvetica-Bold") if (header_left or header_right) else ("FONTSIZE", (0,0), (-1,-1), 9),
    ]))
    return t


def bp_table():
    """JNC 8 / ACC/AHA 2017 BP classification table."""
    headers = ["Category", "Systolic (mmHg)", "", "Diastolic (mmHg)"]
    data = [
        headers,
        ["Normal",              "< 120",       "AND", "< 80"],
        ["Elevated",            "120-129",     "AND", "< 80"],
        ["Stage 1 HTN",         "130-139",     "OR",  "80-89"],
        ["Stage 2 HTN",         "≥ 140",       "OR",  "≥ 90"],
        ["Hypertensive Crisis", "≥ 180",       "AND/OR", "≥ 120"],
    ]
    col_w = [(W - 3*cm) * f for f in [0.35, 0.25, 0.1, 0.30]]
    t = Table(data, colWidths=col_w)
    t.setStyle(TableStyle([
        ("BACKGROUND",    (0, 0), (-1, 0), DARK_BLUE),
        ("TEXTCOLOR",     (0, 0), (-1, 0), WHITE),
        ("FONTNAME",      (0, 0), (-1, 0), "Helvetica-Bold"),
        ("FONTSIZE",      (0, 0), (-1, -1), 8.5),
        ("ROWBACKGROUNDS",(0, 1), (-1, -1), [WHITE, GREY_BG]),
        ("GRID",          (0, 0), (-1, -1), 0.4, LINE_GREY),
        ("TOPPADDING",    (0, 0), (-1, -1), 4),
        ("BOTTOMPADDING", (0, 0), (-1, -1), 4),
        ("LEFTPADDING",   (0, 0), (-1, -1), 6),
        ("ALIGN",         (1, 0), (-1, -1), "CENTER"),
        ("VALIGN",        (0, 0), (-1, -1), "MIDDLE"),
        # Highlight hypertensive crisis row
        ("BACKGROUND",    (0, 5), (-1, 5), colors.HexColor("#FDECEA")),
        ("TEXTCOLOR",     (0, 5), (-1, 5), ACCENT),
        ("FONTNAME",      (0, 5), (-1, 5), "Helvetica-Bold"),
    ]))
    return t


# ── BUILD DOCUMENT ───────────────────────────────────────────────────────────
def build():
    doc = SimpleDocTemplate(
        OUTPUT_PATH,
        pagesize=A4,
        leftMargin=1.5*cm, rightMargin=1.5*cm,
        topMargin=1.6*cm,  bottomMargin=1.2*cm,
        title="Hypertension Case Proforma",
        author="Department of General Medicine",
    )

    story = []

    # ── TITLE BLOCK ──────────────────────────────────────────────────────────
    story.append(Spacer(1, 4*mm))
    title_data = [[
        Paragraph("HYPERTENSION", S("t1", fontSize=18, fontName="Helvetica-Bold",
                                    textColor=DARK_BLUE, alignment=TA_CENTER)),
    ],[
        Paragraph("CASE PROFORMA — General Medicine (MBBS)", S("t2", fontSize=11,
                  fontName="Helvetica", textColor=MED_BLUE, alignment=TA_CENTER)),
    ]]
    tb = Table(title_data, colWidths=[W - 3*cm])
    tb.setStyle(TableStyle([
        ("BACKGROUND",    (0, 0), (-1, -1), LIGHT_BLUE),
        ("TOPPADDING",    (0, 0), (-1, -1), 8),
        ("BOTTOMPADDING", (0, 0), (-1, -1), 8),
        ("ROUNDEDCORNERS", [4]),
    ]))
    story.append(tb)
    story.append(Spacer(1, 6*mm))

    # ── SECTION 1: PATIENT PARTICULARS ──────────────────────────────────────
    story.append(section_header("SECTION 1 : PATIENT PARTICULARS"))

    demo_data = [
        ["Name:", "_" * 35, "IP/OP No.:", "_" * 15],
        ["Age:", "_" * 12, "Sex:", "☐ Male   ☐ Female   ☐ Other"],
        ["Date of Admission:", "_" * 18, "Date of Examination:", "_" * 18],
        ["Ward / Bed No.:", "_" * 18, "Unit:", "_" * 18],
        ["Occupation:", "_" * 22, "Socioeconomic Status:", "☐ Upper  ☐ Middle  ☐ Lower"],
        ["Address:", "_" * 35, "Religion:", "_" * 15],
        ["Informant:", "_" * 22, "Reliability:", "☐ Good  ☐ Fair  ☐ Poor"],
    ]
    cw = [(W-3*cm)*f for f in [0.14, 0.36, 0.18, 0.32]]
    dt = Table(demo_data, colWidths=cw)
    dt.setStyle(TableStyle([
        ("FONTSIZE",      (0, 0), (-1, -1), 9),
        ("FONTNAME",      (0, 0), (0, -1), "Helvetica-Bold"),
        ("FONTNAME",      (0, 0), (2, -1), "Helvetica-Bold"),
        ("TEXTCOLOR",     (0, 0), (0, -1), DARK_BLUE),
        ("TEXTCOLOR",     (2, 0), (2, -1), DARK_BLUE),
        ("TEXTCOLOR",     (1, 0), (1, -1), LINE_GREY),
        ("TOPPADDING",    (0, 0), (-1, -1), 5),
        ("BOTTOMPADDING", (0, 0), (-1, -1), 5),
        ("LEFTPADDING",   (0, 0), (-1, -1), 3),
        ("BACKGROUND",    (0, 0), (-1, -1), GREY_BG),
        ("ROWBACKGROUNDS",(0, 0), (-1, -1), [WHITE, GREY_BG]),
    ]))
    story.append(dt)
    story.append(Spacer(1, 4*mm))

    # ── SECTION 2: CHIEF COMPLAINTS ─────────────────────────────────────────
    story.append(section_header("SECTION 2 : CHIEF COMPLAINTS"))
    story.append(Paragraph(
        "List complaints in chronological order with duration:", SMALL))
    story.append(Spacer(1, 2*mm))

    cc_data = [["No.", "Complaint", "Duration"]]
    for i in range(1, 7):
        cc_data.append([str(i), "_" * 45, "_" * 15])
    cct = Table(cc_data, colWidths=[(W-3*cm)*f for f in [0.07, 0.72, 0.21]])
    cct.setStyle(TableStyle([
        ("BACKGROUND",    (0, 0), (-1, 0), DARK_BLUE),
        ("TEXTCOLOR",     (0, 0), (-1, 0), WHITE),
        ("FONTNAME",      (0, 0), (-1, 0), "Helvetica-Bold"),
        ("FONTSIZE",      (0, 0), (-1, -1), 9),
        ("ROWBACKGROUNDS",(0, 1), (-1, -1), [WHITE, GREY_BG]),
        ("GRID",          (0, 0), (-1, -1), 0.4, LINE_GREY),
        ("TOPPADDING",    (0, 0), (-1, -1), 5),
        ("BOTTOMPADDING", (0, 0), (-1, -1), 5),
        ("LEFTPADDING",   (0, 0), (-1, -1), 6),
        ("ALIGN",         (0, 0), (0, -1), "CENTER"),
        ("TEXTCOLOR",     (1, 1), (1, -1), LINE_GREY),
        ("TEXTCOLOR",     (2, 1), (2, -1), LINE_GREY),
    ]))
    story.append(cct)
    story.append(Spacer(1, 4*mm))

    # ── SECTION 3: HISTORY OF PRESENT ILLNESS ───────────────────────────────
    story.append(section_header("SECTION 3 : HISTORY OF PRESENT ILLNESS"))

    story.append(Paragraph(
        "<b>A. Onset of Hypertension</b>", SUBSEC))
    hpi1 = [
        ["Age at diagnosis:", "_" * 20, "Known HTN since:", "_" * 18],
        ["Incidental finding (asymptomatic):", "☐ Yes  ☐ No",
         "Symptomatic at diagnosis:", "☐ Yes  ☐ No"],
    ]
    cw4 = [(W-3*cm)*f for f in [0.22, 0.28, 0.22, 0.28]]
    t1 = Table(hpi1, colWidths=cw4)
    t1.setStyle(TableStyle([
        ("FONTSIZE",  (0,0),(-1,-1), 9),
        ("FONTNAME",  (0,0),(0,-1), "Helvetica-Bold"),
        ("FONTNAME",  (2,0),(2,-1), "Helvetica-Bold"),
        ("TEXTCOLOR", (0,0),(0,-1), DARK_BLUE),
        ("TEXTCOLOR", (2,0),(2,-1), DARK_BLUE),
        ("TEXTCOLOR", (1,0),(1,-1), LINE_GREY),
        ("TOPPADDING",(0,0),(-1,-1), 5),
        ("BOTTOMPADDING",(0,0),(-1,-1), 5),
        ("ROWBACKGROUNDS",(0,0),(-1,-1),[WHITE, GREY_BG]),
    ]))
    story.append(t1)
    story.append(Spacer(1, 3*mm))

    story.append(Paragraph("<b>B. Current Symptoms - Tick all that apply</b>", SUBSEC))
    sym_data = [
        ["Headache (occipital)", "Blurred vision / Visual disturbance",
         "Chest pain / Angina", "Palpitations"],
        ["Breathlessness (grade:", "Dizziness / Giddiness",
         "Epistaxis", "Facial flushing"],
        ["Nocturia / Polyuria", "Leg swelling / Oedema",
         "Weakness / Fatigue", "Tinnitus"],
        ["Haematuria", "Decreased urine output", "Claudication (leg pain on walking)",
         "Facial / limb numbness"],
        ["Seizures", "Altered consciousness", "Neck stiffness", "Vomiting"],
    ]
    sym_flat = [item for row in sym_data for item in row]
    story.append(checkbox_row(sym_flat, cols=4))
    story.append(Spacer(1, 2*mm))
    story.append(field_row("Duration of current episode:", 1))
    story.append(Spacer(1, 2*mm))
    story.append(Paragraph("<b>Additional details of presenting complaint:</b>", SUBSEC))
    for _ in range(3):
        story.append(field_row("", 1, label_width=0.5*cm))
    story.append(Spacer(1, 4*mm))

    story.append(Paragraph("<b>C. Drug History (current antihypertensives)</b>", SUBSEC))
    drug_data = [["Drug Name", "Dose", "Frequency", "Duration", "Compliance"]]
    for _ in range(5):
        drug_data.append(["_"*20, "_"*10, "_"*12, "_"*10, "☐ Regular  ☐ Irregular"])
    cwd = [(W-3*cm)*f for f in [0.27, 0.13, 0.17, 0.13, 0.30]]
    dt2 = Table(drug_data, colWidths=cwd)
    dt2.setStyle(TableStyle([
        ("BACKGROUND",    (0,0),(-1,0), DARK_BLUE),
        ("TEXTCOLOR",     (0,0),(-1,0), WHITE),
        ("FONTNAME",      (0,0),(-1,0), "Helvetica-Bold"),
        ("FONTSIZE",      (0,0),(-1,-1), 8.5),
        ("ROWBACKGROUNDS",(0,1),(-1,-1), [WHITE, GREY_BG]),
        ("GRID",          (0,0),(-1,-1), 0.4, LINE_GREY),
        ("TOPPADDING",    (0,0),(-1,-1), 5),
        ("BOTTOMPADDING", (0,0),(-1,-1), 5),
        ("LEFTPADDING",   (0,0),(-1,-1), 5),
        ("TEXTCOLOR",     (0,1),(-1,-1), LINE_GREY),
    ]))
    story.append(dt2)
    story.append(Spacer(1, 2*mm))
    story.append(field_row("Other medications (NSAIDs / OCP / steroids / decongestants):", 1, label_width=9*cm))
    story.append(Spacer(1, 4*mm))

    # ── SECTION 4: PAST HISTORY ──────────────────────────────────────────────
    story.append(section_header("SECTION 4 : PAST HISTORY"))

    past_items_l = [
        "Diabetes Mellitus       Type: _____  Since: ___",
        "Coronary Artery Disease  Since: ______",
        "Previous MI / Stent / CABG",
        "Stroke / TIA  When: ____________",
        "CKD / Renal Disease  Stage: _____",
        "Hyperlipidaemia",
        "Thyroid Disorder",
        "Sleep Apnoea",
    ]
    past_items_r = [
        "Peripheral Arterial Disease",
        "Atrial Fibrillation",
        "Heart Failure  (HFrEF / HFpEF)",
        "Aortic Aneurysm",
        "Pheochromocytoma / Conn's",
        "Previous surgery",
        "Hospitalisation (reason): ________",
        "Retinopathy Grade: ___________",
    ]
    story.append(two_col_checklist(past_items_l, past_items_r,
                                   "Cardiovascular / Metabolic", "Other Comorbidities"))
    story.append(Spacer(1, 4*mm))

    # ── SECTION 5: FAMILY HISTORY ────────────────────────────────────────────
    story.append(section_header("SECTION 5 : FAMILY HISTORY"))
    fam = [
        ["Condition", "Father", "Mother", "Sibling(s)", "Maternal Grand", "Paternal Grand"],
        ["Hypertension",     "☐ Yes  ☐ No", "☐ Yes  ☐ No", "☐ Yes  ☐ No", "☐ Yes  ☐ No", "☐ Yes  ☐ No"],
        ["Diabetes Mellitus","☐ Yes  ☐ No", "☐ Yes  ☐ No", "☐ Yes  ☐ No", "☐ Yes  ☐ No", "☐ Yes  ☐ No"],
        ["Heart Disease",    "☐ Yes  ☐ No", "☐ Yes  ☐ No", "☐ Yes  ☐ No", "☐ Yes  ☐ No", "☐ Yes  ☐ No"],
        ["Stroke / CVA",     "☐ Yes  ☐ No", "☐ Yes  ☐ No", "☐ Yes  ☐ No", "☐ Yes  ☐ No", "☐ Yes  ☐ No"],
        ["Renal Disease",    "☐ Yes  ☐ No", "☐ Yes  ☐ No", "☐ Yes  ☐ No", "☐ Yes  ☐ No", "☐ Yes  ☐ No"],
    ]
    cwf = [(W-3*cm)*f for f in [0.22, 0.155, 0.155, 0.155, 0.155, 0.16]]
    ft = Table(fam, colWidths=cwf)
    ft.setStyle(TableStyle([
        ("BACKGROUND",    (0,0),(-1,0), DARK_BLUE),
        ("TEXTCOLOR",     (0,0),(-1,0), WHITE),
        ("FONTNAME",      (0,0),(-1,0), "Helvetica-Bold"),
        ("FONTSIZE",      (0,0),(-1,-1), 8.5),
        ("ROWBACKGROUNDS",(0,1),(-1,-1), [WHITE, GREY_BG]),
        ("GRID",          (0,0),(-1,-1), 0.4, LINE_GREY),
        ("TOPPADDING",    (0,0),(-1,-1), 4),
        ("BOTTOMPADDING", (0,0),(-1,-1), 4),
        ("LEFTPADDING",   (0,0),(-1,-1), 5),
        ("ALIGN",         (1,0),(-1,-1), "CENTER"),
    ]))
    story.append(ft)
    story.append(Spacer(1, 2*mm))
    story.append(field_row("Family history of early CVD (men <55 y, women <65 y):", 1, label_width=9*cm))
    story.append(Spacer(1, 4*mm))

    # ── SECTION 6: PERSONAL / SOCIAL HISTORY ────────────────────────────────
    story.append(section_header("SECTION 6 : PERSONAL / SOCIAL HISTORY"))

    social_data = [
        ["Smoking:", "☐ Never   ☐ Current   ☐ Ex-smoker",
         "Pack-years:", "_________"],
        ["Alcohol:", "☐ Never   ☐ Occasional   ☐ Regular   ☐ Binge",
         "Units/week:", "_________"],
        ["Tobacco (chewing):", "☐ Never   ☐ Current   ☐ Former",
         "Duration:", "_________"],
        ["Diet:", "☐ Vegetarian   ☐ Non-vegetarian",
         "Salt intake:", "☐ High  ☐ Normal  ☐ Restricted"],
        ["Physical activity:", "☐ Sedentary   ☐ Moderate   ☐ Active",
         "BMI category:", "☐ Normal  ☐ Overweight  ☐ Obese"],
        ["Stress level:", "☐ Low   ☐ Moderate   ☐ High",
         "Sleep (hrs/night):", "_________"],
    ]
    soc_t = Table(social_data, colWidths=[(W-3*cm)*f for f in [0.18, 0.40, 0.14, 0.28]])
    soc_t.setStyle(TableStyle([
        ("FONTSIZE",      (0,0),(-1,-1), 9),
        ("FONTNAME",      (0,0),(0,-1), "Helvetica-Bold"),
        ("FONTNAME",      (2,0),(2,-1), "Helvetica-Bold"),
        ("TEXTCOLOR",     (0,0),(0,-1), DARK_BLUE),
        ("TEXTCOLOR",     (2,0),(2,-1), DARK_BLUE),
        ("TOPPADDING",    (0,0),(-1,-1), 5),
        ("BOTTOMPADDING", (0,0),(-1,-1), 5),
        ("ROWBACKGROUNDS",(0,0),(-1,-1), [WHITE, GREY_BG]),
        ("GRID",          (0,0),(-1,-1), 0.3, LINE_GREY),
        ("LEFTPADDING",   (0,0),(-1,-1), 5),
    ]))
    story.append(soc_t)
    story.append(Spacer(1, 4*mm))

    # ── SECTION 7: GENERAL PHYSICAL EXAMINATION ─────────────────────────────
    story.append(section_header("SECTION 7 : GENERAL PHYSICAL EXAMINATION"))

    story.append(Paragraph("<b>A. Vital Signs</b>", SUBSEC))
    vs_data = [
        ["Blood Pressure", "Right Arm (Sitting):", "____/____  mmHg",
         "Left Arm (Sitting):", "____/____  mmHg"],
        ["", "Right Arm (Standing):", "____/____  mmHg",
         "Right Arm (Supine):", "____/____  mmHg"],
        ["", "Pulse Pressure:", "_____  mmHg",
         "Mean Arterial Pressure:", "_____  mmHg"],
        ["Pulse Rate", "Rate:", "_____ bpm",
         "Rhythm:", "☐ Regular  ☐ Irregular"],
        ["", "Character:", "____________________",
         "Volume:", "☐ Normal  ☐ Raised  ☐ Reduced"],
        ["Respiratory Rate", "_____ /min", "",
         "Temperature:", "_____°F / °C"],
        ["SpO2", "_____%  (Room air / O2)", "",
         "Height:", "_____ cm"],
        ["Weight", "_____ kg",  "",
         "BMI:", "_____ kg/m²"],
        ["Waist Circumference", "_____ cm", "",
         "Waist-Hip Ratio:", "_____"],
    ]
    vs_t = Table(vs_data, colWidths=[(W-3*cm)*f for f in [0.19, 0.22, 0.22, 0.2, 0.17]])
    vs_t.setStyle(TableStyle([
        ("FONTSIZE",      (0,0),(-1,-1), 8.5),
        ("FONTNAME",      (0,0),(0,-1), "Helvetica-Bold"),
        ("TEXTCOLOR",     (0,0),(0,-1), DARK_BLUE),
        ("ROWBACKGROUNDS",(0,0),(-1,-1), [WHITE, GREY_BG]),
        ("GRID",          (0,0),(-1,-1), 0.3, LINE_GREY),
        ("TOPPADDING",    (0,0),(-1,-1), 4),
        ("BOTTOMPADDING", (0,0),(-1,-1), 4),
        ("LEFTPADDING",   (0,0),(-1,-1), 5),
        ("TEXTCOLOR",     (2,0),(-1,-1), LINE_GREY),
        ("SPAN",          (0,0),(0,2)),  # BP spans 3 rows
        ("SPAN",          (0,3),(0,4)),  # Pulse spans 2 rows
        ("VALIGN",        (0,0),(-1,-1), "MIDDLE"),
    ]))
    story.append(vs_t)
    story.append(Spacer(1, 3*mm))

    story.append(Paragraph("<b>B. General Appearance</b>", SUBSEC))
    gen_items = [
        "Conscious & oriented", "Cooperative", "Pallor", "Icterus",
        "Cyanosis (central / peripheral)", "Clubbing", "Lymphadenopathy",
        "Pedal oedema (Grade: ____)", "Raised JVP", "Xanthelasma / Xanthoma",
        "Cushingoid facies", "Acromegalic features",
    ]
    story.append(checkbox_row(gen_items, cols=4))
    story.append(Spacer(1, 2*mm))
    story.append(field_row("Other findings:", 1))
    story.append(Spacer(1, 4*mm))

    # ── SECTION 8: SYSTEMIC EXAMINATION ─────────────────────────────────────
    story.append(section_header("SECTION 8 : SYSTEMIC EXAMINATION"))

    # Cardiovascular
    story.append(Paragraph("<b>A. Cardiovascular System</b>", SUBSEC))
    cvs_data = [
        ["Apex Beat:", "Position: ____________", "Character: ____________",
         "Forceful: ☐ Yes  ☐ No"],
        ["Heart Sounds:", "S1: ☐ N  ☐ Loud  ☐ Soft",
         "S2: ☐ N  ☐ A2>P2  ☐ P2>A2", "S3/S4: ☐ Present  ☐ Absent"],
        ["Murmurs:", "☐ Absent", "☐ Present - Site: _________",
         "Grade: ___  Radiation: _________"],
        ["Peripheral Pulses:", "Radial: ☐ Present  ☐ Absent",
         "Femoral: ☐ Present  ☐ Absent", "Dorsalis pedis: ☐ P  ☐ A"],
        ["Radio-femoral delay:", "☐ Present  ☐ Absent", "Bruit:", "☐ Carotid  ☐ Renal  ☐ None"],
    ]
    cvs_t = Table(cvs_data, colWidths=[(W-3*cm)*f for f in [0.19, 0.27, 0.27, 0.27]])
    cvs_t.setStyle(TableStyle([
        ("FONTSIZE",      (0,0),(-1,-1), 8.5),
        ("FONTNAME",      (0,0),(0,-1), "Helvetica-Bold"),
        ("TEXTCOLOR",     (0,0),(0,-1), DARK_BLUE),
        ("ROWBACKGROUNDS",(0,0),(-1,-1), [WHITE, GREY_BG]),
        ("GRID",          (0,0),(-1,-1), 0.3, LINE_GREY),
        ("TOPPADDING",    (0,0),(-1,-1), 4),
        ("BOTTOMPADDING", (0,0),(-1,-1), 4),
        ("LEFTPADDING",   (0,0),(-1,-1), 5),
    ]))
    story.append(cvs_t)
    story.append(Spacer(1, 3*mm))

    # Respiratory
    story.append(Paragraph("<b>B. Respiratory System</b>", SUBSEC))
    story.append(checkbox_row([
        "Air entry equal bilaterally", "Wheeze", "Crepitations",
        "Pleural effusion (R / L)", "Normal vesicular breath sounds", "Rhonchi"], cols=3))
    story.append(field_row("Additional findings:", 1))
    story.append(Spacer(1, 3*mm))

    # Abdomen
    story.append(Paragraph("<b>C. Abdomen</b>", SUBSEC))
    abd_items = [
        "Liver: palpable ___ cm / not palpable",
        "Spleen: palpable / not palpable",
        "Kidneys: ballotable (R / L) / not palpable",
        "Renal bruit: ☐ Present  ☐ Absent",
        "Ascites: ☐ Present  ☐ Absent",
        "Abdominal aortic pulsation: ☐ Normal  ☐ Expansile",
    ]
    story.append(checkbox_row(abd_items, cols=2))
    story.append(Spacer(1, 3*mm))

    # Neurological
    story.append(Paragraph("<b>D. Neurological System</b>", SUBSEC))
    neuro_data = [
        ["Higher functions:", "☐ Normal  ☐ Impaired",
         "Speech:", "☐ Normal  ☐ Dysarthria  ☐ Aphasia"],
        ["Cranial nerves:", "☐ Intact  ☐ Deficit (specify: _______)",
         "Pupils:", "☐ Equal  ☐ Unequal  ☐ Reacting"],
        ["Power (UL):", "R: ___/5  L: ___/5",
         "Power (LL):", "R: ___/5  L: ___/5"],
        ["Reflexes:", "☐ Normal  ☐ Brisk  ☐ Absent",
         "Plantar:", "☐ Flexor  ☐ Extensor  ☐ Equivocal"],
        ["Sensory:", "☐ Normal  ☐ Reduced", "Coordination:", "☐ Normal  ☐ Ataxia"],
        ["Fundoscopy:", "☐ Normal  Grade: ___  ☐ Papilloedema  ☐ Flame haemorrhages  ☐ Exudates  ☐ AV nipping", "", ""],
    ]
    neuro_t = Table(neuro_data, colWidths=[(W-3*cm)*f for f in [0.15, 0.35, 0.15, 0.35]])
    neuro_t.setStyle(TableStyle([
        ("FONTSIZE",      (0,0),(-1,-1), 8.5),
        ("FONTNAME",      (0,0),(0,-1), "Helvetica-Bold"),
        ("TEXTCOLOR",     (0,0),(0,-1), DARK_BLUE),
        ("ROWBACKGROUNDS",(0,0),(-1,-1), [WHITE, GREY_BG]),
        ("GRID",          (0,0),(-1,-1), 0.3, LINE_GREY),
        ("TOPPADDING",    (0,0),(-1,-1), 4),
        ("BOTTOMPADDING", (0,0),(-1,-1), 4),
        ("LEFTPADDING",   (0,0),(-1,-1), 5),
        ("SPAN",          (1,5),(3,5)),
    ]))
    story.append(neuro_t)
    story.append(Spacer(1, 4*mm))

    # ── SECTION 9: INVESTIGATIONS ────────────────────────────────────────────
    story.append(section_header("SECTION 9 : INVESTIGATIONS"))

    # Routine
    story.append(Paragraph("<b>A. Routine / Baseline Investigations</b>", SUBSEC))
    inv_data = [
        ["Investigation", "Result", "Normal Range", "Interpretation"],
        ["Haemoglobin (g/dL)", "", "M: 13-17  F: 12-15", ""],
        ["Total WBC (cells/µL)", "", "4,000-11,000", ""],
        ["Platelet Count (lakh/µL)", "", "1.5-4.5", ""],
        ["Fasting Blood Glucose (mg/dL)", "", "70-100", ""],
        ["HbA1c (%)", "", "< 5.7 normal", ""],
        ["Serum Creatinine (mg/dL)", "", "M:0.7-1.3  F:0.5-1.1", ""],
        ["eGFR (mL/min/1.73m²)", "", "> 60 normal", ""],
        ["Blood Urea (mg/dL)", "", "7-20", ""],
        ["Serum Sodium (mEq/L)", "", "135-145", ""],
        ["Serum Potassium (mEq/L)", "", "3.5-5.0", ""],
        ["Serum Calcium (mg/dL)", "", "8.5-10.5", ""],
        ["Uric Acid (mg/dL)", "", "M:3.5-7.2  F:2.6-6.0", ""],
        ["Total Cholesterol (mg/dL)", "", "< 200 desirable", ""],
        ["LDL (mg/dL)", "", "< 100 optimal", ""],
        ["HDL (mg/dL)", "", "M:> 40  F:> 50", ""],
        ["Triglycerides (mg/dL)", "", "< 150", ""],
        ["TSH (mIU/L)", "", "0.5-4.5", ""],
        ["Urine Albumin-Creatinine Ratio", "", "< 30 normal", ""],
        ["Urine Routine & Microscopy", "", "No RBC/protein/casts", ""],
    ]
    cw_inv = [(W-3*cm)*f for f in [0.35, 0.22, 0.23, 0.20]]
    inv_t = Table(inv_data, colWidths=cw_inv)
    inv_t.setStyle(TableStyle([
        ("BACKGROUND",    (0,0),(-1,0), DARK_BLUE),
        ("TEXTCOLOR",     (0,0),(-1,0), WHITE),
        ("FONTNAME",      (0,0),(-1,0), "Helvetica-Bold"),
        ("FONTSIZE",      (0,0),(-1,-1), 8.5),
        ("ROWBACKGROUNDS",(0,1),(-1,-1), [WHITE, GREY_BG]),
        ("GRID",          (0,0),(-1,-1), 0.4, LINE_GREY),
        ("TOPPADDING",    (0,0),(-1,-1), 3),
        ("BOTTOMPADDING", (0,0),(-1,-1), 3),
        ("LEFTPADDING",   (0,0),(-1,-1), 5),
        ("ALIGN",         (2,0),(-1,-1), "CENTER"),
    ]))
    story.append(inv_t)
    story.append(Spacer(1, 3*mm))

    # Special investigations
    story.append(Paragraph("<b>B. Cardiac & Imaging Investigations</b>", SUBSEC))
    card_inv = [
        ["ECG findings:", "____________________________________________________________________"],
        ["Chest X-ray:", "☐ Cardiomegaly  ☐ Pulmonary oedema  ☐ Rib notching  ☐ Normal"],
        ["2D Echo findings:", "____________________________________________________________________"],
        ["LV mass index:", "_______  g/m²  (Normal: M<115, F<95)"],
        ["EF (%):", "_______  ☐ Normal (>55%)  ☐ Reduced  ☐ Preserved"],
        ["Renal USG:", "R kidney: ___cm  L kidney: ___cm  Cortical thickness: ___cm"],
        ["Renal Doppler:", "☐ Normal  ☐ Renal artery stenosis  ☐ Increased RI"],
        ["CT / MRI Brain:", "☐ Normal  ☐ Lacunar infarcts  ☐ Haemorrhage  ☐ WMC"],
        ["24-hr Ambulatory BP:", "Daytime avg: ____/____  Night avg: ____/____  Dipping: ☐ Yes  ☐ No"],
    ]
    cw_c = [(W-3*cm)*f for f in [0.25, 0.75]]
    card_t = Table(card_inv, colWidths=cw_c)
    card_t.setStyle(TableStyle([
        ("FONTSIZE",      (0,0),(-1,-1), 8.5),
        ("FONTNAME",      (0,0),(0,-1), "Helvetica-Bold"),
        ("TEXTCOLOR",     (0,0),(0,-1), DARK_BLUE),
        ("ROWBACKGROUNDS",(0,0),(-1,-1), [WHITE, GREY_BG]),
        ("GRID",          (0,0),(-1,-1), 0.3, LINE_GREY),
        ("TOPPADDING",    (0,0),(-1,-1), 4),
        ("BOTTOMPADDING", (0,0),(-1,-1), 4),
        ("LEFTPADDING",   (0,0),(-1,-1), 5),
        ("TEXTCOLOR",     (1,0),(-1,-1), LINE_GREY),
    ]))
    story.append(card_t)
    story.append(Spacer(1, 3*mm))

    # Secondary HTN workup
    story.append(Paragraph("<b>C. Secondary Hypertension Workup (if indicated)</b>", SUBSEC))
    sec_inv = [
        ["Plasma renin activity:", "_____________",
         "Serum aldosterone:", "_____________"],
        ["Aldosterone/Renin ratio:", "_____________",
         "24-hr urine catecholamines:", "_____________"],
        ["24-hr urine VMA:", "_____________",
         "Plasma metanephrines:", "_____________"],
        ["Serum cortisol (AM):", "_____________",
         "Overnight dex. suppression:", "_____________"],
        ["CT Adrenals:", "__________________________",
         "MRI Pituitary:", "__________________________"],
        ["Sleep study (AHI):", "_____________",
         "Thyroid function:", "_____________"],
        ["MIBG scan:", "_____________",
         "Renal artery angiogram:", "_____________"],
    ]
    sec_t = Table(sec_inv, colWidths=[(W-3*cm)*f for f in [0.22, 0.28, 0.22, 0.28]])
    sec_t.setStyle(TableStyle([
        ("FONTSIZE",      (0,0),(-1,-1), 8.5),
        ("FONTNAME",      (0,0),(0,-1), "Helvetica-Bold"),
        ("FONTNAME",      (2,0),(2,-1), "Helvetica-Bold"),
        ("TEXTCOLOR",     (0,0),(0,-1), DARK_BLUE),
        ("TEXTCOLOR",     (2,0),(2,-1), DARK_BLUE),
        ("ROWBACKGROUNDS",(0,0),(-1,-1), [WHITE, GREY_BG]),
        ("GRID",          (0,0),(-1,-1), 0.3, LINE_GREY),
        ("TOPPADDING",    (0,0),(-1,-1), 4),
        ("BOTTOMPADDING", (0,0),(-1,-1), 4),
        ("LEFTPADDING",   (0,0),(-1,-1), 5),
        ("TEXTCOLOR",     (1,0),(1,-1), LINE_GREY),
        ("TEXTCOLOR",     (3,0),(3,-1), LINE_GREY),
    ]))
    story.append(sec_t)
    story.append(Spacer(1, 4*mm))

    # ── SECTION 10: BP CLASSIFICATION ───────────────────────────────────────
    story.append(section_header("SECTION 10 : BP CLASSIFICATION (ACC/AHA 2017)"))
    story.append(bp_table())
    story.append(Spacer(1, 2*mm))
    story.append(Paragraph(
        "<b>Patient's BP stage:</b> ☐ Normal   ☐ Elevated   ☐ Stage 1 HTN   "
        "☐ Stage 2 HTN   ☐ Hypertensive Urgency   ☐ Hypertensive Emergency",
        BODY))
    story.append(Spacer(1, 2*mm))
    story.append(Paragraph(
        "<b>Type:</b> ☐ Primary (Essential)   ☐ Secondary (cause: ___________________)   "
        "☐ Isolated Systolic   ☐ Isolated Diastolic   ☐ White-coat HTN",
        BODY))
    story.append(Spacer(1, 4*mm))

    # ── SECTION 11: TARGET ORGAN DAMAGE ─────────────────────────────────────
    story.append(section_header("SECTION 11 : TARGET ORGAN DAMAGE ASSESSMENT"))

    tod_data = [
        ["Organ", "Evidence of Damage", "Severity"],
        ["Heart",
         "☐ LVH on ECG/Echo  ☐ HF  ☐ CAD  ☐ AF  ☐ None",
         "☐ Mild  ☐ Mod  ☐ Severe"],
        ["Brain",
         "☐ Stroke/TIA  ☐ Lacunar infarcts  ☐ Cognitive impairment  ☐ None",
         "☐ Mild  ☐ Mod  ☐ Severe"],
        ["Kidney",
         "☐ Microalbuminuria  ☐ Proteinuria  ☐ CKD  ☐ None",
         "☐ Mild  ☐ Mod  ☐ Severe"],
        ["Eye",
         "☐ Grade I  ☐ Grade II  ☐ Grade III  ☐ Grade IV retinopathy  ☐ None",
         "☐ Mild  ☐ Mod  ☐ Severe"],
        ["Peripheral Vessels",
         "☐ PAD  ☐ Aortic aneurysm  ☐ Carotid plaque  ☐ None",
         "☐ Mild  ☐ Mod  ☐ Severe"],
    ]
    tod_cw = [(W-3*cm)*f for f in [0.15, 0.65, 0.20]]
    tod_t = Table(tod_data, colWidths=tod_cw)
    tod_t.setStyle(TableStyle([
        ("BACKGROUND",    (0,0),(-1,0), DARK_BLUE),
        ("TEXTCOLOR",     (0,0),(-1,0), WHITE),
        ("FONTNAME",      (0,0),(-1,0), "Helvetica-Bold"),
        ("FONTSIZE",      (0,0),(-1,-1), 8.5),
        ("ROWBACKGROUNDS",(0,1),(-1,-1), [WHITE, GREY_BG]),
        ("GRID",          (0,0),(-1,-1), 0.4, LINE_GREY),
        ("TOPPADDING",    (0,0),(-1,-1), 5),
        ("BOTTOMPADDING", (0,0),(-1,-1), 5),
        ("LEFTPADDING",   (0,0),(-1,-1), 5),
    ]))
    story.append(tod_t)
    story.append(Spacer(1, 4*mm))

    # ── SECTION 12: CARDIOVASCULAR RISK STRATIFICATION ──────────────────────
    story.append(section_header("SECTION 12 : CARDIOVASCULAR RISK STRATIFICATION"))

    story.append(Paragraph("<b>Risk Factors Present:</b>", SUBSEC))
    rf_items = [
        "Age ≥ 55 y (Male) / ≥ 65 y (Female)",
        "Smoking",
        "Dyslipidaemia (LDL > 130 or HDL low)",
        "Diabetes Mellitus",
        "Family history of premature CVD",
        "Obesity (BMI ≥ 30)",
        "Sedentary lifestyle",
        "hs-CRP > 2 mg/L",
        "Metabolic syndrome",
        "Microalbuminuria / CKD Stage G3+",
    ]
    story.append(checkbox_row(rf_items, cols=2))
    story.append(Spacer(1, 2*mm))

    risk_strat = [
        ["Risk Category", "Definition", "Patient Qualifies?"],
        ["Low",           "No TOD, no RF, Stage 1 HTN",          "☐"],
        ["Moderate",      "1-2 RF, no TOD, Stage 1-2 HTN",       "☐"],
        ["High",          "≥ 3 RF OR 1 TOD, Stage 1-2 HTN",      "☐"],
        ["Very High",     "Known CVD / DM with TOD / Stage 3 HTN","☐"],
    ]
    rs_t = Table(risk_strat, colWidths=[(W-3*cm)*f for f in [0.18, 0.62, 0.20]])
    rs_t.setStyle(TableStyle([
        ("BACKGROUND",    (0,0),(-1,0), DARK_BLUE),
        ("TEXTCOLOR",     (0,0),(-1,0), WHITE),
        ("FONTNAME",      (0,0),(-1,0), "Helvetica-Bold"),
        ("FONTSIZE",      (0,0),(-1,-1), 9),
        ("ROWBACKGROUNDS",(0,1),(-1,-1), [WHITE, GREY_BG]),
        ("GRID",          (0,0),(-1,-1), 0.4, LINE_GREY),
        ("TOPPADDING",    (0,0),(-1,-1), 5),
        ("BOTTOMPADDING", (0,0),(-1,-1), 5),
        ("LEFTPADDING",   (0,0),(-1,-1), 5),
        ("ALIGN",         (2,0),(-1,-1), "CENTER"),
    ]))
    story.append(rs_t)
    story.append(Spacer(1, 4*mm))

    # ── SECTION 13: DIAGNOSIS ────────────────────────────────────────────────
    story.append(section_header("SECTION 13 : DIAGNOSIS"))

    dx_data = [
        ["Primary Diagnosis:", "_______________________________________________"],
        ["Secondary Diagnosis 1:", "_______________________________________________"],
        ["Secondary Diagnosis 2:", "_______________________________________________"],
        ["Complications:", "_______________________________________________"],
        ["Hypertensive Emergency:", "☐ Yes   ☐ No   If yes, type: _____________________"],
    ]
    dx_t = Table(dx_data, colWidths=[(W-3*cm)*f for f in [0.26, 0.74]])
    dx_t.setStyle(TableStyle([
        ("FONTSIZE",      (0,0),(-1,-1), 9),
        ("FONTNAME",      (0,0),(0,-1), "Helvetica-Bold"),
        ("TEXTCOLOR",     (0,0),(0,-1), DARK_BLUE),
        ("ROWBACKGROUNDS",(0,0),(-1,-1), [WHITE, GREY_BG]),
        ("GRID",          (0,0),(-1,-1), 0.3, LINE_GREY),
        ("TOPPADDING",    (0,0),(-1,-1), 6),
        ("BOTTOMPADDING", (0,0),(-1,-1), 6),
        ("LEFTPADDING",   (0,0),(-1,-1), 5),
        ("TEXTCOLOR",     (1,0),(-1,-1), LINE_GREY),
    ]))
    story.append(dx_t)
    story.append(Spacer(1, 4*mm))

    # ── SECTION 14: MANAGEMENT PLAN ─────────────────────────────────────────
    story.append(section_header("SECTION 14 : MANAGEMENT PLAN"))

    story.append(Paragraph("<b>A. Non-Pharmacological (Lifestyle Modifications)</b>", SUBSEC))
    nlm_items = [
        "Weight reduction (target BMI < 25 kg/m²)",
        "DASH diet / reduce saturated fat",
        "Restrict sodium (< 2.3 g/day NaCl)",
        "Increase potassium intake (diet)",
        "Regular aerobic exercise (150 min/week)",
        "Stop smoking / cessation counselling",
        "Reduce alcohol (< 2 units/day)",
        "Stress reduction / relaxation",
        "Sleep hygiene (target 7-8 hrs)",
        "Home BP monitoring education",
    ]
    story.append(checkbox_row(nlm_items, cols=2))
    story.append(Spacer(1, 3*mm))

    story.append(Paragraph("<b>B. Pharmacological Treatment</b>", SUBSEC))
    story.append(Paragraph(
        "<i>First-line agents: ACE inhibitors, ARBs, CCBs, Thiazide diuretics. "
        "Beta-blockers for specific indications (CHF, post-MI, AF rate control).</i>", SMALL))
    story.append(Spacer(1, 2*mm))

    rx_data = [["Drug", "Class", "Dose", "Frequency", "Indication / Rationale", "Precaution"]]
    for _ in range(6):
        rx_data.append(["", "", "", "", "", ""])
    rx_cw = [(W-3*cm)*f for f in [0.18, 0.15, 0.12, 0.12, 0.27, 0.16]]
    rx_t = Table(rx_data, colWidths=rx_cw)
    rx_t.setStyle(TableStyle([
        ("BACKGROUND",    (0,0),(-1,0), DARK_BLUE),
        ("TEXTCOLOR",     (0,0),(-1,0), WHITE),
        ("FONTNAME",      (0,0),(-1,0), "Helvetica-Bold"),
        ("FONTSIZE",      (0,0),(-1,-1), 8.5),
        ("ROWBACKGROUNDS",(0,1),(-1,-1), [WHITE, GREY_BG]),
        ("GRID",          (0,0),(-1,-1), 0.4, LINE_GREY),
        ("TOPPADDING",    (0,0),(-1,-1), 10),
        ("BOTTOMPADDING", (0,0),(-1,-1), 10),
        ("LEFTPADDING",   (0,0),(-1,-1), 4),
    ]))
    story.append(rx_t)
    story.append(Spacer(1, 3*mm))

    story.append(Paragraph("<b>C. Target BP Goals</b>", SUBSEC))
    goal_data = [
        ["Patient Profile", "Target BP", "Evidence Base"],
        ["General HTN (< 65 y)", "< 130/80 mmHg", "ACC/AHA 2017"],
        ["Elderly (≥ 65 y)", "< 130/80 mmHg (SBP)", "SPRINT trial"],
        ["HTN + Diabetes", "< 130/80 mmHg", "ADA Standards 2024"],
        ["HTN + CKD (non-DM)", "< 130/80 mmHg", "KDIGO 2021"],
        ["HTN + CKD + Proteinuria", "< 130/80 mmHg (ACE/ARB preferred)", "KDIGO 2021"],
        ["HTN + CAD / Post-MI", "< 130/80 mmHg", "ACC/AHA 2017"],
        ["Hypertensive Emergency", "Reduce MAP by 25% in 1 hr, then 160/100 over 2-6 hr", "ESC 2018"],
    ]
    goal_cw = [(W-3*cm)*f for f in [0.37, 0.30, 0.33]]
    goal_t = Table(goal_data, colWidths=goal_cw)
    goal_t.setStyle(TableStyle([
        ("BACKGROUND",    (0,0),(-1,0), MED_BLUE),
        ("TEXTCOLOR",     (0,0),(-1,0), WHITE),
        ("FONTNAME",      (0,0),(-1,0), "Helvetica-Bold"),
        ("FONTSIZE",      (0,0),(-1,-1), 8.5),
        ("ROWBACKGROUNDS",(0,1),(-1,-1), [WHITE, GREY_BG]),
        ("GRID",          (0,0),(-1,-1), 0.4, LINE_GREY),
        ("TOPPADDING",    (0,0),(-1,-1), 4),
        ("BOTTOMPADDING", (0,0),(-1,-1), 4),
        ("LEFTPADDING",   (0,0),(-1,-1), 5),
    ]))
    story.append(goal_t)
    story.append(Spacer(1, 4*mm))

    # ── SECTION 15: PROGRESS NOTES ──────────────────────────────────────────
    story.append(section_header("SECTION 15 : DAILY PROGRESS NOTES"))
    prog_data = [["Date", "BP (mmHg)", "PR (/min)", "Symptoms", "Assessment", "Plan / Changes"]]
    for _ in range(6):
        prog_data.append(["", "", "", "", "", ""])
    prog_cw = [(W-3*cm)*f for f in [0.13, 0.15, 0.12, 0.20, 0.20, 0.20]]
    prog_t = Table(prog_data, colWidths=prog_cw)
    prog_t.setStyle(TableStyle([
        ("BACKGROUND",    (0,0),(-1,0), DARK_BLUE),
        ("TEXTCOLOR",     (0,0),(-1,0), WHITE),
        ("FONTNAME",      (0,0),(-1,0), "Helvetica-Bold"),
        ("FONTSIZE",      (0,0),(-1,-1), 8.5),
        ("ROWBACKGROUNDS",(0,1),(-1,-1), [WHITE, GREY_BG]),
        ("GRID",          (0,0),(-1,-1), 0.4, LINE_GREY),
        ("TOPPADDING",    (0,0),(-1,-1), 18),
        ("BOTTOMPADDING", (0,0),(-1,-1), 18),
        ("LEFTPADDING",   (0,0),(-1,-1), 4),
    ]))
    story.append(prog_t)
    story.append(Spacer(1, 4*mm))

    # ── SECTION 16: DISCHARGE SUMMARY ───────────────────────────────────────
    story.append(section_header("SECTION 16 : DISCHARGE SUMMARY"))

    disc_data = [
        ["Date of Admission:", "_____________", "Date of Discharge:", "_____________"],
        ["Duration of Stay:", "_____________", "Condition at Discharge:",
         "☐ Improved  ☐ Stable  ☐ Same  ☐ DAMA"],
        ["Discharge BP:", "____/____  mmHg", "Discharge HR:", "_____ bpm"],
        ["Final Diagnosis:", "_____________________________",
         "ICD-10 Code:", "___________"],
    ]
    disc_t = Table(disc_data, colWidths=[(W-3*cm)*f for f in [0.20, 0.30, 0.22, 0.28]])
    disc_t.setStyle(TableStyle([
        ("FONTSIZE",      (0,0),(-1,-1), 9),
        ("FONTNAME",      (0,0),(0,-1), "Helvetica-Bold"),
        ("FONTNAME",      (2,0),(2,-1), "Helvetica-Bold"),
        ("TEXTCOLOR",     (0,0),(0,-1), DARK_BLUE),
        ("TEXTCOLOR",     (2,0),(2,-1), DARK_BLUE),
        ("ROWBACKGROUNDS",(0,0),(-1,-1), [WHITE, GREY_BG]),
        ("GRID",          (0,0),(-1,-1), 0.3, LINE_GREY),
        ("TOPPADDING",    (0,0),(-1,-1), 5),
        ("BOTTOMPADDING", (0,0),(-1,-1), 5),
        ("LEFTPADDING",   (0,0),(-1,-1), 5),
        ("TEXTCOLOR",     (1,0),(-1,-1), LINE_GREY),
    ]))
    story.append(disc_t)
    story.append(Spacer(1, 3*mm))

    story.append(Paragraph("<b>Discharge Medications:</b>", SUBSEC))
    disc_rx = [["Drug", "Dose", "Frequency", "Duration", "Special Instructions"]]
    for _ in range(5):
        disc_rx.append(["", "", "", "", ""])
    disc_rx_cw = [(W-3*cm)*f for f in [0.25, 0.15, 0.15, 0.15, 0.30]]
    disc_rx_t = Table(disc_rx, colWidths=disc_rx_cw)
    disc_rx_t.setStyle(TableStyle([
        ("BACKGROUND",    (0,0),(-1,0), DARK_BLUE),
        ("TEXTCOLOR",     (0,0),(-1,0), WHITE),
        ("FONTNAME",      (0,0),(-1,0), "Helvetica-Bold"),
        ("FONTSIZE",      (0,0),(-1,-1), 8.5),
        ("ROWBACKGROUNDS",(0,1),(-1,-1), [WHITE, GREY_BG]),
        ("GRID",          (0,0),(-1,-1), 0.4, LINE_GREY),
        ("TOPPADDING",    (0,0),(-1,-1), 10),
        ("BOTTOMPADDING", (0,0),(-1,-1), 10),
        ("LEFTPADDING",   (0,0),(-1,-1), 4),
    ]))
    story.append(disc_rx_t)
    story.append(Spacer(1, 3*mm))

    story.append(Paragraph("<b>Follow-up Instructions:</b>", SUBSEC))
    fu_items = [
        "Review in OPD in _____ days / weeks",
        "Repeat BP check in _____ days",
        "Repeat labs: ______________________",
        "Ambulatory BP monitoring",
        "Ophthalmology review",
        "Nephrology referral",
        "Cardiology referral",
        "ECHO review in _____ months",
    ]
    story.append(checkbox_row(fu_items, cols=2))
    story.append(Spacer(1, 3*mm))
    story.append(field_row("Patient education given on:", 1))
    story.append(Spacer(1, 4*mm))

    # ── SECTION 17: SIGNATURES ───────────────────────────────────────────────
    story.append(section_header("SECTION 17 : SIGNATURES"))

    sig_data = [
        ["Student Name:", "_________________________",
         "Roll No.:", "_____________"],
        ["Signature:", "_________________________",
         "Date:", "_____________"],
        ["", "", "", ""],
        ["Resident / PG Signature:", "_________________________",
         "Date:", "_____________"],
        ["Consultant Signature:", "_________________________",
         "Date:", "_____________"],
        ["Unit Chief / HOD Signature:", "_________________________",
         "Stamp:", "_____________"],
    ]
    sig_t = Table(sig_data, colWidths=[(W-3*cm)*f for f in [0.25, 0.35, 0.14, 0.26]])
    sig_t.setStyle(TableStyle([
        ("FONTSIZE",      (0,0),(-1,-1), 9),
        ("FONTNAME",      (0,0),(0,-1), "Helvetica-Bold"),
        ("FONTNAME",      (2,0),(2,-1), "Helvetica-Bold"),
        ("TEXTCOLOR",     (0,0),(0,-1), DARK_BLUE),
        ("TEXTCOLOR",     (2,0),(2,-1), DARK_BLUE),
        ("ROWBACKGROUNDS",(0,0),(-1,-1), [WHITE, GREY_BG]),
        ("TOPPADDING",    (0,0),(-1,-1), 8),
        ("BOTTOMPADDING", (0,0),(-1,-1), 8),
        ("LEFTPADDING",   (0,0),(-1,-1), 5),
        ("TEXTCOLOR",     (1,0),(-1,-1), LINE_GREY),
        ("LINEBELOW",     (0,-1),(-1,-1), 0.5, LINE_GREY),
    ]))
    story.append(sig_t)
    story.append(Spacer(1, 4*mm))

    # ── APPENDIX: HYPERTENSION QUICK REFERENCE ──────────────────────────────
    story.append(section_header("APPENDIX : QUICK REFERENCE - ANTIHYPERTENSIVE DRUG CLASSES"))

    drug_ref = [
        ["Class", "Prototype Drug(s)", "Compelling Indications", "Contraindications / Cautions"],
        ["ACE Inhibitors\n(ACEi)", "Enalapril, Ramipril,\nLisinopril",
         "DM, CKD proteinuria,\nHF, post-MI, LVD",
         "Bilateral RAS, Pregnancy,\nHyperkalaemia, Angioedema Hx"],
        ["ARBs", "Losartan, Valsartan,\nTelmisartan",
         "ACEi intolerant, DM,\nCKD, HF",
         "Bilateral RAS, Pregnancy,\nHyperkalaemia"],
        ["CCBs\n(Dihydropyridine)", "Amlodipine, Nifedipine",
         "Elderly ISH, Angina,\nAfro-Caribbean patients",
         "Severe aortic stenosis\n(caution)"],
        ["CCBs\n(Non-DHP)", "Diltiazem, Verapamil",
         "Angina, AF rate control,\nSVT",
         "Heart failure (EF reduced),\nAV block, Bradycardia"],
        ["Thiazide Diuretics", "Hydrochlorothiazide,\nChlorthalidone, Indapamide",
         "Elderly, ISH,\nOsteoporosis",
         "Gout, Hypokalaemia,\nGlucose intolerance"],
        ["Beta-Blockers", "Atenolol, Metoprolol,\nCarvedilol, Bisoprolol",
         "Post-MI, Angina, HF,\nAF rate control, Pregnancy (labetalol)",
         "Asthma, AV block,\nPeripheral arterial disease"],
        ["Aldosterone Antag.", "Spironolactone,\nEplerenone",
         "Resistant HTN, HF,\nConn's syndrome",
         "Hyperkalaemia, CKD\n(severe), renal failure"],
        ["Alpha-Blockers", "Prazosin, Doxazosin",
         "Resistant HTN,\nBPH, Phaeochromocytoma",
         "Postural hypotension,\n1st dose effect"],
        ["Central Agents", "Methyldopa, Clonidine",
         "Pregnancy (methyldopa)\nRefractory HTN",
         "Depression, Rebound HTN\non withdrawal (clonidine)"],
    ]
    drug_ref_cw = [(W-3*cm)*f for f in [0.18, 0.22, 0.28, 0.32]]
    drug_ref_t = Table(drug_ref, colWidths=drug_ref_cw)
    drug_ref_t.setStyle(TableStyle([
        ("BACKGROUND",    (0,0),(-1,0), DARK_BLUE),
        ("TEXTCOLOR",     (0,0),(-1,0), WHITE),
        ("FONTNAME",      (0,0),(-1,0), "Helvetica-Bold"),
        ("FONTSIZE",      (0,0),(-1,-1), 8),
        ("ROWBACKGROUNDS",(0,1),(-1,-1), [WHITE, GREY_BG]),
        ("GRID",          (0,0),(-1,-1), 0.4, LINE_GREY),
        ("TOPPADDING",    (0,0),(-1,-1), 4),
        ("BOTTOMPADDING", (0,0),(-1,-1), 4),
        ("LEFTPADDING",   (0,0),(-1,-1), 5),
        ("VALIGN",        (0,0),(-1,-1), "TOP"),
        ("FONTNAME",      (0,1),(0,-1), "Helvetica-Bold"),
        ("TEXTCOLOR",     (0,1),(0,-1), MED_BLUE),
    ]))
    story.append(drug_ref_t)
    story.append(Spacer(1, 3*mm))

    # Keith-Wagener-Barker Fundoscopy grading
    story.append(Paragraph("<b>Keith-Wagener-Barker Fundoscopy Grading:</b>", SUBSEC))
    kwb = [
        ["Grade", "Features"],
        ["Grade I",  "Mild narrowing / tortuosity of arteries, increased light reflex (copper wire)"],
        ["Grade II", "More severe narrowing, A-V nipping (Gunn's sign), silver wire appearance"],
        ["Grade III","Flame haemorrhages, dot & blot haemorrhages, cotton wool spots (soft exudates)"],
        ["Grade IV", "Grade III features + Papilloedema (bilateral disc oedema)"],
    ]
    kwb_cw = [(W-3*cm)*f for f in [0.10, 0.90]]
    kwb_t = Table(kwb, colWidths=kwb_cw)
    kwb_t.setStyle(TableStyle([
        ("BACKGROUND",    (0,0),(-1,0), MED_BLUE),
        ("TEXTCOLOR",     (0,0),(-1,0), WHITE),
        ("FONTNAME",      (0,0),(-1,0), "Helvetica-Bold"),
        ("FONTSIZE",      (0,0),(-1,-1), 8.5),
        ("ROWBACKGROUNDS",(0,1),(-1,-1), [WHITE, GREY_BG]),
        ("GRID",          (0,0),(-1,-1), 0.4, LINE_GREY),
        ("TOPPADDING",    (0,0),(-1,-1), 4),
        ("BOTTOMPADDING", (0,0),(-1,-1), 4),
        ("LEFTPADDING",   (0,0),(-1,-1), 5),
        ("FONTNAME",      (0,1),(0,-1), "Helvetica-Bold"),
        ("TEXTCOLOR",     (0,1),(0,-1), ACCENT),
    ]))
    story.append(kwb_t)
    story.append(Spacer(1, 3*mm))

    story.append(Paragraph(
        "<b>References:</b> ACC/AHA 2017 Hypertension Guidelines | "
        "ESC/ESH 2018 HTN Guidelines | JNC 8 | WHO/ISH 2020 | "
        "KDIGO 2021 BP in CKD | ADA Standards of Medical Care 2024",
        SMALL))
    story.append(Spacer(1, 3*mm))
    story.append(HRFlowable(width="100%", thickness=0.5, color=LINE_GREY))
    story.append(Spacer(1, 2*mm))
    story.append(Paragraph(
        "This proforma is intended for academic/educational use. "
        "Clinical decisions must be guided by current institutional protocols and attending physician judgement.",
        NOTE))

    # Build
    doc.build(story, canvasmaker=HeaderFooterCanvas)
    print(f"PDF generated: {OUTPUT_PATH}")


if __name__ == "__main__":
    import os
    os.makedirs("/home/daytona/workspace/hypertension-proforma", exist_ok=True)
    build()
Running Command

cd /home/daytona/workspace/hypertension-proforma && python3 generate_proforma.py 2>&1

Running Command

ls -lh /home/daytona/workspace/hypertension-proforma/Hypertension_Case_Proforma.pdf

Your Hypertension Case Proforma PDF is ready:

Hypertension Case Proforma

PDF Document · PDF


Here is what the proforma covers across 17 sections + Appendix:
SectionContent
1Patient Particulars (demographics, IP/OP No., socioeconomic status)
2Chief Complaints (tabulated with duration)
3History of Present Illness - onset, symptoms checklist, drug history, compliance
4Past History (DM, CAD, MI, stroke, CKD, phaeochromocytoma, etc.)
5Family History (6-generation table for HTN, DM, heart disease, stroke, renal)
6Personal / Social History (smoking, alcohol, diet, exercise, stress)
7General Physical Examination - vital signs (both arms BP), BMI, waist-hip ratio
8Systemic Examination - CVS, respiratory, abdomen, full neurological, fundoscopy
9Investigations - baseline labs (20 parameters), cardiac/imaging, secondary HTN workup
10BP Classification table (ACC/AHA 2017 - Normal to Hypertensive Crisis)
11Target Organ Damage (heart, brain, kidney, eye, peripheral vessels)
12CV Risk Stratification (Low / Moderate / High / Very High)
13Diagnosis block with ICD-10 space
14Management - lifestyle modifications, drug table, target BP goals by comorbidity
15Daily Progress Notes table
16Discharge Summary + discharge medications + follow-up plan
17Signatures (student, resident, consultant, unit chief)
AppendixAntihypertensive drug class quick reference + Keith-Wagener-Barker grading
Guidelines referenced: ACC/AHA 2017, ESC/ESH 2018, KDIGO 2021, ADA 2024, JNC 8, WHO/ISH 2020.
This is a shared conversation. Sign in to Orris to start your own chat.