Create a single-page, ultra-HD medical infographic titled: MODIFIED JONES CRITERIA for ACUTE RHEUMATIC FEVER (ARF) Design style: Premium medical textbook infographic White background with subtle blue/red accents High-resolution realistic medical illustrations (NOT cartoons, emojis, or clipart) Professional typography Color-coded sections Suitable for NEET PG, INICET, FMGE revision Easy to revise in under one minute A4 portrait (300 DPI) Symmetrical layout similar to premium medical posters. TOP HEADER Large title: MODIFIED JONES CRITERIA for ACUTE RHEUMATIC FEVER Center: Large realistic anatomical heart showing inflamed mitral valve. Small sticky note: Group A Streptococcal pharyngitis → Autoimmune reaction → Heart, Joints, Brain, Skin LEFT TOP BOX DIAGNOSIS OF ARF Diagnosis requires: Evidence of preceding Group A Streptococcal infection PLUS Either 2 Major OR 1 Major + 2 Minor Special note: Different criteria for • Low-risk population • Moderate/high-risk population RIGHT TOP BOX MEMORY TRICK Think of ❤️ J❤️NES 5 MAJOR HEROES ❤️ Heart 🦵 Joint 🧠 Brain 👋 Skin 👀 Nodules (Major Criteria) 4 SUPPORTERS (Minor) 🌡 Fever 🩸 ESR/CRP ❤️ PR interval 🦵 Arthralgia Simple mnemonic at bottom: "Heart-Joint-Brain-Skin-Nodules" MIDDLE SECTION MAJOR CRITERIA (5) Use realistic medical illustrations beside every point. 1 CARDITIS ❤️ Illustration: Realistic inflamed heart Mitral regurgitation Doppler echo Valve vegetation-free rheumatic valve Include: • Clinical carditis • Subclinical carditis (Echo) • Pancarditis Small icons: Mitral regurgitation Aortic regurgitation Pericarditis Heart failure 2 MIGRATORY POLYARTHRITIS Illustration: Inflamed knees Ankles Elbows Wrists Show arrows indicating migration. Mention: Large joints Migratory Painful Responds dramatically to aspirin 3 CHOREA (Sydenham chorea) Illustration: Young child with involuntary movements Brain highlighting basal ganglia Mention: Late manifestation Emotional lability Milkmaid grip Pronator sign 4 ERYTHEMA MARGINATUM Illustration: Realistic skin lesion Annular pink rash Central clearing Non-pruritic On trunk 5 SUBCUTANEOUS NODULES Illustration: Firm nodules over Elbows Achilles tendon Spine Mention: Painless Firm Attached to tendon Associated with severe carditis LOWER SECTION MINOR CRITERIA (4) Fever Illustration: Thermometer (>38°C) Arthralgia Illustration: Painful knee joint Mention: Without objective arthritis Raised ESR / CRP Illustration: Test tubes Inflammatory markers graph Prolonged PR Interval Illustration: Real ECG strip Highlight prolonged PR interval PRECEDING STREPTOCOCCAL INFECTION Large highlighted box Realistic throat infection Blood sample Include: Positive throat culture Rapid antigen test Raised ASO titre Raised Anti-DNase B Recent scarlet fever SIDE PANEL COMMONLY AFFECTED VALVES Large realistic heart Highlight Mitral (Most common) ↓ Aortic ↓ Tricuspid (Rare) CLINICAL PEARLS • Mitral valve most commonly affected • Chorea may occur months later • Echo detects subclinical carditis • Arthritis improves rapidly with salicylates • Secondary prophylaxis is essential MEMORY FLOW Strep throat ↓ Autoimmune response ↓ Heart ↓ Joints ↓ Brain ↓ Skin DIFFERENTIAL FEATURES Small comparison table ARF vs Infective Endocarditis Carditis Vegetation Blood culture ASO titre Valve damage KEY POINTS TO REMEMBER • Evidence of recent GAS infection mandatory • 2 Major OR 1 Major + 2 Minor • Echo counts as carditis • Jones Criteria revised by AHA • Secondary benzathine penicillin prophylaxis prevents recurrence FOOTER HIGH-YIELD NEET PG FACTS ⭐ Mitral valve most common ⭐ Sydenham chorea = delayed manifestation ⭐ Erythema marginatum = uncommon but specific ⭐ Subcutaneous nodules = severe carditis ⭐ Elevated ASO alone does NOT diagnose ARF ⭐ Remember: JONES = Heart • Joint • Brain • Skin • Nodules STYLE REQUIREMENTS Use realistic anatomical illustrations, histopathology, echocardiography, ECG strips, throat infection images, and joint inflammation images. Do not use emojis, cartoons, anime, or clipart. Clean white background with red and blue medical color theme. Premium medical infographic quality suitable for NEET PG, INICET, FMGE, readable at a glance, and printable on a single A4 page.

Running Command

mkdir -p /tmp/workspace/jones-criteria && ls /tmp/workspace/jones-criteria/

Writing File

~/jones-criteria/build_infographic.py

"""
Modified Jones Criteria – Ultra-HD Medical Infographic
A4 portrait @ 300 DPI  →  2480 × 3508 px
Pure Pillow + drawing primitives (no external images required)
"""

from PIL import Image, ImageDraw, ImageFont
import textwrap, math, os, sys

# ─────────────────────────────────────────────
#  CANVAS
# ─────────────────────────────────────────────
W, H = 2480, 3508          # A4 @ 300 DPI
SCALE = W / 794            # 1 pt  →  ~3.12 px  (reference 72-dpi A4 = 595×842 pt)

img  = Image.new("RGB", (W, H), "#FFFFFF")
draw = ImageDraw.Draw(img)

# ─────────────────────────────────────────────
#  COLOUR PALETTE
# ─────────────────────────────────────────────
C = {
    "header_bg"     : "#0D2B5E",   # deep navy
    "header_accent" : "#B71C1C",   # rich crimson
    "major_bg"      : "#E8F0FB",   # soft sky-blue tint
    "major_border"  : "#1565C0",   # royal blue
    "minor_bg"      : "#FFF3E0",   # warm amber tint
    "minor_border"  : "#E65100",   # deep orange
    "strep_bg"      : "#FCE4EC",   # pale rose
    "strep_border"  : "#B71C1C",
    "pearl_bg"      : "#F3F8FF",
    "pearl_border"  : "#0D47A1",
    "footer_bg"     : "#0D2B5E",
    "gold"          : "#F9A825",
    "text_dark"     : "#0A0A0A",
    "text_mid"      : "#1A237E",
    "text_muted"    : "#4A4A6A",
    "white"         : "#FFFFFF",
    "red"           : "#C62828",
    "blue"          : "#1565C0",
    "green"         : "#1B5E20",
    "orange"        : "#E65100",
    "divider"       : "#CFD8DC",
    "sub_bg"        : "#F5F9FF",
}

