Can you make pdf in different colours with highlights

Asking for Preferences
Asking for Preferences
Reading File
Reading File
Running Command

mkdir -p /home/daytona/workspace/colorful-study-notes && ls /home/daytona/workspโ€ฆ

Writing File

~/colorful-study-notes/create_notes.py

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

OUTPUT = "/home/daytona/workspace/colorful-study-notes/Science_Study_Notes.pdf"

# โ”€โ”€ Custom colours โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
BLUE_DARK   = colors.HexColor("#1a237e")
BLUE_MED    = colors.HexColor("#1565c0")
BLUE_LIGHT  = colors.HexColor("#e3f2fd")
GREEN_DARK  = colors.HexColor("#1b5e20")
GREEN_LIGHT = colors.HexColor("#e8f5e9")
PURPLE_DARK = colors.HexColor("#4a148c")
PURPLE_LIGHT= colors.HexColor("#f3e5f5")
ORANGE_DARK = colors.HexColor("#e65100")
ORANGE_LIGHT= colors.HexColor("#fff3e0")
RED_DARK    = colors.HexColor("#b71c1c")
RED_LIGHT   = colors.HexColor("#ffebee")
YELLOW_HL   = colors.HexColor("#fff176")   # classic yellow highlight
CYAN_HL     = colors.HexColor("#b2ebf2")   # cyan highlight
PINK_HL     = colors.HexColor("#f8bbd0")   # pink highlight
GREY_LIGHT  = colors.HexColor("#f5f5f5")
GREY_MED    = colors.HexColor("#e0e0e0")
TEXT_DARK   = colors.HexColor("#212121")

# โ”€โ”€ Paragraph styles โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
def make_styles():
    styles = getSampleStyleSheet()

    styles.add(ParagraphStyle(
        "DocTitle",
        fontName="Helvetica-Bold",
        fontSize=26,
        textColor=colors.white,
        alignment=TA_CENTER,
        spaceAfter=4,
    ))
    styles.add(ParagraphStyle(
        "DocSubtitle",
        fontName="Helvetica",
        fontSize=13,
        textColor=colors.HexColor("#bbdefb"),
        alignment=TA_CENTER,
        spaceAfter=10,
    ))
    styles.add(ParagraphStyle(
        "SectionHeading",
        fontName="Helvetica-Bold",
        fontSize=15,
        textColor=colors.white,
        spaceBefore=14,
        spaceAfter=6,
        leftIndent=0,
    ))
    styles.add(ParagraphStyle(
        "SubHeading",
        fontName="Helvetica-Bold",
        fontSize=12,
        textColor=BLUE_MED,
        spaceBefore=10,
        spaceAfter=4,
    ))
    styles.add(ParagraphStyle(
        "BodyNote",
        fontName="Helvetica",
        fontSize=10.5,
        textColor=TEXT_DARK,
        spaceBefore=3,
        spaceAfter=3,
        leading=15,
        alignment=TA_JUSTIFY,
    ))
    styles.add(ParagraphStyle(
        "BulletNote",
        fontName="Helvetica",
        fontSize=10.5,
        textColor=TEXT_DARK,
        spaceBefore=2,
        spaceAfter=2,
        leftIndent=14,
        leading=14,
        bulletIndent=4,
    ))
    styles.add(ParagraphStyle(
        "HighlightYellow",
        fontName="Helvetica-Bold",
        fontSize=10.5,
        backColor=YELLOW_HL,
        textColor=TEXT_DARK,
        spaceBefore=3,
        spaceAfter=3,
        leading=15,
        leftIndent=6,
        rightIndent=6,
        borderPadding=(4, 6, 4, 6),
    ))
    styles.add(ParagraphStyle(
        "HighlightCyan",
        fontName="Helvetica",
        fontSize=10.5,
        backColor=CYAN_HL,
        textColor=colors.HexColor("#006064"),
        spaceBefore=3,
        spaceAfter=3,
        leading=15,
        leftIndent=6,
        rightIndent=6,
        borderPadding=(4, 6, 4, 6),
    ))
    styles.add(ParagraphStyle(
        "HighlightPink",
        fontName="Helvetica",
        fontSize=10.5,
        backColor=PINK_HL,
        textColor=RED_DARK,
        spaceBefore=3,
        spaceAfter=3,
        leading=15,
        leftIndent=6,
        rightIndent=6,
        borderPadding=(4, 6, 4, 6),
    ))
    styles.add(ParagraphStyle(
        "Definition",
        fontName="Helvetica-Oblique",
        fontSize=10,
        textColor=PURPLE_DARK,
        backColor=PURPLE_LIGHT,
        spaceBefore=4,
        spaceAfter=4,
        leading=14,
        leftIndent=10,
        rightIndent=10,
        borderPadding=(5, 8, 5, 8),
    ))
    styles.add(ParagraphStyle(
        "KeyFact",
        fontName="Helvetica-Bold",
        fontSize=10.5,
        textColor=GREEN_DARK,
        backColor=GREEN_LIGHT,
        spaceBefore=4,
        spaceAfter=4,
        leading=14,
        leftIndent=10,
        rightIndent=10,
        borderPadding=(5, 8, 5, 8),
    ))
    styles.add(ParagraphStyle(
        "Warning",
        fontName="Helvetica-Bold",
        fontSize=10.5,
        textColor=ORANGE_DARK,
        backColor=ORANGE_LIGHT,
        spaceBefore=4,
        spaceAfter=4,
        leading=14,
        leftIndent=10,
        rightIndent=10,
        borderPadding=(5, 8, 5, 8),
    ))
    return styles

# โ”€โ”€ Coloured section header block โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
def section_block(title_text, bg_color, styles):
    """Returns a table that acts as a coloured heading band."""
    p = Paragraph(title_text, styles["SectionHeading"])
    t = Table([[p]], colWidths=[170*mm])
    t.setStyle(TableStyle([
        ("BACKGROUND", (0, 0), (-1, -1), bg_color),
        ("TOPPADDING",    (0, 0), (-1, -1), 6),
        ("BOTTOMPADDING", (0, 0), (-1, -1), 6),
        ("LEFTPADDING",   (0, 0), (-1, -1), 10),
        ("RIGHTPADDING",  (0, 0), (-1, -1), 10),
        ("ROUNDEDCORNERS", [4, 4, 4, 4]),
    ]))
    return t

# โ”€โ”€ Cover banner โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
def cover_banner(styles):
    p_title    = Paragraph("Science Study Notes", styles["DocTitle"])
    p_subtitle = Paragraph("Physics  โ€ข  Chemistry  โ€ข  Biology", styles["DocSubtitle"])
    t = Table([[p_title], [p_subtitle]], colWidths=[170*mm])
    t.setStyle(TableStyle([
        ("BACKGROUND", (0, 0), (-1, -1), BLUE_DARK),
        ("TOPPADDING",    (0, 0), (-1, -1), 14),
        ("BOTTOMPADDING", (0, 0), (-1, -1), 14),
        ("LEFTPADDING",   (0, 0), (-1, -1), 12),
        ("RIGHTPADDING",  (0, 0), (-1, -1), 12),
    ]))
    return t

