labor

I need a bit more context to give you a useful answer. What aspect of "labor" are you asking about?
Asking for Preferences

What aspect of 'labor' are you interested in?

This is a medical topic, so I'll start by reading the medical library skill.
Quick answer: Labor (parturition) is the process of childbirth divided into three stages: (1) cervical dilation from onset of regular contractions to full dilation (10 cm), (2) expulsion of the fetus from full dilation to delivery, and (3) delivery of the placenta. A fourth stage covering the first 1-2 hours postpartum is also recognized. Management involves monitoring fetal heart rate, uterine contractions, cervical progress, and maternal vitals throughout.
Searching sources...
Reading File
Finding Sources
Finding Sources
Good sources found. Let me read the key sections in parallel.
Reading File
Reading File
Reading File
Now let me get the stages of labor details and management from Tintinalli's, plus search for management/complications.
Reading File
Finding Sources
Finding Sources
Reading File
Finding Sources
Excellent. I now have rich, authoritative content. Let me also fetch the cardinal movements image and get the FHR tracing image.
Reading File
Loading Image
I now have comprehensive information for a complete answer. Let me compile it.

Labor (Parturition) - Obstetrics

Definition

Labor is the process of childbirth consisting of progressive uterine contractions that produce cervical effacement and dilation, leading to fetal expulsion and placental delivery. It is a continuous physiologic process divided into stages for clinical management. - The Developing Human: Clinically Oriented Embryology

True vs. False Labor

Before managing labor, the distinction between true and false labor must be made:
FeatureTrue LaborFalse Labor (Braxton Hicks)
Contraction rhythmRegularIrregular
IntervalsGradually shortenUnchanged
IntensityGradually increasesUnchanged
Discomfort locationBack AND abdomenLower abdomen only
Effect of sedationNo reliefUsually relieved
Cervical dilationYesNo
False labor contractions do not produce cervical change and are treated with hydration and rest. - Tintinalli's Emergency Medicine

Stages of Labor

First Stage - Cervical Dilation

From the onset of regular uterine contractions to full cervical dilation (10 cm).
Divided into two phases:
  • Latent phase: Irregular, infrequent contractions. Cervix softens, effaces, and dilates slowly. This is the preparatory phase.
  • Active phase: Begins once the cervix reaches 3-4 cm dilation. Cervix dilates at:
    • 1.2 cm/hour in nulliparous women
    • 1.5 cm/hour in multiparous women
Average duration:
  • Primigravidas (first birth): ~12 hours total
  • Multigravidas: ~7 hours

Second Stage - Fetal Expulsion

From full dilation (10 cm) to delivery of the infant.
  • Mean duration: 54 minutes for nulliparous women, 20 minutes for multiparous women
  • The fetus descends through the cervix and vagina via the six cardinal movements

Third Stage - Placental Delivery

From delivery of the infant to expulsion of the placenta and membranes.
  • Usually lasts <10 minutes; 90% complete within 15 minutes
  • Active intervention typically not needed until >30 minutes
  • A placenta not expelled within 60 minutes is classified as retained placenta
  • After delivery, uterine retraction reduces the placental attachment area; a hematoma forms deep to the placenta and separates it from the uterine wall. Myometrial contractions constrict spiral arteries to prevent excessive bleeding.
(A fourth stage - the first 1-2 hours postpartum - is clinically recognized for monitoring maternal hemostasis.)

Cardinal Movements of Labor (Second Stage)

The fetal head negotiates the maternal pelvis through six movements in vertex presentation:
  1. Engagement - the widest diameter of the fetal head passes below the pelvic inlet
  2. Flexion - chin onto chest to present the smallest head diameter
  3. Descent - downward progress through the birth canal
  4. Internal rotation - head rotates to align with the anteroposterior pelvic outlet
  5. Extension - head extends under the pubic symphysis at delivery
  6. External rotation (restitution) - head rotates to align with fetal shoulders after delivery
  • Tintinalli's Emergency Medicine, Textbook of Family Medicine 9e

Cervical Assessment

  • Dilation: Diameter of the internal cervical os, 0 to 10 cm (full dilation)
  • Effacement: Thinning/shortening of the cervix, expressed as a percentage
  • Station: Level of the presenting fetal part relative to maternal ischial spines
    • Above spines = negative station (-1, -2, -3)
    • At spines = 0 station
    • Below spines = positive station (+1, +2, +3)
    • +3 station = fetal scalp visible at introitus (imminent delivery)

Rupture of Membranes

  • Spontaneous rupture occurs in active labor in most patients; ~8% rupture before labor onset
  • Confirmed by nitrazine paper (amniotic fluid pH 7.0-7.4 turns paper dark blue; vaginal pH 4.5-5.5 stays yellow)
  • Also confirmed by ferning (NaCl crystals on dried amniotic fluid under microscopy)
  • 50% of women with premature rupture deliver within 5 hours; 95% within 28 hours

Fetal Heart Rate (FHR) Monitoring

Normal FHR: 120-160 bpm. Bradycardia: <110 bpm. Tachycardia: >160 bpm.
Key FHR patterns:
Fetal heart rate variability and uterine contraction patterns - showing normal variability, accelerations, flat tracing (possible hypoxia), variable decelerations, and late decelerations
A = Good variability (reassuring) | B = Accelerations (reassuring) | C = Poor/flat variability (possible fetal hypoxia) | D = Variable decelerations (cord compression) | E = Late decelerations (uteroplacental insufficiency)
Late decelerations - drops in FHR both during and >30 seconds after a contraction - are ominous and indicate uteroplacental insufficiency and fetal hypoxia.
Management of fetal distress:
  1. Position mother in left lateral decubitus (reduces aortocaval compression)
  2. IV hydration
  3. Supplemental oxygen
  4. Emergency obstetric consultation

Initial Clinical Evaluation

When a patient >20 weeks presents with signs of labor, obtain:
  • Maternal vital signs (BP, HR, RR, SpO2, temperature)
  • Fetal heart rate (Doppler US)
  • IV access, blood type, urinalysis
  • History: contraction onset/frequency, membrane status, vaginal bleeding, fetal movement, parity, prior delivery complications, prenatal care, estimated due date
Nagele's Rule: EDD = first day of last menstrual period + 9 months + 7 days
Fundal height: In cm from pubic symphysis to fundal top = gestational age in weeks (±2 weeks) after 20 weeks

Delivery Steps & Post-Delivery

  • Push only after full cervical dilation to avoid lacerations
  • Episiotomy is not routine; reserve for fetal distress, shoulder dystocia, or instrumental delivery
  • After delivery: keep infant warm, gentle stimulation; do not routinely suction nose/mouth (causes bradycardia)
  • Delayed cord clamping: at least 1-3 minutes after birth (increases neonatal iron stores)
  • Apgar scores at 1 and 5 minutes (color, tone, heart rate, respiratory effort, reflexes; score <7 requires action)

Sources:
  • The Developing Human: Clinically Oriented Embryology (9780323611541)
  • Tintinalli's Emergency Medicine: A Comprehensive Study (9781260019933)
  • Creasy & Resnik's Maternal-Fetal Medicine (9780323828499)
  • Textbook of Family Medicine, 9e (9780323239905)

Explain in Hinglish language like I never forget of this concept

🍼 LABOR (Prasav/Delivery) - Hinglish Mein Samjho, Kabhi Nahi Bhuloge!


🎬 Pehle Ek Story Socho...

"Ek baby 9 mahine se ghar ke andar band hai. Ab usse bahar aana hai. Uska journey - woh hai LABOR!"
Bas yahi yaad rakho - Labor = Baby ka bahar aane ka poora journey + process.

✅ TRUE vs FALSE LABOR - "Asli vs Nakli Darwaza Khatkhataana"

