Migraine is now understood as a neurovascular disorder involving abnormal brain excitability, activation of pain pathways, and inflammation around cranial blood vessels. Older theories focused mainly on vasodilation, but standard texts like Harrison's Principles of Internal Medicine explain that migraine is primarily a disorder of the nervous system with secondary vascular changes. Simplified Pathophysiology of Migraine 1. Triggering Phase — “Hyperexcitable Brain” People with migraine have a genetically sensitive or hyperexcitable brain. Common triggers: Stress Lack of sleep Hormonal changes Certain foods Bright light Fasting These triggers activate specific brain regions, especially: Hypothalamus Brainstem nuclei Cortex This explains early symptoms before headache: Yawning Food cravings Mood change Fatigue 2. Cortical Spreading Depression (Especially in Migraine With Aura) A wave of neuronal depolarization spreads slowly across the cerebral cortex. This is called: Cortical Spreading Depression (CSD) Sequence: Sudden neuronal activation Followed by suppression of brain activity Changes in blood flow occur secondarily Rate: About 2–6 mm/min across cortex Effects: Causes aura symptoms: Flashing lights Zig-zag lines Numbness Speech difficulty CSD also activates trigeminal pain pathways. 3. Activation of the Trigeminovascular System (Most Important Step) This is central to migraine pain. The trigeminal nerve supplies: Meninges Large cerebral vessels When activated, trigeminal nerve endings release neuropeptides: CGRP (Calcitonin Gene-Related Peptide) Substance P Neurokinin A These cause: Vasodilation Plasma protein leakage Sterile neurogenic inflammation Result: Throbbing headache pain CGRP is especially important because: Its level rises during attacks CGRP blockers improve migraine 4. Central Sensitization Repeated pain signaling sensitizes neurons in: Trigeminal nucleus caudalis Thalamus This makes the brain overly responsive. Consequences: Normal touch becomes painful Scalp tenderness Pain worsens with movement Sensitivity to light and sound This explains: Allodynia Photophobia Phonophobia 5. Brainstem Dysfunction Brainstem nuclei involved: Dorsal raphe nucleus (serotonin) Locus coeruleus (noradrenaline) Altered neurotransmitters: Serotonin ↓ during attack Dopamine involvement This contributes to: Nausea Vomiting Autonomic symptoms Important Neurotransmitters in Migraine Neurotransmitter Role CGRP Major mediator of pain and vasodilation Serotonin (5-HT) Modulates trigeminal pathways Dopamine Nausea, yawning, prodrome Glutamate Cortical excitability and CSD Why Triptans Work Triptans are: 5-HT1B/1D agonists They: Inhibit CGRP release Reduce trigeminal transmission Cause cranial vasoconstriction Thus they abort migraine attacks. One-Line Flowchart Trigger ↓ Brain hyperexcitability ↓ Cortical spreading depression (± aura) ↓ Trigeminovascular activation ↓ CGRP release + neurogenic inflammation ↓ Pain transmission to brainstem/thalamus ↓ Migraine headache + sensory symptoms High-Yield Harrison-Based Concepts Migraine is primarily a neuronal disorder, not just vascular. Trigeminovascular activation is the key mechanism of pain. CGRP is central in modern migraine theory. Cortical spreading depression explains aura. Central sensitization causes photophobia and allodynia. Standard References Harrison's Principles of Internal Medicine — Chapter on Headache and Migraine Adams and Victor's Principles of Neurology Robbins and Cotran Pathologic Basis of Disease Davidson's Principles and Practice of

Asking for Preferences
Reading File
Searching PubMed

migraine pathophysiology cortical spreading depression trigeminovascular

Finding Sources
Searching PubMed

migraine CGRP pathophysiology trigeminovascular

Reading File
Reading File
Finding Sources
Reading File
Reading File
Reading File
Finding Sources
I now have extensive textbook data to give a thorough verification and expansion. Let me compile the full analysis.

Verification & Expansion of Your Migraine Pathophysiology Summary

Overall verdict: Accurate and well-structured. The content closely aligns with what Bradley & Daroff's Neurology in Clinical Practice, Adams & Victor's Principles of Neurology (12th ed.), Goodman & Gilman's Pharmacological Basis of Therapeutics, and Guyton & Hall's Medical Physiology say. Below I verify each section, flag nuances, correct minor oversimplifications, and expand key points.

Section 1 - Triggering Phase ("Hyperexcitable Brain") ✅ Mostly Accurate

Verified: Bradley & Daroff confirms that migraine involves widespread brain dysfunction across multiple functional networks (pain, visual, auditory, olfactory, sleep-wakefulness). The listed triggers (stress, sleep, hormones, food, light, fasting) are standard.
Important nuance to add - the "migraine generator" debate: Your summary implies a straightforward cascade from the hypothalamus/brainstem. The textbooks are more cautious. Bradley & Daroff states:
"It seems probable that there is not a single 'migraine generator' shared by all people with migraine and that there is not a single 'migraine generator' within individuals from attack to attack."
PET studies do show premonitory activation in the posterolateral hypothalamus, midbrain tegmental area, periaqueductal gray (PAG), and dorsal pons - the PAG is not mentioned in your summary. The PAG is a major pain-modulating center and is consistently highlighted in imaging studies as activated before migraine symptoms begin.
Expansion: The premonitory phase symptoms (yawning, food cravings, mood change, fatigue) are now neuroimaging-supported as reflecting hypothalamic dysfunction - this is correct. One addition: osmophobia (smell sensitivity) during the premonitory and headache phases is considered highly specific for migraine (Bradley & Daroff, citing Chalmer et al., 2018) and is worth including.

Section 2 - Cortical Spreading Depression (CSD) ✅ Accurate, with important caveats

Verified: CSD is confirmed as the electrophysiological substrate of migraine aura by all major texts.
Speed: Minor correction needed. Your summary says "2-6 mm/min." The textbooks are more specific:
  • Bradley & Daroff: "2-4 mm/min"
  • Adams & Victor: "2.2-3 mm/min"
  • Guyton & Hall: consistent with ~3 mm/min
The upper bound of 6 mm/min is too high based on standard references. The range 2-4 mm/min is more defensible.
Important nuance your summary omits:
"It is debated whether or not CSD can lead to activation of the trigeminocervical system and thus trigger the headache phase." - Bradley & Daroff
This is a key point often glossed over. CSD explains the aura confidently, but its causal role in triggering pain is still debated - some data suggest CSD evokes a signal that activates the trigeminal system, but this is not fully proven.
Blood flow clarification: Your summary says "changes in blood flow occur secondarily." This is correct and important - functional MRI evidence shows that a phase of focal hyperemia precedes the oligemia during aura, directly contradicting the old vasospasm theory. Adams & Victor details that the oligemia does not respect arterial vascular territories, ruling out simple vasospasm.
Also: CSD begins most commonly in the occipital lobe and spreads forward. This is why visual aura (flashing lights, zig-zag lines - the classic "scintillating scotoma") is the most common aura type - this detail is worth making explicit.

Section 3 - Trigeminovascular System Activation ✅ Accurate, Expandable

Verified: This is confirmed as the central pain mechanism across all major neurology and pharmacology texts.
What your summary gets right:
  • Trigeminal nerve supplying meninges and large cerebral vessels ✅
  • Release of CGRP, Substance P, Neurokinin A ✅
  • Resulting vasodilation and sterile neurogenic inflammation ✅
Important expansion from Adams & Victor:
"Activation of these fibers releases substance P, CGRP, and other peptides into the vessel wall, which serves to sensitize the trigeminal system to the pulsatility of cranial vessels, and to increase their permeability, thereby promoting an inflammatory response."
The pulsatility of vessels being perceived as pain after sensitization is an important mechanistic detail - it explains the throbbing quality of migraine pain, which is not explicitly made in your summary.
Also note: Nitric oxide (NO) is also released from trigeminovascular neurons and contributes to vasodilation and inflammation - Guyton & Hall specifically mentions NO alongside CGRP and Substance P. Your summary omits NO.
CGRP's clinical importance: Confirmed. CGRP levels rise during attacks and CGRP receptor antagonists (gepants: rimegepant, ubrogepant) and anti-CGRP monoclonal antibodies (erenumab, fremanezumab, galcanezumab) are now approved therapies - a significant expansion of the treatment landscape since older texts. Your summary correctly identifies CGRP blockers work but should mention these drug classes by name.

Section 4 - Central Sensitization ✅ Accurate

Verified: Bradley & Daroff states:
"Recurrent and/or prolonged activation of the trigeminocervical system can lead to peripheral and central sensitization. Sensitized neurons have lower thresholds for activation, increased spontaneous activity, and receptive field expansion. Approximately three-fourths of people with migraine have evidence of cutaneous allodynia during a migraine attack."
What your summary gets right: Trigeminal nucleus caudalis and thalamus involvement, allodynia, photophobia, phonophobia ✅
Minor gap: The three-fourths (75%) prevalence of cutaneous allodynia in migraineurs during attacks is a high-yield fact worth adding. Also: once second-order neuron sensitization occurs (in the thalamus), triptans become less effective at aborting attacks - this is a clinically crucial point (supports early triptan use).
Expansion: Bradley & Daroff also describes third-order neuron sensitization involving cortical neurons, which accounts for the extreme sensitivity to touch and environmental stimuli.

Section 5 - Brainstem Dysfunction ✅ Accurate, with additions

Verified. The dorsal raphe (serotonin) and locus coeruleus (noradrenaline) are correct. However:
PAG omission: The periaqueductal gray (PAG) is repeatedly mentioned in neuroimaging studies as a key activated structure and is involved in descending pain modulation. Repeated migraine attacks may actually damage PAG function over time (iron deposition has been found in PAG in chronic migraine). Your summary does not mention the PAG.
Serotonin detail from Goodman & Gilman:
"Plasma and platelet concentrations of 5HT vary with different phases of the migraine attack. Urinary concentrations of 5HT and its metabolites are elevated during most migraine attacks. Migraine may be precipitated by agents (e.g., reserpine and fenfluramine) that release 5HT from intracellular storage sites."
This is more nuanced than just "serotonin decreases during attack" - it fluctuates across phases.

Neurotransmitter Table - Corrections & Additions

Your table is mostly correct. Here is the expanded version:
Neurotransmitter/MediatorRoleNotes
CGRPPrimary mediator of pain and vasodilationTarget of gepants and anti-CGRP antibodies
Serotonin (5-HT)Modulates trigeminal pathways; fluctuates across attack phasesLevels vary by phase, not simply "decrease"
DopamineNausea, yawning, prodromeDopamine receptor sensitivity may be increased in migraineurs
GlutamateCortical excitability and CSD propagationNMDA receptor involvement in central sensitization
Substance PReleased with CGRP; neurogenic inflammationLess targeted therapeutically than CGRP
Nitric oxide (NO)Vasodilation; triggers migraine; released from trigeminovascular neuronsMissing from your summary - nitroglycerin (a NO donor) is used to experimentally trigger migraine attacks
Neurokinin AReleased with CGRP/SP from trigeminal endingsYour summary mentions it - correct
PACAP (Pituitary adenylate cyclase-activating polypeptide) is an emerging mediator beyond CGRP - it is now a therapeutic target (anti-PACAP antibodies in trials). Recent PubMed review (PMID: 38887982) covers PACAP-targeted treatments.

Section on Triptans - Accurate but Incomplete

Goodman & Gilman confirms 5-HT1B/1D mechanism. However, the mechanism is more nuanced than just "cause cranial vasoconstriction":
"One hypothesis... activation of 5HT1B/1D receptors may cause constriction of intracranial blood vessels... An alternative hypothesis proposes that both 5HT1B and 5HT1D receptors serve as presynaptic autoreceptors that block the release of neurotransmitter or proinflammatory neuropeptides at nerve terminals in the perivascular space."
So triptans work via two mechanisms: (1) cranial vasoconstriction (5-HT1B, vessel smooth muscle) and (2) inhibition of trigeminal neuropeptide release (5-HT1D, presynaptic). Your summary only mentions the second, not the first. Both should be included.
Important clinical point omitted: Triptans are contraindicated in patients with cardiovascular disease because of the vasoconstriction mechanism - this is high-yield clinically.

Points Missing From Your Summary

Missing ConceptSourceImportance
Periaqueductal gray (PAG) activationBradley & Daroff, Adams & VictorKey imaging finding in premonitory phase; descending pain modulation
Nitric oxide (NO) as a mediatorGuyton & HallNitroglycerin triggers migraine experimentally
CSD's causal link to headache is debatedBradley & DaroffIntellectual honesty; CSD clearly explains aura, pain link less certain
75% of migraineurs develop cutaneous allodyniaBradley & DaroffHigh-yield stat
Early triptan use required before central sensitizationTextbook principleMajor clinical implication of the sensitization model
Triptan vasoconstriction mechanism (5-HT1B)Goodman & GilmanExplains contraindication in CVD
PACAP as emerging mediator/targetRecent reviewsBeyond CGRP; emerging therapeutics
Oligemia does not respect arterial territoriesAdams & Victor, Bradley & DaroffDirectly refutes the vasospasm theory
Osmophobia - highly specific for migraineBradley & DaroffDiagnostic specificity
Anti-CGRP monoclonal antibodies (gepants, erenumab, etc.)Current knowledgeMajor therapeutic advancement
Postdrome phaseBradley & DaroffMigraine has 4 phases: prodrome, aura, headache, postdrome

Summary of Accuracy

