Create me a pdf on airway management, in RD and surgical along with it's complications and outcomes based on tintinalli book
mkdir -p /tmp/workspace/airway-management && ls /tmp/workspace/airway-management/
~/airway-management/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 inch, cm
from reportlab.platypus import (
SimpleDocTemplate, Paragraph, Spacer, Table, TableStyle,
HRFlowable, PageBreak, KeepTogether
)
from reportlab.lib.enums import TA_LEFT, TA_CENTER, TA_JUSTIFY
from reportlab.pdfbase import pdfmetrics
from reportlab.pdfbase.ttfonts import TTFont
import os
OUTPUT_PATH = "/tmp/workspace/airway-management/Airway_Management_Tintinalli.pdf"
# ── Colours ──────────────────────────────────────────────────────────────────
DARK_BLUE = colors.HexColor("#1a3a5c")
MID_BLUE = colors.HexColor("#2e6da4")
LIGHT_BLUE = colors.HexColor("#d6e8f7")
ACCENT_TEAL = colors.HexColor("#1f8a8a")
LIGHT_TEAL = colors.HexColor("#d0f0ef")
DARK_RED = colors.HexColor("#8b1a1a")
LIGHT_RED = colors.HexColor("#fde8e8")
YELLOW_BG = colors.HexColor("#fff9e6")
LIGHT_GREY = colors.HexColor("#f5f5f5")
MID_GREY = colors.HexColor("#cccccc")
doc = SimpleDocTemplate(
OUTPUT_PATH,
pagesize=A4,
leftMargin=2*cm, rightMargin=2*cm,
topMargin=2*cm, bottomMargin=2*cm,
title="Airway Management – Tintinalli's Emergency Medicine",
author="Tintinalli's Emergency Medicine (8th Ed.)"
)
styles = getSampleStyleSheet()
# Custom styles
H1 = ParagraphStyle("H1", parent=styles["Heading1"],
fontSize=20, textColor=colors.white, spaceAfter=6,
spaceBefore=4, leading=24, alignment=TA_CENTER,
fontName="Helvetica-Bold")
H2 = ParagraphStyle("H2", parent=styles["Heading2"],
fontSize=14, textColor=colors.white, spaceAfter=4,
spaceBefore=10, leading=18, fontName="Helvetica-Bold")
H3 = ParagraphStyle("H3", parent=styles["Heading3"],
fontSize=11, textColor=DARK_BLUE, spaceAfter=3,
spaceBefore=8, leading=14, fontName="Helvetica-Bold")
H4 = ParagraphStyle("H4", parent=styles["Heading4"],
fontSize=10, textColor=ACCENT_TEAL, spaceAfter=2,
spaceBefore=6, leading=13, fontName="Helvetica-Bold")
BODY = ParagraphStyle("BODY", parent=styles["Normal"],
fontSize=9.5, leading=14, spaceAfter=5,
alignment=TA_JUSTIFY, fontName="Helvetica")
BULLET = ParagraphStyle("BULLET", parent=styles["Normal"],
fontSize=9.5, leading=13, spaceAfter=3,
leftIndent=14, bulletIndent=4, fontName="Helvetica",
bulletText="\u2022")
CAPTION = ParagraphStyle("CAPTION", parent=styles["Normal"],
fontSize=8.5, textColor=colors.HexColor("#555555"),
leading=11, spaceAfter=4, alignment=TA_CENTER,
fontName="Helvetica-Oblique")
SOURCE = ParagraphStyle("SOURCE", parent=styles["Normal"],
fontSize=8, textColor=colors.HexColor("#888888"),
leading=11, spaceAfter=3, fontName="Helvetica-Oblique")
KEY = ParagraphStyle("KEY", parent=styles["Normal"],
fontSize=9.5, leading=13, spaceAfter=4,
leftIndent=8, fontName="Helvetica")
WARNING = ParagraphStyle("WARNING", parent=styles["Normal"],
fontSize=9.5, leading=13, spaceAfter=4,
leftIndent=8, fontName="Helvetica-Bold",
textColor=DARK_RED)
# ── Helpers ───────────────────────────────────────────────────────────────────
def section_banner(text, bg=DARK_BLUE):
"""Full-width section banner paragraph."""
style = ParagraphStyle("BANNER", parent=H2,
backColor=bg, borderPad=6, borderRadius=4,
leftIndent=0, rightIndent=0)
return Paragraph(text, style)
def subsection_bar(text):
style = ParagraphStyle("SUBBAR", parent=H3,
backColor=LIGHT_BLUE, borderPad=4,
leftIndent=0, rightIndent=0)
return Paragraph(text, style)
def info_box(paragraphs, bg=LIGHT_BLUE, border=MID_BLUE):
"""Wrap a list of flowables in a coloured box."""
inner = [[p] for p in paragraphs]
t = Table(inner, colWidths=["100%"])
t.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), bg),
("LINEBELOW", (0,0), (-1,-1), 0.4, border),
("LEFTPADDING", (0,0), (-1,-1), 8),
("RIGHTPADDING", (0,0), (-1,-1), 8),
("TOPPADDING", (0,0), (0,0), 6),
("BOTTOMPADDING", (0,-1), (-1,-1), 6),
("ROUNDEDCORNERS", [4, 4, 4, 4]),
]))
return t
def warning_box(paragraphs):
return info_box(paragraphs, bg=LIGHT_RED, border=DARK_RED)
def key_box(paragraphs):
return info_box(paragraphs, bg=YELLOW_BG, border=colors.HexColor("#e6c000"))
def make_table(headers, rows, col_widths=None):
data = [headers] + rows
if col_widths is None:
n = len(headers)
col_widths = [doc.width / n] * n
t = Table(data, colWidths=col_widths)
style = [
("BACKGROUND", (0,0), (-1,0), MID_BLUE),
("TEXTCOLOR", (0,0), (-1,0), colors.white),
("FONTNAME", (0,0), (-1,0), "Helvetica-Bold"),
("FONTSIZE", (0,0), (-1,-1), 8.5),
("ROWBACKGROUNDS", (0,1), (-1,-1), [colors.white, LIGHT_GREY]),
("GRID", (0,0), (-1,-1), 0.4, MID_GREY),
("VALIGN", (0,0), (-1,-1), "TOP"),
("LEFTPADDING",(0,0), (-1,-1), 5),
("RIGHTPADDING",(0,0),(-1,-1), 5),
("TOPPADDING", (0,0), (-1,-1), 4),
("BOTTOMPADDING",(0,0),(-1,-1), 4),
("WORDWRAP", (0,0), (-1,-1), True),
]
t.setStyle(TableStyle(style))
return t
def bp(text):
return Paragraph(text, BULLET)
def p(text):
return Paragraph(text, BODY)
def h3(text):
return Paragraph(text, H3)
def h4(text):
return Paragraph(text, H4)
def sp(n=4):
return Spacer(1, n)
def hr():
return HRFlowable(width="100%", thickness=0.5, color=MID_GREY, spaceAfter=4, spaceBefore=4)
# ══════════════════════════════════════════════════════════════════════════════
# CONTENT
# ══════════════════════════════════════════════════════════════════════════════
story = []
# ── COVER ─────────────────────────────────────────────────────────────────────
cover_data = [[
Paragraph("AIRWAY MANAGEMENT", ParagraphStyle("CVR1",
fontSize=28, textColor=colors.white, fontName="Helvetica-Bold",
alignment=TA_CENTER, leading=34)),
Spacer(1,8),
Paragraph("Respiratory Distress & Surgical Airway", ParagraphStyle("CVR2",
fontSize=16, textColor=LIGHT_BLUE, fontName="Helvetica",
alignment=TA_CENTER, leading=20)),
Spacer(1,6),
Paragraph("Complications and Outcomes", ParagraphStyle("CVR3",
fontSize=14, textColor=colors.HexColor("#aed6f1"),
fontName="Helvetica-Oblique", alignment=TA_CENTER, leading=18)),
Spacer(1,16),
HRFlowable(width="60%", thickness=1, color=LIGHT_BLUE, hAlign="CENTER"),
Spacer(1,16),
Paragraph("Based on Tintinalli's Emergency Medicine: A Comprehensive Study Guide (9th Ed.)",
ParagraphStyle("CVR4", fontSize=10, textColor=colors.HexColor("#cce5f5"),
fontName="Helvetica-Oblique", alignment=TA_CENTER, leading=14)),
Spacer(1,6),
Paragraph("Chapters 29A · 29B · 30", ParagraphStyle("CVR5",
fontSize=11, textColor=LIGHT_BLUE, fontName="Helvetica-Bold",
alignment=TA_CENTER, leading=14)),
]]
ct = Table(cover_data, colWidths=[doc.width])
ct.setStyle(TableStyle([
("BACKGROUND", (0,0),(-1,-1), DARK_BLUE),
("TOPPADDING", (0,0),(-1,-1), 60),
("BOTTOMPADDING", (0,0),(-1,-1), 60),
("LEFTPADDING", (0,0),(-1,-1), 30),
("RIGHTPADDING", (0,0),(-1,-1), 30),
]))
story.append(ct)
story.append(PageBreak())
# ── TABLE OF CONTENTS ─────────────────────────────────────────────────────────
story.append(section_banner("TABLE OF CONTENTS"))
story.append(sp(6))
toc_items = [
("1.", "Overview of Airway Management in the ED"),
("2.", "Airway Assessment"),
("3.", "Oxygenation Strategies Before Intubation"),
("4.", "Rapid-Sequence Intubation (RSI)"),
(" 4.1", "RSI Steps"),
(" 4.2", "RSI Pretreatment Agents"),
(" 4.3", "RSI Induction Agents"),
(" 4.4", "RSI Neuromuscular Blocking Agents"),
("5.", "Difficult Airway Management"),
(" 5.1", "Anticipated Difficulty"),
(" 5.2", "Unanticipated Difficulty"),
("6.", "Complications of Endotracheal Intubation"),
("7.", "Surgical Airway"),
(" 7.1", "Indications and Patient Selection"),
(" 7.2", "Anatomy of the Cricothyroid Membrane"),
(" 7.3", "Surgical (Open) Cricothyrotomy – Technique"),
(" 7.4", "Percutaneous Cricothyrotomy / Needle Technique"),
(" 7.5", "Paediatric Considerations"),
("8.", "Complications of Surgical Airway"),
("9.", "Outcomes"),
("10.","Key Clinical Pearls"),
]
for num, title in toc_items:
style = ParagraphStyle("TOC", parent=BODY,
leftIndent=20 if num.startswith(" ") else 0,
fontSize=10 if not num.startswith(" ") else 9,
fontName="Helvetica-Bold" if not num.startswith(" ") else "Helvetica",
spaceAfter=3)
story.append(Paragraph(f"<b>{num}</b> {title}", style))
story.append(PageBreak())
# ══════════════════════════════════════════════════════════════════════════════
# SECTION 1 – OVERVIEW
# ══════════════════════════════════════════════════════════════════════════════
story.append(section_banner("1. OVERVIEW OF AIRWAY MANAGEMENT IN THE ED"))
story.append(sp())
story.append(p(
"Emergency airway management is one of the most critical and time-sensitive "
"skills in emergency medicine. The primary goal is to ensure adequate oxygenation "
"and ventilation while minimising physiologic perturbations and procedural complications. "
"Clinicians must simultaneously assess the airway, choose the optimal technique, prepare "
"equipment and medications, and have a fallback plan if primary attempts fail."
))
story.append(sp(4))
story.append(key_box([
Paragraph("<b>Core Principles of ED Airway Management</b>", ParagraphStyle("KB",
parent=BODY, fontName="Helvetica-Bold")),
bp("The most experienced provider should perform the intubation."),
bp("Have a video laryngoscope, gum elastic bougie, and alternative airway devices immediately available."),
bp("Preoxygenate before every attempt; supplement with passive apneic oxygenation during the procedure."),
bp("Plan for failure — communicate the next two steps to the team before beginning."),
bp("RSI is the method of choice for most emergency intubations."),
bp("Approximately 1–3% of overall tracheal intubation attempts fail with standard techniques."),
]))
story.append(sp(8))
# ══════════════════════════════════════════════════════════════════════════════
# SECTION 2 – AIRWAY ASSESSMENT
# ══════════════════════════════════════════════════════════════════════════════
story.append(section_banner("2. AIRWAY ASSESSMENT"))
story.append(sp())
story.append(p(
"Approximately 15% of initial emergency airway attempts fail with standard techniques. "
"Pre-intubation assessment is essential to identify potential difficulties before sedation and paralysis "
"are administered. The LEMON mnemonic is the standard bedside tool."
))
story.append(sp(4))
lemon_data = [
[Paragraph("<b>Letter</b>", BODY), Paragraph("<b>Factor</b>", BODY), Paragraph("<b>Clinical Relevance</b>", BODY)],
[Paragraph("L", BODY), Paragraph("Look externally", BODY), Paragraph("Obesity, short neck, dysmorphic features, trauma, facial hair, limited mouth opening", BODY)],
[Paragraph("E", BODY), Paragraph("Evaluate 3-3-2 rule", BODY), Paragraph("Mouth opening ≥3 fingers; hyoid–chin ≥3 fingers; hyoid–thyroid notch ≥2 fingers", BODY)],
[Paragraph("M", BODY), Paragraph("Mallampati score", BODY), Paragraph("Class III–IV predicts difficult glottic visualisation; tongue occupies posterior pharynx", BODY)],
[Paragraph("O", BODY), Paragraph("Obstruction / Obesity", BODY), Paragraph("Foreign body, angioedema, epiglottitis, tumour, haematoma from trauma", BODY)],
[Paragraph("N", BODY), Paragraph("Neck mobility", BODY), Paragraph("Reduced in C-spine injury, severe arthritis, radiation fibrosis, halo device", BODY)],
]
story.append(make_table(
lemon_data[0], lemon_data[1:],
col_widths=[0.7*cm+0.5*cm, 4*cm, None]
))
story.append(sp(6))
story.append(h3("Additional Assessment Considerations"))
story.append(bp("Obesity or reduced neck flexibility impairs alignment of oral, pharyngeal, and tracheal axes."))
story.append(bp("Physical airway obstruction (foreign body, tumour, angioedema, epiglottitis) may mandate nasal techniques or immediate surgical airway."))
story.append(bp("Mallampati criteria: posterior pharyngeal obstruction by tongue correlates with difficulty."))
story.append(bp("Where available, POCUS of the trachea can confirm endotracheal vs oesophageal placement."))
story.append(sp(8))
# ══════════════════════════════════════════════════════════════════════════════
# SECTION 3 – OXYGENATION BEFORE INTUBATION
# ══════════════════════════════════════════════════════════════════════════════
story.append(section_banner("3. OXYGENATION STRATEGIES BEFORE INTUBATION", bg=ACCENT_TEAL))
story.append(sp())
story.append(p(
"Pre-oxygenation is mandatory before intubation. The goal is an SpO2 ≥95% to extend "
"the apnoeic window and prevent desaturation. Multiple modalities are used."
))
story.append(sp(4))
oxy_data = [
[Paragraph("<b>Method</b>", BODY), Paragraph("<b>Flow / Parameters</b>", BODY), Paragraph("<b>Notes</b>", BODY)],
[Paragraph("Standard non-rebreather mask", BODY), Paragraph("10–15 L/min", BODY), Paragraph("First-line; inadequate for severe respiratory distress", BODY)],
[Paragraph("High-flow nasal cannula (HFNC)", BODY), Paragraph("Up to 60 L/min, heated/humidified", BODY), Paragraph("Provides positive pressure, reduces work of breathing; avoid in pneumothorax or bullous disease", BODY)],
[Paragraph("Flush-rate / apneic oxygenation", BODY), Paragraph("40–60 L/min via nasal cannula", BODY), Paragraph("Maintained during paralysis to extend safe apnoeic period via passive alveolar diffusion", BODY)],
[Paragraph("NIV (BiPAP/CPAP)", BODY), Paragraph("Per patient need", BODY), Paragraph("Buys time in impending respiratory failure; pre-oxygenation before RSI", BODY)],
]
story.append(make_table(oxy_data[0], oxy_data[1:], col_widths=[4*cm, 3.5*cm, None]))
story.append(sp(6))
story.append(warning_box([
Paragraph("<b>⚠ Clinical Warning</b>", ParagraphStyle("WB", parent=BODY, fontName="Helvetica-Bold", textColor=DARK_RED)),
p("HFNC is best avoided in patients who are apnoeic or have bullous lung disease and pneumothoraces."),
]))
story.append(sp(8))
# ══════════════════════════════════════════════════════════════════════════════
# SECTION 4 – RSI
# ══════════════════════════════════════════════════════════════════════════════
story.append(section_banner("4. RAPID-SEQUENCE INTUBATION (RSI)"))
story.append(sp())
story.append(p(
"RSI is the sequential administration of an induction (sedative-hypnotic) agent followed immediately "
"by a neuromuscular blocking agent (NMBA) to facilitate tracheal intubation while minimising "
"physiologic perturbations and the risk of pulmonary aspiration. "
"RSI is the method of choice for emergency airway management and achieves the highest first-pass success rates."
))
story.append(sp(4))
story.append(warning_box([
Paragraph("<b>When NOT to use RSI</b>", ParagraphStyle("WB2", parent=BODY, fontName="Helvetica-Bold", textColor=DARK_RED)),
bp("Deeply comatose or cardiac/respiratory arrest patients — intubate without medications."),
bp("Known or anticipated cannot-intubate-cannot-oxygenate scenario — consider awake or surgical airway first."),
]))
story.append(sp(6))
# 4.1 RSI Steps
story.append(subsection_bar("4.1 RSI Steps — The 7 Ps"))
story.append(sp(4))
steps_data = [
[Paragraph("<b>Step</b>", BODY), Paragraph("<b>Action</b>", BODY), Paragraph("<b>Key Details</b>", BODY)],
[Paragraph("1. Preparation", BODY), Paragraph("Assemble team, equipment, medications", BODY), Paragraph("ETT (7–7.5 mm female; 7.5–8 mm male), 10-mL syringe, stylet, bougie, video laryngoscope, suction, bag-valve mask, SpO2 monitor, capnography", BODY)],
[Paragraph("2. Preoxygenation", BODY), Paragraph("SpO2 ≥95%", BODY), Paragraph("Non-rebreather + HFNC or flush-rate O2; maintain apneic oxygenation during paralysis", BODY)],
[Paragraph("3. Pretreatment", BODY), Paragraph("Optional agents 3 min before", BODY), Paragraph("Lidocaine, fentanyl, atropine (paeds), esmolol — blunt sympathetic response in select cases", BODY)],
[Paragraph("4. Paralysis + Induction", BODY), Paragraph("Simultaneous administration", BODY), Paragraph("Induction agent then NMBA; wait 45–60 sec for succinylcholine, 60–90 sec for rocuronium", BODY)],
[Paragraph("5. Positioning", BODY), Paragraph("Sniffing / ramped position", BODY), Paragraph("Align external auditory canal with sternal notch; critical in obese patients", BODY)],
[Paragraph("6. Placement + Confirmation", BODY), Paragraph("Insert ETT under direct/video view", BODY), Paragraph("Visualise tube passing vocal cords; confirm with waveform capnography + CXR", BODY)],
[Paragraph("7. Post-intubation care", BODY), Paragraph("Secure ETT; set ventilator", BODY), Paragraph("Tape or commercial holder; orogastric tube; ongoing sedation/analgesia; ETCO2 monitoring", BODY)],
]
story.append(make_table(steps_data[0], steps_data[1:], col_widths=[3.5*cm, 4*cm, None]))
story.append(sp(6))
# 4.2 Pretreatment
story.append(subsection_bar("4.2 Pretreatment Agents"))
story.append(sp(4))
pre_data = [
[Paragraph("<b>Agent</b>", BODY), Paragraph("<b>Dose</b>", BODY), Paragraph("<b>Indication</b>", BODY), Paragraph("<b>Rationale</b>", BODY)],
[Paragraph("Lidocaine", BODY), Paragraph("1.5 mg/kg IV", BODY), Paragraph("Reactive airways, elevated ICP", BODY), Paragraph("Blunts bronchoconstriction, attenuates ICP rise", BODY)],
[Paragraph("Fentanyl", BODY), Paragraph("3 mcg/kg IV (slow)", BODY), Paragraph("Elevated ICP, aortic dissection", BODY), Paragraph("Blunts sympathetic surge from laryngoscopy", BODY)],
[Paragraph("Atropine", BODY), Paragraph("0.02 mg/kg IV", BODY), Paragraph("Children <5 y, succinylcholine", BODY), Paragraph("Prevents reflex bradycardia from succinylcholine or vagal stimulation", BODY)],
[Paragraph("Esmolol", BODY), Paragraph("2 mg/kg IV", BODY), Paragraph("Hypertensive emergency, coronary disease", BODY), Paragraph("Blunts tachycardia and hypertension from laryngoscopy", BODY)],
]
story.append(make_table(pre_data[0], pre_data[1:], col_widths=[3*cm, 3*cm, 4*cm, None]))
story.append(sp(6))
# 4.3 Induction Agents
story.append(subsection_bar("4.3 Induction Agents"))
story.append(sp(4))
ind_data = [
[Paragraph("<b>Agent</b>", BODY), Paragraph("<b>Dose (IV)</b>", BODY), Paragraph("<b>Onset</b>", BODY), Paragraph("<b>Advantages</b>", BODY), Paragraph("<b>Cautions</b>", BODY)],
[Paragraph("Etomidate", BODY), Paragraph("0.3 mg/kg", BODY), Paragraph("45–60 s", BODY), Paragraph("Haemodynamically neutral; preserves BP; short duration", BODY), Paragraph("Single dose adrenal suppression; myoclonus", BODY)],
[Paragraph("Ketamine", BODY), Paragraph("1.5–2 mg/kg", BODY), Paragraph("45–60 s", BODY), Paragraph("Bronchodilator; maintains airway reflexes; analgesic; preserves BP in most patients", BODY), Paragraph("Avoid in severe HTN, acute angle-closure glaucoma; emergence reactions", BODY)],
[Paragraph("Propofol", BODY), Paragraph("1.5–2 mg/kg", BODY), Paragraph("30–45 s", BODY), Paragraph("Decreases ICP and CMRO2; anticonvulsant", BODY), Paragraph("Significant hypotension; avoid in haemodynamic instability", BODY)],
[Paragraph("Midazolam", BODY), Paragraph("0.1–0.3 mg/kg", BODY), Paragraph("1–2 min", BODY), Paragraph("Amnestic; widely available; reversible", BODY), Paragraph("Slow onset; variable effect; hypotension; not preferred as sole induction agent", BODY)],
[Paragraph("Methohexital", BODY), Paragraph("1–2 mg/kg", BODY), Paragraph("30–60 s", BODY), Paragraph("Short-acting; useful in seizure patients", BODY), Paragraph("May precipitate seizures in non-epileptics; hypotension", BODY)],
]
story.append(make_table(ind_data[0], ind_data[1:], col_widths=[2.5*cm, 2.5*cm, 2*cm, 4.5*cm, None]))
story.append(sp(6))
# 4.4 NMBAs
story.append(subsection_bar("4.4 Neuromuscular Blocking Agents (NMBAs)"))
story.append(sp(4))
nmba_data = [
[Paragraph("<b>Agent</b>", BODY), Paragraph("<b>Type</b>", BODY), Paragraph("<b>Dose (IV)</b>", BODY), Paragraph("<b>Onset</b>", BODY), Paragraph("<b>Duration</b>", BODY), Paragraph("<b>Cautions</b>", BODY)],
[Paragraph("Succinylcholine", BODY), Paragraph("Depolarising", BODY), Paragraph("1.5 mg/kg", BODY), Paragraph("45–60 s", BODY), Paragraph("6–10 min", BODY), Paragraph("Hyperkalaemia (burns, crush, denervation >24–72 h); malignant hyperthermia; contraindicated in chronic NMJ disease", BODY)],
[Paragraph("Rocuronium", BODY), Paragraph("Non-depolarising", BODY), Paragraph("1.2 mg/kg", BODY), Paragraph("60–90 s", BODY), Paragraph("30–60 min", BODY), Paragraph("Prolonged paralysis; reversible with sugammadex 16 mg/kg", BODY)],
[Paragraph("Vecuronium", BODY), Paragraph("Non-depolarising", BODY), Paragraph("0.1–0.2 mg/kg", BODY), Paragraph("2–3 min (slow)", BODY), Paragraph("25–40 min", BODY), Paragraph("Slower onset limits use in RSI; suitable for post-intubation paralysis", BODY)],
]
story.append(make_table(nmba_data[0], nmba_data[1:], col_widths=[2.5*cm, 3*cm, 2.5*cm, 2*cm, 2.5*cm, None]))
story.append(sp(4))
story.append(key_box([
Paragraph("<b>Succinylcholine vs Rocuronium for RSI</b>", ParagraphStyle("KB2", parent=BODY, fontName="Helvetica-Bold")),
p("Succinylcholine has faster onset (45 s) and shorter duration, making it preferable when a potentially difficult airway needs to recover. "
"Rocuronium at 1.2 mg/kg provides comparable intubating conditions and is preferred when succinylcholine is contraindicated. "
"Sugammadex (16 mg/kg) can reverse high-dose rocuronium within 3 minutes if needed."),
]))
story.append(PageBreak())
# ══════════════════════════════════════════════════════════════════════════════
# SECTION 5 – DIFFICULT AIRWAY
# ══════════════════════════════════════════════════════════════════════════════
story.append(section_banner("5. DIFFICULT AIRWAY MANAGEMENT"))
story.append(sp())
story.append(subsection_bar("5.1 Anticipated Difficulty"))
story.append(sp(4))
story.append(p(
"When difficulty is anticipated based on clinical assessment, the operator should weigh "
"the urgency of intubation against the risk of losing the airway after paralysis."
))
story.append(sp(3))
story.append(bp("If the sole barrier is patient consciousness/agitation: proceed with sedation and paralysis."))
story.append(bp("If major anatomic barriers exist (tumour, trauma, obesity, difficult anatomy): consider deferring RSI. Preserve respiratory drive and protective reflexes."))
story.append(bp("Options: awake flexible fibre-optic laryngoscopy (FFL), blind nasotracheal intubation (if experienced), or upfront surgical airway in severe facial trauma."))
story.append(bp("Adjuncts: BiPAP/CPAP/HFNC may temporise while assembling expert resources (anaesthesiology, ENT, surgery)."))
story.append(sp(6))
story.append(subsection_bar("5.2 Unanticipated Intubation Difficulty"))
story.append(sp(4))
story.append(p(
"A single failed laryngoscopy attempt should prompt immediate corrective action and team communication. "
"Key guiding principles:"
))
story.append(sp(3))
story.append(bp("<b>Stay calm</b> — communicate clearly; use cognitive aids and checklists."))
story.append(bp("<b>Call for help early</b> — anaesthesiology, ENT, intensivists if readily available."))
story.append(bp("<b>Plan two steps ahead</b> — 'I will switch to a Miller blade with bougie. If unsuccessful, I will insert an LMA.'"))
story.append(bp("<b>Modify technique each attempt</b> — change blade type, size, approach, or operator; never repeat failed methods."))
story.append(bp("<b>Use non-invasive rescue</b> — bag-valve mask + OPA/NPA or supraglottic airway (LMA, i-gel) buys time."))
story.append(bp("<b>Let RSI medications wear off</b> — recovery of minimal airway reflexes may restore spontaneous ventilation."))
story.append(bp("<b>Escalate to surgical airway</b> — when cannot intubate-cannot oxygenate situation exists; do not delay."))
story.append(sp(6))
story.append(subsection_bar("5.3 Peri-intubation Hypotension"))
story.append(sp(4))
story.append(p(
"Peri-intubation hypotension occurs after ~23% of ED intubations and cardiac arrest after ~4%. "
"Physiologic changes triggered by laryngoscopy or RSI medications can precipitate hypotension."
))
story.append(bp("Consider empiric isotonic crystalloid infusion prior to RSI."))
story.append(bp("'Push-dose' pressors (dilute epinephrine or phenylephrine) prepared ahead of time can mitigate hypotension."))
story.append(bp("Optimal vasopressor choice and dose are not yet evidence-based; refer to institutional protocols."))
story.append(sp(8))
# ══════════════════════════════════════════════════════════════════════════════
# SECTION 6 – COMPLICATIONS OF ETI
# ══════════════════════════════════════════════════════════════════════════════
story.append(section_banner("6. COMPLICATIONS OF ENDOTRACHEAL INTUBATION"))
story.append(sp())
story.append(p(
"Many complications can be anticipated and mitigated with preparation. "
"Some complications are directly procedure-related (e.g., ETT misplacement), while others are indirect "
"(e.g., hyperventilation-induced haemodynamic compromise)."
))
story.append(sp(4))
comp_data = [
[Paragraph("<b>Complication</b>", BODY), Paragraph("<b>Preventive Strategy</b>", BODY), Paragraph("<b>Corrective Action</b>", BODY)],
[Paragraph("ETT misplacement (oesophageal)", BODY), Paragraph("Visualise ETT entry through glottis; confirm with waveform capnography", BODY), Paragraph("Rapid recognition; remove and replace ETT", BODY)],
[Paragraph("ETT dislodgement", BODY), Paragraph("Secure ETT; minimise movement; continuous capnography", BODY), Paragraph("Rapid recognition; remove and replace", BODY)],
[Paragraph("Mainstem intubation", BODY), Paragraph("Confirm correct depth (21–23 cm at lips in adults); post-intubation CXR", BODY), Paragraph("Adjust ETT depth; unilateral breath sounds clue", BODY)],
[Paragraph("Oxygen desaturation", BODY), Paragraph("Adequate preoxygenation; apneic oxygenation during procedure", BODY), Paragraph("Verify position; clear ETT; hyperventilate", BODY)],
[Paragraph("Hypotension", BODY), Paragraph("Optimise BP before intubation; minimise hypotension-inducing drugs", BODY), Paragraph("Trendelenburg; IV fluids; vasopressors; avoid hyperventilation", BODY)],
[Paragraph("Bradycardia", BODY), Paragraph("Ensure adequate HR; atropine pre-treatment in children", BODY), Paragraph("Hyperventilate; atropine; epinephrine", BODY)],
[Paragraph("Cardiac arrest", BODY), Paragraph("Optimise HR, BP, SpO2 before intubation", BODY), Paragraph("Initiate CPR immediately", BODY)],
[Paragraph("Aspiration", BODY), Paragraph("Avoid aggressive BVM; have suction (SALAD technique) ready; cricoid pressure", BODY), Paragraph("Suction airway; bronchoscopy if massive aspiration", BODY)],
[Paragraph("Dental / oropharyngeal injury", BODY), Paragraph("Avoid levering on teeth; note pre-existing dental disease", BODY), Paragraph("Document; dental/ENT referral if significant", BODY)],
[Paragraph("Laryngeal injury / subglottic stenosis", BODY), Paragraph("Use correct tube size; limit cuff pressure (<25 cmH2O); minimise traumatic attempts", BODY), Paragraph("ENT follow-up; may require surgical management", BODY)],
]
story.append(make_table(comp_data[0], comp_data[1:], col_widths=[3.5*cm, 5.5*cm, None]))
story.append(sp(6))
story.append(key_box([
Paragraph("<b>Waveform Capnography is the Gold Standard</b>", ParagraphStyle("KB3", parent=BODY, fontName="Helvetica-Bold")),
p("Continuous waveform end-tidal CO2 (ETCO2) monitoring is the most reliable method to confirm and maintain "
"correct endotracheal tube position throughout the patient's care. A flat waveform strongly suggests oesophageal placement."),
]))
story.append(PageBreak())
# ══════════════════════════════════════════════════════════════════════════════
# SECTION 7 – SURGICAL AIRWAY
# ══════════════════════════════════════════════════════════════════════════════
story.append(section_banner("7. SURGICAL AIRWAY", bg=DARK_RED))
story.append(sp())
story.append(subsection_bar("7.1 Indications and Patient Selection"))
story.append(sp(4))
story.append(p(
"The primary indication for a surgical airway is a <b>cannot intubate – cannot oxygenate (CICO)</b> scenario, "
"typically after failed attempts at oral/nasal endotracheal intubation. "
"Cricothyrotomy or jet ventilation may be performed <i>before</i> laryngoscopy if standard intubation "
"is highly likely to fail."
))
story.append(sp(3))
story.append(bp("Facial trauma (oropharyngeal bleeding, haematoma, bony disruption) — direct visualisation is impossible."))
story.append(bp("Expanding neck haematoma from penetrating trauma (carotid, vertebral, thyroid artery injury)."))
story.append(bp("Upper airway obstruction (severe angioedema, epiglottitis, foreign body, tumour)."))
story.append(bp("Failed RSI with falling SpO2 despite BVM/supraglottic airway rescue."))
story.append(bp("Severe anatomic distortion — consider primary surgical airway without attempted laryngoscopy."))
story.append(sp(4))
story.append(warning_box([
Paragraph("<b>⚠ Critical Warning</b>", ParagraphStyle("CW", parent=BODY, fontName="Helvetica-Bold", textColor=DARK_RED)),
p("Attempting tracheal intubation prior to cricothyrotomy in an expected CICO scenario may increase risk of "
"harm by delaying oxygenation. If standard intubation seems unlikely to succeed, surgical airway placement "
"does NOT always need to be preceded by a laryngoscopy attempt."),
sp(4),
p("If the trachea or larynx is disrupted (blunt laryngotracheal trauma), do NOT attempt cricothyrotomy — "
"surgical tracheostomy by an ENT/thoracic surgeon is required."),
]))
story.append(sp(6))
story.append(subsection_bar("7.2 Anatomy of the Cricothyroid Membrane (CTM)"))
story.append(sp(4))
story.append(p(
"The CTM lies between the thyroid cartilage superiorly and the cricoid cartilage inferiorly, "
"covered by the pretracheal fascia. It is located approximately one-third of the distance "
"from the manubrium to the chin in the midline."
))
story.append(bp("In men: thyroid cartilage is prominent ('Adam's apple'); CTM is easily palpable."))
story.append(bp("In women and children: thyroid and cricoid cartilages may be difficult to distinguish."))
story.append(bp("Obese/short neck: CTM may be at the level of the manubrium and not palpable."))
story.append(bp("PALPATION TRICK: Start at the sternal notch, move cephalad along the trachea; when fingers 'fall off' a firm structure = thyroid cartilage; first soft spot below = CTM."))
story.append(bp("Average CTM dimensions: 9 mm height × 30 mm width. Largest vessel is a small cricothyroid artery along the superior margin — incise in the inferior third to avoid it."))
story.append(sp(6))
story.append(subsection_bar("7.3 Surgical (Open) Cricothyrotomy — Technique"))
story.append(sp(4))
story.append(p(
"Open cricothyrotomy is the preferred surgical airway in adults. "
"A tracheostomy tube (preferred over ETT because it has an obturator, is shorter, easier to suction, and simpler to secure) "
"is the recommended device. Typical tube size: 6 mm tracheostomy or 5–6 mm ETT. "
"Do NOT use ≥7 mm or <4 mm tubes."
))
story.append(sp(4))
cric_steps = [
("1", "Positioning", "Extend the neck (pad under shoulders). Identify the CTM by palpation."),
("2", "Stabilise larynx", "Non-dominant hand: thumb and middle finger grip the thyroid cartilage. Index finger palpates the CTM ('laryngeal handshake')."),
("3", "Skin incision", "Vertical midline stab incision through skin and subcutaneous tissue, 3–4 cm long over the CTM (vertical incision reduces vascular injury)."),
("4", "CTM incision", "Horizontal stab incision through the inferior third of the CTM with a #20 scalpel. Avoid superior margin (cricothyroid artery)."),
("5", "Dilate opening", "Insert a tracheal hook on the inferior edge of the thyroid cartilage to maintain access. Alternatively use a dilator/haemostat."),
("6", "Tube insertion", "Insert a 6-mm cuffed tracheostomy tube (or ETT over bougie) caudally into the tracheal lumen."),
("7", "Inflate cuff", "Inflate cuff; confirm ventilation with bilateral breath sounds and waveform capnography."),
("8", "Secure tube", "Secure with sutures and/or tracheostomy ties. CXR confirmation."),
]
cric_data = [[Paragraph("<b>#</b>", BODY), Paragraph("<b>Step</b>", BODY), Paragraph("<b>Details</b>", BODY)]]
for num, step, detail in cric_steps:
cric_data.append([Paragraph(num, BODY), Paragraph(f"<b>{step}</b>", BODY), Paragraph(detail, BODY)])
story.append(make_table(cric_data[0], cric_data[1:], col_widths=[0.8*cm, 3.5*cm, None]))
story.append(sp(6))
story.append(subsection_bar("7.4 Needle / Percutaneous Cricothyrotomy (Transtracheal Jet Ventilation)"))
story.append(sp(4))
story.append(p(
"A percutaneous needle technique can be used as a bridge in children or as a temporary rescue in adults "
"when surgical cricothyrotomy cannot be immediately performed. It provides oxygenation but inadequate ventilation."
))
story.append(bp("14-gauge over-the-needle catheter inserted at 90° to skin into CTM."))
story.append(bp("Confirm air aspiration, then angle catheter 45° caudally before removing needle."))
story.append(bp("Connect to jet ventilator or manually insufflate oxygen at 15 L/min."))
story.append(bp("Risk: barotrauma and hypercarbia with prolonged use (CO2 retention within minutes)."))
story.append(bp("This is a <b>bridge only</b> — surgical cricothyrotomy or tracheostomy must follow."))
story.append(sp(6))
story.append(subsection_bar("7.5 Paediatric Considerations"))
story.append(sp(4))
story.append(p(
"Cricothyrotomy is technically more difficult and carries higher risk of laryngeal/tracheal injury in children "
"under 12 years, especially under age 8."
))
story.append(bp("Children <12 years: tracheotomy is preferred over cricothyrotomy."))
story.append(bp("AHA recommends percutaneous transtracheal jet ventilation first in children, with surgical cricothyrotomy as second-line."))
story.append(bp("Hyperextension of the neck increases the sagittal length of the CTM and aids access."))
story.append(bp("Advance planning and simulation training for paediatric surgical airway scenarios are essential."))
story.append(sp(8))
# ══════════════════════════════════════════════════════════════════════════════
# SECTION 8 – COMPLICATIONS OF SURGICAL AIRWAY
# ══════════════════════════════════════════════════════════════════════════════
story.append(section_banner("8. COMPLICATIONS OF SURGICAL AIRWAY"))
story.append(sp())
story.append(p(
"Complications of surgical airway procedures are categorised as early (procedural) and late. "
"Penetrating cervical trauma patients have approximately 10% incidence of difficult airway establishment."
))
story.append(sp(4))
surg_comp_data = [
[Paragraph("<b>Complication</b>", BODY), Paragraph("<b>Timing</b>", BODY), Paragraph("<b>Notes</b>", BODY)],
[Paragraph("Tube misplacement (paratracheal/subcutaneous)", BODY), Paragraph("Early", BODY), Paragraph("Confirm with capnography; failed ventilation; re-attempt with bougie guidance", BODY)],
[Paragraph("Haemorrhage from cricothyroid artery", BODY), Paragraph("Early", BODY), Paragraph("Incise inferior third of CTM; direct pressure; electrocautery if available", BODY)],
[Paragraph("Laryngeal and tracheal injury", BODY), Paragraph("Early / Late", BODY), Paragraph("Posterior tracheal wall perforation; greater risk in children; careful technique essential", BODY)],
[Paragraph("Subglottic stenosis", BODY), Paragraph("Late", BODY), Paragraph("Common long-term complication; risk reduced by early conversion to formal tracheostomy", BODY)],
[Paragraph("Voice change / dysphonia", BODY), Paragraph("Late", BODY), Paragraph("Due to injury to cricothyroid muscle or vocal cords; ENT follow-up required", BODY)],
[Paragraph("Tube dislodgement / accidental decannulation", BODY), Paragraph("Early / Late", BODY), Paragraph("Secure device appropriately; tracheostomy tube preferred for stability", BODY)],
[Paragraph("Infection / cellulitis", BODY), Paragraph("Late", BODY), Paragraph("Clean technique; early antibiotics if signs of infection; wound care", BODY)],
[Paragraph("Tracheomalacia", BODY), Paragraph("Late", BODY), Paragraph("Prolonged cuff inflation or over-sized tube; keep cuff pressure <25 cmH2O", BODY)],
[Paragraph("Tracheo-oesophageal fistula", BODY), Paragraph("Late (rare)", BODY), Paragraph("Posterior wall erosion from high cuff pressure or tube tip trauma", BODY)],
]
story.append(make_table(surg_comp_data[0], surg_comp_data[1:], col_widths=[4.5*cm, 2*cm, None]))
story.append(sp(4))
story.append(key_box([
Paragraph("<b>Conversion to Formal Tracheostomy</b>", ParagraphStyle("KB4", parent=BODY, fontName="Helvetica-Bold")),
p("Emergency cricothyrotomy should be converted to formal tracheostomy within 24–72 hours when possible, "
"to reduce the risk of subglottic stenosis, laryngeal injury, and other long-term complications."),
]))
story.append(PageBreak())
# ══════════════════════════════════════════════════════════════════════════════
# SECTION 9 – OUTCOMES
# ══════════════════════════════════════════════════════════════════════════════
story.append(section_banner("9. OUTCOMES"))
story.append(sp())
story.append(h3("Endotracheal Intubation Outcomes"))
story.append(sp(4))
out_data = [
[Paragraph("<b>Metric</b>", BODY), Paragraph("<b>Value</b>", BODY), Paragraph("<b>Source/Notes</b>", BODY)],
[Paragraph("First-pass intubation success (standard DL)", BODY), Paragraph("~80–85%", BODY), Paragraph("Improves to >90% with video laryngoscopy", BODY)],
[Paragraph("Failed intubation rate (all attempts)", BODY), Paragraph("1–3%", BODY), Paragraph("Even with best technique and equipment", BODY)],
[Paragraph("Peri-intubation hypotension", BODY), Paragraph("~23% of ED intubations", BODY), Paragraph("Tintinalli Ch. 29A; major cause of post-intubation morbidity", BODY)],
[Paragraph("Peri-intubation cardiac arrest", BODY), Paragraph("~4% of ED intubations", BODY), Paragraph("High-risk patients: pre-existing haemodynamic instability", BODY)],
[Paragraph("Oesophageal intubation (unrecognised)", BODY), Paragraph("Preventable fatality", BODY), Paragraph("Eliminated with waveform capnography", BODY)],
[Paragraph("Video laryngoscopy vs direct laryngoscopy", BODY), Paragraph("Higher first-pass success", BODY), Paragraph("Decreases complications and prolonged hypoxia", BODY)],
]
story.append(make_table(out_data[0], out_data[1:], col_widths=[5*cm, 3*cm, None]))
story.append(sp(8))
story.append(h3("Surgical Airway Outcomes"))
story.append(sp(4))
surg_out_data = [
[Paragraph("<b>Metric</b>", BODY), Paragraph("<b>Value / Finding</b>", BODY), Paragraph("<b>Notes</b>", BODY)],
[Paragraph("Success rate of emergency cricothyrotomy", BODY), Paragraph("~90% in experienced hands", BODY), Paragraph("Higher with surgical technique vs needle; operator training critical", BODY)],
[Paragraph("Difficult airway in penetrating cervical trauma", BODY), Paragraph("~10% incidence", BODY), Paragraph("Surgical airway often primary choice; laryngoscopy unreliable", BODY)],
[Paragraph("Subglottic stenosis (long-term)", BODY), Paragraph("Common without conversion", BODY), Paragraph("Reduced by converting to tracheostomy within 24–72 h", BODY)],
[Paragraph("Long-term voice change", BODY), Paragraph("Variable", BODY), Paragraph("Depends on extent of CTM/vocal cord injury", BODY)],
[Paragraph("Mortality attributable to failed airway", BODY), Paragraph("High if not rescued", BODY), Paragraph("CICO without surgical airway = near-certain anoxic brain injury or death", BODY)],
[Paragraph("Paediatric surgical airway complications", BODY), Paragraph("Higher than adult", BODY), Paragraph("Tracheotomy preferred in <12 y; simulate and train specifically", BODY)],
]
story.append(make_table(surg_out_data[0], surg_out_data[1:], col_widths=[5*cm, 3.5*cm, None]))
story.append(sp(8))
# ══════════════════════════════════════════════════════════════════════════════
# SECTION 10 – KEY PEARLS
# ══════════════════════════════════════════════════════════════════════════════
story.append(section_banner("10. KEY CLINICAL PEARLS", bg=ACCENT_TEAL))
story.append(sp())
pearls = [
("Pre-oxygenation is non-negotiable.", "Target SpO2 ≥95%. Use HFNC or flush-rate O2 for apneic oxygenation during RSI to extend the safe apnoeic window."),
("Video laryngoscopy first.", "A video laryngoscope improves first-pass success and reduces complications — use it as the default device."),
("RSI = induction + paralysis simultaneously.", "The goal is to intubate before protective reflexes return. Adequate dose of both agents is critical."),
("Know your succinylcholine contraindications.", "Hyperkalaemia states (burns >24 h, crush >72 h, chronic denervation) and malignant hyperthermia history are absolute contraindications. Use rocuronium + sugammadex instead."),
("Peri-intubation hypotension kills.", "23% of ED intubations are complicated by hypotension. Pre-load with crystalloid and have push-dose pressors ready."),
("One failed attempt = change something.", "Different blade type, size, operator, or approach. Never repeat a failed method."),
("Surgical airway: do not delay in CICO.", "When cannot intubate–cannot oxygenate, time to surgical airway is directly proportional to morbidity and mortality."),
("CTM incision: inferior third only.", "The cricothyroid arteries run along the superior margin. Incise in the inferior third to minimise bleeding."),
("Convert cricothyrotomy to tracheostomy.", "Within 24–72 hours electively to reduce subglottic stenosis and long-term laryngeal injury."),
("Capnography confirms tube position.", "Waveform ETCO2 is the gold standard. A flat line after intubation = oesophageal intubation until proven otherwise."),
]
for title, detail in pearls:
story.append(key_box([
Paragraph(f"<b>{title}</b> {detail}", BODY)
]))
story.append(sp(3))
story.append(sp(10))
story.append(hr())
story.append(Paragraph(
"Source: Tintinalli's Emergency Medicine: A Comprehensive Study Guide, 9th Edition. "
"Chapters 29A (Tracheal Intubation), 29B (RSI), 30 (Surgical Airways). "
"McGraw-Hill Education. ISBN 978-1-260-01993-3.",
SOURCE
))
# ── BUILD ─────────────────────────────────────────────────────────────────────
doc.build(story)
print(f"PDF written to: {OUTPUT_PATH}")