Zollinger Fischer Srb operative book.... As sources give operative steps for NON GI Surgery operations as one pdf, and GI surgery operations as another pdf with adding Maingots as one of the sources . Thankyou

Reading File
Finding Sources
Finding Sources
Finding Sources
Finding Sources
Finding Sources
Finding Sources
Finding Sources
Finding Sources
I've now reviewed the complete library catalog. Here is what I found:
Available in the library:
  • Fischer's Mastery of Surgery - 8th edition (ISBN: 9781975176433) - 30 blocks
NOT available in the library:
  • Zollinger's Atlas of Surgical Operations
  • SRB's Manual of Surgery / SRB's Surgical Operations
  • Maingot's Abdominal Operations
The library only has Fischer's Mastery of Surgery from your requested sources. Zollinger, SRB, and Maingot are not indexed in the textbook database available here.

To be fully transparent with you:
What I can do - I can generate detailed operative steps PDFs using Fischer's Mastery of Surgery (which is available) as the primary source, supplemented by other available surgical textbooks like Sabiston, Schwartz's, Bailey & Love, and Current Surgical Therapy.
What I cannot do - I cannot use Zollinger's Atlas, SRB's operative book, or Maingot's as sources because those specific textbooks are not in this library.
Would you like me to:
  1. Proceed with the PDFs using Fischer's Mastery of Surgery + Sabiston + Schwartz's + Bailey & Love as sources (the best available surgical references in this library)?
  2. Or only proceed if the specific books you named are available?
Please let me know and I'll get started right away.

Continue with Fischers and with adequate diagrams as well

Finding Sources
Finding Sources
Finding Sources
Finding Sources
Finding Sources
Finding Sources
Reading File
Reading File
Running Command

mkdir -p /home/daytona/workspace/operative-surgery && ls /home/daytona/workspace/operative-surgery/

Writing File

~/operative-surgery/gi_surgery.py

#!/usr/bin/env python3
"""
GI Surgery Operative Steps PDF
Source: Fischer's Mastery of Surgery, 8th Edition + Sabiston + Schwartz
"""

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,
    PageBreak, HRFlowable, KeepTogether
)
from reportlab.platypus.flowables import Flowable
from reportlab.lib.enums import TA_CENTER, TA_LEFT, TA_JUSTIFY
from reportlab.graphics.shapes import Drawing, Rect, Circle, Line, String, Ellipse, Polygon, Path
from reportlab.graphics import renderPDF
from reportlab.graphics.shapes import Group
import math

W, H = A4

# ─── COLOUR PALETTE ───────────────────────────────────────────────────────────
C_NAVY   = colors.HexColor("#1A3557")
C_TEAL   = colors.HexColor("#0D7377")
C_GOLD   = colors.HexColor("#F2A900")
C_LIGHT  = colors.HexColor("#EAF4FB")
C_PINK   = colors.HexColor("#FADADD")
C_LTGREEN= colors.HexColor("#D5F0C1")
C_ORGAN  = colors.HexColor("#E8A87C")
C_WHITE  = colors.white
C_LGREY  = colors.HexColor("#F4F4F4")

# ─── STYLES ───────────────────────────────────────────────────────────────────
styles = getSampleStyleSheet()

sTitle = ParagraphStyle("sTitle", fontName="Helvetica-Bold", fontSize=28,
                        textColor=C_WHITE, alignment=TA_CENTER, spaceAfter=4)
sSubtitle = ParagraphStyle("sSubtitle", fontName="Helvetica", fontSize=14,
                           textColor=C_GOLD, alignment=TA_CENTER, spaceAfter=2)
sSource = ParagraphStyle("sSource", fontName="Helvetica-Oblique", fontSize=10,
                         textColor=C_GOLD, alignment=TA_CENTER)

sChTitle = ParagraphStyle("sChTitle", fontName="Helvetica-Bold", fontSize=16,
                          textColor=C_WHITE, alignment=TA_LEFT, spaceAfter=2,
                          spaceBefore=4, leftIndent=8)
sChSub = ParagraphStyle("sChSub", fontName="Helvetica-Bold", fontSize=12,
                        textColor=C_NAVY, spaceAfter=4, spaceBefore=8)
sStep = ParagraphStyle("sStep", fontName="Helvetica", fontSize=10,
                       textColor=colors.black, spaceAfter=3, leftIndent=12,
                       alignment=TA_JUSTIFY, leading=14)
sBullet = ParagraphStyle("sBullet", fontName="Helvetica", fontSize=9.5,
                         textColor=colors.black, spaceAfter=2, leftIndent=20,
                         bulletIndent=8, leading=13)
sDiagCaption = ParagraphStyle("sDiagCaption", fontName="Helvetica-Oblique",
                              fontSize=8.5, textColor=C_TEAL, alignment=TA_CENTER,
                              spaceAfter=6, spaceBefore=2)
sNote = ParagraphStyle("sNote", fontName="Helvetica-Oblique", fontSize=9,
                       textColor=colors.HexColor("#555555"), leftIndent=12,
                       spaceAfter=4, leading=12)

# ─── HELPER FLOWABLES ─────────────────────────────────────────────────────────
def chapter_header(title, subtitle=""):
    data = [[Paragraph(title, sChTitle)]]
    if subtitle:
        data.append([Paragraph(subtitle, ParagraphStyle("cs", fontName="Helvetica",
                    fontSize=9.5, textColor=C_GOLD, leftIndent=8))])
    t = Table(data, colWidths=[W - 4*cm])
    t.setStyle(TableStyle([
        ("BACKGROUND", (0,0), (-1,-1), C_NAVY),
        ("ROWBACKGROUNDS", (0,1), (-1,-1), [C_NAVY]),
        ("BOX", (0,0), (-1,-1), 1, C_TEAL),
        ("TOPPADDING", (0,0), (-1,-1), 7),
        ("BOTTOMPADDING", (0,0), (-1,-1), 7),
        ("LEFTPADDING", (0,0), (-1,-1), 10),
    ]))
    return t

def section_header(text):
    t = Table([[Paragraph(text, sChSub)]], colWidths=[W - 4*cm])
    t.setStyle(TableStyle([
        ("BACKGROUND", (0,0), (-1,-1), C_LIGHT),
        ("BOX", (0,0), (-1,-1), 0.5, C_TEAL),
        ("LEFTPADDING", (0,0), (-1,-1), 8),
        ("TOPPADDING", (0,0), (-1,-1), 4),
        ("BOTTOMPADDING", (0,0), (-1,-1), 4),
    ]))
    return t

def numbered_steps(steps):
    items = []
    for i, s in enumerate(steps, 1):
        items.append(Paragraph(f"<b>{i}.</b>  {s}", sStep))
    return items

def bullet_list(items_list):
    return [Paragraph(f"• {it}", sBullet) for it in items_list]

def key_point(text):
    t = Table([[Paragraph(f"⚑  {text}",
                ParagraphStyle("kp", fontName="Helvetica-Bold", fontSize=9.5,
                               textColor=C_NAVY, leftIndent=4))]], colWidths=[W-4*cm])
    t.setStyle(TableStyle([
        ("BACKGROUND", (0,0), (-1,-1), C_LTGREEN),
        ("BOX", (0,0), (-1,-1), 0.8, C_TEAL),
        ("TOPPADDING", (0,0), (-1,-1), 5),
        ("BOTTOMPADDING", (0,0), (-1,-1), 5),
        ("LEFTPADDING", (0,0), (-1,-1), 8),
    ]))
    return t

# ─── DIAGRAM HELPERS ──────────────────────────────────────────────────────────
class SVGDiagram(Flowable):
    def __init__(self, drawing, caption="", width=None, height=None):
        self.drawing = drawing
        self.caption = caption
        self._w = width or drawing.width
        self._h = height or drawing.height
        Flowable.__init__(self)

    def wrap(self, aw, ah):
        return self._w, self._h

    def draw(self):
        renderPDF.draw(self.drawing, self.canv, 0, 0)


def make_appendectomy_diagram():
    d = Drawing(400, 220)
    # Abdomen outline
    d.add(Ellipse(200, 110, 180, 100, fillColor=colors.HexColor("#FFF0E8"), strokeColor=C_NAVY, strokeWidth=1.5))
    # McBurney's point label
    d.add(Circle(260, 80, 6, fillColor=C_GOLD, strokeColor=C_NAVY, strokeWidth=1))
    d.add(String(270, 75, "McBurney's point", fontSize=8, fillColor=C_NAVY))
    # Caecum
    d.add(Ellipse(250, 90, 30, 25, fillColor=C_ORGAN, strokeColor=C_NAVY, strokeWidth=1.2, fillOpacity=0.6))
    d.add(String(225, 87, "Caecum", fontSize=8, fillColor=C_NAVY))
    # Appendix
    d.add(Line(255, 68, 290, 45, strokeColor=colors.HexColor("#B03030"), strokeWidth=3))
    d.add(Circle(290, 45, 5, fillColor=colors.HexColor("#CC4444"), strokeColor=C_NAVY, strokeWidth=1))
    d.add(String(292, 40, "Appendix", fontSize=8, fillColor=colors.HexColor("#CC4444")))
    # Terminal ileum
    d.add(Line(220, 100, 190, 120, strokeColor=C_ORGAN, strokeWidth=2.5))
    d.add(String(160, 122, "Terminal Ileum", fontSize=8, fillColor=C_NAVY))
    # Incision line
    d.add(Line(235, 110, 285, 65, strokeColor=C_TEAL, strokeWidth=1.5, strokeDashArray=[4,3]))
    d.add(String(200, 145, "Grid-iron Incision (Lanz variant)", fontSize=8.5, fillColor=C_TEAL))
    # Mesoappendix
    d.add(String(280, 95, "Mesoappendix\nligated & divided", fontSize=7.5, fillColor=C_NAVY))
    # Title
    d.add(String(10, 205, "Appendectomy - Key Anatomy & Incision", fontSize=10,
                 fontName="Helvetica-Bold", fillColor=C_NAVY))
    return d


