From now for topic follow the below structure 1. 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 Additional features:include diagram and flow chart

Got it! I'll follow that structured format for every topic going forward, covering all 14 sections with diagrams and flowcharts included. Just tell me the first topic you'd like covered and I'll get started.

Common peroneal nerve

Reading File
Finding Sources
Searching the Web

common peroneal nerve anatomy injury classification treatment

Searching PubMed

"common peroneal nerve" injury treatment

Reading File
Reading File
Finding Sources
Finding Sources
Reading File
Reading File
Reading File
Reading File
Loading Image
Loading Image
Reading File
Reading File
Loading Image
Finding Sources
Finding Sources
Reading File
Reading File
Generating Image

Anatomical diagram of the common peroneal nerve showing its origin from the sciatic nerve, course around the fibular head, division into deep and superficial peroneal nerve branches, motor and sensory distributions in the lower leg and foot, with labeled muscle groups (tibialis anterior, extensor digitorum longus, extensor hallucis longus, peroneus longus, peroneus brevis) and sensory areas on dorsum of foot

Generating Image

Clinical flowchart for management of common peroneal nerve injury showing: initial assessment with history and examination, then NCS/EMG, then branching into low-energy vs high-energy injury, conservative path including observation, ankle foot orthosis, physiotherapy, with timeline of 3-6 months observation, surgical path including neurolysis, nerve repair/grafting, nerve transfer, tendon transfer for late cases, with decision points based on Seddon/Sunderland classification and recovery outcomes

Loading Image
I now have all the information needed. Let me compile the comprehensive structured response.

Common Peroneal Nerve


1. Introduction

The common peroneal nerve (CPN), also called the common fibular nerve, is the lateral terminal division of the sciatic nerve. It is the most commonly injured peripheral nerve in the lower extremity, accounting for its vulnerability to both traumatic and compressive injuries. Damage produces the characteristic clinical syndrome of foot drop - inability to dorsiflex the foot - along with variable sensory loss over the anterolateral leg and dorsum of the foot. Understanding its anatomy is the key to understanding why it is so prone to injury and how to manage the sequelae.

2. History

  • The peroneal nerve and foot drop have been recognised since antiquity, with the term "peroneal" derived from the Greek perone (fibula).
  • Sir Herbert Seddon (1942) and Sir Sydney Sunderland (1951) developed the nerve injury classification systems still used today.
  • The condition was historically recognised in occupational settings (strawberry pickers, textile workers) and in soldiers after prolonged crouching (trench palsy).
  • "Punter's palsy" - peroneal injury from ankle inversion while kicking - was described in American football literature.
  • The concept of intraneural ganglia from the superior tibiofibular joint as an underappreciated cause was clarified in modern imaging studies.

3. Anatomy

Origin and Root Value

  • Root values: L4, L5, S1, S2
  • Arises as the lateral division of the sciatic nerve, separating from it in the posterolateral aspect of the popliteal fossa (or higher in the thigh in cases of early bifurcation)

Course

SegmentRelations
Popliteal fossaLies in a fat plane between lateral head of gastrocnemius and biceps femoris
Around fibular headTurns around the biceps femoris tendon and fibular head - most vulnerable point
Fibular tunnelPasses under a fibrous arch at the origin of peroneus longus muscle
Proximal legDivides into 3 branches

Branches

  1. Superficial peroneal nerve - innervates peroneus longus and brevis (ankle eversion); sensory to anterolateral distal leg and dorsum of foot (except 1st web space)
  2. Deep peroneal nerve - innervates tibialis anterior, extensor digitorum longus, extensor hallucis longus, extensor digitorum brevis (ankle dorsiflexion, toe extension); sensory to 1st dorsal web space
  3. Recurrent articular nerve - sensory to knee joint
  4. Lateral sural cutaneous nerve - sensory to upper lateral leg

Motor Innervation Summary

MuscleActionBranch
Tibialis anteriorDorsiflexion + inversionDeep peroneal
Extensor digitorum longusToe extension, dorsiflexionDeep peroneal
Extensor hallucis longusBig toe extensionDeep peroneal
Extensor digitorum brevisToe extensionDeep peroneal
Peroneus longusEversion, plantarflexionSuperficial peroneal
Peroneus brevisEversionSuperficial peroneal

Anatomical Diagram

Common peroneal nerve anatomy with branches and motor/sensory distributions

MRI Anatomy - Axial View at Knee (Distal Popliteal Fossa)

MRI axial at popliteal fossa showing common peroneal nerve lateral to biceps femoris, with tibial nerve medially
Fig: Axial MRI at the popliteal fossa. The common peroneal nerve lies lateral between the biceps femoris (BF) and lateral gastrocnemius (G-lat). Tibial nerve is medial. - Imaging Anatomy, Vol. 3
MRI axial at level of fibular head showing common peroneal nerve wrapping around
Fig: Axial MRI at the level of the distal popliteal fossa showing the common peroneal nerve and tibial nerve with surrounding structures. - Imaging Anatomy, Vol. 3

Why Is the CPN So Vulnerable?

Six anatomical factors contribute:
  1. Superficial course around the fibular neck - no deep muscle coverage
  2. Tethered proximally by the biceps femoris tendon and distally by the peroneus longus arch
  3. Limited excursion - the nerve has restricted ability to move away from the fibular head
  4. Bony prominence - the fibular head acts as a pulley, concentrating mechanical stress
  5. Early proximal bifurcation in some individuals increases the exposure length
  6. Fascicular arrangement - the deep peroneal fascicles lie on the deep surface at the fibular neck, pressed directly against bone

4. Etiology

Traumatic

CauseNotes
Knee dislocation / multiligament injuryCPN injured in up to 44% of posterolateral corner injuries
Fracture of fibular head/neck~50% of fibular head fractures have associated CPN injury
Direct blow to lateral kneeClassic "car bumper" injury
Knee arthroplasty (TKA)Especially with valgus correction; lithotomy position
Laceration / penetrating traumaWartime, iatrogenic

Compressive / Positional

CauseNotes
Habitual leg crossingMost common compressive cause
Prolonged squattingStrawberry pickers, yoga (yoga foot drop)
Tight plaster castPressure at fibular neck
Obstetric stirrups / lithotomy positionBilateral palsy during prolonged labour (pushing palsy)
Prolonged bed rest / immobilityWeight loss + emaciation exacerbates risk
Tight knee bootsExternal compression

Space-Occupying Lesions

  • Baker cyst extending into retropopliteal space
  • Intraneural ganglion (from superior tibiofibular joint - an underrecognised but treatable cause)
  • Ganglion cyst, lipoma, osteochondroma at fibular head
  • Hematoma, aneurysm

Medical/Systemic

  • Diabetic neuropathy - lower ischaemic threshold predisposes to entrapment
  • Vasculitis - nerve infarct
  • Leprosy
  • Anorexia nervosa / cancer / AIDS - emaciation removes protective fat padding

Iatrogenic

  • Postoperative positioning (lateral decubitus, lithotomy)
  • Orthopaedic operations (high tibial osteotomy, TKA)
  • Poorly applied casts, bandages, or splints

5. Mechanism

General Mechanisms

