make me details note on GERD for Residency, FCPS, MRCP exam as pdf with diagram and image

Reading File
Finding Sources
Finding Sources
Searching PubMed

"gastroesophageal reflux disease"[MeSH Terms] AND management

Reading File
Reading File
Reading File
Reading File
Searching PubMed

"gastroesophageal reflux"[MeSH Terms] AND "proton pump inhibitors"[MeSH Terms]

Finding Sources
Reading File
Searching the Web

GERD pathophysiology diagnosis management guidelines 2024 2025 MRCP residency exam

Finding Sources
Finding Sources
Reading Web Page

https://pmc.ncbi.nlm.nih.gov/articles/PMC8754510

Finding Sources
Finding Sources
Reading File
Reading File
Reading File
Finding Sources
Reading File
Reading File
Loading Image
Loading Image
Running Command

mkdir -p /home/daytona/workspace/gerd-notes && ls /home/daytona/workspace/gerd-n…

Writing File

~/gerd-notes/generate_gerd_pdf.py

#!/usr/bin/env python3
"""
Comprehensive GERD Notes PDF Generator
For Residency / FCPS / MRCP Exam Preparation
"""

import urllib.request
from reportlab.lib.pagesizes import A4
from reportlab.lib import colors
from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
from reportlab.lib.units import inch, cm
from reportlab.platypus import (
    SimpleDocTemplate, Paragraph, Spacer, Table, TableStyle,
    HRFlowable, PageBreak, Image, KeepTogether
)
from reportlab.platypus.flowables import Flowable
from reportlab.lib.enums import TA_LEFT, TA_CENTER, TA_JUSTIFY
from reportlab.graphics.shapes import Drawing, Rect, String, Line, Circle, Polygon
from reportlab.graphics import renderPDF
from reportlab.graphics.charts.barcharts import VerticalBarChart
from io import BytesIO
import os

# ── Color Palette ────────────────────────────────────────────────────────────
DARK_BLUE   = colors.HexColor("#1A3A5C")
MID_BLUE    = colors.HexColor("#2E6DA4")
LIGHT_BLUE  = colors.HexColor("#D6E8FA")
ACCENT_RED  = colors.HexColor("#C0392B")
ACCENT_GREEN= colors.HexColor("#1A7A4A")
ACCENT_ORANGE= colors.HexColor("#D35400")
YELLOW_BG   = colors.HexColor("#FFF9C4")
GREY_BG     = colors.HexColor("#F5F5F5")
WHITE       = colors.white
BLACK       = colors.black
TEAL        = colors.HexColor("#117A8B")
PURPLE      = colors.HexColor("#6C3483")

OUTPUT_PATH = "/home/daytona/workspace/gerd-notes/GERD_Exam_Notes.pdf"

# ── Custom Flowables ─────────────────────────────────────────────────────────
class ColoredBox(Flowable):
    """A colored box with text for key points."""
    def __init__(self, text, bg_color, border_color, width=None, left_bar=True):
        super().__init__()
        self.text = text
        self.bg_color = bg_color
        self.border_color = border_color
        self.box_width = width or (A4[0] - 1.8*inch)
        self.left_bar = left_bar

    def wrap(self, avail_w, avail_h):
        self.box_width = avail_w
        return (avail_w, 0.55*inch)

    def draw(self):
        c = self.canv
        w = self.box_width
        h = 0.45*inch
        if self.left_bar:
            c.setFillColor(self.bg_color)
            c.roundRect(0, 0, w, h, 4, fill=1, stroke=0)
            c.setFillColor(self.border_color)
            c.rect(0, 0, 4, h, fill=1, stroke=0)
        else:
            c.setFillColor(self.bg_color)
            c.roundRect(0, 0, w, h, 4, fill=1, stroke=0)
            c.setStrokeColor(self.border_color)
            c.setLineWidth(1.2)
            c.roundRect(0, 0, w, h, 4, fill=0, stroke=1)
        c.setFillColor(BLACK)
        c.setFont("Helvetica", 9)
        c.drawString(12, h/2 - 4, self.text)


class SectionDivider(Flowable):
    """A fancy section divider with number."""
    def __init__(self, number, title, color=DARK_BLUE):
        super().__init__()
        self.number = number
        self.title = title
        self.color = color

    def wrap(self, avail_w, avail_h):
        self.width = avail_w
        return (avail_w, 0.5*inch)

    def draw(self):
        c = self.canv
        w = self.width
        # Background bar
        c.setFillColor(self.color)
        c.roundRect(0, 2, w, 0.42*inch, 5, fill=1, stroke=0)
        # Circle with number
        c.setFillColor(WHITE)
        c.circle(0.28*inch, 0.23*inch, 0.18*inch, fill=1, stroke=0)
        c.setFillColor(self.color)
        c.setFont("Helvetica-Bold", 13)
        c.drawCentredString(0.28*inch, 0.165*inch, str(self.number))
        # Title
        c.setFillColor(WHITE)
        c.setFont("Helvetica-Bold", 14)
        c.drawString(0.6*inch, 0.16*inch, self.title.upper())


class PathwayArrow(Flowable):
    """Simple horizontal pathway diagram."""
    def __init__(self, steps, colors_list, width=None):
        super().__init__()
        self.steps = steps
        self.colors_list = colors_list
        self.box_width = width

    def wrap(self, avail_w, avail_h):
        self.box_width = avail_w
        return (avail_w, 0.85*inch)

    def draw(self):
        c = self.canv
        n = len(self.steps)
        box_w = (self.box_width - 0.1*inch) / n - 0.08*inch
        box_h = 0.55*inch
        y = 0.12*inch
        for i, (step, col) in enumerate(zip(self.steps, self.colors_list)):
            x = i * (box_w + 0.1*inch + 0.08*inch)
            c.setFillColor(col)
            c.roundRect(x, y, box_w, box_h, 5, fill=1, stroke=0)
            c.setFillColor(WHITE)
            c.setFont("Helvetica-Bold", 7.5)
            words = step.split('\n')
            if len(words) == 1:
                c.drawCentredString(x + box_w/2, y + box_h/2 - 4, step)
            else:
                for j, word in enumerate(words):
                    c.drawCentredString(x + box_w/2, y + box_h/2 + (len(words)/2 - j - 0.5)*10, word)
            # Arrow
            if i < n - 1:
                ax = x + box_w + 2
                ay = y + box_h/2
                c.setFillColor(colors.HexColor("#555555"))
                c.setStrokeColor(colors.HexColor("#555555"))
                c.setLineWidth(1.5)
                c.line(ax, ay, ax + 8, ay)
                c.polygon([ax+8, ay+4, ax+8, ay-4, ax+14, ay], fill=1, stroke=0)


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

    styles.add(ParagraphStyle(
        'MainTitle',
        parent=styles['Title'],
        fontSize=26, fontName='Helvetica-Bold',
        textColor=WHITE, alignment=TA_CENTER,
        spaceAfter=4
    ))
    styles.add(ParagraphStyle(
        'Subtitle',
        fontSize=13, fontName='Helvetica',
        textColor=LIGHT_BLUE, alignment=TA_CENTER,
        spaceAfter=6
    ))
    styles.add(ParagraphStyle(
        'H2', fontSize=13, fontName='Helvetica-Bold',
        textColor=DARK_BLUE, spaceBefore=10, spaceAfter=5,
        borderPad=2
    ))
    styles.add(ParagraphStyle(
        'H3', fontSize=11, fontName='Helvetica-Bold',
        textColor=MID_BLUE, spaceBefore=7, spaceAfter=3
    ))
    styles.add(ParagraphStyle(
        'H4', fontSize=10, fontName='Helvetica-BoldOblique',
        textColor=TEAL, spaceBefore=5, spaceAfter=2
    ))
    styles.add(ParagraphStyle(
        'Body', fontSize=9.5, fontName='Helvetica',
        textColor=colors.HexColor("#222222"),
        leading=14, spaceAfter=4, alignment=TA_JUSTIFY
    ))
    styles.add(ParagraphStyle(
        'Bullet', fontSize=9.5, fontName='Helvetica',
        textColor=colors.HexColor("#222222"),
        leading=13, spaceAfter=2,
        leftIndent=12, bulletIndent=0,
        alignment=TA_LEFT
    ))
    styles.add(ParagraphStyle(
        'SubBullet', fontSize=9, fontName='Helvetica',
        textColor=colors.HexColor("#333333"),
        leading=12, spaceAfter=2,
        leftIndent=24, bulletIndent=12
    ))
    styles.add(ParagraphStyle(
        'KeyPoint', fontSize=9.5, fontName='Helvetica-Bold',
        textColor=ACCENT_RED, leading=13, spaceAfter=2,
        leftIndent=8
    ))
    styles.add(ParagraphStyle(
        'TableHeader', fontSize=9, fontName='Helvetica-Bold',
        textColor=WHITE, alignment=TA_CENTER
    ))
    styles.add(ParagraphStyle(
        'TableCell', fontSize=8.5, fontName='Helvetica',
        textColor=BLACK, leading=12
    ))
    styles.add(ParagraphStyle(
        'Caption', fontSize=8, fontName='Helvetica-Oblique',
        textColor=colors.HexColor("#555555"), alignment=TA_CENTER,
        spaceAfter=6
    ))
    styles.add(ParagraphStyle(
        'SmallNote', fontSize=8, fontName='Helvetica',
        textColor=colors.HexColor("#666666"), leading=11, spaceAfter=2
    ))
    styles.add(ParagraphStyle(
        'PageFooter', fontSize=8, fontName='Helvetica',
        textColor=colors.HexColor("#888888"), alignment=TA_CENTER
    ))
    return styles

S = make_styles()

def b(text): return f"<b>{text}</b>"
def i(text): return f"<i>{text}</i>"
def color_text(text, hex_color): return f'<font color="{hex_color}">{text}</font>'

def bullet(text, style='Bullet'):
    return Paragraph(f"&#8226; {text}", S[style])

def subbullet(text):
    return Paragraph(f"&#x25E6; {text}", S['SubBullet'])

def sp(n=6):
    return Spacer(1, n)

def hr(color=MID_BLUE, thickness=0.5):
    return HRFlowable(width="100%", thickness=thickness, color=color, spaceAfter=4, spaceBefore=4)