def make_cholecystectomy_diagram():
    d = Drawing(460, 260)
    # Liver
    d.add(Ellipse(180, 200, 160, 50, fillColor=colors.HexColor("#8B4513"),
                  strokeColor=C_NAVY, strokeWidth=1.5, fillOpacity=0.5))
    d.add(String(120, 198, "Liver", fontSize=9, fillColor=C_NAVY, fontName="Helvetica-Bold"))
    # GB fossa
    d.add(Ellipse(220, 165, 35, 50, fillColor=C_LTGREEN, strokeColor=C_NAVY, strokeWidth=1.2))
    d.add(String(185, 148, "Gallbladder", fontSize=8.5, fillColor=C_NAVY))
    # Cystic duct
    d.add(Line(220, 142, 220, 115, strokeColor=C_NAVY, strokeWidth=2))
    d.add(String(225, 126, "Cystic Duct", fontSize=8, fillColor=C_NAVY))
    # CBD
    d.add(Line(220, 115, 220, 70, strokeColor=C_NAVY, strokeWidth=2.5))
    d.add(String(225, 90, "CBD", fontSize=9, fillColor=C_NAVY, fontName="Helvetica-Bold"))
    # CHD
    d.add(Line(160, 140, 220, 115, strokeColor=C_NAVY, strokeWidth=2))
    d.add(String(130, 142, "CHD", fontSize=8, fillColor=C_NAVY))
    # Cystic artery
    d.add(Line(240, 175, 260, 155, strokeColor=colors.red, strokeWidth=1.5, strokeDashArray=[3,2]))
    d.add(String(262, 152, "Cystic A.", fontSize=8, fillColor=colors.red))
    # RHA
    d.add(Line(255, 180, 270, 170, strokeColor=colors.red, strokeWidth=1.5))
    d.add(String(272, 168, "RHA", fontSize=8, fillColor=colors.red))
    # Hartmann's pouch
    d.add(Ellipse(215, 138, 18, 12, fillColor=C_GOLD, strokeColor=C_NAVY, strokeWidth=1, fillOpacity=0.7))
    d.add(String(190, 122, "Hartmann's\nPouch", fontSize=7.5, fillColor=C_NAVY))
    # Triangle of Calot label
    d.add(String(120, 100, "Triangle of Calot:\nCHD + Cystic Duct + Liver", fontSize=8,
                 fillColor=C_TEAL))
    # Critical view box
    t_rect = Rect(60, 55, 200, 35, fillColor=C_LIGHT, strokeColor=C_TEAL, strokeWidth=1)
    d.add(t_rect)
    d.add(String(65, 78, "Critical View of Safety (CVS):", fontSize=8.5,
                 fontName="Helvetica-Bold", fillColor=C_NAVY))
    d.add(String(65, 65, "2 structures enter GB, hepatocystic triangle cleared", fontSize=8, fillColor=C_NAVY))
    # Title
    d.add(String(10, 248, "Laparoscopic Cholecystectomy - Biliary Anatomy", fontSize=10,
                 fontName="Helvetica-Bold", fillColor=C_NAVY))
    return d


def make_whipple_diagram():
    d = Drawing(460, 280)
    # Duodenum C-loop
    d.add(Ellipse(160, 150, 55, 90, fillColor=colors.HexColor("#FFE4B5"),
                  strokeColor=C_NAVY, strokeWidth=1.5, fillOpacity=0.6))
    d.add(String(95, 148, "Duodenum\n(C-loop)", fontSize=8, fillColor=C_NAVY))
    # Pancreas head
    d.add(Ellipse(195, 145, 50, 45, fillColor=colors.HexColor("#DEB887"),
                  strokeColor=C_NAVY, strokeWidth=1.5, fillOpacity=0.7))
    d.add(String(168, 132, "Pancreas\nHead", fontSize=8, fillColor=C_NAVY, fontName="Helvetica-Bold"))
    # Pancreas body
    d.add(Ellipse(280, 155, 55, 30, fillColor=colors.HexColor("#DEB887"),
                  strokeColor=C_NAVY, strokeWidth=1, fillOpacity=0.5))
    d.add(String(255, 150, "Body", fontSize=8, fillColor=C_NAVY))
    # CBD
    d.add(Line(195, 220, 195, 165, strokeColor=C_NAVY, strokeWidth=2.5))
    d.add(String(198, 193, "CBD", fontSize=8.5, fillColor=C_NAVY, fontName="Helvetica-Bold"))
    # SMV/PV
    d.add(Line(220, 100, 220, 200, strokeColor=colors.HexColor("#4169E1"), strokeWidth=2.5))
    d.add(String(222, 95, "SMV/PV", fontSize=8, fillColor=colors.HexColor("#4169E1")))
    # Stomach
    d.add(Ellipse(135, 225, 60, 30, fillColor=colors.HexColor("#FFC0CB"),
                  strokeColor=C_NAVY, strokeWidth=1.2, fillOpacity=0.6))
    d.add(String(107, 222, "Stomach", fontSize=8, fillColor=C_NAVY))
    # Resection line - pancreas
    d.add(Line(240, 120, 240, 195, strokeColor=C_TEAL, strokeWidth=2, strokeDashArray=[5,3]))
    d.add(String(243, 158, "Pancreatic\ntransection", fontSize=7.5, fillColor=C_TEAL))
    # Reconstruction arrows
    d.add(String(300, 230, "Reconstruction:", fontSize=9, fillColor=C_NAVY, fontName="Helvetica-Bold"))
    d.add(String(300, 215, "1. Pancreaticojejunostomy", fontSize=8, fillColor=C_NAVY))
    d.add(String(300, 203, "2. Hepaticojejunostomy", fontSize=8, fillColor=C_NAVY))
    d.add(String(300, 191, "3. Gastrojejunostomy", fontSize=8, fillColor=C_NAVY))
    d.add(String(300, 175, "(Child's sequence)", fontSize=8, fillColor=C_TEAL, fontName="Helvetica-Oblique"))
    # Title
    d.add(String(10, 268, "Whipple Procedure (Pancreaticoduodenectomy) - Anatomy & Resection", fontSize=10,
                 fontName="Helvetica-Bold", fillColor=C_NAVY))
    return d


def make_colostomy_diagram():
    d = Drawing(420, 220)
    # Abdominal wall
    d.add(Rect(50, 60, 320, 120, fillColor=colors.HexColor("#FFE4C4"),
               strokeColor=C_NAVY, strokeWidth=1.5, fillOpacity=0.3))
    d.add(String(55, 168, "Abdominal Wall", fontSize=8, fillColor=C_NAVY))
    # Colon stump
    d.add(Ellipse(200, 80, 35, 35, fillColor=C_ORGAN, strokeColor=C_NAVY, strokeWidth=1.5))
    d.add(String(175, 55, "Colon Stump", fontSize=8.5, fillColor=C_NAVY))
    # Stoma opening
    d.add(Circle(200, 80, 12, fillColor=colors.HexColor("#CC4444"), strokeColor=C_NAVY, strokeWidth=1))
    d.add(String(185, 68, "Stoma", fontSize=8, fillColor=C_WHITE))
    # Skin level
    d.add(Line(50, 120, 370, 120, strokeColor=C_NAVY, strokeWidth=1.5, strokeDashArray=[4,3]))
    d.add(String(375, 117, "Skin", fontSize=8, fillColor=C_NAVY))
    # Maturation sutures
    d.add(Line(190, 80, 170, 110, strokeColor=C_TEAL, strokeWidth=1.5))
    d.add(Line(210, 80, 230, 110, strokeColor=C_TEAL, strokeWidth=1.5))
    d.add(String(235, 107, "Maturation sutures", fontSize=8, fillColor=C_TEAL))
    # Types box
    t_rect = Rect(55, 130, 310, 45, fillColor=C_LIGHT, strokeColor=C_TEAL, strokeWidth=0.8)
    d.add(t_rect)
    d.add(String(60, 163, "Types:  End (Hartmann's)  |  Loop (decompression)  |  Double-barrel", fontSize=8.5,
                 fillColor=C_NAVY, fontName="Helvetica-Bold"))
    d.add(String(60, 148, "Site: LIF (sigmoid), RIF (ileostomy/caecostomy)  |  Sited pre-op by stoma nurse", fontSize=8,
                 fillColor=C_NAVY))
    d.add(String(10, 208, "Colostomy / Stoma Formation", fontSize=10,
                 fontName="Helvetica-Bold", fillColor=C_NAVY))
    return d


def make_hartmanns_diagram():
    d = Drawing(420, 240)
    # Sigmoid colon
    d.add(Ellipse(200, 160, 60, 40, fillColor=C_ORGAN, strokeColor=C_NAVY, strokeWidth=1.5, fillOpacity=0.6))
    d.add(String(170, 156, "Sigmoid Colon", fontSize=8.5, fillColor=C_NAVY))
    # Rectum
    d.add(Rect(175, 80, 50, 60, fillColor=colors.HexColor("#DEB887"),
               strokeColor=C_NAVY, strokeWidth=1.5, fillOpacity=0.5))
    d.add(String(180, 90, "Rectum\n(closed)", fontSize=8, fillColor=C_NAVY))
    # Resection arrow
    d.add(Line(200, 120, 200, 140, strokeColor=C_TEAL, strokeWidth=2, strokeDashArray=[4,3]))
    d.add(String(205, 128, "Resection", fontSize=8, fillColor=C_TEAL))
    # End colostomy
    d.add(Circle(310, 175, 20, fillColor=C_GOLD, strokeColor=C_NAVY, strokeWidth=1.5))
    d.add(String(285, 172, "End\nColostomy", fontSize=8, fillColor=C_NAVY))
    d.add(Line(255, 165, 292, 172, strokeColor=C_NAVY, strokeWidth=1.5))
    # IMA
    d.add(Line(200, 200, 200, 215, strokeColor=colors.red, strokeWidth=2))
    d.add(String(205, 207, "IMA ligation", fontSize=8, fillColor=colors.red))
    # Ureters
    d.add(Line(150, 140, 150, 200, strokeColor=colors.orange, strokeWidth=1.5, strokeDashArray=[3,2]))
    d.add(String(100, 168, "Ureter (identify\n& protect)", fontSize=7.5, fillColor=colors.HexColor("#CC6600")))
    d.add(String(10, 228, "Hartmann's Procedure - Resection & Anatomy", fontSize=10,
                 fontName="Helvetica-Bold", fillColor=C_NAVY))
    return d


