Elicit Step wise medical history in rheumatoid arthritis

Reading File
Now let me search the medical library for rheumatoid arthritis history-taking content in parallel:
Finding Sources
Finding Sources
Good findings. Let me read the most relevant sections - the S Das manual on clinical surgery (excellent for history-taking), Goldman-Cecil Medicine RA section, and Firestein Rheumatology textbook:
Reading File
Reading File
Finding Sources
Finding Sources
Reading File
Finding Sources
Reading File
Now let me read the core Firestein & Kelley RA section and the Goldman-Cecil opening pages of the RA chapter:
Reading File
Reading File
Now let me get the main clinical presentation section from Firestein & Kelley block 4 (which has the large RA section):
Reading File
That block is about pathophysiology, not clinical history. Let me search for the clinical presentation/features section of Firestein's RA chapter:
Reading File
Reading File
Let me look at the block with clinical presentation/signs in Firestein (block 3) and the Goldman-Cecil opening of the RA chapter:
Reading File
Reading File
I now have comprehensive data from multiple authoritative sources. Let me compile the complete, stepwise medical history for rheumatoid arthritis.
Loading Image
I now have all the information needed. Here is the comprehensive stepwise medical history for rheumatoid arthritis:

Stepwise Medical History in Rheumatoid Arthritis

Severe advanced rheumatoid arthritis of both hands showing ulnar deviation at MCPs, swan-neck deformity, dorsal tendon swelling, and muscle wasting
Severe advanced RA: ulnar deviation at MCPs, swan-neck deformity, dorsal tendon swelling, and thenar wasting

Step 1 — Demographic Profile (Biodata)

  • Age: Peak onset is 40-60 years; RA can occur at any age including juvenile form (<16 years = JIA)
  • Sex: Female predominance (F:M = 3:1); sex hormones influence disease onset and severity
  • Occupation: Ask about repetitive joint use (manual labour, typing); disability impacting work is common
  • Marital status / living alone: Relevant for functional assessment and support

Step 2 — Chief Complaints

Elicit in the patient's own words, with duration for each:
  1. Joint pain (arthralgia/arthritis) - most common presenting complaint
  2. Joint swelling
  3. Morning stiffness
  4. Difficulty using hands / reduced grip
  5. Fatigue and generalized weakness
  6. Deformity (in chronic/advanced disease)

Step 3 — History of Presenting Illness (HOPI)

This is the core of the history. Address each complaint systematically:

A. Joint Pain

  • Site: Which joints are involved first? Classic RA starts in the small joints of the hands (PIP and MCP joints) and toes (MTP joints). Importantly, DIP joints are typically spared - their involvement suggests psoriatic arthritis or OA
  • Onset: Insidious (most common in RA) vs. acute; some patients have a palindromic pattern (migratory, episodic attacks)
  • Character: Dull aching; throbbing pain suggests acute inflammation
  • Radiation: Does it radiate? Cervical spine involvement can cause neck pain radiating to arms (C1-C2 subluxation)
  • Aggravating / Relieving factors: Pain worsens with activity, improves with warmth and gentle movement; pain is also reportedly aggravated during rainy seasons and at full/new moon
  • Severity: Score on a 0-10 numerical rating scale
  • Progression: Which joints were involved first? How did disease spread (additive vs. migratory vs. simultaneous)?
  • Symmetry: RA is characteristically bilateral and symmetric - involvement of both wrists, both MCPs, both PIPs

B. Joint Swelling

  • Which joints? Symmetrical involvement of small joints of hands and feet is characteristic
  • Is swelling soft (synovial effusion) or boggy (synovial proliferation/pannus)?
  • Is it persistent or intermittent?

C. Morning Stiffness - The Key Diagnostic Feature

  • Duration of morning stiffness - must be elicited precisely; in RA it lasts >1 hour (often hours) and is a hallmark feature
  • Distinguishes RA from OA (where stiffness lasts <30 minutes)
  • Ask: "When you wake up, how long does it take before your joints are as loose as they'll be for the rest of the day?"
  • Stiffness is relieved by warmth and activity

D. Functional Impairment

  • Difficulty gripping objects, opening jars, buttoning clothes
  • Difficulty walking, climbing stairs
  • Activities of daily living (ADL) assessment

E. Extra-articular Symptoms (Review of Systems Pertaining to RA)