Socho ek visitor aa raha hai...
TRUE Labor (Asli Visitor)FALSE Labor (Prank Call)
ContractionsRegular - jaise train scheduleIrregular - kabhi aaye kabhi na aaye
IntervalGradually kam hota jaata haiSame rehta hai
DardBadhta jaata haiSame rehta hai
Dard kahanPeeth + Pet dono meinSirf neeche pet mein
Neend/Sedation se?Koi asar nahi - asli haiRelief milti hai - nakli tha
Cervix khulti hai?Haan! ✅Nahi ❌

🧠 Trick:

"Asli Visitor Regular aata hai, Dono taraf se darwaza bajata hai, aur neend se nahi rukta!"
False labor = Braxton Hicks - bas body ka rehearsal hai, actual show nahi!

🎭 STAGES OF LABOR - "3 Acts Wala Drama"

🎬 ACT 1 - FIRST STAGE: "Darwaza Kholna"

Onset of contractions ➜ Cervix full 10 cm dilate ho jaaye
Yeh do scenes mein hota hai:
Scene A - Latent Phase (Dhheema Dhheema)
  • Cervix soft hoti hai, efface hoti hai (얇ी hoti hai)
  • Contractions irregular, mild
  • Body bol raha hai: "Theek hai, prepare ho raha hoon..."
Scene B - Active Phase (Asli Action!)
  • Cervix 3-4 cm pe pohanch jaaye = Active phase shuru!
  • Ab cervix opens at fixed speed:
    • 🥇 Nullipara (pehli baar): 1.2 cm/hour
    • 🥈 Multipara (pehle bhi hua hai): 1.5 cm/hour
Total duration:
  • Pehli baar maa bani: ~12 ghante
  • Pehle bhi delivery hui hai: ~7 ghante

🧠 Trick:

"Pehli baar SLOW (1.2), Second time FAST (1.5) - Experienced driver tezi chalata hai!"

🎬 ACT 2 - SECOND STAGE: "Baby Ka Bahar Aana"

Full dilation (10 cm) ➜ Baby deliver ho jaaye
  • Baby ab neeche utarta hai cervix aur vagina se
  • Maa push karti hai
  • Duration:
    • Nullipara: ~54 minutes
    • Multipara: ~20 minutes
Push kab karein? Sirf jab cervix full 10 cm ho - pehle push kiya toh cervix cut ho sakti hai!

🎬 ACT 3 - THIRD STAGE: "Placenta Ka Jaana"

Baby deliver ➜ Placenta bahar aaye
  • Usually 15 minutes mein ho jaata hai
  • 90% cases mein 15 min mein complete
  • 30 min tak wait kar sakte hain
  • 60 min ke baad bhi nahi aaya = Retained Placenta (emergency!)

🧠 Trick:

"Baby aata hai, Placenta uske baad "bye bye" kehke jaata hai - max 60 min ka notice period!"

🕺 CARDINAL MOVEMENTS - "Baby Ka Dance Moves"

Baby seedha nahi aata - woh dance karta hai birth canal mein! 6 moves hain:
1. 🎯 ENGAGEMENT     - Baby ka head pelvis mein ghusa
2. 🙇 FLEXION        - Chin chest pe - chhota dikhne ke liye
3. ⬇️ DESCENT        - Neeche utarna
4. 🔄 INTERNAL ROTATION - Andar rotate karna (fit hone ke liye)
5. 🔝 EXTENSION      - Head pubic bone ke neeche se nikalta hai
6. 🔃 EXTERNAL ROTATION - Bahar aake shoulders ke saath align karna

🧠 Trick (6 moves yaad karne ka):

"Every Fetus Does Its Excellent Exit" Engagement → Flexion → Descent → Internal rotation → Extension → External rotation

💓 FETAL HEART RATE - "Baby Ka Report Card"

Normal FHR = 120-160 bpm
PatternMatlabStatus
Good variabilityBaby active aur healthy✅ Reassuring
AccelerationsBaby happy✅ Reassuring
Flat/Poor variabilityBaby thaka hua / hypoxia?⚠️ Concerning
Variable decelerationsCord compression - umbilical cord dab rahi⚠️ Watch
Late decelerationsUteroplacental insufficiency - baby ko oxygen nahi mil raha🚨 EMERGENCY

🧠 Trick:

"Late = Wait mat karo! Late deceleration = placenta fail, baby ko oxygen nahi = TURANT action lo!"
Fetal distress mein kya karo (yaad karo: "LEFT OIC")
  • L - Left lateral position (maa ko baayi taraf let-ao)
  • O - Oxygen do
  • I - IV hydration do
  • C - Call/Consult obstetrics ASAP

🔬 CERVIX CHECK - "Lock Ki Condition"

  • Dilation: Kitna khula (0 to 10 cm) - 10 cm = full open
  • Effacement: Cervix kitni patli hui (% mein) - 100% = completely thin
  • Station: Baby ka level ischial spines ke relative
    • Negative = Spines ke upar (abhi door hai)
    • 0 = Exactly spines pe
    • Positive = Spines ke neeche (aa raha hai!)
    • +3 = Scalp dikh raha hai = Delivery hone waali hai! 🚨

🧠 Trick:

"Station zero = Starting line. Plus mein = Race jeet raha hai baby!"

💧 MEMBRANE RUPTURE - "Pani Ka Toot-na"

  • Amniotic fluid pH = 7.0-7.4 (alkaline)
  • Vaginal fluid pH = 4.5-5.5 (acidic)
  • Test: Nitrazine paper
    • Blue = Amniotic fluid (rupture hua!) ✅
    • Yellow = Vaginal fluid (rupture nahi hua)

🧠 Trick:

"Blue matlab 'Baahar aa' - membrane toot gayi!"
Doosra test: Ferning - microscope pe NaCl crystals fern jaisa dikhte hain amniotic fluid mein.

👶 DELIVERY KE BAAD - "Post Match Analysis"

  1. Cord clamping: Delivery ke baad 1-3 minute WAIT karo (delayed cord clamping = baby ko zyada iron milta hai)
  2. Suction mat karo routinely - bradycardia ho sakti hai baby ko
  3. Apgar Score - 1 min aur 5 min pe (Color, Tone, HR, Respiratory effort, Reflex)
    • 7-10 = Healthy baby ✅
    • <7 = Help chahiye ⚠️

🏆 ULTIMATE SUMMARY TABLE

LABOR = 3 Acts

ACT 1️⃣  → Darwaza Kholo (Contractions → 10 cm dilation)
          Latent + Active phase
          1.2 cm/hr (Nulli) | 1.5 cm/hr (Multi)

ACT 2️⃣  → Baby Aao (10 cm → Delivery)
          54 min (Nulli) | 20 min (Multi)
          6 Cardinal Moves: Every Fetus Does Its Excellent Exit

ACT 3️⃣  → Placenta Jao (Delivery → Placenta out)
          15 min usually | 60 min = Retained!

🎯 Final Yaad-Rakhne Wali Line: "Labor ek drama hai - pehle darwaza khula, phir hero aaya, phir set saaf hua. Har act ka time hota hai, aur baby ka dance (cardinal movements) miss mat karna!" 😄

Create a cheat sheet PDF for labor stages & fetal monitoring

Let me read the PDF skill first.
Reading File
Running Command

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

Writing File

~/labor-cheatsheet/create_pdf.py

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

OUTPUT_PATH = "/home/daytona/workspace/labor-cheatsheet/Labor_Cheatsheet.pdf"
os.makedirs(os.path.dirname(OUTPUT_PATH), exist_ok=True)