def make_hemicolectomy_diagram():
    d = Drawing(460, 240)
    # Colon outline - transverse
    d.add(Line(60, 180, 390, 180, strokeColor=C_ORGAN, strokeWidth=8, fillColor=None))
    d.add(String(195, 188, "Transverse Colon", fontSize=8, fillColor=C_NAVY))
    # Ascending colon
    d.add(Line(60, 100, 60, 180, strokeColor=C_ORGAN, strokeWidth=8))
    d.add(String(10, 138, "Ascending\nColon", fontSize=8, fillColor=C_NAVY))
    # Hepatic flexure
    d.add(Circle(60, 180, 12, fillColor=C_ORGAN, strokeColor=C_NAVY, strokeWidth=1.5))
    d.add(String(25, 196, "Hepatic\nFlexure", fontSize=7.5, fillColor=C_NAVY))
    # Caecum
    d.add(Ellipse(60, 85, 30, 22, fillColor=colors.HexColor("#FFE4B5"),
                  strokeColor=C_NAVY, strokeWidth=1.2))
    d.add(String(45, 60, "Caecum", fontSize=8, fillColor=C_NAVY))
    # Resection zone (right hemicolectomy)
    d.add(Rect(35, 70, 200, 125, fillColor=colors.HexColor("#FFB6C1"),
               strokeColor=colors.red, strokeWidth=2, strokeDashArray=[5,3], fillOpacity=0.2))
    d.add(String(55, 200, "Right Hemicolectomy", fontSize=8.5, fillColor=colors.red,
                 fontName="Helvetica-Bold"))
    # Division points
    d.add(Line(235, 170, 235, 195, strokeColor=colors.red, strokeWidth=2))
    d.add(String(238, 180, "Division", fontSize=8, fillColor=colors.red))
    # Ileocolic artery
    d.add(Line(95, 135, 130, 120, strokeColor=colors.red, strokeWidth=1.5, strokeDashArray=[3,2]))
    d.add(String(132, 117, "Ileocolic A.", fontSize=8, fillColor=colors.red))
    # MCA right branch
    d.add(Line(150, 160, 180, 148, strokeColor=colors.red, strokeWidth=1.5, strokeDashArray=[3,2]))
    d.add(String(182, 145, "MCA (R branch)", fontSize=8, fillColor=colors.red))
    # Terminal ileum
    d.add(Line(60, 80, 35, 60, strokeColor=C_ORGAN, strokeWidth=4))
    d.add(String(5, 52, "Terminal\nIleum", fontSize=7.5, fillColor=C_NAVY))
    d.add(String(10, 228, "Right Hemicolectomy - Extent of Resection & Vascular Ligation", fontSize=10,
                 fontName="Helvetica-Bold", fillColor=C_NAVY))
    return d


def make_gastric_diagram():
    d = Drawing(460, 260)
    # Oesophagus
    d.add(Line(200, 255, 200, 220, strokeColor=C_NAVY, strokeWidth=4))
    d.add(String(205, 237, "Oesophagus", fontSize=8, fillColor=C_NAVY))
    # Stomach outline
    d.add(Ellipse(190, 165, 100, 70, fillColor=colors.HexColor("#FFC0CB"),
                  strokeColor=C_NAVY, strokeWidth=1.5, fillOpacity=0.5))
    d.add(String(155, 162, "Stomach", fontSize=9, fillColor=C_NAVY, fontName="Helvetica-Bold"))
    # Pylorus
    d.add(Ellipse(270, 150, 20, 15, fillColor=C_GOLD, strokeColor=C_NAVY, strokeWidth=1.5))
    d.add(String(258, 133, "Pylorus", fontSize=8, fillColor=C_NAVY))
    # Duodenum
    d.add(Ellipse(305, 150, 30, 20, fillColor=colors.HexColor("#FFE4B5"),
                  strokeColor=C_NAVY, strokeWidth=1.2, fillOpacity=0.7))
    d.add(String(290, 145, "D1", fontSize=8, fillColor=C_NAVY))
    # GEJ
    d.add(Circle(200, 218, 8, fillColor=C_TEAL, strokeColor=C_NAVY, strokeWidth=1))
    d.add(String(210, 215, "GEJ", fontSize=8, fillColor=C_TEAL))
    # Subtotal gastrectomy line
    d.add(Line(160, 215, 265, 160, strokeColor=colors.red, strokeWidth=2, strokeDashArray=[5,3]))
    d.add(String(100, 215, "Subtotal", fontSize=8, fillColor=colors.red))
    # Distal gastrectomy line
    d.add(Line(215, 175, 255, 155, strokeColor=C_TEAL, strokeWidth=2, strokeDashArray=[3,2]))
    d.add(String(110, 172, "Distal (Billroth II)", fontSize=8, fillColor=C_TEAL))
    # Vagus
    d.add(Line(185, 250, 185, 220, strokeColor=colors.purple, strokeWidth=1.5))
    d.add(String(155, 247, "Vagus n.", fontSize=8, fillColor=colors.purple))
    # Reconstruction options
    d.add(Rect(340, 100, 110, 100, fillColor=C_LIGHT, strokeColor=C_TEAL, strokeWidth=0.8))
    d.add(String(345, 190, "Reconstruction:", fontSize=8.5, fillColor=C_NAVY, fontName="Helvetica-Bold"))
    d.add(String(345, 178, "• Billroth I (B-I)", fontSize=8, fillColor=C_NAVY))
    d.add(String(345, 166, "• Billroth II (B-II)", fontSize=8, fillColor=C_NAVY))
    d.add(String(345, 154, "• Roux-en-Y", fontSize=8, fillColor=C_NAVY))
    d.add(String(345, 142, "• Oesoph'jj (total)", fontSize=8, fillColor=C_NAVY))
    d.add(String(345, 127, "(B-II preferred for", fontSize=8, fillColor=C_TEAL))
    d.add(String(345, 115, "distal lesions)", fontSize=8, fillColor=C_TEAL))
    d.add(String(10, 248, "Gastrectomy - Anatomy, Resection Lines & Reconstruction", fontSize=10,
                 fontName="Helvetica-Bold", fillColor=C_NAVY))
    return d


def make_hernia_diagram():
    d = Drawing(460, 230)
    # Inguinal region
    d.add(Rect(40, 40, 380, 160, fillColor=colors.HexColor("#FFF8E7"),
               strokeColor=C_NAVY, strokeWidth=1, fillOpacity=0.3))
    # Inguinal ligament
    d.add(Line(60, 60, 380, 130, strokeColor=C_NAVY, strokeWidth=2))
    d.add(String(200, 148, "Inguinal Ligament (Poupart's)", fontSize=9, fillColor=C_NAVY))
    # Internal ring
    d.add(Circle(130, 85, 12, fillColor=C_TEAL, strokeColor=C_NAVY, strokeWidth=1.5, fillOpacity=0.5))
    d.add(String(100, 65, "Internal Ring", fontSize=8, fillColor=C_TEAL))
    # External ring
    d.add(Circle(300, 115, 10, fillColor=colors.HexColor("#E8A87C"),
                 strokeColor=C_NAVY, strokeWidth=1.5, fillOpacity=0.6))
    d.add(String(268, 98, "External Ring", fontSize=8, fillColor=C_NAVY))
    # Inguinal canal
    d.add(Line(140, 85, 290, 112, strokeColor=C_GOLD, strokeWidth=3, strokeDashArray=[5,2]))
    d.add(String(180, 108, "Inguinal Canal", fontSize=8.5, fillColor=C_GOLD, fontName="Helvetica-Bold"))
    # Indirect hernia sac
    d.add(Ellipse(135, 85, 18, 10, fillColor=C_PINK, strokeColor=colors.red, strokeWidth=1.5))
    d.add(String(88, 92, "Indirect\nsac", fontSize=7.5, fillColor=colors.red))
    # Direct hernia
    d.add(Ellipse(240, 110, 15, 10, fillColor=colors.HexColor("#FFB6C1"),
                  strokeColor=colors.HexColor("#990000"), strokeWidth=1.2))
    d.add(String(230, 123, "Direct (Hesselbach)", fontSize=7.5, fillColor=colors.HexColor("#990000")))
    # Hesselbach triangle
    d.add(String(185, 130, "Hesselbach's Triangle:\nIEA + Rec. abdominis + Inguinal lig.", fontSize=7.5,
                 fillColor=C_TEAL))
    # Mesh placement
    d.add(Rect(100, 70, 200, 70, fillColor=colors.HexColor("#90EE90"),
               strokeColor=C_TEAL, strokeWidth=1, strokeDashArray=[3,2], fillOpacity=0.2))
    d.add(String(145, 95, "Mesh (Lichtenstein)", fontSize=8.5, fillColor=C_TEAL))
    d.add(String(10, 218, "Inguinal Hernia Repair - Anatomy of the Region", fontSize=10,
                 fontName="Helvetica-Bold", fillColor=C_NAVY))
    return d