# ── Cover Page ───────────────────────────────────────────────────────────────
def cover_page():
    elems = []
    # Header background handled via custom flowable
    class CoverHeader(Flowable):
        def wrap(self, aw, ah):
            self.width = aw
            return (aw, 2.4*inch)
        def draw(self):
            c = self.canv
            w = self.width
            # Gradient-like background
            c.setFillColor(DARK_BLUE)
            c.roundRect(0, 0, w, 2.3*inch, 10, fill=1, stroke=0)
            c.setFillColor(MID_BLUE)
            c.roundRect(0, 0.05*inch, w, 0.6*inch, 10, fill=1, stroke=0)
            # GERD big title
            c.setFillColor(WHITE)
            c.setFont("Helvetica-Bold", 38)
            c.drawCentredString(w/2, 1.55*inch, "GERD")
            c.setFont("Helvetica-Bold", 15)
            c.setFillColor(LIGHT_BLUE)
            c.drawCentredString(w/2, 1.22*inch, "Gastroesophageal Reflux Disease")
            c.setFont("Helvetica", 11)
            c.setFillColor(WHITE)
            c.drawCentredString(w/2, 0.95*inch, "Comprehensive Exam Notes")
            # Badge row
            c.setFillColor(ACCENT_RED)
            bw = 1.0*inch
            bh = 0.28*inch
            badges = ["RESIDENCY", "FCPS", "MRCP"]
            total = len(badges) * bw + (len(badges)-1)*0.15*inch
            start_x = (w - total)/2
            for idx, badge in enumerate(badges):
                bx = start_x + idx*(bw + 0.15*inch)
                c.setFillColor([ACCENT_RED, ACCENT_GREEN, ACCENT_ORANGE][idx])
                c.roundRect(bx, 0.12*inch, bw, bh, 4, fill=1, stroke=0)
                c.setFillColor(WHITE)
                c.setFont("Helvetica-Bold", 8.5)
                c.drawCentredString(bx + bw/2, 0.22*inch, badge)

    elems.append(CoverHeader())
    elems.append(sp(16))

    # Info boxes
    info_data = [
        [Paragraph(b("Specialty"), S['TableHeader']),
         Paragraph(b("Target Exams"), S['TableHeader']),
         Paragraph(b("Evidence Base"), S['TableHeader']),
         Paragraph(b("Year"), S['TableHeader'])],
        [Paragraph("Gastroenterology\nGeneral Medicine", S['TableCell']),
         Paragraph("FCPS-II, MRCP Part 1/2\nResidency / USMLE", S['TableCell']),
         Paragraph("Goldman-Cecil, Yamada's\nACG/AGA Guidelines 2022-25", S['TableCell']),
         Paragraph("2025-26\nUpdated", S['TableCell'])]
    ]
    info_tbl = Table(info_data, colWidths=[1.4*inch, 1.6*inch, 2.2*inch, 1.0*inch])
    info_tbl.setStyle(TableStyle([
        ('BACKGROUND', (0,0), (-1,0), DARK_BLUE),
        ('BACKGROUND', (0,1), (-1,1), LIGHT_BLUE),
        ('TEXTCOLOR', (0,0), (-1,0), WHITE),
        ('FONTNAME', (0,0), (-1,0), 'Helvetica-Bold'),
        ('FONTSIZE', (0,0), (-1,-1), 8.5),
        ('ALIGN', (0,0), (-1,-1), 'CENTER'),
        ('VALIGN', (0,0), (-1,-1), 'MIDDLE'),
        ('GRID', (0,0), (-1,-1), 0.5, colors.white),
        ('ROWBACKGROUNDS', (0,1), (-1,-1), [LIGHT_BLUE]),
        ('ROUNDEDCORNERS', [5,5,5,5]),
        ('TOPPADDING', (0,0), (-1,-1), 6),
        ('BOTTOMPADDING', (0,0), (-1,-1), 6),
    ]))
    elems.append(info_tbl)
    elems.append(sp(14))

    # Topics covered
    elems.append(Paragraph(b("Topics Covered in This Document"), S['H2']))
    elems.append(hr())
    topics = [
        ("1", "Definition & Epidemiology", MID_BLUE),
        ("2", "Pathophysiology & Mechanisms", TEAL),
        ("3", "Clinical Features (Typical & Atypical)", ACCENT_GREEN),
        ("4", "Diagnosis & Investigations", ACCENT_ORANGE),
        ("5", "Los Angeles Classification", ACCENT_RED),
        ("6", "Complications (Barrett's, Stricture, Adenocarcinoma)", PURPLE),
        ("7", "Management (Stepwise Approach)", DARK_BLUE),
        ("8", "Surgery & Endoscopic Therapy", MID_BLUE),
        ("9", "Special Situations & High-Yield Points", TEAL),
        ("10", "Exam High-Yield Summary", ACCENT_RED),
    ]
    tdata = []
    row = []
    for idx, (num, topic, col) in enumerate(topics):
        cell_para = Paragraph(
            f'<font color="{col.hexval()}"><b>{num}.</b></font> {topic}',
            S['Bullet']
        )
        row.append(cell_para)
        if len(row) == 2:
            tdata.append(row)
            row = []
    if row:
        row.append(Paragraph("", S['Body']))
        tdata.append(row)

    tbl = Table(tdata, colWidths=[3.1*inch, 3.1*inch])
    tbl.setStyle(TableStyle([
        ('BACKGROUND', (0,0), (-1,-1), GREY_BG),
        ('GRID', (0,0), (-1,-1), 0.5, colors.white),
        ('TOPPADDING', (0,0), (-1,-1), 6),
        ('BOTTOMPADDING', (0,0), (-1,-1), 6),
        ('LEFTPADDING', (0,0), (-1,-1), 8),
    ]))
    elems.append(tbl)
    elems.append(sp(14))

    # Source note
    elems.append(Paragraph(
        f'<i>Sources: Goldman-Cecil Medicine (26e) · Yamada\'s Textbook of Gastroenterology (7e) · '
        f'Robbins &amp; Cotran Pathologic Basis of Disease · Current Surgical Therapy (14e) · '
        f'ACG Clinical Guidelines 2022 · AGA Guidelines 2022 · ASGE Guidelines 2025</i>',
        S['SmallNote']
    ))
    elems.append(PageBreak())
    return elems


# ── Section 1: Definition & Epidemiology ────────────────────────────────────
def section1():
    elems = []
    elems.append(SectionDivider(1, "Definition & Epidemiology", DARK_BLUE))
    elems.append(sp(8))

    elems.append(Paragraph(b("Definition (Montreal Consensus)"), S['H3']))
    elems.append(Paragraph(
        "GERD is defined as a condition that develops when the reflux of stomach contents into the "
        "esophagus causes <b>troublesome symptoms</b> or <b>complications</b>. Physiologic reflux "
        "occurs in everyone; GERD is diagnosed when it becomes clinically significant.",
        S['Body']
    ))
    elems.append(sp(6))

    # Epidemiology table
    elems.append(Paragraph(b("Epidemiology"), S['H3']))
    epi_data = [
        [Paragraph(b("Parameter"), S['TableHeader']),
         Paragraph(b("Data"), S['TableHeader'])],
        [Paragraph("Global Prevalence", S['TableCell']),
         Paragraph("10-20% in Western world; <5% in Asia", S['TableCell'])],
        [Paragraph("USA Prevalence", S['TableCell']),
         Paragraph("~44% ever had symptoms; ~30% in prior week", S['TableCell'])],
        [Paragraph("Gender", S['TableCell']),
         Paragraph("Equal M=F for GERD; M>F for Barrett's esophagus", S['TableCell'])],
        [Paragraph("Age", S['TableCell']),
         Paragraph("Increases with age; plateau at 7th-9th decade for Barrett's", S['TableCell'])],
        [Paragraph("Highest in", S['TableCell']),
         Paragraph("North America > Europe; Northern Europe > Southern Europe", S['TableCell'])],
    ]
    epi_tbl = Table(epi_data, colWidths=[2.0*inch, 4.2*inch])
    epi_tbl.setStyle(TableStyle([
        ('BACKGROUND', (0,0), (-1,0), DARK_BLUE),
        ('BACKGROUND', (0,1), (-1,1), LIGHT_BLUE),
        ('ROWBACKGROUNDS', (0,1), (-1,-1), [LIGHT_BLUE, WHITE]),
        ('TEXTCOLOR', (0,0), (-1,0), WHITE),
        ('GRID', (0,0), (-1,-1), 0.5, colors.HexColor("#CCCCCC")),
        ('FONTSIZE', (0,0), (-1,-1), 8.5),
        ('TOPPADDING', (0,0), (-1,-1), 5),
        ('BOTTOMPADDING', (0,0), (-1,-1), 5),
        ('LEFTPADDING', (0,0), (-1,-1), 8),
    ]))
    elems.append(epi_tbl)
    elems.append(sp(8))

    elems.append(Paragraph(b("Risk Factors"), S['H3']))
    rf_data = [
        [Paragraph(b("Modifiable"), S['TableHeader']),
         Paragraph(b("Non-modifiable"), S['TableHeader'])],
        [Paragraph(
            "• Obesity / central adiposity\n• High-fat diet, spicy foods, chocolate, caffeine\n"
            "• Alcohol & smoking\n• Late-night meals, large meals\n• Certain drugs (CCBs, nitrates,\n"
            "  anticholinergics, bisphosphonates)\n• Pregnancy",
            S['TableCell']),
         Paragraph(
            "• Male sex (for Barrett's esophagus)\n• Older age\n• Positive family history\n"
            "• Monozygotic twin concordance\n• White/European ethnicity\n• Hiatal hernia",
            S['TableCell'])]
    ]
    rf_tbl = Table(rf_data, colWidths=[3.1*inch, 3.1*inch])
    rf_tbl.setStyle(TableStyle([
        ('BACKGROUND', (0,0), (-1,0), TEAL),
        ('BACKGROUND', (0,1), (0,1), colors.HexColor("#E8F5E9")),
        ('BACKGROUND', (1,1), (1,1), colors.HexColor("#FFF3E0")),
        ('TEXTCOLOR', (0,0), (-1,0), WHITE),
        ('GRID', (0,0), (-1,-1), 0.5, colors.HexColor("#CCCCCC")),
        ('FONTSIZE', (0,0), (-1,-1), 8.5),
        ('TOPPADDING', (0,0), (-1,-1), 6),
        ('BOTTOMPADDING', (0,0), (-1,-1), 6),
        ('LEFTPADDING', (0,0), (-1,-1), 8),
        ('VALIGN', (0,0), (-1,-1), 'TOP'),
    ]))
    elems.append(rf_tbl)
    elems.append(sp(8))
    return elems


