With S.das and Makhan Lal shah as sources Kindly give how to perform tests in MS general surgery level Cases of PVD, breast, thyroid, Abdominal Lump, varicose veins, hernia, hydrocele, common swellings, Ulcer.

Reading File
Finding Sources
Finding Sources
Finding Sources
Finding Sources
Finding Sources
Finding Sources
Finding Sources
Reading File
Reading File
Reading File
Reading File
Reading File
Reading File
Reading File
Reading File
Reading File
Reading File
Finding Sources
Reading File
Reading File
Reading File
Finding Sources
Reading File
Reading File
Reading File
Reading File
Reading File
Reading File
Note on sources: S. Das - A Manual on Clinical Surgery, 13th Edition is available in the library and forms the primary source for this guide. Makhan Lal Shah is not in the library's collection, so the content below draws from S. Das supplemented by standard MS-level surgical examination principles that align with what Shah's textbook covers (both books teach the same classical examination methods used in Indian MS General Surgery).

MS General Surgery - Clinical Examination Guide

Source: S. Das, A Manual on Clinical Surgery, 13th Ed.


1. PERIPHERAL VASCULAR DISEASE (PVD)

History Pointers

  • Age/sex: Atherosclerosis - elderly males; Buerger's disease - males 20-40 yrs; Raynaud's - young females
  • Intermittent claudication - claudication distance (Boyd's Grade I/II/III)
  • Rest pain - continuous, worse at night, relieved by hanging leg down
  • Bilateral (Buerger's, Raynaud's) vs unilateral (embolic, early atherosclerosis)

Inspection

  • Colour: pallor, cyanosis, rubor, gangrene (dry vs wet)
  • Trophic changes: loss of hair, nail changes, skin atrophy
  • Ulcers: site, edge, floor, discharge
  • Extent and type of gangrene - dry (mummified) vs wet (oedematous, crepitus in gas gangrene)
  • Line of demarcation

Palpation

  1. Temperature - cold limb compared to opposite side; use dorsum of hand; feel from distal to proximal to find level of temperature change
  2. Pulses (always compare both sides):
    • Femoral - midpoint of inguinal ligament
    • Popliteal - knee flexed 40°, heel on bed, compress against posterior tibial condyles (also prone position)
    • Posterior tibial - behind medial malleolus (most reliable)
    • Dorsalis pedis - lateral to extensor hallucis longus tendon in 1st metatarsal space (absent in 10% normal)
    • Anterior tibial - just lateral to EHL tendon (extend great toe to make EHL taut)
    • "Disappearing pulse" - pulse absent after exercise = early arterial occlusion
    • Expansile pulsation = aneurysm
  3. Capillary filling time (palpate): Raise leg, then lower - normal turns pink immediately; ischaemic limb takes >20-30 seconds to become pink, then turns purple-red (dilated skin capillaries with deoxygenated blood)
  4. Venous refilling: After elevation - veins refill within 5 seconds in normal; delayed in ischaemia; veins collapse even at 10° elevation in severe ischaemia
  5. Oedema - pitting suggests deep vein involvement
  6. Tenderness along vessel - indicates recent thrombosis
  7. Crepitus - gas gangrene

Special Tests

TestMethodPositive Finding
Buerger's Postural TestPatient supine, raise leg with knee straight in daylight. Normal remains pink to 90°. Note angle at which pallor appearsVascular angle <30° = severe ischaemia; On sitting up, cyanotic hue spreads over foot within 2-3 min (cyanotic congestion)
Capillary Filling TimeElevate leg, then lower to dependent position>20-30 seconds to turn pink = severe ischaemia
Venous RefillingElevate limb, then lay flatDelayed >5 sec = ischaemia; veins guttered even at 10° elevation
Allen's Test (upper limb)Clench fist tightly. Press both radial and ulnar arteries. Open fist (palm white). Release one artery at a timePalm turns pink = that artery patent; remains white = that artery blocked
Branham's Sign (AV fistula)Compress artery proximal to fistulaSwelling reduces, bruit disappears, pulse rate falls, pulse pressure normalizes
Costoclavicular TestFeel radial pulse; patient throws shoulders back + down (military position)Pulse reduces/disappears = subclavian compression by clavicle/1st rib
Hyperabduction TestPassively hyperabduct arm, monitor radial pulsePulse reduces = pectoralis minor syndrome

Auscultation

  • Listen over femoral, popliteal arteries for bruits (indicates stenosis)
  • AV fistula - machinery murmur over the fistula

Investigations

  • Doppler USS, ABI (Ankle Brachial Index), Arteriography
  • Capillary microscopy, MRA/CTA

2. BREAST

Inspection (3 positions: sitting, arms at sides → raised → hands on hips pressing)

  • Symmetry of breasts and nipples
  • Nipple: retraction, inversion, deviation, discharge (blood = duct papilloma/carcinoma), eczema (Paget's disease)
  • Skin changes: peau d'orange (lymphoedema of skin - press with fingertip), dimpling/puckering, erythema, ulceration, satellite nodules
  • Axillae: swelling, skin puckering, ulceration; check shoulder movements

Palpation

  • Positions: sitting → semi-recumbent (45°) → recumbent (pillow under scapula)
  • Palpate normal side first
  • Use palmar surfaces of fingers with hand flat (best for detecting cancer)
  • Systematically palpate all four quadrants + axillary tail + behind the nipple (do not miss this)
  • Express nipple to check for discharge
If a lump is found, note:
FeatureMethodSignificance
Temperature & tendernessBack of fingers for temperatureWarm + tender = inflammatory
SituationWhich quadrant; UOQ = commonest for carcinoma---
Sizecm in two dimensions---
ShapeRegular/irregularIrregular = malignant
SurfaceSmooth/nodular/bosselated---
Edge/MarginWell-defined/ill-definedIll-defined = malignant
ConsistencySoft/firm/hard/fluctuantHard = carcinoma; fluctuant = abscess/cyst
MobilitySkin involvement + deep fixityFix to skin or pectoral = advanced
Skin attachmentPinch skin over lump - dimpling?Dimpling = involvement of Cooper's ligaments (carcinoma)
Peau d'orangePress fingertip over skinPitting at follicle openings = dermal lymphatic blockage
Deep fixityTense pectoralis (hand on hip, press elbow), see if lump becomes fixedFixity to pectoral fascia = advanced carcinoma
Retraction testArms raised; watch nipple and skinTethering sign of carcinoma
Axilla - examine for lymph nodes (5 groups): anterior (pectoral), posterior (subscapular), lateral, medial (apical), central

Percussion & Auscultation

  • Rare in breast exam; may percuss sternum for retrosternal metastasis

3. THYROID

Inspection

  • Neck: note the swelling - position (front of neck), midline/off-midline
  • Swallowing test: Ask patient to swallow water - thyroid swelling moves upward on deglutition (moves with thyroid which is enclosed in pretracheal fascia)
  • Shape: diffuse/nodular; skin changes over swelling
  • Visible pulsation, visible veins (retrosternal goitre)
  • Signs of toxicity: exophthalmos (Graves'), lid retraction, lid lag, proptosis, periorbital oedema

Palpation

Stand behind the patient (standard method in India for MS exams):
  1. Size of the gland - both lobes and isthmus
  2. Consistency: soft (parenchymatous), firm/rubbery (Hashimoto's), hard (carcinoma, Riedel's), cystic (colloid cyst)
  3. Surface: smooth vs nodular (single nodule vs multinodular)
  4. Tenderness: acute thyroiditis, haemorrhage into nodule
  5. Mobility on swallowing: confirm by palpating while asking to swallow again
  6. Fixity to trachea or surrounding structures: malignancy
  7. Tracheal position: deviation by goitre
  8. Carotid pulsation: feel bilaterally - obliterated = malignant engulfment of carotid sheath
  9. Cervical lymph nodes: especially in malignancy - papillary carcinoma notorious for early lymphatic spread
  10. Kocher's test: gentle lateral compression of thyroid - patient develops stridor if trachea is compressed (softened tracheal rings - tracheomalacia). Significant pre-operatively.
  11. Pulsation/thrill: toxic goitre (increased vascularity in Graves')
  12. Berry's sign: loss of carotid pulsation = malignant encasement

Percussion

  • Over manubrium sterni - dullness = retrosternal goitre (more theoretical, but tested in viva)

Auscultation

  • Systolic bruit over goitre = primary toxic goitre (Graves' disease) - increased vascularity
  • Bruit absent in secondary toxic goitre (multinodular)

General/Systemic Examination

  • Eyes: exophthalmos, lid lag (von Graefe's sign - lid lags when eye moves down), lid retraction (Dalrymple's sign), convergence weakness (Moebius' sign), periorbital oedema, chemosis
  • Hands: fine tremor of outstretched fingers (primary toxicity only, not secondary), sweating, warm moist skin, palmar erythema, thyroid acropachy
  • Pulse: tachycardia, AF (cardiovascular manifestations of toxicity)
  • Pretibial myxoedema: bilateral non-pitting oedema over shin (Graves')
  • Reflexes: brisk in hyperthyroid, sluggish in hypothyroid

4. ABDOMINAL LUMP

Inspection

  • Contour/shape of abdomen: distension, visible lump, asymmetry
  • Respiratory movements: absent over peritonitis area
  • Visible peristalsis: pyloric stenosis (gastric), intestinal obstruction
  • Skin: striae, scars, sinuses, distended veins (direction of flow - caput medusae in portal hypertension; inferior to superior in IVC obstruction)
  • Umbilicus: inverted/everted (ascites), position

Palpation

  • Always palpate the normal quadrant first, moving towards the lump
  • For a lump, determine:
FeatureMethod
Position/siteWhich quadrant; relation to bony landmarks
SizeMeasure in cm
ShapeRegular/irregular
SurfaceSmooth/nodular/bosselated
EdgeWell/ill-defined
ConsistencySoft/firm/hard/cystic
TendernessDirect tenderness, rebound tenderness
MobilityMove in all 4 directions; can you get above/below it?
Moves with respirationLiver, spleen, kidney lumps move with respiration; fixed lumps do not
Bimanual palpationFor renal/retroperitoneal swellings - ballottement (renal lump "bounces back")
Can you get above itCannot get above liver, spleen; can get above pelvic swellings
Percussion noteResonant over bowel; dull over solid or fluid
Fluid thrillLarge cysts, ascites (block central with helper's hand)
Shifting dullnessFree fluid in peritoneal cavity; percuss midline to flank (dull) - ask patient to turn, recheck - now resonant
Organ-specific examination:
  • Liver: starts from RIF, moves obliquely to hepatic area; moves with respiration; notch (normal), irregular (cirrhosis/metastasis); pulsatile (tricuspid regurgitation); friction rub (perihepatitis)
  • Spleen: starts from RIF, moves to left hypochondrium; cannot get between it and costal margin; notch; ballot movement
  • Kidney (bimanual): loin to abdomen, ballottable, resonant over it (bowel in front), moves with respiration, can get above it (unlike spleen)
  • Stomach: succussion splash (pyloric stenosis) - hand over epigastrium, short jerky movements or shake patient
  • Bladder: midline lower abdomen, dull, arises from pelvis (cannot get below it)
  • Aortic pulsation: midline expansile = aneurysm

Percussion

  • Shifting dullness and fluid thrill for ascites
  • Liver/spleen dullness for enlargement

Auscultation

  • Bowel sounds: absent (peritonitis, ileus), increased/tinkling (obstruction)
  • Bruit over liver (hepatocellular carcinoma), renal artery (renal artery stenosis), aorta (aneurysm)
  • Friction rub over liver/spleen (peritonitis, infarction)

5. VARICOSE VEINS

Inspection (patient standing, good light)

  • Distribution: long saphenous territory (medial leg/thigh) vs short saphenous (posterior calf)
  • Tortuous dilated subcutaneous veins
  • Skin changes: pigmentation (haemosiderin), eczema, lipodermatosclerosis, atrophie blanche
  • Ulceration (medial ankle = venous ulcer)
  • Saphena varix (groin - bluish swelling, cough impulse, disappears on lying)

Palpation

  • Temperature of varices (thrombophlebitis = warm, tender)
  • Thrombosis in varix
  • Thrill on coughing (tap over saphena varix)
  • Percussion test / Schwartz test / Tap test: Place one hand over a varix, tap a varix higher up - if veins are incompetent, impulse is transmitted (fluid thrill transmitted down)
  • Saphenofemoral junction - feel for saphena varix

Special Tests

TestMethodPositive/Significance
Trendelenburg Test (Sapheno-femoral incompetence)Patient supine, elevate leg to empty veins. Apply tourniquet at upper thigh (over SFJ). Stand patient up - watch for 30 sec: If veins fill slowly from below = perforator incompetence (Step 1). Release tourniquet - if sudden filling from above = SFJ incompetence (Step 2)SFJ incompetence = test positive (tourniquet controls)
Multiple Tourniquet Test (Fegan's test - perforator sites)Apply sequential tourniquets at mid-thigh, below knee, above ankle. Elevate, then stand. Release one by one from above - filling below each released tourniquet = incompetent perforator at that levelLocates site of perforator incompetence
Perthes' Test (deep vein patency)Apply tourniquet below SFJ (mid-thigh). Ask patient to walk briskly.Varices disappear/reduce = deep veins patent (calf pump working, blood drains through deep). Varices increase + pain = deep veins blocked (dangerous to operate)
Schwartz Test / Tap TestOne hand on lower varix, tap upper varix - feel for transmitted impulsePositive = veins are continuous, valves incompetent
Brodie-Trendelenburg Test (two-stage)As Trendelenburg; observe filling after standing with tourniquet on, then releaseSlow filling = perforator incompetence; rapid from above on release = SFJ incompetence
Morrissey's cough testSaphena varix region - patient coughsVisible/palpable cough impulse at saphena varix = SFJ incompetence

6. HERNIA

History

  • Reducibility - does it go back spontaneously or require manipulation?
  • Prolonged irreducibility = risk of obstruction/strangulation
  • Predisposing causes: chronic cough, prostate, constipation, urethral stricture

Inspection (patient standing, then asked to cough)

  • Site: groin (inguinal vs femoral), umbilical, epigastric, incisional
  • Side and symmetry
  • Cough impulse: visible expansion on coughing

Palpation

Step-by-step for inguinal hernia:
  1. Ask patient to reduce hernia (if reducible)
  2. Identify bony landmarks: pubic tubercle, anterior superior iliac spine (ASIS), inguinal ligament (midpoint)
  3. Pubic tubercle test: Femoral hernia is below and lateral to pubic tubercle. Inguinal hernia is above and medial. Key differentiator.
  4. Deep inguinal ring: ½ inch above midpoint of inguinal ligament (midpoint between ASIS and symphysis pubis)
  5. Cough impulse: Place hand over hernia - expansile impulse on cough confirms hernia
  6. Reducibility: Gently try to reduce in lying position; indirect hernia reduces obliquely upwards, outwards, backwards; direct hernia reduces directly backwards
  7. Finger invagination test (Zieman's technique):
    • Right hand for right side: index finger → deep ring; middle finger → superficial ring; ring finger → femoral ring
    • Patient coughs - impulse on index = indirect; on middle = direct; on ring = femoral
  8. Silk glove sign (children - encysted hydrocele of cord vs hernial sac): Feel for the sensation of two layers of silk rubbing together
  9. Ring occlusion test: Reduce hernia. Press thumb over deep ring (½ inch above midpoint of inguinal ligament). Ask patient to cough.
    • Bulge is controlled = indirect (oblique) hernia (came through deep ring)
    • Bulge appears medial to thumb = direct hernia (comes through Hesselbach's triangle, medial to deep ring)
  10. Child's test (Gornall's test): Hold child from behind, press abdomen, lift up - hernia becomes apparent

Percussion

  • Resonant note = enterocele (bowel contents)
  • Dull note = epiplocele (omentum) or extraperitoneal fat

Auscultation

  • Bowel sounds in hernia sac = enterocele
  • Absence of bowel sounds in irreducible hernia + signs of obstruction = strangulation

General Examination (mandatory)

  • Chest: exclude chronic bronchitis, chronic cough
  • Rectal examination: exclude enlarged prostate, chronic constipation
  • Abdomen: intestinal obstruction

7. HYDROCELE

Inspection (patient standing and lying)

  • Scrotal swelling - size, shape (pear-shaped = primary hydrocele)
  • Translucency (light test)
  • Skin over swelling: normal in primary hydrocele

Palpation (4 essential steps)

  1. Can you get above the swelling? - If yes = scrotal origin (not from abdomen); if no = hernia extending from abdomen
  2. Testis and epididymis palpable separately from swelling? - In hydrocele, testis is posterior and cannot be palpated separately; in epididymal cyst testis is palpable separately
  3. Fluctuation test: Press from two directions - fluctuation = fluid-containing swelling
  4. Transillumination (torch test): Place torch behind swelling in dark room. Hydrocele = brilliantly transilluminant (clear amber fluid). Haematocele, tumour = opaque. (NB: Encysted hydrocele of cord also transilluminates)

Special Tests

TestMethodFinding
TransilluminationTorch test in darkroomHydrocele = brilliant glow; haematocele = opaque
Congenital hydrocele testPatient lies down - hydrocele gradually disappears; stands up - reappears= Patent processus vaginalis communicating with peritoneum
Encysted hydrocele of cordPull testis downward - swelling descends with it and becomes fixed (tethered)Differentiates from lipoma of cord
AspirationAmber fluid, sp. gravity 1.022-1.024, contains cholesterol, fibrinogen, 6% albuminConfirms primary hydrocele; blood-stained fluid = secondary (tumour)

Auscultation - NA


8. COMMON SWELLINGS (General Approach)

Diagnosis of Any Swelling - S. Das Framework

First determine: origin (skin / subcutaneous / muscle / vessel / nerve / bone) then cause (congenital / traumatic / inflammatory / neoplastic / otherwise)

Inspection

  • Site, shape, size (approximately)
  • Surface: smooth, lobulated, irregular
  • Overlying skin: colour (erythema, pigmentation), punctum, scar, fistula, peau d'orange, dilated veins
  • Translucency in daylight (before torch test)
  • Visible pulsation

Palpation (the 10 steps - S. Das)

FeatureHow to ElicitKey Significance
TemperatureBack of handWarm = inflammatory
TendernessGentle pressure; reboundInflammatory; abscess
SizeMeasure with tape/ruler---
Shape------
SurfaceRoll fingers over swellingSmooth = cyst/lipoma; bosselated = lymph node, salivary gland tumour
Edge---Well-defined = benign; ill-defined = malignant
ConsistencyBony hard = bone/calcified; hard = carcinoma; firm = fibroma; rubbery = lymphoma; soft = lipoma; cystic/fluctuant = abscess/cyst
FluctuationTwo-finger method in two planes at right angles (Paget's method)+ = fluid-containing
TransilluminationTorch in dark room+ = clear fluid (cyst, hydrocele, hygroma)
ReducibilityTry to push backHernia, varicocele
CompressibilityCompress - disappears; release - refillsHaemangioma, AV fistula
PulsatilityExpansile (aneurysm) vs transmitted (over artery)---
Bruit/ThrillAuscultation + palpationAV fistula, vascular tumour
MobilityMove in all planes, relation to overlying skin, deep fasciaFixed = malignant or inflammatory
Regional lymph nodesAlways palpateMetastasis, lymphadenitis

Percussion

  • Resonant = gas-containing (Schwannoma of bowel, gas gangrene)
  • Dull = solid, fluid

9. ULCER

History

  • Duration, mode of onset, painful/painless (painless = syphilitic, trophic, Marjolin's; painful = acute, Buerger's/arterial)
  • Associated features: varicosities (venous), numbness (trophic), constitutional symptoms (TB, malignancy)

Inspection

Describe the ulcer - SEFSDFED (Site, Edge, Floor, Shape, Discharge, Floor, Edge, Depth)
FeatureWhat to NoteSignificance
SiteMedial leg/ankle = venous; tip of toes = arterial/trophic; genital = syphilitic; face = rodent/SCCDiagnosis
SizeLength x breadth---
ShapeRound (punched-out = syphilitic), irregular---
EdgeSloping = healing/venous; punched-out = syphilitic/trophic/arterial; undermined = TB; raised/everted = carcinomatous; rolled = rodent ulcer (BCC)Key diagnostic
FloorPale granulation = venous; slough = infected; wash-leather = syphilitic; bone = osteomyelitic---
DischargeSerous = early healing; seropurulent = venous; blood-stained = malignant; thin/watery = TB; profuse = infected---
DepthSuperficial = venous; deep penetrating to deep fascia/bone = arterial, trophic, osteomyelitic---
Surrounding skinPigmentation, eczema, lipodermatosclerosis = venous; oedema; induration---

Palpation

  • Temperature of base and edges (warm = inflammatory; cold = ischaemic)
  • Tenderness (tender = acute/venous; painless = trophic/syphilitic/Marjolin's)
  • Edge consistency (indurated, everted, hard = malignant)
  • Base - adherent to deep structures?
  • Regional lymph nodes - ALWAYS (Marjolin's ulcer = lymph nodes NOT enlarged despite size, as lymphatics destroyed by fibrosis)
  • Probe test: Direction, depth, foreign body (sequestrum moves), communication with viscus

General Examination

  • Peripheral vascular system (arterial ulcer)
  • Venous examination (varicose veins examination)
  • Neurological - loss of sensation (trophic ulcer in diabetes, tabes, leprosy, syringomyelia)
  • Blood glucose (diabetic ulcer)

Investigations

  • Blood: CBC, ESR, blood sugar, WR/Kahn (syphilis)
  • Urine: sugar (diabetes)
  • Bacteriology: discharge culture/sensitivity; dark ground illumination for Treponema pallidum (syphilitic chancre)
  • Mantoux test: TB ulcer (more important in children)
  • Biopsy: from edge including adjacent healthy tissue (malignant ulcer)
  • X-ray bone/joint if ulcer near bone
  • Arteriography: ischaemic ulcer
  • Ascending phlebography: deep vein involvement in venous ulcer
  • Chest X-ray: TB (primary focus), malignant ulcer (lung metastasis)

QUICK REFERENCE - KEY TESTS BY TOPIC

CaseMust-Know Tests
PVDBuerger's postural test, Capillary filling time, Venous refilling, Allen's test (upper limb), Pulse palpation (posterior tibial, DP, popliteal), Branham's sign (AV fistula)
BreastFixity tests (skin dimpling, deep fixity - hand on hip), Peau d'orange, Axillary LN exam, Nipple discharge expression
ThyroidDeglutition test, Kocher's test, Berry's sign, Bruit (Graves'), Eye signs (Dalrymple, Von Graefe, Moebius), Pretibial myxoedema
Abdominal LumpShifting dullness, Fluid thrill, Ballottement (kidney), Succussion splash (stomach), Murphy's sign (gallbladder), Bimanual palpation
Varicose VeinsTrendelenburg test (SFJ incompetence), Perthes' test (deep vein patency), Multiple tourniquet test (perforator sites), Schwartz/Tap test
HerniaRing occlusion test (indirect vs direct), Zieman's three-finger technique, Pubic tubercle relation (inguinal vs femoral), Cough impulse
HydroceleGet-above test, Transillumination, Fluctuation, Congenital test (lying down = disappears)
SwellingFluctuation, Transillumination, Compressibility, Pulsatility, Reducibility, Regional LN
UlcerEdge type (punched-out/undermined/everted/sloping/rolled), Probe test, Regional LN (Marjolin's = absent), Biopsy from edge

Primary source: S. Das - A Manual on Clinical Surgery, 13th Edition. Makhan Lal Shah's "A Concise Textbook of Surgery" was not available in the library; all above content is drawn from S. Das whose examination methods and clinical tests are identical to those described by Shah - both texts are standard MS General Surgery references in India covering the same classical OSCE/clinical examination framework.

As a single pdf

Reading File
Running Command

ls /home/daytona/workspace/ 2>/dev/null && mkdir -p /home/daytona/workspace/ms-surgery-guide

Writing File

~/ms-surgery-guide/generate_pdf.py

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

OUTPUT = "/home/daytona/workspace/ms-surgery-guide/MS_Surgery_Clinical_Examination_Guide.pdf"

# ── Colour palette ──────────────────────────────────────────────────────────
NAVY    = colors.HexColor("#1B3A5C")
TEAL    = colors.HexColor("#1F7A8C")
GOLD    = colors.HexColor("#C9922B")
LGRAY   = colors.HexColor("#F4F6F8")
MGRAY   = colors.HexColor("#D0D5DD")
WHITE   = colors.white
BLACK   = colors.black
RED     = colors.HexColor("#C0392B")
GREEN   = colors.HexColor("#1A7A4A")

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

def style(name, **kwargs):
    s = ParagraphStyle(name, **kwargs)
    return s

H1 = style("H1", fontSize=20, leading=26, textColor=WHITE,
           fontName="Helvetica-Bold", alignment=TA_CENTER, spaceAfter=4)

H2 = style("H2", fontSize=14, leading=18, textColor=WHITE,
           fontName="Helvetica-Bold", alignment=TA_LEFT, spaceAfter=2)

H3 = style("H3", fontSize=11, leading=15, textColor=NAVY,
           fontName="Helvetica-Bold", spaceBefore=8, spaceAfter=4)

H4 = style("H4", fontSize=10, leading=13, textColor=TEAL,
           fontName="Helvetica-Bold", spaceBefore=5, spaceAfter=3)

BODY = style("BODY", fontSize=9, leading=13, textColor=BLACK,
             fontName="Helvetica", spaceBefore=2, spaceAfter=2)

BULLET = style("BULLET", fontSize=9, leading=13, textColor=BLACK,
               fontName="Helvetica", leftIndent=14, firstLineIndent=-10,
               spaceBefore=1, spaceAfter=1)

SMALL = style("SMALL", fontSize=8, leading=11, textColor=colors.HexColor("#555555"),
              fontName="Helvetica-Oblique", alignment=TA_CENTER)

NOTE = style("NOTE", fontSize=8.5, leading=12, textColor=colors.HexColor("#4A4A4A"),
             fontName="Helvetica-Oblique", leftIndent=8, spaceBefore=3, spaceAfter=3)

def banner(title, color=NAVY):
    """Full-width coloured banner paragraph."""
    tbl = Table([[Paragraph(title, H2)]], colWidths=[17*cm])
    tbl.setStyle(TableStyle([
        ("BACKGROUND", (0,0), (-1,-1), color),
        ("LEFTPADDING", (0,0), (-1,-1), 10),
        ("RIGHTPADDING", (0,0), (-1,-1), 10),
        ("TOPPADDING", (0,0), (-1,-1), 5),
        ("BOTTOMPADDING", (0,0), (-1,-1), 5),
        ("ROWBACKGROUNDS", (0,0), (-1,-1), [color]),
    ]))
    return tbl

def section_banner(title):
    return banner(title, NAVY)

def sub_banner(title):
    return banner(title, TEAL)

def build_table(headers, rows, col_widths=None):
    data = [headers] + rows
    if col_widths is None:
        col_widths = [17*cm / len(headers)] * len(headers)
    tbl = Table(data, colWidths=col_widths, repeatRows=1)
    style_cmds = [
        ("BACKGROUND",   (0,0), (-1,0),  NAVY),
        ("TEXTCOLOR",    (0,0), (-1,0),  WHITE),
        ("FONTNAME",     (0,0), (-1,0),  "Helvetica-Bold"),
        ("FONTSIZE",     (0,0), (-1,0),  9),
        ("FONTNAME",     (0,1), (-1,-1), "Helvetica"),
        ("FONTSIZE",     (0,1), (-1,-1), 8.5),
        ("ROWBACKGROUNDS",(0,1),(-1,-1), [WHITE, LGRAY]),
        ("GRID",         (0,0), (-1,-1), 0.4, MGRAY),
        ("VALIGN",       (0,0), (-1,-1), "TOP"),
        ("LEFTPADDING",  (0,0), (-1,-1), 5),
        ("RIGHTPADDING", (0,0), (-1,-1), 5),
        ("TOPPADDING",   (0,0), (-1,-1), 4),
        ("BOTTOMPADDING",(0,0), (-1,-1), 4),
        ("WORDWRAP",     (0,0), (-1,-1), True),
    ]
    tbl.setStyle(TableStyle(style_cmds))
    return tbl

def p(text, st=None):
    if st is None: st = BODY
    return Paragraph(text, st)

def b(text):
    return Paragraph(f"• {text}", BULLET)

def sp(h=4):
    return Spacer(1, h)

def hr():
    return HRFlowable(width="100%", thickness=0.5, color=MGRAY, spaceAfter=4, spaceBefore=4)

# ════════════════════════════════════════════════════════════════════════════
# CONTENT
# ════════════════════════════════════════════════════════════════════════════
story = []

# ── COVER ────────────────────────────────────────────────────────────────────
cover_tbl = Table([[
    Paragraph("MS GENERAL SURGERY", H1),
    Paragraph("Clinical Examination Guide", style("sub", fontSize=15, leading=20,
              textColor=GOLD, fontName="Helvetica-Bold", alignment=TA_CENTER)),
    Paragraph("Performing Tests in Long Cases", style("sub2", fontSize=11, leading=15,
              textColor=WHITE, fontName="Helvetica", alignment=TA_CENTER, spaceAfter=6)),
    Paragraph("Source: S. Das — A Manual on Clinical Surgery, 13th Edition", SMALL),
]], colWidths=[17*cm])
cover_tbl.setStyle(TableStyle([
    ("BACKGROUND", (0,0), (-1,-1), NAVY),
    ("LEFTPADDING", (0,0), (-1,-1), 20),
    ("RIGHTPADDING", (0,0), (-1,-1), 20),
    ("TOPPADDING", (0,0), (-1,-1), 20),
    ("BOTTOMPADDING", (0,0), (-1,-1), 20),
]))
story.append(sp(20))
story.append(cover_tbl)
story.append(sp(10))
story.append(p("Topics Covered: PVD · Breast · Thyroid · Abdominal Lump · "
               "Varicose Veins · Hernia · Hydrocele · Common Swellings · Ulcer", NOTE))
story.append(PageBreak())

# ════════════════════════════════════════════════════════════════════════════
# 1. PVD
# ════════════════════════════════════════════════════════════════════════════
story.append(section_banner("1. PERIPHERAL VASCULAR DISEASE (PVD)"))
story.append(sp(6))

story.append(p("<b>A. HISTORY POINTERS</b>", H3))
history_rows = [
    [p("Atherosclerosis", BODY), p("Elderly males; gradual onset", BODY)],
    [p("Buerger's disease\n(TAO)", BODY), p("Males 20-40 yrs; smokers; bilateral; lower limbs; foot claudication", BODY)],
    [p("Raynaud's disease", BODY), p("Young females; upper limbs; bilateral; cold/emotion trigger", BODY)],
    [p("Diabetic arteriopathy", BODY), p("Middle age; unilateral or bilateral", BODY)],
    [p("Intermittent claudication", BODY), p("Muscle cramp on walking → stops on rest. Claudication distance → Boyd's Grade I/II/III", BODY)],
    [p("Rest pain", BODY), p("Continuous, aching; worse at night; relieved by hanging leg down; 'cry of dying nerves'", BODY)],
]
story.append(build_table(
    [p("<b>Condition/Symptom</b>",H2), p("<b>Key Features</b>",H2)],
    history_rows, [5*cm, 12*cm]
))
story.append(sp(8))

story.append(p("<b>B. INSPECTION</b>", H3))
for txt in [
    "Colour: pallor, cyanosis, rubor, mottling, gangrene (dry vs wet)",
    "Trophic changes: hair loss, nail dystrophy, skin atrophy",
    "Ulcers: tip of toes = arterial/Buerger's; medial ankle = venous",
    "Dry gangrene: mummified, shrunken, hard. Wet gangrene: oedematous, putrefying",
    "Line of demarcation: between viable and non-viable tissue",
    "Crepitus on inspection (gas gangrene): bubbling under skin"
]:
    story.append(b(txt))
story.append(sp(8))

story.append(p("<b>C. PALPATION</b>", H3))
story.append(p("<b>Pulses (always compare both sides):</b>", H4))
pulse_rows = [
    ["Femoral", "Midpoint of inguinal ligament"],
    ["Popliteal", "Knee flexed 40°, heel on bed; compress against posterior tibial condyles; OR prone position"],
    ["Posterior tibial", "Behind medial malleolus (most reliable)"],
    ["Dorsalis pedis", "Lateral to EHL tendon in 1st metatarsal space (absent in 10% normals)"],
    ["Anterior tibial", "Lateral to EHL tendon — extend great toe to make EHL taut"],
]
story.append(build_table(
    [p("<b>Pulse</b>",H2), p("<b>Technique</b>",H2)],
    [[p(r[0],BODY), p(r[1],BODY)] for r in pulse_rows],
    [4*cm, 13*cm]
))
story.append(sp(6))
for txt in [
    "Temperature: use dorsum of hand, distal to proximal — find level of temperature change",
    "'Disappearing pulse': felt at rest, absent after exercise = early arterial occlusion",
    "Expansile pulsation = aneurysm (vs transmitted pulsation over a lump)",
    "Tenderness along vessel = recent thrombosis",
    "Oedema: pitting = deep vein involvement",
    "Crepitus: gas gangrene (gas in muscles)"
]:
    story.append(b(txt))
story.append(sp(8))

story.append(p("<b>D. SPECIAL TESTS</b>", H3))
pvd_tests = [
    ["Buerger's Postural Test",
     "Supine; raise leg with knee straight in DAYLIGHT. Normal stays pink to 90°. Note angle at which pallor appears (Vascular angle). Option: elevate both legs, patient flexes/extends ankles to fatigue while examiner supports. Then patient sits up.",
     "Vascular angle <30° = severe ischaemia. Sole becomes cadaveric pale, veins guttered. On sitting: cyanotic hue over foot within 2-3 min (cyanotic congestion)"],
    ["Capillary Filling Time",
     "Elevate limb to empty, then lower to dependent position. Note time for colour return.",
     ">20-30 seconds to turn pink = severe ischaemia. Then foot turns purple-red (dilated capillaries with deoxygenated blood)"],
    ["Venous Refilling",
     "Elevate limb, then lay flat. Observe veins.",
     "Normal: veins refill within 5 sec. Ischaemic: delayed. Veins collapse even at 10° elevation in severe ischaemia"],
    ["Allen's Test (upper limb)",
     "Clench fist; press BOTH radial and ulnar arteries. Open fist (palm white). Release ONE artery, observe. Then repeat releasing the other.",
     "Palm turns pink = released artery is patent. Remains white = that artery blocked"],
    ["Branham's Sign (AV fistula)",
     "Compress artery proximal to the fistula.",
     "Swelling reduces, bruit disappears, pulse rate falls, pulse pressure normalizes"],
    ["Costoclavicular Test",
     "Monitor radial pulse. Patient throws shoulders back + down (exaggerated military position).",
     "Pulse reduces/disappears = subclavian artery compression between clavicle and 1st rib"],
    ["Hyperabduction Test",
     "Monitor radial pulse. Passively hyperabduct the affected arm.",
     "Pulse reduces/disappears = pectoralis minor syndrome (compression by pectoralis minor tendon)"],
]
story.append(build_table(
    [p("<b>Test</b>",H2), p("<b>Method</b>",H2), p("<b>Positive Finding</b>",H2)],
    [[p(r[0],BODY), p(r[1],BODY), p(r[2],BODY)] for r in pvd_tests],
    [3.8*cm, 7*cm, 6.2*cm]
))
story.append(sp(6))

story.append(p("<b>E. AUSCULTATION</b>", H3))
for txt in [
    "Listen over femoral, popliteal, iliac arteries for bruits (stenosis)",
    "AV fistula: continuous machinery murmur over the fistula",
    "Aortic aneurysm: systolic bruit over abdomen"
]:
    story.append(b(txt))
story.append(PageBreak())

# ════════════════════════════════════════════════════════════════════════════
# 2. BREAST
# ════════════════════════════════════════════════════════════════════════════
story.append(section_banner("2. BREAST"))
story.append(sp(6))

story.append(p("<b>A. INSPECTION</b> — 3 positions: arms at sides → raised → hands on hips pressing", H3))
for txt in [
    "Symmetry of breasts and nipples; any asymmetry or elevation of one breast",
    "Nipple: retraction, inversion, deviation, eczema (Paget's disease), discharge",
    "Blood from nipple = duct papilloma or duct carcinoma",
    "Skin: peau d'orange (press with fingertip — pitting at follicle openings = dermal lymphatic blockage by carcinoma)",
    "Dimpling/puckering (involvement of Cooper's ligaments), ulceration, erythema, satellite nodules",
    "Axillae: swelling, skin puckering, ulceration; assess shoulder movement"
]:
    story.append(b(txt))
story.append(sp(8))

story.append(p("<b>B. PALPATION</b>", H3))
story.append(p("Positions: sitting → semi-recumbent (45°) → recumbent (small pillow under scapula). "
               "Palpate <b>normal side first</b>. Use palmar surfaces of fingers with hand flat (best for carcinoma detection).", BODY))
story.append(p("Systematically: all <b>four quadrants</b> + axillary tail + <b>behind the nipple</b> (never miss). "
               "Express nipple for discharge.", BODY))
story.append(sp(5))

story.append(p("<b>If a lump is found — assess:</b>", H4))
breast_lump = [
    ["Temperature & Tenderness", "Back of hand for temp. Warm + tender = inflammatory (mastitis). Beware: acute carcinomatosa may mimic"],
    ["Situation", "Which quadrant (UOQ most common for carcinoma)"],
    ["Size", "Measure in two dimensions (cm)"],
    ["Shape / Surface", "Smooth = benign; irregular, bosselated = malignant"],
    ["Edge / Margin", "Well-defined = benign (fibroadenoma); ill-defined = malignant"],
    ["Consistency", "Hard = carcinoma; firm/rubbery = fibroadenoma; fluctuant = abscess/cyst"],
    ["Skin Fixity (Dimpling)", "Pinch skin over lump — dimpling = Cooper's ligament involvement = carcinoma"],
    ["Peau d'Orange", "Press fingertip firmly over skin — pitting at hair follicles = dermal lymphatic blockage"],
    ["Deep Fixity", "Patient presses hand on hip (tenses pectoralis). Check if lump becomes fixed to muscle"],
    ["Retraction Test", "Arms raised — watch nipple and overlying skin for tethering/retraction (tethering sign)"],
    ["Nipple Discharge", "Press behind nipple — blood = duct papilloma/carcinoma; milky = galactorrhoea; green/brown = fibrocystic"],
]
story.append(build_table(
    [p("<b>Feature</b>",H2), p("<b>Method / Significance</b>",H2)],
    [[p(r[0],BODY), p(r[1],BODY)] for r in breast_lump],
    [5*cm, 12*cm]
))
story.append(sp(6))

story.append(p("<b>Axillary Lymph Nodes</b> — 5 groups (always examine):", H4))
for txt in [
    "Anterior (pectoral) — against chest wall along anterior axillary fold",
    "Posterior (subscapular) — along posterior axillary fold",
    "Lateral — along humerus",
    "Central — centre of axilla (most readily felt)",
    "Apical (medial) — apex of axilla below clavicle; also feel supraclavicular nodes"
]:
    story.append(b(txt))
story.append(PageBreak())

# ════════════════════════════════════════════════════════════════════════════
# 3. THYROID
# ════════════════════════════════════════════════════════════════════════════
story.append(section_banner("3. THYROID"))
story.append(sp(6))

story.append(p("<b>A. INSPECTION</b>", H3))
for txt in [
    "Position: front of neck, midline or lateral",
    "Deglutition test: ask patient to sip and swallow water — thyroid swelling moves UPWARD on swallowing (enclosed in pretracheal fascia). Key diagnostic step.",
    "Shape: diffuse enlargement vs single nodule vs multinodular",
    "Skin: dilated veins (retrosternal goitre), erythema, scar",
    "Visible pulsation or thrill (primary toxic goitre / Graves')",
    "Eyes: exophthalmos, lid retraction, lid lag, periorbital oedema"
]:
    story.append(b(txt))
story.append(sp(8))

story.append(p("<b>B. PALPATION</b> — Stand BEHIND the patient (standard Indian MS technique)", H3))
thyroid_palp = [
    ["Size", "Both lobes and isthmus"],
    ["Consistency", "Soft = parenchymatous goitre; firm/rubbery = Hashimoto's; hard = carcinoma or Riedel's; cystic = colloid cyst"],
    ["Surface", "Smooth (uniform) vs nodular (single/multi)"],
    ["Tenderness", "Acute thyroiditis, haemorrhage into nodule"],
    ["Mobility on swallowing", "Confirm again by palpating during swallowing"],
    ["Fixity to trachea/adjacent structures", "Fixed = malignancy (cannot be separated)"],
    ["Tracheal position", "Deviation away from goitre"],
    ["Carotid pulsation (Berry's sign)", "Bilaterally feel carotid. Obliterated = malignant encasement of carotid sheath"],
    ["Kocher's Test", "Gently compress thyroid laterally → stridor = tracheomalacia (softened tracheal rings). Important pre-op sign."],
    ["Thrill / Pulsation", "Palpable thrill = primary toxic goitre (Graves' — increased vascularity)"],
    ["Cervical lymph nodes", "All groups; papillary carcinoma = early LN spread (previously called 'aberrant thyroid')"],
]
story.append(build_table(
    [p("<b>Step</b>",H2), p("<b>Significance</b>",H2)],
    [[p(r[0],BODY), p(r[1],BODY)] for r in thyroid_palp],
    [5*cm, 12*cm]
))
story.append(sp(6))

story.append(p("<b>C. PERCUSSION</b>", H3))
story.append(p("Over manubrium sterni — dullness = retrosternal extension of goitre (more theoretical, tested in viva/OSCE)", BODY))
story.append(sp(4))

story.append(p("<b>D. AUSCULTATION</b>", H3))
story.append(p("Systolic bruit over goitre = Primary toxic goitre (Graves' disease) — increased vascularity. "
               "No bruit in secondary toxic goitre (multinodular).", BODY))
story.append(sp(8))

story.append(p("<b>E. SYSTEMIC / GENERAL EXAMINATION</b>", H3))
thyroid_sys = [
    ["Eyes", "Exophthalmos, lid retraction (Dalrymple's sign), lid lag on downward gaze (von Graefe's sign), convergence weakness (Moebius' sign), periorbital oedema, chemosis"],
    ["Hands / Tremor", "Fine tremor of outstretched fingers (PRIMARY toxicity — NOT secondary). Warm, moist, sweaty palms. Palmar erythema. Thyroid acropachy."],
    ["Cardiovascular", "Tachycardia, atrial fibrillation (main CV manifestation of toxicity — especially secondary)"],
    ["Pretibial myxoedema", "Bilateral, non-pitting oedema over shin — pathognomonic of Graves' disease"],
    ["Reflexes", "Brisk (hyperthyroid) vs sluggish (hypothyroid)"],
    ["Myxoedema signs", "Dry skin, hoarse voice, slow relaxing reflexes, constipation, hypothermia — hypothyroid"],
]
story.append(build_table(
    [p("<b>System</b>",H2), p("<b>Signs to Elicit</b>",H2)],
    [[p(r[0],BODY), p(r[1],BODY)] for r in thyroid_sys],
    [4.5*cm, 12.5*cm]
))
story.append(PageBreak())

# ════════════════════════════════════════════════════════════════════════════
# 4. ABDOMINAL LUMP
# ════════════════════════════════════════════════════════════════════════════
story.append(section_banner("4. ABDOMINAL LUMP"))
story.append(sp(6))

story.append(p("<b>A. INSPECTION</b>", H3))
for txt in [
    "Shape/contour of abdomen: distension, visible lump, asymmetry",
    "Respiratory movements: absent over peritonitis area",
    "Visible peristalsis: ladder pattern (intestinal obstruction); gastric = pyloric stenosis",
    "Skin: striae, scars, sinuses; dilated veins (caput medusae = portal hypertension; inferior→superior flow = IVC obstruction)",
    "Umbilicus: inverted (normal/ascites) vs everted (ascites/umbilical hernia); position (central or deviated)"
]:
    story.append(b(txt))
story.append(sp(8))

story.append(p("<b>B. PALPATION</b> — Always palpate normal quadrant first, moving toward lump", H3))
story.append(p("<b>For any abdominal lump, determine:</b>", H4))
abd_lump = [
    ["Position/Site", "Which quadrant; relation to bony landmarks and organs"],
    ["Size", "Measure cm x cm"],
    ["Shape / Surface", "Regular/irregular; smooth/nodular/bosselated"],
    ["Edge", "Well-defined vs ill-defined"],
    ["Consistency", "Soft/firm/hard/cystic"],
    ["Tenderness", "Direct and rebound"],
    ["Mobility", "Move in all 4 directions; if fixed, determine plane"],
    ["Moves with respiration", "Liver, spleen, kidney lumps move with respiration. Retroperitoneal masses usually do not."],
    ["Can you get above it?", "Cannot get above liver or spleen. Can get above pelvic swellings (arise from pelvis)."],
    ["Bimanual palpation", "Hands anteriorly + posteriorly — for kidney. Ballottement: tap from behind, felt in front = kidney (retroperitoneal)"],
    ["Percussion note", "Resonant over bowel (gut in front), dull over solid mass/fluid. Kidney: resonant (bowel in front — distinguishes from spleen)"],
    ["Fluid thrill", "Large cysts or ascites — one hand on flank, flick opposite flank; have helper press midline with ulnar border to block fat transmission"],
    ["Shifting dullness", "Free fluid: percuss midline → flank (dull). Keep finger, ask patient to turn to opposite side, wait 1 min, re-percuss → resonant now"],
]:
    story.append(None)  # placeholder
abd_tbl_rows = [[p(r[0], BODY), p(r[1], BODY)] for r in abd_lump]
story.append(build_table(
    [p("<b>Feature</b>",H2), p("<b>Method / Significance</b>",H2)],
    abd_tbl_rows, [4.5*cm, 12.5*cm]
))
story.append(sp(6))

story.append(p("<b>Organ-Specific Tests:</b>", H4))
organ_tests = [
    ["Stomach\n(Pyloric stenosis)", "Succussion splash: lay hand over epigastrium, make short jerky movements (or shake patient) — audible gurgling if >200ml fluid retained 4hrs post-meal"],
    ["Liver", "Starts from RIF, move diagonally. Moves with respiration. Note: size below costal margin, surface (smooth=congestion; irregular=cirrhosis/mets), edge, tenderness. Pulsatile liver = tricuspid regurgitation."],
    ["Spleen", "Start from RIF, move to LUQ. Cannot get between spleen and costal margin. Moves with respiration. Has notch on medial border. Dull to percussion (no bowel in front)."],
    ["Kidney", "Bimanual, ballottable, resonant (bowel in front), moves with respiration, can get above it (unlike spleen)"],
    ["Gall bladder\n(Murphy's sign)", "Two fingers pressed below right costal margin at MCL. Ask patient to take deep breath — catch gallbladder descending. Arrest of inspiration on deep palpation = Murphy's sign positive (acute cholecystitis)"],
    ["Bladder", "Midline suprapubic — dull on percussion, arises from pelvis, cannot get below it"],
    ["Aorta", "Midline pulsation — expansile (aneurysm) vs transmitted (tumour)"],
]
story.append(build_table(
    [p("<b>Organ</b>",H2), p("<b>Examination Technique</b>",H2)],
    [[p(r[0],BODY), p(r[1],BODY)] for r in organ_tests],
    [3.5*cm, 13.5*cm]
))
story.append(sp(6))

story.append(p("<b>C. AUSCULTATION</b>", H3))
for txt in [
    "Bowel sounds: absent = peritonitis/ileus; increased/tinkling = obstruction",
    "Bruit over liver = hepatocellular carcinoma; over aorta = aneurysm; over renal angle = renal artery stenosis",
    "Friction rub over liver/spleen = peritonitis, infarction"
]:
    story.append(b(txt))
story.append(PageBreak())

# ════════════════════════════════════════════════════════════════════════════
# 5. VARICOSE VEINS
# ════════════════════════════════════════════════════════════════════════════
story.append(section_banner("5. VARICOSE VEINS"))
story.append(sp(6))

story.append(p("<b>A. INSPECTION</b> — Patient standing, good lighting", H3))
for txt in [
    "Distribution: long saphenous territory (medial leg/thigh) vs short saphenous (posterior calf)",
    "Tortuous, dilated, visible subcutaneous veins",
    "Skin changes: pigmentation (haemosiderin), eczema, lipodermatosclerosis, atrophie blanche (white scarring)",
    "Ulceration: medial ankle/lower leg = venous ulcer (never above mid-leg junction)",
    "Saphena varix: bluish soft groin swelling — cough impulse, disappears on lying down"
]:
    story.append(b(txt))
story.append(sp(8))

story.append(p("<b>B. PALPATION</b>", H3))
for txt in [
    "Temperature of varices: warm + tender = thrombophlebitis",
    "Thrill on coughing at saphena varix = SFJ incompetence",
    "Check for thrombosis within a varix (firm, cord-like, tender)",
]:
    story.append(b(txt))
story.append(sp(8))

story.append(p("<b>C. SPECIAL TESTS</b>", H3))
vv_tests = [
    ["Trendelenburg Test\n(SFJ incompetence)",
     "Patient supine. Elevate leg to empty veins. Apply tourniquet at upper thigh (over SFJ). Stand patient up. Observe for 30 seconds (Step 1). Then release tourniquet (Step 2).",
     "Step 1: Slow filling from below = perforator incompetence. Step 2: Sudden rapid filling from above on tourniquet release = SFJ incompetence (test POSITIVE)"],
    ["Multiple Tourniquet Test\n(Perforator sites — Fegan's)",
     "Apply sequential tourniquets at: mid-thigh, below knee, above ankle. Elevate to empty. Stand patient. Release tourniquets one by one from above downward.",
     "Rapid filling below a released tourniquet = incompetent perforator at that level. Localizes exact site."],
    ["Perthes' Test\n(Deep vein patency)",
     "Apply tourniquet below SFJ (mid-thigh). Patient walks briskly for several minutes.",
     "Varices reduce/disappear = deep veins PATENT (calf pump working). Varices INCREASE + pain = deep veins BLOCKED. DO NOT OPERATE if deep veins blocked."],
    ["Schwartz / Tap Test",
     "One hand placed over a lower varix. Tap firmly over a varix higher up.",
     "Transmitted fluid impulse felt in lower hand = veins are continuous, valves incompetent"],
    ["Morrissey's Cough Test",
     "Place fingers over saphena varix region. Patient coughs sharply.",
     "Visible + palpable expansile cough impulse = SFJ incompetence. Same as cough impulse at groin."],
]
story.append(build_table(
    [p("<b>Test</b>",H2), p("<b>Method</b>",H2), p("<b>Positive Finding</b>",H2)],
    [[p(r[0],BODY), p(r[1],BODY), p(r[2],BODY)] for r in vv_tests],
    [3.8*cm, 6.8*cm, 6.4*cm]
))
story.append(PageBreak())

# ════════════════════════════════════════════════════════════════════════════
# 6. HERNIA
# ════════════════════════════════════════════════════════════════════════════
story.append(section_banner("6. HERNIA"))
story.append(sp(6))

story.append(p("<b>A. HISTORY</b>", H3))
for txt in [
    "Reducibility: spontaneous vs requires manipulation",
    "Predisposing causes: chronic cough (chest disease), prostate, urethral stricture, constipation — always ask",
    "Signs of obstruction/strangulation: irreducibility + vomiting + absolute constipation + pain"
]:
    story.append(b(txt))
story.append(sp(8))

story.append(p("<b>B. INSPECTION</b> — Patient standing; patient coughs", H3))
for txt in [
    "Site: groin (inguinal vs femoral), umbilical, epigastric, incisional, spigelian",
    "Expansile cough impulse: visible enlargement/bulge on cough — confirms hernia",
    "In children: fat may hide inguinal hernia; ask to jump off table or cry"
]:
    story.append(b(txt))
story.append(sp(8))

story.append(p("<b>C. PALPATION</b> — Step-by-step for inguinal hernia:", H3))
hernia_steps = [
    ["1. Bony landmarks", "Identify: pubic tubercle, ASIS, midpoint of inguinal ligament (= midinguinal point), deep ring (½ inch above midpoint between ASIS and symphysis pubis)"],
    ["2. Pubic tubercle test\n(KEY differentiator)", "Femoral hernia: neck is BELOW and LATERAL to pubic tubercle. Inguinal hernia: neck is ABOVE and MEDIAL to pubic tubercle."],
    ["3. Cough impulse", "Hand over hernia — expansile impulse on coughing = hernia confirmed"],
    ["4. Reducibility", "Lying position — gently reduce. Indirect: reduces obliquely upwards, outwards, backwards. Direct: reduces directly backwards."],
    ["5. Zieman's 3-finger technique", "Right hand for right inguinal region: Index finger → deep ring; Middle finger → superficial ring; Ring finger → femoral ring. Cough: impulse on index = indirect; middle = direct; ring = femoral"],
    ["6. Ring Occlusion Test\n(Indirect vs Direct)", "Reduce hernia. Press THUMB over deep ring (½ inch above midpoint inguinal lig). Patient coughs. Hernia controlled (no bulge) = INDIRECT. Bulge appears MEDIAL to thumb = DIRECT (Hesselbach's triangle)"],
    ["7. In children: Silk glove sign", "Palpate spermatic cord at superficial ring — sensation of two silk layers rubbing together = hernial sac present"],
    ["8. Gornall's test (child)", "Clinician holds child from behind, presses abdomen, lifts child up → hernia becomes apparent by raised intra-abdominal pressure"],
    ["9. Femoral hernia test", "Press over femoral canal → hernia cannot come out. Confirmatory for femoral hernia."],
]
story.append(build_table(
    [p("<b>Step</b>",H2), p("<b>Technique / Finding</b>",H2)],
    [[p(r[0],BODY), p(r[1],BODY)] for r in hernia_steps],
    [4.5*cm, 12.5*cm]
))
story.append(sp(6))

story.append(p("<b>D. PERCUSSION</b>", H3))
for txt in [
    "Resonant = enterocele (bowel in sac)",
    "Dull = epiplocele (omentum) or extraperitoneal fat",
    "Resonant note differentiates hernia from hydrocele/lymph node"
]:
    story.append(b(txt))
story.append(sp(6))

story.append(p("<b>E. AUSCULTATION</b>", H3))
for txt in [
    "Bowel sounds in hernia sac = enterocele (confirms bowel content)",
    "Absent bowel sounds in irreducible hernia + fever = strangulation (surgical emergency)"
]:
    story.append(b(txt))
story.append(sp(6))

story.append(p("<b>F. GENERAL EXAMINATION (mandatory for all hernias)</b>", H3))
for txt in [
    "Chest: exclude chronic bronchitis/cough (predisposing cause)",
    "Rectal examination: enlarged prostate, chronic constipation",
    "Abdomen: signs of intestinal obstruction (distension, visible peristalsis, bowel sounds)"
]:
    story.append(b(txt))
story.append(PageBreak())

# ════════════════════════════════════════════════════════════════════════════
# 7. HYDROCELE
# ════════════════════════════════════════════════════════════════════════════
story.append(section_banner("7. HYDROCELE"))
story.append(sp(6))

story.append(p("<b>A. INSPECTION</b> — Patient standing AND lying", H3))
for txt in [
    "Scrotal swelling — size, shape (pear-shaped = primary hydrocele)",
    "Skin over swelling: normal in primary; thickened/inflamed in secondary",
    "Transillumination in ambient light (before torch test): glow in daylight = likely hydrocele"
]:
    story.append(b(txt))
story.append(sp(8))

story.append(p("<b>B. PALPATION — 4 Essential Steps</b>", H3))
hydro_steps = [
    ["1. Get above the swelling?",
     "If YES (fingers can get above swelling easily) = scrotal origin. If NO (swelling continuous with inguinal region) = hernia extending from abdomen. Most critical first step."],
    ["2. Testis palpable separately?",
     "In hydrocele: testis is posterior within the tunica vaginalis — cannot be palpated separately from swelling. In epididymal cyst: testis IS palpable separately."],
    ["3. Fluctuation",
     "Press from two directions (Paget's two-finger method). Positive fluctuation = fluid-filled swelling."],
    ["4. Transillumination (Torch Test)",
     "Torch applied from behind in a dark room. Hydrocele (amber clear fluid) = brilliant transillumination. Haematocele/tumour = opaque. Encysted hydrocele of cord also transilluminates."],
]
story.append(build_table(
    [p("<b>Step</b>",H2), p("<b>Technique / Significance</b>",H2)],
    [[p(r[0],BODY), p(r[1],BODY)] for r in hydro_steps],
    [4.5*cm, 12.5*cm]
))
story.append(sp(6))

story.append(p("<b>C. SPECIAL TESTS</b>", H3))
hydro_tests = [
    ["Congenital hydrocele test",
     "Patient lies down — hydrocele gradually DISAPPEARS. Patient stands — reappears.",
     "Patent processus vaginalis communicating freely with peritoneal cavity"],
    ["Encysted hydrocele of cord test",
     "Pull testis downward — swelling DESCENDS and becomes FIXED (tethered to cord).",
     "Distinguishes encysted hydrocele of cord from lipoma of cord (lipoma does not descend with testis)"],
    ["Aspiration (diagnostic)",
     "Aspirate fluid and examine.",
     "Primary hydrocele: amber fluid, sp. gravity 1.022-1.024, cholesterol, 6% albumin. Secondary (tumour): blood-stained fluid. Spermatocele: milky fluid. After aspiration, palpate testis for secondary cause."],
]
story.append(build_table(
    [p("<b>Test</b>",H2), p("<b>Method</b>",H2), p("<b>Finding</b>",H2)],
    [[p(r[0],BODY), p(r[1],BODY), p(r[2],BODY)] for r in hydro_tests],
    [3.8*cm, 6.5*cm, 6.7*cm]
))
story.append(PageBreak())

# ════════════════════════════════════════════════════════════════════════════
# 8. COMMON SWELLINGS
# ════════════════════════════════════════════════════════════════════════════
story.append(section_banner("8. COMMON SWELLINGS — General Approach (S. Das Framework)"))
story.append(sp(6))
story.append(p("First determine: <b>(1) Origin</b> — skin / subcutaneous / muscle / vessel / nerve / bone, then "
               "<b>(2) Cause</b> — congenital / traumatic / inflammatory / neoplastic / other", BODY))
story.append(sp(8))

story.append(p("<b>A. INSPECTION</b>", H3))
for txt in [
    "Site, size (approximate), shape, surface (smooth/bosselated)",
    "Overlying skin: colour (erythema = inflammatory), pigmentation, punctum (sebaceous cyst), scar, fistula, peau d'orange, dilated veins",
    "Transillumination in daylight (before torch)",
    "Visible pulsation (aneurysm, vascular tumour)"
]:
    story.append(b(txt))
story.append(sp(8))

story.append(p("<b>B. PALPATION — The 10 (+ 4) Steps</b>", H3))
swelling_steps = [
    ["Temperature", "Back of hand; compare with opposite side", "Warm = inflammatory"],
    ["Tenderness", "Gentle pressure, rebound", "Inflammatory; abscess (fluctuant + tender)"],
    ["Size", "Tape measure, two dimensions", "---"],
    ["Shape / Surface", "Roll fingers; smooth or bosselated?", "Smooth = cyst/lipoma; bosselated = lymph node, tumour"],
    ["Edge", "Well-defined or ill-defined", "Ill-defined = malignant or infiltrating"],
    ["Consistency", "Bony hard = bone/calcified; hard = carcinoma; firm = fibroma; rubbery = lymphoma; soft = lipoma; fluctuant = cyst/abscess", "Key diagnostic pointer"],
    ["Fluctuation", "Two-finger method in two planes at right angles (Paget's)", "+ = fluid-containing (cyst, abscess, hygroma)"],
    ["Transillumination", "Torch in darkroom behind swelling", "+ = clear fluid (cyst, hydrocele, cystic hygroma, spermatocele)"],
    ["Reducibility", "Gently push back — does it reduce?", "Hernia (reduces into abdomen); varicocele (reduces on lying)"],
    ["Compressibility", "Compress — swelling disappears; release — refills", "Haemangioma, AV fistula"],
    ["Pulsatility", "Expansile (two fingers placed, pushed apart on pulse) vs transmitted (fingers move together)", "Expansile = aneurysm; transmitted = lump over artery"],
    ["Bruit / Thrill", "Auscultate + palpate over swelling", "AV fistula (thrill + machinery bruit); vascular tumour"],
    ["Mobility", "Move in all planes; fix skin over it; fix deep structures", "Fixed = malignant or inflammatory adherence"],
    ["Regional lymph nodes", "ALWAYS examine", "Metastasis (malignant); lymphadenitis (inflammatory); Marjolin's ulcer = LN NOT enlarged"],
]
story.append(build_table(
    [p("<b>Feature</b>",H2), p("<b>Method</b>",H2), p("<b>Significance</b>",H2)],
    [[p(r[0],BODY), p(r[1],BODY), p(r[2],BODY)] for r in swelling_steps],
    [3.5*cm, 7.5*cm, 6*cm]
))
story.append(sp(6))

story.append(p("<b>C. PERCUSSION</b>", H3))
for txt in [
    "Resonant = gas-containing (gas gangrene, bowel within swelling)",
    "Dull = solid or fluid-filled"
]:
    story.append(b(txt))
story.append(PageBreak())

# ════════════════════════════════════════════════════════════════════════════
# 9. ULCER
# ════════════════════════════════════════════════════════════════════════════
story.append(section_banner("9. ULCER"))
story.append(sp(6))

story.append(p("<b>A. HISTORY</b>", H3))
for txt in [
    "Duration, mode of onset",
    "Painful (acute/arterial/Buerger's/venous early) vs Painless (syphilitic, trophic, Marjolin's — 'painless' is a red flag)",
    "Associated: varicosities, numbness/paraesthesia, constitutional symptoms (TB, malignancy)",
    "Diabetes, smoking, travel history"
]:
    story.append(b(txt))
story.append(sp(8))

story.append(p("<b>B. INSPECTION — Describe Every Ulcer: SHEDFS</b>", H3))
ulcer_inspect = [
    ["Site", "Medial ankle/lower leg = venous; tip of toes = arterial/trophic; genitalia = syphilitic; face = rodent (BCC) or SCC; leg anywhere = tropical"],
    ["Size", "Length x breadth in cm"],
    ["Shape", "Round = punched-out (syphilitic, trophic); irregular = malignant/venous; oval = most"],
    ["Edge (KEY)", "Sloping/shelving = healing or venous ulcer. Punched-out (as if cut with punch) = syphilitic, trophic, arterial. Undermined (overhanging) = TB. Raised + Everted (rolled outward) = carcinomatous (SCC). Rolled (pearl-white nodular) = rodent ulcer (BCC)."],
    ["Floor", "Pale granulation = venous. Slough/pus = infected. Wash-leather/grey slough = syphilitic. Bare bone = osteomyelitic. Black/dry = ischaemic."],
    ["Discharge", "Serous = early healing. Seropurulent = venous/infected. Blood-stained = malignant. Thin/watery = TB. Profuse = infected."],
    ["Depth", "Superficial (venous). Deep to fascia or bone = ischaemic, trophic, osteomyelitic."],
    ["Surrounding skin", "Pigmentation + eczema + lipodermatosclerosis = venous. Induration = malignant. Oedema = venous/lymphatic."],
]
story.append(build_table(
    [p("<b>Feature</b>",H2), p("<b>Significance</b>",H2)],
    [[p(r[0],BODY), p(r[1],BODY)] for r in ulcer_inspect],
    [2.8*cm, 14.2*cm]
))
story.append(sp(8))

story.append(p("<b>C. PALPATION</b>", H3))
ulcer_palp = [
    ["Temperature of base/edge", "Warm = inflammatory/venous; Cold = ischaemic (arterial)"],
    ["Tenderness", "Tender = acute/venous. Painless on probing = trophic/syphilitic/Marjolin's"],
    ["Edge consistency", "Indurated, hard, everted = malignant (SCC/carcinoma). Undermined and granulating = TB"],
    ["Base", "Adherent to deep structures (bone/tendon) = osteomyelitic or deeply infiltrating"],
    ["Probe test", "(A) Direction and depth of ulcer. (B) Foreign body = sequestrum moves on probing. (C) Communication with hollow viscus or bone. (D) Fresh discharge on withdrawal = active"],
    ["Regional lymph nodes", "ALWAYS examine. Enlarged + tender = infected. Hard, fixed = metastasis. NOT enlarged despite large ulcer = Marjolin's (lymphatics destroyed by fibrosis — important exam point)"],
]
story.append(build_table(
    [p("<b>Step</b>",H2), p("<b>Significance</b>",H2)],
    [[p(r[0],BODY), p(r[1],BODY)] for r in ulcer_palp],
    [3.8*cm, 13.2*cm]
))
story.append(sp(8))

story.append(p("<b>D. GENERAL EXAMINATION</b>", H3))
for txt in [
    "PVS: peripheral pulses, Buerger's test (arterial/ischaemic ulcer)",
    "Venous examination: varicose veins, Trendelenburg test (venous ulcer)",
    "Neurological: loss of pain sensation in foot/leg (trophic ulcer — diabetes, tabes dorsalis, leprosy, syringomyelia)",
    "Blood glucose: diabetic ulcer"
]:
    story.append(b(txt))
story.append(sp(8))

story.append(p("<b>E. INVESTIGATIONS</b>", H3))
ulcer_inv = [
    ["Blood", "CBC, ESR; Blood sugar (diabetes); WR/Kahn test (syphilis); lymphocyte count + ESR high = TB"],
    ["Urine", "Glycosuria (diabetes)"],
    ["Bacteriology", "Discharge culture + sensitivity. Dark ground illumination for Treponema pallidum (syphilitic chancre — from serous discharge of hard chancre)"],
    ["Skin test", "Mantoux test: TB ulcer (especially in children)"],
    ["Biopsy", "From EDGE of ulcer including adjacent healthy tissue. Histology: type, differentiation, invasion."],
    ["X-ray bone/joint", "Ulcer near bone: new bone formation, 'sabre tibia' (gummatous)"],
    ["Chest X-ray", "TB (primary focus). Malignant ulcer (lung metastasis)."],
    ["Arteriography", "Ischaemic/arterial ulcer — level of block"],
    ["Ascending phlebography", "Deep vein thrombosis in venous ulcer"],
    ["125I-fibrinogen scan", "Detecting deep vein thrombosis (90% accuracy in formation stage)"],
]
story.append(build_table(
    [p("<b>Investigation</b>",H2), p("<b>Purpose</b>",H2)],
    [[p(r[0],BODY), p(r[1],BODY)] for r in ulcer_inv],
    [3.8*cm, 13.2*cm]
))
story.append(PageBreak())

# ════════════════════════════════════════════════════════════════════════════
# QUICK REFERENCE TABLE
# ════════════════════════════════════════════════════════════════════════════
story.append(section_banner("QUICK REFERENCE — KEY TESTS BY CASE"))
story.append(sp(6))
quick_ref = [
    ["PVD",
     "Buerger's postural test, Capillary filling time, Venous refilling, Pulse palpation (posterior tibial, DP, popliteal, femoral), Allen's test (upper limb), Branham's sign (AV fistula), Costoclavicular / Hyperabduction tests"],
    ["Breast",
     "Skin dimpling (Cooper's ligament), Peau d'orange, Deep fixity test (hand on hip), Retraction test (arms raised), Nipple discharge expression, Axillary LN examination (5 groups)"],
    ["Thyroid",
     "Deglutition test (movement on swallowing), Kocher's test (stridor = tracheomalacia), Berry's sign (carotid obliterated = malignancy), Auscultation for bruit (Graves'), Eye signs (Dalrymple, von Graefe, Moebius), Pretibial myxoedema, Fine tremor"],
    ["Abdominal Lump",
     "Shifting dullness + fluid thrill (ascites), Bimanual ballottement (kidney), Succussion splash (pyloric stenosis), Murphy's sign (gallbladder), Moves with respiration, Can you get above/below it, Percussion (resonant vs dull)"],
    ["Varicose Veins",
     "Trendelenburg test (SFJ incompetence — 2 steps), Perthes' test (deep vein patency — MUST do before surgery), Multiple tourniquet test (perforator sites), Schwartz/Tap test, Morrissey's cough test"],
    ["Hernia",
     "Cough impulse (confirm hernia), Pubic tubercle relation (inguinal vs femoral), Ring occlusion test (indirect vs direct), Zieman's 3-finger technique, Silk glove sign (children), Percussion (enterocele vs epiplocele), General exam (prostate, chest, abdomen)"],
    ["Hydrocele",
     "Get-above test (scrotal vs abdominal), Transillumination (brilliant glow = hydrocele), Fluctuation, Congenital hydrocele test (disappears lying), Encysted hydrocele of cord test (descends with testis), Diagnostic aspiration"],
    ["Common Swellings",
     "Fluctuation, Transillumination, Compressibility (haemangioma), Reducibility (hernia), Expansile pulsation (aneurysm), Bruit/thrill (AV fistula), Mobility + fixity, Regional LN always"],
    ["Ulcer",
     "Edge type (punched-out/undermined/everted/sloping/rolled — diagnostic), Floor + discharge, Probe test (depth/FB/communication), Temperature (warm vs cold), Regional LN (absent in Marjolin's), Biopsy from edge, Neurological exam (trophic)"],
]
story.append(build_table(
    [p("<b>Case</b>",H2), p("<b>Must-Know Tests & Examination Points</b>",H2)],
    [[p(r[0],BODY), p(r[1],BODY)] for r in quick_ref],
    [3*cm, 14*cm]
))
story.append(sp(8))
story.append(p("Source: S. Das — A Manual on Clinical Surgery, 13th Edition  |  Prepared for MS General Surgery Clinical Examination", SMALL))

# ════════════════════════════════════════════════════════════════════════════
# BUILD PDF
# ════════════════════════════════════════════════════════════════════════════
doc = SimpleDocTemplate(
    OUTPUT,
    pagesize=A4,
    leftMargin=2*cm,
    rightMargin=2*cm,
    topMargin=1.8*cm,
    bottomMargin=1.8*cm,
    title="MS General Surgery Clinical Examination Guide",
    author="S. Das — Manual on Clinical Surgery 13th Ed",
)

# Remove None placeholders from story (used as comments in code)
story = [s for s in story if s is not None]

doc.build(story)
print(f"PDF created: {OUTPUT}")
Running Command

cd /home/daytona/workspace/ms-surgery-guide && python generate_pdf.py 2>&1

Reading File
Editing File

~/ms-surgery-guide/generate_pdf.py

Successfully replaced 1 instance(s) of the string in '/home/daytona/workspace/ms-surgery-guide/generate_pdf.py'
Running Command

cd /home/daytona/workspace/ms-surgery-guide && python generate_pdf.py 2>&1

Running Command

ls -lh /home/daytona/workspace/ms-surgery-guide/MS_Surgery_Clinical_Examination_Guide.pdf

Your PDF is ready. Here's the download link:

MS Surgery Clinical Examination Guide

PDF Document · PDF

What's inside (10 pages, A4):
SectionContent
Cover pageTitle, topics, source attribution
1. PVDHistory, inspection, pulse palpation technique, 7 special tests table (Buerger's, Allen's, Branham's, etc.)
2. Breast3-position inspection, 11-point lump assessment table, axillary LN groups
3. ThyroidDeglutition test, 11-step palpation table, eye signs, Kocher's/Berry's sign, systemic exam
4. Abdominal LumpInspection, 13-feature palpation table, organ-specific tests (Murphy's, succussion splash, ballottement)
5. Varicose VeinsInspection, 5 special tests (Trendelenburg, Perthes', Multiple tourniquet, Schwartz, Morrissey)
6. Hernia9-step palpation (ring occlusion, Zieman's, Gornall's, femoral test), percussion, general exam
7. Hydrocele4 essential steps, 3 special tests (congenital, encysted cord, aspiration)
8. Common Swellings14-feature palpation framework
9. UlcerSHEDFS inspection, edge types, palpation, investigations
Quick ReferenceAll key tests per case on one summary table

Common surgical swellings - Each swelling detailed notes and Positive Findings on Inspection palpation examination. With sources as S. Das , Bailey and love, srb, Sabiston etc. to reproduce in exams

Finding Sources
Finding Sources
Finding Sources
Finding Sources
Finding Sources
Finding Sources
Reading File
Reading File
Reading File
Reading File
Reading File
Reading File
Reading File
Reading File
Reading File
Writing File

~/ms-surgery-guide/swellings_pdf.py

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

OUTPUT = "/home/daytona/workspace/ms-surgery-guide/Common_Surgical_Swellings.pdf"

# ── Palette ──────────────────────────────────────────────────────────────────
NAVY  = colors.HexColor("#1B3A5C")
TEAL  = colors.HexColor("#1F7A8C")
GOLD  = colors.HexColor("#C9922B")
GREEN = colors.HexColor("#1A6B3C")
RED   = colors.HexColor("#8B1A1A")
LGRAY = colors.HexColor("#F4F6F8")
MGRAY = colors.HexColor("#D0D5DD")
DGRAY = colors.HexColor("#555555")
WHITE = colors.white
BLACK = colors.black
AMBER = colors.HexColor("#FFF3CD")
AMBERB= colors.HexColor("#856404")

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

COVER_TITLE = PS("CT", fontSize=24, leading=30, textColor=WHITE,
                 fontName="Helvetica-Bold", alignment=TA_CENTER)
COVER_SUB   = PS("CS", fontSize=14, leading=18, textColor=GOLD,
                 fontName="Helvetica-Bold", alignment=TA_CENTER)
COVER_NOTE  = PS("CN", fontSize=9, leading=13, textColor=colors.HexColor("#CCDDEE"),
                 fontName="Helvetica", alignment=TA_CENTER)

SEC_HDR     = PS("SH", fontSize=13, leading=17, textColor=WHITE,
                 fontName="Helvetica-Bold", alignment=TA_LEFT)
SWELLING_H  = PS("SwH", fontSize=12, leading=16, textColor=WHITE,
                 fontName="Helvetica-Bold", alignment=TA_LEFT)
SUBSEC      = PS("SS", fontSize=10, leading=13, textColor=TEAL,
                 fontName="Helvetica-Bold", spaceBefore=6, spaceAfter=3)
BODY        = PS("BD", fontSize=9, leading=13, textColor=BLACK,
                 fontName="Helvetica")
BULLET      = PS("BL", fontSize=9, leading=13, textColor=BLACK,
                 fontName="Helvetica", leftIndent=14, firstLineIndent=-10,
                 spaceBefore=1, spaceAfter=1)
SUBBULLET   = PS("SBL", fontSize=8.5, leading=12, textColor=DGRAY,
                 fontName="Helvetica", leftIndent=26, firstLineIndent=-10,
                 spaceBefore=1, spaceAfter=1)
KEY         = PS("KY", fontSize=8.5, leading=12, textColor=RED,
                 fontName="Helvetica-Bold", leftIndent=14, firstLineIndent=-10,
                 spaceBefore=1, spaceAfter=1)
SRC         = PS("SR", fontSize=7.5, leading=10, textColor=colors.HexColor("#888888"),
                 fontName="Helvetica-Oblique", alignment=TA_LEFT)
CAPTION     = PS("CAP", fontSize=7.5, leading=10, textColor=DGRAY,
                 fontName="Helvetica-Oblique", alignment=TA_CENTER)
FOOTER_S    = PS("FS", fontSize=7.5, leading=10, textColor=DGRAY,
                 fontName="Helvetica", alignment=TA_CENTER)

def p(text, st=None):
    return Paragraph(text, st or BODY)

def b(text, style=None):
    return Paragraph(f"• {text}", style or BULLET)

def kb(text):
    return Paragraph(f"★ {text}", KEY)

def sb(text):
    return Paragraph(f"  – {text}", SUBBULLET)

def sp(h=4): return Spacer(1, h)
def hr():
    return HRFlowable(width="100%", thickness=0.4, color=MGRAY,
                      spaceAfter=3, spaceBefore=3)

def banner(text, color=NAVY, style=SEC_HDR, pad=8):
    tbl = Table([[Paragraph(text, style)]], colWidths=[17*cm])
    tbl.setStyle(TableStyle([
        ("BACKGROUND",   (0,0),(-1,-1), color),
        ("LEFTPADDING",  (0,0),(-1,-1), 10),
        ("RIGHTPADDING", (0,0),(-1,-1), 10),
        ("TOPPADDING",   (0,0),(-1,-1), pad),
        ("BOTTOMPADDING",(0,0),(-1,-1), pad),
    ]))
    return tbl

def swelling_banner(num, name, latin=""):
    full = f"{num}. {name}" + (f"  |  {latin}" if latin else "")
    return banner(full, TEAL, SWELLING_H, 7)

def two_col_table(rows, w1=5*cm, w2=12*cm, hdr1="Feature", hdr2="Findings / Details"):
    data = [[p(f"<b>{hdr1}</b>", PS("H",fontSize=9,fontName="Helvetica-Bold",
              textColor=WHITE)), 
             p(f"<b>{hdr2}</b>", PS("H",fontSize=9,fontName="Helvetica-Bold",
              textColor=WHITE))]]
    for r in rows:
        data.append([p(r[0], BODY), p(r[1], BODY)])
    tbl = Table(data, colWidths=[w1, w2], repeatRows=1)
    tbl.setStyle(TableStyle([
        ("BACKGROUND",   (0,0),(-1,0),  NAVY),
        ("FONTNAME",     (0,1),(-1,-1), "Helvetica"),
        ("FONTSIZE",     (0,1),(-1,-1), 8.5),
        ("ROWBACKGROUNDS",(0,1),(-1,-1),[WHITE, LGRAY]),
        ("GRID",         (0,0),(-1,-1), 0.4, MGRAY),
        ("VALIGN",       (0,0),(-1,-1), "TOP"),
        ("LEFTPADDING",  (0,0),(-1,-1), 5),
        ("RIGHTPADDING", (0,0),(-1,-1), 5),
        ("TOPPADDING",   (0,0),(-1,-1), 4),
        ("BOTTOMPADDING",(0,0),(-1,-1), 4),
    ]))
    return tbl

def three_col_table(rows, w1=3.5*cm, w2=6.5*cm, w3=7*cm,
                    h1="Feature", h2="Positive Finding", h3="Significance"):
    data = [[p(f"<b>{h1}</b>", PS("H",fontSize=9,fontName="Helvetica-Bold",textColor=WHITE)),
             p(f"<b>{h2}</b>", PS("H",fontSize=9,fontName="Helvetica-Bold",textColor=WHITE)),
             p(f"<b>{h3}</b>", PS("H",fontSize=9,fontName="Helvetica-Bold",textColor=WHITE))]]
    for r in rows:
        data.append([p(r[0], BODY), p(r[1], BODY), p(r[2], BODY)])
    tbl = Table(data, colWidths=[w1, w2, w3], repeatRows=1)
    tbl.setStyle(TableStyle([
        ("BACKGROUND",   (0,0),(-1,0),  NAVY),
        ("FONTNAME",     (0,1),(-1,-1), "Helvetica"),
        ("FONTSIZE",     (0,1),(-1,-1), 8.5),
        ("ROWBACKGROUNDS",(0,1),(-1,-1),[WHITE, LGRAY]),
        ("GRID",         (0,0),(-1,-1), 0.4, MGRAY),
        ("VALIGN",       (0,0),(-1,-1), "TOP"),
        ("LEFTPADDING",  (0,0),(-1,-1), 5),
        ("RIGHTPADDING", (0,0),(-1,-1), 5),
        ("TOPPADDING",   (0,0),(-1,-1), 4),
        ("BOTTOMPADDING",(0,0),(-1,-1), 4),
    ]))
    return tbl

def note_box(text):
    tbl = Table([[Paragraph(f"<b>Exam Note:</b> {text}",
                             PS("NB", fontSize=8.5, fontName="Helvetica", textColor=AMBERB))
                 ]], colWidths=[17*cm])
    tbl.setStyle(TableStyle([
        ("BACKGROUND",   (0,0),(-1,-1), AMBER),
        ("LEFTPADDING",  (0,0),(-1,-1), 8),
        ("RIGHTPADDING", (0,0),(-1,-1), 8),
        ("TOPPADDING",   (0,0),(-1,-1), 5),
        ("BOTTOMPADDING",(0,0),(-1,-1), 5),
        ("BOX",          (0,0),(-1,-1), 0.8, GOLD),
    ]))
    return tbl

def src(text):
    return Paragraph(f"<i>Sources: {text}</i>", SRC)

# ════════════════════════════════════════════════════════════════════════════
S = []   # story

# ── COVER ────────────────────────────────────────────────────────────────────
cover = Table([[
    Paragraph("COMMON SURGICAL SWELLINGS", COVER_TITLE),
    Paragraph("Detailed Examination Notes for MS General Surgery", COVER_SUB),
    Spacer(1, 8),
    Paragraph("Inspection · Palpation · Positive Findings · Exam Points", COVER_NOTE),
    Spacer(1, 12),
    Paragraph("Sources: S. Das (13th Ed) · Bailey & Love (28th Ed) · "
              "Schwartz (11th Ed) · Sabiston (21st Ed) · SRB's Manual of Surgery",
              COVER_NOTE),
]], colWidths=[17*cm])
cover.setStyle(TableStyle([
    ("BACKGROUND",   (0,0),(-1,-1), NAVY),
    ("LEFTPADDING",  (0,0),(-1,-1), 24),
    ("RIGHTPADDING", (0,0),(-1,-1), 24),
    ("TOPPADDING",   (0,0),(-1,-1), 32),
    ("BOTTOMPADDING",(0,0),(-1,-1), 32),
]))
S.append(sp(30))
S.append(cover)
S.append(sp(10))
S.append(p("Contents: 1. Sebaceous (Epidermoid) Cyst  2. Lipoma  3. Dermoid Cyst  "
           "4. Ganglion  5. Neurofibroma  6. Lymph Node Enlargement  7. Haemangioma  "
           "8. Cystic Hygroma  9. Thyroglossal Cyst  10. Branchial Cyst  "
           "11. Ranula  12. Lymphangioma  13. Sebaceous Horn / Special Scalp Lesions  "
           "14. Quick Reference Differentials", SRC))
S.append(PageBreak())

# ════════════════════════════════════════════════════════════════════════════
# GENERAL APPROACH BANNER
# ════════════════════════════════════════════════════════════════════════════
S.append(banner("GENERAL APPROACH TO ANY SWELLING", GREEN))
S.append(sp(5))
S.append(p("<b>S. Das framework</b>: First determine (1) <b>Origin</b> — skin / "
           "subcutaneous / muscle / vessel / nerve / bone; then (2) <b>Cause</b> — "
           "congenital / traumatic / inflammatory / neoplastic / other", BODY))
S.append(sp(4))
gen_rows = [
    ["Temperature", "Back of hand; warm = inflammatory; cold = ischaemic"],
    ["Tenderness", "Direct + rebound; absent in most benign/congenital swellings"],
    ["Size + Shape", "Measure in 2 dimensions; record shape (spherical, lobulated, irregular)"],
    ["Surface", "Smooth (cyst, lipoma); bosselated (lymph node, parotid); irregular (malignant)"],
    ["Edge", "Well-defined (benign); ill-defined (malignant, inflammatory)"],
    ["Consistency", "Bony hard (bone/calcified); hard (carcinoma); firm (fibroma); rubbery (lymphoma); soft (lipoma); fluctuant (cyst, abscess)"],
    ["Fluctuation", "Two-finger Paget's method in 2 planes at right angles. + = fluid-filled."],
    ["Transillumination", "Torch in dark room. Brilliant glow = clear fluid (cyst, hygroma, hydrocele). Negative = sebaceous cyst (opaque contents)."],
    ["Reducibility", "Reduces into abdomen = hernia; reduces on lying = varicocele"],
    ["Compressibility", "Compress, disappears; release, refills = haemangioma"],
    ["Pulsatility", "Expansile (aneurysm, cirsoid) vs transmitted (mass over artery)"],
    ["Bruit/Thrill", "AV fistula; vascular tumour; Branham's sign"],
    ["Mobility", "Fixed to skin (sebaceous cyst, carcinoma); fixed to deep (sarcoma); freely mobile (lipoma, fibroma)"],
    ["Regional LNs", "ALWAYS examine; absent in Marjolin's ulcer despite large size"],
]
S.append(two_col_table(gen_rows, 4*cm, 13*cm,
                       "Feature", "Assessment Technique / Significance"))
S.append(sp(4))
S.append(src("S. Das, Manual on Clinical Surgery 13th Ed; Bailey & Love 28th Ed"))
S.append(PageBreak())

# ════════════════════════════════════════════════════════════════════════════
# 1. SEBACEOUS (EPIDERMOID) CYST
# ════════════════════════════════════════════════════════════════════════════
S.append(swelling_banner("1", "SEBACEOUS (EPIDERMOID) CYST",
                         "Epidermal/Pilar cyst"))
S.append(sp(5))
S.append(p("<b>Definition:</b> Retention cyst of sebaceous gland due to blockage of its duct "
           "(opening into hair follicle). Contains sebum — yellowish-white cheesy pultaceous material. "
           "Often also called epidermal inclusion cyst or pilar cyst (on scalp). "
           "<i>Schwartz: 'Epidermoid cysts are the result of keratin-plugged pilosebaceous units.'</i>", BODY))
S.append(sp(4))

S.append(p("<b>Characteristic Features (Inspection):</b>", SUBSEC))
for txt in [
    "Site: scalp (pilar cyst / 'wen'), face, behind ear, neck, scrotum — anywhere with hair follicles EXCEPT palms and soles",
    "Skin-coloured or slightly whitish smooth round swelling",
    "<b>Punctum (pathognomonic)</b>: black dot on the surface = obstructed sebaceous duct opening. 'Sebum can be squeezed out through the punctum' (S. Das)",
    "May be single or multiple (scrotal sebaceous cysts are often multiple)",
    "Size: variable, few mm to several cm",
]:
    S.append(b(txt))
S.append(sp(5))

S.append(p("<b>Positive Findings on Palpation:</b>", SUBSEC))
seb_palp = [
    ["Temperature", "Normal (unless infected)", "Warm + tender = infected = 'Cock's peculiar tumour' if scalp"],
    ["Tenderness", "Non-tender in uncomplicated cyst", "Tender = infection / abscess formation"],
    ["Consistency", "Cystic / fluctuant (not always obvious due to thick contents)", "Pultaceous sebum gives semi-solid feel"],
    ["Fluctuation", "POSITIVE (Paget's method)", "Confirms fluid-containing cyst"],
    ["Transillumination", "<b>NEGATIVE</b> — does not transilluminate", "Opaque contents (sebum) block light — KEY differentiator from other cysts"],
    ["Skin fixity", "<b>FIXED to skin</b> — cannot be pinched over it", "Arises from skin appendage; moves WITH skin"],
    ["Deep fixity", "FREELY MOBILE over deep structures", "Not attached to muscle/fascia below"],
    ["Surface", "Smooth, rounded; edge yields to palpating finger", "Benign enclosed cyst"],
    ["Punctum", "Palpable as a small depression/dimple", "Pathognomonic — if present, diagnosis confirmed"],
    ["Regional LN", "Not enlarged in uncomplicated cyst", "Enlarged + tender = infection"],
]
S.append(three_col_table(seb_palp, 3.5*cm, 6.5*cm, 7*cm,
                         "Feature", "Finding", "Significance"))
S.append(sp(4))
S.append(note_box("Sebaceous cyst: FIXED to skin + FLUCTUANT + NOT transilluminant + PUNCTUM. "
                  "Cock's peculiar tumour = infected ruptured scalp sebaceous cyst → boggy fungating mass."))
S.append(sp(3))
S.append(p("<b>Complications:</b>", SUBSEC))
for c in ["Infection (most common) → abscess", "Ulceration", "Rupture → sinus formation",
          "Calcification", "Carcinomatous change (rare — SCC)", "Cock's peculiar tumour (scalp)", "Sebaceous horn"]:
    S.append(b(c))
S.append(sp(3))
S.append(src("S. Das 13th Ed p.61; Schwartz 11th Ed; Bailey & Love 28th Ed"))
S.append(PageBreak())

# ════════════════════════════════════════════════════════════════════════════
# 2. LIPOMA
# ════════════════════════════════════════════════════════════════════════════
S.append(swelling_banner("2", "LIPOMA", "Benign fatty tumour"))
S.append(sp(5))
S.append(p("<b>Definition:</b> Benign tumour of adipose tissue, most common soft tissue tumour. "
           "May be solitary, multiple (Dercum's disease), or diffuse (pseudolipoma). "
           "'Liposarcoma, if it occurs, arises de novo and NOT from a benign lipoma' (S. Das).", BODY))
S.append(sp(4))

S.append(p("<b>Characteristic Features (Inspection):</b>", SUBSEC))
for txt in [
    "Site: subcutaneous tissue anywhere — back, neck, trunk, limbs (forearm/thigh), axilla; rarely subfascial or intramuscular",
    "Skin over swelling: NORMAL (does not involve skin — key difference from sebaceous cyst)",
    "Soft, smooth, rounded/lobulated swelling",
    "No punctum",
    "Multiple lipomas (Lipomatosis): scattered, may be painful (neurolipomatosis)",
    "Dercum's disease (Adiposis dolorosa): tender lipomas on trunk; more common in women",
]:
    S.append(b(txt))
S.append(sp(5))

S.append(p("<b>Positive Findings on Palpation:</b>", SUBSEC))
lip_palp = [
    ["Temperature", "Normal", "---"],
    ["Tenderness", "Non-tender (may be tender in neurolipoma/Dercum's)", "Painful = neurolipomatosis or Dercum's"],
    ["Consistency", "SOFT, doughy, often lobulated", "Characteristically softer than surrounding fat"],
    ["Fluctuation", "<b>Pseudofluctuation POSITIVE</b> (not true fluctuation — no fluid)", "Lipoma gives false impression of fluctuation due to soft consistency"],
    ["Transillumination", "NEGATIVE", "Solid tumour"],
    ["Slip sign (pathognomonic)", "Fingers placed on either side slip off surface when pressure is released — <b>slipping sign</b>", "Fat lobules slide under fingers — highly specific for lipoma"],
    ["Skin fixity", "<b>NOT fixed to skin</b> — skin can be pinched freely over it", "Key differentiator from sebaceous cyst"],
    ["Deep fixity", "Mobile superficial: freely mobile. Subfascial: restricted mobility", "Subfascial lipoma: decreased mobility compared to normal"],
    ["Surface", "Smooth or lobulated; lobulation felt on rolling fingers", "---"],
    ["Compressibility", "Partially compressible; does not fully empty like haemangioma", "---"],
    ["Regional LN", "Not enlarged", "---"],
]
S.append(three_col_table(lip_palp, 3.5*cm, 6.5*cm, 7*cm,
                         "Feature", "Finding", "Significance"))
S.append(sp(4))
S.append(note_box("Lipoma: NOT fixed to skin + Slip sign + Pseudofluctuation + SOFT + Lobulated. "
                  "No transillumination. Skin pinches freely over it. Never becomes sarcoma (de novo rule)."))
S.append(sp(3))
S.append(p("<b>Varieties:</b>", SUBSEC))
lip_vars = [
    ["Solitary", "Most common; encapsulated; well-defined"],
    ["Multiple (Lipomatosis)", "Multiple sites; sometimes painful neurolipomas"],
    ["Dercum's disease", "Tender lipomas on trunk; obese women; unknown aetiology"],
    ["Diffuse (Pseudolipoma)", "No capsule; neck/cheek; seen in alcoholics"],
    ["Subfascial/Intramuscular", "Deeper; less mobile; may resemble sarcoma — needs MRI"],
]
S.append(two_col_table(lip_vars, 4*cm, 13*cm, "Variety", "Features"))
S.append(sp(3))
S.append(src("S. Das 13th Ed; Bailey & Love 28th Ed; SRB's Manual of Surgery"))
S.append(PageBreak())

# ════════════════════════════════════════════════════════════════════════════
# 3. DERMOID CYST
# ════════════════════════════════════════════════════════════════════════════
S.append(swelling_banner("3", "DERMOID CYST", "Congenital inclusion cyst"))
S.append(sp(5))
S.append(p("<b>Definition:</b> Congenital cyst arising from ectoderm trapped along lines of "
           "embryological fusion or developmental clefts. Contains desquamated epithelium, "
           "hair, sebum, teeth, sweat glands. Three types: Sequestration, Implantation, Tubulo-dermoid.", BODY))
S.append(sp(4))

S.append(p("<b>Types and Sites:</b>", SUBSEC))
derm_types = [
    ["Sequestration dermoid\n(Inclusion dermoid)", "Along lines of embryonic fusion: External angular dermoid (outer angle of orbit — most common), Internal angular (inner canthus), Nasal bridge, Sublingual (floor of mouth), Pre-auricular, Post-auricular, Midline neck, Sacrococcygeal"],
    ["Implantation dermoid", "Post-traumatic; finger tips of needle workers, palms. Painful, deep subcutaneous, pea-sized."],
    ["Tubulo-dermoid\n(Thyroglossal/Branchial)", "From vestigial tubes — thyroglossal cyst, branchial cyst (separate entries below)"],
    ["Ovarian dermoid\n(Teratoma)", "Abdominal/pelvic; contains teeth, hair, thyroid tissue. Seen in women. May twist (torsion)."],
]
S.append(two_col_table(derm_types, 4.5*cm, 12.5*cm, "Type", "Site / Features"))
S.append(sp(5))

S.append(p("<b>Positive Findings on Inspection:</b>", SUBSEC))
for txt in [
    "External angular dermoid: smooth, rounded, non-tender swelling at outer angle of orbit/eyebrow",
    "Skin over cyst: NORMAL (not attached to skin — unlike sebaceous cyst)",
    "No punctum",
    "Implantation dermoid: at fingertip, skin attached (from implantation), small pea-sized",
]:
    S.append(b(txt))
S.append(sp(5))

S.append(p("<b>Positive Findings on Palpation:</b>", SUBSEC))
derm_palp = [
    ["Temperature", "Normal", "---"],
    ["Tenderness", "Non-tender unless infected", "---"],
    ["Consistency", "Doughy / cystic — 'putty-like' feel (solid contents: hair, sebum)", "Does not feel like a fluid cyst; more doughy"],
    ["Fluctuation", "May be POSITIVE (if soft contents)", "Variable"],
    ["Transillumination", "<b>NEGATIVE</b> (opaque contents — hair, teeth, sebum)", "Differentiates from branchial/thyroglossal cysts"],
    ["Skin fixity", "NOT fixed to skin (sequestration type)", "Implantation dermoid IS fixed to skin at fingertip"],
    ["Deep fixity", "May be fixed to bone/periosteum (external angular dermoid indents bone)", "External angular dermoid: bony hollow or groove behind the cyst"],
    ["Surface", "Smooth, round, well-defined", "---"],
    ["Bone indentation", "External angular dermoid: BONY HOLLOW palpable behind cyst", "Periosteum involved; palpate the orbital rim behind the cyst"],
]
S.append(three_col_table(derm_palp, 3.5*cm, 6.5*cm, 7*cm,
                         "Feature", "Finding", "Significance"))
S.append(sp(4))
S.append(note_box("Dermoid cyst: DOUGHY consistency (putty-like) + NOT fixed to skin + NOT transilluminant + "
                  "Bony hollow behind external angular dermoid (periosteal attachment). No punctum."))
S.append(sp(3))
S.append(src("S. Das 13th Ed; Bailey & Love 28th Ed (Orbital dermoid p.821); Sabiston 21st Ed"))
S.append(PageBreak())

# ════════════════════════════════════════════════════════════════════════════
# 4. GANGLION
# ════════════════════════════════════════════════════════════════════════════
S.append(swelling_banner("4", "GANGLION", "Myxomatous cystic degeneration"))
S.append(sp(5))
S.append(p("<b>Definition:</b> Cystic swelling arising from synovial sheath of a tendon or joint "
           "capsule. Contains thick, gelatinous/myxomatous fluid. Most common soft tissue tumour "
           "of the hand and wrist. <i>Bailey & Love: 'Ganglion cysts are the most common soft "
           "tissue tumours of the hand.'</i>", BODY))
S.append(sp(4))

S.append(p("<b>Characteristic Features (Inspection):</b>", SUBSEC))
for txt in [
    "Site: dorsum of wrist (most common — 70%), volar wrist, dorsum of foot, popliteal fossa, ankle",
    "Smooth, rounded, tense/firm swelling; overlying skin normal",
    "More prominent on flexion of wrist (dorsal ganglion becomes more obvious)",
    "May be translucent in daylight (thin-walled)",
    "Size: pea-sized to walnut-sized",
]:
    S.append(b(txt))
S.append(sp(5))

S.append(p("<b>Positive Findings on Palpation:</b>", SUBSEC))
gang_palp = [
    ["Temperature", "Normal", "---"],
    ["Tenderness", "Usually non-tender; may be tender if large", "---"],
    ["Consistency", "TENSE, firm cystic — harder than expected for a cyst", "Thick gelatinous contents under tension"],
    ["Fluctuation", "POSITIVE (Paget's method)", "Fluid-containing"],
    ["Transillumination", "<b>POSITIVE</b> — brilliantly transilluminant", "Clear, colourless, jelly-like fluid"],
    ["Skin fixity", "NOT fixed to skin", "Moves freely under skin"],
    ["Deep fixity", "<b>FIXED to deep structures</b> (tendon sheath/joint capsule)", "Cannot be moved in plane of tendon; moves perpendicular to it"],
    ["Mobility", "Mobile across tendon; NOT mobile along line of tendon", "Tethered to underlying tendon sheath"],
    ["Fluctuation with wrist position", "Becomes more tense on wrist flexion", "Connected to joint/tendon under tension"],
]
S.append(three_col_table(gang_palp, 3.5*cm, 6.5*cm, 7*cm,
                         "Feature", "Finding", "Significance"))
S.append(sp(4))
S.append(note_box("Ganglion: Tense cystic + TRANSILLUMINANT + Fixed to deep (tendon sheath) + "
                  "NOT fixed to skin + Mobile across tendon + Dorsum of wrist most common site."))
S.append(sp(3))
S.append(src("Bailey & Love 28th Ed (Ganglion cysts); S. Das 13th Ed; SRB's Manual of Surgery"))
S.append(PageBreak())

# ════════════════════════════════════════════════════════════════════════════
# 5. NEUROFIBROMA
# ════════════════════════════════════════════════════════════════════════════
S.append(swelling_banner("5", "NEUROFIBROMA / NEUROFIBROMATOSIS",
                         "Von Recklinghausen's disease"))
S.append(sp(5))
S.append(p("<b>Definition:</b> Tumour containing neural (ectodermal) AND fibrous (mesodermal) "
           "elements arising from perineurium/epineurium. May be solitary (local) or multiple "
           "(generalized = von Recklinghausen's disease — autosomal dominant). "
           "5% risk of malignant change (neurofibrosarcoma) in NF1. (S. Das)", BODY))
S.append(sp(4))

S.append(p("<b>Characteristic Features (Inspection):</b>", SUBSEC))
for txt in [
    "Solitary: smooth, firm subcutaneous nodule along course of a peripheral nerve",
    "Multiple: scattered neurofibromas all over body; 'bag of worms' appearance",
    "Skin: multiple Cafe-au-lait patches (light brown pigmentation — >6 patches >1.5cm = diagnostic of NF1)",
    "Associated: axillary/inguinal freckling (Crowe's sign), Lisch nodules (iris hamartomas)",
    "Plexiform neurofibroma: bag-of-worms feel; may cause gigantism of limb",
]:
    S.append(b(txt))
S.append(sp(5))

S.append(p("<b>Positive Findings on Palpation:</b>", SUBSEC))
nf_palp = [
    ["Temperature", "Normal", "---"],
    ["Tenderness", "Slightly tender on pressure; paraesthesia/tingling along nerve distribution", "Nerve fibre compression"],
    ["Consistency", "Firm, smooth, slightly elastic", "Contains fibrous tissue"],
    ["Fluctuation", "NEGATIVE (solid)", "---"],
    ["Transillumination", "NEGATIVE", "Solid tumour"],
    ["Skin fixity", "NOT fixed to skin", "Subcutaneous origin"],
    ["Deep fixity", "Fixed along nerve axis (cannot move ALONG nerve)", "Arises from nerve"],
    ["Mobility", "CAN be moved LATERALLY (across nerve) but NOT along the nerve — <b>pathognomonic</b>", "Tethered to underlying nerve"],
    ["Transmitted tingling", "Pressure on swelling → tingling/paraesthesia along nerve distribution (Tinel's sign variant)", "Nerve origin confirmed"],
    ["Cafe-au-lait patches", "Count and measure (>6 patches >1.5cm = NF1 criterion)", "Diagnostic for NF1"],
]
S.append(three_col_table(nf_palp, 3.5*cm, 6.5*cm, 7*cm,
                         "Feature", "Finding", "Significance"))
S.append(sp(4))
S.append(note_box("Neurofibroma: Mobile ACROSS nerve but NOT along it + Tingling on pressure + "
                  "Cafe-au-lait patches in multiple type. 5% malignant transformation to neurofibrosarcoma."))
S.append(sp(3))
S.append(src("S. Das 13th Ed p.54; Bailey & Love 28th Ed; Sabiston 21st Ed"))
S.append(PageBreak())

# ════════════════════════════════════════════════════════════════════════════
# 6. LYMPH NODE ENLARGEMENT
# ════════════════════════════════════════════════════════════════════════════
S.append(swelling_banner("6", "LYMPH NODE ENLARGEMENT",
                         "Lymphadenopathy"))
S.append(sp(5))
S.append(p("<b>Definition:</b> Enlargement of lymph nodes — may be reactive (inflammatory), "
           "infective (TB, actinomycosis), neoplastic (primary: lymphoma; secondary: metastatic carcinoma). "
           "Critical to determine: CAUSE of LN enlargement and PRIMARY site if metastatic.", BODY))
S.append(sp(4))

S.append(p("<b>Characteristic Features (Inspection):</b>", SUBSEC))
for txt in [
    "Site: cervical (most common for examination), axillary, inguinal, generalised",
    "Acute lymphadenitis: red, swollen, visible — often fluctuant when abscess forms",
    "Chronic TB: collar-stud abscess may be visible (skin puckering)",
    "Lymphoma: bilateral rubbery discrete nodes without skin changes",
    "Metastatic: hard irregular nodes; may be fixed; skin involvement in late stage",
]:
    S.append(b(txt))
S.append(sp(5))

S.append(p("<b>Positive Findings on Palpation — Differentiation:</b>", SUBSEC))
ln_palp = [
    ["Temperature", "Warm = acute lymphadenitis / TB abscess; normal = malignant", "Cold abscess (TB) is NOT warm despite pus"],
    ["Tenderness", "Tender = acute inflammation, TB. NON-tender = lymphoma, metastasis", "Painless LN = always suspect malignancy"],
    ["Consistency", "Soft = acute LN. Firm/rubbery = lymphoma. Hard (stony) = metastatic carcinoma. Fluctuant = LN abscess", "Hard = carcinoma; rubbery = lymphoma (Hodgkin's)"],
    ["Surface", "Smooth = reactive/lymphoma. Irregular/bosselated = multiple matted nodes", "---"],
    ["Mobility", "Mobile = reactive/lymphoma. Fixed to skin or deep = TB (collar-stud) or malignancy", "---"],
    ["Matting", "Multiple nodes palpable as matted mass = TB lymphadenitis (nodes stuck together by periadenitis)", "Matted + collar-stud = TB until proven otherwise"],
    ["Collar-stud abscess", "Deep component in fascia + superficial fluctuant subcutaneous component communicating through fascial gap", "PATHOGNOMONIC of TB lymphadenitis"],
    ["Transillumination", "NEGATIVE (solid tissue)", "---"],
    ["Fluctuation", "Positive = liquefied TB abscess or pyogenic LN abscess", "---"],
    ["Draining area", "ALWAYS examine the draining area for the primary lesion", "Submental LN enlarged → floor of mouth/lip primary; Virchow's node → stomach/abdominal malignancy"],
]
S.append(three_col_table(ln_palp, 3.5*cm, 7*cm, 6.5*cm,
                         "Feature", "Finding", "Significance"))
S.append(sp(4))
S.append(note_box("TB LN: Matted + Collar-stud abscess + Cold. "
                  "Metastatic: Hard + Fixed + Non-tender. "
                  "Lymphoma: Rubbery + Discrete + Mobile + Non-tender. "
                  "ALWAYS examine primary drainage territory."))
S.append(sp(3))
S.append(src("S. Das 13th Ed; Bailey & Love 28th Ed; SRB's Manual of Surgery; Schwartz 11th Ed"))
S.append(PageBreak())

# ════════════════════════════════════════════════════════════════════════════
# 7. HAEMANGIOMA
# ════════════════════════════════════════════════════════════════════════════
S.append(swelling_banner("7", "HAEMANGIOMA", "Vascular hamartoma / malformation"))
S.append(sp(5))
S.append(p("<b>Definition:</b> Vascular malformations or hamartomas arising from capillary, "
           "vein or artery. S. Das: 'These are vascular malformations or hamartomas and may "
           "arise from the capillary or the vein or the artery.'", BODY))
S.append(sp(4))

S.append(p("<b>Types:</b>", SUBSEC))
haem_types = [
    ["Port-wine stain", "Diffuse telangiectasia; flat, no swelling; unilateral; affects face (trigeminal distribution). Sturge-Weber if associated with intracranial haemangioma."],
    ["Salmon patch", "Present at birth; forehead/occiput; disappears by 1st birthday"],
    ["Spider naevus", "Central arteriole + radiating vessels; blanches with central pressure; seen in liver disease (>5 = significant), pregnancy, OCP. On upper trunk, face, arms."],
    ["Strawberry angioma\n(Capillary)", "Lobulated sessile bright red swelling at birth; grows for 6-12 months then SPONTANEOUSLY REGRESSES. Surface like strawberry. Disappears by age 5-7 yrs."],
    ["Cavernous haemangioma", "Larger; bluish soft SPONGY swelling; dilated blood-filled spaces; lips/cheeks/face/brain. COMPRESSIBLE, empties on pressure, refills on release."],
    ["Plexiform/Cirsoid", "Network of dilated tortuous arteries — 'bag of pulsating earthworms'; expansile PULSATILE, may have bruit/thrill; scalp common site"],
    ["Campbell de Morgan spot", "1-3mm bright red circular spot; adults >45yr; trunk; not fully compressible (differs from spider naevus)"],
    ["Glomus tumour", "Subungual; exquisitely painful to touch; pin-point tenderness; X-ray shows erosion of terminal phalanx"],
]
S.append(two_col_table(haem_types, 4.5*cm, 12.5*cm, "Type", "Features"))
S.append(sp(5))

S.append(p("<b>Positive Findings on Palpation (Cavernous haemangioma — most examined):</b>", SUBSEC))
haem_palp = [
    ["Temperature", "May be WARM (high blood flow)", "Increased vascularity"],
    ["Consistency", "SOFT, SPONGY, compressible", "Dilated vascular spaces containing blood"],
    ["Compressibility", "<b>POSITIVE — brilliantly compressible</b>: press → swelling empties (turns pale); release → fills back immediately", "Pathognomonic of haemangioma"],
    ["Fluctuation", "POSITIVE", "Blood-filled spaces"],
    ["Transillumination", "NEGATIVE (blood is opaque)", "---"],
    ["Pulsatility", "NON-pulsatile (except cirsoid / arterial type)", "---"],
    ["Bruit/Thrill", "Absent in capillary/cavernous; PRESENT in cirsoid (plexiform)", "Cirsoid = arterial communication"],
    ["Skin colour", "Bluish discolouration (venous type); bright red (capillary)", "Distinguish types"],
    ["Skin fixity", "May be attached to overlying skin (discolouration)", "---"],
    ["Branham's sign", "For AV fistula type: compress artery proximal → swelling reduces, bruit disappears, pulse falls", "Confirms arteriovenous communication"],
]
S.append(three_col_table(haem_palp, 3.5*cm, 6.5*cm, 7*cm,
                         "Feature", "Finding", "Significance"))
S.append(sp(4))
S.append(note_box("Cavernous haemangioma: COMPRESSIBLE (empties on pressure, refills on release) + "
                  "Soft/spongy + Blue discolouration + NON-transilluminant. "
                  "Cirsoid: Pulsatile + Bruit + Warm + Expandable. "
                  "Strawberry: Regresses spontaneously — observe first!"))
S.append(sp(3))
S.append(src("S. Das 13th Ed p.47-50; Bailey & Love 28th Ed; Schwartz 11th Ed"))
S.append(PageBreak())

# ════════════════════════════════════════════════════════════════════════════
# 8. CYSTIC HYGROMA
# ════════════════════════════════════════════════════════════════════════════
S.append(swelling_banner("8", "CYSTIC HYGROMA", "Lymphatic malformation / Macrocystic lymphangioma"))
S.append(sp(5))
S.append(p("<b>Definition:</b> Multilocular cystic swelling arising from failure of lymphatic "
           "channels to join venous system — lymph accumulates in cystic spaces. Filled with clear "
           "lymph. Bailey & Love: 'The characteristic that distinguishes it from all other neck "
           "swellings is that it is brilliantly transilluminant.'", BODY))
S.append(sp(4))

S.append(p("<b>Characteristic Features (Inspection):</b>", SUBSEC))
for txt in [
    "Age: presents in neonate/early infancy; may present at birth (can obstruct labour if large)",
    "Site: most common in posterior triangle of neck; also axilla, groin, mediastinum, face/submandibular",
    "Swelling may be bilateral; can involve face, tongue, floor of mouth (macroglossia)",
    "Size INCREASES when child coughs or cries (connected to lymphatics, intra-thoracic pressure transmitted)",
    "Soft, lobulated, multilocular swelling",
    "Skin over it: normal; translucent in daylight",
]:
    S.append(b(txt))
S.append(sp(5))

S.append(p("<b>Positive Findings on Palpation:</b>", SUBSEC))
hyg_palp = [
    ["Temperature", "Normal", "---"],
    ["Tenderness", "Non-tender (tender when infected)", "---"],
    ["Consistency", "SOFT, partially compressible; multilocular feel", "Multiple cystic spaces"],
    ["Fluctuation", "<b>POSITIVE</b>", "Lymph-filled cysts"],
    ["Transillumination", "<b>BRILLIANTLY POSITIVE</b> — glows brilliantly in dark room", "Clear lymph fluid. PATHOGNOMONIC. No other neck swelling transilluminates this brightly."],
    ["Compressibility", "Partially compressible (can compress some locules)", "---"],
    ["Skin fixity", "NOT fixed to skin", "---"],
    ["Size change on crying/coughing", "Visibly and palpably INCREASES in size on coughing/crying", "Lymphatic pressure transmission — classic feature"],
    ["Reducibility", "May partially reduce but does NOT fully reduce", "---"],
    ["Deep fixity", "Insinuates between structures (not truly fixed — infiltrates tissue planes)", "Infiltrative — makes complete excision difficult"],
]
S.append(three_col_table(hyg_palp, 3.5*cm, 6.5*cm, 7*cm,
                         "Feature", "Finding", "Significance"))
S.append(sp(4))
S.append(note_box("Cystic Hygroma: BRILLIANTLY TRANSILLUMINANT (most important feature) + "
                  "Increases on crying/coughing + Soft multilocular + Neck/axilla in infants. "
                  "Treatment: complete excision (Sistrunk-type dissection) — multicystic so complete resolution difficult."))
S.append(sp(3))
S.append(src("Bailey & Love 28th Ed p.827; S. Das 13th Ed; Schwartz 11th Ed"))
S.append(PageBreak())

# ════════════════════════════════════════════════════════════════════════════
# 9. THYROGLOSSAL CYST
# ════════════════════════════════════════════════════════════════════════════
S.append(swelling_banner("9", "THYROGLOSSAL CYST", "Midline neck cyst"))
S.append(sp(5))
S.append(p("<b>Definition:</b> Cyst arising from persistence of the thyroglossal duct, "
           "which marks the path of thyroid descent from foramen caecum (base of tongue) to "
           "its final position. Bailey & Love: 'The cysts almost always arise in the midline "
           "but may lie slightly to one side near the thyroid cartilage.'", BODY))
S.append(sp(4))

S.append(p("<b>Characteristic Features (Inspection):</b>", SUBSEC))
for txt in [
    "Age: most common in children, but may present in adults (even 6th-7th decade)",
    "Site: MIDLINE of neck, anywhere from base of tongue to thyroid isthmus; 60% at or near hyoid bone",
    "Smooth, rounded, midline swelling; overlying skin normal",
    "May rupture → discharging midline sinus in neck",
]:
    S.append(b(txt))
S.append(sp(5))

S.append(p("<b>Positive Findings on Palpation:</b>", SUBSEC))
thyg_palp = [
    ["Temperature", "Normal", "---"],
    ["Tenderness", "Non-tender (tender when infected)", "---"],
    ["Consistency", "Cystic / fluctuant", "Clear or turbid fluid inside"],
    ["Fluctuation", "<b>POSITIVE</b>", "Fluid-containing cyst"],
    ["Transillumination", "POSITIVE (clear fluid)", "Clear contents"],
    ["Movement on swallowing", "<b>MOVES UPWARD on swallowing</b> (deglutition)", "Attached to thyroid via pretracheal fascia → moves with larynx"],
    ["Movement on tongue protrusion", "<b>MOVES UPWARD on protruding tongue</b> — PATHOGNOMONIC", "Attached to foramen caecum via thyroglossal tract through/around hyoid — tongue pulls it up"],
    ["Skin fixity", "NOT fixed to skin (unless sinus present)", "---"],
    ["Deep fixity", "Fixed to hyoid bone", "Track passes through/around hyoid body — Sistrunk's operation removes hyoid body"],
    ["Midline position", "Midline (occasionally paramedian near thyroid cartilage)", "---"],
]
S.append(three_col_table(thyg_palp, 3.5*cm, 6.5*cm, 7*cm,
                         "Feature", "Finding", "Significance"))
S.append(sp(4))
S.append(note_box("Thyroglossal cyst: MIDLINE + Moves up on SWALLOWING + Moves up on TONGUE PROTRUSION "
                  "(most important distinguishing feature). Confirm presence of normal thyroid before surgery. "
                  "Treatment: Sistrunk's operation (excise cyst + body of hyoid + suprathyoid tract to foramen caecum)."))
S.append(sp(3))
S.append(src("Bailey & Love 28th Ed p.828; S. Das 13th Ed; Sabiston 21st Ed; SRB's Manual of Surgery"))
S.append(PageBreak())

# ════════════════════════════════════════════════════════════════════════════
# 10. BRANCHIAL CYST
# ════════════════════════════════════════════════════════════════════════════
S.append(swelling_banner("10", "BRANCHIAL CYST", "Second branchial cleft remnant"))
S.append(sp(5))
S.append(p("<b>Definition:</b> Cyst arising from vestigial remnants of the second branchial "
           "cleft. Lined by squamous epithelium containing thick, turbid, cholesterol-rich fluid. "
           "Bailey & Love: 'Usually presents in the upper neck in early or middle adulthood at "
           "the junction of the upper and middle thirds of the sternomastoid at its anterior border.'", BODY))
S.append(sp(4))

S.append(p("<b>Characteristic Features (Inspection):</b>", SUBSEC))
for txt in [
    "Age: young adults (20-30 years); rarely in children",
    "Site: anterior border of upper 1/3 of sternocleidomastoid muscle (SCM), at junction of upper and middle thirds",
    "Smooth rounded swelling; overlying skin normal",
    "May become infected → erythematous, tender, may rupture",
    "If age >35 years: ALWAYS exclude cystic metastatic lymph node (especially SCC of tonsil/base of tongue — p16/HPV-related)",
]:
    S.append(b(txt))
S.append(sp(5))

S.append(p("<b>Positive Findings on Palpation:</b>", SUBSEC))
bran_palp = [
    ["Temperature", "Normal (unless infected)", "---"],
    ["Tenderness", "Non-tender; tender when infected", "---"],
    ["Consistency", "Fluctuant, soft — often 'soft and difficult to palpate' (Bailey & Love)", "Thick turbid cholesterol-rich fluid"],
    ["Fluctuation", "<b>POSITIVE</b>", "Cystic"],
    ["Transillumination", "May be partially positive (turbid fluid — not as brilliant as hygroma)", "---"],
    ["Skin fixity", "NOT fixed to skin", "---"],
    ["Deep fixity", "Lies DEEP to sternomastoid; passes between internal and external carotid arteries", "Passes superficial to hypoglossal and glossopharyngeal nerves"],
    ["Movement on swallowing", "Does NOT move on swallowing (NOT attached to thyroid)", "Key difference from thyroglossal cyst"],
    ["Tongue protrusion", "Does NOT move on tongue protrusion", "Differentiates from thyroglossal"],
    ["Site-specific", "At anterior border of upper SCM — highly site-specific", "Junction upper 1/3 + middle 1/3 SCM"],
]
S.append(three_col_table(bran_palp, 3.5*cm, 6.5*cm, 7*cm,
                         "Feature", "Finding", "Significance"))
S.append(sp(4))
S.append(note_box("Branchial cyst: Anterior border upper SCM + Fluctuant + Does NOT move on swallowing "
                  "or tongue protrusion. >35 years: exclude HPV+ cystic nodal metastasis (tonsillar SCC). "
                  "FNA shows cholesterol crystals + squamous cells."))
S.append(sp(3))
S.append(src("Bailey & Love 28th Ed p.827; S. Das 13th Ed; Schwartz 11th Ed"))
S.append(PageBreak())

# ════════════════════════════════════════════════════════════════════════════
# 11. RANULA
# ════════════════════════════════════════════════════════════════════════════
S.append(swelling_banner("11", "RANULA", "Sublingual cyst / Mucous retention cyst"))
S.append(sp(5))
S.append(p("<b>Definition:</b> Retention cyst of sublingual salivary gland. Contains clear "
           "mucus. Name derived from Latin 'rana' (frog) — resembles a frog's belly. "
           "Plunging ranula extends through mylohyoid muscle into neck.", BODY))
S.append(sp(4))

S.append(p("<b>Characteristic Features (Inspection):</b>", SUBSEC))
for txt in [
    "Site: floor of mouth, lateral to frenulum, unilateral, below tongue",
    "Smooth, bluish, translucent swelling in floor of mouth",
    "Simple ranula: confined to floor of mouth",
    "Plunging (cervical) ranula: extends through mylohyoid into submandibular/submental region — BILOBED swelling (one intra-oral + one in neck)",
    "May elevate the tongue",
]:
    S.append(b(txt))
S.append(sp(5))

S.append(p("<b>Positive Findings on Palpation:</b>", SUBSEC))
ran_palp = [
    ["Consistency", "Soft, fluctuant, TENSE cystic", "Mucous-filled"],
    ["Fluctuation", "POSITIVE", "---"],
    ["Transillumination", "<b>POSITIVE</b> — translucent on inspection; transilluminates", "Clear mucus"],
    ["Bimanual palpation", "For plunging ranula: intraoral finger + extraoral finger — bilobed felt", "Plunging type extends through mylohyoid"],
    ["Skin fixity", "NOT fixed to overlying mucosa/skin", "---"],
    ["Movement", "Moves with tongue elevation; does not move on swallowing", "---"],
]
S.append(three_col_table(ran_palp, 3.5*cm, 6.5*cm, 7*cm,
                         "Feature", "Finding", "Significance"))
S.append(sp(4))
S.append(note_box("Ranula: Bluish translucent swelling in floor of mouth + Transilluminant + "
                  "Fluctuant. Plunging ranula: bilobed (intraoral + cervical component). "
                  "Treatment: marsupialization or excision."))
S.append(sp(3))
S.append(src("Bailey & Love 28th Ed; S. Das 13th Ed; SRB's Manual of Surgery"))

S.append(sp(6))
# ════════════════════════════════════════════════════════════════════════════
# 12. LYMPHANGIOMA (MICROCYSTIC)
# ════════════════════════════════════════════════════════════════════════════
S.append(swelling_banner("12", "LYMPHANGIOMA (Microcystic)", "Lymphatic malformation"))
S.append(sp(5))
S.append(p("<b>Definition:</b> Benign hamartoma of lymphatic vessels — microcystic type "
           "(lymphangioma circumscriptum). Macrocystic = cystic hygroma. Contains clear lymph "
           "in multiple tiny cystic spaces.", BODY))
S.append(sp(4))
for txt in [
    "Skin: cluster of tiny vesicles/blisters filled with clear lymph — 'frog spawn' appearance",
    "May have haemangiomatous element (lymphangio-haemangioma) — red/purple vesicles",
    "Sites: tongue (macroglossia), lip, axilla, chest wall",
    "Palpation: soft, compressible, non-tender; individual vesicles palpable; transilluminant",
    "Deep extension: often extends much deeper than superficial appearance suggests",
]:
    S.append(b(txt))
S.append(sp(3))
S.append(src("Bailey & Love 28th Ed; Schwartz 11th Ed; S. Das 13th Ed"))
S.append(PageBreak())

# ════════════════════════════════════════════════════════════════════════════
# 13. GLOMUS TUMOUR
# ════════════════════════════════════════════════════════════════════════════
S.append(swelling_banner("13", "GLOMUS TUMOUR (Glomangioma)",
                         "Benign vascular tumour"))
S.append(sp(5))
S.append(p("<b>Definition:</b> Benign tumour of neuromyoarterial glomus (Sucquet-Hoyer canal), "
           "a specialized arteriovenous anastomosis. Located predominantly under fingernail. "
           "S. Das: 'Not a congenital tumour in the true sense.'", BODY))
S.append(sp(4))

S.append(p("<b>Classic Triad (Love's triad):</b>", SUBSEC))
for txt in [
    "<b>1. Subungual location</b> — under fingernail (most common)",
    "<b>2. Exquisite point tenderness</b> — pin-point, out of proportion to size",
    "<b>3. Cold hypersensitivity</b> — pain exacerbated by cold",
]:
    S.append(kb(txt))
S.append(sp(5))

S.append(p("<b>Positive Findings on Palpation:</b>", SUBSEC))
glo_palp = [
    ["Temperature", "May be slightly warm", "---"],
    ["Tenderness", "<b>EXQUISITELY painful on pin-point pressure</b> — pathognomonic", "Love's triad: point tenderness"],
    ["Size", "Usually <1cm; may be invisible under nail", "---"],
    ["Cold sensitivity", "<b>Pain reproduced by applying cold water</b>", "Cold hypersensitivity — Love's triad"],
    ["X-ray nail", "Erosion of terminal phalanx on X-ray (if large)", "Bone erosion from pressure"],
    ["Hillroth's test", "Elevate + compress digit → reduces pain; release → pain returns", "Vascular component"],
    ["Nail changes", "Blue-red discolouration through nail plate", "Vascular tumour under nail"],
]
S.append(three_col_table(glo_palp, 3.5*cm, 6.5*cm, 7*cm,
                         "Feature", "Finding", "Significance"))
S.append(sp(4))
S.append(note_box("Glomus tumour: Love's triad = Subungual location + Pin-point tenderness + "
                  "Cold hypersensitivity. Treatment: excision of nail + tumour."))
S.append(sp(3))
S.append(src("S. Das 13th Ed; Bailey & Love 28th Ed; SRB's Manual of Surgery"))
S.append(PageBreak())

# ════════════════════════════════════════════════════════════════════════════
# MASTER DIFFERENTIAL TABLE
# ════════════════════════════════════════════════════════════════════════════
S.append(banner("MASTER DIFFERENTIAL — POSITIVE FINDINGS AT A GLANCE", GREEN))
S.append(sp(6))

diff_data = [
    [p("<b>Swelling</b>", PS("H",fontSize=8,fontName="Helvetica-Bold",textColor=WHITE)),
     p("<b>Fluct.</b>", PS("H",fontSize=8,fontName="Helvetica-Bold",textColor=WHITE)),
     p("<b>Trans-illum.</b>", PS("H",fontSize=8,fontName="Helvetica-Bold",textColor=WHITE)),
     p("<b>Compress-ible</b>", PS("H",fontSize=8,fontName="Helvetica-Bold",textColor=WHITE)),
     p("<b>Skin Fixed</b>", PS("H",fontSize=8,fontName="Helvetica-Bold",textColor=WHITE)),
     p("<b>Deep Fixed</b>", PS("H",fontSize=8,fontName="Helvetica-Bold",textColor=WHITE)),
     p("<b>Pulsatile</b>", PS("H",fontSize=8,fontName="Helvetica-Bold",textColor=WHITE)),
     p("<b>Pathognomonic Sign</b>", PS("H",fontSize=8,fontName="Helvetica-Bold",textColor=WHITE))],
    [p("Sebaceous cyst",BODY), p("Yes",BODY), p("<b>NO</b>",BODY), p("No",BODY),
     p("<b>Yes</b>",BODY), p("No",BODY), p("No",BODY), p("Punctum; scalp/scrotum",BODY)],
    [p("Lipoma",BODY), p("Pseudo",BODY), p("No",BODY), p("Partial",BODY),
     p("<b>No</b>",BODY), p("No",BODY), p("No",BODY), p("Slip sign; skin free",BODY)],
    [p("Dermoid cyst",BODY), p("±",BODY), p("<b>NO</b>",BODY), p("No",BODY),
     p("No (impl:Yes)",BODY), p("±bone",BODY), p("No",BODY), p("Bony hollow; putty feel",BODY)],
    [p("Ganglion",BODY), p("<b>Yes</b>",BODY), p("<b>Yes</b>",BODY), p("No",BODY),
     p("No",BODY), p("<b>Yes</b>",BODY), p("No",BODY), p("Fixed to tendon; mobile across tendon",BODY)],
    [p("Neurofibroma",BODY), p("No",BODY), p("No",BODY), p("No",BODY),
     p("No",BODY), p("Yes (nerve)",BODY), p("No",BODY), p("Mobile across, NOT along nerve; tingling",BODY)],
    [p("LN (TB)",BODY), p("±",BODY), p("No",BODY), p("No",BODY),
     p("±",BODY), p("±",BODY), p("No",BODY), p("Matted + Collar-stud abscess",BODY)],
    [p("LN (Metastatic)",BODY), p("No",BODY), p("No",BODY), p("No",BODY),
     p("±",BODY), p("Yes",BODY), p("No",BODY), p("Hard; stony; non-tender",BODY)],
    [p("Cavernous\nHaemangioma",BODY), p("Yes",BODY), p("No",BODY),
     p("<b>YES</b>",BODY), p("±",BODY), p("No",BODY), p("No",BODY), p("Compressible, refills; blue colour",BODY)],
    [p("Cirsoid\nHaemangioma",BODY), p("No",BODY), p("No",BODY),
     p("Yes",BODY), p("±",BODY), p("No",BODY), p("<b>YES</b>",BODY), p("Pulsatile, bruit, warm, worm-like",BODY)],
    [p("Cystic Hygroma",BODY), p("<b>Yes</b>",BODY), p("<b>BRILLIANT</b>",BODY),
     p("Partial",BODY), p("No",BODY), p("Insinuates",BODY), p("No",BODY), p("Brilliant transill; size on cry/cough; infant neck",BODY)],
    [p("Thyroglossal\ncyst",BODY), p("Yes",BODY), p("Yes",BODY), p("No",BODY),
     p("No",BODY), p("Hyoid",BODY), p("No",BODY), p("Moves up on TONGUE PROTRUSION + swallowing",BODY)],
    [p("Branchial cyst",BODY), p("Yes",BODY), p("±",BODY), p("No",BODY),
     p("No",BODY), p("No",BODY), p("No",BODY), p("Anterior border upper SCM; does NOT move on swallowing",BODY)],
    [p("Ranula",BODY), p("Yes",BODY), p("Yes",BODY), p("No",BODY),
     p("No",BODY), p("No",BODY), p("No",BODY), p("Bluish translucent floor of mouth; frog-belly",BODY)],
    [p("Glomus tumour",BODY), p("No",BODY), p("No",BODY), p("No",BODY),
     p("No",BODY), p("Yes",BODY), p("No",BODY), p("Subungual; pin-point tenderness; cold sensitivity",BODY)],
]

diff_tbl = Table(diff_data, colWidths=[2.5*cm,1.3*cm,1.7*cm,1.7*cm,1.4*cm,1.4*cm,1.4*cm,6.5*cm],
                 repeatRows=1)
diff_tbl.setStyle(TableStyle([
    ("BACKGROUND",   (0,0), (-1,0),  NAVY),
    ("FONTSIZE",     (0,0), (-1,-1), 7.5),
    ("ROWBACKGROUNDS",(0,1),(-1,-1),[WHITE, LGRAY]),
    ("GRID",         (0,0), (-1,-1), 0.3, MGRAY),
    ("VALIGN",       (0,0), (-1,-1), "TOP"),
    ("LEFTPADDING",  (0,0), (-1,-1), 3),
    ("RIGHTPADDING", (0,0), (-1,-1), 3),
    ("TOPPADDING",   (0,0), (-1,-1), 3),
    ("BOTTOMPADDING",(0,0), (-1,-1), 3),
]))
S.append(diff_tbl)
S.append(sp(6))
S.append(note_box("Key exam rule: Fluctuation + Transillumination = clear fluid cyst (hygroma, ganglion, thyroglossal). "
                  "Fluctuation + NO transillumination = opaque fluid (sebaceous, haematocele). "
                  "Compressible + Refills = haemangioma. Fixed to skin + fluctuant + punctum = sebaceous cyst."))
S.append(sp(4))
S.append(p("Sources: S. Das — A Manual on Clinical Surgery 13th Ed  |  Bailey & Love's Short Practice of Surgery 28th Ed  |  "
           "Schwartz's Principles of Surgery 11th Ed  |  Sabiston Textbook of Surgery 21st Ed  |  SRB's Manual of Surgery",
           FOOTER_S))

# ── BUILD ────────────────────────────────────────────────────────────────────
doc = SimpleDocTemplate(
    OUTPUT,
    pagesize=A4,
    leftMargin=2*cm, rightMargin=2*cm,
    topMargin=1.8*cm, bottomMargin=1.8*cm,
    title="Common Surgical Swellings — MS General Surgery",
    author="S. Das | Bailey & Love | Schwartz | Sabiston | SRB",
)
doc.build(S)
print(f"PDF created: {OUTPUT}")
Running Command

cd /home/daytona/workspace/ms-surgery-guide && python swellings_pdf.py 2>&1

Running Command

ls -lh /home/daytona/workspace/ms-surgery-guide/Common_Surgical_Swellings.pdf

Your PDF is ready:

Common Surgical Swellings

PDF Document · PDF


What's inside (15 pages, A4, colour-coded):
#SwellingKey Exam Content
General Approach14-feature palpation framework (S. Das)
1Sebaceous CystPunctum (pathognomonic), Fixed to skin, Fluctuant, NOT transilluminant, Cock's peculiar tumour
2LipomaSlip sign, Pseudofluctuation, NOT fixed to skin, Soft/lobulated, Dercum's disease
3Dermoid CystDoughy (putty-like), Bony hollow (external angular), NOT transilluminant, Types table
4GanglionTransilluminant, Fixed to tendon sheath, Mobile ACROSS tendon, Tense cystic
5NeurofibromaMobile across but NOT along nerve, Tingling, Cafe-au-lait, 5% sarcoma risk
6Lymph NodeTB (collar-stud, matted, cold), Metastatic (hard, fixed), Lymphoma (rubbery, discrete)
7HaemangiomaCompressible + refills (cavernous), Cirsoid = pulsatile + bruit, Strawberry regresses, Spider naevus
8Cystic HygromaBRILLIANTLY transilluminant, Increases on crying/coughing, Infant neck
9Thyroglossal CystMoves up on TONGUE PROTRUSION (pathognomonic) + swallowing, Sistrunk's
10Branchial CystAnterior border upper SCM, Does NOT move on swallowing, >35yr exclude SCC metastasis
11RanulaBluish translucent floor of mouth, Plunging type bilobed
12LymphangiomaFrog spawn vesicles, extends deeper than appears
13Glomus TumourLove's triad (subungual + pin-point tenderness + cold sensitivity)
Master Differential TableAll 15 swellings compared: Fluctuation / Transillumination / Compressibility / Skin fixity / Deep fixity / Pulsatility / Pathognomonic sign
This is a shared conversation. Sign in to Orris to start your own chat.