Your ClaimVerdictNotes
Migraine is neuronal, not purely vascular✅ ConfirmedWell-supported across all texts
CSD rate "2-6 mm/min"⚠️ Slightly highTextbooks say 2-4 mm/min
Hypothalamus + brainstem as trigger regions✅ ConfirmedPAG should be added
Trigeminal nerve releases CGRP, SP, Neurokinin A✅ ConfirmedAdd NO
Sterile neurogenic inflammation✅ ConfirmedClassic Moskowitz model
Central sensitization - trigeminal nucleus caudalis + thalamus✅ ConfirmedAdd: 75% allodynia rate
Serotonin ↓ during attack⚠️ Oversimplified5-HT levels vary by phase
Triptans = 5-HT1B/1D agonists✅ ConfirmedAdd vasoconstriction mechanism and CVD contraindication
CSD activates trigeminal pain pathways⚠️ DebatedTextbooks explicitly call this debated
Your summary is a strong, accurate overview. The main items to refine are: the CSD speed (2-4 not 2-6 mm/min), the debate around whether CSD directly triggers the headache phase, the omission of NO and PAG, the 4-phase migraine model (including postdrome), and the dual mechanism of triptans.
References used:
  • Bradley and Daroff's Neurology in Clinical Practice, block26
  • Adams and Victor's Principles of Neurology 12th ed., block2
  • Goodman & Gilman's The Pharmacological Basis of Therapeutics, block4
  • Guyton and Hall Textbook of Medical Physiology, block6
  • Recent PubMed reviews: PMID 38887982 (PACAP treatments, 2024), PMID 41087022 (sex differences in migraine, 2025)

Generate a PDF quick-reference card on migraine pathophysiology

Reading File
Running Command

ls -la /home/daytona/workspace/ 2>/dev/null && mkdir -p /home/daytona/workspace/migraine-ref-card

Writing File

~/migraine-ref-card/generate_card.py

#!/usr/bin/env python3
"""
Migraine Pathophysiology Quick-Reference Card
Single A4 landscape page, generated with ReportLab
"""

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

OUT = "/home/daytona/workspace/migraine-ref-card/Migraine_Pathophysiology_QuickRef.pdf"

# ── Palette ──────────────────────────────────────────────────────────────────
C_HEADER   = HexColor("#1A3A5C")   # deep navy
C_ACCENT1  = HexColor("#C0392B")   # arterial red  (pain / CGRP)
C_ACCENT2  = HexColor("#2980B9")   # blue          (neural)
C_ACCENT3  = HexColor("#27AE60")   # green         (triptans / tx)
C_ACCENT4  = HexColor("#8E44AD")   # purple        (sensitization)
C_ACCENT5  = HexColor("#E67E22")   # orange        (CSD)
C_LIGHT    = HexColor("#EBF5FB")   # very light blue tint
C_LIGHT2   = HexColor("#FDFEFE")
C_LTGRAY   = HexColor("#F2F3F4")
C_ROWALT   = HexColor("#EAF4FB")

PAGE = landscape(A4)
W, H = PAGE  # 297 x 210 mm

doc = SimpleDocTemplate(
    OUT,
    pagesize=PAGE,
    leftMargin=10*mm,
    rightMargin=10*mm,
    topMargin=8*mm,
    bottomMargin=6*mm,
    title="Migraine Pathophysiology Quick-Reference Card",
    author="Orris Medical",
)

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

BASE       = S("base",      fontName="Helvetica",       fontSize=7,   leading=9.5, textColor=black)
BOLD       = S("bold",      fontName="Helvetica-Bold",  fontSize=7,   leading=9.5, textColor=black)
TITLE      = S("title",     fontName="Helvetica-Bold",  fontSize=15,  leading=18,  textColor=white, alignment=TA_CENTER)
SUBTITLE   = S("subtitle",  fontName="Helvetica",       fontSize=8,   leading=10,  textColor=HexColor("#AED6F1"), alignment=TA_CENTER)
SHEAD      = S("shead",     fontName="Helvetica-Bold",  fontSize=8,   leading=10,  textColor=white, alignment=TA_CENTER)
SHEAD_L    = S("shead_l",   fontName="Helvetica-Bold",  fontSize=8,   leading=10,  textColor=white, alignment=TA_LEFT)
ITEM       = S("item",      fontName="Helvetica",       fontSize=6.8, leading=9,   textColor=HexColor("#1B2631"))
ITEM_BOLD  = S("itembold",  fontName="Helvetica-Bold",  fontSize=6.8, leading=9,   textColor=HexColor("#1B2631"))
LABEL      = S("label",     fontName="Helvetica-Bold",  fontSize=6.5, leading=8.5, textColor=C_HEADER)
ARROW      = S("arrow",     fontName="Helvetica-Bold",  fontSize=9,   leading=11,  textColor=C_ACCENT1, alignment=TA_CENTER)
NOTE       = S("note",      fontName="Helvetica-Oblique",fontSize=6.2,leading=8,   textColor=HexColor("#555555"))
WARN       = S("warn",      fontName="Helvetica-Bold",  fontSize=6.5, leading=8.5, textColor=HexColor("#922B21"))

def p(text, style=BASE): return Paragraph(text, style)
def pb(text): return Paragraph(text, BOLD)
def pi(text): return Paragraph(text, ITEM)
def bullet(text, color="#1A3A5C"): 
    return Paragraph(f'<font color="{color}">&#9658;</font> {text}', ITEM)
def dot(text, color="#1A3A5C"): 
    return Paragraph(f'<font color="{color}">&#8226;</font> {text}', ITEM)

# ── Helper: section header cell ──────────────────────────────────────────────
def hdr(text, bg=C_HEADER):
    return Table(
        [[p(text, SHEAD)]],
        colWidths=["100%"],
        style=TableStyle([
            ("BACKGROUND", (0,0), (-1,-1), bg),
            ("TOPPADDING",    (0,0), (-1,-1), 3),
            ("BOTTOMPADDING", (0,0), (-1,-1), 3),
            ("LEFTPADDING",   (0,0), (-1,-1), 4),
            ("RIGHTPADDING",  (0,0), (-1,-1), 4),
            ("ROUNDEDCORNERS", [3,3,3,3]),
        ])
    )

# ══════════════════════════════════════════════════════════════════════════════
# SECTION BUILDERS
# ══════════════════════════════════════════════════════════════════════════════

def make_title_banner():
    """Full-width title bar"""
    data = [[
        p("MIGRAINE PATHOPHYSIOLOGY", TITLE),
        p("Quick-Reference Card  |  Neurovascular Disorder of Brain Excitability  |  Sources: Bradley & Daroff • Adams & Victor • Goodman & Gilman • Guyton & Hall", SUBTITLE),
    ]]
    t = Table(data, colWidths=[110*mm, 170*mm],
              style=TableStyle([
                  ("BACKGROUND", (0,0), (-1,-1), C_HEADER),
                  ("VALIGN",     (0,0), (-1,-1), "MIDDLE"),
                  ("TOPPADDING",    (0,0), (-1,-1), 4),
                  ("BOTTOMPADDING", (0,0), (-1,-1), 4),
                  ("LEFTPADDING",   (0,0), (-1,-1), 8),
                  ("RIGHTPADDING",  (0,0), (-1,-1), 8),
              ]))
    return t

def make_flowchart():
    """Vertical cascade flowchart in one narrow column"""
    steps = [
        (C_HEADER,   "TRIGGER",              "Stress • Sleep deprivation\nHormonal change • Bright light\nCertain foods • Fasting"),
        (C_ACCENT2,  "BRAIN HYPEREXCITABILITY","Hypothalamus activation\nBrainstem nuclei (PAG, dorsal pons)\nProdrome: yawning, cravings, fatigue"),
        (C_ACCENT5,  "CORTICAL SPREADING\nDEPRESSION (CSD)",  "Wave of depolarization 2–4 mm/min\nOccipital → anterior cortex\nAura: zig-zag lines, numbness, speech Δ"),
        (C_ACCENT1,  "TRIGEMINOVASCULAR\nACTIVATION",       "Trigeminal endings on meninges/vessels\nRelease: CGRP • SP • NKA • NO\nNeurogenic sterile inflammation"),
        (C_ACCENT4,  "CENTRAL\nSENSITIZATION",             "Trigeminal nucleus caudalis → Thalamus\nAllodynia (≈75% of attacks)\nPhotophobia • Phonophobia"),
        (C_ACCENT3,  "MIGRAINE HEADACHE",    "Throbbing unilateral pain 4–72 h\nNausea / vomiting • Osmophobia\n± Postdrome fatigue/cognitive fog"),
    ]
    rows = []
    for bg, title, detail in steps:
        title_cell = p(f'<b><font color="white">{title}</font></b>', S("fc_t", fontName="Helvetica-Bold", fontSize=6.8, leading=8.5, alignment=TA_CENTER))
        detail_cell = p(detail, S("fc_d", fontName="Helvetica", fontSize=6.2, leading=8, alignment=TA_CENTER, textColor=HexColor("#1B2631")))
        block = Table([
            [title_cell],
            [detail_cell],
        ], colWidths=[52*mm],
           style=TableStyle([
               ("BACKGROUND",    (0,0), (0,0), bg),
               ("BACKGROUND",    (0,1), (0,1), C_LTGRAY),
               ("TOPPADDING",    (0,0), (-1,-1), 2),
               ("BOTTOMPADDING", (0,0), (-1,-1), 2),
               ("LEFTPADDING",   (0,0), (-1,-1), 3),
               ("RIGHTPADDING",  (0,0), (-1,-1), 3),
               ("BOX", (0,0), (-1,-1), 0.5, bg),
           ]))
        rows.append([block])
        if (bg, title, detail) != steps[-1]:
            rows.append([p("▼", S("arr", fontName="Helvetica-Bold", fontSize=10, leading=11, textColor=C_ACCENT1, alignment=TA_CENTER))])

    return Table(rows, colWidths=[54*mm],
                 style=TableStyle([
                     ("TOPPADDING",    (0,0), (-1,-1), 0),
                     ("BOTTOMPADDING", (0,0), (-1,-1), 0),
                     ("LEFTPADDING",   (0,0), (-1,-1), 0),
                     ("RIGHTPADDING",  (0,0), (-1,-1), 0),
                 ]))

def make_phases():
    """4 phases of migraine attack"""
    phases = [
        (C_ACCENT2,  "1. PRODROME\n(hours-days before)", "Hypothalamic activation\nYawning, food cravings\nMood & sleep changes\nPolyuria, osmophobia"),
        (C_ACCENT5,  "2. AURA\n(20–60 min; ~30% of pts)", "CSD in occipital cortex\nScintillating scotoma\nZig-zag (fortification) lines\nNumbness, dysphasia"),
        (C_ACCENT1,  "3. HEADACHE\n(4–72 hours)", "Trigeminovascular activation\nThrobbing unilateral pain\nN/V, photo/phono/osmophobia\nAllodynia (≈75%)"),
        (C_ACCENT4,  "4. POSTDROME\n(hours-days after)", "Fatigue, cognitive fog\n'Migraine hangover'\nNeck stiffness\nPoor concentration"),
    ]
    rows = [[
        Table([[p(f'<b><font color="white">{t}</font></b>', S("ph_t", fontName="Helvetica-Bold", fontSize=6.5, leading=8, alignment=TA_CENTER)),
                p(d, S("ph_d", fontName="Helvetica", fontSize=6, leading=7.8, alignment=TA_LEFT, textColor=HexColor("#1B2631")))
               ]], colWidths=[60*mm],
               style=TableStyle([
                   ("BACKGROUND", (0,0), (0,0), bg),
                   ("BACKGROUND", (0,1), (0,1), C_LTGRAY),
                   ("TOPPADDING",    (0,0), (-1,-1), 2),
                   ("BOTTOMPADDING", (0,0), (-1,-1), 2),
                   ("LEFTPADDING",   (0,0), (-1,-1), 3),
                   ("RIGHTPADDING",  (0,0), (-1,-1), 3),
                   ("BOX", (0,0), (-1,-1), 0.5, bg),
               ]))
        for bg, t, d in phases
    ]]
    return Table(rows, colWidths=[62*mm]*4,
                 style=TableStyle([
                     ("TOPPADDING",    (0,0), (-1,-1), 0),
                     ("BOTTOMPADDING", (0,0), (-1,-1), 0),
                     ("LEFTPADDING",   (0,0), (-1,-1), 1),
                     ("RIGHTPADDING",  (0,0), (-1,-1), 1),
                 ]))

