~/rabies-pdf/generate_rabies_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, KeepTogether
)
from reportlab.lib.enums import TA_CENTER, TA_LEFT, TA_JUSTIFY
from reportlab.platypus import PageBreak
from reportlab.lib.colors import HexColor
# ── Colour palette ─────────────────────────────────────────────────────────────
C_DEEP_BLUE = HexColor("#1a3a5c")
C_MID_BLUE = HexColor("#2563ae")
C_LIGHT_BLUE = HexColor("#dbeafe")
C_TEAL = HexColor("#0e7490")
C_TEAL_LIGHT = HexColor("#cffafe")
C_RED = HexColor("#b91c1c")
C_RED_LIGHT = HexColor("#fee2e2")
C_GREEN = HexColor("#15803d")
C_GREEN_LIGHT = HexColor("#dcfce7")
C_AMBER = HexColor("#b45309")
C_AMBER_LIGHT = HexColor("#fef3c7")
C_PURPLE = HexColor("#6d28d9")
C_PURPLE_LIGHT= HexColor("#ede9fe")
C_GRAY_DARK = HexColor("#374151")
C_GRAY_MID = HexColor("#6b7280")
C_GRAY_LIGHT = HexColor("#f3f4f6")
C_WHITE = colors.white
C_BLACK = colors.black
PAGE_W, PAGE_H = A4
MARGIN = 1.8 * cm
# ── Document setup ─────────────────────────────────────────────────────────────
OUTPUT = "/home/daytona/workspace/rabies-pdf/Rabies_Prophylaxis_NEET_PG.pdf"
doc = SimpleDocTemplate(
OUTPUT,
pagesize=A4,
leftMargin=MARGIN, rightMargin=MARGIN,
topMargin=MARGIN, bottomMargin=MARGIN,
title="Rabies Prophylaxis – NEET PG Quick Reference",
author="Orris Medical",
)
styles = getSampleStyleSheet()
USABLE_W = PAGE_W - 2 * MARGIN
# ── Custom paragraph styles ───────────────────────────────────────────────────
def S(name, parent="Normal", **kw):
s = ParagraphStyle(name, parent=styles[parent], **kw)
return s
sTitle = S("sTitle", fontSize=22, textColor=C_WHITE, alignment=TA_CENTER,
fontName="Helvetica-Bold", leading=28, spaceAfter=2)
sSubtitle = S("sSubtitle", fontSize=11, textColor=HexColor("#bfdbfe"),
alignment=TA_CENTER, fontName="Helvetica", spaceAfter=0)
sH1 = S("sH1", fontSize=13, textColor=C_WHITE, fontName="Helvetica-Bold",
leading=18, spaceAfter=0, spaceBefore=0)
sH2 = S("sH2", fontSize=11, textColor=C_DEEP_BLUE, fontName="Helvetica-Bold",
leading=15, spaceBefore=6, spaceAfter=3)
sH3 = S("sH3", fontSize=10, textColor=C_MID_BLUE, fontName="Helvetica-Bold",
leading=14, spaceBefore=4, spaceAfter=2)
sBody = S("sBody", fontSize=9, textColor=C_GRAY_DARK, fontName="Helvetica",
leading=13, spaceAfter=2)
sBullet = S("sBullet", fontSize=9, textColor=C_GRAY_DARK, fontName="Helvetica",
leading=13, leftIndent=10, bulletIndent=0, spaceAfter=1)
sTableHdr = S("sTableHdr", fontSize=9, textColor=C_WHITE, fontName="Helvetica-Bold",
alignment=TA_CENTER, leading=12)
sTableCell = S("sTableCell", fontSize=8.5,textColor=C_GRAY_DARK, fontName="Helvetica",
alignment=TA_CENTER, leading=12)
sTableCellL = S("sTableCellL", fontSize=8.5,textColor=C_GRAY_DARK, fontName="Helvetica",
alignment=TA_LEFT, leading=12)
sNote = S("sNote", fontSize=8, textColor=C_AMBER, fontName="Helvetica-Oblique",
leading=11, spaceAfter=2)
sImportant = S("sImportant", fontSize=9, textColor=C_RED, fontName="Helvetica-Bold",
leading=12, spaceAfter=2)
sTip = S("sTip", fontSize=8.5,textColor=C_GREEN, fontName="Helvetica-Oblique",
leading=12, spaceAfter=2)
sFooter = S("sFooter", fontSize=7.5,textColor=C_GRAY_MID, alignment=TA_CENTER,
fontName="Helvetica-Oblique")
# ── Helper builders ────────────────────────────────────────────────────────────
def section_header(text, color=C_DEEP_BLUE, icon=""):
tbl = Table([[Paragraph(f"{icon} {text}" if icon else text, sH1)]],
colWidths=[USABLE_W])
tbl.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), color),
("ROUNDEDCORNERS", [5]),
("TOPPADDING", (0,0), (-1,-1), 6),
("BOTTOMPADDING", (0,0), (-1,-1), 6),
("LEFTPADDING", (0,0), (-1,-1), 10),
]))
return tbl
def info_box(text, bg=C_LIGHT_BLUE, fg=C_DEEP_BLUE, border=C_MID_BLUE):
style = S("_ib", fontSize=9, textColor=fg, fontName="Helvetica",
leading=13)
tbl = Table([[Paragraph(text, style)]], colWidths=[USABLE_W])
tbl.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), bg),
("LINEABOVE", (0,0), (-1,0), 1.5, border),
("LINEBEFORE", (0,0), (0,-1), 3, border),
("TOPPADDING", (0,0), (-1,-1), 6),
("BOTTOMPADDING", (0,0), (-1,-1), 6),
("LEFTPADDING", (0,0), (-1,-1), 10),
("RIGHTPADDING", (0,0), (-1,-1), 8),
]))
return tbl
def build_table(headers, rows, col_widths, header_color=C_DEEP_BLUE,
alt_color=C_GRAY_LIGHT, border_color=C_MID_BLUE):
data = [[Paragraph(h, sTableHdr) for h in headers]]
for i, row in enumerate(rows):
data.append([Paragraph(str(c), sTableCell if j > 0 else sTableCellL)
for j, c in enumerate(row)])
style = TableStyle([
("BACKGROUND", (0,0), (-1,0), header_color),
("ROWBACKGROUNDS",(0,1), (-1,-1), [C_WHITE, alt_color]),
("GRID", (0,0), (-1,-1), 0.4, border_color),
("VALIGN", (0,0), (-1,-1), "MIDDLE"),
("TOPPADDING", (0,0), (-1,-1), 5),
("BOTTOMPADDING", (0,0), (-1,-1), 5),
("LEFTPADDING", (0,0), (-1,-1), 6),
("RIGHTPADDING", (0,0), (-1,-1), 6),
("ROUNDEDCORNERS",[3]),
])
return Table(data, colWidths=col_widths, style=style, repeatRows=1)
def star_badge(tier, text, color):
stars = "★" * tier + "☆" * (3 - tier)
label = f'<font color="{color.hexval()}">{stars} TIER {tier} — {text}</font>'
tbl = Table([[Paragraph(label, S("_badge", fontSize=9, fontName="Helvetica-Bold",
textColor=color, leading=12))]],
colWidths=[USABLE_W])
tbl.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), HexColor("#fafafa")),
("LINEBELOW", (0,0), (-1,-1), 1.2, color),
("TOPPADDING", (0,0), (-1,-1), 4),
("BOTTOMPADDING", (0,0), (-1,-1), 4),
("LEFTPADDING", (0,0), (-1,-1), 8),
]))
return tbl
# ── Page background / header callback ─────────────────────────────────────────
def on_page(canvas, doc):
canvas.saveState()
# subtle side stripe
canvas.setFillColor(C_DEEP_BLUE)
canvas.rect(0, PAGE_H - 8*mm, PAGE_W, 8*mm, fill=1, stroke=0)
canvas.setFillColor(C_WHITE)
canvas.setFont("Helvetica-Bold", 8)
canvas.drawString(MARGIN, PAGE_H - 5.5*mm, "RABIES PROPHYLAXIS • NEET PG QUICK REFERENCE")
canvas.setFont("Helvetica", 8)
canvas.drawRightString(PAGE_W - MARGIN, PAGE_H - 5.5*mm,
f"Page {doc.page}")
# bottom rule
canvas.setStrokeColor(C_MID_BLUE)
canvas.setLineWidth(0.8)
canvas.line(MARGIN, 12*mm, PAGE_W - MARGIN, 12*mm)
canvas.setFont("Helvetica-Oblique", 7)
canvas.setFillColor(C_GRAY_MID)
canvas.drawCentredString(PAGE_W/2, 8*mm, "Orris Medical • Community Medicine • For NEET PG Exam Preparation")
canvas.restoreState()
# ══════════════════════════════════════════════════════════════════════════════
# BUILD STORY
# ══════════════════════════════════════════════════════════════════════════════
story = []
sp = lambda n=4: Spacer(1, n)
# ─── COVER BANNER ─────────────────────────────────────────────────────────────
cover = Table([
[Paragraph("RABIES", sTitle)],
[Paragraph("Prophylaxis • Quick Reference Guide • NEET PG", sSubtitle)],
[Paragraph("Community Medicine | Communicable Diseases", sSubtitle)],
], colWidths=[USABLE_W])
cover.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), C_DEEP_BLUE),
("TOPPADDING", (0,0), (-1,-1), 10),
("BOTTOMPADDING", (0,-1),(-1,-1), 14),
("LEFTPADDING", (0,0), (-1,-1), 12),
("LINEBELOW", (0,-1),(-1,-1), 3, C_MID_BLUE),
]))
story += [cover, sp(10)]
# ══════════════════════════════════════════════════════════════════════════════
# TIER 1
# ══════════════════════════════════════════════════════════════════════════════
story += [star_badge(3, "HIGHEST YIELD — Direct MCQ Material", C_RED), sp(6)]
# ─── 1. Classification of Exposure ────────────────────────────────────────────
story += [section_header("1. Classification of Exposure (WHO)", C_RED), sp(4)]
cat_headers = ["Category", "Description / Features", "Immediate Action"]
cat_rows = [
["Category I",
"Touching / feeding animals\nLicks on INTACT skin",
"WASH ONLY\n(no vaccine, no Ig)"],
["Category II",
"Nibbling of uncovered skin\nMinor scratches WITHOUT bleeding\nAbrasions without bleeding",
"WOUND CARE\n+ VACCINE"],
["Category III",
"Single or multiple transdermal bites/scratches\nLicks on BROKEN skin / mucous membrane\nContamination of mucous membrane with saliva\nWild animal / BAT exposure (WHO)\nContact with bats in India — NOT needed",
"WOUND CARE\n+ VACCINE\n+ IMMUNOGLOBULIN"],
]
cat_widths = [2.8*cm, 9.0*cm, 4.0*cm]
# Rebuild with colour-coded rows
cat_data = [[Paragraph(h, sTableHdr) for h in cat_headers]]
row_bgs = [C_GREEN_LIGHT, C_AMBER_LIGHT, C_RED_LIGHT]
for i, row in enumerate(cat_rows):
cat_data.append([Paragraph(str(c), sTableCellL) for c in row])
cat_tbl = Table(cat_data, colWidths=cat_widths, repeatRows=1)
cat_tbl.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,0), C_DEEP_BLUE),
("BACKGROUND", (0,1), (-1,1), C_GREEN_LIGHT),
("BACKGROUND", (0,2), (-1,2), C_AMBER_LIGHT),
("BACKGROUND", (0,3), (-1,3), C_RED_LIGHT),
("GRID", (0,0), (-1,-1), 0.5, C_MID_BLUE),
("VALIGN", (0,0), (-1,-1), "MIDDLE"),
("TOPPADDING", (0,0), (-1,-1), 6),
("BOTTOMPADDING", (0,0), (-1,-1), 6),
("LEFTPADDING", (0,0), (-1,-1), 6),
("FONTNAME", (0,1), (0,-1), "Helvetica-Bold"),
("TEXTCOLOR", (0,1), (0,-1), C_DEEP_BLUE),
]))
story += [cat_tbl, sp(4)]
story += [info_box("★ Memory tip: I = Wash only | II = Vaccine | III = Vaccine + Ig",
C_AMBER_LIGHT, C_AMBER, C_AMBER), sp(8)]
# ─── 2. Animals ───────────────────────────────────────────────────────────────
story += [section_header("2. Animals: Vaccine Required vs. Not Required", C_TEAL), sp(4)]
ani_headers = ["(-) Vaccine NOT Needed", "(+) Vaccine NEEDED"]
ani_rows = [
["Rat", "Dog"],
["Rabbit", "Cat"],
["Squirrel", "Cattle"],
["", "Wild Animals"],
["", "Bats — WHO (but India: NOT needed)"],
]
ani_widths = [USABLE_W/2, USABLE_W/2]
ani_data = [[Paragraph(h, sTableHdr) for h in ani_headers]]
for row in ani_rows:
ani_data.append([Paragraph(str(c), sTableCellL) for c in row])
ani_tbl = Table(ani_data, colWidths=ani_widths, repeatRows=1)
ani_tbl.setStyle(TableStyle([
("BACKGROUND", (0,0), (0,0), C_GREEN),
("BACKGROUND", (1,0), (1,0), C_RED),
("ROWBACKGROUNDS",(0,1), (-1,-1), [C_WHITE, C_GRAY_LIGHT]),
("GRID", (0,0), (-1,-1), 0.5, C_GRAY_MID),
("VALIGN", (0,0), (-1,-1), "MIDDLE"),
("TOPPADDING", (0,0), (-1,-1), 5),
("BOTTOMPADDING", (0,0), (-1,-1), 5),
("LEFTPADDING", (0,0), (-1,-1), 8),
]))
story += [ani_tbl, sp(4)]
story += [info_box("★ KEY: Rodents (rat, rabbit, squirrel) = NO vaccine. Dog / Cat / Cattle / Wild = YES vaccine.",
C_GREEN_LIGHT, C_GREEN, C_GREEN), sp(8)]
# ─── 3. PEP Vaccine Schedules ─────────────────────────────────────────────────
story += [section_header("3. Post-Exposure Prophylaxis (PEP) — Vaccine Schedules", C_MID_BLUE), sp(4)]
story += [Paragraph("Vaccine type: Cell Cultured Vaccine (CCV) — e.g., PCECV, PVRV", sH3), sp(3)]
pep_headers = ["Regimen", "Dose & Route", "Schedule (Days)", "Sites", "Visits"]
pep_rows = [
["Essen Regimen",
"0.5 mL IM\n(Deltoid; anterolateral\nthigh if <2 yr)",
"0, 3, 7, 14, 28",
"1 site\n(deltoid)",
"5"],
["Updated Thai Red\nCross (ID) — Better",
"0.1 mL ID\n(2 sites each visit)",
"0, 3, 7, 28",
"2 sites\n(both deltoids)",
"4"],
["Zagreb (2-1-1) IM\n(WHO alternative)",
"1 mL IM",
"Day 0 (×2 sites),\nDay 7, Day 21",
"2 on day 0,\n1 each after",
"3"],
["4-dose IM\n(healthy immunocomp.)",
"0.5–1 mL IM",
"0, 3, 7, 14",
"1 site\n(deltoid)",
"4"],
]
pep_widths = [3.5*cm, 3.5*cm, 4.0*cm, 2.8*cm, 1.5*cm]
story += [build_table(pep_headers, pep_rows, pep_widths, C_MID_BLUE), sp(4)]
story += [info_box(
"★ Most asked: Essen = 0,3,7,14,28 (5 visits, IM) | Thai Red Cross ID = 0,3,7,28 (4 visits, ID, 2 sites)\n"
"★ For Cat II & III only. Cat I = no vaccine needed.",
C_LIGHT_BLUE, C_DEEP_BLUE, C_MID_BLUE), sp(8)]
# ─── 4. Immunoglobulin ────────────────────────────────────────────────────────
story += [section_header("4. Rabies Immunoglobulin (RIG) — Passive Immunization", C_RED), sp(4)]
ig_headers = ["Type", "Dose", "Volume", "Notes"]
ig_rows = [
["HRIG\n(Human Rabies Ig)", "20 IU/kg body weight",
"Half in wound\nHalf IM (gluteal)",
"PREFERRED — no serum sickness risk"],
["ERIG\n(Equine Rabies Ig)", "40 IU/kg body weight",
"Half in wound\nHalf IM (gluteal)",
"Skin test first — risk of anaphylaxis"],
]
ig_widths = [2.8*cm, 3.5*cm, 4.0*cm, 5.5*cm]
story += [build_table(ig_headers, ig_rows, ig_widths, C_RED), sp(4)]
story += [info_box(
"★ HRIG = 20 IU/kg | ERIG = 40 IU/kg (double dose for equine — easier recall)\n"
"★ Administer IN and AROUND the wound — neutralises virus locally\n"
"★ Can be given up to DAY 7 after first vaccine dose ONLY — NOT after that\n"
"★ NEVER mix in same syringe as vaccine — use different sites",
C_RED_LIGHT, C_RED, C_RED), sp(8)]
# ══════════════════════════════════════════════════════════════════════════════
# TIER 2
# ══════════════════════════════════════════════════════════════════════════════
story += [star_badge(2, "HIGH YIELD", C_MID_BLUE), sp(6)]
# ─── 5. Wound Management ──────────────────────────────────────────────────────
story += [section_header("5. Wound Management Steps (in order)", C_TEAL), sp(4)]
wm_headers = ["Step", "Method", "Agent Used", "Mechanism of Action"]
wm_rows = [
["1", "Physical Mx", "Water — wash 10–15 min", "MECHANICAL REMOVAL of virus"],
["2", "Chemical Mx", "Soap + disinfectants (povidone-iodine, ethanol)", "INACTIVATION of virus"],
["3", "Biological Mx", "Local Ig infiltration around wound", "NEUTRALISATION of virus"],
["4", "Antibiotics", "Amoxicillin-clavulanate (empiric)", "Prevent secondary infection"],
["5", "TT injection", "Tetanus Toxoid (0.5 mL IM)", "Prevent tetanus co-infection"],
["6", "Suturing", "Delayed suturing with LOOSE sutures", "Allows drainage, reduces anaerobic environment"],
]
wm_widths = [1.0*cm, 3.0*cm, 5.2*cm, 6.6*cm]
story += [build_table(wm_headers, wm_rows, wm_widths, C_TEAL), sp(4)]
story += [info_box(
"★ Washing = mechanical REMOVAL | Soap = inactivation | Ig = neutralisation\n"
" (These 3 mechanisms are separate and frequently asked in MCQs)",
C_TEAL_LIGHT, C_TEAL, C_TEAL), sp(8)]
# ─── 6. Pre-Exposure Prophylaxis ──────────────────────────────────────────────
story += [section_header("6. Pre-Exposure Prophylaxis (PrEP)", C_PURPLE), sp(4)]
story += [Paragraph(
"Target group: At-risk individuals — veterinarians, lab workers, wildlife handlers, spelunkers (cave explorers)", sBody), sp(3)]
prep_headers = ["Route", "Schedule (Days)", "Visits", "Site"]
prep_rows = [
["IM or ID", "0, 7, 21 or 28", "3", "Deltoid (IM)"],
]
prep_widths = [3*cm, 5*cm, 2.5*cm, 5.3*cm]
story += [build_table(prep_headers, prep_rows, prep_widths, C_PURPLE), sp(4)]
story += [info_box("★ PrEP = 0, 7, 21/28 — 3 visits | IM or ID, deltoid",
C_PURPLE_LIGHT, C_PURPLE, C_PURPLE), sp(8)]
# ─── 7. Re-Exposure Prophylaxis ───────────────────────────────────────────────
story += [section_header("7. Re-Exposure Prophylaxis (REP)", C_AMBER), sp(4)]
rep_headers = ["Scenario", "Action", "Schedule", "Ig Needed?"]
rep_rows = [
["Bite < 3 months after last PEP",
"NO vaccine needed",
"—",
"No"],
["Bite > 3 months after last PEP",
"Booster doses only",
"Day 0 and Day 3 (0.1 mL ID)",
"No"],
]
rep_widths = [4.5*cm, 3.5*cm, 4.0*cm, 3.8*cm]
story += [build_table(rep_headers, rep_rows, rep_widths, C_AMBER), sp(4)]
story += [info_box(
"★ REP = only 2 visits (Day 0 and Day 3) | No Ig required | Route: ID",
C_AMBER_LIGHT, C_AMBER, C_AMBER), sp(8)]
# ══════════════════════════════════════════════════════════════════════════════
# TIER 3
# ══════════════════════════════════════════════════════════════════════════════
story += [star_badge(1, "IMPORTANT — Special Scenarios & One-Liners", C_GREEN), sp(6)]
# ─── 8. Special Scenarios ─────────────────────────────────────────────────────
story += [section_header("8. Special Clinical Scenarios", C_GREEN), sp(4)]
sc_headers = ["Scenario", "Management"]
sc_rows = [
["Dog bite (any)", "Start PEP IMMEDIATELY (Day 0)"],
["Pet/vaccinated dog bite", "Still give vaccine — do NOT skip"],
["10-day observation rule",
"Domestic dog/cat: if healthy at 10 days from bite → PEP can be STOPPED"],
["HIV / Immunocompromised + Cat II bite",
"Treat as CATEGORY III → Vaccine + Ig"],
["Pregnancy",
"NOT a contraindication (C/I) — give PEP normally"],
["Cat bite (Cat II) — standard patient",
"Vaccine only (no Ig)"],
["Wild animal or bat bite (WHO)",
"Always Category III → Vaccine + Ig"],
["Bats in India",
"Not applicable (bats not considered rabies vectors in India — NOT needed)"],
["Cannot observe animal",
"Start PEP immediately; do not wait"],
]
sc_widths = [6.0*cm, 9.8*cm]
story += [build_table(sc_headers, sc_rows, sc_widths, C_GREEN), sp(6)]
# ─── 9. Elimination ───────────────────────────────────────────────────────────
story += [section_header("9. Rabies Elimination & Global Target", C_GRAY_DARK), sp(4)]
story += [
Paragraph('★ WHO Goal: <b>"ZERO BY 30"</b> — Zero human deaths from dog-mediated rabies by <b>2030</b>', sBody),
sp(3),
Paragraph("★ Most cost-effective strategy: Mass vaccination of dogs + elimination of stray dogs", sBody),
sp(3),
Paragraph("★ Rabies is 100% preventable with prompt and correct prophylaxis", sBody),
sp(8),
]
# ─── 10. QUICK RECALL BOX ─────────────────────────────────────────────────────
story += [section_header("10. Rapid Recall — MCQ One-Liners", C_DEEP_BLUE), sp(4)]
oneliner_data = [
[Paragraph("Fact", sTableHdr), Paragraph("Answer", sTableHdr)],
[Paragraph("Dose of HRIG", sTableCellL),
Paragraph("20 IU/kg IM", sTableCellL)],
[Paragraph("Dose of ERIG", sTableCellL),
Paragraph("40 IU/kg IM", sTableCellL)],
[Paragraph("Essen PEP schedule", sTableCellL),
Paragraph("0, 3, 7, 14, 28 (5 visits, 0.5 mL IM)", sTableCellL)],
[Paragraph("Thai Red Cross ID schedule", sTableCellL),
Paragraph("0, 3, 7, 28 (4 visits, 0.1 mL ID × 2 sites)", sTableCellL)],
[Paragraph("PrEP schedule", sTableCellL),
Paragraph("0, 7, 21/28 (3 visits, IM or ID)", sTableCellL)],
[Paragraph("REP schedule", sTableCellL),
Paragraph("Day 0 & Day 3 only (2 visits, no Ig)", sTableCellL)],
[Paragraph("Ig deadline", sTableCellL),
Paragraph("Up to Day 7 after 1st vaccine dose", sTableCellL)],
[Paragraph("Ig in REP?", sTableCellL),
Paragraph("NO — not needed in re-exposure", sTableCellL)],
[Paragraph("Rodent bites (rat, rabbit, squirrel)", sTableCellL),
Paragraph("NO vaccine required", sTableCellL)],
[Paragraph("Bat bite — WHO", sTableCellL),
Paragraph("Category III (vaccine + Ig); India = NOT needed", sTableCellL)],
[Paragraph("Pregnancy + rabies exposure", sTableCellL),
Paragraph("NOT a contraindication — give PEP normally", sTableCellL)],
[Paragraph("HIV + Cat II bite", sTableCellL),
Paragraph("Treat as Category III (vaccine + Ig)", sTableCellL)],
[Paragraph("10-day rule", sTableCellL),
Paragraph("Healthy domestic dog/cat at 10 days → stop PEP", sTableCellL)],
[Paragraph("Washing wound mechanism", sTableCellL),
Paragraph("Mechanical REMOVAL of virus (not inactivation)", sTableCellL)],
[Paragraph("Soap/disinfectant mechanism", sTableCellL),
Paragraph("INACTIVATION of virus", sTableCellL)],
[Paragraph("Local Ig mechanism", sTableCellL),
Paragraph("NEUTRALISATION of virus", sTableCellL)],
[Paragraph("Most cost-effective rabies strategy", sTableCellL),
Paragraph("Mass dog vaccination + eliminate stray dogs", sTableCellL)],
[Paragraph("WHO 2030 goal", sTableCellL),
Paragraph("ZERO BY 30 — zero human rabies deaths", sTableCellL)],
]
ol_tbl = Table(oneliner_data, colWidths=[6.5*cm, 9.3*cm], repeatRows=1)
ol_tbl.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,0), C_DEEP_BLUE),
("ROWBACKGROUNDS",(0,1), (-1,-1), [C_WHITE, C_LIGHT_BLUE]),
("GRID", (0,0), (-1,-1), 0.4, C_MID_BLUE),
("VALIGN", (0,0), (-1,-1), "MIDDLE"),
("TOPPADDING", (0,0), (-1,-1), 5),
("BOTTOMPADDING", (0,0), (-1,-1), 5),
("LEFTPADDING", (0,0), (-1,-1), 6),
]))
story += [ol_tbl, sp(10)]
# ─── FINAL NOTE ───────────────────────────────────────────────────────────────
footer_tbl = Table([[Paragraph(
"This guide is compiled from Park's Preventive & Social Medicine, Tintinalli's Emergency Medicine, "
"Red Book 2021, and Roberts & Hedges' Clinical Procedures. For NEET PG exam preparation only.",
sFooter)]], colWidths=[USABLE_W])
footer_tbl.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), C_LIGHT_BLUE),
("TOPPADDING", (0,0), (-1,-1), 6),
("BOTTOMPADDING", (0,0), (-1,-1), 6),
("LEFTPADDING", (0,0), (-1,-1), 10),
]))
story.append(footer_tbl)
# ── Build ──────────────────────────────────────────────────────────────────────
doc.build(story, onFirstPage=on_page, onLaterPages=on_page)
print(f"PDF created: {OUTPUT}")