What is the good standard test for SAH within 6 hrs and beyond 6 hrs support your answer with reference

Reading File
Finding Sources
Searching PubMed

"subarachnoid hemorrhage" AND diagnosis AND "CT angiography" AND "lumbar puncture"

Searching the Web

subarachnoid hemorrhage gold standard test within 6 hours beyond 6 hours CT xanthochromia 2024 guidelines

Reading File
Reading File
Searching PubMed

"subarachnoid hemorrhage" AND "CT sensitivity" AND "6 hours" AND "lumbar puncture"

Searching PubMed

"subarachnoid hemorrhage" AND diagnosis AND xanthochromia AND spectrophotometry

Finding Sources
I now have comprehensive data from multiple authoritative sources. Let me compile the full answer.

Diagnosis of Subarachnoid Hemorrhage (SAH): Standard Tests by Time Window

Quick Answer

The standard diagnostic approach to SAH is time-dependent: non-contrast CT head (NCCT) within 6 hours of ictus is nearly 100% sensitive and can rule out SAH without further testing; beyond 6 hours, CT sensitivity drops and lumbar puncture (LP) with CSF xanthochromia (ideally by spectrophotometry) becomes the confirmatory gold standard.

Within 6 Hours of Ictus: Non-Contrast CT Head (NCCT)

NCCT is the first-line and near-definitive test when performed within 6 hours.
  • Sensitivity approaches 98-100% when CT is performed within 6 hours of headache onset on a third-generation or newer scanner, interpreted by an experienced radiologist.
  • The Ottawa SAH Rule prospective validation study confirmed 95.5% sensitivity for negative NCCT at 6 hours. Subsequent meta-analysis (Dubosh et al., 2016) found fewer than 1.5 in 1000 patients with SAH would be missed if LP is omitted when all criteria are met: normal head CT on a modern scanner within 6 hours, interpreted by an experienced radiologist, in a patient with isolated thunderclap headache and normal neurological exam.
  • If the NCCT is performed within 6 hours and is negative, LP can reasonably be omitted in low-risk patients after shared decision-making.
"Brain noncontrast computed tomography (NCCT) is a highly sensitive imaging modality for diagnosis of aSAH... NCCT scan confirms a SAH with very high sensitivity, close to 100%, in the first 3 days."
  • Bradley and Daroff's Neurology in Clinical Practice (block15, lines 1820-1822)
Important caveats for the CT 6-hour rule:
  • Requires a modern (third-generation or newer) CT scanner
  • Must be read by a radiologist experienced in SAH
  • Does NOT apply to patients with severe anemia (insufficient RBC concentration for CT detection)
  • Does NOT apply if there is seizure, syncope, or neck stiffness accompanying the headache

Beyond 6 Hours of Ictus: LP + CSF Xanthochromia (Spectrophotometry)

When NCCT is performed after 6 hours, or is negative but clinical suspicion remains high, LP with xanthochromia detection is the gold standard.

Why CT Sensitivity Falls

CT sensitivity declines as subarachnoid blood is metabolized:
  • Within 6 hours: ~98-100%
  • 6-24 hours: ~85-95%
  • 48-72 hours: ~75%
  • Day 5: ~60%
"The sensitivity decreases moderately with time as the subarachnoid blood is metabolized and cleared."
  • Bradley and Daroff's Neurology in Clinical Practice
"Although the sensitivity of CT for making the diagnosis of SAH can range from 92% to 98% when performed within 24 hours of the onset of symptoms, it decreases to 75% when performed 48-72 hours after..."
  • Pfenninger and Fowler's Procedures for Primary Care

CSF Xanthochromia: The Gold Standard Beyond 6 Hours

Xanthochromia = yellow discoloration of CSF supernatant due to heme breakdown products.
After bleeding into the CSF:
  1. RBCs lyse and release oxyhemoglobin
  2. Leptomeningeal heme oxygenase converts oxyhemoglobin to bilirubin (and sometimes methemoglobin) - this is time-dependent
  3. Bilirubin appears approximately 2-4 hours after hemorrhage, and becomes reliably detectable by 12 hours
  4. Xanthochromia can persist for 2-4 weeks
"The detection of xanthochromia in the CSF is still considered to be the gold standard for diagnosing SAH, especially for patients with a negative CT scan obtained >6 h from initial symptom onset."
  • Norwegian observational study (Aaseth et al., Eur J Neurol, 2024 - PMID: 39092827)

Visual Inspection vs. Spectrophotometry

MethodNotes
Visual inspectionUnreliable - CSF may appear clear despite abnormal spectrophotometric scan
Spectrophotometry (gold standard)Detects oxyhemoglobin peak (410-418 nm) and bilirubin peak (450-460 nm). UK guidelines recommend this as the definitive method.
"Diagnosis of SAH therefore hinges on the detection of bilirubin in CSF, for which spectrophotometry is the recommended approach. Visual inspection for the yellow discoloration (xanthochromia) imparted to CSF is not considered to be reliable."
  • Tietz Textbook of Laboratory Medicine, 7th Edition (block18, line 2864)
Spectrophotometric criteria:
  • Bilirubin: broad peak at 450-460 nm (pathognomonic - arises only from in vivo conversion, not traumatic tap)
  • Oxyhemoglobin: peak at 410-418 nm (can arise from traumatic tap; therefore less specific)
  • Only bilirubin is pathognomonic; oxyhemoglobin alone is insufficient for diagnosis

LP Timing Recommendations

  • LP should ideally be performed at least 12 hours after ictus to allow bilirubin formation (UK guideline recommendation)
  • However, in the ED, immediate LP after negative CT is acceptable with awareness: a very early LP (< 12 hours) showing only oxyhemoglobin and no bilirubin does NOT rule out SAH
  • The fourth (last) tube of CSF is preferred for spectrophotometry (least likely to reflect a traumatic tap)
  • Sample must be protected from light and centrifuged within 1 hour of collection
"It is worth noting that because bilirubin is produced in a time-dependent manner, the absence of detectable bilirubin does not rule out SAH, particularly if CSF is collected within 12 hours of the onset of the bleed."
  • Tietz Textbook of Laboratory Medicine, 7th Edition

CSF RBC Count as Adjunct

  • RBC count in the 3rd/4th CSF tube helps differentiate SAH from traumatic tap
  • If RBC count > 2,000 x 10⁶/L in a consistent manner across all tubes, SAH is suspected
  • A "traumatic tap" shows declining RBCs from tube 1 to tube 4
  • True xanthochromia (bilirubin) is pathognomonic and overrides any question of traumatic tap

Role of CT Angiography (CTA)

CTA can directly visualize the aneurysm and is recommended after positive CT or positive LP to locate the aneurysm source. It can also be used as an alternative to LP when:
  • LP is contraindicated
  • SAH is the only concern
  • The clinician accepts a small miss rate from incidental aneurysm findings (~2.5% of population)
If CTA is negative and SAH source is still sought, four-vessel conventional catheter angiography (DSA) with 3D reconstruction is mandatory.

Summary Table

Time from IctusTest of ChoiceSensitivityNotes
< 6 hoursNon-contrast CT head (NCCT)~98-100%Can rule out SAH alone if all criteria met; no LP needed in low-risk patients
6-24 hoursNCCT + LP (if CT negative)CT ~85-95%LP with xanthochromia is needed; shared decision-making for very low risk
> 24 hours - 2 weeksLP + CSF xanthochromia (spectrophotometry)CT declining rapidlyLP is primary test; spectrophotometry for bilirubin is gold standard
Any time if CT negativeLP (spectrophotometry)CSF bilirubin ~100% specific for SAHMinimum 12 hrs from ictus for reliable bilirubin formation

Key References

  1. Bradley and Daroff's Neurology in Clinical Practice - Subarachnoid Hemorrhage section (lines 1820-1838): CT sensitivity and LP role
  2. Tietz Textbook of Laboratory Medicine, 7th Edition - Evaluation for Subarachnoid Hemorrhage (Bilirubin, Xanthochromia) (p. 1634): spectrophotometry as gold standard
  3. Tintinalli's Emergency Medicine - NCCT and LP diagnostic criteria
  4. Roberts and Hedges' Clinical Procedures in Emergency - Spectrophotometry for xanthochromia interpretation
  5. Aaseth K et al. "Diagnostic workup of acute headache and subarachnoid hemorrhage in a Norwegian population." Eur J Neurol. 2024 Sep. [PMID: 39092827] - Confirms xanthochromia as gold standard beyond 6 hours
  6. Nowicki N et al. "Clinical-biological approaches to spectrophotometric detection of oxyhemoglobin and bilirubin in CSF in management of aneurysmal SAH." Ann Biol Clin (Paris). 2024 Nov. [PMID: 39612298]
  7. Sjulstad AS et al. "Visual inspection versus spectrophotometry for xanthochromia detection." Headache. 2025 Jan. [PMID: 39087907] - Confirms spectrophotometry superiority over visual inspection
  8. NICE Guideline NG228 - Diagnostic accuracy of investigations for aneurysmal SAH: supports CT within 6 hours then LP beyond 6 hours

Clinical and radiological gradings for SAH

Finding Sources
Finding Sources
Searching the Web

SAH clinical grading Hunt Hess WFNS Fisher scale modified Fisher radiological grading comparison 2024

Reading File
Reading File
Reading File
Reading File
Finding Sources
Searching PubMed

"subarachnoid hemorrhage" AND "grading scale" AND prognosis

Reading File
Reading File
Reading File
Loading Image
Reading Web Page

https://derangedphysiology.com/main/required-reading/neurolo…

I now have all the information needed for a complete, well-referenced answer. Let me compile it.

Clinical and Radiological Grading Systems for Subarachnoid Hemorrhage (SAH)

SAH grading systems serve two main purposes: clinical grades assess neurological status to guide surgical/endovascular timing and predict outcome; radiological grades quantify blood on CT to predict risk of vasospasm and delayed cerebral ischemia (DCI). The most widely used are discussed below.

CLINICAL GRADING SCALES

1. Hunt and Hess Scale (1968)

The oldest and most widely used clinical grading system, originally designed to guide surgical risk stratification.
"The Hunt-Hess grading system categorizes patients clinically... Presenting neurologic symptoms may range from mild headache to coma to sudden death."
  • Schwartz's Principles of Surgery, 11th Edition
GradeClinical PresentationHospital Mortality
0Asymptomatic; unruptured aneurysm-
1Awake; asymptomatic or mild headache; mild nuchal rigidity~3%
2Awake; moderate to severe headache, nuchal rigidity, possible cranial nerve palsy (e.g., CN III or IV)~3%
3Lethargic/drowsy, confused, mild focal neurological deficit (e.g., pronator drift)~9%
4Stuporous; significant neurological deficit (e.g., hemiplegia); possible early decerebrate posturing~24%
5Comatose; decerebrate posturing (moribund)~70%
Mortality data from 580 patients at Columbia University Medical Center - Goldman-Cecil Medicine
Clinical use:
  • Grades 1-3 = "good grade" - suitable for early surgery/coiling
  • Grades 4-5 = "poor grade" - require stabilization, may need delayed intervention
  • Grade 4 and 5 patients require intubation and hemodynamic monitoring
Limitations: Subjective grading - "vegetative disturbance" and "moribund appearance" are not well defined. Hunt and Hess themselves acknowledged the classifications are "arbitrary and that the margins between categories may be ill-defined."

2. World Federation of Neurosurgical Societies (WFNS) Scale (1988)

A more objective scale based on Glasgow Coma Scale (GCS) score and presence of motor deficit. Introduced to improve inter-rater reliability over Hunt-Hess.
"The WFNS SAH Grading Scale is also used for this purpose... Both scales are used in conjunction as a quick way to communicate severity of aneurysmal SAH."
  • Schwartz's Principles of Surgery, 11th Edition
GradeGCS ScoreMotor DeficitExpected Outcome
015AbsentUnruptured (some versions)
115AbsentGood
213-14AbsentGood
313-14PresentFair
47-12Present or absentPoor
53-6Present or absentVery poor
(From Tintinalli's Emergency Medicine, Table 166-3; Bradley and Daroff's Neurology in Clinical Practice, Table 67.2)
Advantages over Hunt-Hess:
  • Objective (uses GCS, a validated tool)
  • Motor deficit is a clear binary variable
  • Better inter-rater reliability
Limitations:
  • Requires accurate GCS scoring without sedation
  • Cannot be used in intubated/sedated patients
  • Motor deficit only truly distinguishes Grade 2 from Grade 3 (in grades 4 and 5, it is irrelevant)

Comparison: Hunt-Hess vs WFNS

FeatureHunt-HessWFNS
Year19681988
BasisClinical examGCS + motor deficit
ObjectivityLowerHigher
Sedated patientsUnreliableUnreliable
Primary useSurgical timing, prognosisUniversal grading, research

RADIOLOGICAL GRADING SCALES

3. Fisher Scale (1980)

The original CT-based grading system, designed to predict vasospasm risk based on the amount and distribution of subarachnoid blood.
"The extent of blood is a predictor of the probability of vasospasm and DCI."
  • Bradley and Daroff's Neurology in Clinical Practice