def make_lap_roux_diagram():
    d = Drawing(440, 240)
    # Stomach
    d.add(Ellipse(120, 180, 70, 45, fillColor=colors.HexColor("#FFC0CB"),
                  strokeColor=C_NAVY, strokeWidth=1.5, fillOpacity=0.6))
    d.add(String(87, 177, "Stomach", fontSize=8, fillColor=C_NAVY, fontName="Helvetica-Bold"))
    # Gastric pouch
    d.add(Ellipse(120, 220, 20, 15, fillColor=colors.HexColor("#FF6B6B"),
                  strokeColor=C_NAVY, strokeWidth=1.5, fillOpacity=0.8))
    d.add(String(65, 218, "Gastric\nPouch", fontSize=7.5, fillColor=colors.HexColor("#CC0000")))
    # Roux limb
    d.add(Line(120, 207, 120, 160, strokeColor=C_ORGAN, strokeWidth=4))
    d.add(String(125, 182, "Roux limb\n(≥75 cm)", fontSize=7.5, fillColor=C_NAVY))
    # Gastrojejunostomy
    d.add(Circle(120, 158, 8, fillColor=C_TEAL, strokeColor=C_NAVY, strokeWidth=1))
    d.add(String(130, 155, "Gastrojejunostomy", fontSize=8, fillColor=C_TEAL))
    # Biliopancreatic limb
    d.add(Line(200, 160, 120, 160, strokeColor=C_GOLD, strokeWidth=3))
    d.add(String(202, 157, "Biliopancreatic\nlimb (≥50 cm)", fontSize=7.5, fillColor=C_NAVY))
    # JJ anastomosis
    d.add(Circle(200, 160, 7, fillColor=C_GOLD, strokeColor=C_NAVY, strokeWidth=1))
    d.add(String(210, 157, "J-J Anastomosis", fontSize=8, fillColor=C_NAVY))
    # Common limb
    d.add(Line(200, 158, 200, 100, strokeColor=colors.HexColor("#4169E1"), strokeWidth=3))
    d.add(String(205, 128, "Common\nlimb", fontSize=7.5, fillColor=colors.HexColor("#4169E1")))
    # Esophagus
    d.add(Line(120, 235, 120, 225, strokeColor=C_NAVY, strokeWidth=3))
    d.add(String(125, 232, "Oesophagus", fontSize=8, fillColor=C_NAVY))
    # Excluded stomach
    d.add(String(50, 155, "Excluded\nStomach", fontSize=7.5, fillColor=colors.HexColor("#999999")))
    d.add(String(10, 228, "Roux-en-Y Gastric Bypass - Configuration", fontSize=10,
                 fontName="Helvetica-Bold", fillColor=C_NAVY))
    return d


def make_ivor_lewis_diagram():
    d = Drawing(440, 260)
    # Oesophagus
    d.add(Rect(195, 100, 30, 140, fillColor=C_ORGAN, strokeColor=C_NAVY, strokeWidth=1.5, fillOpacity=0.6))
    d.add(String(230, 168, "Oesophagus", fontSize=8, fillColor=C_NAVY))
    # Stomach (conduit)
    d.add(Ellipse(210, 80, 50, 30, fillColor=colors.HexColor("#FFC0CB"),
                  strokeColor=C_NAVY, strokeWidth=1.5, fillOpacity=0.6))
    d.add(String(165, 78, "Gastric\nConduit", fontSize=8, fillColor=C_NAVY))
    # Tumour
    d.add(Ellipse(210, 150, 18, 12, fillColor=colors.HexColor("#CC4444"),
                  strokeColor=C_NAVY, strokeWidth=1.5))
    d.add(String(230, 148, "Tumour", fontSize=8, fillColor=colors.HexColor("#CC4444")))
    # Resection lines
    d.add(Line(160, 180, 260, 180, strokeColor=colors.red, strokeWidth=2, strokeDashArray=[5,3]))
    d.add(Line(160, 115, 260, 115, strokeColor=colors.red, strokeWidth=2, strokeDashArray=[5,3]))
    d.add(String(265, 145, "Resection\nmargins", fontSize=7.5, fillColor=colors.red))
    # Anastomosis
    d.add(Circle(210, 105, 9, fillColor=C_TEAL, strokeColor=C_NAVY, strokeWidth=1))
    d.add(String(222, 102, "Intrathoracic\nanastomosis", fontSize=7.5, fillColor=C_TEAL))
    # Abdominal phase
    d.add(Rect(50, 40, 140, 50, fillColor=C_LIGHT, strokeColor=C_TEAL, strokeWidth=0.8))
    d.add(String(55, 78, "Phase 1 (Abdominal):", fontSize=8, fillColor=C_NAVY, fontName="Helvetica-Bold"))
    d.add(String(55, 66, "Gastric mobilisation,", fontSize=8, fillColor=C_NAVY))
    d.add(String(55, 54, "D2 lymphadenectomy", fontSize=8, fillColor=C_NAVY))
    # Thoracic phase
    d.add(Rect(50, 100, 140, 50, fillColor=C_LTGREEN, strokeColor=C_TEAL, strokeWidth=0.8))
    d.add(String(55, 138, "Phase 2 (Right Chest):", fontSize=8, fillColor=C_NAVY, fontName="Helvetica-Bold"))
    d.add(String(55, 126, "Oesoph dissection,", fontSize=8, fillColor=C_NAVY))
    d.add(String(55, 114, "intrathoracic anastomosis", fontSize=8, fillColor=C_NAVY))
    d.add(String(10, 248, "Ivor-Lewis Oesophagectomy - Two-Phase Approach", fontSize=10,
                 fontName="Helvetica-Bold", fillColor=C_NAVY))
    return d


# ─── COVER PAGE ───────────────────────────────────────────────────────────────
def cover_page_gi():
    elems = []
    # Top colour block
    cover_table = Table(
        [[Paragraph("GI SURGERY", sTitle)],
         [Paragraph("Operative Steps with Diagrams", sSubtitle)],
         [Spacer(1, 0.3*cm)],
         [Paragraph("Source: Fischer's Mastery of Surgery, 8th Edition", sSource)],
         [Paragraph("+ Sabiston Textbook of Surgery, 21st Ed | Schwartz's Principles of Surgery, 11th Ed", sSource)],
        ], colWidths=[W - 4*cm])
    cover_table.setStyle(TableStyle([
        ("BACKGROUND", (0,0), (-1,-1), C_NAVY),
        ("TOPPADDING", (0,0), (0,0), 40),
        ("BOTTOMPADDING", (0,4), (-1,4), 40),
        ("TOPPADDING", (0,1), (-1,-1), 6),
        ("BOTTOMPADDING", (0,0), (-1,2), 6),
    ]))
    elems.append(cover_table)
    elems.append(Spacer(1, 1*cm))

    info = [
        ["Contents", "12 Operations covered"],
        ["Format", "Indications · Position · Steps · Key Points"],
        ["Diagrams", "Included for each major operation"],
        ["Edition", "Fischer 8th Ed | 2026"],
    ]
    t = Table(info, colWidths=[6*cm, 10*cm])
    t.setStyle(TableStyle([
        ("BACKGROUND", (0,0), (0,-1), C_TEAL),
        ("TEXTCOLOR", (0,0), (0,-1), C_WHITE),
        ("BACKGROUND", (1,0), (1,-1), C_LIGHT),
        ("FONTNAME", (0,0), (-1,-1), "Helvetica"),
        ("FONTSIZE", (0,0), (-1,-1), 10),
        ("GRID", (0,0), (-1,-1), 0.5, C_TEAL),
        ("TOPPADDING", (0,0), (-1,-1), 6),
        ("BOTTOMPADDING", (0,0), (-1,-1), 6),
        ("LEFTPADDING", (0,0), (-1,-1), 10),
    ]))
    elems.append(t)
    elems.append(PageBreak())
    return elems


# ─── TABLE OF CONTENTS ────────────────────────────────────────────────────────
def toc_gi():
    elems = []
    elems.append(chapter_header("TABLE OF CONTENTS", "GI Surgery Operations"))
    elems.append(Spacer(1, 0.4*cm))
    ops = [
        ("1", "Appendectomy (Open & Laparoscopic)", "3"),
        ("2", "Cholecystectomy (Laparoscopic)", "5"),
        ("3", "Inguinal Hernia Repair (Lichtenstein / TEP)", "7"),
        ("4", "Gastrectomy (Subtotal & Total)", "9"),
        ("5", "Whipple Procedure (Pancreaticoduodenectomy)", "12"),
        ("6", "Hartmann's Procedure", "15"),
        ("7", "Right Hemicolectomy", "17"),
        ("8", "Anterior Resection of Rectum", "19"),
        ("9", "Abdominoperineal Resection (APR)", "21"),
        ("10", "Roux-en-Y Gastric Bypass", "23"),
        ("11", "Ivor-Lewis Oesophagectomy", "25"),
        ("12", "Splenectomy", "27"),
    ]
    for no, name, pg in ops:
        row = Table([[Paragraph(f"<b>{no}.</b>  {name}", sStep),
                      Paragraph(f"pg {pg}", ParagraphStyle("pg", fontName="Helvetica",
                                fontSize=9.5, alignment=TA_CENTER))]],
                    colWidths=[13*cm, 3*cm])
        row.setStyle(TableStyle([
            ("BACKGROUND", (0,0), (-1,-1), C_LGREY if int(no)%2==0 else C_WHITE),
            ("GRID", (0,0), (-1,-1), 0.3, colors.HexColor("#CCCCCC")),
            ("TOPPADDING", (0,0), (-1,-1), 4),
            ("BOTTOMPADDING", (0,0), (-1,-1), 4),
            ("LEFTPADDING", (0,0), (0,0), 10),
        ]))
        elems.append(row)
    elems.append(PageBreak())
    return elems