# ── Section 2: Pathophysiology ───────────────────────────────────────────────
def section2():
    elems = []
    elems.append(SectionDivider(2, "Pathophysiology", TEAL))
    elems.append(sp(8))

    elems.append(Paragraph(b("Anti-Reflux Barrier (Normal Defense)"), S['H3']))
    elems.append(Paragraph(
        "The esophagus is protected by four overlapping mechanisms. Failure of any of these "
        "leads to pathologic reflux:", S['Body']
    ))
    defense_data = [
        [Paragraph(b("Defense Mechanism"), S['TableHeader']),
         Paragraph(b("Components"), S['TableHeader']),
         Paragraph(b("Role"), S['TableHeader'])],
        [Paragraph("1. Anti-reflux Barrier", S['TableCell']),
         Paragraph("LES + crural diaphragm + phrenoesophageal\nligament + angle of His", S['TableCell']),
         Paragraph("Primary mechanical barrier", S['TableCell'])],
        [Paragraph("2. Esophageal Clearance", S['TableCell']),
         Paragraph("Peristalsis (volume) + swallowed saliva\n(acid neutralization)", S['TableCell']),
         Paragraph("Clears refluxed material", S['TableCell'])],
        [Paragraph("3. Epithelial Defense", S['TableCell']),
         Paragraph("Mucous layer + tight junctions +\nbicarbonate secretion", S['TableCell']),
         Paragraph("Resists mucosal injury", S['TableCell'])],
        [Paragraph("4. Gastric Emptying", S['TableCell']),
         Paragraph("Normal gastric motility", S['TableCell']),
         Paragraph("Reduces gastric volume available to reflux", S['TableCell'])],
    ]
    def_tbl = Table(defense_data, colWidths=[1.6*inch, 2.6*inch, 1.9*inch])
    def_tbl.setStyle(TableStyle([
        ('BACKGROUND', (0,0), (-1,0), TEAL),
        ('ROWBACKGROUNDS', (0,1), (-1,-1), [LIGHT_BLUE, WHITE]),
        ('TEXTCOLOR', (0,0), (-1,0), WHITE),
        ('GRID', (0,0), (-1,-1), 0.5, colors.HexColor("#CCCCCC")),
        ('FONTSIZE', (0,0), (-1,-1), 8.5),
        ('TOPPADDING', (0,0), (-1,-1), 5),
        ('BOTTOMPADDING', (0,0), (-1,-1), 5),
        ('LEFTPADDING', (0,0), (-1,-1), 6),
        ('VALIGN', (0,0), (-1,-1), 'TOP'),
    ]))
    elems.append(def_tbl)
    elems.append(sp(8))

    # Pathophysiology diagram
    elems.append(Paragraph(b("Mechanisms of GERD (Stepwise Pathway)"), S['H3']))
    elems.append(PathwayArrow(
        ["tLESR\n(most common)", "Low LES\nPressure", "Hiatal\nHernia", "Impaired\nClearance", "Mucosal\nDamage"],
        [MID_BLUE, TEAL, ACCENT_ORANGE, PURPLE, ACCENT_RED]
    ))
    elems.append(sp(4))

    elems.append(Paragraph(b("Key Pathophysiologic Mechanisms"), S['H3']))

    mechs = [
        ("Transient LES Relaxations (tLESRs) - MOST COMMON",
         "Vagally-mediated reflex triggered by gastric distension. LES relaxes WITHOUT a swallow. "
         "This is the dominant mechanism in GERD patients. GABA-B receptor agonists (baclofen) and "
         "mGluR5 antagonists can reduce tLESRs."),
        ("Low Resting LES Pressure",
         "Normal LES pressure: 10-35 mmHg. A pressure <6 mmHg = free reflux. "
         "Associated with: scleroderma, certain drugs (CCBs, nitrates, theophylline, "
         "anticholinergics), foods (fat, chocolate, peppermint, alcohol)."),
        ("Hiatal Hernia",
         "Displaces LES above the diaphragm, separating LES from crural diaphragm. "
         "Creates a 'trap' (hernia sac) for gastric contents that can reflux during LES relaxation. "
         "Displaces the acid pocket (unbuffered acid in gastric cardia) into the hernia, "
         "worsening postprandial reflux. The larger the hernia, the worse the GERD."),
        ("Obesity",
         "Central fat increases intra-abdominal pressure → increases gastroesophageal pressure gradient "
         "→ promotes tLESRs. Also increases hiatal hernia incidence and disturbs GEJ anatomy."),
        ("Impaired Esophageal Clearance",
         "Reduced peristaltic amplitude or frequency fails to clear refluxed material. "
         "Saliva production reduced during sleep, explaining nocturnal GERD severity."),
        ("Delayed Gastric Emptying",
         "Increased gastric volume → more material available to reflux. Relevant in diabetic gastroparesis."),
        ("Acid Pocket",
         "Unbuffered acid accumulates just below GEJ post-prandially. In GERD patients, this pocket is "
         "larger and more proximal, and may extend into a hiatal hernia sac."),
    ]
    for title, text in mechs:
        elems.append(Paragraph(f"<b>{title}</b>", S['H4']))
        elems.append(Paragraph(text, S['Body']))

    elems.append(sp(8))

    # Injurious agents table
    elems.append(Paragraph(b("Injurious Agents in Refluxate"), S['H3']))
    agents_data = [
        [Paragraph(b("Agent"), S['TableHeader']),
         Paragraph(b("Damage"), S['TableHeader']),
         Paragraph(b("Clinical Significance"), S['TableHeader'])],
        [Paragraph("Hydrochloric Acid", S['TableCell']),
         Paragraph("Denatures proteins, disrupts tight junctions", S['TableCell']),
         Paragraph("Primary injurious agent; pH <4 most harmful", S['TableCell'])],
        [Paragraph("Pepsin", S['TableCell']),
         Paragraph("Proteolytic; active at pH <4", S['TableCell']),
         Paragraph("Potentiates acid injury", S['TableCell'])],
        [Paragraph("Bile Salts", S['TableCell']),
         Paragraph("Detergent effect on mucosa", S['TableCell']),
         Paragraph("Important in Barrett's development", S['TableCell'])],
        [Paragraph("Trypsin/Pancreatic enzymes", S['TableCell']),
         Paragraph("Mucosal injury at alkaline pH", S['TableCell']),
         Paragraph("Relevant in post-gastrectomy, duodenogastric reflux", S['TableCell'])],
    ]
    agents_tbl = Table(agents_data, colWidths=[1.5*inch, 2.0*inch, 2.65*inch])
    agents_tbl.setStyle(TableStyle([
        ('BACKGROUND', (0,0), (-1,0), PURPLE),
        ('ROWBACKGROUNDS', (0,1), (-1,-1), [colors.HexColor("#F3E5F5"), WHITE]),
        ('TEXTCOLOR', (0,0), (-1,0), WHITE),
        ('GRID', (0,0), (-1,-1), 0.5, colors.HexColor("#CCCCCC")),
        ('FONTSIZE', (0,0), (-1,-1), 8.5),
        ('TOPPADDING', (0,0), (-1,-1), 5),
        ('BOTTOMPADDING', (0,0), (-1,-1), 5),
        ('LEFTPADDING', (0,0), (-1,-1), 6),
        ('VALIGN', (0,0), (-1,-1), 'TOP'),
    ]))
    elems.append(agents_tbl)
    elems.append(sp(8))
    return elems


# ── Section 3: Clinical Features ────────────────────────────────────────────
def section3():
    elems = []
    elems.append(SectionDivider(3, "Clinical Features", ACCENT_GREEN))
    elems.append(sp(8))

    # GERD Syndrome Classification
    elems.append(Paragraph(b("Montreal Classification of GERD Syndromes"), S['H3']))
    mc_data = [
        [Paragraph(b("Esophageal Syndromes"), S['TableHeader']),
         Paragraph(b("Extra-Esophageal Syndromes"), S['TableHeader'])],
        [Paragraph(
            "<b>Symptomatic Syndromes:</b>\n"
            "• Typical reflux syndrome (heartburn + regurgitation)\n"
            "• Reflux chest pain syndrome\n\n"
            "<b>Syndromes with esophageal injury:</b>\n"
            "• Reflux esophagitis\n• Reflux stricture\n• Barrett's esophagus\n"
            "• Esophageal adenocarcinoma",
            S['TableCell']),
         Paragraph(
            "<b>Established associations:</b>\n"
            "• Reflux cough syndrome\n• Reflux laryngitis syndrome\n"
            "• Reflux asthma syndrome\n• Reflux dental erosion syndrome\n\n"
            "<b>Proposed associations:</b>\n"
            "• Sinusitis, pharyngitis, recurrent otitis media\n"
            "• Idiopathic pulmonary fibrosis\n• Recurrent aspiration pneumonia",
            S['TableCell'])]
    ]
    mc_tbl = Table(mc_data, colWidths=[3.1*inch, 3.1*inch])
    mc_tbl.setStyle(TableStyle([
        ('BACKGROUND', (0,0), (-1,0), ACCENT_GREEN),
        ('BACKGROUND', (0,1), (0,1), colors.HexColor("#E8F5E9")),
        ('BACKGROUND', (1,1), (1,1), colors.HexColor("#E3F2FD")),
        ('TEXTCOLOR', (0,0), (-1,0), WHITE),
        ('GRID', (0,0), (-1,-1), 0.5, colors.HexColor("#CCCCCC")),
        ('FONTSIZE', (0,0), (-1,-1), 8.5),
        ('TOPPADDING', (0,0), (-1,-1), 6),
        ('BOTTOMPADDING', (0,0), (-1,-1), 6),
        ('LEFTPADDING', (0,0), (-1,-1), 8),
        ('VALIGN', (0,0), (-1,-1), 'TOP'),
    ]))
    elems.append(mc_tbl)
    elems.append(sp(8))

    elems.append(Paragraph(b("Typical Symptoms"), S['H3']))
    typical = [
        ("Heartburn", "Retrosternal burning sensation radiating upward from epigastrium to throat. "
         "Worsens after meals, when bending, or lying down. Relieved by antacids. "
         "<b>High specificity but LOW sensitivity</b> for GERD."),
        ("Regurgitation", "Effortless return of gastric contents to oropharynx/mouth with sour/bitter taste. "
         "NOT preceded by nausea. Bending/belching provokes it. "
         "<b>Distinguish from vomiting</b> (which requires effort and nausea) and "
         "<b>rumination</b> (effortless, subconscious, during meals, no heartburn)."),
        ("Water Brash", "Excessive salivation (mouth fills with saliva) - vagal reflex from esophageal acidification."),
        ("Globus", "Sensation of a lump or fullness in the throat, irrespective of swallowing."),
        ("Dysphagia", "Reported by >30% of GERD patients. Causes: peptic stricture, Schatzki ring, "
         "impaired peristalsis, or mucosal inflammation. <b>Alarm symptom</b> - needs endoscopy."),
        ("Odynophagia", "Pain on swallowing - suggests esophageal ulcer or deep erosion. <b>Alarm symptom.</b>"),
    ]
    for name, desc in typical:
        elems.append(Paragraph(f"<b>{name}:</b> {desc}", S['Bullet']))
        elems.append(sp(3))

    elems.append(sp(6))
    elems.append(Paragraph(b("Alarm Symptoms (Red Flags) - Mandate Urgent Endoscopy"), S['H3']))

    class RedFlagBox(Flowable):
        def wrap(self, aw, ah):
            self.width = aw
            return (aw, 1.1*inch)
        def draw(self):
            c = self.canv
            w = self.width
            c.setFillColor(colors.HexColor("#FFEBEE"))
            c.roundRect(0, 0, w, 1.0*inch, 6, fill=1, stroke=0)
            c.setStrokeColor(ACCENT_RED)
            c.setLineWidth(2)
            c.roundRect(0, 0, w, 1.0*inch, 6, fill=0, stroke=1)
            c.setFillColor(ACCENT_RED)
            c.setFont("Helvetica-Bold", 10)
            c.drawString(10, 0.8*inch, "RED FLAGS - REFER FOR URGENT ENDOSCOPY")
            c.setFont("Helvetica", 8.5)
            c.setFillColor(BLACK)
            flags = [
                "• Dysphagia  • Odynophagia  • Unintentional weight loss",
                "• Anemia / hematemesis / melena  • Palpable abdominal mass",
                "• Progressive symptoms despite adequate PPI therapy  • Age >55 with new-onset symptoms",
            ]
            for j, flag in enumerate(flags):
                c.drawString(10, 0.58*inch - j*0.16*inch, flag)

    elems.append(RedFlagBox())
    elems.append(sp(8))

    elems.append(Paragraph(b("Atypical (Extra-Esophageal) Symptoms"), S['H3']))
    atypical_data = [
        [Paragraph(b("System"), S['TableHeader']),
         Paragraph(b("Manifestation"), S['TableHeader']),
         Paragraph(b("Notes"), S['TableHeader'])],
        [Paragraph("Pulmonary", S['TableCell']),
         Paragraph("Chronic cough, asthma, aspiration pneumonia,\nidiopathic pulmonary fibrosis", S['TableCell']),
         Paragraph("GERD is 3rd most common cause of chronic cough\n(after rhinosinusitis, asthma). "
                   "50-75% have NO typical GERD symptoms.", S['TableCell'])],
        [Paragraph("ENT", S['TableCell']),
         Paragraph("Laryngitis, hoarseness, globus, chronic\nthroat-clearing, subglottic stenosis", S['TableCell']),
         Paragraph("Laryngopharyngeal reflux (LPR); "
                   "Reinke's edema, posterior laryngitis (cobblestoning)", S['TableCell'])],
        [Paragraph("Dental", S['TableCell']),
         Paragraph("Dental erosions (enamel erosion)", S['TableCell']),
         Paragraph("Prevalence 17-68% in GERD patients;\npalatal surface most affected", S['TableCell'])],
        [Paragraph("Cardiac", S['TableCell']),
         Paragraph("Non-cardiac chest pain (NCCP)", S['TableCell']),
         Paragraph("GERD is MOST COMMON esophageal cause of NCCP\n(more than spastic motor disorders). "
                   "Abnormal pH in 21-48% of NCCP.", S['TableCell'])],
        [Paragraph("Sleep", S['TableCell']),
         Paragraph("Nocturnal symptoms, sleep apnea", S['TableCell']),
         Paragraph("Head-of-bed elevation recommended", S['TableCell'])],
    ]
    atyp_tbl = Table(atypical_data, colWidths=[1.1*inch, 2.0*inch, 3.05*inch])
    atyp_tbl.setStyle(TableStyle([
        ('BACKGROUND', (0,0), (-1,0), ACCENT_GREEN),
        ('ROWBACKGROUNDS', (0,1), (-1,-1), [colors.HexColor("#E8F5E9"), WHITE]),
        ('TEXTCOLOR', (0,0), (-1,0), WHITE),
        ('GRID', (0,0), (-1,-1), 0.5, colors.HexColor("#CCCCCC")),
        ('FONTSIZE', (0,0), (-1,-1), 8.5),
        ('TOPPADDING', (0,0), (-1,-1), 5),
        ('BOTTOMPADDING', (0,0), (-1,-1), 5),
        ('LEFTPADDING', (0,0), (-1,-1), 6),
        ('VALIGN', (0,0), (-1,-1), 'TOP'),
    ]))
    elems.append(atyp_tbl)
    elems.append(sp(8))
    return elems