# ── Colour palette ──────────────────────────────────────────────────────────
C_DARK_BLUE   = colors.HexColor("#1A237E")
C_MED_BLUE    = colors.HexColor("#3949AB")
C_LIGHT_BLUE  = colors.HexColor("#E8EAF6")
C_TEAL        = colors.HexColor("#00695C")
C_LIGHT_TEAL  = colors.HexColor("#E0F2F1")
C_RED         = colors.HexColor("#C62828")
C_LIGHT_RED   = colors.HexColor("#FFEBEE")
C_ORANGE      = colors.HexColor("#E65100")
C_LIGHT_ORANGE= colors.HexColor("#FFF3E0")
C_YELLOW_BG   = colors.HexColor("#FFFDE7")
C_GREEN       = colors.HexColor("#2E7D32")
C_LIGHT_GREEN = colors.HexColor("#E8F5E9")
C_PURPLE      = colors.HexColor("#6A1B9A")
C_LIGHT_PURPLE= colors.HexColor("#F3E5F5")
C_GREY_BG     = colors.HexColor("#F5F5F5")
C_WHITE       = colors.white
C_BLACK       = colors.black
C_HEADER_BG   = colors.HexColor("#0D47A1")

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

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

TITLE = S("TITLE", fontSize=22, fontName="Helvetica-Bold",
          textColor=C_WHITE, alignment=TA_CENTER, spaceAfter=2)
SUBTITLE = S("SUBTITLE", fontSize=11, fontName="Helvetica",
             textColor=colors.HexColor("#BBDEFB"), alignment=TA_CENTER)
SECTION_HEAD = S("SEC", fontSize=12, fontName="Helvetica-Bold",
                 textColor=C_WHITE, alignment=TA_CENTER, spaceAfter=1)
BODY = S("BODY", fontSize=8.5, fontName="Helvetica",
         textColor=C_BLACK, leading=13)
BODY_BOLD = S("BB", fontSize=8.5, fontName="Helvetica-Bold", textColor=C_BLACK)
SMALL = S("SM", fontSize=7.5, fontName="Helvetica", textColor=C_BLACK, leading=11)
SMALL_BOLD = S("SMB", fontSize=7.5, fontName="Helvetica-Bold", textColor=C_BLACK)
CELL = S("CELL", fontSize=8, fontName="Helvetica", textColor=C_BLACK,
         alignment=TA_CENTER, leading=11)
CELL_BOLD = S("CELLB", fontSize=8, fontName="Helvetica-Bold", textColor=C_BLACK,
              alignment=TA_CENTER)
TRICK = S("TRICK", fontSize=8, fontName="Helvetica-Oblique",
          textColor=C_PURPLE, leading=12)
EMOJI_S = S("EMJI", fontSize=9, fontName="Helvetica-Bold", textColor=C_TEAL)

# ── Custom Flowables ─────────────────────────────────────────────────────────

class ColorBox(Flowable):
    """A coloured rounded-corner header box."""
    def __init__(self, text, bg=C_DARK_BLUE, fg=C_WHITE,
                 width=None, height=22, radius=4, fontsize=11):
        Flowable.__init__(self)
        self.text = text
        self.bg   = bg
        self.fg   = fg
        self._w   = width
        self.height = height
        self.radius = radius
        self.fontsize = fontsize

    def wrap(self, avW, avH):
        self.width = self._w or avW
        return self.width, self.height

    def draw(self):
        c = self.canv
        c.setFillColor(self.bg)
        c.roundRect(0, 0, self.width, self.height, self.radius, fill=1, stroke=0)
        c.setFillColor(self.fg)
        c.setFont("Helvetica-Bold", self.fontsize)
        c.drawCentredString(self.width/2, (self.height - self.fontsize)/2 + 1, self.text)


class TrickBox(Flowable):
    """A yellow sticky-note style memory trick box."""
    def __init__(self, text, width=None, height=None):
        Flowable.__init__(self)
        self.text = text
        self._w   = width
        self._h   = height

    def wrap(self, avW, avH):
        self.width = self._w or avW
        self.height = self._h or 30
        return self.width, self.height

    def draw(self):
        c = self.canv
        c.setFillColor(colors.HexColor("#FFF9C4"))
        c.setStrokeColor(colors.HexColor("#F9A825"))
        c.setLineWidth(1.2)
        c.roundRect(0, 0, self.width, self.height, 5, fill=1, stroke=1)
        c.setFillColor(C_PURPLE)
        c.setFont("Helvetica-BoldOblique", 7.5)
        lines = self.text.split("\n")
        y = self.height - 11
        for line in lines:
            c.drawString(6, y, line)
            y -= 11


class StageBar(Flowable):
    """Horizontal 3-stage progress bar."""
    def __init__(self, width=None, height=38):
        Flowable.__init__(self)
        self._w = width
        self.height = height

    def wrap(self, avW, avH):
        self.width = self._w or avW
        return self.width, self.height

    def draw(self):
        c = self.canv
        w = self.width
        seg = w / 3
        colors_list = [C_MED_BLUE, C_TEAL, C_ORANGE]
        labels = ["STAGE 1\nContractions → 10cm", "STAGE 2\n10cm → Baby Out", "STAGE 3\nBaby → Placenta Out"]
        for i in range(3):
            x = i * seg
            c.setFillColor(colors_list[i])
            c.rect(x + 1, 12, seg - 2, 22, fill=1, stroke=0)
            c.setFillColor(C_WHITE)
            c.setFont("Helvetica-Bold", 7)
            lines = labels[i].split("\n")
            c.drawCentredString(x + seg/2, 26, lines[0])
            c.setFont("Helvetica", 6.5)
            c.drawCentredString(x + seg/2, 16, lines[1])
        # Arrow connectors
        for i in range(1, 3):
            x = i * seg
            c.setFillColor(C_WHITE)
            c.setFont("Helvetica-Bold", 14)
            c.drawCentredString(x, 17, "→")
        # Duration line
        durations = [
            ("Primi: ~12h | Multi: ~7h", C_MED_BLUE),
            ("Primi: 54min | Multi: 20min", C_TEAL),
            ("~15min (max 60min)", C_ORANGE),
        ]
        c.setFont("Helvetica", 6)
        for i, (txt, col) in enumerate(durations):
            c.setFillColor(col)
            c.drawCentredString(i * seg + seg/2, 5, txt)


class FHRBox(Flowable):
    """FHR pattern visual legend."""
    def __init__(self, width=None, height=85):
        Flowable.__init__(self)
        self._w = width
        self.height = height

    def wrap(self, avW, avH):
        self.width = self._w or avW
        return self.width, self.height

    def draw(self):
        c = self.canv
        w = self.width
        patterns = [
            ("Good Variability",        "120-160 bpm, wavy line",                "REASSURING",   C_GREEN,  C_LIGHT_GREEN),
            ("Accelerations",           "HR rises >15bpm for >15sec",            "REASSURING",   C_GREEN,  C_LIGHT_GREEN),
            ("Poor/Flat Variability",   "<5 bpm variation - possible hypoxia",   "CONCERNING",   C_ORANGE, C_LIGHT_ORANGE),
            ("Variable Decelerations",  "Abrupt drop - cord compression",        "WATCH",        C_ORANGE, C_LIGHT_ORANGE),
            ("Late Decelerations",      "Drop after peak contraction - UTI",     "EMERGENCY",    C_RED,    C_LIGHT_RED),
        ]
        row_h = self.height / len(patterns)
        for i, (name, desc, status, col, bg) in enumerate(patterns):
            y = self.height - (i + 1) * row_h
            # background
            c.setFillColor(bg)
            c.rect(0, y + 1, w, row_h - 2, fill=1, stroke=0)
            # status badge
            badge_w = 62
            c.setFillColor(col)
            c.roundRect(w - badge_w - 2, y + 3, badge_w, row_h - 6, 3, fill=1, stroke=0)
            c.setFillColor(C_WHITE)
            c.setFont("Helvetica-Bold", 6.5)
            c.drawCentredString(w - badge_w/2 - 2, y + (row_h - 6)/2 + 1, status)
            # text
            c.setFillColor(col)
            c.setFont("Helvetica-Bold", 7.5)
            c.drawString(4, y + row_h/2 + 1, name)
            c.setFillColor(C_BLACK)
            c.setFont("Helvetica", 6.5)
            c.drawString(4, y + row_h/2 - 8, desc)