def make_neurotransmitters():
    """Neurotransmitter table"""
    header = [
        p("<b>Mediator</b>", SHEAD_L),
        p("<b>Role in Migraine</b>", SHEAD_L),
        p("<b>Clinical Note</b>", SHEAD_L),
    ]
    rows = [
        ["CGRP",         "Primary vasodilator & pain mediator; released from trigeminal endings",    "Target: gepants (rimegepant, ubrogepant)\nAnti-CGRP mAbs: erenumab, fremanezumab"],
        ["Serotonin\n(5-HT)", "Modulates trigeminal pain pathways;\nfluctuates across attack phases", "5-HT1B/1D = triptan target\nReserpine (releases 5-HT) triggers migraine"],
        ["CGRP", "", ""],  # placeholder – replaced below
        ["Substance P",  "Co-released with CGRP; plasma protein leakage\n& neurogenic inflammation", "Contributes to vessel wall sensitization"],
        ["Nitric Oxide\n(NO)",   "Vasodilator from trigeminovascular neurons;\nnitroglycerin → experimental migraine", "NO synthase inhibitors under investigation"],
        ["Dopamine",     "Prodrome: yawning, nausea\nHypersensitivity of D2 receptors",              "Prochlorperazine (D2 blocker) used acutely"],
        ["Glutamate",    "Drives cortical hyperexcitability\nand CSD propagation",                   "NMDA receptor involvement in\ncentral sensitization"],
        ["Neurokinin A\n(NKA)",  "Co-released with CGRP/SP from trigeminal\nC-fibers",              "Less studied therapeutically than CGRP"],
        ["PACAP",        "Emerging mediator; triggers migraine;\nneurovascular modulator",           "Anti-PACAP mAbs in clinical trials (2024–)"],
    ]
    # Remove placeholder row
    rows = [r for r in rows if r[0] != "CGRP" or r[1] != ""]

    table_data = [header]
    for i, r in enumerate(rows):
        table_data.append([
            p(f"<b>{r[0]}</b>", ITEM_BOLD),
            p(r[1], ITEM),
            p(r[2], ITEM),
        ])

    col_w = [28*mm, 60*mm, 55*mm]
    ts = TableStyle([
        ("BACKGROUND",    (0,0), (-1,0), C_ACCENT2),
        ("ROWBACKGROUNDS",(0,1), (-1,-1), [C_LIGHT2, C_ROWALT]),
        ("GRID",          (0,0), (-1,-1), 0.3, HexColor("#BDC3C7")),
        ("TOPPADDING",    (0,0), (-1,-1), 2),
        ("BOTTOMPADDING", (0,0), (-1,-1), 2),
        ("LEFTPADDING",   (0,0), (-1,-1), 3),
        ("RIGHTPADDING",  (0,0), (-1,-1), 3),
        ("VALIGN",        (0,0), (-1,-1), "TOP"),
    ])
    return Table(table_data, colWidths=col_w, style=ts)

def make_triptans():
    """Triptan mechanism box"""
    data = [
        [p("<b>TRIPTANS — 5-HT<sub rise=2>1B/1D</sub> Agonists</b>", S("th", fontName="Helvetica-Bold", fontSize=7.2, leading=9, textColor=white))],
        [p("Mechanism 1 (5-HT<sub rise=2>1B</sub>): Cranial vasoconstriction\n"
           "Mechanism 2 (5-HT<sub rise=2>1D</sub>): Presynaptic inhibition of CGRP/SP release\n"
           "→ Both reduce neurogenic inflammation & pain transmission\n\n"
           "<b>Key point:</b> Most effective when taken <b>early</b> — before central\n"
           "sensitization establishes (i.e., before allodynia begins)\n\n"
           "<b>Contraindicated:</b> Ischaemic heart disease, uncontrolled HTN,\n"
           "prior stroke (vasoconstriction risk)",
           ITEM)],
    ]
    return Table(data, colWidths=[56*mm],
                 style=TableStyle([
                     ("BACKGROUND", (0,0), (0,0), C_ACCENT3),
                     ("BACKGROUND", (0,1), (0,1), HexColor("#EAFAF1")),
                     ("BOX",        (0,0), (-1,-1), 0.8, C_ACCENT3),
                     ("TOPPADDING",    (0,0), (-1,-1), 3),
                     ("BOTTOMPADDING", (0,0), (-1,-1), 3),
                     ("LEFTPADDING",   (0,0), (-1,-1), 4),
                     ("RIGHTPADDING",  (0,0), (-1,-1), 4),
                 ]))

def make_csd_box():
    """CSD detail box"""
    data = [
        [p("<b>CORTICAL SPREADING DEPRESSION</b>", S("ch", fontName="Helvetica-Bold", fontSize=7.2, leading=9, textColor=white))],
        [p("• Wave of neuronal depolarization then suppression\n"
           "• Origin: usually occipital lobe → spreads anteriorly\n"
           "• Rate: 2–4 mm/min (does NOT respect vascular territories)\n"
           "• Preceded by brief focal hyperaemia, followed by oligaemia\n"
           "• Electrophysiological basis of aura (confirmed)\n"
           "• Whether CSD directly triggers headache is <b>debated</b>\n"
           "• CSD may activate the trigeminocervical complex via\n"
           "  inflammatory mediator diffusion to the meninges",
           ITEM)],
    ]
    return Table(data, colWidths=[56*mm],
                 style=TableStyle([
                     ("BACKGROUND", (0,0), (0,0), C_ACCENT5),
                     ("BACKGROUND", (0,1), (0,1), HexColor("#FEF9E7")),
                     ("BOX",        (0,0), (-1,-1), 0.8, C_ACCENT5),
                     ("TOPPADDING",    (0,0), (-1,-1), 3),
                     ("BOTTOMPADDING", (0,0), (-1,-1), 3),
                     ("LEFTPADDING",   (0,0), (-1,-1), 4),
                     ("RIGHTPADDING",  (0,0), (-1,-1), 4),
                 ]))

def make_sensitization_box():
    """Central sensitization box"""
    data = [
        [p("<b>CENTRAL SENSITIZATION</b>", S("sh", fontName="Helvetica-Bold", fontSize=7.2, leading=9, textColor=white))],
        [p("Peripheral sensitization: trigeminal C-fibers → respond to\n"
           "normally innocuous stimuli (vessel pulsation → throbbing pain)\n\n"
           "1st-order neuron sensitization → activates\n"
           "2nd-order neurons in trigeminal nucleus caudalis\n"
           "→ Cutaneous allodynia (scalp tenderness, ≈75% of attacks)\n\n"
           "3rd-order neuron sensitization → thalamus/cortex\n"
           "→ Whole-body allodynia, photophobia, phonophobia\n\n"
           "<b>Clinical implication:</b> Once allodynia is present,\n"
           "triptans are less effective — treat EARLY",
           ITEM)],
    ]
    return Table(data, colWidths=[56*mm],
                 style=TableStyle([
                     ("BACKGROUND", (0,0), (0,0), C_ACCENT4),
                     ("BACKGROUND", (0,1), (0,1), HexColor("#F5EEF8")),
                     ("BOX",        (0,0), (-1,-1), 0.8, C_ACCENT4),
                     ("TOPPADDING",    (0,0), (-1,-1), 3),
                     ("BOTTOMPADDING", (0,0), (-1,-1), 3),
                     ("LEFTPADDING",   (0,0), (-1,-1), 4),
                     ("RIGHTPADDING",  (0,0), (-1,-1), 4),
                 ]))

def make_key_facts():
    """High-yield facts"""
    facts = [
        ("<b>Vascular vs Neural:</b>", "Migraine is primarily a <b>neuronal</b> disorder; vascular changes are secondary. MRA studies show no change in cerebral artery diameter during attacks."),
        ("<b>Genetics:</b>", "1st-degree relatives: ×2 risk (MO without aura); ×4 risk (MA with aura). FHM linked to CACNA1A, ATP1A2, SCN1A mutations."),
        ("<b>Prevalence:</b>", "12% general population (18% women, 6% men). Peak 4th decade. WHO: among most disabling conditions worldwide."),
        ("<b>Chronic migraine:</b>", "≥15 headache days/month including ≥8 migraine days. Affects ~2% of population. Average 22 headache days/month."),
        ("<b>CGRP therapies:</b>", "Acute: gepants (rimegepant, ubrogepant, atogepant). Preventive: anti-CGRP mAbs (erenumab, fremanezumab, galcanezumab, eptinezumab)."),
        ("<b>PAG role:</b>", "Periaqueductal gray activated in premonitory phase (PET). Descending pain modulator. Iron deposition in PAG found in chronic migraine."),
        ("<b>NO triggers:</b>", "Nitroglycerin (NO donor) reliably triggers migraine — used in research models. NO released from trigeminovascular neurons."),
        ("<b>Osmophobia:</b>", "Smell hypersensitivity; not in formal ICHD criteria but highly specific for migraine diagnosis when present."),
    ]
    rows = [[p(k, ITEM_BOLD), p(v, ITEM)] for k, v in facts]
    header = [[p("<b>High-Yield Clinical Facts</b>", SHEAD_L), p("", SHEAD_L)]]
    t = Table(header + rows,
              colWidths=[32*mm, 111*mm],
              style=TableStyle([
                  ("BACKGROUND",    (0,0), (-1,0), C_HEADER),
                  ("ROWBACKGROUNDS",(0,1), (-1,-1), [C_LIGHT2, C_ROWALT]),
                  ("GRID",          (0,0), (-1,-1), 0.3, HexColor("#BDC3C7")),
                  ("TOPPADDING",    (0,0), (-1,-1), 2),
                  ("BOTTOMPADDING", (0,0), (-1,-1), 2),
                  ("LEFTPADDING",   (0,0), (-1,-1), 3),
                  ("RIGHTPADDING",  (0,0), (-1,-1), 3),
                  ("VALIGN",        (0,0), (-1,-1), "TOP"),
                  ("SPAN",          (0,0), (1,0)),
              ]))
    return t

def make_footer():
    foot_text = (
        "Sources: Bradley & Daroff's Neurology in Clinical Practice  •  Adams & Victor's Principles of Neurology 12e  •  "
        "Goodman & Gilman's Pharmacological Basis of Therapeutics  •  Guyton & Hall Medical Physiology  •  "
        "ICHD-3 (IHS)  •  PubMed PMIDs: 38887982, 41087022  |  "
        "CSD = Cortical Spreading Depression  •  CGRP = Calcitonin Gene-Related Peptide  •  "
        "SP = Substance P  •  NKA = Neurokinin A  •  NO = Nitric Oxide  •  "
        "PAG = Periaqueductal Gray  •  mAb = Monoclonal Antibody  •  FHM = Familial Hemiplegic Migraine"
    )
    return p(foot_text, S("foot", fontName="Helvetica", fontSize=5.5, leading=7, textColor=HexColor("#7F8C8D"), alignment=TA_CENTER))

# ══════════════════════════════════════════════════════════════════════════════
# LAYOUT ASSEMBLY
# ══════════════════════════════════════════════════════════════════════════════

def build():
    story = []

    # ── Title banner ──────────────────────────────────────────────────────────
    story.append(make_title_banner())
    story.append(Spacer(1, 2*mm))

    # ── Row 1: Flowchart | Phases | Neurotransmitters ─────────────────────────
    # Section headers
    fc_hdr   = hdr("PATHOPHYSIOLOGY PATHWAY", C_HEADER)
    ph_hdr   = hdr("4 PHASES OF MIGRAINE ATTACK", C_ACCENT2)
    nt_hdr   = hdr("KEY MEDIATORS & NEUROTRANSMITTERS", C_ACCENT2)

    fc_content = make_flowchart()
    ph_content = make_phases()
    nt_content = make_neurotransmitters()

    # Phase + NT stacked in right portion
    right_block = Table([
        [ph_hdr],
        [ph_content],
        [Spacer(1, 1.5*mm)],
        [nt_hdr],
        [nt_content],
    ], colWidths=[250*mm],
       style=TableStyle([
           ("TOPPADDING",    (0,0), (-1,-1), 0),
           ("BOTTOMPADDING", (0,0), (-1,-1), 0),
           ("LEFTPADDING",   (0,0), (-1,-1), 0),
           ("RIGHTPADDING",  (0,0), (-1,-1), 0),
       ]))

    row1 = Table([
        [
            Table([[fc_hdr],[fc_content]], colWidths=[54*mm],
                  style=TableStyle([("TOPPADDING",(0,0),(-1,-1),0),("BOTTOMPADDING",(0,0),(-1,-1),0),
                                    ("LEFTPADDING",(0,0),(-1,-1),0),("RIGHTPADDING",(0,0),(-1,-1),0)])),
            right_block,
        ]
    ], colWidths=[55*mm, 251*mm],
       style=TableStyle([
           ("VALIGN",        (0,0), (-1,-1), "TOP"),
           ("TOPPADDING",    (0,0), (-1,-1), 0),
           ("BOTTOMPADDING", (0,0), (-1,-1), 0),
           ("LEFTPADDING",   (0,0), (-1,-1), 0),
           ("RIGHTPADDING",  (0,0), (-1,-1), 1.5*mm),
           ("LINEAFTER",     (0,0), (0,-1), 0.5, HexColor("#BDC3C7")),
       ]))

    story.append(row1)
    story.append(Spacer(1, 1.5*mm))

    # ── Row 2: CSD box | Sensitization box | Triptans box | High-Yield Facts ─
    csd_block = Table([
        [make_csd_box()],
    ], colWidths=[57*mm],
       style=TableStyle([("TOPPADDING",(0,0),(-1,-1),0),("BOTTOMPADDING",(0,0),(-1,-1),0),
                         ("LEFTPADDING",(0,0),(-1,-1),0),("RIGHTPADDING",(0,0),(-1,-1),0)]))

    sens_block = Table([
        [make_sensitization_box()],
    ], colWidths=[57*mm],
       style=TableStyle([("TOPPADDING",(0,0),(-1,-1),0),("BOTTOMPADDING",(0,0),(-1,-1),0),
                         ("LEFTPADDING",(0,0),(-1,-1),0),("RIGHTPADDING",(0,0),(-1,-1),0)]))

    trip_block = Table([
        [make_triptans()],
    ], colWidths=[57*mm],
       style=TableStyle([("TOPPADDING",(0,0),(-1,-1),0),("BOTTOMPADDING",(0,0),(-1,-1),0),
                         ("LEFTPADDING",(0,0),(-1,-1),0),("RIGHTPADDING",(0,0),(-1,-1),0)]))

    facts_block = make_key_facts()

    row2 = Table([
        [csd_block, sens_block, trip_block, facts_block]
    ], colWidths=[58*mm, 58*mm, 58*mm, 147*mm],
       style=TableStyle([
           ("VALIGN",        (0,0), (-1,-1), "TOP"),
           ("TOPPADDING",    (0,0), (-1,-1), 0),
           ("BOTTOMPADDING", (0,0), (-1,-1), 0),
           ("LEFTPADDING",   (0,0), (-1,-1), 0),
           ("RIGHTPADDING",  (0,0), (-1,-1), 1.5*mm),
       ]))

    story.append(row2)
    story.append(Spacer(1, 1.5*mm))

    # ── Footer ────────────────────────────────────────────────────────────────
    story.append(HRFlowable(width="100%", thickness=0.5, color=HexColor("#BDC3C7")))
    story.append(Spacer(1, 0.8*mm))
    story.append(make_footer())

    doc.build(story)
    print(f"PDF written: {OUT}")

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