# ── Section 4: Diagnosis ─────────────────────────────────────────────────────
def section4():
    elems = []
    elems.append(SectionDivider(4, "Diagnosis & Investigations", ACCENT_ORANGE))
    elems.append(sp(8))

    # Diagnostic algorithm
    elems.append(Paragraph(b("Diagnostic Algorithm (ACG/AGA 2022 Guidelines)"), S['H3']))
    algo_data = [
        [Paragraph(b("Step"), S['TableHeader']),
         Paragraph(b("Action"), S['TableHeader']),
         Paragraph(b("Recommendation"), S['TableHeader'])],
        [Paragraph("Step 1", S['TableCell']),
         Paragraph("Classic symptoms (heartburn + regurgitation)\nNO alarm features", S['TableCell']),
         Paragraph("Empiric 8-week PPI trial (once daily before meal)\n"
                   "[Strong recommendation, moderate evidence - ACG 2022]", S['TableCell'])],
        [Paragraph("Step 2a", S['TableCell']),
         Paragraph("Symptoms respond to PPI trial", S['TableCell']),
         Paragraph("Attempt PPI discontinuation. If recurrence → long-term PPI\n"
                   "(on-demand or continuous)", S['TableCell'])],
        [Paragraph("Step 2b", S['TableCell']),
         Paragraph("Symptoms do NOT respond adequately\nOR symptoms recur on stopping PPI", S['TableCell']),
         Paragraph("Upper endoscopy (after stopping PPI for 2-4 weeks ideally)\n"
                   "[Strong recommendation]", S['TableCell'])],
        [Paragraph("Step 3a", S['TableCell']),
         Paragraph("Endoscopy shows LA Grade C/D esophagitis,\nlong-segment Barrett's, or peptic stricture", S['TableCell']),
         Paragraph("GERD confirmed. No need for reflux monitoring off therapy.\n"
                   "Initiate aggressive management.", S['TableCell'])],
        [Paragraph("Step 3b", S['TableCell']),
         Paragraph("Endoscopy normal / LA Grade A or B only", S['TableCell']),
         Paragraph("Reflux monitoring OFF therapy (pH or impedance-pH)\n"
                   "to confirm diagnosis [Strong recommendation]", S['TableCell'])],
        [Paragraph("Step 4", S['TableCell']),
         Paragraph("Extraesophageal symptoms WITHOUT\ntypical GERD symptoms", S['TableCell']),
         Paragraph("Reflux testing before PPI therapy (to establish GERD)\n"
                   "then treat concurrent esophageal GERD syndrome", S['TableCell'])],
    ]
    algo_tbl = Table(algo_data, colWidths=[0.85*inch, 2.3*inch, 3.0*inch])
    algo_tbl.setStyle(TableStyle([
        ('BACKGROUND', (0,0), (-1,0), ACCENT_ORANGE),
        ('ROWBACKGROUNDS', (0,1), (-1,-1), [colors.HexColor("#FFF3E0"), WHITE]),
        ('TEXTCOLOR', (0,0), (-1,0), WHITE),
        ('GRID', (0,0), (-1,-1), 0.5, colors.HexColor("#CCCCCC")),
        ('FONTSIZE', (0,0), (-1,-1), 8.5),
        ('TOPPADDING', (0,0), (-1,-1), 5),
        ('BOTTOMPADDING', (0,0), (-1,-1), 5),
        ('LEFTPADDING', (0,0), (-1,-1), 6),
        ('VALIGN', (0,0), (-1,-1), 'TOP'),
    ]))
    elems.append(algo_tbl)
    elems.append(sp(8))

    elems.append(Paragraph(b("Investigations in Detail"), S['H3']))

    inv_data = [
        [Paragraph(b("Investigation"), S['TableHeader']),
         Paragraph(b("Indication / Use"), S['TableHeader']),
         Paragraph(b("Key Facts"), S['TableHeader'])],
        [Paragraph("Upper GI Endoscopy\n(OGD/EGD)", S['TableCell']),
         Paragraph("• Alarm symptoms\n• Failure of empiric PPI\n• Confirm GERD\n"
                   "• Surveillance (Barrett's)", S['TableCell']),
         Paragraph("LA Grade C/D or Barrett's = definitive GERD.\n"
                   "Ideally off PPI 2-4 weeks before. Biopsy for "
                   "Barrett's/dysplasia.", S['TableCell'])],
        [Paragraph("Ambulatory 24-hr\npH Monitoring", S['TableCell']),
         Paragraph("• Gold standard for diagnosing GERD\n• Must be OFF PPI (7 days)\n"
                   "• Correlating symptoms with reflux", S['TableCell']),
         Paragraph("DeMeester score >14.72 OR\n"
                   "Acid exposure time (AET) >6% = pathologic.\n"
                   "Wireless capsule: 48-96 hrs, more comfortable.", S['TableCell'])],
        [Paragraph("Impedance-pH\nMonitoring", S['TableCell']),
         Paragraph("• Detects non-acid reflux\n• Persistent symptoms on PPI\n"
                   "• Preferred for extraesophageal GERD", S['TableCell']),
         Paragraph("Can detect weakly acid and non-acid reflux.\n"
                   "Symptom Index (SI) >50% significant.\n"
                   "Symptom Association Probability (SAP) >95% significant.", S['TableCell'])],
        [Paragraph("Esophageal\nManometry (HRM)", S['TableCell']),
         Paragraph("• Pre-surgical workup\n• Rule out achalasia\n"
                   "• Determine type of fundoplication\n• NOT for primary GERD diagnosis", S['TableCell']),
         Paragraph("High-resolution manometry not recommended as\ndiagnostic test for GERD alone. "
                   "Chicago Classification v4.0 for motility disorders.", S['TableCell'])],
        [Paragraph("Barium Esophagram", S['TableCell']),
         Paragraph("• Detect hiatal hernia\n• Evaluate dysphagia\n"
                   "• Assess strictures pre-dilation", S['TableCell']),
         Paragraph("Higher sensitivity than endoscopy for subtle\nstrictures (use solid challenge - barium pill). "
                   "Not sensitive for mild GERD.", S['TableCell'])],
        [Paragraph("Mucosal Impedance\n(new)", S['TableCell']),
         Paragraph("• Adjunct to endoscopy\n• Differentiate GERD from EoE", S['TableCell']),
         Paragraph("Catheter-based balloon sensor during endoscopy.\n"
                   "Promising - detects mucosal integrity changes. ASGE 2025.", S['TableCell'])],
    ]
    inv_tbl = Table(inv_data, colWidths=[1.4*inch, 2.0*inch, 2.75*inch])
    inv_tbl.setStyle(TableStyle([
        ('BACKGROUND', (0,0), (-1,0), DARK_BLUE),
        ('ROWBACKGROUNDS', (0,1), (-1,-1), [LIGHT_BLUE, WHITE]),
        ('TEXTCOLOR', (0,0), (-1,0), WHITE),
        ('GRID', (0,0), (-1,-1), 0.5, colors.HexColor("#CCCCCC")),
        ('FONTSIZE', (0,0), (-1,-1), 8.5),
        ('TOPPADDING', (0,0), (-1,-1), 5),
        ('BOTTOMPADDING', (0,0), (-1,-1), 5),
        ('LEFTPADDING', (0,0), (-1,-1), 6),
        ('VALIGN', (0,0), (-1,-1), 'TOP'),
    ]))
    elems.append(inv_tbl)
    elems.append(sp(8))
    return elems