1. Compression/Entrapment The nerve is pressed between the fibular head and overlying soft tissues. Sustained pressure causes local ischaemia → segmental demyelination → neurapraxia. If sustained, progresses to axonal injury.
2. Traction / Stretch Forced plantarflexion-inversion of the ankle (e.g., punter's palsy, knee dislocation) stretches the nerve around its fibular tether. Traction injury more commonly produces axonotmesis or neurotmesis than pure compression.
3. Direct Laceration Complete or partial nerve transection. Requires surgical intervention.
4. Intraneural Ganglion Mechanism Disruption of the superior tibiofibular joint capsule allows synovial fluid to dissect along the articular branch of the CPN retrogradely into the main nerve trunk, creating a cystic expansion with intraneural compression.
5. Ischaemia Compartment syndrome of the anterior/lateral compartment → ischaemic neuropathy affecting the deep peroneal nerve particularly.

6. Pathology

Wallerian Degeneration

Distal to a complete axonal injury, the axon and myelin sheath undergo Wallerian degeneration within 3-7 days. Schwann cells proliferate to form bands of Büngner, guiding regenerating axons.

Nerve Regeneration Rate

  • Axonal regeneration proceeds at 1-3 mm/day (approximately 1 inch per month)
  • Grade 1-2 injuries: rapid regeneration, excellent recovery
  • Grade 3: slower (~1 mm/day), incomplete and unpredictable
  • Grades 4-5: no spontaneous regeneration; requires surgical intervention

Denervation Changes in Muscle

  • Fibrillation potentials appear on EMG within 3 weeks of axonal injury
  • Muscle atrophy begins within weeks; irreversible after approximately 12-18 months
  • This establishes the critical window for surgical nerve repair (should not exceed 12 months)

7. Clinical Features

Symptoms

  • Foot drop - inability to dorsiflex the foot; the hallmark presentation
  • High-stepping gait (steppage gait) - hip and knee flexed excessively to clear the toe from the ground
  • Sensory loss over anterolateral leg and dorsum of foot (deep peroneal pattern: 1st web space only; superficial peroneal: broader dorsum)
  • Pain - variable; more common with intraneural ganglia or entrapment
  • Onset may be acute (trauma) or noticed on waking (compression during sleep)

Signs

FindingSignificance
Weakness of dorsiflexionDeep peroneal branch
Weakness of eversionSuperficial peroneal branch
Preserved inversionTibial nerve (L4/L5 mediated) - key differentiator from L5 root
Preserved plantar flexionTibial nerve intact
Sensory loss dorsum of footSuperficial peroneal
Sensory loss 1st web space onlyDeep peroneal branch only
Tinel's sign at fibular headSuggests compressive/regenerating lesion
Steppage gaitCompensation for foot drop

Selective Deep Peroneal Involvement

In many fibular head lesions, the deep branch fascicles (lying on the deep/medial surface) are preferentially injured, producing predominantly dorsiflexion weakness with relative sparing of eversion. In some cases, the extensor hallucis longus fascicle alone is affected, producing big toe drop rather than full foot drop.

Differential Diagnosis of Foot Drop

ConditionKey Distinguishing Features
CPN palsyEversion weak, inversion spared, Tinel at fibular head, NCS abnormal
L5 radiculopathyInversion AND eversion weak, hip abduction may be weak, back pain, EMG shows paraspinal changes
Lumbosacral plexopathyBroader deficit, hip abduction weak
ALS/motor neuron diseaseUpper motor neuron signs, widespread fasciculations
Tibialis anterior tendon rupturePalpable gap, normal EMG

8. Investigation

Clinical

  • Detailed neurological examination (motor testing, sensory mapping, reflexes)
  • Tinel's sign at fibular head
  • Assessment for systemic causes (diabetes, weight loss, vasculitis)

Electrodiagnostic Studies (Gold Standard)

StudyFinding in CPN Palsy
Motor NCSSlowed conduction velocity across fibular head; reduced CMAP amplitude distal to lesion; localises lesion
Sensory NCSReduced/absent superficial peroneal SNAP
EMG (needle)Fibrillation potentials, reduced recruitment in tibialis anterior, EHL, EDL, peroneus muscles
EMG paraspinalsNormal in CPN palsy - differentiates from L5 radiculopathy
Key NCS finding: Conduction block (>50% drop in CMAP amplitude) across fibular head = neurapraxia (good prognosis). Axonal loss (reduced amplitude throughout) = axonotmesis or worse.
EMG findings appear 3 weeks post-injury - early testing may be falsely reassuring.

Laboratory

  • Blood glucose / HbA1c (diabetes screen)
  • ESR, ANCA, cryoglobulins (if vasculitis suspected)

9. Radiograph

Plain X-rays have limited direct utility for nerve assessment but are essential for:
  • Fibular head/neck fractures - up to 50% have associated CPN injury
  • Knee dislocation - identifies bony injury
  • Tibial plateau fractures - associated with posterolateral corner and CPN injury
  • Calcification near fibular head suggesting ganglion calcification or bony lesion
  • Assessment of alignment (valgus knee increases CPN stretch risk)

10. CT

CT is not the primary modality for nerve assessment but is useful for:
  • Characterising bony lesions (osteochondroma, exostosis) compressing the nerve
  • Fracture detail at fibular head - exact fracture pattern, displacement
  • Pre-operative planning for complex periarticular fractures
  • Identifying calcified ganglia
  • CT myelogram if MR contraindicated and radiculopathy is in the differential
Axial CT at popliteal level showing the common peroneal nerve and surrounding anatomy
Axial CT/MR hybrid image at the knee level showing the common peroneal nerve in relation to biceps femoris, lateral gastrocnemius, and fibula. - Imaging Anatomy, Vol. 3

11. MRI

MRI is the imaging modality of choice for the common peroneal nerve.

Normal MRI Appearance

  • Nerve appears as small bundles of fascicles in a supporting fatty background
  • Isointense to muscle on T1; slightly hyperintense on T2/PD
  • Best seen on axial sequences; nerve typically visible in most routine knee MRI sequences

Pathological Findings

FindingSignificance
T2 hyperintensity of nerve without enlargementNeurapraxia (reversible)
T2 hyperintensity + nerve enlargementAxonotmesis, inflammation
Nerve discontinuity / neuromaNeurotmesis (Sunderland grade 5)
Intraneural cystic lesion tracking from tibiofibular jointIntraneural ganglion
Denervation changes in anterior compartment (T2 bright muscle)Subacute/chronic axonal injury
Fat replacement in anterior compartment musclesChronic denervation (irreversible)

MRI Knee Series (Axial)

MRI at popliteal fossa - common peroneal nerve near lateral gastrocnemius and biceps femoris
Axial MRI showing the common peroneal nerve at the level of the femoral condyles, adjacent to lateral gastrocnemius (G-lat) and medial gastrocnemius (G-med) origins. - Imaging Anatomy, Vol. 3

MRI Protocol

  • Knee MRI: Standard sequences + dedicated axial T1 spin echo for nerve mapping
  • High-resolution peripheral nerve MRI (MR neurography): 3T, 3D STIR or DWIBS sequences; allows nerve tracking from sciatic origin to distal branches
  • Coverage should extend from proximal thigh to proximal fibula to encompass entire vulnerable segment

12. Classification

Seddon Classification (1942)

GradeDescriptionPrognosis
NeurapraxiaMyelin injury only; axon intact; conduction blockFull recovery in weeks-months without surgery
AxonotmesisAxon disrupted; endoneurium intactRecovery at 1-3 mm/day; usually good
NeurotmesisComplete nerve division including connective tissue sheathsNo spontaneous recovery; surgery required

Sunderland Classification (1951) - More Detailed

GradeStructures DisruptedRecovery Potential
1Myelin only (= neurapraxia)Full; within 12 weeks
2Axon discontinuity; endoneurium intact (= axonotmesis)Excellent; rapid regeneration at 2-3 mm/day
3Axon + endoneurium; perineurium intactIncomplete, unpredictable; ~1 mm/day; intraneural scarring
4Axon + endoneurium + perineurium; epineurium intactNo spontaneous recovery; neuroma-in-continuity
5Complete nerve disruption (= neurotmesis)No recovery; end neuroma formation
6 (MacKinnon addition)Mixed/combined pattern across fasciclesVariable early recovery then plateau

Classification by Location

LevelFeatures
Above knee (sciatic level)Combined tibial + peroneal deficits
Fibular head (most common)Classic CPN palsy
Deep peroneal onlyDorsiflexion weakness; eversion spared
Superficial peroneal onlyEversion weakness; sensory on dorsum
Anterior tarsal tunnelExtensor digitorum brevis + 1st web space

13. Treatment

Management Flowchart

Clinical management flowchart for common peroneal nerve injury

A. Non-Operative Management

Indications:
  • Neurapraxia (Sunderland grade 1) / low-energy compressive injuries
  • Axonotmesis with reasonable recovery potential
  • Systemic/metabolic cause amenable to treatment
1. Activity Modification and Risk Factor Elimination
  • Avoid leg crossing, prolonged squatting
  • Rapid weight loss if entrapment related to obesity causing excess pressure
  • Treat underlying diabetes, vasculitis, hypothyroidism
  • Pad lateral knee if continued pressure unavoidable
2. Ankle-Foot Orthosis (AFO)
  • Rigid or articulated AFO maintains ankle in neutral dorsiflexion during swing phase
  • Provides:
    • Toe dorsiflexion during swing phase
    • Medial/lateral stability at ankle during stance
    • Push-off stimulation during late stance
  • Carbon fibre AFOs are lightweight and functionally superior to traditional polypropylene
3. Physiotherapy
  • Maintain joint range of motion to prevent contracture
  • Stretching of triceps surae to prevent equinus
  • Strengthening of intact muscle groups
  • Gait retraining
4. Functional Electrical Stimulation (FES)
  • Peroneal nerve stimulator devices (e.g., WalkAide, Bioness L300)
  • Surface electrode over CPN triggers dorsiflexion during swing phase
  • Increasingly used as first-line adjunct to AFO
5. Observation Period
  • Neurapraxia: expect recovery within 4-12 weeks
  • Axonotmesis: observe for 3-6 months for signs of reinnervation
  • Serial EMG/NCS to track recovery
  • No spontaneous improvement after 3-6 months → surgical re-evaluation

B. Operative Management

Indications for Surgery:
  • High-energy injuries (laceration, fracture-dislocation, gunshot) → explore within 3 weeks
  • No recovery after 3-6 months of observation (low energy) or no recovery at 3 months (axonal loss on NCS)
  • Known anatomical compressor (ganglion, tumour, bony fragment)
  • Intraneural ganglion confirmed on MRI
Critical Surgical Principle: Nerve repair results become suboptimal if surgery is performed more than 12 months after injury or if graft length required exceeds 12 cm.
1. Neurolysis (External and Internal)
  • Release of fibrous/scar tissue compressing the nerve externally (external neurolysis) or between fascicles (internal neurolysis)
  • Indications: entrapment, neuroma-in-continuity (Sunderland grade 3-4), intraneural ganglion
  • For intraneural ganglia: decompression + resection of articular branch + tibiofibular joint capsule repair to prevent recurrence
  • Success in up to 60-70% if performed within 6 months of injury
2. Nerve Repair (Neurorrhaphy)
  • Primary repair: Direct epineural or fascicular suture; only if tension-free
  • Indications: sharp laceration, early exploration, small gap
  • Best results when performed early with short gap and low lesion
  • Under ideal conditions (early, low lesion, small gap): 60-70% achieve useful dorsiflexion (anti-gravity)
3. Nerve Grafting
  • For gaps > 2-3 cm preventing tension-free repair
  • Autograft (sural nerve, medial cutaneous nerve of forearm) remains the gold standard
  • Mean graft length in published series: 7 cm; shorter grafts give significantly better outcomes
  • Among 465 patients undergoing peroneal nerve reconstruction: 49% achieved >M3 recovery - Sabiston Textbook of Surgery
  • Allograft (processed decellularised nerve) used for gaps 5-70 mm when donor site morbidity must be minimised
4. Nerve Transfer
  • Transfers a fascicle from the tibial nerve to the distal CPN (end-to-end fashion)
  • Used when proximal stump unavailable or gap too long for grafting
  • Meta-analysis: 62.9% achieved >M3 function with tibial-to-CPN nerve transfer
  • Avoids long regeneration distances; particularly useful for proximal injuries
5. Tendon Transfer (Salvage Procedure)
  • For late presentations (>12-18 months), irreversible denervation, or failed nerve repair
  • Standard transfer: Tibialis posterior transfer to dorsum of foot (Bridle procedure or direct transfer through interosseous membrane)
  • Restores active dorsiflexion using a tibial nerve-innervated muscle
  • Additional: peroneus longus to brevis transfer, toe extensor augmentation
  • Most reliable and durable long-term solution for established foot drop
Surgical Approach
  • Patient supine or lateral decubitus; thigh tourniquet
  • Longitudinal incision from popliteal fossa, curving anterolaterally around fibular head
  • Knee flexion relaxes the nerve
  • Expose nerve from popliteal fossa to fibular tunnel
  • Protect sural nerve branch

14. Recent Advances

1. MR Neurography (High-Resolution Nerve Imaging)

  • 3T MRI with dedicated surface coils, 3D-STIR and diffusion tensor imaging (DTI) allows direct visualisation of the nerve, fascicular detail, and continuity - aiding surgical planning

2. Nerve Transfers

  • Expanding use of selective tibial nerve branch transfer to deep peroneal nerve targets (tibialis anterior, EHL)
  • End-to-side neurorrhaphy techniques allow partial reinnervation without fully sacrificing donor nerve

3. Intraoperative Nerve Monitoring and Nerve Stimulation

  • Intraoperative EMG and nerve action potential (NAP) recording during surgery guides extent of resection vs neurolysis in neuroma-in-continuity cases

4. Nerve Conduits and Processed Allografts

  • Polyglycolic acid and collagen conduits for short gaps (< 3 cm); processed nerve allografts (Avance) for 5-70 mm gaps avoiding donor site morbidity from sural nerve harvest

5. Functional Electrical Stimulation (FES) / Neuroprosthetics

  • Implantable FES systems (e.g., ActiGait, Bioness L300 Plus) with closed-loop gait-triggered stimulation are now in clinical use, providing functional improvement equivalent to or better than fixed AFO

6. Platelet-Rich Plasma (PRP) and Growth Factors

  • Emerging evidence for PRP injection at lesion site to promote remyelination and axonal regeneration; mostly experimental

7. Ultrasound-Guided Diagnosis and Intervention

  • High-frequency ultrasound (15-18 MHz) allows real-time dynamic assessment of the nerve at the fibular head, identification of ganglion cysts, and ultrasound-guided aspiration of intraneural ganglia

8. Intraneural Ganglion - Tibiofibular Joint Repair

  • Recognition that recurrence after simple decompression is reduced by articular branch excision and tibiofibular joint capsule repair - now the standard surgical approach

Quick Reference Summary

FeatureDetail
Root valueL4, L5, S1, S2
OriginLateral division of sciatic nerve
Most vulnerable pointFibular head/neck
Most common injuryCompression/entrapment
Key clinical signFoot drop + weak eversion, preserved inversion
Gold standard investigationNCS/EMG
Critical repair window< 12 months post-injury
Best surgical outcome60-70% achieve anti-gravity dorsiflexion (ideal conditions)
Late salvageTibialis posterior tendon transfer

Sources:

Generate a quick reference clinical decision support PDF on CPN injury management

For answer structure given According to Orthopaedics point of view

Reading File
Running Command

ls /home/daytona/workspace/ 2>/dev/null || echo "workspace empty or not found"

Running Command

mkdir -p /home/daytona/workspace/cpn-nerve && python3 -c "import reportlab; print(reportlab.Version)"

Writing File

~/cpn-nerve/generate_cpn_pdf.py

"""
CPN Injury Management - Quick Reference Clinical Decision Support PDF
Orthopaedic Perspective
"""

from reportlab.lib.pagesizes import A4
from reportlab.lib import colors
from reportlab.lib.units import mm, cm
from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
from reportlab.lib.enums import TA_CENTER, TA_LEFT, TA_JUSTIFY
from reportlab.platypus import (
    SimpleDocTemplate, Paragraph, Spacer, Table, TableStyle,
    HRFlowable, KeepTogether, PageBreak
)
from reportlab.platypus.flowables import Flowable
from reportlab.graphics.shapes import Drawing, Rect, String, Line, Polygon, Arrow
from reportlab.graphics import renderPDF
from reportlab.lib.colors import HexColor
import io

# ─── COLOUR PALETTE ────────────────────────────────────────────────────────────
NAVY      = HexColor("#0D2B55")
TEAL      = HexColor("#0A7E8C")
ORANGE    = HexColor("#E87722")
LIGHT_BG  = HexColor("#F0F4F8")
MID_BLUE  = HexColor("#1A5276")
GREEN     = HexColor("#1E8449")
RED       = HexColor("#C0392B")
YELLOW_BG = HexColor("#FEF9E7")
WHITE     = colors.white
GREY      = HexColor("#7F8C8D")
LIGHT_GREY= HexColor("#ECF0F1")
BOX_BLUE  = HexColor("#D6EAF8")
BOX_GREEN = HexColor("#D5F5E3")
BOX_RED   = HexColor("#FADBD8")
BOX_ORANGE= HexColor("#FDEBD0")

W, H = A4  # 595 x 842 pt

# ─── STYLES ────────────────────────────────────────────────────────────────────
styles = getSampleStyleSheet()

def make_style(name, **kwargs):
    return ParagraphStyle(name, **kwargs)

title_style = make_style('Title',
    fontName='Helvetica-Bold', fontSize=22, textColor=WHITE,
    alignment=TA_CENTER, spaceAfter=4)

subtitle_style = make_style('Subtitle',
    fontName='Helvetica', fontSize=11, textColor=HexColor("#BDC3C7"),
    alignment=TA_CENTER, spaceAfter=2)

section_style = make_style('Section',
    fontName='Helvetica-Bold', fontSize=12, textColor=WHITE,
    alignment=TA_LEFT, spaceBefore=6, spaceAfter=4,
    leftIndent=8)

body_style = make_style('Body',
    fontName='Helvetica', fontSize=9, textColor=HexColor("#2C3E50"),
    alignment=TA_LEFT, spaceAfter=3, leading=13)

bold_body = make_style('BoldBody',
    fontName='Helvetica-Bold', fontSize=9, textColor=HexColor("#2C3E50"),
    alignment=TA_LEFT, spaceAfter=3, leading=13)

small_style = make_style('Small',
    fontName='Helvetica', fontSize=8, textColor=HexColor("#2C3E50"),
    alignment=TA_LEFT, spaceAfter=2, leading=11)

bullet_style = make_style('Bullet',
    fontName='Helvetica', fontSize=8.5, textColor=HexColor("#2C3E50"),
    alignment=TA_LEFT, leftIndent=10, spaceAfter=2, leading=12,
    bulletIndent=0)

table_header = make_style('TableHeader',
    fontName='Helvetica-Bold', fontSize=8.5, textColor=WHITE,
    alignment=TA_CENTER)

table_body = make_style('TableBody',
    fontName='Helvetica', fontSize=8, textColor=HexColor("#2C3E50"),
    alignment=TA_LEFT, leading=11)

caption_style = make_style('Caption',
    fontName='Helvetica-Oblique', fontSize=7.5, textColor=GREY,
    alignment=TA_CENTER, spaceAfter=3)

flowchart_label = make_style('FlowLabel',
    fontName='Helvetica-Bold', fontSize=8, textColor=WHITE,
    alignment=TA_CENTER, leading=10)

alert_style = make_style('Alert',
    fontName='Helvetica-Bold', fontSize=9, textColor=WHITE,
    alignment=TA_CENTER, leading=13)

# ─── HEADER BANNER FLOWABLE ────────────────────────────────────────────────────
class HeaderBanner(Flowable):
    def __init__(self, width, height=70):
        Flowable.__init__(self)
        self.width = width
        self.height = height

    def draw(self):
        c = self.canv
        # Main background
        c.setFillColor(NAVY)
        c.roundRect(0, 0, self.width, self.height, 8, fill=1, stroke=0)
        # Accent bar
        c.setFillColor(TEAL)
        c.roundRect(0, 0, 6, self.height, 3, fill=1, stroke=0)
        # Right accent
        c.setFillColor(ORANGE)
        c.roundRect(self.width-6, 0, 6, self.height, 3, fill=1, stroke=0)

        # Title
        c.setFillColor(WHITE)
        c.setFont("Helvetica-Bold", 20)
        c.drawCentredString(self.width/2, self.height - 30, "COMMON PERONEAL NERVE INJURY")
        # Subtitle
        c.setFillColor(HexColor("#BDC3C7"))
        c.setFont("Helvetica", 10)
        c.drawCentredString(self.width/2, self.height - 46,
            "Quick Reference Clinical Decision Support  |  Orthopaedic Perspective")
        # Footer line of header
        c.setFillColor(ORANGE)
        c.setFont("Helvetica-Bold", 8)
        c.drawCentredString(self.width/2, 8, "Campbell's Operative Orthopaedics 15e • Adams & Victor 12e • Harrison's 22e • Localization in Clinical Neurology 8e")

# ─── SECTION HEADER ────────────────────────────────────────────────────────────
class SectionHeader(Flowable):
    def __init__(self, text, width, color=TEAL, number=None):
        Flowable.__init__(self)
        self.text = text
        self.width = width
        self.color = color
        self.number = number
        self.height = 22

    def draw(self):
        c = self.canv
        c.setFillColor(self.color)
        c.roundRect(0, 0, self.width, self.height, 4, fill=1, stroke=0)
        c.setFillColor(WHITE)
        c.setFont("Helvetica-Bold", 11)
        label = f"  {self.number}. {self.text}" if self.number else f"  {self.text}"
        c.drawString(10, 6, label)

# ─── COLOURED BOX ──────────────────────────────────────────────────────────────
class ColourBox(Flowable):
    def __init__(self, content_items, width, bg_color=BOX_BLUE, border_color=TEAL,
                 title=None, title_color=TEAL):
        Flowable.__init__(self)
        self.content_items = content_items
        self.width = width
        self.bg_color = bg_color
        self.border_color = border_color
        self.title = title
        self.title_color = title_color
        # estimate height
        lines = sum(1 + item.count('\n') for item in content_items)
        self.height = (22 if title else 0) + lines * 13 + 14

    def draw(self):
        c = self.canv
        c.setFillColor(self.bg_color)
        c.setStrokeColor(self.border_color)
        c.setLineWidth(1.5)
        c.roundRect(0, 0, self.width, self.height, 5, fill=1, stroke=1)
        y = self.height - 12
        if self.title:
            c.setFillColor(self.title_color)
            c.setFont("Helvetica-Bold", 9)
            c.drawString(8, y, self.title)
            y -= 13
            c.setStrokeColor(self.border_color)
            c.setLineWidth(0.5)
            c.line(6, y + 2, self.width - 6, y + 2)
            y -= 4
        c.setFillColor(HexColor("#2C3E50"))
        c.setFont("Helvetica", 8.5)
        for item in self.content_items:
            lines = item.split('\n')
            for line in lines:
                if line.strip():
                    c.drawString(10, y, line)
                    y -= 12

# ─── ALERT BOX ─────────────────────────────────────────────────────────────────
class AlertBox(Flowable):
    def __init__(self, text, width, bg=RED, icon="⚠"):
        Flowable.__init__(self)
        self.text = text
        self.width = width
        self.bg = bg
        self.icon = icon
        self.height = 28

    def draw(self):
        c = self.canv
        c.setFillColor(self.bg)
        c.roundRect(0, 0, self.width, self.height, 5, fill=1, stroke=0)
        c.setFillColor(WHITE)
        c.setFont("Helvetica-Bold", 9.5)
        c.drawCentredString(self.width/2, 9, self.text)

# ─── FLOWCHART ─────────────────────────────────────────────────────────────────
class ManagementFlowchart(Flowable):
    def __init__(self, width):
        Flowable.__init__(self)
        self.width = width
        self.height = 310

    def box(self, c, x, y, w, h, text, bg, text_color=WHITE, fontsize=8, radius=5, bold=False):
        c.setFillColor(bg)
        c.setStrokeColor(HexColor("#2C3E50"))
        c.setLineWidth(0.8)
        c.roundRect(x, y, w, h, radius, fill=1, stroke=1)
        c.setFillColor(text_color)
        font = "Helvetica-Bold" if bold else "Helvetica"
        c.setFont(font, fontsize)
        lines = text.split('\n')
        line_h = fontsize + 2
        total_h = len(lines) * line_h
        start_y = y + h/2 + total_h/2 - line_h
        for line in lines:
            c.drawCentredString(x + w/2, start_y, line)
            start_y -= line_h

    def arrow(self, c, x1, y1, x2, y2, label=""):
        c.setStrokeColor(NAVY)
        c.setLineWidth(1.2)
        c.line(x1, y1, x2, y2)
        # arrowhead
        c.setFillColor(NAVY)
        size = 5
        if x1 == x2:  # vertical
            c.polygon([x2-size/2, y2+size, x2+size/2, y2+size, x2, y2], fill=1, stroke=0)
        else:  # horizontal
            c.polygon([x2-size, y2+size/2, x2-size, y2-size/2, x2, y2], fill=1, stroke=0)
        if label:
            c.setFillColor(ORANGE)
            c.setFont("Helvetica-Bold", 7.5)
            mx, my = (x1+x2)/2, (y1+y2)/2
            c.drawCentredString(mx, my + 4, label)

    def draw(self):
        c = self.canv
        W = self.width
        # Background
        c.setFillColor(LIGHT_BG)
        c.roundRect(0, 0, W, self.height, 6, fill=1, stroke=0)

        # Title
        c.setFillColor(NAVY)
        c.setFont("Helvetica-Bold", 10)
        c.drawCentredString(W/2, self.height - 16, "CPN INJURY — MANAGEMENT ALGORITHM")

        # Row Y positions (top to bottom)
        y_top = self.height - 45
        bw = 140   # box width
        bh = 30
        cx = W/2

        # ── Box 1: Initial Assessment
        self.box(c, cx - bw/2, y_top, bw, bh, "INITIAL ASSESSMENT\nHistory + Examination", NAVY, bold=True)
        self.arrow(c, cx, y_top, cx, y_top - 18)

        # ── Box 2: NCS/EMG
        y2 = y_top - 18 - bh
        self.box(c, cx - bw/2, y2, bw, bh, "NCS / EMG\n(≥3 weeks post-injury)", TEAL, bold=True)
        self.arrow(c, cx, y2, cx, y2 - 18)

        # ── Decision diamond — Energy of Injury
        y3 = y2 - 18 - 36
        dw, dh = 150, 36
        # Draw diamond
        c.setFillColor(MID_BLUE)
        c.setStrokeColor(NAVY)
        c.setLineWidth(1)
        cx_d, cy_d = cx, y3 + dh/2
        c.beginPath()
        c.moveTo(cx_d, cy_d + dh/2)
        c.lineTo(cx_d + dw/2, cy_d)
        c.lineTo(cx_d, cy_d - dh/2)
        c.lineTo(cx_d - dw/2, cy_d)
        c.closePath()
        c.drawPath(c._currentPath if hasattr(c, '_currentPath') else c.beginPath(), fill=1, stroke=1)
        # Redraw properly
        pts = [cx_d, cy_d + dh/2, cx_d + dw/2, cy_d, cx_d, cy_d - dh/2, cx_d - dw/2, cy_d]
        c.setFillColor(MID_BLUE)
        c.polygon(pts, fill=1, stroke=1)
        c.setFillColor(WHITE)
        c.setFont("Helvetica-Bold", 8)
        c.drawCentredString(cx_d, cy_d + 4, "Mechanism of Injury?")
        c.setFont("Helvetica", 7.5)
        c.drawCentredString(cx_d, cy_d - 6, "Energy / Type")

        # Left arrow (High energy) — to the left
        lx = 80
        c.setStrokeColor(NAVY); c.setLineWidth(1.2)
        c.line(cx_d - dw/2, cy_d, lx + 110, cy_d)
        c.polygon([lx+110, cy_d+4, lx+110, cy_d-4, lx+120, cy_d], fill=1, stroke=0)
        c.setFillColor(RED); c.setFont("Helvetica-Bold", 7.5)
        c.drawCentredString((cx_d - dw/2 + lx + 110)/2, cy_d + 6, "HIGH ENERGY")

        # Right arrow (Low energy) — to the right
        rx = W - 80
        c.setStrokeColor(NAVY); c.setLineWidth(1.2)
        c.line(cx_d + dw/2, cy_d, rx - 110, cy_d)
        c.polygon([rx-120, cy_d+4, rx-120, cy_d-4, rx-110, cy_d], fill=1, stroke=0)
        c.setFillColor(GREEN); c.setFont("Helvetica-Bold", 7.5)
        c.drawCentredString((cx_d + dw/2 + rx - 110)/2, cy_d + 6, "LOW ENERGY")

        # ── LEFT COLUMN: High Energy
        bw2 = 130
        lbx = 20
        y_he = y3 - 14
        self.box(c, lbx, y_he - bh, bw2, bh, "Surgical Exploration\nwithin 3 WEEKS", RED)
        c.setStrokeColor(NAVY); c.setLineWidth(1.2)
        c.line(lx + 55, cy_d, lx + 55, y_he)
        c.polygon([lx+50, y_he, lx+60, y_he, lx+55, y_he-5], fill=1, stroke=0)
        c.setFillColor(NAVY)

        y_he2 = y_he - bh - 12
        self.box(c, lbx, y_he2 - bh, bw2, bh, "Intraop NAP Recording\n+ Sunderland Grade", ORANGE, text_color=HexColor("#2C3E50"))
        c.setStrokeColor(NAVY); c.setLineWidth(1.2)
        c.line(lbx + bw2/2, y_he - bh, lbx + bw2/2, y_he2)
        c.polygon([lbx + bw2/2 - 4, y_he2, lbx + bw2/2 + 4, y_he2, lbx + bw2/2, y_he2 - 5], fill=1, stroke=0)
        c.setFillColor(NAVY)

        y_he3 = y_he2 - bh - 12
        self.box(c, lbx, y_he3 - bh, bw2, bh, "Repair / Graft / Neurolysis\n(see surgical algorithm)", TEAL)
        c.setStrokeColor(NAVY); c.setLineWidth(1.2)
        c.line(lbx + bw2/2, y_he2 - bh, lbx + bw2/2, y_he3)
        c.polygon([lbx + bw2/2 - 4, y_he3, lbx + bw2/2 + 4, y_he3, lbx + bw2/2, y_he3 - 5], fill=1, stroke=0)
        c.setFillColor(NAVY)

        # ── RIGHT COLUMN: Low Energy
        rbx = W - 20 - bw2
        y_le = y3 - 14
        self.box(c, rbx, y_le - bh, bw2, bh, "Conservative Rx\nAFO + Physio", GREEN)
        c.setStrokeColor(NAVY); c.setLineWidth(1.2)
        c.line(rx - 55, cy_d, rx - 55, y_le)
        c.polygon([rx-60, y_le, rx-50, y_le, rx-55, y_le-5], fill=1, stroke=0)
        c.setFillColor(NAVY)

        y_le2 = y_le - bh - 12
        # Observation period box
        self.box(c, rbx, y_le2 - bh, bw2, bh, "Observe 3–6 months\nSerial NCS/EMG", HexColor("#1A6B3C"))
        c.setStrokeColor(NAVY); c.setLineWidth(1.2)
        c.line(rbx + bw2/2, y_le - bh, rbx + bw2/2, y_le2)
        c.polygon([rbx + bw2/2 - 4, y_le2, rbx + bw2/2 + 4, y_le2, rbx + bw2/2, y_le2 - 5], fill=1, stroke=0)
        c.setFillColor(NAVY)

        # Recovery? diamond
        y_le3 = y_le2 - bh - 12
        dw2, dh2 = 120, 30
        rx_d, ry_d = rbx + bw2/2, y_le3 - dh2/2
        pts2 = [rx_d, ry_d + dh2/2, rx_d + dw2/2, ry_d, rx_d, ry_d - dh2/2, rx_d - dw2/2, ry_d]
        c.setFillColor(ORANGE)
        c.polygon(pts2, fill=1, stroke=1)
        c.setFillColor(HexColor("#2C3E50"))
        c.setFont("Helvetica-Bold", 7.5)
        c.drawCentredString(rx_d, ry_d + 3, "Recovery?")
        c.setFont("Helvetica", 7)
        c.drawCentredString(rx_d, ry_d - 7, "Clinical + EMG")

        c.setStrokeColor(NAVY); c.setLineWidth(1.2)
        c.line(rbx + bw2/2, y_le2 - bh, rbx + bw2/2, y_le3 + dh2/2)

        # YES arrow going down-right
        y_yes = y_le3 - dh2/2 - 12
        self.box(c, rbx, y_yes - 22, bw2, 22, "Continue Conservative\n+ Rehabilitation", GREEN)
        c.setStrokeColor(GREEN); c.setLineWidth(1.2)
        c.line(rx_d, y_le3 - dh2/2, rx_d, y_yes)
        c.polygon([rx_d - 4, y_yes, rx_d + 4, y_yes, rx_d, y_yes - 4], fill=1, stroke=0)
        c.setFillColor(GREEN); c.setFont("Helvetica-Bold", 7); c.drawString(rx_d + 5, y_le3 - dh2/2 - 7, "YES")

        # NO arrow going left toward high energy column
        c.setStrokeColor(RED); c.setLineWidth(1.2)
        c.line(rx_d - dw2/2, ry_d, cx + 10, ry_d)
        c.setFont("Helvetica-Bold", 7); c.setFillColor(RED)
        c.drawString(rx_d - dw2/2 + 3, ry_d + 4, "NO → Surgery")

        # ── BOTTOM: Outcome boxes
        y_bot = 18
        bw3 = 80
        boxes_data = [
            (20,   "Grade 1-2\nFull Recovery", GREEN),
            (115,  "Grade 3\nPartial Recovery", TEAL),
            (210,  "Grade 4\nNeurolysis ±\nGraft", ORANGE),
            (310,  "Grade 5\nDirect Repair\nor Graft", RED),
            (405,  ">12 months\nTendon\nTransfer", MID_BLUE),
        ]
        c.setFillColor(NAVY); c.setFont("Helvetica-Bold", 7.5)
        c.drawCentredString(W/2, y_bot + 44, "── Sunderland Grade & Expected Outcome ──")
        for bx_off, label, col in boxes_data:
            bh3 = 38
            self.box(c, bx_off, y_bot, bw3, bh3, label, col, fontsize=7.5)


# ─── BUILD PDF ─────────────────────────────────────────────────────────────────
def build_pdf(path):
    doc = SimpleDocTemplate(
        path,
        pagesize=A4,
        leftMargin=15*mm,
        rightMargin=15*mm,
        topMargin=10*mm,
        bottomMargin=10*mm,
        title="CPN Injury – Quick Reference (Orthopaedics)",
        author="Orris Clinical AI",
        subject="Common Peroneal Nerve Injury Management"
    )

    story = []
    usable_W = W - 30*mm   # ~535 pt
    col_half = (usable_W - 6) / 2

    # ── HEADER
    story.append(HeaderBanner(usable_W, 72))
    story.append(Spacer(1, 8))

    # ════════════════════════════════════════════════════════════
    # ROW 1: Anatomy Snapshot | Etiology at a Glance
    # ════════════════════════════════════════════════════════════
    story.append(SectionHeader("ANATOMY SNAPSHOT", usable_W, TEAL, "1"))
    story.append(Spacer(1, 4))

    anatomy_data = [
        [Paragraph('<b>Feature</b>', table_header), Paragraph('<b>Detail</b>', table_header)],
        [Paragraph('Root value', table_body), Paragraph('L4, L5, S1, S2', table_body)],
        [Paragraph('Origin', table_body), Paragraph('Lateral division of sciatic nerve (popliteal fossa)', table_body)],
        [Paragraph('Most vulnerable point', table_body), Paragraph('Fibular head / neck — superficial, tethered, no muscle cover', table_body)],
        [Paragraph('Fibular tunnel', table_body), Paragraph('Fibrous arch at origin of peroneus longus', table_body)],
        [Paragraph('Branches', table_body), Paragraph('Deep peroneal, superficial peroneal, recurrent articular, lat. sural cutaneous', table_body)],
        [Paragraph('<b>Deep peroneal</b>', bold_body), Paragraph('Tibialis anterior, EHL, EDL, EDB → dorsiflexion + toe extension + 1st web space sensation', table_body)],
        [Paragraph('<b>Superficial peroneal</b>', bold_body), Paragraph('Peroneus longus & brevis → eversion + dorsal foot sensation', table_body)],
    ]

    anatomy_table = Table(anatomy_data, colWidths=[col_half*0.38, col_half*1.62])
    anatomy_table.setStyle(TableStyle([
        ('BACKGROUND', (0,0), (-1,0), TEAL),
        ('TEXTCOLOR', (0,0), (-1,0), WHITE),
        ('FONTNAME', (0,0), (-1,0), 'Helvetica-Bold'),
        ('FONTSIZE', (0,0), (-1,-1), 8.5),
        ('ROWBACKGROUNDS', (0,1), (-1,-1), [WHITE, LIGHT_BG]),
        ('GRID', (0,0), (-1,-1), 0.4, HexColor("#BDC3C7")),
        ('ROWBACKGROUNDS', (0,5), (-1,6), [BOX_BLUE, BOX_GREEN]),
        ('BOTTOMPADDING', (0,0), (-1,-1), 4),
        ('TOPPADDING', (0,0), (-1,-1), 4),
        ('LEFTPADDING', (0,0), (-1,-1), 6),
        ('VALIGN', (0,0), (-1,-1), 'MIDDLE'),
        ('ROUNDEDCORNERS', [4,4,4,4]),
    ]))
    story.append(anatomy_table)
    story.append(Spacer(1, 8))

    # ════════════════════════════════════════════════════════════
    # ROW 2: Etiology + Classification side by side
    # ════════════════════════════════════════════════════════════
    # LEFT: Etiology
    etiol_data = [
        [Paragraph('<b>Category</b>', table_header), Paragraph('<b>Common Causes</b>', table_header)],
        [Paragraph('Traumatic', table_body), Paragraph('Knee dislocation (44% CPN injury), fibular head # (50% CPN), direct blow, TKA', table_body)],
        [Paragraph('Compressive', table_body), Paragraph('Leg crossing, tight cast, prolonged squatting, lithotomy position, bed rest', table_body)],
        [Paragraph('SOL', table_body), Paragraph('Intraneural ganglion (tibiofibular joint), Baker cyst, ganglion, lipoma', table_body)],
        [Paragraph('Systemic', table_body), Paragraph('Diabetes, vasculitis, emaciation, leprosy', table_body)],
        [Paragraph('Iatrogenic', table_body), Paragraph('Lateral decubitus positioning, HTO, poor cast application', table_body)],
    ]
    etiol_table = Table(etiol_data, colWidths=[col_half*0.33, col_half*0.67])
    etiol_table.setStyle(TableStyle([
        ('BACKGROUND', (0,0), (-1,0), ORANGE),
        ('TEXTCOLOR', (0,0), (-1,0), WHITE),
        ('FONTNAME', (0,0), (-1,0), 'Helvetica-Bold'),
        ('FONTSIZE', (0,0), (-1,-1), 8),
        ('ROWBACKGROUNDS', (0,1), (-1,-1), [WHITE, LIGHT_BG]),
        ('GRID', (0,0), (-1,-1), 0.4, HexColor("#BDC3C7")),
        ('BOTTOMPADDING', (0,0), (-1,-1), 4),
        ('TOPPADDING', (0,0), (-1,-1), 4),
        ('LEFTPADDING', (0,0), (-1,-1), 5),
        ('VALIGN', (0,0), (-1,-1), 'MIDDLE'),
    ]))

    # RIGHT: Classification
    class_data = [
        [Paragraph('<b>Grade</b>', table_header), Paragraph('<b>Seddon</b>', table_header),
         Paragraph('<b>Pathology</b>', table_header), Paragraph('<b>Prognosis</b>', table_header)],
        [Paragraph('1', table_body), Paragraph('Neurapraxia', table_body),
         Paragraph('Myelin only', table_body), Paragraph('Full; weeks', table_body)],
        [Paragraph('2', table_body), Paragraph('Axonotmesis', table_body),
         Paragraph('Axon intact endo', table_body), Paragraph('Excellent 2-3mm/d', table_body)],
        [Paragraph('3', table_body), Paragraph('Axonotmesis', table_body),
         Paragraph('Axon + endo', table_body), Paragraph('Incomplete 1mm/d', table_body)],
        [Paragraph('4', table_body), Paragraph('Neurotmesis', table_body),
         Paragraph('+ perineurium', table_body), Paragraph('Neuroma-in-cont.', table_body)],
        [Paragraph('5', table_body), Paragraph('Neurotmesis', table_body),
         Paragraph('Complete', table_body), Paragraph('Surgery essential', table_body)],
        [Paragraph('6', table_body), Paragraph('Mixed', table_body),
         Paragraph('Variable fascicles', table_body), Paragraph('Variable', table_body)],
    ]
    class_table = Table(class_data, colWidths=[col_half*0.14, col_half*0.28, col_half*0.30, col_half*0.28])
    class_table.setStyle(TableStyle([
        ('BACKGROUND', (0,0), (-1,0), MID_BLUE),
        ('TEXTCOLOR', (0,0), (-1,0), WHITE),
        ('FONTNAME', (0,0), (-1,0), 'Helvetica-Bold'),
        ('FONTSIZE', (0,0), (-1,-1), 7.5),
        ('ROWBACKGROUNDS', (0,1), (-1,-1), [WHITE, LIGHT_BG]),
        ('GRID', (0,0), (-1,-1), 0.4, HexColor("#BDC3C7")),
        ('BOTTOMPADDING', (0,0), (-1,-1), 3),
        ('TOPPADDING', (0,0), (-1,-1), 3),
        ('LEFTPADDING', (0,0), (-1,-1), 4),
        ('VALIGN', (0,0), (-1,-1), 'MIDDLE'),
        ('BACKGROUND', (0,4), (-1,5), [BOX_RED, BOX_RED]),
    ]))

    # Combine in two-column row
    etiol_hdr = SectionHeader("ETIOLOGY", col_half, ORANGE, "2")
    class_hdr = SectionHeader("SUNDERLAND CLASSIFICATION", col_half, MID_BLUE, "3")

    two_col = Table([[etiol_hdr, Spacer(6, 1), class_hdr]], colWidths=[col_half, 6, col_half])
    two_col.setStyle(TableStyle([('VALIGN', (0,0), (-1,-1), 'TOP'), ('LEFTPADDING', (0,0),(-1,-1), 0), ('RIGHTPADDING', (0,0),(-1,-1), 0)]))
    story.append(two_col)
    story.append(Spacer(1, 3))

    two_col2 = Table([[etiol_table, Spacer(6, 1), class_table]], colWidths=[col_half, 6, col_half])
    two_col2.setStyle(TableStyle([('VALIGN', (0,0), (-1,-1), 'TOP'), ('LEFTPADDING', (0,0),(-1,-1), 0), ('RIGHTPADDING', (0,0),(-1,-1), 0)]))
    story.append(two_col2)
    story.append(Spacer(1, 8))

    # ════════════════════════════════════════════════════════════
    # ROW 3: Clinical Features + Differential Diagnosis
    # ════════════════════════════════════════════════════════════
    story.append(SectionHeader("CLINICAL FEATURES & DIFFERENTIAL DIAGNOSIS", usable_W, MID_BLUE, "4"))
    story.append(Spacer(1, 4))

    # Clinical features
    cf_data = [
        [Paragraph('<b>Motor Deficit</b>', bold_body), Paragraph('<b>Sensory Loss</b>', bold_body), Paragraph('<b>Key Gait</b>', bold_body)],
        [Paragraph('• Foot drop (dorsiflexion weakness)\n• Weak eversion (peronei)\n• Toe extension weakness\n• Preserved inversion ✓\n• Preserved plantarflexion ✓', table_body),
         Paragraph('• Dorsum of foot (sup. peroneal)\n• Lateral leg (lat. sural cut.)\n• 1st web space (deep peroneal)\n• Sole SPARED ✓', table_body),
         Paragraph('• Steppage gait\n  (high knee lift to\n  clear toe from ground)\n• Toe slapping on\n  ground contact', table_body)],
    ]
    cf_table = Table(cf_data, colWidths=[col_half*0.75, col_half*0.65, col_half*0.60])
    cf_table.setStyle(TableStyle([
        ('BACKGROUND', (0,0), (-1,0), MID_BLUE),
        ('TEXTCOLOR', (0,0), (-1,0), WHITE),
        ('FONTNAME', (0,0), (-1,0), 'Helvetica-Bold'),
        ('FONTSIZE', (0,0), (-1,-1), 8.5),
        ('GRID', (0,0), (-1,-1), 0.4, HexColor("#BDC3C7")),
        ('BACKGROUND', (0,1), (-1,1), BOX_BLUE),
        ('BOTTOMPADDING', (0,0), (-1,-1), 5),
        ('TOPPADDING', (0,0), (-1,-1), 5),
        ('LEFTPADDING', (0,0), (-1,-1), 6),
        ('VALIGN', (0,0), (-1,-1), 'TOP'),
    ]))
    story.append(cf_table)
    story.append(Spacer(1, 5))

    # Differential
    diff_data = [
        [Paragraph('<b>Condition</b>', table_header),
         Paragraph('<b>Inversion</b>', table_header),
         Paragraph('<b>Eversion</b>', table_header),
         Paragraph('<b>Back Pain</b>', table_header),
         Paragraph('<b>EMG Paraspinals</b>', table_header),
         Paragraph('<b>Tinel Fibular Head</b>', table_header)],
        [Paragraph('CPN Palsy', table_body), Paragraph('Normal ✓', table_body),
         Paragraph('Weak ✗', table_body), Paragraph('Absent', table_body),
         Paragraph('Normal', table_body), Paragraph('Present', table_body)],
        [Paragraph('L5 Radiculopathy', table_body), Paragraph('Weak ✗', table_body),
         Paragraph('Weak ✗', table_body), Paragraph('Often present', table_body),
         Paragraph('Abnormal', table_body), Paragraph('Absent', table_body)],
        [Paragraph('LS Plexopathy', table_body), Paragraph('Weak ✗', table_body),
         Paragraph('Weak ✗', table_body), Paragraph('Variable', table_body),
         Paragraph('Normal', table_body), Paragraph('Absent', table_body)],
        [Paragraph('Tib. Ant. Tendon Rupture', table_body), Paragraph('Normal ✓', table_body),
         Paragraph('Normal ✓', table_body), Paragraph('Absent', table_body),
         Paragraph('Normal', table_body), Paragraph('Absent — palpable gap', table_body)],
    ]
    diff_table = Table(diff_data, colWidths=[col_half*0.47, col_half*0.26, col_half*0.26,
                                              col_half*0.33, col_half*0.38, col_half*0.30])
    diff_table.setStyle(TableStyle([
        ('BACKGROUND', (0,0), (-1,0), NAVY),
        ('TEXTCOLOR', (0,0), (-1,0), WHITE),
        ('FONTNAME', (0,0), (-1,0), 'Helvetica-Bold'),
        ('FONTSIZE', (0,0), (-1,-1), 8),
        ('ROWBACKGROUNDS', (0,1), (-1,-1), [WHITE, LIGHT_BG]),
        ('GRID', (0,0), (-1,-1), 0.4, HexColor("#BDC3C7")),
        ('BOTTOMPADDING', (0,0), (-1,-1), 4),
        ('TOPPADDING', (0,0), (-1,-1), 4),
        ('LEFTPADDING', (0,0), (-1,-1), 5),
        ('VALIGN', (0,0), (-1,-1), 'MIDDLE'),
        ('BACKGROUND', (0,1), (-1,1), BOX_GREEN),
    ]))
    story.append(diff_table)
    story.append(Spacer(1, 8))

    # ════════════════════════════════════════════════════════════
    # ROW 4: Investigations
    # ════════════════════════════════════════════════════════════
    story.append(SectionHeader("INVESTIGATIONS", usable_W, HexColor("#6C3483"), "5"))
    story.append(Spacer(1, 4))

    inv_data = [
        [Paragraph('<b>Investigation</b>', table_header), Paragraph('<b>Key Findings / Notes</b>', table_header),
         Paragraph('<b>Timing</b>', table_header)],
        [Paragraph('NCS – Motor', table_body),
         Paragraph('Conduction block across fibular head (>50% CMAP drop) = neurapraxia; Axonal loss = axonotmesis/worse', table_body),
         Paragraph('Any time; repeat at 3 months', table_body)],
        [Paragraph('NCS – Sensory', table_body),
         Paragraph('Superficial peroneal SNAP absent or reduced', table_body),
         Paragraph('From day 1', table_body)],
        [Paragraph('EMG (Needle)', table_body),
         Paragraph('Fibrillations in TA, EHL, EDL, peronei. Normal paraspinals → rules out L5 root', table_body),
         Paragraph('≥3 weeks post-injury', table_body)],
        [Paragraph('X-Ray Knee/Fibula', table_body),
         Paragraph('Fibular head # (50% CPN), knee dislocation, tibial plateau #. Alignment assessment', table_body),
         Paragraph('Acute', table_body)],
        [Paragraph('MRI Knee / Neurography', table_body),
         Paragraph('T2 bright nerve = neurapraxia/axonotmesis. Nerve gap = neurotmesis. Intraneural ganglion → cystic lesion tracking from STFJ', table_body),
         Paragraph('Subacute / pre-op', table_body)],
        [Paragraph('USS (High-Freq 15-18MHz)', table_body),
         Paragraph('Dynamic assessment, ganglion identification, ultrasound-guided aspiration', table_body),
         Paragraph('Any time', table_body)],
        [Paragraph('Blood (HbA1c, ESR, ANCA)', table_body),
         Paragraph('Rule out systemic cause (diabetes, vasculitis)', table_body),
         Paragraph('Initial workup', table_body)],
    ]
    inv_table = Table(inv_data, colWidths=[col_half*0.48, col_half*1.22, col_half*0.30])
    inv_table.setStyle(TableStyle([
        ('BACKGROUND', (0,0), (-1,0), HexColor("#6C3483")),
        ('TEXTCOLOR', (0,0), (-1,0), WHITE),
        ('FONTNAME', (0,0), (-1,0), 'Helvetica-Bold'),
        ('FONTSIZE', (0,0), (-1,-1), 8.5),
        ('ROWBACKGROUNDS', (0,1), (-1,-1), [WHITE, LIGHT_BG]),
        ('GRID', (0,0), (-1,-1), 0.4, HexColor("#BDC3C7")),
        ('BOTTOMPADDING', (0,0), (-1,-1), 4),
        ('TOPPADDING', (0,0), (-1,-1), 4),
        ('LEFTPADDING', (0,0), (-1,-1), 6),
        ('VALIGN', (0,0), (-1,-1), 'MIDDLE'),
    ]))
    story.append(inv_table)
    story.append(Spacer(1, 8))

    # ════════════════════════════════════════════════════════════
    # PAGE BREAK
    # ════════════════════════════════════════════════════════════
    story.append(PageBreak())
    story.append(HeaderBanner(usable_W, 40))
    story.append(Spacer(1, 8))

    # ════════════════════════════════════════════════════════════
    # MANAGEMENT FLOWCHART
    # ════════════════════════════════════════════════════════════
    story.append(SectionHeader("MANAGEMENT ALGORITHM", usable_W, NAVY, "6"))
    story.append(Spacer(1, 4))
    story.append(ManagementFlowchart(usable_W))
    story.append(Spacer(1, 8))

    # ════════════════════════════════════════════════════════════
    # NON-OPERATIVE + OPERATIVE side by side
    # ════════════════════════════════════════════════════════════
    nonop_hdr = SectionHeader("A. NON-OPERATIVE MANAGEMENT", col_half, GREEN, "7")
    op_hdr = SectionHeader("B. OPERATIVE MANAGEMENT", col_half, RED, "8")

    hdr_row = Table([[nonop_hdr, Spacer(6,1), op_hdr]], colWidths=[col_half, 6, col_half])
    hdr_row.setStyle(TableStyle([('VALIGN',(0,0),(-1,-1),'TOP'),('LEFTPADDING',(0,0),(-1,-1),0),('RIGHTPADDING',(0,0),(-1,-1),0)]))
    story.append(hdr_row)
    story.append(Spacer(1, 3))

    nonop_items = [
        [Paragraph('<b>Measure</b>', table_header), Paragraph('<b>Details</b>', table_header)],
        [Paragraph('Indication', table_body), Paragraph('Grade 1-2 / low-energy / metabolic cause', table_body)],
        [Paragraph('AFO (Ankle-Foot Orthosis)', table_body), Paragraph('Rigid/articulated — maintains neutral dorsiflexion during swing. Carbon fibre preferred', table_body)],
        [Paragraph('Physiotherapy', table_body), Paragraph('ROM, Achilles stretching (prevent equinus), gait retraining, strengthening intact muscles', table_body)],
        [Paragraph('Risk factor removal', table_body), Paragraph('Stop leg crossing, treat DM, weight loss, knee pad', table_body)],
        [Paragraph('FES (Peroneal Stimulator)', table_body), Paragraph('WalkAide / Bioness L300 — triggers dorsiflexion; adjunct to AFO', table_body)],
        [Paragraph('Observation window', table_body), Paragraph('Grade 1: 4-12 weeks. Grade 2-3: 3-6 months. Serial NCS/EMG', table_body)],
        [Paragraph('Failure threshold', table_body), Paragraph('No clinical/EMG recovery at 3 months (axonal loss) → refer for surgery', table_body)],
    ]
    nonop_table = Table(nonop_items, colWidths=[col_half*0.44, col_half*0.56])
    nonop_table.setStyle(TableStyle([
        ('BACKGROUND', (0,0), (-1,0), GREEN),
        ('TEXTCOLOR', (0,0), (-1,0), WHITE),
        ('FONTNAME', (0,0), (-1,0), 'Helvetica-Bold'),
        ('FONTSIZE', (0,0), (-1,-1), 8),
        ('ROWBACKGROUNDS', (0,1), (-1,-1), [WHITE, BOX_GREEN]),
        ('GRID', (0,0), (-1,-1), 0.4, HexColor("#BDC3C7")),
        ('BOTTOMPADDING', (0,0), (-1,-1), 4),
        ('TOPPADDING', (0,0), (-1,-1), 4),
        ('LEFTPADDING', (0,0), (-1,-1), 5),
        ('VALIGN', (0,0), (-1,-1), 'TOP'),
        ('BACKGROUND', (0,7), (-1,7), BOX_ORANGE),
    ]))

    op_items = [
        [Paragraph('<b>Procedure</b>', table_header), Paragraph('<b>Indication / Outcome</b>', table_header)],
        [Paragraph('Timing (High energy)', table_body), Paragraph('Explore within 3 WEEKS of laceration/fracture', table_body)],
        [Paragraph('Timing (Low energy)', table_body), Paragraph('Surgery if no recovery at 3-6 months', table_body)],
        [Paragraph('Neurolysis', table_body), Paragraph('Sunderland 3-4, entrapment, intraneural ganglion. Decompress + articular branch excision + STFJ repair', table_body)],
        [Paragraph('Primary Repair\n(Neurorrhaphy)', table_body), Paragraph('Sharp laceration, small gap, tension-free. 60-70% useful dorsiflexion (ideal)', table_body)],
        [Paragraph('Nerve Graft\n(Sural / Allograft)', table_body), Paragraph('Gap >2-3 cm. Mean graft 7 cm. 49% >M3 recovery. Worse if >12 cm graft', table_body)],
        [Paragraph('Nerve Transfer\n(Tibial → CPN)', table_body), Paragraph('Proximal injury / long gap. 62.9% >M3. End-to-end to distal CPN', table_body)],
        [Paragraph('Tendon Transfer\n(Tibialis Post.)', table_body), Paragraph('SALVAGE >12-18 months / irreversible. Bridle procedure — most reliable long-term', table_body)],
    ]
    op_table = Table(op_items, colWidths=[col_half*0.40, col_half*0.60])
    op_table.setStyle(TableStyle([
        ('BACKGROUND', (0,0), (-1,0), RED),
        ('TEXTCOLOR', (0,0), (-1,0), WHITE),
        ('FONTNAME', (0,0), (-1,0), 'Helvetica-Bold'),
        ('FONTSIZE', (0,0), (-1,-1), 8),
        ('ROWBACKGROUNDS', (0,1), (-1,-1), [WHITE, BOX_RED]),
        ('GRID', (0,0), (-1,-1), 0.4, HexColor("#BDC3C7")),
        ('BOTTOMPADDING', (0,0), (-1,-1), 4),
        ('TOPPADDING', (0,0), (-1,-1), 4),
        ('LEFTPADDING', (0,0), (-1,-1), 5),
        ('VALIGN', (0,0), (-1,-1), 'TOP'),
        ('BACKGROUND', (0,7), (-1,7), BOX_ORANGE),
    ]))

    content_row = Table([[nonop_table, Spacer(6,1), op_table]], colWidths=[col_half, 6, col_half])
    content_row.setStyle(TableStyle([('VALIGN',(0,0),(-1,-1),'TOP'),('LEFTPADDING',(0,0),(-1,-1),0),('RIGHTPADDING',(0,0),(-1,-1),0)]))
    story.append(content_row)
    story.append(Spacer(1, 8))

    # ════════════════════════════════════════════════════════════
    # CRITICAL TIMELINES + OUTCOMES
    # ════════════════════════════════════════════════════════════
    story.append(SectionHeader("CRITICAL TIMELINES & SURGICAL OUTCOMES", usable_W, ORANGE, "9"))
    story.append(Spacer(1, 4))

    timeline_data = [
        [Paragraph('<b>Timeline</b>', table_header),
         Paragraph('<b>Decision Point</b>', table_header),
         Paragraph('<b>Action</b>', table_header)],
        [Paragraph('Day 0-21', table_body),
         Paragraph('High-energy injury (laceration, fracture-dislocation)', table_body),
         Paragraph('Surgical exploration ± primary repair', table_body)],
        [Paragraph('3 weeks post-injury', table_body),
         Paragraph('EMG now reliable (fibrillations detectable)', table_body),
         Paragraph('Baseline EMG / NCS', table_body)],
        [Paragraph('3 months', table_body),
         Paragraph('Neurapraxia should show clinical/EMG recovery', table_body),
         Paragraph('If no recovery → upgrade suspicion → MRI ± surgical referral', table_body)],
        [Paragraph('3-6 months', table_body),
         Paragraph('Low-energy: failure of conservative Rx', table_body),
         Paragraph('Neurolysis / nerve repair', table_body)],
        [Paragraph('<12 months', table_body),
         Paragraph('CRITICAL WINDOW for nerve repair', table_body),
         Paragraph('Nerve repair/graft suboptimal if >12 months post-injury', table_body)],
        [Paragraph('>12-18 months', table_body),
         Paragraph('Irreversible muscle denervation / failed nerve repair', table_body),
         Paragraph('Tibialis posterior tendon transfer (Bridle procedure)', table_body)],
    ]
    tl_table = Table(timeline_data, colWidths=[col_half*0.36, col_half*0.84, col_half*0.80])
    tl_table.setStyle(TableStyle([
        ('BACKGROUND', (0,0), (-1,0), ORANGE),
        ('TEXTCOLOR', (0,0), (-1,0), WHITE),
        ('FONTNAME', (0,0), (-1,0), 'Helvetica-Bold'),
        ('FONTSIZE', (0,0), (-1,-1), 8.5),
        ('ROWBACKGROUNDS', (0,1), (-1,-1), [WHITE, LIGHT_BG]),
        ('GRID', (0,0), (-1,-1), 0.4, HexColor("#BDC3C7")),
        ('BACKGROUND', (0,5), (-1,5), BOX_RED),
        ('BACKGROUND', (0,6), (-1,6), BOX_ORANGE),
        ('FONTNAME', (0,5), (-1,5), 'Helvetica-Bold'),
        ('BOTTOMPADDING', (0,0), (-1,-1), 4),
        ('TOPPADDING', (0,0), (-1,-1), 4),
        ('LEFTPADDING', (0,0), (-1,-1), 6),
        ('VALIGN', (0,0), (-1,-1), 'MIDDLE'),
    ]))
    story.append(tl_table)
    story.append(Spacer(1, 8))

    # ════════════════════════════════════════════════════════════
    # OUTCOMES SUMMARY + RECENT ADVANCES
    # ════════════════════════════════════════════════════════════
    out_hdr = SectionHeader("OUTCOMES (Evidence-Based)", col_half, TEAL, "10")
    adv_hdr = SectionHeader("RECENT ADVANCES", col_half, HexColor("#6C3483"), "11")

    out_items = [
        [Paragraph('<b>Procedure</b>', table_header), Paragraph('<b>Outcome</b>', table_header)],
        [Paragraph('Neurolysis (early, <6m)', table_body), Paragraph('60-70% recovery', table_body)],
        [Paragraph('Primary repair (ideal)', table_body), Paragraph('60-70% anti-gravity dorsiflexion', table_body)],
        [Paragraph('Nerve grafting (meta-analysis, n=465)', table_body), Paragraph('49% achieve >M3', table_body)],
        [Paragraph('Nerve transfer (tibial→CPN)', table_body), Paragraph('62.9% achieve >M3', table_body)],
        [Paragraph('Repair >12 months post-injury', table_body), Paragraph('Suboptimal — do NOT repair', table_body)],
        [Paragraph('Graft >12 cm', table_body), Paragraph('Poor outcome expected', table_body)],
        [Paragraph('Tendon transfer (late)', table_body), Paragraph('Most reliable, durable long-term', table_body)],
    ]
    out_table = Table(out_items, colWidths=[col_half*0.58, col_half*0.42])
    out_table.setStyle(TableStyle([
        ('BACKGROUND', (0,0), (-1,0), TEAL),
        ('TEXTCOLOR', (0,0), (-1,0), WHITE),
        ('FONTNAME', (0,0), (-1,0), 'Helvetica-Bold'),
        ('FONTSIZE', (0,0), (-1,-1), 8),
        ('ROWBACKGROUNDS', (0,1), (-1,-1), [WHITE, BOX_BLUE]),
        ('GRID', (0,0), (-1,-1), 0.4, HexColor("#BDC3C7")),
        ('BACKGROUND', (0,5), (-1,6), BOX_RED),
        ('BOTTOMPADDING', (0,0), (-1,-1), 4),
        ('TOPPADDING', (0,0), (-1,-1), 4),
        ('LEFTPADDING', (0,0), (-1,-1), 5),
        ('VALIGN', (0,0), (-1,-1), 'MIDDLE'),
    ]))

    adv_items = [
        [Paragraph('<b>Advance</b>', table_header), Paragraph('<b>Clinical Relevance</b>', table_header)],
        [Paragraph('MR Neurography (3T DTI)', table_body), Paragraph('Fascicular detail, continuity; guides surgical planning', table_body)],
        [Paragraph('Nerve Transfers', table_body), Paragraph('Tibial branch → deep CPN; avoids long graft distances', table_body)],
        [Paragraph('Implantable FES (ActiGait)', table_body), Paragraph('Closed-loop, gait-triggered stimulation; better than fixed AFO', table_body)],
        [Paragraph('Nerve Allografts (Avance)', table_body), Paragraph('5-70 mm gaps; avoids sural harvest morbidity', table_body)],
        [Paragraph('Intraneural Ganglion Rx', table_body), Paragraph('Articular branch excision + STFJ capsule repair = low recurrence', table_body)],
        [Paragraph('Intraop NAP Recording', table_body), Paragraph('Guides resection vs neurolysis in neuroma-in-continuity', table_body)],
        [Paragraph('PRP / Growth Factors', table_body), Paragraph('Emerging — promotes remyelination; experimental', table_body)],
    ]
    adv_table = Table(adv_items, colWidths=[col_half*0.44, col_half*0.56])
    adv_table.setStyle(TableStyle([
        ('BACKGROUND', (0,0), (-1,0), HexColor("#6C3483")),
        ('TEXTCOLOR', (0,0), (-1,0), WHITE),
        ('FONTNAME', (0,0), (-1,0), 'Helvetica-Bold'),
        ('FONTSIZE', (0,0), (-1,-1), 8),
        ('ROWBACKGROUNDS', (0,1), (-1,-1), [WHITE, HexColor("#F3E5F5")]),
        ('GRID', (0,0), (-1,-1), 0.4, HexColor("#BDC3C7")),
        ('BOTTOMPADDING', (0,0), (-1,-1), 4),
        ('TOPPADDING', (0,0), (-1,-1), 4),
        ('LEFTPADDING', (0,0), (-1,-1), 5),
        ('VALIGN', (0,0), (-1,-1), 'MIDDLE'),
    ]))

    hdr_row2 = Table([[out_hdr, Spacer(6,1), adv_hdr]], colWidths=[col_half, 6, col_half])
    hdr_row2.setStyle(TableStyle([('VALIGN',(0,0),(-1,-1),'TOP'),('LEFTPADDING',(0,0),(-1,-1),0),('RIGHTPADDING',(0,0),(-1,-1),0)]))
    story.append(hdr_row2)
    story.append(Spacer(1, 3))

    content_row2 = Table([[out_table, Spacer(6,1), adv_table]], colWidths=[col_half, 6, col_half])
    content_row2.setStyle(TableStyle([('VALIGN',(0,0),(-1,-1),'TOP'),('LEFTPADDING',(0,0),(-1,-1),0),('RIGHTPADDING',(0,0),(-1,-1),0)]))
    story.append(content_row2)
    story.append(Spacer(1, 8))

    # ════════════════════════════════════════════════════════════
    # QUICK REFERENCE PEARL BOX
    # ════════════════════════════════════════════════════════════
    pearls_data = [
        [
            Paragraph('<b>🔑 CLINICAL PEARLS</b>', ParagraphStyle('ph', fontName='Helvetica-Bold', fontSize=9, textColor=NAVY)),
        ],
        [
            Paragraph(
                '• <b>Preserved inversion</b> = CPN palsy (not L5 root); eversion tests the superficial peroneal nerve specifically<br/>'
                '• <b>Wait ≥3 weeks</b> before EMG — fibrillations appear 3 weeks after axonal injury; early normal EMG does not rule out axonal loss<br/>'
                '• <b>EMG paraspinals:</b> Normal → CPN palsy | Abnormal → L5 radiculopathy<br/>'
                '• <b>Intraneural ganglion</b> suspect when: palpable mass at fibular head + fluctuating weakness with weight-bearing + BMI-associated + no weight loss history<br/>'
                '• <b>TKA foot drop:</b> Decompress if not recovering; lithotomy/lateral decubitus positioning is the main iatrogenic cause<br/>'
                '• <b>Critical window:</b> Nerve repair >12 months post-injury OR graft >12 cm = predictably poor outcome — proceed to tendon transfer<br/>'
                '• <b>Tibialis anterior tendon rupture</b> mimics CPN palsy — look for palpable gap, check EMG (normal in tendon rupture)',
                ParagraphStyle('pearl_body', fontName='Helvetica', fontSize=8.5, textColor=HexColor("#2C3E50"), leading=13, leftIndent=5)
            )
        ]
    ]
    pearls_table = Table(pearls_data, colWidths=[usable_W])
    pearls_table.setStyle(TableStyle([
        ('BACKGROUND', (0,0), (-1,0), YELLOW_BG),
        ('BACKGROUND', (0,1), (-1,1), YELLOW_BG),
        ('BOX', (0,0), (-1,-1), 1.5, ORANGE),
        ('LINEBELOW', (0,0), (-1,0), 0.8, ORANGE),
        ('BOTTOMPADDING', (0,0), (-1,-1), 8),
        ('TOPPADDING', (0,0), (-1,-1), 6),
        ('LEFTPADDING', (0,0), (-1,-1), 10),
        ('VALIGN', (0,0), (-1,-1), 'TOP'),
    ]))
    story.append(pearls_table)
    story.append(Spacer(1, 6))

    # ─── FOOTER
    footer_data = [[
        Paragraph('<font size="7" color="#7F8C8D">Sources: Campbell\'s Operative Orthopaedics 15e (2026) • Adams &amp; Victor\'s Principles of Neurology 12e • Harrison\'s Internal Medicine 22e • Localization in Clinical Neurology 8e • Sabiston Textbook of Surgery 8e • Imaging Anatomy Vol.3 | Generated by Orris Clinical AI — June 2026 | For educational use only</font>', body_style)
    ]]
    footer_table = Table(footer_data, colWidths=[usable_W])
    footer_table.setStyle(TableStyle([
        ('LINEABOVE', (0,0), (-1,0), 0.5, GREY),
        ('TOPPADDING', (0,0), (-1,-1), 4),
        ('LEFTPADDING', (0,0), (-1,-1), 0),
    ]))
    story.append(footer_table)

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

if __name__ == "__main__":
    out_path = "/home/daytona/workspace/cpn-nerve/CPN_Injury_Quick_Reference.pdf"
    build_pdf(out_path)
Running Command

cd /home/daytona/workspace/cpn-nerve && python3 generate_cpn_pdf.py 2>&1

Editing File

~/cpn-nerve/generate_cpn_pdf.py

Successfully replaced 1 instance(s) of the string in '/home/daytona/workspace/cpn-nerve/generate_cpn_pdf.py'
Running Command

cd /home/daytona/workspace/cpn-nerve && python3 generate_cpn_pdf.py 2>&1

Editing File

~/cpn-nerve/generate_cpn_pdf.py

Successfully replaced 1 instance(s) of the string in '/home/daytona/workspace/cpn-nerve/generate_cpn_pdf.py'
Running Command

grep -n "ROWBACKGROUNDS" /home/daytona/workspace/cpn-nerve/generate_cpn_pdf.py

Running Command

python3 -c " import re with open('/home/daytona/workspace/cpn-nerve/generate_cpn_pdf.py', 'r') as f: content = f.read() # Replace all ROWBACKGROUNDS with just removing them (use single color BACKGROUND for all data rows instead) # Strategy: replace ('ROWBACKGROUNDS', ...) lines with a simple background that won't cause errors # We'll replace each with a comment and add background lines manually # Simple approach: replace all ROWBACKGROUNDS lines with nothing (remove them) content = re.sub(r\"\s*\\('ROWBACKGROUNDS',[^)]+\\),\", '', content) with open('/home/daytona/workspace/cpn-nerve/generate_cpn_pdf.py', 'w') as f: f.write(content) print('Done') "

Running Command

cd /home/daytona/workspace/cpn-nerve && python3 generate_cpn_pdf.py 2>&1

Writing File

~/cpn-nerve/generate_cpn_pdf.py

"""
CPN Injury Management - Quick Reference Clinical Decision Support PDF
Orthopaedic Perspective - ReportLab (clean, no ROWBACKGROUNDS)
"""

from reportlab.lib.pagesizes import A4
from reportlab.lib import colors
from reportlab.lib.units import mm
from reportlab.lib.styles import ParagraphStyle
from reportlab.lib.enums import TA_CENTER, TA_LEFT
from reportlab.platypus import (
    SimpleDocTemplate, Paragraph, Spacer, Table, TableStyle,
    PageBreak
)
from reportlab.platypus.flowables import Flowable
from reportlab.lib.colors import HexColor

# ── Colours
NAVY       = HexColor("#0D2B55")
TEAL       = HexColor("#0A7E8C")
ORANGE     = HexColor("#E87722")
MID_BLUE   = HexColor("#1A5276")
GREEN      = HexColor("#1E8449")
DARK_GREEN = HexColor("#1A6B3C")
RED        = HexColor("#C0392B")
PURPLE     = HexColor("#6C3483")
WHITE      = colors.white
GREY       = HexColor("#7F8C8D")
LIGHT_GREY = HexColor("#ECF0F1")
LIGHT_BG   = HexColor("#F0F4F8")
BOX_BLUE   = HexColor("#D6EAF8")
BOX_GREEN  = HexColor("#D5F5E3")
BOX_RED    = HexColor("#FADBD8")
BOX_ORANGE = HexColor("#FDEBD0")
BOX_PURPLE = HexColor("#F3E5F5")
YELLOW_BG  = HexColor("#FEF9E7")

W, H = A4   # 595 x 842 pt


# ── Styles
def S(name, **kw):
    return ParagraphStyle(name, **kw)

TH  = S('TH',  fontName='Helvetica-Bold', fontSize=8.5, textColor=WHITE,   alignment=TA_CENTER, leading=11)
TB  = S('TB',  fontName='Helvetica',      fontSize=8,   textColor=HexColor("#2C3E50"), alignment=TA_LEFT, leading=11)
TBB = S('TBB', fontName='Helvetica-Bold', fontSize=8,   textColor=HexColor("#2C3E50"), alignment=TA_LEFT, leading=11)
THs = S('THs', fontName='Helvetica-Bold', fontSize=7.5, textColor=WHITE,   alignment=TA_CENTER, leading=10)
TBs = S('TBs', fontName='Helvetica',      fontSize=7.5, textColor=HexColor("#2C3E50"), alignment=TA_LEFT, leading=10)
BODY = S('BODY', fontName='Helvetica', fontSize=8.5, textColor=HexColor("#2C3E50"), alignment=TA_LEFT, leading=13)


def alt_bg(table_style_list, n_rows, start=1, c1=WHITE, c2=LIGHT_BG):
    """Append alternating background rows to a style list."""
    for i in range(start, n_rows):
        col = c1 if (i % 2 == 1) else c2
        table_style_list.append(('BACKGROUND', (0, i), (-1, i), col))


# ── Header Banner
class HeaderBanner(Flowable):
    def __init__(self, w, h=70):
        super().__init__()
        self.width, self.height = w, h

    def draw(self):
        c = self.canv
        c.setFillColor(NAVY); c.roundRect(0, 0, self.width, self.height, 8, fill=1, stroke=0)
        c.setFillColor(TEAL);   c.roundRect(0, 0, 6, self.height, 3, fill=1, stroke=0)
        c.setFillColor(ORANGE); c.roundRect(self.width - 6, 0, 6, self.height, 3, fill=1, stroke=0)
        c.setFillColor(WHITE); c.setFont("Helvetica-Bold", 19)
        c.drawCentredString(self.width / 2, self.height - 30, "COMMON PERONEAL NERVE INJURY")
        c.setFillColor(HexColor("#BDC3C7")); c.setFont("Helvetica", 10)
        c.drawCentredString(self.width / 2, self.height - 46,
            "Quick Reference Clinical Decision Support  |  Orthopaedic Perspective")
        c.setFillColor(ORANGE); c.setFont("Helvetica-Bold", 7.5)
        c.drawCentredString(self.width / 2, 8,
            "Campbell's Operative Orthopaedics 15e (2026)  •  Adams & Victor 12e  •  Harrison's 22e  •  Localization in Clinical Neurology 8e")


class MiniHeader(Flowable):
    def __init__(self, w, h=36):
        super().__init__()
        self.width, self.height = w, h

    def draw(self):
        c = self.canv
        c.setFillColor(NAVY); c.roundRect(0, 0, self.width, self.height, 6, fill=1, stroke=0)
        c.setFillColor(WHITE); c.setFont("Helvetica-Bold", 13)
        c.drawCentredString(self.width / 2, self.height - 20,
            "COMMON PERONEAL NERVE — QUICK REFERENCE")
        c.setFillColor(HexColor("#BDC3C7")); c.setFont("Helvetica", 8)
        c.drawCentredString(self.width / 2, 6, "Page 2 of 2  |  Orthopaedic Decision Support")


# ── Section Header
class SecHdr(Flowable):
    def __init__(self, text, w, color=TEAL, num=None):
        super().__init__()
        self.text, self.width, self.color, self.num = text, w, color, num
        self.height = 22

    def draw(self):
        c = self.canv
        c.setFillColor(self.color)
        c.roundRect(0, 0, self.width, self.height, 4, fill=1, stroke=0)
        c.setFillColor(WHITE); c.setFont("Helvetica-Bold", 10.5)
        lbl = f"  {self.num}. {self.text}" if self.num else f"  {self.text}"
        c.drawString(10, 6, lbl)


# ── Management Flowchart
class Flowchart(Flowable):
    def __init__(self, w):
        super().__init__()
        self.width, self.height = w, 295

    def rbox(self, c, x, y, w, h, lines, bg, fg=WHITE, fs=8, bold=False):
        c.setFillColor(bg); c.setStrokeColor(NAVY); c.setLineWidth(0.7)
        c.roundRect(x, y, w, h, 4, fill=1, stroke=1)
        c.setFillColor(fg); fn = "Helvetica-Bold" if bold else "Helvetica"
        c.setFont(fn, fs)
        lh = fs + 2
        total = len(lines) * lh
        sy = y + h / 2 + total / 2 - lh + 1
        for ln in lines:
            c.drawCentredString(x + w / 2, sy, ln)
            sy -= lh

    def arr(self, c, x1, y1, x2, y2, col=NAVY):
        c.setStrokeColor(col); c.setLineWidth(1.1)
        c.line(x1, y1, x2, y2)
        sz = 5
        c.setFillColor(col)
        if x1 == x2:
            c.polygon([x2 - sz/2, y2 + sz, x2 + sz/2, y2 + sz, x2, y2], fill=1, stroke=0)
        else:
            if x2 > x1:
                c.polygon([x2 - sz, y2 + sz/2, x2 - sz, y2 - sz/2, x2, y2], fill=1, stroke=0)
            else:
                c.polygon([x2 + sz, y2 + sz/2, x2 + sz, y2 - sz/2, x2, y2], fill=1, stroke=0)

    def diamond(self, c, cx, cy, hw, hh, lines, bg, fg=WHITE, fs=8):
        c.setFillColor(bg); c.setStrokeColor(NAVY); c.setLineWidth(0.7)
        pts = [cx, cy+hh, cx+hw, cy, cx, cy-hh, cx-hw, cy]
        c.polygon(pts, fill=1, stroke=1)
        c.setFillColor(fg); c.setFont("Helvetica-Bold", fs)
        lh = fs + 2
        total = len(lines) * lh
        sy = cy + total/2 - lh/2
        for ln in lines:
            c.drawCentredString(cx, sy, ln)
            sy -= lh

    def draw(self):
        c = self.canv
        # background
        c.setFillColor(LIGHT_BG); c.roundRect(0, 0, self.width, self.height, 6, fill=1, stroke=0)
        c.setFillColor(NAVY); c.setFont("Helvetica-Bold", 9.5)
        c.drawCentredString(self.width/2, self.height - 14, "CPN INJURY — ORTHOPAEDIC MANAGEMENT ALGORITHM")

        W = self.width
        cx = W / 2
        bw, bh = 148, 28

        # Row 1: Initial Assessment
        y1 = self.height - 38
        self.rbox(c, cx-bw/2, y1, bw, bh, ["INITIAL ASSESSMENT", "History + Examination"], NAVY, bold=True)
        self.arr(c, cx, y1, cx, y1 - 14)

        # Row 2: NCS/EMG
        y2 = y1 - 14 - bh
        self.rbox(c, cx-bw/2, y2, bw, bh, ["NCS / EMG (≥3 weeks post-injury)"], TEAL, bold=True)
        self.arr(c, cx, y2, cx, y2 - 14)

        # Row 3: Diamond
        y3 = y2 - 14 - 35
        self.diamond(c, cx, y3, 155, 34, ["MECHANISM?"], MID_BLUE)
        # left label
        c.setFillColor(RED); c.setFont("Helvetica-Bold", 7.5)
        c.drawString(26, y3 + 5, "HIGH ENERGY")
        c.setFillColor(DARK_GREEN)
        c.drawString(W - 108, y3 + 5, "LOW ENERGY")

        # Left branch arrows
        self.arr(c, cx - 155, y3, 20 + 130, y3, col=RED)
        # Right branch arrows
        self.arr(c, cx + 155, y3, W - 20 - 130, y3, col=DARK_GREEN)

        lbx = 18
        rbx = W - 18 - 130

        # HIGH ENERGY path (left column)
        y_l1 = y3 - 14
        self.arr(c, 18+130/2, y3, 18+130/2, y_l1)
        self.rbox(c, lbx, y_l1-bh, 130, bh, ["Surgical Exploration", "within 3 WEEKS"], RED, bold=True)
        y_l2 = y_l1 - bh - 12
        self.arr(c, lbx+65, y_l1-bh, lbx+65, y_l2)
        self.rbox(c, lbx, y_l2-bh+5, 130, bh, ["Intraop NAP Recording", "+ Grade Assessment"], ORANGE, fg=HexColor("#2C3E50"))
        y_l3 = y_l2 - bh - 6
        self.arr(c, lbx+65, y_l2-bh+5, lbx+65, y_l3)
        self.rbox(c, lbx, y_l3-bh, 130, bh, ["Neurolysis / Repair", "/ Graft / Transfer"], TEAL, bold=True)

        # LOW ENERGY path (right column)
        y_r1 = y3 - 14
        self.arr(c, rbx+65, y3, rbx+65, y_r1)
        self.rbox(c, rbx, y_r1-bh, 130, bh, ["Conservative Rx", "AFO + Physio"], DARK_GREEN, bold=True)
        y_r2 = y_r1 - bh - 12
        self.arr(c, rbx+65, y_r1-bh, rbx+65, y_r2)
        self.rbox(c, rbx, y_r2-bh+5, 130, bh, ["Observe 3–6 months", "Serial NCS/EMG"], GREEN)

        # Recovery diamond
        y_r3 = y_r2 - bh - 8
        self.arr(c, rbx+65, y_r2-bh+5, rbx+65, y_r3+25)
        self.diamond(c, rbx+65, y_r3, 68, 25, ["Recovery?"], ORANGE, fg=HexColor("#2C3E50"), fs=8)
        # YES → down
        y_r4 = y_r3 - 25 - 8
        self.arr(c, rbx+65, y_r3-25, rbx+65, y_r4, col=GREEN)
        c.setFillColor(GREEN); c.setFont("Helvetica-Bold", 7)
        c.drawString(rbx+68, y_r3-14, "YES")
        self.rbox(c, rbx, y_r4-22, 130, 22, ["Continue Conservative Rx"], DARK_GREEN)
        # NO → left arrow connecting to surgery
        self.arr(c, rbx+65-68, y_r3, lbx+65+20, y_r3, col=RED)
        c.setFillColor(RED); c.setFont("Helvetica-Bold", 7)
        c.drawString(lbx+80, y_r3+4, "NO → SURGERY")

        # Bottom legend row
        y_bot = 10
        bw3 = 90
        legend = [
            (10,   "Grade 1-2", "Full Recovery", GREEN),
            (107,  "Grade 3",   "Partial / Neurolysis", TEAL),
            (214,  "Grade 4",   "Neurolysis ± Graft", ORANGE),
            (317,  "Grade 5",   "Repair or Graft", RED),
            (415,  ">12 months","Tendon Transfer", MID_BLUE),
        ]
        c.setFillColor(NAVY); c.setFont("Helvetica-Bold", 7)
        c.drawCentredString(W/2, y_bot+50, "─── Sunderland Grade → Expected Treatment ───")
        for lx, g, txt, col in legend:
            self.rbox(c, lx, y_bot, 88, 38, [g, txt], col, fs=7.5)


def base_ts(header_color, n_data, alt1=WHITE, alt2=LIGHT_BG, extra=None):
    """Build a base TableStyle with alternating rows."""
    ts = [
        ('BACKGROUND', (0, 0), (-1, 0), header_color),
        ('TEXTCOLOR',  (0, 0), (-1, 0), WHITE),
        ('FONTNAME',   (0, 0), (-1, 0), 'Helvetica-Bold'),
        ('FONTSIZE',   (0, 0), (-1,-1), 8.5),
        ('GRID',       (0, 0), (-1,-1), 0.4, HexColor("#BDC3C7")),
        ('BOTTOMPADDING', (0, 0), (-1,-1), 4),
        ('TOPPADDING',    (0, 0), (-1,-1), 4),
        ('LEFTPADDING',   (0, 0), (-1,-1), 6),
        ('VALIGN',     (0, 0), (-1,-1), 'MIDDLE'),
    ]
    for i in range(1, n_data + 1):
        ts.append(('BACKGROUND', (0, i), (-1, i), alt1 if i % 2 == 1 else alt2))
    if extra:
        ts.extend(extra)
    return TableStyle(ts)


def build_pdf(path):
    doc = SimpleDocTemplate(
        path, pagesize=A4,
        leftMargin=14*mm, rightMargin=14*mm,
        topMargin=10*mm,  bottomMargin=10*mm,
        title="CPN Injury Quick Reference – Orthopaedics",
        author="Orris Clinical AI",
        subject="Common Peroneal Nerve Injury Management"
    )

    story = []
    UW = W - 28*mm        # usable width ≈ 539 pt
    C  = (UW - 6) / 2     # half-column ≈ 266 pt

    def two_col(left, right, sep=6):
        t = Table([[left, Spacer(sep, 1), right]], colWidths=[C, sep, C])
        t.setStyle(TableStyle([
            ('VALIGN', (0,0),(-1,-1), 'TOP'),
            ('LEFTPADDING',  (0,0),(-1,-1), 0),
            ('RIGHTPADDING', (0,0),(-1,-1), 0),
        ]))
        return t

    # ═══════════════════════════════════════ PAGE 1 ═══════════
    story.append(HeaderBanner(UW, 70))
    story.append(Spacer(1, 7))

    # ── 1. Anatomy
    story.append(SecHdr("ANATOMY SNAPSHOT", UW, TEAL, "1"))
    story.append(Spacer(1, 3))

    anat = [
        [Paragraph('<b>Feature</b>', TH),     Paragraph('<b>Detail</b>', TH)],
        [Paragraph('Root value',     TB),     Paragraph('L4, L5, S1, S2', TB)],
        [Paragraph('Origin',         TB),     Paragraph('Lateral division of sciatic nerve, posterolateral popliteal fossa', TB)],
        [Paragraph('Vulnerable point', TB),   Paragraph('Fibular head/neck — superficial, tethered, no muscle cover', TB)],
        [Paragraph('Fibular tunnel', TB),     Paragraph('Fibrous arch at origin of peroneus longus', TB)],
        [Paragraph('<b>Deep peroneal</b>',  TBB), Paragraph('Tibialis ant., EHL, EDL, EDB → dorsiflexion, toe extension; sensation 1st web space', TB)],
        [Paragraph('<b>Superficial peroneal</b>', TBB), Paragraph('Peroneus longus & brevis → eversion; sensation dorsum of foot', TB)],
        [Paragraph('Other branches', TB),     Paragraph('Recurrent articular (knee), lateral sural cutaneous (upper lat. leg)', TB)],
    ]
    at = Table(anat, colWidths=[C*0.34, C*1.66])
    at.setStyle(base_ts(TEAL, 7,
        extra=[
            ('BACKGROUND', (0,5), (-1,5), BOX_BLUE),
            ('BACKGROUND', (0,6), (-1,6), BOX_GREEN),
        ]
    ))
    story.append(at)
    story.append(Spacer(1, 7))

    # ── 2+3: Etiology | Classification
    etiol = [
        [Paragraph('<b>Category</b>', TH),   Paragraph('<b>Common Causes</b>', TH)],
        [Paragraph('Traumatic', TB),         Paragraph('Knee dislocation (44% CPN), fibular head # (50% CPN), direct blow, TKA', TB)],
        [Paragraph('Compressive', TB),       Paragraph('Leg crossing, tight cast, squatting, lithotomy, bed rest', TB)],
        [Paragraph('Space-occupying', TB),   Paragraph('Intraneural ganglion (STFJ), Baker cyst, ganglion, lipoma', TB)],
        [Paragraph('Systemic', TB),          Paragraph('Diabetes, vasculitis, emaciation, leprosy', TB)],
        [Paragraph('Iatrogenic', TB),        Paragraph('Lateral decubitus position, HTO, poor cast application', TB)],
    ]
    et = Table(etiol, colWidths=[C*0.34, C*0.66])
    et.setStyle(base_ts(ORANGE, 5))

    classif = [
        [Paragraph('<b>Gr</b>', THs), Paragraph('<b>Seddon</b>', THs), Paragraph('<b>Pathology</b>', THs), Paragraph('<b>Prognosis</b>', THs)],
        [Paragraph('1', TBs), Paragraph('Neurapraxia', TBs), Paragraph('Myelin only', TBs), Paragraph('Full; wks–3m', TBs)],
        [Paragraph('2', TBs), Paragraph('Axonotmesis', TBs), Paragraph('Axon intact endo', TBs), Paragraph('Excellent 2–3mm/d', TBs)],
        [Paragraph('3', TBs), Paragraph('Axonotmesis', TBs), Paragraph('Axon + endo', TBs), Paragraph('Incomplete 1mm/d', TBs)],
        [Paragraph('4', TBs), Paragraph('Neurotmesis', TBs), Paragraph('+ perineurium', TBs), Paragraph('Neuroma-in-cont.', TBs)],
        [Paragraph('5', TBs), Paragraph('Neurotmesis', TBs), Paragraph('Complete', TBs), Paragraph('Surgery required', TBs)],
        [Paragraph('6', TBs), Paragraph('Mixed', TBs), Paragraph('Variable fascicles', TBs), Paragraph('Variable', TBs)],
    ]
    ct = Table(classif, colWidths=[C*0.12, C*0.27, C*0.32, C*0.29])
    ct.setStyle(base_ts(MID_BLUE, 6,
        extra=[
            ('FONTSIZE', (0,0),(-1,-1), 7.5),
            ('BACKGROUND', (0,4),(-1,5), BOX_RED),
        ]
    ))

    story.append(two_col(SecHdr("ETIOLOGY", C, ORANGE, "2"), SecHdr("SUNDERLAND CLASSIFICATION", C, MID_BLUE, "3")))
    story.append(Spacer(1, 3))
    story.append(two_col(et, ct))
    story.append(Spacer(1, 7))

    # ── 4. Clinical Features + Differential
    story.append(SecHdr("CLINICAL FEATURES & DIFFERENTIAL DIAGNOSIS", UW, MID_BLUE, "4"))
    story.append(Spacer(1, 3))

    cf = [
        [Paragraph('<b>Motor Deficit</b>', TH), Paragraph('<b>Sensory Loss</b>', TH), Paragraph('<b>Gait / Sign</b>', TH)],
        [
            Paragraph('• Foot drop (weak dorsiflexion)<br/>• Weak eversion<br/>• Weak toe extension<br/>• Preserved inversion ✓<br/>• Preserved plantarflexion ✓', TB),
            Paragraph('• Dorsum of foot (sup. peroneal)<br/>• Lateral upper leg (lat. sural)<br/>• 1st web space (deep peroneal)<br/>• Sole SPARED ✓', TB),
            Paragraph('• Steppage (high-stepping) gait<br/>• Toe slapping at heel-strike<br/>• Tinel at fibular head<br/>• NO back pain typically', TB),
        ],
    ]
    cft = Table(cf, colWidths=[C*0.70, C*0.62, C*0.68])
    cft.setStyle(TableStyle([
        ('BACKGROUND', (0,0),(-1,0), MID_BLUE),
        ('TEXTCOLOR',  (0,0),(-1,0), WHITE),
        ('FONTNAME',   (0,0),(-1,0), 'Helvetica-Bold'),
        ('BACKGROUND', (0,1),(-1,1), BOX_BLUE),
        ('FONTSIZE',   (0,0),(-1,-1), 8.5),
        ('GRID',       (0,0),(-1,-1), 0.4, HexColor("#BDC3C7")),
        ('TOPPADDING',    (0,0),(-1,-1), 5),
        ('BOTTOMPADDING', (0,0),(-1,-1), 5),
        ('LEFTPADDING',   (0,0),(-1,-1), 6),
        ('VALIGN',     (0,0),(-1,-1), 'TOP'),
    ]))
    story.append(cft)
    story.append(Spacer(1, 4))

    diff = [
        [Paragraph('<b>Condition</b>', THs),   Paragraph('<b>Inversion</b>', THs),
         Paragraph('<b>Eversion</b>', THs),    Paragraph('<b>EMG Paraspinals</b>', THs),
         Paragraph('<b>Tinel Fib.Head</b>', THs), Paragraph('<b>Back Pain</b>', THs)],
        [Paragraph('CPN Palsy', TBs),          Paragraph('Normal ✓', TBs),
         Paragraph('Weak', TBs),               Paragraph('Normal', TBs),
         Paragraph('Present', TBs),            Paragraph('Absent', TBs)],
        [Paragraph('L5 Radiculopathy', TBs),   Paragraph('Weak', TBs),
         Paragraph('Weak', TBs),               Paragraph('Abnormal', TBs),
         Paragraph('Absent', TBs),             Paragraph('Often present', TBs)],
        [Paragraph('LS Plexopathy', TBs),      Paragraph('Weak', TBs),
         Paragraph('Weak', TBs),               Paragraph('Normal', TBs),
         Paragraph('Absent', TBs),             Paragraph('Variable', TBs)],
        [Paragraph('Tib. Ant. Tendon Rupture', TBs), Paragraph('Normal ✓', TBs),
         Paragraph('Normal ✓', TBs),           Paragraph('Normal', TBs),
         Paragraph('Absent — palpable gap', TBs), Paragraph('Absent', TBs)],
    ]
    dt = Table(diff, colWidths=[UW*0.23, UW*0.10, UW*0.10, UW*0.18, UW*0.22, UW*0.17])
    ts_diff = [
        ('BACKGROUND', (0,0),(-1,0), NAVY),
        ('TEXTCOLOR',  (0,0),(-1,0), WHITE),
        ('FONTNAME',   (0,0),(-1,0), 'Helvetica-Bold'),
        ('FONTSIZE',   (0,0),(-1,-1), 7.5),
        ('GRID',       (0,0),(-1,-1), 0.4, HexColor("#BDC3C7")),
        ('TOPPADDING',    (0,0),(-1,-1), 3),
        ('BOTTOMPADDING', (0,0),(-1,-1), 3),
        ('LEFTPADDING',   (0,0),(-1,-1), 5),
        ('VALIGN',     (0,0),(-1,-1), 'MIDDLE'),
        ('BACKGROUND', (0,1),(-1,1), BOX_GREEN),
        ('BACKGROUND', (0,2),(-1,2), LIGHT_BG),
        ('BACKGROUND', (0,3),(-1,3), WHITE),
        ('BACKGROUND', (0,4),(-1,4), LIGHT_BG),
    ]
    dt.setStyle(TableStyle(ts_diff))
    story.append(dt)
    story.append(Spacer(1, 7))

    # ── 5. Investigations
    story.append(SecHdr("INVESTIGATIONS", UW, PURPLE, "5"))
    story.append(Spacer(1, 3))

    inv = [
        [Paragraph('<b>Investigation</b>', TH), Paragraph('<b>Key Findings / Notes</b>', TH), Paragraph('<b>Timing</b>', TH)],
        [Paragraph('NCS – Motor', TB),
         Paragraph('Conduction block (>50% CMAP drop) across fibular head = neurapraxia; reduced amplitude throughout = axonal loss', TB),
         Paragraph('Any time; repeat at 3m', TB)],
        [Paragraph('NCS – Sensory', TB),
         Paragraph('Superficial peroneal SNAP absent or reduced', TB),
         Paragraph('From day 1', TB)],
        [Paragraph('EMG (Needle)', TB),
         Paragraph('Fibrillations in TA, EHL, EDL, peronei after 3 weeks. Normal paraspinals = CPN (not L5 root)', TB),
         Paragraph('≥3 weeks post-injury', TB)],
        [Paragraph('X-Ray (Knee/Fibula)', TB),
         Paragraph('Fibular head # (50% CPN), knee dislocation, tibial plateau #; alignment', TB),
         Paragraph('Acute', TB)],
        [Paragraph('MRI / MR Neurography', TB),
         Paragraph('T2 bright nerve = neurapraxia. Nerve gap = neurotmesis. Intraneural ganglion = cystic lesion from STFJ', TB),
         Paragraph('Subacute / pre-op', TB)],
        [Paragraph('Ultrasound (15–18 MHz)', TB),
         Paragraph('Dynamic nerve assessment, ganglion identification, USS-guided aspiration', TB),
         Paragraph('Any time', TB)],
        [Paragraph('Bloods (HbA1c, ESR, ANCA)', TB),
         Paragraph('Rule out diabetes, vasculitis', TB),
         Paragraph('Initial workup', TB)],
    ]
    inv_ts = [
        ('BACKGROUND', (0,0),(-1,0), PURPLE),
        ('TEXTCOLOR',  (0,0),(-1,0), WHITE),
        ('FONTNAME',   (0,0),(-1,0), 'Helvetica-Bold'),
        ('FONTSIZE',   (0,0),(-1,-1), 8.5),
        ('GRID',       (0,0),(-1,-1), 0.4, HexColor("#BDC3C7")),
        ('TOPPADDING',    (0,0),(-1,-1), 4),
        ('BOTTOMPADDING', (0,0),(-1,-1), 4),
        ('LEFTPADDING',   (0,0),(-1,-1), 6),
        ('VALIGN',     (0,0),(-1,-1), 'TOP'),
    ]
    for i in range(1, 8):
        inv_ts.append(('BACKGROUND', (0,i),(-1,i), WHITE if i%2==1 else LIGHT_BG))
    it = Table(inv, colWidths=[UW*0.24, UW*0.58, UW*0.18])
    it.setStyle(TableStyle(inv_ts))
    story.append(it)
    story.append(Spacer(1, 7))

    # ═══════════════════════════════════════ PAGE 2 ═══════════
    story.append(PageBreak())
    story.append(MiniHeader(UW, 36))
    story.append(Spacer(1, 7))

    # ── 6. Flowchart
    story.append(SecHdr("MANAGEMENT ALGORITHM", UW, NAVY, "6"))
    story.append(Spacer(1, 4))
    story.append(Flowchart(UW))
    story.append(Spacer(1, 7))

    # ── 7 + 8: Non-op | Operative
    nonop = [
        [Paragraph('<b>Measure</b>', TH),       Paragraph('<b>Details</b>', TH)],
        [Paragraph('Indication', TB),            Paragraph('Grade 1–2 / low-energy / metabolic cause', TB)],
        [Paragraph('AFO', TB),                   Paragraph('Rigid or articulated; carbon fibre preferred; maintains neutral dorsiflexion in swing phase', TB)],
        [Paragraph('Physiotherapy', TB),          Paragraph('ROM, Achilles stretching (prevent equinus), gait retraining, strengthening', TB)],
        [Paragraph('Risk factor removal', TB),   Paragraph('Stop leg crossing, treat DM, weight loss, lateral knee pad', TB)],
        [Paragraph('FES', TB),                   Paragraph('WalkAide/Bioness L300 — gait-triggered peroneal stimulation; adjunct to AFO', TB)],
        [Paragraph('Observation', TB),           Paragraph('Grade 1: 4–12 wks.  Grades 2–3: 3–6 months.  Serial NCS/EMG to track', TB)],
        [Paragraph('<b>Failure threshold</b>', TBB), Paragraph('<b>No clinical/EMG recovery at 3 months (axonal loss) → refer for surgery</b>', TBB)],
    ]
    not_ts = [
        ('BACKGROUND', (0,0),(-1,0), GREEN),
        ('TEXTCOLOR',  (0,0),(-1,0), WHITE),
        ('FONTNAME',   (0,0),(-1,0), 'Helvetica-Bold'),
        ('FONTSIZE',   (0,0),(-1,-1), 8),
        ('GRID',       (0,0),(-1,-1), 0.4, HexColor("#BDC3C7")),
        ('TOPPADDING',    (0,0),(-1,-1), 4),
        ('BOTTOMPADDING', (0,0),(-1,-1), 4),
        ('LEFTPADDING',   (0,0),(-1,-1), 5),
        ('VALIGN',     (0,0),(-1,-1), 'TOP'),
        ('BACKGROUND', (0,7),(-1,7), BOX_ORANGE),
    ]
    for i in range(1, 7):
        not_ts.append(('BACKGROUND', (0,i),(-1,i), WHITE if i%2==1 else BOX_GREEN))
    nt = Table(nonop, colWidths=[C*0.42, C*0.58])
    nt.setStyle(TableStyle(not_ts))

    op = [
        [Paragraph('<b>Procedure</b>', TH),     Paragraph('<b>Indication / Outcome</b>', TH)],
        [Paragraph('Timing — High energy', TB), Paragraph('Explore + primary repair within <b>3 WEEKS</b> of laceration / fracture-dislocation', TB)],
        [Paragraph('Timing — Low energy', TB),  Paragraph('Surgery if no recovery at 3–6 months', TB)],
        [Paragraph('Neurolysis', TB),            Paragraph('Grade 3–4, entrapment, intraneural ganglion. External ± internal neurolysis + articular branch excision + STFJ capsule repair', TB)],
        [Paragraph('Primary Repair', TB),        Paragraph('Sharp laceration, small gap, tension-free. <b>60–70% achieve useful dorsiflexion</b> under ideal conditions', TB)],
        [Paragraph('Nerve Graft', TB),           Paragraph('Gap >2–3 cm. Sural nerve (gold standard) or allograft (5–70 mm). Mean graft 7 cm. <b>49% achieve >M3</b> (n=465, meta-analysis)', TB)],
        [Paragraph('Nerve Transfer', TB),        Paragraph('Proximal injury / long gap. Tibial branch → distal CPN. <b>62.9% >M3</b> (meta-analysis)', TB)],
        [Paragraph('<b>Tendon Transfer (SALVAGE)</b>', TBB), Paragraph('<b>Late (>12–18m) / failed repair. Tibialis posterior transfer (Bridle). Most durable long-term result</b>', TBB)],
    ]
    op_ts = [
        ('BACKGROUND', (0,0),(-1,0), RED),
        ('TEXTCOLOR',  (0,0),(-1,0), WHITE),
        ('FONTNAME',   (0,0),(-1,0), 'Helvetica-Bold'),
        ('FONTSIZE',   (0,0),(-1,-1), 8),
        ('GRID',       (0,0),(-1,-1), 0.4, HexColor("#BDC3C7")),
        ('TOPPADDING',    (0,0),(-1,-1), 4),
        ('BOTTOMPADDING', (0,0),(-1,-1), 4),
        ('LEFTPADDING',   (0,0),(-1,-1), 5),
        ('VALIGN',     (0,0),(-1,-1), 'TOP'),
        ('BACKGROUND', (0,7),(-1,7), BOX_ORANGE),
    ]
    for i in range(1, 7):
        op_ts.append(('BACKGROUND', (0,i),(-1,i), WHITE if i%2==1 else BOX_RED))
    ot = Table(op, colWidths=[C*0.40, C*0.60])
    ot.setStyle(TableStyle(op_ts))

    story.append(two_col(SecHdr("A. NON-OPERATIVE MANAGEMENT", C, GREEN, "7"), SecHdr("B. OPERATIVE MANAGEMENT", C, RED, "8")))
    story.append(Spacer(1, 3))
    story.append(two_col(nt, ot))
    story.append(Spacer(1, 7))

    # ── 9. Critical Timelines
    story.append(SecHdr("CRITICAL TIMELINES & SURGICAL OUTCOMES", UW, ORANGE, "9"))
    story.append(Spacer(1, 3))

    tl = [
        [Paragraph('<b>Timeline</b>', TH), Paragraph('<b>Decision Point</b>', TH), Paragraph('<b>Action</b>', TH)],
        [Paragraph('Day 0–21', TB), Paragraph('High-energy (laceration, fracture-dislocation)', TB), Paragraph('Explore ± primary repair', TB)],
        [Paragraph('3 weeks', TB), Paragraph('EMG now reliable (fibrillations detectable)', TB), Paragraph('Baseline EMG / NCS', TB)],
        [Paragraph('3 months', TB), Paragraph('Neurapraxia should show recovery by now', TB), Paragraph('If no recovery → MRI ± surgical referral', TB)],
        [Paragraph('3–6 months', TB), Paragraph('Low-energy failure of conservative Rx', TB), Paragraph('Neurolysis / nerve repair', TB)],
        [Paragraph('<b>&lt;12 months</b>', TBB), Paragraph('<b>CRITICAL WINDOW for nerve repair</b>', TBB), Paragraph('<b>Surgery beyond 12m = suboptimal result</b>', TBB)],
        [Paragraph('>12–18 months', TB), Paragraph('Irreversible denervation / failed nerve repair', TB), Paragraph('Tibialis posterior tendon transfer (Bridle)', TB)],
    ]
    tl_ts = [
        ('BACKGROUND', (0,0),(-1,0), ORANGE),
        ('TEXTCOLOR',  (0,0),(-1,0), WHITE),
        ('FONTNAME',   (0,0),(-1,0), 'Helvetica-Bold'),
        ('FONTSIZE',   (0,0),(-1,-1), 8.5),
        ('GRID',       (0,0),(-1,-1), 0.4, HexColor("#BDC3C7")),
        ('TOPPADDING',    (0,0),(-1,-1), 4),
        ('BOTTOMPADDING', (0,0),(-1,-1), 4),
        ('LEFTPADDING',   (0,0),(-1,-1), 6),
        ('VALIGN',     (0,0),(-1,-1), 'MIDDLE'),
        ('BACKGROUND', (0,5),(-1,5), BOX_RED),
        ('FONTNAME',   (0,5),(-1,5), 'Helvetica-Bold'),
        ('BACKGROUND', (0,6),(-1,6), BOX_ORANGE),
    ]
    for i in [1,2,3,4]:
        tl_ts.append(('BACKGROUND', (0,i),(-1,i), WHITE if i%2==1 else LIGHT_BG))
    tlt = Table(tl, colWidths=[UW*0.17, UW*0.48, UW*0.35])
    tlt.setStyle(TableStyle(tl_ts))
    story.append(tlt)
    story.append(Spacer(1, 7))

    # ── 10 + 11: Outcomes | Recent Advances
    outcomes = [
        [Paragraph('<b>Procedure</b>', TH), Paragraph('<b>Outcome</b>', TH)],
        [Paragraph('Neurolysis (early, <6m)', TB), Paragraph('60–70% useful recovery', TB)],
        [Paragraph('Primary repair (ideal conditions)', TB), Paragraph('60–70% anti-gravity dorsiflexion', TB)],
        [Paragraph('Nerve grafting (meta-analysis, n=465)', TB), Paragraph('<b>49% achieve >M3</b>', TBB)],
        [Paragraph('Nerve transfer: tibial → CPN', TB), Paragraph('<b>62.9% achieve >M3</b>', TBB)],
        [Paragraph('Repair >12 months post-injury', TB), Paragraph('Poor — do NOT attempt nerve repair', TB)],
        [Paragraph('Graft length >12 cm', TB), Paragraph('Suboptimal outcome', TB)],
        [Paragraph('Tendon transfer (late salvage)', TB), Paragraph('Most reliable, durable long-term', TB)],
    ]
    out_ts = [
        ('BACKGROUND', (0,0),(-1,0), TEAL),
        ('TEXTCOLOR',  (0,0),(-1,0), WHITE),
        ('FONTNAME',   (0,0),(-1,0), 'Helvetica-Bold'),
        ('FONTSIZE',   (0,0),(-1,-1), 8),
        ('GRID',       (0,0),(-1,-1), 0.4, HexColor("#BDC3C7")),
        ('TOPPADDING',    (0,0),(-1,-1), 4),
        ('BOTTOMPADDING', (0,0),(-1,-1), 4),
        ('LEFTPADDING',   (0,0),(-1,-1), 5),
        ('VALIGN',     (0,0),(-1,-1), 'MIDDLE'),
        ('BACKGROUND', (0,5),(-1,6), BOX_RED),
    ]
    for i in [1,2,3,4,7]:
        out_ts.append(('BACKGROUND', (0,i),(-1,i), WHITE if i%2==1 else BOX_BLUE))
    outt = Table(outcomes, colWidths=[C*0.60, C*0.40])
    outt.setStyle(TableStyle(out_ts))

    adv = [
        [Paragraph('<b>Advance</b>', TH), Paragraph('<b>Clinical Relevance</b>', TH)],
        [Paragraph('MR Neurography (3T DTI)', TB), Paragraph('Fascicular detail + continuity; guides surgical planning', TB)],
        [Paragraph('Nerve Transfers', TB), Paragraph('Tibial branch → distal CPN; avoids long regeneration distance', TB)],
        [Paragraph('Implantable FES (ActiGait)', TB), Paragraph('Closed-loop gait-triggered stimulation; superior to fixed AFO', TB)],
        [Paragraph('Nerve Allografts (Avance)', TB), Paragraph('5–70 mm gaps; no sural harvest morbidity', TB)],
        [Paragraph('Intraneural Ganglion Rx', TB), Paragraph('Articular branch excision + STFJ repair = low recurrence', TB)],
        [Paragraph('Intraop NAP Recording', TB), Paragraph('Guides resection vs. neurolysis in neuroma-in-continuity', TB)],
        [Paragraph('USS-Guided Aspiration', TB), Paragraph('Ganglion cyst aspiration under real-time high-freq USS', TB)],
    ]
    adv_ts = [
        ('BACKGROUND', (0,0),(-1,0), PURPLE),
        ('TEXTCOLOR',  (0,0),(-1,0), WHITE),
        ('FONTNAME',   (0,0),(-1,0), 'Helvetica-Bold'),
        ('FONTSIZE',   (0,0),(-1,-1), 8),
        ('GRID',       (0,0),(-1,-1), 0.4, HexColor("#BDC3C7")),
        ('TOPPADDING',    (0,0),(-1,-1), 4),
        ('BOTTOMPADDING', (0,0),(-1,-1), 4),
        ('LEFTPADDING',   (0,0),(-1,-1), 5),
        ('VALIGN',     (0,0),(-1,-1), 'TOP'),
    ]
    for i in range(1, 8):
        adv_ts.append(('BACKGROUND', (0,i),(-1,i), WHITE if i%2==1 else BOX_PURPLE))
    advt = Table(adv, colWidths=[C*0.45, C*0.55])
    advt.setStyle(TableStyle(adv_ts))

    story.append(two_col(SecHdr("OUTCOMES (Evidence-Based)", C, TEAL, "10"), SecHdr("RECENT ADVANCES", C, PURPLE, "11")))
    story.append(Spacer(1, 3))
    story.append(two_col(outt, advt))
    story.append(Spacer(1, 7))

    # ── Clinical Pearls
    pearls = [
        [Paragraph('<b>🔑  ORTHOPAEDIC CLINICAL PEARLS</b>',
            ParagraphStyle('ph', fontName='Helvetica-Bold', fontSize=9, textColor=NAVY))],
        [Paragraph(
            '• <b>Preserved inversion</b> differentiates CPN palsy from L5 radiculopathy — inversion (tibialis posterior + tibialis ant.) is L4/L5 via tibial nerve; if inversion weak → suspect L5 root<br/>'
            '• <b>Wait ≥3 weeks</b> before EMG — fibrillation potentials take 3 weeks to appear after axonal injury; early normal EMG does NOT exclude axonotmesis<br/>'
            '• <b>EMG paraspinals:</b> Normal → CPN palsy | Abnormal → L5 radiculopathy. This single finding is the most reliable differentiator<br/>'
            '• <b>Intraneural ganglion:</b> Suspect when there is a palpable mass at fibular head + fluctuating weakness with weight-bearing + no weight loss history. MRI shows cystic lesion tracking from STFJ along articular branch<br/>'
            '• <b>TKA foot drop:</b> Most common iatrogenic CPN injury; explore if no recovery; common in valgus-correcting osteotomy and lithotomy positioning<br/>'
            '• <b>Critical 12-month rule:</b> Nerve repair/graft >12 months post-injury OR graft >12 cm = predictably suboptimal — proceed to tendon transfer instead<br/>'
            '• <b>Tibialis anterior tendon rupture</b> mimics CPN palsy — look for palpable gap at ankle, EMG is normal (no denervation), MRI shows tendon discontinuity',
            ParagraphStyle('pb', fontName='Helvetica', fontSize=8.5, textColor=HexColor("#2C3E50"),
                           leading=13, leftIndent=5, spaceAfter=2)
        )],
    ]
    pearl_t = Table(pearls, colWidths=[UW])
    pearl_t.setStyle(TableStyle([
        ('BACKGROUND', (0,0),(-1,-1), YELLOW_BG),
        ('BOX',        (0,0),(-1,-1), 1.5, ORANGE),
        ('LINEBELOW',  (0,0),(-1,0),  0.8, ORANGE),
        ('TOPPADDING',    (0,0),(-1,-1), 6),
        ('BOTTOMPADDING', (0,0),(-1,-1), 7),
        ('LEFTPADDING',   (0,0),(-1,-1), 10),
        ('VALIGN',     (0,0),(-1,-1), 'TOP'),
    ]))
    story.append(pearl_t)
    story.append(Spacer(1, 6))

    # ── Footer
    foot = [[Paragraph(
        '<font size="7" color="#7F8C8D">Sources: Campbell\'s Operative Orthopaedics 15e (2026) • Adams &amp; Victor\'s Principles of Neurology 12e • Harrison\'s Internal Medicine 22e • '
        'Localization in Clinical Neurology 8e • Sabiston Textbook of Surgery 8e • Imaging Anatomy Vol.3  |  '
        'Generated by Orris Clinical AI — June 2026  |  For educational use only. Verify all clinical decisions against current guidelines.</font>',
        BODY)]]
    ft = Table(foot, colWidths=[UW])
    ft.setStyle(TableStyle([
        ('LINEABOVE',  (0,0),(-1,0), 0.5, GREY),
        ('TOPPADDING', (0,0),(-1,-1), 4),
        ('LEFTPADDING',(0,0),(-1,-1), 0),
    ]))
    story.append(ft)

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


if __name__ == "__main__":
    build_pdf("/home/daytona/workspace/cpn-nerve/CPN_Injury_Quick_Reference.pdf")
This is a shared conversation. Sign in to Orris to start your own chat.