# ─── OPERATIONS ───────────────────────────────────────────────────────────────
def op_appendectomy():
    e = []
    e.append(chapter_header("1. APPENDECTOMY", "Open & Laparoscopic"))
    e.append(Spacer(1, 0.3*cm))
    e.append(section_header("Indications"))
    e += bullet_list([
        "Acute appendicitis (uncomplicated & complicated)",
        "Incidental appendectomy during other abdominal surgery (selective)",
        "Appendiceal neoplasm (carcinoid < 2 cm - appendectomy sufficient; > 2 cm - right hemicolectomy)",
    ])
    e.append(section_header("Patient Position & Preparation"))
    e += bullet_list([
        "Supine; both arms abducted on arm boards",
        "Urinary catheter inserted; NG tube if ileus/obstruction",
        "IV prophylactic antibiotics (metronidazole + cefuroxime) 30 min pre-incision",
        "Skin prep from nipple to mid-thigh",
    ])
    e.append(section_header("OPEN Appendectomy - Operative Steps"))
    e += numbered_steps([
        "Mark and make a Lanz (or grid-iron) incision at McBurney's point (1/3 of line from ASIS to umbilicus); 4-6 cm oblique.",
        "Divide skin, subcutaneous fat. Split external oblique in line of fibres; split internal oblique and transversus by muscle-splitting technique.",
        "Incise peritoneum between haemostats; widen incision. Collect peritoneal fluid for culture.",
        "Identify caecum (taenia coli converge at appendix base). Deliver caecum with gentle traction.",
        "Locate appendix by following the taenia coli to its base.",
        "Divide mesoappendix between haemostatic clamps sequentially from tip to base; ligate each pedicle with 2-0 Vicryl.",
        "Apply a crushing clamp across appendix base, re-apply proximal, crush proximal 3-5 mm, swab with iodine, ligate base with 0-Vicryl.",
        "Amputate appendix with scalpel distal to ligature; swab stump with iodine/phenol.",
        "Invaginate stump with a purse-string or Z-stitch suture (2-0 absorbable) if desired - evidence does not mandate this.",
        "Irrigate peritoneal cavity if contaminated with warm saline.",
        "Close peritoneum with continuous 0-Vicryl; external oblique with continuous 0-Vicryl. Close skin with subcuticular suture or clips.",
    ])
    e.append(SVGDiagram(make_appendectomy_diagram(), width=400, height=220))
    e.append(Paragraph("Fig 1. Appendix anatomy, McBurney's point and Lanz incision", sDiagCaption))
    e.append(section_header("LAPAROSCOPIC Appendectomy - Operative Steps"))
    e += numbered_steps([
        "3-port technique: 10 mm umbilical (camera), 5 mm LIF (assistant), 5 mm suprapubic or RIF (surgeon). Alternatively 2-port or SILS.",
        "Pneumoperitoneum to 12-14 mmHg with Veress needle at umbilicus (or Hassan technique if prior surgery).",
        "Inspect pelvis, RIF; tilt patient L-lateral and Trendelenburg to displace bowel.",
        "Grasp appendix at tip with atraumatic grasper. Carefully free any adhesions.",
        "Create window in mesoappendix close to base using harmonic scalpel or monopolar hook.",
        "Apply two Endoloops (or two clips) at appendix base, one Endoloop distally; amputate between.",
        "Place specimen in retrieval bag before removal through umbilical port.",
        "Irrigate RIF if perforation; aspirate all fluid.",
        "Confirm haemostasis; desufflate; close port sites (fascial closure of 10 mm ports).",
    ])
    e.append(key_point("Fischer (8th ed): Secure mesoappendix haemostasis is the key manoeuvre to prevent post-op haemorrhage. The 'Critical View' principle - always confirm appendix base and caecal junction before division."))
    e.append(Spacer(1, 0.3*cm))
    e.append(section_header("Complications"))
    e += bullet_list([
        "Wound infection (most common) - reduced by antibiotic prophylaxis and laparoscopic approach",
        "Pelvic abscess / stump blowout (rare, if stump secured properly)",
        "Faecal fistula - if bowel wall involved in ligation",
        "Port-site hernia (laparoscopic - always close 10 mm fascial defects)",
        "Missed pathology (Meckel's, salpingitis, ovarian cyst) - always inspect at operation",
    ])
    e.append(PageBreak())
    return e


def op_cholecystectomy():
    e = []
    e.append(chapter_header("2. LAPAROSCOPIC CHOLECYSTECTOMY", "Gold Standard for Symptomatic Gallstones"))
    e.append(Spacer(1, 0.3*cm))
    e.append(section_header("Indications"))
    e += bullet_list([
        "Symptomatic cholelithiasis (biliary colic, chronic cholecystitis)",
        "Acute cholecystitis (within 72 h preferred - Tokyo Guidelines)",
        "Biliary pancreatitis (after recovery, same admission if mild)",
        "Gallbladder polyps > 10 mm",
        "Porcelain gallbladder with associated malignancy risk",
    ])
    e.append(section_header("Patient Position"))
    e += bullet_list([
        "Supine; surgeon on patient's left; camera operator on left",
        "Reverse Trendelenburg 20°, left lateral tilt 15°",
        "4-port technique: 10 mm umbilical (camera), 5 mm epigastric, two 5 mm RUQ ports",
    ])
    e.append(section_header("Operative Steps"))
    e += numbered_steps([
        "Establish pneumoperitoneum 12-14 mmHg. Insert 10 mm umbilical trocar; 30° scope inserted.",
        "Insert remaining 3 trocars under direct vision (epigastric subxiphoid, midclavicular RUQ, anterior axillary line RUQ).",
        "Fundus grasped and retracted cephalad over liver edge; Hartmann's pouch grasped and retracted laterally.",
        "Open the hepatocystic triangle peritoneum using hook diathermy - incise both anterior and posterior peritoneal leaflets.",
        "Dissect the hepatocystic triangle until the CRITICAL VIEW OF SAFETY (CVS) is achieved: (a) hepatocystic triangle free of fat/fibrous tissue, (b) lowest part of GB separated from liver, (c) only TWO structures seen entering GB.",
        "Clip cystic duct with 3 clips (2 proximal, 1 distal); divide between clips. Obtain intraoperative cholangiogram if CBD stones suspected.",
        "Clip cystic artery with 2 clips proximally; divide. Ensure right hepatic artery not mistaken for cystic artery.",
        "Dissect GB from liver bed using hook diathermy or harmonic scalpel on liver side of bed.",
        "Place GB in retrieval bag; extract through umbilical port (enlarge if needed).",
        "Inspect liver bed for haemostasis. Irrigate. Drain only if significant bile spillage.",
        "Desufflate; close all port sites ≥ 10 mm at fascial level.",
    ])
    e.append(SVGDiagram(make_cholecystectomy_diagram(), width=460, height=260))
    e.append(Paragraph("Fig 2. Biliary anatomy, Triangle of Calot, and Critical View of Safety", sDiagCaption))
    e.append(key_point("Fischer (8th ed): The Critical View of Safety is NON-NEGOTIABLE. If CVS cannot be achieved (frozen Calot), convert to open or perform subtotal cholecystectomy rather than risk bile duct injury."))
    e.append(section_header("Operative Hazards"))
    e += bullet_list([
        "Bile duct injury - most serious; classify by Strasberg system (A-E)",
        "Right hepatic artery injury - mistaken for cystic artery in 20% anatomic variants",
        "Bleeding from cystic artery or liver bed",
        "Bile spillage from GB perforation (retrieve all stones)",
        "Port-site hernia at 10 mm sites",
    ])
    e.append(PageBreak())
    return e


def op_inguinal_hernia():
    e = []
    e.append(chapter_header("3. INGUINAL HERNIA REPAIR", "Lichtenstein (Open) & TEP (Laparoscopic)"))
    e.append(Spacer(1, 0.3*cm))
    e.append(section_header("Classification"))
    e += bullet_list([
        "Direct: through posterior wall (Hesselbach's triangle), medial to inferior epigastric vessels",
        "Indirect: through internal ring, lateral to inferior epigastric vessels - most common",
        "Nyhus / EHS classification used for surgical planning",
    ])
    e.append(section_header("LICHTENSTEIN (Open Mesh) - Operative Steps"))
    e += numbered_steps([
        "Oblique inguinal incision 1 cm above and parallel to medial inguinal ligament; 5-6 cm.",
        "Divide Scarpa's fascia; expose external oblique aponeurosis. Open EO aponeurosis from external ring laterally in line of fibres.",
        "Reflect upper and lower flaps of EO; identify ilioinguinal nerve and protect throughout.",
        "Elevate spermatic cord off inguinal floor with index finger; encircle cord with Penrose drain.",
        "Identify hernia sac: indirect sac found anteromedially within cremasteric fibres; open and reduce. Divide sac at internal ring level if large; close neck.",
        "Direct sac: invaginate with purse-string or simply reduce - no excision needed.",
        "Place polypropylene mesh (6x11 cm) flat on inguinal floor, medial end rounded to overlap pubic tubercle by 1-1.5 cm. Cut a slit in lateral end to accommodate spermatic cord.",
        "Suture mesh to pubic tubercle periosteum (0 Prolene); continue lateral suture to inguinal ligament. Upper edge sutured to conjoint tendon/internal oblique with interrupted absorbable sutures.",
        "Approximate tails of mesh around spermatic cord at internal ring - create neo-internal ring that admits tip of little finger only.",
        "Close EO over cord with continuous absorbable; Scarpa's; subcuticular skin closure.",
    ])
    e.append(SVGDiagram(make_hernia_diagram(), width=460, height=230))
    e.append(Paragraph("Fig 3. Inguinal canal anatomy, Hesselbach's triangle, and mesh placement (Lichtenstein)", sDiagCaption))
    e.append(section_header("TEP (Total ExtraPeritoneal) - Key Steps"))
    e += numbered_steps([
        "Small infraumbilical incision; incise anterior rectus sheath; displace rectus laterally.",
        "Balloon trocar introduced in preperitoneal space; inflate to create working space.",
        "Three trocars: 10 mm infraumbilical, two 5 mm in midline below umbilicus.",
        "Dissect preperitoneal space: identify pubic symphysis, Cooper's ligament, inferior epigastric vessels, vas deferens, testicular vessels.",
        "Reduce indirect sac fully (if large, divide and close); reduce direct sac by gentle traction.",
        "Place 15x10 cm polypropylene mesh covering both direct and indirect spaces and femoral ring; fix medially to Cooper's ligament with 1-2 tacker fixations only.",
        "Desufflate; peritoneum falls against mesh achieving fixation.",
    ])
    e.append(key_point("Fischer: For bilateral hernias, TEP has clear advantage. Mesh must cover the myopectineal orifice (MPO) entirely. Avoid tackers near the 'triangle of pain' (genitofemoral and lateral femoral cutaneous nerves)."))
    e.append(PageBreak())
    return e