# ── Build document ────────────────────────────────────────────────────────────
doc = SimpleDocTemplate(
    OUTPUT_PATH,
    pagesize=A4,
    leftMargin=12*mm, rightMargin=12*mm,
    topMargin=10*mm, bottomMargin=10*mm,
)

PW = A4[0] - 24*mm   # printable width
story = []

# ════════════════════════════════════════════════════════════════════════════
# HEADER BANNER
# ════════════════════════════════════════════════════════════════════════════
class HeaderBanner(Flowable):
    def __init__(self, width, height=58):
        Flowable.__init__(self)
        self.width = width
        self.height = height

    def wrap(self, avW, avH):
        return self.width, self.height

    def draw(self):
        c = self.canv
        # gradient-like background using two rects
        c.setFillColor(C_HEADER_BG)
        c.roundRect(0, 0, self.width, self.height, 8, fill=1, stroke=0)
        # decorative circles
        c.setFillColor(colors.HexColor("#1565C0"))
        c.circle(self.width - 30, self.height - 15, 40, fill=1, stroke=0)
        c.circle(20, 8, 28, fill=1, stroke=0)
        # Title
        c.setFillColor(C_WHITE)
        c.setFont("Helvetica-Bold", 20)
        c.drawCentredString(self.width/2, self.height - 26, "LABOR: Stages & Fetal Monitoring")
        c.setFont("Helvetica", 9)
        c.setFillColor(colors.HexColor("#BBDEFB"))
        c.drawCentredString(self.width/2, self.height - 40,
            "Quick Reference Cheat Sheet  |  Obstetrics  |  Tintinalli · Creasy & Resnik · Developing Human")
        # Tags
        tags = ["3 Stages", "Cardinal Movements", "FHR Patterns", "True vs False Labor", "Cervical Assessment"]
        tag_w = 74
        total = len(tags) * tag_w + (len(tags)-1)*4
        start_x = (self.width - total)/2
        for j, tag in enumerate(tags):
            tx = start_x + j*(tag_w+4)
            c.setFillColor(colors.HexColor("#1565C0"))
            c.roundRect(tx, 4, tag_w, 13, 3, fill=1, stroke=0)
            c.setFillColor(colors.HexColor("#90CAF9"))
            c.setFont("Helvetica", 6.5)
            c.drawCentredString(tx + tag_w/2, 8, tag)

story.append(HeaderBanner(PW))
story.append(Spacer(1, 4*mm))

# ════════════════════════════════════════════════════════════════════════════
# ROW 1 — Stage Bar + True vs False
# ════════════════════════════════════════════════════════════════════════════
story.append(ColorBox("STAGES OF LABOR AT A GLANCE", bg=C_MED_BLUE, height=20))
story.append(Spacer(1, 2*mm))
story.append(StageBar(PW, height=42))
story.append(Spacer(1, 3*mm))

# ════════════════════════════════════════════════════════════════════════════
# ROW 2 — Stage details (3 columns)
# ════════════════════════════════════════════════════════════════════════════
def stage_cell(num, color, title, details, duration):
    inner = [
        [Paragraph(f"<b>STAGE {num}</b>", ParagraphStyle("sh", fontSize=10,
            fontName="Helvetica-Bold", textColor=C_WHITE, alignment=TA_CENTER))],
        [Paragraph(title, ParagraphStyle("st", fontSize=8, fontName="Helvetica",
            textColor=C_WHITE, alignment=TA_CENTER))],
    ]
    for d in details:
        inner.append([Paragraph(f"• {d}", ParagraphStyle("sd", fontSize=7.5,
            fontName="Helvetica", textColor=C_BLACK, leading=11))])
    inner.append([Paragraph(f"<b>Duration:</b> {duration}",
        ParagraphStyle("dur", fontSize=7.5, fontName="Helvetica-Bold", textColor=color, leading=11))])
    t = Table(inner, colWidths=[(PW/3 - 4*mm)])
    hdr_rows = 2
    ts = TableStyle([
        ("BACKGROUND", (0,0), (-1,hdr_rows-1), color),
        ("BACKGROUND", (0,hdr_rows), (-1,-1), C_GREY_BG),
        ("BOX", (0,0), (-1,-1), 0.8, color),
        ("ROWBACKGROUNDS", (0,hdr_rows), (-1,-2), [C_WHITE, C_GREY_BG]),
        ("TOPPADDING", (0,0), (-1,-1), 3),
        ("BOTTOMPADDING", (0,0), (-1,-1), 3),
        ("LEFTPADDING", (0,0), (-1,-1), 5),
        ("RIGHTPADDING", (0,0), (-1,-1), 5),
    ])
    t.setStyle(ts)
    return t

s1 = stage_cell(1, C_MED_BLUE, "Onset contractions → 10 cm dilation",
    ["Latent phase: irregular contractions, cervix softens + effaces",
     "Active phase: starts at 3-4 cm dilation",
     "Nullipara rate: 1.2 cm/hr",
     "Multipara rate: 1.5 cm/hr",
     "Avg total: Primi 12h | Multi 7h"],
    "Primi ~12h | Multi ~7h")

s2 = stage_cell(2, C_TEAL, "Full dilation (10 cm) → Baby delivered",
    ["Push ONLY after full 10 cm (avoids lacerations)",
     "6 Cardinal Movements (see below)",
     "Station at +3 = scalp visible, delivery imminent",
     "Mean: Nullipara 54 min | Multipara 20 min",
     "Fetal descent follows cardinal movements"],
    "Nulli 54 min | Multi 20 min")

s3 = stage_cell(3, C_ORANGE, "Baby out → Placenta delivered",
    ["Uterus retracts → hematoma forms → placenta separates",
     "Myometrial contractions clamp spiral arteries",
     "90% complete within 15 minutes",
     "Intervene if not out by 30 min",
     "Retained placenta = not out by 60 min"],
    "~15 min (max 60 min)")

row2 = Table([[s1, s2, s3]],
             colWidths=[PW/3 - 2*mm, PW/3 - 2*mm, PW/3 - 2*mm])
row2.setStyle(TableStyle([
    ("VALIGN", (0,0), (-1,-1), "TOP"),
    ("LEFTPADDING", (0,0), (-1,-1), 2),
    ("RIGHTPADDING", (0,0), (-1,-1), 2),
]))
story.append(row2)
story.append(Spacer(1, 2*mm))
story.append(TrickBox(
    'Memory Trick: "Darwaza Kholo (S1) → Hero Aao (S2) → Set Saaf Karo (S3)"\n'
    'Rates: "Experienced driver tezi chalata hai" — Multi (1.5) > Nulli (1.2) cm/hr',
    height=26
))
story.append(Spacer(1, 3*mm))

# ════════════════════════════════════════════════════════════════════════════
# ROW 3 — True vs False Labor + Cervical Assessment
# ════════════════════════════════════════════════════════════════════════════
left_col_w = PW * 0.48
right_col_w = PW * 0.48
gap = PW - left_col_w - right_col_w

# TRUE vs FALSE
tvf_head = [
    [Paragraph("<b>FEATURE</b>", CELL_BOLD),
     Paragraph("<b>TRUE LABOR ✓</b>", ParagraphStyle("th", fontSize=8, fontName="Helvetica-Bold",
         textColor=C_WHITE, alignment=TA_CENTER)),
     Paragraph("<b>FALSE LABOR ✗</b>", ParagraphStyle("fh", fontSize=8, fontName="Helvetica-Bold",
         textColor=C_WHITE, alignment=TA_CENTER))],
]
tvf_rows = [
    ["Rhythm",           "Regular",              "Irregular"],
    ["Interval",         "Gradually shortens",   "Unchanged"],
    ["Intensity",        "Gradually increases",  "Unchanged"],
    ["Pain location",    "Back + Abdomen",        "Lower abdomen only"],
    ["Sedation effect",  "No relief",             "Usually relieved"],
    ["Cervical change",  "YES ✓",                 "NO ✗"],
]
tvf_data = tvf_head + [[Paragraph(r[0], SMALL_BOLD),
                         Paragraph(r[1], SMALL),
                         Paragraph(r[2], SMALL)] for r in tvf_rows]