cd /home/daytona/workspace/migraine-ref-card && python3 generate_card.py 2>&1

Running Command

ls -lh /home/daytona/workspace/migraine-ref-card/

Your PDF quick-reference card is ready:

Migraine Pathophysiology QuickRef

PDF Document · PDF


Here is what is included on the single A4 landscape page:
1. Pathophysiology Pathway (flowchart column)
  • Color-coded cascade: Trigger → Brain Hyperexcitability → CSD → Trigeminovascular Activation → Central Sensitization → Migraine Headache
  • Each step has its own color and key bullet points
2. 4 Phases of Migraine Attack
  • Prodrome, Aura, Headache, Postdrome - each with clinical details
3. Key Mediators & Neurotransmitters table
  • 8 mediators including CGRP, Serotonin, NO, Dopamine, Glutamate, SP, NKA, and PACAP - with roles and clinical notes (gepants, anti-CGRP mAbs, etc.)
4. CSD box (orange) - mechanism, speed (2-4 mm/min corrected), debate about its role in triggering headache
5. Central Sensitization box (purple) - 3-tier sensitization model, 75% allodynia stat, early triptan rule
6. Triptans box (green) - dual mechanism (5-HT1B vasoconstriction + 5-HT1D presynaptic inhibition), contraindications
7. High-Yield Facts panel - genetics, epidemiology, PAG role, NO triggers, osmophobia, CGRP therapies
Footer - full source citations and abbreviations key

Make it in simplified way for me to understand as I am UG student

Writing File

~/migraine-ref-card/generate_simple_card.py

#!/usr/bin/env python3
"""
Migraine Pathophysiology - Simple UG Student Quick-Reference Card
A4 landscape, plain language, big fonts, friendly colors
"""

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

OUT = "/home/daytona/workspace/migraine-ref-card/Migraine_SimpleGuide_UG.pdf"

PAGE = landscape(A4)
W, H = PAGE

# ── Friendly palette ──────────────────────────────────────────────────────────
NAVY    = HexColor("#1A3A5C")
RED     = HexColor("#E74C3C")
BLUE    = HexColor("#2980B9")
GREEN   = HexColor("#27AE60")
PURPLE  = HexColor("#8E44AD")
ORANGE  = HexColor("#E67E22")
TEAL    = HexColor("#16A085")
YELLOW  = HexColor("#F39C12")
LGRAY   = HexColor("#F4F6F7")
ALTROW  = HexColor("#EAF4FB")
LGREEN  = HexColor("#EAFAF1")
LORANGE = HexColor("#FEF9E7")
LPURPLE = HexColor("#F5EEF8")
LRED    = HexColor("#FDEDEC")
LBLUE   = HexColor("#EBF5FB")

doc = SimpleDocTemplate(
    OUT, pagesize=PAGE,
    leftMargin=9*mm, rightMargin=9*mm,
    topMargin=7*mm, bottomMargin=6*mm,
    title="Migraine Pathophysiology – UG Student Guide",
)

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

def p(text, style):
    return Paragraph(text, style)

TITLE   = S("T",  fontName="Helvetica-Bold",    fontSize=16, leading=20, textColor=white,               alignment=TA_CENTER)
SUBT    = S("ST", fontName="Helvetica",          fontSize=8,  leading=10, textColor=HexColor("#AED6F1"), alignment=TA_CENTER)
SHEAD   = S("SH", fontName="Helvetica-Bold",     fontSize=8.5,leading=11, textColor=white,               alignment=TA_CENTER)
SHEAD_L = S("SHL",fontName="Helvetica-Bold",     fontSize=8.5,leading=11, textColor=white,               alignment=TA_LEFT)
BODY    = S("B",  fontName="Helvetica",          fontSize=7.5,leading=10, textColor=HexColor("#1B2631"))
BODYB   = S("BB", fontName="Helvetica-Bold",     fontSize=7.5,leading=10, textColor=HexColor("#1B2631"))
BIG     = S("BG", fontName="Helvetica-Bold",     fontSize=9,  leading=12, textColor=HexColor("#1B2631"), alignment=TA_CENTER)
NOTE    = S("N",  fontName="Helvetica-Oblique",  fontSize=6.5,leading=8.5,textColor=HexColor("#7F8C8D"))
FOOT    = S("F",  fontName="Helvetica",          fontSize=5.8,leading=7.5,textColor=HexColor("#95A5A6"), alignment=TA_CENTER)
EMOJI_S = S("ES", fontName="Helvetica-Bold",     fontSize=8,  leading=10, textColor=HexColor("#1B2631"), alignment=TA_CENTER)

def cell_block(title, title_bg, body_text, body_bg, width):
    """A box with a colored header and light body."""
    return Table([
        [p(title, SHEAD)],
        [p(body_text, BODY)],
    ], colWidths=[width],
       style=TableStyle([
           ("BACKGROUND",    (0,0),(0,0), title_bg),
           ("BACKGROUND",    (0,1),(0,1), body_bg),
           ("BOX",           (0,0),(-1,-1), 0.8, title_bg),
           ("TOPPADDING",    (0,0),(-1,-1), 3),
           ("BOTTOMPADDING", (0,0),(-1,-1), 3),
           ("LEFTPADDING",   (0,0),(-1,-1), 4),
           ("RIGHTPADDING",  (0,0),(-1,-1), 4),
           ("VALIGN",        (0,0),(-1,-1), "TOP"),
       ]))

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

# ── TITLE BAR ─────────────────────────────────────────────────────────────────
title_bar = Table([[
    p("MIGRAINE — HOW IT HAPPENS", TITLE),
    p("A Plain-Language Guide for Undergraduate Medical Students\n"
      "Based on: Bradley & Daroff • Adams & Victor • Goodman & Gilman • Guyton & Hall", SUBT),
]], colWidths=[105*mm, 172*mm],
   style=TableStyle([
       ("BACKGROUND", (0,0),(-1,-1), NAVY),
       ("VALIGN",     (0,0),(-1,-1), "MIDDLE"),
       ("TOPPADDING",    (0,0),(-1,-1), 5),
       ("BOTTOMPADDING", (0,0),(-1,-1), 5),
       ("LEFTPADDING",   (0,0),(-1,-1), 8),
       ("RIGHTPADDING",  (0,0),(-1,-1), 8),
   ]))
story.append(title_bar)
story.append(Spacer(1, 2.5*mm))

# ══════════════════════════════════════════════════════════════════════════════
# ROW 1  —  Step-by-step story  (left)  +  4 Phases  (right)
# ══════════════════════════════════════════════════════════════════════════════

# ── STEP-BY-STEP STORY ──────────────────────────────────────────────────────
steps = [
    (NAVY,   "STEP 1 — WHAT IS MIGRAINE?",
     "Migraine is a <b>brain disease</b>, not just a headache.\n"
     "The brain is over-sensitive (hyperexcitable).\n"
     "Blood vessel changes are <b>secondary</b> — the brain fires first."),

    (BLUE,   "STEP 2 — THE TRIGGER",
     "Stress, bad sleep, skipping meals, bright lights,\n"
     "hormonal changes or certain foods → brain gets\n"
     "overloaded → attack begins in the <b>hypothalamus\n"
     "& brainstem</b> (hours before headache!)"),

    (ORANGE, "STEP 3 — AURA (in ~30% of people)",
     "A wave of electricity called <b>Cortical Spreading\n"
     "Depression (CSD)</b> crawls across the back of the brain\n"
     "at ~3 mm/min. This causes:\n"
     "  ★ Zig-zag flashing lines in vision\n"
     "  ★ Numbness on one side\n"
     "  ★ Difficulty speaking"),

    (RED,    "STEP 4 — PAIN STARTS",
     "CSD irritates the <b>trigeminal nerve</b> (the pain nerve\n"
     "of the face & head). It releases chemicals:\n"
     "  → CGRP  → Substance P  → Nitric Oxide\n"
     "These cause: blood vessel swelling + inflammation\n"
     "around the brain = <b>THROBBING HEADACHE</b>"),

    (PURPLE, "STEP 5 — BRAIN GETS SUPER-SENSITIVE",
     "Repeated pain signals make brain cells overly\n"
     "reactive (<b>central sensitization</b>).\n"
     "Now even a gentle touch hurts (allodynia).\n"
     "Bright light, sound, smells all become unbearable.\n"
     "This is why you hide in a dark, quiet room."),

    (GREEN,  "STEP 6 — ATTACK ENDS / RECOVERY",
     "Pain fades. But a <b>postdrome (hangover) phase</b>\n"
     "follows: fatigue, brain fog, neck stiffness.\n"
     "Can last hours to a day.\n"
     "The brain slowly resets until the next trigger."),
]

step_rows = []
for i, (bg, title, body) in enumerate(steps):
    lbg = [LBLUE, LORANGE, LORANGE, LRED, LPURPLE, LGREEN][i]
    block = Table([
        [p(title, SHEAD)],
        [p(body,  BODY)],
    ], colWidths=[55*mm],
       style=TableStyle([
           ("BACKGROUND",    (0,0),(0,0), bg),
           ("BACKGROUND",    (0,1),(0,1), lbg),
           ("BOX",           (0,0),(-1,-1), 0.8, bg),
           ("TOPPADDING",    (0,0),(-1,-1), 2),
           ("BOTTOMPADDING", (0,0),(-1,-1), 2),
           ("LEFTPADDING",   (0,0),(-1,-1), 4),
           ("RIGHTPADDING",  (0,0),(-1,-1), 4),
       ]))
    step_rows.append([block])
    if i < len(steps)-1:
        step_rows.append([p("     ▼", S("aw", fontName="Helvetica-Bold", fontSize=10, leading=11, textColor=RED))])

steps_col = Table(step_rows, colWidths=[56*mm],
                  style=TableStyle([
                      ("TOPPADDING",    (0,0),(-1,-1), 0),
                      ("BOTTOMPADDING", (0,0),(-1,-1), 0),
                      ("LEFTPADDING",   (0,0),(-1,-1), 0),
                      ("RIGHTPADDING",  (0,0),(-1,-1), 0),
                  ]))

# ── 4 PHASES ─────────────────────────────────────────────────────────────────
phases_hdr = Table([[p("THE 4 PHASES OF A MIGRAINE ATTACK", SHEAD)]],
                   colWidths=[100*mm],
                   style=TableStyle([
                       ("BACKGROUND",(0,0),(-1,-1), BLUE),
                       ("TOPPADDING",(0,0),(-1,-1), 3),
                       ("BOTTOMPADDING",(0,0),(-1,-1), 3),
                       ("LEFTPADDING",(0,0),(-1,-1), 4),
                   ]))

phase_data = [
    (BLUE,   "1️⃣  PRODROME\n(hours–days BEFORE headache)",
     "What happens: Hypothalamus wakes up early.\n"
     "What you feel: Yawning a lot, craving sweet food,\n"
     "  mood swings, tiredness, needing to pee more.\n"
     "<b>Think of it as:</b> The body's early warning system."),
    (ORANGE, "2️⃣  AURA\n(20–60 min BEFORE headache; ~30% of people)",
     "What happens: CSD wave crosses the brain.\n"
     "What you see/feel: Flashing zig-zag lights,\n"
     "  blind spot, tingling arm, trouble finding words.\n"
     "<b>Think of it as:</b> An electrical storm in the brain."),
    (RED,    "3️⃣  HEADACHE\n(4–72 hours)",
     "What happens: Trigeminal nerve fires; CGRP released.\n"
     "What you feel: Throbbing pain (usually one side),\n"
     "  nausea, vomiting, hate light & sound & smell.\n"
     "<b>Think of it as:</b> The alarm bells are ringing loudly."),
    (PURPLE, "4️⃣  POSTDROME\n(hours–1 day AFTER headache)",
     "What happens: Brain slowly calms down.\n"
     "What you feel: Exhausted, foggy, neck stiff,\n"
     "  hard to concentrate — like a hangover.\n"
     "<b>Think of it as:</b> The brain recovering from the storm."),
]

ph_rows = []
for bg, title, body in phase_data:
    lbg_map = {BLUE: LBLUE, ORANGE: LORANGE, RED: LRED, PURPLE: LPURPLE}
    lbg = lbg_map.get(bg, LGRAY)
    block = Table([
        [p(title, SHEAD)],
        [p(body, BODY)],
    ], colWidths=[97*mm],
       style=TableStyle([
           ("BACKGROUND",(0,0),(0,0), bg),
           ("BACKGROUND",(0,1),(0,1), lbg),
           ("BOX",(0,0),(-1,-1), 0.8, bg),
           ("TOPPADDING",(0,0),(-1,-1), 2),
           ("BOTTOMPADDING",(0,0),(-1,-1), 2),
           ("LEFTPADDING",(0,0),(-1,-1), 4),
           ("RIGHTPADDING",(0,0),(-1,-1), 4),
       ]))
    ph_rows.append([block])
    if (bg, title, body) != phase_data[-1]:
        ph_rows.append([Spacer(1, 1*mm)])