# ── Section 5: Los Angeles Classification (with image) ──────────────────────
def section5():
    elems = []
    elems.append(SectionDivider(5, "Los Angeles Classification of Esophagitis", ACCENT_RED))
    elems.append(sp(8))

    la_data = [
        [Paragraph(b("Grade"), S['TableHeader']),
         Paragraph(b("Endoscopic Finding"), S['TableHeader']),
         Paragraph(b("Clinical Significance"), S['TableHeader'])],
        [Paragraph("A", S['TableCell']),
         Paragraph("One or more mucosal breaks <5 mm long,\nnot extending between tops of 2 mucosal folds", S['TableCell']),
         Paragraph("Mild esophagitis; PPI for 4-8 weeks. May not confirm GERD diagnosis alone.", S['TableCell'])],
        [Paragraph("B", S['TableCell']),
         Paragraph("One or more mucosal breaks >5 mm long,\nnot extending between tops of 2 mucosal folds", S['TableCell']),
         Paragraph("Moderate; 8 weeks PPI, re-endoscope to confirm healing.", S['TableCell'])],
        [Paragraph("C", S['TableCell']),
         Paragraph("Mucosal break continuous between tops of\n≥2 folds but <75% of circumference", S['TableCell']),
         Paragraph("Severe; CONFIRMS GERD diagnosis. 8-12 weeks high-dose PPI.\n"
                   "No need for pH monitoring to confirm diagnosis.", S['TableCell'])],
        [Paragraph("D", S['TableCell']),
         Paragraph("Mucosal break involving ≥75% of\nesophageal circumference", S['TableCell']),
         Paragraph("Very severe; CONFIRMS GERD. Consider early surgery referral.\n"
                   "High risk for stricture / Barrett's.", S['TableCell'])],
    ]
    la_tbl = Table(la_data, colWidths=[0.6*inch, 2.5*inch, 3.05*inch])
    la_tbl.setStyle(TableStyle([
        ('BACKGROUND', (0,0), (-1,0), ACCENT_RED),
        ('ROWBACKGROUNDS', (0,1), (-1,-1), [colors.HexColor("#FFEBEE"), WHITE]),
        ('TEXTCOLOR', (0,0), (-1,0), WHITE),
        ('GRID', (0,0), (-1,-1), 0.5, colors.HexColor("#CCCCCC")),
        ('FONTSIZE', (0,0), (-1,-1), 8.5),
        ('TOPPADDING', (0,0), (-1,-1), 6),
        ('BOTTOMPADDING', (0,0), (-1,-1), 6),
        ('LEFTPADDING', (0,0), (-1,-1), 8),
        ('VALIGN', (0,0), (-1,-1), 'TOP'),
    ]))
    elems.append(la_tbl)
    elems.append(sp(8))

    # Try to include the LA classification image
    img_url = "https://cdn.orris.care/cdss_images/f94e730e08c384d7bb094a78cdb91d45929bbb7a711a437b276f749072dc6c07.png"
    img_path = "/home/daytona/workspace/gerd-notes/la_classification.png"
    try:
        urllib.request.urlretrieve(img_url, img_path)
        if os.path.exists(img_path) and os.path.getsize(img_path) > 1000:
            elems.append(Paragraph(b("Endoscopic Images - Los Angeles Classification"), S['H3']))
            img = Image(img_path, width=5.5*inch, height=2.8*inch)
            img.hAlign = 'CENTER'
            elems.append(img)
            elems.append(Paragraph(
                "Fig. 1: Los Angeles Classification of reflux esophagitis (Grades A-D). "
                "Grade A: small isolated mucosal break. Grade B: larger break. "
                "Grade C: confluent breaks <75% circumference. Grade D: circumferential involvement. "
                "(Source: Current Surgical Therapy 14e / Nayar & Vaezi, 2004)",
                S['Caption']
            ))
    except Exception as e:
        elems.append(Paragraph(f"[Image: LA Classification diagram - {str(e)[:50]}]", S['Caption']))

    elems.append(sp(8))

    elems.append(Paragraph(b("Key Exam Point on LA Classification"), S['H3']))
    elems.append(Paragraph(
        "LA Grade C or D = definitive confirmation of GERD diagnosis (no need for pH monitoring). "
        "LA Grade A or B = insufficient to confirm GERD (may be seen in healthy subjects); "
        "if diagnosis uncertain, proceed to reflux monitoring off PPI therapy. "
        "Note: up to 30% of LA Grade A lesions may be normal variants.",
        S['Body']
    ))
    elems.append(sp(8))
    return elems


# ── Section 6: Complications ─────────────────────────────────────────────────
def section6():
    elems = []
    elems.append(SectionDivider(6, "Complications of GERD", PURPLE))
    elems.append(sp(8))

    # Complications overview
    elems.append(PathwayArrow(
        ["Esophagitis\n(erosive)", "Peptic\nUlcer", "Stricture\n(peptic)", "Barrett's\nEsophagus", "Adeno-\ncarcinoma"],
        [MID_BLUE, TEAL, ACCENT_ORANGE, PURPLE, ACCENT_RED]
    ))
    elems.append(sp(4))

    elems.append(Paragraph(b("1. Erosive Esophagitis"), S['H3']))
    elems.append(Paragraph(
        "Mucosal breaks (erosions/ulcerations) in the distal esophagus. Classified by LA system. "
        "Heals with 8-12 weeks PPI therapy. Recurrence common if PPI stopped. "
        "Complications: bleeding (hematemesis/anemia), stricture.",
        S['Body']
    ))

    elems.append(Paragraph(b("2. Peptic Stricture"), S['H3']))
    elems.append(Paragraph(
        "Fibrous narrowing from chronic acid injury and healing. Presents as <b>progressive "
        "dysphagia to solids</b>. Diagnosed on barium esophagram (higher sensitivity) or endoscopy. "
        "Treatment: endoscopic dilation (gradual, to ≥13 mm) + long-term PPI. "
        "For recalcitrant strictures: intralesional triamcinolone injection.",
        S['Body']
    ))

    elems.append(Paragraph(b("3. Barrett's Esophagus"), S['H3']))
    elems.append(Paragraph(
        "Intestinal metaplasia replaces normal squamous epithelium of distal esophagus. "
        "The most important complication due to its association with esophageal adenocarcinoma.",
        S['Body']
    ))

    be_data = [
        [Paragraph(b("Feature"), S['TableHeader']),
         Paragraph(b("Details"), S['TableHeader'])],
        [Paragraph("Prevalence", S['TableCell']),
         Paragraph("5-15% of endoscopy patients with GERD symptoms; 1.3-1.6% general population", S['TableCell'])],
        [Paragraph("Demographics", S['TableCell']),
         Paragraph("Middle-aged White men; ~25% are women or <50 yrs; 45% have NO reflux symptoms", S['TableCell'])],
        [Paragraph("Risk Factors", S['TableCell']),
         Paragraph("Long-standing reflux, smoking, male sex, older age, central obesity, White ethnicity", S['TableCell'])],
        [Paragraph("Endoscopic Appearance", S['TableCell']),
         Paragraph("Tongues of red, velvety mucosa extending upward from GEJ\n"
                   "(salmon-colored mucosa above Z-line)", S['TableCell'])],
        [Paragraph("Classification", S['TableCell']),
         Paragraph("Long-segment: ≥3 cm | Short-segment: <3 cm (lower cancer risk)", S['TableCell'])],
        [Paragraph("Histology (MUST KNOW)", S['TableCell']),
         Paragraph("Intestinal-type metaplasia with GOBLET CELLS (wine goblet shape, alcian-blue positive).\n"
                   "Goblet cells are DIAGNOSTIC of Barrett's.", S['TableCell'])],
        [Paragraph("Cancer Risk", S['TableCell']),
         Paragraph("Annual cancer risk ~0.1-0.3% per year overall; higher with dysplasia and long-segment.\n"
                   "CDX2 transcription factor promotes columnar metaplasia.", S['TableCell'])],
        [Paragraph("Dysplasia Grades", S['TableCell']),
         Paragraph("No dysplasia → Low-grade dysplasia (LGD) → High-grade dysplasia (HGD) → "
                   "Adenocarcinoma\nAtypical mitoses, nuclear hyperchromasia, increased N:C ratio", S['TableCell'])],
    ]
    be_tbl = Table(be_data, colWidths=[1.6*inch, 4.6*inch])
    be_tbl.setStyle(TableStyle([
        ('BACKGROUND', (0,0), (-1,0), PURPLE),
        ('ROWBACKGROUNDS', (0,1), (-1,-1), [colors.HexColor("#F3E5F5"), WHITE]),
        ('TEXTCOLOR', (0,0), (-1,0), WHITE),
        ('GRID', (0,0), (-1,-1), 0.5, colors.HexColor("#CCCCCC")),
        ('FONTSIZE', (0,0), (-1,-1), 8.5),
        ('TOPPADDING', (0,0), (-1,-1), 5),
        ('BOTTOMPADDING', (0,0), (-1,-1), 5),
        ('LEFTPADDING', (0,0), (-1,-1), 6),
        ('VALIGN', (0,0), (-1,-1), 'TOP'),
    ]))
    elems.append(be_tbl)
    elems.append(sp(8))

    # Barrett's image
    img_url2 = "https://cdn.orris.care/cdss_images/854a9069e076aef6407662efaf7ced76b5083d57a1275c30a53c50192f11de0c.png"
    img_path2 = "/home/daytona/workspace/gerd-notes/barretts.png"

    # Barrett's surveillance table
    elems.append(Paragraph(b("Barrett's Esophagus - Surveillance & Management"), S['H3']))
    surv_data = [
        [Paragraph(b("Histology"), S['TableHeader']),
         Paragraph(b("Surveillance Interval"), S['TableHeader']),
         Paragraph(b("Management"), S['TableHeader'])],
        [Paragraph("No dysplasia", S['TableCell']),
         Paragraph("Every 3-5 years", S['TableCell']),
         Paragraph("Continue PPI. Lifestyle modification.", S['TableCell'])],
        [Paragraph("Indefinite for dysplasia", S['TableCell']),
         Paragraph("Repeat endoscopy in 3-6 months", S['TableCell']),
         Paragraph("Optimize PPI therapy.", S['TableCell'])],
        [Paragraph("Low-grade dysplasia (LGD)", S['TableCell']),
         Paragraph("Every 6 months × 2, then annually", S['TableCell']),
         Paragraph("Endoscopic eradication (RFA, EMR) preferred.\nCan survey if patient declines ablation.", S['TableCell'])],
        [Paragraph("High-grade dysplasia (HGD)", S['TableCell']),
         Paragraph("N/A - treat immediately", S['TableCell']),
         Paragraph("Endoscopic eradication therapy (RFA or EMR).\nEsophagectomy if endoscopic therapy unavailable.", S['TableCell'])],
        [Paragraph("Intramucosal adenocarcinoma\n(T1a)", S['TableCell']),
         Paragraph("N/A - treat immediately", S['TableCell']),
         Paragraph("EMR + RFA if no lymphovascular invasion.", S['TableCell'])],
    ]
    surv_tbl = Table(surv_data, colWidths=[1.6*inch, 1.6*inch, 3.0*inch])
    surv_tbl.setStyle(TableStyle([
        ('BACKGROUND', (0,0), (-1,0), PURPLE),
        ('ROWBACKGROUNDS', (0,1), (-1,-1), [colors.HexColor("#F3E5F5"), WHITE]),
        ('TEXTCOLOR', (0,0), (-1,0), WHITE),
        ('GRID', (0,0), (-1,-1), 0.5, colors.HexColor("#CCCCCC")),
        ('FONTSIZE', (0,0), (-1,-1), 8.5),
        ('TOPPADDING', (0,0), (-1,-1), 5),
        ('BOTTOMPADDING', (0,0), (-1,-1), 5),
        ('LEFTPADDING', (0,0), (-1,-1), 6),
        ('VALIGN', (0,0), (-1,-1), 'TOP'),
    ]))
    elems.append(surv_tbl)
    elems.append(sp(8))
    return elems