tvf_w = [left_col_w*0.36, left_col_w*0.34, left_col_w*0.30]
tvf_t = Table(tvf_data, colWidths=tvf_w)
tvf_t.setStyle(TableStyle([
    ("BACKGROUND", (0,0), (-1,0), C_DARK_BLUE),
    ("BACKGROUND", (1,1), (1,-1), C_LIGHT_GREEN),
    ("BACKGROUND", (2,1), (2,-1), C_LIGHT_RED),
    ("TEXTCOLOR", (0,0), (-1,0), C_WHITE),
    ("ROWBACKGROUNDS", (0,1), (0,-1), [C_WHITE, C_GREY_BG]),
    ("BOX", (0,0), (-1,-1), 0.5, C_DARK_BLUE),
    ("INNERGRID", (0,0), (-1,-1), 0.3, colors.HexColor("#BBBBBB")),
    ("TOPPADDING", (0,0), (-1,-1), 3),
    ("BOTTOMPADDING", (0,0), (-1,-1), 3),
    ("LEFTPADDING", (0,0), (-1,-1), 4),
    ("RIGHTPADDING", (0,0), (-1,-1), 4),
    ("ALIGN", (1,0), (-1,-1), "CENTER"),
    ("VALIGN", (0,0), (-1,-1), "MIDDLE"),
]))

# CERVICAL ASSESSMENT
cerv_data = [
    [Paragraph("<b>CERVICAL ASSESSMENT</b>", ParagraphStyle("ch", fontSize=8.5,
        fontName="Helvetica-Bold", textColor=C_WHITE, alignment=TA_CENTER))],
    [Paragraph("<b>Dilation:</b> Diameter of internal os (0 → 10 cm = full)\n"
               "<b>Effacement:</b> Cervical thinning expressed as %\n"
               "<b>Station:</b> Presenting part relative to ischial spines", SMALL)],
]
station_rows = [
    ["-3 / -2 / -1", "Above spines", "NOT YET"],
    ["0",            "At spines",    "ENGAGED"],
    ["+1 / +2",      "Below spines", "DESCENDING"],
    ["+3",           "Scalp visible","DELIVERY IMMINENT!"],
]
station_data = [
    [Paragraph("<b>Station</b>", SMALL_BOLD),
     Paragraph("<b>Position</b>", SMALL_BOLD),
     Paragraph("<b>Meaning</b>", SMALL_BOLD)]
] + [[Paragraph(r[0], SMALL), Paragraph(r[1], SMALL),
      Paragraph(r[2], ParagraphStyle("sm2", fontSize=7.5, fontName="Helvetica-Bold",
          textColor=C_RED if r[2].startswith("DELIVERY") else C_TEAL))]
     for r in station_rows]
sw = [right_col_w*0.25, right_col_w*0.40, right_col_w*0.35]
station_t = Table(station_data, colWidths=sw)
station_t.setStyle(TableStyle([
    ("BACKGROUND", (0,0), (-1,0), C_TEAL),
    ("TEXTCOLOR",  (0,0), (-1,0), C_WHITE),
    ("ROWBACKGROUNDS", (0,1), (-1,-1), [C_WHITE, C_LIGHT_TEAL]),
    ("BOX", (0,0), (-1,-1), 0.5, C_TEAL),
    ("INNERGRID", (0,0), (-1,-1), 0.3, colors.HexColor("#BBBBBB")),
    ("TOPPADDING", (0,0), (-1,-1), 3),
    ("BOTTOMPADDING", (0,0), (-1,-1), 3),
    ("LEFTPADDING", (0,0), (-1,-1), 4),
    ("RIGHTPADDING", (0,0), (-1,-1), 4),
    ("ALIGN", (0,0), (-1,-1), "CENTER"),
    ("VALIGN", (0,0), (-1,-1), "MIDDLE"),
]))

# Membrane rupture mini box
mem_data = [
    [Paragraph("<b>MEMBRANE RUPTURE TEST</b>", ParagraphStyle("mh", fontSize=8,
        fontName="Helvetica-Bold", textColor=C_WHITE, alignment=TA_CENTER))],
    [Paragraph(
        "<b>Nitrazine paper:</b><br/>"
        "• Amniotic fluid pH 7.0-7.4 → <b>BLUE</b> (ruptured ✓)<br/>"
        "• Vaginal fluid pH 4.5-5.5 → <b>Yellow</b> (intact)<br/>"
        "False + : blood, lubricant, Trichomonas, semen<br/>"
        "<b>Ferning:</b> NaCl crystals on dried fluid under microscope", SMALL)],
]
mem_t = Table(mem_data, colWidths=[right_col_w])
mem_t.setStyle(TableStyle([
    ("BACKGROUND", (0,0), (-1,0), C_TEAL),
    ("BACKGROUND", (0,1), (-1,-1), C_LIGHT_TEAL),
    ("BOX", (0,0), (-1,-1), 0.5, C_TEAL),
    ("TOPPADDING", (0,0), (-1,-1), 3),
    ("BOTTOMPADDING", (0,0), (-1,-1), 3),
    ("LEFTPADDING", (0,0), (-1,-1), 5),
    ("RIGHTPADDING", (0,0), (-1,-1), 5),
]))

right_inner = Table([
    [station_t],
    [Spacer(1, 2*mm)],
    [mem_t],
], colWidths=[right_col_w])
right_inner.setStyle(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),
]))

# Left: TRUE vs FALSE with header
tvf_title = Table(
    [[Paragraph("<b>TRUE vs FALSE LABOR</b>", ParagraphStyle("tvfh", fontSize=8.5,
        fontName="Helvetica-Bold", textColor=C_WHITE, alignment=TA_CENTER))]],
    colWidths=[left_col_w]
)
tvf_title.setStyle(TableStyle([
    ("BACKGROUND", (0,0), (-1,-1), C_DARK_BLUE),
    ("TOPPADDING", (0,0), (-1,-1), 4),
    ("BOTTOMPADDING", (0,0), (-1,-1), 4),
]))
left_inner = Table([[tvf_title], [tvf_t]], colWidths=[left_col_w])
left_inner.setStyle(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),
]))

row3 = Table([[left_inner, Spacer(gap, 1), right_inner]],
             colWidths=[left_col_w, gap, right_col_w])
row3.setStyle(TableStyle([
    ("VALIGN", (0,0), (-1,-1), "TOP"),
    ("LEFTPADDING", (0,0), (-1,-1), 0),
    ("RIGHTPADDING", (0,0), (-1,-1), 0),
]))
story.append(row3)
story.append(Spacer(1, 3*mm))

# ════════════════════════════════════════════════════════════════════════════
# ROW 4 — Cardinal Movements + FHR Monitoring
# ════════════════════════════════════════════════════════════════════════════
card_w = PW * 0.42
fhr_w  = PW * 0.54
gap2   = PW - card_w - fhr_w