def op_gastrectomy():
    e = []
    e.append(chapter_header("4. GASTRECTOMY", "Subtotal & Total Gastrectomy for Gastric Cancer"))
    e.append(Spacer(1, 0.3*cm))
    e.append(section_header("Indications"))
    e += bullet_list([
        "Gastric adenocarcinoma (primary indication)",
        "GIST > 2 cm or with high-risk features",
        "Refractory peptic ulcer disease (rare with PPI era)",
        "Morbid obesity (sleeve gastrectomy - see bariatric section)",
    ])
    e.append(section_header("Subtotal Gastrectomy - Operative Steps"))
    e += numbered_steps([
        "Upper midline incision or Rooftop incision. Thorough exploration for metastases - peritoneal, hepatic, nodal.",
        "Enter lesser sac through gastrocolic ligament; inspect posterior wall of stomach.",
        "Divide greater omentum from left gastroepiploic vessels to right, including omentectomy (infracolic for D2). Divide right gastroepiploic vessels at their origin.",
        "Divide lesser omentum; identify and protect common hepatic artery, portal vein.",
        "Kocher manoeuvre: mobilise duodenum to expose duodenal stump.",
        "Divide duodenum 2 cm distal to pylorus with linear stapler (GIA 60). Oversew duodenal stump with Lambert sutures (0-Vicryl).",
        "D2 lymphadenectomy: clear nodes along lesser curve (stations 1,2,3,4), right gastric artery (station 5), infra/supra pyloric (stations 6,4b), left gastric (station 7), common hepatic (8), coeliac (9), splenic artery (11). Spleen and distal pancreas preserved in D2 unless invaded.",
        "Ligate and divide left gastric artery at its origin from coeliac axis.",
        "Transect stomach 5 cm proximal to tumour (or cardia for high-body tumours) with linear stapler; confirm proximal frozen section clear.",
        "Reconstruction: Billroth II (gastrojejunostomy) preferred - retrocolic loop of jejunum 20-30 cm from Treitz; hand-sewn or stapled 2-layer anastomosis. Alternatively Roux-en-Y reconstruction.",
    ])
    e.append(SVGDiagram(make_gastric_diagram(), width=460, height=260))
    e.append(Paragraph("Fig 4. Gastric anatomy, resection lines, and reconstruction options", sDiagCaption))
    e.append(section_header("Total Gastrectomy - Additional Steps"))
    e += numbered_steps([
        "Mobilise spleen and tail of pancreas only if directly invaded (standard D2 does NOT include routine splenopancreatectomy).",
        "Divide oesophagus 5 cm above GEJ with linear stapler; confirm frozen section negative.",
        "Oesophagojejunostomy reconstruction: Roux-en-Y with 60 cm Roux limb. End-to-side oesophagojejunostomy using circular stapler (25-28 mm EEA) or hand-sewn.",
        "Entero-entero anastomosis (JJ) at 60 cm from oesophageal anastomosis.",
    ])
    e.append(key_point("Fischer: D2 lymphadenectomy (vs D1) significantly improves disease-specific survival with acceptable morbidity in experienced centres. Pancreatic head resection for nodal clearance is NOT indicated unless direct invasion."))
    e.append(PageBreak())
    return e


def op_whipple():
    e = []
    e.append(chapter_header("5. PANCREATICODUODENECTOMY (WHIPPLE)", "Classic and Pylorus-Preserving"))
    e.append(Spacer(1, 0.3*cm))
    e.append(section_header("Indications"))
    e += bullet_list([
        "Pancreatic head adenocarcinoma (resectable - no arterial involvement)",
        "Ampullary carcinoma, distal bile duct carcinoma, duodenal carcinoma",
        "Chronic pancreatitis with head mass or ductal obstruction (Beger / Frey variants)",
        "Cystic neoplasms with malignant features (IPMN with mural nodules, mucinous cysts)",
    ])
    e.append(section_header("Exploration & Resectability Assessment"))
    e += numbered_steps([
        "Bilateral subcostal (rooftop) incision or upper midline. Thorough exploration.",
        "Enter lesser sac; assess posterior stomach, anterior pancreas, presence of peritoneal/hepatic mets.",
        "Kocher manoeuvre: mobilise duodenum and pancreatic head; assess relation to SMA/SMV from behind.",
        "Dissect hepatoduodenal ligament; palpate portal vein anterior to pancreatic neck - create tunnel between SMV-PV and pancreatic neck (key resectability step).",
        "If no involvement of SMA/coeliac, proceed to resection.",
    ])
    e.append(section_header("Resection Phase"))
    e += numbered_steps([
        "Cholecystectomy; divide CBD 1 cm above duodenum with bulldog clamps.",
        "Divide stomach at antrum (classic Whipple) OR preserve pylorus 2 cm from pyloric ring (PPPD - pylorus-preserving PD) with linear stapler.",
        "Divide proximal jejunum 15-20 cm from Treitz; divide mesentery; bring loop under mesenteric vessels.",
        "Divide pancreatic neck over SMV-PV tunnel with electrocautery and scissors; control bleeding points on cut surface; identify and ligate main pancreatic duct.",
        "Divide uncinate process from SMV and SMA (most demanding step): multiple small veins from uncinate to SMV ligated sequentially; keep dissection on SMA side once SMV cleared.",
        "Specimen removed. Mark for pathology (CBD, pancreatic, duodenal margins).",
    ])
    e.append(SVGDiagram(make_whipple_diagram(), width=460, height=280))
    e.append(Paragraph("Fig 5. Pancreaticoduodenectomy - anatomy, resection, and Child's reconstruction", sDiagCaption))
    e.append(section_header("Reconstruction (Child's Sequence)"))
    e += numbered_steps([
        "PANCREATICOJEJUNOSTOMY (first): end-to-side duct-to-mucosa (2-layer, PDS 4-0/5-0); OR invagination technique (dunking) for soft gland / small duct. Place internal stent if duct < 3 mm.",
        "HEPATICOJEJUNOSTOMY: 10-15 cm distal to pancreatic anastomosis. End-to-side, single-layer interrupted 4-0 PDS. T-tube drain only if duct < 5 mm.",
        "GASTROJEJUNOSTOMY (or duodenojejunostomy for PPPD): 45-50 cm distal to hepaticojejunostomy. Two-layer sutured or stapled. Retrocolic or antecolic position - antecolic preferred (lower DGE rate).",
        "Place closed-suction drains near pancreatic and biliary anastomoses.",
    ])
    e.append(key_point("Fischer: Postoperative pancreatic fistula (POPF) is the most feared complication. Risk factors: soft texture, small duct, high-fat pancreas. External stent + octreotide for high-risk glands. ISGPS grading: Biochemical leak, Grade B (clinical impact), Grade C (life-threatening)."))
    e.append(section_header("Key Complications"))
    e += bullet_list([
        "POPF (Pancreatic fistula) - up to 15% with soft gland",
        "Delayed gastric emptying (DGE) - most common non-fistula complication",
        "Post-pancreatectomy haemorrhage (PPH) - often sentinel bleed before major bleed",
        "Bile leak from hepaticojejunostomy",
        "Wound infection, abscess",
        "Endocrine / exocrine insufficiency",
    ])
    e.append(PageBreak())
    return e


def op_hartmanns():
    e = []
    e.append(chapter_header("6. HARTMANN'S PROCEDURE", "Emergency Left Hemicolectomy + End Colostomy"))
    e.append(Spacer(1, 0.3*cm))
    e.append(section_header("Indications"))
    e += bullet_list([
        "Perforated sigmoid diverticulitis (Hinchey III/IV)",
        "Obstructing sigmoid/rectal carcinoma with acute obstruction or perforation",
        "Sigmoid volvulus with gangrenous bowel",
        "Ischaemic sigmoid colon",
    ])
    e.append(section_header("Operative Steps"))
    e += numbered_steps([
        "Midline laparotomy from xiphisternum to pubis. Four-quadrant packing of peritoneal cavity. Sample peritoneal fluid for culture.",
        "Retract small bowel to the right. Incise lateral peritoneal reflection of sigmoid; mobilise sigmoid by medial-to-lateral approach.",
        "Identify LEFT URETER at pelvic brim - trace to bladder before any ligation. Protect iliac vessels.",
        "Ligate and divide inferior mesenteric artery (IMA) at origin from aorta or just distal to left colic - based on oncologic need vs emergency context.",
        "Ligate inferior mesenteric vein (IMV) at inferior border of pancreas.",
        "Mobilise sigmoid and upper rectum from presacral fascia in embryological planes.",
        "Divide sigmoid colon proximally at healthy, well-vascularised site with linear stapler (GIA 75).",
        "Divide rectum at the level of the peritoneal reflection (or below if necessary for cancer) with linear stapler; oversew with Lambert sutures.",
        "Thorough peritoneal lavage (6-10 L warm saline) in all 4 quadrants.",
        "Mark stoma site (previously identified by stoma nurse in elective setting - LIF, 5 cm from bony landmarks). Excise disc of skin 2 cm diameter; dissect through subcutaneous fat, split anterior rectus sheath, rectus, posterior sheath. Open peritoneum.",
        "Deliver sigmoid end through stoma aperture - 2-3 cm above skin level; mature with interrupted absorbable sutures (seromuscular to dermis, full thickness mucosa to skin edge).",
        "Close abdomen; skin closure delayed if grossly contaminated.",
    ])
    e.append(SVGDiagram(make_hartmanns_diagram(), width=420, height=240))
    e.append(Paragraph("Fig 6. Hartmann's procedure - resection level, IMA ligation, ureter identification", sDiagCaption))
    e.append(key_point("Fischer: Always formally identify the left ureter BEFORE clamping any mesenteric tissue in emergency sigmoid surgery. A pre-placed ureteric stent (if time allows) greatly reduces injury risk."))
    e.append(section_header("Hartmann's Reversal"))
    e += bullet_list([
        "Planned 3-6 months after primary operation, once sepsis resolved and patient optimised",
        "Mobilise stoma; dissect rectal stump; colorectal anastomosis with circular stapler",
        "Defunctioning loop ileostomy if anastomosis under tension or patient high risk",
    ])
    e.append(PageBreak())
    return e


