Nuclear medicine in orthopedics

Nuclear medicine in orthopedics. Introduction 2. History (if relevant) 3. Anatomy 4. Etiology 5. Mechanism (if applicable) 6. Pathology 7. Clinical Features 8. Investigation 9. Radiograph 10. CT 11. MRI 12. Classification 13. Treatment A. Non-operative B. Operative 14. Recent Advances. Follow above pattern for answers

Reading File
Finding Sources
Finding Sources
Searching PubMed

"nuclear medicine" AND "orthopedics" AND bone scan

Finding Sources
Finding Sources
Reading Article

PMID: 39283958

Finding Sources
Finding Sources
Searching the Web

nuclear medicine orthopedics bone scan SPECT PET applications clinical

Reading File
Reading File
Finding Sources
Finding Sources
Finding Sources
Reading File
Reading File
Reading File
Reading File
Reading File
Searching the Web

nuclear medicine orthopedics history radiopharmaceuticals gallium indium WBC scan recent advances 2024

Reading File
Finding Sources
Reading File
Reading File
Reading File
Reading File
Reading File
I now have sufficient information from the textbooks and literature to compose a comprehensive, structured answer. Let me compile it.

Nuclear Medicine in Orthopedics


1. Introduction

Nuclear medicine imaging plays a unique and complementary role in orthopedic practice by providing functional information about bone and soft tissue metabolism, rather than purely structural anatomy. Unlike plain radiography, CT, or MRI - which depict anatomy - nuclear medicine techniques detect physiologic changes such as altered blood flow, osteoblastic activity, metabolic hyperactivity, and inflammatory cell accumulation. These functional signals often precede visible structural changes by days to weeks, making nuclear imaging particularly valuable in early disease detection.
The principal modalities used in orthopedics include:
  • Bone scintigraphy (planar and three-phase)
  • SPECT and SPECT/CT (single-photon emission computed tomography)
  • PET and PET/CT (positron emission tomography)
  • Gallium-67 scintigraphy
  • Labeled leukocyte (WBC) scintigraphy (Indium-111 and Tc-99m HMPAO)
  • Marrow imaging (Tc-99m sulfur colloid)

2. History

  • 1950s-1960s: Early radioisotope studies used strontium-85 and fluorine-18 for bone imaging, but with poor image quality and high radiation doses.
  • Early 1970s: Introduction of technetium-99m (99mTc)-labeled diphosphonates (particularly MDP - methylene diphosphonate) revolutionized bone scanning. The high affinity of diphosphonates for bone led to their use with 99mTc labeling. The 140 keV photon energy of 99mTc was ideally suited to existing gamma cameras.
  • 1970s-1980s: Three-phase bone scanning developed; gallium-67 and indium-111-labeled leukocyte studies introduced for infection imaging.
  • 1990s: SPECT developed, providing tomographic bone imaging with improved localization.
  • 2000s: Hybrid SPECT/CT cameras introduced, combining functional and anatomical imaging simultaneously. 18F-FDG PET/CT became available for oncologic and infectious indications.
  • 2010s-present: 18F-NaF PET/CT, PET/MRI, and novel radiotracers expand clinical applications; digital PET detectors improve sensitivity and resolution.