# Cardinal Movements
card_data = [
    [Paragraph("<b>6 CARDINAL MOVEMENTS OF LABOR</b>",
        ParagraphStyle("cmh", fontSize=8.5, fontName="Helvetica-Bold",
            textColor=C_WHITE, alignment=TA_CENTER))],
]
moves = [
    ("1", "ENGAGEMENT",        "Widest head diameter below pelvic inlet",         "E"),
    ("2", "FLEXION",           "Chin on chest → smallest head diameter presented", "F"),
    ("3", "DESCENT",           "Downward progress through birth canal",            "D"),
    ("4", "INTERNAL ROTATION", "Head rotates to align with AP pelvic outlet",      "I"),
    ("5", "EXTENSION",         "Head extends under pubic symphysis",               "E"),
    ("6", "EXTERNAL ROTATION", "Head rotates to align with shoulders post-delivery","E"),
]
for num, name, desc, _ in moves:
    card_data.append([
        Table([[
            Paragraph(f"<b>{num}</b>",
                ParagraphStyle("mn", fontSize=9, fontName="Helvetica-Bold",
                    textColor=C_WHITE, alignment=TA_CENTER)),
            Paragraph(f"<b>{name}</b><br/><font size=7>{desc}</font>",
                ParagraphStyle("md", fontSize=7.5, fontName="Helvetica",
                    textColor=C_BLACK, leading=10))
        ]], colWidths=[14*mm, card_w - 14*mm - 10*mm])
    ])

trick_row = [Paragraph(
    '<b>Mnemonic: "Every Fetus Does Its Excellent Exit"</b><br/>'
    'E-ngagement  F-lexion  D-escent  I-nternal  E-xtension  E-xternal',
    ParagraphStyle("mn2", fontSize=7, fontName="Helvetica-BoldOblique",
        textColor=C_PURPLE, leading=10)
)]
card_data.append([trick_row])

card_t = Table(card_data, colWidths=[card_w])
num_rows = len(card_data)
bg_colors = [C_MED_BLUE, C_TEAL, C_MED_BLUE, C_TEAL, C_MED_BLUE, C_TEAL, C_MED_BLUE]
ts2 = [
    ("BACKGROUND", (0,0), (-1,0), C_DARK_BLUE),
    ("BACKGROUND", (0,-1), (-1,-1), colors.HexColor("#FFF9C4")),
    ("BOX", (0,0), (-1,-1), 0.5, C_DARK_BLUE),
    ("TOPPADDING", (0,0), (-1,-1), 3),
    ("BOTTOMPADDING", (0,0), (-1,-1), 3),
    ("LEFTPADDING", (0,0), (-1,-1), 4),
    ("RIGHTPADDING", (0,0), (-1,-1), 4),
]
for i, col in enumerate(bg_colors[:len(moves)]):
    ts2.append(("BACKGROUND", (0, i+1), (-1, i+1),
                C_LIGHT_BLUE if i % 2 == 0 else C_LIGHT_TEAL))
card_t.setStyle(TableStyle(ts2))

# FHR Monitoring
fhr_title = Table(
    [[Paragraph("<b>FETAL HEART RATE MONITORING</b>",
        ParagraphStyle("fhrh", fontSize=8.5, fontName="Helvetica-Bold",
            textColor=C_WHITE, alignment=TA_CENTER))]],
    colWidths=[fhr_w]
)
fhr_title.setStyle(TableStyle([
    ("BACKGROUND", (0,0), (-1,-1), C_RED),
    ("TOPPADDING", (0,0), (-1,-1), 4),
    ("BOTTOMPADDING", (0,0), (-1,-1), 4),
]))

normal_row = Table([[
    Paragraph("<b>Normal FHR: 120-160 bpm</b>",
        ParagraphStyle("nr", fontSize=8, fontName="Helvetica-Bold",
            textColor=C_WHITE, alignment=TA_CENTER)),
    Paragraph("<b>Bradycardia: &lt;110 bpm</b>",
        ParagraphStyle("br", fontSize=8, fontName="Helvetica-Bold",
            textColor=C_WHITE, alignment=TA_CENTER)),
    Paragraph("<b>Tachycardia: &gt;160 bpm</b>",
        ParagraphStyle("tr", fontSize=8, fontName="Helvetica-Bold",
            textColor=C_WHITE, alignment=TA_CENTER)),
]], colWidths=[fhr_w/3]*3)
normal_row.setStyle(TableStyle([
    ("BACKGROUND", (0,0), (0,0), C_GREEN),
    ("BACKGROUND", (1,0), (1,0), C_ORANGE),
    ("BACKGROUND", (2,0), (2,0), C_RED),
    ("TOPPADDING", (0,0), (-1,-1), 4),
    ("BOTTOMPADDING", (0,0), (-1,-1), 4),
    ("INNERGRID", (0,0), (-1,-1), 0.5, C_WHITE),
]))

patterns = [
    ("Good Variability",       "120-160 bpm, wavy line, beat-to-beat variation",            "REASSURING",        C_GREEN,  C_LIGHT_GREEN),
    ("Accelerations",          "HR rises >15 bpm for >15 sec above baseline",                "REASSURING",        C_GREEN,  C_LIGHT_GREEN),
    ("Poor/Flat Variability",  "Variation <5 bpm — possible fetal hypoxia or sleep cycle",   "CONCERNING",        C_ORANGE, C_LIGHT_ORANGE),
    ("Variable Decelerations", "Abrupt drops unrelated to contractions — cord compression",  "WATCH CLOSELY",     C_ORANGE, C_LIGHT_ORANGE),
    ("Late Decelerations",     "Drop AFTER contraction peak — uteroplacental insufficiency", "EMERGENCY!",        C_RED,    C_LIGHT_RED),
]
pat_data = [
    [Paragraph("<b>Pattern</b>", SMALL_BOLD),
     Paragraph("<b>Description</b>", SMALL_BOLD),
     Paragraph("<b>Status</b>", SMALL_BOLD)]
]
for name, desc, status, col, bg in patterns:
    pat_data.append([
        Paragraph(f"<b>{name}</b>", ParagraphStyle("pn", fontSize=7.5,
            fontName="Helvetica-Bold", textColor=col)),
        Paragraph(desc, SMALL),
        Paragraph(f"<b>{status}</b>", ParagraphStyle("ps", fontSize=7,
            fontName="Helvetica-Bold", textColor=col, alignment=TA_CENTER)),
    ])

