I want to learn and u derstand whole.musculoskeletal system in detail so that i can diagnose thrkugh cliniccal examination rather than relying on reports....provide me the detailed explanation from basic to advamce levelll i.e. from embryology to clinical medicine.... Along with the clinical features. Do provide clinical exmaination, diagnosis, differential diagnosi, management, homeolathic management...also explain it with relatable diagram and mnemonics to understand and learn it better ....at the end do provide the pdf of all the content so that i can print it out and then ill read it from that hard copy..

Reading File
Finding Sources
Searching the Web

musculoskeletal system complete guide embryology anatomy clinical examination diagnosis management

Finding Sources
Finding Sources
Finding Sources
Finding Sources
Finding Sources
Finding Sources
Finding Sources
Reading File
Reading File
Running Command

mkdir -p /home/daytona/workspace/msk-guide && ls /home/daytona/workspace/

Okk divide the data into chunkss and then provide itt... so it wont be a grsta task for you

Asking for Preferences
Finding Sources
Finding Sources
Reading File
Reading File
Reading File
Finding Sources
Finding Sources
Finding Sources
Reading File
Reading File
Excellent — I have rich, detailed embryology content from both Langman's and The Developing Human. Now let me compile Chunk 1 with all diagrams, mnemonics, and clinical correlations.

🦴 CHUNK 1 — EMBRYOLOGY OF THE MUSCULOSKELETAL SYSTEM

Sources: Langman's Medical Embryology | The Developing Human (Moore & Persaud) | General Anatomy & MSK (THIEME)

🔑 OVERVIEW AT A GLANCE