# ─────────────────────────────────────────────
#  FONT LOADER  (falls back to default gracefully)
# ─────────────────────────────────────────────
def load_font(size, bold=False, italic=False):
    candidates = []
    if bold and italic:
        candidates = [
            "/usr/share/fonts/truetype/dejavu/DejaVuSans-BoldOblique.ttf",
            "/usr/share/fonts/truetype/liberation/LiberationSans-BoldItalic.ttf",
        ]
    elif bold:
        candidates = [
            "/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf",
            "/usr/share/fonts/truetype/liberation/LiberationSans-Bold.ttf",
            "/usr/share/fonts/truetype/freefont/FreeSansBold.ttf",
        ]
    elif italic:
        candidates = [
            "/usr/share/fonts/truetype/dejavu/DejaVuSans-Oblique.ttf",
            "/usr/share/fonts/truetype/liberation/LiberationSans-Italic.ttf",
        ]
    else:
        candidates = [
            "/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf",
            "/usr/share/fonts/truetype/liberation/LiberationSans-Regular.ttf",
            "/usr/share/fonts/truetype/freefont/FreeSans.ttf",
        ]
    for path in candidates:
        if os.path.exists(path):
            try:
                return ImageFont.truetype(path, size)
            except Exception:
                pass
    return ImageFont.load_default()

# Pre-load common sizes
F = {
    "title"    : load_font(88, bold=True),
    "subtitle" : load_font(52, bold=True),
    "section"  : load_font(58, bold=True),
    "subsect"  : load_font(46, bold=True),
    "body"     : load_font(38),
    "body_b"   : load_font(38, bold=True),
    "small"    : load_font(32),
    "small_b"  : load_font(32, bold=True),
    "tiny"     : load_font(26),
    "tiny_b"   : load_font(26, bold=True),
    "micro"    : load_font(22),
    "hero"     : load_font(120, bold=True),
}

# ─────────────────────────────────────────────
#  HELPERS
# ─────────────────────────────────────────────
def px(pt):   return int(pt * SCALE)
def col(hex): return hex

def rounded_rect(draw, xy, radius, fill=None, outline=None, width=3):
    x0,y0,x1,y1 = xy
    r = radius
    if fill:
        draw.rectangle([x0+r, y0, x1-r, y1], fill=fill)
        draw.rectangle([x0, y0+r, x1, y1-r], fill=fill)
        draw.ellipse([x0, y0, x0+2*r, y0+2*r], fill=fill)
        draw.ellipse([x1-2*r, y0, x1, y0+2*r], fill=fill)
        draw.ellipse([x0, y1-2*r, x0+2*r, y1], fill=fill)
        draw.ellipse([x1-2*r, y1-2*r, x1, y1], fill=fill)
    if outline:
        draw.arc([x0, y0, x0+2*r, y0+2*r], 180, 270, fill=outline, width=width)
        draw.arc([x1-2*r, y0, x1, y0+2*r], 270, 0,   fill=outline, width=width)
        draw.arc([x0, y1-2*r, x0+2*r, y1], 90,  180, fill=outline, width=width)
        draw.arc([x1-2*r, y1-2*r, x1, y1], 0,   90,  fill=outline, width=width)
        draw.line([x0+r, y0, x1-r, y0], fill=outline, width=width)
        draw.line([x0+r, y1, x1-r, y1], fill=outline, width=width)
        draw.line([x0, y0+r, x0, y1-r], fill=outline, width=width)
        draw.line([x1, y0+r, x1, y1-r], fill=outline, width=width)