Screen actively - these occur predominantly in seropositive (RF/ACPA-positive) patients:
SystemSymptoms to Ask
ConstitutionalFatigue (often pronounced), weight loss, low-grade fever, malaise
SkinSubcutaneous nodules (firm, non-tender, extensor surfaces - forearms, olecranon)
EyesDry eyes (Sicca/keratoconjunctivitis sicca), red eye (episcleritis, scleritis), visual changes
CardiovascularChest pain, palpitations, breathlessness (pericarditis, pleuritis, premature CAD)
RespiratoryDry cough, breathlessness (ILD, pleural effusion, rheumatoid nodules in lungs, rarely bronchiolitis obliterans)
NeurologicalTingling/numbness in hands (carpal tunnel syndrome - very common in RA), weakness in legs (cervical myelopathy from C1-C2 subluxation), stocking-glove neuropathy
ENTHoarseness, throat fullness (cricoarytenoid joint involvement)
HaematologicalPallor, easy bruising (anaemia of chronic disease; in Felty's syndrome: splenomegaly + neutropenia)
Urinary/RenalAnkle swelling (amyloidosis in long-standing RA)

Step 4 — Past Medical History

Ask specifically about:
  1. Previous episodes of joint pain/swelling - RA may have a palindromic prodrome
  2. History of tuberculosis, gonorrhoea, syphilis, typhoid or pneumonia - relevant to differential diagnosis of infective/reactive arthritis
  3. Previous trauma to joints - can precipitate or complicate OA
  4. Previous investigations - prior RF testing, X-rays, any previous diagnosis
  5. Previous treatment - steroids, NSAIDs, DMARDs; response to treatment helps confirm diagnosis
  6. Cardiovascular disease, diabetes, osteoporosis - important comorbidities and treatment considerations
  7. Thyroid disease - hypothyroidism commonly co-exists with RA and causes rheumatic symptoms

Step 5 — Treatment History

  • Current medications: NSAIDs, glucocorticoids (dose, duration), conventional DMARDs (methotrexate, hydroxychloroquine, sulfasalazine, leflunomide), biologic DMARDs (TNF inhibitors, IL-6 inhibitors, abatacept, rituximab), targeted synthetic DMARDs (JAK inhibitors - tofacitinib, baricitinib)
  • Response to treatment: Any improvement? Side effects?
  • Steroid history: Long-term use raises risk of osteoporosis, infections, adrenal suppression
  • NSAID use: GI bleeding risk, renal function monitoring required
  • Vaccinations: Ask about hepatitis B, pneumococcal, influenza status (essential before starting biologics)

Step 6 — Family History

  • Rheumatoid arthritis or autoimmune diseases in first-degree relatives - RA has a significant heritable component (~60% genetic contribution); risk in first-degree relatives is 3-5x higher
  • Haemophilia, gout, tuberculosis, rheumatic fever - relevant to differentials
  • Cardiovascular disease - RA patients have increased cardiovascular mortality; family history adds further risk
  • Family history of periodontal disease is also emerging as relevant (shared microbiome and citrullination pathways)

Step 7 — Personal / Social History

  • Smoking: A major environmental risk factor for seropositive RA; smoking promotes citrullination via PAD2 enzyme induction in alveolar macrophages; smokers have much higher ACPA levels (57% vs 7% in non-smokers)
  • Alcohol: Interacts with methotrexate (hepatotoxicity)
  • Diet: Mediterranean-style diet is protective; obesity worsens inflammation
  • Occupation: Joint stress; disability and work absence are early features even in pre-clinical disease
  • Physical activity level
  • Living situation: Support at home; ability to carry out ADLs independently
  • Stress / mental health: Psychological stress is a potential trigger; depression is a common comorbidity

Step 8 — Menstrual and Obstetric History (in women)

  • Pregnancy: RA classically improves during pregnancy (especially 2nd and 3rd trimester) and often flares postpartum
  • Oral contraceptive use: May be protective against developing RA
  • Menarche/menopause: Onset around or after menopause is common; hormonal influence on autoimmunity
  • Breastfeeding: Associated with postpartum flares

Step 9 — Systemic Review (remaining systems)

Briefly screen for:
  • GI: nausea, diarrhoea (NSAID/DMARD side effects; GI amyloidosis in chronic RA)
  • Genitourinary: proteinuria, oedema (amyloidosis, gold-induced membranous nephropathy)
  • CNS: memory, mood (depression in chronic pain)

Putting it Together: ACR/EULAR 2010 Classification Criteria (Diagnostic Aid)

When taking history, keep in mind the scoring framework you are building toward:
DomainScore
Joint involvement: 1 large joint = 0; 2-10 large joints = 1; 1-3 small joints = 2; 4-10 small joints = 3; >10 joints (at least 1 small) = 50-5
Serology: RF or ACPA negative = 0; low positive = 2; high positive (>3x ULN) = 30-3
Duration of synovitis: <6 weeks = 0; ≥6 weeks = 10-1
Acute phase reactants: Normal CRP and ESR = 0; Abnormal = 10-1
Score ≥6 = Definite RA. The history of duration of joint symptoms (≥6 weeks), pattern of joint involvement, and systemic features directly feeds into this scoring.

Summary: Red Flags in History Suggesting Poor Prognosis

Eliciting these in the history signals a need for aggressive early DMARD therapy:
  • High-titer RF or ACPA positivity
  • Many small joints involved at onset (score ≥5 joint domain)
  • Persistent elevated CRP/ESR
  • Early functional limitation
  • Extra-articular features
  • Erosions on imaging at presentation

Sources: Goldman-Cecil Medicine (9780323930345), Firestein & Kelley's Textbook of Rheumatology (9780323935364), S Das Manual on Clinical Surgery 13th Ed (9788190568104)

Generate a detailed patient history template for RA initial assessment

Asking for Preferences

What format would you like the template in?

Reading File
Running Command

mkdir -p /home/daytona/workspace/ra-template && ls /home/daytona/workspace/ra-template

Writing File

~/ra-template/generate_ra_template.py

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_LEFT, TA_CENTER, TA_RIGHT
from reportlab.platypus import (
    SimpleDocTemplate, Paragraph, Spacer, Table, TableStyle,
    HRFlowable, KeepTogether
)
from reportlab.pdfbase import pdfmetrics
from reportlab.pdfbase.ttfonts import TTFont
import os

OUTPUT_PATH = "/home/daytona/workspace/ra-template/RA_Initial_Assessment_Template.pdf"

# ── Colour palette ────────────────────────────────────────────────────────────
DEEP_BLUE    = colors.HexColor("#1A3A5C")
MID_BLUE     = colors.HexColor("#2E6DA4")
LIGHT_BLUE   = colors.HexColor("#D6E8F7")
ACCENT_RED   = colors.HexColor("#C0392B")
LIGHT_GREY   = colors.HexColor("#F4F6F8")
MID_GREY     = colors.HexColor("#BDC3C7")
DARK_GREY    = colors.HexColor("#2C3E50")
WHITE        = colors.white
FIELD_BG     = colors.HexColor("#FAFBFC")
SECTION_HDR  = colors.HexColor("#EBF3FB")

W, H = A4   # 210 x 297 mm

doc = SimpleDocTemplate(
    OUTPUT_PATH,
    pagesize=A4,
    topMargin=18*mm,
    bottomMargin=18*mm,
    leftMargin=18*mm,
    rightMargin=18*mm,
    title="Rheumatoid Arthritis – Initial Patient Assessment",
    author="Rheumatology Department",
)

styles = getSampleStyleSheet()

# ── Custom paragraph styles ───────────────────────────────────────────────────
def PS(name, parent="Normal", **kw):
    return ParagraphStyle(name, parent=styles[parent], **kw)

TITLE_STYLE  = PS("DocTitle",  fontSize=18, textColor=WHITE,        leading=22, alignment=TA_CENTER, spaceAfter=2)
SUBTITLE_S   = PS("DocSub",    fontSize=10, textColor=LIGHT_BLUE,   leading=13, alignment=TA_CENTER, spaceAfter=0)
SEC_HEAD     = PS("SecHead",   fontSize=10, textColor=WHITE,        leading=14, alignment=TA_LEFT,   spaceBefore=4, spaceAfter=2, fontName="Helvetica-Bold")
SUB_HEAD     = PS("SubHead",   fontSize=9,  textColor=MID_BLUE,    leading=12, alignment=TA_LEFT,   spaceBefore=3, spaceAfter=1, fontName="Helvetica-Bold")
LABEL        = PS("Label",     fontSize=8,  textColor=DARK_GREY,   leading=10, alignment=TA_LEFT,   fontName="Helvetica-Bold")
BODY         = PS("Body",      fontSize=8,  textColor=DARK_GREY,   leading=11, alignment=TA_LEFT)
SMALL        = PS("Small",     fontSize=7,  textColor=colors.HexColor("#7F8C8D"), leading=9, alignment=TA_LEFT)
NOTE         = PS("Note",      fontSize=7.5, textColor=ACCENT_RED, leading=10, alignment=TA_LEFT,  fontName="Helvetica-Oblique")
FIELD_LABEL  = PS("FLabel",    fontSize=7.5, textColor=colors.HexColor("#5D6D7E"), leading=10, fontName="Helvetica-Bold")

PAGE_W = W - 36*mm   # usable width

# ── Helper: blank write-in line ───────────────────────────────────────────────
def field_row(label, lines=1, height=7*mm):
    """Single labelled field with underline."""
    inner = [
        [Paragraph(label, FIELD_LABEL), ""],
    ]
    col_w = PAGE_W / 2
    t = Table(inner, colWidths=[col_w*0.38, col_w*0.62])
    t.setStyle(TableStyle([
        ("VALIGN",       (0,0), (-1,-1), "BOTTOM"),
        ("LINEBELOW",    (1,0), (1,0), 0.5, MID_GREY),
        ("BOTTOMPADDING",(0,0), (-1,-1), 2),
        ("TOPPADDING",   (0,0), (-1,-1), 2),
    ]))
    return t

def two_fields(lbl1, lbl2):
    """Two labelled fields side by side."""
    col = PAGE_W / 2
    data = [[Paragraph(lbl1, FIELD_LABEL), "", Paragraph(lbl2, FIELD_LABEL), ""]]
    t = Table(data, colWidths=[col*0.38, col*0.62, col*0.38, col*0.62])
    t.setStyle(TableStyle([
        ("VALIGN",       (0,0), (-1,-1), "BOTTOM"),
        ("LINEBELOW",    (1,0), (1,0), 0.5, MID_GREY),
        ("LINEBELOW",    (3,0), (3,0), 0.5, MID_GREY),
        ("BOTTOMPADDING",(0,0), (-1,-1), 2),
        ("TOPPADDING",   (0,0), (-1,-1), 2),
    ]))
    return t

def three_fields(lbl1, lbl2, lbl3):
    """Three labelled fields side by side."""
    col = PAGE_W / 3
    data = [[Paragraph(lbl1, FIELD_LABEL), "", Paragraph(lbl2, FIELD_LABEL), "", Paragraph(lbl3, FIELD_LABEL), ""]]
    t = Table(data, colWidths=[col*0.42, col*0.58, col*0.42, col*0.58, col*0.42, col*0.58])
    t.setStyle(TableStyle([
        ("VALIGN",       (0,0), (-1,-1), "BOTTOM"),
        ("LINEBELOW",    (1,0), (1,0), 0.5, MID_GREY),
        ("LINEBELOW",    (3,0), (3,0), 0.5, MID_GREY),
        ("LINEBELOW",    (5,0), (5,0), 0.5, MID_GREY),
        ("BOTTOMPADDING",(0,0), (-1,-1), 2),
        ("TOPPADDING",   (0,0), (-1,-1), 2),
    ]))
    return t

def section_header(title, icon=""):
    """Blue section header band."""
    data = [[Paragraph(f"{icon}  {title}", SEC_HEAD)]]
    t = Table(data, colWidths=[PAGE_W])
    t.setStyle(TableStyle([
        ("BACKGROUND",   (0,0), (-1,-1), DEEP_BLUE),
        ("TOPPADDING",   (0,0), (-1,-1), 5),
        ("BOTTOMPADDING",(0,0), (-1,-1), 5),
        ("LEFTPADDING",  (0,0), (-1,-1), 8),
    ]))
    return t

def sub_header(title):
    """Light-blue sub-section header."""
    data = [[Paragraph(title, SUB_HEAD)]]
    t = Table(data, colWidths=[PAGE_W])
    t.setStyle(TableStyle([
        ("BACKGROUND",   (0,0), (-1,-1), SECTION_HDR),
        ("TOPPADDING",   (0,0), (-1,-1), 3),
        ("BOTTOMPADDING",(0,0), (-1,-1), 3),
        ("LEFTPADDING",  (0,0), (-1,-1), 6),
        ("LINEBELOW",    (0,0), (-1,-1), 0.8, MID_BLUE),
    ]))
    return t

def checkbox_row(items, cols=3):
    """Row of tick-box options."""
    # Pad to fill cols
    while len(items) % cols != 0:
        items.append("")
    rows = [items[i:i+cols] for i in range(0, len(items), cols)]
    cell_w = PAGE_W / cols
    data = []
    for row in rows:
        data.append([Paragraph(f"☐  {item}" if item else "", BODY) for item in row])
    t = Table(data, colWidths=[cell_w]*cols)
    t.setStyle(TableStyle([
        ("VALIGN",       (0,0), (-1,-1), "MIDDLE"),
        ("TOPPADDING",   (0,0), (-1,-1), 2),
        ("BOTTOMPADDING",(0,0), (-1,-1), 2),
        ("LEFTPADDING",  (0,0), (-1,-1), 4),
    ]))
    return t

def text_box(label, height=14*mm):
    """Large multi-line text entry box."""
    data = [
        [Paragraph(label, FIELD_LABEL)],
        [""],
    ]
    t = Table(data, colWidths=[PAGE_W], rowHeights=[None, height])
    t.setStyle(TableStyle([
        ("BOX",          (0,0), (-1,-1), 0.5, MID_GREY),
        ("BACKGROUND",   (0,0), (-1,-1), FIELD_BG),
        ("TOPPADDING",   (0,0), (-1,-1), 3),
        ("LEFTPADDING",  (0,0), (-1,-1), 5),
        ("VALIGN",       (0,0), (-1,-1), "TOP"),
    ]))
    return t

def spacer(h=3*mm):
    return Spacer(1, h)

def hr():
    return HRFlowable(width=PAGE_W, thickness=0.4, color=MID_GREY, spaceAfter=2, spaceBefore=2)

# ── VAS / NRS scale ───────────────────────────────────────────────────────────
def pain_scale():
    """0-10 NRS pain scale boxes."""
    boxes = [str(i) for i in range(11)]
    col_w = PAGE_W / 11
    data = [boxes]
    t = Table(data, colWidths=[col_w]*11, rowHeights=[8*mm])
    style = [
        ("ALIGN",        (0,0), (-1,-1), "CENTER"),
        ("VALIGN",       (0,0), (-1,-1), "MIDDLE"),
        ("FONTNAME",     (0,0), (-1,-1), "Helvetica-Bold"),
        ("FONTSIZE",     (0,0), (-1,-1), 9),
        ("BOX",          (0,0), (-1,-1), 0.8, DEEP_BLUE),
        ("INNERGRID",    (0,0), (-1,-1), 0.5, DEEP_BLUE),
    ]
    # Colour: green→yellow→red
    green_cols  = [0,1,2,3]
    yellow_cols = [4,5,6]
    red_cols    = [7,8,9,10]
    for c in green_cols:
        style.append(("BACKGROUND", (c,0), (c,0), colors.HexColor("#D5F5E3")))
    for c in yellow_cols:
        style.append(("BACKGROUND", (c,0), (c,0), colors.HexColor("#FEF9E7")))
    for c in red_cols:
        style.append(("BACKGROUND", (c,0), (c,0), colors.HexColor("#FADBD8")))
    t.setStyle(TableStyle(style))
    return t

# ── Joint diagram table ───────────────────────────────────────────────────────
def joint_involvement_table():
    joints = [
        "MCP joints (2-5)",
        "PIP joints",
        "Wrists",
        "Elbows",
        "Shoulders",
        "Knees",
        "Ankles",
        "MTP joints",
        "Cervical spine",
        "Hips",
        "TMJ",
        "Cricoarytenoid",
    ]
    header = [
        Paragraph("Joint", FIELD_LABEL),
        Paragraph("Right", FIELD_LABEL),
        Paragraph("Left", FIELD_LABEL),
        Paragraph("Bilateral", FIELD_LABEL),
        Paragraph("Tenderness", FIELD_LABEL),
        Paragraph("Swelling", FIELD_LABEL),
        Paragraph("Warmth", FIELD_LABEL),
        Paragraph("Deformity", FIELD_LABEL),
    ]
    col_widths = [PAGE_W*0.20, PAGE_W*0.08, PAGE_W*0.08, PAGE_W*0.10,
                  PAGE_W*0.14, PAGE_W*0.10, PAGE_W*0.10, PAGE_W*0.10]
    rows = [header]
    for i, j in enumerate(joints):
        bg = LIGHT_GREY if i % 2 == 0 else WHITE
        rows.append([
            Paragraph(j, BODY), "☐", "☐", "☐", "☐", "☐", "☐", "☐"
        ])
    t = Table(rows, colWidths=col_widths)
    ts = TableStyle([
        ("BACKGROUND",   (0,0), (-1,0),  SECTION_HDR),
        ("FONTNAME",     (0,0), (-1,0),  "Helvetica-Bold"),
        ("FONTSIZE",     (0,0), (-1,-1), 8),
        ("ALIGN",        (1,0), (-1,-1), "CENTER"),
        ("VALIGN",       (0,0), (-1,-1), "MIDDLE"),
        ("ROWBACKGROUNDS",(0,1),(-1,-1), [LIGHT_GREY, WHITE]),
        ("INNERGRID",    (0,0), (-1,-1), 0.3, MID_GREY),
        ("BOX",          (0,0), (-1,-1), 0.8, MID_BLUE),
        ("TOPPADDING",   (0,0), (-1,-1), 3),
        ("BOTTOMPADDING",(0,0), (-1,-1), 3),
        ("LEFTPADDING",  (0,0), (-1,-1), 4),
    ])
    t.setStyle(ts)
    return t

# ── Extra-articular checklist table ──────────────────────────────────────────
def extra_articular_table():
    systems = [
        ("Constitutional",    "Fatigue  ☐    Weight loss  ☐    Low-grade fever  ☐    Malaise  ☐"),
        ("Skin / Nodules",    "Rheumatoid nodules  ☐    Vasculitis  ☐    Pyoderma gangrenosum  ☐"),
        ("Eyes",              "Dry eyes (sicca)  ☐    Episcleritis  ☐    Scleritis  ☐    Visual blurring  ☐"),
        ("Cardiovascular",    "Chest pain  ☐    Palpitations  ☐    Breathlessness on exertion  ☐    Pericarditis hx  ☐"),
        ("Respiratory",       "Dry cough  ☐    Breathlessness at rest  ☐    Pleuritic pain  ☐    Haemoptysis  ☐"),
        ("Neurological",      "Carpal tunnel syndrome  ☐    Tarsal tunnel  ☐    Cervical myelopathy  ☐    Peripheral neuropathy  ☐"),
        ("ENT",               "Hoarseness  ☐    Throat fullness  ☐    Stridor  ☐    Jaw pain (TMJ)  ☐"),
        ("Haematological",    "Pallor  ☐    Splenomegaly  ☐    Lymphadenopathy  ☐    Recurrent infections  ☐"),
        ("Renal",             "Oedema  ☐    Frothy urine (proteinuria)  ☐    Reduced urine output  ☐"),
        ("Gastrointestinal",  "Nausea/vomiting  ☐    GI bleeding  ☐    Mouth ulcers  ☐    Abdominal pain  ☐"),
    ]
    header = [Paragraph("System", FIELD_LABEL), Paragraph("Symptoms — circle / tick all present", FIELD_LABEL)]
    rows = [header]
    for s, sym in systems:
        rows.append([Paragraph(s, BODY), Paragraph(sym, BODY)])
    col_widths = [PAGE_W*0.20, PAGE_W*0.80]
    t = Table(rows, colWidths=col_widths)
    t.setStyle(TableStyle([
        ("BACKGROUND",    (0,0), (-1,0),  SECTION_HDR),
        ("FONTNAME",      (0,0), (-1,0),  "Helvetica-Bold"),
        ("FONTSIZE",      (0,0), (-1,-1), 7.5),
        ("VALIGN",        (0,0), (-1,-1), "TOP"),
        ("ROWBACKGROUNDS",(0,1),(-1,-1),  [LIGHT_GREY, WHITE]),
        ("INNERGRID",     (0,0), (-1,-1), 0.3, MID_GREY),
        ("BOX",           (0,0), (-1,-1), 0.8, MID_BLUE),
        ("TOPPADDING",    (0,0), (-1,-1), 3),
        ("BOTTOMPADDING", (0,0), (-1,-1), 3),
        ("LEFTPADDING",   (0,0), (-1,-1), 4),
    ]))
    return t

# ── ACR/EULAR scoring table ───────────────────────────────────────────────────
def acr_eular_table():
    data = [
        [Paragraph("Domain", FIELD_LABEL), Paragraph("Criteria", FIELD_LABEL), Paragraph("Score", FIELD_LABEL), Paragraph("Tick", FIELD_LABEL)],
        [Paragraph("Joint Involvement\n(select highest)", BODY),
         Paragraph("1 medium-large joint", BODY), Paragraph("0", BODY), "☐"],
        ["", Paragraph("2-10 medium-large joints", BODY), Paragraph("1", BODY), "☐"],
        ["", Paragraph("1-3 small joints", BODY), Paragraph("2", BODY), "☐"],
        ["", Paragraph("4-10 small joints", BODY), Paragraph("3", BODY), "☐"],
        ["", Paragraph(">10 joints incl. ≥1 small joint", BODY), Paragraph("5", BODY), "☐"],
        [Paragraph("Serology\n(select highest)", BODY),
         Paragraph("RF negative AND ACPA negative", BODY), Paragraph("0", BODY), "☐"],
        ["", Paragraph("RF or ACPA low positive (≤3× ULN)", BODY), Paragraph("2", BODY), "☐"],
        ["", Paragraph("RF or ACPA high positive (>3× ULN)", BODY), Paragraph("3", BODY), "☐"],
        [Paragraph("Duration of\nSynovitis", BODY),
         Paragraph("<6 weeks", BODY), Paragraph("0", BODY), "☐"],
        ["", Paragraph("≥6 weeks", BODY), Paragraph("1", BODY), "☐"],
        [Paragraph("Acute Phase\nReactants", BODY),
         Paragraph("Normal CRP and ESR", BODY), Paragraph("0", BODY), "☐"],
        ["", Paragraph("Abnormal CRP or ESR", BODY), Paragraph("1", BODY), "☐"],
        [Paragraph("TOTAL SCORE", FIELD_LABEL), Paragraph("Score ≥6 = Definite RA", NOTE),
         Paragraph("__ / 10", FIELD_LABEL), ""],
    ]
    col_widths = [PAGE_W*0.22, PAGE_W*0.52, PAGE_W*0.14, PAGE_W*0.12]
    t = Table(data, colWidths=col_widths)
    t.setStyle(TableStyle([
        ("BACKGROUND",    (0,0), (-1,0),   SECTION_HDR),
        ("FONTNAME",      (0,0), (-1,0),   "Helvetica-Bold"),
        ("FONTSIZE",      (0,0), (-1,-1),  8),
        ("VALIGN",        (0,0), (-1,-1),  "MIDDLE"),
        ("ALIGN",         (2,0), (3,-1),   "CENTER"),
        ("SPAN",          (0,1), (0,5)),
        ("SPAN",          (0,6), (0,8)),
        ("SPAN",          (0,9), (0,10)),
        ("SPAN",          (0,11),(0,12)),
        ("INNERGRID",     (0,0), (-1,-1),  0.3, MID_GREY),
        ("BOX",           (0,0), (-1,-1),  0.8, MID_BLUE),
        ("BACKGROUND",    (0,-1),(-1,-1),  colors.HexColor("#EBF3FB")),
        ("FONTNAME",      (0,-1),(-1,-1),  "Helvetica-Bold"),
        ("TOPPADDING",    (0,0), (-1,-1),  3),
        ("BOTTOMPADDING", (0,0), (-1,-1),  3),
        ("LEFTPADDING",   (0,0), (-1,-1),  5),
        ("ROWBACKGROUNDS",(0,1), (-1,-2),  [LIGHT_GREY, WHITE]),
    ]))
    return t

# ── Disease activity scores ───────────────────────────────────────────────────
def das28_table():
    data = [
        [Paragraph("DAS28 Component", FIELD_LABEL),
         Paragraph("Value", FIELD_LABEL),
         Paragraph("DAS28 Interpretation", FIELD_LABEL),
         Paragraph("Threshold", FIELD_LABEL)],
        [Paragraph("Tender joint count (28)", BODY), "____",
         Paragraph("Remission", BODY), Paragraph("< 2.6", BODY)],
        [Paragraph("Swollen joint count (28)", BODY), "____",
         Paragraph("Low disease activity", BODY), Paragraph("2.6 – 3.2", BODY)],
        [Paragraph("ESR (mm/hr)  or  CRP (mg/L)", BODY), "____",
         Paragraph("Moderate disease activity", BODY), Paragraph("3.2 – 5.1", BODY)],
        [Paragraph("Patient global VAS (0-100 mm)", BODY), "____",
         Paragraph("High disease activity", BODY), Paragraph("> 5.1", BODY)],
        [Paragraph("DAS28 Score:", FIELD_LABEL), "____________",
         Paragraph("Interpretation:", FIELD_LABEL), "_______________"],
    ]
    col_widths = [PAGE_W*0.35, PAGE_W*0.15, PAGE_W*0.32, PAGE_W*0.18]
    t = Table(data, colWidths=col_widths)
    t.setStyle(TableStyle([
        ("BACKGROUND",    (0,0), (-1,0),  SECTION_HDR),
        ("FONTNAME",      (0,0), (-1,0),  "Helvetica-Bold"),
        ("FONTSIZE",      (0,0), (-1,-1), 8),
        ("VALIGN",        (0,0), (-1,-1), "MIDDLE"),
        ("INNERGRID",     (0,0), (-1,-1), 0.3, MID_GREY),
        ("BOX",           (0,0), (-1,-1), 0.8, MID_BLUE),
        ("ROWBACKGROUNDS",(0,1),(-1,-2),  [LIGHT_GREY, WHITE]),
        ("BACKGROUND",    (0,-1),(-1,-1), colors.HexColor("#EBF3FB")),
        ("FONTNAME",      (0,-1),(-1,-1), "Helvetica-Bold"),
        ("TOPPADDING",    (0,0), (-1,-1), 3),
        ("BOTTOMPADDING", (0,0), (-1,-1), 3),
        ("LEFTPADDING",   (0,0), (-1,-1), 5),
    ]))
    return t

# ─────────────────────────────────────────────────────────────────────────────
#  TITLE PAGE / HEADER
# ─────────────────────────────────────────────────────────────────────────────
def build_header():
    title_data = [
        [Paragraph("RHEUMATOID ARTHRITIS", TITLE_STYLE)],
        [Paragraph("Initial Patient Assessment Template", SUBTITLE_S)],
        [Paragraph("ACR/EULAR 2010 Classification Criteria | DAS28 | Disease Activity Monitoring", SUBTITLE_S)],
    ]
    t = Table(title_data, colWidths=[PAGE_W])
    t.setStyle(TableStyle([
        ("BACKGROUND",   (0,0), (-1,-1), DEEP_BLUE),
        ("TOPPADDING",   (0,0), (-1,-1), 7),
        ("BOTTOMPADDING",(0,0), (-1,-1), 6),
        ("LEFTPADDING",  (0,0), (-1,-1), 10),
    ]))
    return t


# ─────────────────────────────────────────────────────────────────────────────
#  BUILD DOCUMENT
# ─────────────────────────────────────────────────────────────────────────────
story = []

# Title
story.append(build_header())
story.append(spacer(4*mm))

# ── SECTION 1: PATIENT DEMOGRAPHICS ─────────────────────────────────────────
story.append(section_header("1.  PATIENT DEMOGRAPHICS"))
story.append(spacer(2*mm))
story.append(three_fields("Patient Name:", "Date of Birth:", "Age (yrs):"))
story.append(spacer(2*mm))
story.append(three_fields("Hospital / MRN:", "Date of Assessment:", "Clinician:"))
story.append(spacer(2*mm))
story.append(two_fields("Sex:  ☐ Male   ☐ Female   ☐ Other", "Marital Status:"))
story.append(spacer(2*mm))
story.append(two_fields("Occupation:", "Educational level:"))
story.append(spacer(2*mm))
story.append(two_fields("Address / Contact:", "Referred by:"))
story.append(spacer(4*mm))

# ── SECTION 2: CHIEF COMPLAINTS ─────────────────────────────────────────────
story.append(section_header("2.  CHIEF COMPLAINTS  (with duration)"))
story.append(spacer(2*mm))
complaints = [
    "Joint pain (arthralgia / arthritis)", "Joint swelling",
    "Morning stiffness", "Difficulty using hands / reduced grip",
    "Fatigue / generalised weakness", "Joint deformity",
    "Other:"
]
for i, c in enumerate(complaints):
    data = [[
        Paragraph(f"{i+1}.  {c}", BODY),
        Paragraph("Duration:", FIELD_LABEL),
        "",
    ]]
    t = Table(data, colWidths=[PAGE_W*0.55, PAGE_W*0.15, PAGE_W*0.30])
    t.setStyle(TableStyle([
        ("VALIGN",       (0,0), (-1,-1), "BOTTOM"),
        ("LINEBELOW",    (2,0), (2,0), 0.5, MID_GREY),
        ("TOPPADDING",   (0,0), (-1,-1), 2),
        ("BOTTOMPADDING",(0,0), (-1,-1), 2),
    ]))
    story.append(t)
story.append(spacer(4*mm))

# ── SECTION 3: HISTORY OF PRESENTING ILLNESS ────────────────────────────────
story.append(section_header("3.  HISTORY OF PRESENTING ILLNESS (HOPI)"))
story.append(spacer(2*mm))

# 3A – Joint Pain
story.append(sub_header("A.  Joint Pain"))
story.append(spacer(1*mm))

story.append(two_fields("Site (which joints first involved)?", "Current joints involved:"))
story.append(spacer(2*mm))

story.append(Paragraph("Onset:", FIELD_LABEL))
story.append(checkbox_row(["Insidious (gradual)", "Acute / sudden", "Palindromic (episodic, migratory)", "Polyarticular from start", "Oligoarticular from start"], cols=3))
story.append(spacer(2*mm))

story.append(Paragraph("Character of pain:", FIELD_LABEL))
story.append(checkbox_row(["Dull aching", "Throbbing", "Burning", "Sharp", "Deep boring"], cols=5))
story.append(spacer(2*mm))

story.append(Paragraph("Pattern of joint involvement:", FIELD_LABEL))
story.append(checkbox_row(["Symmetric bilateral", "Asymmetric", "Additive (new joints added)", "Migratory (moves joint to joint)", "Persistent in same joints"], cols=3))
story.append(spacer(2*mm))

story.append(Paragraph("Aggravating factors:", FIELD_LABEL))
story.append(checkbox_row(["Activity / movement", "Rest", "Cold / rainy weather", "New / full moon", "Morning / after inactivity", "Stress"], cols=3))
story.append(spacer(2*mm))

story.append(Paragraph("Relieving factors:", FIELD_LABEL))
story.append(checkbox_row(["Warmth / heat", "Gentle movement", "NSAIDs / analgesics", "Steroids", "Rest"], cols=5))
story.append(spacer(2*mm))

story.append(Paragraph("Radiation:", FIELD_LABEL))
story.append(checkbox_row(["No radiation", "Neck → arm (cervical involvement)", "Wrist → hand (carpal tunnel)", "Other:"], cols=4))
story.append(spacer(2*mm))

story.append(Paragraph("Pain severity — NRS (circle number):", FIELD_LABEL))
story.append(spacer(1*mm))
story.append(pain_scale())
story.append(Paragraph("0 = No pain   |   10 = Worst imaginable pain", SMALL))
story.append(spacer(3*mm))

# 3B – Stiffness
story.append(sub_header("B.  Morning Stiffness  — KEY DIAGNOSTIC FEATURE"))
story.append(spacer(1*mm))
story.append(Paragraph("⚠  In RA, morning stiffness typically lasts >1 hour. Duration differentiates RA (>1 hr) from OA (<30 min).", NOTE))
story.append(spacer(2*mm))

data = [
    [Paragraph("Duration of morning stiffness:", FIELD_LABEL), "", ""],
    [Paragraph("☐  <30 minutes", BODY), Paragraph("☐  30–60 minutes", BODY), Paragraph("☐  >1 hour — specify: ___ hrs ___ mins", BODY)],
]
t = Table(data, colWidths=[PAGE_W/3]*3)
t.setStyle(TableStyle([
    ("SPAN",         (0,0), (2,0)),
    ("LINEBELOW",    (0,0), (2,0), 0.5, MID_GREY),
    ("TOPPADDING",   (0,0), (-1,-1), 2),
    ("BOTTOMPADDING",(0,0), (-1,-1), 2),
]))
story.append(t)
story.append(spacer(2*mm))
story.append(Paragraph("Is stiffness relieved by:  ☐ Warmth   ☐ Movement   ☐ Hot shower   ☐ Other: _______________", BODY))
story.append(spacer(3*mm))

# 3C – Swelling
story.append(sub_header("C.  Joint Swelling"))
story.append(spacer(1*mm))
story.append(Paragraph("Nature of swelling:  ☐ Soft (effusion)   ☐ Boggy (synovial proliferation/pannus)   ☐ Bony / hard (late disease)", BODY))
story.append(spacer(2*mm))
story.append(Paragraph("Distribution:  ☐ Symmetric   ☐ Asymmetric   ☐ Migratory", BODY))
story.append(spacer(3*mm))

# 3D – Functional Impact
story.append(sub_header("D.  Functional Impairment (HAQ proxy)"))
story.append(spacer(1*mm))
story.append(Paragraph("Can the patient perform the following? (☐ Yes  ☐ No  ☐ With difficulty)", FIELD_LABEL))
story.append(spacer(1*mm))
functional_items = [
    "Dress / button clothes", "Grip objects / open jar", "Walk on flat ground",
    "Climb stairs", "Turn taps / doorknobs", "Write / type",
    "Rise from chair unaided", "Carry shopping bag", "Sleep without pain waking them"
]
story.append(checkbox_row(functional_items, cols=3))
story.append(spacer(4*mm))

# ── SECTION 4: EXTRA-ARTICULAR MANIFESTATIONS ────────────────────────────────
story.append(section_header("4.  EXTRA-ARTICULAR MANIFESTATIONS  (review of systems)"))
story.append(spacer(2*mm))
story.append(Paragraph("More common in RF-positive / ACPA-positive seropositive patients. Tick all that are present.", SMALL))
story.append(spacer(2*mm))
story.append(extra_articular_table())
story.append(spacer(4*mm))

# ── SECTION 5: JOINT INVOLVEMENT MAP ─────────────────────────────────────────
story.append(section_header("5.  JOINT INVOLVEMENT MAP"))
story.append(spacer(2*mm))
story.append(Paragraph("Tick each joint involved. Note: RA characteristically SPARES DIP joints — involvement suggests PsA or OA.", NOTE))
story.append(spacer(2*mm))
story.append(joint_involvement_table())
story.append(spacer(2*mm))
story.append(two_fields("Total tender joint count (TJC):", "Total swollen joint count (SJC):"))
story.append(spacer(4*mm))

# ── SECTION 6: PAST MEDICAL HISTORY ──────────────────────────────────────────
story.append(section_header("6.  PAST MEDICAL HISTORY"))
story.append(spacer(2*mm))

pmh_items = [
    ("Previous episodes of joint pain / swelling?", "☐ Yes  ☐ No"),
    ("Tuberculosis?", "☐ Yes  ☐ No"),
    ("Gonorrhoea / sexually transmitted infection?", "☐ Yes  ☐ No"),
    ("Hepatitis B or C?", "☐ Yes  ☐ No"),
    ("Cardiovascular disease (IHD, HF, stroke)?", "☐ Yes  ☐ No"),
    ("Diabetes mellitus?", "☐ Yes  ☐ No"),
    ("Hypertension?", "☐ Yes  ☐ No"),
    ("Osteoporosis / osteopenia?", "☐ Yes  ☐ No"),
    ("Hypothyroidism?", "☐ Yes  ☐ No"),
    ("Sicca syndrome / Sjogren's?", "☐ Yes  ☐ No"),
    ("Malignancy?", "☐ Yes  ☐ No"),
    ("Previous joint surgery / arthroplasty?", "☐ Yes  ☐ No"),
    ("Serious infections (hospitalisation)?", "☐ Yes  ☐ No"),
    ("Other:  __________________________________", "☐ Yes  ☐ No"),
]
pmh_rows = [[Paragraph(q, BODY), Paragraph(a, BODY)] for q, a in pmh_items]
t = Table(pmh_rows, colWidths=[PAGE_W*0.75, PAGE_W*0.25])
t.setStyle(TableStyle([
    ("FONTSIZE",      (0,0), (-1,-1), 8),
    ("ROWBACKGROUNDS",(0,0),(-1,-1),  [LIGHT_GREY, WHITE]),
    ("INNERGRID",     (0,0), (-1,-1), 0.3, MID_GREY),
    ("BOX",           (0,0), (-1,-1), 0.8, MID_BLUE),
    ("TOPPADDING",    (0,0), (-1,-1), 3),
    ("BOTTOMPADDING", (0,0), (-1,-1), 3),
    ("LEFTPADDING",   (0,0), (-1,-1), 5),
    ("VALIGN",        (0,0), (-1,-1), "MIDDLE"),
]))
story.append(t)
story.append(spacer(4*mm))

# ── SECTION 7: DRUG / TREATMENT HISTORY ──────────────────────────────────────
story.append(section_header("7.  DRUG AND TREATMENT HISTORY"))
story.append(spacer(2*mm))

tx_headers = [
    Paragraph("Drug / Treatment", FIELD_LABEL),
    Paragraph("Dose", FIELD_LABEL),
    Paragraph("Duration", FIELD_LABEL),
    Paragraph("Response", FIELD_LABEL),
    Paragraph("Side Effects", FIELD_LABEL),
]
tx_rows = [tx_headers]
for _ in range(7):
    tx_rows.append(["", "", "", "", ""])
t = Table(tx_rows, colWidths=[PAGE_W*0.28, PAGE_W*0.14, PAGE_W*0.14, PAGE_W*0.22, PAGE_W*0.22],
          rowHeights=[None] + [8*mm]*7)
t.setStyle(TableStyle([
    ("BACKGROUND",    (0,0), (-1,0),  SECTION_HDR),
    ("FONTNAME",      (0,0), (-1,0),  "Helvetica-Bold"),
    ("FONTSIZE",      (0,0), (-1,-1), 8),
    ("INNERGRID",     (0,0), (-1,-1), 0.3, MID_GREY),
    ("BOX",           (0,0), (-1,-1), 0.8, MID_BLUE),
    ("VALIGN",        (0,0), (-1,-1), "MIDDLE"),
    ("ROWBACKGROUNDS",(0,1),(-1,-1),  [LIGHT_GREY, WHITE]),
    ("TOPPADDING",    (0,0), (-1,-1), 3),
    ("BOTTOMPADDING", (0,0), (-1,-1), 3),
    ("LEFTPADDING",   (0,0), (-1,-1), 4),
]))
story.append(t)
story.append(spacer(2*mm))

story.append(Paragraph("Vaccination status (essential before biologic therapy):", FIELD_LABEL))
story.append(spacer(1*mm))
story.append(checkbox_row(["Hepatitis B  ☐ Done  ☐ Not done", "Pneumococcal  ☐ Done  ☐ Not done",
                            "Influenza (annual)  ☐ Done  ☐ Not done",
                            "COVID-19  ☐ Done  ☐ Not done",
                            "Varicella Zoster  ☐ Done  ☐ Not done",
                            "Herpes Zoster  ☐ Done  ☐ Not done"], cols=3))
story.append(spacer(4*mm))

# ── SECTION 8: ALLERGIES ─────────────────────────────────────────────────────
story.append(section_header("8.  DRUG ALLERGIES AND ADVERSE REACTIONS"))
story.append(spacer(2*mm))
story.append(text_box("Drug / Agent → Type of reaction → Date (if known):", height=12*mm))
story.append(spacer(4*mm))

# ── SECTION 9: FAMILY HISTORY ────────────────────────────────────────────────
story.append(section_header("9.  FAMILY HISTORY"))
story.append(spacer(2*mm))

fh_items = [
    ("Rheumatoid arthritis (first-degree relatives)?", "☐ Yes  ☐ No  ☐ Unknown"),
    ("Other autoimmune disease (SLE, psoriasis, IBD, thyroid)?", "☐ Yes  ☐ No  ☐ Unknown"),
    ("Gout?", "☐ Yes  ☐ No  ☐ Unknown"),
    ("Tuberculosis?", "☐ Yes  ☐ No  ☐ Unknown"),
    ("Premature cardiovascular disease?", "☐ Yes  ☐ No  ☐ Unknown"),
    ("Malignancy?", "☐ Yes  ☐ No  ☐ Unknown"),
    ("Periodontal disease (gum disease)?", "☐ Yes  ☐ No  ☐ Unknown"),
]
fh_rows = [[Paragraph(q, BODY), Paragraph(a, BODY)] for q, a in fh_items]
t = Table(fh_rows, colWidths=[PAGE_W*0.70, PAGE_W*0.30])
t.setStyle(TableStyle([
    ("FONTSIZE",      (0,0), (-1,-1), 8),
    ("ROWBACKGROUNDS",(0,0),(-1,-1),  [LIGHT_GREY, WHITE]),
    ("INNERGRID",     (0,0), (-1,-1), 0.3, MID_GREY),
    ("BOX",           (0,0), (-1,-1), 0.8, MID_BLUE),
    ("TOPPADDING",    (0,0), (-1,-1), 3),
    ("BOTTOMPADDING", (0,0), (-1,-1), 3),
    ("LEFTPADDING",   (0,0), (-1,-1), 5),
    ("VALIGN",        (0,0), (-1,-1), "MIDDLE"),
]))
story.append(t)
story.append(spacer(2*mm))
story.append(text_box("Additional family history details:", height=10*mm))
story.append(spacer(4*mm))

# ── SECTION 10: PERSONAL / SOCIAL HISTORY ────────────────────────────────────
story.append(section_header("10.  PERSONAL AND SOCIAL HISTORY"))
story.append(spacer(2*mm))

story.append(Paragraph("Smoking status:", FIELD_LABEL))
story.append(Paragraph(
    "☐ Never smoked     ☐ Ex-smoker — Quit date: ___________   Pack-years: ______     ☐ Current smoker — Pack-years: ______",
    BODY))
story.append(Paragraph("Note: Smoking is a major environmental risk factor for seropositive RA (ACPA/RF). Promotes PAD enzyme-mediated citrullination.", NOTE))
story.append(spacer(2*mm))

story.append(Paragraph("Alcohol:", FIELD_LABEL))
story.append(Paragraph(
    "☐ None     ☐ Occasional (<14 units/week)     ☐ Regular (>14 units/week)  "
    "  Units/week: ______   (Critical: interacts with methotrexate — hepatotoxicity risk)",
    BODY))
story.append(spacer(2*mm))

story.append(two_fields("Occupation (current / previous):", "Occupational exposures:"))
story.append(spacer(2*mm))

story.append(Paragraph("Physical activity:", FIELD_LABEL))
story.append(checkbox_row(["Sedentary", "Light activity", "Moderate exercise", "Vigorous exercise"], cols=4))
story.append(spacer(2*mm))

story.append(two_fields("Diet (Mediterranean? Obesity?):", "BMI: ____  kg/m²"))
story.append(spacer(2*mm))

story.append(Paragraph("Living situation:", FIELD_LABEL))
story.append(checkbox_row(["Lives alone", "Lives with family", "Carer available at home",
                            "Independent in ADLs", "Requires ADL assistance"], cols=3))
story.append(spacer(2*mm))

story.append(two_fields("Socioeconomic status:", "Mental health / Depression screening:"))
story.append(spacer(4*mm))

# ── SECTION 11: MENSTRUAL / OBSTETRIC HISTORY (women) ────────────────────────
story.append(section_header("11.  MENSTRUAL AND OBSTETRIC HISTORY  (women only)"))
story.append(spacer(2*mm))
story.append(Paragraph("Note: RA classically IMPROVES during pregnancy (2nd/3rd trimester) and FLARES postpartum.", NOTE))
story.append(spacer(2*mm))

story.append(three_fields("Menarche age:", "Menopause age:", "LMP:"))
story.append(spacer(2*mm))
story.append(two_fields("Gravida: ____  Para: ____", "Miscarriages: ____"))
story.append(spacer(2*mm))
story.append(Paragraph("Oral contraceptive use:  ☐ Never   ☐ Past   ☐ Current  (may be protective against RA onset)", BODY))
story.append(spacer(2*mm))
story.append(Paragraph("Postpartum flare experienced?  ☐ Yes   ☐ No", BODY))
story.append(spacer(2*mm))
story.append(two_fields("Current contraception (if relevant):", "Planning pregnancy?  ☐ Yes  ☐ No"))
story.append(spacer(4*mm))

# ── SECTION 12: ACR/EULAR CLASSIFICATION CRITERIA ───────────────────────────
story.append(section_header("12.  ACR/EULAR 2010 CLASSIFICATION CRITERIA  (Score ≥6 = Definite RA)"))
story.append(spacer(2*mm))
story.append(acr_eular_table())
story.append(spacer(4*mm))

# ── SECTION 13: DISEASE ACTIVITY ASSESSMENT ──────────────────────────────────
story.append(section_header("13.  DISEASE ACTIVITY ASSESSMENT  —  DAS28"))
story.append(spacer(2*mm))
story.append(das28_table())
story.append(spacer(2*mm))
story.append(two_fields("CDAI score:", "SDAI score:"))
story.append(spacer(4*mm))

# ── SECTION 14: INVESTIGATIONS REQUESTED ─────────────────────────────────────
story.append(section_header("14.  INVESTIGATIONS REQUESTED"))
story.append(spacer(2*mm))

story.append(sub_header("Serology / Immunology"))
story.append(checkbox_row([
    "Rheumatoid Factor (RF)", "Anti-CCP (ACPA)", "ANA",
    "Anti-dsDNA", "Anti-Sm", "ANCA",
    "Complement C3/C4", "Immunoglobulins", "Cryoglobulins",
], cols=3))
story.append(spacer(2*mm))

story.append(sub_header("Haematology / Biochemistry"))
story.append(checkbox_row([
    "Full Blood Count (FBC)", "ESR", "CRP",
    "Urea + Creatinine + eGFR", "Liver Function Tests", "Uric acid",
    "Fasting glucose / HbA1c", "Thyroid function (TSH)", "Lipid profile",
    "Serum calcium / phosphate", "Vitamin D (25-OH)", "Urine dipstick / PCR",
], cols=3))
story.append(spacer(2*mm))

story.append(sub_header("Imaging"))
story.append(checkbox_row([
    "X-ray hands / wrists (PA)", "X-ray feet (DP)", "X-ray cervical spine (lateral flexion/extension)",
    "Ultrasound joints (specify): ___________", "MRI (specify): ___________",
    "DEXA scan (bone density)",
    "Chest X-ray", "HRCT chest (ILD screen)", "Echocardiogram",
], cols=3))
story.append(spacer(2*mm))

story.append(sub_header("Pre-biologic / Pre-DMARD Screening"))
story.append(checkbox_row([
    "Mantoux / Quantiferon-TB Gold (TB screening)", "Hepatitis B sAg + sAb + cAb",
    "Hepatitis C antibody", "HIV (if indicated)",
    "VDRL / syphilis screen (if indicated)", "Varicella IgG titres",
], cols=2))
story.append(spacer(4*mm))

# ── SECTION 15: CLINICIAN ASSESSMENT & PLAN ──────────────────────────────────
story.append(section_header("15.  CLINICIAN ASSESSMENT AND MANAGEMENT PLAN"))
story.append(spacer(2*mm))
story.append(text_box("Diagnosis / Working Diagnosis:", height=10*mm))
story.append(spacer(2*mm))
story.append(text_box("Differential Diagnoses:", height=10*mm))
story.append(spacer(2*mm))
story.append(text_box("Management Plan (DMARDs, biologics, NSAIDs, steroids, physio, OT, surgical referral):", height=20*mm))
story.append(spacer(2*mm))
story.append(text_box("Patient Education Points Discussed:", height=12*mm))
story.append(spacer(2*mm))
story.append(two_fields("Review date:", "Rheumatologist signature:"))
story.append(spacer(4*mm))

# ── FOOTER NOTE ───────────────────────────────────────────────────────────────
story.append(hr())
story.append(Paragraph(
    "Template based on ACR/EULAR 2010 RA Classification Criteria | Aletaha D et al. Arthritis Rheum 2010;62:2569–2581 | "
    "Goldman-Cecil Medicine | Firestein & Kelley's Textbook of Rheumatology | S Das Manual on Clinical Surgery",
    SMALL
))
story.append(Paragraph("For clinical use only. Not a substitute for individual clinical judgement.", SMALL))

# ── BUILD ──────────────────────────────────────────────────────────────────────
doc.build(story)
print(f"PDF generated: {OUTPUT_PATH}")
Running Command

cd /home/daytona/workspace/ra-template && python generate_ra_template.py 2>&1

Running Command

ls -lh /home/daytona/workspace/ra-template/RA_Initial_Assessment_Template.pdf

Your PDF is ready. Download it here:

RA Initial Assessment Template

PDF Document · PDF


Here's what the template covers across 15 structured sections:
#SectionHighlights
1Patient DemographicsName, DOB, MRN, clinician, referral
2Chief Complaints7 common RA complaints with duration fields
3HOPIJoint pain (site, onset, character, pattern, aggravating/relieving), NRS pain scale (colour-coded 0-10), morning stiffness with tick-boxes, swelling characterisation, HAQ-proxy functional checklist
4Extra-articular Manifestations10-system table (constitutional, skin, eyes, CVS, respiratory, neuro, ENT, haem, renal, GI) with tick-box symptoms
5Joint Involvement Map12-joint grid with columns for R/L/bilateral, tenderness, swelling, warmth, deformity; TJC and SJC fields
6Past Medical History14-item checklist (TB, hepatitis, CV disease, osteoporosis, thyroid, malignancy etc.)
7Drug & Treatment History7-row medication table (drug, dose, duration, response, side effects) + vaccination status
8AllergiesFree-text reaction log
9Family HistoryRA, autoimmune, gout, TB, premature CVD, periodontal disease
10Personal / Social HistorySmoking (pack-years), alcohol (MTX interaction warning), diet/BMI, occupation, ADL independence
11Menstrual / Obstetric HistoryPregnancy improvement / postpartum flare note, OCP use, contraception
12ACR/EULAR 2010 CriteriaScoring table for joint involvement, serology, synovitis duration, acute phase reactants (score ≥6 = definite RA)
13Disease Activity — DAS28TJC/SJC/ESR/global VAS entry fields with DAS28 interpretation thresholds
14InvestigationsSerology, haematology, imaging, pre-biologic/pre-DMARD screening checklists
15Assessment & PlanDiagnosis, differentials, management plan, patient education, review date
This is a shared conversation. Sign in to Orris to start your own chat.