GroupCT FindingsVasospasm Risk
1No blood detectedLow
2Diffuse or thin layer of subarachnoid blood; all vertical layers < 1 mm (interhemispheric, insular, ambient cistern)Low
3Localized clots OR vertical layers of blood ≥ 1 mm thicknessHigh
4Diffuse or no subarachnoid blood, but with intraparenchymal or intraventricular clotsHigh
(From Bradley and Daroff's Neurology, Box 67.3 - Fisher Scale CT Classification)
Key point: Fisher Groups 3 and 4 are associated with highest vasospasm rates - thick subarachnoid blood and intraventricular hemorrhage (IVH) are the main risk factors.
Limitations:
  • Does not account for IVH in combination with thick SAH (Group 4 can paradoxically have less vasospasm than Group 3 in some series)
  • Does not differentiate risk when both thick blood AND IVH are present

4. Modified Fisher Scale (Claassen/Frontera, 2006)

A revised version addressing the main limitation of the original Fisher scale - it adds IVH as an independent variable.
GradeSubarachnoid BloodIntraventricular Hemorrhage (IVH)Symptomatic Vasospasm Risk
0NoneNone0%
1Focal or diffuse; thinNone24%
2Focal thin or diffusePresent33%
3ThickNone33%
4ThickPresent40%
(Frontera et al., Neurosurgery, 2006; Deranged Physiology; MDCalc)
Key improvements:
  • IVH is now a separate independent risk variable
  • Patients with IVH alone now score Grade 2, whereas on the original Fisher scale they would score Grade 1 or 0 - markedly underestimating their vasospasm risk
  • Specifically applies to aneurysmal SAH only
Remaining limitations:
  • Grades 2 and 3 have identical vasospasm incidence (33%) - insufficient separation of risk
  • Inter-rater reliability for "thick vs thin" blood is moderate (72-78%)

5. Hijdra Sum Score (Mentioned for Completeness)

A semi-quantitative CT grading scale that assesses blood volume in each of the 10 major subarachnoid cisterns and fissures, scoring 0-3 per region (total 0-30).
"After SAH, the Hijdra sum score seems to be superior to the more commonly used modified Fisher scale in assessing the amount of subarachnoid blood and in predicting the occurrence and severity of cerebral vasospasm."
  • Miller's Anesthesia, 10th Edition
Used primarily in research; less practical at bedside than Fisher/modified Fisher.

CT Image: Diffuse SAH

Below is a non-contrast CT showing diffuse subarachnoid blood in the cisterns (left), confirmed by CTA showing an anterior communicating artery aneurysm (right):
Non-contrast CT showing diffuse subarachnoid blood in the cisterns with CTA confirming anterior communicating artery aneurysm
Schwartz's Principles of Surgery, 11th Ed., Fig. 42-17

Summary Overview

ScaleTypeYearWhat It GradesPrimary Use
Hunt-HessClinical1968Neurological status (0-5)Surgical timing, outcome prediction
WFNSClinical1988GCS + motor deficit (0-5)Universal grading, research
FisherRadiological1980CT blood volume/distribution (1-4)Predicts vasospasm
Modified FisherRadiological2006CT blood + IVH (0-4)Predicts symptomatic vasospasm more accurately
Hijdra SumRadiological1985Semi-quantitative cisternal blood (0-30)Research; superior vasospasm prediction

Key References

  1. Bradley and Daroff's Neurology in Clinical Practice - Table 67.2 (Clinical Grading Scales) and Box 67.3 (Fisher Scale)
  2. Schwartz's Principles of Surgery, 11th Ed. - Table 42-5 (Hunt-Hess), WFNS discussion
  3. Tintinalli's Emergency Medicine - Table 166-3 (Hunt-Hess vs WFNS comparison)
  4. Goldman-Cecil Medicine - Table 377-3 (Hunt-Hess with mortality data)
  5. Miller's Anesthesia, 10th Ed. - Hijdra vs modified Fisher comparison
  6. Frontera JA et al. "Prediction of symptomatic vasospasm after subarachnoid hemorrhage: the modified Fisher scale." Neurosurgery. 2006;59(1):21-27.
  7. Drake CG. "Report of World Federation of Neurological Surgeons Committee on a Universal Subarachnoid Hemorrhage Grading Scale." J Neurosurg. 1988;68:985-986.
  8. Al-Mufti F et al. "The Modified Hunt and Hess Grading Scale." Stroke: Vascular and Interventional Neurology. 2024 - recent proposed modification

?

Could you clarify what you'd like to know? Are you asking me to:
  1. Continue with more detail on SAH grading (e.g., Ogilvy-Carter scale, Barrow Neurological Institute scale)?
  2. Move on to a new topic?
  3. Something specific you'd like me to explain differently or expand on?

Create a study guide PDF on SAH grading systems 20mins each for an hour; topic ecmo demystified basics to bedside; what all needs to be covered and or demonstrated - give a structured layout

Asking for Preferences
Reading File
Searching the Web

ECMO basics to bedside teaching session curriculum VV VA ECPella junior doctors 2024

Running Command

mkdir -p /home/daytona/workspace/sah-ecmo && ls /home/daytona/workspace/sah-ecmo/

Writing File

~/sah-ecmo/build_sah_pdf.py

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

# ── colour palette ──────────────────────────────────────────────────────────
NAVY    = colors.HexColor('#1a3a5c')
TEAL    = colors.HexColor('#2a7f8f')
AMBER   = colors.HexColor('#e07b23')
LTBLUE  = colors.HexColor('#ddeef6')
LTAMBER = colors.HexColor('#fef3e2')
WHITE   = colors.white
GREY    = colors.HexColor('#f4f6f8')
DKGREY  = colors.HexColor('#444444')
RED     = colors.HexColor('#c0392b')
GREEN   = colors.HexColor('#1e8449')

doc = SimpleDocTemplate(
    '/home/daytona/workspace/sah-ecmo/SAH_Grading_Study_Guide.pdf',
    pagesize=A4,
    leftMargin=1.8*cm, rightMargin=1.8*cm,
    topMargin=1.8*cm, bottomMargin=1.8*cm,
    title='SAH Grading Systems – Study Guide',
    author='Orris Medical Education'
)

styles = getSampleStyleSheet()

# Custom styles
def S(name, **kw):
    base = kw.pop('parent', 'Normal')
    return ParagraphStyle(name, parent=styles[base], **kw)

TITLE      = S('TITLE',    fontSize=22, textColor=WHITE,   alignment=TA_CENTER, fontName='Helvetica-Bold', spaceAfter=4)
SUBTITLE   = S('SUBTITLE', fontSize=12, textColor=LTBLUE,  alignment=TA_CENTER, fontName='Helvetica',      spaceAfter=6)
H1         = S('H1',       fontSize=15, textColor=WHITE,   fontName='Helvetica-Bold', spaceAfter=2, spaceBefore=2)
H2         = S('H2',       fontSize=12, textColor=NAVY,    fontName='Helvetica-Bold', spaceAfter=3, spaceBefore=6)
H3         = S('H3',       fontSize=10, textColor=TEAL,    fontName='Helvetica-Bold', spaceAfter=2, spaceBefore=4)
BODY       = S('BODY',     fontSize=9,  textColor=DKGREY,  fontName='Helvetica',      leading=14, spaceAfter=3, alignment=TA_JUSTIFY)
SMALL      = S('SMALL',    fontSize=8,  textColor=DKGREY,  fontName='Helvetica',      leading=11)
BADGE      = S('BADGE',    fontSize=8,  textColor=WHITE,   fontName='Helvetica-Bold', alignment=TA_CENTER)
TIMEBADGE  = S('TIMEBADGE',fontSize=9,  textColor=AMBER,   fontName='Helvetica-Bold')
CAPTION    = S('CAPTION',  fontSize=8,  textColor=colors.HexColor('#777777'), fontName='Helvetica-Oblique', alignment=TA_CENTER, spaceBefore=1)
BULLET     = S('BULLET',   fontSize=9,  textColor=DKGREY,  fontName='Helvetica', leading=13, leftIndent=12, spaceAfter=1)
KEY        = S('KEY',      fontSize=9,  textColor=NAVY,    fontName='Helvetica-Bold', leading=13, leftIndent=12, spaceAfter=1)

def banner(text, bg=NAVY, style=H1, height=0.7*cm):
    tbl = Table([[Paragraph(text, style)]], colWidths=[17.4*cm], rowHeights=[height])
    tbl.setStyle(TableStyle([
        ('BACKGROUND', (0,0),(-1,-1), bg),
        ('VALIGN',     (0,0),(-1,-1), 'MIDDLE'),
        ('LEFTPADDING',(0,0),(-1,-1), 8),
        ('RIGHTPADDING',(0,0),(-1,-1), 8),
        ('TOPPADDING', (0,0),(-1,-1), 4),
        ('BOTTOMPADDING',(0,0),(-1,-1), 4),
        ('ROUNDEDCORNERS',[3,3,3,3]),
    ]))
    return tbl

def section_banner(text, bg=TEAL):
    return banner(text, bg=bg, style=H1, height=0.65*cm)

def info_box(text, bg=LTBLUE, border=TEAL):
    tbl = Table([[Paragraph(text, BODY)]], colWidths=[17.4*cm])
    tbl.setStyle(TableStyle([
        ('BACKGROUND', (0,0),(-1,-1), bg),
        ('BOX',        (0,0),(-1,-1), 1.2, border),
        ('LEFTPADDING',(0,0),(-1,-1), 8),
        ('RIGHTPADDING',(0,0),(-1,-1), 8),
        ('TOPPADDING', (0,0),(-1,-1), 6),
        ('BOTTOMPADDING',(0,0),(-1,-1), 6),
    ]))
    return tbl

def warning_box(text):
    return info_box(f'<b>⚠ Key Point:</b> {text}', bg=LTAMBER, border=AMBER)

def two_col(left, right, lw=8.4*cm, rw=8.4*cm, gap=0.6*cm):
    tbl = Table([[left, right]], colWidths=[lw, rw])
    tbl.setStyle(TableStyle([
        ('VALIGN',(0,0),(-1,-1),'TOP'),
        ('LEFTPADDING',(0,0),(-1,-1),0),
        ('RIGHTPADDING',(0,0),(-1,-1),0),
    ]))
    return tbl

def grading_table(headers, rows, col_widths, header_bg=NAVY):
    data = [headers] + rows
    tbl = Table(data, colWidths=col_widths)
    n = len(rows)
    style = [
        ('BACKGROUND', (0,0), (-1,0), header_bg),
        ('TEXTCOLOR',  (0,0), (-1,0), WHITE),
        ('FONTNAME',   (0,0), (-1,0), 'Helvetica-Bold'),
        ('FONTSIZE',   (0,0), (-1,-1), 8.5),
        ('LEADING',    (0,0), (-1,-1), 12),
        ('ALIGN',      (0,0), (-1,-1), 'LEFT'),
        ('VALIGN',     (0,0), (-1,-1), 'MIDDLE'),
        ('GRID',       (0,0), (-1,-1), 0.4, colors.HexColor('#cccccc')),
        ('LEFTPADDING',(0,0), (-1,-1), 5),
        ('RIGHTPADDING',(0,0),(-1,-1), 5),
        ('TOPPADDING', (0,0), (-1,-1), 4),
        ('BOTTOMPADDING',(0,0),(-1,-1), 4),
    ]
    for i in range(1, n+1):
        bg = GREY if i % 2 == 0 else WHITE
        style.append(('BACKGROUND', (0,i), (-1,i), bg))
    tbl.setStyle(TableStyle(style))
    return tbl

def time_chip(label, color=TEAL):
    tbl = Table([[Paragraph(label, BADGE)]], colWidths=[3.2*cm], rowHeights=[0.45*cm])
    tbl.setStyle(TableStyle([
        ('BACKGROUND',(0,0),(-1,-1), color),
        ('VALIGN',(0,0),(-1,-1),'MIDDLE'),
        ('ALIGN',(0,0),(-1,-1),'CENTER'),
        ('LEFTPADDING',(0,0),(-1,-1),4),
        ('RIGHTPADDING',(0,0),(-1,-1),4),
        ('TOPPADDING',(0,0),(-1,-1),2),
        ('BOTTOMPADDING',(0,0),(-1,-1),2),
    ]))
    return tbl

def bullet_list(items, style=BULLET):
    return ListFlowable(
        [ListItem(Paragraph(i, style), leftIndent=10, bulletColor=TEAL, value='bullet') for i in items],
        bulletType='bullet', leftIndent=6, bulletFontSize=8
    )

# ═══════════════════════════════════════════════════════════════════════════
# BUILD STORY
# ═══════════════════════════════════════════════════════════════════════════
story = []

# ────────────────────────── COVER PAGE ─────────────────────────────────────
cover_bg = Table(
    [[Paragraph('SAH GRADING SYSTEMS', TITLE)],
     [Paragraph('A Structured 1-Hour Study Guide for Junior Doctors & Residents', SUBTITLE)],
     [Spacer(1, 0.3*cm)],
     [Paragraph('3 Sessions × 20 Minutes | Clinical + Radiological Grading | Prognostication', SUBTITLE)],
    ],
    colWidths=[17.4*cm]
)
cover_bg.setStyle(TableStyle([
    ('BACKGROUND',(0,0),(-1,-1), NAVY),
    ('TOPPADDING',(0,0),(-1,-1),14),
    ('BOTTOMPADDING',(0,0),(-1,-1),10),
    ('LEFTPADDING',(0,0),(-1,-1),16),
    ('RIGHTPADDING',(0,0),(-1,-1),16),
]))
story.append(cover_bg)
story.append(Spacer(1, 0.4*cm))

story.append(info_box(
    '<b>Learning Objectives:</b> By the end of this guide you will be able to: '
    '(1) apply the Hunt-Hess and WFNS clinical grading scales and interpret their prognostic value; '
    '(2) classify SAH on CT using the Fisher and modified Fisher scales; '
    '(3) correlate clinical and radiological grades to guide management decisions; '
    '(4) avoid common grading pitfalls at the bedside.'
))
story.append(Spacer(1, 0.3*cm))

# Session overview strip
session_data = [
    ['SESSION 1 – 20 min', 'SESSION 2 – 20 min', 'SESSION 3 – 20 min'],
    ['Why Grade SAH?\nHunt-Hess Scale\nWFNS Scale', 'Fisher Scale (CT)\nModified Fisher Scale\nCT Anatomy Review', 'Grade Correlation\nManagement Links\nQuick Quiz + Pitfalls'],
]
session_tbl = Table(session_data, colWidths=[5.6*cm, 5.6*cm, 5.6*cm])
session_tbl.setStyle(TableStyle([
    ('BACKGROUND',(0,0),(-1,0), TEAL),
    ('TEXTCOLOR',(0,0),(-1,0), WHITE),
    ('FONTNAME',(0,0),(-1,0),'Helvetica-Bold'),
    ('FONTNAME',(0,1),(-1,-1),'Helvetica'),
    ('FONTSIZE',(0,0),(-1,-1),9),
    ('ALIGN',(0,0),(-1,-1),'CENTER'),
    ('VALIGN',(0,0),(-1,-1),'MIDDLE'),
    ('GRID',(0,0),(-1,-1),0.5, WHITE),
    ('BACKGROUND',(0,1),(-1,-1), LTBLUE),
    ('TOPPADDING',(0,0),(-1,-1),5),
    ('BOTTOMPADDING',(0,0),(-1,-1),5),
    ('LEADING',(0,1),(-1,-1),14),
]))
story.append(session_tbl)
story.append(Spacer(1, 0.5*cm))
story.append(HRFlowable(width='100%', thickness=1, color=TEAL))
story.append(Spacer(1, 0.2*cm))

# ═══════════════════════════════════════════════════════════════════
# SESSION 1 – CLINICAL GRADING
# ═══════════════════════════════════════════════════════════════════
story.append(KeepTogether([
    banner('SESSION 1  |  Clinical Grading Scales', bg=NAVY),
    Spacer(1, 0.15*cm),
    two_col(
        time_chip('20 MINUTES', TEAL),
        Paragraph('Hunt-Hess Scale  •  WFNS Scale  •  Why grade at all?', H3)
    ),
    Spacer(1, 0.2*cm),
]))

story.append(H2('1.1  Why Do We Grade SAH?'))
story.append(BODY.__class__)  # placeholder - use Paragraph
story.append(Paragraph(
    'Grading SAH at presentation serves three critical purposes: '
    '(1) <b>communication</b> - a shared language for handovers, referrals and trials; '
    '(2) <b>prognostication</b> - predicting hospital mortality and neurological outcome; '
    '(3) <b>management decisions</b> - timing of surgery/coiling, ICU admission, and neuroprotection. '
    'Higher grade correlates with worse outcome; missing a grade change of even 1 point can indicate an evolving complication.',
    BODY
))
story.append(warning_box(
    'A decline of even 1 GCS point or new motor deficit should prompt immediate reassessment – '
    'it may signal rebleeding, hydrocephalus, or herniation.'
))
story.append(Spacer(1, 0.3*cm))

story.append(H2('1.2  Hunt-Hess Scale  (Hunt & Hess, 1968)'))
story.append(Paragraph(
    'The oldest widely used clinical grading scale. Originally designed as a guide to surgical risk. '
    'Grades 1-3 = "good grade" (suitable for early intervention); grades 4-5 = "poor grade" (requires stabilisation first).',
    BODY
))
story.append(Spacer(1, 0.15*cm))

hh_table = grading_table(
    [Paragraph('<b>Grade</b>', SMALL), Paragraph('<b>Clinical Findings</b>', SMALL),
     Paragraph('<b>Hospital Mortality</b>', SMALL), Paragraph('<b>Key Feature</b>', SMALL)],
    [
        [Paragraph('<b>0</b>', SMALL), Paragraph('Unruptured aneurysm – asymptomatic', SMALL), Paragraph('-', SMALL), Paragraph('Incidental finding', SMALL)],
        [Paragraph('<b>1</b>', SMALL), Paragraph('Asymptomatic or mild headache; slight nuchal rigidity', SMALL), Paragraph('~3%', SMALL), Paragraph('No deficit', SMALL)],
        [Paragraph('<b>2</b>', SMALL), Paragraph('Moderate-severe headache; nuchal rigidity; possible CN palsy (III/IV)', SMALL), Paragraph('~3%', SMALL), Paragraph('CN palsy only', SMALL)],
        [Paragraph('<b>3</b>', SMALL), Paragraph('Drowsy/confused; mild focal deficit (e.g. pronator drift)', SMALL), Paragraph('~9%', SMALL), Paragraph('Altered consciousness', SMALL)],
        [Paragraph('<b>4</b>', SMALL), Paragraph('Stupor; moderate-severe hemiparesis; early decerebrate posturing', SMALL), Paragraph('~24%', SMALL), Paragraph('Stupor + motor deficit', SMALL)],
        [Paragraph('<b>5</b>', SMALL), Paragraph('Deep coma; decerebrate rigidity; moribund', SMALL), Paragraph('~70%', SMALL), Paragraph('Coma', SMALL)],
    ],
    [1.2*cm, 7.0*cm, 3.0*cm, 4.2*cm],
    header_bg=NAVY
)
story.append(hh_table)
story.append(Paragraph('Source: Goldman-Cecil Medicine; Columbia University Medical Center data (n=580)', CAPTION))
story.append(Spacer(1, 0.25*cm))

story.append(info_box(
    '<b>Limitations of Hunt-Hess:</b> Subjective descriptors ("vegetative disturbance", "moribund appearance"). '
    'Hunt and Hess themselves wrote: <i>"It is recognized that such classifications are arbitrary and that '
    'the margins between categories may be ill defined."</i> Inter-rater variability is a known issue.'
))
story.append(Spacer(1, 0.3*cm))

story.append(H2('1.3  WFNS Scale  (World Federation of Neurological Surgeons, 1988)'))
story.append(Paragraph(
    'A more objective scale based on GCS score + presence of motor deficit. '
    'Introduced to improve inter-rater reliability and international standardisation.',
    BODY
))
story.append(Spacer(1, 0.15*cm))

wfns_table = grading_table(
    [Paragraph('<b>Grade</b>', SMALL), Paragraph('<b>GCS Score</b>', SMALL),
     Paragraph('<b>Motor Deficit</b>', SMALL), Paragraph('<b>Prognosis</b>', SMALL)],
    [
        [Paragraph('<b>1</b>', SMALL), Paragraph('15', SMALL), Paragraph('Absent', SMALL), Paragraph('Good', SMALL)],
        [Paragraph('<b>2</b>', SMALL), Paragraph('13-14', SMALL), Paragraph('Absent', SMALL), Paragraph('Good-Fair', SMALL)],
        [Paragraph('<b>3</b>', SMALL), Paragraph('13-14', SMALL), Paragraph('Present', SMALL), Paragraph('Fair', SMALL)],
        [Paragraph('<b>4</b>', SMALL), Paragraph('7-12', SMALL), Paragraph('Present or absent', SMALL), Paragraph('Poor', SMALL)],
        [Paragraph('<b>5</b>', SMALL), Paragraph('3-6', SMALL), Paragraph('Present or absent', SMALL), Paragraph('Very poor', SMALL)],
    ],
    [2.0*cm, 3.5*cm, 4.5*cm, 7.4*cm],
    header_bg=TEAL
)
story.append(wfns_table)
story.append(Spacer(1, 0.2*cm))

story.append(H2('1.4  Hunt-Hess vs WFNS – Side-by-Side'))
compare_data = [
    [Paragraph('<b>Feature</b>', SMALL), Paragraph('<b>Hunt-Hess</b>', SMALL), Paragraph('<b>WFNS</b>', SMALL)],
    [Paragraph('Year', SMALL), Paragraph('1968', SMALL), Paragraph('1988', SMALL)],
    [Paragraph('Basis', SMALL), Paragraph('Clinical descriptors', SMALL), Paragraph('GCS + motor deficit', SMALL)],
    [Paragraph('Objectivity', SMALL), Paragraph('Lower', SMALL), Paragraph('Higher', SMALL)],
    [Paragraph('Sedated patients', SMALL), Paragraph('Unreliable', SMALL), Paragraph('Unreliable', SMALL)],
    [Paragraph('Primary use', SMALL), Paragraph('Surgical timing, prognosis', SMALL), Paragraph('Universal grading, research', SMALL)],
    [Paragraph('Good/Poor grade cut-off', SMALL), Paragraph('Grade ≤3 = good', SMALL), Paragraph('Grade ≤2 = good', SMALL)],
]
compare_tbl = Table(compare_data, colWidths=[4.0*cm, 6.5*cm, 6.5*cm])
compare_tbl.setStyle(TableStyle([
    ('BACKGROUND',(0,0),(-1,0), NAVY),
    ('TEXTCOLOR',(0,0),(-1,0), WHITE),
    ('FONTNAME',(0,0),(-1,0),'Helvetica-Bold'),
    ('FONTSIZE',(0,0),(-1,-1),8.5),
    ('GRID',(0,0),(-1,-1),0.4, colors.HexColor('#cccccc')),
    ('VALIGN',(0,0),(-1,-1),'MIDDLE'),
    ('TOPPADDING',(0,0),(-1,-1),4),
    ('BOTTOMPADDING',(0,0),(-1,-1),4),
    ('LEFTPADDING',(0,0),(-1,-1),5),
    ('BACKGROUND',(0,2),(-1,2), GREY),
    ('BACKGROUND',(0,4),(-1,4), GREY),
    ('BACKGROUND',(0,6),(-1,6), GREY),
]))
story.append(compare_tbl)
story.append(Spacer(1, 0.3*cm))

story.append(H2('1.5  Session 1 Self-Check'))
story.append(bullet_list([
    'A 54-year-old presents with thunderclap headache, GCS 15, neck stiffness, no focal deficit – what Hunt-Hess and WFNS grade?  <i>[Ans: HH Grade 1-2; WFNS Grade 1]</i>',
    'A patient is stuporous with right hemiplegia – what Hunt-Hess grade?  <i>[Ans: HH Grade 4]</i>',
    'Why might WFNS be preferred in a multi-centre trial over Hunt-Hess?  <i>[Ans: objective, reproducible GCS-based scoring]</i>',
    'At what Hunt-Hess grade would you consider delaying aneurysm surgery? <i>[Ans: Grade 4-5 – stabilise first]</i>',
]))

story.append(PageBreak())

# ═══════════════════════════════════════════════════════════════════
# SESSION 2 – RADIOLOGICAL GRADING
# ═══════════════════════════════════════════════════════════════════
story.append(KeepTogether([
    banner('SESSION 2  |  Radiological Grading (CT-Based)', bg=NAVY),
    Spacer(1, 0.15*cm),
    two_col(
        time_chip('20 MINUTES', TEAL),
        Paragraph('Fisher Scale  •  Modified Fisher Scale  •  CT Anatomy', H3)
    ),
    Spacer(1, 0.2*cm),
]))

story.append(H2('2.1  What Does CT Tell Us About SAH?'))
story.append(Paragraph(
    'Non-contrast CT (NCCT) is the first-line investigation for SAH. Beyond <i>diagnosing</i> the bleed, '
    'CT findings predict the risk of <b>vasospasm</b> and <b>delayed cerebral ischaemia (DCI)</b> – '
    'the leading cause of morbidity and mortality after the initial bleed. '
    'The two key CT grading systems are the Fisher Scale (1980) and the Modified Fisher Scale (2006).',
    BODY
))
story.append(info_box(
    '<b>CT Anatomy Reminder – Know These Structures:</b> '
    'Basal cisterns (suprasellar, ambient, quadrigeminal, sylvian fissure), '
    'interhemispheric fissure, cerebral ventricles (I-IV), subarachnoid space vs parenchyma. '
    'Blood in the <i>subarachnoid space</i> appears as hyperdense (bright white) filling of the cisterns/fissures.'
))
story.append(Spacer(1, 0.3*cm))

story.append(H2('2.2  Fisher Scale  (Fisher et al., 1980)'))
story.append(Paragraph(
    'Designed to predict the <b>risk of symptomatic vasospasm</b> based on the amount and pattern of '
    'subarachnoid blood on CT. Groups 3 and 4 carry the highest vasospasm risk.',
    BODY
))
story.append(Spacer(1, 0.15*cm))

fisher_table = grading_table(
    [Paragraph('<b>Group</b>', SMALL), Paragraph('<b>CT Finding</b>', SMALL), Paragraph('<b>Vasospasm Risk</b>', SMALL)],
    [
        [Paragraph('<b>1</b>', SMALL), Paragraph('No blood detected on CT', SMALL), Paragraph('Low', SMALL)],
        [Paragraph('<b>2</b>', SMALL), Paragraph('Diffuse or thin layer of subarachnoid blood; all vertical layers <1 mm thick\n(interhemispheric fissure, insular cistern, ambient cistern)', SMALL), Paragraph('Low-Moderate', SMALL)],
        [Paragraph('<b>3</b>', SMALL), Paragraph('Localised clots OR vertical layers ≥1 mm thickness', SMALL), Paragraph('<b>HIGH</b>', SMALL)],
        [Paragraph('<b>4</b>', SMALL), Paragraph('Diffuse or no subarachnoid blood BUT intraparenchymal or intraventricular clots present', SMALL), Paragraph('<b>HIGH</b>', SMALL)],
    ],
    [1.8*cm, 10.6*cm, 5.0*cm],
    header_bg=NAVY
)
story.append(fisher_table)
story.append(Spacer(1, 0.2*cm))

story.append(warning_box(
    'Fisher Group 4 can paradoxically predict less vasospasm than Group 3 in some series – '
    'this is the key limitation the Modified Fisher Scale was designed to correct.'
))
story.append(Spacer(1, 0.3*cm))

story.append(H2('2.3  Modified Fisher Scale  (Frontera et al., 2006)'))
story.append(Paragraph(
    'Revised to address the Fisher scale\'s failure to account for intraventricular haemorrhage (IVH) '
    'as an independent risk factor for vasospasm. IVH is now a separate variable on a 0-4 scale.',
    BODY
))
story.append(Spacer(1, 0.15*cm))

mf_table = grading_table(
    [Paragraph('<b>Grade</b>', SMALL), Paragraph('<b>Subarachnoid Blood</b>', SMALL),
     Paragraph('<b>IVH</b>', SMALL), Paragraph('<b>Symptomatic Vasospasm Risk</b>', SMALL)],
    [
        [Paragraph('<b>0</b>', SMALL), Paragraph('None', SMALL), Paragraph('None', SMALL), Paragraph('0%', SMALL)],
        [Paragraph('<b>1</b>', SMALL), Paragraph('Focal or diffuse; thin', SMALL), Paragraph('None', SMALL), Paragraph('24%', SMALL)],
        [Paragraph('<b>2</b>', SMALL), Paragraph('Focal thin or diffuse', SMALL), Paragraph('Present', SMALL), Paragraph('33%', SMALL)],
        [Paragraph('<b>3</b>', SMALL), Paragraph('Thick', SMALL), Paragraph('None', SMALL), Paragraph('33%', SMALL)],
        [Paragraph('<b>4</b>', SMALL), Paragraph('Thick', SMALL), Paragraph('Present', SMALL), Paragraph('40% (highest)', SMALL)],
    ],
    [1.8*cm, 5.8*cm, 2.8*cm, 7.0*cm],
    header_bg=TEAL
)
story.append(mf_table)
story.append(Paragraph('Source: Frontera JA et al. Neurosurgery. 2006;59(1):21-27', CAPTION))
story.append(Spacer(1, 0.2*cm))

story.append(H2('2.4  Fisher vs Modified Fisher – Key Differences'))
story.append(Paragraph(
    'The main change: <b>IVH is now an independent risk variable</b>. A patient with IVH but no subarachnoid blood '
    'scores Modified Fisher Grade 2 (33% vasospasm risk) – on the original scale they would score Group 1 (low risk), '
    'drastically underestimating their risk. This is clinically significant.',
    BODY
))
story.append(Spacer(1, 0.15*cm))

story.append(info_box(
    '<b>Limitations of Modified Fisher:</b> '
    '(1) Grades 2 and 3 have identical vasospasm incidence (33%) – insufficient separation. '
    '(2) Inter-rater reliability for "thick vs thin" blood is only moderate (72-78%). '
    '(3) The Hijdra Sum Score is more quantitative and may be superior for research purposes '
    '(Miller\'s Anesthesia, 10th Ed.).'
))
story.append(Spacer(1, 0.2*cm))

story.append(H2('2.5  Session 2 Self-Check'))
story.append(bullet_list([
    'CT shows thick blood in the basal cisterns, no IVH – what Modified Fisher grade and vasospasm risk? <i>[Ans: Grade 3, 33%]</i>',
    'CT shows thin SAH + blood in both lateral ventricles – what Modified Fisher grade? <i>[Ans: Grade 2, 33%]</i>',
    'Which Fisher group can have HIGH vasospasm risk despite minimal subarachnoid blood? <i>[Ans: Group 4 – due to IVH/parenchymal clot]</i>',
    'A patient has Fisher Group 1 – do they need vasospasm monitoring? <i>[Ans: Low risk but clinical vigilance still required]</i>',
]))

story.append(PageBreak())

# ═══════════════════════════════════════════════════════════════════
# SESSION 3 – INTEGRATION + MANAGEMENT + QUIZ
# ═══════════════════════════════════════════════════════════════════
story.append(KeepTogether([
    banner('SESSION 3  |  Grade Correlation, Management & Pitfalls', bg=NAVY),
    Spacer(1, 0.15*cm),
    two_col(
        time_chip('20 MINUTES', TEAL),
        Paragraph('Clinical-Radiological Correlation  •  Management Decisions  •  Quick Quiz', H3)
    ),
    Spacer(1, 0.2*cm),
]))

story.append(H2('3.1  Putting It Together – Clinical + CT Grade Correlation'))
story.append(Paragraph(
    'Clinical grade and CT grade are <b>complementary</b> – use both together to guide decisions. '
    'A good clinical grade with a bad CT grade (or vice versa) should raise suspicion and heighten monitoring.',
    BODY
))
story.append(Spacer(1, 0.15*cm))

integration_table = grading_table(
    [Paragraph('<b>Clinical Grade</b>', SMALL), Paragraph('<b>CT (Modified Fisher)</b>', SMALL),
     Paragraph('<b>Interpretation & Action</b>', SMALL)],
    [
        [Paragraph('HH 1-2 / WFNS 1-2', SMALL), Paragraph('mFisher 0-1', SMALL), Paragraph('Good grade, low vasospasm risk – early aneurysm treatment, standard monitoring', SMALL)],
        [Paragraph('HH 1-2 / WFNS 1-2', SMALL), Paragraph('mFisher 3-4', SMALL), Paragraph('Good grade but HIGH vasospasm risk – early treatment, aggressive vasospasm surveillance', SMALL)],
        [Paragraph('HH 3 / WFNS 3', SMALL), Paragraph('mFisher 2-3', SMALL), Paragraph('Moderate grade – ICU admission, close neuro obs, consider early intervention', SMALL)],
        [Paragraph('HH 4-5 / WFNS 4-5', SMALL), Paragraph('mFisher 3-4', SMALL), Paragraph('Poor grade + high bleed burden – intubate, ICP monitoring, stabilise before intervention', SMALL)],
    ],
    [4.2*cm, 3.8*cm, 9.4*cm],
    header_bg=NAVY
)
story.append(integration_table)
story.append(Spacer(1, 0.3*cm))

story.append(H2('3.2  Management Pearls by Grade'))
story.append(Spacer(1, 0.1*cm))

mgmt_data = [
    [Paragraph('<b>Domain</b>', SMALL), Paragraph('<b>Good Grade (HH 1-3)</b>', SMALL), Paragraph('<b>Poor Grade (HH 4-5)</b>', SMALL)],
    [Paragraph('Airway', SMALL), Paragraph('Self-maintaining; monitor closely', SMALL), Paragraph('Intubate and ventilate', SMALL)],
    [Paragraph('Aneurysm Tx', SMALL), Paragraph('Early coiling/clipping (within 24-72h)', SMALL), Paragraph('Stabilise first; delayed if needed', SMALL)],
    [Paragraph('Blood Pressure', SMALL), Paragraph('SBP 120-160 mmHg until secured', SMALL), Paragraph('Tight control; titrate to CPP 60-80', SMALL)],
    [Paragraph('Nimodipine', SMALL), Paragraph('60mg q4h × 21 days (all grades)', SMALL), Paragraph('60mg q4h × 21 days (all grades)', SMALL)],
    [Paragraph('Vasospasm watch', SMALL), Paragraph('TCD daily; clinical exam q4-6h', SMALL), Paragraph('TCD + continuous EEG; ICP monitoring', SMALL)],
    [Paragraph('Hydrocephalus', SMALL), Paragraph('Monitor; LP or EVD if symptomatic', SMALL), Paragraph('EVD early if acute obstructive hydrocephalus', SMALL)],
    [Paragraph('Seizure prophylaxis', SMALL), Paragraph('Levetiracetam if seizure occurs; stop after aneurysm secured', SMALL), Paragraph('Continued AED + EEG monitoring', SMALL)],
]
mgmt_tbl = Table(mgmt_data, colWidths=[3.5*cm, 6.6*cm, 6.6*cm])
mgmt_tbl.setStyle(TableStyle([
    ('BACKGROUND',(0,0),(-1,0), TEAL),
    ('TEXTCOLOR',(0,0),(-1,0), WHITE),
    ('FONTNAME',(0,0),(-1,0),'Helvetica-Bold'),
    ('FONTSIZE',(0,0),(-1,-1),8.5),
    ('GRID',(0,0),(-1,-1),0.4, colors.HexColor('#cccccc')),
    ('VALIGN',(0,0),(-1,-1),'MIDDLE'),
    ('TOPPADDING',(0,0),(-1,-1),4),
    ('BOTTOMPADDING',(0,0),(-1,-1),4),
    ('LEFTPADDING',(0,0),(-1,-1),5),
    ('BACKGROUND',(0,2),(-1,2), GREY),
    ('BACKGROUND',(0,4),(-1,4), GREY),
    ('BACKGROUND',(0,6),(-1,6), GREY),
]))
story.append(mgmt_tbl)
story.append(Spacer(1, 0.3*cm))

story.append(H2('3.3  Common Pitfalls – Do Not Miss'))
story.append(bullet_list([
    '<b>Pitfall 1:</b> Grading on admission only. SAH grade can change rapidly – reassess every 4-6 hours.',
    '<b>Pitfall 2:</b> Using Hunt-Hess on a sedated/intubated patient. Both HH and WFNS are invalid post-sedation – document the pre-sedation grade.',
    '<b>Pitfall 3:</b> Fisher Group 1 = "safe". CT-negative SAH exists; always correlate with LP if clinical suspicion is high.',
    '<b>Pitfall 4:</b> Ignoring IVH on CT. A normal-looking cistern with bilateral IVH is Modified Fisher Grade 2 (33% vasospasm risk) – not low risk.',
    '<b>Pitfall 5:</b> Diagnosing grade without reading the CT personally. Know the cistern anatomy – do not rely solely on the radiology report.',
    '<b>Pitfall 6:</b> Equating poor grade with futility. Hunt-Hess Grade 5 carries 70% mortality but 30% can survive – do not automatically withdraw care without senior discussion.',
]))
story.append(Spacer(1, 0.25*cm))

story.append(H2('3.4  Quick Quiz – 5 Questions'))
story.append(info_box(
    '<b>Q1.</b> A patient has thunderclap headache, GCS 14, right CN III palsy. No motor deficit. '
    'CT shows thin diffuse SAH, no IVH. State: Hunt-Hess grade, WFNS grade, Modified Fisher grade. '
    'What is the vasospasm risk? <br/><br/>'
    '<b>Q2.</b> CT shows thick blood in the basal cisterns + blood in both lateral ventricles. '
    'What is the Modified Fisher grade and the expected vasospasm incidence?<br/><br/>'
    '<b>Q3.</b> Why is WFNS Grade 3 higher risk than Grade 2 despite the same GCS? <br/><br/>'
    '<b>Q4.</b> At what time post-ictus should nimodipine be started, and for how long? <br/><br/>'
    '<b>Q5.</b> A patient admitted as Hunt-Hess Grade 2 suddenly drops to Grade 3. What are the three most likely causes?'
))
story.append(Spacer(1, 0.15*cm))
story.append(info_box(
    '<b>Answers:</b><br/>'
    'Q1: HH Grade 2 (severe headache + CN palsy only); WFNS Grade 2 (GCS 13-14, no motor); mFisher Grade 1 (thin diffuse, no IVH) → 24% vasospasm risk.<br/>'
    'Q2: Modified Fisher Grade 4 (thick SAH + IVH present) → 40% vasospasm risk.<br/>'
    'Q3: WFNS Grade 3 adds motor deficit to GCS 13-14, indicating greater neurological injury.<br/>'
    'Q4: Within 48 hours of haemorrhage; continued for 21 days (60 mg every 4 hours).<br/>'
    'Q5: (1) Rebleeding; (2) Acute hydrocephalus; (3) Cerebral vasospasm/DCI.',
    bg=LTAMBER, border=AMBER
))
story.append(Spacer(1, 0.3*cm))

story.append(H2('3.5  Full Grading Summary – Quick Reference'))
story.append(Spacer(1, 0.1*cm))

summary_data = [
    [Paragraph('<b>Scale</b>', SMALL), Paragraph('<b>Type</b>', SMALL), Paragraph('<b>Year</b>', SMALL),
     Paragraph('<b>What It Grades</b>', SMALL), Paragraph('<b>Primary Use</b>', SMALL)],
    [Paragraph('Hunt-Hess', SMALL), Paragraph('Clinical', SMALL), Paragraph('1968', SMALL),
     Paragraph('Neurological status (0-5)', SMALL), Paragraph('Surgical timing, prognosis', SMALL)],
    [Paragraph('WFNS', SMALL), Paragraph('Clinical', SMALL), Paragraph('1988', SMALL),
     Paragraph('GCS + motor deficit (1-5)', SMALL), Paragraph('Universal grading, research', SMALL)],
    [Paragraph('Fisher', SMALL), Paragraph('Radiological', SMALL), Paragraph('1980', SMALL),
     Paragraph('CT blood volume/distribution (1-4)', SMALL), Paragraph('Predicts vasospasm', SMALL)],
    [Paragraph('Modified Fisher', SMALL), Paragraph('Radiological', SMALL), Paragraph('2006', SMALL),
     Paragraph('CT blood + IVH (0-4)', SMALL), Paragraph('More accurate vasospasm prediction', SMALL)],
    [Paragraph('Hijdra Sum Score', SMALL), Paragraph('Radiological', SMALL), Paragraph('1985', SMALL),
     Paragraph('Semi-quantitative cisternal blood (0-30)', SMALL), Paragraph('Research; superior vasospasm prediction', SMALL)],
]
summary_tbl = Table(summary_data, colWidths=[3.2*cm, 2.2*cm, 1.5*cm, 5.3*cm, 5.2*cm])
summary_tbl.setStyle(TableStyle([
    ('BACKGROUND',(0,0),(-1,0), NAVY),
    ('TEXTCOLOR',(0,0),(-1,0), WHITE),
    ('FONTNAME',(0,0),(-1,0),'Helvetica-Bold'),
    ('FONTSIZE',(0,0),(-1,-1),8.5),
    ('GRID',(0,0),(-1,-1),0.4, colors.HexColor('#cccccc')),
    ('VALIGN',(0,0),(-1,-1),'MIDDLE'),
    ('TOPPADDING',(0,0),(-1,-1),4),
    ('BOTTOMPADDING',(0,0),(-1,-1),4),
    ('LEFTPADDING',(0,0),(-1,-1),5),
    ('BACKGROUND',(0,2),(-1,2), GREY),
    ('BACKGROUND',(0,4),(-1,4), GREY),
]))
story.append(summary_tbl)
story.append(Spacer(1, 0.3*cm))

# Footer strip
footer_data = [[
    Paragraph('References: Bradley & Daroff\'s Neurology | Tintinalli\'s Emergency Medicine | '
              'Schwartz\'s Surgery 11e | Goldman-Cecil Medicine | Tietz Textbook Lab Medicine | '
              'Frontera JA et al. Neurosurgery 2006', CAPTION),
]]
footer_tbl = Table(footer_data, colWidths=[17.4*cm])
footer_tbl.setStyle(TableStyle([
    ('BACKGROUND',(0,0),(-1,-1), NAVY),
    ('TOPPADDING',(0,0),(-1,-1),5),
    ('BOTTOMPADDING',(0,0),(-1,-1),5),
    ('LEFTPADDING',(0,0),(-1,-1),8),
    ('TEXTCOLOR',(0,0),(-1,-1), LTBLUE),
]))
story.append(footer_tbl)

# ── Build ──────────────────────────────────────────────────────────────────
# Remove stray class references
story = [s for s in story if not isinstance(s, type)]

doc.build(story)
print("PDF built successfully.")
Running Command

cd /home/daytona/workspace/sah-ecmo && python build_sah_pdf.py 2>&1

Running Command

cd /home/daytona/workspace/sah-ecmo && python -c " from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle from reportlab.lib import colors from reportlab.platypus import Paragraph styles = getSampleStyleSheet() NAVY = colors.HexColor('#1a3a5c') h2style = ParagraphStyle('MyH2', parent=styles['Normal'], fontSize=12, textColor=NAVY, fontName='Helvetica-Bold') p = Paragraph('Test', h2style) print('OK') "

Writing File

~/sah-ecmo/build_sah_pdf.py

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

# ── Colours ──────────────────────────────────────────────────────────────
NAVY    = colors.HexColor('#1a3a5c')
TEAL    = colors.HexColor('#2a7f8f')
AMBER   = colors.HexColor('#e07b23')
LTBLUE  = colors.HexColor('#ddeef6')
LTAMBER = colors.HexColor('#fef3e2')
WHITE   = colors.white
GREY    = colors.HexColor('#f4f6f8')
DKGREY  = colors.HexColor('#444444')
MIDGREY = colors.HexColor('#cccccc')

# ── Styles ────────────────────────────────────────────────────────────────
_base = getSampleStyleSheet()

def sty(name, **kw):
    parent = kw.pop('parent', 'Normal')
    return ParagraphStyle(name, parent=_base[parent], **kw)

st_title    = sty('st_title',   fontSize=22, textColor=WHITE,  alignment=TA_CENTER, fontName='Helvetica-Bold', spaceAfter=4)
st_subtitle = sty('st_subtitle',fontSize=11, textColor=LTBLUE, alignment=TA_CENTER, fontName='Helvetica',      spaceAfter=4)
st_h1       = sty('st_h1',     fontSize=14, textColor=WHITE,  fontName='Helvetica-Bold', spaceAfter=2, spaceBefore=2)
st_h2       = sty('st_h2',     fontSize=12, textColor=NAVY,   fontName='Helvetica-Bold', spaceAfter=3, spaceBefore=6)
st_h3       = sty('st_h3',     fontSize=10, textColor=TEAL,   fontName='Helvetica-Bold', spaceAfter=2, spaceBefore=3)
st_body     = sty('st_body',   fontSize=9,  textColor=DKGREY, fontName='Helvetica',      leading=13, spaceAfter=3, alignment=TA_JUSTIFY)
st_small    = sty('st_small',  fontSize=8.5,textColor=DKGREY, fontName='Helvetica',      leading=11)
st_badge    = sty('st_badge',  fontSize=8,  textColor=WHITE,  fontName='Helvetica-Bold', alignment=TA_CENTER)
st_caption  = sty('st_caption',fontSize=7.5,textColor=colors.HexColor('#888888'), fontName='Helvetica-Oblique', alignment=TA_CENTER, spaceBefore=1)
st_bullet   = sty('st_bullet', fontSize=9,  textColor=DKGREY, fontName='Helvetica', leading=13, leftIndent=8, spaceAfter=1)

# ── Helper functions ───────────────────────────────────────────────────────
def P(txt, style=None):
    return Paragraph(txt, style or st_body)

def banner(text, bg=NAVY, style=None, height=0.65*cm):
    s = style or st_h1
    tbl = Table([[P(text, s)]], colWidths=[17.4*cm], rowHeights=[height])
    tbl.setStyle(TableStyle([
        ('BACKGROUND',   (0,0),(-1,-1), bg),
        ('VALIGN',       (0,0),(-1,-1), 'MIDDLE'),
        ('LEFTPADDING',  (0,0),(-1,-1), 10),
        ('RIGHTPADDING', (0,0),(-1,-1), 10),
        ('TOPPADDING',   (0,0),(-1,-1), 4),
        ('BOTTOMPADDING',(0,0),(-1,-1), 4),
    ]))
    return tbl

def info_box(text, bg=LTBLUE, border=TEAL):
    tbl = Table([[P(text, st_body)]], colWidths=[17.4*cm])
    tbl.setStyle(TableStyle([
        ('BACKGROUND',   (0,0),(-1,-1), bg),
        ('BOX',          (0,0),(-1,-1), 1.2, border),
        ('LEFTPADDING',  (0,0),(-1,-1), 8),
        ('RIGHTPADDING', (0,0),(-1,-1), 8),
        ('TOPPADDING',   (0,0),(-1,-1), 6),
        ('BOTTOMPADDING',(0,0),(-1,-1), 6),
    ]))
    return tbl

def warn_box(text):
    return info_box(f'<b>Key Point: </b>{text}', bg=LTAMBER, border=AMBER)

def time_chip(label, bg=TEAL):
    tbl = Table([[P(label, st_badge)]], colWidths=[3.4*cm], rowHeights=[0.5*cm])
    tbl.setStyle(TableStyle([
        ('BACKGROUND',   (0,0),(-1,-1), bg),
        ('VALIGN',       (0,0),(-1,-1), 'MIDDLE'),
        ('ALIGN',        (0,0),(-1,-1), 'CENTER'),
        ('LEFTPADDING',  (0,0),(-1,-1), 4),
        ('RIGHTPADDING', (0,0),(-1,-1), 4),
    ]))
    return tbl

def two_col(left, right, lw=4.0*cm, rw=13.0*cm):
    tbl = Table([[left, right]], colWidths=[lw, rw])
    tbl.setStyle(TableStyle([
        ('VALIGN',      (0,0),(-1,-1), 'MIDDLE'),
        ('LEFTPADDING', (0,0),(-1,-1), 0),
        ('RIGHTPADDING',(0,0),(-1,-1), 0),
        ('TOPPADDING',  (0,0),(-1,-1), 0),
        ('BOTTOMPADDING',(0,0),(-1,-1), 0),
    ]))
    return tbl

def data_table(headers, rows, col_widths, hdr_bg=NAVY):
    data = [headers] + rows
    tbl = Table(data, colWidths=col_widths)
    n = len(rows)
    ts = [
        ('BACKGROUND',   (0,0),(-1,0), hdr_bg),
        ('TEXTCOLOR',    (0,0),(-1,0), WHITE),
        ('FONTNAME',     (0,0),(-1,0), 'Helvetica-Bold'),
        ('FONTSIZE',     (0,0),(-1,-1), 8.5),
        ('LEADING',      (0,0),(-1,-1), 12),
        ('ALIGN',        (0,0),(-1,-1), 'LEFT'),
        ('VALIGN',       (0,0),(-1,-1), 'MIDDLE'),
        ('GRID',         (0,0),(-1,-1), 0.4, MIDGREY),
        ('LEFTPADDING',  (0,0),(-1,-1), 5),
        ('RIGHTPADDING', (0,0),(-1,-1), 5),
        ('TOPPADDING',   (0,0),(-1,-1), 4),
        ('BOTTOMPADDING',(0,0),(-1,-1), 4),
    ]
    for i in range(1, n+1):
        if i % 2 == 0:
            ts.append(('BACKGROUND', (0,i),(-1,i), GREY))
    tbl.setStyle(TableStyle(ts))
    return tbl

def bullets(items):
    return ListFlowable(
        [ListItem(P(item, st_bullet), leftIndent=10, bulletColor=TEAL, value='bullet') for item in items],
        bulletType='bullet', leftIndent=6, bulletFontSize=8
    )

# ── Document ──────────────────────────────────────────────────────────────
doc = SimpleDocTemplate(
    '/home/daytona/workspace/sah-ecmo/SAH_Grading_Study_Guide.pdf',
    pagesize=A4,
    leftMargin=1.8*cm, rightMargin=1.8*cm,
    topMargin=1.8*cm,  bottomMargin=1.8*cm,
    title='SAH Grading Systems - Study Guide',
    author='Orris Medical Education'
)

story = []

# ═══════════════════════════ COVER ════════════════════════════════════════
cover = Table([
    [P('SAH GRADING SYSTEMS', st_title)],
    [P('A Structured 1-Hour Study Guide  |  Junior Doctors &amp; Residents', st_subtitle)],
    [Spacer(1, 0.2*cm)],
    [P('3 Sessions × 20 Minutes  |  Clinical + Radiological Grading  |  Prognostication &amp; Management', st_subtitle)],
], colWidths=[17.4*cm])
cover.setStyle(TableStyle([
    ('BACKGROUND',   (0,0),(-1,-1), NAVY),
    ('TOPPADDING',   (0,0),(-1,-1), 14),
    ('BOTTOMPADDING',(0,0),(-1,-1), 12),
    ('LEFTPADDING',  (0,0),(-1,-1), 14),
    ('RIGHTPADDING', (0,0),(-1,-1), 14),
]))
story.append(cover)
story.append(Spacer(1, 0.4*cm))

story.append(info_box(
    '<b>Learning Objectives:</b> By the end of this guide you will be able to: '
    '(1) Apply Hunt-Hess and WFNS clinical grading and interpret their prognostic significance; '
    '(2) Classify SAH on CT using the Fisher and Modified Fisher scales; '
    '(3) Correlate clinical and radiological grades to guide management; '
    '(4) Recognise and avoid common grading pitfalls at the bedside.'
))
story.append(Spacer(1, 0.3*cm))

# Session overview
sess_data = [
    ['SESSION 1 – 20 min', 'SESSION 2 – 20 min', 'SESSION 3 – 20 min'],
    ['Why Grade SAH?\nHunt-Hess Scale\nWFNS Scale', 'Fisher CT Scale\nModified Fisher Scale\nCT Anatomy Review', 'Grade Correlation\nManagement Pearls\nQuick Quiz + Pitfalls'],
]
sess_tbl = Table(sess_data, colWidths=[5.6*cm, 5.6*cm, 5.6*cm])
sess_tbl.setStyle(TableStyle([
    ('BACKGROUND',   (0,0),(-1,0), TEAL),
    ('TEXTCOLOR',    (0,0),(-1,0), WHITE),
    ('FONTNAME',     (0,0),(-1,0), 'Helvetica-Bold'),
    ('BACKGROUND',   (0,1),(-1,1), LTBLUE),
    ('FONTSIZE',     (0,0),(-1,-1), 9),
    ('ALIGN',        (0,0),(-1,-1), 'CENTER'),
    ('VALIGN',       (0,0),(-1,-1), 'MIDDLE'),
    ('GRID',         (0,0),(-1,-1), 0.5, WHITE),
    ('TOPPADDING',   (0,0),(-1,-1), 6),
    ('BOTTOMPADDING',(0,0),(-1,-1), 6),
    ('LEADING',      (0,1),(-1,1), 14),
]))
story.append(sess_tbl)
story.append(Spacer(1, 0.4*cm))
story.append(HRFlowable(width='100%', thickness=1.5, color=TEAL))
story.append(Spacer(1, 0.2*cm))

# ═══════════════════════ SESSION 1 ════════════════════════════════════════
story.append(KeepTogether([
    banner('SESSION 1  |  Clinical Grading Scales', NAVY),
    Spacer(1, 0.15*cm),
    two_col(time_chip('20 MINUTES'), P('Hunt-Hess Scale  •  WFNS Scale  •  Why grade at all?', st_h3)),
    Spacer(1, 0.2*cm),
]))

story.append(P('1.1  Why Do We Grade SAH?', st_h2))
story.append(P(
    'Grading SAH at presentation serves three purposes: '
    '<b>(1) Communication</b> - a shared language across teams and research; '
    '<b>(2) Prognostication</b> - predicting hospital mortality and neurological outcome; '
    '<b>(3) Management decisions</b> - timing of surgery/coiling, ICU admission, and neuroprotection. '
    'A grade change of even 1 point can signal a new complication and should trigger immediate reassessment.',
    st_body
))
story.append(warn_box(
    'A decline of 1 GCS point or new motor deficit demands immediate reassessment – '
    'it may indicate rebleeding, acute hydrocephalus, or herniation.'
))
story.append(Spacer(1, 0.3*cm))

story.append(P('1.2  Hunt-Hess Scale  (Hunt &amp; Hess, 1968)', st_h2))
story.append(P(
    'The oldest and most widely used clinical grading scale, originally designed to guide surgical risk stratification. '
    'Grades 1-3 = "good grade" (suitable for early intervention); grades 4-5 = "poor grade" (requires stabilisation first). '
    'Mortality data from 580 patients treated at Columbia University Medical Center.',
    st_body
))
story.append(Spacer(1, 0.15*cm))

hh_tbl = data_table(
    [P('<b>Grade</b>', st_small), P('<b>Clinical Findings</b>', st_small),
     P('<b>Hospital Mortality</b>', st_small), P('<b>Key Feature</b>', st_small)],
    [
        [P('<b>0</b>', st_small), P('Unruptured aneurysm; asymptomatic', st_small), P('–', st_small), P('Incidental finding', st_small)],
        [P('<b>1</b>', st_small), P('Asymptomatic or mild headache; slight nuchal rigidity', st_small), P('~3%', st_small), P('No deficit', st_small)],
        [P('<b>2</b>', st_small), P('Moderate-severe headache; nuchal rigidity; possible CN palsy (III/IV)', st_small), P('~3%', st_small), P('CN palsy only', st_small)],
        [P('<b>3</b>', st_small), P('Drowsy/confused; mild focal deficit (e.g. pronator drift)', st_small), P('~9%', st_small), P('Altered consciousness', st_small)],
        [P('<b>4</b>', st_small), P('Stupor; moderate-severe hemiparesis; early decerebrate posturing', st_small), P('~24%', st_small), P('Stupor + motor deficit', st_small)],
        [P('<b>5</b>', st_small), P('Deep coma; decerebrate rigidity; moribund', st_small), P('~70%', st_small), P('Coma', st_small)],
    ],
    [1.2*cm, 7.0*cm, 3.0*cm, 4.2*cm]
)
story.append(hh_tbl)
story.append(P('Source: Goldman-Cecil Medicine; Columbia University Medical Center (n=580)', st_caption))
story.append(Spacer(1, 0.2*cm))
story.append(info_box(
    '<b>Limitations of Hunt-Hess:</b> Subjective language – "vegetative disturbance" and "moribund appearance" are imprecise. '
    'Hunt and Hess themselves wrote: <i>"It is recognized that such classifications are arbitrary and that '
    'the margins between categories may be ill defined."</i>  Inter-rater variability is a known limitation.'
))
story.append(Spacer(1, 0.3*cm))

story.append(P('1.3  WFNS Scale  (World Federation of Neurological Surgeons, 1988)', st_h2))
story.append(P(
    'A more objective scale based on Glasgow Coma Scale (GCS) score and presence of motor deficit. '
    'Introduced to improve inter-rater reliability and international standardisation in clinical trials.',
    st_body
))
story.append(Spacer(1, 0.15*cm))

wfns_tbl = data_table(
    [P('<b>Grade</b>', st_small), P('<b>GCS Score</b>', st_small),
     P('<b>Motor Deficit</b>', st_small), P('<b>Prognosis</b>', st_small)],
    [
        [P('<b>1</b>', st_small), P('15', st_small), P('Absent', st_small), P('Good', st_small)],
        [P('<b>2</b>', st_small), P('13–14', st_small), P('Absent', st_small), P('Good-Fair', st_small)],
        [P('<b>3</b>', st_small), P('13–14', st_small), P('Present', st_small), P('Fair', st_small)],
        [P('<b>4</b>', st_small), P('7–12', st_small), P('Present or absent', st_small), P('Poor', st_small)],
        [P('<b>5</b>', st_small), P('3–6', st_small), P('Present or absent', st_small), P('Very poor', st_small)],
    ],
    [2.0*cm, 3.5*cm, 4.5*cm, 7.4*cm],
    hdr_bg=TEAL
)
story.append(wfns_tbl)
story.append(Spacer(1, 0.2*cm))

story.append(P('1.4  Hunt-Hess vs WFNS – Side-by-Side', st_h2))
compare = [
    [P('<b>Feature</b>', st_small), P('<b>Hunt-Hess</b>', st_small), P('<b>WFNS</b>', st_small)],
    [P('Year introduced', st_small), P('1968', st_small), P('1988', st_small)],
    [P('Grading basis', st_small), P('Clinical descriptors', st_small), P('GCS + motor deficit', st_small)],
    [P('Objectivity', st_small), P('Lower', st_small), P('Higher', st_small)],
    [P('Sedated patients', st_small), P('Invalid – document pre-sedation grade', st_small), P('Invalid – document pre-sedation grade', st_small)],
    [P('"Good grade" cut-off', st_small), P('Grade 1-3', st_small), P('Grade 1-2', st_small)],
    [P('Primary use', st_small), P('Surgical timing, prognostication', st_small), P('Universal grading, research', st_small)],
]
cmp_tbl = Table(compare, colWidths=[4.0*cm, 6.5*cm, 6.5*cm])
cmp_tbl.setStyle(TableStyle([
    ('BACKGROUND',   (0,0),(-1,0), NAVY),
    ('TEXTCOLOR',    (0,0),(-1,0), WHITE),
    ('FONTNAME',     (0,0),(-1,0), 'Helvetica-Bold'),
    ('FONTSIZE',     (0,0),(-1,-1), 8.5),
    ('GRID',         (0,0),(-1,-1), 0.4, MIDGREY),
    ('VALIGN',       (0,0),(-1,-1), 'MIDDLE'),
    ('TOPPADDING',   (0,0),(-1,-1), 4),
    ('BOTTOMPADDING',(0,0),(-1,-1), 4),
    ('LEFTPADDING',  (0,0),(-1,-1), 5),
    ('BACKGROUND',   (0,2),(-1,2), GREY),
    ('BACKGROUND',   (0,4),(-1,4), GREY),
    ('BACKGROUND',   (0,6),(-1,6), GREY),
]))
story.append(cmp_tbl)
story.append(Spacer(1, 0.3*cm))

story.append(P('1.5  Session 1 Self-Check', st_h2))
story.append(bullets([
    'Thunderclap headache, GCS 15, neck stiffness, no focal deficit: what Hunt-Hess and WFNS grade?  <i>[HH Grade 1-2; WFNS Grade 1]</i>',
    'Patient is stuporous with right hemiplegia: what Hunt-Hess grade?  <i>[HH Grade 4]</i>',
    'Why might WFNS be preferred in a multi-centre trial?  <i>[Objective, GCS-based, reproducible]</i>',
    'At what Hunt-Hess grade would you consider delaying aneurysm surgery?  <i>[Grade 4-5 – stabilise first]</i>',
]))
story.append(PageBreak())

# ═══════════════════════ SESSION 2 ════════════════════════════════════════
story.append(KeepTogether([
    banner('SESSION 2  |  Radiological Grading – CT-Based Scales', NAVY),
    Spacer(1, 0.15*cm),
    two_col(time_chip('20 MINUTES'), P('Fisher Scale  •  Modified Fisher Scale  •  CT Anatomy', st_h3)),
    Spacer(1, 0.2*cm),
]))

story.append(P('2.1  What Does CT Tell Us About SAH?', st_h2))
story.append(P(
    'Non-contrast CT (NCCT) is the first-line investigation for SAH. Beyond <i>diagnosing</i> the bleed, '
    'CT findings predict the risk of <b>vasospasm</b> and <b>delayed cerebral ischaemia (DCI)</b> – '
    'the leading cause of morbidity and mortality after the initial haemorrhage. '
    'Subarachnoid blood appears as hyperdense (bright white) signal filling the cisterns and fissures.',
    st_body
))
story.append(info_box(
    '<b>CT Anatomy Reminder – Know These Structures:</b> '
    'Basal cisterns (suprasellar, ambient, quadrigeminal, sylvian fissure), '
    'interhemispheric fissure, cerebral ventricles (I-IV), subarachnoid space vs parenchyma. '
    'Identify each cistern before applying any grading scale.'
))
story.append(Spacer(1, 0.3*cm))

story.append(P('2.2  Original Fisher Scale  (Fisher et al., 1980)', st_h2))
story.append(P(
    'Designed to predict the risk of <b>symptomatic vasospasm</b> from the amount and distribution '
    'of subarachnoid blood on CT. Groups 3 and 4 carry the highest vasospasm risk.',
    st_body
))
story.append(Spacer(1, 0.15*cm))

fisher_tbl = data_table(
    [P('<b>Group</b>', st_small), P('<b>CT Finding</b>', st_small), P('<b>Vasospasm Risk</b>', st_small)],
    [
        [P('<b>1</b>', st_small), P('No blood detected on CT', st_small), P('Very low', st_small)],
        [P('<b>2</b>', st_small), P('Diffuse or thin layer of subarachnoid blood; all vertical layers &lt;1 mm thick (interhemispheric, insular, ambient cisterns)', st_small), P('Low-moderate', st_small)],
        [P('<b>3</b>', st_small), P('Localised clots OR vertical layers of blood ≥1 mm thickness', st_small), P('<b>HIGH</b>', st_small)],
        [P('<b>4</b>', st_small), P('Diffuse or no subarachnoid blood BUT intraparenchymal or intraventricular clots present', st_small), P('<b>HIGH</b>', st_small)],
    ],
    [1.8*cm, 11.0*cm, 4.6*cm]
)
story.append(fisher_tbl)
story.append(P('Source: Bradley and Daroff\'s Neurology in Clinical Practice, Box 67.3', st_caption))
story.append(Spacer(1, 0.15*cm))
story.append(warn_box(
    'Fisher Group 4 can paradoxically show LESS vasospasm than Group 3 in some series – '
    'because it may have minimal cistern blood (just parenchymal/ventricular clots). '
    'This non-monotonic relationship was the key driver for the Modified Fisher Scale.'
))
story.append(Spacer(1, 0.3*cm))

story.append(P('2.3  Modified Fisher Scale  (Frontera et al., 2006)', st_h2))
story.append(P(
    'Revised to address the original Fisher scale\'s failure to account for intraventricular haemorrhage (IVH) '
    'as an independent risk factor for vasospasm. IVH is now a separate binary variable on a 0-4 scale. '
    '<b>This scale applies to aneurysmal SAH only.</b>',
    st_body
))
story.append(Spacer(1, 0.15*cm))

mf_tbl = data_table(
    [P('<b>Grade</b>', st_small), P('<b>Subarachnoid Blood</b>', st_small),
     P('<b>IVH</b>', st_small), P('<b>Symptomatic Vasospasm Risk</b>', st_small)],
    [
        [P('<b>0</b>', st_small), P('None', st_small), P('None', st_small), P('0%', st_small)],
        [P('<b>1</b>', st_small), P('Focal or diffuse; thin', st_small), P('Absent', st_small), P('24%', st_small)],
        [P('<b>2</b>', st_small), P('Focal thin or diffuse', st_small), P('<b>Present</b>', st_small), P('33%', st_small)],
        [P('<b>3</b>', st_small), P('<b>Thick</b>', st_small), P('Absent', st_small), P('33%', st_small)],
        [P('<b>4</b>', st_small), P('<b>Thick</b>', st_small), P('<b>Present</b>', st_small), P('<b>40% (highest)</b>', st_small)],
    ],
    [1.8*cm, 5.8*cm, 2.8*cm, 7.0*cm],
    hdr_bg=TEAL
)
story.append(mf_tbl)
story.append(P('Source: Frontera JA et al. Neurosurgery. 2006;59(1):21-27', st_caption))
story.append(Spacer(1, 0.2*cm))
story.append(P('2.4  Key Improvements of Modified Fisher Scale', st_h2))
story.append(P(
    'Patients with IVH alone (no subarachnoid blood) now score Grade 2 (33% vasospasm risk). '
    'On the original Fisher scale they would score Group 1 – dramatically underestimating their risk. '
    'IVH as an independent variable makes this scale more clinically actionable.',
    st_body
))
story.append(info_box(
    '<b>Limitations of Modified Fisher:</b> '
    '(1) Grades 2 and 3 have identical vasospasm incidence (33%) – insufficient separation between categories. '
    '(2) Inter-rater reliability for distinguishing "thick vs thin" blood is only 72-78%. '
    '(3) The Hijdra Sum Score (semi-quantitative, 0-30 across 10 cisterns) is more precise and may be '
    'superior for research – though impractical for rapid bedside grading (Miller\'s Anesthesia, 10th Ed.).'
))
story.append(Spacer(1, 0.25*cm))
story.append(P('2.5  Session 2 Self-Check', st_h2))
story.append(bullets([
    'CT: thick blood in basal cisterns, no IVH – Modified Fisher grade and vasospasm risk?  <i>[Grade 3; 33%]</i>',
    'CT: thin SAH + blood in both lateral ventricles – Modified Fisher grade?  <i>[Grade 2; 33%]</i>',
    'Which Fisher group can show HIGH vasospasm risk despite minimal subarachnoid blood?  <i>[Group 4 – IVH/parenchymal clot]</i>',
    'Why does a Modified Fisher Grade 2 patient need the same vasospasm vigilance as Grade 3?  <i>[Both carry 33% risk]</i>',
]))
story.append(PageBreak())

# ═══════════════════════ SESSION 3 ════════════════════════════════════════
story.append(KeepTogether([
    banner('SESSION 3  |  Correlation, Management &amp; Pitfalls', NAVY),
    Spacer(1, 0.15*cm),
    two_col(time_chip('20 MINUTES'), P('Clinical-Radiological Correlation  •  Management  •  Quick Quiz', st_h3)),
    Spacer(1, 0.2*cm),
]))

story.append(P('3.1  Putting It Together – Clinical + CT Grade Correlation', st_h2))
story.append(P(
    'Use both clinical and CT grades together. A good clinical grade with a high CT grade (or vice versa) '
    'should heighten your vigilance and monitoring frequency.',
    st_body
))
story.append(Spacer(1, 0.15*cm))

integration = [
    [P('<b>Clinical Grade</b>', st_small), P('<b>Modified Fisher</b>', st_small), P('<b>Action</b>', st_small)],
    [P('HH 1-2 / WFNS 1-2', st_small), P('0-1', st_small), P('Good grade + low vasospasm risk: early aneurysm treatment, standard monitoring', st_small)],
    [P('HH 1-2 / WFNS 1-2', st_small), P('3-4', st_small), P('Good grade but HIGH vasospasm risk: early treatment + aggressive vasospasm surveillance', st_small)],
    [P('HH 3 / WFNS 3', st_small), P('2-3', st_small), P('Moderate grade: ICU admission, hourly neuro obs, consider early intervention', st_small)],
    [P('HH 4-5 / WFNS 4-5', st_small), P('3-4', st_small), P('Poor grade + heavy bleed: intubate, ICP monitoring, stabilise before intervention', st_small)],
]
int_tbl = Table(integration, colWidths=[4.2*cm, 2.8*cm, 10.4*cm])
int_tbl.setStyle(TableStyle([
    ('BACKGROUND',   (0,0),(-1,0), NAVY),
    ('TEXTCOLOR',    (0,0),(-1,0), WHITE),
    ('FONTNAME',     (0,0),(-1,0), 'Helvetica-Bold'),
    ('FONTSIZE',     (0,0),(-1,-1), 8.5),
    ('GRID',         (0,0),(-1,-1), 0.4, MIDGREY),
    ('VALIGN',       (0,0),(-1,-1), 'MIDDLE'),
    ('TOPPADDING',   (0,0),(-1,-1), 4),
    ('BOTTOMPADDING',(0,0),(-1,-1), 4),
    ('LEFTPADDING',  (0,0),(-1,-1), 5),
    ('BACKGROUND',   (0,2),(-1,2), GREY),
    ('BACKGROUND',   (0,4),(-1,4), GREY),
]))
story.append(int_tbl)
story.append(Spacer(1, 0.3*cm))

story.append(P('3.2  Management Pearls by Grade', st_h2))
mgmt = [
    [P('<b>Domain</b>', st_small), P('<b>Good Grade (HH 1-3)</b>', st_small), P('<b>Poor Grade (HH 4-5)</b>', st_small)],
    [P('Airway', st_small), P('Self-maintaining; monitor', st_small), P('Intubate and ventilate', st_small)],
    [P('Aneurysm Tx', st_small), P('Early coiling/clipping (24-72 h)', st_small), P('Stabilise first; delayed intervention', st_small)],
    [P('Blood Pressure', st_small), P('SBP 120-160 mmHg until secured', st_small), P('Tight BP control; CPP 60-80 mmHg', st_small)],
    [P('Nimodipine', st_small), P('60 mg q4h × 21 days (all grades)', st_small), P('60 mg q4h × 21 days (all grades)', st_small)],
    [P('Vasospasm', st_small), P('TCD daily; clinical exam q4-6 h', st_small), P('TCD + continuous EEG; ICP monitoring', st_small)],
    [P('Hydrocephalus', st_small), P('Monitor; LP or EVD if symptomatic', st_small), P('Early EVD if obstructive hydrocephalus', st_small)],
    [P('Seizures', st_small), P('Levetiracetam if occurs; stop after aneurysm secured', st_small), P('Continue AED + cEEG monitoring', st_small)],
]
mg_tbl = Table(mgmt, colWidths=[3.5*cm, 6.6*cm, 6.6*cm])
mg_tbl.setStyle(TableStyle([
    ('BACKGROUND',   (0,0),(-1,0), TEAL),
    ('TEXTCOLOR',    (0,0),(-1,0), WHITE),
    ('FONTNAME',     (0,0),(-1,0), 'Helvetica-Bold'),
    ('FONTSIZE',     (0,0),(-1,-1), 8.5),
    ('GRID',         (0,0),(-1,-1), 0.4, MIDGREY),
    ('VALIGN',       (0,0),(-1,-1), 'MIDDLE'),
    ('TOPPADDING',   (0,0),(-1,-1), 4),
    ('BOTTOMPADDING',(0,0),(-1,-1), 4),
    ('LEFTPADDING',  (0,0),(-1,-1), 5),
    ('BACKGROUND',   (0,2),(-1,2), GREY),
    ('BACKGROUND',   (0,4),(-1,4), GREY),
    ('BACKGROUND',   (0,6),(-1,6), GREY),
]))
story.append(mg_tbl)
story.append(Spacer(1, 0.25*cm))

story.append(P('3.3  Common Pitfalls – Do Not Miss', st_h2))
story.append(bullets([
    '<b>Grade on admission only:</b> SAH grade can change rapidly – reassess every 4-6 hours.',
    '<b>Grading post-sedation:</b> Both HH and WFNS are invalid after sedation – always document the <i>pre-sedation</i> grade.',
    '<b>Fisher Group 1 = "safe":</b> CT-negative SAH exists; correlate with LP if clinical suspicion remains high.',
    '<b>Ignoring IVH on CT:</b> Bilateral IVH alone = Modified Fisher Grade 2 (33% vasospasm risk) – not low risk.',
    '<b>Relying on the radiology report alone:</b> Learn cisternal anatomy – read the CT yourself.',
    '<b>Poor grade = futility:</b> Hunt-Hess Grade 5 carries 70% mortality but 30% can survive – never withdraw care without senior discussion.',
]))
story.append(Spacer(1, 0.25*cm))

story.append(P('3.4  Quick Quiz – 5 Questions', st_h2))
story.append(info_box(
    '<b>Q1.</b> Thunderclap headache, GCS 14, right CN III palsy, no motor deficit. CT: thin diffuse SAH, no IVH. '
    'State Hunt-Hess grade, WFNS grade, Modified Fisher grade, and vasospasm risk.<br/><br/>'
    '<b>Q2.</b> CT: thick blood in basal cisterns + blood in both lateral ventricles. '
    'Modified Fisher grade and expected vasospasm incidence?<br/><br/>'
    '<b>Q3.</b> Why is WFNS Grade 3 higher risk than Grade 2 despite an identical GCS range?<br/><br/>'
    '<b>Q4.</b> When should nimodipine be started and for how long?<br/><br/>'
    '<b>Q5.</b> A patient admitted as HH Grade 2 suddenly drops to Grade 3. List three causes.'
))
story.append(Spacer(1, 0.15*cm))
story.append(info_box(
    '<b>Answers:</b><br/>'
    '<b>Q1:</b> HH Grade 2 (severe headache + CN palsy, no motor); WFNS Grade 2 (GCS 13-14, no motor); '
    'Modified Fisher Grade 1 (thin, no IVH) → 24% vasospasm risk.<br/>'
    '<b>Q2:</b> Modified Fisher Grade 4 (thick SAH + IVH) → 40% vasospasm risk.<br/>'
    '<b>Q3:</b> Grade 3 adds motor deficit to GCS 13-14, indicating greater cortical/subcortical injury.<br/>'
    '<b>Q4:</b> Within 48 hours of haemorrhage; continued for 21 days (60 mg every 4 hours).<br/>'
    '<b>Q5:</b> (1) Rebleeding; (2) Acute hydrocephalus; (3) Cerebral vasospasm/DCI.',
    bg=LTAMBER, border=AMBER
))
story.append(Spacer(1, 0.3*cm))

story.append(P('3.5  Full Grading Summary – Quick Reference Card', st_h2))
summary = [
    [P('<b>Scale</b>', st_small), P('<b>Type</b>', st_small), P('<b>Year</b>', st_small),
     P('<b>What It Grades</b>', st_small), P('<b>Primary Use</b>', st_small)],
    [P('Hunt-Hess', st_small), P('Clinical', st_small), P('1968', st_small),
     P('Neurological status (0-5)', st_small), P('Surgical timing, prognosis', st_small)],
    [P('WFNS', st_small), P('Clinical', st_small), P('1988', st_small),
     P('GCS + motor deficit (1-5)', st_small), P('Universal grading, research', st_small)],
    [P('Fisher', st_small), P('Radiological', st_small), P('1980', st_small),
     P('CT blood volume/distribution (1-4)', st_small), P('Predicts vasospasm', st_small)],
    [P('Modified Fisher', st_small), P('Radiological', st_small), P('2006', st_small),
     P('CT blood + IVH (0-4)', st_small), P('More accurate vasospasm prediction', st_small)],
    [P('Hijdra Sum Score', st_small), P('Radiological', st_small), P('1985', st_small),
     P('Semi-quantitative cisternal blood (0-30)', st_small), P('Research; superior vasospasm prediction', st_small)],
]
sum_tbl = Table(summary, colWidths=[3.3*cm, 2.3*cm, 1.6*cm, 5.4*cm, 4.8*cm])
sum_tbl.setStyle(TableStyle([
    ('BACKGROUND',   (0,0),(-1,0), NAVY),
    ('TEXTCOLOR',    (0,0),(-1,0), WHITE),
    ('FONTNAME',     (0,0),(-1,0), 'Helvetica-Bold'),
    ('FONTSIZE',     (0,0),(-1,-1), 8.5),
    ('GRID',         (0,0),(-1,-1), 0.4, MIDGREY),
    ('VALIGN',       (0,0),(-1,-1), 'MIDDLE'),
    ('TOPPADDING',   (0,0),(-1,-1), 4),
    ('BOTTOMPADDING',(0,0),(-1,-1), 4),
    ('LEFTPADDING',  (0,0),(-1,-1), 5),
    ('BACKGROUND',   (0,2),(-1,2), GREY),
    ('BACKGROUND',   (0,4),(-1,4), GREY),
]))
story.append(sum_tbl)
story.append(Spacer(1, 0.3*cm))

# Footer
footer = Table([[P(
    'References: Bradley &amp; Daroff\'s Neurology in Clinical Practice | Tintinalli\'s Emergency Medicine | '
    'Schwartz\'s Principles of Surgery 11e | Goldman-Cecil Medicine | '
    'Tietz Textbook of Laboratory Medicine 7e | Frontera JA et al. Neurosurgery 2006 | '
    'Drake CG. J Neurosurg 1988',
    st_caption
)]], colWidths=[17.4*cm])
footer.setStyle(TableStyle([
    ('BACKGROUND',   (0,0),(-1,-1), NAVY),
    ('TOPPADDING',   (0,0),(-1,-1), 5),
    ('BOTTOMPADDING',(0,0),(-1,-1), 5),
    ('LEFTPADDING',  (0,0),(-1,-1), 8),
    ('TEXTCOLOR',    (0,0),(-1,-1), LTBLUE),
]))
story.append(footer)

doc.build(story)
print("SAH_Grading_Study_Guide.pdf built successfully.")
Editing File

~/sah-ecmo/build_sah_pdf.py

Successfully replaced 1 instance(s) of the string in '/home/daytona/workspace/sah-ecmo/build_sah_pdf.py'
Running Command

cat > /home/daytona/workspace/sah-ecmo/build_sah_pdf.py << 'PYEOF' from reportlab.lib.pagesizes import A4 from reportlab.lib import colors from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle from reportlab.lib.units import cm from reportlab.platypus import (SimpleDocTemplate, Paragraph, Spacer, Table, TableStyle, HRFlowable, PageBreak, KeepTogether, ListFlowable, ListItem) from reportlab.lib.enums import TA_CENTER, TA_JUSTIFY NAVY = colors.HexColor('#1a3a5c') TEAL = colors.HexColor('#2a7f8f') AMBER = colors.HexColor('#e07b23') LTBLUE = colors.HexColor('#ddeef6') LTAMBER = colors.HexColor('#fef3e2') WHITE = colors.white GREY = colors.HexColor('#f4f6f8') DKGREY = colors.HexColor('#444444') MIDGREY = colors.HexColor('#cccccc') _base = getSampleStyleSheet() def sty(nm,**kw): p=kw.pop('parent','Normal') return ParagraphStyle(nm,parent=_base[p],**kw) st_title = sty('st_title', fontSize=22,textColor=WHITE, alignment=TA_CENTER,fontName='Helvetica-Bold',spaceAfter=4) st_subtitle = sty('st_subtitle',fontSize=11,textColor=LTBLUE,alignment=TA_CENTER,fontName='Helvetica',spaceAfter=4) st_h1 = sty('st_h1', fontSize=14,textColor=WHITE, fontName='Helvetica-Bold',spaceAfter=2,spaceBefore=2) st_h2 = sty('st_h2', fontSize=12,textColor=NAVY, fontName='Helvetica-Bold',spaceAfter=3,spaceBefore=6) st_h3 = sty('st_h3', fontSize=10,textColor=TEAL, fontName='Helvetica-Bold',spaceAfter=2,spaceBefore=3) st_body = sty('st_body', fontSize=9, textColor=DKGREY,fontName='Helvetica',leading=13,spaceAfter=3,alignment=TA_JUSTIFY) st_small = sty('st_small', fontSize=8.5,textColor=DKGREY,fontName='Helvetica',leading=11) st_badge = sty('st_badge', fontSize=8, textColor=WHITE, fontName='Helvetica-Bold',alignment=TA_CENTER) st_caption = sty('st_caption',fontSize=7.5,textColor=colors.HexColor('#888888'),fontName='Helvetica-Oblique',alignment=TA_CENTER,spaceBefore=1) st_bullet = sty('st_bullet', fontSize=9, textColor=DKGREY,fontName='Helvetica',leading=13,leftIndent=8,spaceAfter=1) def P(txt,s=None): return Paragraph(txt,s or st_body) def banner(text,bg=NAVY,s=None,h=0.65*cm): tbl=Table([[P(text,s or st_h1)]],colWidths=[17.4*cm],rowHeights=[h]) tbl.setStyle(TableStyle([('BACKGROUND',(0,0),(-1,-1),bg),('VALIGN',(0,0),(-1,-1),'MIDDLE'), ('LEFTPADDING',(0,0),(-1,-1),10),('RIGHTPADDING',(0,0),(-1,-1),10), ('TOPPADDING',(0,0),(-1,-1),4),('BOTTOMPADDING',(0,0),(-1,-1),4)])) return tbl def ibox(text,bg=LTBLUE,border=TEAL): tbl=Table([[P(text,st_body)]],colWidths=[17.4*cm]) tbl.setStyle(TableStyle([('BACKGROUND',(0,0),(-1,-1),bg),('BOX',(0,0),(-1,-1),1.2,border), ('LEFTPADDING',(0,0),(-1,-1),8),('RIGHTPADDING',(0,0),(-1,-1),8), ('TOPPADDING',(0,0),(-1,-1),6),('BOTTOMPADDING',(0,0),(-1,-1),6)])) return tbl def wbox(text): return ibox('<b>Key Point: </b>'+text,LTAMBER,AMBER) def chip(lbl,bg=TEAL): tbl=Table([[P(lbl,st_badge)]],colWidths=[3.4*cm],rowHeights=[0.5*cm]) tbl.setStyle(TableStyle([('BACKGROUND',(0,0),(-1,-1),bg),('VALIGN',(0,0),(-1,-1),'MIDDLE'), ('ALIGN',(0,0),(-1,-1),'CENTER'),('LEFTPADDING',(0,0),(-1,-1),4),('RIGHTPADDING',(0,0),(-1,-1),4)])) return tbl def twocol(l,r,lw=4.0*cm,rw=13.0*cm): tbl=Table([[l,r]],colWidths=[lw,rw]) tbl.setStyle(TableStyle([('VALIGN',(0,0),(-1,-1),'MIDDLE'),('LEFTPADDING',(0,0),(-1,-1),0), ('RIGHTPADDING',(0,0),(-1,-1),0),('TOPPADDING',(0,0),(-1,-1),0),('BOTTOMPADDING',(0,0),(-1,-1),0)])) return tbl def dtbl(hdrs,rows,cw,hbg=NAVY): data=[hdrs]+rows tbl=Table(data,colWidths=cw) ts=[('BACKGROUND',(0,0),(-1,0),hbg),('TEXTCOLOR',(0,0),(-1,0),WHITE), ('FONTNAME',(0,0),(-1,0),'Helvetica-Bold'),('FONTSIZE',(0,0),(-1,-1),8.5), ('LEADING',(0,0),(-1,-1),12),('ALIGN',(0,0),(-1,-1),'LEFT'),('VALIGN',(0,0),(-1,-1),'MIDDLE'), ('GRID',(0,0),(-1,-1),0.4,MIDGREY),('LEFTPADDING',(0,0),(-1,-1),5), ('RIGHTPADDING',(0,0),(-1,-1),5),('TOPPADDING',(0,0),(-1,-1),4),('BOTTOMPADDING',(0,0),(-1,-1),4)] for i in range(1,len(rows)+1): if i%2==0: ts.append(('BACKGROUND',(0,i),(-1,i),GREY)) tbl.setStyle(TableStyle(ts)) return tbl def blist(items): return ListFlowable([ListItem(P(i,st_bullet),leftIndent=10,bulletColor=TEAL,value='bullet') for i in items], bulletType='bullet',leftIndent=6,bulletFontSize=8) doc=SimpleDocTemplate('/home/daytona/workspace/sah-ecmo/SAH_Grading_Study_Guide.pdf', pagesize=A4,leftMargin=1.8*cm,rightMargin=1.8*cm,topMargin=1.8*cm,bottomMargin=1.8*cm, title='SAH Grading Systems - Study Guide',author='Orris Medical Education') story=[] # COVER cov=Table([[P('SAH GRADING SYSTEMS',st_title)], [P('A Structured 1-Hour Study Guide | Junior Doctors &amp; Residents',st_subtitle)], [Spacer(1,0.2*cm)], [P('3 Sessions x 20 Minutes | Clinical + Radiological Grading | Prognostication &amp; Management',st_subtitle)]], colWidths=[17.4*cm]) cov.setStyle(TableStyle([('BACKGROUND',(0,0),(-1,-1),NAVY), ('TOPPADDING',(0,0),(-1,-1),14),('BOTTOMPADDING',(0,0),(-1,-1),12), ('LEFTPADDING',(0,0),(-1,-1),14),('RIGHTPADDING',(0,0),(-1,-1),14)])) story.append(cov) story.append(Spacer(1,0.4*cm)) story.append(ibox('<b>Learning Objectives:</b> By the end of this guide you will: ' '(1) Apply Hunt-Hess and WFNS clinical grading and interpret their prognostic significance; ' '(2) Classify SAH on CT using Fisher and Modified Fisher scales; ' '(3) Correlate clinical and radiological grades to guide management; ' '(4) Recognise and avoid common grading pitfalls at the bedside.')) story.append(Spacer(1,0.3*cm)) sd=Table([['SESSION 1 - 20 min','SESSION 2 - 20 min','SESSION 3 - 20 min'], ['Why Grade SAH?\nHunt-Hess Scale\nWFNS Scale','Fisher CT Scale\nModified Fisher Scale\nCT Anatomy Review', 'Grade Correlation\nManagement Pearls\nQuick Quiz + Pitfalls']], colWidths=[5.6*cm,5.6*cm,5.6*cm]) sd.setStyle(TableStyle([('BACKGROUND',(0,0),(-1,0),TEAL),('TEXTCOLOR',(0,0),(-1,0),WHITE), ('FONTNAME',(0,0),(-1,0),'Helvetica-Bold'),('BACKGROUND',(0,1),(-1,1),LTBLUE), ('FONTSIZE',(0,0),(-1,-1),9),('ALIGN',(0,0),(-1,-1),'CENTER'),('VALIGN',(0,0),(-1,-1),'MIDDLE'), ('GRID',(0,0),(-1,-1),0.5,WHITE),('TOPPADDING',(0,0),(-1,-1),6),('BOTTOMPADDING',(0,0),(-1,-1),6)])) story.append(sd) story.append(Spacer(1,0.4*cm)) story.append(HRFlowable(width='100%',thickness=1.5,color=TEAL)) story.append(Spacer(1,0.2*cm)) # SESSION 1 story.append(KeepTogether([banner('SESSION 1 | Clinical Grading Scales'),Spacer(1,0.15*cm), twocol(chip('20 MINUTES'),P('Hunt-Hess Scale - WFNS Scale - Why grade at all?',st_h3)),Spacer(1,0.2*cm)])) story.append(P('1.1 Why Do We Grade SAH?',st_h2)) story.append(P('Grading SAH at presentation serves three purposes: <b>(1) Communication</b> - a shared language ' 'across teams and research; <b>(2) Prognostication</b> - predicting hospital mortality and neurological outcome; ' '<b>(3) Management decisions</b> - timing of surgery/coiling, ICU admission, and neuroprotection. ' 'A grade change of even 1 point can signal a new complication.',st_body)) story.append(wbox('A decline of 1 GCS point or new motor deficit demands immediate reassessment - ' 'it may indicate rebleeding, acute hydrocephalus, or herniation.')) story.append(Spacer(1,0.3*cm)) story.append(P('1.2 Hunt-Hess Scale (Hunt &amp; Hess, 1968)',st_h2)) story.append(P('The oldest and most widely used clinical grading scale, originally designed to guide surgical risk. ' 'Grades 1-3 = "good grade" (early intervention); grades 4-5 = "poor grade" (stabilise first).',st_body)) story.append(Spacer(1,0.15*cm)) story.append(dtbl( [P('<b>Grade</b>',st_small),P('<b>Clinical Findings</b>',st_small),P('<b>Hospital Mortality</b>',st_small),P('<b>Key Feature</b>',st_small)], [[P('<b>0</b>',st_small),P('Unruptured aneurysm; asymptomatic',st_small),P('-',st_small),P('Incidental finding',st_small)], [P('<b>1</b>',st_small),P('Asymptomatic or mild headache; slight nuchal rigidity',st_small),P('~3%',st_small),P('No neurological deficit',st_small)], [P('<b>2</b>',st_small),P('Moderate-severe headache; nuchal rigidity; possible CN palsy (III/IV)',st_small),P('~3%',st_small),P('CN palsy only',st_small)], [P('<b>3</b>',st_small),P('Drowsy/confused; mild focal deficit (e.g. pronator drift)',st_small),P('~9%',st_small),P('Altered consciousness',st_small)], [P('<b>4</b>',st_small),P('Stupor; moderate-severe hemiparesis; early decerebrate posturing',st_small),P('~24%',st_small),P('Stupor + motor deficit',st_small)], [P('<b>5</b>',st_small),P('Deep coma; decerebrate rigidity; moribund',st_small),P('~70%',st_small),P('Coma',st_small)]], [1.2*cm,7.0*cm,3.0*cm,4.2*cm])) story.append(P('Source: Goldman-Cecil Medicine; Columbia University Medical Center (n=580)',st_caption)) story.append(Spacer(1,0.2*cm)) story.append(ibox('<b>Limitations of Hunt-Hess:</b> Subjective language. Hunt and Hess themselves wrote: ' '"It is recognized that such classifications are arbitrary and that the margins between categories may be ill defined." ' 'Inter-rater variability is a known limitation, particularly between grades 3 and 4.')) story.append(Spacer(1,0.3*cm)) story.append(P('1.3 WFNS Scale (World Federation of Neurological Surgeons, 1988)',st_h2)) story.append(P('A more objective scale based on Glasgow Coma Scale (GCS) + presence of motor deficit. ' 'Introduced to improve inter-rater reliability and international standardisation in clinical trials.',st_body)) story.append(Spacer(1,0.15*cm)) story.append(dtbl( [P('<b>Grade</b>',st_small),P('<b>GCS Score</b>',st_small),P('<b>Motor Deficit</b>',st_small),P('<b>Prognosis</b>',st_small)], [[P('<b>1</b>',st_small),P('15',st_small),P('Absent',st_small),P('Good',st_small)], [P('<b>2</b>',st_small),P('13-14',st_small),P('Absent',st_small),P('Good-Fair',st_small)], [P('<b>3</b>',st_small),P('13-14',st_small),P('Present',st_small),P('Fair',st_small)], [P('<b>4</b>',st_small),P('7-12',st_small),P('Present or absent',st_small),P('Poor',st_small)], [P('<b>5</b>',st_small),P('3-6',st_small),P('Present or absent',st_small),P('Very poor',st_small)]], [2.0*cm,3.5*cm,4.5*cm,7.4*cm],hbg=TEAL)) story.append(Spacer(1,0.2*cm)) story.append(P('1.4 Hunt-Hess vs WFNS Comparison',st_h2)) ct=Table([[P('<b>Feature</b>',st_small),P('<b>Hunt-Hess</b>',st_small),P('<b>WFNS</b>',st_small)], [P('Year',st_small),P('1968',st_small),P('1988',st_small)], [P('Grading basis',st_small),P('Clinical descriptors',st_small),P('GCS + motor deficit',st_small)], [P('Objectivity',st_small),P('Lower',st_small),P('Higher',st_small)], [P('Sedated patients',st_small),P('Invalid - document pre-sedation grade',st_small),P('Invalid - document pre-sedation grade',st_small)], [P('"Good grade" cut-off',st_small),P('Grade 1-3',st_small),P('Grade 1-2',st_small)], [P('Primary use',st_small),P('Surgical timing, prognostication',st_small),P('Universal grading, research',st_small)]], colWidths=[4.0*cm,6.5*cm,6.5*cm]) ct.setStyle(TableStyle([('BACKGROUND',(0,0),(-1,0),NAVY),('TEXTCOLOR',(0,0),(-1,0),WHITE), ('FONTNAME',(0,0),(-1,0),'Helvetica-Bold'),('FONTSIZE',(0,0),(-1,-1),8.5), ('GRID',(0,0),(-1,-1),0.4,MIDGREY),('VALIGN',(0,0),(-1,-1),'MIDDLE'), ('TOPPADDING',(0,0),(-1,-1),4),('BOTTOMPADDING',(0,0),(-1,-1),4),('LEFTPADDING',(0,0),(-1,-1),5), ('BACKGROUND',(0,2),(-1,2),GREY),('BACKGROUND',(0,4),(-1,4),GREY),('BACKGROUND',(0,6),(-1,6),GREY)])) story.append(ct) story.append(Spacer(1,0.3*cm)) story.append(P('1.5 Session 1 Self-Check',st_h2)) story.append(blist([ 'Thunderclap headache, GCS 15, neck stiffness, no focal deficit: HH and WFNS grade? <i>[HH Grade 1-2; WFNS Grade 1]</i>', 'Patient is stuporous with right hemiplegia: HH grade? <i>[HH Grade 4]</i>', 'Why might WFNS be preferred in a multi-centre trial? <i>[Objective, GCS-based, reproducible]</i>', 'At what HH grade would you consider delaying aneurysm surgery? <i>[Grade 4-5]</i>'])) story.append(PageBreak()) # SESSION 2 story.append(KeepTogether([banner('SESSION 2 | Radiological Grading - CT-Based Scales'),Spacer(1,0.15*cm), twocol(chip('20 MINUTES'),P('Fisher Scale - Modified Fisher Scale - CT Anatomy',st_h3)),Spacer(1,0.2*cm)])) story.append(P('2.1 What Does CT Tell Us About SAH?',st_h2)) story.append(P('Non-contrast CT (NCCT) is the first-line investigation for SAH. Beyond diagnosing the bleed, ' 'CT findings predict the risk of <b>vasospasm</b> and <b>delayed cerebral ischaemia (DCI)</b> - ' 'the leading cause of morbidity/mortality after the initial haemorrhage. ' 'Blood appears as hyperdense (bright white) signal filling the cisterns and fissures.',st_body)) story.append(ibox('<b>CT Anatomy Reminder:</b> Know the basal cisterns (suprasellar, ambient, quadrigeminal, ' 'sylvian fissure), interhemispheric fissure, and ventricles (I-IV). ' 'Identify each cistern before applying any grading scale.')) story.append(Spacer(1,0.3*cm)) story.append(P('2.2 Original Fisher Scale (Fisher et al., 1980)',st_h2)) story.append(P('Designed to predict the risk of <b>symptomatic vasospasm</b> from the amount and distribution ' 'of subarachnoid blood on CT. Groups 3 and 4 carry the highest vasospasm risk.',st_body)) story.append(Spacer(1,0.15*cm)) story.append(dtbl( [P('<b>Group</b>',st_small),P('<b>CT Finding</b>',st_small),P('<b>Vasospasm Risk</b>',st_small)], [[P('<b>1</b>',st_small),P('No blood detected on CT',st_small),P('Very low',st_small)], [P('<b>2</b>',st_small),P('Diffuse or thin layer of SAH; all vertical layers &lt;1 mm thick',st_small),P('Low-moderate',st_small)], [P('<b>3</b>',st_small),P('Localised clots OR vertical layers of blood >=1 mm thickness',st_small),P('<b>HIGH</b>',st_small)], [P('<b>4</b>',st_small),P('Diffuse or no SAH blood BUT intraparenchymal or intraventricular clots present',st_small),P('<b>HIGH</b>',st_small)]], [1.8*cm,11.0*cm,4.6*cm])) story.append(P('Source: Bradley and Daroff\'s Neurology in Clinical Practice, Box 67.3',st_caption)) story.append(Spacer(1,0.15*cm)) story.append(wbox('Fisher Group 4 can paradoxically show LESS vasospasm than Group 3 in some series ' '(minimal cisternal blood despite IVH/parenchymal clot). ' 'This non-monotonic relationship was the key driver for developing the Modified Fisher Scale.')) story.append(Spacer(1,0.3*cm)) story.append(P('2.3 Modified Fisher Scale (Frontera et al., 2006)',st_h2)) story.append(P('Revised to address the original Fisher scale\'s failure to account for IVH as an independent risk factor. ' 'IVH is now a separate binary variable. <b>Applies to aneurysmal SAH only.</b>',st_body)) story.append(Spacer(1,0.15*cm)) story.append(dtbl( [P('<b>Grade</b>',st_small),P('<b>Subarachnoid Blood</b>',st_small),P('<b>IVH</b>',st_small),P('<b>Vasospasm Risk</b>',st_small)], [[P('<b>0</b>',st_small),P('None',st_small),P('None',st_small),P('0%',st_small)], [P('<b>1</b>',st_small),P('Focal or diffuse; thin',st_small),P('Absent',st_small),P('24%',st_small)], [P('<b>2</b>',st_small),P('Focal thin or diffuse',st_small),P('<b>Present</b>',st_small),P('33%',st_small)], [P('<b>3</b>',st_small),P('<b>Thick</b>',st_small),P('Absent',st_small),P('33%',st_small)], [P('<b>4</b>',st_small),P('<b>Thick</b>',st_small),P('<b>Present</b>',st_small),P('<b>40% (highest)</b>',st_small)]], [1.8*cm,5.8*cm,2.8*cm,7.0*cm],hbg=TEAL)) story.append(P('Source: Frontera JA et al. Prediction of symptomatic vasospasm after SAH. Neurosurgery. 2006;59(1):21-27',st_caption)) story.append(Spacer(1,0.2*cm)) story.append(ibox('<b>Key improvement:</b> A patient with IVH alone (no SAH blood) now scores Grade 2 (33% vasospasm risk). ' 'On the original Fisher scale they would score Group 1 - dramatically underestimating their risk.<br/>' '<b>Limitations:</b> (1) Grades 2 and 3 have identical vasospasm incidence (33%). ' '(2) Inter-rater reliability for thick vs thin blood is only 72-78%.')) story.append(Spacer(1,0.25*cm)) story.append(P('2.4 Session 2 Self-Check',st_h2)) story.append(blist([ 'CT: thick blood in basal cisterns, no IVH - Modified Fisher grade and vasospasm risk? <i>[Grade 3; 33%]</i>', 'CT: thin SAH + blood in both lateral ventricles - Modified Fisher grade? <i>[Grade 2; 33%]</i>', 'Which Fisher group shows HIGH vasospasm risk despite minimal subarachnoid blood? <i>[Group 4 - due to IVH/parenchymal clot]</i>', 'Why does Modified Fisher Grade 2 need the same vasospasm vigilance as Grade 3? <i>[Both carry 33% risk]</i>'])) story.append(PageBreak()) # SESSION 3 story.append(KeepTogether([banner('SESSION 3 | Correlation, Management &amp; Pitfalls'),Spacer(1,0.15*cm), twocol(chip('20 MINUTES'),P('Clinical-Radiological Correlation - Management Pearls - Quick Quiz',st_h3)),Spacer(1,0.2*cm)])) story.append(P('3.1 Clinical + CT Grade Correlation',st_h2)) story.append(P('Use both clinical and CT grades together. A mismatch (good clinical grade + bad CT, or vice versa) ' 'should heighten vigilance and monitoring frequency.',st_body)) it=Table([[P('<b>Clinical Grade</b>',st_small),P('<b>Modified Fisher</b>',st_small),P('<b>Action</b>',st_small)], [P('HH 1-2 / WFNS 1-2',st_small),P('0-1',st_small),P('Early aneurysm treatment; standard monitoring',st_small)], [P('HH 1-2 / WFNS 1-2',st_small),P('3-4',st_small),P('Early treatment + aggressive vasospasm surveillance',st_small)], [P('HH 3 / WFNS 3',st_small),P('2-3',st_small),P('ICU admission; hourly neuro obs; consider early intervention',st_small)], [P('HH 4-5 / WFNS 4-5',st_small),P('3-4',st_small),P('Intubate; ICP monitoring; stabilise before intervention',st_small)]], colWidths=[4.2*cm,2.8*cm,10.4*cm]) it.setStyle(TableStyle([('BACKGROUND',(0,0),(-1,0),NAVY),('TEXTCOLOR',(0,0),(-1,0),WHITE), ('FONTNAME',(0,0),(-1,0),'Helvetica-Bold'),('FONTSIZE',(0,0),(-1,-1),8.5), ('GRID',(0,0),(-1,-1),0.4,MIDGREY),('VALIGN',(0,0),(-1,-1),'MIDDLE'), ('TOPPADDING',(0,0),(-1,-1),4),('BOTTOMPADDING',(0,0),(-1,-1),4),('LEFTPADDING',(0,0),(-1,-1),5), ('BACKGROUND',(0,2),(-1,2),GREY),('BACKGROUND',(0,4),(-1,4),GREY)])) story.append(Spacer(1,0.15*cm)) story.append(it) story.append(Spacer(1,0.25*cm)) story.append(P('3.2 Management Pearls by Grade',st_h2)) mt=Table([[P('<b>Domain</b>',st_small),P('<b>Good Grade (HH 1-3)</b>',st_small),P('<b>Poor Grade (HH 4-5)</b>',st_small)], [P('Airway',st_small),P('Self-maintaining; close monitoring',st_small),P('Intubate and ventilate',st_small)], [P('Aneurysm Tx',st_small),P('Early coiling/clipping (24-72 h)',st_small),P('Stabilise first; delayed if needed',st_small)], [P('Blood Pressure',st_small),P('SBP 120-160 mmHg until secured',st_small),P('Tight BP control; CPP 60-80 mmHg',st_small)], [P('Nimodipine',st_small),P('60 mg q4h x 21 days (ALL grades)',st_small),P('60 mg q4h x 21 days (ALL grades)',st_small)], [P('Vasospasm',st_small),P('TCD daily; neuro exam q4-6 h',st_small),P('TCD + continuous EEG; ICP monitoring',st_small)], [P('Hydrocephalus',st_small),P('Monitor; LP or EVD if symptomatic',st_small),P('Early EVD if obstructive HCP',st_small)], [P('Seizures',st_small),P('Levetiracetam if occurs; stop after aneurysm secured',st_small),P('Continue AED + cEEG',st_small)]], colWidths=[3.5*cm,6.6*cm,6.6*cm]) mt.setStyle(TableStyle([('BACKGROUND',(0,0),(-1,0),TEAL),('TEXTCOLOR',(0,0),(-1,0),WHITE), ('FONTNAME',(0,0),(-1,0),'Helvetica-Bold'),('FONTSIZE',(0,0),(-1,-1),8.5), ('GRID',(0,0),(-1,-1),0.4,MIDGREY),('VALIGN',(0,0),(-1,-1),'MIDDLE'), ('TOPPADDING',(0,0),(-1,-1),4),('BOTTOMPADDING',(0,0),(-1,-1),4),('LEFTPADDING',(0,0),(-1,-1),5), ('BACKGROUND',(0,2),(-1,2),GREY),('BACKGROUND',(0,4),(-1,4),GREY),('BACKGROUND',(0,6),(-1,6),GREY)])) story.append(mt) story.append(Spacer(1,0.25*cm)) story.append(P('3.3 Common Pitfalls - Do Not Miss',st_h2)) story.append(blist([ '<b>Grade on admission only:</b> SAH grade can change rapidly - reassess every 4-6 hours.', '<b>Grading post-sedation:</b> Both HH and WFNS are invalid after sedation. Always document the pre-sedation grade.', '<b>Fisher Group 1 = safe:</b> CT-negative SAH exists. Correlate with LP if clinical suspicion remains high.', '<b>Ignoring IVH on CT:</b> Bilateral IVH alone = Modified Fisher Grade 2 (33% vasospasm risk) - not low risk.', '<b>Relying solely on radiology report:</b> Learn cisternal anatomy. Read the CT yourself.', '<b>Poor grade = futility:</b> HH Grade 5 carries 70% mortality but 30% can survive. Never withdraw without senior discussion.'])) story.append(Spacer(1,0.25*cm)) story.append(P('3.4 Quick Quiz',st_h2)) story.append(ibox('<b>Q1.</b> Thunderclap headache, GCS 14, right CN III palsy, no motor deficit. ' 'CT: thin diffuse SAH, no IVH. State HH grade, WFNS grade, Modified Fisher grade, and vasospasm risk.<br/><br/>' '<b>Q2.</b> CT: thick blood in basal cisterns + blood in both lateral ventricles. ' 'Modified Fisher grade and vasospasm incidence?<br/><br/>' '<b>Q3.</b> Why is WFNS Grade 3 higher risk than Grade 2 despite an identical GCS range?<br/><br/>' '<b>Q4.</b> When should nimodipine be started and for how long?<br/><br/>' '<b>Q5.</b> A patient admitted HH Grade 2 suddenly drops to Grade 3. List three causes.')) story.append(Spacer(1,0.15*cm)) story.append(ibox('<b>Answers:</b><br/>' '<b>Q1:</b> HH Grade 2; WFNS Grade 2 (GCS 13-14, no motor); Modified Fisher Grade 1 (thin, no IVH) = 24% vasospasm risk.<br/>' '<b>Q2:</b> Modified Fisher Grade 4 (thick + IVH) = 40% vasospasm risk.<br/>' '<b>Q3:</b> Grade 3 adds motor deficit to GCS 13-14, indicating greater cortical/subcortical injury.<br/>' '<b>Q4:</b> Within 48 hours; continued for 21 days (60 mg every 4 hours).<br/>' '<b>Q5:</b> (1) Rebleeding; (2) Acute hydrocephalus; (3) Cerebral vasospasm/DCI.', bg=LTAMBER,border=AMBER)) story.append(Spacer(1,0.3*cm)) story.append(P('3.5 Full Grading Summary - Quick Reference Card',st_h2)) sr=Table([[P('<b>Scale</b>',st_small),P('<b>Type</b>',st_small),P('<b>Year</b>',st_small), P('<b>What It Grades</b>',st_small),P('<b>Primary Use</b>',st_small)], [P('Hunt-Hess',st_small),P('Clinical',st_small),P('1968',st_small), P('Neurological status (0-5)',st_small),P('Surgical timing, prognosis',st_small)], [P('WFNS',st_small),P('Clinical',st_small),P('1988',st_small), P('GCS + motor deficit (1-5)',st_small),P('Universal grading, research',st_small)], [P('Fisher',st_small),P('Radiological',st_small),P('1980',st_small), P('CT blood volume/distribution (1-4)',st_small),P('Predicts vasospasm',st_small)], [P('Modified Fisher',st_small),P('Radiological',st_small),P('2006',st_small), P('CT blood + IVH (0-4)',st_small),P('Accurate vasospasm prediction',st_small)], [P('Hijdra Sum Score',st_small),P('Radiological',st_small),P('1985',st_small), P('Semi-quantitative cisternal blood (0-30)',st_small),P('Research; superior prediction',st_small)]], colWidths=[3.3*cm,2.3*cm,1.6*cm,5.4*cm,4.8*cm]) sr.setStyle(TableStyle([('BACKGROUND',(0,0),(-1,0),NAVY),('TEXTCOLOR',(0,0),(-1,0),WHITE), ('FONTNAME',(0,0),(-1,0),'Helvetica-Bold'),('FONTSIZE',(0,0),(-1,-1),8.5), ('GRID',(0,0),(-1,-1),0.4,MIDGREY),('VALIGN',(0,0),(-1,-1),'MIDDLE'), ('TOPPADDING',(0,0),(-1,-1),4),('BOTTOMPADDING',(0,0),(-1,-1),4),('LEFTPADDING',(0,0),(-1,-1),5), ('BACKGROUND',(0,2),(-1,2),GREY),('BACKGROUND',(0,4),(-1,4),GREY)])) story.append(sr) story.append(Spacer(1,0.3*cm)) ft=Table([[P('References: Bradley &amp; Daroff\'s Neurology | Tintinalli\'s Emergency Medicine | ' 'Schwartz\'s Principles of Surgery 11e | Goldman-Cecil Medicine | ' 'Tietz Textbook Lab Medicine 7e | Frontera JA et al. Neurosurgery 2006 | Drake CG. J Neurosurg 1988', st_caption)]],colWidths=[17.4*cm]) ft.setStyle(TableStyle([('BACKGROUND',(0,0),(-1,-1),NAVY), ('TOPPADDING',(0,0),(-1,-1),5),('BOTTOMPADDING',(0,0),(-1,-1),5), ('LEFTPADDING',(0,0),(-1,-1),8),('TEXTCOLOR',(0,0),(-1,-1),LTBLUE)])) story.append(ft) doc.build(story) print("SUCCESS") PYEOF echo "Script written"

Running Command

cd /home/daytona/workspace/sah-ecmo && python build_sah_pdf.py 2>&1

This is a shared conversation. Sign in to Orris to start your own chat.