# ── Section 7: Management ────────────────────────────────────────────────────
def section7():
    elems = []
    elems.append(SectionDivider(7, "Management of GERD", DARK_BLUE))
    elems.append(sp(8))

    elems.append(Paragraph(b("Step 1: Lifestyle Modifications (All Patients)"), S['H3']))
    lifestyle_data = [
        [Paragraph(b("Recommendation"), S['TableHeader']),
         Paragraph(b("Evidence"), S['TableHeader']),
         Paragraph(b("Notes"), S['TableHeader'])],
        [Paragraph("Weight loss (if overweight/obese)", S['TableCell']),
         Paragraph("Strong (RCT evidence)", S['TableCell']),
         Paragraph("Most effective single lifestyle intervention; reduces tLESRs", S['TableCell'])],
        [Paragraph("Head-of-bed elevation (15-20 cm)", S['TableCell']),
         Paragraph("Good (RCTs)", S['TableCell']),
         Paragraph("For nocturnal symptoms; use bed wedge, not extra pillows", S['TableCell'])],
        [Paragraph("Avoid meals 2-3 hrs before bedtime", S['TableCell']),
         Paragraph("Conditional", S['TableCell']),
         Paragraph("Reduces supine reflux risk", S['TableCell'])],
        [Paragraph("Avoid trigger foods", S['TableCell']),
         Paragraph("Conditional (limited data)", S['TableCell']),
         Paragraph("Fat, chocolate, peppermint, spicy foods, citrus, tomatoes, caffeine, alcohol", S['TableCell'])],
        [Paragraph("Stop smoking", S['TableCell']),
         Paragraph("Conditional", S['TableCell']),
         Paragraph("Smoking reduces LES pressure", S['TableCell'])],
        [Paragraph("Avoid tight clothing", S['TableCell']),
         Paragraph("Expert opinion", S['TableCell']),
         Paragraph("Reduces intra-abdominal pressure", S['TableCell'])],
        [Paragraph("Left lateral decubitus sleeping position", S['TableCell']),
         Paragraph("Good", S['TableCell']),
         Paragraph("Reduces nocturnal acid exposure", S['TableCell'])],
    ]
    ls_tbl = Table(lifestyle_data, colWidths=[1.8*inch, 1.3*inch, 3.1*inch])
    ls_tbl.setStyle(TableStyle([
        ('BACKGROUND', (0,0), (-1,0), MID_BLUE),
        ('ROWBACKGROUNDS', (0,1), (-1,-1), [LIGHT_BLUE, WHITE]),
        ('TEXTCOLOR', (0,0), (-1,0), WHITE),
        ('GRID', (0,0), (-1,-1), 0.5, colors.HexColor("#CCCCCC")),
        ('FONTSIZE', (0,0), (-1,-1), 8.5),
        ('TOPPADDING', (0,0), (-1,-1), 5),
        ('BOTTOMPADDING', (0,0), (-1,-1), 5),
        ('LEFTPADDING', (0,0), (-1,-1), 6),
        ('VALIGN', (0,0), (-1,-1), 'TOP'),
    ]))
    elems.append(ls_tbl)
    elems.append(sp(8))

    elems.append(Paragraph(b("Step 2: Pharmacological Management"), S['H3']))

    elems.append(Paragraph(b("A. Antacids & Alginates"), S['H4']))
    elems.append(bullet("Magnesium/aluminum hydroxide - rapid symptom relief, short-acting"))
    elems.append(bullet("Sodium alginate forms a viscous 'raft' on top of gastric contents, reducing reflux"))
    elems.append(bullet("Suitable for mild, intermittent symptoms. No healing effect on esophagitis."))
    elems.append(sp(4))

    elems.append(Paragraph(b("B. H2-Receptor Antagonists (H2RAs)"), S['H4']))
    elems.append(bullet("Ranitidine (withdrawn - NDMA contamination), Famotidine, Cimetidine, Nizatidine"))
    elems.append(bullet("Competitive reversible histamine H2 receptor blockade on parietal cells"))
    elems.append(bullet("Effective for mild-moderate GERD; tolerance (tachyphylaxis) develops within 2 weeks"))
    elems.append(bullet("Useful as add-on nighttime dose with PPI for nocturnal acid breakthrough"))
    elems.append(sp(4))

    elems.append(Paragraph(b("C. Proton Pump Inhibitors (PPIs) - FIRST-LINE TREATMENT"), S['H4']))

    ppi_data = [
        [Paragraph(b("PPI"), S['TableHeader']),
         Paragraph(b("Dose"), S['TableHeader']),
         Paragraph(b("Notes"), S['TableHeader'])],
        [Paragraph("Omeprazole", S['TableCell']),
         Paragraph("20-40 mg OD/BD", S['TableCell']),
         Paragraph("First PPI; best studied; substrate of CYP2C19 (genetic polymorphism affects efficacy)", S['TableCell'])],
        [Paragraph("Lansoprazole", S['TableCell']),
         Paragraph("15-30 mg OD", S['TableCell']),
         Paragraph("Once daily adequate for GERD maintenance", S['TableCell'])],
        [Paragraph("Pantoprazole", S['TableCell']),
         Paragraph("20-40 mg OD", S['TableCell']),
         Paragraph("Fewest drug interactions; preferred in polypharmacy patients", S['TableCell'])],
        [Paragraph("Rabeprazole", S['TableCell']),
         Paragraph("10-20 mg OD", S['TableCell']),
         Paragraph("Least dependent on CYP2C19; more consistent suppression", S['TableCell'])],
        [Paragraph("Esomeprazole", S['TableCell']),
         Paragraph("20-40 mg OD", S['TableCell']),
         Paragraph("S-isomer of omeprazole; marginally superior healing rates in LA Grade C/D", S['TableCell'])],
        [Paragraph("Dexlansoprazole", S['TableCell']),
         Paragraph("30-60 mg OD", S['TableCell']),
         Paragraph("Dual delayed-release; can be taken without regard to meals (MRCP point)", S['TableCell'])],
    ]
    ppi_tbl = Table(ppi_data, colWidths=[1.3*inch, 1.3*inch, 3.6*inch])
    ppi_tbl.setStyle(TableStyle([
        ('BACKGROUND', (0,0), (-1,0), DARK_BLUE),
        ('ROWBACKGROUNDS', (0,1), (-1,-1), [LIGHT_BLUE, WHITE]),
        ('TEXTCOLOR', (0,0), (-1,0), WHITE),
        ('GRID', (0,0), (-1,-1), 0.5, colors.HexColor("#CCCCCC")),
        ('FONTSIZE', (0,0), (-1,-1), 8.5),
        ('TOPPADDING', (0,0), (-1,-1), 5),
        ('BOTTOMPADDING', (0,0), (-1,-1), 5),
        ('LEFTPADDING', (0,0), (-1,-1), 6),
        ('VALIGN', (0,0), (-1,-1), 'TOP'),
    ]))
    elems.append(ppi_tbl)
    elems.append(sp(6))

    # PPI key points
    ppi_keys = [
        ("TIMING", "Take 30-60 minutes BEFORE the first meal of the day (activates the H+/K+-ATPase)"),
        ("MECHANISM", "Irreversibly block H+/K+-ATPase (proton pump) on parietal cell canalicular membrane. "
         "Bind covalently as active sulfenamide after acid activation."),
        ("EFFICACY", "Heal 80-95% of erosive esophagitis in 8 weeks. Superior to H2RAs."),
        ("ADVERSE EFFECTS", "Short-term: headache, diarrhea, nausea. Long-term: hypomagnesemia, "
         "C. difficile infection, community-acquired pneumonia, bone fractures (prolonged), "
         "vitamin B12 deficiency, renal interstitial nephritis, SIBO"),
        ("REBOUND ACID", "Hypersecretion on stopping PPI; taper gradually in long-term users"),
        ("CYP2C19", "Omeprazole/esomeprazole inhibit CYP2C19 → may reduce clopidogrel efficacy "
         "(IMPORTANT drug interaction for cardiology MRCP questions)"),
    ]
    for key, val in ppi_keys:
        elems.append(Paragraph(f'<font color="{MID_BLUE.hexval()}"><b>{key}:</b></font> {val}', S['Bullet']))
        elems.append(sp(2))

    elems.append(sp(6))
    elems.append(Paragraph(b("D. Potassium-Competitive Acid Blockers (P-CABs) - Vonoprazan"), S['H4']))
    elems.append(Paragraph(
        "Vonoprazan reversibly blocks K+ binding site on H+/K+-ATPase. "
        "Unlike PPIs, does NOT require acid activation → works faster, more consistent suppression. "
        "Meta-analysis (Simadibrata 2024, PMID 38263507) shows superior efficacy vs PPIs in "
        "PPI-resistant GERD. Network meta-analysis (Zhuang 2024, PMID 38345252) shows P-CABs "
        "superior to PPIs for Grade C/D esophagitis healing. Approved in Japan/USA; gaining "
        "adoption in UK/South Asia.",
        S['Body']
    ))
    elems.append(sp(6))

    elems.append(Paragraph(b("E. Other Agents"), S['H4']))
    elems.append(bullet("Sucralfate: cytoprotective; useful in pregnancy (limited systemic absorption)"))
    elems.append(bullet("Prokinetics (metoclopramide, domperidone): limited evidence; used for gastroparesis-related GERD"))
    elems.append(bullet("Baclofen (GABA-B agonist): reduces tLESRs; used in refractory GERD; "
                        "side effects limit use (sedation, confusion) - NOT recommended without objective GERD evidence (ACG)"))
    elems.append(bullet("TCAs / SSRIs: for functional heartburn / visceral hypersensitivity component"))
    elems.append(sp(8))
    return elems


