~/interbody-fusion-guide/generate_pdf.py
from reportlab.lib.pagesizes import A4
from reportlab.lib import colors
from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
from reportlab.lib.units import cm, mm
from reportlab.platypus import (
SimpleDocTemplate, Paragraph, Spacer, Table, TableStyle,
HRFlowable, PageBreak, KeepTogether
)
from reportlab.lib.enums import TA_CENTER, TA_LEFT, TA_JUSTIFY
from reportlab.platypus import ListFlowable, ListItem
from reportlab.lib.colors import HexColor
OUTPUT_PATH = "/tmp/workspace/interbody-fusion-guide/Interbody_Fusion_Techniques_Guide.pdf"
# ─── COLOR PALETTE ───────────────────────────────────────────────────────────
C_DARK_BLUE = HexColor("#1A3A5C")
C_MED_BLUE = HexColor("#2E6DA4")
C_LIGHT_BLUE = HexColor("#D6E8F7")
C_ALIF = HexColor("#1B6CA8") # blue
C_PLIF = HexColor("#1E8449") # green
C_TLIF = HexColor("#B7770D") # amber
C_XLIF = HexColor("#7D3C98") # purple
C_ALIF_LIGHT = HexColor("#D6EAF8")
C_PLIF_LIGHT = HexColor("#D5F5E3")
C_TLIF_LIGHT = HexColor("#FEF9E7")
C_XLIF_LIGHT = HexColor("#F5EEF8")
C_WHITE = colors.white
C_LIGHT_GREY = HexColor("#F2F2F2")
C_MID_GREY = HexColor("#CCCCCC")
C_TEXT = HexColor("#1A1A1A")
# ─── STYLES ──────────────────────────────────────────────────────────────────
styles = getSampleStyleSheet()
def make_style(name, parent='Normal', **kwargs):
s = ParagraphStyle(name, parent=styles[parent], **kwargs)
return s
TITLE_STYLE = make_style('DocTitle', fontSize=26, textColor=C_WHITE,
alignment=TA_CENTER, fontName='Helvetica-Bold',
spaceAfter=6)
SUBTITLE_STYLE = make_style('DocSubtitle', fontSize=13, textColor=HexColor("#C8DCF0"),
alignment=TA_CENTER, fontName='Helvetica',
spaceAfter=4)
AUTHOR_STYLE = make_style('Author', fontSize=10, textColor=HexColor("#90B8D8"),
alignment=TA_CENTER, fontName='Helvetica-Oblique')
SECTION_TITLE = make_style('SectionTitle', fontSize=18, textColor=C_WHITE,
fontName='Helvetica-Bold', alignment=TA_LEFT,
spaceBefore=0, spaceAfter=0)
H2 = make_style('H2', fontSize=13, textColor=C_DARK_BLUE,
fontName='Helvetica-Bold', spaceBefore=10, spaceAfter=4)
H3 = make_style('H3', fontSize=11, textColor=C_MED_BLUE,
fontName='Helvetica-Bold', spaceBefore=6, spaceAfter=3)
BODY = make_style('Body', fontSize=10, textColor=C_TEXT,
fontName='Helvetica', leading=15, spaceAfter=4,
alignment=TA_JUSTIFY)
BODY_BOLD = make_style('BodyBold', fontSize=10, textColor=C_TEXT,
fontName='Helvetica-Bold', leading=15)
STEP_NUM = make_style('StepNum', fontSize=11, textColor=C_WHITE,
fontName='Helvetica-Bold', alignment=TA_CENTER)
STEP_TEXT = make_style('StepText', fontSize=10, textColor=C_TEXT,
fontName='Helvetica', leading=14, spaceAfter=2)
STEP_TITLE = make_style('StepTitle', fontSize=10, textColor=C_DARK_BLUE,
fontName='Helvetica-Bold', leading=14)
CAUTION = make_style('Caution', fontSize=9.5, textColor=HexColor("#7E5109"),
fontName='Helvetica', leading=13, spaceAfter=3)
TIP = make_style('Tip', fontSize=9.5, textColor=HexColor("#145A32"),
fontName='Helvetica', leading=13, spaceAfter=3)
TABLE_HEADER = make_style('TH', fontSize=9, textColor=C_WHITE,
fontName='Helvetica-Bold', alignment=TA_CENTER)
TABLE_CELL = make_style('TC', fontSize=9, textColor=C_TEXT,
fontName='Helvetica', leading=12, alignment=TA_LEFT)
TABLE_CELL_C = make_style('TCC', fontSize=9, textColor=C_TEXT,
fontName='Helvetica', leading=12, alignment=TA_CENTER)
FOOTER_STYLE = make_style('Footer', fontSize=8, textColor=HexColor("#888888"),
alignment=TA_CENTER, fontName='Helvetica-Oblique')
TOC_TITLE = make_style('TOCTitle', fontSize=11, textColor=C_DARK_BLUE,
fontName='Helvetica-Bold', leading=14)
TOC_ENTRY = make_style('TOCEntry', fontSize=10, textColor=C_TEXT,
fontName='Helvetica', leading=14, leftIndent=12)
# ─── HELPERS ─────────────────────────────────────────────────────────────────
def section_header(title, color, subtitle=None):
"""A full-width colored banner for each section."""
inner = [Paragraph(title, SECTION_TITLE)]
if subtitle:
inner.append(Paragraph(subtitle, make_style(
'SH_Sub', fontSize=10, textColor=HexColor("#D0E8FF"),
fontName='Helvetica-Oblique', alignment=TA_LEFT)))
tbl = Table([[inner]], colWidths=[17*cm])
tbl.setStyle(TableStyle([
('BACKGROUND', (0,0), (-1,-1), color),
('TOPPADDING', (0,0), (-1,-1), 10),
('BOTTOMPADDING', (0,0), (-1,-1), 10),
('LEFTPADDING', (0,0), (-1,-1), 14),
('RIGHTPADDING', (0,0), (-1,-1), 14),
('ROUNDEDCORNERS', [6,6,6,6]),
]))
return tbl
def step_row(num, title, detail, color):
"""A single numbered step row."""
num_cell = Table([[Paragraph(str(num), STEP_NUM)]], colWidths=[1.1*cm], rowHeights=[1.1*cm])
num_cell.setStyle(TableStyle([
('BACKGROUND', (0,0), (-1,-1), color),
('TOPPADDING', (0,0), (-1,-1), 0),
('BOTTOMPADDING', (0,0), (-1,-1), 0),
('LEFTPADDING', (0,0), (-1,-1), 0),
('RIGHTPADDING', (0,0), (-1,-1), 0),
('VALIGN', (0,0), (-1,-1), 'MIDDLE'),
('ROUNDEDCORNERS', [4,4,4,4]),
]))
text_cell = [Paragraph(title, STEP_TITLE), Paragraph(detail, STEP_TEXT)]
row_tbl = Table([[num_cell, text_cell]], colWidths=[1.3*cm, 15.7*cm])
row_tbl.setStyle(TableStyle([
('VALIGN', (0,0), (-1,-1), 'TOP'),
('LEFTPADDING', (0,0), (0,-1), 0),
('RIGHTPADDING', (0,0), (0,-1), 6),
('TOPPADDING', (0,0), (-1,-1), 4),
('BOTTOMPADDING', (0,0), (-1,-1), 4),
('LEFTPADDING', (1,0), (1,-1), 8),
('BACKGROUND', (1,0), (1,-1), C_LIGHT_GREY),
('LINEBELOW', (0,0), (-1,-1), 0.5, C_MID_GREY),
]))
return row_tbl
def info_box(text, bg_color, label="NOTE"):
"""A coloured info/caution/tip box."""
tbl = Table([[Paragraph(f"<b>{label}:</b> {text}", BODY)]], colWidths=[17*cm])
tbl.setStyle(TableStyle([
('BACKGROUND', (0,0), (-1,-1), bg_color),
('TOPPADDING', (0,0), (-1,-1), 7),
('BOTTOMPADDING', (0,0), (-1,-1), 7),
('LEFTPADDING', (0,0), (-1,-1), 10),
('RIGHTPADDING', (0,0), (-1,-1), 10),
('BOX', (0,0), (-1,-1), 0.8, C_MID_GREY),
]))
return tbl
def comparison_table(header_row, data_rows, col_widths, header_color):
table_data = []
header_cells = [Paragraph(h, TABLE_HEADER) for h in header_row]
table_data.append(header_cells)
for row in data_rows:
table_data.append([Paragraph(str(c), TABLE_CELL) for c in row])
tbl = Table(table_data, colWidths=col_widths, repeatRows=1)
style = [
('BACKGROUND', (0,0), (-1,0), header_color),
('TEXTCOLOR', (0,0), (-1,0), C_WHITE),
('FONTNAME', (0,0), (-1,0), 'Helvetica-Bold'),
('FONTSIZE', (0,0), (-1,-1), 9),
('ALIGN', (0,0), (-1,0), 'CENTER'),
('VALIGN', (0,0), (-1,-1), 'TOP'),
('GRID', (0,0), (-1,-1), 0.4, C_MID_GREY),
('ROWBACKGROUNDS', (0,1), (-1,-1), [C_WHITE, C_LIGHT_GREY]),
('TOPPADDING', (0,0), (-1,-1), 5),
('BOTTOMPADDING', (0,0), (-1,-1), 5),
('LEFTPADDING', (0,0), (-1,-1), 5),
('RIGHTPADDING', (0,0), (-1,-1), 5),
]
tbl.setStyle(TableStyle(style))
return tbl
# ─── COVER PAGE ──────────────────────────────────────────────────────────────
def build_cover():
elems = []
elems.append(Spacer(1, 2.5*cm))
cover_tbl = Table([[
Paragraph("LUMBAR INTERBODY FUSION", TITLE_STYLE),
]], colWidths=[17*cm])
cover_tbl.setStyle(TableStyle([
('BACKGROUND', (0,0), (-1,-1), C_DARK_BLUE),
('TOPPADDING', (0,0), (-1,-1), 20),
('BOTTOMPADDING', (0,0), (-1,-1), 8),
('LEFTPADDING', (0,0), (-1,-1), 16),
('RIGHTPADDING', (0,0), (-1,-1), 16),
]))
subtitle_tbl = Table([[
Paragraph("Step-by-Step Surgical Guide", SUBTITLE_STYLE),
]], colWidths=[17*cm])
subtitle_tbl.setStyle(TableStyle([
('BACKGROUND', (0,0), (-1,-1), C_MED_BLUE),
('TOPPADDING', (0,0), (-1,-1), 8),
('BOTTOMPADDING', (0,0), (-1,-1), 18),
('LEFTPADDING', (0,0), (-1,-1), 16),
('RIGHTPADDING', (0,0), (-1,-1), 16),
]))
elems.append(cover_tbl)
elems.append(subtitle_tbl)
elems.append(Spacer(1, 0.6*cm))
# 4 technique boxes
tech_data = [
[Paragraph("ALIF", make_style('T1', fontSize=16, textColor=C_WHITE,
fontName='Helvetica-Bold', alignment=TA_CENTER)),
Paragraph("PLIF", make_style('T2', fontSize=16, textColor=C_WHITE,
fontName='Helvetica-Bold', alignment=TA_CENTER)),
Paragraph("TLIF", make_style('T3', fontSize=16, textColor=C_WHITE,
fontName='Helvetica-Bold', alignment=TA_CENTER)),
Paragraph("XLIF", make_style('T4', fontSize=16, textColor=C_WHITE,
fontName='Helvetica-Bold', alignment=TA_CENTER))],
[Paragraph("Anterior<br/>Lumbar<br/>Interbody Fusion",
make_style('T1s', fontSize=9, textColor=HexColor("#C8DCF0"),
fontName='Helvetica', alignment=TA_CENTER)),
Paragraph("Posterior<br/>Lumbar<br/>Interbody Fusion",
make_style('T2s', fontSize=9, textColor=HexColor("#C8DCF0"),
fontName='Helvetica', alignment=TA_CENTER)),
Paragraph("Transforaminal<br/>Lumbar<br/>Interbody Fusion",
make_style('T3s', fontSize=9, textColor=HexColor("#C8DCF0"),
fontName='Helvetica', alignment=TA_CENTER)),
Paragraph("Extreme Lateral<br/>Lumbar<br/>Interbody Fusion",
make_style('T4s', fontSize=9, textColor=HexColor("#C8DCF0"),
fontName='Helvetica', alignment=TA_CENTER))],
]
tech_tbl = Table(tech_data, colWidths=[4.25*cm]*4, rowHeights=[1.5*cm, 1.5*cm])
tech_tbl.setStyle(TableStyle([
('BACKGROUND', (0,0), (0,-1), C_ALIF),
('BACKGROUND', (1,0), (1,-1), C_PLIF),
('BACKGROUND', (2,0), (2,-1), C_TLIF),
('BACKGROUND', (3,0), (3,-1), C_XLIF),
('VALIGN', (0,0), (-1,-1), 'MIDDLE'),
('TOPPADDING', (0,0), (-1,-1), 8),
('BOTTOMPADDING', (0,0), (-1,-1), 8),
('INNERGRID', (0,0), (-1,-1), 1.5, C_WHITE),
]))
elems.append(tech_tbl)
elems.append(Spacer(1, 0.6*cm))
elems.append(Paragraph("Reference: Campbell's Operative Orthopaedics 15th Ed 2026 · Grainger & Allison's Diagnostic Radiology · Gray's Anatomy for Students", AUTHOR_STYLE))
elems.append(Spacer(1, 0.3*cm))
elems.append(Paragraph("Compiled by Orris Medical AI · July 2026", AUTHOR_STYLE))
return elems
# ─── TOC ─────────────────────────────────────────────────────────────────────
def build_toc():
elems = []
elems.append(PageBreak())
elems.append(Paragraph("TABLE OF CONTENTS", H2))
elems.append(HRFlowable(width="100%", thickness=1.5, color=C_DARK_BLUE, spaceAfter=8))
entries = [
("1. Overview & Concept", "3"),
("2. Axial Anatomy & Approach Zones", "3"),
("3. ALIF — Anterior Lumbar Interbody Fusion", "4"),
(" 3.1 Indications & Contraindications", "4"),
(" 3.2 Anatomy at Risk", "4"),
(" 3.3 Step-by-Step Technique", "5"),
(" 3.4 Complications", "6"),
("4. PLIF — Posterior Lumbar Interbody Fusion", "7"),
(" 4.1 Indications & Contraindications", "7"),
(" 4.2 Anatomy at Risk", "7"),
(" 4.3 Step-by-Step Technique", "8"),
(" 4.4 Complications", "9"),
("5. TLIF — Transforaminal Lumbar Interbody Fusion", "10"),
(" 5.1 Indications & Contraindications", "10"),
(" 5.2 Kambin's Triangle", "10"),
(" 5.3 Step-by-Step Technique", "11"),
(" 5.4 Complications", "12"),
("6. XLIF/LLIF — Extreme Lateral Interbody Fusion", "13"),
(" 6.1 Indications & Contraindications", "13"),
(" 6.2 Safe Zone & EMG Monitoring", "13"),
(" 6.3 Step-by-Step Technique", "14"),
(" 6.4 Complications", "15"),
("7. Master Comparison Table", "16"),
("8. Cage Materials & Bone Graft Options", "17"),
("9. Decision Algorithm by Level", "17"),
]
for title, page in entries:
row = Table([[Paragraph(title, TOC_ENTRY), Paragraph(page, make_style(
'TOCP', fontSize=10, fontName='Helvetica', alignment=TA_CENTER,
textColor=C_MED_BLUE))]],
colWidths=[15*cm, 2*cm])
row.setStyle(TableStyle([
('LINEBELOW', (0,0), (-1,-1), 0.3, C_MID_GREY),
('TOPPADDING', (0,0), (-1,-1), 3),
('BOTTOMPADDING', (0,0), (-1,-1), 3),
]))
elems.append(row)
return elems
# ─── OVERVIEW ────────────────────────────────────────────────────────────────
def build_overview():
elems = []
elems.append(PageBreak())
elems.append(section_header("1. OVERVIEW & CONCEPT", C_DARK_BLUE,
"Lumbar Interbody Fusion — Principles"))
elems.append(Spacer(1, 0.4*cm))
elems.append(Paragraph(
"Lumbar interbody fusion (LIF) techniques access the intervertebral disc space "
"to remove the disc, prepare the vertebral endplates, and insert an interbody "
"cage packed with bone graft material. The goal is to achieve <b>circumferential "
"fusion</b> (anterior + posterior column), restoring disc height, correcting "
"sagittal alignment, and providing long-term stability.", BODY))
elems.append(Spacer(1, 0.3*cm))
elems.append(Paragraph("Core Surgical Goals", H3))
goals = [
("Stability", "Eliminate painful motion at the diseased segment"),
("Decompression", "Restore foraminal height and canal dimensions"),
("Alignment", "Restore/improve lumbar lordosis and sagittal balance"),
("Fusion", "Achieve solid bony union — hardware alone will fatigue-fracture without fusion"),
]
for g, d in goals:
elems.append(Paragraph(f"<b>{g}:</b> {d}", BODY))
elems.append(Spacer(1, 0.3*cm))
elems.append(Paragraph("Two-Element Framework (Common to All LIF Techniques)", H3))
fw_data = [
["Element", "Options", "Purpose"],
["Anchor\n(Vertebral Attachment)", "Pedicle screws\nTranslaminar screws", "Secure the construct to bone"],
["Interbody Device", "PEEK cage · Titanium cage\nCarbon composite cage", "Restore height · Promote fusion"],
["Graft Material", "Autologous bone · Allograft\nBMP-2 · Ceramic substitute", "Drive osteogenesis within the cage"],
]
fw_tbl = comparison_table(fw_data[0], fw_data[1:],
[4*cm, 7*cm, 6*cm], C_DARK_BLUE)
elems.append(fw_tbl)
elems.append(Spacer(1, 0.5*cm))
elems.append(section_header("2. AXIAL ANATOMY & APPROACH ZONES", C_DARK_BLUE,
"Cross-sectional view of the lumbar spine showing surgical corridors"))
elems.append(Spacer(1, 0.4*cm))
elems.append(Paragraph(
"Each technique uses a distinct corridor to reach the disc space. "
"Understanding the axial anatomy prevents injury to vascular, neural, "
"and visceral structures adjacent to each approach zone.", BODY))
elems.append(Spacer(1, 0.2*cm))
zone_data = [
["Approach", "Direction", "Key Corridor Structures", "Primary Risk"],
["ALIF", "Directly anterior", "Transperitoneal or retroperitoneal;\nAnterior to aorta & IVC", "Vascular, retrograde ejaculation"],
["PLIF", "Directly posterior", "Posterior midline through spinal canal", "Bilateral nerve root / dural injury"],
["TLIF", "Posterolateral", "Posterior midline; unilateral foramen\n(Kambin's triangle)", "Exiting nerve root injury"],
["XLIF/LLIF", "Directly lateral", "Retroperitoneal; through psoas muscle", "Lumbar plexus / genitofemoral nerve"],
["OLIF/ATP", "Oblique-anterior", "Between anterior vessels & psoas", "Sympathetic chain, vessels"],
]
zone_tbl = comparison_table(zone_data[0], zone_data[1:],
[2.5*cm, 3*cm, 6*cm, 5.5*cm], C_DARK_BLUE)
elems.append(zone_tbl)
elems.append(Spacer(1, 0.3*cm))
elems.append(info_box(
"The iliac crest blocks access to L5-S1 in XLIF/LLIF. "
"ALIF is the preferred approach for L5-S1 interbody fusion requiring a large cage.",
HexColor("#EBF5FB"), "KEY ANATOMY POINT"))
return elems
# ─── ALIF ────────────────────────────────────────────────────────────────────
def build_alif():
elems = []
elems.append(PageBreak())
elems.append(section_header(
"3. ALIF — ANTERIOR LUMBAR INTERBODY FUSION", C_ALIF,
"Approach: Anterior (transperitoneal or retroperitoneal) | Position: Supine"))
elems.append(Spacer(1, 0.4*cm))
elems.append(Paragraph("3.1 Indications & Contraindications", H2))
ic_data = [
["INDICATIONS", "CONTRAINDICATIONS / CAUTIONS"],
["Degenerative disc disease (L4-5, L5-S1)\nSpondylolisthesis (grade I-II)\nSagittal imbalance / flatback correction\nPseudarthrosis (revision after posterior fusion)\nDiscogenic low back pain\nAdjacent segment disease",
"Prior retroperitoneal surgery / extensive abdominal adhesions\nOsteoporosis (cage subsidence risk)\nMale patient desiring future fertility (retrograde ejaculation risk)\nNo available vascular/access surgeon\nMorbid obesity\nInflammatory bowel disease / stoma"],
]
ic_tbl = Table([[Paragraph(ic_data[0][0], TABLE_HEADER),
Paragraph(ic_data[0][1], TABLE_HEADER)],
[Paragraph(ic_data[1][0], BODY),
Paragraph(ic_data[1][1], BODY)]],
colWidths=[8.5*cm, 8.5*cm])
ic_tbl.setStyle(TableStyle([
('BACKGROUND', (0,0), (-1,0), C_ALIF),
('BACKGROUND', (0,1), (0,1), C_ALIF_LIGHT),
('BACKGROUND', (1,1), (1,1), HexColor("#FDEDEC")),
('GRID', (0,0), (-1,-1), 0.4, C_MID_GREY),
('VALIGN', (0,0), (-1,-1), 'TOP'),
('TOPPADDING', (0,0), (-1,-1), 6),
('BOTTOMPADDING', (0,0), (-1,-1), 6),
('LEFTPADDING', (0,0), (-1,-1), 7),
('RIGHTPADDING', (0,0), (-1,-1), 7),
]))
elems.append(ic_tbl)
elems.append(Spacer(1, 0.4*cm))
elems.append(Paragraph("3.2 Anatomy at Risk", H2))
anat_data = [
["Structure", "Location", "Injury Consequence"],
["Aorta / iliac arteries", "Anterior to vertebral body", "Catastrophic haemorrhage"],
["IVC / iliac veins", "Right anterolateral to vertebra", "Major venous haemorrhage"],
["Superior hypogastric plexus", "Anterior to L5-S1 disc space", "Retrograde ejaculation (NOT impotence)"],
["Left ureter", "Crosses left iliac artery", "Ureteral injury, hydronephrosis"],
["Sympathetic chain", "Anterolateral to vertebral bodies", "Sympathetic dysfunction"],
["Lumbosacral trunk (L4-L5 nerve)", "Posterior to iliac vessels", "Motor weakness lower limb"],
]
elems.append(comparison_table(anat_data[0], anat_data[1:],
[4.5*cm, 5.5*cm, 7*cm], C_ALIF))
elems.append(Spacer(1, 0.4*cm))
elems.append(info_box(
"Retrograde ejaculation occurs in 0.5–5% of male patients due to injury to the "
"superior hypogastric plexus. It is distinct from impotence (erectile function is preserved). "
"Minimise by using blunt dissection from left to right and avoiding electrocautery anterior to L5-S1.",
HexColor("#FEF9E7"), "CAUTION"))
elems.append(Spacer(1, 0.4*cm))
elems.append(Paragraph("3.3 Step-by-Step Technique (Transperitoneal — L5-S1)", H2))
steps = [
("Patient Positioning", "Supine on a radiolucent table. Slight Trendelenburg to allow bowel to fall cephalad. "
"Ensure fluoroscopy access for lateral and AP views. Secure both arms padded on armboards."),
("Skin Incision", "Vertical midline from umbilicus to pubis OR transverse Pfannenstiel incision (preferred — cosmetically superior, better exposure). "
"Pfannenstiel requires transection of the rectus abdominis sheath."),
("Peritoneal Entry", "Identify and open posterior rectus sheath and abdominal fascia. Carefully open the peritoneum. "
"Pack abdominal contents cephalad with moistened lap pads."),
("Posterior Peritoneum", "Identify the aortic bifurcation and sacral promontory by palpation through the posterior peritoneum. "
"Make a longitudinal incision in the posterior peritoneum in the midline, around the aortic bifurcation."),
("Vessel Mobilisation", "Extend incision distally along the right common iliac artery to its bifurcation. "
"Identify right ureter crossing the right iliac artery — curve incision medially to avoid it. "
"Retract common iliac vessels laterally with vessel loops or retractors."),
("Middle Sacral Vessels", "Identify and ligate/clip the middle sacral artery and vein in the midline "
"over the L5-S1 disc space (see Fig 44.36B)."),
("Disc Exposure", "AVOID electrocautery anterior to the L5-S1 disc space — protect the superior hypogastric plexus. "
"Use blunt dissection left to right. Expose the anterior annulus of L5-S1 clearly."),
("Level Confirmation", "Confirm the correct disc level with lateral fluoroscopy using a needle or Kirschner wire in the disc space."),
("Discectomy", "Incise the anterior annulus with a scalpel (box or H-shaped annulotomy). "
"Remove all disc material using curettes, rongeurs, and pituitary forceps. "
"Achieve complete discectomy including cartilaginous endplates."),
("Endplate Preparation", "Use rasps, scrapers, and curettes to decorticate the endplates to bleeding bone. "
"Avoid violating the cortical endplate (increases subsidence risk). "
"Achieve flat, parallel endplates to accept the cage."),
("Trial Cage Sizing", "Insert trial cages of increasing height until the desired disc distraction is achieved. "
"Confirm with lateral fluoroscopy. Choose the largest cage that fits without over-distraction."),
("Cage Insertion", "Pack the final cage with autologous bone graft, allograft, or BMP-2. "
"Insert the cage in the anterior-central position to maximise lordosis and endplate contact. "
"Confirm AP and lateral position with fluoroscopy."),
("Haemostasis & Closure", "Obtain haemostasis. Close the posterior peritoneum over the great vessels. "
"Close the abdominal wall in layers (rectus sheath, subcutaneous tissue, skin). "
"Insert a urinary catheter preoperatively; remove on day 1-2."),
("Supplemental Posterior Fixation", "For most indications, posterior percutaneous pedicle screw-rod fixation is added "
"(same anaesthetic or staged). This converts ALIF to a 360° fusion construct."),
]
for i, (title, detail) in enumerate(steps, 1):
elems.append(step_row(i, title, detail, C_ALIF))
elems.append(Spacer(1, 0.15*cm))
elems.append(Spacer(1, 0.4*cm))
elems.append(Paragraph("3.4 ALIF Complications", H2))
comp_data = [
["Complication", "Incidence", "Prevention / Management"],
["Retrograde ejaculation", "0.5–5% males", "Blunt dissection; avoid electrocautery anterior to L5-S1"],
["Vascular injury (aorta/IVC/iliac)", "1–3%", "Gentle retraction; vascular access surgeon on standby"],
["Cage subsidence", "4–10%", "Avoid endplate violation; choose correct cage size"],
["Postoperative ileus", "3–5%", "Gentle bowel handling; early ambulation"],
["Wound infection (superficial/deep)", "1–2%", "Prophylactic antibiotics; sterile technique"],
["Approach-related nerve injury", "<1%", "Identify ureter; avoid deep retraction near L4-5 nerve"],
["Pseudarthrosis", "3–8%", "Ensure solid endplate preparation; use BMP-2 if needed"],
["Deep vein thrombosis/PE", "1–3%", "Sequential compression devices; early mobilisation"],
]
elems.append(comparison_table(comp_data[0], comp_data[1:],
[5*cm, 3*cm, 9*cm], C_ALIF))
return elems
# ─── PLIF ────────────────────────────────────────────────────────────────────
def build_plif():
elems = []
elems.append(PageBreak())
elems.append(section_header(
"4. PLIF — POSTERIOR LUMBAR INTERBODY FUSION", C_PLIF,
"Approach: Posterior midline | Position: Prone"))
elems.append(Spacer(1, 0.4*cm))
elems.append(Paragraph("4.1 Indications & Contraindications", H2))
ic_data = [
["INDICATIONS", "CONTRAINDICATIONS / CAUTIONS"],
["Lumbar spondylolisthesis with neural compression\nDegenerative disc disease with instability\nRecurrent disc herniation (after previous discectomy)\nSpondylolysis with instability\nDegenerative scoliosis requiring decompression + fusion\nSegmental instability following laminectomy",
"Severe epidural fibrosis (previous posterior surgery — consider TLIF instead)\nOsteoporosis (small cages + limited endplate contact)\nSevere canal stenosis with multiple adhesions\nActive infection at operative level\nMajor comorbidities precluding prolonged prone position"],
]
ic_tbl = Table([[Paragraph(ic_data[0][0], TABLE_HEADER),
Paragraph(ic_data[0][1], TABLE_HEADER)],
[Paragraph(ic_data[1][0], BODY),
Paragraph(ic_data[1][1], BODY)]],
colWidths=[8.5*cm, 8.5*cm])
ic_tbl.setStyle(TableStyle([
('BACKGROUND', (0,0), (-1,0), C_PLIF),
('BACKGROUND', (0,1), (0,1), C_PLIF_LIGHT),
('BACKGROUND', (1,1), (1,1), HexColor("#FDEDEC")),
('GRID', (0,0), (-1,-1), 0.4, C_MID_GREY),
('VALIGN', (0,0), (-1,-1), 'TOP'),
('TOPPADDING', (0,0), (-1,-1), 6),
('BOTTOMPADDING', (0,0), (-1,-1), 6),
('LEFTPADDING', (0,0), (-1,-1), 7),
('RIGHTPADDING', (0,0), (-1,-1), 7),
]))
elems.append(ic_tbl)
elems.append(Spacer(1, 0.4*cm))
elems.append(Paragraph("4.2 Anatomy at Risk", H2))
anat_data = [
["Structure", "Location", "Injury Consequence"],
["Dural sac / cauda equina", "Central posterior to disc", "CSF leak, neural injury, arachnoiditis"],
["Traversing nerve roots (bilateral)", "Medial to pedicles bilaterally", "Radiculopathy, motor weakness, foot drop"],
["Epidural veins", "Surrounding dural sac", "Epidural haematoma, blood loss"],
["Segmental vessels", "Lateral to disc anteriorly", "Haemorrhage during discectomy"],
["Anterior dura / nerve sleeves", "Anterior to posterior longitudinal ligament", "Injury during disc removal"],
]
elems.append(comparison_table(anat_data[0], anat_data[1:],
[4.5*cm, 5.5*cm, 7*cm], C_PLIF))
elems.append(Spacer(1, 0.3*cm))
elems.append(info_box(
"PLIF requires BILATERAL nerve root retraction to gain access to both sides of the disc space. "
"This is the most significant disadvantage vs. TLIF (unilateral retraction). "
"In the presence of previous posterior surgery with epidural scarring, "
"TLIF through the foramen is strongly preferred.",
HexColor("#EAFAF1"), "TECHNIQUE NOTE"))
elems.append(Spacer(1, 0.4*cm))
elems.append(Paragraph("4.3 Step-by-Step Technique", H2))
steps = [
("Patient Positioning", "Prone on a 4-post frame or Wilson frame. Hips and knees slightly flexed to reduce lumbar lordosis "
"and open the interlaminar space. Abdomen hangs free (reduces epidural venous pressure and blood loss). "
"Ensure no ocular pressure."),
("Skin Incision", "Standard posterior midline incision over the target level(s). Length depends on number of levels. "
"Mark skin landmarks with fluoroscopy before incision."),
("Muscle Dissection", "Subperiosteal dissection of paraspinal muscles bilaterally. "
"Expose laminae, facet joints, and transverse processes at the target level(s). "
"Use Cobb elevator and electrocautery."),
("Pedicle Screw Placement", "Place bilateral pedicle screws above and below the target disc before neural work. "
"This provides stability and allows distraction across the disc space. "
"Confirm with AP and lateral fluoroscopy."),
("Laminectomy / Laminotomy", "Perform a wide bilateral laminectomy and medial facetectomy to expose the posterior disc. "
"Remove ligamentum flavum. The dural sac and bilateral nerve roots must be visible."),
("Epidural Haemostasis", "Control epidural bleeding with bipolar diathermy and Gelfoam/Surgicel. "
"Thorough haemostasis before neural retraction is essential."),
("Bilateral Nerve Root Retraction", "Using nerve root retractors, gently retract the dural sac medially AND both traversing "
"nerve roots medially on each side. This creates bilateral corridors lateral to the dura. "
"Limit retraction time — prolonged retraction causes nerve injury."),
("Annulotomy (Bilateral)", "Using a 15-blade or Kerrison rongeur, make annulotomy windows bilaterally. "
"Access the disc space from both sides."),
("Discectomy", "Remove disc material bilaterally using curettes, pituitary rongeurs, and disc forceps. "
"Achieve complete disc removal. Visualise the anterior annulus."),
("Endplate Preparation", "Use rasps and curettes to prepare the endplates bilaterally to bleeding cancellous bone. "
"Match the endplate contour to the cage profile."),
("Trial Cage Sizing", "Insert bilateral trial sizers to determine correct cage dimensions. "
"Distraction across the pedicle screws (using the rod and distractor) opens the disc space "
"and facilitates cage insertion."),
("Cage Insertion (Bilateral)", "Pack two small PLIF cages (typically 10-12 mm wide, kidney-shaped) with bone graft. "
"Insert one cage from each side, positioning them in the anterior one-third of the disc space. "
"Confirm position with AP and lateral fluoroscopy."),
("Posterolateral Bone Grafting", "Decorticate transverse processes and facet joints. "
"Apply autologous bone graft for posterolateral fusion."),
("Rod Insertion & Compression", "Insert connecting rods bilaterally. Apply compression across the construct "
"to seat the cages and close the disc space. Tighten all screw caps."),
("Closure", "Irrigate wound thoroughly with antibiotic solution. Place suction drain(s). "
"Close paraspinal fascia, subcutaneous tissue, and skin in layers."),
]
for i, (title, detail) in enumerate(steps, 1):
elems.append(step_row(i, title, detail, C_PLIF))
elems.append(Spacer(1, 0.12*cm))
elems.append(Spacer(1, 0.4*cm))
elems.append(Paragraph("4.4 PLIF Complications", H2))
comp_data = [
["Complication", "Incidence", "Prevention / Management"],
["Dural tear / CSF leak", "5–10%", "Primary repair with 6-0 Prolene; fibrin glue; flat bed rest 24–48h"],
["Bilateral nerve root injury", "2–5%", "Minimise retraction duration; careful technique"],
["Epidural haematoma", "1–3%", "Haemostasis before retraction; suction drain postop"],
["Cage migration / expulsion", "1–5%", "Size cage correctly; position anteriorly; compress construct"],
["Adjacent segment disease", "5–10%/year", "Minimise fusion levels; preserve motion where possible"],
["Pseudarthrosis", "5–10%", "Thorough endplate prep; adequate graft volume; stop NSAIDs/smoking"],
["Infection (deep)", "1–3%", "Prophylactic antibiotics; drain removal by 48h"],
["Foot drop / motor deficit", "<1%", "Immediate post-op exam; urgent MRI if new deficit"],
]
elems.append(comparison_table(comp_data[0], comp_data[1:],
[5*cm, 3*cm, 9*cm], C_PLIF))
return elems
# ─── TLIF ────────────────────────────────────────────────────────────────────
def build_tlif():
elems = []
elems.append(PageBreak())
elems.append(section_header(
"5. TLIF — TRANSFORAMINAL LUMBAR INTERBODY FUSION", C_TLIF,
"Approach: Posterolateral through foramen (unilateral) | Position: Prone"))
elems.append(Spacer(1, 0.4*cm))
elems.append(Paragraph("5.1 Indications & Contraindications", H2))
ic_data = [
["INDICATIONS", "CONTRAINDICATIONS / CAUTIONS"],
["Spondylolisthesis grades I-II (gold standard)\nDegenerative disc disease with instability\nRecurrent disc herniation (after PLIF or discectomy)\nPost-laminectomy instability\nPrevious posterior surgery (TLIF avoids bilateral scar)\nSingle-level degenerative disease\nMinimally invasive surgery (MIS-TLIF)",
"Bilateral foraminal stenosis requiring bilateral decompression\nSevere foraminal scarring at entry side\nConjoined nerve root anomaly at approach foramen\nActive discitis / infection\nSevere osteoporosis"],
]
ic_tbl = Table([[Paragraph(ic_data[0][0], TABLE_HEADER),
Paragraph(ic_data[0][1], TABLE_HEADER)],
[Paragraph(ic_data[1][0], BODY),
Paragraph(ic_data[1][1], BODY)]],
colWidths=[8.5*cm, 8.5*cm])
ic_tbl.setStyle(TableStyle([
('BACKGROUND', (0,0), (-1,0), C_TLIF),
('BACKGROUND', (0,1), (0,1), C_TLIF_LIGHT),
('BACKGROUND', (1,1), (1,1), HexColor("#FDEDEC")),
('GRID', (0,0), (-1,-1), 0.4, C_MID_GREY),
('VALIGN', (0,0), (-1,-1), 'TOP'),
('TOPPADDING', (0,0), (-1,-1), 6),
('BOTTOMPADDING', (0,0), (-1,-1), 6),
('LEFTPADDING', (0,0), (-1,-1), 7),
('RIGHTPADDING', (0,0), (-1,-1), 7),
]))
elems.append(ic_tbl)
elems.append(Spacer(1, 0.4*cm))
elems.append(Paragraph("5.2 Kambin's Triangle — The TLIF Safe Working Zone", H2))
elems.append(Paragraph(
"Kambin's triangle is the anatomical safe zone for posterolateral disc access used in TLIF. "
"Working within this triangle avoids injury to the traversing and exiting nerve roots.", BODY))
kb_data = [
["Side of Triangle", "Anatomical Structure"],
["Hypotenuse (lateral)", "Exiting nerve root in the foramen"],
["Base (inferior)", "Superior endplate of the lower vertebra"],
["Height (medial)", "Traversing nerve root / lateral border of dural sac"],
["Safe working area", "Within this triangle — typically 8-12 mm diameter space"],
]
kb_tbl = comparison_table(kb_data[0], kb_data[1:],
[5.5*cm, 11.5*cm], C_TLIF)
elems.append(kb_tbl)
elems.append(Spacer(1, 0.3*cm))
elems.append(info_box(
"At L4-5 and L5-S1, the exiting nerve root (L4 or L5) runs in the superior portion "
"of the foramen. Always identify and protect it before inserting the cage. "
"The exiting root is at greater risk in TLIF than PLIF.",
HexColor("#FEF9E7"), "CAUTION"))
elems.append(Spacer(1, 0.4*cm))
elems.append(Paragraph("5.3 Step-by-Step Technique (Open TLIF)", H2))
steps = [
("Patient Positioning", "Prone on a 4-post frame or Jackson table. Abdomen hanging free. "
"Slight reverse Trendelenburg. Fluoroscopy set for lateral and AP views. "
"If MIS-TLIF: tubular retractor system aligned over target foramen."),
("Skin Incision", "Posterior midline incision OR paramedian incision for MIS-TLIF. "
"Length depends on number of levels and if bilateral decompression is planned. "
"Confirm level with fluoroscopy before incising fascia."),
("Muscle Dissection", "Subperiosteal dissection of paraspinal muscles. "
"For MIS-TLIF: sequential muscle dilation through tubular retractor. "
"Expose the facet joint on the approach side (usually the symptomatic side)."),
("Bilateral Pedicle Screw Placement", "Place bilateral pedicle screws above and below the target level "
"BEFORE facetectomy to maintain stability. Use fluoroscopy or navigation to confirm. "
"For MIS-TLIF: percutaneous screws placed through stab incisions before/after interbody work."),
("Ipsilateral Laminotomy / Facetectomy", "On the approach side: perform a partial or complete ipsilateral "
"facetectomy (superior articular process of lower level + inferior articular process of upper level). "
"This opens the foramen and exposes Kambin's triangle. "
"Also perform laminotomy for canal access if decompression is required."),
("Contralateral Decompression (if needed)", "Using angled curettes and Kerrison rongeurs, perform "
"contralateral laminotomy and foraminotomy through the same ipsilateral approach by "
"tilting the table and working 'over the top'. This avoids bilateral approach."),
("Nerve Root Identification", "Identify the exiting nerve root in the foramen (ipsilateral) and the "
"traversing nerve root medially. Protect both. "
"Use Woodson probe to palpate nerve root before inserting any instrument into the disc."),
("Annulotomy", "With the exiting nerve root retracted superolaterally and traversing root "
"retracted medially, perform a unilateral annulotomy at the posterolateral corner of the disc. "
"Use a 15-blade scalpel or Kerrison rongeur."),
("Discectomy", "Thorough disc removal using curettes, pituitary rongeurs, straight and angled instruments. "
"Work from one side through the foramen. Achieve decompression of the anterior neural elements."),
("Endplate Preparation", "Rasps, disc space shavers, and curettes used to prepare both endplates "
"to cancellous bone while preserving the cortical rim (cage support). "
"Confirm with fluoroscopy — instrument should reach the anterior annulus."),
("Cage Selection & Packing", "Select a curved or kidney-shaped TLIF cage of appropriate height. "
"Pack with bone graft (autologous bone from facetectomy + allograft or BMP-2)."),
("Cage Insertion", "Insert cage through the foramen using an inserter handle. "
"Rotate/translate cage into the anterior-central position (anterior half of disc space). "
"A cage sitting posteriorly risks nerve compression and provides less lordosis correction. "
"Confirm with AP and lateral fluoroscopy."),
("Contralateral Bone Graft", "Pack bone graft into the contralateral side of the disc space through "
"the same ipsilateral window using a curved bone graft funnel."),
("Posterolateral Graft", "Decorticate ipsilateral transverse processes. Apply autologous bone graft."),
("Rod Insertion & Compression", "Insert connecting rods bilaterally. Apply compression to seat "
"the cage and close the disc height. Final tightening. Confirm final construct with fluoroscopy."),
("Closure", "Irrigate copiously. Place suction drain. Close fascia, subcutaneous, skin in layers."),
]
for i, (title, detail) in enumerate(steps, 1):
elems.append(step_row(i, title, detail, C_TLIF))
elems.append(Spacer(1, 0.1*cm))
elems.append(Spacer(1, 0.4*cm))
elems.append(Paragraph("5.4 TLIF Complications", H2))
comp_data = [
["Complication", "Incidence", "Prevention / Management"],
["Exiting nerve root injury", "1–5%", "Identify root before disc entry; gentle retraction; avoid overfilling foramen"],
["Dural tear", "3–7%", "Primary repair; fibrin glue; avoid CSF fistula"],
["Cage migration", "1–4%", "Position cage anteriorly; compress construct after cage placement"],
["Pseudarthrosis", "3–7%", "Thorough endplate prep; adequate graft; cease NSAIDs/smoking preop"],
["Adjacent segment disease", "5%/year", "Preserve motion segments; match fusion to pathology only"],
["Postop neurological deficit", "<2%", "Immediate neurological assessment; urgent MRI/CT if deficit"],
["Infection", "1–3%", "Prophylactic antibiotics; irrigation; drain by 48h"],
["Haematoma (epidural)", "0.5–1%", "Adequate haemostasis; drain; urgent decompression if dense deficit"],
]
elems.append(comparison_table(comp_data[0], comp_data[1:],
[5*cm, 3*cm, 9*cm], C_TLIF))
return elems
# ─── XLIF ────────────────────────────────────────────────────────────────────
def build_xlif():
elems = []
elems.append(PageBreak())
elems.append(section_header(
"6. XLIF/LLIF — EXTREME LATERAL INTERBODY FUSION", C_XLIF,
"Approach: Direct lateral through psoas | Position: Lateral decubitus"))
elems.append(Spacer(1, 0.4*cm))
elems.append(Paragraph("6.1 Indications & Contraindications", H2))
ic_data = [
["INDICATIONS", "CONTRAINDICATIONS / CAUTIONS"],
["Degenerative disc disease L1-L4 (multi-level)\nDegenerative scoliosis correction\nSagittal imbalance (with posterior fixation)\nAdjacent segment disease (above L5-S1)\nRetroperitoneal approach contraindicated (prior ALIF)\nMinimally invasive multi-level fusion\nFailed prior posterior fusion (revision via lateral)",
"L5-S1 disc (iliac crest obstruction — use ALIF)\nPrior ipsilateral retroperitoneal surgery (relative)\nPsoas abscess or tumour\nBilateral severe canal stenosis requiring direct decompression\nHigh-grade spondylolisthesis (anterior translation prevents lateral access)\nCoagulopathy"],
]
ic_tbl = Table([[Paragraph(ic_data[0][0], TABLE_HEADER),
Paragraph(ic_data[0][1], TABLE_HEADER)],
[Paragraph(ic_data[1][0], BODY),
Paragraph(ic_data[1][1], BODY)]],
colWidths=[8.5*cm, 8.5*cm])
ic_tbl.setStyle(TableStyle([
('BACKGROUND', (0,0), (-1,0), C_XLIF),
('BACKGROUND', (0,1), (0,1), C_XLIF_LIGHT),
('BACKGROUND', (1,1), (1,1), HexColor("#FDEDEC")),
('GRID', (0,0), (-1,-1), 0.4, C_MID_GREY),
('VALIGN', (0,0), (-1,-1), 'TOP'),
('TOPPADDING', (0,0), (-1,-1), 6),
('BOTTOMPADDING', (0,0), (-1,-1), 6),
('LEFTPADDING', (0,0), (-1,-1), 7),
('RIGHTPADDING', (0,0), (-1,-1), 7),
]))
elems.append(ic_tbl)
elems.append(Spacer(1, 0.4*cm))
elems.append(Paragraph("6.2 Safe Zone & EMG Monitoring", H2))
elems.append(Paragraph(
"The disc is divided into four zones (I-IV) from anterior (A) to posterior (P) per the Moro classification. "
"The lumbar plexus migrates anteriorly at lower lumbar levels, "
"making L4-5 the most dangerous level for XLIF.", BODY))
sz_data = [
["Zone", "Location on Disc", "Contents / Risk", "Relevance to XLIF"],
["I (Anterior)", "Anterior quarter", "Anterior to psoas; great vessel zone", "ALIF territory — avoid in XLIF"],
["II (Anterior-mid)", "Second quarter from front", "Anterior to lumbar plexus", "OPTIMAL XLIF working zone"],
["III (Posterior-mid)", "Third quarter", "Lumbar plexus traverses here", "HIGH RISK — avoid if possible"],
["IV (Posterior)", "Posterior quarter", "Lumbar plexus and dural sac", "UNSAFE — do not enter"],
]
elems.append(comparison_table(sz_data[0], sz_data[1:],
[2.5*cm, 3.5*cm, 6*cm, 5*cm], C_XLIF))
elems.append(Spacer(1, 0.3*cm))
elems.append(Paragraph("EMG Thresholds (NVM5/NovaBay Monitoring):", H3))
emg_data = [
["Threshold (mA)", "Interpretation", "Action"],
[">10 mA", "Nerve at SAFE distance", "Continue dilator advancement"],
["5–10 mA", "Nerve NEAR — caution zone", "Slow down; redirect slightly anterior"],
["<5 mA", "Nerve VERY CLOSE — STOP", "Remove dilator; redirect significantly or abort"],
]
elems.append(comparison_table(emg_data[0], emg_data[1:],
[3.5*cm, 6.5*cm, 7*cm], C_XLIF))
elems.append(Spacer(1, 0.3*cm))
elems.append(info_box(
"L4-5 is the most neurologically challenging level for XLIF. The lumbar plexus "
"(particularly the femoral nerve) migrates to the anterior half of the psoas "
"at this level, dramatically reducing the safe working zone. "
"Some surgeons prefer TLIF or OLIF at L4-5 for this reason.",
HexColor("#F5EEF8"), "CRITICAL POINT — L4-5 XLIF"))
elems.append(Spacer(1, 0.4*cm))
elems.append(Paragraph("6.3 Step-by-Step Technique", H2))
steps = [
("Patient Positioning", "Right lateral decubitus (left side up — approach from the left). "
"The patient is placed perpendicular to the table and secured with kidney rest and tape. "
"The operating table is flexed at the hip to open the lateral flank space. "
"All bony prominences padded. Neuromonitoring (EMG) electrodes placed in lower extremity muscles."),
("Fluoroscopic Planning", "Obtain a true lateral fluoroscopic view — ensure the pedicles are perfectly "
"superimposed. Mark the disc centre on the skin. Confirm the iliac crest is below the target disc "
"(if iliac crest obstructs — XLIF not feasible; use ALIF or TLIF)."),
("Retroperitoneal Access (Flank Incision)", "Make a 2-3 cm transverse or oblique incision in the flank "
"posterior to the anterior axillary line. Incise external oblique, internal oblique, and transverse "
"abdominis along their fibres (muscle-splitting technique). "
"Identify and enter the retroperitoneal space."),
("Peritoneal Sac Mobilisation", "Bluntly sweep the peritoneal sac anteriorly with the fingers. "
"Use a finger to confirm the retroperitoneal corridor — "
"feel the psoas muscle posteriorly and the peritoneal sac anteriorly."),
("Lateral Skin Incision", "With finger in the retroperitoneal space, turn the index finger laterally "
"toward the lateral skin over the disc. Make a second 2-cm stab incision at this mark."),
("Initial Dilator Insertion", "Insert the initial dilator through the lateral incision under finger guidance. "
"Use live EMG monitoring as the dilator contacts the psoas muscle. "
"Advance slowly — <b>EMG must remain >10 mA throughout</b>. "
"Confirm position with AP and lateral fluoroscopy."),
("Sequential Dilation of Psoas", "Pass sequential dilators of increasing diameter through the psoas muscle "
"under continuous EMG monitoring. Monitor all lower limb muscle groups. "
"Spread the psoas fibres longitudinally (parallel to nerve direction) "
"rather than transversely to minimise plexus injury."),
("Retractor Placement", "Once the largest dilator reaches the disc surface, insert the expandable "
"lateral retractor system. Expand the blades to create a working window over the disc. "
"Attach to the table-mounted arm holder. Reconfirm position with fluoroscopy."),
("Level Confirmation", "Final AP and lateral fluoroscopy before disc work. "
"A Kirschner wire or marker needle in the disc confirms the correct level."),
("Annulotomy", "Make a wide annulotomy on the lateral disc surface with a 15-blade scalpel "
"or electrosurgical device. The annulotomy window should span the full anterior-posterior "
"width of the disc to allow insertion of a wide cage."),
("Discectomy", "Complete disc removal using straight and angled curettes, rongeurs, and pituitary forceps. "
"Work from the lateral window to reach the contralateral side. "
"The XLIF cage will span the full width — both endplates must be cleared."),
("Endplate Preparation", "Use laterally-angled rasps and scrapers to prepare both endplates. "
"The XLIF cage spans both apophyseal rings bilaterally — "
"this is the biomechanical advantage over PLIF/TLIF cages. "
"Preserve the cortical apophyseal ring for cage support."),
("Trial Sizing", "Insert lateral trial cages to determine the correct height and width. "
"The cage footprint should span the full width of the endplate. "
"Confirm with AP fluoroscopy — cage should reach the contralateral apophyseal ring."),
("Cage Packing & Insertion", "Pack the cage with bone graft (allograft/autograft/BMP-2). "
"Insert the cage using a lateral inserter handle, advancing to the anterior-central position. "
"AP view confirms cage spans full endplate width. Lateral view confirms anterior positioning."),
("Supplemental Fixation", "XLIF provides interbody support but inadequate rotational control alone. "
"Options: (a) percutaneous posterior bilateral pedicle screws (standard), "
"(b) lateral plate (standalone at single level if bone quality adequate). "
"Patient may be repositioned prone for posterior fixation."),
("Retractor Removal & Closure", "Slowly remove the retractor while checking for bleeding. "
"The psoas reconstitutes around the working corridor. "
"Close lateral incision in layers: transverse abdominis, internal oblique, "
"external oblique, subcutaneous, skin. No drain usually required."),
]
for i, (title, detail) in enumerate(steps, 1):
elems.append(step_row(i, title, detail, C_XLIF))
elems.append(Spacer(1, 0.1*cm))
elems.append(Spacer(1, 0.4*cm))
elems.append(Paragraph("6.4 XLIF Complications", H2))
comp_data = [
["Complication", "Incidence", "Prevention / Management"],
["Genitofemoral nerve injury\n(anterior thigh numbness)", "5–15%", "Most resolve spontaneously in 3–6 months; reassurance; gabapentin"],
["Lumbar plexus injury\n(thigh pain, hip flexor weakness)", "1–5%", "Strict EMG monitoring; limit retraction; avoid L4-5 if plexus not safe"],
["Femoral nerve injury\n(quadriceps weakness)", "<2%", "EMG monitoring; abort if threshold <5 mA; urgent MRI if postop weakness"],
["Approach-side hip flexor weakness", "10–30% transient", "Psoas retraction; resolves in 6–12 weeks in most"],
["Sympathetic chain injury", "<1%", "Retrograde ejaculation; careful anterior dissection"],
["Cage subsidence", "4–10%", "Preserve apophyseal ring; avoid endplate violation"],
["Inadequate decompression", "Variable", "Add posterior decompression if indirect decompression insufficient"],
["Peritoneal entry / bowel injury", "<0.5%", "Careful retroperitoneal dissection; surgical repair if entered"],
]
elems.append(comparison_table(comp_data[0], comp_data[1:],
[4.5*cm, 3*cm, 9.5*cm], C_XLIF))
return elems
# ─── COMPARISON ──────────────────────────────────────────────────────────────
def build_comparison():
elems = []
elems.append(PageBreak())
elems.append(section_header("7. MASTER COMPARISON TABLE", C_DARK_BLUE,
"ALIF vs. PLIF vs. TLIF vs. XLIF"))
elems.append(Spacer(1, 0.5*cm))
data = [
["Feature", "ALIF", "PLIF", "TLIF", "XLIF/LLIF"],
["Approach direction", "Anterior", "Posterior (bilateral)", "Posterolateral (unilateral)", "Direct lateral through psoas"],
["Patient position", "Supine", "Prone", "Prone", "Lateral decubitus"],
["Access surgeon needed", "Yes (vascular / gen surg)", "No", "No", "No"],
["Levels accessible", "L4-S1 (best L5-S1)", "L3-S1", "L3-S1", "L1-L4 ONLY (not L5-S1)"],
["Cage footprint", "Largest (lordotic)", "Smallest (2 bilateral)", "Intermediate (1 unilateral)", "Widest (spans full endplate)"],
["Lordosis restoration", "Best", "Least", "Good", "Good"],
["Direct decompression", "No", "Yes (bilateral)", "Yes (unilateral)", "No (indirect only)"],
["Neural retraction needed", "None", "Bilateral", "Unilateral", "None"],
["Neuromonitoring required", "Optional", "SSEP/MEP optional", "SSEP/MEP optional", "EMG MANDATORY"],
["Unique complication", "Retrograde ejaculation; vascular injury", "Bilateral nerve injury; dural tear", "Exiting nerve root injury", "Lumbar plexus / genitofemoral nerve"],
["MIS option available", "Mini-ALIF", "Limited", "MIS-TLIF (standard)", "Standard MIS"],
["Blood loss", "Moderate", "Moderate-high", "Low-moderate", "Low"],
["Hospital stay", "2–4 days", "3–5 days", "2–4 days", "1–3 days"],
["360° fusion", "Yes (+ posterior screws)", "Yes (all-posterior)", "Yes (all-posterior)", "Yes (+ posterior screws)"],
]
header = data[0]
rows = data[1:]
tbl_data = [[Paragraph(h, TABLE_HEADER) for h in header]]
for row in rows:
cells = [Paragraph(row[0], BODY_BOLD)]
colors_row = [C_ALIF_LIGHT, C_PLIF_LIGHT, C_TLIF_LIGHT, C_XLIF_LIGHT]
for j, cell in enumerate(row[1:]):
cells.append(Paragraph(cell, TABLE_CELL))
tbl_data.append(cells)
tbl = Table(tbl_data, colWidths=[4*cm, 3.25*cm, 3.25*cm, 3.25*cm, 3.25*cm], repeatRows=1)
style = [
('BACKGROUND', (0,0), (-1,0), C_DARK_BLUE),
('BACKGROUND', (1,1), (1,-1), C_ALIF_LIGHT),
('BACKGROUND', (2,1), (2,-1), C_PLIF_LIGHT),
('BACKGROUND', (3,1), (3,-1), C_TLIF_LIGHT),
('BACKGROUND', (4,1), (4,-1), C_XLIF_LIGHT),
('BACKGROUND', (0,1), (0,-1), C_LIGHT_GREY),
('FONTNAME', (0,1), (0,-1), 'Helvetica-Bold'),
('FONTSIZE', (0,0), (-1,-1), 8.5),
('GRID', (0,0), (-1,-1), 0.4, C_MID_GREY),
('VALIGN', (0,0), (-1,-1), 'TOP'),
('TOPPADDING', (0,0), (-1,-1), 5),
('BOTTOMPADDING', (0,0), (-1,-1), 5),
('LEFTPADDING', (0,0), (-1,-1), 4),
('RIGHTPADDING', (0,0), (-1,-1), 4),
('TEXTCOLOR', (0,0), (-1,0), C_WHITE),
]
tbl.setStyle(TableStyle(style))
elems.append(tbl)
return elems
# ─── CAGE MATERIALS ──────────────────────────────────────────────────────────
def build_cage_and_algorithm():
elems = []
elems.append(PageBreak())
elems.append(section_header("8. CAGE MATERIALS & BONE GRAFT OPTIONS", C_DARK_BLUE))
elems.append(Spacer(1, 0.4*cm))
cage_data = [
["Material", "Radiopacity", "Key Properties", "Common Use"],
["PEEK\n(Polyether ether ketone)", "Radiolucent\n(with markers)", "Modulus close to bone; reduces stress shielding;\nRadiolucent — fusion assessment easy", "Most common; all techniques"],
["Titanium (mesh/solid)", "Radiopaque", "Excellent osseointegration; high strength;\nCan cause artefact on MRI/CT", "Revision; corpectomy cages"],
["Carbon composite", "Radiolucent", "Radiolucent; strong; good biocompatibility", "ALIF, TLIF"],
["Bioabsorbable (PLA)", "Radiolucent", "Resorbs over time; avoids permanent implant;\nLimited long-term data", "Experimental / paediatric"],
]
elems.append(comparison_table(cage_data[0], cage_data[1:],
[3.5*cm, 3*cm, 6*cm, 4.5*cm], C_DARK_BLUE))
elems.append(Spacer(1, 0.4*cm))
elems.append(Paragraph("Bone Graft Options", H2))
graft_data = [
["Graft Type", "Source", "Properties", "Limitations"],
["Autologous\nIliac crest bone", "Patient's iliac crest", "Gold standard; osteogenic + osteoconductive + osteoinductive", "Donor site pain; limited volume"],
["Local autograft\n(facet/lamina bone)", "Laminectomy/facetectomy chips", "Readily available; no donor site morbidity", "Lower volume; variable quality"],
["Allograft\n(bone bank)", "Cadaveric bone bank", "No donor site; available in large quantities;\nFemoral rings, fibular strut, chips", "No live cells; infection risk (small); slower fusion"],
["BMP-2\n(Infuse, Medtronic)", "Recombinant human", "Strong osteoinductive signal; high fusion rates;\nReduces autograft need", "Expensive; ectopic bone; oedema; cancer risk debate"],
["Ceramics\n(TCP, HA, CaSO4)", "Synthetic", "Osteoconductive scaffold; readily available;\nNo infection risk", "Not osteoinductive; brittle"],
["DBM (Demineralised\nBone Matrix)", "Processed allograft", "Some osteoinductivity; easy to use", "Variable efficacy; cost"],
]
elems.append(comparison_table(graft_data[0], graft_data[1:],
[3.5*cm, 3*cm, 5.5*cm, 5*cm], C_DARK_BLUE))
elems.append(Spacer(1, 0.5*cm))
elems.append(section_header("9. DECISION ALGORITHM BY LEVEL", C_DARK_BLUE,
"Choosing the right approach based on level and patient factors"))
elems.append(Spacer(1, 0.4*cm))
algo_data = [
["Level", "First-Choice Approach", "Rationale / Key Factors"],
["L5-S1", "ALIF", "Largest cage; best lordosis; iliac crest does not obstruct; L5-S1 most accessible anteriorly"],
["L5-S1\n(ALIF not feasible)", "TLIF", "Previous abdominal surgery; male requesting fertility preservation; no vascular surgeon available"],
["L4-5", "TLIF or ALIF", "TLIF if prior retroperitoneal surgery or high iliac crest; ALIF if large cage + lordosis needed"],
["L4-5\n(low iliac crest, good psoas anatomy)", "XLIF", "MIS approach; low blood loss; if direct decompression not needed"],
["L2-4\n(multi-level, deformity)", "XLIF + posterior fixation", "Efficient multi-level corridor; good cage footprint; combine with posterior correction"],
["L1-4\n(need direct decompression)", "TLIF", "Canal/foraminal stenosis requiring direct neural decompression"],
["Any level\n(prior posterior surgery)", "ALIF or XLIF", "Avoids epidural scar tissue; anterior/lateral virgin corridor"],
["Any level\n(sagittal imbalance)", "ALIF or XLIF + PSO/SPO", "Lordotic ALIF cage or lateral cage + posterior osteotomy for major deformity"],
]
elems.append(comparison_table(algo_data[0], algo_data[1:],
[3.5*cm, 4.5*cm, 9*cm], C_DARK_BLUE))
elems.append(Spacer(1, 0.5*cm))
elems.append(info_box(
"All interbody fusion constructs will eventually fail by hardware loosening or fracture "
"if solid bony fusion does not occur. The cage is a temporary scaffold — "
"fusion is the ultimate goal. Smoking cessation, optimisation of diabetes/osteoporosis, "
"and avoidance of NSAIDs in the post-fusion period are essential to achieve solid fusion.",
HexColor("#EBF5FB"), "FINAL NOTE — CRITICAL PRINCIPLE"))
elems.append(Spacer(1, 0.4*cm))
elems.append(Paragraph(
"Reference: Campbell's Operative Orthopaedics 15th Ed 2026 · "
"Grainger & Allison's Diagnostic Radiology · Gray's Anatomy for Students 4th Ed · "
"Schwartz's Principles of Surgery 11th Ed",
make_style('Ref', fontSize=8, textColor=HexColor("#666666"),
fontName='Helvetica-Oblique', alignment=TA_CENTER)))
return elems
# ─── PAGE TEMPLATE ───────────────────────────────────────────────────────────
def on_later_pages(canvas, doc):
canvas.saveState()
canvas.setFont('Helvetica', 8)
canvas.setFillColor(HexColor("#888888"))
canvas.drawString(2*cm, 1.2*cm,
"Lumbar Interbody Fusion — Step-by-Step Surgical Guide | Orris Medical AI")
canvas.drawRightString(19*cm, 1.2*cm, f"Page {doc.page}")
canvas.setStrokeColor(HexColor("#CCCCCC"))
canvas.line(2*cm, 1.5*cm, 19*cm, 1.5*cm)
canvas.restoreState()
def on_first_page(canvas, doc):
canvas.saveState()
canvas.restoreState()
# ─── BUILD PDF ───────────────────────────────────────────────────────────────
def build_pdf():
doc = SimpleDocTemplate(
OUTPUT_PATH,
pagesize=A4,
topMargin=2*cm,
bottomMargin=2*cm,
leftMargin=2*cm,
rightMargin=2*cm,
title="Lumbar Interbody Fusion — Step-by-Step Surgical Guide",
author="Orris Medical AI",
subject="ALIF PLIF TLIF XLIF Surgical Technique Guide",
)
elements = []
elements += build_cover()
elements += build_toc()
elements += build_overview()
elements += build_alif()
elements += build_plif()
elements += build_tlif()
elements += build_xlif()
elements += build_comparison()
elements += build_cage_and_algorithm()
doc.build(elements,
onFirstPage=on_first_page,
onLaterPages=on_later_pages)
print(f"PDF saved to: {OUTPUT_PATH}")
if __name__ == "__main__":
build_pdf()