Polyarticular pain and it’s causes

Reading File
Finding Sources
Finding Sources
Searching PubMed

polyarticular arthritis differential diagnosis

Reading File
Reading File
Reading File
Reading File
Reading File
Loading Image
Reading File
Loading Image
I now have comprehensive information to provide a thorough answer. Let me compile this.

Polyarticular Pain and Its Causes

Polyarticular arthritis is defined as joint pain involving more than 4 joints simultaneously. It is a broad clinical syndrome that can result from infectious, autoimmune, crystal, or degenerative processes. The first step in evaluation is determining whether the arthritis is inflammatory or noninflammatory, and then classifying joint distribution and symmetry.
  • Frameworks for Internal Medicine, p. 685
  • ROSEN's Emergency Medicine, p. 2335

Classification Framework

Arthritis classification flowchart: noninflammatory vs inflammatory, branching into monoarticular, oligoarticular, and polyarticular
Key clinical questions to ask:
  • Acute vs. chronic onset?
  • Symmetric vs. asymmetric?
  • Large vs. small joints involved?
  • Inflammatory signs present (warmth, swelling, morning stiffness >1 hour)?

Causes of Polyarticular Pain

1. Autoimmune / Connective Tissue Diseases

ConditionHallmark Features
Rheumatoid Arthritis (RA)Symmetric, small joint involvement (MCPs, PIPs, wrists, MTPs); anti-CCP antibodies; joint erosions on X-ray; female predominance 2-3:1
Systemic Lupus Erythematosus (SLE)Positive ANA and anti-dsDNA antibodies; multisystem involvement; arthritis often non-erosive
Polymyositis / DermatomyositisProximal muscle weakness; elevated serum creatine kinase; skin rash in DM
Adult-Onset Still's DiseaseMarkedly elevated serum ferritin; quotidian fever; salmon-colored rash
SarcoidosisGranulomatous disease; primarily affects lungs; polyarticular arthritis as extrapulmonary manifestation
Serum SicknessDrug/foreign protein exposure history (e.g., antithymocyte globulin); immune complex-mediated
  • Frameworks for Internal Medicine, p. 685

2. Seronegative Spondyloarthropathies

These typically cause asymmetric, large-joint or axial involvement:
  • Ankylosing spondylitis - sacroiliitis, axial involvement, HLA-B27 associated
  • Psoriatic arthritis - skin/nail involvement, asymmetric, dactylitis
  • Reactive arthritis - follows genitourinary or GI infection; classic triad: urethritis, conjunctivitis, arthritis
  • IBD-associated arthritis - parallels gut disease activity in peripheral form
  • ROSEN's Emergency Medicine, p. 2413

3. Infectious Causes

PathogenPresentation
Gonococcal arthritisMigratory polyarthralgias + skin lesions (pustular/vasculitic); sexually active young adults; most common septic arthritis in this age group
Lyme diseaseTick exposure; large joint involvement (especially knee); preceded by erythema migrans
Septic arthritisA significant proportion of septic joint cases present with multijoint involvement; always include in differential
Infective endocarditisPolyarthritis as immune-complex manifestation; heart murmur, fever, embolic phenomena
Rheumatic feverGroup A streptococcal pharyngitis; migratory inflammatory arthritis; most common in developing countries
  • ROSEN's Emergency Medicine, p. 2407-2408

4. Viral Arthritides

VirusArthritis Pattern
Parvovirus B19"Slapped-cheek" rash in children; symmetric polyarticular arthritis in adults; self-limited
Hepatitis BSymmetric, migratory; subsides with onset of jaundice
Hepatitis CRA-like mimic, symmetric
HIVOften monoarticular (feet/ankles); variable course
Rubella / rubella vaccine30% of females; self-limited within 2 weeks
Alphaviruses (Chikungunya, Ross River, Mayaro)Mosquito-borne; can last 3-6 months
Flaviviruses (Dengue, Zika, West Nile)Acute joint + bone pain; high fever; supportive treatment
  • ROSEN's Emergency Medicine, Table 102.9

5. Crystal Arthropathies

  • Gout (monosodium urate crystals) - can be polyarticular in chronic tophaceous gout; acutely more often monoarticular
  • Pseudogout / CPDD (calcium pyrophosphate deposition) - can mimic RA with symmetric polyarticular inflammatory arthritis of large and small joints; flares tend to involve joints sequentially; 10% have positive RF but anti-CCP and erosions are absent
  • Rheumatology 2-Volume Set (Elsevier 2022), p. 7677

6. Noninflammatory Polyarticular Causes

These lack inflammatory signs and are included in the broader differential:
  • Polyarticular osteoarthritis - DIP, PIP, CMC joints; Heberden's/Bouchard's nodes; no systemic inflammation
  • Hemochromatosis - Iron overload; involves MCPs (especially 2nd/3rd); chondrocalcinosis
  • Hypertrophic osteoarthropathy - Periosteal new bone formation; associated with lung disease
  • Acromegaly - Excess GH; large joint arthropathy

Diagnostic Approach Algorithm

The following algorithm from Rosen's Emergency Medicine guides the workup:
Algorithm for Polyarticular Joint Pain - from complete history/exam, through effusion assessment and arthrocentesis, to septic vs non-septic causes
Key steps:
  1. Complete history and physical - determine articular vs. periarticular (bursitis/tendinitis)
  2. Assess for joint effusion - if present, perform arthrocentesis
  3. Determine if suggestive of septic arthritis (fever, high WBC, risk factors)
  4. If no effusion: consider viral arthritis, early rheumatologic illness, osteoarthritis
  5. If effusion present, not septic: consider gout, pseudogout, rheumatologic illness, seronegative spondyloarthropathy, viral
  6. If septic: swabs for GC, Lyme testing, IV antibiotics + orthopedic consultation

Quick Differential Summary by Pattern

PatternTop Diagnoses
Symmetric small joints, chronicRA, SLE, viral (Hep B/C, Parvovirus)
Asymmetric, large joints, young maleSeronegative spondyloarthropathy, reactive arthritis
Migratory, fever, young sexually activeGonococcal arthritis
Migratory, fever, recent strep pharyngitisAcute rheumatic fever
Quotidian fever, high ferritin, rashAdult-onset Still's disease
Post-viral, self-limitedParvovirus B19, Rubella, Chikungunya
Elderly, large + small joints, no anti-CCPCPDD ("pseudorheumatoid")
Multisystem, ANA+SLE, sarcoidosis, dermatomyositis

It’s diagnostic approach

Finding Sources
Finding Sources
Finding Sources
Finding Sources
Finding Sources
Finding Sources
Reading File
Finding Sources
Finding Sources
Finding Sources
Reading File
Reading File
I now have rich content to give a thorough diagnostic approach. Let me compile a structured, comprehensive answer.

Diagnostic Approach to Polyarticular Pain

The evaluation of polyarticular pain (>4 joints involved) follows a structured, stepwise approach that combines history, physical examination, investigations, and synovial fluid analysis to narrow the differential.

Step 1: History

Key questions to ask guide the entire diagnostic process:

Onset and Duration

FeatureSignificance
Acute (<6 weeks)Infection (gonococcal, viral, septic), crystal arthropathy (gout, pseudogout), acute rheumatic fever, reactive arthritis
Chronic (>6 weeks)RA, SLE, seronegative spondyloarthropathies, polyarticular OA
Migratory arthritisGonococcal arthritis, acute rheumatic fever, viral arthritides (Hep B)
Additive/cumulativeRA, psoriatic arthritis, reactive arthritis