pat_t = Table(pat_data, colWidths=[fhr_w*0.30, fhr_w*0.48, fhr_w*0.22])
pat_ts = [
    ("BACKGROUND", (0,0), (-1,0), colors.HexColor("#880E4F")),
    ("TEXTCOLOR", (0,0), (-1,0), C_WHITE),
    ("BOX", (0,0), (-1,-1), 0.5, C_RED),
    ("INNERGRID", (0,0), (-1,-1), 0.3, colors.HexColor("#CCCCCC")),
    ("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), "MIDDLE"),
]
for i, (_, _, _, col, bg) in enumerate(patterns):
    pat_ts.append(("BACKGROUND", (0, i+1), (-1, i+1), bg))
pat_t.setStyle(TableStyle(pat_ts))

# Distress action box
action_data = [[
    Paragraph("<b>FETAL DISTRESS ACTION (LEFT OIC):</b>  "
              "<b>L</b>eft lateral position  |  <b>O</b>xygen  |  <b>I</b>V fluids  |  <b>C</b>onsult OB",
        ParagraphStyle("act", fontSize=8, fontName="Helvetica-Bold",
            textColor=C_WHITE, alignment=TA_CENTER))
]]
action_t = Table(action_data, colWidths=[fhr_w])
action_t.setStyle(TableStyle([
    ("BACKGROUND", (0,0), (-1,-1), C_RED),
    ("TOPPADDING", (0,0), (-1,-1), 5),
    ("BOTTOMPADDING", (0,0), (-1,-1), 5),
]))

trick_fhr = Table([[
    Paragraph('<b>Trick: "Late = Deri mat karo! Uteroplacental failure = TURANT action!"</b>',
        ParagraphStyle("tf", fontSize=7.5, fontName="Helvetica-BoldOblique",
            textColor=C_PURPLE))
]], colWidths=[fhr_w])
trick_fhr.setStyle(TableStyle([
    ("BACKGROUND", (0,0), (-1,-1), colors.HexColor("#FFF9C4")),
    ("BOX", (0,0), (-1,-1), 0.8, colors.HexColor("#F9A825")),
    ("TOPPADDING", (0,0), (-1,-1), 4),
    ("BOTTOMPADDING", (0,0), (-1,-1), 4),
    ("LEFTPADDING", (0,0), (-1,-1), 5),
]))

fhr_block = Table([
    [fhr_title],
    [normal_row],
    [pat_t],
    [action_t],
    [Spacer(1,2)],
    [trick_fhr],
], colWidths=[fhr_w])
fhr_block.setStyle(TableStyle([
    ("TOPPADDING", (0,0), (-1,-1), 1),
    ("BOTTOMPADDING", (0,0), (-1,-1), 1),
    ("LEFTPADDING", (0,0), (-1,-1), 0),
    ("RIGHTPADDING", (0,0), (-1,-1), 0),
]))

row4 = Table([[card_t, Spacer(gap2, 1), fhr_block]],
             colWidths=[card_w, gap2, fhr_w])
row4.setStyle(TableStyle([
    ("VALIGN", (0,0), (-1,-1), "TOP"),
    ("LEFTPADDING", (0,0), (-1,-1), 0),
    ("RIGHTPADDING", (0,0), (-1,-1), 0),
]))
story.append(row4)
story.append(Spacer(1, 3*mm))

# ════════════════════════════════════════════════════════════════════════════
# ROW 5 — Post-delivery + Apgar + Footer
# ════════════════════════════════════════════════════════════════════════════
post_w = PW * 0.48
apgar_w = PW * 0.48
gap3 = PW - post_w - apgar_w

post_items = [
    ("Cord Clamping", "Delay AT LEAST 1-3 min after birth (increases neonatal iron)"),
    ("Suction",       "Do NOT routinely suction nose/mouth (causes bradycardia)"),
    ("Warmth",        "Keep infant warm, provide gentle stimulation"),
    ("Episiotomy",    "NOT routine — only for fetal distress, shoulder dystocia, forceps"),
    ("Pushing",       "Only push after FULL 10 cm dilation"),
    ("Apgar",         "Score at 1 min AND 5 min post-delivery"),
]
post_data = [[Paragraph("<b>POST-DELIVERY ESSENTIALS</b>",
    ParagraphStyle("pdh", fontSize=8.5, fontName="Helvetica-Bold",
        textColor=C_WHITE, alignment=TA_CENTER))]]
for item, desc in post_items:
    post_data.append([Paragraph(f"<b>{item}:</b> {desc}", SMALL)])
post_t = Table(post_data, colWidths=[post_w])
post_t.setStyle(TableStyle([
    ("BACKGROUND", (0,0), (-1,0), C_PURPLE),
    ("BACKGROUND", (0,1), (-1,-1), C_LIGHT_PURPLE),
    ("ROWBACKGROUNDS", (0,1), (-1,-1), [C_LIGHT_PURPLE, C_WHITE]),
    ("BOX", (0,0), (-1,-1), 0.5, C_PURPLE),
    ("INNERGRID", (0,0), (-1,-1), 0.3, colors.HexColor("#CCCCCC")),
    ("TOPPADDING", (0,0), (-1,-1), 3),
    ("BOTTOMPADDING", (0,0), (-1,-1), 3),
    ("LEFTPADDING", (0,0), (-1,-1), 5),
    ("RIGHTPADDING", (0,0), (-1,-1), 5),
]))

apgar_rows = [
    ["Color",             "Pink all over",     "Pink body, blue extremities", "Blue/pale all over"],
    ["Tone",              "Active motion",      "Some flexion",                "Limp"],
    ["Heart Rate",        ">100 bpm",           "<100 bpm",                    "Absent"],
    ["Respiratory Effort","Strong cry",         "Weak/irregular",              "Absent"],
    ["Reflex/Grimace",    "Cries/coughs",       "Grimace only",                "No response"],
]
apgar_data = [
    [Paragraph("<b>APGAR SCORE</b>",
        ParagraphStyle("ah", fontSize=8.5, fontName="Helvetica-Bold",
            textColor=C_WHITE, alignment=TA_CENTER)),
     Paragraph(""), Paragraph(""), Paragraph("")],
    [Paragraph("<b>Sign</b>", CELL_BOLD),
     Paragraph("<b>2</b>", ParagraphStyle("s2", fontSize=8, fontName="Helvetica-Bold",
         textColor=C_GREEN, alignment=TA_CENTER)),
     Paragraph("<b>1</b>", ParagraphStyle("s1", fontSize=8, fontName="Helvetica-Bold",
         textColor=C_ORANGE, alignment=TA_CENTER)),
     Paragraph("<b>0</b>", ParagraphStyle("s0", fontSize=8, fontName="Helvetica-Bold",
         textColor=C_RED, alignment=TA_CENTER))],
]
for row in apgar_rows:
    apgar_data.append([Paragraph(row[0], SMALL_BOLD)] +
                      [Paragraph(v, SMALL) for v in row[1:]])
apgar_data.append([
    Paragraph("<b>Score 7-10</b> = Healthy ✓  |  "
              "<b>Score &lt;7</b> = Needs intervention  |  "
              "<b>HR &lt;100</b> = Positive pressure ventilation",
        ParagraphStyle("as", fontSize=7, fontName="Helvetica-Bold",
            textColor=C_BLACK, alignment=TA_CENTER)),
    Paragraph(""), Paragraph(""), Paragraph(""),
])

aw = [apgar_w*0.30, apgar_w*0.24, apgar_w*0.24, apgar_w*0.22]
apgar_t = Table(apgar_data, colWidths=aw)
apgar_t.setStyle(TableStyle([
    ("SPAN", (0,0), (-1,0)),
    ("SPAN", (0,-1), (-1,-1)),
    ("BACKGROUND", (0,0), (-1,0), colors.HexColor("#4A148C")),
    ("BACKGROUND", (0,1), (-1,1), colors.HexColor("#7B1FA2")),
    ("TEXTCOLOR", (0,0), (-1,1), C_WHITE),
    ("BACKGROUND", (1,2), (1,-2), C_LIGHT_GREEN),
    ("BACKGROUND", (2,2), (2,-2), C_LIGHT_ORANGE),
    ("BACKGROUND", (3,2), (3,-2), C_LIGHT_RED),
    ("BACKGROUND", (0,-1), (-1,-1), colors.HexColor("#EDE7F6")),
    ("ROWBACKGROUNDS", (0,2), (0,-2), [C_WHITE, C_GREY_BG]),
    ("BOX", (0,0), (-1,-1), 0.5, colors.HexColor("#4A148C")),
    ("INNERGRID", (0,0), (-1,-1), 0.3, colors.HexColor("#CCCCCC")),
    ("TOPPADDING", (0,0), (-1,-1), 3),
    ("BOTTOMPADDING", (0,0), (-1,-1), 3),
    ("LEFTPADDING", (0,0), (-1,-1), 4),
    ("RIGHTPADDING", (0,0), (-1,-1), 4),
    ("ALIGN", (1,0), (-1,-1), "CENTER"),
    ("VALIGN", (0,0), (-1,-1), "MIDDLE"),
]))

row5 = Table([[post_t, Spacer(gap3, 1), apgar_t]],
             colWidths=[post_w, gap3, apgar_w])
row5.setStyle(TableStyle([
    ("VALIGN", (0,0), (-1,-1), "TOP"),
    ("LEFTPADDING", (0,0), (-1,-1), 0),
    ("RIGHTPADDING", (0,0), (-1,-1), 0),
]))
story.append(row5)
story.append(Spacer(1, 3*mm))

# ════════════════════════════════════════════════════════════════════════════
# FOOTER
# ════════════════════════════════════════════════════════════════════════════
footer_data = [[
    Paragraph("Sources: Tintinalli's Emergency Medicine | Creasy & Resnik's Maternal-Fetal Medicine | The Developing Human | Textbook of Family Medicine 9e",
        ParagraphStyle("ft", fontSize=6.5, fontName="Helvetica", textColor=C_WHITE, alignment=TA_CENTER)),
    Paragraph("Orris Medical Education  |  For Study Purposes Only",
        ParagraphStyle("ft2", fontSize=6.5, fontName="Helvetica-Bold", textColor=colors.HexColor("#BBDEFB"), alignment=TA_RIGHT)),
]]
footer_t = Table(footer_data, colWidths=[PW*0.72, PW*0.28])
footer_t.setStyle(TableStyle([
    ("BACKGROUND", (0,0), (-1,-1), C_DARK_BLUE),
    ("TOPPADDING", (0,0), (-1,-1), 5),
    ("BOTTOMPADDING", (0,0), (-1,-1), 5),
    ("LEFTPADDING", (0,0), (-1,-1), 6),
    ("RIGHTPADDING", (0,0), (-1,-1), 6),
    ("ROUNDEDCORNERS", [4]),
]))
story.append(footer_t)

# ── Build ─────────────────────────────────────────────────────────────────
doc.build(story)
print(f"PDF created: {OUTPUT_PATH}")
Running Command

cd /home/daytona/workspace/labor-cheatsheet && python create_pdf.py 2>&1

Running Command

ls -lh /home/daytona/workspace/labor-cheatsheet/Labor_Cheatsheet.pdf

12KB seems small - let me verify the PDF is valid and check if it rendered correctly.
Running Command

cd /home/daytona/workspace/labor-cheatsheet && python -c " from pypdf import PdfReader r = PdfReader('Labor_Cheatsheet.pdf') print(f'Pages: {len(r.pages)}') print(f'Page size: {r.pages[0].mediabox}') text = r.pages[0].extract_text() print(f'Text chars: {len(text)}') print('First 300 chars:', text[:300]) "

2 pages - content is overflowing to a second page. Let me fix the layout to make everything fit on one page by tightening spacing and font sizes.
Editing File

~/labor-cheatsheet/create_pdf.py

Successfully replaced 1 instance(s) of the string in '/home/daytona/workspace/labor-cheatsheet/create_pdf.py'
Editing File

~/labor-cheatsheet/create_pdf.py

Successfully replaced 1 instance(s) of the string in '/home/daytona/workspace/labor-cheatsheet/create_pdf.py'
Now reduce all spacers and the header banner height:
Editing File

~/labor-cheatsheet/create_pdf.py

Successfully replaced 1 instance(s) of the string in '/home/daytona/workspace/labor-cheatsheet/create_pdf.py'
Now reduce all spacers to tighten vertical space:
Running Command

cd /home/daytona/workspace/labor-cheatsheet && python -c " content = open('create_pdf.py').read() # Reduce spacers content = content.replace('story.append(Spacer(1, 4*mm))', 'story.append(Spacer(1, 2*mm))') content = content.replace('story.append(Spacer(1, 3*mm))', 'story.append(Spacer(1, 2*mm))') content = content.replace('story.append(Spacer(1, 2*mm))', 'story.append(Spacer(1, 1*mm))') # Reduce stage bar height content = content.replace('story.append(StageBar(PW, height=42))', 'story.append(StageBar(PW, height=36))') # Reduce trick box height content = content.replace('TrickBox(\n \'Memory Trick:', 'TrickBox(\n \'Memory Trick:') open('create_pdf.py', 'w').write(content) print('done') "

Running Command

cd /home/daytona/workspace/labor-cheatsheet && python create_pdf.py 2>&1

Running Command

cd /home/daytona/workspace/labor-cheatsheet && python -c " from pypdf import PdfReader r = PdfReader('Labor_Cheatsheet.pdf') print(f'Pages: {len(r.pages)}') import os; print(f'Size: {os.path.getsize(\"Labor_Cheatsheet.pdf\")/1024:.1f} KB') "

Still 2 pages. Let me check what's overflowing and aggressively trim the second page content.
Running Command

cd /home/daytona/workspace/labor-cheatsheet && python -c " from pypdf import PdfReader r = PdfReader('Labor_Cheatsheet.pdf') print('PAGE 2 TEXT:') print(r.pages[1].extract_text()[:800]) "

The post-delivery + Apgar section is overflowing. I need to reduce padding and font sizes in that row, and tighten the APGAR table specifically. Let me do a targeted fix:
Running Command

cd /home/daytona/workspace/labor-cheatsheet && python -c " content = open('create_pdf.py').read() # Reduce all TOPPADDING/BOTTOMPADDING from 3 to 2 content = content.replace('(\"TOPPADDING\", (0,0), (-1,-1), 3)', '(\"TOPPADDING\", (0,0), (-1,-1), 2)') content = content.replace('(\"BOTTOMPADDING\", (0,0), (-1,-1), 3)', '(\"BOTTOMPADDING\", (0,0), (-1,-1), 2)') # reduce 5-padding to 3 content = content.replace('(\"TOPPADDING\", (0,0), (-1,-1), 5)', '(\"TOPPADDING\", (0,0), (-1,-1), 3)') content = content.replace('(\"BOTTOMPADDING\", (0,0), (-1,-1), 5)', '(\"BOTTOMPADDING\", (0,0), (-1,-1), 3)') # reduce 4-padding to 2 content = content.replace('(\"TOPPADDING\", (0,0), (-1,-1), 4)', '(\"TOPPADDING\", (0,0), (-1,-1), 2)') content = content.replace('(\"BOTTOMPADDING\", (0,0), (-1,-1), 4)', '(\"BOTTOMPADDING\", (0,0), (-1,-1), 2)') open('create_pdf.py', 'w').write(content) print('done') "

Running Command

cd /home/daytona/workspace/labor-cheatsheet && python create_pdf.py 2>&1 && python -c " from pypdf import PdfReader; import os r = PdfReader('Labor_Cheatsheet.pdf') print(f'Pages: {len(r.pages)}, Size: {os.path.getsize(\"Labor_Cheatsheet.pdf\")/1024:.1f} KB') "

Still 2 pages. A 2-page cheat sheet is actually better for readability - let me accept this and make the second page clean. The content split is natural: Page 1 = Stages + True/False + Cardinal Movements + FHR; Page 2 = Post-Delivery + Apgar. Let me verify the layout is clean and the PDF is complete.
Running Command

cd /home/daytona/workspace/labor-cheatsheet && python -c " from pypdf import PdfReader; import os r = PdfReader('Labor_Cheatsheet.pdf') print(f'Pages: {len(r.pages)}') for i, p in enumerate(r.pages): t = p.extract_text() print(f'--- Page {i+1} ({len(t)} chars) ---') print(t[:200]) print('...') print(t[-100:]) print() "

The PDF is complete and well-structured. All content is present across both pages with the footer on page 2.Your Labor Cheat Sheet PDF is ready! It's a 2-page, color-coded reference document:

Labor Cheatsheet

PDF Document · PDF


What's inside:

Page 1 - Core Concepts
  • Header banner with topic tags (3 Stages, Cardinal Movements, FHR Patterns, etc.)
  • Stage Progress Bar - visual 3-stage flow with durations at a glance
  • 3-column Stage Details - Stage 1, 2, 3 with color blocks (blue/teal/orange), key facts, and durations
  • Memory trick box - "Darwaza Kholo → Hero Aao → Set Saaf Karo"
  • True vs False Labor table - side-by-side green/red comparison
  • Cervical Assessment - station table with color coding (-3 to +3)
  • Membrane Rupture - Nitrazine test + Ferning explained
  • 6 Cardinal Movements - numbered boxes with mnemonic "Every Fetus Does Its Excellent Exit"
  • FHR Monitoring table - all 5 patterns color-coded (green/orange/red), normal ranges, fetal distress action "LEFT OIC"
Page 2 - Post-Delivery
  • Post-delivery essentials - cord clamping, suction, episiotomy rules
  • APGAR Score table - full scoring grid with color-coded 0/1/2 columns + action thresholds
  • Footer with textbook sources
This is a shared conversation. Sign in to Orris to start your own chat.