# ── Section 8: Surgery & Endoscopic Therapy ──────────────────────────────────
def section8():
    elems = []
    elems.append(SectionDivider(8, "Surgery & Endoscopic Therapy", MID_BLUE))
    elems.append(sp(8))

    elems.append(Paragraph(b("Indications for Surgical/Endoscopic Referral"), S['H3']))
    ind_items = [
        "Medically refractory GERD (failure of twice-daily PPI for ≥8 weeks)",
        "Patient preference / unwilling to take lifelong medication",
        "Significant PPI side effects or intolerance",
        "Large hiatal hernia with mechanical symptoms",
        "Objective GERD (pH-proven) with persistent symptoms",
        "High-grade dysplasia / early adenocarcinoma in Barrett's esophagus",
        "Esophageal injury (esophagitis, Barrett's) despite adequate medical therapy",
    ]
    for item in ind_items:
        elems.append(bullet(item))

    elems.append(sp(8))
    elems.append(Paragraph(b("Surgical Options"), S['H3']))

    surg_data = [
        [Paragraph(b("Procedure"), S['TableHeader']),
         Paragraph(b("Description"), S['TableHeader']),
         Paragraph(b("Indication / Notes"), S['TableHeader'])],
        [Paragraph("Laparoscopic Nissen\nFundoplication (LNF)\n360° wrap", S['TableCell']),
         Paragraph("Complete 360° posterior wrap of gastric fundus\naround lower esophagus", S['TableCell']),
         Paragraph("Gold standard for normal esophageal motility.\n"
                   "Meta-analysis (Li 2023, PMID 36998190): Nissen vs Toupet - Nissen has lower "
                   "GERD recurrence; Toupet has lower dysphagia rate.", S['TableCell'])],
        [Paragraph("Laparoscopic Toupet\nFundoplication\n270° wrap", S['TableCell']),
         Paragraph("Partial 270° posterior wrap", S['TableCell']),
         Paragraph("Preferred in ineffective esophageal motility (Chicago\nClassification v4.0) "
                   "to prevent post-op dysphagia.", S['TableCell'])],
        [Paragraph("Laparoscopic Dor\n180° anterior wrap", S['TableCell']),
         Paragraph("Anterior partial wrap", S['TableCell']),
         Paragraph("After Heller myotomy for achalasia.\nSometimes used in poor motility.", S['TableCell'])],
        [Paragraph("Magnetic Sphincter\nAugmentation (MSA)\nLINX device", S['TableCell']),
         Paragraph("Ring of magnetic titanium beads placed\naround LES laparoscopically", S['TableCell']),
         Paragraph("Minimally invasive alternative to fundoplication.\nPreserves ability to belch/vomit. "
                   "Requires normal esophageal motility.\nContraindicated: metal allergy, MRI needs.", S['TableCell'])],
        [Paragraph("Roux-en-Y gastric bypass", S['TableCell']),
         Paragraph("Bariatric surgery creating Roux limb", S['TableCell']),
         Paragraph("Excellent anti-reflux effect; preferred in morbid\nobesity with GERD.", S['TableCell'])],
    ]
    surg_tbl = Table(surg_data, colWidths=[1.4*inch, 2.1*inch, 2.65*inch])
    surg_tbl.setStyle(TableStyle([
        ('BACKGROUND', (0,0), (-1,0), MID_BLUE),
        ('ROWBACKGROUNDS', (0,1), (-1,-1), [LIGHT_BLUE, WHITE]),
        ('TEXTCOLOR', (0,0), (-1,0), WHITE),
        ('GRID', (0,0), (-1,-1), 0.5, colors.HexColor("#CCCCCC")),
        ('FONTSIZE', (0,0), (-1,-1), 8.5),
        ('TOPPADDING', (0,0), (-1,-1), 5),
        ('BOTTOMPADDING', (0,0), (-1,-1), 5),
        ('LEFTPADDING', (0,0), (-1,-1), 6),
        ('VALIGN', (0,0), (-1,-1), 'TOP'),
    ]))
    elems.append(surg_tbl)
    elems.append(sp(8))

    elems.append(Paragraph(b("Endoscopic Therapies for Barrett's Esophagus"), S['H3']))
    endo_data = [
        [Paragraph(b("Technique"), S['TableHeader']),
         Paragraph(b("Mechanism"), S['TableHeader']),
         Paragraph(b("Use"), S['TableHeader'])],
        [Paragraph("RFA (Radiofrequency\nAblation)", S['TableCell']),
         Paragraph("Thermal energy delivered via balloon/focal\ncatheter ablates metaplastic mucosa", S['TableCell']),
         Paragraph("First-line for flat Barrett's + dysplasia.\n~80-90% complete eradication of dysplasia.", S['TableCell'])],
        [Paragraph("EMR (Endoscopic\nMucosal Resection)", S['TableCell']),
         Paragraph("Injection + snare resection of visible nodules\nor dysplastic areas", S['TableCell']),
         Paragraph("Staging + treatment of HGD/early T1a adenocarcinoma.\nShould precede RFA for nodular disease.", S['TableCell'])],
        [Paragraph("ESD (Endoscopic\nSubmucosal Dissection)", S['TableCell']),
         Paragraph("En-bloc submucosal dissection using\nspecialized knives", S['TableCell']),
         Paragraph("For larger lesions or those needing en-bloc\nresection; more technically demanding.", S['TableCell'])],
        [Paragraph("Cryotherapy", S['TableCell']),
         Paragraph("Liquid nitrogen or CO2 freezes tissue", S['TableCell']),
         Paragraph("Alternative when RFA fails or not available.", S['TableCell'])],
    ]
    endo_tbl = Table(endo_data, colWidths=[1.4*inch, 2.1*inch, 2.65*inch])
    endo_tbl.setStyle(TableStyle([
        ('BACKGROUND', (0,0), (-1,0), PURPLE),
        ('ROWBACKGROUNDS', (0,1), (-1,-1), [colors.HexColor("#F3E5F5"), WHITE]),
        ('TEXTCOLOR', (0,0), (-1,0), WHITE),
        ('GRID', (0,0), (-1,-1), 0.5, colors.HexColor("#CCCCCC")),
        ('FONTSIZE', (0,0), (-1,-1), 8.5),
        ('TOPPADDING', (0,0), (-1,-1), 5),
        ('BOTTOMPADDING', (0,0), (-1,-1), 5),
        ('LEFTPADDING', (0,0), (-1,-1), 6),
        ('VALIGN', (0,0), (-1,-1), 'TOP'),
    ]))
    elems.append(endo_tbl)
    elems.append(sp(8))
    return elems


# ── Section 9: Special Situations ────────────────────────────────────────────
def section9():
    elems = []
    elems.append(SectionDivider(9, "Special Situations", TEAL))
    elems.append(sp(8))

    special = [
        ("GERD in Pregnancy",
         "Very common (30-80%); due to progesterone-mediated LES relaxation + uterine pressure. "
         "Treatment ladder: lifestyle → antacids/alginates → H2RAs (famotidine - Category B) → "
         "PPIs (Category B: all PPIs except omeprazole Category C in some guidelines). "
         "Sucralfate: safe (not absorbed). Resolve post-partum in most."),
        ("GERD in Scleroderma",
         "Severely impaired LES + absent/weak peristalsis. Aggressive PPI therapy required. "
         "Surgery CONTRAINDICATED (absent peristalsis - fundoplication causes dysphagia). "
         "High Barrett's risk."),
        ("Nocturnal GERD",
         "Most acid suppression occurs at night. Add H2RA at bedtime ('nocturnal acid breakthrough') "
         "to PPI therapy. Head-of-bed elevation and left lateral position. Avoid food within 3 hrs."),
        ("Laryngopharyngeal Reflux (LPR)",
         "Posterior laryngitis, hoarseness, chronic cough, throat clearing. "
         "Only 40% have typical GERD symptoms. Diagnosis: laryngoscopy (cobblestoning, erythema, "
         "pseudosulcus). Requires TWICE-daily PPI for minimum 3 months. "
         "Poor symptom-acid correlation; do not start PPI without objective confirmation."),
        ("GERD and Asthma",
         "Bidirectional relationship: GERD triggers asthma (micro-aspiration, vagal reflex); "
         "asthma drugs (beta-agonists, theophylline) worsen GERD (reduce LES pressure). "
         "If asthma poorly controlled + typical GERD symptoms: treat GERD. "
         "If asthma + NO typical GERD: pH/impedance testing before PPI."),
        ("PPI-Refractory GERD",
         "Definition: failure of twice-daily PPI therapy. Differential: non-compliance, "
         "incorrect timing, functional heartburn, weakly acidic reflux, esophageal hypersensitivity, "
         "EoE, or bile reflux. Investigations: impedance-pH ON therapy. "
         "Treatment options: optimize PPI timing, switch PPI, vonoprazan, baclofen, TCA/SSRI, "
         "surgical referral."),
    ]
    for title, text in special:
        elems.append(Paragraph(f"<b>{title}</b>", S['H3']))
        elems.append(Paragraph(text, S['Body']))
        elems.append(sp(4))

    return elems