phases_col = Table([[phases_hdr]] + ph_rows, colWidths=[100*mm],
                   style=TableStyle([
                       ("TOPPADDING",(0,0),(-1,-1), 0),
                       ("BOTTOMPADDING",(0,0),(-1,-1), 0),
                       ("LEFTPADDING",(0,0),(-1,-1), 0),
                       ("RIGHTPADDING",(0,0),(-1,-1), 0),
                   ]))

# ── CHEMICALS & TRIPTANS side-by-side ────────────────────────────────────────
chem_hdr = Table([[p("KEY CHEMICALS (MEDIATORS)", SHEAD)]],
                 colWidths=[115*mm],
                 style=TableStyle([
                     ("BACKGROUND",(0,0),(-1,-1), TEAL),
                     ("TOPPADDING",(0,0),(-1,-1), 3),
                     ("BOTTOMPADDING",(0,0),(-1,-1), 3),
                     ("LEFTPADDING",(0,0),(-1,-1), 4),
                 ]))

chem_rows = [
    [p("<b>Chemical</b>", BODYB), p("<b>What it does (simple!)</b>", BODYB), p("<b>Why it matters</b>", BODYB)],
    [p("CGRP", BODYB),
     p("Makes blood vessels swell + sends pain signals", BODY),
     p("MAIN target of new drugs (gepants, erenumab)", BODY)],
    [p("Serotonin\n(5-HT)", BODYB),
     p("Controls pain pathways — levels change\nduring the attack", BODY),
     p("Triptans work ON this chemical", BODY)],
    [p("Substance P", BODYB),
     p("Causes inflammation & vessel leakage\naround the brain", BODY),
     p("Released alongside CGRP", BODY)],
    [p("Nitric Oxide\n(NO)", BODYB),
     p("Dilates blood vessels;\nnitroglycerin (a NO donor) triggers migraine", BODY),
     p("Important trigger in research studies", BODY)],
    [p("Dopamine", BODYB),
     p("Causes yawning, nausea in the prodrome", BODY),
     p("Anti-nausea drugs block dopamine", BODY)],
    [p("Glutamate", BODYB),
     p("Drives the brain's over-excitement\n& helps CSD spread", BODY),
     p("Involved in central sensitization", BODY)],
]
chem_table = Table(chem_rows, colWidths=[22*mm, 53*mm, 38*mm],
                   style=TableStyle([
                       ("BACKGROUND",    (0,0),(-1,0), TEAL),
                       ("TEXTCOLOR",     (0,0),(-1,0), white),
                       ("ROWBACKGROUNDS",(0,1),(-1,-1), [HexColor("#EAFAF1"), HexColor("#F0F3F4")]),
                       ("GRID",          (0,0),(-1,-1), 0.3, HexColor("#BDC3C7")),
                       ("TOPPADDING",    (0,0),(-1,-1), 2),
                       ("BOTTOMPADDING", (0,0),(-1,-1), 2),
                       ("LEFTPADDING",   (0,0),(-1,-1), 3),
                       ("RIGHTPADDING",  (0,0),(-1,-1), 3),
                       ("VALIGN",        (0,0),(-1,-1), "TOP"),
                   ]))

chem_col = Table([[chem_hdr],[chem_table]], colWidths=[115*mm],
                 style=TableStyle([("TOPPADDING",(0,0),(-1,-1),0),("BOTTOMPADDING",(0,0),(-1,-1),0),
                                   ("LEFTPADDING",(0,0),(-1,-1),0),("RIGHTPADDING",(0,0),(-1,-1),0)]))

# ── TRIPTANS SIMPLE BOX ───────────────────────────────────────────────────────
trip_col = Table([
    [p("💊  WHY DO TRIPTANS WORK?", SHEAD)],
    [p(
        "Triptans (e.g. sumatriptan) are <b>5-HT1B/1D agonists</b>.\n\n"
        "<b>Two ways they stop the attack:</b>\n\n"
        "1️⃣  They <b>narrow</b> the swollen blood vessels\n"
        "     around the brain (5-HT<b>1B</b> receptor)\n\n"
        "2️⃣  They <b>stop the trigeminal nerve</b> from\n"
        "     releasing CGRP and Substance P\n"
        "     (5-HT<b>1D</b> receptor — presynaptic)\n\n"
        "<b>Best taken EARLY</b> — before the brain becomes\n"
        "super-sensitive (allodynia sets in)\n\n"
        "<b>⚠ NOT safe in:</b> heart disease, stroke history,\n"
        "uncontrolled high blood pressure\n"
        "(because of the blood vessel narrowing effect)",
        BODY
    )],
], colWidths=[56*mm],
   style=TableStyle([
       ("BACKGROUND", (0,0),(0,0), GREEN),
       ("BACKGROUND", (0,1),(0,1), LGREEN),
       ("BOX",        (0,0),(-1,-1), 0.8, GREEN),
       ("TOPPADDING",    (0,0),(-1,-1), 3),
       ("BOTTOMPADDING", (0,0),(-1,-1), 3),
       ("LEFTPADDING",   (0,0),(-1,-1), 4),
       ("RIGHTPADDING",  (0,0),(-1,-1), 4),
   ]))

right_col = Table([
    [chem_col, Spacer(2*mm,1), trip_col]
], colWidths=[116*mm, 2*mm, 57*mm],
   style=TableStyle([
       ("VALIGN",        (0,0),(-1,-1), "TOP"),
       ("TOPPADDING",    (0,0),(-1,-1), 0),
       ("BOTTOMPADDING", (0,0),(-1,-1), 0),
       ("LEFTPADDING",   (0,0),(-1,-1), 0),
       ("RIGHTPADDING",  (0,0),(-1,-1), 0),
   ]))

mid_col = Table([
    [phases_col],
    [Spacer(1,1.5*mm)],
    [right_col],
], colWidths=[177*mm],
   style=TableStyle([
       ("TOPPADDING",    (0,0),(-1,-1), 0),
       ("BOTTOMPADDING", (0,0),(-1,-1), 0),
       ("LEFTPADDING",   (0,0),(-1,-1), 0),
       ("RIGHTPADDING",  (0,0),(-1,-1), 0),
   ]))

# ── REMEMBER BOX (right strip) ───────────────────────────────────────────────
remember = [
    ("🧠", "NEURONAL first,\nvascular second"),
    ("⚡", "CSD = basis\nof AURA"),
    ("🔴", "CGRP = main\npain chemical"),
    ("🤚", "Allodynia = sign\nof sensitization"),
    ("⏱", "Triptans work\nbest taken EARLY"),
    ("👩", "3× more common\nin women"),
    ("🧬", "Genetic — runs\nin families"),
    ("😫", "WHO: one of most\ndisabling diseases"),
]

rem_rows = []
for icon, text in remember:
    rem_rows.append([
        Table([[
            p(icon, S("ic", fontName="Helvetica", fontSize=14, leading=16, alignment=TA_CENTER)),
            p(text, S("rt", fontName="Helvetica-Bold", fontSize=6.5, leading=8.5, textColor=NAVY)),
        ]], colWidths=[9*mm, 44*mm],
              style=TableStyle([
                  ("BACKGROUND",(0,0),(-1,-1), ALTROW),
                  ("BOX",(0,0),(-1,-1), 0.4, HexColor("#AED6F1")),
                  ("VALIGN",(0,0),(-1,-1),"MIDDLE"),
                  ("TOPPADDING",(0,0),(-1,-1), 2),
                  ("BOTTOMPADDING",(0,0),(-1,-1), 2),
                  ("LEFTPADDING",(0,0),(-1,-1), 2),
                  ("RIGHTPADDING",(0,0),(-1,-1), 2),
              ]))
    ])
    rem_rows.append([Spacer(1, 1*mm)])

rem_hdr = Table([[p("REMEMBER!", SHEAD)]],
                colWidths=[55*mm],
                style=TableStyle([
                    ("BACKGROUND",(0,0),(-1,-1), RED),
                    ("TOPPADDING",(0,0),(-1,-1), 3),
                    ("BOTTOMPADDING",(0,0),(-1,-1), 3),
                    ("LEFTPADDING",(0,0),(-1,-1), 4),
                ]))

rem_col = Table([[rem_hdr]] + rem_rows, colWidths=[55*mm],
                style=TableStyle([
                    ("TOPPADDING",(0,0),(-1,-1), 0),
                    ("BOTTOMPADDING",(0,0),(-1,-1), 0),
                    ("LEFTPADDING",(0,0),(-1,-1), 0),
                    ("RIGHTPADDING",(0,0),(-1,-1), 0),
                ]))

# ── ASSEMBLE 3-COLUMN MAIN ROW ───────────────────────────────────────────────
main_row = Table([[
    steps_col,
    mid_col,
    rem_col,
]], colWidths=[57*mm, 178*mm, 56*mm],
   style=TableStyle([
       ("VALIGN",        (0,0),(-1,-1), "TOP"),
       ("TOPPADDING",    (0,0),(-1,-1), 0),
       ("BOTTOMPADDING", (0,0),(-1,-1), 0),
       ("LEFTPADDING",   (0,0),(-1,-1), 0),
       ("RIGHTPADDING",  (0,0),(-1,-1), 1.5*mm),
       ("LINEAFTER",     (0,0),(0,-1), 0.5, HexColor("#BDC3C7")),
       ("LINEAFTER",     (1,0),(1,-1), 0.5, HexColor("#BDC3C7")),
   ]))

story.append(main_row)
story.append(Spacer(1, 1.5*mm))

# ── FOOTER ────────────────────────────────────────────────────────────────────
story.append(HRFlowable(width="100%", thickness=0.4, color=HexColor("#BDC3C7")))
story.append(Spacer(1, 0.8*mm))
story.append(p(
    "Sources: Bradley & Daroff's Neurology in Clinical Practice  •  Adams & Victor's Principles of Neurology 12e  •  "
    "Goodman & Gilman's The Pharmacological Basis of Therapeutics  •  Guyton & Hall Textbook of Medical Physiology  •  ICHD-3  |  "
    "CGRP = Calcitonin Gene-Related Peptide  •  CSD = Cortical Spreading Depression  •  5-HT = Serotonin  •  PAG = Periaqueductal Gray  •  NO = Nitric Oxide",
    FOOT
))

doc.build(story)
print(f"PDF written: {OUT}")
Running Command

cd /home/daytona/workspace/migraine-ref-card && python3 generate_simple_card.py 2>&1

Running Command

ls -lh /home/daytona/workspace/migraine-ref-card/

Here you go! Your student-friendly version is ready:

Migraine SimpleGuide UG

PDF Document · PDF


Here is what makes this one different from the previous version:
Left column - 6 Steps as a story
  • Written in plain language ("The brain fires first, not the blood vessels")
  • Each step has a "Think of it as..." analogy (e.g., Aura = "an electrical storm in the brain")
  • Color-coded numbered steps with arrows
Middle column - 4 Phases + Chemicals
  • Each phase explained in simple what happens / what you feel format
  • Chemicals table uses everyday language ("Makes blood vessels swell + sends pain signals")
  • Triptans box explains the two mechanisms simply with numbered points
Right column - "REMEMBER!" strip
  • 8 key exam facts in icon + short phrase format - perfect for last-minute revision
  • e.g. "CSD = basis of AURA", "Triptans work best taken EARLY", "3x more common in women"
What was removed/simplified
  • No dense jargon (no "oligemia", "perisynaptic", etc.)
  • No complex debate text
  • Plain analogies used throughout

Explain the pathophysiology of migraine in a simplified way with reference of standard textbooks like harrison

Reading File
Finding Sources
Finding Sources
Finding Sources
Finding Sources
Finding Sources
Reading File
Reading File
Reading File
Reading File
I now have rich, first-hand content from Harrison's 22e, Bradley & Daroff, and Adams & Victor. Here is the full simplified explanation:

Pathophysiology of Migraine — Simplified for UG Students

Based on: Harrison's Principles of Internal Medicine 22e (2025), Bradley & Daroff's Neurology in Clinical Practice, Adams & Victor's Principles of Neurology 12e, Guyton & Hall Medical Physiology

First, the Big Picture

"Migraine is primarily a disorder of the nervous system — the brain dysfunction comes first. Blood vessel changes are secondary, not the cause." — Harrison's Principles of Internal Medicine 22e
The old idea (proposed by Wolff, 1950s) was that migraine was caused by blood vessels expanding and pressing on nerves. That theory is now outdated. Modern textbooks agree: migraine is a brain disease where the nervous system is abnormally sensitive.

Step 1 — Why Some People Get Migraine: The Hyperexcitable Brain

Think of the normal brain as having a "dimmer switch" that controls how much stimulation it lets in. In migraine patients, this dimmer switch is stuck too high — the brain is hyperexcitable and does not habituate (get used to) sensory input the way a normal brain does.
Harrison's states:
"Migraineurs are particularly sensitive to environmental and sensory stimuli; migraine-prone patients do not habituate easily to sensory stimuli."
Why does this happen? Genetics plays a major role:
  • First-degree relatives of a migraineur have 2-4x higher risk of also getting migraines
  • In a specific type called Familial Hemiplegic Migraine (FHM), mutations are found in ion channel genes (CACNA1A, ATP1A2, SCN1A) — these genes control how excitable brain cells are
  • In most common migraine, the genetics are more complex but the principle is the same: a lower threshold for brain activation

Step 2 — The Trigger Fires the Starting Gun

