~/fosfomycin-guide/generate_pdf.py
#!/usr/bin/env python3
"""
Fosfomycin Pocket Reference Guide - PDF Generator
Uses ReportLab for a professional, clinically formatted pocket guide
"""
from reportlab.lib.pagesizes import A4
from reportlab.lib import colors
from reportlab.lib.units import mm, cm
from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
from reportlab.lib.enums import TA_CENTER, TA_LEFT, TA_JUSTIFY
from reportlab.platypus import (
SimpleDocTemplate, Paragraph, Spacer, Table, TableStyle,
HRFlowable, KeepTogether, PageBreak
)
from reportlab.platypus.flowables import BalancedColumns
from reportlab.pdfbase import pdfmetrics
from reportlab.pdfbase.ttfonts import TTFont
from reportlab.graphics.shapes import Drawing, Rect, String, Line
from reportlab.graphics import renderPDF
import os
# ── Colour palette ──────────────────────────────────────────────────────────
NAVY = colors.HexColor("#0D2B55") # header / section bars
TEAL = colors.HexColor("#007C91") # sub-headers
AMBER = colors.HexColor("#E8871A") # warning / caution
GREEN = colors.HexColor("#1A7A4A") # susceptible / positive
RED = colors.HexColor("#C0392B") # resistant / negative
LIGHT_BLUE = colors.HexColor("#D6EAF8") # alternate row
LIGHT_GREY = colors.HexColor("#F2F3F4") # section bg
WHITE = colors.white
DARK_TEXT = colors.HexColor("#1C1C1C")
# ── Page setup ───────────────────────────────────────────────────────────────
OUTPUT = "/tmp/workspace/fosfomycin-guide/Fosfomycin_Pocket_Reference.pdf"
PAGE_W, PAGE_H = A4
MARGIN = 15 * mm
doc = SimpleDocTemplate(
OUTPUT,
pagesize=A4,
leftMargin=MARGIN,
rightMargin=MARGIN,
topMargin=12 * mm,
bottomMargin=12 * mm,
title="Fosfomycin Pocket Reference Guide",
author="Clinical Reference",
subject="Fosfomycin Drug Profile",
)
# ── Styles ────────────────────────────────────────────────────────────────────
styles = getSampleStyleSheet()
def style(name, **kw):
return ParagraphStyle(name, **kw)
COVER_TITLE = style("CoverTitle", fontSize=28, textColor=WHITE,
fontName="Helvetica-Bold", alignment=TA_CENTER, leading=34)
COVER_SUB = style("CoverSub", fontSize=13, textColor=colors.HexColor("#AED6F1"),
fontName="Helvetica", alignment=TA_CENTER, leading=18)
COVER_BADGE = style("CoverBadge", fontSize=10, textColor=WHITE,
fontName="Helvetica-Bold", alignment=TA_CENTER)
SEC_HEAD = style("SecHead", fontSize=11, textColor=WHITE,
fontName="Helvetica-Bold", alignment=TA_LEFT,
leftIndent=4, spaceBefore=6, spaceAfter=2)
SUBSEC_HEAD = style("SubSecHead", fontSize=10, textColor=NAVY,
fontName="Helvetica-Bold", spaceBefore=5, spaceAfter=2)
BODY = style("Body", fontSize=8.5, textColor=DARK_TEXT,
fontName="Helvetica", leading=12, spaceAfter=2)
BODY_BOLD = style("BodyBold", fontSize=8.5, textColor=DARK_TEXT,
fontName="Helvetica-Bold", leading=12)
SMALL = style("Small", fontSize=7.5, textColor=colors.HexColor("#555555"),
fontName="Helvetica", leading=10)
TABLE_HDR = style("TableHdr", fontSize=8, textColor=WHITE,
fontName="Helvetica-Bold", alignment=TA_CENTER)
TABLE_CELL = style("TableCell", fontSize=8, textColor=DARK_TEXT,
fontName="Helvetica", leading=11)
TABLE_CELL_B= style("TableCellB", fontSize=8, textColor=DARK_TEXT,
fontName="Helvetica-Bold", leading=11)
FOOTER_ST = style("Footer", fontSize=7, textColor=colors.HexColor("#888888"),
fontName="Helvetica", alignment=TA_CENTER)
NOTE_ST = style("Note", fontSize=7.5, textColor=colors.HexColor("#555555"),
fontName="Helvetica-Oblique", leading=10)
WARN_ST = style("Warn", fontSize=8, textColor=colors.HexColor("#7D3C00"),
fontName="Helvetica-Bold", leading=11)
GREEN_ST = style("GreenSt", fontSize=8, textColor=GREEN,
fontName="Helvetica-Bold", leading=11)
# ── Helper functions ──────────────────────────────────────────────────────────
def section_header(text, color=NAVY):
"""Coloured section bar with white text."""
tbl = Table([[Paragraph(text, SEC_HEAD)]], colWidths=[PAGE_W - 2*MARGIN])
tbl.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), color),
("TOPPADDING", (0,0), (-1,-1), 4),
("BOTTOMPADDING", (0,0), (-1,-1), 4),
("LEFTPADDING", (0,0), (-1,-1), 6),
("RIGHTPADDING", (0,0), (-1,-1), 6),
("ROUNDEDCORNERS", [3,3,3,3]),
]))
return tbl
def two_col_table(rows, col1w=60*mm, col2w=None, header=None, alt=True):
"""Generic two-column table with optional header and alternating rows."""
if col2w is None:
col2w = PAGE_W - 2*MARGIN - col1w
data = []
if header:
data.append([Paragraph(header[0], TABLE_HDR), Paragraph(header[1], TABLE_HDR)])
for i, (k, v) in enumerate(rows):
kp = Paragraph(str(k), TABLE_CELL_B)
vp = Paragraph(str(v), TABLE_CELL)
data.append([kp, vp])
style_cmds = [
("GRID", (0,0), (-1,-1), 0.4, colors.HexColor("#CCCCCC")),
("TOPPADDING", (0,0), (-1,-1), 3),
("BOTTOMPADDING", (0,0), (-1,-1), 3),
("LEFTPADDING", (0,0), (-1,-1), 5),
("RIGHTPADDING", (0,0), (-1,-1), 5),
("VALIGN", (0,0), (-1,-1), "TOP"),
]
if header:
style_cmds += [
("BACKGROUND", (0,0), (-1,0), TEAL),
("TEXTCOLOR", (0,0), (-1,0), WHITE),
]
start = 1
else:
start = 0
if alt:
for i in range(start, len(data), 2):
style_cmds.append(("BACKGROUND", (0,i), (-1,i), LIGHT_GREY))
tbl = Table(data, colWidths=[col1w, col2w])
tbl.setStyle(TableStyle(style_cmds))
return tbl
def three_col_table(rows, widths, header=None):
data = []
if header:
data.append([Paragraph(h, TABLE_HDR) for h in header])
for row in rows:
data.append([Paragraph(str(c), TABLE_CELL) for c in row])
style_cmds = [
("GRID", (0,0), (-1,-1), 0.4, colors.HexColor("#CCCCCC")),
("TOPPADDING", (0,0), (-1,-1), 3),
("BOTTOMPADDING", (0,0), (-1,-1), 3),
("LEFTPADDING", (0,0), (-1,-1), 5),
("RIGHTPADDING", (0,0), (-1,-1), 5),
("VALIGN", (0,0), (-1,-1), "TOP"),
]
if header:
style_cmds += [
("BACKGROUND", (0,0), (-1,0), TEAL),
("TEXTCOLOR", (0,0), (-1,0), WHITE),
]
for i in range(1, len(data), 2):
style_cmds.append(("BACKGROUND", (0,i), (-1,i), LIGHT_GREY))
tbl = Table(data, colWidths=widths)
tbl.setStyle(TableStyle(style_cmds))
return tbl
def sp(h=3):
return Spacer(1, h*mm)
def hr():
return HRFlowable(width="100%", thickness=0.5, color=colors.HexColor("#CCCCCC"), spaceAfter=3)
def bullet(text, color=TEAL):
return Paragraph(f'<font color="#{color.hexval()[1:]}">▶</font> {text}', BODY)
def note(text):
return Paragraph(f'<i>{text}</i>', NOTE_ST)
def warning_box(text):
data = [[Paragraph(f"⚠ {text}", WARN_ST)]]
tbl = Table(data, colWidths=[PAGE_W - 2*MARGIN])
tbl.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), colors.HexColor("#FEF9E7")),
("LEFTBORDER_COLOR", (0,0), (-1,-1), AMBER),
("BOX", (0,0), (-1,-1), 1.5, AMBER),
("TOPPADDING", (0,0), (-1,-1), 5),
("BOTTOMPADDING", (0,0), (-1,-1), 5),
("LEFTPADDING", (0,0), (-1,-1), 8),
("RIGHTPADDING", (0,0), (-1,-1), 8),
]))
return tbl
def green_box(text):
data = [[Paragraph(f"✔ {text}", GREEN_ST)]]
tbl = Table(data, colWidths=[PAGE_W - 2*MARGIN])
tbl.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), colors.HexColor("#EAFAF1")),
("BOX", (0,0), (-1,-1), 1.5, GREEN),
("TOPPADDING", (0,0), (-1,-1), 5),
("BOTTOMPADDING", (0,0), (-1,-1), 5),
("LEFTPADDING", (0,0), (-1,-1), 8),
("RIGHTPADDING", (0,0), (-1,-1), 8),
]))
return tbl
# ── Cover page helper ─────────────────────────────────────────────────────────
def cover_page():
"""Returns a Table that acts as a full-page cover."""
content_w = PAGE_W - 2*MARGIN
# Title block
title_data = [
[Paragraph("FOSFOMYCIN", COVER_TITLE)],
[Paragraph("Pocket Reference Guide", COVER_SUB)],
[Spacer(1, 6*mm)],
[Paragraph("For Clinical Use", COVER_SUB)],
]
title_tbl = Table(title_data, colWidths=[content_w])
title_tbl.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), NAVY),
("TOPPADDING", (0,0), (-1,-1), 6),
("BOTTOMPADDING", (0,0), (-1,-1), 6),
("LEFTPADDING", (0,0), (-1,-1), 10),
("RIGHTPADDING", (0,0), (-1,-1), 10),
("ROUNDEDCORNERS", [4,4,4,4]),
]))
# Badges row
badges = [
("BACTERICIDAL", GREEN),
("UNIQUE MOA", TEAL),
("ESBL-ACTIVE", NAVY),
("SINGLE DOSE", AMBER),
]
badge_cells = []
for label, col in badges:
p = Paragraph(label, COVER_BADGE)
badge_cells.append(p)
badge_tbl = Table([badge_cells], colWidths=[content_w/4]*4)
badge_tbl.setStyle(TableStyle([
("BACKGROUND", (0,0), (0,0), GREEN),
("BACKGROUND", (1,0), (1,0), TEAL),
("BACKGROUND", (2,0), (2,0), NAVY),
("BACKGROUND", (3,0), (3,0), AMBER),
("TOPPADDING", (0,0), (-1,-1), 5),
("BOTTOMPADDING", (0,0), (-1,-1), 5),
("ALIGN", (0,0), (-1,-1), "CENTER"),
("GRID", (0,0), (-1,-1), 1, WHITE),
]))
# Quick facts
qf_rows = [
("Class", "Phosphonic acid antibiotic (unique structural class)"),
("Target", "MurA — enolpyruvyl transferase (step 1 of peptidoglycan synthesis)"),
("Formulations", "Oral: 3 g sachet (Monurol) | IV: 6 g vial (Contepo, FDA 2025)"),
("Primary Use", "Uncomplicated cystitis (oral) | cUTI / pyelonephritis (IV)"),
("Key Advantage", "Active against ESBL-producers, VRE, MRSA; no cross-resistance"),
]
qf_tbl = two_col_table(qf_rows, col1w=42*mm)
elements = [
sp(4),
title_tbl,
sp(5),
badge_tbl,
sp(5),
Paragraph("AT-A-GLANCE", style("AG", fontSize=9, textColor=TEAL,
fontName="Helvetica-Bold", spaceBefore=2, spaceAfter=3)),
qf_tbl,
sp(4),
note("Sources: Harrison's 22E | Goodman & Gilman's | Lippincott Pharmacology | "
"Rosen's Emergency Medicine | Merck Manual Apr 2025 | Drugs.com Dec 2025"),
]
return elements
# ── BUILD CONTENT ─────────────────────────────────────────────────────────────
story = []
# ─── COVER ────────────────────────────────────────────────────────────────────
story.extend(cover_page())
story.append(PageBreak())
# ─── PAGE 2: MECHANISM + SPECTRUM ─────────────────────────────────────────────
story.append(section_header("1. MECHANISM OF ACTION"))
story.append(sp(2))
moa_rows = [
("Target", "MurA (UDP-GlcNAc enolpyruvyl transferase) — catalyzes step 1 of peptidoglycan synthesis"),
("Binding", "Covalent, irreversible alkylation of Cys115 in MurA active site via epoxide ring"),
("Effect", "Blocks N-acetylmuramic acid (NAM) formation → no peptidoglycan → cell lysis"),
("Extra Effect", "Reduces bacterial adherence to uroepithelial cells (anti-adhesin activity)"),
("Type", "Bactericidal | Concentration-dependent killing"),
("Uniqueness", "No cross-resistance with ANY other antibiotic class (unique structural scaffold)"),
("Testing Note", "Susceptibility testing requires glucose-6-phosphate media supplementation"),
]
story.append(two_col_table(moa_rows, col1w=38*mm))
story.append(sp(3))
story.append(section_header("2. ANTIMICROBIAL SPECTRUM"))
story.append(sp(2))
spectrum_rows = [
("Gram-Negative", "Susceptibility", "Notes"),
("E. coli", "✔ Susceptible", "Primary uropathogen target"),
("Proteus spp.", "✔ Susceptible", "—"),
("Klebsiella pneumoniae", "~ Variable", "Most ESBL-producers susceptible"),
("Enterobacter spp.", "~ Variable", "Check MIC"),
("Serratia marcescens", "~ Variable", "Check MIC"),
("Pseudomonas aeruginosa", "✘ Resistant", "Intrinsic resistance"),
("Acinetobacter baumannii", "✘ Resistant", "Intrinsic resistance"),
("Burkholderia spp.", "✘ Resistant", "Intrinsic resistance"),
]
gn_header = spectrum_rows[0]
gn_data = spectrum_rows[1:]
w3 = [60*mm, 40*mm, PAGE_W - 2*MARGIN - 100*mm]
gn_tbl = three_col_table(gn_data, w3, header=list(gn_header))
gp_rows = [
("Gram-Positive", "Susceptibility", "Notes"),
("Enterococcus faecalis", "✔ Susceptible", "Including VanA VRE"),
("Enterococcus faecium (VRE)", "✔ Susceptible", "—"),
("S. saprophyticus", "✔ Susceptible", "—"),
("S. aureus / MRSA", "✔ Often susceptible", "Resistance may emerge on monotherapy"),
]
gp_data = gp_rows[1:]
gp_tbl = three_col_table(gp_data, w3, header=list(gp_rows[0]))
story.append(gn_tbl)
story.append(sp(2))
story.append(gp_tbl)
story.append(sp(2))
story.append(green_box(
"ESBL-PRODUCING Enterobacterales: the vast majority remain susceptible — "
"fosfomycin is one of the few oral options available (Harrison's 22E)"
))
story.append(sp(3))
# ─── PAGE 3: PHARMACOKINETICS + DOSING ────────────────────────────────────────
story.append(section_header("3. PHARMACOKINETICS"))
story.append(sp(2))
pk_header = ["Parameter", "Oral (Tromethamine)", "IV (Disodium)"]
pk_data = [
("Bioavailability", "~40%", "100% (IV)"),
("Peak serum conc.", "~26 µg/mL at 2 h (3 g)", "High (dose-dependent)"),
("Urinary conc.", "1,000–4,000 µg/mL", "Very high"),
("Urine active time", "Up to 48 h (single dose)","Continuous during infusion"),
("Protein binding", "Negligible", "Negligible"),
("Vd", "Wide (kidney, bladder, prostate)", "Wide"),
("Metabolism", "None — excreted unchanged","None — excreted unchanged"),
("Elimination", "Renal (GFR + tubular secretion)", "Renal"),
("Half-life (t½)", "5–8 hours", "4–8 hours"),
("Activity in urine", "Greater in acidic pH", "Greater in acidic pH"),
]
pk_tbl_data = [[Paragraph(pk_header[0], TABLE_HDR),
Paragraph(pk_header[1], TABLE_HDR),
Paragraph(pk_header[2], TABLE_HDR)]]
for i, row in enumerate(pk_data):
pk_tbl_data.append([Paragraph(row[0], TABLE_CELL_B),
Paragraph(row[1], TABLE_CELL),
Paragraph(row[2], TABLE_CELL)])
pk_widths = [52*mm, 60*mm, PAGE_W - 2*MARGIN - 112*mm]
pk_tbl = Table(pk_tbl_data, colWidths=pk_widths)
pk_style = TableStyle([
("BACKGROUND", (0,0), (-1,0), TEAL),
("GRID", (0,0), (-1,-1), 0.4, colors.HexColor("#CCCCCC")),
("TOPPADDING", (0,0), (-1,-1), 3),
("BOTTOMPADDING", (0,0), (-1,-1), 3),
("LEFTPADDING", (0,0), (-1,-1), 5),
("RIGHTPADDING", (0,0), (-1,-1), 5),
("VALIGN", (0,0), (-1,-1), "TOP"),
])
for i in range(1, len(pk_tbl_data), 2):
pk_style.add("BACKGROUND", (0,i), (-1,i), LIGHT_GREY)
pk_tbl.setStyle(pk_style)
story.append(pk_tbl)
story.append(sp(3))
story.append(section_header("4. DOSING & FORMULATIONS"))
story.append(sp(2))
dose_data = [
["Indication", "Formulation", "Dose & Regimen", "Notes"],
["Uncomplicated cystitis\n(FDA-approved)", "Oral 3 g sachet\n(Monurol)", "Single 3 g dose\n(dissolved in water)", "First-line; avoid if pyelonephritis suspected"],
["Complicated UTI\n(off-label, oral)", "Oral 3 g sachet", "3 g every 48 h × 3 doses", "Off-label; consider IV if severe"],
["UTI prophylaxis\n(off-label)", "Oral 3 g sachet", "3 g every 10 days", "Recurrent UTI prevention"],
["Complicated UTI / APN\n(IV, FDA-approved 2025)", "IV 6 g vial\n(Contepo)", "6 g IV q8h × 7–14 days", "Adults ≥18 yr; E. coli or K. pneumoniae"],
["MDR/systemic infections\n(off-label, IV)", "IV formulation", "4–8 g q6–8h\n(PK/PD guided)", "Use IN COMBINATION; TDM in renal impairment"],
]
dose_widths = [38*mm, 28*mm, 42*mm, PAGE_W - 2*MARGIN - 108*mm]
dose_tbl_data = []
for i, row in enumerate(dose_data):
cell_style = TABLE_HDR if i == 0 else TABLE_CELL
dose_tbl_data.append([Paragraph(c, TABLE_HDR if i==0 else TABLE_CELL) for c in row])
dose_tbl = Table(dose_tbl_data, colWidths=dose_widths)
dose_style = TableStyle([
("BACKGROUND", (0,0), (-1,0), NAVY),
("GRID", (0,0), (-1,-1), 0.4, colors.HexColor("#CCCCCC")),
("TOPPADDING", (0,0), (-1,-1), 3),
("BOTTOMPADDING", (0,0), (-1,-1), 3),
("LEFTPADDING", (0,0), (-1,-1), 5),
("RIGHTPADDING", (0,0), (-1,-1), 5),
("VALIGN", (0,0), (-1,-1), "TOP"),
("ROWBACKGROUNDS", (0,1), (-1,-1), [WHITE, LIGHT_GREY]),
])
dose_tbl.setStyle(dose_style)
story.append(dose_tbl)
story.append(sp(2))
story.append(warning_box(
"Oral fosfomycin achieves LOW SYSTEMIC concentrations — do NOT use for pyelonephritis, "
"bacteremia, or deep-seated infections. Use IV formulation for systemic disease."
))
story.append(sp(3))
# ─── PAGE 4: ADRs + RESISTANCE + INTERACTIONS ─────────────────────────────────
story.append(section_header("5. ADVERSE EFFECTS"))
story.append(sp(2))
adr_rows = [
("GI: nausea, diarrhea, dyspepsia", "Most common; usually mild and self-limiting"),
("Headache, dizziness", "Occasional; reversible"),
("Vaginitis", "Reported with oral use"),
("Asthenia", "Uncommon"),
("Sodium load (IV)", "Each gram fosfomycin disodium ≈ 0.32 mEq Na — monitor in CHF, fluid restriction"),
("Hypokalemia (IV)", "High-dose IV therapy; monitor electrolytes"),
]
story.append(two_col_table(adr_rows, col1w=65*mm,
header=["Adverse Effect", "Clinical Note"]))
story.append(sp(2))
story.append(green_box(
"Notably ABSENT: no hepatotoxicity, nephrotoxicity, QT prolongation, tendon rupture, "
"peripheral neuropathy, or photosensitivity — a favorable safety profile vs. fluoroquinolones"
))
story.append(sp(3))
story.append(section_header("6. RESISTANCE MECHANISMS"))
story.append(sp(2))
res_rows = [
("Reduced uptake (most common)",
"Mutations in glpT (glycerol-3-phosphate transporter) or uhpT (hexose phosphate transporter); "
"fosfomycin requires these carriers to enter the bacterial cell"),
("MurA target mutation",
"Cys115 → Asp substitution in the MurA active site prevents covalent binding"),
("Enzymatic inactivation (plasmid)",
"FosA (glutathione-S-transferase), FosB, FosC, FosX enzymes open the epoxide ring and "
"inactivate the drug — transferable on plasmids"),
("Efflux pumps",
"Minor contribution observed in some strains"),
]
story.append(two_col_table(res_rows, col1w=55*mm,
header=["Mechanism", "Detail"]))
story.append(sp(2))
story.append(warning_box(
"Resistance does NOT emerge during oral cystitis treatment. It HAS been documented during "
"IV therapy for osteomyelitis and respiratory infections — ALWAYS combine IV fosfomycin "
"with a second agent for systemic infections."
))
story.append(sp(3))
story.append(section_header("7. DRUG INTERACTIONS"))
story.append(sp(2))
int_rows = [
("Metoclopramide / prokinetics",
"Decreased serum conc. and urinary excretion of fosfomycin (accelerated GI transit)"),
("Antacids (Ca²⁺, Mg²⁺)",
"May reduce oral absorption — separate dosing by ≥2 hours"),
("Meropenem (IV)",
"In vitro synergy against E. coli — a useful combination for MDR infections"),
("Cimetidine",
"No clinically significant effect on fosfomycin pharmacokinetics"),
("CYP450 substrates",
"No interaction — fosfomycin is NOT hepatically metabolized"),
]
story.append(two_col_table(int_rows, col1w=55*mm,
header=["Drug / Class", "Interaction"]))
story.append(sp(3))
# ─── PAGE 5: SPECIAL POPULATIONS + CLINICAL USE ───────────────────────────────
story.append(section_header("8. SPECIAL POPULATIONS"))
story.append(sp(2))
pop_rows = [
("Pregnancy",
"Oral single-dose widely used for UTI in pregnancy; considered safe (Category B). "
"Preferred when nitrofurantoin/TMP-SMX are contraindicated near term."),
("Breastfeeding",
"Excreted in breast milk; avoid if alternatives available."),
("Pediatrics",
"Emerging evidence supports use. Reviewed in Tran, Pharmacotherapy 2023 "
"(PMID 36825460). No oral pediatric formulation widely approved in the US."),
("Renal impairment\n(CrCl <50 mL/min)",
"IV: significant dose reduction required; TDM recommended in critically ill. "
"Oral single-dose: generally safe but urinary concentrations may be lower."),
("Hepatic impairment",
"No hepatic metabolism — no dose adjustment needed."),
("Elderly",
"Oral single-dose appropriate. IV requires caution (sodium load, variable PK, "
"increased risk of electrolyte disturbances)."),
("Immunocompromised / MDR",
"Use in combination regimens. Clinical success ~75–80% for combination therapy "
"against MDR pathogens (Frontiers Microbiology 2025)."),
]
story.append(two_col_table(pop_rows, col1w=48*mm,
header=["Population", "Guidance"]))
story.append(sp(3))
story.append(section_header("9. CLINICAL USE & COMBINATIONS FOR MDR INFECTIONS"))
story.append(sp(2))
combo_data = [
["Pathogen / Scenario", "Combination Partner", "Evidence / Notes"],
["ESBL-producing E. coli / K. pneumoniae (UTI)",
"Fosfomycin ORAL alone",
"One of few oral options; high susceptibility retained"],
["Carbapenem-resistant Enterobacterales (CRE)",
"+ Meropenem or Imipenem",
"Synergy shown in vitro and clinical reports; prevents resistance emergence"],
["MDR P. aeruginosa",
"+ Aminoglycoside or β-lactam",
"Note: P. aeruginosa has variable intrinsic resistance; IV only"],
["MRSA (bacteremia, endocarditis)",
"+ Daptomycin or Rifampicin",
"Off-label; case series show clinical benefit"],
["VRE infections",
"+ Daptomycin or Linezolid",
"Fosfomycin retains activity vs. vancomycin-resistant strains"],
["Carbapenem-resistant A. baumannii",
"+ Colistin",
"Synergy confirmed by time-kill assays (2025 data); A. baumannii has intrinsic resistance — check MIC"],
]
combo_widths = [52*mm, 46*mm, PAGE_W - 2*MARGIN - 98*mm]
combo_tbl_data = []
for i, row in enumerate(combo_data):
combo_tbl_data.append([Paragraph(c, TABLE_HDR if i==0 else TABLE_CELL) for c in row])
combo_tbl = Table(combo_tbl_data, colWidths=combo_widths)
combo_style = TableStyle([
("BACKGROUND", (0,0), (-1,0), NAVY),
("GRID", (0,0), (-1,-1), 0.4, colors.HexColor("#CCCCCC")),
("TOPPADDING", (0,0), (-1,-1), 3),
("BOTTOMPADDING", (0,0), (-1,-1), 3),
("LEFTPADDING", (0,0), (-1,-1), 5),
("RIGHTPADDING", (0,0), (-1,-1), 5),
("VALIGN", (0,0), (-1,-1), "TOP"),
("ROWBACKGROUNDS", (0,1), (-1,-1), [WHITE, LIGHT_GREY]),
])
combo_tbl.setStyle(combo_style)
story.append(combo_tbl)
story.append(sp(3))
# ─── FINAL PAGE: QUICK REFERENCE SUMMARY ──────────────────────────────────────
story.append(section_header("10. QUICK REFERENCE SUMMARY", color=NAVY))
story.append(sp(2))
summary_rows = [
("Drug class", "Phosphonic acid antibiotic — unique class, no structural relatives"),
("Mechanism", "Irreversible MurA inhibitor → blocks peptidoglycan synthesis (step 1)"),
("Bactericidal?", "Yes — concentration-dependent killing"),
("Oral dose", "3 g single dose (tromethamine salt, granules dissolved in water)"),
("Oral bioavailability","~40%"),
("Peak urinary conc.", "1,000–4,000 µg/mL (maintained up to 48 h)"),
("t½", "5–8 h (oral); 4–8 h (IV)"),
("Protein binding", "Negligible — 100% free drug"),
("Metabolism", "None — excreted unchanged in urine"),
("Spectrum highlights", "E. coli, Proteus, Enterococcus (incl. VRE), MRSA, ESBL-producers"),
("Resistant organisms", "Pseudomonas, Acinetobacter, Burkholderia (intrinsic)"),
("FDA indications", "Uncomplicated cystitis (oral, 1996) | cUTI / Pyelonephritis (IV, Oct 2025)"),
("Key ADRs", "GI upset, headache, dizziness, vaginitis; sodium load (IV)"),
("Key interaction", "Metoclopramide → decreased absorption"),
("Pregnancy safety", "Category B — oral single-dose widely used in pregnancy"),
("Resistance warning", "Use IV only in COMBINATION to prevent resistance emergence"),
]
story.append(two_col_table(summary_rows, col1w=48*mm))
story.append(sp(3))
story.append(warning_box(
"ALWAYS confirm susceptibility before use. Fosfomycin resistance is increasing in "
"nosocomial settings. For IV therapy, use in combination and monitor renal function / "
"electrolytes regularly."
))
story.append(sp(2))
story.append(HRFlowable(width="100%", thickness=1, color=NAVY))
story.append(sp(2))
story.append(Paragraph(
"<b>References:</b> Harrison's Principles of Internal Medicine 22E (2025) | "
"Goodman & Gilman's Pharmacological Basis of Therapeutics | "
"Lippincott Illustrated Reviews: Pharmacology | Rosen's Emergency Medicine | "
"Merck Manual Professional Apr 2025 | Drugs.com Monograph Dec 2025 | "
"Kim & Lees, <i>Biochemistry</i> 2025 (PMID 40127436) | "
"Cai et al., <i>Int J Antimicrob Agents</i> 2023 (PMID 37748624)",
SMALL
))
story.append(sp(1))
story.append(Paragraph(
"<i>This reference is for educational and clinical support purposes. "
"Always verify doses and guidelines against current institutional protocols "
"and up-to-date prescribing information.</i>",
NOTE_ST
))
# ── Page numbering callback ────────────────────────────────────────────────────
def add_page_number(canvas, doc):
canvas.saveState()
# Footer bar
canvas.setFillColor(NAVY)
canvas.rect(0, 0, PAGE_W, 10*mm, fill=1, stroke=0)
canvas.setFillColor(WHITE)
canvas.setFont("Helvetica", 7)
canvas.drawCentredString(PAGE_W/2, 3.5*mm,
f"FOSFOMYCIN POCKET REFERENCE | Page {doc.page} | Clinical Use Only")
# Header stripe (pages 2+)
if doc.page > 1:
canvas.setFillColor(LIGHT_BLUE)
canvas.rect(0, PAGE_H - 8*mm, PAGE_W, 8*mm, fill=1, stroke=0)
canvas.setFillColor(NAVY)
canvas.setFont("Helvetica-Bold", 7)
canvas.drawString(MARGIN, PAGE_H - 5*mm, "FOSFOMYCIN — Pocket Clinical Reference")
canvas.drawRightString(PAGE_W - MARGIN, PAGE_H - 5*mm,
"August 2026")
canvas.restoreState()
# ── Build ─────────────────────────────────────────────────────────────────────
doc.build(story, onFirstPage=add_page_number, onLaterPages=add_page_number)
print(f"PDF generated: {OUTPUT}")
print(f"Size: {os.path.getsize(OUTPUT):,} bytes")