# โ”€โ”€ Key-term table โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
def key_terms_table(rows, header_color, row_colors, styles):
    """rows = list of (term, definition) tuples."""
    data = [["Term", "Definition"]]
    data += [[r[0], r[1]] for r in rows]
    col_w = [55*mm, 115*mm]
    t = Table(data, colWidths=col_w, repeatRows=1)
    ts = [
        ("BACKGROUND", (0, 0), (-1, 0), header_color),
        ("TEXTCOLOR",  (0, 0), (-1, 0), colors.white),
        ("FONTNAME",   (0, 0), (-1, 0), "Helvetica-Bold"),
        ("FONTSIZE",   (0, 0), (-1, 0), 11),
        ("ALIGN",      (0, 0), (-1, 0), "CENTER"),
        ("VALIGN",     (0, 0), (-1, -1), "MIDDLE"),
        ("FONTNAME",   (0, 1), (0, -1), "Helvetica-Bold"),
        ("FONTSIZE",   (0, 1), (-1, -1), 10),
        ("GRID",       (0, 0), (-1, -1), 0.5, GREY_MED),
        ("TOPPADDING",    (0, 0), (-1, -1), 5),
        ("BOTTOMPADDING", (0, 0), (-1, -1), 5),
        ("LEFTPADDING",   (0, 0), (-1, -1), 8),
        ("RIGHTPADDING",  (0, 0), (-1, -1), 8),
    ]
    for i, rc in enumerate(row_colors):
        ts.append(("BACKGROUND", (0, i + 1), (-1, i + 1), rc))
    t.setStyle(TableStyle(ts))
    return t

# โ”€โ”€ Page footer โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
class FooterCanvas(canvas.Canvas):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self._saved_page_states = []

    def showPage(self):
        self._saved_page_states.append(dict(self.__dict__))
        self._startPage()

    def save(self):
        num_pages = len(self._saved_page_states)
        for state in self._saved_page_states:
            self.__dict__.update(state)
            self._draw_footer(num_pages)
            canvas.Canvas.showPage(self)
        canvas.Canvas.save(self)

    def _draw_footer(self, page_count):
        page = self.__dict__.get("_pageNumber", 1)
        self.saveState()
        self.setFont("Helvetica", 8)
        self.setFillColor(colors.grey)
        self.drawCentredString(A4[0] / 2, 18, f"Science Study Notes  โ€”  Page {page} of {page_count}")
        self.setStrokeColor(GREY_MED)
        self.line(20*mm, 22*mm, A4[0] - 20*mm, 22*mm)
        self.restoreState()