# ── Section 10: High-Yield Summary ───────────────────────────────────────────
def section10():
    elems = []
    elems.append(SectionDivider(10, "High-Yield Exam Summary", ACCENT_RED))
    elems.append(sp(8))

    elems.append(Paragraph(b("Must-Know Facts for FCPS / MRCP / Residency"), S['H3']))

    class HighYieldBox(Flowable):
        def __init__(self, items, col_header, bg, border):
            super().__init__()
            self.items = items
            self.col_header = col_header
            self.bg = bg
            self.border = border
        def wrap(self, aw, ah):
            self.width = aw
            h = 0.35*inch + len(self.items) * 0.18*inch
            self.height = h
            return (aw, h)
        def draw(self):
            c = self.canv
            w = self.width
            h = self.height
            c.setFillColor(self.bg)
            c.roundRect(0, 0, w, h, 5, fill=1, stroke=0)
            c.setStrokeColor(self.border)
            c.setLineWidth(1.5)
            c.roundRect(0, 0, w, h, 5, fill=0, stroke=1)
            c.setFillColor(self.border)
            c.setFont("Helvetica-Bold", 9.5)
            c.drawString(8, h - 0.25*inch, self.col_header)
            c.setFillColor(BLACK)
            c.setFont("Helvetica", 8.5)
            for j, item in enumerate(self.items):
                c.drawString(14, h - 0.38*inch - j*0.18*inch, f"• {item}")

    hy_groups = [
        ("DEFINITION & EPIDEMIOLOGY", DARK_BLUE, colors.HexColor("#E3F2FD"), [
            "Montreal definition: troublesome symptoms OR complications from esophageal reflux",
            "Prevalence: 10-20% Western; <5% Asia; USA up to 44%",
            "Risk factors: obesity (most modifiable), hiatal hernia, smoking, genetics",
            "Physiologic reflux occurs normally - GERD = pathologic amount",
        ]),
        ("PATHOPHYSIOLOGY KEY POINTS", TEAL, colors.HexColor("#E0F2F1"), [
            "Most common mechanism = Transient LES Relaxations (tLESRs)",
            "Vagally mediated, triggered by gastric distension",
            "Hiatal hernia: separates LES from crural diaphragm, creates acid pocket",
            "Acid pocket: unbuffered acid below GEJ, source of postprandial reflux",
            "Obesity: increases intra-abdominal pressure → more tLESRs",
        ]),
        ("CLINICAL FEATURES", ACCENT_GREEN, colors.HexColor("#E8F5E9"), [
            "Heartburn + regurgitation: HIGH specificity, LOW sensitivity for GERD",
            "GERD is MOST COMMON esophageal cause of non-cardiac chest pain",
            "Chronic cough: GERD is 3rd commonest cause; 50-75% no typical GERD symptoms",
            "Rumination ≠ regurgitation (rumination: subconscious, no heartburn, post-meal)",
            "Alarm symptoms: dysphagia, weight loss, anemia, hematemesis, odynophagia",
        ]),
        ("INVESTIGATIONS", ACCENT_ORANGE, colors.HexColor("#FFF3E0"), [
            "Classic symptoms + no alarms → empiric 8-week PPI (no endoscopy needed first)",
            "Gold standard for GERD: 24-hr pH monitoring (DeMeester score >14.72, AET >6%)",
            "LA Grade C/D = confirms GERD; no pH monitoring needed",
            "LA Grade A/B alone = does NOT confirm GERD diagnosis",
            "Manometry: NOT for GERD diagnosis; use for pre-surgical workup only",
            "pH monitoring: must be OFF PPI for 7 days",
        ]),
        ("MANAGEMENT", MID_BLUE, colors.HexColor("#E3F2FD"), [
            "PPIs: take 30-60 min BEFORE first meal (not at bedtime)",
            "Dexlansoprazole: only PPI taken WITHOUT regard to meals",
            "Omeprazole/esomeprazole inhibit CYP2C19 → reduce clopidogrel efficacy",
            "Vonoprazan (P-CAB): superior to PPI in resistant GERD and Grade C/D esophagitis",
            "Nissen fundoplication: 360° wrap; gold standard for surgical GERD",
            "Toupet (270°): preferred in poor esophageal motility",
            "Surgery contraindicated in scleroderma (no peristalsis)",
        ]),
        ("BARRETT'S ESOPHAGUS", PURPLE, colors.HexColor("#F3E5F5"), [
            "Goblet cells (intestinal metaplasia) = DIAGNOSTIC of Barrett's",
            "Only 10% of symptomatic GERD → Barrett's; 45% Barrett's have NO reflux symptoms",
            "Cancer risk ~0.1-0.3%/yr; higher with LGD, HGD, long-segment, male, obesity",
            "HGD/early adenocarcinoma → EMR then RFA",
            "Long-segment Barrett's = ≥3 cm; short-segment <3 cm",
            "CDX2 transcription factor promotes columnar metaplasia",
            "Surveillance: no dysplasia → 3-5 years; LGD → 6 months; HGD → treat immediately",
        ]),
        ("LA CLASSIFICATION (MUST MEMORIZE)", ACCENT_RED, colors.HexColor("#FFEBEE"), [
            "Grade A: mucosal break <5 mm, not crossing fold tops",
            "Grade B: mucosal break >5 mm, not crossing fold tops",
            "Grade C: mucosal break crossing fold tops, <75% circumference",
            "Grade D: mucosal break ≥75% circumference (circumferential)",
            "Only LA Grade C/D confirms GERD diagnosis on endoscopy",
        ]),
    ]

    for header, border_col, bg_col, items in hy_groups:
        elems.append(KeepTogether([
            HighYieldBox(items, header, bg_col, border_col),
            sp(8)
        ]))

    # Differentials table
    elems.append(Paragraph(b("GERD - Key Differentials"), S['H3']))
    diff_data = [
        [Paragraph(b("Condition"), S['TableHeader']),
         Paragraph(b("Distinguishing Features"), S['TableHeader'])],
        [Paragraph("Functional Heartburn", S['TableCell']),
         Paragraph("Normal pH/impedance testing; no acid-symptom correlation; "
                   "responds to neuromodulators (TCAs/SSRIs), not PPIs", S['TableCell'])],
        [Paragraph("Eosinophilic Esophagitis (EoE)", S['TableCell']),
         Paragraph("Young atopic males; dysphagia/food impaction dominant; "
                   "eosinophils >15/HPF on biopsy; furrows/rings on endoscopy; "
                   "responds to PPI or swallowed budesonide", S['TableCell'])],
        [Paragraph("Achalasia", S['TableCell']),
         Paragraph("Dysphagia to solids AND liquids; regurgitation of undigested food; "
                   "bird-beak on barium; absent peristalsis + aperistalsis on manometry", S['TableCell'])],
        [Paragraph("Rumination Syndrome", S['TableCell']),
         Paragraph("Effortless regurgitation during meals; no heartburn; "
                   "subconscious; resolves with behavioral therapy/diaphragmatic breathing", S['TableCell'])],
        [Paragraph("Peptic Ulcer Disease", S['TableCell']),
         Paragraph("Epigastric pain; relieved by food (DU) or worsened by food (GU); "
                   "H. pylori testing; endoscopy shows ulcer", S['TableCell'])],
        [Paragraph("Cardiac Chest Pain", S['TableCell']),
         Paragraph("Exertional, radiation to arm/jaw, diaphoresis, ECG changes; "
                   "MUST EXCLUDE before esophageal workup", S['TableCell'])],
    ]
    diff_tbl = Table(diff_data, colWidths=[1.6*inch, 4.6*inch])
    diff_tbl.setStyle(TableStyle([
        ('BACKGROUND', (0,0), (-1,0), DARK_BLUE),
        ('ROWBACKGROUNDS', (0,1), (-1,-1), [LIGHT_BLUE, WHITE]),
        ('TEXTCOLOR', (0,0), (-1,0), WHITE),
        ('GRID', (0,0), (-1,-1), 0.5, colors.HexColor("#CCCCCC")),
        ('FONTSIZE', (0,0), (-1,-1), 8.5),
        ('TOPPADDING', (0,0), (-1,-1), 5),
        ('BOTTOMPADDING', (0,0), (-1,-1), 5),
        ('LEFTPADDING', (0,0), (-1,-1), 6),
        ('VALIGN', (0,0), (-1,-1), 'TOP'),
    ]))
    elems.append(diff_tbl)
    elems.append(sp(8))

    # Recent evidence
    elems.append(Paragraph(b("Recent Evidence (2023-2025)"), S['H3']))
    recent_ev = [
        ("PMID 38263507 (J Gastroenterol Hepatol 2024)",
         "Vonoprazan (P-CAB) superior to PPIs for PPI-resistant GERD - systematic review & meta-analysis"),
        ("PMID 38345252 (Am J Gastroenterol 2024)",
         "P-CABs superior to PPIs for Grade C/D esophagitis healing - network meta-analysis"),
        ("PMID 36998190 (Surg Innov 2023)",
         "Nissen vs Toupet fundoplication: Nissen = lower GERD recurrence; Toupet = lower dysphagia"),
        ("ASGE 2025",
         "New mucosal impedance testing (catheter-based balloon) during endoscopy - differentiates GERD from EoE"),
        ("ACG 2022",
         "Empiric 8-week PPI recommended for classic symptoms without alarms (before endoscopy)"),
    ]
    for ref, text in recent_ev:
        elems.append(Paragraph(
            f'<font color="{MID_BLUE.hexval()}"><b>{ref}:</b></font> {text}',
            S['Bullet']
        ))
        elems.append(sp(2))

    elems.append(sp(8))

    # Final footer
    elems.append(hr(DARK_BLUE, 1))
    elems.append(Paragraph(
        "Prepared for Residency / FCPS / MRCP Examination Preparation | May 2026 | "
        "Sources: Goldman-Cecil Medicine (26e), Yamada's Gastroenterology (7e), Robbins Pathology, "
        "Current Surgical Therapy (14e), ACG/AGA/ASGE Guidelines",
        S['Caption']
    ))
    return elems


# ── Page Template (Header + Footer) ─────────────────────────────────────────
def add_header_footer(canvas, doc):
    canvas.saveState()
    page_width = A4[0]
    # Header bar
    canvas.setFillColor(DARK_BLUE)
    canvas.rect(0, A4[1] - 0.45*inch, page_width, 0.45*inch, fill=1, stroke=0)
    canvas.setFillColor(WHITE)
    canvas.setFont("Helvetica-Bold", 10)
    canvas.drawString(0.4*inch, A4[1] - 0.3*inch, "GERD - Comprehensive Exam Notes")
    canvas.setFont("Helvetica", 8)
    canvas.drawRightString(page_width - 0.4*inch, A4[1] - 0.3*inch, "Residency | FCPS | MRCP")
    # Footer
    canvas.setFillColor(DARK_BLUE)
    canvas.rect(0, 0, page_width, 0.35*inch, fill=1, stroke=0)
    canvas.setFillColor(WHITE)
    canvas.setFont("Helvetica", 8)
    canvas.drawCentredString(page_width/2, 0.12*inch,
        f"Page {doc.page} | Goldman-Cecil · Yamada's · ACG/AGA Guidelines 2022-25")
    canvas.restoreState()


def first_page(canvas, doc):
    canvas.saveState()
    # Full dark blue background for cover
    canvas.setFillColor(DARK_BLUE)
    canvas.rect(0, A4[1]-0.4*inch, A4[0], 0.4*inch, fill=1, stroke=0)
    canvas.setFillColor(WHITE)
    canvas.setFont("Helvetica", 7)
    canvas.drawCentredString(A4[0]/2, A4[1]-0.27*inch, "GASTROENTEROLOGY | EXAM PREPARATION")
    canvas.restoreState()


# ── Main build ───────────────────────────────────────────────────────────────
def build_pdf():
    doc = SimpleDocTemplate(
        OUTPUT_PATH,
        pagesize=A4,
        leftMargin=0.9*inch,
        rightMargin=0.9*inch,
        topMargin=0.65*inch,
        bottomMargin=0.55*inch,
        title="GERD Comprehensive Exam Notes",
        author="Medical AI Assistant",
        subject="GERD - Residency/FCPS/MRCP"
    )

    story = []
    story += cover_page()
    story += section1()
    story.append(PageBreak())
    story += section2()
    story.append(PageBreak())
    story += section3()
    story.append(PageBreak())
    story += section4()
    story.append(PageBreak())
    story += section5()
    story.append(PageBreak())
    story += section6()
    story.append(PageBreak())
    story += section7()
    story.append(PageBreak())
    story += section8()
    story.append(PageBreak())
    story += section9()
    story.append(PageBreak())
    story += section10()

    doc.build(
        story,
        onFirstPage=first_page,
        onLaterPages=add_header_footer
    )
    print(f"PDF generated: {OUTPUT_PATH}")
    import os
    size = os.path.getsize(OUTPUT_PATH)
    print(f"File size: {size/1024:.1f} KB")

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

cd /home/daytona/workspace/gerd-notes && python generate_gerd_pdf.py 2>&1

Editing File

~/gerd-notes/generate_gerd_pdf.py

Successfully replaced 1 instance(s) of the string in '/home/daytona/workspace/gerd-notes/generate_gerd_pdf.py'
Running Command

cd /home/daytona/workspace/gerd-notes && sed -i "s/style='Bullet'/style='BulletI…

Running Command

cd /home/daytona/workspace/gerd-notes && python -c " content = open('generate_ge…

Running Command

cd /home/daytona/workspace/gerd-notes && python -c " content = open('generate_ge…

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