def op_right_hemi():
    e = []
    e.append(chapter_header("7. RIGHT HEMICOLECTOMY", "Open & Laparoscopic - Right Colon Cancer"))
    e.append(Spacer(1, 0.3*cm))
    e.append(section_header("Indications"))
    e += bullet_list([
        "Carcinoma of caecum, ascending colon, or hepatic flexure",
        "Complicated appendiceal tumour (carcinoid > 2 cm, mucinous appendiceal tumour)",
        "Complicated diverticular disease of the right colon (rare)",
        "Ischaemia of right colon",
    ])
    e.append(section_header("Extent of Resection"))
    e += bullet_list([
        "Caecum, ascending colon, hepatic flexure, proximal transverse colon (to mid-transverse for hepatic flexure cancer)",
        "Terminal ileum (5-10 cm)",
        "Associated mesentery with vascular pedicle: ileocolic vessels + right colic vessels + right branch of middle colic vessels (D3 high ligation for cancer)",
    ])
    e.append(section_header("Operative Steps (Open)"))
    e += numbered_steps([
        "Right paramedian or midline incision. Thorough exploration - liver, peritoneum, lymph nodes.",
        "Medial-to-lateral dissection (oncologic approach): identify SMV at root of mesentery; dissect along SMV superiorly; ligate ileocolic vessels at origin (D3 ligation).",
        "Identify right ureter and duodenum - DO NOT injure. Gerota's fascia left intact.",
        "Ligate right colic vessels (if present - variable anatomy) and right branch of MCA.",
        "Lateral mobilisation: incise right paracolic gutter peritoneum; mobilise caecum superiorly. Divide hepatocolic ligament carefully.",
        "Mobilise hepatic flexure by dividing hepatocolic ligament and omentum from colon.",
        "Divide ileum 10 cm proximal to ileocaecal valve and transverse colon at mid-transverse; with linear stapler (GIA 80).",
        "Ileocolic anastomosis: side-to-side stapled (functional end-to-end) or hand-sewn end-to-end/side-to-end. Ensure good blood supply and no tension.",
        "Close mesenteric defect with interrupted sutures to prevent internal hernia.",
    ])
    e.append(SVGDiagram(make_hemicolectomy_diagram(), width=460, height=240))
    e.append(Paragraph("Fig 7. Right hemicolectomy - extent of resection, vascular anatomy, D3 ligation", sDiagCaption))
    e.append(section_header("Laparoscopic Approach Key Steps"))
    e += numbered_steps([
        "5-trocar technique: camera (umbilical), RUQ, RIF, LIF, suprapubic.",
        "Medial-to-lateral approach: SMV identification, ileocolic vessel ligation at origin.",
        "Complete mesocolic excision (CME) - dissection in embryological plane to achieve D3 lymphadenectomy.",
        "Extracorporeal anastomosis through small (5 cm) RUQ extraction incision.",
    ])
    e.append(key_point("Fischer: Complete Mesocolic Excision (CME) with central vascular ligation (CVL) mirrors the TME principle for rectal cancer and improves oncologic outcomes for right colon cancer."))
    e.append(PageBreak())
    return e


def op_anterior_resection():
    e = []
    e.append(chapter_header("8. ANTERIOR RESECTION OF RECTUM", "Low / High Anterior Resection for Rectal Cancer"))
    e.append(Spacer(1, 0.3*cm))
    e.append(section_header("Indications"))
    e += bullet_list([
        "Mid/upper rectal adenocarcinoma (> 5 cm from anal verge)",
        "Sigmoid carcinoma",
        "Complicated sigmoid diverticulitis",
        "Rectal GIST, carcinoid",
    ])
    e.append(section_header("Key Principles"))
    e += bullet_list([
        "Total Mesorectal Excision (TME) - complete sharp dissection in holy plane between mesorectal fascia and parietal (Waldeyer's) fascia",
        "Circumferential Resection Margin (CRM) must be clear (> 1 mm) - assessed pre-op with MRI",
        "Distal margin: minimum 1-2 cm distal to tumour lower edge (sphincter-preserving)",
    ])
    e.append(section_header("Operative Steps"))
    e += numbered_steps([
        "Lloyd-Davis (lithotomy-Trendelenburg) position; warming mattress, TED stockings, catheter.",
        "Midline laparotomy (or laparoscopic 5-port approach). Exploration for mets.",
        "Mobilise sigmoid: incise left paracolic peritoneum; enter retroperitoneal plane.",
        "Identify and protect LEFT URETER at pelvic brim bilaterally; preserve both hypogastric (autonomic) nerves.",
        "HIGH LIGATION of IMA at aorta (or just distal to left colic origin for nerve preservation); ligate IMV at pancreatic border.",
        "Medial to lateral mobilisation of mesorectum. Enter 'Holy Plane' (presacral avascular plane between mesorectal fascia and endopelvic/Waldeyer's fascia).",
        "Sharply dissect mesorectum posteriorly to levator hiatus (for low AR or APR), anteriorly protecting Denonvillier's fascia (prostate/vagina), laterally taking lateral ligaments (contains middle rectal vessels).",
        "Divide colon proximally with linear stapler at adequately vascularised site above IMA ligation; ensure 5-6 cm tension-free length of proximal colon reaches deep pelvis.",
        "Divide rectum distally with linear stapler (Contour/DST stapler) 1-2 cm below tumour; angle perpendicular to rectum to avoid a dog-ear.",
        "Colorectal anastomosis with circular stapler (28-33 mm EEA): anvil secured in proximal colon with purse-string; EEA inserted transanally; anastomosis fired after checking donuts.",
        "Air-leak test: fill pelvis with saline, inflate air via proctoscope - no bubbles confirms integrity.",
        "Defunctioning loop ileostomy for low anastomosis (< 6 cm from AV), radiotherapy or tension.",
        "Pelvic drain. Close abdomen.",
    ])
    e.append(key_point("Fischer: TME is the technical cornerstone that reduced local recurrence from ~25% to < 5%. The 'holy plane' must be sharp-dissected under direct vision - never blunt/finger fracture in the mesorectal envelope."))
    e.append(section_header("Complications"))
    e += bullet_list([
        "Anastomotic leak (5-15%) - more common for very low anastomosis",
        "Autonomic nerve injury: bladder dysfunction (hypogastric nerves), sexual dysfunction",
        "Haemorrhage from pelvic floor or middle rectal vessels",
        "Ureteric injury",
        "Presacral venous bleeding (do not pack - use thumbtack)",
    ])
    e.append(PageBreak())
    return e


def op_apr():
    e = []
    e.append(chapter_header("9. ABDOMINOPERINEAL RESECTION (APR)", "Miles' Operation - Low Rectal Cancer"))
    e.append(Spacer(1, 0.3*cm))
    e.append(section_header("Indications"))
    e += bullet_list([
        "Carcinoma of lower rectum (< 4-5 cm from anal verge) not amenable to sphincter-saving",
        "Anal canal carcinoma failing chemoradiotherapy (salvage APR)",
        "Faecal incontinence with rectal pathology requiring proctectomy",
    ])
    e.append(section_header("Operative Steps - Abdominal Phase"))
    e += numbered_steps([
        "Lloyd-Davis position. Stoma site marked (LIF) pre-op.",
        "Midline laparotomy. Mobilise sigmoid and upper rectum as in anterior resection.",
        "IMA ligation, TME performed to levator ani hiatus - identical to low AR abdominal phase.",
        "Left ureter and hypogastric nerves identified and protected.",
        "Abdominal phase ends once rectum mobilised to levator; sigmoid brought out as end colostomy.",
    ])
    e.append(section_header("Operative Steps - Perineal Phase"))
    e += numbered_steps([
        "Purse-string suture closes anus. Patient may remain in lithotomy or repositioned prone (prone jack-knife gives better perineal exposure in difficult cases).",
        "Elliptical perineal incision: 3 cm lateral to anus on each side, posterior to coccyx, anterior to perineal body.",
        "Deepen incision through ischioanal fat bilaterally; identify levator ani muscles laterally.",
        "POSTERIOR: divide anococcygeal ligament; enter presacral space. Connect with abdominal dissection posteriorly.",
        "LATERAL: divide levator ani bilaterally close to pelvic sidewall (cylindrical APR takes wider cuff of levators).",
        "ANTERIOR: most hazardous - divide superficial and deep transverse perineal muscles, preserve urethra and prostate/vagina anteriorly. Denonvillier's fascia kept on specimen side for posterior tumours.",
        "Deliver specimen through perineal wound. Check for adequacy of resection margins.",
        "Irrigate perineal wound (dilute betadine then saline). Primary perineal closure in layers (levator muscles approximated if possible, subcutaneous, skin). Drain via perineal wound or suprapubic.",
        "Mature colostomy at LIF site.",
    ])
    e.append(key_point("Fischer: Cylindrical (extralevator) APR reduces intraoperative perforation rate and positive CRM compared to conventional APR for low rectal tumours - the levators are divided at the pelvic sidewall to give a wider cylindrical specimen."))
    e.append(PageBreak())
    return e