# โ”€โ”€ Main build โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
def build():
    doc = SimpleDocTemplate(
        OUTPUT,
        pagesize=A4,
        topMargin=18*mm, bottomMargin=28*mm,
        leftMargin=20*mm, rightMargin=20*mm,
        title="Science Study Notes",
        author="Orris AI",
    )
    styles = make_styles()
    S = styles
    story = []

    # โ”€โ”€ Cover banner โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
    story.append(cover_banner(S))
    story.append(Spacer(1, 12))

    # โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
    #  SECTION 1 โ€“ PHYSICS
    # โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
    story.append(section_block("โšก  Section 1: Physics", BLUE_MED, S))
    story.append(Spacer(1, 6))

    story.append(Paragraph("1.1  Newton's Laws of Motion", S["SubHeading"]))
    story.append(Paragraph(
        "Isaac Newton formulated three fundamental laws that describe the relationship "
        "between the motion of an object and the forces acting on it.",
        S["BodyNote"]))

    story.append(Paragraph(
        "โ˜…  KEY FACT: Newton's First Law โ€” An object at rest stays at rest, and an object "
        "in motion stays in motion unless acted upon by an external force (Inertia).",
        S["KeyFact"]))

    story.append(Paragraph(
        "โ˜…  KEY FACT: Newton's Second Law โ€” Force = Mass ร— Acceleration  (F = ma).",
        S["KeyFact"]))

    story.append(Paragraph(
        "โ˜…  KEY FACT: Newton's Third Law โ€” For every action there is an equal and opposite reaction.",
        S["KeyFact"]))

    story.append(Spacer(1, 4))
    story.append(Paragraph("1.2  Work, Energy & Power", S["SubHeading"]))

    story.append(Paragraph(
        "<b>Work</b> done on an object equals the force applied multiplied by the distance "
        "moved in the direction of the force.  W = F ร— d  (unit: Joule, J).",
        S["BodyNote"]))

    story.append(Paragraph(
        "โš   REMEMBER: Energy cannot be created or destroyed โ€” only converted from one form "
        "to another (Law of Conservation of Energy).",
        S["Warning"]))

    story.append(Paragraph(
        "Power is the rate of doing work:  P = W / t  (unit: Watt, W).",
        S["HighlightYellow"]))

    story.append(Spacer(1, 4))
    story.append(Paragraph("1.3  Waves & Light", S["SubHeading"]))
    story.append(Paragraph(
        "Light travels at approximately <b>3 ร— 10<super>8</super> m/s</b> in a vacuum. "
        "It exhibits both wave-like and particle-like behaviour (wave-particle duality).",
        S["BodyNote"]))
    story.append(Paragraph(
        "The electromagnetic spectrum (low โ†’ high frequency): Radio โ†’ Microwave โ†’ Infrared "
        "โ†’ Visible light โ†’ Ultraviolet โ†’ X-ray โ†’ Gamma ray.",
        S["HighlightCyan"]))

    story.append(Spacer(1, 6))
    story.append(Paragraph("Physics Key Terms", S["SubHeading"]))
    physics_terms = [
        ("Velocity",    "Speed in a given direction (vector quantity)."),
        ("Acceleration","Rate of change of velocity (m/sยฒ)."),
        ("Momentum",    "Mass ร— Velocity  (p = mv).  Conserved in collisions."),
        ("Frequency",   "Number of wave cycles per second (unit: Hertz, Hz)."),
        ("Amplitude",   "Maximum displacement of a wave from its rest position."),
    ]
    row_colors_phys = [BLUE_LIGHT, GREY_LIGHT, BLUE_LIGHT, GREY_LIGHT, BLUE_LIGHT]
    story.append(key_terms_table(physics_terms, BLUE_MED, row_colors_phys, S))

    story.append(Spacer(1, 10))

    # โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
    #  SECTION 2 โ€“ CHEMISTRY
    # โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
    story.append(section_block("๐Ÿงช  Section 2: Chemistry", colors.HexColor("#7b1fa2"), S))
    story.append(Spacer(1, 6))

    story.append(Paragraph("2.1  Atomic Structure", S["SubHeading"]))
    story.append(Paragraph(
        "An atom consists of a nucleus containing <b>protons</b> (positive charge) and "
        "<b>neutrons</b> (no charge), surrounded by <b>electrons</b> (negative charge) "
        "arranged in energy levels (shells).",
        S["BodyNote"]))

    story.append(Paragraph(
        "Definition โ€” Atomic Number: The number of protons in the nucleus of an atom. "
        "It uniquely identifies each element on the Periodic Table.",
        S["Definition"]))

    story.append(Paragraph(
        "Definition โ€” Isotopes: Atoms of the same element with the same number of protons "
        "but a different number of neutrons (e.g., Carbon-12 vs Carbon-14).",
        S["Definition"]))

    story.append(Spacer(1, 4))
    story.append(Paragraph("2.2  Chemical Bonding", S["SubHeading"]))

    bond_data = [
        ["Bond Type",     "Between",              "Example"],
        ["Ionic",         "Metal + Non-metal",    "NaCl (table salt)"],
        ["Covalent",      "Non-metal + Non-metal","Hโ‚‚O (water)"],
        ["Metallic",      "Metal + Metal",        "Copper wire"],
        ["Hydrogen Bond", "Polar molecules",      "DNA base pairs"],
    ]
    bond_col_w = [40*mm, 65*mm, 65*mm]
    bt = Table(bond_data, colWidths=bond_col_w, repeatRows=1)
    bt.setStyle(TableStyle([
        ("BACKGROUND",    (0, 0), (-1, 0), colors.HexColor("#7b1fa2")),
        ("TEXTCOLOR",     (0, 0), (-1, 0), colors.white),
        ("FONTNAME",      (0, 0), (-1, 0), "Helvetica-Bold"),
        ("FONTNAME",      (0, 1), (0, -1), "Helvetica-Bold"),
        ("FONTSIZE",      (0, 0), (-1, -1), 10),
        ("ALIGN",         (0, 0), (-1, 0), "CENTER"),
        ("VALIGN",        (0, 0), (-1, -1), "MIDDLE"),
        ("GRID",          (0, 0), (-1, -1), 0.5, GREY_MED),
        ("TOPPADDING",    (0, 0), (-1, -1), 5),
        ("BOTTOMPADDING", (0, 0), (-1, -1), 5),
        ("LEFTPADDING",   (0, 0), (-1, -1), 8),
        ("RIGHTPADDING",  (0, 0), (-1, -1), 8),
        ("BACKGROUND",    (0, 1), (-1, 1), PURPLE_LIGHT),
        ("BACKGROUND",    (0, 2), (-1, 2), GREEN_LIGHT),
        ("BACKGROUND",    (0, 3), (-1, 3), ORANGE_LIGHT),
        ("BACKGROUND",    (0, 4), (-1, 4), RED_LIGHT),
    ]))
    story.append(bt)

    story.append(Spacer(1, 6))
    story.append(Paragraph("2.3  Acids, Bases & pH", S["SubHeading"]))
    story.append(Paragraph(
        "The pH scale runs from <b>0 (strongly acidic)</b> to <b>14 (strongly basic/alkaline)</b>. "
        "pH 7 is neutral (pure water at 25 ยฐC).",
        S["BodyNote"]))
    story.append(Paragraph(
        "๐Ÿ”‘  HIGHLIGHT: Litmus paper test โ€” turns RED in acid, BLUE in base.",
        S["HighlightPink"]))
    story.append(Paragraph(
        "โš   REMEMBER: Strong acids (HCl, Hโ‚‚SOโ‚„, HNOโ‚ƒ) fully dissociate in water. "
        "Weak acids (ethanoic acid, carbonic acid) only partially dissociate.",
        S["Warning"]))

    story.append(Spacer(1, 10))

    # โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
    #  SECTION 3 โ€“ BIOLOGY
    # โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
    story.append(section_block("๐ŸŒฟ  Section 3: Biology", GREEN_DARK, S))
    story.append(Spacer(1, 6))

    story.append(Paragraph("3.1  The Cell", S["SubHeading"]))
    story.append(Paragraph(
        "The cell is the basic unit of life. There are two main types:",
        S["BodyNote"]))

    cell_data = [
        ["Feature",      "Prokaryotic Cell",       "Eukaryotic Cell"],
        ["Nucleus",       "Absent",                 "Present (membrane-bound)"],
        ["Size",          "1โ€“10 ยตm",                "10โ€“100 ยตm"],
        ["DNA",           "Circular, no histones",  "Linear, with histones"],
        ["Examples",      "Bacteria, Archaea",      "Plants, Animals, Fungi"],
    ]
    cell_col_w = [40*mm, 65*mm, 65*mm]
    ct = Table(cell_data, colWidths=cell_col_w, repeatRows=1)
    ct.setStyle(TableStyle([
        ("BACKGROUND",    (0, 0), (-1, 0), GREEN_DARK),
        ("TEXTCOLOR",     (0, 0), (-1, 0), colors.white),
        ("FONTNAME",      (0, 0), (-1, 0), "Helvetica-Bold"),
        ("FONTNAME",      (0, 1), (0, -1), "Helvetica-Bold"),
        ("FONTSIZE",      (0, 0), (-1, -1), 10),
        ("ALIGN",         (0, 0), (-1, 0), "CENTER"),
        ("VALIGN",        (0, 0), (-1, -1), "MIDDLE"),
        ("GRID",          (0, 0), (-1, -1), 0.5, GREY_MED),
        ("TOPPADDING",    (0, 0), (-1, -1), 5),
        ("BOTTOMPADDING", (0, 0), (-1, -1), 5),
        ("LEFTPADDING",   (0, 0), (-1, -1), 8),
        ("RIGHTPADDING",  (0, 0), (-1, -1), 8),
        ("BACKGROUND",    (0, 1), (-1, 1), GREEN_LIGHT),
        ("BACKGROUND",    (0, 2), (-1, 2), GREY_LIGHT),
        ("BACKGROUND",    (0, 3), (-1, 3), GREEN_LIGHT),
        ("BACKGROUND",    (0, 4), (-1, 4), GREY_LIGHT),
    ]))
    story.append(ct)

    story.append(Spacer(1, 6))
    story.append(Paragraph("3.2  Photosynthesis & Respiration", S["SubHeading"]))

    story.append(Paragraph(
        "๐ŸŒฑ  PHOTOSYNTHESIS (in chloroplasts):",
        S["KeyFact"]))
    story.append(Paragraph(
        "6COโ‚‚  +  6Hโ‚‚O  +  Light energy  โ†’  Cโ‚†Hโ‚โ‚‚Oโ‚†  +  6Oโ‚‚",
        S["HighlightYellow"]))

    story.append(Spacer(1, 4))
    story.append(Paragraph(
        "๐Ÿ”ฅ  AEROBIC RESPIRATION (in mitochondria):",
        S["Warning"]))
    story.append(Paragraph(
        "Cโ‚†Hโ‚โ‚‚Oโ‚†  +  6Oโ‚‚  โ†’  6COโ‚‚  +  6Hโ‚‚O  +  ATP (energy)",
        S["HighlightCyan"]))

    story.append(Spacer(1, 6))
    story.append(Paragraph("3.3  Genetics", S["SubHeading"]))
    story.append(Paragraph(
        "<b>DNA</b> (deoxyribonucleic acid) carries the genetic information of living organisms. "
        "It is a double helix made of nucleotide base pairs: <b>A-T</b> and <b>G-C</b>.",
        S["BodyNote"]))
    story.append(Paragraph(
        "Definition โ€” Gene: A segment of DNA that codes for a specific protein or trait. "
        "Humans have approximately 20,000โ€“25,000 genes.",
        S["Definition"]))
    story.append(Paragraph(
        "โš   REMEMBER: Mitosis produces 2 identical daughter cells (for growth/repair). "
        "Meiosis produces 4 genetically unique cells (for sexual reproduction).",
        S["Warning"]))
    story.append(Paragraph(
        "๐Ÿ”‘  HIGHLIGHT: Dominant alleles mask recessive alleles. "
        "A recessive trait only shows when the organism is homozygous recessive (aa).",
        S["HighlightPink"]))

    story.append(Spacer(1, 10))

    # โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
    #  QUICK REFERENCE BOX
    # โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
    story.append(HRFlowable(width="100%", thickness=1.5, color=BLUE_MED, spaceAfter=8))
    story.append(Paragraph("Quick Reference: Important Equations", S["SubHeading"]))

    eq_data = [
        ["Subject",   "Formula",                    "Description"],
        ["Physics",   "F = ma",                     "Newton's Second Law"],
        ["Physics",   "KE = ยฝmvยฒ",                  "Kinetic Energy"],
        ["Physics",   "v = fฮป",                     "Wave speed"],
        ["Chemistry", "n = m / Mr",                 "Moles = mass / molar mass"],
        ["Chemistry", "pH = โˆ’log[Hโบ]",              "pH definition"],
        ["Biology",   "Energy = Power ร— Time",       "Energy equation"],
        ["Biology",   "Magnification = image/object","Microscopy"],
    ]
    eq_col_w = [28*mm, 60*mm, 82*mm]
    eq_t = Table(eq_data, colWidths=eq_col_w, repeatRows=1)
    eq_row_bg = [BLUE_LIGHT, BLUE_LIGHT, BLUE_LIGHT, PURPLE_LIGHT, PURPLE_LIGHT, GREEN_LIGHT, GREEN_LIGHT]
    ts = [
        ("BACKGROUND",    (0, 0), (-1, 0), BLUE_DARK),
        ("TEXTCOLOR",     (0, 0), (-1, 0), colors.white),
        ("FONTNAME",      (0, 0), (-1, 0), "Helvetica-Bold"),
        ("FONTNAME",      (0, 1), (1, -1), "Helvetica-Bold"),
        ("FONTSIZE",      (0, 0), (-1, -1), 10),
        ("ALIGN",         (0, 0), (-1, 0), "CENTER"),
        ("ALIGN",         (1, 1), (1, -1), "CENTER"),
        ("VALIGN",        (0, 0), (-1, -1), "MIDDLE"),
        ("GRID",          (0, 0), (-1, -1), 0.5, GREY_MED),
        ("TOPPADDING",    (0, 0), (-1, -1), 5),
        ("BOTTOMPADDING", (0, 0), (-1, -1), 5),
        ("LEFTPADDING",   (0, 0), (-1, -1), 8),
        ("RIGHTPADDING",  (0, 0), (-1, -1), 8),
    ]
    for i, rc in enumerate(eq_row_bg):
        ts.append(("BACKGROUND", (0, i + 1), (-1, i + 1), rc))
    eq_t.setStyle(TableStyle(ts))
    story.append(eq_t)

    story.append(Spacer(1, 8))

    # โ”€โ”€ Build โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
    doc.build(story, canvasmaker=FooterCanvas)
    print(f"PDF saved to: {OUTPUT}")