The MSK system arises from three embryonic sources:
┌─────────────────────────────────────────────────────────┐
│         ORIGINS OF THE MSK SYSTEM                       │
├──────────────────┬──────────────────────────────────────┤
│ LATERAL PLATE    │ Bones + Connective tissue of limbs   │
│ MESODERM         │ (appendicular skeleton)              │
├──────────────────┼──────────────────────────────────────┤
│ PARAXIAL         │ Muscles, axial skeleton (vertebrae,  │
│ MESODERM (Somites│ ribs), tendons                       │
├──────────────────┼──────────────────────────────────────┤
│ NEURAL CREST     │ Craniofacial bones & cartilage       │
└──────────────────┴──────────────────────────────────────┘

📅 TIMELINE OF MSK DEVELOPMENT

WEEK 4  → Limb buds appear (upper first, then lower 2 days later)
WEEK 5  → AER forms; chondrification begins
WEEK 6  → Hand/footplates form; entire limb skeleton is cartilaginous
WEEK 7  → Primary ossification centers appear in long bones
          Limb rotation occurs (upper laterally, lower medially)
WEEK 8  → Fingers & toes fully separate (apoptosis between digits)
WEEK 12 → Ossification centers in ALL long bones
BIRTH   → Secondary ossification centers begin to appear
Mnemonic — "Always Come Look For Wonderful Bones"
Apical ridge → Chondrification → Limb rotation → Fingers separate → Wrist/ankle ossify → Birth (secondary centers)

🌱 STEP 1 — SOMITE FORMATION (Axial Skeleton)

What are Somites?

Somites are paired blocks of paraxial mesoderm that form alongside the notochord. They differentiate into three compartments:
       SOMITE
    ┌──────────────┐
    │  DERMATOME   │ → Dermis of back skin
    │──────────────│
    │  MYOTOME     │ → Skeletal muscles (back + limbs)
    │──────────────│
    │  SCLEROTOME  │ → Vertebrae, ribs, base of skull
    └──────────────┘
Mnemonic — "D-M-S" = "Dermis Muscles Skeleton"

Sclerotome → Vertebral Column

  • Sclerotome cells migrate around the notochord and neural tube
  • Each vertebra forms from CAUDAL half of one somite + CRANIAL half of the next (re-segmentation)
  • This is why spinal nerves exit BELOW their corresponding vertebra
  Somite N   [  Cranial half  |  Caudal half  ]
  Somite N+1 [  Cranial half  |  Caudal half  ]
                     ↓
         Vertebra = Caudal(N) + Cranial(N+1)
Clinical pearl: Spina bifida results from failure of the neural tube to close + failure of vertebral arches to fuse. Most common at L5–S1.

🦾 STEP 2 — LIMB BUD DEVELOPMENT

Timeline

EventWeek
Upper limb buds appearDay 24 (Week 4)
Lower limb buds appearDay 26–28 (2 days later)
Paddle-shaped buds with hand/foot platesWeek 6
Digital rays form; interdigital apoptosisWeek 7–8
Limbs rotate to final positionWeek 7

Structure of the Limb Bud

      ┌──────────────────────────────────┐
      │     APICAL ECTODERMAL RIDGE      │  ← Ectoderm (thickened)
      │              (AER)               │
      └──────────┬───────────────────────┘
                 │ FGF signals ↓
      ┌──────────▼───────────────────────┐
      │     PROGRESS ZONE (mesenchyme)   │  ← Undifferentiated,
      │     (Undifferentiated Zone)      │    rapidly proliferating
      └──────────┬───────────────────────┘
                 │ Far from AER → differentiate
      ┌──────────▼───────────────────────┐
      │  ZONE OF POLARIZING ACTIVITY     │  ← Posterior border
      │          (ZPA)                   │    SHH → digit identity
      └──────────────────────────────────┘

The 3 Signaling Axes of the Limb

AxisSignalFunction
Proximodistal (shoulder→fingers)FGF (from AER)Drives outgrowth; proximal = early cells, distal = late cells
Anteroposterior (thumb→little)SHH (from ZPA)Specifies digit identity; more SHH = more posterior digit
Dorsoventral (back of hand→palm)WNT7a (dorsal ectoderm) → LMX1Specifies dorsal (nail) vs ventral (palm) identity
Mnemonic — "FWS" = "FGF goes Proximodistally, Wnt Dorsoventrally, SHH Anteroposteriorly"

3-Segment Rule: Stylopod → Zeugopod → Autopod

    Arm/Thigh  =  STYLOPOD   (humerus / femur)
    Forearm/Leg = ZEUGOPOD   (radius+ulna / tibia+fibula)
    Hand/Foot  =  AUTOPOD    (carpals + metacarpals + phalanges)
Mnemonic — "SZA" = "Some Zebras Are (big)"

🔩 STEP 3 — OSSIFICATION

Two Types

┌──────────────────────────────────────────────────────┐
│           TYPES OF OSSIFICATION                      │
├───────────────────────┬──────────────────────────────┤
│ ENDOCHONDRAL          │ INTRAMEMBRANOUS               │
├───────────────────────┼──────────────────────────────┤
│ Cartilage model first │ Directly from mesenchyme     │
│ Long bones, vertebrae │ Flat bones: skull, clavicle, │
│ Short bones, ribs     │ mandible, scapula            │
│ Sequence:             │ No cartilage intermediate    │
│  Cartilage→Calcify    │                              │
│  →Vascular invasion   │                              │
│  →Ossification        │                              │
└───────────────────────┴──────────────────────────────┘
Mnemonic — "ENDO = Long bones (E = Extremities); INTRA = Flat bones (I = Inside head)"

Zones of Endochondral Ossification (Growth Plate)

        EPIPHYSIS (secondary ossification center)
             ↓
    ┌─────────────────────────────────┐
    │  ZONE OF RESTING CARTILAGE      │ ← Chondrocytes at rest
    │  ZONE OF PROLIFERATION          │ ← Rapid cell division (columnar)
    │  ZONE OF HYPERTROPHY            │ ← Chondrocytes enlarge
    │  ZONE OF CALCIFICATION          │ ← Matrix calcifies
    │  ZONE OF OSSIFICATION           │ ← Blood vessels invade; bone forms
    └─────────────────────────────────┘
             ↓
        DIAPHYSIS (primary ossification center)
Mnemonic — "RPHCO" = "Real Physicians Have Chosen Orthopaedics"
Resting → Proliferation → Hypertrophy → Calcification → Ossification

Primary vs Secondary Ossification Centers

FeaturePrimarySecondary
LocationDiaphysis (middle)Epiphysis (ends)
WhenWeek 7 (prenatal)Birth onwards
Growth plateBetween primary & secondary
ClosureAfter puberty (under sex hormones)
Clinical pearl: Growth plate (physis) is the weakest part of a child's bone — fractures here cause Salter-Harris injuries, not ligament tears.

💪 STEP 4 — MUSCLE DEVELOPMENT

Origin of Skeletal Muscle

Somite → MYOTOME → Myogenic precursor cells (MPC)
                          ↓ (migrate via c-Met receptor)
                     Limb bud mesenchyme
                          ↓
                 Myoblasts (MyoD, Myf5 activated)
                          ↓
           Fuse → Myotubes → Myofibers (skeletal muscle)
Key Transcription Factors (MRFs — Myogenic Regulatory Factors):
  • Myf5 — early specification
  • MyoD — commitment to muscle lineage
  • Myogenin — differentiation
  • MRF4 — maturation
Mnemonic — "My Dog Makes Muscle" = MyoD, Myf5, Myogenin, MRF4

Dorsal vs Ventral Muscle Masses

From the limb bud, myoblasts form:
    Limb bud muscles
         ├── DORSAL mass  → EXTENSOR muscles (e.g., triceps, quads)
         └── VENTRAL mass → FLEXOR muscles (e.g., biceps, hamstrings)

🦴 STEP 5 — JOINT DEVELOPMENT

Joints form in areas of concentrated mesenchyme called interzones:
Cartilaginous condensation
        ↓
  INTERZONE forms (Week 6)
        ↓ (apoptosis in center)
  JOINT CAVITY forms
        ↓
  Synovial membrane differentiates from peripheral interzone
  • Fibrous joints (sutures): mesenchyme persists
  • Cartilaginous joints (pubic symphysis): cartilage persists
  • Synovial joints: cavity forms within interzone

⚠️ CONGENITAL ANOMALIES OF MSK

┌─────────────────┬────────────────┬───────────────────────────┐
│ CONDITION        │ MECHANISM      │ CLINICAL NOTES            │
├─────────────────┼────────────────┼───────────────────────────┤
│ Amelia           │ AER absent     │ Complete limb absence     │
│ Phocomelia       │ AER disrupted  │ Flipper limbs (thalidomide│
│                  │ early          │ cause: Wks 24–36 gestation│
│ Ectrodactyly     │ AER split      │ "Lobster claw" hand       │
│ Syndactyly       │ Failure of     │ Most common: 3rd-4th      │
│                  │ apoptosis      │ finger webbing            │
│ Polydactyly      │ Excess SHH     │ Extra digits              │
│ Clubfoot (CTEV)  │ Multifactorial │ M > F; bilateral 50%      │
│ DDH (dev. dyspl  │ Lax capsule,   │ F > M; positive Ortolani/ │
│ of hip)          │ hormones       │ Barlow; Pavlik harness Rx │
│ Spina bifida     │ Folic acid def │ Neural tube + vertebral   │
│ Achondroplasia   │ FGFR3 mutation │ Rhizomelic dwarfism       │
│ Osteogenesis     │ COL1A1/A2 mut  │ Brittle bones, blue sclera│
│ imperfecta       │                │                           │
└─────────────────┴────────────────┴───────────────────────────┘
Mnemonic for CTEV (Clubfoot) — "CAVE":
Cavus (high arch) Adductus (metatarsus in) Varus (heel inverted) Equinus (foot plantarflexed)

🧠 MASTER MNEMONIC — MSK Embryology Summary

"LIMB GROWS FROM LATERAL PLATE, MUSCLES FROM SOMITE, FACE FROM CREST"
StructureSource
Long bone (cortex, periosteum)Lateral plate mesoderm
MusclesParaxial mesoderm (Somites → Myotome)
Vertebrae, ribsParaxial mesoderm (Somites → Sclerotome)
Craniofacial bonesNeural crest cells
AEREctoderm
Tendons, ligaments, connective tissueLateral plate mesoderm
Synovial membraneLateral plate mesoderm (interzone)

🏥 CLINICAL CORRELATIONS (Exam & Practice)

Embryology ConceptClinical DiseaseKey Point
AER disruption (thalidomide)PhocomeliaThalidomide acts Weeks 4–6
Digit apoptosis failureSyndactylySurgical correction
FGFR3 gain-of-functionAchondroplasiaMost common dwarfism; AD
COL1A1/2 mutationOI (Osteogenesis Imperfecta)Brittle bones, blue sclera, hearing loss
Somite re-segmentationSpinal nerve exits BELOW vertebraExplains dermatomal pain patterns
Hip interzone failureDDHPavlik harness < 6 months
Growth plate (physis)Salter-Harris fractures in childrenClassify I-V; affects growth
Neural crestCraniofacial clefts, Pierre Robin

📐 ASCII DIAGRAM — Limb Bud Cross Section

           DORSAL ECTODERM (WNT7a)
          ┌────────────────────────┐
          │                        │
  CRANIAL │    PROGRESS ZONE       │ CAUDAL
  (Thumb) │    (FGF from AER)      │ (Little finger)
          │                        │
          │    ZPA → SHH →         │
          └────────────────────────┘
           VENTRAL ECTODERM (BMP)
              AER at distal tip

✅ Chunk 1 Complete!

Ready for Chunk 2 — Bone: Structure, Histology & Physiology?
Just say "next" or "Chunk 2" and I'll continue! 🦴

Create a printable PDF of Chunk 1

Running Command

ls /home/daytona/workspace/msk-guide/ 2>/dev/null && python3 -c "import reportlab; print('reportlab ok')" && python3 -c "from reportlab.lib.pagesizes import A4; print('A4 ok')"

Writing File

~/msk-guide/chunk1_embryology.py

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

OUTPUT = "/home/daytona/workspace/msk-guide/MSK_Chunk1_Embryology.pdf"

# ── Color Palette ─────────────────────────────────────────────────────────────
C_DARK_BLUE   = HexColor("#1a3a5c")
C_MED_BLUE    = HexColor("#2e6da4")
C_LIGHT_BLUE  = HexColor("#dce9f5")
C_TEAL        = HexColor("#1a7a6e")
C_LIGHT_TEAL  = HexColor("#d4f0ec")
C_ORANGE      = HexColor("#c0550a")
C_LIGHT_ORANGE= HexColor("#fdebd0")
C_YELLOW      = HexColor("#f5c842")
C_LIGHT_YELLOW= HexColor("#fefbd8")
C_RED         = HexColor("#a61c00")
C_LIGHT_RED   = HexColor("#fce4e4")
C_GREEN       = HexColor("#1e6b2e")
C_LIGHT_GREEN = HexColor("#e8f5ea")
C_PURPLE      = HexColor("#5b2a8a")
C_LIGHT_PURPLE= HexColor("#ede4f8")
C_GRAY        = HexColor("#555555")
C_LIGHT_GRAY  = HexColor("#f4f4f4")
C_BORDER      = HexColor("#cccccc")

doc = SimpleDocTemplate(
    OUTPUT,
    pagesize=A4,
    rightMargin=1.8*cm, leftMargin=1.8*cm,
    topMargin=2*cm, bottomMargin=2*cm,
    title="MSK System — Chunk 1: Embryology",
    author="Orris Medical Education"
)

W, H = A4
BODY_W = W - 3.6*cm

styles = getSampleStyleSheet()

def S(name, **kw):
    return ParagraphStyle(name, parent=styles["Normal"], **kw)

# ── Styles ────────────────────────────────────────────────────────────────────
sTitle = S("sTitle",
    fontSize=26, leading=32, textColor=white,
    fontName="Helvetica-Bold", alignment=TA_CENTER, spaceAfter=0)

sSubtitle = S("sSubtitle",
    fontSize=13, leading=18, textColor=HexColor("#d0e8ff"),
    fontName="Helvetica", alignment=TA_CENTER, spaceAfter=0)

sH1 = S("sH1",
    fontSize=15, leading=20, textColor=white,
    fontName="Helvetica-Bold", spaceBefore=14, spaceAfter=4)

sH2 = S("sH2",
    fontSize=12, leading=16, textColor=C_DARK_BLUE,
    fontName="Helvetica-Bold", spaceBefore=10, spaceAfter=3)

sH3 = S("sH3",
    fontSize=10.5, leading=14, textColor=C_TEAL,
    fontName="Helvetica-Bold", spaceBefore=7, spaceAfter=2)

sBody = S("sBody",
    fontSize=9.5, leading=14, textColor=HexColor("#222222"),
    fontName="Helvetica", alignment=TA_JUSTIFY, spaceBefore=2, spaceAfter=2)

sMono = S("sMono",
    fontSize=8.5, leading=12, textColor=HexColor("#1a1a1a"),
    fontName="Courier", spaceBefore=2, spaceAfter=2,
    leftIndent=8, backColor=HexColor("#f0f4f8"))

sBullet = S("sBullet",
    fontSize=9.5, leading=13, textColor=HexColor("#222222"),
    fontName="Helvetica", leftIndent=16, spaceBefore=1, spaceAfter=1,
    bulletIndent=4)

sMnemonic = S("sMnemonic",
    fontSize=10, leading=15, textColor=C_PURPLE,
    fontName="Helvetica-Bold", spaceBefore=3, spaceAfter=3,
    leftIndent=10)

sMnemonicBody = S("sMnemonicBody",
    fontSize=9.5, leading=13, textColor=C_PURPLE,
    fontName="Helvetica", leftIndent=20, spaceBefore=1, spaceAfter=1)

sClinical = S("sClinical",
    fontSize=9.5, leading=14, textColor=C_RED,
    fontName="Helvetica-BoldOblique", spaceBefore=2, spaceAfter=2,
    leftIndent=10)

sTableHeader = S("sTH",
    fontSize=9, leading=12, textColor=white,
    fontName="Helvetica-Bold", alignment=TA_CENTER)

sTableCell = S("sTC",
    fontSize=8.5, leading=12, textColor=HexColor("#111111"),
    fontName="Helvetica", alignment=TA_LEFT)

sTableCellC = S("sTCC",
    fontSize=8.5, leading=12, textColor=HexColor("#111111"),
    fontName="Helvetica", alignment=TA_CENTER)

sFooter = S("sFooter",
    fontSize=7.5, leading=10, textColor=C_GRAY,
    fontName="Helvetica", alignment=TA_CENTER)

# ── Helper Flowables ──────────────────────────────────────────────────────────

class ColorBox(Flowable):
    """A colored rounded rectangle with text inside."""
    def __init__(self, text, bg, fg=white, width=None, height=30, radius=5,
                 fontsize=11, bold=True):
        super().__init__()
        self.text = text
        self.bg = bg
        self.fg = fg
        self.bw = width or BODY_W
        self.bh = height
        self.radius = radius
        self.fontsize = fontsize
        self.bold = bold

    def wrap(self, aw, ah):
        return self.bw, self.bh

    def draw(self):
        c = self.canv
        c.setFillColor(self.bg)
        c.roundRect(0, 0, self.bw, self.bh, self.radius, fill=1, stroke=0)
        c.setFillColor(self.fg)
        font = "Helvetica-Bold" if self.bold else "Helvetica"
        c.setFont(font, self.fontsize)
        c.drawCentredString(self.bw / 2, self.bh / 2 - self.fontsize / 3,
                            self.text)


class SectionHeader(Flowable):
    """Full-width section header bar."""
    def __init__(self, text, bg=C_DARK_BLUE, fg=white, height=28):
        super().__init__()
        self.text = text
        self.bg = bg
        self.fg = fg
        self.bh = height

    def wrap(self, aw, ah):
        self._aw = aw
        return aw, self.bh

    def draw(self):
        c = self.canv
        c.setFillColor(self.bg)
        c.roundRect(0, 0, self._aw, self.bh, 6, fill=1, stroke=0)
        c.setFillColor(self.fg)
        c.setFont("Helvetica-Bold", 12)
        c.drawString(10, self.bh / 2 - 5, self.text)


class IconBox(Flowable):
    """Small icon + label pill."""
    def __init__(self, icon, text, bg, fg=white, width=180, height=22):
        super().__init__()
        self.icon = icon
        self.text = text
        self.bg = bg
        self.fg = fg
        self.bw = width
        self.bh = height

    def wrap(self, aw, ah):
        return self.bw, self.bh

    def draw(self):
        c = self.canv
        c.setFillColor(self.bg)
        c.roundRect(0, 0, self.bw, self.bh, 5, fill=1, stroke=0)
        c.setFillColor(self.fg)
        c.setFont("Helvetica-Bold", 9)
        c.drawString(8, self.bh / 2 - 4, f"{self.icon}  {self.text}")


def box_para(text, bg, border_color=None, pad=8, style=None):
    st = style or sBody
    bc = border_color or bg
    data = [[Paragraph(text, st)]]
    t = Table(data, colWidths=[BODY_W - 2])
    t.setStyle(TableStyle([
        ("BACKGROUND", (0,0), (-1,-1), bg),
        ("BOX",        (0,0), (-1,-1), 0.8, bc),
        ("LEFTPADDING",  (0,0), (-1,-1), pad),
        ("RIGHTPADDING", (0,0), (-1,-1), pad),
        ("TOPPADDING",   (0,0), (-1,-1), pad),
        ("BOTTOMPADDING",(0,0), (-1,-1), pad),
        ("ROUNDEDCORNERS", (0,0), (-1,-1), [4,4,4,4]),
    ]))
    return t


def two_col(left_items, right_items, left_bg, right_bg, lw=0.5):
    """Two-column table from lists of flowables."""
    LW = BODY_W * lw - 3
    RW = BODY_W * (1-lw) - 3
    data = [[left_items, right_items]]
    t = Table(data, colWidths=[LW, RW])
    t.setStyle(TableStyle([
        ("BACKGROUND",   (0,0),(0,-1), left_bg),
        ("BACKGROUND",   (1,0),(1,-1), right_bg),
        ("VALIGN",       (0,0),(-1,-1), "TOP"),
        ("LEFTPADDING",  (0,0),(-1,-1), 8),
        ("RIGHTPADDING", (0,0),(-1,-1), 8),
        ("TOPPADDING",   (0,0),(-1,-1), 8),
        ("BOTTOMPADDING",(0,0),(-1,-1), 8),
        ("BOX",          (0,0),(-1,-1), 0.5, C_BORDER),
        ("INNERGRID",    (0,0),(-1,-1), 0.5, C_BORDER),
    ]))
    return t


def std_table(headers, rows, col_widths=None, header_bg=C_DARK_BLUE):
    cw = col_widths or [BODY_W / len(headers)] * len(headers)
    header_row = [Paragraph(h, sTableHeader) for h in headers]
    body_rows  = [[Paragraph(str(c), sTableCell) for c in row] for row in rows]
    all_rows   = [header_row] + body_rows
    t = Table(all_rows, colWidths=cw, repeatRows=1)
    style = [
        ("BACKGROUND",   (0,0),(-1, 0), header_bg),
        ("ROWBACKGROUNDS",(0,1),(-1,-1),[white, C_LIGHT_GRAY]),
        ("TEXTCOLOR",    (0,0),(-1, 0), white),
        ("FONTNAME",     (0,0),(-1, 0), "Helvetica-Bold"),
        ("FONTSIZE",     (0,0),(-1,-1), 8.5),
        ("GRID",         (0,0),(-1,-1), 0.4, C_BORDER),
        ("VALIGN",       (0,0),(-1,-1), "MIDDLE"),
        ("TOPPADDING",   (0,0),(-1,-1), 5),
        ("BOTTOMPADDING",(0,0),(-1,-1), 5),
        ("LEFTPADDING",  (0,0),(-1,-1), 6),
        ("RIGHTPADDING", (0,0),(-1,-1), 6),
    ]
    t.setStyle(TableStyle(style))
    return t


def mnemonic_box(title, body_lines, width=None):
    bw = width or BODY_W
    items = [Paragraph(f"🧠  {title}", sMnemonic)]
    for line in body_lines:
        items.append(Paragraph(f"    {line}", sMnemonicBody))
    data = [[items]]
    t = Table([[items]], colWidths=[bw - 2])
    t.setStyle(TableStyle([
        ("BACKGROUND",   (0,0),(-1,-1), C_LIGHT_PURPLE),
        ("BOX",          (0,0),(-1,-1), 1.0, C_PURPLE),
        ("LEFTPADDING",  (0,0),(-1,-1), 10),
        ("RIGHTPADDING", (0,0),(-1,-1), 10),
        ("TOPPADDING",   (0,0),(-1,-1), 8),
        ("BOTTOMPADDING",(0,0),(-1,-1), 8),
        ("ROUNDEDCORNERS",(0,0),(-1,-1),[5,5,5,5]),
    ]))
    return t


def clinical_pearl(text):
    data = [[Paragraph(f"🩺  CLINICAL PEARL:  {text}", sClinical)]]
    t = Table(data, colWidths=[BODY_W - 2])
    t.setStyle(TableStyle([
        ("BACKGROUND",   (0,0),(-1,-1), C_LIGHT_RED),
        ("BOX",          (0,0),(-1,-1), 1.0, C_RED),
        ("LEFTPADDING",  (0,0),(-1,-1), 10),
        ("RIGHTPADDING", (0,0),(-1,-1), 10),
        ("TOPPADDING",   (0,0),(-1,-1), 6),
        ("BOTTOMPADDING",(0,0),(-1,-1), 6),
    ]))
    return t


def sp(n=6):
    return Spacer(1, n)


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


# ── Cover Page ────────────────────────────────────────────────────────────────
def cover_page(story):
    # Blue cover banner
    cover = Table(
        [[Paragraph("MUSCULOSKELETAL SYSTEM", sTitle)],
         [Paragraph("Complete Clinical Learning Series", sSubtitle)],
         [Spacer(1, 10)],
         [Paragraph("CHUNK 1", ParagraphStyle("big", parent=sTitle, fontSize=38,
                    textColor=C_YELLOW, leading=44))],
         [Paragraph("EMBRYOLOGY", ParagraphStyle("big2", parent=sTitle, fontSize=22,
                    textColor=white, leading=28))],
         [Spacer(1, 6)],
         [Paragraph("From First Principles to Clinical Correlations", sSubtitle)],
        ],
        colWidths=[BODY_W]
    )
    cover.setStyle(TableStyle([
        ("BACKGROUND",   (0,0),(-1,-1), C_DARK_BLUE),
        ("TOPPADDING",   (0,0),(-1,-1), 18),
        ("BOTTOMPADDING",(0,0),(-1,-1), 18),
        ("LEFTPADDING",  (0,0),(-1,-1), 20),
        ("RIGHTPADDING", (0,0),(-1,-1), 20),
        ("ROUNDEDCORNERS",(0,0),(-1,-1),[8,8,8,8]),
    ]))
    story.append(cover)
    story.append(sp(14))

    # Info boxes row
    info = [
        ["📚  Sources", "Langman's Embryology\nThe Developing Human (Moore)\nGeneral Anatomy – THIEME Atlas"],
        ["🎯  Learning\nObjectives", "Understand limb bud formation\nOssification types & growth plate\nCongenital MSK anomalies\nKey molecular signals"],
        ["🏥  Clinical\nRelevance", "Salter-Harris fractures\nAchondroplasia, OI, DDH\nThalidomide embryopathy\nSpina bifida, Clubfoot"],
    ]
    rows = []
    for label, content in info:
        rows.append([
            Paragraph(label, ParagraphStyle("infoL", parent=sBody, fontName="Helvetica-Bold",
                      fontSize=9.5, textColor=C_DARK_BLUE)),
            Paragraph(content.replace("\n","<br/>"), sBody)
        ])
    t = Table(rows, colWidths=[BODY_W*0.28, BODY_W*0.72])
    t.setStyle(TableStyle([
        ("ROWBACKGROUNDS",(0,0),(-1,-1),[C_LIGHT_BLUE, white]),
        ("BOX",          (0,0),(-1,-1), 0.8, C_MED_BLUE),
        ("INNERGRID",    (0,0),(-1,-1), 0.4, C_BORDER),
        ("LEFTPADDING",  (0,0),(-1,-1), 8),
        ("RIGHTPADDING", (0,0),(-1,-1), 8),
        ("TOPPADDING",   (0,0),(-1,-1), 6),
        ("BOTTOMPADDING",(0,0),(-1,-1), 6),
        ("VALIGN",       (0,0),(-1,-1), "TOP"),
    ]))
    story.append(t)
    story.append(sp(14))

    # Chunk roadmap
    story.append(SectionHeader("📋  COMPLETE MSK SERIES — CHUNK ROADMAP", C_TEAL))
    story.append(sp(6))
    chunks = [
        ("01", "Embryology", "★ THIS CHUNK", C_DARK_BLUE),
        ("02", "Bone — Structure, Histology & Physiology", "", C_TEAL),
        ("03", "Muscle — Types, Structure & Physiology", "", C_TEAL),
        ("04", "Joints — Classification & Biomechanics", "", C_TEAL),
        ("05", "Clinical Examination (GALS + Regional)", "", C_MED_BLUE),
        ("06", "Fractures — Types, Healing, Management", "", C_MED_BLUE),
        ("07", "Joint Diseases — OA, RA, Gout, Septic", "", C_MED_BLUE),
        ("08", "Bone Diseases — Osteoporosis, Paget's, Rickets", "", C_MED_BLUE),
        ("09", "Muscle Diseases — Myopathies, Dystrophies", "", C_ORANGE),
        ("10", "Spine — Back Pain, Disc, Scoliosis", "", C_ORANGE),
        ("11", "Tumors of MSK System", "", C_ORANGE),
        ("12", "Homeopathic Management", "", C_PURPLE),
    ]
    rdata = []
    for num, title, note, col in chunks:
        bg = C_LIGHT_BLUE if note else white
        rdata.append([
            Paragraph(f"<b>{num}</b>", ParagraphStyle("cn", parent=sTableCellC,
                      textColor=white, fontName="Helvetica-Bold", alignment=TA_CENTER)),
            Paragraph(title, sTableCell),
            Paragraph(f"<b>{note}</b>" if note else "", ParagraphStyle("cnn",
                      parent=sTableCell, textColor=C_RED, fontName="Helvetica-Bold")),
        ])
    ct = Table(rdata, colWidths=[BODY_W*0.1, BODY_W*0.7, BODY_W*0.2])
    cstyle = [
        ("BACKGROUND",   (0,0),(0,-1), C_DARK_BLUE),
        ("ROWBACKGROUNDS",(1,0),(1,-1),[C_LIGHT_BLUE, white]),
        ("ROWBACKGROUNDS",(0,0),(0,-1),[C_DARK_BLUE]),
        ("GRID",         (0,0),(-1,-1), 0.4, C_BORDER),
        ("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),
    ]
    # highlight chunk 1
    cstyle.append(("BACKGROUND",(1,0),(1,0), C_LIGHT_BLUE))
    cstyle.append(("BACKGROUND",(2,0),(2,0), C_LIGHT_BLUE))
    ct.setStyle(TableStyle(cstyle))
    story.append(ct)
    story.append(PageBreak())


# ── Page header/footer callback ───────────────────────────────────────────────
def on_page(canvas, doc):
    canvas.saveState()
    # Header bar
    canvas.setFillColor(C_DARK_BLUE)
    canvas.rect(1.8*cm, H - 1.6*cm, W - 3.6*cm, 0.7*cm, fill=1, stroke=0)
    canvas.setFillColor(white)
    canvas.setFont("Helvetica-Bold", 8)
    canvas.drawString(2.1*cm, H - 1.25*cm, "MSK SYSTEM  |  CHUNK 1: EMBRYOLOGY")
    canvas.setFont("Helvetica", 8)
    canvas.drawRightString(W - 1.9*cm, H - 1.25*cm, "Orris Medical Education  |  2026")
    # Footer
    canvas.setFillColor(C_GRAY)
    canvas.setFont("Helvetica", 7.5)
    canvas.drawCentredString(W/2, 1.2*cm, f"Page {doc.page}")
    canvas.setFillColor(C_MED_BLUE)
    canvas.rect(1.8*cm, 1.55*cm, W - 3.6*cm, 0.03*cm, fill=1, stroke=0)
    canvas.restoreState()


# ── Build Story ───────────────────────────────────────────────────────────────
story = []
cover_page(story)

# ═══════════════════════════════════════════════════════════════════════════════
# SECTION 1 — OVERVIEW
# ═══════════════════════════════════════════════════════════════════════════════
story.append(SectionHeader("1.  OVERVIEW — ORIGINS OF THE MSK SYSTEM", C_DARK_BLUE))
story.append(sp(8))

story.append(Paragraph(
    "The musculoskeletal system arises from <b>three distinct embryonic germ-layer derivatives</b>. "
    "Understanding these origins explains why different MSK conditions have different "
    "genetic, structural, and clinical profiles.",
    sBody))
story.append(sp(8))

origins = [
    ["Source", "Structures Formed", "Key Pathology if Disrupted"],
    ["Lateral Plate Mesoderm\n(Somatic layer)", "Bones & connective tissue of limbs\n(appendicular skeleton)\nPeriosteum, tendons, ligaments", "Phocomelia, amelia\nLimb reduction defects"],
    ["Paraxial Mesoderm\n(Somites)", "Axial skeleton: vertebrae, ribs, sternum\nAll skeletal muscles\nDermis of back", "Scoliosis, hemivertebra\nMuscular dystrophies"],
    ["Neural Crest Cells", "Craniofacial bones & cartilage\nMandible, maxilla, nasal bones\nOdontoblasts (teeth)", "Craniofacial clefts\nPierre Robin sequence\nTreacher Collins"],
]
story.append(std_table(
    origins[0], origins[1:],
    col_widths=[BODY_W*0.28, BODY_W*0.42, BODY_W*0.30],
    header_bg=C_DARK_BLUE
))
story.append(sp(8))

story.append(mnemonic_box(
    "MNEMONIC — Origins of MSK",
    ['"LIMB From Lateral, MUSCLES From sOMITES, FACE From cREST"',
     "Lateral plate → Limb bones",
     "soMITEs        → Muscles + axIal skeleToN",
     "neural CREST   → CRaniofacial boNes"]
))
story.append(sp(10))

# ═══════════════════════════════════════════════════════════════════════════════
# SECTION 2 — TIMELINE
# ═══════════════════════════════════════════════════════════════════════════════
story.append(SectionHeader("2.  DEVELOPMENTAL TIMELINE", C_TEAL))
story.append(sp(8))

timeline_data = [
    ["Week", "Event", "Clinical Significance"],
    ["Week 4\n(Day 24–28)", "Upper limb buds appear (Day 24)\nLower limb buds appear (Day 26–28)\nAER begins forming", "Thalidomide most damaging\nin Weeks 4–6"],
    ["Week 5", "AER fully established\nChondrification begins\nProgress zone active", "FGF, SHH, WNT signals\ncritical here"],
    ["Week 6", "Hand & footplates form\nEntire limb skeleton is cartilaginous\nDigital rays appear", "Polydactyly / syndactyly\norigins at this stage"],
    ["Week 7", "Primary ossification centers appear\nInterdigital apoptosis begins\nLimb rotation occurs\nMuscle mass divides (dorsal/ventral)", "Salter-Harris injuries\naffect this growth plate"],
    ["Week 8", "Fingers and toes fully separated\nJoint cavities forming", "Digits recognisable\non ultrasound"],
    ["Week 12", "Ossification centers in ALL long bones", "Prenatal US can detect\nshortened limbs (e.g. achondroplasia)"],
    ["Birth →\nChildhood", "Secondary ossification centers appear\n(epiphyses)", "Avascular necrosis risk\nin Perthes disease"],
]
story.append(std_table(
    timeline_data[0], timeline_data[1:],
    col_widths=[BODY_W*0.18, BODY_W*0.48, BODY_W*0.34],
    header_bg=C_TEAL
))
story.append(sp(8))

story.append(mnemonic_box(
    "TIMELINE MNEMONIC — \"Always Come Look For Wonderful Bones\"",
    ["A — AER forms (Week 4–5)",
     "C — Chondrification (Week 5)",
     "L — Limb rotation (Week 7)",
     "F — Fingers separate (Week 8)",
     "W — Wrist/ankle ossify (Week 7–12)",
     "B — Birth (secondary ossification centers)"]
))
story.append(sp(10))

# ═══════════════════════════════════════════════════════════════════════════════
# SECTION 3 — SOMITES
# ═══════════════════════════════════════════════════════════════════════════════
story.append(SectionHeader("3.  SOMITE FORMATION & THE AXIAL SKELETON", C_DARK_BLUE))
story.append(sp(8))

story.append(Paragraph(
    "<b>Somites</b> are paired blocks of paraxial mesoderm that appear alongside the notochord "
    "from the cranial end downward. By week 5, approximately <b>42–44 pairs</b> of somites are present. "
    "Each somite differentiates into three compartments:",
    sBody))
story.append(sp(8))

# Somite diagram table
somite_diag = Table(
    [[Paragraph("<b>SOMITE</b>", ParagraphStyle("sd", parent=sBody, alignment=TA_CENTER,
               fontName="Helvetica-Bold", textColor=C_DARK_BLUE, fontSize=11))],
     [Table(
         [[Paragraph("<b>DERMATOME</b>", ParagraphStyle("d1", parent=sBody, alignment=TA_CENTER,
                     fontName="Helvetica-Bold", textColor=white)),
           Paragraph("<b>MYOTOME</b>", ParagraphStyle("d2", parent=sBody, alignment=TA_CENTER,
                     fontName="Helvetica-Bold", textColor=white)),
           Paragraph("<b>SCLEROTOME</b>", ParagraphStyle("d3", parent=sBody, alignment=TA_CENTER,
                     fontName="Helvetica-Bold", textColor=white))],
          [Paragraph("→ Dermis\nof back", sTableCellC),
           Paragraph("→ Skeletal\nmuscles", sTableCellC),
           Paragraph("→ Vertebrae\n& Ribs", sTableCellC)],
         ],
         colWidths=[BODY_W*0.28, BODY_W*0.28, BODY_W*0.28]
     )]
    ],
    colWidths=[BODY_W*0.88]
)
somite_diag.setStyle(TableStyle([
    ("BACKGROUND", (0,0),(-1,0), C_LIGHT_BLUE),
    ("BOX",        (0,0),(-1,-1), 1, C_MED_BLUE),
    ("TOPPADDING", (0,0),(-1,-1), 6),
    ("BOTTOMPADDING",(0,0),(-1,-1), 6),
]))

inner = somite_diag._cellvalues[1][0]
inner.setStyle(TableStyle([
    ("BACKGROUND",  (0,0),(0,-1), HexColor("#2e6da4")),
    ("BACKGROUND",  (1,0),(1,-1), HexColor("#1a7a6e")),
    ("BACKGROUND",  (2,0),(2,-1), HexColor("#c0550a")),
    ("GRID",        (0,0),(-1,-1), 0.5, white),
    ("TOPPADDING",  (0,0),(-1,-1), 5),
    ("BOTTOMPADDING",(0,0),(-1,-1), 5),
    ("TEXTCOLOR",   (0,1),(-1,-1), HexColor("#111111")),
    ("BACKGROUND",  (0,1),(0,1), C_LIGHT_BLUE),
    ("BACKGROUND",  (1,1),(1,1), C_LIGHT_TEAL),
    ("BACKGROUND",  (2,1),(2,1), C_LIGHT_ORANGE),
]))
story.append(somite_diag)
story.append(sp(6))

story.append(mnemonic_box(
    "MNEMONIC — Somite Compartments: \"D-M-S = Dermis, Muscles, Skeleton\"",
    ["D = Dermatome → Dermis of the back",
     "M = Myotome   → Muscles (all skeletal muscles of trunk & limbs)",
     "S = Sclerotome → Skeleton (vertebrae, ribs, skull base)"]
))
story.append(sp(8))

story.append(Paragraph("<b>Vertebral Re-segmentation (CRITICAL CONCEPT):</b>", sH3))
story.append(Paragraph(
    "Each vertebra is NOT formed from one somite. Instead, each vertebra forms from the "
    "<b>caudal half of one somite + cranial half of the next somite</b>. "
    "This re-segmentation explains why spinal nerves exit <b>BELOW</b> their corresponding vertebra — "
    "because the nerve grows through the cranial half of the original somite, which becomes "
    "the caudal part of the vertebra above.",
    sBody))
story.append(sp(6))

reseg = Table(
    [[Paragraph("Somite N", sTableCellC), Paragraph("Cranial ½", sTableCellC), Paragraph("Caudal ½", sTableCellC)],
     [Paragraph("Somite N+1", sTableCellC), Paragraph("Cranial ½", sTableCellC), Paragraph("Caudal ½", sTableCellC)],
     [Paragraph("→ Vertebra formed", ParagraphStyle("rv", parent=sTableCellC, fontName="Helvetica-Bold",
               textColor=C_DARK_BLUE)), Paragraph("Caudal(N) +", sTableCellC), Paragraph("Cranial(N+1)", sTableCellC)],
    ],
    colWidths=[BODY_W*0.33]*3
)
reseg.setStyle(TableStyle([
    ("BACKGROUND",  (0,0),(0,1), C_LIGHT_BLUE),
    ("BACKGROUND",  (1,0),(-1,0), C_LIGHT_TEAL),
    ("BACKGROUND",  (1,1),(-1,1), C_LIGHT_ORANGE),
    ("BACKGROUND",  (0,2),(-1,2), HexColor("#fff3e0")),
    ("GRID",        (0,0),(-1,-1), 0.5, C_BORDER),
    ("TOPPADDING",  (0,0),(-1,-1), 5),
    ("BOTTOMPADDING",(0,0),(-1,-1), 5),
    ("FONTNAME",    (0,2),(0,2), "Helvetica-Bold"),
    ("ALIGN",       (0,0),(-1,-1), "CENTER"),
]))
story.append(reseg)
story.append(sp(6))

story.append(clinical_pearl(
    "Spina bifida = failure of posterior vertebral arch fusion + often failure of "
    "neural tube closure. Most common at L5–S1. Prevented by folic acid 400 µg/day "
    "preconceptionally. Folic acid deficiency → failure of neural tube closure → "
    "myelomeningocele."
))
story.append(sp(10))

# ═══════════════════════════════════════════════════════════════════════════════
# SECTION 4 — LIMB BUD DEVELOPMENT
# ═══════════════════════════════════════════════════════════════════════════════
story.append(SectionHeader("4.  LIMB BUD DEVELOPMENT", C_DARK_BLUE))
story.append(sp(8))

story.append(Paragraph(
    "Limb buds form at day 24 (upper) and day 26 (lower) as outpocketings of the "
    "<b>lateral body wall</b> driven by FGF10 from the lateral plate mesoderm. "
    "Each limb bud has a mesenchymal core covered by ectoderm, with a specialised "
    "thickened rim called the <b>Apical Ectodermal Ridge (AER)</b>.",
    sBody))
story.append(sp(8))

# Three axes table
story.append(Paragraph("<b>The 3 Axes of Limb Patterning</b>", sH3))

axes_data = [
    ["Axis", "Signal Molecule", "Source", "Function", "Mnemonic"],
    ["Proximodistal\n(Shoulder → Fingers)", "FGF-4, FGF-8", "AER\n(Apical Ectodermal Ridge)", "Drives outgrowth;\nProximal = early, Distal = late", "F = Far out\n(Proximodistal)"],
    ["Anteroposterior\n(Thumb → Little finger)", "SHH\n(Sonic Hedgehog)", "ZPA\n(Zone of Polarizing Activity)\n— Posterior border", "Specifies digit identity;\nMore SHH = posterior digit", "S = Side-to-side\n(SHH)"],
    ["Dorsoventral\n(Dorsum → Palm)", "WNT7a\n→ LMX1", "Dorsal ectoderm", "Dorsal (nail/extensors)\nvs. ventral (palm/flexors)", "W = Which side\n(WNT)"],
]
story.append(std_table(
    axes_data[0], axes_data[1:],
    col_widths=[BODY_W*0.22, BODY_W*0.16, BODY_W*0.24, BODY_W*0.24, BODY_W*0.14],
    header_bg=C_MED_BLUE
))
story.append(sp(8))

story.append(mnemonic_box(
    "MNEMONIC — 3 Axes: \"FWS\"",
    ["F = FGF → proximoDistal (Far-to-near, think F = Far)",
     "W = WNT → dorsoVentral (W = Which side is up?)",
     "S = SHH → Anteroposteriор (S = Side-to-side, Sonic)"]
))
story.append(sp(8))

# Segment table
story.append(Paragraph("<b>The 3 Limb Segments (Stylopod–Zeugopod–Autopod)</b>", sH3))
seg_data = [
    ["Segment", "Upper Limb", "Lower Limb", "Mnemonic"],
    ["STYLOPOD\n(proximal)", "Humerus", "Femur", "STY = STock\n(one bone)"],
    ["ZEUGOPOD\n(middle)", "Radius + Ulna", "Tibia + Fibula", "ZEU = TWo\n(two bones)"],
    ["AUTOPOD\n(distal)", "Carpals + Metacarpals\n+ Phalanges", "Tarsals + Metatarsals\n+ Phalanges", "AUTO = mAny\n(many bones)"],
]
story.append(std_table(
    seg_data[0], seg_data[1:],
    col_widths=[BODY_W*0.22, BODY_W*0.22, BODY_W*0.22, BODY_W*0.34],
    header_bg=C_TEAL
))
story.append(sp(6))

story.append(mnemonic_box(
    "MNEMONIC — Segments: \"SZA = Some Zebras Are Amazingly fast\"",
    ["S = Stylopod (1 bone)", "Z = Zeugopod (2 bones)", "A = Autopod (many)"]
))
story.append(sp(8))

# Limb rotation
story.append(Paragraph("<b>Limb Rotation (Week 7)</b>", sH3))
story.append(Paragraph(
    "Originally, both limbs project <b>ventrally</b> with the flexor surface facing anteriorly. "
    "During week 7, the limbs rotate in <b>opposite directions</b>:",
    sBody))
story.append(sp(4))

rot_data = [
    ["Feature", "Upper Limb", "Lower Limb"],
    ["Direction of rotation", "Laterally (90°)", "Medially (90°)"],
    ["Preaxial border", "Thumb side (radial)", "Big toe side (tibial)"],
    ["Postaxial border", "Little finger (ulnar)", "Little toe (fibular)"],
    ["Elbow position", "Points posteriorly", "—"],
    ["Knee position", "—", "Points anteriorly"],
    ["Result", "Palm faces anteriorly\n(anatomical position)", "Sole faces posteriorly"],
]
story.append(std_table(
    rot_data[0], rot_data[1:],
    col_widths=[BODY_W*0.30, BODY_W*0.35, BODY_W*0.35],
    header_bg=C_ORANGE
))
story.append(sp(6))

story.append(clinical_pearl(
    "Because the upper limb rotates LATERALLY and the lower limb rotates MEDIALLY — "
    "the knee flexes anteriorly and the elbow flexes posteriorly. "
    "This explains the different orientation of dermatomes on upper vs lower limbs."
))
story.append(sp(10))

# ═══════════════════════════════════════════════════════════════════════════════
# SECTION 5 — OSSIFICATION
# ═══════════════════════════════════════════════════════════════════════════════
story.append(PageBreak())
story.append(SectionHeader("5.  OSSIFICATION — TYPES & GROWTH PLATE", C_DARK_BLUE))
story.append(sp(8))

story.append(Paragraph(
    "Bone forms by two distinct processes. The type of ossification depends on "
    "whether a <b>cartilage model (template)</b> is first laid down or not.",
    sBody))
story.append(sp(8))

# Two-col comparison
endo_items = [
    Paragraph("<b>ENDOCHONDRAL OSSIFICATION</b>", ParagraphStyle("eh", parent=sH3, textColor=C_DARK_BLUE)),
    Paragraph("• Cartilage model formed first", sBullet),
    Paragraph("• Bones: long bones, vertebrae, ribs, base of skull", sBullet),
    Paragraph("• Begins: Week 7 (primary center in diaphysis)", sBullet),
    Paragraph("• Sequence: Cartilage → Calcify → Vascular invasion → Bone", sBullet),
    Spacer(1,4),
    Paragraph("<b>Think: E = Extremities (long bones)</b>",
              ParagraphStyle("ep", parent=sBullet, textColor=C_MED_BLUE, fontName="Helvetica-Bold")),
]
intramem_items = [
    Paragraph("<b>INTRAMEMBRANOUS OSSIFICATION</b>", ParagraphStyle("ih", parent=sH3, textColor=C_TEAL)),
    Paragraph("• No cartilage model — direct from mesenchyme", sBullet),
    Paragraph("• Bones: flat bones of skull, clavicle, mandible, scapula", sBullet),
    Paragraph("• Mesenchymal cells → osteoblasts → osteoid → bone", sBullet),
    Paragraph("• Fontanelles = areas of incomplete intramembranous ossification", sBullet),
    Spacer(1,4),
    Paragraph("<b>Think: I = Inside the head (flat skull bones)</b>",
              ParagraphStyle("ip", parent=sBullet, textColor=C_TEAL, fontName="Helvetica-Bold")),
]
story.append(two_col(endo_items, intramem_items, C_LIGHT_BLUE, C_LIGHT_TEAL))
story.append(sp(8))

# Growth plate zones
story.append(Paragraph("<b>Zones of the Epiphyseal Growth Plate (Physis)</b>", sH3))
story.append(Paragraph(
    "The growth plate is organized into 5 zones from the epiphysis toward the diaphysis:",
    sBody))
story.append(sp(6))

zone_data = [
    ["Zone", "What Happens", "Key Pathology"],
    ["1. RESTING\n(Reserve)", "Chondrocytes at rest; nutrient storage; stem cell-like\npopulation", "Morquio syndrome\naffects this zone"],
    ["2. PROLIFERATIVE", "Rapid mitosis → columns of flattened chondrocytes\n(\"stack of coins\")\nMost active growth occurs here", "Achondroplasia = ↓\nproliferation"],
    ["3. HYPERTROPHIC", "Chondrocytes enlarge (×5); secrete VEGF;\nMatrix mineralization begins\nWeakest zone (Salter-Harris II–V)", "Most fractures through\nthis zone"],
    ["4. CALCIFICATION\n(Provisional)", "Calcium deposited in matrix;\nchondrocytes die by apoptosis", "Rickets = ↑ width\nfailure to calcify"],
    ["5. OSSIFICATION\n(Primary spongiosa)", "Blood vessels invade; osteoblasts deposit bone\non calcified cartilage spicules", "Osteomyelitis starts\nhere (slow blood flow)"],
]
story.append(std_table(
    zone_data[0], zone_data[1:],
    col_widths=[BODY_W*0.22, BODY_W*0.48, BODY_W*0.30],
    header_bg=C_DARK_BLUE
))
story.append(sp(8))

story.append(mnemonic_box(
    "MNEMONIC — Growth Plate Zones: \"RPHCO\"",
    ["R = Resting (Reserve)",
     "P = Proliferative",
     "H = Hypertrophic",
     "C = Calcification",
     "O = Ossification",
     '"Real Physicians Have Chosen Orthopaedics"']
))
story.append(sp(6))

story.append(clinical_pearl(
    "The HYPERTROPHIC zone is the weakest zone of the growth plate. "
    "Salter-Harris fractures (Types II–V) typically occur here. "
    "Type I (through physis) and Type II (through physis + metaphysis) are most common. "
    "Type V (crush) = worst prognosis — damages reserve/proliferative zone → growth arrest."
))
story.append(sp(8))

# Primary vs Secondary centers
story.append(Paragraph("<b>Primary vs. Secondary Ossification Centers</b>", sH3))
pso_data = [
    ["Feature", "PRIMARY Center", "SECONDARY Center"],
    ["Location", "Diaphysis (shaft)", "Epiphysis (ends)"],
    ["Timing", "Week 7 prenatal", "Birth → early childhood\n(variable per bone)"],
    ["Growth plate", "Between primary & secondary centers", "—"],
    ["Closure", "After puberty (sex hormones)", "—"],
    ["Exception", "Clavicle = first to ossify (primary)\nby intramembranous ossification", "Femoral head = first\nsecondary center (4 months)"],
]
story.append(std_table(
    pso_data[0], pso_data[1:],
    col_widths=[BODY_W*0.25, BODY_W*0.375, BODY_W*0.375],
    header_bg=C_MED_BLUE
))
story.append(sp(10))

# ═══════════════════════════════════════════════════════════════════════════════
# SECTION 6 — MUSCLE DEVELOPMENT
# ═══════════════════════════════════════════════════════════════════════════════
story.append(SectionHeader("6.  MUSCLE DEVELOPMENT", C_TEAL))
story.append(sp(8))

story.append(Paragraph(
    "Skeletal muscles originate from <b>myotomes</b> of the somites. "
    "Myogenic precursor cells (MPCs) migrate via the <b>c-Met receptor</b> (encoded by the MET gene) "
    "into the limb buds. There, they differentiate under the control of "
    "<b>Myogenic Regulatory Factors (MRFs)</b>.",
    sBody))
story.append(sp(8))

mrf_data = [
    ["MRF Gene", "Function", "Mnemonic"],
    ["MYF5", "Early specification of muscle progenitors", "My = My first step"],
    ["MyoD", "Commitment to muscle lineage (master regulator)", "D = Decision/Determine"],
    ["MYOGENIN", "Terminal differentiation of myoblasts", "G = Go differentiate"],
    ["MRF4", "Maturation of muscle fibers", "4 = Final/Finish"],
]
story.append(std_table(
    mrf_data[0], mrf_data[1:],
    col_widths=[BODY_W*0.18, BODY_W*0.52, BODY_W*0.30],
    header_bg=C_TEAL
))
story.append(sp(6))

story.append(mnemonic_box(
    "MNEMONIC — MRFs: \"My Dog Makes Muscle\"",
    ["My = MYF5 (first gene expressed)",
     "Dog = MyoD (master regulator — commitment)",
     "Makes = Myogenin (differentiation)",
     "Muscle = MRF4 (maturation)"]
))
story.append(sp(8))

story.append(Paragraph("<b>Dorsal vs. Ventral Muscle Masses</b>", sH3))
story.append(Paragraph(
    "After migrating into the limb bud, myoblasts form a <b>single large muscle mass</b> "
    "that separates into dorsal and ventral components:",
    sBody))
story.append(sp(4))

dv_data = [
    ["Mass", "Muscles Formed", "Nerve Supply"],
    ["DORSAL mass", "EXTENSORS (e.g., triceps, quadriceps,\nextensor digitorum)", "Posterior division of plexus\n(radial n., femoral n.)"],
    ["VENTRAL mass", "FLEXORS (e.g., biceps, brachialis,\nhamstrings, calf muscles)", "Anterior division of plexus\n(musculocutaneous, tibial n.)"],
]
story.append(std_table(
    dv_data[0], dv_data[1:],
    col_widths=[BODY_W*0.18, BODY_W*0.46, BODY_W*0.36],
    header_bg=C_ORANGE
))
story.append(sp(6))

story.append(clinical_pearl(
    "Muscles derived from the DORSAL mass are supplied by POSTERIOR divisions of the plexus. "
    "Muscles from VENTRAL mass → ANTERIOR divisions. "
    "This explains brachial plexus injury patterns: upper trunk injury (Erb's palsy, C5-C6) → "
    "waiter's tip position; lower trunk injury (Klumpke's palsy, C8-T1) → claw hand."
))
story.append(sp(10))

# ═══════════════════════════════════════════════════════════════════════════════
# SECTION 7 — JOINT DEVELOPMENT
# ═══════════════════════════════════════════════════════════════════════════════
story.append(SectionHeader("7.  JOINT DEVELOPMENT", C_DARK_BLUE))
story.append(sp(8))

story.append(Paragraph(
    "Joints develop within regions of concentrated mesenchyme called <b>interzones</b> "
    "that appear between the cartilaginous bone models around week 6. "
    "The type of joint formed depends on what happens to this interzone:",
    sBody))
story.append(sp(6))

jt_data = [
    ["Joint Type", "Interzone Fate", "Signals", "Example"],
    ["FIBROUS\n(e.g., skull sutures)", "Mesenchyme persists\nas dense fibrous tissue", "—", "Sagittal suture,\ntibio-fibular syndesmosis"],
    ["CARTILAGINOUS\n(e.g., pubic symphysis)", "Cartilage persists\n(fibrocartilage)", "—", "Pubic symphysis,\nintervertebral discs"],
    ["SYNOVIAL\n(e.g., knee, hip)", "Central apoptosis\n→ joint cavity forms;\nPeripheral → synovial membrane", "WNT, BMP, IHH,\nGDF5, TGF-β", "Hip, knee, shoulder,\nelbow, wrist"],
]
story.append(std_table(
    jt_data[0], jt_data[1:],
    col_widths=[BODY_W*0.22, BODY_W*0.26, BODY_W*0.24, BODY_W*0.28],
    header_bg=C_MED_BLUE
))
story.append(sp(6))

story.append(clinical_pearl(
    "GDF5 (Growth Differentiation Factor 5) mutations cause brachydactyly type C and "
    "Grebe chondrodysplasia — because GDF5 is critical for joint formation in the digits. "
    "WNT signaling maintains joint cavity; disruption → joint fusion (synostosis)."
))
story.append(sp(10))

# ═══════════════════════════════════════════════════════════════════════════════
# SECTION 8 — CONGENITAL ANOMALIES
# ═══════════════════════════════════════════════════════════════════════════════
story.append(PageBreak())
story.append(SectionHeader("8.  CONGENITAL ANOMALIES OF THE MSK SYSTEM", C_RED))
story.append(sp(8))

anom_data = [
    ["Condition", "Embryological Defect", "Key Clinical Features", "Tx / Notes"],
    ["AMELIA", "AER completely absent →\nno limb outgrowth", "Complete absence of one\nor more limbs", "Prosthetics"],
    ["PHOCOMELIA", "AER disrupted early\n(Wks 4–6) → stylopod &\nzeugopod absent", "Hands/feet attached\ndirectly to trunk\n(\"flipper limb\")", "Thalidomide embryopathy;\n1950s–60s tragedy"],
    ["ECTRODACTYLY\n(Split hand/foot)", "AER splits → two\nseparate ridges", "\"Lobster claw\" hand;\nmissing central digits", "Surgical correction;\nEEC syndrome"],
    ["SYNDACTYLY", "Failure of interdigital\napoptosis", "Webbing between fingers;\nmost common: 3rd–4th\nwebspace", "Most common limb\ndefect; AD inheritance\npossible"],
    ["POLYDACTYLY", "Excess SHH from ZPA →\nextra digit formation", "Extra digit(s); most\ncommon: postaxial\n(little finger side)", "Simple excision;\nassoc. with syndromes"],
    ["CLUBFOOT\n(CTEV)", "Multifactorial;\ngenetic + positional", "CAVE: Cavus, Adductus,\nVarus, Equinus\nM > F; bilateral 50%", "Ponseti method\n(serial casting +\ntenotomy)"],
    ["DDH\n(Dev. Dysplasia\nof Hip)", "Shallow acetabulum;\nlax capsule (hormones,\npositioning)", "F > M (6:1); positive\nOrtolani & Barlow;\nleg length discrepancy", "< 6 months: Pavlik\nharness; > 18 months:\nopen reduction"],
    ["ACHONDRO-\nPLASIA", "FGFR3 gain-of-function\nmutation → ↓ cartilage\nproliferation", "Rhizomelic dwarfism;\nnormal trunk length;\nmacrocephaly;\ntransverse narrowing", "AD; 80% de novo\nmutation; FGFR3 inhib.\n(vosoritide) emerging"],
    ["OSTEOGENESIS\nIMPERFECTA (OI)", "COL1A1 / COL1A2\nmutation → defective\ntype I collagen", "Brittle bones;\nblue sclerae;\nhearing loss;\ndentinogenesis imperfecta", "Bisphosphonates;\nrods for long bones;\nclassify Type I–IV"],
    ["SPINA BIFIDA", "Failure of neural tube\nclosure + vertebral\narch non-fusion", "Spina bifida occulta\n(hidden) → cystica\n→ meningomyelocele", "Prevention: Folic acid\n400 µg/day\npreconceptionally"],
    ["KLIPPEL-FEIL\nSYNDROME", "Failure of cervical\nvertebral segmentation", "Short neck, low\nposterior hairline,\n↓ cervical ROM", "Triad: SLR\n(Short neck, Low\nhairline, Reduced ROM)"],
]
story.append(std_table(
    anom_data[0], anom_data[1:],
    col_widths=[BODY_W*0.17, BODY_W*0.25, BODY_W*0.30, BODY_W*0.28],
    header_bg=C_RED
))
story.append(sp(8))

story.append(mnemonic_box(
    "MNEMONIC — CTEV (Clubfoot): \"CAVE\"",
    ["C = Cavus (exaggerated plantar arch)",
     "A = Adductus (metatarsus adductus — forefoot turned in)",
     "V = Varus (heel inverted — sole faces inward)",
     "E = Equinus (foot plantarflexed — toes point down)",
     "Treatment: Ponseti method — serial casting corrects C, A, V then tenotomy for E"]
))
story.append(sp(8))

story.append(mnemonic_box(
    "MNEMONIC — DDH Diagnosis: \"ORTOLAN Knows BARLOW\"",
    ["ORTOLANI = Reduction test: dislocated hip CLICKS BACK IN (O = Open/reduce)",
     "BARLOW   = Dislocation test: relocatable hip DISLOCATES OUT (B = Boot out)",
     "Both tests: hip flexed 90°, knee flexed, examiner's thumbs on medial thigh, fingers on greater trochanter",
     "AFTER 3 months: Ortolani/Barlow become unreliable → use GALEAZZI sign (shortened limb)"]
))
story.append(sp(10))

# ═══════════════════════════════════════════════════════════════════════════════
# SECTION 9 — KEY SIGNALING MOLECULES SUMMARY
# ═══════════════════════════════════════════════════════════════════════════════
story.append(SectionHeader("9.  KEY SIGNALING MOLECULES — QUICK REFERENCE", C_TEAL))
story.append(sp(8))

sig_data = [
    ["Molecule", "Full Name", "Source", "Function", "Clinical Disease if Mutated"],
    ["FGF-10", "Fibroblast Growth Factor 10", "Lateral plate mesoderm", "Initiates limb outgrowth", "Aplasia of lacrimal/salivary glands (ALSG)"],
    ["FGF-4/8", "Fibroblast Growth Factors 4 & 8", "AER", "Maintains progress zone; drives proximodistal growth", "AER failure → phocomelia/amelia"],
    ["SHH", "Sonic Hedgehog", "ZPA (posterior limb bud)", "Anteroposterior digit identity (more SHH = posterior digits)", "Preaxial polydactyly (ectopic SHH)"],
    ["WNT7a", "Wingless-Int 7a", "Dorsal ectoderm", "Dorsoventral axis; specifies dorsal limb identity", "Fuhrmann syndrome; Al-Awadi syndrome"],
    ["BMP-2/4", "Bone Morphogenetic Proteins", "Ventral ectoderm", "Drives interdigital apoptosis; AER positioning", "Failure → syndactyly"],
    ["HOX genes", "Homeobox genes (HOXA, HOXD)", "Mesoderm", "Pattern limb along proximodistal & anteroposterior axes", "Synpolydactyly (HOXD13 mutation)"],
    ["FGFR3", "FGF Receptor 3", "Growth plate chondrocytes", "Normally INHIBITS proliferation; gain-of-function = less growth", "Achondroplasia (G380R mutation)"],
    ["GDF5", "Growth Differentiation Factor 5", "Interzone mesenchyme", "Joint formation; promotes chondrogenesis in digits", "Brachydactyly type C; Grebe syndrome"],
    ["TBX5/TBX4", "T-box genes 5 & 4", "Lateral plate mesoderm", "Specify upper (TBX5) vs. lower (TBX4) limb identity", "Holt-Oram syndrome (TBX5 mutation → heart + arm defects)"],
]
story.append(std_table(
    sig_data[0], sig_data[1:],
    col_widths=[BODY_W*0.10, BODY_W*0.22, BODY_W*0.17, BODY_W*0.27, BODY_W*0.24],
    header_bg=C_TEAL
))
story.append(sp(10))

# ═══════════════════════════════════════════════════════════════════════════════
# SECTION 10 — SALTER-HARRIS FRACTURES
# ═══════════════════════════════════════════════════════════════════════════════
story.append(SectionHeader("10.  CLINICAL APPLICATION — SALTER-HARRIS FRACTURES", C_ORANGE))
story.append(sp(8))

story.append(Paragraph(
    "Because the <b>physis (growth plate) is weaker than ligaments in children</b>, "
    "trauma causes physeal fractures rather than ligament sprains. The Salter-Harris "
    "classification describes 5 types:",
    sBody))
story.append(sp(6))

sh_data = [
    ["Type", "Description", "Mnemonic", "Prognosis"],
    ["I\n(5%)", "Fracture through physis ONLY\n(Salter-Harris = S)\nX-ray may be normal", "S = Straight\nthrough physis", "Excellent; growth preserved\nif not displaced"],
    ["II\n(75%)", "Through physis + exits\nthrough METAPHYSIS\n(most common)", "A = Above\n(metaphysis above)", "Excellent; growth usually\nunaffected"],
    ["III\n(10%)", "Through physis + exits\nthrough EPIPHYSIS\n(intra-articular)", "L = Lower\n(epiphysis lower)", "Fair; ORIF needed if\ndisplaced (joint involved)"],
    ["IV\n(10%)", "Through metaphysis +\nphysis + epiphysis\n(complete vertical split)", "TE = Through\nEverything", "Poor; ORIF essential;\ngrowth arrest risk"],
    ["V\n(rare)", "Crush/compression injury\nof physis\nX-ray may be normal initially", "R = wReck\n(crushed)", "Worst; inevitable growth\narrest → limb shortening"],
]
story.append(std_table(
    sh_data[0], sh_data[1:],
    col_widths=[BODY_W*0.10, BODY_W*0.33, BODY_W*0.24, BODY_W*0.33],
    header_bg=C_ORANGE
))
story.append(sp(6))

story.append(mnemonic_box(
    "MNEMONIC — Salter-Harris: \"SALTER\"",
    ["S = Slip (physis only) — Type I",
     "A = Above (metaphysis) — Type II",
     "L = Lower (epiphysis) — Type III",
     "T = Through everything (metaphysis + physis + epiphysis) — Type IV",
     "E = Everything crushed — Type V",
     "R = Ruined growth plate"]
))
story.append(sp(8))

story.append(clinical_pearl(
    "Type II is the MOST COMMON Salter-Harris fracture (75%). "
    "Always get X-rays in two planes. If normal X-ray but tenderness over physis → "
    "treat as Type I (splint + follow-up). "
    "Growth arrest (premature physeal closure) → limb length discrepancy or angular deformity."
))
story.append(sp(10))

# ═══════════════════════════════════════════════════════════════════════════════
# SECTION 11 — MASTER SUMMARY TABLE
# ═══════════════════════════════════════════════════════════════════════════════
story.append(SectionHeader("11.  MASTER SUMMARY — EMBRYOLOGY TO CLINIC", C_DARK_BLUE))
story.append(sp(8))

master_data = [
    ["Embryo Concept", "Structure Formed", "Disease if Disrupted", "Clinical Exam Finding"],
    ["Lateral plate mesoderm", "Appendicular skeleton (limb bones)", "Phocomelia, amelia, limb reduction", "Absent/shortened limb; prosthetic needed"],
    ["Somite sclerotome", "Vertebrae, ribs", "Hemivertebra, block vertebrae, spina bifida", "Scoliosis, neurological deficit, tethered cord"],
    ["Somite myotome", "All skeletal muscles", "Muscular dystrophies, congenital myopathies", "Hypotonia, ↓ DTRs, waddling gait"],
    ["Neural crest", "Craniofacial bones", "Cleft palate, micrognathia, Pierre Robin", "Airway compromise, feeding difficulties"],
    ["AER + FGF signaling", "Proximal-to-distal limb growth", "Phocomelia (AER absent/disrupted)", "Flipper limbs; thalidomide history"],
    ["ZPA + SHH", "Anteroposterior digit pattern", "Pre/post-axial polydactyly", "Extra digits; family history"],
    ["Interdigital apoptosis", "Separation of digits", "Syndactyly", "Webbed digits; surgical release"],
    ["Interzone apoptosis", "Synovial joint cavity", "Synostosis (fused joint)", "Fixed joint; limited ROM"],
    ["FGFR3 (growth plate)", "Long bone length", "Achondroplasia (FGFR3 GOF)", "Short stature, rhizomelia, macrocephaly, trident hand"],
    ["COL1A1/2 genes", "Type I collagen", "Osteogenesis imperfecta", "Blue sclerae, hearing loss, repeated fractures, dentinogenesis imperfecta"],
    ["Growth plate (physis)", "Longitudinal bone growth", "Salter-Harris fractures", "Physeal tenderness; angular deformity post-healing"],
    ["Hip interzone (DDH)", "Hip joint/acetabulum", "Dev. dysplasia of hip", "Ortolani/Barlow positive; Galeazzi sign; limping at walking age"],
]
story.append(std_table(
    master_data[0], master_data[1:],
    col_widths=[BODY_W*0.22, BODY_W*0.22, BODY_W*0.26, BODY_W*0.30],
    header_bg=C_DARK_BLUE
))
story.append(sp(12))

# ═══════════════════════════════════════════════════════════════════════════════
# SECTION 12 — QUICK REVISION CARDS
# ═══════════════════════════════════════════════════════════════════════════════
story.append(SectionHeader("12.  QUICK REVISION — HIGH-YIELD FACTS", C_GREEN))
story.append(sp(8))

facts = [
    "Upper limb buds appear at Day 24; lower limb buds at Day 26–28.",
    "The AER (Apical Ectodermal Ridge) drives PROXIMODISTAL growth via FGF-4 and FGF-8.",
    "The ZPA (Zone of Polarizing Activity) drives ANTEROPOSTERIOR patterning via SHH.",
    "WNT7a from dorsal ectoderm drives DORSOVENTRAL axis via transcription factor LMX1.",
    "Entire limb skeleton is cartilaginous by end of Week 6 — endochondral ossification.",
    "Flat skull bones = intramembranous ossification; no cartilage model needed.",
    "Growth plate zones (RPHCO): Resting → Proliferative → Hypertrophic → Calcification → Ossification.",
    "Hypertrophic zone = WEAKEST zone of growth plate → Salter-Harris fractures occur here.",
    "Salter-Harris Type II (75%) = most common physeal fracture; excellent prognosis.",
    "Salter-Harris Type V (crush) = rarest but WORST prognosis → growth arrest.",
    "Achondroplasia = FGFR3 gain-of-function; AD; 80% de novo; decreased proliferative zone activity.",
    "OI (Osteogenesis Imperfecta) = Type I collagen defect; blue sclerae, hearing loss, brittle bones.",
    "DDH: Ortolani = relocate (click IN); Barlow = dislocate (click OUT). Pavlik harness < 6 months.",
    "Clubfoot CTEV: CAVE mnemonic. Treatment = Ponseti method (serial casting + Achilles tenotomy).",
    "Spina bifida prevention = folic acid 400 µg/day from PRECONCEPTION through first trimester.",
    "Thalidomide disrupts FGF signaling in Weeks 4–6 → phocomelia (most sensitive period).",
    "Klippel-Feil syndrome: failure of cervical segmentation; Triad = Short neck, Low hairline, Limited ROM.",
    "Upper limb rotates LATERALLY; lower limb rotates MEDIALLY in Week 7.",
    "Muscles of DORSAL mass → extensors (radial/femoral nerve); VENTRAL mass → flexors (musculocutaneous/tibial).",
    "Each vertebra = CAUDAL half of one somite + CRANIAL half of next somite (re-segmentation).",
]

fact_rows = []
for i, fact in enumerate(facts):
    bg = C_LIGHT_BLUE if i % 2 == 0 else white
    fact_rows.append([
        Paragraph(f"<b>{i+1:02d}</b>", ParagraphStyle("fnum", parent=sTableCellC,
                  fontName="Helvetica-Bold", textColor=C_DARK_BLUE, alignment=TA_CENTER)),
        Paragraph(fact, sTableCell)
    ])

ft = Table(fact_rows, colWidths=[BODY_W*0.08, BODY_W*0.92])
ftstyle = [
    ("ROWBACKGROUNDS",(0,0),(-1,-1),[C_LIGHT_BLUE, white]),
    ("GRID",         (0,0),(-1,-1), 0.4, C_BORDER),
    ("VALIGN",       (0,0),(-1,-1), "MIDDLE"),
    ("TOPPADDING",   (0,0),(-1,-1), 5),
    ("BOTTOMPADDING",(0,0),(-1,-1), 5),
    ("LEFTPADDING",  (0,0),(-1,-1), 6),
    ("RIGHTPADDING", (0,0),(-1,-1), 6),
]
ft.setStyle(TableStyle(ftstyle))
story.append(ft)
story.append(sp(12))

# ── Final footer note ─────────────────────────────────────────────────────────
story.append(hr())
story.append(Paragraph(
    "<b>Sources:</b> Langman's Medical Embryology (13th ed.) | "
    "The Developing Human: Clinically Oriented Embryology (Moore & Persaud) | "
    "General Anatomy &amp; Musculoskeletal System — THIEME Atlas of Anatomy | "
    "Miller's Review of Orthopaedics (9th ed.)",
    sFooter))
story.append(sp(4))
story.append(Paragraph(
    "© Orris Medical Education, 2026 | For educational use only | "
    "Proceed to Chunk 2: Bone — Structure, Histology &amp; Physiology",
    sFooter))

# ── Build ──────────────────────────────────────────────────────────────────────
doc.build(story, onFirstPage=on_page, onLaterPages=on_page)
print(f"PDF saved: {OUTPUT}")
Your credits are exhausted. Your daily credits reset tomorrow, or you can purchase a top-up for more.
This is a shared conversation. Sign in to Orris to start your own chat.