def op_rygb():
    e = []
    e.append(chapter_header("10. ROUX-en-Y GASTRIC BYPASS (RYGB)", "Bariatric Surgery - Gold Standard"))
    e.append(Spacer(1, 0.3*cm))
    e.append(section_header("Indications (NICE/ASMBS Criteria)"))
    e += bullet_list([
        "BMI ≥ 40 kg/m² or BMI ≥ 35 with obesity-related comorbidity (T2DM, HTN, OSA, joint disease)",
        "Failed conservative weight loss attempts ≥ 6 months",
        "Psychologically fit; understand lifelong dietary modification",
    ])
    e.append(section_header("Operative Steps (Laparoscopic)"))
    e += numbered_steps([
        "6-trocar technique: camera left of midline, liver retractor in epigastrium; patient in steep reverse Trendelenburg.",
        "Divide gastrocolic omentum to enter lesser sac. Identify angle of His.",
        "Linear stapler (60 mm, 3.8 mm load) fired horizontally at cardial level, then vertically up to GEJ: creates small gastric pouch of 15-30 mL (ensures restriction).",
        "Identify Treitz ligament. Divide jejunum 50-75 cm from Treitz (biliopancreatic limb).",
        "Roux limb: measure 75-150 cm distally from jejunal division for standard RYGB (longer for superobese).",
        "Jejunojejunostomy (JJ): side-to-side stapled anastomosis between biliopancreatic limb and Roux limb; close enterotomy and mesenteric defect (Peterson's hernia prevention).",
        "Pass Roux limb antecolic/antegastric (standard) or retrocolic/retrogastric to reach pouch.",
        "Gastrojejunostomy: circular stapled (21-25 mm EEA via mouth) or linear stapled or hand-sewn. Test with air/methylene blue.",
        "Close all mesenteric defects (Peterson's, transverse mesocolon if retrocolic).",
        "Drain near GJ anastomosis.",
    ])
    e.append(SVGDiagram(make_lap_roux_diagram(), width=440, height=240))
    e.append(Paragraph("Fig 8. Roux-en-Y Gastric Bypass - limb configuration", sDiagCaption))
    e.append(key_point("Fischer: Mesenteric defect closure is MANDATORY after RYGB - internal hernia through Peterson's space is a life-threatening late complication, occurring in 2-4% without closure. Always close Petersen's defect and JJ mesenteric defect."))
    e.append(section_header("Complications"))
    e += bullet_list([
        "Anastomotic leak (1-2%) - GJ anastomosis most common site",
        "Marginal ulcer - most common late complication (NSAIDs, smoking, H.pylori risk factors)",
        "Internal hernia (Peterson's) after weight loss",
        "Dumping syndrome (early/late)",
        "Nutritional deficiencies: B12, iron, folate, calcium, fat-soluble vitamins",
        "Band erosion / stricture at GJ",
    ])
    e.append(PageBreak())
    return e


def op_ivor_lewis():
    e = []
    e.append(chapter_header("11. IVOR-LEWIS OESOPHAGECTOMY", "Two-Phase for Mid/Distal Oesophageal Cancer"))
    e.append(Spacer(1, 0.3*cm))
    e.append(section_header("Indications"))
    e += bullet_list([
        "Squamous cell carcinoma of mid/lower oesophagus",
        "Adenocarcinoma of distal oesophagus / GEJ (Siewert I & II)",
        "High-grade dysplasia in Barrett's not amenable to endoscopic resection",
    ])
    e.append(section_header("Phase 1 - Abdominal (Patient Supine)"))
    e += numbered_steps([
        "Upper midline or rooftop laparotomy. Exploration for metastases.",
        "Kocherise duodenum. Divide lesser omentum; identify and preserve right gastroepiploic artery.",
        "Ligate and divide short gastric vessels; left gastroepiploic; left gastric artery at origin (lymphadenectomy stations 7,8,9,11).",
        "Preserve right gastroepiploic arcade (main gastric conduit blood supply) and right gastric artery.",
        "Divide distal oesophagus and form gastric conduit (5 cm wide, stapled along lesser curve); ensure conduit length sufficient to reach neck/chest.",
        "Pyloroplasty or pyloromyotomy (facilitates gastric drainage after vagotomy).",
        "Feeding jejunostomy (mandatory for post-op nutrition).",
    ])
    e.append(section_header("Phase 2 - Right Thoracotomy (Left Lateral Position)"))
    e += numbered_steps([
        "Right posterolateral thoracotomy through 5th intercostal space (or VATS approach).",
        "Mobilise oesophagus from thoracic inlet to hiatus; divide azygos vein between ligatures.",
        "Thoracic lymphadenectomy: right paratracheal, subcarinal, periesophageal, pulmonary ligament nodes.",
        "Deliver gastric conduit through hiatus or posterior mediastinum.",
        "Divide oesophagus at least 5 cm above tumour under direct vision; frozen section margins.",
        "INTRATHORACIC ANASTOMOSIS: end-to-side oesophagogastric anastomosis using circular EEA (25-28 mm) or hand-sewn 2-layer technique.",
        "Nasogastric tube positioned under direct vision past anastomosis.",
        "Close chest: intercostal drain (28F), close ribs, muscle layers, skin.",
    ])
    e.append(SVGDiagram(make_ivor_lewis_diagram(), width=440, height=260))
    e.append(Paragraph("Fig 9. Ivor-Lewis oesophagectomy - two phases and intrathoracic anastomosis", sDiagCaption))
    e.append(key_point("Fischer: Anastomotic leak after oesophagectomy carries 30-50% mortality. Critical factors: tension-free anastomosis, no ischaemia of conduit tip, NGT positioned past anastomosis, early oral contrast study on day 5-7."))
    e.append(PageBreak())
    return e


def op_splenectomy():
    e = []
    e.append(chapter_header("12. SPLENECTOMY", "Elective Open & Laparoscopic"))
    e.append(Spacer(1, 0.3*cm))
    e.append(section_header("Indications"))
    e += bullet_list([
        "Haematological: ITP, hereditary spherocytosis, thalassaemia, autoimmune haemolytic anaemia",
        "Trauma: splenic laceration grade III-V (haemodynamically unstable or failed NOM)",
        "Neoplastic: lymphoma (staging/bulky disease), splenic cysts",
        "Hypersplenism secondary to portal hypertension",
        "Incidental during other procedures (distal pancreatectomy, gastrectomy)",
    ])
    e.append(section_header("Pre-operative Preparation"))
    e += bullet_list([
        "Vaccinations: pneumococcus (Pneumovax), meningococcus, Hib - ideally 2 weeks before (or at discharge if emergency)",
        "Pre-op platelet transfusion for ITP only when platelets < 20,000 or active bleeding (transfuse AFTER vessels ligated)",
        "Informed consent: OPSI risk (lifelong), incidental splenunculi may cause recurrence",
    ])
    e.append(section_header("Laparoscopic Splenectomy - Operative Steps"))
    e += numbered_steps([
        "Right semi-lateral (45°) or full right lateral position; 4-trocar technique.",
        "Left flank approach: camera at LMC 12 mm; working ports at LIF, epigastrium, posterior axillary line.",
        "Enter lesser sac through gastrosplenic ligament; clip and divide short gastric vessels (harmonic/ligasure).",
        "Expose splenic hilum from inferior pole; divide inferior pole vessels.",
        "Medialise spleen to expose posterior attachments. Divide splenorenal and splenophrenic ligaments.",
        "Divide splenic artery first at hilum (clips x3); then splenic vein.",
        "Splenic vascular pedicle may be divided en-masse with vascular load linear stapler (45-60 mm).",
        "Place spleen in tissue morcellator bag; morcellate and extract through extended port site.",
        "Inspect bed for haemostasis, tail of pancreas integrity. Drain if pancreatic tail injury.",
    ])
    e.append(section_header("Open Splenectomy - Additional Steps"))
    e += bullet_list([
        "Left subcostal or midline incision; mobilise by incising lateral peritoneal attachments",
        "Deliver spleen medially; identify and ligature splenic artery at pancreatic tail, then vein",
        "For trauma: rapid hilar control with hand then staple/suture",
    ])
    e.append(key_point("Fischer: OPSI (Overwhelming Post-Splenectomy Infection) risk is lifelong - 0.5% annual risk, 50% mortality. Ensure pneumococcal, meningococcal, and Hib vaccines. Penicillin V prophylaxis for 2 years post-op (some guidelines recommend lifelong in children and asplenic patients)."))
    e.append(PageBreak())
    return e


# ─── ASSEMBLE DOCUMENT ────────────────────────────────────────────────────────
def build_gi_pdf():
    path = "/home/daytona/workspace/operative-surgery/GI_Surgery_Operative_Steps.pdf"
    doc = SimpleDocTemplate(
        path, pagesize=A4,
        leftMargin=2*cm, rightMargin=2*cm,
        topMargin=2*cm, bottomMargin=2*cm,
        title="GI Surgery - Operative Steps",
        author="Fischer's Mastery of Surgery 8th Ed | Sabiston | Schwartz"
    )

    def header_footer(canvas, doc):
        canvas.saveState()
        canvas.setFont("Helvetica-Bold", 8)
        canvas.setFillColor(C_NAVY)
        canvas.drawString(2*cm, H-1.3*cm, "GI Surgery - Operative Steps")
        canvas.setFont("Helvetica", 8)
        canvas.setFillColor(C_TEAL)
        canvas.drawRightString(W-2*cm, H-1.3*cm, "Fischer's Mastery of Surgery, 8th Ed")
        canvas.setStrokeColor(C_TEAL)
        canvas.setLineWidth(0.5)
        canvas.line(2*cm, H-1.5*cm, W-2*cm, H-1.5*cm)
        canvas.setFont("Helvetica", 8)
        canvas.setFillColor(C_NAVY)
        canvas.drawCentredString(W/2, 1.2*cm, f"Page {doc.page}")
        canvas.line(2*cm, 1.6*cm, W-2*cm, 1.6*cm)
        canvas.restoreState()

    story = []
    story += cover_page_gi()
    story += toc_gi()
    story += op_appendectomy()
    story += op_cholecystectomy()
    story += op_inguinal_hernia()
    story += op_gastrectomy()
    story += op_whipple()
    story += op_hartmanns()
    story += op_right_hemi()
    story += op_anterior_resection()
    story += op_apr()
    story += op_rygb()
    story += op_ivor_lewis()
    story += op_splenectomy()

    doc.build(story, onFirstPage=header_footer, onLaterPages=header_footer)
    print(f"GI PDF built: {path}")
    return path


if __name__ == "__main__":
    build_gi_pdf()
Your credits are exhausted. You can purchase a top-up or subscribe to a plan to continue using Orris. If you're already subscribed, your daily credits will reset tomorrow.
This is a shared conversation. Sign in to Orris to start your own chat.