build()
Running Command

cd /home/daytona/workspace/colorful-study-notes && python create_notes.py 2>&1

Editing File

~/colorful-study-notes/create_notes.py

Successfully replaced 1 instance(s) of the string in '/home/daytona/workspace/colorful-study-notes/create_notes.py'
Running Command

cd /home/daytona/workspace/colorful-study-notes && sed -i 's/S\["Definition"\]/Sโ€ฆ

Running Command

python3 -c " content = open('/home/daytona/workspace/colorful-study-notes/createโ€ฆ

The PDF was built successfully. Here's your download link:

Science Study Notes

PDF Document ยท PDF


Here's what's inside the PDF:
Structure - 3 coloured sections + quick reference:
SectionColour theme
PhysicsBlue
ChemistryPurple
BiologyGreen
Highlight styles used throughout:
  • ๐ŸŸก Yellow highlight - key formulas (F = ma, P = W/t, photosynthesis equation)
  • ๐Ÿฉต Cyan highlight - spectrum / equation facts
  • ๐Ÿฉท Pink highlight - must-remember exam tips
  • ๐ŸŸข Green boxes - key facts (Newton's Laws, cell types)
  • ๐ŸŸ  Orange boxes - warnings/reminders (conservation of energy, acid strength)
  • ๐ŸŸฃ Purple boxes - definitions (atomic number, isotopes, gene)
Also includes:
  • Colour-coded comparison tables (chemical bonds, prokaryotic vs eukaryotic cells)
  • A quick-reference equation table at the end (Physics, Chemistry, Biology)
  • Page numbers in the footer
If you want a different topic (e.g. History, Maths, Geography) or want to add/change content, just let me know!

Now create on ALTS advanced life trauma support

Reading File
Finding Sources
Finding Sources
Searching the Web

ATLS 10th edition advanced trauma life support primary survey ABCDE guidelines 2024

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

~/colorful-study-notes/create_atls.py

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

OUTPUT = "/home/daytona/workspace/colorful-study-notes/ATLS_Study_Notes.pdf"

# โ”€โ”€ Colour palette โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
RED_DARK     = colors.HexColor("#b71c1c")
RED_MED      = colors.HexColor("#c62828")
RED_LIGHT    = colors.HexColor("#ffebee")
ORANGE_DARK  = colors.HexColor("#e65100")
ORANGE_LIGHT = colors.HexColor("#fff3e0")
AMBER_DARK   = colors.HexColor("#ff6f00")
AMBER_LIGHT  = colors.HexColor("#fff8e1")
BLUE_DARK    = colors.HexColor("#0d47a1")
BLUE_MED     = colors.HexColor("#1565c0")
BLUE_LIGHT   = colors.HexColor("#e3f2fd")
TEAL_DARK    = colors.HexColor("#004d40")
TEAL_MED     = colors.HexColor("#00695c")
TEAL_LIGHT   = colors.HexColor("#e0f2f1")
GREEN_DARK   = colors.HexColor("#1b5e20")
GREEN_MED    = colors.HexColor("#2e7d32")
GREEN_LIGHT  = colors.HexColor("#e8f5e9")
PURPLE_DARK  = colors.HexColor("#4a148c")
PURPLE_MED   = colors.HexColor("#6a1b9a")
PURPLE_LIGHT = colors.HexColor("#f3e5f5")
GREY_DARK    = colors.HexColor("#37474f")
GREY_LIGHT   = colors.HexColor("#f5f5f5")
GREY_MED     = colors.HexColor("#e0e0e0")
YELLOW_HL    = colors.HexColor("#fff176")
CYAN_HL      = colors.HexColor("#b2ebf2")
PINK_HL      = colors.HexColor("#f8bbd0")
TEXT_DARK    = colors.HexColor("#212121")
WHITE        = colors.white

# โ”€โ”€ Styles โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
def make_styles():
    base = getSampleStyleSheet()

    def add(name, **kw):
        if name not in base:
            base.add(ParagraphStyle(name, **kw))

    add("DocTitle",    fontName="Helvetica-Bold",   fontSize=28, textColor=WHITE,
        alignment=TA_CENTER, spaceAfter=2)
    add("DocSubtitle", fontName="Helvetica",        fontSize=13, textColor=colors.HexColor("#ffcdd2"),
        alignment=TA_CENTER, spaceAfter=6)
    add("DocEdition",  fontName="Helvetica-Oblique",fontSize=10, textColor=colors.HexColor("#ffcdd2"),
        alignment=TA_CENTER, spaceAfter=10)
    add("SecHead",     fontName="Helvetica-Bold",   fontSize=14, textColor=WHITE,
        spaceBefore=8, spaceAfter=4)
    add("SubHead",     fontName="Helvetica-Bold",   fontSize=12, textColor=BLUE_MED,
        spaceBefore=10, spaceAfter=4)
    add("BodyTxt",     fontName="Helvetica",        fontSize=10.5, textColor=TEXT_DARK,
        spaceBefore=3, spaceAfter=3, leading=15, alignment=TA_JUSTIFY)
    add("BulletTxt",   fontName="Helvetica",        fontSize=10.5, textColor=TEXT_DARK,
        spaceBefore=2, spaceAfter=2, leftIndent=14, leading=14)
    add("HLYellow",    fontName="Helvetica-Bold",   fontSize=10.5, backColor=YELLOW_HL,
        textColor=TEXT_DARK, spaceBefore=3, spaceAfter=3, leading=15,
        leftIndent=6, rightIndent=6, borderPadding=(4, 6, 4, 6))
    add("HLCyan",      fontName="Helvetica",        fontSize=10.5, backColor=CYAN_HL,
        textColor=TEAL_DARK, spaceBefore=3, spaceAfter=3, leading=15,
        leftIndent=6, rightIndent=6, borderPadding=(4, 6, 4, 6))
    add("HLPink",      fontName="Helvetica",        fontSize=10.5, backColor=PINK_HL,
        textColor=RED_DARK, spaceBefore=3, spaceAfter=3, leading=15,
        leftIndent=6, rightIndent=6, borderPadding=(4, 6, 4, 6))
    add("BoxGreen",    fontName="Helvetica-Bold",   fontSize=10.5, backColor=GREEN_LIGHT,
        textColor=GREEN_DARK, spaceBefore=4, spaceAfter=4, leading=14,
        leftIndent=10, rightIndent=10, borderPadding=(5, 8, 5, 8))
    add("BoxOrange",   fontName="Helvetica-Bold",   fontSize=10.5, backColor=ORANGE_LIGHT,
        textColor=ORANGE_DARK, spaceBefore=4, spaceAfter=4, leading=14,
        leftIndent=10, rightIndent=10, borderPadding=(5, 8, 5, 8))
    add("BoxRed",      fontName="Helvetica-Bold",   fontSize=10.5, backColor=RED_LIGHT,
        textColor=RED_DARK, spaceBefore=4, spaceAfter=4, leading=14,
        leftIndent=10, rightIndent=10, borderPadding=(5, 8, 5, 8))
    add("BoxPurple",   fontName="Helvetica-Oblique",fontSize=10, backColor=PURPLE_LIGHT,
        textColor=PURPLE_DARK, spaceBefore=4, spaceAfter=4, leading=14,
        leftIndent=10, rightIndent=10, borderPadding=(5, 8, 5, 8))
    add("BoxBlue",     fontName="Helvetica",        fontSize=10.5, backColor=BLUE_LIGHT,
        textColor=BLUE_DARK, spaceBefore=4, spaceAfter=4, leading=14,
        leftIndent=10, rightIndent=10, borderPadding=(5, 8, 5, 8))
    return base

# โ”€โ”€ Helper: coloured section header โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
def sec_hdr(title, bg, styles):
    p = Paragraph(title, styles["SecHead"])
    t = Table([[p]], colWidths=[170*mm])
    t.setStyle(TableStyle([
        ("BACKGROUND",    (0,0),(-1,-1), bg),
        ("TOPPADDING",    (0,0),(-1,-1), 7),
        ("BOTTOMPADDING", (0,0),(-1,-1), 7),
        ("LEFTPADDING",   (0,0),(-1,-1), 12),
        ("RIGHTPADDING",  (0,0),(-1,-1), 12),
    ]))
    return t

# โ”€โ”€ Cover banner โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
def cover(styles):
    rows = [
        [Paragraph("ATLSยฎ Study Notes", styles["DocTitle"])],
        [Paragraph("Advanced Trauma Life Support", styles["DocSubtitle"])],
        [Paragraph("11th Edition (2025) โ€” American College of Surgeons", styles["DocEdition"])],
    ]
    t = Table(rows, colWidths=[170*mm])
    t.setStyle(TableStyle([
        ("BACKGROUND",    (0,0),(-1,-1), RED_DARK),
        ("TOPPADDING",    (0,0),(-1,-1), 12),
        ("BOTTOMPADDING", (0,0),(-1,-1), 12),
        ("LEFTPADDING",   (0,0),(-1,-1), 14),
        ("RIGHTPADDING",  (0,0),(-1,-1), 14),
    ]))
    return t

# โ”€โ”€ Generic 3-col table โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
def make_table(data, col_widths, header_bg, row_bgs=None, font_size=10):
    t = Table(data, colWidths=col_widths, repeatRows=1)
    ts = [
        ("BACKGROUND",    (0,0),(-1, 0), header_bg),
        ("TEXTCOLOR",     (0,0),(-1, 0), WHITE),
        ("FONTNAME",      (0,0),(-1, 0), "Helvetica-Bold"),
        ("FONTSIZE",      (0,0),(-1,-1), font_size),
        ("ALIGN",         (0,0),(-1, 0), "CENTER"),
        ("VALIGN",        (0,0),(-1,-1), "MIDDLE"),
        ("GRID",          (0,0),(-1,-1), 0.4, GREY_MED),
        ("TOPPADDING",    (0,0),(-1,-1), 5),
        ("BOTTOMPADDING", (0,0),(-1,-1), 5),
        ("LEFTPADDING",   (0,0),(-1,-1), 7),
        ("RIGHTPADDING",  (0,0),(-1,-1), 7),
        ("FONTNAME",      (0,1),(0,-1),  "Helvetica-Bold"),
    ]
    if row_bgs:
        for i, bg in enumerate(row_bgs):
            ts.append(("BACKGROUND", (0,i+1),(-1,i+1), bg))
    t.setStyle(TableStyle(ts))
    return t

# โ”€โ”€ Footer canvas โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
class FooterCanvas(canvasmod.Canvas):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self._saved_page_states = []

    def showPage(self):
        self._saved_page_states.append(dict(self.__dict__))
        self._startPage()

    def save(self):
        n = len(self._saved_page_states)
        for state in self._saved_page_states:
            self.__dict__.update(state)
            self._draw_footer(n)
            canvasmod.Canvas.showPage(self)
        canvasmod.Canvas.save(self)

    def _draw_footer(self, total):
        pg = self.__dict__.get("_pageNumber", 1)
        self.saveState()
        self.setFont("Helvetica", 8)
        self.setFillColor(colors.grey)
        self.drawCentredString(A4[0]/2, 16, f"ATLSยฎ Study Notes  |  Page {pg} of {total}  |  American College of Surgeons 11th Ed. (2025)")
        self.setStrokeColor(RED_DARK)
        self.setLineWidth(0.8)
        self.line(20*mm, 21*mm, A4[0]-20*mm, 21*mm)
        self.restoreState()

# โ”€โ”€ BUILD โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
def build():
    doc = SimpleDocTemplate(
        OUTPUT, pagesize=A4,
        topMargin=15*mm, bottomMargin=28*mm,
        leftMargin=20*mm, rightMargin=20*mm,
        title="ATLS Study Notes", author="Orris AI"
    )
    S = make_styles()
    story = []

    # โ”€โ”€ COVER โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
    story.append(cover(S))
    story.append(Spacer(1, 8))

    # โ”€โ”€ INTRO BOX โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
    story.append(Paragraph(
        "ATLSยฎ is the standardised training program of the American College of Surgeons for "
        "managing acute trauma. Its core principle: <b>treat the greatest threat to life first</b>. "
        "The 11th edition (2025) introduced the landmark shift from ABCDE to <b>X-ABCDE</b>, "
        "prioritising catastrophic external haemorrhage control before airway management.",
        S["BoxBlue"]))
    story.append(Spacer(1, 6))

    # โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
    # SECTION 1 โ€” X-ABCDE PRIMARY SURVEY
    # โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
    story.append(sec_hdr("๐Ÿšจ  Section 1: The Primary Survey โ€” X-ABCDE", RED_MED, S))
    story.append(Spacer(1, 5))

    story.append(Paragraph(
        "The primary survey rapidly identifies and treats <b>immediately life-threatening</b> "
        "conditions. Every step is performed simultaneously with resuscitation.",
        S["BodyTxt"]))

    story.append(Paragraph(
        "๐Ÿ”‘  NEW (11th Ed.): X-ABCDE replaces ABCDE. 'X' = eXsanguinating haemorrhage "
        "control is now the FIRST priority before airway, because catastrophic external "
        "bleeding is the leading correctable cause of preventable trauma death.",
        S["BoxRed"]))
    story.append(Spacer(1, 4))

    xabcde = [
        ["Step", "Stands For",       "Action"],
        ["X",    "eXsanguinating\nHaemorrhage",
                 "Apply direct pressure / tourniquet / wound packing with haemostatic dressing. "
                 "Control life-threatening external bleeding FIRST."],
        ["A",    "Airway +\nC-spine",
                 "Jaw thrust / chin lift. OPA/NPA. In-line C-spine immobilisation. "
                 "RSI/ETT if GCS 3-8 or unable to protect airway."],
        ["B",    "Breathing +\nVentilation",
                 "Assess for tension pneumothorax, open pneumothorax, flail chest, "
                 "massive haemothorax. Needle decompression / chest drain / occlusive dressing."],
        ["C",    "Circulation +\nHaemorrhage",
                 "2 large-bore IVs or IO access. Control internal bleeding. "
                 "Permissive hypotension (SBP 70-90 mmHg) until definitive haemostasis. "
                 "MTP if ongoing haemorrhage."],
        ["D",    "Disability\n(Neurology)",
                 "GCS, pupils (PERRL), blood glucose. GCS < 9 = intubate. "
                 "Prevent secondary brain injury (avoid hypoxia, hypotension)."],
        ["E",    "Exposure +\nEnvironment",
                 "Fully undress patient (cut clothes). Log-roll. "
                 "Prevent hypothermia โ€” warm blankets, warm IV fluids, warm environment."],
    ]
    row_bgs = [RED_LIGHT, BLUE_LIGHT, TEAL_LIGHT, ORANGE_LIGHT, PURPLE_LIGHT, GREEN_LIGHT]
    story.append(make_table(xabcde, [12*mm, 28*mm, 130*mm], RED_MED, row_bgs))
    story.append(Spacer(1, 6))

    # Life threats identified in primary survey
    story.append(Paragraph("Life-Threatening Conditions โ€” Identified in Primary Survey", S["SubHead"]))
    lt_data = [
        ["Condition",               "Step", "Immediate Action"],
        ["Airway obstruction",      "A",    "Jaw thrust, suction, OPA/NPA, RSI/ETT"],
        ["Tension pneumothorax",    "B",    "Needle decompression (2nd ICS MCL) โ†’ chest drain"],
        ["Open pneumothorax",       "B",    "3-sided occlusive dressing โ†’ chest drain"],
        ["Massive haemothorax",     "B/C",  "IV/IO access, chest drain, surgery if > 1500 mL"],
        ["Flail chest",             "B",    "O2, analgesia, PPV if respiratory failure"],
        ["Cardiac tamponade",       "C",    "Pericardiocentesis / emergency thoracotomy"],
        ["Exsanguinating haemorrhage", "X/C", "Tourniquet, packing, MTP, OR/angio"],
    ]
    lt_bgs = [RED_LIGHT, BLUE_LIGHT, TEAL_LIGHT, TEAL_LIGHT,
              ORANGE_LIGHT, RED_LIGHT, RED_LIGHT]
    story.append(make_table(lt_data, [55*mm, 14*mm, 101*mm], RED_DARK, lt_bgs))
    story.append(Spacer(1, 8))

    # โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
    # SECTION 2 โ€” SHOCK & RESUSCITATION
    # โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
    story.append(sec_hdr("๐Ÿฉธ  Section 2: Haemorrhagic Shock โ€” Classification & Resuscitation",
                         ORANGE_DARK, S))
    story.append(Spacer(1, 5))

    story.append(Paragraph(
        "Haemorrhagic shock is classified into four classes based on estimated blood loss "
        "(EBL), vital signs and clinical findings. For a 70 kg adult, total blood volume โ‰ˆ 5 L.",
        S["BodyTxt"]))

    shock_data = [
        ["Parameter",     "Class I",       "Class II",      "Class III",     "Class IV"],
        ["Blood loss (mL)","< 750",         "750โ€“1500",      "1500โ€“2000",     "> 2000"],
        ["Blood loss (%)", "< 15%",         "15โ€“30%",        "30โ€“40%",        "> 40%"],
        ["HR (bpm)",       "< 100",         "100โ€“120",       "120โ€“140",       "> 140"],
        ["BP",             "Normal",        "Normal",        "Decreased",     "Very low"],
        ["RR (breaths/min)","14โ€“20",        "20โ€“30",         "30โ€“40",         "> 35"],
        ["Urine output",   "> 30 mL/hr",   "20โ€“30 mL/hr",   "5โ€“15 mL/hr",    "Negligible"],
        ["Consciousness",  "Anxious",       "Agitated",      "Confused",      "Lethargic/Unconscious"],
        ["Fluid (initial)","Crystalloid",  "Crystalloid",   "Blood + cryst.", "Blood + MTP"],
    ]
    shock_bgs = [ORANGE_LIGHT, AMBER_LIGHT, ORANGE_LIGHT, AMBER_LIGHT,
                 ORANGE_LIGHT, AMBER_LIGHT, ORANGE_LIGHT, AMBER_LIGHT]
    story.append(make_table(shock_data, [40*mm, 32*mm, 32*mm, 33*mm, 33*mm],
                            ORANGE_DARK, shock_bgs, font_size=9.5))
    story.append(Spacer(1, 5))

    story.append(Paragraph(
        "โš   REMEMBER: Elderly patients and those on beta-blockers may NOT show tachycardia "
        "even with significant blood loss โ€” do not rely on HR alone!",
        S["BoxOrange"]))

    story.append(Paragraph(
        "๐Ÿ”‘  HIGHLIGHT: Permissive hypotension โ€” target SBP 70โ€“90 mmHg (or palpable radial "
        "pulse) in penetrating trauma until definitive haemostasis. Avoid in TBI patients "
        "(keep SBP โ‰ฅ 110 mmHg to maintain cerebral perfusion).",
        S["HLYellow"]))

    story.append(Paragraph("Damage Control Resuscitation (DCR)", S["SubHead"]))
    story.append(Paragraph(
        "DCR combines <b>damage control surgery</b> with targeted resuscitation to break "
        "the lethal triad of hypothermia, acidosis and coagulopathy.",
        S["BodyTxt"]))

    dcr_items = [
        ("Apply direct pressure / tourniquet / haemostatic dressing to external bleeding sites."),
        ("Facilitate early transfer to OR or angiography suite for definitive haemorrhage control."),
        ("Minimise crystalloid infusions. Use controlled resuscitation with permissive hypotension."),
        ("Massive Transfusion Protocol (MTP): pRBC : FFP : Platelets in 1:1:1 ratio."),
        ("Tranexamic acid (TXA): 1 g IV over 10 min, then 1 g over 8 hrs โ€” give within 3 hrs of injury."),
        ("Correct hypothermia: warm blankets, warm fluids, warm environment."),
        ("Correct coagulopathy: FFP, cryoprecipitate, calcium supplementation."),
        ("Prevent and treat acidosis by restoring tissue perfusion."),
    ]
    for item in dcr_items:
        story.append(Paragraph(f"โ€ข {item}", S["BulletTxt"]))

    story.append(Paragraph(
        "๐Ÿ”‘  MTP RATIO: pRBC : FFP : Platelets = 1:1:1. Strong evidence supports this. "
        "Type O-negative blood for females of childbearing age; O-positive acceptable for males.",
        S["HLCyan"]))
    story.append(Spacer(1, 8))

    # โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
    # SECTION 3 โ€” AIRWAY MANAGEMENT
    # โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
    story.append(sec_hdr("๐Ÿ’จ  Section 3: Airway Management", BLUE_MED, S))
    story.append(Spacer(1, 5))

    story.append(Paragraph(
        "Airway compromise is rapidly fatal. <b>All trauma patients receive high-flow "
        "O2 (15 L/min via NRB mask)</b> until assessment is complete.",
        S["BodyTxt"]))

    airway_data = [
        ["Technique",                "Indication",                         "Notes"],
        ["Chin lift / Jaw thrust",   "Unconscious but breathing",          "Jaw thrust preferred with C-spine concern"],
        ["OPA (oral pharyngeal)",    "Unconscious, no gag reflex",         "Size = corner of mouth to earlobe"],
        ["NPA (nasal pharyngeal)",   "Semi-conscious / active gag",        "Avoid in suspected base of skull #"],
        ["BVM ventilation",          "Apnoea / agonal breathing",          "2-person technique preferred"],
        ["RSI + Endotracheal tube",  "GCS โ‰ค 8, airway protection needed", "Drug-assisted intubation โ€” ketamine + suxamethonium or rocuronium"],
        ["Surgical airway (cric)",   "Cannot intubate, cannot oxygenate", "Needle cric โ†’ surgical cricothyrotomy"],
        ["Supraglottic airway (iGel/LMA)", "Failed intubation rescue",   "Bridge to definitive airway"],
    ]
    airway_bgs = [BLUE_LIGHT, GREY_LIGHT, BLUE_LIGHT, GREY_LIGHT,
                  BLUE_LIGHT, RED_LIGHT, GREY_LIGHT]
    story.append(make_table(airway_data, [45*mm, 60*mm, 65*mm], BLUE_DARK, airway_bgs))
    story.append(Spacer(1, 5))

    story.append(Paragraph(
        "โš   C-SPINE RULE: Maintain in-line immobilisation until spine injury excluded. "
        "Use jaw thrust (not chin lift) when C-spine injury suspected.",
        S["BoxOrange"]))
    story.append(Paragraph(
        "๐Ÿ”‘  HIGHLIGHT: RSI drugs (11th Ed.) โ€” preference for drug-assisted intubation. "
        "Ketamine (1โ€“2 mg/kg IV) as induction agent is haemodynamically favourable in trauma. "
        "Suxamethonium (1.5 mg/kg) or Rocuronium (1.2 mg/kg) as paralytic.",
        S["HLPink"]))
    story.append(Spacer(1, 8))

    # โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
    # SECTION 4 โ€” SECONDARY SURVEY
    # โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
    story.append(sec_hdr("๐Ÿ”  Section 4: Secondary Survey โ€” Head-to-Toe", TEAL_MED, S))
    story.append(Spacer(1, 5))

    story.append(Paragraph(
        "The secondary survey is a <b>complete head-to-toe examination</b> begun only "
        "after the primary survey is complete and resuscitation is initiated. "
        "It aims to identify ALL injuries.",
        S["BodyTxt"]))

    story.append(Paragraph(
        "โ˜…  AMPLE History: Allergies | Medications | Past medical history | "
        "Last meal | Events leading to injury",
        S["BoxGreen"]))

    story.append(Spacer(1, 4))
    sec_data = [
        ["Region",         "Key Assessments"],
        ["Head & Scalp",   "Lacerations, haematomas, depressed skull fractures, facial fractures"],
        ["Eyes",           "Pupil equality & reactivity, visual acuity, globe injury, periorbital bruising (raccoon eyes)"],
        ["Ears / Nose",    "Haemotympanum, CSF otorrhoea/rhinorrhoea, Battle's sign (mastoid bruising)"],
        ["Maxillofacial",  "Mandible, midface stability, dental injuries, nasal fractures"],
        ["Neck",           "Tracheal deviation, JVD, subcutaneous emphysema, vascular injury, C-spine tenderness"],
        ["Chest",          "Rib tenderness, breath sounds, heart sounds, clavicle/sternum palpation"],
        ["Abdomen",        "Guarding, rigidity, distension, peritonism. FAST scan / CT abdomen"],
        ["Pelvis",         "Single gentle AP compression โ€” do NOT rock (can worsen bleeding). Pelvic binder if unstable"],
        ["Perineum/Rectum","Urethral meatus blood, high-riding prostate, rectal tone"],
        ["Extremities",    "Deformity, vascular status (pulses), neurological function, compartment syndrome"],
        ["Back",           "Log-roll: spine tenderness, posterior injuries, rectal exam"],
        ["Neurological",   "Full GCS reassessment, peripheral motor/sensory exam, reflexes"],
    ]
    sec_bgs = [TEAL_LIGHT, GREY_LIGHT]*7
    story.append(make_table(sec_data, [35*mm, 135*mm], TEAL_DARK, sec_bgs[:len(sec_data)-1]))
    story.append(Spacer(1, 8))

    # โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
    # SECTION 5 โ€” TBI & SPINE
    # โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
    story.append(sec_hdr("๐Ÿง   Section 5: Traumatic Brain Injury (TBI) & Spine", PURPLE_MED, S))
    story.append(Spacer(1, 5))

    story.append(Paragraph("<b>Glasgow Coma Scale (GCS)</b>", S["SubHead"]))
    gcs_data = [
        ["Component",     "Response",                     "Score"],
        ["Eye Opening (E)","Spontaneous",                 "4"],
        ["",              "To voice",                    "3"],
        ["",              "To pain",                     "2"],
        ["",              "None",                        "1"],
        ["Verbal (V)",    "Oriented",                    "5"],
        ["",              "Confused",                    "4"],
        ["",              "Inappropriate words",         "3"],
        ["",              "Incomprehensible sounds",     "2"],
        ["",              "None",                        "1"],
        ["Motor (M)",     "Obeys commands",              "6"],
        ["",              "Localises pain",              "5"],
        ["",              "Withdraws from pain",         "4"],
        ["",              "Abnormal flexion (decorticate)","3"],
        ["",              "Extension (decerebrate)",     "2"],
        ["",              "None",                        "1"],
    ]
    gcs_bgs = [PURPLE_LIGHT, GREY_LIGHT]*8
    story.append(make_table(gcs_data, [45*mm, 100*mm, 25*mm], PURPLE_DARK,
                            gcs_bgs[:len(gcs_data)-1], font_size=10))
    story.append(Spacer(1, 5))

    story.append(Paragraph(
        "๐Ÿ”‘  GCS SCORING: Max = 15 (normal). Min = 3.  "
        "Mild TBI: GCS 13โ€“15 | Moderate TBI: GCS 9โ€“12 | Severe TBI: GCS โ‰ค 8 (intubate).",
        S["HLYellow"]))
    story.append(Paragraph(
        "โš   SECONDARY BRAIN INJURY PREVENTION: Avoid hypoxia (SpO2 < 90%) and "
        "hypotension (SBP < 90 mmHg). These are the two most preventable causes of "
        "worsened outcome in TBI. Target SBP โ‰ฅ 110 mmHg in TBI.",
        S["BoxOrange"]))
    story.append(Paragraph(
        "Herniation signs (Cushing's triad): bradycardia + hypertension + irregular "
        "respirations โ€” indicates critically raised ICP, requires immediate action "
        "(head elevation 30ยฐ, hyperventilate to PaCO2 35-40, mannitol/hypertonic saline, "
        "urgent neurosurgery).",
        S["BoxPurple"]))

    story.append(Spacer(1, 6))
    story.append(Paragraph("Spinal Cord Injury", S["SubHead"]))
    story.append(Paragraph(
        "Maintain in-line immobilisation until radiological clearance. Spinal shock "
        "(hypotension + bradycardia) responds to IV fluids ยฑ vasopressors. "
        "Neurogenic shock is a diagnosis of exclusion โ€” haemorrhagic shock must be ruled out first.",
        S["BodyTxt"]))
    story.append(Paragraph(
        "โš   IMPORTANT (11th Ed.): Routine corticosteroids for acute spinal cord injury "
        "are NO LONGER recommended. Evidence of harm outweighs benefit.",
        S["BoxRed"]))
    story.append(Spacer(1, 8))

    # โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
    # SECTION 6 โ€” SPECIFIC TRAUMA TYPES
    # โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
    story.append(sec_hdr("๐Ÿฆด  Section 6: Specific Injury Patterns", GREEN_MED, S))
    story.append(Spacer(1, 5))

    injuries = [
        ("Tension Pneumothorax",
         "Absent breath sounds + tracheal deviation (AWAY from injury) + haemodynamic collapse. "
         "IMMEDIATE needle decompression (2nd ICS mid-clavicular line OR 4th/5th ICS AAL). "
         "Do NOT wait for CXR!"),
        ("Cardiac Tamponade (Beck's Triad)",
         "Hypotension + muffled heart sounds + JVD. "
         "Mechanism: blunt/penetrating. Echo (FAST) confirms. "
         "Rx: pericardiocentesis or emergency thoracotomy."),
        ("Pelvic Fractures",
         "High-energy mechanism. Can lose 3โ€“4 L blood into retroperitoneum. "
         "Apply pelvic binder early. Do NOT rock the pelvis. "
         "Angioembolisation or preperitoneal packing for haemorrhage control."),
        ("Abdominal Trauma โ€” FAST",
         "eFAST (extended FAST): assesses pericardium, hepatorenal, splenorenal spaces, "
         "pelvis and pleural cavities. Positive FAST + haemodynamic instability = OR. "
         "Stable patient = CT abdomen with contrast."),
        ("Burns",
         "Parkland formula: 4 mL ร— weight (kg) ร— %TBSA burned. Give half in first 8 hrs "
         "(from time of injury), half in next 16 hrs. Use Lactated Ringer's. "
         "Ensure urine output 0.5โ€“1 mL/kg/hr in adults."),
        ("Paediatric Trauma",
         "Weight estimate: (age + 4) ร— 2. Preferred fluid: 20 mL/kg warmed crystalloid bolus. "
         "Blood pressure less reliable indicator โ€” HR is more sensitive for shock. "
         "Anatomical differences: large head, flexible ribs, protuberant abdomen."),
        ("Obstetric Trauma",
         "Left lateral tilt (15โ€“30ยฐ) to relieve aortocaval compression from 20 weeks onwards. "
         "Kleihauer-Betke test for fetomaternal haemorrhage. Anti-D for Rh-negative mothers. "
         "Perimortem C-section if cardiac arrest โ‰ฅ 20 weeks gestation."),
        ("Geriatric Trauma",
         "Anticoagulants/beta-blockers mask haemorrhage signs. Lower threshold for CT and ICU admission. "
         "Pre-existing conditions complicate resuscitation. Higher morbidity and mortality."),
    ]
    for title, text in injuries:
        story.append(Paragraph(f"<b>{title}</b>", S["SubHead"]))
        story.append(Paragraph(text, S["BodyTxt"]))
        story.append(Spacer(1, 3))

    story.append(Spacer(1, 8))

    # โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
    # SECTION 7 โ€” QUICK REFERENCE / MNEMONICS
    # โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
    story.append(HRFlowable(width="100%", thickness=1.5, color=RED_DARK, spaceAfter=8))
    story.append(sec_hdr("๐Ÿ“‹  Section 7: Quick Reference, Mnemonics & Key Numbers", GREY_DARK, S))
    story.append(Spacer(1, 5))

    mnem_data = [
        ["Mnemonic / Rule",           "Expanded"],
        ["X-ABCDE",                   "eXsanguinating haemorrhage โ†’ Airway โ†’ Breathing โ†’ Circulation โ†’ Disability โ†’ Exposure"],
        ["AMPLE (history)",            "Allergies | Medications | Past history | Last meal | Events of injury"],
        ["Beck's Triad",               "Hypotension | Muffled heart sounds | JVD โ†’ Cardiac tamponade"],
        ["Cushing's Triad",            "Hypertension | Bradycardia | Irregular respirations โ†’ Raised ICP"],
        ["Lethal Triad",               "Hypothermia + Acidosis + Coagulopathy โ€” mutually worsening, deadly combination"],
        ["FAST",                       "Focused Assessment with Sonography in Trauma โ€” pericardium, liver, spleen, pelvis"],
        ["eFAST",                      "Extended FAST adds bilateral lung fields for pneumo/haemothorax"],
        ["DCR",                        "Damage Control Resuscitation โ€” early blood products, permissive hypotension, TXA"],
        ["MTP ratio",                  "Massive Transfusion Protocol: pRBC : FFP : Plt = 1:1:1"],
        ["TXA window",                 "Tranexamic acid must be given within 3 hours of injury"],
        ["Parkland (Burns)",           "4 mL ร— kg ร— %TBSA โ€” half in first 8 hrs, half in next 16 hrs"],
        ["GCS severe TBI",             "GCS โ‰ค 8 = intubate to protect airway and prevent secondary injury"],
    ]
    mnem_bgs = [GREY_LIGHT, RED_LIGHT, ORANGE_LIGHT, PURPLE_LIGHT, RED_LIGHT,
                TEAL_LIGHT, TEAL_LIGHT, ORANGE_LIGHT, AMBER_LIGHT, AMBER_LIGHT,
                GREEN_LIGHT, BLUE_LIGHT]
    story.append(make_table(mnem_data, [52*mm, 118*mm], GREY_DARK, mnem_bgs))
    story.append(Spacer(1, 6))

    # Key numbers
    story.append(Paragraph("Critical Numbers at a Glance", S["SubHead"]))
    nums_data = [
        ["Value",                   "Threshold / Target"],
        ["SpO2",                    "โ‰ฅ 94% (โ‰ฅ 99% in TBI)"],
        ["SBP โ€” permissive hypotension", "70โ€“90 mmHg (penetrating trauma, haemorrhage)"],
        ["SBP โ€” TBI",               "โ‰ฅ 110 mmHg"],
        ["Urine output (adult)",    "โ‰ฅ 0.5 mL/kg/hr"],
        ["Urine output (child)",    "1 mL/kg/hr"],
        ["GCS โ€” intubation threshold","โ‰ค 8"],
        ["Haemothorax โ€” surgical",  "> 1500 mL initial drain OR > 200 mL/hr ร— 2-4 hrs"],
        ["ICP normal",              "< 20 mmHg"],
        ["CPP target (TBI)",        "60โ€“70 mmHg"],
        ["TXA โ€” give within",       "3 hours of injury"],
        ["O-neg blood for",         "Females of childbearing age (Rh sensitisation risk)"],
    ]
    nums_bgs = [BLUE_LIGHT, ORANGE_LIGHT, RED_LIGHT, TEAL_LIGHT, TEAL_LIGHT,
                PURPLE_LIGHT, RED_LIGHT, ORANGE_LIGHT, BLUE_LIGHT, BLUE_LIGHT,
                AMBER_LIGHT]
    story.append(make_table(nums_data, [80*mm, 90*mm], BLUE_DARK, nums_bgs))
    story.append(Spacer(1, 8))

    # โ”€โ”€ BUILD โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
    doc.build(story, canvasmaker=FooterCanvas)
    print(f"PDF saved โ†’ {OUTPUT}")

build()
Running Command

python /home/daytona/workspace/colorful-study-notes/create_atls.py 2>&1

Your ATLS study notes PDF is ready! Download it here:

ATLS Study Notes

PDF Document ยท PDF


Here's what's inside, section by section:
SectionColourContent
1. X-ABCDE Primary SurveyRedFull X-ABCDE table + 7 life-threatening conditions & immediate actions
2. Haemorrhagic ShockOrangeClass I-IV shock table + Damage Control Resuscitation principles
3. Airway ManagementBlue7 airway techniques from basic to surgical cric + RSI drugs
4. Secondary SurveyTealHead-to-toe 13-region examination table + AMPLE history
5. TBI & SpinePurpleFull GCS scoring table + secondary brain injury prevention
6. Specific Injury PatternsGreenTension pneumo, tamponade, pelvis, FAST, burns, paeds, obstetric, geriatric
7. Quick ReferenceGreyAll mnemonics (X-ABCDE, AMPLE, Beck's, Cushing's, lethal triad) + critical numbers table
Key 11th Edition (2025) updates highlighted throughout:
  • ๐Ÿ”ด X-ABCDE replaces ABCDE - exsanguinating haemorrhage control is now the FIRST step
  • ๐ŸŸก Drug-assisted intubation (ketamine preferred) now formally recommended
  • ๐ŸŸ  Permissive hypotension (SBP 70-90 mmHg) - explicitly defined
  • ๐Ÿ”ด Corticosteroids for spinal cord injury - NO LONGER recommended
  • ๐Ÿฉต TXA must be given within 3 hours of injury
This is a shared conversation. Sign in to Orris to start your own chat.