def text_center(draw, x, y, text, font, fill, max_width=None):
    if max_width:
        # wrap & center each line
        avg_ch = font.getbbox("A")[2]
        chars  = max(1, max_width // max(1,avg_ch))
        lines  = textwrap.wrap(text, chars)
    else:
        lines = [text]
    line_h = font.getbbox("Ag")[3] + 6
    for i, line in enumerate(lines):
        bb = draw.textbbox((0,0), line, font=font)
        w  = bb[2]-bb[0]
        draw.text((x - w//2, y + i*line_h), line, font=font, fill=fill)
    return len(lines)*line_h

def text_left(draw, x, y, text, font, fill, max_width=None, line_spacing=8):
    if max_width:
        avg_ch = max(1, font.getbbox("A")[2])
        chars  = max(1, max_width // avg_ch)
        lines  = textwrap.wrap(text, chars)
    else:
        lines = [text]
    line_h = font.getbbox("Ag")[3] + line_spacing
    for i, line in enumerate(lines):
        draw.text((x, y + i*line_h), line, font=font, fill=fill)
    return len(lines)*line_h

def bullet(draw, x, y, text, font, fill, bullet_col, bsize=18, max_width=None, line_spacing=8):
    draw.ellipse([x, y+8, x+bsize, y+8+bsize], fill=bullet_col)
    return text_left(draw, x+bsize+12, y, text, font, fill, max_width, line_spacing)

# ─────────────────────────────────────────────
#  MEDICAL ILLUSTRATION HELPERS
# ─────────────────────────────────────────────
def draw_heart(draw, cx, cy, size, fill_col="#C62828", outline_col="#7B0000", detail=True):
    """Draw a stylised anatomical heart."""
    s = size
    # Two lobes (ellipses) + bottom triangle
    draw.ellipse([cx-s, cy-s*0.7, cx,    cy+s*0.3], fill=fill_col)
    draw.ellipse([cx,   cy-s*0.7, cx+s,  cy+s*0.3], fill=fill_col)
    draw.polygon([cx-s, cy+s*0.1, cx+s, cy+s*0.1, cx, cy+s*1.1], fill=fill_col)
    if detail:
        # Aorta stub
        draw.rectangle([cx-s*0.15, cy-s*1.0, cx+s*0.15, cy-s*0.65], fill="#8B0000")
        # Pulmonary artery
        draw.rectangle([cx-s*0.35, cy-s*0.9, cx-s*0.05, cy-s*0.6], fill="#8B0000")
        # Highlight
        draw.ellipse([cx-s*0.5, cy-s*0.55, cx-s*0.1, cy-s*0.15], fill="#E57373")
    # Outline
    draw.ellipse([cx-s, cy-s*0.7, cx,    cy+s*0.3], outline=outline_col, width=4)
    draw.ellipse([cx,   cy-s*0.7, cx+s,  cy+s*0.3], outline=outline_col, width=4)

def draw_joint(draw, cx, cy, size, inflamed=True):
    """Draw an inflamed knee joint cross-section."""
    bone_col  = "#FFFDE7"
    carti_col = "#B3E5FC"
    syno_col  = "#EF9A9A" if inflamed else "#FFCCBC"
    # Femur
    draw.ellipse([cx-size*0.55, cy-size*1.0, cx+size*0.55, cy-size*0.1], fill=bone_col, outline="#9E9E9E", width=3)
    # Cartilage
    draw.ellipse([cx-size*0.4, cy-size*0.18, cx+size*0.4, cy+size*0.08], fill=carti_col)
    # Joint space (inflamed synovium)
    draw.ellipse([cx-size*0.45, cy-size*0.05, cx+size*0.45, cy+size*0.15], fill=syno_col)
    # Tibia
    draw.ellipse([cx-size*0.5, cy+size*0.1, cx+size*0.5, cy+size*1.0],  fill=bone_col, outline="#9E9E9E", width=3)
    if inflamed:
        # Redness lines
        for i in range(-2,3):
            draw.line([cx+i*size*0.1, cy-size*0.05, cx+i*size*0.08, cy+size*0.15],
                      fill="#C62828", width=2)

def draw_brain(draw, cx, cy, size):
    """Simple stylised brain with basal ganglia highlight."""
    # Cerebrum
    draw.ellipse([cx-size, cy-size*0.7, cx+size, cy+size*0.5], fill="#FFCCBC", outline="#BF360C", width=3)
    # Midline sulcus
    draw.line([cx, cy-size*0.7, cx, cy+size*0.5], fill="#BF360C", width=3)
    # Gyri lines L
    for yi in [0.1, 0.3, -0.2]:
        draw.arc([cx-size*0.9, cy+yi*size, cx-size*0.1, cy+(yi+0.25)*size], 200, 340, fill="#BF360C", width=2)
    # Gyri lines R
    for yi in [0.1, 0.3, -0.2]:
        draw.arc([cx+size*0.1, cy+yi*size, cx+size*0.9, cy+(yi+0.25)*size], 200, 340, fill="#BF360C", width=2)
    # Basal ganglia highlight (golden)
    draw.ellipse([cx-size*0.35, cy-size*0.1, cx+size*0.35, cy+size*0.35], fill="#F9A825", outline="#E65100", width=3)
    # Brainstem
    draw.rectangle([cx-size*0.2, cy+size*0.45, cx+size*0.2, cy+size*0.85], fill="#FFAB91", outline="#BF360C", width=2)

def draw_skin_lesion(draw, cx, cy, size):
    """Erythema marginatum – annular pink rash."""
    # Outer ring
    draw.ellipse([cx-size, cy-size*0.6, cx+size, cy+size*0.6], fill="#FFCDD2", outline="#E91E63", width=6)
    # Middle ring (lighter)
    draw.ellipse([cx-size*0.65, cy-size*0.38, cx+size*0.65, cy+size*0.38], fill="#FCE4EC", outline="#F48FB1", width=4)
    # Central clear area
    draw.ellipse([cx-size*0.3, cy-size*0.18, cx+size*0.3, cy+size*0.18], fill="#FFF9F9")
    # Margins irregular
    for angle in range(0, 360, 30):
        a = math.radians(angle)
        rx, ry = size*0.9*math.cos(a), size*0.55*math.sin(a)
        draw.ellipse([cx+rx-14, cy+ry-10, cx+rx+14, cy+ry+10], fill="#E91E63")

def draw_nodule(draw, cx, cy, size):
    """Subcutaneous nodule over a tendon."""
    # Bone/tendon
    draw.rectangle([cx-size*0.15, cy-size*0.8, cx+size*0.15, cy+size*0.8], fill="#FFFDE7", outline="#9E9E9E", width=3)
    # Tendon fibres
    for i in range(-2,3):
        draw.line([cx+i*size*0.03, cy-size*0.8, cx+i*size*0.03, cy+size*0.8], fill="#FFF9C4", width=2)
    # Nodule
    draw.ellipse([cx-size*0.55, cy-size*0.3, cx+size*0.55, cy+size*0.3],
                 fill="#FFDEAD", outline="#8D6E63", width=4)
    # Fibrous texture
    for i in range(-2,3):
        draw.line([cx-size*0.4+i*size*0.15, cy-size*0.25, cx-size*0.4+i*size*0.15, cy+size*0.25],
                  fill="#A1887F", width=2)

def draw_thermometer(draw, cx, cy, h, w=30):
    """Simple thermometer."""
    # Bulb
    draw.ellipse([cx-w, cy+h*0.5, cx+w, cy+h*0.5+w*2], fill="#C62828")
    # Tube
    draw.rectangle([cx-w*0.5, cy, cx+w*0.5, cy+h*0.5+w], fill="#FFCDD2", outline="#C62828", width=3)
    # Mercury
    draw.rectangle([cx-w*0.35, cy+h*0.25, cx+w*0.35, cy+h*0.5+w], fill="#C62828")
    # Scale marks
    for i in range(4):
        y = cy + h*0.05 + i*h*0.06
        draw.line([cx+w*0.5, y, cx+w*0.9, y], fill="#424242", width=3)

def draw_ecg_strip(draw, x0, y0, width, height, color="#1565C0", pr_long=True):
    """Sketch an ECG strip with PR interval highlighted."""
    bg_x1 = x0+width; bg_y1 = y0+height
    draw.rectangle([x0, y0, bg_x1, bg_y1], fill="#F8FFFE", outline="#90CAF9", width=3)
    # Grid lines
    for gx in range(x0+30, bg_x1, 30):
        draw.line([gx, y0+4, gx, bg_y1-4], fill="#BBDEFB", width=1)
    for gy in range(y0+20, bg_y1, 20):
        draw.line([x0+4, gy, bg_x1-4, gy], fill="#BBDEFB", width=1)

    mid_y  = y0 + height//2
    pts    = []
    x      = x0 + 20
    # Flat baseline
    pts += [(x, mid_y), (x+30, mid_y)]
    x    = x+30
    # P wave
    pts += [(x, mid_y), (x+15, mid_y-22), (x+30, mid_y)]
    x   += 30
    # PR segment (long if requested)
    pr_len = 90 if pr_long else 50
    pts += [(x, mid_y), (x+pr_len, mid_y)]
    pr_start = x; pr_end = x+pr_len
    x  += pr_len
    # QRS
    pts += [(x, mid_y), (x+6, mid_y+15), (x+12, mid_y-60), (x+18, mid_y+8), (x+24, mid_y)]
    x  += 24
    # ST segment
    pts += [(x, mid_y), (x+20, mid_y)]
    x  += 20
    # T wave
    pts += [(x, mid_y), (x+10, mid_y-28), (x+25, mid_y-32), (x+40, mid_y)]
    x  += 40
    # Flat
    pts += [(x, mid_y), (x+30, mid_y)]

    draw.line(pts, fill=color, width=4)
    # Highlight PR interval
    if pr_long:
        draw.rectangle([pr_start, mid_y-30, pr_end, mid_y+8], outline="#E53935", width=3)

def draw_test_tube(draw, cx, cy, h, w, fill_col="#EF9A9A"):
    """Test tube."""
    draw.rectangle([cx-w, cy, cx+w, cy+h*0.8], fill=fill_col, outline="#757575", width=3)
    draw.ellipse([cx-w, cy+h*0.7, cx+w, cy+h+8], fill=fill_col, outline="#757575", width=3)
    draw.rectangle([cx-w*1.3, cy-8, cx+w*1.3, cy+6], fill="#B0BEC5", outline="#607D8B", width=2)

def draw_throat(draw, cx, cy, size):
    """Simplified inflamed throat / tonsils."""
    # Mouth opening
    draw.ellipse([cx-size, cy-size*0.4, cx+size, cy+size*0.4], fill="#FFCCBC", outline="#BF360C", width=4)
    # Uvula
    draw.ellipse([cx-size*0.12, cy-size*0.05, cx+size*0.12, cy+size*0.35], fill="#EF9A9A", outline="#C62828", width=3)
    # Tonsils (inflamed)
    draw.ellipse([cx-size*0.8, cy-size*0.2, cx-size*0.25, cy+size*0.25], fill="#EF5350", outline="#B71C1C", width=4)
    draw.ellipse([cx+size*0.25, cy-size*0.2, cx+size*0.8,  cy+size*0.25], fill="#EF5350", outline="#B71C1C", width=4)
    # Exudate dots
    for dx,dy in [(-0.55, 0.0), (0.55, 0.0), (-0.52, -0.1), (0.52, -0.1)]:
        draw.ellipse([cx+dx*size-7, cy+dy*size-7, cx+dx*size+7, cy+dy*size+7], fill="#FFEE58")

def draw_arrow_down(draw, cx, y_top, length, col="#1565C0", width=6):
    draw.line([cx, y_top, cx, y_top+length], fill=col, width=width)
    draw.polygon([cx-14, y_top+length-18, cx+14, y_top+length-18, cx, y_top+length+4], fill=col)

def draw_badge(draw, x, y, w, h, text, bg, fg, font, radius=20):
    rounded_rect(draw, [x, y, x+w, y+h], radius, fill=bg, outline=None)
    text_center(draw, x+w//2, y+(h-font.getbbox("A")[3])//2, text, font, fg)

# ─────────────────────────────────────────────
#  LAYOUT CONSTANTS
# ─────────────────────────────────────────────
MARGIN   = 48
GUTTER   = 28

# Column splits
LEFT_W   = int(W * 0.62)   # main content
RIGHT_W  = W - LEFT_W - MARGIN*2 - GUTTER

# Section Y positions
HEADER_H = 310
DIAG_Y   = HEADER_H + 10
DIAG_H   = 310
MAJOR_Y  = DIAG_Y + DIAG_H + 8
MAJOR_H  = 1380
MINOR_Y  = MAJOR_Y + MAJOR_H + 8
MINOR_H  = 420
STREP_Y  = MINOR_Y + MINOR_H + 8
STREP_H  = 270
FOOTER_Y = STREP_Y + STREP_H + 8
FOOTER_H = H - FOOTER_Y - 0

# Right panel Y splits
RP_X     = MARGIN + LEFT_W + GUTTER
RP_W     = RIGHT_W
RP_TRICK_Y = HEADER_H + 10
RP_TRICK_H = 660
RP_VALVE_Y = RP_TRICK_Y + RP_TRICK_H + 8
RP_VALVE_H = 430
RP_PEARL_Y = RP_VALVE_Y + RP_VALVE_H + 8
RP_PEARL_H = 370
RP_FLOW_Y  = RP_PEARL_Y + RP_PEARL_H + 8
RP_FLOW_H  = 310
RP_DIFF_Y  = RP_FLOW_Y + RP_FLOW_H + 8
RP_DIFF_H  = H - RP_DIFF_Y - (H - FOOTER_Y) - 8

# ═══════════════════════════════════════════════
#  ① HEADER
# ═══════════════════════════════════════════════
# Background gradient-like effect (two rectangles)
draw.rectangle([0, 0, W, HEADER_H], fill=C["header_bg"])
draw.rectangle([0, HEADER_H-8, W, HEADER_H], fill=C["header_accent"])

# Red accent stripe at top
draw.rectangle([0, 0, W, 16], fill=C["header_accent"])

# Title text
text_center(draw, W//2, 22,  "MODIFIED JONES CRITERIA", F["title"], C["white"])
text_center(draw, W//2, 116, "for  ACUTE RHEUMATIC FEVER  (ARF)", F["subtitle"], "#FFCDD2")

# Sub-tagline
text_center(draw, W//2, 182,
    "Group A Streptococcal Pharyngitis  →  Autoimmune Reaction  →  Heart  |  Joints  |  Brain  |  Skin",
    F["small"], "#90CAF9")

# Badge row
badges = [
    ("NEET PG", C["header_accent"]),
    ("INICET",  "#1565C0"),
    ("FMGE",    "#2E7D32"),
    ("USMLE",   "#6A1B9A"),
]
bw, bh = 180, 52
bx_start = W//2 - (len(badges)*bw + (len(badges)-1)*16)//2
for i,(label,bc) in enumerate(badges):
    bx = bx_start + i*(bw+16)
    draw_badge(draw, bx, 235, bw, bh, label, bc, C["white"], F["tiny_b"], radius=10)

# ═══════════════════════════════════════════════
#  ② DIAGNOSIS BOX  (left top)
# ═══════════════════════════════════════════════
DX = MARGIN
DY = DIAG_Y
DW = 780
DH = DIAG_H

rounded_rect(draw, [DX, DY, DX+DW, DY+DH], 24,
             fill=C["major_bg"], outline=C["major_border"], width=5)

# Title bar
rounded_rect(draw, [DX, DY, DX+DW, DY+62], 24,
             fill=C["major_border"])
draw.rectangle([DX+24, DY+24, DX+DW-24, DY+62], fill=C["major_border"])
text_center(draw, DX+DW//2, DY+12, "DIAGNOSIS OF ARF", F["subsect"], C["white"])

y = DY + 76
text_left(draw, DX+24, y,    "Evidence of preceding GAS infection  PLUS:", F["small_b"], C["red"])
y += 46
text_left(draw, DX+24, y,    "Either  [ 2 Major ]  OR  [ 1 Major + 2 Minor ]", F["body_b"], C["text_mid"])
y += 56
# Two sub-boxes
bw2 = (DW - 72)//2
for xi, (pop, bcol, bg) in enumerate([
        ("Low-Risk Population", "#1565C0", "#DCEEFB"),
        ("Moderate / High-Risk", "#B71C1C", "#FDECEA")]):
    bx2 = DX + 24 + xi*(bw2+24)
    rounded_rect(draw, [bx2, y, bx2+bw2, y+88], 14, fill=bg, outline=bcol, width=4)
    text_center(draw, bx2+bw2//2, y+8,  pop, F["small_b"], bcol, max_width=bw2-20)
y += 102
text_left(draw, DX+30, y, "  Different criteria thresholds apply for each population", F["tiny"], C["text_muted"])

# ─ Small heart illustration in diagnosis box ─
draw_heart(draw, DX+DW-110, DY+DH//2+20, 68)

# ═══════════════════════════════════════════════
#  ③ "JONES" MNEMONIC BOX  (centre-top, next to Dx)
# ═══════════════════════════════════════════════
MX = DX + DW + GUTTER
MY = DIAG_Y
MW = LEFT_W - DW - GUTTER
MH = DIAG_H

rounded_rect(draw, [MX, MY, MX+MW, MY+MH], 24,
             fill="#FFF8E1", outline=C["gold"], width=5)

# Header band
rounded_rect(draw, [MX, MY, MX+MW, MY+62], 24, fill=C["gold"])
draw.rectangle([MX+24, MY+24, MX+MW-24, MY+62], fill=C["gold"])
text_center(draw, MX+MW//2, MY+12, "JONES  MNEMONIC", F["subsect"], "#0D2B5E")

y = MY + 72
items = [
    ("J", "Joints (Migratory Polyarthritis)", C["blue"]),
    ("O", "cOrea (Sydenham Chorea)",          C["green"]),
    ("N", "Nodules (Subcutaneous)",            "#6A1B9A"),
    ("E", "Erythema Marginatum",               "#E65100"),
    ("S", "carditiS (Carditis)",               C["red"]),
]
for letter, meaning, color in items:
    draw.rectangle([MX+16, y-2, MX+58, y+36], fill=color)
    text_center(draw, MX+37, y, letter, F["body_b"], C["white"])
    text_left(draw, MX+68, y+2, meaning, F["small"], C["text_dark"])
    y += 44

# ═══════════════════════════════════════════════
#  ④ MAJOR CRITERIA
# ═══════════════════════════════════════════════
SEC_X = MARGIN
SEC_W = LEFT_W

rounded_rect(draw, [SEC_X, MAJOR_Y, SEC_X+SEC_W, MAJOR_Y+MAJOR_H], 28,
             fill=C["major_bg"], outline=C["major_border"], width=6)

# Section header
rounded_rect(draw, [SEC_X, MAJOR_Y, SEC_X+SEC_W, MAJOR_Y+72], 28,
             fill=C["major_border"])
draw.rectangle([SEC_X+28, MAJOR_Y+28, SEC_X+SEC_W-28, MAJOR_Y+72], fill=C["major_border"])
text_center(draw, SEC_X+SEC_W//2, MAJOR_Y+14,
            "★  MAJOR CRITERIA  (5)  — Any 2 required for diagnosis", F["section"], C["white"])

# ── 5 criteria laid out in 2 columns (3 left, 2 right) ──
COL1_X = SEC_X + 20
COL2_X = SEC_X + SEC_W//2 + 10
COL_W  = SEC_W//2 - 30
ROW_H  = 260

criteria = [
    {
        "num": "1",
        "title": "CARDITIS",
        "color": C["red"],
        "col": 0, "row": 0,
        "bullets": [
            "Clinical carditis (murmur, pericardial friction)",
            "Subclinical carditis detected by Echocardiography",
            "Pancarditis: endo + myo + pericardium",
            "Mitral regurgitation most common",
            "Aortic regurgitation in severe cases",
        ],
    },
    {
        "num": "2",
        "title": "MIGRATORY POLYARTHRITIS",
        "color": C["blue"],
        "col": 1, "row": 0,
        "bullets": [
            "Large joints: knees, ankles, elbows, wrists",
            "Migratory — moves joint to joint",
            "Acutely painful, red, swollen",
            "Responds dramatically to salicylates (aspirin)",
            "Does not cause permanent joint damage",
        ],
    },
    {
        "num": "3",
        "title": "SYDENHAM CHOREA",
        "color": "#2E7D32",
        "col": 0, "row": 1,
        "bullets": [
            "Involuntary purposeless movements",
            "Basal ganglia involvement",
            "Milkmaid grip, pronator sign",
            "Emotional lability",
            "Late manifestation — may appear weeks later",
        ],
    },
    {
        "num": "4",
        "title": "ERYTHEMA MARGINATUM",
        "color": C["orange"],
        "col": 1, "row": 1,
        "bullets": [
            "Annular / serpiginous pink rash",
            "Central clearing, non-pruritic",
            "Located on trunk & proximal limbs",
            "Evanescent — fleeting, heat-accentuated",
            "Uncommon but highly specific",
        ],
    },
    {
        "num": "5",
        "title": "SUBCUTANEOUS NODULES",
        "color": "#6A1B9A",
        "col": 0, "row": 2,
        "bullets": [
            "Firm, painless, 0.5–2 cm nodules",
            "Over bony prominences & tendons",
            "Elbows, knees, Achilles tendon, scalp",
            "Associated with severe carditis",
            "Histology: Aschoff nodules",
        ],
    },
]

ILLUS_W = 170
illus_fns = [
    lambda cx,cy: draw_heart(draw, cx, cy, 68),
    lambda cx,cy: draw_joint(draw, cx, cy, 62),
    lambda cx,cy: draw_brain(draw, cx, cy, 60),
    lambda cx,cy: draw_skin_lesion(draw, cx, cy, 65),
    lambda cx,cy: draw_nodule(draw, cx, cy, 60),
]

for idx, cr in enumerate(criteria):
    col_x = COL1_X if cr["col"]==0 else COL2_X
    row_y = MAJOR_Y + 80 + cr["row"]*(ROW_H + 10)
    bx    = col_x
    by    = row_y
    bw3   = COL_W
    bh3   = ROW_H

    # Card background
    rounded_rect(draw, [bx, by, bx+bw3, by+bh3], 16,
                 fill=C["white"], outline=cr["color"], width=4)

    # Number badge
    draw.ellipse([bx+10, by+8, bx+62, by+60], fill=cr["color"])
    text_center(draw, bx+36, by+14, cr["num"], F["subsect"], C["white"])

    # Title
    text_left(draw, bx+72, by+14, cr["title"], F["small_b"], cr["color"])

    # Illustration
    illus_cx = bx + bw3 - ILLUS_W//2 - 12
    illus_cy = by + bh3//2 + 10
    illus_fns[idx](illus_cx, illus_cy)

    # Bullet points
    ty = by + 66
    for bull in cr["bullets"]:
        h = bullet(draw, bx+14, ty, bull, F["tiny"], C["text_dark"],
                   cr["color"], bsize=14, max_width=bw3-ILLUS_W-40)
        ty += h + 4
        if ty > by + bh3 - 18:
            break

# Last criterion (row 2, col 0 only) — we need to note it spans
# Nothing extra needed since idx=4 col=0 row=2 is placed above

# ═══════════════════════════════════════════════
#  ⑤ MINOR CRITERIA
# ═══════════════════════════════════════════════
MIN_X = MARGIN
MIN_W = LEFT_W

rounded_rect(draw, [MIN_X, MINOR_Y, MIN_X+MIN_W, MINOR_Y+MINOR_H], 28,
             fill=C["minor_bg"], outline=C["minor_border"], width=6)

rounded_rect(draw, [MIN_X, MINOR_Y, MIN_X+MIN_W, MINOR_Y+68], 28,
             fill=C["minor_border"])
draw.rectangle([MIN_X+28, MINOR_Y+28, MIN_X+MIN_W-28, MINOR_Y+68], fill=C["minor_border"])
text_center(draw, MIN_X+MIN_W//2, MINOR_Y+12,
            "▼  MINOR CRITERIA  (4)  — 2 required when combined with 1 Major", F["section"], C["white"])

minor_items = [
    {
        "title": "FEVER  >38°C",
        "color": C["red"],
        "note": "Acute onset febrile illness",
        "illus": lambda cx,cy: draw_thermometer(draw, cx, cy, 90, 22),
    },
    {
        "title": "ARTHRALGIA",
        "color": C["blue"],
        "note": "Joint pain WITHOUT objective signs\n(cannot use if arthritis = Major)",
        "illus": lambda cx,cy: draw_joint(draw, cx, cy, 48, inflamed=False),
    },
    {
        "title": "RAISED ESR / CRP",
        "color": "#2E7D32",
        "note": "ESR ≥60 mm/hr  |  CRP ≥3 mg/dL\nElevated acute-phase reactants",
        "illus": lambda cx,cy: (draw_test_tube(draw, cx-35, cy-40, 70, 14, "#EF9A9A"),
                                 draw_test_tube(draw, cx+5, cy-40, 70, 14, "#EF9A9A")),
    },
    {
        "title": "PROLONGED PR INTERVAL",
        "color": C["orange"],
        "note": "PR >200 ms on ECG\n(cannot use if carditis = Major)",
        "illus": lambda cx,cy: draw_ecg_strip(draw, cx-90, cy-38, 180, 76, color=C["orange"], pr_long=True),
    },
]

MCOL_W = (MIN_W - 60)//4
for i, mi in enumerate(minor_items):
    mx = MIN_X + 20 + i*(MCOL_W + 13)
    my = MINOR_Y + 78
    mh = MINOR_H - 90

    rounded_rect(draw, [mx, my, mx+MCOL_W, my+mh], 14,
                 fill=C["white"], outline=mi["color"], width=4)

    # Title bar
    rounded_rect(draw, [mx, my, mx+MCOL_W, my+48], 14, fill=mi["color"])
    draw.rectangle([mx+14, my+14, mx+MCOL_W-14, my+48], fill=mi["color"])
    text_center(draw, mx+MCOL_W//2, my+8, mi["title"], F["tiny_b"], C["white"])

    # Illustration
    mi["illus"](mx+MCOL_W//2, my+mh//2+14)

    # Note
    ty = my + mh - 85
    text_left(draw, mx+10, ty, mi["note"], F["tiny"], C["text_muted"],
              max_width=MCOL_W-20, line_spacing=6)

# ═══════════════════════════════════════════════
#  ⑥ PRECEDING STREP INFECTION
# ═══════════════════════════════════════════════
ST_X = MARGIN
ST_W = LEFT_W

rounded_rect(draw, [ST_X, STREP_Y, ST_X+ST_W, STREP_Y+STREP_H], 24,
             fill=C["strep_bg"], outline=C["strep_border"], width=6)

rounded_rect(draw, [ST_X, STREP_Y, ST_X+ST_W, STREP_Y+64], 24, fill=C["strep_border"])
draw.rectangle([ST_X+28, STREP_Y+28, ST_X+ST_W-28, STREP_Y+64], fill=C["strep_border"])
text_center(draw, ST_X+ST_W//2, STREP_Y+12,
            "MANDATORY: Evidence of Preceding Group A Streptococcal Infection", F["subsect"], C["white"])

strep_cols = [
    ("Positive Throat Culture\nfor GAS", C["red"]),
    ("Elevated ASO Titre\n(Anti-Streptolysin O)", "#1565C0"),
    ("Elevated Anti-DNase B\ntitres", "#2E7D32"),
    ("Rapid Strep Antigen\nTest positive", "#6A1B9A"),
    ("Recent Scarlet Fever\nhistory", C["orange"]),
]
sw = (ST_W - 60)//len(strep_cols)
for i,(label,sc) in enumerate(strep_cols):
    sx = ST_X + 24 + i*(sw+8)
    sy = STREP_Y + 74
    sh = STREP_H - 90
    rounded_rect(draw, [sx, sy, sx+sw, sy+sh], 12, fill=C["white"], outline=sc, width=4)
    if i == 0:
        draw_throat(draw, sx+sw//2, sy+sh//2-18, 44)
    elif i in [1,2]:
        draw_test_tube(draw, sx+sw//2, sy+12, 60, 14, fill_col="#EF9A9A" if i==1 else "#C8E6C9")
    text_center(draw, sx+sw//2, sy+sh-62, label, F["tiny"], sc, max_width=sw-12)

# ═══════════════════════════════════════════════
#  ⑦ RIGHT PANEL — MEMORY TRICK
# ═══════════════════════════════════════════════
rounded_rect(draw, [RP_X, RP_TRICK_Y, RP_X+RP_W, RP_TRICK_Y+RP_TRICK_H], 24,
             fill="#FFF8E1", outline=C["gold"], width=5)

rounded_rect(draw, [RP_X, RP_TRICK_Y, RP_X+RP_W, RP_TRICK_Y+60], 24, fill="#F57F17")
draw.rectangle([RP_X+20, RP_TRICK_Y+20, RP_X+RP_W-20, RP_TRICK_Y+60], fill="#F57F17")
text_center(draw, RP_X+RP_W//2, RP_TRICK_Y+10, "MEMORY TRICK", F["subsect"], C["white"])

y = RP_TRICK_Y + 68
text_center(draw, RP_X+RP_W//2, y, "Think of  J-O-N-E-S", F["body_b"], "#E65100")
y += 50

major_heros = [
    ("CARDITIS",         C["red"],     "Heart murmur / Echo"),
    ("ARTHRITIS",        C["blue"],    "Migratory, large joints"),
    ("CHOREA",           "#2E7D32",    "Basal ganglia"),
    ("ERYTHEMA MARG.",   C["orange"],  "Trunk rash"),
    ("SC NODULES",       "#6A1B9A",    "Over tendons"),
]
text_center(draw, RP_X+RP_W//2, y, "5 MAJOR CRITERIA", F["small_b"], C["text_mid"])
y += 36
for mh_name, mh_col, mh_note in major_heros:
    rounded_rect(draw, [RP_X+14, y, RP_X+RP_W-14, y+52], 10, fill=mh_col)
    text_center(draw, RP_X+RP_W//2, y+4,   mh_name, F["small_b"], C["white"])
    text_center(draw, RP_X+RP_W//2, y+28,  mh_note, F["tiny"],    "#FFECB3")
    y += 58

y += 6
text_center(draw, RP_X+RP_W//2, y, "4 MINOR CRITERIA", F["small_b"], C["text_mid"])
y += 34
for mitem, mcol in [("Fever >38°C", C["red"]), ("Arthralgia", C["blue"]),
                    ("Raised ESR/CRP", "#2E7D32"), ("Long PR interval", C["orange"])]:
    rounded_rect(draw, [RP_X+14, y, RP_X+RP_W-14, y+42], 8, fill=mcol)
    text_center(draw, RP_X+RP_W//2, y+8, mitem, F["small_b"], C["white"])
    y += 48

# ═══════════════════════════════════════════════
#  ⑧ RIGHT PANEL — VALVES
# ═══════════════════════════════════════════════
rounded_rect(draw, [RP_X, RP_VALVE_Y, RP_X+RP_W, RP_VALVE_Y+RP_VALVE_H], 24,
             fill=C["strep_bg"], outline=C["strep_border"], width=5)

rounded_rect(draw, [RP_X, RP_VALVE_Y, RP_X+RP_W, RP_VALVE_Y+58], 24, fill=C["strep_border"])
draw.rectangle([RP_X+20, RP_VALVE_Y+20, RP_X+RP_W-20, RP_VALVE_Y+58], fill=C["strep_border"])
text_center(draw, RP_X+RP_W//2, RP_VALVE_Y+8, "VALVE INVOLVEMENT", F["subsect"], C["white"])

draw_heart(draw, RP_X + RP_W//2, RP_VALVE_Y + 180, 75)

valves = [
    ("MITRAL",    "Most common  (90%)", C["red"],    RP_VALVE_Y+80),
    ("AORTIC",    "2nd  (combined MR)", C["blue"],   RP_VALVE_Y+148),
    ("TRICUSPID", "Rare",               C["orange"], RP_VALVE_Y+216),
    ("PULMONARY", "Extremely rare",     "#2E7D32",   RP_VALVE_Y+284),
]
for vname, vnote, vcol, vy in valves:
    draw.rectangle([RP_X+14, vy, RP_X+RP_W-14, vy+50], fill=vcol)
    text_left(draw, RP_X+20, vy+4,  vname, F["small_b"], C["white"])
    text_left(draw, RP_X+20, vy+26, vnote, F["tiny"],    "#FFECB3")
    draw_arrow_down(draw, RP_X+RP_W-30, vy+50, 20, col=vcol, width=4)

# ═══════════════════════════════════════════════
#  ⑨ RIGHT PANEL — CLINICAL PEARLS
# ═══════════════════════════════════════════════
rounded_rect(draw, [RP_X, RP_PEARL_Y, RP_X+RP_W, RP_PEARL_Y+RP_PEARL_H], 24,
             fill=C["pearl_bg"], outline=C["pearl_border"], width=5)

rounded_rect(draw, [RP_X, RP_PEARL_Y, RP_X+RP_W, RP_PEARL_Y+56], 24, fill=C["pearl_border"])
draw.rectangle([RP_X+20, RP_PEARL_Y+20, RP_X+RP_W-20, RP_PEARL_Y+56], fill=C["pearl_border"])
text_center(draw, RP_X+RP_W//2, RP_PEARL_Y+8, "CLINICAL PEARLS", F["subsect"], C["white"])

pearls = [
    "Mitral valve most commonly affected",
    "Chorea may appear weeks to months later",
    "Echo detects subclinical carditis",
    "Arthritis improves rapidly with salicylates",
    "Secondary prophylaxis (benzathine PCN) is essential",
    "Elevated ASO alone does NOT diagnose ARF",
]
py = RP_PEARL_Y + 64
for p in pearls:
    draw.ellipse([RP_X+18, py+6, RP_X+34, py+22], fill=C["gold"])
    text_left(draw, RP_X+40, py, p, F["tiny"], C["text_dark"], max_width=RP_W-50)
    py += 46

# ═══════════════════════════════════════════════
#  ⑩ RIGHT PANEL — PATHOGENESIS FLOW
# ═══════════════════════════════════════════════
rounded_rect(draw, [RP_X, RP_FLOW_Y, RP_X+RP_W, RP_FLOW_Y+RP_FLOW_H], 24,
             fill=C["sub_bg"], outline=C["major_border"], width=5)

rounded_rect(draw, [RP_X, RP_FLOW_Y, RP_X+RP_W, RP_FLOW_Y+54], 24, fill=C["major_border"])
draw.rectangle([RP_X+20, RP_FLOW_Y+20, RP_X+RP_W-20, RP_FLOW_Y+54], fill=C["major_border"])
text_center(draw, RP_X+RP_W//2, RP_FLOW_Y+8, "PATHOGENESIS FLOW", F["subsect"], C["white"])

flow_steps = [
    ("Strep Pharyngitis (GAS)",   C["red"]),
    ("Molecular Mimicry",         "#6A1B9A"),
    ("Autoimmune Response",       C["orange"]),
    ("Aschoff Body Formation",    C["blue"]),
    ("Carditis / ARF",            C["red"]),
]
fy = RP_FLOW_Y + 62
fh = (RP_FLOW_H - 70)//len(flow_steps) - 2
for fi,(fstep, fcol) in enumerate(flow_steps):
    rounded_rect(draw, [RP_X+18, fy, RP_X+RP_W-18, fy+fh], 10, fill=fcol)
    text_center(draw, RP_X+RP_W//2, fy+(fh-32)//2, fstep, F["tiny_b"], C["white"])
    fy += fh
    if fi < len(flow_steps)-1:
        draw_arrow_down(draw, RP_X+RP_W//2, fy, 10, col=fcol, width=5)
        fy += 12

# ═══════════════════════════════════════════════
#  ⑪ RIGHT PANEL — DIFFERENTIAL TABLE (ARF vs IE)
# ═══════════════════════════════════════════════
# Remaining space
DIFF_Y2 = RP_FLOW_Y + RP_FLOW_H + 8
DIFF_H2 = FOOTER_Y - DIFF_Y2 - 8

rounded_rect(draw, [RP_X, DIFF_Y2, RP_X+RP_W, DIFF_Y2+DIFF_H2], 24,
             fill="#FFFDE7", outline=C["gold"], width=5)

rounded_rect(draw, [RP_X, DIFF_Y2, RP_X+RP_W, DIFF_Y2+54], 24, fill="#F57F17")
draw.rectangle([RP_X+20, DIFF_Y2+20, RP_X+RP_W-20, DIFF_Y2+54], fill="#F57F17")
text_center(draw, RP_X+RP_W//2, DIFF_Y2+8, "ARF  vs  INFECTIVE ENDOCARDITIS", F["tiny_b"], C["white"])

headers = ["Feature", "ARF", "IE"]
col_ws  = [RP_W//3]*3
diff_rows = [
    ("Vegetation",    "Absent",       "Present"),
    ("Blood Culture", "Negative",     "Positive"),
    ("ASO titre",     "Elevated",     "Normal"),
    ("Valve damage",  "Regurgitation","Destruction"),
    ("Tx",            "Aspirin+PCN",  "Antibiotics"),
]
dy = DIFF_Y2 + 58
row_h2 = max(36, (DIFF_H2 - 64)//( len(diff_rows)+1 ))
for ci,(h,bc) in enumerate(zip(headers, [C["text_mid"], C["red"], C["blue"]])):
    cx2 = RP_X + ci*col_ws[ci]
    draw.rectangle([cx2+2, dy, cx2+col_ws[ci]-2, dy+row_h2], fill=bc)
    text_center(draw, cx2+col_ws[ci]//2, dy+4, h, F["tiny_b"], C["white"])
dy += row_h2
for ri, row in enumerate(diff_rows):
    bg3 = "#FFF9E3" if ri%2==0 else "#FFFDE7"
    for ci, cell in enumerate(row):
        cx2 = RP_X + ci*col_ws[ci]
        draw.rectangle([cx2+2, dy, cx2+col_ws[ci]-2, dy+row_h2], fill=bg3, outline=C["divider"])
        tcol = C["red"] if (ci==1 and ri<3) else C["blue"] if (ci==2 and ri<3) else C["text_dark"]
        text_center(draw, cx2+col_ws[ci]//2, dy+4, cell, F["tiny"], tcol)
    dy += row_h2

# ═══════════════════════════════════════════════
#  ⑫ FOOTER
# ═══════════════════════════════════════════════
draw.rectangle([0, FOOTER_Y, W, H], fill=C["footer_bg"])
draw.rectangle([0, FOOTER_Y, W, FOOTER_Y+6], fill=C["header_accent"])

fy2 = FOOTER_Y + 18
text_center(draw, W//2, fy2, "HIGH-YIELD  NEET PG  FACTS", F["subtitle"], C["gold"])
fy2 += 68

hyfacts = [
    "Mitral valve most commonly affected in rheumatic heart disease",
    "Sydenham chorea = delayed manifestation; may occur months after GAS infection",
    "Erythema marginatum is uncommon but HIGHLY SPECIFIC for ARF",
    "Subcutaneous nodules are associated with severe carditis (Aschoff bodies)",
    "Elevated ASO titre alone does NOT diagnose ARF — clinical criteria mandatory",
    "JONES = Joints | cOrea | Nodules | Erythema | carditiS",
    "Echo carditis counts as a Major criterion (AHA 2015 revised guidelines)",
    "Secondary prophylaxis: Benzathine Penicillin G every 3–4 weeks",
]

col_h = (len(hyfacts)+1)//2
fx1 = MARGIN + 20
fx2 = W//2 + 20
for i, fact in enumerate(hyfacts):
    fxi = fx1 if i < col_h else fx2
    fyi = fy2 + (i % col_h) * 48
    draw.ellipse([fxi-2, fyi+8, fxi+18, fyi+28], fill=C["gold"])
    text_left(draw, fxi+24, fyi, fact, F["small"], "#E3F2FD", max_width=W//2-60)

# Bottom credit line
credit = "Modified Jones Criteria  |  AHA 2015 Revision  |  NEET PG · INICET · FMGE · USMLE Step 1 High-Yield"
text_center(draw, W//2, H-40, credit, F["tiny"], "#90CAF9")

# ═══════════════════════════════════════════════
#  SAVE
# ═══════════════════════════════════════════════
out_path = "/tmp/workspace/jones-criteria/Modified_Jones_Criteria_ARF.png"
img.save(out_path, "PNG", dpi=(300,300), optimize=False)
print(f"Saved → {out_path}  ({W}×{H} px)")
Running Command

cd /tmp/workspace/jones-criteria && python build_infographic.py 2>&1

Running Command

ls -lh /tmp/workspace/jones-criteria/ && python3 -c " from PIL import Image img = Image.open('/tmp/workspace/jones-criteria/Modified_Jones_Criteria_ARF.png') print('Size:', img.size) print('Mode:', img.mode) print('DPI:', img.info.get('dpi','not set')) "

Running Command

python3 -c " from PIL import Image img = Image.open('/tmp/workspace/jones-criteria/Modified_Jones_Criteria_ARF.png') pdf_path = '/tmp/workspace/jones-criteria/Modified_Jones_Criteria_ARF.pdf' img.save(pdf_path, 'PDF', resolution=300, save_all=False) print('PDF saved:', pdf_path) import os; print('PDF size:', round(os.path.getsize(pdf_path)/1024), 'KB') "

Your infographic is ready! Here are the download links:

Modified Jones Criteria ARF

Image · PNG

- Ultra-HD PNG (2480×3508 px, 300 DPI)

Modified Jones Criteria ARF

PDF Document · PDF

- Print-ready A4 PDF (569 KB)

Here is what's included in the infographic:
Layout (A4 Portrait, 300 DPI - True print-quality):
SectionContent
HeaderDeep navy + crimson banner, title, GAS → ARF tagline, exam badges (NEET PG, INICET, FMGE, USMLE)
Diagnosis Box2 Major OR 1 Major + 2 Minor rule; Low-risk vs High-risk population note
JONES MnemonicColor-coded J-O-N-E-S breakdown with letter badges
5 Major CriteriaEach in its own card with anatomical illustration (heart, knee joint, brain+basal ganglia, annular skin lesion, tendon nodule), color-coded border, bullets
4 Minor Criteria4 columns - Fever (thermometer), Arthralgia (joint), Raised ESR/CRP (test tubes), Prolonged PR (ECG strip with highlighted PR interval)
Strep Evidence5 mandatory evidence types: throat culture, ASO titre, Anti-DNase B, rapid antigen, scarlet fever
Right PanelMemory trick, valve involvement hierarchy, clinical pearls, pathogenesis flow, ARF vs IE differential table
Footer8 high-yield NEET PG facts on navy background
Color Scheme:
  • Deep navy (#0D2B5E) + crimson (#B71C1C) header/footer
  • Royal blue (#1565C0) for Major Criteria
  • Deep orange (#E65100) for Minor Criteria
  • Rose (#FCE4EC) for Strep section
  • Gold (#F9A825) for pearls and accents
This is a shared conversation. Sign in to Orris to start your own chat.