Morning Stiffness

  • >1 hour = strongly suggests inflammatory arthritis (RA, SLE, spondyloarthropathy)
  • <30 minutes = suggests noninflammatory/degenerative (OA)

Joint Pattern

PatternLikely Diagnosis
Symmetric, small joints (MCPs, PIPs, wrists, MTPs)RA
Asymmetric, large jointsSeronegative spondyloarthropathy, reactive arthritis
DIP joints prominentPsoriatic arthritis, OA (Heberden's nodes)
Axial + peripheralAnkylosing spondylitis, IBD-related arthropathy

Associated Systemic Symptoms

  • Fever - infection (GC, septic, viral), Still's disease, SLE, rheumatic fever
  • Rash - SLE (malar), psoriasis, reactive arthritis (keratoderma), Still's disease (salmon-colored), Lyme (erythema migrans)
  • Eye symptoms (uveitis, conjunctivitis) - reactive arthritis, ankylosing spondylitis, sarcoidosis
  • Urogenital symptoms - reactive arthritis, gonococcal arthritis
  • GI symptoms - reactive arthritis (Salmonella, Shigella, Yersinia trigger), IBD-related
  • Skin/nail changes - psoriatic arthritis
  • Dry eyes/mouth - Sjögren syndrome
  • Raynaud's phenomenon - SLE, mixed connective tissue disease, scleroderma

Exposure and Risk History

  • Recent pharyngitis - acute rheumatic fever
  • Sexual activity - gonococcal arthritis
  • Tick exposure - Lyme disease
  • Recent viral illness - parvovirus B19, hepatitis B/C, chikungunya
  • Travel - arboviral disease (dengue, chikungunya, Zika)
  • Drug history - serum sickness (antithymocyte globulin), drug-induced lupus
  • Family history - RA, psoriasis, ankylosing spondylitis (HLA-B27), gout

Step 2: Physical Examination

Confirm Articular vs. Periarticular

  • True articular disease: pain reproduced with both active and passive range of motion, joint line tenderness, effusion
  • Periarticular (bursitis, tendinitis): pain with active but not passive movement, localized tenderness outside the joint line

Inflammatory Signs (SHARP)

  • Swelling (synovial thickening / effusion)
  • Heat
  • Arythema (redness)
  • Range of motion - restricted
  • Pain at rest or with movement

Joint-Specific Findings

FindingImplication
Soft boggy swellingSynovial thickening = inflammatory
Hard bony enlargementOA (Heberden's/Bouchard's nodes)
Effusion (ballottement/bulge sign)Inflammatory - warrants arthrocentesis
Ulnar deviation, swan-neck, Boutonnière deformitiesChronic RA
Dactylitis ("sausage digit")Psoriatic arthritis, reactive arthritis
Sacroiliac joint tendernessSpondyloarthropathy

Extra-articular Findings

  • Tophi (ears, tendons) - gout
  • Subcutaneous nodules - RA
  • Malar rash - SLE
  • Psoriatic plaques/nail pitting - psoriatic arthritis
  • Oral ulcers - SLE, reactive arthritis, Behçet's
  • Lymphadenopathy + hepatosplenomegaly - Still's disease, SLE, viral
  • Heart murmur - infective endocarditis, rheumatic fever (carditis)
  • Lung involvement - sarcoidosis, RA (ILD)

Step 3: Investigations

Blood Tests

TestPurpose
ESR, CRPConfirm inflammation; elevated in inflammatory arthritis, infection
CBC with differentialLeukocytosis (infection, Still's); anemia of chronic disease (RA, SLE); thrombocytopenia (SLE)
Rheumatoid factor (RF)Positive in RA (~70-80%); also in SLE, hepatitis C, CPDD (~10%)
Anti-CCP (anti-citrullinated peptide)Highly specific for RA; predicts erosive disease
ANAScreen for SLE and other CTDs; high sensitivity, low specificity
Anti-dsDNA, Anti-SmSpecific for SLE if ANA positive
Uric acidElevated in gout (note: may be normal during acute attack)
Serum ferritinMarkedly elevated (often >10,000 ng/mL) in Still's disease
ASO titerElevated in acute rheumatic fever (recent streptococcal infection)
Blood culturesIf infective endocarditis or septic arthritis suspected
LFTs, Hepatitis B/C serologyViral arthritis workup
Parvovirus B19 IgM/IgGAcute viral arthritis
Lyme serology (ELISA + Western blot)Endemic area exposure / migratory large-joint arthritis
HLA-B27Seronegative spondyloarthropathies
Complement (C3, C4)Low in active SLE (consumption)
TSHHypothyroidism can mimic arthropathy
Serum creatine kinaseElevated in polymyositis/dermatomyositis
  • Miller's Review of Orthopaedics, p. 2412; Harrison's Principles of Internal Medicine 22E

Synovial Fluid Analysis

Arthrocentesis is performed whenever an effusion is present. This is the single most important investigation when effusion is identified.
ParameterNormalNoninflammatory (OA)Inflammatory (RA, crystal)Septic
AppearanceClear, strawClear/yellowTurbid, yellowPurulent/cloudy
ViscosityHighHighLowLow
WBC (cells/µL)<200<2,0002,000-50,000>50,000 (often >100,000)
% PMNs<25%<25%>50%>75%
Glucose= serum= serumLowVery low
CultureNegativeNegativeNegativePositive (in septic)
CrystalsNoneNoneUrate (gout) or CPP (pseudogout)None
  • Firestein & Kelley's Textbook of Rheumatology, p. 2101
Crystal analysis:
  • Monosodium urate (gout): needle-shaped, negatively birefringent (yellow under parallel light)
  • Calcium pyrophosphate (pseudogout): rhomboid-shaped, weakly positively birefringent (blue under parallel light)

Imaging

ModalityUse
Plain X-raysFirst-line: erosions (RA), joint space narrowing (OA), chondrocalcinosis (CPDD), periosteal reaction
UltrasoundDetect early synovitis, guide arthrocentesis, assess tendons/entheses
MRIBest for early erosions (RA), sacroiliac joints (AS), soft tissue involvement
CTBony detail; axial spondyloarthropathy, sacroiliitis
Bone scanDiffuse inflammatory activity; polyarticular involvement

Step 4: Diagnostic Algorithm

The following algorithm from Rosen's Emergency Medicine structures the workup from presentation to diagnosis:
Algorithm for Polyarticular Joint Pain - from complete history/exam, through effusion assessment and arthrocentesis, to septic vs. non-septic workup
Key decision branches:
  1. History + exam → articular vs. periarticular (bursitis/tendinitis)
  2. Effusion present?
    • No → Consider viral arthritis, early rheumatologic illness, OA; outpatient viral and rheumatologic testing
    • Yes → Arthrocentesis
  3. Effusion present + arthrocentesis doneSeptic features? (fever, WBC >50,000, Gram stain +)
    • Yes → GC swabs, Lyme testing, IV antibiotics, orthopedic consult
    • No → Consider gout/pseudogout, rheumatologic illness, OA, seronegative spondyloarthropathy, viral; close follow-up
  • ROSEN's Emergency Medicine, Fig. 102.6

Summary: Key Discriminating Features at a Glance

ClueDiagnosis to Consider
Anti-CCP positive + erosionsRA
ANA + anti-dsDNASLE
Ferritin >10,000 + quotidian fever + rashAdult-onset Still's disease
Urate crystals, negatively birefringentGout
CPP crystals, positively birefringentPseudogout / CPDD
HLA-B27 + sacroiliitisAnkylosing spondylitis
Post-GI/GU infection + urethritis + conjunctivitisReactive arthritis
Migratory arthritis + skin pustules, sexually activeGonococcal arthritis
Post-pharyngitis + carditis + migratory arthritisAcute rheumatic fever
Child with "slapped cheek" contactParvovirus B19
Mosquito exposure, tropical travelChikungunya, Dengue, Zika

Create a diagnostic reference chart summarizing this approach in PDF format

Reading File
Running Command

mkdir -p /tmp/workspace/polyarticular-chart && ls /tmp/workspace/

Writing File

~/polyarticular-chart/generate_chart.py

from reportlab.lib.pagesizes import A4, landscape
from reportlab.lib import colors
from reportlab.lib.units import cm, mm
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 HRFlowable
from reportlab.graphics.shapes import Drawing, Rect, String, Line, Arrow
from reportlab.graphics import renderPDF

# ── Colour palette ──────────────────────────────────────────────────────────
NAVY      = colors.HexColor("#1A3A5C")
TEAL      = colors.HexColor("#1A7A8A")
TEAL_LIGHT= colors.HexColor("#D4EFF3")
BLUE_PALE = colors.HexColor("#E8F4FD")
ORANGE    = colors.HexColor("#E07B2A")
ORANGE_LT = colors.HexColor("#FEF0E2")
RED_LT    = colors.HexColor("#FDECEA")
RED       = colors.HexColor("#C0392B")
GREEN     = colors.HexColor("#1E7E4B")
GREEN_LT  = colors.HexColor("#E6F5EC")
PURPLE    = colors.HexColor("#5B3FA6")
PURPLE_LT = colors.HexColor("#EDE8F9")
YELLOW_LT = colors.HexColor("#FFFBEA")
YELLOW    = colors.HexColor("#D4AC0D")
GREY_LT   = colors.HexColor("#F4F6F8")
GREY_MID  = colors.HexColor("#CED4DA")
GREY_DARK = colors.HexColor("#495057")
WHITE     = colors.white
BLACK     = colors.black

OUTPUT = "/tmp/workspace/polyarticular-chart/Polyarticular_Pain_Diagnostic_Reference.pdf"

doc = SimpleDocTemplate(
    OUTPUT,
    pagesize=A4,
    leftMargin=1.4*cm, rightMargin=1.4*cm,
    topMargin=1.4*cm, bottomMargin=1.4*cm,
    title="Polyarticular Pain – Diagnostic Reference Chart",
    author="Orris Medical Reference",
)

styles = getSampleStyleSheet()

def S(name, **kw):
    return ParagraphStyle(name, **kw)

# ── Shared styles ────────────────────────────────────────────────────────────
TITLE_STYLE = S("Title2", fontName="Helvetica-Bold", fontSize=18,
                textColor=WHITE, alignment=TA_CENTER, leading=22)
SUB_TITLE   = S("SubTitle2", fontName="Helvetica", fontSize=9,
                textColor=WHITE, alignment=TA_CENTER, leading=12)
SEC_TITLE   = S("SecTitle", fontName="Helvetica-Bold", fontSize=10,
                textColor=WHITE, alignment=TA_CENTER, leading=13, spaceAfter=0)
COL_HEADER  = S("ColHdr", fontName="Helvetica-Bold", fontSize=8,
                textColor=WHITE, alignment=TA_CENTER, leading=10)
BODY        = S("Body2", fontName="Helvetica", fontSize=7.5,
                textColor=GREY_DARK, alignment=TA_LEFT, leading=10)
BODY_BOLD   = S("BodyBold", fontName="Helvetica-Bold", fontSize=7.5,
                textColor=NAVY, alignment=TA_LEFT, leading=10)
BODY_C      = S("BodyC", fontName="Helvetica", fontSize=7.5,
                textColor=GREY_DARK, alignment=TA_CENTER, leading=10)
BODY_BOLD_C = S("BodyBoldC", fontName="Helvetica-Bold", fontSize=7.5,
                textColor=NAVY, alignment=TA_CENTER, leading=10)
SMALL       = S("Small", fontName="Helvetica", fontSize=6.8,
                textColor=GREY_DARK, alignment=TA_LEFT, leading=9)
SMALL_C     = S("SmallC", fontName="Helvetica", fontSize=6.8,
                textColor=GREY_DARK, alignment=TA_CENTER, leading=9)
SMALL_BOLD  = S("SmallBold", fontName="Helvetica-Bold", fontSize=7,
                textColor=NAVY, alignment=TA_LEFT, leading=9)
SMALL_BOLD_C= S("SmallBoldC", fontName="Helvetica-Bold", fontSize=7,
                textColor=NAVY, alignment=TA_CENTER, leading=9)
FOOT        = S("Foot", fontName="Helvetica-Oblique", fontSize=6.5,
                textColor=GREY_DARK, alignment=TA_CENTER, leading=9)

# ── Helper: section header bar ───────────────────────────────────────────────
def section_header(text, bg=NAVY, fg=WHITE, fs=10):
    p = Paragraph(text, ParagraphStyle("sh", fontName="Helvetica-Bold",
                  fontSize=fs, textColor=fg, alignment=TA_CENTER, leading=fs+3))
    t = Table([[p]], colWidths=[doc.width])
    t.setStyle(TableStyle([
        ("BACKGROUND", (0,0), (-1,-1), bg),
        ("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", [4]),
    ]))
    return t

# ── Helper: two-tone sub-header ───────────────────────────────────────────────
def sub_header(text, bg=TEAL):
    p = Paragraph(text, ParagraphStyle("sbh", fontName="Helvetica-Bold",
                  fontSize=8, textColor=WHITE, alignment=TA_LEFT, leading=10))
    t = Table([[p]], colWidths=[doc.width])
    t.setStyle(TableStyle([
        ("BACKGROUND", (0,0), (-1,-1), bg),
        ("TOPPADDING",  (0,0), (-1,-1), 3),
        ("BOTTOMPADDING",(0,0),(-1,-1), 3),
        ("LEFTPADDING", (0,0), (-1,-1), 8),
        ("RIGHTPADDING",(0,0), (-1,-1), 6),
    ]))
    return t

# ── Helper: standard table style ─────────────────────────────────────────────
def base_style(header_bg=NAVY, alt_bg=GREY_LT, grid=GREY_MID):
    return TableStyle([
        ("BACKGROUND",    (0,0), (-1,0),  header_bg),
        ("TEXTCOLOR",     (0,0), (-1,0),  WHITE),
        ("FONTNAME",      (0,0), (-1,0),  "Helvetica-Bold"),
        ("FONTSIZE",      (0,0), (-1,0),  7.5),
        ("ALIGN",         (0,0), (-1,-1), "CENTER"),
        ("VALIGN",        (0,0), (-1,-1), "MIDDLE"),
        ("ROWBACKGROUNDS",(0,1), (-1,-1), [WHITE, alt_bg]),
        ("GRID",          (0,0), (-1,-1), 0.4, grid),
        ("TOPPADDING",    (0,0), (-1,-1), 3),
        ("BOTTOMPADDING", (0,0), (-1,-1), 3),
        ("LEFTPADDING",   (0,0), (-1,-1), 4),
        ("RIGHTPADDING",  (0,0), (-1,-1), 4),
        ("FONTNAME",      (0,1), (-1,-1), "Helvetica"),
        ("FONTSIZE",      (0,1), (-1,-1), 7),
        ("TEXTCOLOR",     (0,1), (-1,-1), GREY_DARK),
    ])

def P(txt, style=BODY):
    return Paragraph(txt, style)

W = doc.width  # full usable width

story = []

# ══════════════════════════════════════════════════════════════════════════════
# TITLE BANNER
# ══════════════════════════════════════════════════════════════════════════════
title_data = [[
    Paragraph("POLYARTICULAR PAIN", TITLE_STYLE),
    Paragraph("Diagnostic Reference Chart", SUB_TITLE),
]]
# stack vertically
banner_inner = Table([
    [Paragraph("POLYARTICULAR PAIN", TITLE_STYLE)],
    [Paragraph("Diagnostic Reference Chart  •  >4 joints involved", SUB_TITLE)],
], colWidths=[W])
banner_inner.setStyle(TableStyle([
    ("BACKGROUND", (0,0), (-1,-1), NAVY),
    ("TOPPADDING",  (0,0), (-1,-1), 8),
    ("BOTTOMPADDING",(0,0),(-1,-1), 8),
]))
story.append(banner_inner)
story.append(Spacer(1, 5))

# ══════════════════════════════════════════════════════════════════════════════
# ROW 1 — STEP 1: HISTORY  (full width)
# ══════════════════════════════════════════════════════════════════════════════
story.append(section_header("STEP 1 — HISTORY", bg=NAVY))
story.append(Spacer(1, 3))

# --- Onset + Morning stiffness side by side
onset_data = [
    [P("Onset", COL_HEADER), P("Consider", COL_HEADER)],
    [P("Acute (<6 wks)", SMALL_BOLD), P("Infection (GC, viral, septic), crystal arthropathy, rheumatic fever, reactive arthritis", SMALL)],
    [P("Chronic (>6 wks)", SMALL_BOLD), P("RA, SLE, seronegative spondyloarthropathy, polyarticular OA", SMALL)],
    [P("Migratory", SMALL_BOLD), P("Gonococcal arthritis, acute rheumatic fever, Hepatitis B", SMALL)],
    [P("Additive", SMALL_BOLD), P("RA, psoriatic arthritis, reactive arthritis", SMALL)],
]
onset_t = Table(onset_data, colWidths=[3.2*cm, 8.2*cm])
onset_t.setStyle(TableStyle([
    ("BACKGROUND",    (0,0), (-1,0),  TEAL),
    ("TEXTCOLOR",     (0,0), (-1,0),  WHITE),
    ("FONTNAME",      (0,0), (-1,0),  "Helvetica-Bold"),
    ("FONTSIZE",      (0,0), (-1,-1), 7),
    ("GRID",          (0,0), (-1,-1), 0.4, GREY_MID),
    ("ROWBACKGROUNDS",(0,1), (-1,-1), [WHITE, TEAL_LIGHT]),
    ("VALIGN",        (0,0), (-1,-1), "MIDDLE"),
    ("TOPPADDING",    (0,0), (-1,-1), 3),
    ("BOTTOMPADDING", (0,0), (-1,-1), 3),
    ("LEFTPADDING",   (0,0), (-1,-1), 4),
    ("RIGHTPADDING",  (0,0), (-1,-1), 4),
    ("TEXTCOLOR",     (0,1), (-1,-1), GREY_DARK),
]))

stiff_data = [
    [P("Morning Stiffness", COL_HEADER)],
    [P("⬛ >1 hour  →  Inflammatory (RA, SLE, SpA)", SMALL_BOLD)],
    [P("⬜ <30 min  →  Non-inflammatory / OA", SMALL)],
]
stiff_t = Table(stiff_data, colWidths=[5.6*cm])
stiff_t.setStyle(TableStyle([
    ("BACKGROUND",    (0,0), (-1,0),  TEAL),
    ("TEXTCOLOR",     (0,0), (-1,0),  WHITE),
    ("FONTNAME",      (0,0), (-1,0),  "Helvetica-Bold"),
    ("FONTSIZE",      (0,0), (-1,-1), 7),
    ("GRID",          (0,0), (-1,-1), 0.4, GREY_MID),
    ("ROWBACKGROUNDS",(0,1), (-1,-1), [WHITE, TEAL_LIGHT]),
    ("VALIGN",        (0,0), (-1,-1), "MIDDLE"),
    ("TOPPADDING",    (0,0), (-1,-1), 3),
    ("BOTTOMPADDING", (0,0), (-1,-1), 3),
    ("LEFTPADDING",   (0,0), (-1,-1), 5),
    ("RIGHTPADDING",  (0,0), (-1,-1), 4),
    ("TEXTCOLOR",     (0,1), (-1,-1), GREY_DARK),
]))

row1 = Table([[onset_t, stiff_t]], colWidths=[11.7*cm, 5.8*cm],
             hAlign="LEFT")
row1.setStyle(TableStyle([
    ("VALIGN", (0,0), (-1,-1), "TOP"),
    ("LEFTPADDING",  (0,0), (-1,-1), 0),
    ("RIGHTPADDING", (0,0), (-1,-1), 0),
    ("TOPPADDING",   (0,0), (-1,-1), 0),
    ("BOTTOMPADDING",(0,0), (-1,-1), 0),
    ("LINEBETWEEN",  (0,0), (0,-1),  0, WHITE),
]))
story.append(row1)
story.append(Spacer(1, 4))

# --- Joint pattern + Associated symptoms side by side
jp_data = [
    [P("Joint Pattern", COL_HEADER), P("Likely Diagnosis", COL_HEADER)],
    [P("Symmetric small joints\n(MCPs, PIPs, wrists, MTPs)", SMALL_BOLD), P("Rheumatoid Arthritis", SMALL)],
    [P("Asymmetric large joints", SMALL_BOLD), P("Seronegative SpA, reactive arthritis", SMALL)],
    [P("DIP joints prominent", SMALL_BOLD), P("Psoriatic arthritis, OA (Heberden's nodes)", SMALL)],
    [P("Axial + peripheral", SMALL_BOLD), P("Ankylosing spondylitis, IBD-related arthropathy", SMALL)],
    [P("Migratory large joints", SMALL_BOLD), P("Acute rheumatic fever, gonococcal arthritis", SMALL)],
]
jp_t = Table(jp_data, colWidths=[5.0*cm, 6.5*cm])
jp_t.setStyle(TableStyle([
    ("BACKGROUND",    (0,0), (-1,0),  ORANGE),
    ("TEXTCOLOR",     (0,0), (-1,0),  WHITE),
    ("FONTNAME",      (0,0), (-1,0),  "Helvetica-Bold"),
    ("FONTSIZE",      (0,0), (-1,-1), 7),
    ("GRID",          (0,0), (-1,-1), 0.4, GREY_MID),
    ("ROWBACKGROUNDS",(0,1), (-1,-1), [WHITE, ORANGE_LT]),
    ("VALIGN",        (0,0), (-1,-1), "MIDDLE"),
    ("TOPPADDING",    (0,0), (-1,-1), 3),
    ("BOTTOMPADDING", (0,0), (-1,-1), 3),
    ("LEFTPADDING",   (0,0), (-1,-1), 4),
    ("RIGHTPADDING",  (0,0), (-1,-1), 4),
    ("TEXTCOLOR",     (0,1), (-1,-1), GREY_DARK),
]))

sx_data = [
    [P("Associated Symptom / Exposure", COL_HEADER), P("Consider", COL_HEADER)],
    [P("Fever + quotidian + rash", SMALL_BOLD), P("Still's disease", SMALL)],
    [P("Malar rash, serositis", SMALL_BOLD), P("SLE", SMALL)],
    [P("Psoriatic plaques/nail pitting", SMALL_BOLD), P("Psoriatic arthritis", SMALL)],
    [P("Urethritis + conjunctivitis", SMALL_BOLD), P("Reactive / GC arthritis", SMALL)],
    [P("Post-pharyngitis + carditis", SMALL_BOLD), P("Acute rheumatic fever", SMALL)],
    [P("Recent viral / child 'slapped cheek'", SMALL_BOLD), P("Parvovirus B19", SMALL)],
    [P("Tick exposure / endemic area", SMALL_BOLD), P("Lyme disease", SMALL)],
    [P("Mosquito bite / tropical travel", SMALL_BOLD), P("Chikungunya, Dengue, Zika", SMALL)],
    [P("Proximal muscle weakness", SMALL_BOLD), P("Polymyositis / dermatomyositis", SMALL)],
]
sx_t = Table(sx_data, colWidths=[5.0*cm, 3.8*cm])
sx_t.setStyle(TableStyle([
    ("BACKGROUND",    (0,0), (-1,0),  ORANGE),
    ("TEXTCOLOR",     (0,0), (-1,0),  WHITE),
    ("FONTNAME",      (0,0), (-1,0),  "Helvetica-Bold"),
    ("FONTSIZE",      (0,0), (-1,-1), 7),
    ("GRID",          (0,0), (-1,-1), 0.4, GREY_MID),
    ("ROWBACKGROUNDS",(0,1), (-1,-1), [WHITE, ORANGE_LT]),
    ("VALIGN",        (0,0), (-1,-1), "MIDDLE"),
    ("TOPPADDING",    (0,0), (-1,-1), 3),
    ("BOTTOMPADDING", (0,0), (-1,-1), 3),
    ("LEFTPADDING",   (0,0), (-1,-1), 4),
    ("RIGHTPADDING",  (0,0), (-1,-1), 4),
    ("TEXTCOLOR",     (0,1), (-1,-1), GREY_DARK),
]))

row2 = Table([[jp_t, sx_t]], colWidths=[11.7*cm, 5.8*cm], hAlign="LEFT")
row2.setStyle(TableStyle([
    ("VALIGN", (0,0), (-1,-1), "TOP"),
    ("LEFTPADDING",  (0,0), (-1,-1), 0),
    ("RIGHTPADDING", (0,0), (-1,-1), 0),
    ("TOPPADDING",   (0,0), (-1,-1), 0),
    ("BOTTOMPADDING",(0,0), (-1,-1), 0),
]))
story.append(row2)
story.append(Spacer(1, 4))

# ══════════════════════════════════════════════════════════════════════════════
# STEP 2 — PHYSICAL EXAMINATION
# ══════════════════════════════════════════════════════════════════════════════
story.append(section_header("STEP 2 — PHYSICAL EXAMINATION", bg=PURPLE))
story.append(Spacer(1, 3))

exam_data = [
    [P("Finding", COL_HEADER), P("Interpretation", COL_HEADER),
     P("Finding", COL_HEADER), P("Interpretation", COL_HEADER)],

    [P("Soft boggy swelling", SMALL_BOLD), P("Synovial thickening = inflammatory", SMALL),
     P("Ulnar deviation / swan-neck /\nBoutonnière deformity", SMALL_BOLD), P("Chronic RA", SMALL)],

    [P("Hard bony enlargement", SMALL_BOLD), P("OA — Heberden's / Bouchard's nodes", SMALL),
     P("Dactylitis ('sausage digit')", SMALL_BOLD), P("Psoriatic or reactive arthritis", SMALL)],

    [P("Joint effusion", SMALL_BOLD), P("Inflammatory → do arthrocentesis", SMALL),
     P("Sacroiliac tenderness", SMALL_BOLD), P("Spondyloarthropathy", SMALL)],

    [P("Pain active only\n(not passive ROM)", SMALL_BOLD), P("Periarticular (bursitis/tendinitis)", SMALL),
     P("Tophi (ears, tendons)", SMALL_BOLD), P("Chronic tophaceous gout", SMALL)],

    [P("Morning stiffness >1 hr", SMALL_BOLD), P("Inflammatory arthritis", SMALL),
     P("Subcutaneous nodules", SMALL_BOLD), P("Rheumatoid arthritis", SMALL)],
]

cw_exam = [3.8*cm, 5.0*cm, 3.8*cm, 5.0*cm]
exam_t = Table(exam_data, colWidths=cw_exam)
exam_t.setStyle(TableStyle([
    ("BACKGROUND",    (0,0), (-1,0),  PURPLE),
    ("TEXTCOLOR",     (0,0), (-1,0),  WHITE),
    ("FONTNAME",      (0,0), (-1,0),  "Helvetica-Bold"),
    ("FONTSIZE",      (0,0), (-1,-1), 7),
    ("GRID",          (0,0), (-1,-1), 0.4, GREY_MID),
    ("ROWBACKGROUNDS",(0,1), (-1,-1), [WHITE, PURPLE_LT]),
    ("VALIGN",        (0,0), (-1,-1), "MIDDLE"),
    ("TOPPADDING",    (0,0), (-1,-1), 3),
    ("BOTTOMPADDING", (0,0), (-1,-1), 3),
    ("LEFTPADDING",   (0,0), (-1,-1), 4),
    ("RIGHTPADDING",  (0,0), (-1,-1), 4),
    ("TEXTCOLOR",     (0,1), (-1,-1), GREY_DARK),
    ("LINEAFTER",     (1,0), (1,-1),  1.2, PURPLE),
]))
story.append(exam_t)
story.append(Spacer(1, 4))

# ══════════════════════════════════════════════════════════════════════════════
# STEP 3 — INVESTIGATIONS
# ══════════════════════════════════════════════════════════════════════════════
story.append(section_header("STEP 3 — INVESTIGATIONS", bg=colors.HexColor("#1E7E4B")))
story.append(Spacer(1, 3))

# --- Blood tests (two columns)
blood_data = [
    [P("Test", COL_HEADER), P("Significance", COL_HEADER),
     P("Test", COL_HEADER), P("Significance", COL_HEADER)],
    [P("ESR / CRP", SMALL_BOLD), P("Elevated → confirms inflammation; infection", SMALL),
     P("ANA", SMALL_BOLD), P("Screen for SLE & CTDs (sensitive, not specific)", SMALL)],
    [P("CBC + differential", SMALL_BOLD), P("Leukocytosis (infection/Still's); anaemia (RA/SLE)", SMALL),
     P("Anti-dsDNA / Anti-Sm", SMALL_BOLD), P("Specific for SLE if ANA +ve", SMALL)],
    [P("RF (rheumatoid factor)", SMALL_BOLD), P("+ve in RA (70-80%); also SLE, Hep C, CPDD", SMALL),
     P("Serum uric acid", SMALL_BOLD), P("Elevated in gout (may be normal in acute attack)", SMALL)],
    [P("Anti-CCP", SMALL_BOLD), P("Highly specific for RA; predicts erosive disease", SMALL),
     P("Serum ferritin", SMALL_BOLD), P(">10,000 ng/mL — strongly suggests Still's disease", SMALL)],
    [P("Blood cultures", SMALL_BOLD), P("If endocarditis or septic arthritis suspected", SMALL),
     P("ASO titer", SMALL_BOLD), P("Elevated after streptococcal infection (rheumatic fever)", SMALL)],
    [P("Hepatitis B/C serology", SMALL_BOLD), P("Viral arthritis workup", SMALL),
     P("Parvovirus B19 IgM/IgG", SMALL_BOLD), P("Acute viral polyarthritis", SMALL)],
    [P("Lyme serology\n(ELISA + Western blot)", SMALL_BOLD), P("Endemic area / tick exposure / migratory large-joint", SMALL),
     P("HLA-B27", SMALL_BOLD), P("Seronegative spondyloarthropathies (AS, PsA, ReA)", SMALL)],
    [P("Complement C3/C4", SMALL_BOLD), P("Low in active SLE (consumption)", SMALL),
     P("CK (creatine kinase)", SMALL_BOLD), P("Elevated in polymyositis / dermatomyositis", SMALL)],
    [P("TSH", SMALL_BOLD), P("Hypothyroidism can mimic arthropathy", SMALL),
     P("Urine dipstick / ANCA", SMALL_BOLD), P("Renal involvement (SLE, vasculitis)", SMALL)],
]
cw_blood = [3.0*cm, 5.5*cm, 3.0*cm, 6.0*cm]
blood_t = Table(blood_data, colWidths=cw_blood)
blood_t.setStyle(TableStyle([
    ("BACKGROUND",    (0,0), (-1,0),  GREEN),
    ("TEXTCOLOR",     (0,0), (-1,0),  WHITE),
    ("FONTNAME",      (0,0), (-1,0),  "Helvetica-Bold"),
    ("FONTSIZE",      (0,0), (-1,-1), 7),
    ("GRID",          (0,0), (-1,-1), 0.4, GREY_MID),
    ("ROWBACKGROUNDS",(0,1), (-1,-1), [WHITE, GREEN_LT]),
    ("VALIGN",        (0,0), (-1,-1), "MIDDLE"),
    ("TOPPADDING",    (0,0), (-1,-1), 3),
    ("BOTTOMPADDING", (0,0), (-1,-1), 3),
    ("LEFTPADDING",   (0,0), (-1,-1), 4),
    ("RIGHTPADDING",  (0,0), (-1,-1), 4),
    ("TEXTCOLOR",     (0,1), (-1,-1), GREY_DARK),
    ("LINEAFTER",     (1,0), (1,-1),  1.2, GREEN),
]))
story.append(blood_t)
story.append(Spacer(1, 4))

# ══════════════════════════════════════════════════════════════════════════════
# STEP 4 — SYNOVIAL FLUID + IMAGING  (side by side)
# ══════════════════════════════════════════════════════════════════════════════
story.append(section_header("STEP 4 — SYNOVIAL FLUID ANALYSIS & IMAGING", bg=RED))
story.append(Spacer(1, 3))

sf_data = [
    [P("Parameter", COL_HEADER), P("Normal", COL_HEADER),
     P("Non-inflam.", COL_HEADER), P("Inflammatory", COL_HEADER), P("Septic", COL_HEADER)],
    [P("Appearance", SMALL_BOLD), P("Clear", SMALL_C), P("Clear/yellow", SMALL_C),
     P("Turbid yellow", SMALL_C), P("Purulent", SMALL_C)],
    [P("Viscosity", SMALL_BOLD), P("High", SMALL_C), P("High", SMALL_C),
     P("Low", SMALL_C), P("Low", SMALL_C)],
    [P("WBC (/µL)", SMALL_BOLD), P("<200", SMALL_C), P("<2,000", SMALL_C),
     P("2,000–50,000", SMALL_C), P(">50,000", SMALL_C)],
    [P("% PMNs", SMALL_BOLD), P("<25%", SMALL_C), P("<25%", SMALL_C),
     P(">50%", SMALL_C), P(">75%", SMALL_C)],
    [P("Glucose", SMALL_BOLD), P("= serum", SMALL_C), P("= serum", SMALL_C),
     P("Low", SMALL_C), P("Very low", SMALL_C)],
    [P("Culture", SMALL_BOLD), P("Neg", SMALL_C), P("Neg", SMALL_C),
     P("Neg", SMALL_C), P("Positive", SMALL_C)],
    [P("Crystals", SMALL_BOLD), P("None", SMALL_C), P("None", SMALL_C),
     P("Urate/CPP", SMALL_C), P("None", SMALL_C)],
]
cw_sf = [2.8*cm, 1.6*cm, 1.9*cm, 2.4*cm, 2.0*cm]
sf_t = Table(sf_data, colWidths=cw_sf)
sf_t.setStyle(TableStyle([
    ("BACKGROUND",    (0,0), (-1,0),  RED),
    ("TEXTCOLOR",     (0,0), (-1,0),  WHITE),
    ("FONTNAME",      (0,0), (-1,0),  "Helvetica-Bold"),
    ("FONTSIZE",      (0,0), (-1,-1), 7),
    ("GRID",          (0,0), (-1,-1), 0.4, GREY_MID),
    ("ROWBACKGROUNDS",(0,1), (-1,-1), [WHITE, RED_LT]),
    ("VALIGN",        (0,0), (-1,-1), "MIDDLE"),
    ("TOPPADDING",    (0,0), (-1,-1), 3),
    ("BOTTOMPADDING", (0,0), (-1,-1), 3),
    ("LEFTPADDING",   (0,0), (-1,-1), 3),
    ("RIGHTPADDING",  (0,0), (-1,-1), 3),
    ("TEXTCOLOR",     (0,1), (-1,-1), GREY_DARK),
    # highlight septic column
    ("BACKGROUND",    (4,1), (4,-1), colors.HexColor("#FDECEA")),
    ("TEXTCOLOR",     (4,1), (4,-1), RED),
    ("FONTNAME",      (4,1), (4,-1), "Helvetica-Bold"),
]))

crystal_data = [
    [P("Crystal Analysis", COL_HEADER)],
    [P("Gout (MSU)", SMALL_BOLD)],
    [P("Needle-shaped\nNegatively birefringent\n(yellow under parallel light)", SMALL)],
    [P("Pseudogout (CPP)", SMALL_BOLD)],
    [P("Rhomboid-shaped\nWeakly + birefringent\n(blue under parallel light)", SMALL)],
]
cry_t = Table(crystal_data, colWidths=[3.5*cm])
cry_t.setStyle(TableStyle([
    ("BACKGROUND",    (0,0), (-1,0),  RED),
    ("TEXTCOLOR",     (0,0), (-1,0),  WHITE),
    ("FONTNAME",      (0,0), (-1,0),  "Helvetica-Bold"),
    ("FONTSIZE",      (0,0), (-1,-1), 7),
    ("GRID",          (0,0), (-1,-1), 0.4, GREY_MID),
    ("ROWBACKGROUNDS",(0,1), (-1,-1), [RED_LT, WHITE, RED_LT, WHITE]),
    ("VALIGN",        (0,0), (-1,-1), "MIDDLE"),
    ("TOPPADDING",    (0,0), (-1,-1), 3),
    ("BOTTOMPADDING", (0,0), (-1,-1), 3),
    ("LEFTPADDING",   (0,0), (-1,-1), 4),
    ("RIGHTPADDING",  (0,0), (-1,-1), 4),
    ("TEXTCOLOR",     (0,1), (-1,-1), GREY_DARK),
]))

img_data = [
    [P("Imaging Modality", COL_HEADER), P("Best For", COL_HEADER)],
    [P("Plain X-ray", SMALL_BOLD), P("Erosions (RA), joint space (OA), chondrocalcinosis (CPDD)", SMALL)],
    [P("Ultrasound", SMALL_BOLD), P("Early synovitis, guide arthrocentesis, tendons/entheses", SMALL)],
    [P("MRI", SMALL_BOLD), P("Early erosions (RA), sacroiliac joints (AS), soft tissue", SMALL)],
    [P("CT", SMALL_BOLD), P("Bony detail; axial SpA, sacroiliitis", SMALL)],
    [P("Bone scan", SMALL_BOLD), P("Diffuse inflammatory activity across multiple joints", SMALL)],
]
cw_img = [2.2*cm, 4.1*cm]
img_t = Table(img_data, colWidths=cw_img)
img_t.setStyle(TableStyle([
    ("BACKGROUND",    (0,0), (-1,0),  RED),
    ("TEXTCOLOR",     (0,0), (-1,0),  WHITE),
    ("FONTNAME",      (0,0), (-1,0),  "Helvetica-Bold"),
    ("FONTSIZE",      (0,0), (-1,-1), 7),
    ("GRID",          (0,0), (-1,-1), 0.4, GREY_MID),
    ("ROWBACKGROUNDS",(0,1), (-1,-1), [WHITE, RED_LT]),
    ("VALIGN",        (0,0), (-1,-1), "MIDDLE"),
    ("TOPPADDING",    (0,0), (-1,-1), 3),
    ("BOTTOMPADDING", (0,0), (-1,-1), 3),
    ("LEFTPADDING",   (0,0), (-1,-1), 4),
    ("RIGHTPADDING",  (0,0), (-1,-1), 4),
    ("TEXTCOLOR",     (0,1), (-1,-1), GREY_DARK),
]))

sf_row = Table([[sf_t, cry_t, img_t]], colWidths=[11.0*cm, 3.5*cm, 6.5*cm+0.5*cm], hAlign="LEFT")
sf_row.setStyle(TableStyle([
    ("VALIGN", (0,0), (-1,-1), "TOP"),
    ("LEFTPADDING",  (0,0), (-1,-1), 0),
    ("RIGHTPADDING", (0,0), (-1,-1), 0),
    ("TOPPADDING",   (0,0), (-1,-1), 0),
    ("BOTTOMPADDING",(0,0), (-1,-1), 0),
]))
story.append(sf_row)
story.append(Spacer(1, 4))

# ══════════════════════════════════════════════════════════════════════════════
# STEP 5 — DIAGNOSTIC ALGORITHM (text-based flowchart)
# ══════════════════════════════════════════════════════════════════════════════
story.append(section_header("STEP 5 — DIAGNOSTIC ALGORITHM", bg=colors.HexColor("#2C3E50")))
story.append(Spacer(1, 3))

BOX_STYLE = ParagraphStyle("box", fontName="Helvetica-Bold", fontSize=7.5,
                            textColor=NAVY, alignment=TA_CENTER, leading=10)
BOX_SMALL = ParagraphStyle("boxs", fontName="Helvetica", fontSize=6.8,
                            textColor=GREY_DARK, alignment=TA_LEFT, leading=9)

def flow_box(text, bg, tc=NAVY, bold=True):
    fn = "Helvetica-Bold" if bold else "Helvetica"
    p = Paragraph(text, ParagraphStyle("fb", fontName=fn, fontSize=7.5,
                  textColor=tc, alignment=TA_CENTER, leading=10))
    t = Table([[p]])
    t.setStyle(TableStyle([
        ("BACKGROUND",    (0,0), (-1,-1), bg),
        ("BOX",           (0,0), (-1,-1), 0.8, GREY_DARK),
        ("TOPPADDING",    (0,0), (-1,-1), 4),
        ("BOTTOMPADDING", (0,0), (-1,-1), 4),
        ("LEFTPADDING",   (0,0), (-1,-1), 5),
        ("RIGHTPADDING",  (0,0), (-1,-1), 5),
    ]))
    return t

def arrow_cell(text="▼", col=GREY_DARK):
    return Paragraph(f'<font color="#{col.hexval()[1:] if hasattr(col,"hexval") else "495057"}">{text}</font>',
                     ParagraphStyle("arr", fontName="Helvetica-Bold", fontSize=10,
                                    alignment=TA_CENTER, leading=12))

# Build flowchart as a structured table
# Row labels: start, arrow, question1, branches, outcomes
ALGO = [
    # row 0: START
    [Paragraph("", BODY_C),
     flow_box("Polyarticular Joint Pain  (>4 joints)", TEAL_LIGHT),
     Paragraph("", BODY_C)],
    # row 1: arrow down
    [Paragraph("", BODY_C), Paragraph("▼", ParagraphStyle("a", fontName="Helvetica-Bold", fontSize=12, alignment=TA_CENTER)), Paragraph("", BODY_C)],
    # row 2: history + exam
    [Paragraph("", BODY_C),
     flow_box("Complete History & Physical Examination\nArticular vs. Periarticular?", colors.HexColor("#EAF6FB")),
     Paragraph("", BODY_C)],
    # row 3: split
    [flow_box("Periarticular", ORANGE_LT, tc=ORANGE, bold=False),
     Paragraph("", BODY_C),
     flow_box("Articular", TEAL_LIGHT, tc=TEAL, bold=False)],
    # row 4: periarticular outcome + spacer + articular question
    [Paragraph("→ Bursitis / Tendinitis\nSymptomatic Rx\nConsider viral testing",
               ParagraphStyle("peri", fontName="Helvetica", fontSize=7, textColor=ORANGE, leading=10)),
     Paragraph("", BODY_C),
     flow_box("Joint Effusion Present?", colors.HexColor("#EAF6FB"))],
    # row 5: No effusion / Yes effusion
    [Paragraph("", BODY_C),
     flow_box("NO effusion", GREEN_LT, tc=GREEN, bold=False),
     flow_box("YES → Arthrocentesis", RED_LT, tc=RED, bold=False)],
    # row 6: outcomes
    [Paragraph("", BODY_C),
     Paragraph("• Viral arthritis\n• Osteoarthritis\n• Early rheumatologic illness\n→ Outpatient viral / rheum testing",
               ParagraphStyle("ne", fontName="Helvetica", fontSize=6.8, textColor=GREEN, leading=9)),
     flow_box("Suggestive of Septic Arthritis?", RED_LT, tc=RED)],
    # row 7: septic branches
    [Paragraph("", BODY_C),
     Paragraph("", BODY_C),
     flow_box("NO                          YES", RED_LT, tc=RED, bold=False)],
    # row 8: septic outcomes
    [Paragraph("", BODY_C),
     Paragraph("NO:\n• Gout / Pseudogout\n• Crystal arthropathy\n• Rheumatologic illness\n• Seroneg. SpA, viral\n→ Close f/u + rheum referral",
               ParagraphStyle("ns", fontName="Helvetica", fontSize=6.8, textColor=GREY_DARK, leading=9)),
     Paragraph("YES:\n• GC swabs (genital/oral/skin)\n• Lyme serology (endemic areas)\n• Blood cultures\n→ IV antibiotics + ortho consult",
               ParagraphStyle("ys", fontName="Helvetica", fontSize=6.8, textColor=RED, leading=9))],
]

algo_t = Table(ALGO, colWidths=[3.8*cm, 9.4*cm, 4.3*cm])
algo_t.setStyle(TableStyle([
    ("VALIGN", (0,0), (-1,-1), "MIDDLE"),
    ("ALIGN",  (0,0), (-1,-1), "CENTER"),
    ("TOPPADDING",    (0,0), (-1,-1), 2),
    ("BOTTOMPADDING", (0,0), (-1,-1), 2),
    ("LEFTPADDING",   (0,0), (-1,-1), 2),
    ("RIGHTPADDING",  (0,0), (-1,-1), 2),
    ("SPAN",   (0,0), (2,0)),   # start box spans all
    ("SPAN",   (0,1), (2,1)),   # arrow
    ("SPAN",   (0,2), (2,2)),   # h&p box
]))
story.append(algo_t)
story.append(Spacer(1, 4))

# ══════════════════════════════════════════════════════════════════════════════
# STEP 6 — QUICK DISCRIMINATOR CLUES
# ══════════════════════════════════════════════════════════════════════════════
story.append(section_header("QUICK DISCRIMINATOR CLUES", bg=colors.HexColor("#7D3C98")))
story.append(Spacer(1, 3))

clue_data = [
    [P("Key Clue", COL_HEADER), P("Diagnosis", COL_HEADER),
     P("Key Clue", COL_HEADER), P("Diagnosis", COL_HEADER)],
    [P("Anti-CCP +ve + erosions on X-ray", SMALL_BOLD), P("Rheumatoid Arthritis", SMALL),
     P("Migratory + skin pustules + sexually active", SMALL_BOLD), P("Gonococcal arthritis", SMALL)],
    [P("ANA +ve + anti-dsDNA +ve", SMALL_BOLD), P("Systemic Lupus Erythematosus", SMALL),
     P("Post-pharyngitis + carditis + migratory", SMALL_BOLD), P("Acute Rheumatic Fever", SMALL)],
    [P("Ferritin >10,000 + quotidian fever + salmon rash", SMALL_BOLD), P("Adult-onset Still's", SMALL),
     P("Child contact: 'slapped cheek' rash", SMALL_BOLD), P("Parvovirus B19", SMALL)],
    [P("Needle crystals, negatively birefringent", SMALL_BOLD), P("Gout (MSU)", SMALL),
     P("Mosquito exposure / tropical travel", SMALL_BOLD), P("Chikungunya / Dengue / Zika", SMALL)],
    [P("Rhomboid crystals, weakly +ve birefringent", SMALL_BOLD), P("Pseudogout (CPDD)", SMALL),
     P("Proximal muscle weakness + elevated CK", SMALL_BOLD), P("Polymyositis / Dermatomyositis", SMALL)],
    [P("HLA-B27 + sacroiliitis + young male", SMALL_BOLD), P("Ankylosing Spondylitis", SMALL),
     P("Lung infiltrates + bilateral ankle swelling", SMALL_BOLD), P("Sarcoidosis (Löfgren's)", SMALL)],
    [P("Post-GI/GU infection + urethritis + conjunctivitis", SMALL_BOLD), P("Reactive Arthritis", SMALL),
     P("Serum sickness: drug/foreign protein exposure", SMALL_BOLD), P("Serum Sickness", SMALL)],
]

cw_clue = [5.8*cm, 3.5*cm, 5.8*cm, 3.5*cm]
clue_t = Table(clue_data, colWidths=cw_clue)
clue_t.setStyle(TableStyle([
    ("BACKGROUND",    (0,0), (-1,0),  colors.HexColor("#7D3C98")),
    ("TEXTCOLOR",     (0,0), (-1,0),  WHITE),
    ("FONTNAME",      (0,0), (-1,0),  "Helvetica-Bold"),
    ("FONTSIZE",      (0,0), (-1,-1), 7),
    ("GRID",          (0,0), (-1,-1), 0.4, GREY_MID),
    ("ROWBACKGROUNDS",(0,1), (-1,-1), [WHITE, PURPLE_LT]),
    ("VALIGN",        (0,0), (-1,-1), "MIDDLE"),
    ("TOPPADDING",    (0,0), (-1,-1), 3),
    ("BOTTOMPADDING", (0,0), (-1,-1), 3),
    ("LEFTPADDING",   (0,0), (-1,-1), 4),
    ("RIGHTPADDING",  (0,0), (-1,-1), 4),
    ("TEXTCOLOR",     (0,1), (-1,-1), GREY_DARK),
    ("LINEAFTER",     (1,0), (1,-1),  1.2, colors.HexColor("#7D3C98")),
]))
story.append(clue_t)
story.append(Spacer(1, 4))

# ══════════════════════════════════════════════════════════════════════════════
# FOOTER
# ══════════════════════════════════════════════════════════════════════════════
story.append(HRFlowable(width=W, thickness=0.5, color=GREY_MID))
story.append(Spacer(1, 2))
story.append(Paragraph(
    "Sources: Firestein & Kelley's Textbook of Rheumatology (2-Vol Set) • ROSEN's Emergency Medicine • "
    "Miller's Review of Orthopaedics 9E • Frameworks for Internal Medicine • Harrison's Principles of Internal Medicine 22E  |  "
    "Generated by Orris Medical Reference • July 2026",
    FOOT
))

# ══════════════════════════════════════════════════════════════════════════════
# BUILD
# ══════════════════════════════════════════════════════════════════════════════
doc.build(story)
print(f"PDF saved: {OUTPUT}")
Running Command

cd /tmp/workspace/polyarticular-chart && python generate_chart.py 2>&1

Editing File

~/polyarticular-chart/generate_chart.py

Successfully replaced 1 instance(s) of the string in '/tmp/workspace/polyarticular-chart/generate_chart.py'
Running Command

cd /tmp/workspace/polyarticular-chart && python generate_chart.py 2>&1

Running Command

ls -lh /tmp/workspace/polyarticular-chart/

Your diagnostic reference chart PDF is ready:

Polyarticular Pain Diagnostic Reference

PDF Document · PDF


What's included in the chart (single A4 page):
SectionContent
Step 1 — HistoryOnset/duration patterns, morning stiffness rule, joint distribution patterns, associated symptoms and exposure clues
Step 2 — Physical ExamInflammatory vs. non-inflammatory signs, key findings and their interpretations (effusion, deformities, dactylitis, tophi, etc.)
Step 3 — InvestigationsFull blood test panel with clinical significance (ESR, CRP, RF, anti-CCP, ANA, anti-dsDNA, ferritin, ASO, HLA-B27, cultures, and more)
Step 4 — Synovial Fluid + ImagingFluid analysis comparison table (normal vs. OA vs. inflammatory vs. septic), crystal analysis (gout vs. pseudogout birefringence), imaging modalities
Step 5 — Diagnostic AlgorithmStructured flowchart from presentation → H&P → effusion → arthrocentesis → septic vs. non-septic branches
Step 6 — Quick Discriminator Clues8 high-yield key clue → diagnosis pairings for rapid bedside reference
The chart uses colour-coded sections (teal for history, purple for exam, green for labs, red for fluids/imaging) for easy navigation during clinical use.

1. Psoriasis 2. Scabies 3. Stevens–Johnson Syndrome (SJS) 4. Pemphigus vulgaris 5. Acne vulgaris 6. Leprosy (Hansen’s disease) 7. Syphilis 8. Lichen planus Make me detail pdf of this topics of derma that I can write in mbbs proff exam

Your credits are exhausted. You can purchase a top-up or subscribe to a plan to continue using Orris. If you're already subscribed, your daily credits will reset tomorrow.

SLE

Your credits are exhausted. You can purchase a top-up or subscribe to a plan to continue using Orris. If you're already subscribed, your daily credits will reset tomorrow.
This is a shared conversation. Sign in to Orris to start your own chat.