A trigger alone does not cause migraine — it just pushes an already-sensitive brain over the edge. Common triggers include:
TriggerSimple Explanation
Stress (or stress let-down)Brain suddenly relaxes after being tense
Sleep changesDisrupts brainstem control of pain pathways
Skipping meals / fastingLow glucose affects brain metabolism
Hormonal changesEstrogen drop before menstruation is a major trigger
Bright lights / loud soundsBrain is already too sensitive
Certain foods / alcoholChemical stimulation (especially nitrates in wine)
Barometric pressure changesSensory overload in a sensitive brain
Harrison's specifically notes that some apparent "triggers" like light sensitivity may actually be part of the premonitory phase itself — meaning the attack has already quietly begun.

Step 3 — The Prodrome ("Warning Phase") — Hours Before the Headache

Long before the headache starts, the hypothalamus and brainstem become abnormally active. This is why patients feel strange hours (or even a day) before the pain:
  • Yawning excessively
  • Craving sweet food
  • Mood swings (irritable or euphoric)
  • Fatigue, drowsiness
  • Needing to urinate more
Why the hypothalamus? Harrison's explains:
"The sensory sensitivity that is characteristic of migraine is probably due to dysfunction of monoaminergic and other sensory control systems located in the brainstem and hypothalamus."
Brain imaging (PET scans) has shown the hypothalamus becoming active 24 hours before the headache starts. The brainstem - particularly the periaqueductal gray (PAG), dorsal pons, and midbrain - also activates early. The PAG is a key pain-control centre; when it malfunctions, pain pathways are no longer properly suppressed.

Step 4 — Cortical Spreading Depression: The Electrical Storm (Causes the Aura)

In about 25-30% of migraineurs, a dramatic electrical event occurs in the brain before the headache. This is called Cortical Spreading Depression (CSD).
Simple analogy: Imagine a wave of electricity that sweeps across your brain like a slow tidal wave, then leaves silence (suppression) behind it.
Here is what actually happens:
  1. A sudden intense burst of neuronal firing starts in the occipital cortex (back of the brain - the visual area)
  2. This wave of depolarization spreads forward across the cortex at a rate of 2-4 mm per minute (very slow compared to normal nerve signals)
  3. Behind the wave, neurons go quiet (depression/suppression)
  4. Blood flow initially increases briefly, then decreases (oligemia)
  5. The whole wave does not follow blood vessel boundaries - ruling out simple vasospasm as the cause
What does the patient feel during CSD? Since CSD starts in the occipital lobe (vision area) and spreads forward:
  • Positive symptoms first (brain firing): Flashing lights, zig-zag lines, sparkles - called a "scintillating scotoma"
  • Negative symptoms follow (brain suppression): Blind spots, numbness, difficulty speaking
  • Symptoms march across the visual field slowly over ~20-30 minutes (mirroring the 2-4 mm/min spread rate)
Adams & Victor notes: Lashley plotted his own visual aura and calculated the cortical impairment progressed at 2-3 mm/min - matching the CSD wave exactly.
Important: CSD clearly explains the AURA. Whether CSD directly triggers the headache phase is still debated in the literature (Bradley & Daroff, 2023).

Step 5 — Trigeminovascular Activation: Where the Pain Comes From

This is the most important step for understanding migraine pain. Harrison's describes the key structures:
"The innervation of the large intracranial vessels and dura mater by the trigeminal nerve is known as the trigeminovascular system."
Here is the sequence in simple terms:

The Trigeminal Nerve is the Pain Nerve of the Head

The trigeminal nerve (Cranial Nerve V) sends tiny nerve fibres to wrap around:
  • The meninges (coverings of the brain)
  • Large cerebral blood vessels
  • The dura mater
Normally these fibres are quiet. But when migraine begins - either triggered by CSD or directly by brainstem dysfunction - these fibres get activated.

What Happens When They Fire?