(Sources: Rheumatology 2-Volume Set (Elsevier), p. 428; Rockwood and Green's Fractures in Adults 10th Ed, p. 253)

3. Anatomy Relevant to Nuclear Medicine Imaging

Understanding the normal distribution of radiotracers is essential for image interpretation:
  • Normal bone scan: Shows characteristic distribution with slightly greater uptake in the axial skeleton (spine, pelvis) compared to the appendicular skeleton. Kidneys and bladder are visible due to renal excretion of unbound tracer.
  • Skeletally immature patients: Normal avid uptake in growth plates, resulting in symmetrically increased bands of activity adjacent to joints and apophyses - this must not be confused with pathology.
  • Physiologic hot spots: Sternoclavicular joints, costochondral junctions, and sacroiliac joints may show mildly increased uptake normally.
  • Tracer pharmacokinetics: After IV injection of 99mTc-MDP, >50% is delivered to bone within 1 hour; the remainder excreted renally. In a normally hydrated subject, less than 5% remains in blood 3 hours post-injection.
(Source: Rockwood and Green's Fractures in Adults 10th Ed, pp. 252-253; Rheumatology 2-Volume Set, p. 427)

4. Etiology / Indications (Clinical Scenarios Requiring Nuclear Medicine)

Nuclear medicine studies are indicated when:
  1. Structural imaging (X-ray, CT, MRI) is inconclusive but disease is clinically suspected
  2. Whole-body survey is needed (e.g., metastatic staging, metabolic bone disease, Paget's, polyarticular disease)
  3. Functional activity of a lesion needs assessment (active vs. chronic, hot vs. cold)
  4. Infection needs differentiation from aseptic inflammation or loosening
  5. Early disease before radiographic changes appear (e.g., stress fractures, early osteomyelitis, avascular necrosis)
Key orthopedic conditions evaluated include:
  • Fractures (stress, insufficiency, occult, child abuse)
  • Osteomyelitis and septic arthritis
  • Periprosthetic joint infection vs. aseptic loosening
  • Bone tumors (primary and metastatic)
  • Avascular necrosis
  • Paget's disease
  • Reflex sympathetic dystrophy (CRPS)
  • Arthritis (osteoarthritis, spondyloarthritis, sacroiliitis, gout)
  • Metabolic bone disease (osteoporosis, osteomalacia)

5. Mechanism / Radiopharmaceuticals and Their Mechanisms

Technetium-99m Diphosphonates (Tc-99m MDP / HMDP)

  • Diphosphonates are chemisorbed onto hydroxyapatite crystals in bone at sites of increased osteoblastic activity.
  • Regional blood flow is also critical - areas of increased perfusion deliver greater tracer to the skeleton.
  • Binding is proportional to both osteoblastic activity and regional blood flow.
  • Half-life: 6 hours; photon energy 140 keV - ideal for gamma camera detection.

Gallium-67 Citrate

  • After IV injection, gallium rapidly binds to serum transferrin and circulates in the bloodstream.
  • Taken up into cells, particularly leukocytes. At infection sites, neutrophils release lactoferrin (which has higher gallium affinity than transferrin), concentrating gallium at inflammatory foci.
  • Also taken up by bacteria directly and at sites of increased vascular permeability.
  • Imaging at 24-48 hours post-injection (slow clearance = higher background).

Indium-111 Labeled White Blood Cells (WBCs)

  • Patient's white blood cells (primarily granulocytes) are extracted, labeled with In-111 oxine, and reinjected.
  • Labeled WBCs migrate to sites of active infection and inflammation - purely reflecting leukocyte trafficking.
  • 24-hour imaging standard for peripheral skeleton.
  • Requires concurrent sulfur colloid marrow imaging to avoid false positives from normal marrow distribution.

Tc-99m HMPAO-Labeled WBCs

  • HMPAO (hexamethylpropyleneamine oxime) crosses cell membranes and labels granulocytes.
  • Faster labeling and lower cost than In-111; imaging at 4 hours.

18F-Fluorodeoxyglucose (FDG) - PET

  • FDG is an analogue of glucose. Cells take it up via glucose transporters; hexokinase phosphorylates it to FDG-6-phosphate, which cannot proceed further in glycolysis and accumulates in proportion to glucose consumption.
  • 18F decays emitting a positron which annihilates with a nearby electron, producing two 511 keV photons 180° apart - detected by PET ring detectors.
  • Avid uptake in metabolically active cells: cancer cells, activated inflammatory cells.

18F-Sodium Fluoride (NaF) - PET

  • Taken up by bone via ion exchange at hydroxyapatite (similar mechanism to Tc-MDP but via PET), giving much higher sensitivity and spatial resolution.
(Sources: Rockwood and Green's Fractures in Adults 10th Ed, pp. 252-255; Rheumatology 2-Volume Set, pp. 427-430; Campbell's Operative Orthopaedics 15th Ed; Miller's Review of Orthopaedics 9th Ed)

6. Pathology - Disease-Specific Nuclear Medicine Findings

A. Fractures

  • Acute fractures: Bone scan positive in 80% within 24 hours, 95% by 72 hours. Minimum time to normalization 5 months; 90% normalize by 2 years.
  • Stress/insufficiency fractures: Focal areas of increased radiotracer uptake at characteristic sites. Sacral insufficiency fractures show the classic "Honda sign" (H-pattern) of uptake.
  • Healing complications: Persistently increased uptake index may predict delayed union or nonunion.
  • Non-accidental trauma (child abuse): Bone scan detects ~25% of injuries missed on skeletal survey, particularly metaphyseal lesions.

B. Osteomyelitis

  • Three-phase bone scan: increased activity on all three phases at the site of infection.
  • Sensitivity ~90%, comparable to MRI (96%), but less specific (78% vs 92% for vertebral osteomyelitis).
  • "Hot" scan: increased uptake - intact vascularity to infected bone.
  • "Cold" scan: decreased uptake - blood flow disrupted by periosteal pus, sequestrum, necrosis, or soft-tissue swelling.
  • Gallium + bone scan combination: gallium activity greater than or in different distribution than bone scan activity = diagnostic for osteomyelitis.
  • Spinal osteomyelitis: In-111 WBC scan has low sensitivity and problematic photopenic defects; FDG-PET/CT preferred.

C. Periprosthetic Joint Infection vs. Aseptic Loosening

  • Bone scan alone: positive for up to 2 years post-arthroplasty due to physiologic bone remodeling - cannot distinguish infection from normal healing.
  • Combined bone + gallium scan: gallium activity out of proportion to bone scan activity suggests infection.
  • In-111 WBC + sulfur colloid marrow scan: high specificity for periprosthetic infection; sensitivity somewhat low.
  • FDG-PET/CT: sensitivity 95%, specificity 93% for prosthetic joint infection - outperforms Tc-99m + In-111 WBC combination.

D. Bone Tumors

  • Whole-body bone scan: standard for detecting and following bone metastases (technetium bone scintigraphy - osteoblastic lesions appear as hot spots).
  • Multiple myeloma exception: purely lytic, little osteoblastic response - bone scan may be falsely negative; FDG-PET/CT superior.
  • Osteosarcoma: almost all are hypervascular and PET-avid; FDG-PET or bone scan for metastatic staging.
  • FDG-PET/CT: high sensitivity and specificity for bone neoplasms, with added ability to detect soft tissue and visceral disease simultaneously.
  • Benign tumors: 18F-FDG dual time point PET can help differentiate benign from malignant.

E. Avascular Necrosis (AVN)

  • Early (ischemic) phase: "cold" scan - hypoperfused area.
  • Reparative phase: increased uptake as osteoblastic repair activity increases ("hot" scan).
  • Bone scan is sensitive but non-specific; MRI remains the gold standard for early AVN.

F. Arthritis / Inflammatory Conditions

  • Osteoarthritis: increased subchondral uptake before radiographic changes appear; predicts disease progression (normal scan highly predictive of no progression at 5 years); low specificity limits clinical utility.
  • Sacroiliitis: increased 99mTc-diphosphonate uptake; sacroiliac joint-to-sacrum ratio used; MRI superior for diagnosis but whole-body scintigraphy allows simultaneous assessment of peripheral joint involvement in spondyloarthritis.
  • Paget's disease: characteristically intense uptake involving entire bone or anatomical segment (e.g., whole femur, hemipelvis).
  • CRPS (Reflex Sympathetic Dystrophy): three-phase bone scan shows diffuse periarticular hyperemia and increased uptake.
  • Gout: SPECT/CT can identify and confirm articular nature of gouty tophi deposits.

G. Metabolic Bone Disease

  • Osteomalacia/Rickets: multiple symmetric focal uptake at pseudofracture (Looser zone) sites.
  • Superscan: diffuse symmetrically increased uptake throughout skeleton with absent renal activity - seen in metabolic bone disease (renal osteodystrophy, hyperparathyroidism) and diffuse metastatic disease.
  • Osteoporosis: bone densitometry (DEXA) is separate from scintigraphy; single-photon absorptiometry (using 125I) measures cortical bone density in appendicular skeleton; dual-photon absorptiometry (isotope-based) measures axial skeleton and femoral neck.

7. Clinical Features (What the Clinician Needs to Know)

FeatureBone ScintigraphyGalliumIn-111 WBCFDG-PET/CT
Tracer99mTc-MDPGa-67 citrateIn-111 oxine-WBC18F-FDG
Imaging time2-4 hours (delayed phase)24-48 hours24 hours1-1.5 hours
SensitivityHighModerateModerate-HighHigh
SpecificityLowModerateHigh (with marrow scan)High
Radiation doseLow-moderateModerateModerateModerate
Best forScreening, whole-body survey, fracturesOsteomyelitis (combined with bone scan)Periprosthetic infection, peripheral osteomyelitisSpine infection, tumors, metabolic, PJI
Key clinical points:
  • A normal bone scan has high negative predictive value for most conditions - if the scan is normal, disease is very unlikely.
  • This does NOT hold for multiple myeloma (reduced osteoblastic response = false negative).
  • Bone scan remains positive for up to 2 years after arthroplasty due to physiologic remodeling.
  • Three-phase technique increases specificity from 74% to 94% for osteomyelitis diagnosis.

8. Investigation (Procedural Details)

Three-Phase Bone Scan Protocol

  1. Phase 1 - Flow phase (radionuclide angiogram): Dynamic images immediately during IV injection; shows arterial blood flow through the region.
  2. Phase 2 - Blood pool phase (tissue phase, 5-10 min post-injection): Static images showing equilibrium of tracer throughout intravascular volume and extracellular space; reflects regional hyperemia.
  3. Phase 3 - Delayed phase (2-4 hours post-injection): Renal excretion has cleared background; shows osteoblastic activity specifically.
  • A fourth phase (24-hour imaging) is sometimes added for further background clearance.

Patient Preparation

  • Good hydration encouraged to promote renal clearance.
  • Voiding before delayed imaging to reduce bladder artifact over pelvis.
  • No specific dietary restrictions for bone scan.
  • For FDG-PET: 4-6 hour fast required; blood glucose <200 mg/dL.

Radiation Dosimetry

  • 99mTc-MDP whole-body scan: approximately 3-5 mSv.
  • Ga-67 (whole body): approximately 10-15 mSv.
  • FDG-PET/CT: approximately 7-10 mSv.
  • Nuclear studies are contraindicated in pregnancy (relative); used with extreme caution in children.

9. Radiograph (Plain X-ray vs. Nuclear Medicine)

Plain radiographs are typically the first-line imaging study in orthopedics, but they have fundamental limitations that nuclear medicine addresses:
ConditionX-ray SensitivityBone Scan Sensitivity
Acute osteomyelitis (first 10-14 days)Very low (changes appear after 30-50% bone destruction)~90% within 72 hours
Stress fracturesLow (~50%)~95-100%
Occult hip fracture~65-80%~95%
Early metastasesLow (cortical destruction required)High (osteoblastic activity precedes lysis)
Early AVNVery lowModerate (but MRI superior)
Key concept: Nuclear medicine scintigraphy detects physiological changes that precede anatomical/structural changes visible on X-ray by days to weeks.

10. CT in Nuclear Medicine Context

CT itself is not a nuclear medicine technique, but hybrid SPECT/CT and PET/CT scanners combine functional nuclear imaging with CT anatomical detail in the same session:

SPECT/CT

  • CT provides precise anatomic localization of scintigraphic abnormalities that would otherwise be poorly localized on planar images (e.g., spine, pelvis, foot/ankle).
  • The combination leads to a real "synergy": scintigraphy's sensitivity for active lesions + CT's specificity for the nature of those lesions.
  • Specificity dramatically improves: differentiates degenerative osteophytes from metastases in spine, localizes uptake in complex anatomy (hindfoot, wrist).
  • Sensitivity 93% -> 97.2% and specificity 78.8% -> 97.4% for bone metastases when upgrading from planar to whole-body SPECT/CT.
  • Important for: loose screws/implants (shows radiotracer uptake around hardware), sacral insufficiency fractures, facet joint arthritis vs. metastases, Bertolotti's syndrome (lumbosacral transitional vertebra arthritic change).
  • Leukocyte SPECT/CT: correctly characterizes and localizes WBC uptake in osteomyelitis, discriminating soft tissue from bone infection.

PET/CT

  • Combines 18F-FDG metabolic data with full diagnostic-quality CT.
  • PET/CT advent in 2000 was a landmark development.
  • For osteomyelitis: PET/CT superior to planar bone scan + Ga-67 SPECT/CT for spondylodiskitis - provides fundamental diagnostic and treatment management information.
(Source: Rheumatology 2-Volume Set, pp. 3180-3200; IAEA SPECT/CT Clinical Applications)

11. MRI vs. Nuclear Medicine

ParameterMRINuclear Medicine
Soft tissue detailSuperiorPoor
Sensitivity for osteomyelitis96%~90% (bone scan)
Specificity for vertebral osteomyelitis92%78%
Whole-body surveyLimited / time-consumingExcellent (single scan)
Implants/hardwareContraindicated/limitedNo contraindication
Metabolic activityCannot assessPrimary capability
CostHighModerate
RadiationNoneYes
AvailabilityWideSpecialized centers
Nuclear medicine advantages over MRI:
  • Whole-body scan in one session.
  • No contraindication with metallic implants (unlike MRI).
  • Detects multifocal disease simultaneously (e.g., polyarticular spondyloarthritis, metastases, Paget's, CRMO).
  • Superior for periprosthetic joint infection around metal hardware.
  • Better than MRI for Paget's disease extent assessment.
MRI advantages:
  • No radiation.
  • Superior soft tissue characterization and marrow detail.
  • Preferred for early AVN, disc infection, soft tissue tumors, labral/ligamentous pathology.

12. Classification / Types of Nuclear Medicine Studies in Orthopedics

By Technique

A. Planar Scintigraphy
  • Simple 2D projection images.
  • Whole body or spot views.
  • Limited spatial resolution and anatomic localization.
B. Three-Phase Bone Scan (TPBS)
  • Flow + Blood pool + Delayed phases.
  • Increases specificity for osteomyelitis (74% → 94%).
  • Standard for trauma, infection, loosening workup.
C. SPECT (Single Photon Emission CT)
  • Tomographic 99mTc-MDP acquisition.
  • Rotating gamma camera acquires volumetric data.
  • Better spatial resolution and 3D localization than planar.
  • Main applications: spine (facet joints, pars defects), complex foot/ankle pathology.
D. SPECT/CT
  • Hybrid: SPECT + CT in same session.
  • Gold standard for anatomic correlation of scintigraphic findings.
  • Particularly valuable in spine, foot/ankle, hip, wrist.
E. Gallium-67 Scintigraphy
  • Infection/inflammation imaging.
  • Combined with bone scan for osteomyelitis diagnosis.
  • 24-48 hour imaging.
F. Labeled Leukocyte Scintigraphy
  • In-111 oxine-WBC: gold standard for peripheral osteomyelitis and periprosthetic infection.
  • Tc-99m HMPAO-WBC: faster labeling, 4-hour imaging.
  • Must combine with sulfur colloid marrow scan to avoid false positives.
G. Marrow Imaging (Tc-99m Sulfur Colloid)
  • Maps normal bone marrow distribution.
  • Used as adjunct to WBC scan for osteomyelitis/periprosthetic infection.
H. FDG-PET / PET/CT
  • Metabolic imaging.
  • Indications: bone tumors, spinal infection, periprosthetic infection, metabolic bone disease, fever of unknown origin.
I. 18F-NaF PET/CT
  • High-resolution bone scanning.
  • Superior sensitivity and spatial resolution vs. Tc-MDP.
  • Emerging clinical role.
J. Bone Densitometry (Absorptiometry)
  • Single-photon absorptiometry (125I): appendicular cortical bone.
  • Dual-photon absorptiometry: axial skeleton and femoral neck.
  • Superseded by DEXA but historically part of nuclear medicine.

13. Treatment

A. Non-Operative Role of Nuclear Medicine

Nuclear medicine primarily serves a diagnostic and monitoring role:
  1. Diagnosis and staging: Guides conservative management decisions (e.g., bone scan-negative stress fracture = lower-risk, can continue activity with modification; bone scan-positive = activity restriction, protected weight-bearing).
  2. Monitoring treatment response:
    • Serial bone scans to monitor healing of fractures (decreasing uptake index = healing).
    • Gallium scan (not bone scan) used to monitor response to antibiotic therapy in osteomyelitis - bone scan uptake remains elevated long after infection resolution.
    • PET/CT for monitoring chemotherapy response in bone tumors.
  3. Guiding biopsy: Hot spots on bone scan or FDG-PET can direct biopsy to the most metabolically active region of a tumor.
  4. Theranostics (therapeutic nuclear medicine):
    • Radium-223 (Ra-223) dichloride (Xofigo): bone-seeking alpha-emitting radiopharmaceutical approved for castration-resistant prostate cancer with bone metastases; acts as calcium mimetic, delivered to sites of increased osteoblastic activity → kills adjacent tumor cells with alpha radiation; significantly prolongs survival and delays skeletal events.
    • Samarium-153 EDTMP (Quadramet) and Strontium-89: beta-emitting bone-seeking agents used for palliation of painful bone metastases; concentrate at metastatic sites.
    • Lutetium-177 PSMA (177Lu-PSMA-617 / Pluvicto): for PSMA-positive metastatic castration-resistant prostate cancer including bone metastases.
    • Iodine-131 for thyroid cancer bone metastases.
  5. Preoperative planning: Bone scan/SPECT/CT helps define the full extent of disease (e.g., Paget's) before elective surgery.

B. Operative Role of Nuclear Medicine

  1. Preoperative assessment:
    • Three-phase bone scan to differentiate septic loosening vs. aseptic loosening before revision arthroplasty.
    • FDG-PET/CT or WBC scan to confirm periprosthetic joint infection before revision surgery.
    • Whole-body bone scan for metastasis staging before prophylactic fixation decisions.
    • Bone scan to assess vascularity/healing potential (e.g., scaphoid non-union, tibial non-union).
  2. Intraoperative nuclear medicine (Radioguided Surgery):
    • Sentinel lymph node biopsy (SLNB): Tc-99m nanocolloid injected preoperatively; intraoperative gamma probe used to identify the sentinel lymph node in soft tissue sarcoma and other tumors. This is a major operative application.
    • Radioguided occult lesion localization (ROLL): Radiotracer injected into a bone lesion preoperatively under imaging guidance; intraoperative gamma probe guides resection.
    • Radio-guided parathyroidectomy: Tc-99m sestamibi injected; intraoperative probe guides removal of hyperfunctioning parathyroid (relevant to orthopedics in hyperparathyroid bone disease management).
  3. Postoperative assessment:
    • Post-fusion SPECT/CT: identifies failed or pseudarthrotic segments needing revision.
    • Identifies hardware loosening (screw uptake around pedicle screws, iliac screws).
    • Post-arthroplasty infection surveillance.

14. Recent Advances

1. Digital PET and Total-Body PET

  • Digital PET scanners with silicon photomultiplier (SiPM) detectors provide markedly improved sensitivity and spatial resolution vs. analog systems.
  • Total-body PET scanners (EXPLORER) can image the entire body simultaneously with extremely low radiation doses - important for pediatric and repeated imaging scenarios.

2. PET/MRI

  • Combines the metabolic information of PET with the superior soft tissue contrast of MRI.
  • Reduced radiation exposure vs. PET/CT (MRI component is radiation-free).
  • Particularly valuable in pediatric patients and for soft tissue sarcomas adjacent to bone.
  • Technical challenges (MRI-based attenuation correction, scanner integration, cost) limit current availability.
  • Emerging evidence for superior characterization of bone marrow, soft tissue extension of tumors, and infected joint prostheses.

3. Novel Radiotracers

  • 18F-NaF: Bone-specific PET tracer with superior pharmacokinetics, spatial resolution, and sensitivity vs. Tc-99m MDP. FDA approved; increasing availability. Sensitivity increases from 93% (planar) to >99% for bone metastases.
  • PSMA-targeted agents (68Ga-PSMA-11, 18F-DCFPyL): Revolutionized prostate cancer staging and bone metastasis detection; more sensitive than conventional bone scan for early metastatic disease.
  • 68Ga-labeled somatostatin analogues: For detection of oncogenic osteomalacia (FGF-23 secreting tumors) - a significant advance over prior approaches.
  • FAPI (Fibroblast Activation Protein Inhibitors): Newer PET tracers targeting tumor stroma; low background uptake in bone makes them promising for skeletal metastasis detection.

4. SPECT/CT Advances

  • Cadmium zinc telluride (CZT) detector-based cameras: faster acquisition, lower dose, improved resolution.
  • Whole-body SPECT/CT significantly improves bone metastasis detection accuracy (sensitivity 97.2%, specificity 97.4% vs. planar 93%/78.8%).
  • Now considered standard of care in many centers over planar scintigraphy alone.

5. Theranostics Paradigm

  • The concept of using the same molecular target for both diagnosis (imaging) and therapy is reshaping oncologic nuclear medicine.
  • 68Ga-PSMA (diagnosis) → 177Lu-PSMA-617 (therapy): approved paradigm for prostate cancer with bone metastases.
  • 68Ga-DOTATATE (diagnosis) → 177Lu-DOTATATE (therapy): for neuroendocrine tumor-related bone metastases.
  • Ra-223: First and only bone-targeted radiopharmaceutical proven to improve overall survival (ALSYMPCA trial).

6. Artificial Intelligence (AI) Integration

  • AI-assisted bone scan interpretation: automated lesion detection and classification, reducing interobserver variability.
  • Deep learning algorithms for SPECT and PET image reconstruction: noise reduction, improved lesion conspicuity.
  • AI-based quantitative bone scan index (BSI) for objective tumor burden assessment and treatment response monitoring.

7. Appropriate Use Criteria

  • Society of Nuclear Medicine and Molecular Imaging (SNMMI) and EANM have published Appropriate Use Criteria for musculoskeletal infection imaging, guiding rational selection between bone scan, WBC scan, gallium, and FDG-PET/CT based on clinical scenario.

Key References:

Generate a quick reference PDF comparing bone scan vs. PET/CT vs. SPECT for common orthopedic conditions

Reading File
Reading File
Running Command

ls -la /home/daytona/workspace/ 2>/dev/null || echo "workspace not found"

Running Command

mkdir -p /home/daytona/workspace/nuclear-ortho-pdf && echo "created"

Writing File

~/nuclear-ortho-pdf/generate_pdf.py

#!/usr/bin/env python3
"""
Quick Reference PDF: Nuclear Medicine in Orthopedics
Bone Scan vs. PET/CT vs. SPECT for Common Orthopedic Conditions
"""

from reportlab.lib.pagesizes import A4
from reportlab.lib import colors
from reportlab.lib.units import mm, cm
from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
from reportlab.lib.enums import TA_CENTER, TA_LEFT, TA_JUSTIFY
from reportlab.platypus import (
    SimpleDocTemplate, Paragraph, Spacer, Table, TableStyle,
    HRFlowable, KeepTogether, PageBreak
)
from reportlab.lib.colors import HexColor, white, black
import os

OUTPUT_PATH = "/home/daytona/workspace/nuclear-ortho-pdf/Nuclear_Medicine_Ortho_Quick_Ref.pdf"

# ── Colour palette ──────────────────────────────────────────────────────────
C_NAVY    = HexColor("#1a3a5c")   # header / title bar
C_TEAL    = HexColor("#1a7a7a")   # section headers
C_BLUE    = HexColor("#2c6fad")   # bone scan column header
C_ORANGE  = HexColor("#d96b1e")   # PET/CT column header
C_GREEN   = HexColor("#2e7d32")   # SPECT column header
C_LTBLUE  = HexColor("#dde8f5")   # bone scan row bg
C_LTORANGE= HexColor("#fef0e3")   # PET/CT row bg
C_LTGREEN = HexColor("#e8f5e9")   # SPECT row bg
C_LGREY   = HexColor("#f4f6f8")   # alternating row bg
C_MGREY   = HexColor("#d0d5db")   # table border
C_HEADING_BG = HexColor("#e8edf2")
C_GOLD    = HexColor("#c49a00")   # warnings / notes

# ── Styles ──────────────────────────────────────────────────────────────────
styles = getSampleStyleSheet()

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

TITLE_STYLE = S("DocTitle",
    fontName="Helvetica-Bold", fontSize=22, textColor=white,
    alignment=TA_CENTER, spaceAfter=4, leading=28)

SUBTITLE_STYLE = S("DocSubtitle",
    fontName="Helvetica", fontSize=11, textColor=HexColor("#cce0ff"),
    alignment=TA_CENTER, spaceAfter=2, leading=14)

DATE_STYLE = S("DocDate",
    fontName="Helvetica-Oblique", fontSize=9, textColor=HexColor("#aaccee"),
    alignment=TA_CENTER, spaceAfter=0)

SECTION_TITLE = S("SectionTitle",
    fontName="Helvetica-Bold", fontSize=13, textColor=white,
    alignment=TA_LEFT, spaceBefore=6, spaceAfter=2, leading=16,
    leftIndent=6)

BODY = S("Body",
    fontName="Helvetica", fontSize=8.5, textColor=HexColor("#1a1a1a"),
    alignment=TA_LEFT, leading=12, spaceAfter=3)

BODY_BOLD = S("BodyBold",
    fontName="Helvetica-Bold", fontSize=8.5, textColor=HexColor("#1a1a1a"),
    alignment=TA_LEFT, leading=12)

CELL = S("Cell",
    fontName="Helvetica", fontSize=7.5, textColor=HexColor("#1a1a1a"),
    alignment=TA_LEFT, leading=10, spaceAfter=1)

CELL_BOLD = S("CellBold",
    fontName="Helvetica-Bold", fontSize=8, textColor=HexColor("#1a1a1a"),
    alignment=TA_LEFT, leading=11)

CELL_CENTER = S("CellCenter",
    fontName="Helvetica", fontSize=7.5, textColor=HexColor("#1a1a1a"),
    alignment=TA_CENTER, leading=10)

COL_HDR = S("ColHdr",
    fontName="Helvetica-Bold", fontSize=9, textColor=white,
    alignment=TA_CENTER, leading=12)

COL_HDR_SUB = S("ColHdrSub",
    fontName="Helvetica-Oblique", fontSize=7.5, textColor=HexColor("#e8f0ff"),
    alignment=TA_CENTER, leading=10)

ROW_HDR = S("RowHdr",
    fontName="Helvetica-Bold", fontSize=8, textColor=white,
    alignment=TA_LEFT, leading=11, leftIndent=3)

LEGEND_STYLE = S("Legend",
    fontName="Helvetica", fontSize=7.5, textColor=HexColor("#444444"),
    alignment=TA_LEFT, leading=11)

NOTE_STYLE = S("Note",
    fontName="Helvetica-Oblique", fontSize=8, textColor=C_NAVY,
    alignment=TA_LEFT, leading=11, leftIndent=8, rightIndent=8,
    spaceBefore=4, spaceAfter=4)

FOOTER_STYLE = S("Footer",
    fontName="Helvetica-Oblique", fontSize=7, textColor=HexColor("#888888"),
    alignment=TA_CENTER, leading=9)

# ── Helpers ──────────────────────────────────────────────────────────────────
def p(text, style=CELL):
    return Paragraph(text, style)

def section_banner(text, color=C_TEAL):
    """A colored banner paragraph acting as a section title."""
    para = Paragraph(f"<font color='white'><b>{text}</b></font>", SECTION_TITLE)
    t = Table([[para]], colWidths=[175*mm])
    t.setStyle(TableStyle([
        ("BACKGROUND", (0,0), (-1,-1), color),
        ("TOPPADDING",  (0,0), (-1,-1), 5),
        ("BOTTOMPADDING",(0,0),(-1,-1), 5),
        ("LEFTPADDING", (0,0), (-1,-1), 8),
        ("RIGHTPADDING",(0,0), (-1,-1), 8),
        ("ROUNDEDCORNERS", [4, 4, 4, 4]),
    ]))
    return t

def divider(color=C_MGREY, thickness=0.6):
    return HRFlowable(width="100%", thickness=thickness, color=color, spaceAfter=4, spaceBefore=4)

# ── Rating symbols ───────────────────────────────────────────────────────────
def stars(n, total=5):
    """Return filled/empty star string."""
    return "★" * n + "☆" * (total - n)

def badge(text, bg):
    """Inline colored badge using a 1-cell table."""
    para = Paragraph(f"<font color='white'><b>{text}</b></font>",
        S("badge", fontName="Helvetica-Bold", fontSize=7.5, textColor=white,
          alignment=TA_CENTER, leading=10))
    t = Table([[para]], colWidths=[22*mm], rowHeights=[6*mm])
    t.setStyle(TableStyle([
        ("BACKGROUND", (0,0), (-1,-1), bg),
        ("TOPPADDING",  (0,0),(-1,-1), 1),
        ("BOTTOMPADDING",(0,0),(-1,-1), 1),
        ("LEFTPADDING", (0,0),(-1,-1), 2),
        ("RIGHTPADDING",(0,0),(-1,-1), 2),
    ]))
    return t

# ── Page geometry ─────────────────────────────────────────────────────────────
PAGE_W, PAGE_H = A4
MARGIN = 12*mm
CONTENT_W = PAGE_W - 2*MARGIN

# ── Build document ────────────────────────────────────────────────────────────
def build_pdf():
    doc = SimpleDocTemplate(
        OUTPUT_PATH,
        pagesize=A4,
        leftMargin=MARGIN, rightMargin=MARGIN,
        topMargin=MARGIN, bottomMargin=15*mm,
        title="Nuclear Medicine in Orthopedics – Quick Reference",
        author="Orris Medical Reference",
        subject="Bone Scan vs PET/CT vs SPECT – Orthopedic Conditions"
    )

    story = []

    # ═══════════════════════════════════════════════════════════════════════
    # HEADER BLOCK
    # ═══════════════════════════════════════════════════════════════════════
    header_title   = Paragraph("NUCLEAR MEDICINE IN ORTHOPEDICS", TITLE_STYLE)
    header_sub     = Paragraph("Quick Reference: Bone Scan  |  PET/CT  |  SPECT/CT", SUBTITLE_STYLE)
    header_date    = Paragraph("Orris Medical Reference  •  July 2026", DATE_STYLE)

    header_table = Table(
        [[header_title], [header_sub], [header_date]],
        colWidths=[CONTENT_W]
    )
    header_table.setStyle(TableStyle([
        ("BACKGROUND", (0,0), (-1,-1), C_NAVY),
        ("TOPPADDING",    (0,0), (-1,-1), 8),
        ("BOTTOMPADDING", (0,0), (-1,-1), 4),
        ("LEFTPADDING",   (0,0), (-1,-1), 12),
        ("RIGHTPADDING",  (0,0), (-1,-1), 12),
    ]))
    story.append(header_table)
    story.append(Spacer(1, 6*mm))

    # ═══════════════════════════════════════════════════════════════════════
    # SECTION 1 – MODALITY OVERVIEW
    # ═══════════════════════════════════════════════════════════════════════
    story.append(section_banner("1.  MODALITY OVERVIEW"))
    story.append(Spacer(1, 3*mm))

    overview_col_w = [CONTENT_W * 0.18, CONTENT_W * 0.27, CONTENT_W * 0.18,
                      CONTENT_W * 0.18, CONTENT_W * 0.19]

    overview_header = [
        p("Parameter", COL_HDR),
        p("Bone Scan\n(99mTc-MDP)", COL_HDR),
        p("SPECT/CT\n(99mTc-MDP)", COL_HDR),
        p("FDG-PET/CT\n(18F-FDG)", COL_HDR),
        p("18F-NaF PET/CT", COL_HDR),
    ]

    overview_rows = [
        ["Tracer",
         "99mTc-MDP diphosphonate",
         "99mTc-MDP (tomographic)",
         "18F-Fluorodeoxyglucose",
         "18F-Sodium fluoride"],
        ["Mechanism",
         "Chemisorption to hydroxyapatite; proportional to osteoblastic activity + regional blood flow",
         "Same as bone scan – adds 3D CT anatomic correlation",
         "FDG phosphorylation by hexokinase; accumulates in metabolically active cells",
         "Ion exchange at hydroxyapatite; bone-specific PET tracer"],
        ["Imaging time\npost-injection",
         "2–4 hours (delayed phase)\n+ flow & pool phases for 3-phase",
         "2–4 hours + CT acquisition",
         "60–90 min whole-body",
         "30–60 min"],
        ["Spatial resolution",
         "Low (~10 mm)",
         "Moderate (7–8 mm) + CT detail",
         "Moderate–High (4–6 mm)",
         "High (3–4 mm)"],
        ["Sensitivity",
         "High (screening)",
         "High + improved specificity",
         "Very high",
         "Very high (>99%)"],
        ["Specificity",
         "Low (many false positives)",
         "Improved (CT correlation)",
         "High",
         "High"],
        ["Radiation dose",
         "~3–5 mSv",
         "~7–10 mSv (SPECT + CT)",
         "~7–10 mSv",
         "~5–7 mSv"],
        ["Availability",
         "Widely available",
         "Widely available",
         "Specialized centres",
         "Limited (increasing)"],
        ["Relative cost",
         "Low–Moderate",
         "Moderate",
         "High",
         "High"],
        ["Whole-body\nsurvey",
         "Yes – single session",
         "Limited by time",
         "Yes – 1 hour",
         "Yes"],
        ["Metallic implants",
         "No contraindication",
         "No contraindication",
         "No contraindication",
         "No contraindication"],
    ]

    ov_data = [overview_header]
    for row in overview_rows:
        ov_data.append([p(row[0], CELL_BOLD)] + [p(row[i], CELL) for i in range(1, 5)])

    ov_table = Table(ov_data, colWidths=overview_col_w, repeatRows=1)
    ov_table.setStyle(TableStyle([
        # Header
        ("BACKGROUND",    (0,0), (-1,0), C_NAVY),
        ("TEXTCOLOR",     (0,0), (-1,0), white),
        ("FONTNAME",      (0,0), (-1,0), "Helvetica-Bold"),
        ("FONTSIZE",      (0,0), (-1,0), 8.5),
        ("ALIGN",         (0,0), (-1,0), "CENTER"),
        ("VALIGN",        (0,0), (-1,-1), "TOP"),
        # Col 1 highlight
        ("BACKGROUND",    (1,1), (1,-1), C_LTBLUE),
        # Col 3 highlight
        ("BACKGROUND",    (3,1), (3,-1), C_LTORANGE),
        # Alternating on even rows for non-highlighted
        *[("BACKGROUND", (0,i), (0,i), C_LGREY) for i in range(1, len(ov_data), 2)],
        *[("BACKGROUND", (2,i), (2,i), HexColor("#e8f5e9")) for i in range(1, len(ov_data), 2)],
        *[("BACKGROUND", (4,i), (4,i), HexColor("#fdf5dc")) for i in range(1, len(ov_data), 2)],
        # Grid
        ("GRID",          (0,0), (-1,-1), 0.4, C_MGREY),
        ("LINEBELOW",     (0,0), (-1,0), 1.5, C_NAVY),
        # Padding
        ("TOPPADDING",    (0,0), (-1,-1), 3),
        ("BOTTOMPADDING", (0,0), (-1,-1), 3),
        ("LEFTPADDING",   (0,0), (-1,-1), 4),
        ("RIGHTPADDING",  (0,0), (-1,-1), 4),
    ]))
    story.append(ov_table)
    story.append(Spacer(1, 5*mm))

    # ═══════════════════════════════════════════════════════════════════════
    # SECTION 2 – CONDITION-BY-CONDITION COMPARISON
    # ═══════════════════════════════════════════════════════════════════════
    story.append(section_banner("2.  CONDITION-BY-CONDITION COMPARISON"))
    story.append(Spacer(1, 3*mm))

    # Legend
    legend_items = [
        ("●●●", "Preferred / First-line"),
        ("●●○", "Useful / Second-line"),
        ("●○○", "Limited value"),
        ("○○○", "Not recommended"),
        ("—",   "Not applicable / Not used"),
    ]
    leg_data = [[p(sym + "  " + desc, LEGEND_STYLE) for sym, desc in legend_items]]
    leg_t = Table(leg_data, colWidths=[CONTENT_W/5]*5)
    leg_t.setStyle(TableStyle([
        ("BACKGROUND",    (0,0), (-1,-1), HexColor("#f0f4f8")),
        ("GRID",          (0,0), (-1,-1), 0.3, C_MGREY),
        ("TOPPADDING",    (0,0), (-1,-1), 3),
        ("BOTTOMPADDING", (0,0), (-1,-1), 3),
        ("LEFTPADDING",   (0,0), (-1,-1), 5),
    ]))
    story.append(leg_t)
    story.append(Spacer(1, 3*mm))

    # Column widths for main comparison table
    cw = [
        CONTENT_W * 0.22,   # Condition
        CONTENT_W * 0.195,  # Bone Scan
        CONTENT_W * 0.195,  # SPECT/CT
        CONTENT_W * 0.195,  # FDG-PET/CT
        CONTENT_W * 0.195,  # Notes
    ]

    def cond_header():
        return [
            p("Condition", COL_HDR),
            p("Bone Scan\n(99mTc-MDP)", COL_HDR),
            p("SPECT/CT\n(99mTc-MDP)", COL_HDR),
            p("FDG-PET/CT\n(18F-FDG)", COL_HDR),
            p("Key Notes", COL_HDR),
        ]

    def cond_row(condition, bone, spect, pet, notes, cat_color=None):
        row = [
            p(condition, CELL_BOLD),
            p(bone, CELL),
            p(spect, CELL),
            p(pet, CELL),
            p(notes, CELL),
        ]
        return row

    # Category sub-header row
    def cat_row(text, color):
        cell = p(f"<b>{text}</b>",
            S("cat", fontName="Helvetica-Bold", fontSize=8.5, textColor=white,
              alignment=TA_LEFT, leading=12, leftIndent=4))
        return [cell, p(""), p(""), p(""), p("")]

    conditions_data = [cond_header()]

    # ── TRAUMA ──────────────────────────────────────────────────────────────
    conditions_data.append(cat_row("  TRAUMA & FRACTURES", HexColor("#2e5490")))

    conditions_data.append(cond_row(
        "Occult / stress\nfracture",
        "●●●  Highly sensitive (95% at 72h)\nFocal uptake at fracture site",
        "●●○  Better localisation\n(spine, foot, ankle)",
        "●○○  Rarely needed;\nuseful if bone scan equivocal",
        "3-phase scan adds hyperaemia info;\nMRI preferred if available"
    ))
    conditions_data.append(cond_row(
        "Sacral insufficiency\nfracture",
        "●●●  Classic H-pattern\n('Honda sign')",
        "●●●  Confirms H-pattern\nwith CT anatomy",
        "●○○  Not first-line",
        "Elderly, post-radiation, osteoporosis;\nMRI alternative"
    ))
    conditions_data.append(cond_row(
        "Scaphoid fracture\n(radiograph negative)",
        "●●●  Sensitive within 72h",
        "●●●  Best nuclear option;\nprecise anatomic localisation",
        "—",
        "MRI is gold standard;\nSPECT/CT useful where MRI unavailable"
    ))
    conditions_data.append(cond_row(
        "Delayed union /\nnon-union",
        "●●○  Persistent uptake\nindex predicts complications",
        "●●○  Localises to fracture\ngap / callus",
        "—",
        "Decreasing uptake = healing;\npersistent = non-union risk"
    ))
    conditions_data.append(cond_row(
        "Non-accidental\ntrauma (child abuse)",
        "●●○  Detects 25% injuries\nmissed on skeletal survey",
        "●●○  Metaphyseal lesions",
        "—",
        "Skeletal survey = first-line;\nbone scan used adjunctively"
    ))

    # ── INFECTION ────────────────────────────────────────────────────────────
    conditions_data.append(cat_row("  INFECTION", HexColor("#1a5c3a")))

    conditions_data.append(cond_row(
        "Acute osteomyelitis\n(peripheral)",
        "●●●  3-phase: sensitivity ~90%;\nspecificity increases 74→94%",
        "●●●  Improved specificity;\ndifferentiates cellulitis vs bone",
        "●●○  High accuracy;\noption if bone scan equivocal",
        "Hot scan = intact vascularity;\nCold scan = ischaemic/sequestrum"
    ))
    conditions_data.append(cond_row(
        "Vertebral\nosteomyelitis /\nspondylodiskitis",
        "●●○  Sensitivity ~90%;\nspecificity only 78%",
        "●●○  Better than planar",
        "●●●  First-line nuclear;\nsensitivity + specificity >90%;\nsuperiority over Ga-67+bone scan",
        "In-111 WBC has LOW sensitivity\nfor spine; FDG-PET preferred"
    ))
    conditions_data.append(cond_row(
        "Periprosthetic\njoint infection (PJI)\nvs aseptic loosening",
        "●○○  Positive up to 2yr\npost-op (remodelling);\nnot reliable alone",
        "●●○  SPECT/CT improves\nlocalisation of uptake\naround hardware",
        "●●●  Sensitivity 95%,\nspecificity 93%;\noutperforms bone+WBC combo",
        "Bone + Ga-67: useful if PET unavailable;\nIn-111 WBC + marrow scan = high specificity"
    ))
    conditions_data.append(cond_row(
        "Diabetic foot /\nperipheral\nosteomyelitis",
        "●●○  3-phase: increased\nall 3 phases in osteomyelitis",
        "●●●  Distinguishes soft\ntissue from bone infection;\nhigh specificity",
        "●●○  Useful;\n18F-FDG not impaired\nby hyperglycaemia if <200 mg/dL",
        "In-111 WBC + marrow scan:\ngold standard for diabetic foot"
    ))

    # ── TUMOURS ──────────────────────────────────────────────────────────────
    conditions_data.append(cat_row("  BONE TUMOURS & METASTASES", HexColor("#5c1a1a")))

    conditions_data.append(cond_row(
        "Bone metastases\nstaging / follow-up",
        "●●●  Standard of care;\nwhole-body osteoblastic\nmetastasis survey",
        "●●●  SPECT/CT dramatically\nimproves specificity\n(78.8%→97.4%)",
        "●●●  High S+S; detects\nlytic lesions bone scan misses;\nwhole-body in 90 min",
        "Myeloma: bone scan UNRELIABLE\n(lytic; little osteoblastic response)\n→ use FDG-PET or whole-body MRI"
    ))
    conditions_data.append(cond_row(
        "Multiple myeloma",
        "○○○  Often FALSE NEGATIVE\n(no osteoblastic response)",
        "○○○  Same limitation",
        "●●●  Preferred;\ndetects active disease\nand treatment response",
        "Whole-body MRI also first-line;\nFDG-PET for extramedullary disease"
    ))
    conditions_data.append(cond_row(
        "Osteosarcoma /\nEwing sarcoma",
        "●●●  Hypervascular tumours;\npositive bone scan;\nuse for skip lesions",
        "●●○  Localisation of\nprimary tumour extent",
        "●●●  All osteosarcomas\nPET-avid; staging + response\nmonitoring",
        "FDG-PET/CT for pulmonary mets\n(bone scan misses lung); MRI\nfor local staging"
    ))
    conditions_data.append(cond_row(
        "Benign bone tumour\n(differentiation)",
        "●●○  Detects active lesions;\nnon-specific",
        "●●●  Best nuclear option;\ncharacterises anatomic\nrelationship",
        "●●○  Dual time-point FDG\nhelps benign vs malignant\ndifferentiation",
        "Biopsy remains gold standard;\nnuclear guides biopsy site"
    ))

    # ── ARTHRITIS ────────────────────────────────────────────────────────────
    conditions_data.append(cat_row("  ARTHRITIS & INFLAMMATION", HexColor("#4a3a00")))

    conditions_data.append(cond_row(
        "Sacroiliitis /\nspondyloarthritis",
        "●●○  Elevated SI:sacrum\nratio; low specificity;\nwhole-body surveys\nperipheral joints",
        "●●●  Best nuclear study;\nprecise localisation;\nidentifies active joints",
        "●●○  FDG-PET detects\nactive axial + peripheral\ninflammation",
        "MRI preferred for early sacroiliitis;\nnuclear useful when MRI unavailable\nor for whole-body mapping"
    ))
    conditions_data.append(cond_row(
        "Osteoarthritis\nprogression",
        "●●○  Detects subchondral\nactivity before X-ray;\nnormal scan = low\nprogression risk at 5yr",
        "●●●  SPECT/CT identifies\ncompartment-specific\nactive OA; guides\ninjection/surgery",
        "●○○  Not routine;\nresearch use",
        "Low clinical utility for routine OA;\nSPECT/CT most useful for knee,\nfacet, foot/ankle OA"
    ))
    conditions_data.append(cond_row(
        "Gout / crystal\narthropathy",
        "●○○  Non-specific\nincreased uptake",
        "●●●  SPECT/CT: confirms\narticular nature of tophi;\nidentifies active joints",
        "●○○  Not routine",
        "SPECT/CT specifically identifies\ntophi vs erosions vs degenerative\nchanges"
    ))
    conditions_data.append(cond_row(
        "CRPS / Reflex\nSympathetic\nDystrophy",
        "●●●  3-phase: diffuse\nperiarticular hyperaemia;\nincreased delayed uptake",
        "●●○  Confirms and\nlocalises findings",
        "●○○  Limited data",
        "Three-phase bone scan is the\nnuclear study of choice for CRPS;\nMRI and clinical diagnosis also key"
    ))

    # ── METABOLIC BONE ───────────────────────────────────────────────────────
    conditions_data.append(cat_row("  METABOLIC BONE DISEASE", HexColor("#1a3a5c")))

    conditions_data.append(cond_row(
        "Paget's disease",
        "●●●  Intense uptake in\naffected bone; whole-body\nextent mapping",
        "●●●  Precise extent\nassessment; pre-surgical\nplanning",
        "●○○  Not routinely used",
        "Bone scan best for whole-body\nextent; X-ray for lytic/sclerotic\nphase characterisation"
    ))
    conditions_data.append(cond_row(
        "Avascular necrosis\n(AVN)",
        "●●○  Early: 'cold' scan\n(ischaemia); Reparative:\n'hot' scan",
        "●●○  Better localisation",
        "●○○  Not first-line",
        "MRI is gold standard for early AVN;\nbone scan useful when MRI\nunavailable"
    ))
    conditions_data.append(cond_row(
        "Superscan\n(diffuse metabolic)",
        "●●●  Diffusely increased\nuptake; absent renal\nactivity",
        "●●○  Confirms distribution",
        "●●○  Differentiates\nmetastatic vs metabolic",
        "Causes: hyperparathyroidism,\nrenal osteodystrophy, diffuse\nmetastatic disease"
    ))
    conditions_data.append(cond_row(
        "Looser zones\n(osteomalacia)",
        "●●●  Multiple symmetric\nfocal uptake at\npseudofracture sites",
        "●●○  Localisation",
        "—",
        "Characteristic bilateral symmetric\nfoci at neck of femur, ribs,\nscapulae, pubic rami"
    ))
    conditions_data.append(cond_row(
        "Oncogenic\nosteomalacia\n(FGF-23 tumour)",
        "●○○  Non-specific",
        "●○○",
        "●○○",
        "68Ga-DOTATATE or 68Ga-DOTA-SST\nPET/CT is GOLD STANDARD for\nlocalising the culprit tumour"
    ))

    # ── SPINE ────────────────────────────────────────────────────────────────
    conditions_data.append(cat_row("  SPINE", HexColor("#3a1a5c")))

    conditions_data.append(cond_row(
        "Low back pain\n(facet / pars)",
        "●○○  Planar cannot\ndistinguish facet vs\nbody vs pars",
        "●●●  SPECT/CT: identifies\nfacet OA, pars defect,\nBertolotti syndrome;\nguides injections",
        "●○○  Not first-line\nfor mechanical LBP",
        "SPECT/CT is preferred nuclear study\nfor complex spinal pain;\nchanges management in ~30% cases"
    ))
    conditions_data.append(cond_row(
        "Post-fusion\nassessment",
        "●●○  Detects persistent\nactivity at non-union\nor loose hardware",
        "●●●  Identifies loose\nscrew, failed fusion\nsegment, iliac crest\ndonor site fracture",
        "●○○  Limited data for\nspinal hardware",
        "SPECT/CT: radiotracer uptake\naround hardware = loosening;\nuptake at graft = active fusion"
    ))

    # Build main table
    main_t = Table(conditions_data, colWidths=cw, repeatRows=1)

    # Build style commands
    ts_cmds = [
        # Header row
        ("BACKGROUND",    (0,0), (-1,0), C_NAVY),
        ("TEXTCOLOR",     (0,0), (-1,0), white),
        ("ALIGN",         (0,0), (-1,0), "CENTER"),
        ("FONTNAME",      (0,0), (-1,0), "Helvetica-Bold"),
        ("FONTSIZE",      (0,0), (-1,0), 8.5),
        # General
        ("VALIGN",        (0,0), (-1,-1), "TOP"),
        ("GRID",          (0,0), (-1,-1), 0.3, C_MGREY),
        ("LINEBELOW",     (0,0), (-1,0), 1.5, C_NAVY),
        ("TOPPADDING",    (0,0), (-1,-1), 3),
        ("BOTTOMPADDING", (0,0), (-1,-1), 3),
        ("LEFTPADDING",   (0,0), (-1,-1), 4),
        ("RIGHTPADDING",  (0,0), (-1,-1), 4),
        # Condition column always light
        ("BACKGROUND",    (0,1), (0,-1), C_LGREY),
    ]

    # Category header rows – colour entire row
    cat_indices = []
    for idx, row in enumerate(conditions_data):
        if idx == 0:
            continue
        # Category rows have empty cells 1-4
        if all(isinstance(row[i], Paragraph) and row[i].text in ("", "<b></b>") for i in range(1,5)):
            cat_indices.append(idx)

    # Re-detect category rows by checking second cell text
    cat_row_indices = []
    for idx, row in enumerate(conditions_data):
        if idx == 0:
            continue
        # Category rows have blank paragraphs in cols 1-4
        texts = [row[i].text.strip() for i in range(1, 5)]
        if all(t == "" for t in texts):
            cat_row_indices.append(idx)

    cat_colors_map = {}
    cat_color_list = [
        HexColor("#2e5490"), HexColor("#1a5c3a"), HexColor("#5c1a1a"),
        HexColor("#4a3a00"), HexColor("#1a3a5c"), HexColor("#3a1a5c")
    ]
    ci = 0
    for idx in cat_row_indices:
        c_col = cat_color_list[ci % len(cat_color_list)]
        ts_cmds.append(("BACKGROUND", (0, idx), (-1, idx), c_col))
        ts_cmds.append(("SPAN",       (0, idx), (-1, idx)))
        ts_cmds.append(("TEXTCOLOR",  (0, idx), (-1, idx), white))
        ts_cmds.append(("FONTNAME",   (0, idx), (-1, idx), "Helvetica-Bold"))
        ts_cmds.append(("FONTSIZE",   (0, idx), (-1, idx), 8.5))
        ts_cmds.append(("TOPPADDING",    (0, idx), (-1, idx), 4))
        ts_cmds.append(("BOTTOMPADDING", (0, idx), (-1, idx), 4))
        ci += 1

    # Alternating row colors for non-category rows
    for idx in range(1, len(conditions_data)):
        if idx in cat_row_indices:
            continue
        if idx % 2 == 0:
            ts_cmds.append(("BACKGROUND", (1, idx), (1, idx), C_LTBLUE))
            ts_cmds.append(("BACKGROUND", (2, idx), (2, idx), HexColor("#e8f5e9")))
            ts_cmds.append(("BACKGROUND", (3, idx), (3, idx), C_LTORANGE))
            ts_cmds.append(("BACKGROUND", (4, idx), (4, idx), HexColor("#fdf8ee")))
        else:
            ts_cmds.append(("BACKGROUND", (1, idx), (1, idx), HexColor("#eef4fc")))
            ts_cmds.append(("BACKGROUND", (2, idx), (2, idx), HexColor("#f1f9f1")))
            ts_cmds.append(("BACKGROUND", (3, idx), (3, idx), HexColor("#fef8f2")))
            ts_cmds.append(("BACKGROUND", (4, idx), (4, idx), white))

    main_t.setStyle(TableStyle(ts_cmds))
    story.append(main_t)
    story.append(Spacer(1, 5*mm))

    # ═══════════════════════════════════════════════════════════════════════
    # PAGE BREAK  → Radiopharmaceuticals + Special Agents
    # ═══════════════════════════════════════════════════════════════════════
    story.append(PageBreak())

    # ── Header on page 2
    story.append(header_table)
    story.append(Spacer(1, 5*mm))

    # ═══════════════════════════════════════════════════════════════════════
    # SECTION 3 – THREE-PHASE BONE SCAN PROTOCOL
    # ═══════════════════════════════════════════════════════════════════════
    story.append(section_banner("3.  THREE-PHASE BONE SCAN – PHASES & INTERPRETATION"))
    story.append(Spacer(1, 3*mm))

    phase_cw = [CONTENT_W*0.12, CONTENT_W*0.16, CONTENT_W*0.16, CONTENT_W*0.28, CONTENT_W*0.28]
    phase_data = [
        [p("Phase", COL_HDR), p("Timing", COL_HDR), p("Images", COL_HDR),
         p("Normal Appearance", COL_HDR), p("Abnormal / Clinical Significance", COL_HDR)],
        [p("Phase 1\nFlow", CELL_BOLD),
         p("0–60 sec\n(dynamic)", CELL),
         p("Radionuclide angiogram", CELL),
         p("Symmetric, rapid arterial transit", CELL),
         p("Asymmetric hyperaemia → osteomyelitis, tumour, CRPS, acute fracture", CELL)],
        [p("Phase 2\nBlood Pool", CELL_BOLD),
         p("5–10 min", CELL),
         p("Static soft tissue images", CELL),
         p("Slight soft tissue background; symmetric", CELL),
         p("Increased soft tissue uptake → cellulitis, synovitis, hyperaemia. Differentiates from Phase 3 bone uptake", CELL)],
        [p("Phase 3\nDelayed", CELL_BOLD),
         p("2–4 hours", CELL),
         p("Skeletal delayed images", CELL),
         p("Symmetric skeletal uptake; axial > appendicular; avid growth plates in children", CELL),
         p("Focal increased uptake → osteomyelitis, fracture, metastasis, Paget's, OA, tumour; focal decreased ('cold') → AVN, sequestrum, aggressive tumour", CELL)],
        [p("Phase 4\n(optional)", CELL_BOLD),
         p("24 hours", CELL),
         p("24h delayed images", CELL),
         p("Further background clearance", CELL),
         p("Increased specificity for chronic low-grade osteomyelitis; spine infection assessment", CELL)],
    ]
    phase_t = Table(phase_data, colWidths=phase_cw, repeatRows=1)
    phase_t.setStyle(TableStyle([
        ("BACKGROUND",    (0,0), (-1,0), C_TEAL),
        ("TEXTCOLOR",     (0,0), (-1,0), white),
        ("FONTNAME",      (0,0), (-1,0), "Helvetica-Bold"),
        ("ALIGN",         (0,0), (-1,0), "CENTER"),
        ("VALIGN",        (0,0), (-1,-1), "TOP"),
        ("GRID",          (0,0), (-1,-1), 0.4, C_MGREY),
        ("LINEBELOW",     (0,0), (-1,0), 1.2, C_TEAL),
        ("BACKGROUND",    (0,1), (-1,1), C_LTBLUE),
        ("BACKGROUND",    (0,2), (-1,2), HexColor("#e8f5e9")),
        ("BACKGROUND",    (0,3), (-1,3), C_LTORANGE),
        ("BACKGROUND",    (0,4), (-1,4), HexColor("#fdf5dc")),
        ("TOPPADDING",    (0,0), (-1,-1), 3),
        ("BOTTOMPADDING", (0,0), (-1,-1), 3),
        ("LEFTPADDING",   (0,0), (-1,-1), 4),
        ("RIGHTPADDING",  (0,0), (-1,-1), 4),
    ]))
    story.append(phase_t)
    story.append(Spacer(1, 4*mm))

    # ═══════════════════════════════════════════════════════════════════════
    # SECTION 4 – RADIOPHARMACEUTICALS REFERENCE
    # ═══════════════════════════════════════════════════════════════════════
    story.append(section_banner("4.  RADIOPHARMACEUTICAL QUICK REFERENCE", C_NAVY))
    story.append(Spacer(1, 3*mm))

    rp_cw = [CONTENT_W*0.18, CONTENT_W*0.12, CONTENT_W*0.14, CONTENT_W*0.16,
             CONTENT_W*0.14, CONTENT_W*0.26]
    rp_data = [
        [p("Agent", COL_HDR), p("Half-life", COL_HDR), p("Imaging time", COL_HDR),
         p("Primary mechanism", COL_HDR), p("Dose (mSv)", COL_HDR), p("Key orthopedic use", COL_HDR)],
        [p("99mTc-MDP\n(Tc-99m)", CELL_BOLD), p("6 hours", CELL), p("2–4 hours", CELL),
         p("Hydroxyapatite chemisorption; osteoblastic activity", CELL), p("3–5 mSv", CELL),
         p("Bone scan (fracture, osteomyelitis, metastasis, Paget's, AVN, CRPS)", CELL)],
        [p("67Ga-Citrate\n(Gallium-67)", CELL_BOLD), p("78 hours", CELL), p("24–48 hours", CELL),
         p("Transferrin/lactoferrin binding; leukocyte uptake at infection", CELL), p("10–15 mSv", CELL),
         p("Osteomyelitis (combined with bone scan); tumours; spinal infection", CELL)],
        [p("111In-WBC\n(Indium-111)", CELL_BOLD), p("67 hours", CELL), p("24 hours", CELL),
         p("Labelled patient's own granulocytes migrate to infection", CELL), p("8–12 mSv", CELL),
         p("Peripheral osteomyelitis; periprosthetic infection (use with marrow scan)", CELL)],
        [p("99mTc-HMPAO-WBC", CELL_BOLD), p("6 hours", CELL), p("4 hours", CELL),
         p("HMPAO crosses cell membranes; labels granulocytes", CELL), p("5–8 mSv", CELL),
         p("Faster alternative to In-111 WBC; peripheral osteomyelitis; diabetic foot", CELL)],
        [p("99mTc-Sulfur\nColloid", CELL_BOLD), p("6 hours", CELL), p("20 min", CELL),
         p("RES phagocytosis; marrow mapping", CELL), p("2–4 mSv", CELL),
         p("Marrow imaging (adjunct to WBC scan for osteomyelitis / PJI diagnosis)", CELL)],
        [p("18F-FDG\n(PET)", CELL_BOLD), p("110 min", CELL), p("60–90 min", CELL),
         p("Glucose analogue; hexokinase phosphorylation; metabolic trapping", CELL), p("7–10 mSv", CELL),
         p("Bone tumours; spinal infection; periprosthetic infection; multiple myeloma", CELL)],
        [p("18F-NaF\n(PET)", CELL_BOLD), p("110 min", CELL), p("30–60 min", CELL),
         p("Fluoride ion exchange at hydroxyapatite; bone-specific", CELL), p("5–7 mSv", CELL),
         p("High-resolution bone scan; metastasis detection (sensitivity >99%)", CELL)],
        [p("223Ra-Dichloride\n(Radium-223)", CELL_BOLD), p("11.4 days", CELL), p("Therapeutic", CELL),
         p("Calcium mimetic; alpha emitter; targets osteoblastic metastases", CELL), p("Therapeutic", CELL),
         p("Palliation + survival benefit in castrate-resistant prostate cancer with bone mets", CELL)],
        [p("68Ga-DOTATATE\n(PET)", CELL_BOLD), p("68 min", CELL), p("60–90 min", CELL),
         p("Somatostatin receptor targeting", CELL), p("5–7 mSv", CELL),
         p("Oncogenic osteomalacia tumour localisation (FGF-23 secreting tumours)", CELL)],
    ]
    rp_t = Table(rp_data, colWidths=rp_cw, repeatRows=1)
    rp_ts = [
        ("BACKGROUND",    (0,0), (-1,0), C_NAVY),
        ("TEXTCOLOR",     (0,0), (-1,0), white),
        ("FONTNAME",      (0,0), (-1,0), "Helvetica-Bold"),
        ("ALIGN",         (0,0), (-1,0), "CENTER"),
        ("VALIGN",        (0,0), (-1,-1), "TOP"),
        ("GRID",          (0,0), (-1,-1), 0.4, C_MGREY),
        ("LINEBELOW",     (0,0), (-1,0), 1.5, C_NAVY),
        ("TOPPADDING",    (0,0), (-1,-1), 3),
        ("BOTTOMPADDING", (0,0), (-1,-1), 3),
        ("LEFTPADDING",   (0,0), (-1,-1), 4),
        ("RIGHTPADDING",  (0,0), (-1,-1), 4),
    ]
    for i in range(1, len(rp_data)):
        bg = C_LGREY if i % 2 == 0 else white
        rp_ts.append(("BACKGROUND", (0, i), (0, i), HexColor("#e4eaf4")))
        if i % 2 == 0:
            rp_ts.append(("BACKGROUND", (1, i), (-1, i), C_LGREY))
    rp_t.setStyle(TableStyle(rp_ts))
    story.append(rp_t)
    story.append(Spacer(1, 4*mm))

    # ═══════════════════════════════════════════════════════════════════════
    # SECTION 5 – SENSITIVITY & SPECIFICITY
    # ═══════════════════════════════════════════════════════════════════════
    story.append(section_banner("5.  SENSITIVITY & SPECIFICITY SUMMARY", C_TEAL))
    story.append(Spacer(1, 3*mm))

    ss_cw = [CONTENT_W*0.24, CONTENT_W*0.19, CONTENT_W*0.19, CONTENT_W*0.19, CONTENT_W*0.19]
    ss_data = [
        [p("Indication", COL_HDR), p("Bone Scan\nSens / Spec", COL_HDR),
         p("SPECT/CT\nSens / Spec", COL_HDR), p("FDG-PET/CT\nSens / Spec", COL_HDR),
         p("18F-NaF PET\nSens / Spec", COL_HDR)],
        [p("Bone metastases", CELL_BOLD),     p("93% / 78%", CELL), p("97% / 97%", CELL),  p("97% / 95%", CELL),   p(">99% / 97%", CELL)],
        [p("Osteomyelitis\n(peripheral)", CELL_BOLD), p("90% / 74–94%", CELL), p("90–95% / 90–95%", CELL), p("92% / 87%", CELL), p("—", CELL)],
        [p("Spinal osteomyelitis", CELL_BOLD), p("90% / 78%", CELL), p("90% / 83%", CELL), p(">95% / >90%", CELL), p("—", CELL)],
        [p("Periprosthetic\njoint infection", CELL_BOLD), p("50% / 95%\n(Tc+In-111 combo)", CELL), p("Improved", CELL), p("95% / 93%", CELL), p("—", CELL)],
        [p("Acute fracture\n(occult)", CELL_BOLD), p("95% / moderate", CELL), p("95–98% / high", CELL), p("—", CELL), p("~99% / high", CELL)],
        [p("AVN (early)", CELL_BOLD),          p("Moderate", CELL), p("Moderate–high", CELL), p("Variable", CELL), p("High", CELL)],
    ]
    ss_t = Table(ss_data, colWidths=ss_cw, repeatRows=1)
    ss_ts = [
        ("BACKGROUND", (0,0), (-1,0), C_TEAL),
        ("TEXTCOLOR",  (0,0), (-1,0), white),
        ("FONTNAME",   (0,0), (-1,0), "Helvetica-Bold"),
        ("ALIGN",      (0,0), (-1,0), "CENTER"),
        ("VALIGN",     (0,0), (-1,-1), "TOP"),
        ("GRID",       (0,0), (-1,-1), 0.4, C_MGREY),
        ("LINEBELOW",  (0,0), (-1,0), 1.2, C_TEAL),
        ("TOPPADDING", (0,0), (-1,-1), 3),
        ("BOTTOMPADDING", (0,0), (-1,-1), 3),
        ("LEFTPADDING",   (0,0), (-1,-1), 4),
        ("RIGHTPADDING",  (0,0), (-1,-1), 4),
    ]
    for i in range(1, len(ss_data)):
        if i % 2 == 0:
            ss_ts.append(("BACKGROUND", (0,i), (-1,i), C_LGREY))
        ss_ts.append(("BACKGROUND", (1,i), (1,i), C_LTBLUE))
        ss_ts.append(("BACKGROUND", (2,i), (2,i), HexColor("#e8f5e9")))
        ss_ts.append(("BACKGROUND", (3,i), (3,i), C_LTORANGE))
        ss_ts.append(("BACKGROUND", (4,i), (4,i), HexColor("#fdf5dc")))
    ss_t.setStyle(TableStyle(ss_ts))
    story.append(ss_t)
    story.append(Spacer(1, 4*mm))

    # ═══════════════════════════════════════════════════════════════════════
    # SECTION 6 – RECENT ADVANCES
    # ═══════════════════════════════════════════════════════════════════════
    story.append(section_banner("6.  RECENT ADVANCES (2020–2026)", C_NAVY))
    story.append(Spacer(1, 3*mm))

    advances = [
        ("Digital PET / Total-Body PET",
         "Silicon photomultiplier (SiPM) detectors improve sensitivity and resolution. Total-body PET (EXPLORER) images entire body simultaneously at ultra-low radiation doses – valuable for repeated imaging and paediatric patients."),
        ("PET/MRI",
         "Combines FDG metabolic data with MRI soft-tissue contrast. Reduced radiation vs PET/CT (MRI is radiation-free). Superior for soft-tissue sarcoma adjacent to bone, paediatric imaging, and periprosthetic infection. Technical challenges (MRI-based attenuation correction, cost) limit availability."),
        ("18F-NaF PET/CT",
         "Bone-specific PET tracer; sensitivity >99% for bone metastases. Superior pharmacokinetics, spatial resolution, and quantification vs 99mTc-MDP. FDA-approved; rapidly replacing conventional bone scan in high-end centres."),
        ("PSMA-targeted PET",
         "68Ga-PSMA-11 / 18F-DCFPyL: higher sensitivity than bone scan for early prostate cancer bone metastases. Revolutionised staging of prostate cancer skeletal disease."),
        ("Theranostics",
         "Diagnostic + therapeutic use of same molecular target: 68Ga-PSMA (imaging) → 177Lu-PSMA-617 (therapy); Ra-223 (first bone-targeted agent proven to improve overall survival – ALSYMPCA trial); 177Lu-DOTATATE for neuroendocrine bone mets. Alpha therapy (Pb-212, Ac-225) in trials."),
        ("CZT-SPECT Cameras",
         "Cadmium zinc telluride solid-state detectors: faster acquisition, smaller footprint, lower dose, higher resolution than conventional SPECT. Improving bone SPECT/CT performance in clinical practice."),
        ("AI Integration",
         "AI-assisted bone scan interpretation for automated lesion detection. Deep learning for SPECT/PET reconstruction (noise reduction, improved conspicuity). Quantitative Bone Scan Index (BSI) for objective tumour burden and treatment response monitoring."),
        ("Appropriate Use Criteria",
         "SNMMI/EANM published formal Appropriate Use Criteria for musculoskeletal infection imaging (2022–2024), guiding rational selection between bone scan, WBC scan, Ga-67, and FDG-PET/CT based on clinical scenario and anatomic site."),
        ("68Ga-DOTATATE / FAPI PET",
         "68Ga-DOTATATE PET/CT is gold standard for localising FGF-23-secreting tumours causing oncogenic osteomalacia. FAPI (fibroblast activation protein inhibitors) PET shows promise for musculoskeletal tumours with low background bone uptake."),
    ]

    adv_cw = [CONTENT_W*0.27, CONTENT_W*0.73]
    adv_data = [[p("Advance", COL_HDR), p("Summary", COL_HDR)]]
    for title_adv, desc in advances:
        adv_data.append([p(title_adv, CELL_BOLD), p(desc, CELL)])

    adv_t = Table(adv_data, colWidths=adv_cw, repeatRows=1)
    adv_ts = [
        ("BACKGROUND",    (0,0), (-1,0), C_NAVY),
        ("TEXTCOLOR",     (0,0), (-1,0), white),
        ("FONTNAME",      (0,0), (-1,0), "Helvetica-Bold"),
        ("ALIGN",         (0,0), (-1,0), "CENTER"),
        ("VALIGN",        (0,0), (-1,-1), "TOP"),
        ("GRID",          (0,0), (-1,-1), 0.4, C_MGREY),
        ("LINEBELOW",     (0,0), (-1,0), 1.5, C_NAVY),
        ("TOPPADDING",    (0,0), (-1,-1), 3),
        ("BOTTOMPADDING", (0,0), (-1,-1), 3),
        ("LEFTPADDING",   (0,0), (-1,-1), 5),
        ("RIGHTPADDING",  (0,0), (-1,-1), 5),
    ]
    for i in range(1, len(adv_data)):
        if i % 2 == 0:
            adv_ts.append(("BACKGROUND", (0,i), (0,i), HexColor("#dde8f5")))
            adv_ts.append(("BACKGROUND", (1,i), (1,i), C_LGREY))
        else:
            adv_ts.append(("BACKGROUND", (0,i), (0,i), HexColor("#e8edf2")))
    adv_t.setStyle(TableStyle(adv_ts))
    story.append(adv_t)
    story.append(Spacer(1, 4*mm))

    # ═══════════════════════════════════════════════════════════════════════
    # CLINICAL PEARLS BOX
    # ═══════════════════════════════════════════════════════════════════════
    story.append(section_banner("  CLINICAL PEARLS & PITFALLS", HexColor("#7b3f00")))
    story.append(Spacer(1, 3*mm))

    pearls = [
        ("PEARL", "A normal bone scan has HIGH negative predictive value – disease very unlikely if normal.",
         HexColor("#1a5c3a")),
        ("EXCEPTION", "Multiple myeloma – bone scan often FALSE NEGATIVE (lytic; no osteoblastic response). Use FDG-PET/CT.",
         HexColor("#5c1a1a")),
        ("PITFALL", "Bone scan remains positive for up to 2 years post-arthroplasty due to physiologic remodelling – cannot reliably diagnose periprosthetic infection on bone scan alone.",
         HexColor("#4a3a00")),
        ("PEARL", "Three-phase bone scan improves specificity for osteomyelitis: 74% → 94%.",
         HexColor("#1a3a5c")),
        ("PITFALL", "'Cold' scan in osteomyelitis = disrupted blood flow (periosteal pus, sequestrum, necrosis) – do not exclude osteomyelitis based on cold scan alone.",
         HexColor("#5c1a1a")),
        ("PEARL", "Gallium-67 (not bone scan) is used to MONITOR treatment response in osteomyelitis – bone scan uptake persists long after infection resolution.",
         HexColor("#1a5c3a")),
        ("PITFALL", "Indium-111 WBC scan has LOW sensitivity for SPINAL osteomyelitis – prefer FDG-PET/CT for vertebral infections.",
         HexColor("#4a3a00")),
        ("PEARL", "SPECT/CT is the key upgrade from planar scintigraphy – always preferred for complex anatomy (spine, foot/ankle, wrist, hip) and when specificity matters.",
         HexColor("#1a3a5c")),
        ("PEARL", "Superscan = diffusely increased whole-body uptake + absent renal activity: think hyperparathyroidism, renal osteodystrophy, or diffuse blastic metastases.",
         HexColor("#3a1a5c")),
    ]

    pearl_cw = [CONTENT_W*0.10, CONTENT_W*0.90]
    pearl_data = []
    for ptype, ptext, pcolor in pearls:
        badge_p = Paragraph(f"<font color='white'><b>{ptype}</b></font>",
            S("pb", fontName="Helvetica-Bold", fontSize=7.5, textColor=white,
              alignment=TA_CENTER, leading=10))
        pearl_data.append([badge_p, p(ptext, CELL)])

    pearl_t = Table(pearl_data, colWidths=pearl_cw)
    pearl_ts = [
        ("VALIGN",        (0,0), (-1,-1), "MIDDLE"),
        ("GRID",          (0,0), (-1,-1), 0.4, C_MGREY),
        ("TOPPADDING",    (0,0), (-1,-1), 4),
        ("BOTTOMPADDING", (0,0), (-1,-1), 4),
        ("LEFTPADDING",   (0,0), (-1,-1), 4),
        ("RIGHTPADDING",  (0,0), (-1,-1), 4),
    ]
    pearl_colors_map = [p[2] for p in pearls]
    for i, (ptype, _, pc) in enumerate(pearls):
        pearl_ts.append(("BACKGROUND", (0,i), (0,i), pc))
        if i % 2 == 0:
            pearl_ts.append(("BACKGROUND", (1,i), (1,i), C_LGREY))
    pearl_t.setStyle(TableStyle(pearl_ts))
    story.append(pearl_t)
    story.append(Spacer(1, 5*mm))

    # ═══════════════════════════════════════════════════════════════════════
    # FOOTER
    # ═══════════════════════════════════════════════════════════════════════
    divider(C_NAVY, 1.0)
    story.append(divider(C_NAVY, 1.0))
    story.append(Paragraph(
        "References: Rockwood & Green's Fractures in Adults 10e (2025) | Campbell's Operative Orthopaedics 15e (2026) | "
        "Miller's Review of Orthopaedics 9e | Rheumatology 2-Vol Set (Elsevier 2022) | "
        "Grainger & Allison's Diagnostic Radiology | "
        "Ibaseta A et al. JBJS Rev 2024 (PMID: 39283958) | "
        "SNMMI Appropriate Use Criteria 2024",
        FOOTER_STYLE
    ))
    story.append(Spacer(1, 2*mm))
    story.append(Paragraph(
        "This document is for educational reference only. Clinical decisions should be based on complete clinical context and institutional protocols.",
        FOOTER_STYLE
    ))

    doc.build(story)
    print(f"PDF saved: {OUTPUT_PATH}")

if __name__ == "__main__":
    build_pdf()
Running Command

cd /home/daytona/workspace/nuclear-ortho-pdf && python3 generate_pdf.py 2>&1

Running Command

ls -lh /home/daytona/workspace/nuclear-ortho-pdf/Nuclear_Medicine_Ortho_Quick_Re…

Your quick reference PDF is ready.

Nuclear Medicine Ortho Quick Ref

PDF Document · PDF


What's inside (2-page A4 color document):
Page 1
  • Modality Overview Table - Bone Scan vs SPECT/CT vs FDG-PET/CT vs 18F-NaF PET/CT across 11 parameters (tracer, mechanism, timing, resolution, sensitivity, specificity, dose, cost, etc.)
  • Condition-by-Condition Comparison covering 6 categories with color-coded rows:
    • Trauma & Fractures (occult fracture, sacral insufficiency, scaphoid, non-union, child abuse)
    • Infection (osteomyelitis, spondylodiskitis, periprosthetic infection, diabetic foot)
    • Bone Tumours & Metastases (metastases, myeloma, osteosarcoma, benign differentiation)
    • Arthritis (sacroiliitis, OA, gout, CRPS)
    • Metabolic Bone Disease (Paget's, AVN, superscan, osteomalacia, oncogenic osteomalacia)
    • Spine (low back pain, post-fusion assessment)
Page 2
  • Three-Phase Bone Scan Protocol - each phase with timing, appearance, and clinical significance
  • Radiopharmaceutical Reference - 9 agents (Tc-99m MDP, Ga-67, In-111 WBC, HMPAO-WBC, Sulfur Colloid, FDG, NaF, Ra-223, 68Ga-DOTATATE)
  • Sensitivity & Specificity Summary across conditions
  • Recent Advances (2020-2026) - Digital PET, PET/MRI, NaF, PSMA, Theranostics, CZT-SPECT, AI, FAPI
  • Clinical Pearls & Pitfalls - 9 high-yield points (myeloma false negative, bone scan post-arthroplasty, cold scan pitfall, etc.)
This is a shared conversation. Sign in to Orris to start your own chat.