The activated trigeminal nerve endings release a cocktail of chemicals called neuropeptides:
ChemicalWhat it does
CGRP (Calcitonin Gene-Related Peptide)Dilates blood vessels; major pain signaller - the MOST important
PACAP (Pituitary Adenylate Cyclase-Activating Polypeptide)Similar to CGRP; newer target of therapy (Harrison's 22e)
Substance PCauses plasma protein leakage from vessels
Nitric Oxide (NO)Vasodilator; nitroglycerin (a NO donor) reliably triggers migraine
These chemicals cause what is called sterile neurogenic inflammation around the blood vessels of the brain:
  • Blood vessels swell and dilate
  • Plasma proteins leak out of vessels into surrounding tissue
  • Inflammatory soup forms around the meninges
  • The meninges become swollen and sensitive
Result: Pain signals are sent from the meninges through the trigeminal nerve to the trigeminal nucleus caudalis in the brainstem, then up to the thalamus, then to the cortex - where it is perceived as throbbing, pulsating headache. The throbbing quality occurs because the already-sensitised pain fibres detect every normal heartbeat pulsation of the blood vessels.
Harrison's confirms CGRP's central role:
"CGRP receptor antagonists, gepants, have now been shown to be effective in the acute and preventive treatment of migraine, and four monoclonal antibodies to CGRP, or its receptor, have been shown to be effective in migraine prevention."

Step 6 — Central Sensitization: Why Everything Becomes Painful

As the trigeminal system keeps firing pain signals, something changes in the brain's pain-processing centres. The neurons become sensitized - they lower their threshold and start firing more easily. This is called central sensitization.
Bradley & Daroff explains:
"Recurrent and/or prolonged activation of the trigeminocervical system can lead to peripheral and central sensitization. Sensitized neurons have lower thresholds for activation, increased spontaneous activity, and receptive field expansion."
Think of it this way: normally, a gentle touch on the scalp feels fine. But during migraine with central sensitization, the same gentle touch is registered as pain. This is called allodynia (pain from a normally non-painful stimulus).
The three levels of sensitization:
1st order neuron sensitized → trigeminal nerve endings
        ↓
2nd order neuron sensitized → trigeminal nucleus caudalis
        ↓  (allodynia begins here - scalp tenderness)
3rd order neuron sensitized → thalamus + cortex
        ↓  (whole-body allodynia, photophobia, phonophobia)
~75% of migraineurs develop cutaneous allodynia during an attack (Bradley & Daroff). This is why:
  • Combing hair or wearing glasses hurts during an attack
  • Bright light becomes unbearable (photophobia)
  • Normal sounds are painful (phonophobia)
  • Smells become overwhelming (osmophobia)
Clinical importance: Once allodynia (central sensitization) is established, triptans become LESS effective. This is why early treatment is emphasised.

Step 7 — Brainstem Neurotransmitter Changes

The brainstem is not just a passive relay - it actively modulates pain. Several key neurotransmitter systems go wrong in migraine:
SystemNormal roleIn Migraine
Serotonin (5-HT) via Dorsal Raphe NucleusDescending pain suppressionFluctuates across attack phases; levels drop during acute attack
Noradrenaline via Locus CoeruleusArousal, attention, pain modulationDysregulated; contributes to sensory hypersensitivity
DopamineControls prodrome symptomsD2 receptor hypersensitivity; causes yawning, nausea
Harrison's highlights serotonin's importance historically:
"In the late 1950s, methysergide was suggested to antagonize certain peripheral actions of 5-HT and was introduced as a migraine preventive... The triptans were designed to stimulate selectively subpopulations of 5-HT receptors."

Why Do Triptans Work? (Pharmacology Simplified)

Triptans (e.g., sumatriptan, rizatriptan) are 5-HT1B/1D receptor agonists.
Harrison's 22e clarifies:
"Triptans arrest nerve signaling in the nociceptive pathways of the trigeminovascular system, at least in the trigeminal nucleus caudalis and trigeminal sensory thalamus, in addition to promoting cranial vasoconstriction."
Two mechanisms:
  1. 5-HT1B activation (on blood vessel smooth muscle) → cranial vasoconstriction → reduces the dilated, inflamed meningeal vessels
  2. 5-HT1D activation (on trigeminal nerve terminals - presynaptic) → blocks release of CGRP and Substance P → stops the neurogenic inflammation
Ditans (e.g., lasmiditan) act only at 5-HT1F receptors on neurons - no vasoconstriction - so they are safer in patients with cardiovascular disease.

The Complete Pathway: One Glance Summary

TRIGGERS (stress, sleep, hormones, food, light)
           ↓
HYPOTHALAMUS + BRAINSTEM over-activate
(prodrome: yawning, cravings, fatigue — hours before pain)
           ↓
CORTICAL SPREADING DEPRESSION  [in 25-30%]
(wave of depolarization, 2-4 mm/min, occipital → frontal)
           ↓  → AURA (zig-zag lights, numbness, dysphasia)
TRIGEMINOVASCULAR ACTIVATION
(trigeminal nerve fires → CGRP + Substance P + NO released)
           ↓
STERILE NEUROGENIC INFLAMMATION
(meningeal vessels dilate, plasma leaks, inflammation forms)
           ↓
PAIN SIGNALS → trigeminal nucleus caudalis → thalamus → cortex
= THROBBING HEADACHE (usually unilateral, 4-72 hours)
           ↓
CENTRAL SENSITIZATION
(allodynia, photophobia, phonophobia, osmophobia)
           ↓
POSTDROME (fatigue, brain fog, neck stiffness — the "hangover")

Summary Table — High-Yield for Exams

ConceptKey PointSource
Migraine is neuronal, NOT vascularBlood vessel changes are secondaryHarrison's 22e
Key structureTrigeminovascular systemHarrison's, Adams & Victor
Main pain chemicalCGRP (and PACAP)Harrison's 22e
Basis of auraCortical Spreading Depression (CSD)Bradley & Daroff
CSD rate2-4 mm/min (occipital to frontal)Bradley & Daroff
CSD and headache linkStill debatedBradley & Daroff
Allodynia prevalence~75% during attacksBradley & Daroff
Triptan mechanism5-HT1B (vasoconstriction) + 5-HT1D (blocks CGRP release)Harrison's 22e, Goodman & Gilman
Newer drugsGepants (CGRP antagonists), anti-CGRP mAbs, ditansHarrison's 22e
Migraine prevalence15% women, 6% men; most disabling neurological condition worldwideHarrison's 22e

References:
  • Harrison's Principles of Internal Medicine, 22nd Edition (2025, McGraw-Hill) — Chapter 441
  • Bradley and Daroff's Neurology in Clinical Practice — Chapter 102 (Pathophysiology section)
  • Adams and Victor's Principles of Neurology, 12th Edition — Pathogenesis of Migraine
  • Guyton and Hall Textbook of Medical Physiology — Chapter 49 (Headache)
  • Goodman & Gilman's The Pharmacological Basis of Therapeutics — Chapter 5 (Serotonin and triptans)

Make a visual flowchart poster showing the complete migraine pathway

Running Command

ls /home/daytona/workspace/migraine-ref-card/

Writing File

~/migraine-ref-card/generate_flowchart_poster.py

#!/usr/bin/env python3
"""
Migraine Complete Pathway — Visual Flowchart Poster
A3 portrait, rich colors, arrows, side branches, icons
"""

from reportlab.lib.pagesizes import A3
from reportlab.lib.units import mm, cm
from reportlab.lib.colors import HexColor, white, black
from reportlab.pdfgen.canvas import Canvas
from reportlab.platypus import Paragraph
from reportlab.lib.styles import ParagraphStyle
from reportlab.lib.enums import TA_CENTER, TA_LEFT
import math

OUT = "/home/daytona/workspace/migraine-ref-card/Migraine_Flowchart_Poster.pdf"

# A3 portrait
W_MM, H_MM = 297, 420
W = W_MM * mm
H = H_MM * mm

# ── Palette ───────────────────────────────────────────────────────────────────
NAVY    = HexColor("#0D2137")
DKBLUE  = HexColor("#1A3A5C")
BLUE    = HexColor("#2471A3")
LBLUE   = HexColor("#D6EAF8")
TEAL    = HexColor("#148F77")
LTEAL   = HexColor("#D1F2EB")
ORANGE  = HexColor("#D35400")
LORANGE = HexColor("#FDEBD0")
RED     = HexColor("#C0392B")
LRED    = HexColor("#FADBD8")
PURPLE  = HexColor("#7D3C98")
LPURPLE = HexColor("#F4ECF7")
GREEN   = HexColor("#1E8449")
LGREEN  = HexColor("#D5F5E3")
GOLD    = HexColor("#B7950B")
LGOLD   = HexColor("#FEF9E7")
GRAY    = HexColor("#566573")
LGRAY   = HexColor("#F2F3F4")
MGRAY   = HexColor("#D5D8DC")

c = Canvas(OUT, pagesize=(W, H))

# ── Drawing helpers ───────────────────────────────────────────────────────────

def rgba(color, alpha=1.0):
    return color

def draw_rounded_rect(canvas, x, y, w, h, r=4*mm, fill_color=white, stroke_color=DKBLUE, stroke_width=1.2):
    canvas.setFillColor(fill_color)
    canvas.setStrokeColor(stroke_color)
    canvas.setLineWidth(stroke_width)
    canvas.roundRect(x, y, w, h, r, stroke=1, fill=1)

def draw_rect(canvas, x, y, w, h, fill_color=white, stroke_color=DKBLUE, stroke_width=1.0):
    canvas.setFillColor(fill_color)
    canvas.setStrokeColor(stroke_color)
    canvas.setLineWidth(stroke_width)
    canvas.rect(x, y, w, h, stroke=1, fill=1)

def draw_arrow_down(canvas, x, top_y, bottom_y, color=DKBLUE, width=1.5):
    """Draw a vertical arrow pointing downward."""
    canvas.setStrokeColor(color)
    canvas.setFillColor(color)
    canvas.setLineWidth(width)
    # Line
    canvas.line(x, top_y, x, bottom_y + 4*mm)
    # Arrowhead
    aw = 3*mm
    canvas.beginPath()
    canvas.moveTo(x, bottom_y)
    canvas.lineTo(x - aw, bottom_y + 4*mm)
    canvas.lineTo(x + aw, bottom_y + 4*mm)
    canvas.closePath()
    canvas.drawPath(canvas._code and canvas._code or canvas, fill=1)  # fallback

def filled_arrow_down(canvas, cx, top_y, bottom_y, color=RED, w=2.5*mm):
    """Solid filled downward arrow."""
    canvas.setFillColor(color)
    canvas.setStrokeColor(color)
    canvas.setLineWidth(1.5)
    mid = (top_y + bottom_y) / 2
    # Shaft
    canvas.rect(cx - w*0.4, mid, w*0.8, top_y - mid, fill=1, stroke=0)
    # Head
    canvas.beginPath()
    canvas.moveTo(cx, bottom_y)
    canvas.lineTo(cx - w, mid + 1*mm)
    canvas.lineTo(cx + w, mid + 1*mm)
    canvas.closePath()
    canvas.setFillColor(color)
    canvas.drawPath(canvas._code and None or None)

def arrow_down(canvas, cx, y_top, y_bot, color=DKBLUE, lw=2):
    """Simple arrow down."""
    hw = 3.5*mm
    canvas.setStrokeColor(color)
    canvas.setFillColor(color)
    canvas.setLineWidth(lw)
    canvas.line(cx, y_top, cx, y_bot + hw)
    p = canvas.beginPath()
    p.moveTo(cx, y_bot)
    p.lineTo(cx - hw, y_bot + hw*1.2)
    p.lineTo(cx + hw, y_bot + hw*1.2)
    p.close()
    canvas.drawPath(p, fill=1, stroke=0)

def arrow_right(canvas, x_left, x_right, cy, color=DKBLUE, lw=1.5):
    hw = 2.5*mm
    canvas.setStrokeColor(color)
    canvas.setFillColor(color)
    canvas.setLineWidth(lw)
    canvas.line(x_left, cy, x_right - hw, cy)
    p = canvas.beginPath()
    p.moveTo(x_right, cy)
    p.lineTo(x_right - hw*1.2, cy + hw)
    p.lineTo(x_right - hw*1.2, cy - hw)
    p.close()
    canvas.drawPath(p, fill=1, stroke=0)

def arrow_left(canvas, x_left, x_right, cy, color=DKBLUE, lw=1.5):
    hw = 2.5*mm
    canvas.setStrokeColor(color)
    canvas.setFillColor(color)
    canvas.setLineWidth(lw)
    canvas.line(x_right, cy, x_left + hw, cy)
    p = canvas.beginPath()
    p.moveTo(x_left, cy)
    p.lineTo(x_left + hw*1.2, cy + hw)
    p.lineTo(x_left + hw*1.2, cy - hw)
    p.close()
    canvas.drawPath(p, fill=1, stroke=0)

def put_text(canvas, text, x, y, size=9, color=black, bold=False, align='center'):
    font = "Helvetica-Bold" if bold else "Helvetica"
    canvas.setFont(font, size)
    canvas.setFillColor(color)
    if align == 'center':
        canvas.drawCentredString(x, y, text)
    elif align == 'left':
        canvas.drawString(x, y, text)
    elif align == 'right':
        canvas.drawRightString(x, y, text)

def put_para(canvas, text, x, y, width, size=8, color=black, bold=False, leading=None, align=TA_CENTER):
    if leading is None:
        leading = size * 1.35
    font = "Helvetica-Bold" if bold else "Helvetica"
    style = ParagraphStyle("tmp", fontName=font, fontSize=size, leading=leading,
                            textColor=color, alignment=align)
    para = Paragraph(text, style)
    w, h = para.wrap(width, 999)
    para.drawOn(canvas, x - (width/2 if align == TA_CENTER else 0), y - h)
    return h

def main_box(canvas, cx, cy, bw, bh, title, subtitle, body_lines,
             hdr_color=DKBLUE, body_color=LGRAY, icon="", num=""):
    """Draw a main flowchart node box."""
    x = cx - bw/2
    y = cy - bh/2
    hdr_h = 11*mm

    # Shadow
    canvas.setFillColor(HexColor("#C0C0C0"))
    canvas.setStrokeColor(HexColor("#C0C0C0"))
    canvas.roundRect(x+1.5*mm, y-1.5*mm, bw, bh, 4*mm, fill=1, stroke=0)

    # Body
    draw_rounded_rect(canvas, x, y, bw, bh, r=4*mm,
                      fill_color=body_color, stroke_color=hdr_color, stroke_width=1.5)

    # Header band (top of box)
    canvas.saveState()
    canvas.clipPath(canvas.beginPath(), fill=0, stroke=0)
    p2 = canvas.beginPath()
    p2.roundRect(x, y + bh - hdr_h, bw, hdr_h, 4*mm)
    canvas.clipPath(p2, fill=0, stroke=0)
    canvas.setFillColor(hdr_color)
    canvas.rect(x, y + bh - hdr_h, bw, hdr_h, fill=1, stroke=0)
    canvas.restoreState()

    # Draw header rect (simple approach)
    canvas.setFillColor(hdr_color)
    canvas.roundRect(x, y + bh - hdr_h, bw, hdr_h, 4*mm, fill=1, stroke=0)
    # Cover bottom corners of header
    canvas.rect(x, y + bh - hdr_h, bw, hdr_h/2, fill=1, stroke=0)

    # Step number circle
    if num:
        cr = 4.5*mm
        canvas.setFillColor(white)
        canvas.setStrokeColor(hdr_color)
        canvas.setLineWidth(0)
        canvas.circle(x + cr + 2*mm, y + bh - hdr_h/2, cr, fill=1, stroke=0)
        canvas.setFillColor(hdr_color)
        canvas.setFont("Helvetica-Bold", 8)
        canvas.drawCentredString(x + cr + 2*mm, y + bh - hdr_h/2 - 2.5, num)

    # Icon + Title in header
    tx = cx + (4*mm if num else 0)
    canvas.setFont("Helvetica-Bold", 9)
    canvas.setFillColor(white)
    canvas.drawCentredString(tx, y + bh - hdr_h/2 - 3, f"{icon}  {title}" if icon else title)

    # Subtitle
    if subtitle:
        canvas.setFont("Helvetica-Oblique", 7)
        canvas.setFillColor(HexColor("#555555"))
        canvas.drawCentredString(cx, y + bh - hdr_h - 5*mm, subtitle)

    # Body lines
    line_y = y + bh - hdr_h - (8*mm if subtitle else 5*mm)
    for line in body_lines:
        if line.startswith("**") and line.endswith("**"):
            canvas.setFont("Helvetica-Bold", 7.5)
            canvas.setFillColor(hdr_color)
            canvas.drawCentredString(cx, line_y, line[2:-2])
        elif line.startswith("•"):
            canvas.setFont("Helvetica", 7.2)
            canvas.setFillColor(HexColor("#1B2631"))
            canvas.drawString(x + 5*mm, line_y, line)
        elif line == "---":
            canvas.setStrokeColor(MGRAY)
            canvas.setLineWidth(0.4)
            canvas.line(x + 4*mm, line_y + 2*mm, x + bw - 4*mm, line_y + 2*mm)
        else:
            canvas.setFont("Helvetica", 7.2)
            canvas.setFillColor(HexColor("#1B2631"))
            canvas.drawCentredString(cx, line_y, line)
        line_y -= 4.8*mm

def side_box(canvas, cx, cy, bw, bh, title, lines, color=TEAL, light=LTEAL):
    x = cx - bw/2
    y = cy - bh/2
    draw_rounded_rect(canvas, x, y, bw, bh, r=3*mm,
                      fill_color=light, stroke_color=color, stroke_width=1.2)
    # Header
    canvas.setFillColor(color)
    canvas.roundRect(x, y + bh - 8*mm, bw, 8*mm, 3*mm, fill=1, stroke=0)
    canvas.rect(x, y + bh - 8*mm, bw, 4*mm, fill=1, stroke=0)
    canvas.setFont("Helvetica-Bold", 7.5)
    canvas.setFillColor(white)
    canvas.drawCentredString(cx, y + bh - 5.5, title)
    ly = y + bh - 11*mm
    for line in lines:
        if line.startswith("•"):
            canvas.setFont("Helvetica", 6.5)
            canvas.setFillColor(HexColor("#1B2631"))
            canvas.drawString(x + 3*mm, ly, line)
        else:
            canvas.setFont("Helvetica-Bold", 6.5)
            canvas.setFillColor(color)
            canvas.drawCentredString(cx, ly, line)
        ly -= 4.2*mm

# ══════════════════════════════════════════════════════════════════════════════
# POSTER LAYOUT
# ══════════════════════════════════════════════════════════════════════════════

# ── TITLE BANNER ──────────────────────────────────────────────────────────────
banner_h = 22*mm
canvas_obj = c

c.setFillColor(NAVY)
c.rect(0, H - banner_h, W, banner_h, fill=1, stroke=0)

# Diagonal accent stripe
c.setFillColor(HexColor("#C0392B"))
p = c.beginPath()
p.moveTo(0, H - banner_h)
p.lineTo(60*mm, H - banner_h)
p.lineTo(45*mm, H)
p.lineTo(0, H)
p.close()
c.drawPath(p, fill=1, stroke=0)

c.setFont("Helvetica-Bold", 22)
c.setFillColor(white)
c.drawCentredString(W/2, H - 13*mm, "MIGRAINE PATHOPHYSIOLOGY")

c.setFont("Helvetica", 9)
c.setFillColor(HexColor("#AED6F1"))
c.drawCentredString(W/2, H - 20*mm,
    "Complete Neurovascular Pathway  |  Harrison's 22e  •  Bradley & Daroff  •  Adams & Victor  •  Guyton & Hall")

# Red stripe bottom of banner
c.setFillColor(RED)
c.rect(0, H - banner_h - 2*mm, W, 2*mm, fill=1, stroke=0)

# ── LAYOUT PARAMETERS ─────────────────────────────────────────────────────────
# Main column centre x
MCX = W / 2
# Box widths
MW = 90*mm    # main box width
SW = 62*mm    # side box width
MH_TALL = 38*mm
MH_MED  = 34*mm
MH_SH   = 30*mm

# Starting Y (below banner)
TOP_Y = H - banner_h - 5*mm

# Vertical spacing between box centres
STEP = 45*mm

# ── NODE POSITIONS (centre y) ─────────────────────────────────────────────────
y1  = TOP_Y - 20*mm   # Step 1: Trigger
y2  = y1 - STEP        # Step 2: Hyperexcitable Brain
y3  = y2 - STEP        # Step 3: CSD/Aura
y4  = y3 - STEP        # Step 4: Trigeminovascular Activation
y5  = y4 - STEP        # Step 5: Neurogenic Inflammation
y6  = y5 - STEP        # Step 6: Central Sensitization
y7  = y6 - STEP        # Step 7: HEADACHE
y8  = y7 - STEP        # Step 8: Postdrome

# ── DRAW CONNECTING ARROWS ────────────────────────────────────────────────────
arrow_color = RED
arrow_top_gap = 5.5*mm
arrow_bot_gap = 5.5*mm

node_ys = [y1, y2, y3, y4, y5, y6, y7, y8]
box_heights = [MH_SH, MH_MED, MH_TALL, MH_TALL, MH_MED, MH_TALL, MH_TALL, MH_MED]

for i in range(len(node_ys)-1):
    top_box_bot = node_ys[i] - box_heights[i]/2
    bot_box_top = node_ys[i+1] + box_heights[i+1]/2
    arrow_down(c, MCX,
               top_box_bot - 1*mm,
               bot_box_top + 1*mm,
               color=RED, lw=2.2)

# ── NODE 1: TRIGGERS ──────────────────────────────────────────────────────────
main_box(c, MCX, y1, MW, MH_SH,
         "TRIGGERS", "What sets off the attack?",
         ["• Stress / stress let-down",
          "• Sleep disruption",
          "• Skipping meals / fasting",
          "• Hormonal changes (oestrogen drop)",
          "• Bright lights, loud sounds",
          "• Alcohol / nitrates / weather change"],
         hdr_color=GRAY, body_color=LGRAY, num="1")

# ── NODE 2: HYPEREXCITABLE BRAIN ─────────────────────────────────────────────
main_box(c, MCX, y2, MW, MH_MED,
         "HYPEREXCITABLE BRAIN", "The underlying problem",
         ["• Brain has LOW threshold for activation",
          "• Does NOT habituate to sensory input",
          "• Genetic basis: ion channel mutations",
          "• Hypothalamus activates 24h BEFORE pain",
          "• Brainstem: PAG, dorsal pons, raphe nuclei"],
         hdr_color=BLUE, body_color=LBLUE, num="2")

# Side box: Genetics
side_box(c, MCX + MW/2 + 4*mm + SW/2, y2, SW, 28*mm,
         "GENETICS",
         ["• CACNA1A (FHM type 1)",
          "• ATP1A2 (FHM type 2)",
          "• SCN1A (FHM type 3)",
          "• 1st-degree relatives:",
          "  2-4x higher risk",
          "• More common in women (3:1)"],
         color=BLUE, light=LBLUE)
arrow_right(c, MCX + MW/2, MCX + MW/2 + 4*mm, y2, color=BLUE, lw=1.5)

# ── NODE 3: CSD / AURA ───────────────────────────────────────────────────────
main_box(c, MCX, y3, MW, MH_TALL,
         "CORTICAL SPREADING DEPRESSION", "Basis of Aura  (~25-30% of patients)",
         ["**Wave of neuronal depolarisation**",
          "• Starts in occipital cortex (visual area)",
          "• Spreads FORWARD at 2-4 mm/min",
          "• Does NOT follow arterial territories",
          "---",
          "• Flashing zig-zag lights (scintillating scotoma)",
          "• Blind spot, numbness, speech difficulty",
          "• Symptoms march over ~20-30 min"],
         hdr_color=ORANGE, body_color=LORANGE, num="3")

# Side box: Aura symptoms detail
side_box(c, MCX - MW/2 - 4*mm - SW/2, y3, SW, MH_TALL,
         "AURA TYPES",
         ["Visual (most common):",
          "• Zig-zag fortification lines",
          "• Scintillating scotoma",
          "• Blurring / blind spot",
          "Sensory:",
          "• Numbness / pins & needles",
          "Motor (rare - FHM):",
          "• Unilateral weakness",
          "Speech:",
          "• Dysphasia"],
         color=ORANGE, light=LORANGE)
arrow_left(c, MCX - MW/2 - 4*mm, MCX - MW/2, y3, color=ORANGE, lw=1.5)

# ── NODE 4: TRIGEMINOVASCULAR ACTIVATION ─────────────────────────────────────
main_box(c, MCX, y4, MW, MH_TALL,
         "TRIGEMINOVASCULAR ACTIVATION", "The KEY mechanism of migraine pain",
         ["• Trigeminal nerve fibres wrap meninges & vessels",
          "• CSD or brainstem signals activate trigeminal endings",
          "---",
          "**Neuropeptides released:**",
          "• CGRP — main pain mediator (vasodilation)",
          "• Substance P — plasma protein leakage",
          "• PACAP — emerging mediator (Harrison's 22e)",
          "• Nitric Oxide — vasodilation"],
         hdr_color=RED, body_color=LRED, num="4")

# Side box: CGRP importance
side_box(c, MCX + MW/2 + 4*mm + SW/2, y4, SW, MH_TALL,
         "WHY CGRP MATTERS",
         ["• Rises sharply during attack",
          "• Dilates meningeal vessels",
          "• Sensitises trigeminal fibres",
          "• Promotes neurogenic inflam.",
          "CGRP-targeted drugs:",
          "• Gepants (acute + preventive)",
          "• Erenumab (anti-CGRP-R mAb)",
          "• Fremanezumab",
          "• Galcanezumab",
          "• Eptinezumab"],
         color=RED, light=LRED)
arrow_right(c, MCX + MW/2, MCX + MW/2 + 4*mm, y4, color=RED, lw=1.5)

# ── NODE 5: NEUROGENIC INFLAMMATION ──────────────────────────────────────────
main_box(c, MCX, y5, MW, MH_MED,
         "STERILE NEUROGENIC INFLAMMATION", "Around the meningeal vessels",
         ["• Meningeal blood vessels DILATE",
          "• Plasma proteins leak out of vessel walls",
          "• Mast cells degranulate",
          "• Inflammatory soup forms around meninges",
          "• Meninges swell and become hypersensitive"],
         hdr_color=PURPLE, body_color=LPURPLE, num="5")

# ── NODE 6: CENTRAL SENSITIZATION ────────────────────────────────────────────
main_box(c, MCX, y6, MW, MH_TALL,
         "CENTRAL SENSITIZATION", "Why everything becomes painful",
         ["• Repeated pain signals LOWER threshold of neurons",
          "• 1st order: trigeminal nerve endings (scalp tender)",
          "• 2nd order: trigeminal nucleus caudalis",
          "• 3rd order: thalamus + cortex",
          "---",
          "• Allodynia: gentle touch = pain (~75% of attacks)",
          "• Photophobia, Phonophobia, Osmophobia",
          "• Triptans LESS effective once allodynia sets in"],
         hdr_color=PURPLE, body_color=LPURPLE, num="6")

# Side box: Sensitization cascade
side_box(c, MCX - MW/2 - 4*mm - SW/2, y6, SW, MH_TALL,
         "SENSITIZATION CASCADE",
         ["Peripheral:",
          "• C-fibres detect vessel pulsation",
          "• = Throbbing quality of pain",
          "1st order → 2nd order:",
          "• Scalp tenderness",
          "• Allodynia begins",
          "2nd → 3rd order:",
          "• Thalamic neurons fire",
          "• Light/sound/smell = pain",
          "• Whole-body allodynia"],
         color=PURPLE, light=LPURPLE)
arrow_left(c, MCX - MW/2 - 4*mm, MCX - MW/2, y6, color=PURPLE, lw=1.5)

# ── NODE 7: HEADACHE ─────────────────────────────────────────────────────────
# Make this the focal "output" box - larger and bold
HW = 100*mm
HH = 40*mm
hx = MCX - HW/2
hy = y7 - HH/2

# Glow effect
c.setFillColor(HexColor("#FDEDEC"))
c.setStrokeColor(RED)
c.setLineWidth(0)
c.roundRect(hx - 2*mm, hy - 2*mm, HW + 4*mm, HH + 4*mm, 6*mm, fill=1, stroke=0)

main_box(c, MCX, y7, HW, HH,
         "MIGRAINE HEADACHE", "The full clinical attack",
         ["**Throbbing, pulsating, usually unilateral**",
          "• Moderate to severe intensity",
          "• Lasts 4 to 72 hours untreated",
          "• Aggravated by physical activity",
          "---",
          "• Nausea / Vomiting",
          "• Photophobia + Phonophobia + Osmophobia",
          "• Cutaneous allodynia"],
         hdr_color=RED, body_color=HexColor("#FDFEFE"), num="7")

# Side box: Why TRIPTANS work
side_box(c, MCX + HW/2 + 4*mm + SW/2, y7, SW, HH,
         "WHY TRIPTANS WORK",
         ["Triptans = 5-HT1B/1D agonists",
          "",
          "5-HT1B (blood vessels):",
          "• Cranial vasoconstriction",
          "• Reverses meningeal dilation",
          "",
          "5-HT1D (nerve terminals):",
          "• Blocks CGRP + SP release",
          "• Stops neurogenic inflam.",
          "",
          "Take EARLY (before allodynia)",
          "Avoid in IHD / stroke / HTN"],
         color=GREEN, light=LGREEN)
arrow_right(c, MCX + HW/2, MCX + HW/2 + 4*mm, y7, color=GREEN, lw=1.5)

# Serotonin side box LEFT of headache
side_box(c, MCX - HW/2 - 4*mm - SW/2, y7, SW, HH,
         "NEUROTRANSMITTERS",
         ["CGRP: main pain + vasodilation",
          "5-HT: pain modulation",
          "(fluctuates across phases)",
          "Dopamine: nausea, yawning",
          "Glutamate: drives CSD",
          "Noradrenaline: sensory hypersens.",
          "PACAP: emerging (Harrison's 22e)",
          "NO: vasodilator, triggers attack"],
         color=TEAL, light=LTEAL)
arrow_left(c, MCX - HW/2 - 4*mm, MCX - HW/2, y7, color=TEAL, lw=1.5)

# ── NODE 8: POSTDROME ────────────────────────────────────────────────────────
main_box(c, MCX, y8, MW, MH_MED,
         "POSTDROME", "The 'migraine hangover'  (hours to 1 day)",
         ["• Fatigue and exhaustion",
          "• Cognitive fog / poor concentration",
          "• Neck stiffness",
          "• Mood changes (elation or depression)",
          "• Brain slowly resets to baseline"],
         hdr_color=GRAY, body_color=LGRAY, num="8")

# ── STEP LABELS ON ARROW SHAFT ───────────────────────────────────────────────
label_data = [
    (y1, y2, "Brain enters\nalert state"),
    (y2, y3, "Electrical\nwave begins"),
    (y3, y4, "Pain nerve\nactivated"),
    (y4, y5, "Chemicals\nreleased"),
    (y5, y6, "Neurons\noverstimulated"),
    (y6, y7, "Pain fully\nperceived"),
    (y7, y8, "Attack\nresolves"),
]
for y_top_node, y_bot_node, label in label_data:
    top_h = box_heights[node_ys.index(y_top_node)] if y_top_node in node_ys else MH_MED
    bot_h = box_heights[node_ys.index(y_bot_node)] if y_bot_node in node_ys else MH_MED
    mid_y = (y_top_node - top_h/2 + y_bot_node + bot_h/2) / 2
    c.setFillColor(HexColor("#FDFEFE"))
    c.setStrokeColor(MGRAY)
    c.setLineWidth(0.4)
    c.roundRect(MCX + 4*mm, mid_y - 4*mm, 22*mm, 8.5*mm, 2*mm, fill=1, stroke=1)
    c.setFont("Helvetica-Oblique", 5.8)
    c.setFillColor(GRAY)
    lines = label.split("\n")
    c.drawString(MCX + 5*mm, mid_y + 1.5*mm, lines[0])
    if len(lines) > 1:
        c.drawString(MCX + 5*mm, mid_y - 2.5*mm, lines[1])

# ── FOOTER ────────────────────────────────────────────────────────────────────
footer_h = 14*mm
c.setFillColor(NAVY)
c.rect(0, 0, W, footer_h, fill=1, stroke=0)

c.setFillColor(RED)
c.rect(0, footer_h, W, 1.5*mm, fill=1, stroke=0)

c.setFont("Helvetica-Bold", 7)
c.setFillColor(white)
c.drawCentredString(W/2, footer_h - 5*mm,
    "Sources: Harrison's Principles of Internal Medicine 22e (2025)  •  Bradley & Daroff's Neurology in Clinical Practice  •  Adams & Victor's Principles of Neurology 12e  •  Guyton & Hall Medical Physiology")
c.setFont("Helvetica", 6.5)
c.setFillColor(HexColor("#AED6F1"))
c.drawCentredString(W/2, footer_h - 10*mm,
    "CGRP = Calcitonin Gene-Related Peptide  •  CSD = Cortical Spreading Depression  •  PAG = Periaqueductal Gray  •  FHM = Familial Hemiplegic Migraine  •  5-HT = Serotonin  •  NO = Nitric Oxide  •  PACAP = Pituitary Adenylate Cyclase-Activating Polypeptide  •  mAb = Monoclonal Antibody")

# ── LEGEND ────────────────────────────────────────────────────────────────────
leg_x = 8*mm
leg_y = y8 - MH_MED/2 - 8*mm
legend_items = [
    (GRAY,   "Trigger / Prodrome / Postdrome"),
    (BLUE,   "Brain / Neural Mechanism"),
    (ORANGE, "Cortical Spreading Depression"),
    (RED,    "Pain Pathway / Headache"),
    (PURPLE, "Sensitization"),
    (GREEN,  "Treatment"),
    (TEAL,   "Neurotransmitters"),
]
c.setFillColor(LGRAY)
c.setStrokeColor(MGRAY)
c.setLineWidth(0.5)
c.roundRect(leg_x - 2*mm, leg_y - 4*mm, 55*mm, len(legend_items)*6.5*mm + 10*mm, 3*mm, fill=1, stroke=1)
c.setFont("Helvetica-Bold", 7)
c.setFillColor(DKBLUE)
c.drawString(leg_x, leg_y + len(legend_items)*6.5*mm + 3*mm, "COLOUR KEY")
for i, (col, label) in enumerate(legend_items):
    ly = leg_y + (len(legend_items) - 1 - i) * 6.5*mm
    c.setFillColor(col)
    c.roundRect(leg_x, ly, 6*mm, 4.5*mm, 1*mm, fill=1, stroke=0)
    c.setFont("Helvetica", 6.5)
    c.setFillColor(HexColor("#1B2631"))
    c.drawString(leg_x + 8*mm, ly + 0.8*mm, label)

c.save()
print(f"Poster saved: {OUT}")
Running Command

cd /home/daytona/workspace/migraine-ref-card && python3 generate_flowchart_poster.py 2>&1

Running Command

ls -lh /home/daytona/workspace/migraine-ref-card/Migraine_Flowchart_Poster.pdf

Your visual flowchart poster is ready:

Migraine Flowchart Poster

PDF Document · PDF


Here is what is in the poster (A3 portrait, print-ready):
Central Flowchart — 8 numbered nodes connected by red arrows:
StepNodeColour
1TriggersGrey
2Hyperexcitable BrainBlue
3Cortical Spreading DepressionOrange
4Trigeminovascular ActivationRed
5Sterile Neurogenic InflammationPurple
6Central SensitizationPurple
7MIGRAINE HEADACHE (highlighted focal box)Red
8PostdromeGrey
Side branches (branching left and right from main flow):
  • Right of Step 2: Genetics box (FHM mutations, family risk)
  • Left of Step 3: Aura Types (visual, sensory, motor, speech)
  • Right of Step 4: Why CGRP Matters + drug names (gepants, mAbs)
  • Left of Step 6: Sensitization Cascade (1st → 2nd → 3rd order neurons)
  • Right of Step 7: Why Triptans Work (5-HT1B + 5-HT1D explained simply)
  • Left of Step 7: Neurotransmitters (CGRP, 5-HT, dopamine, NO, PACAP, glutamate)
Also includes:
  • Small transition labels on each arrow shaft ("Brain enters alert state", "Electrical wave begins", etc.)
  • Colour key legend
  • Full source citations in the footer
This is a shared conversation. Sign in to Orris to start your own chat.