Please prepare similar similar handbook for ESL 3rd grade students with similar variety of logical questions and answers under them (not funny ) questions on remaining topic like object pronouns,demonstrative pronouns and possessive pronouns, because possessive adjectives you have already made.

Reading File
Running Command

cd /home/daytona/workspace/attachments/469133f1-f8b2-45f4-bccf-c1a2a94490f5/ && …

Running Command

cd /home/daytona/workspace/attachments/469133f1-f8b2-45f4-bccf-c1a2a94490f5/ && …

Reading File
Running Command

mkdir -p /home/daytona/workspace/esl-pronouns && ls /home/daytona/workspace/esl-…

Writing File

~/esl-pronouns/build_handbooks.py

"""
ESL Grade 3 Pronouns Handbooks
Builds three PDFs: Object Pronouns, Demonstrative Pronouns, Possessive Pronouns
Matches the style of the existing Possessive Adjectives handbook.
"""

from reportlab.lib.pagesizes import A4
from reportlab.lib import colors
from reportlab.lib.units import cm
from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
from reportlab.lib.enums import TA_CENTER, TA_LEFT, TA_JUSTIFY
from reportlab.platypus import (
    SimpleDocTemplate, Paragraph, Spacer, Table, TableStyle, HRFlowable, KeepTogether
)
from reportlab.pdfbase import pdfmetrics
from reportlab.pdfbase.ttfonts import TTFont
import os

# ── Colours (matching the blue-teal palette of the original) ──────────────────
DARK_BLUE   = colors.HexColor("#1B3A6B")
TEAL        = colors.HexColor("#0A7D8C")
LIGHT_TEAL  = colors.HexColor("#D9F0F3")
GOLD        = colors.HexColor("#F5A623")
LIGHT_GOLD  = colors.HexColor("#FFF8E7")
WHITE       = colors.white
GREY_BG     = colors.HexColor("#F4F6F9")
DARK_TEXT   = colors.HexColor("#1A1A2E")
Q_BLUE      = colors.HexColor("#E8F4FD")
A_GREEN     = colors.HexColor("#E8F9EE")

PAGE_W, PAGE_H = A4

# ── Helper: base doc ──────────────────────────────────────────────────────────
def make_doc(filename):
    return SimpleDocTemplate(
        filename,
        pagesize=A4,
        leftMargin=2*cm, rightMargin=2*cm,
        topMargin=1.8*cm, bottomMargin=1.8*cm
    )

# ── Styles ────────────────────────────────────────────────────────────────────
ss = getSampleStyleSheet()

def sty(name, **kw):
    base = kw.pop("parent", "Normal")
    s = ParagraphStyle(name, parent=ss[base], **kw)
    return s

COVER_TITLE   = sty("CoverTitle",  fontSize=34, leading=40, alignment=TA_CENTER,
                     textColor=WHITE, fontName="Helvetica-Bold")
COVER_SUB     = sty("CoverSub",    fontSize=16, leading=22, alignment=TA_CENTER,
                     textColor=LIGHT_TEAL, fontName="Helvetica")
COVER_RU      = sty("CoverRu",     fontSize=13, leading=18, alignment=TA_CENTER,
                     textColor=colors.HexColor("#C8E6F5"), fontName="Helvetica")
COVER_BAND    = sty("CoverBand",   fontSize=11, leading=16, alignment=TA_CENTER,
                     textColor=WHITE, fontName="Helvetica")
COVER_TAGLINE = sty("CoverTag",    fontSize=10, leading=14, alignment=TA_CENTER,
                     textColor=colors.HexColor("#FFE0A0"), fontName="Helvetica-Oblique")

SEC_HEAD      = sty("SecHead",     fontSize=15, leading=20, alignment=TA_CENTER,
                     textColor=DARK_BLUE, fontName="Helvetica-Bold")
SEC_HEAD_RU   = sty("SecHeadRu",   fontSize=11, leading=15, alignment=TA_CENTER,
                     textColor=TEAL, fontName="Helvetica-Oblique")

BODY          = sty("Body",        fontSize=11, leading=16, alignment=TA_JUSTIFY,
                     textColor=DARK_TEXT, fontName="Helvetica")
BODY_RU       = sty("BodyRu",      fontSize=10, leading=14, alignment=TA_JUSTIFY,
                     textColor=colors.HexColor("#444466"), fontName="Helvetica-Oblique")

EXAMPLE_EN    = sty("ExEN",        fontSize=11, leading=16, alignment=TA_LEFT,
                     textColor=DARK_BLUE, fontName="Helvetica-Bold")
EXAMPLE_RU    = sty("ExRU",        fontSize=10, leading=14, alignment=TA_LEFT,
                     textColor=TEAL, fontName="Helvetica-Oblique")

Q_STYLE       = sty("QStyle",      fontSize=11, leading=16, alignment=TA_LEFT,
                     textColor=DARK_BLUE, fontName="Helvetica-Bold")
A_STYLE       = sty("AStyle",      fontSize=11, leading=16, alignment=TA_LEFT,
                     textColor=colors.HexColor("#1A6B2E"), fontName="Helvetica")
RU_Q          = sty("RuQ",         fontSize=9,  leading=13, alignment=TA_LEFT,
                     textColor=colors.HexColor("#555577"), fontName="Helvetica-Oblique")
RU_A          = sty("RuA",         fontSize=9,  leading=13, alignment=TA_LEFT,
                     textColor=colors.HexColor("#2A7A44"), fontName="Helvetica-Oblique")

TABLE_HEADER  = sty("TblHdr",      fontSize=11, leading=14, alignment=TA_CENTER,
                     textColor=WHITE, fontName="Helvetica-Bold")
TABLE_CELL    = sty("TblCell",     fontSize=10, leading=13, alignment=TA_LEFT,
                     textColor=DARK_TEXT, fontName="Helvetica")
TABLE_RU      = sty("TblRu",       fontSize=9,  leading=12, alignment=TA_LEFT,
                     textColor=colors.HexColor("#555577"), fontName="Helvetica-Oblique")

NOTE_STYLE    = sty("Note",        fontSize=10, leading=14, alignment=TA_CENTER,
                     textColor=DARK_BLUE, fontName="Helvetica-Bold")
NOTE_RU       = sty("NoteRu",      fontSize=9,  leading=13, alignment=TA_CENTER,
                     textColor=TEAL, fontName="Helvetica-Oblique")

# ── Reusable page-section divider ─────────────────────────────────────────────
def divider():
    return HRFlowable(width="100%", thickness=1.5, color=TEAL, spaceAfter=6, spaceBefore=6)

# ── Coloured box paragraph ────────────────────────────────────────────────────
def colour_box(content_rows, bg=LIGHT_TEAL, padding=8, col_widths=None):
    """Wrap paragraphs in a single-cell table to get a coloured background."""
    inner = []
    for row in content_rows:
        if isinstance(row, str):
            inner.append(Paragraph(row, BODY))
        else:
            inner.append(row)
    data = [[inner]]
    col_w = col_widths or [PAGE_W - 4*cm]
    t = Table(data, colWidths=col_w)
    t.setStyle(TableStyle([
        ("BACKGROUND",  (0,0), (-1,-1), bg),
        ("ROUNDEDCORNERS", [8]),
        ("BOX",         (0,0), (-1,-1), 0.5, TEAL),
        ("TOPPADDING",  (0,0), (-1,-1), padding),
        ("BOTTOMPADDING",(0,0),(-1,-1), padding),
        ("LEFTPADDING", (0,0), (-1,-1), padding),
        ("RIGHTPADDING",(0,0), (-1,-1), padding),
        ("VALIGN",      (0,0), (-1,-1), "TOP"),
    ]))
    return t

# ── Cover page helper ─────────────────────────────────────────────────────────
def cover_page(story, en_title, ru_title, pronoun_list_en, pronoun_list_ru, emoji_row="📚 ✏️ 📚"):
    """Build a cover page matching the original handbook."""
    # Full-width navy header box
    header_data = [[
        Paragraph(f"Grade 3 ESL", COVER_BAND),
    ]]
    header_data2 = [[
        Paragraph("3-й класс ЭСЛ", COVER_BAND),
    ]]
    # Build cover as a big coloured table
    cover_table_data = [
        [Paragraph(emoji_row, sty("emoji", fontSize=26, leading=32, alignment=TA_CENTER, fontName="Helvetica"))],
        [Spacer(1, 0.3*cm)],
        [Paragraph(en_title, COVER_TITLE)],
        [Paragraph(ru_title, COVER_RU)],
        [Spacer(1, 0.4*cm)],
        [Paragraph("Handbook – Table, Formula & Conversations", COVER_SUB)],
        [Paragraph("Справочник – таблица, формула и разговоры", COVER_RU)],
        [Spacer(1, 0.4*cm)],
        [Paragraph(pronoun_list_en, COVER_BAND)],
        [Paragraph(pronoun_list_ru, COVER_RU)],
        [Spacer(1, 0.5*cm)],
        [Paragraph("English ⇄ Russian", sty("lang", fontSize=13, leading=18, alignment=TA_CENTER,
                     textColor=GOLD, fontName="Helvetica-Bold"))],
        [Paragraph("Английский ⇄ Русский", COVER_RU)],
        [Spacer(1, 0.5*cm)],
        [Paragraph("Made with ❤️ for young learners", COVER_TAGLINE)],
        [Paragraph("Создано с ❤️ для юных учеников", COVER_TAGLINE)],
    ]
    cover_t = Table(cover_table_data, colWidths=[PAGE_W - 4*cm])
    cover_t.setStyle(TableStyle([
        ("BACKGROUND",      (0,0), (-1,-1), DARK_BLUE),
        ("ALIGN",           (0,0), (-1,-1), "CENTER"),
        ("VALIGN",          (0,0), (-1,-1), "MIDDLE"),
        ("TOPPADDING",      (0,0), (-1,-1), 6),
        ("BOTTOMPADDING",   (0,0), (-1,-1), 6),
        ("LEFTPADDING",     (0,0), (-1,-1), 18),
        ("RIGHTPADDING",    (0,0), (-1,-1), 18),
        ("BOX",             (0,0), (-1,-1), 2, GOLD),
    ]))
    story.append(cover_t)
    story.append(Spacer(1, 0.5*cm))

# ── Q&A block ─────────────────────────────────────────────────────────────────
def qa_block(story, q_en, q_ru, a_en, a_ru, q_num):
    """Render a single Q-and-A pair in the conversation style."""
    q_data = [
        [Paragraph(f"❓ Q{q_num}: {q_en}", Q_STYLE)],
        [Paragraph(q_ru, RU_Q)],
    ]
    a_data = [
        [Paragraph(f"✅ {a_en}", A_STYLE)],
        [Paragraph(a_ru, RU_A)],
    ]
    w = [PAGE_W - 4*cm]
    qt = Table(q_data, colWidths=w)
    qt.setStyle(TableStyle([
        ("BACKGROUND", (0,0),(-1,-1), Q_BLUE),
        ("BOX",        (0,0),(-1,-1), 0.5, TEAL),
        ("TOPPADDING", (0,0),(-1,-1), 5),
        ("BOTTOMPADDING",(0,0),(-1,-1), 5),
        ("LEFTPADDING",(0,0),(-1,-1), 8),
        ("RIGHTPADDING",(0,0),(-1,-1), 8),
    ]))
    at = Table(a_data, colWidths=w)
    at.setStyle(TableStyle([
        ("BACKGROUND", (0,0),(-1,-1), A_GREEN),
        ("BOX",        (0,0),(-1,-1), 0.5, colors.HexColor("#4CAF50")),
        ("TOPPADDING", (0,0),(-1,-1), 5),
        ("BOTTOMPADDING",(0,0),(-1,-1), 5),
        ("LEFTPADDING",(0,0),(-1,-1), 8),
        ("RIGHTPADDING",(0,0),(-1,-1), 8),
    ]))
    story.append(KeepTogether([qt, Spacer(1,0.15*cm), at, Spacer(1,0.3*cm)]))

# ══════════════════════════════════════════════════════════════════════════════
# BOOK 1 – OBJECT PRONOUNS
# ══════════════════════════════════════════════════════════════════════════════
def build_object_pronouns():
    out = "/home/daytona/workspace/esl-pronouns/ESL_Grade3_Object_Pronouns.pdf"
    doc = make_doc(out)
    story = []

    # ── Cover ────────────────────────────────────────────────────────────────
    cover_page(
        story,
        en_title="Object\nPronouns",
        ru_title="Объектные местоимения",
        pronoun_list_en="Me • You • Him • Her • It • Us • Them",
        pronoun_list_ru="Меня • Тебя • Его • Её • Его/Её • Нас • Их",
        emoji_row="📚 ✏️ 📚"
    )

    # ── Page 2 – What is an Object Pronoun? ───────────────────────────────────
    story.append(divider())
    story.append(Paragraph("What is an Object Pronoun? 🤔", SEC_HEAD))
    story.append(Paragraph("Что такое объектное местоимение?", SEC_HEAD_RU))
    story.append(Spacer(1, 0.3*cm))

    defn_rows = [
        Paragraph("An <b>object pronoun</b> replaces the name of a person or thing that receives the action of a verb. It always comes <b>after</b> the verb or a preposition.", BODY),
        Spacer(1, 0.2*cm),
        Paragraph("<b>Объектное местоимение</b> заменяет имя человека или предмета, на которое направлено действие глагола. Оно всегда стоит <b>после</b> глагола или предлога.", BODY_RU),
    ]
    story.append(colour_box(defn_rows, bg=LIGHT_TEAL))
    story.append(Spacer(1, 0.3*cm))

    examples = [
        ("🤔 She sees <b>me</b> every morning.", "Она видит <b>меня</b> каждое утро."),
        ("🤔 The teacher called <b>him</b>.", "Учитель позвал <b>его</b>."),
        ("🤔 Can you help <b>us</b>?", "Можешь помочь <b>нам</b>?"),
    ]
    for en, ru in examples:
        story.append(Paragraph(en, EXAMPLE_EN))
        story.append(Paragraph(ru, EXAMPLE_RU))
        story.append(Spacer(1, 0.15*cm))

    # ── Page 3 – Table ────────────────────────────────────────────────────────
    story.append(divider())
    story.append(Paragraph("🤔 Object Pronouns Table", SEC_HEAD))
    story.append(Paragraph("Таблица объектных местоимений", SEC_HEAD_RU))
    story.append(Spacer(1, 0.25*cm))

    tbl_data = [
        [Paragraph("Object Pronoun (EN)\nОбъектное местоимение", TABLE_HEADER),
         Paragraph("Russian Translation\nПеревод на русский", TABLE_HEADER),
         Paragraph("Example Sentence\nПример предложения", TABLE_HEADER)],
        [Paragraph("ME\nМЕНЯ", TABLE_CELL), Paragraph("меня / мне\nМЕНЯ / МНЕ", TABLE_RU), Paragraph("She called me.\nОна позвонила мне.", TABLE_CELL)],
        [Paragraph("YOU\nТЕБЯ / ВАС", TABLE_CELL), Paragraph("тебя / вас\nТЕБЯ / ВАС", TABLE_RU), Paragraph("I see you every day.\nЯ вижу тебя каждый день.", TABLE_CELL)],
        [Paragraph("HIM\nЕГО", TABLE_CELL), Paragraph("его / ему\nЕГО / ЕМУ", TABLE_RU), Paragraph("We helped him.\nМы помогли ему.", TABLE_CELL)],
        [Paragraph("HER\nЕЁ", TABLE_CELL), Paragraph("её / ей\nЕЁ / ЕЙ", TABLE_RU), Paragraph("He thanked her.\nОн поблагодарил её.", TABLE_CELL)],
        [Paragraph("IT\nЕГО / ЕЁ", TABLE_CELL), Paragraph("его / её\nЕГО / ЕЁ", TABLE_RU), Paragraph("I can see it clearly.\nЯ вижу его отчётливо.", TABLE_CELL)],
        [Paragraph("US\nНАС", TABLE_CELL), Paragraph("нас / нам\nНАС / НАМ", TABLE_RU), Paragraph("She invited us.\nОна пригласила нас.", TABLE_CELL)],
        [Paragraph("THEM\nИХ", TABLE_CELL), Paragraph("их / им\nИХ / ИМ", TABLE_RU), Paragraph("I know them well.\nЯ знаю их хорошо.", TABLE_CELL)],
    ]
    col_w = [4*cm, 4.5*cm, 7*cm]
    tbl = Table(tbl_data, colWidths=col_w, repeatRows=1)
    tbl.setStyle(TableStyle([
        ("BACKGROUND",    (0,0), (-1,0), DARK_BLUE),
        ("BACKGROUND",    (0,1), (-1,1), LIGHT_TEAL),
        ("BACKGROUND",    (0,2), (-1,2), WHITE),
        ("BACKGROUND",    (0,3), (-1,3), LIGHT_TEAL),
        ("BACKGROUND",    (0,4), (-1,4), WHITE),
        ("BACKGROUND",    (0,5), (-1,5), LIGHT_TEAL),
        ("BACKGROUND",    (0,6), (-1,6), WHITE),
        ("BACKGROUND",    (0,7), (-1,7), LIGHT_TEAL),
        ("BOX",           (0,0), (-1,-1), 1, TEAL),
        ("INNERGRID",     (0,0), (-1,-1), 0.5, TEAL),
        ("TOPPADDING",    (0,0), (-1,-1), 5),
        ("BOTTOMPADDING", (0,0), (-1,-1), 5),
        ("LEFTPADDING",   (0,0), (-1,-1), 6),
        ("RIGHTPADDING",  (0,0), (-1,-1), 6),
        ("VALIGN",        (0,0), (-1,-1), "MIDDLE"),
    ]))
    story.append(tbl)

    # ── Page 4 – Formula ──────────────────────────────────────────────────────
    story.append(Spacer(1, 0.4*cm))
    story.append(divider())
    story.append(Paragraph("✏️ Formula to Build Sentences", SEC_HEAD))
    story.append(Paragraph("Формула для составления предложений", SEC_HEAD_RU))
    story.append(Spacer(1, 0.2*cm))

    formula_data = [[
        Paragraph("SUBJECT", TABLE_HEADER),
        Paragraph("+", TABLE_HEADER),
        Paragraph("VERB", TABLE_HEADER),
        Paragraph("+", TABLE_HEADER),
        Paragraph("OBJECT PRONOUN", TABLE_HEADER),
    ]]
    ftbl = Table(formula_data, colWidths=[3.5*cm, 0.8*cm, 3.5*cm, 0.8*cm, 5.4*cm])
    ftbl.setStyle(TableStyle([
        ("BACKGROUND",    (0,0), (0,0), DARK_BLUE),
        ("BACKGROUND",    (1,0), (1,0), WHITE),
        ("BACKGROUND",    (2,0), (2,0), TEAL),
        ("BACKGROUND",    (3,0), (3,0), WHITE),
        ("BACKGROUND",    (4,0), (4,0), GOLD),
        ("BOX",           (0,0), (-1,-1), 1, DARK_BLUE),
        ("INNERGRID",     (0,0), (-1,-1), 0.5, TEAL),
        ("TOPPADDING",    (0,0), (-1,-1), 7),
        ("BOTTOMPADDING", (0,0), (-1,-1), 7),
        ("ALIGN",         (0,0), (-1,-1), "CENTER"),
        ("VALIGN",        (0,0), (-1,-1), "MIDDLE"),
    ]))
    story.append(ftbl)
    story.append(Spacer(1, 0.25*cm))

    story.append(Paragraph("🤔 Example Sentences / Примеры предложений", SEC_HEAD))
    story.append(Spacer(1, 0.15*cm))

    formula_examples = [
        ("She", "sees", "me", "Она видит меня."),
        ("We", "helped", "him", "Мы помогли ему."),
        ("The teacher", "called", "them", "Учитель позвал их."),
        ("I", "will call", "you tomorrow", "Я позвоню тебе завтра."),
        ("They", "surprised", "us", "Они удивили нас."),
        ("He", "thanked", "her", "Он поблагодарил её."),
    ]
    fe_data = [[Paragraph("Subject\nПодлежащее", TABLE_HEADER),
                Paragraph("Verb\nГлагол", TABLE_HEADER),
                Paragraph("Object Pronoun\nОбъектное мест.", TABLE_HEADER),
                Paragraph("Translation\nПеревод", TABLE_HEADER)]]
    for s, v, op, ru in formula_examples:
        fe_data.append([Paragraph(s, TABLE_CELL), Paragraph(v, TABLE_CELL),
                        Paragraph(op, TABLE_CELL), Paragraph(ru, TABLE_RU)])
    fetbl = Table(fe_data, colWidths=[3.5*cm, 3*cm, 4*cm, 5*cm], repeatRows=1)
    fetbl.setStyle(TableStyle([
        ("BACKGROUND",    (0,0), (-1,0), DARK_BLUE),
        ("ROWBACKGROUNDS",(0,1), (-1,-1), [LIGHT_GOLD, WHITE]),
        ("BOX",           (0,0), (-1,-1), 1, TEAL),
        ("INNERGRID",     (0,0), (-1,-1), 0.5, TEAL),
        ("TOPPADDING",    (0,0), (-1,-1), 4),
        ("BOTTOMPADDING", (0,0), (-1,-1), 4),
        ("LEFTPADDING",   (0,0), (-1,-1), 5),
        ("RIGHTPADDING",  (0,0), (-1,-1), 5),
        ("VALIGN",        (0,0), (-1,-1), "MIDDLE"),
    ]))
    story.append(fetbl)

    # ── Pages 5–7 – Conversations Q1–Q15 ─────────────────────────────────────
    conversations = [
        # Q, Q_ru, A, A_ru
        ("Who did the teacher call to the board?",
         "Кого учитель вызвал к доске?",
         "She called me. I walked to the board and wrote the answer.",
         "Она вызвала меня. Я подошёл к доске и написал ответ."),

        ("Can you see the bird on the tree?",
         "Ты видишь птицу на дереве?",
         "Yes, I can see it. It is sitting very still on the branch.",
         "Да, я вижу её. Она сидит очень тихо на ветке."),

        ("Did your friends invite you to the party?",
         "Твои друзья пригласили тебя на вечеринку?",
         "Yes, they invited me and I am very excited to go.",
         "Да, они пригласили меня, и я очень рад идти."),

        ("Who helped Tim with his homework?",
         "Кто помог Тиму с домашним заданием?",
         "His older sister helped him. She explained every problem clearly.",
         "Его старшая сестра помогла ему. Она объяснила каждую задачу понятно."),

        ("Did the coach choose Sara for the team?",
         "Тренер выбрал Сару в команду?",
         "Yes, the coach chose her. She is a very fast runner.",
         "Да, тренер выбрал её. Она очень быстро бегает."),

        ("Did you and your class win the quiz?",
         "Ты и твой класс выиграли викторину?",
         "Yes! The principal gave us a trophy and took our photograph.",
         "Да! Директор вручил нам кубок и сфотографировал нас."),

        ("Where are the new books? Did the librarian bring them?",
         "Где новые книги? Библиотекарь принёс их?",
         "Yes, she brought them this morning and put them on the shelf.",
         "Да, она принесла их этим утром и поставила на полку."),

        ("Your dog ran away — did anyone find it?",
         "Твоя собака убежала — кто-нибудь нашёл её?",
         "The neighbour found it and brought it home safely.",
         "Сосед нашёл её и безопасно привёл домой."),

        ("Did your teacher read your story?",
         "Учитель прочитал твой рассказ?",
         "Yes, she read it and said it was very creative.",
         "Да, она прочитала его и сказала, что он очень творческий."),

        ("Can we sit with you at lunch?",
         "Мы можем сесть с тобой на обед?",
         "Of course! You can sit next to me. There is enough room.",
         "Конечно! Вы можете сесть рядом со мной. Места достаточно."),

        ("Did the doctor check Max and Lily?",
         "Врач осмотрел Макса и Лили?",
         "Yes, the doctor checked them and said they are both healthy.",
         "Да, врач осмотрел их и сказал, что они оба здоровы."),

        ("Who did you wave to at the gate?",
         "Кому ты помахал у ворот?",
         "I waved to her. She waved back and smiled at me.",
         "Я помахал ей. Она помахала в ответ и улыбнулась мне."),

        ("Can your father drive us to school?",
         "Твой папа может отвезти нас в школу?",
         "Yes, he can drive us. He leaves at 7:30 every morning.",
         "Да, он может отвезти нас. Он уезжает в 7:30 каждое утро."),

        ("Did the storm damage the fence?",
         "Буря повредила забор?",
         "Yes, it damaged it badly. My father will repair it on Saturday.",
         "Да, она сильно повредила его. Мой папа починит его в субботу."),

        ("Why did the principal call you and Tom?",
         "Почему директор вызвал тебя и Тома?",
         "She called us because we won first place in the science fair.",
         "Она вызвала нас, потому что мы заняли первое место на ярмарке науки."),
    ]

    # Split into 3 pages (Q1-5, Q6-10, Q11-15)
    for page_idx, start in enumerate([0, 5, 10]):
        story.append(divider())
        end = start + 5
        story.append(Paragraph(f"🤔 Conversations – Q{start+1} to Q{end}", SEC_HEAD))
        story.append(Paragraph(f"Разговоры – Вопросы {start+1}–{end}", SEC_HEAD_RU))
        story.append(Spacer(1, 0.25*cm))
        for i, (qe, qr, ae, ar) in enumerate(conversations[start:end], start=start+1):
            qa_block(story, qe, qr, ae, ar, i)

    # ── Page 8 – Quick Reference ──────────────────────────────────────────────
    story.append(divider())
    story.append(Paragraph("🤔 Quick Reference Card", SEC_HEAD))
    story.append(Paragraph("Быстрая справочная карточка", SEC_HEAD_RU))
    story.append(Spacer(1, 0.25*cm))

    qref_data = [
        [Paragraph("Pronoun\nМестоимение", TABLE_HEADER),
         Paragraph("Russian\nПо-русски", TABLE_HEADER),
         Paragraph("Quick Example (EN + RU)\nПример (англ. + рус.)", TABLE_HEADER)],
        [Paragraph("ME\nМЕНЯ", TABLE_CELL),
         Paragraph("меня/мне", TABLE_RU),
         Paragraph("She sees me.\nОна видит меня.", TABLE_CELL)],
        [Paragraph("YOU\nТЕБЯ", TABLE_CELL),
         Paragraph("тебя/вас", TABLE_RU),
         Paragraph("I called you.\nЯ позвонил тебе.", TABLE_CELL)],
        [Paragraph("HIM\nЕГО", TABLE_CELL),
         Paragraph("его/ему", TABLE_RU),
         Paragraph("We helped him.\nМы помогли ему.", TABLE_CELL)],
        [Paragraph("HER\nЕЁ", TABLE_CELL),
         Paragraph("её/ей", TABLE_RU),
         Paragraph("He thanked her.\nОн поблагодарил её.", TABLE_CELL)],
        [Paragraph("IT\nЕГО/ЕЁ", TABLE_CELL),
         Paragraph("его/её", TABLE_RU),
         Paragraph("I can see it.\nЯ вижу его.", TABLE_CELL)],
        [Paragraph("US\nНАС", TABLE_CELL),
         Paragraph("нас/нам", TABLE_RU),
         Paragraph("She invited us.\nОна пригласила нас.", TABLE_CELL)],
        [Paragraph("THEM\nИХ", TABLE_CELL),
         Paragraph("их/им", TABLE_RU),
         Paragraph("I know them.\nЯ знаю их.", TABLE_CELL)],
    ]
    qref_tbl = Table(qref_data, colWidths=[3.5*cm, 4*cm, 8*cm], repeatRows=1)
    qref_tbl.setStyle(TableStyle([
        ("BACKGROUND",    (0,0), (-1,0), DARK_BLUE),
        ("ROWBACKGROUNDS",(0,1), (-1,-1), [LIGHT_TEAL, WHITE]),
        ("BOX",           (0,0), (-1,-1), 1, TEAL),
        ("INNERGRID",     (0,0), (-1,-1), 0.5, TEAL),
        ("TOPPADDING",    (0,0), (-1,-1), 5),
        ("BOTTOMPADDING", (0,0), (-1,-1), 5),
        ("LEFTPADDING",   (0,0), (-1,-1), 6),
        ("RIGHTPADDING",  (0,0), (-1,-1), 6),
        ("VALIGN",        (0,0), (-1,-1), "MIDDLE"),
    ]))
    story.append(qref_tbl)
    story.append(Spacer(1, 0.3*cm))
    story.append(colour_box([
        Paragraph("🤔 Object pronouns come AFTER the verb or preposition!  •  Объектные местоимения стоят ПОСЛЕ глагола или предлога!", NOTE_STYLE)
    ], bg=LIGHT_GOLD))

    doc.build(story)
    print(f"✅ Created: {out}")

# ══════════════════════════════════════════════════════════════════════════════
# BOOK 2 – DEMONSTRATIVE PRONOUNS
# ══════════════════════════════════════════════════════════════════════════════
def build_demonstrative_pronouns():
    out = "/home/daytona/workspace/esl-pronouns/ESL_Grade3_Demonstrative_Pronouns.pdf"
    doc = make_doc(out)
    story = []

    # ── Cover ────────────────────────────────────────────────────────────────
    cover_page(
        story,
        en_title="Demonstrative\nPronouns",
        ru_title="Указательные местоимения",
        pronoun_list_en="This • That • These • Those",
        pronoun_list_ru="Этот/Эта/Это • Тот/Та/То • Эти • Те",
        emoji_row="📚 ✏️ 📚"
    )

    # ── Page 2 – What is a Demonstrative Pronoun? ─────────────────────────────
    story.append(divider())
    story.append(Paragraph("What is a Demonstrative Pronoun? 🤔", SEC_HEAD))
    story.append(Paragraph("Что такое указательное местоимение?", SEC_HEAD_RU))
    story.append(Spacer(1, 0.3*cm))

    defn_rows = [
        Paragraph("A <b>demonstrative pronoun</b> points to a specific person or thing. <b>This</b> and <b>these</b> are used for things that are <b>near</b>. <b>That</b> and <b>those</b> are used for things that are <b>far away</b>.", BODY),
        Spacer(1, 0.2*cm),
        Paragraph("<b>Указательное местоимение</b> указывает на конкретного человека или предмет. <b>This/These</b> — для близких предметов. <b>That/Those</b> — для далёких.", BODY_RU),
    ]
    story.append(colour_box(defn_rows, bg=LIGHT_TEAL))
    story.append(Spacer(1, 0.3*cm))

    examples = [
        ("🤔 <b>This</b> is my pencil. (near me)", "<b>Это</b> мой карандаш. (рядом со мной)"),
        ("🤔 <b>That</b> is a tall building. (far away)", "<b>То</b> — высокое здание. (далеко)"),
        ("🤔 <b>These</b> are my books.", "<b>Эти</b> — мои книги."),
        ("🤔 <b>Those</b> are his shoes.", "<b>Те</b> — его туфли."),
    ]
    for en, ru in examples:
        story.append(Paragraph(en, EXAMPLE_EN))
        story.append(Paragraph(ru, EXAMPLE_RU))
        story.append(Spacer(1, 0.15*cm))

    # ── Page 3 – Table ────────────────────────────────────────────────────────
    story.append(divider())
    story.append(Paragraph("🤔 Demonstrative Pronouns Table", SEC_HEAD))
    story.append(Paragraph("Таблица указательных местоимений", SEC_HEAD_RU))
    story.append(Spacer(1, 0.25*cm))

    tbl_data = [
        [Paragraph("Demonstrative\nУказательное", TABLE_HEADER),
         Paragraph("Number / Distance\nЧисло / Расстояние", TABLE_HEADER),
         Paragraph("Russian\nПо-русски", TABLE_HEADER),
         Paragraph("Example Sentence\nПример", TABLE_HEADER)],
        [Paragraph("THIS\nЭТО", TABLE_CELL),
         Paragraph("Singular / Near\nЕд.ч. / Близко", TABLE_RU),
         Paragraph("этот / эта / это", TABLE_RU),
         Paragraph("This is my bag.\nЭта сумка — моя.", TABLE_CELL)],
        [Paragraph("THAT\nТО", TABLE_CELL),
         Paragraph("Singular / Far\nЕд.ч. / Далеко", TABLE_RU),
         Paragraph("тот / та / то", TABLE_RU),
         Paragraph("That is a big tree.\nТо — большое дерево.", TABLE_CELL)],
        [Paragraph("THESE\nЭТИ", TABLE_CELL),
         Paragraph("Plural / Near\nМн.ч. / Близко", TABLE_RU),
         Paragraph("эти", TABLE_RU),
         Paragraph("These are my crayons.\nЭти — мои карандаши.", TABLE_CELL)],
        [Paragraph("THOSE\nТЕ", TABLE_CELL),
         Paragraph("Plural / Far\nМн.ч. / Далеко", TABLE_RU),
         Paragraph("те", TABLE_RU),
         Paragraph("Those are her books.\nТе — её книги.", TABLE_CELL)],
    ]
    col_w = [3*cm, 4*cm, 4*cm, 5.5*cm]
    tbl = Table(tbl_data, colWidths=col_w, repeatRows=1)
    tbl.setStyle(TableStyle([
        ("BACKGROUND",    (0,0), (-1,0), DARK_BLUE),
        ("BACKGROUND",    (0,1), (-1,1), LIGHT_TEAL),
        ("BACKGROUND",    (0,2), (-1,2), WHITE),
        ("BACKGROUND",    (0,3), (-1,3), LIGHT_TEAL),
        ("BACKGROUND",    (0,4), (-1,4), WHITE),
        ("BOX",           (0,0), (-1,-1), 1, TEAL),
        ("INNERGRID",     (0,0), (-1,-1), 0.5, TEAL),
        ("TOPPADDING",    (0,0), (-1,-1), 5),
        ("BOTTOMPADDING", (0,0), (-1,-1), 5),
        ("LEFTPADDING",   (0,0), (-1,-1), 6),
        ("RIGHTPADDING",  (0,0), (-1,-1), 6),
        ("VALIGN",        (0,0), (-1,-1), "MIDDLE"),
    ]))
    story.append(tbl)

    # Near vs Far visual note
    story.append(Spacer(1, 0.3*cm))
    near_far_data = [
        [Paragraph("📍 NEAR (близко)", sty("nf1", fontSize=11, leading=14, alignment=TA_CENTER,
                    textColor=DARK_BLUE, fontName="Helvetica-Bold")),
         Paragraph("📍 FAR (далеко)", sty("nf2", fontSize=11, leading=14, alignment=TA_CENTER,
                    textColor=DARK_BLUE, fontName="Helvetica-Bold"))],
        [Paragraph("Singular: <b>THIS</b> (ед.ч.)\nPlural: <b>THESE</b> (мн.ч.)", TABLE_CELL),
         Paragraph("Singular: <b>THAT</b> (ед.ч.)\nPlural: <b>THOSE</b> (мн.ч.)", TABLE_CELL)],
    ]
    nf_tbl = Table(near_far_data, colWidths=[7.75*cm, 7.75*cm])
    nf_tbl.setStyle(TableStyle([
        ("BACKGROUND",    (0,0), (0,-1), colors.HexColor("#DFF5E1")),
        ("BACKGROUND",    (1,0), (1,-1), colors.HexColor("#FFF0D0")),
        ("BOX",           (0,0), (-1,-1), 1, TEAL),
        ("INNERGRID",     (0,0), (-1,-1), 0.5, TEAL),
        ("ALIGN",         (0,0), (-1,-1), "CENTER"),
        ("TOPPADDING",    (0,0), (-1,-1), 7),
        ("BOTTOMPADDING", (0,0), (-1,-1), 7),
    ]))
    story.append(nf_tbl)

    # ── Page 4 – Formula ──────────────────────────────────────────────────────
    story.append(Spacer(1, 0.4*cm))
    story.append(divider())
    story.append(Paragraph("✏️ Formula to Build Sentences", SEC_HEAD))
    story.append(Paragraph("Формула для составления предложений", SEC_HEAD_RU))
    story.append(Spacer(1, 0.2*cm))

    formula_data = [[
        Paragraph("DEM. PRONOUN", TABLE_HEADER),
        Paragraph("+", TABLE_HEADER),
        Paragraph("IS / ARE", TABLE_HEADER),
        Paragraph("+", TABLE_HEADER),
        Paragraph("REST OF SENTENCE", TABLE_HEADER),
    ]]
    ftbl = Table(formula_data, colWidths=[4.5*cm, 0.8*cm, 3*cm, 0.8*cm, 5.4*cm])
    ftbl.setStyle(TableStyle([
        ("BACKGROUND",    (0,0), (0,0), DARK_BLUE),
        ("BACKGROUND",    (1,0), (1,0), WHITE),
        ("BACKGROUND",    (2,0), (2,0), TEAL),
        ("BACKGROUND",    (3,0), (3,0), WHITE),
        ("BACKGROUND",    (4,0), (4,0), GOLD),
        ("BOX",           (0,0), (-1,-1), 1, DARK_BLUE),
        ("INNERGRID",     (0,0), (-1,-1), 0.5, TEAL),
        ("TOPPADDING",    (0,0), (-1,-1), 7),
        ("BOTTOMPADDING", (0,0), (-1,-1), 7),
        ("ALIGN",         (0,0), (-1,-1), "CENTER"),
        ("VALIGN",        (0,0), (-1,-1), "MIDDLE"),
    ]))
    story.append(ftbl)
    story.append(Spacer(1, 0.25*cm))

    story.append(Paragraph("🤔 Example Sentences / Примеры предложений", SEC_HEAD))
    story.append(Spacer(1, 0.15*cm))

    formula_examples = [
        ("This", "is", "my notebook.", "Это мой блокнот."),
        ("That", "is", "a very old bridge.", "То — очень старый мост."),
        ("These", "are", "fresh apples.", "Эти — свежие яблоки."),
        ("Those", "are", "my father's tools.", "Те — инструменты моего папы."),
        ("This", "is", "the correct answer.", "Это правильный ответ."),
        ("Those", "are", "wild birds.", "Те — дикие птицы."),
    ]
    fe_data = [[Paragraph("Dem. Pronoun\nУказат. мест.", TABLE_HEADER),
                Paragraph("Verb\nГлагол", TABLE_HEADER),
                Paragraph("Rest\nОстаток", TABLE_HEADER),
                Paragraph("Translation\nПеревод", TABLE_HEADER)]]
    for dp, v, rest, ru in formula_examples:
        fe_data.append([Paragraph(dp, TABLE_CELL), Paragraph(v, TABLE_CELL),
                        Paragraph(rest, TABLE_CELL), Paragraph(ru, TABLE_RU)])
    fetbl = Table(fe_data, colWidths=[3.5*cm, 2.5*cm, 5*cm, 4.5*cm], repeatRows=1)
    fetbl.setStyle(TableStyle([
        ("BACKGROUND",    (0,0), (-1,0), DARK_BLUE),
        ("ROWBACKGROUNDS",(0,1), (-1,-1), [LIGHT_GOLD, WHITE]),
        ("BOX",           (0,0), (-1,-1), 1, TEAL),
        ("INNERGRID",     (0,0), (-1,-1), 0.5, TEAL),
        ("TOPPADDING",    (0,0), (-1,-1), 4),
        ("BOTTOMPADDING", (0,0), (-1,-1), 4),
        ("LEFTPADDING",   (0,0), (-1,-1), 5),
        ("RIGHTPADDING",  (0,0), (-1,-1), 5),
        ("VALIGN",        (0,0), (-1,-1), "MIDDLE"),
    ]))
    story.append(fetbl)

    # ── Conversations Q1–Q15 ──────────────────────────────────────────────────
    conversations = [
        ("What is that tall building near the park?",
         "Что это за высокое здание у парка?",
         "That is the new library. It opened last month and has many books.",
         "То — новая библиотека. Она открылась в прошлом месяце и в ней много книг."),

        ("Are these your colour pencils on the table?",
         "Это твои цветные карандаши на столе?",
         "Yes, these are mine. I use them for my art class every Friday.",
         "Да, эти — мои. Я использую их на уроке рисования каждую пятницу."),

        ("What is this small animal in the box?",
         "Что это за маленькое животное в коробке?",
         "This is a hamster. This is my pet and its name is Peanut.",
         "Это хомяк. Это моё домашнее животное, его зовут Пинат."),

        ("Whose shoes are those by the front door?",
         "Чьи это туфли у парадной двери?",
         "Those are my father's shoes. He always leaves them there after work.",
         "Те — туфли моего папы. Он всегда оставляет их там после работы."),

        ("Is this the right classroom for Grade 3?",
         "Это правильный класс для 3-го класса?",
         "Yes, this is the right one. Our teacher is already inside.",
         "Да, это правильный. Наш учитель уже внутри."),

        ("What are those colourful flags on the wall?",
         "Что это за разноцветные флаги на стене?",
         "Those are country flags. Our teacher put them up for a geography lesson.",
         "Те — флаги стран. Наш учитель повесил их для урока географии."),

        ("Is this water safe to drink?",
         "Эта вода безопасна для питья?",
         "Yes, this is clean drinking water from the school filter.",
         "Да, это чистая питьевая вода из школьного фильтра."),

        ("What are these papers on your desk?",
         "Что это за бумаги на твоём столе?",
         "These are my test results. I got a high score in all subjects.",
         "Это мои результаты тестов. Я получил высокий балл по всем предметам."),

        ("Can you see those children in the yard?",
         "Ты видишь тех детей во дворе?",
         "Yes, I can see them. Those are my classmates playing football.",
         "Да, я вижу их. Те — мои одноклассники, они играют в футбол."),

        ("Whose drawing is this on the board?",
         "Чей это рисунок на доске?",
         "This is Anna's drawing. She drew it during free time today.",
         "Это рисунок Анны. Она нарисовала его сегодня на свободном уроке."),

        ("Are those mountains real or in a picture?",
         "Те горы настоящие или на картинке?",
         "Those are real mountains. We can see them from the school roof.",
         "Те горы настоящие. Мы можем видеть их с крыши школы."),

        ("What is this sweet smell in the kitchen?",
         "Что это за сладкий запах на кухне?",
         "This is the smell of fresh bread. The cook baked it this morning.",
         "Это запах свежего хлеба. Повар испёк его этим утром."),

        ("Are these apples from your garden?",
         "Эти яблоки из вашего сада?",
         "Yes, these are from our garden. My mother picked them yesterday.",
         "Да, эти — из нашего сада. Мама сорвала их вчера."),

        ("What are those bright lights in the sky?",
         "Что это за яркие огни в небе?",
         "Those are stars. On a clear night you can count hundreds of them.",
         "Те — звёзды. В ясную ночь можно сосчитать сотни из них."),

        ("Is this the book you wanted to borrow?",
         "Это та книга, которую ты хотел взять?",
         "Yes, this is the one! I have been looking for it all week.",
         "Да, это она! Я искал её всю неделю."),
    ]

    for start in [0, 5, 10]:
        end = start + 5
        story.append(divider())
        story.append(Paragraph(f"🤔 Conversations – Q{start+1} to Q{end}", SEC_HEAD))
        story.append(Paragraph(f"Разговоры – Вопросы {start+1}–{end}", SEC_HEAD_RU))
        story.append(Spacer(1, 0.25*cm))
        for i, (qe, qr, ae, ar) in enumerate(conversations[start:end], start=start+1):
            qa_block(story, qe, qr, ae, ar, i)

    # ── Quick Reference Card ──────────────────────────────────────────────────
    story.append(divider())
    story.append(Paragraph("🤔 Quick Reference Card", SEC_HEAD))
    story.append(Paragraph("Быстрая справочная карточка", SEC_HEAD_RU))
    story.append(Spacer(1, 0.25*cm))

    qref_data = [
        [Paragraph("Pronoun\nМестоимение", TABLE_HEADER),
         Paragraph("Use\nКогда", TABLE_HEADER),
         Paragraph("Russian\nПо-русски", TABLE_HEADER),
         Paragraph("Quick Example (EN + RU)\nПример", TABLE_HEADER)],
        [Paragraph("THIS\nЭТО", TABLE_CELL),
         Paragraph("Singular / Near\nЕд.ч./Близко", TABLE_RU),
         Paragraph("этот/эта/это", TABLE_RU),
         Paragraph("This is my pen.\nЭто моя ручка.", TABLE_CELL)],
        [Paragraph("THAT\nТО", TABLE_CELL),
         Paragraph("Singular / Far\nЕд.ч./Далеко", TABLE_RU),
         Paragraph("тот/та/то", TABLE_RU),
         Paragraph("That is a cloud.\nТо — облако.", TABLE_CELL)],
        [Paragraph("THESE\nЭТИ", TABLE_CELL),
         Paragraph("Plural / Near\nМн.ч./Близко", TABLE_RU),
         Paragraph("эти", TABLE_RU),
         Paragraph("These are my boots.\nЭти — мои сапоги.", TABLE_CELL)],
        [Paragraph("THOSE\nТЕ", TABLE_CELL),
         Paragraph("Plural / Far\nМн.ч./Далеко", TABLE_RU),
         Paragraph("те", TABLE_RU),
         Paragraph("Those are tall trees.\nТе — высокие деревья.", TABLE_CELL)],
    ]
    qref_tbl = Table(qref_data, colWidths=[3*cm, 3.5*cm, 3.5*cm, 5.5*cm], repeatRows=1)
    qref_tbl.setStyle(TableStyle([
        ("BACKGROUND",    (0,0), (-1,0), DARK_BLUE),
        ("ROWBACKGROUNDS",(0,1), (-1,-1), [LIGHT_TEAL, WHITE]),
        ("BOX",           (0,0), (-1,-1), 1, TEAL),
        ("INNERGRID",     (0,0), (-1,-1), 0.5, TEAL),
        ("TOPPADDING",    (0,0), (-1,-1), 5),
        ("BOTTOMPADDING", (0,0), (-1,-1), 5),
        ("LEFTPADDING",   (0,0), (-1,-1), 6),
        ("RIGHTPADDING",  (0,0), (-1,-1), 6),
        ("VALIGN",        (0,0), (-1,-1), "MIDDLE"),
    ]))
    story.append(qref_tbl)
    story.append(Spacer(1, 0.3*cm))
    story.append(colour_box([
        Paragraph("🤔 THIS/THESE = near you  •  THAT/THOSE = far away  •  THIS/THAT = singular  •  THESE/THOSE = plural", NOTE_STYLE),
        Paragraph("THIS/THESE = рядом  •  THAT/THOSE = далеко  •  THIS/THAT = ед. число  •  THESE/THOSE = мн. число", NOTE_RU),
    ], bg=LIGHT_GOLD))

    doc.build(story)
    print(f"✅ Created: {out}")

# ══════════════════════════════════════════════════════════════════════════════
# BOOK 3 – POSSESSIVE PRONOUNS
# ══════════════════════════════════════════════════════════════════════════════
def build_possessive_pronouns():
    out = "/home/daytona/workspace/esl-pronouns/ESL_Grade3_Possessive_Pronouns.pdf"
    doc = make_doc(out)
    story = []

    # ── Cover ────────────────────────────────────────────────────────────────
    cover_page(
        story,
        en_title="Possessive\nPronouns",
        ru_title="Притяжательные местоимения (самостоятельные)",
        pronoun_list_en="Mine • Yours • His • Hers • Ours • Theirs",
        pronoun_list_ru="Мой/Моя • Твой/Твоя • Его • Её • Наш/Наша • Их",
        emoji_row="📚 ✏️ 📚"
    )

    # ── Page 2 – What is a Possessive Pronoun? ────────────────────────────────
    story.append(divider())
    story.append(Paragraph("What is a Possessive Pronoun? 🤔", SEC_HEAD))
    story.append(Paragraph("Что такое притяжательное местоимение (самостоятельное)?", SEC_HEAD_RU))
    story.append(Spacer(1, 0.3*cm))

    defn_rows = [
        Paragraph("A <b>possessive pronoun</b> shows that something belongs to someone. Unlike possessive adjectives (my, your, his…), possessive pronouns <b>stand alone</b> — they do not come before a noun.", BODY),
        Spacer(1, 0.2*cm),
        Paragraph("<b>Притяжательное местоимение</b> показывает принадлежность. В отличие от притяжательных прилагательных (my, your, his…), оно стоит <b>самостоятельно</b> — без существительного.", BODY_RU),
    ]
    story.append(colour_box(defn_rows, bg=LIGHT_TEAL))
    story.append(Spacer(1, 0.3*cm))

    examples = [
        ("🤔 This pencil is <b>mine</b>.", "Этот карандаш — <b>мой</b>."),
        ("🤔 That red bag is <b>hers</b>.", "Та красная сумка — <b>её</b>."),
        ("🤔 The blue umbrella is <b>ours</b>.", "Синий зонт — <b>наш</b>."),
        ("🤔 Those books are <b>theirs</b>.", "Те книги — <b>их</b>."),
    ]
    for en, ru in examples:
        story.append(Paragraph(en, EXAMPLE_EN))
        story.append(Paragraph(ru, EXAMPLE_RU))
        story.append(Spacer(1, 0.15*cm))

    # ── Possessive Adjective vs Pronoun note ──────────────────────────────────
    story.append(Spacer(1, 0.2*cm))
    cmp_data = [
        [Paragraph("Possessive ADJECTIVE\n(before a noun)", TABLE_HEADER),
         Paragraph("Possessive PRONOUN\n(stands alone)", TABLE_HEADER)],
        [Paragraph("This is <b>my</b> book.\nЭто <b>моя</b> книга.", TABLE_CELL),
         Paragraph("This book is <b>mine</b>.\nЭта книга — <b>моя</b>.", TABLE_CELL)],
        [Paragraph("<b>Your</b> pencil is sharp.\n<b>Твой</b> карандаш острый.", TABLE_CELL),
         Paragraph("The sharp pencil is <b>yours</b>.\nОстрый карандаш — <b>твой</b>.", TABLE_CELL)],
    ]
    cmp_tbl = Table(cmp_data, colWidths=[7.75*cm, 7.75*cm])
    cmp_tbl.setStyle(TableStyle([
        ("BACKGROUND",    (0,0), (-1,0), DARK_BLUE),
        ("BACKGROUND",    (0,1), (0,-1), colors.HexColor("#FFF0D0")),
        ("BACKGROUND",    (1,1), (1,-1), colors.HexColor("#DFF5E1")),
        ("BOX",           (0,0), (-1,-1), 1, TEAL),
        ("INNERGRID",     (0,0), (-1,-1), 0.5, TEAL),
        ("TOPPADDING",    (0,0), (-1,-1), 7),
        ("BOTTOMPADDING", (0,0), (-1,-1), 7),
        ("LEFTPADDING",   (0,0), (-1,-1), 7),
        ("RIGHTPADDING",  (0,0), (-1,-1), 7),
    ]))
    story.append(cmp_tbl)

    # ── Page 3 – Table ────────────────────────────────────────────────────────
    story.append(divider())
    story.append(Paragraph("🤔 Possessive Pronouns Table", SEC_HEAD))
    story.append(Paragraph("Таблица притяжательных местоимений", SEC_HEAD_RU))
    story.append(Spacer(1, 0.25*cm))

    tbl_data = [
        [Paragraph("Possessive Pronoun (EN)\nПритяжательное мест.", TABLE_HEADER),
         Paragraph("Russian Translation\nПеревод на русский", TABLE_HEADER),
         Paragraph("Example Sentence\nПример предложения", TABLE_HEADER)],
        [Paragraph("MINE\nМОЙ/МОЯ/МОЁ/МОИ", TABLE_CELL),
         Paragraph("мой / моя / моё / мои", TABLE_RU),
         Paragraph("This pencil is mine.\nЭтот карандаш — мой.", TABLE_CELL)],
        [Paragraph("YOURS\nТВОЙ/ВАШ", TABLE_CELL),
         Paragraph("твой / твоя / ваш / ваша", TABLE_RU),
         Paragraph("Is this seat yours?\nЭто место твоё?", TABLE_CELL)],
        [Paragraph("HIS\nЕГО", TABLE_CELL),
         Paragraph("его", TABLE_RU),
         Paragraph("The blue jacket is his.\nСиняя куртка — его.", TABLE_CELL)],
        [Paragraph("HERS\nЕЁ", TABLE_CELL),
         Paragraph("её", TABLE_RU),
         Paragraph("That red umbrella is hers.\nТот красный зонт — её.", TABLE_CELL)],
        [Paragraph("OURS\nНАШ/НАША", TABLE_CELL),
         Paragraph("наш / наша / наше / наши", TABLE_RU),
         Paragraph("This classroom is ours.\nЭтот класс — наш.", TABLE_CELL)],
        [Paragraph("THEIRS\nИХ", TABLE_CELL),
         Paragraph("их", TABLE_RU),
         Paragraph("Those bikes are theirs.\nТе велосипеды — их.", TABLE_CELL)],
    ]
    col_w = [4.5*cm, 4.5*cm, 6.5*cm]
    tbl = Table(tbl_data, colWidths=col_w, repeatRows=1)
    tbl.setStyle(TableStyle([
        ("BACKGROUND",    (0,0), (-1,0), DARK_BLUE),
        ("BACKGROUND",    (0,1), (-1,1), LIGHT_TEAL),
        ("BACKGROUND",    (0,2), (-1,2), WHITE),
        ("BACKGROUND",    (0,3), (-1,3), LIGHT_TEAL),
        ("BACKGROUND",    (0,4), (-1,4), WHITE),
        ("BACKGROUND",    (0,5), (-1,5), LIGHT_TEAL),
        ("BACKGROUND",    (0,6), (-1,6), WHITE),
        ("BOX",           (0,0), (-1,-1), 1, TEAL),
        ("INNERGRID",     (0,0), (-1,-1), 0.5, TEAL),
        ("TOPPADDING",    (0,0), (-1,-1), 5),
        ("BOTTOMPADDING", (0,0), (-1,-1), 5),
        ("LEFTPADDING",   (0,0), (-1,-1), 6),
        ("RIGHTPADDING",  (0,0), (-1,-1), 6),
        ("VALIGN",        (0,0), (-1,-1), "MIDDLE"),
    ]))
    story.append(tbl)

    # ── Page 4 – Formula ──────────────────────────────────────────────────────
    story.append(Spacer(1, 0.4*cm))
    story.append(divider())
    story.append(Paragraph("✏️ Formula to Build Sentences", SEC_HEAD))
    story.append(Paragraph("Формула для составления предложений", SEC_HEAD_RU))
    story.append(Spacer(1, 0.2*cm))

    formula_data = [[
        Paragraph("NOUN / SUBJECT", TABLE_HEADER),
        Paragraph("+", TABLE_HEADER),
        Paragraph("IS / ARE", TABLE_HEADER),
        Paragraph("+", TABLE_HEADER),
        Paragraph("POSSESSIVE PRONOUN", TABLE_HEADER),
    ]]
    ftbl = Table(formula_data, colWidths=[4*cm, 0.8*cm, 3*cm, 0.8*cm, 5.9*cm])
    ftbl.setStyle(TableStyle([
        ("BACKGROUND",    (0,0), (0,0), DARK_BLUE),
        ("BACKGROUND",    (1,0), (1,0), WHITE),
        ("BACKGROUND",    (2,0), (2,0), TEAL),
        ("BACKGROUND",    (3,0), (3,0), WHITE),
        ("BACKGROUND",    (4,0), (4,0), GOLD),
        ("BOX",           (0,0), (-1,-1), 1, DARK_BLUE),
        ("INNERGRID",     (0,0), (-1,-1), 0.5, TEAL),
        ("TOPPADDING",    (0,0), (-1,-1), 7),
        ("BOTTOMPADDING", (0,0), (-1,-1), 7),
        ("ALIGN",         (0,0), (-1,-1), "CENTER"),
        ("VALIGN",        (0,0), (-1,-1), "MIDDLE"),
    ]))
    story.append(ftbl)
    story.append(Spacer(1, 0.25*cm))

    story.append(Paragraph("🤔 Example Sentences / Примеры предложений", SEC_HEAD))
    story.append(Spacer(1, 0.15*cm))

    formula_examples = [
        ("This eraser", "is", "mine", "Этот ластик — мой."),
        ("The green backpack", "is", "yours", "Зелёный рюкзак — твой."),
        ("That trophy", "is", "his", "Тот кубок — его."),
        ("The pink water bottle", "is", "hers", "Розовая бутылка воды — её."),
        ("The corner table", "is", "ours", "Угловой стол — наш."),
        ("Those big umbrellas", "are", "theirs", "Те большие зонты — их."),
    ]
    fe_data = [[Paragraph("Noun / Subject\nПодлежащее", TABLE_HEADER),
                Paragraph("Verb\nГлагол", TABLE_HEADER),
                Paragraph("Poss. Pronoun\nПрит. мест.", TABLE_HEADER),
                Paragraph("Translation\nПеревод", TABLE_HEADER)]]
    for s, v, pp, ru in formula_examples:
        fe_data.append([Paragraph(s, TABLE_CELL), Paragraph(v, TABLE_CELL),
                        Paragraph(pp, TABLE_CELL), Paragraph(ru, TABLE_RU)])
    fetbl = Table(fe_data, colWidths=[4.5*cm, 2.5*cm, 3.5*cm, 5*cm], repeatRows=1)
    fetbl.setStyle(TableStyle([
        ("BACKGROUND",    (0,0), (-1,0), DARK_BLUE),
        ("ROWBACKGROUNDS",(0,1), (-1,-1), [LIGHT_GOLD, WHITE]),
        ("BOX",           (0,0), (-1,-1), 1, TEAL),
        ("INNERGRID",     (0,0), (-1,-1), 0.5, TEAL),
        ("TOPPADDING",    (0,0), (-1,-1), 4),
        ("BOTTOMPADDING", (0,0), (-1,-1), 4),
        ("LEFTPADDING",   (0,0), (-1,-1), 5),
        ("RIGHTPADDING",  (0,0), (-1,-1), 5),
        ("VALIGN",        (0,0), (-1,-1), "MIDDLE"),
    ]))
    story.append(fetbl)

    # ── Conversations Q1–Q15 ──────────────────────────────────────────────────
    conversations = [
        ("Whose eraser is on the floor?",
         "Чей ластик лежит на полу?",
         "That eraser is mine. I dropped it when I was writing.",
         "Тот ластик — мой. Я уронил его, когда писал."),

        ("Is this blue jacket yours?",
         "Эта синяя куртка твоя?",
         "Yes, that jacket is mine. I left it on the chair after lunch.",
         "Да, та куртка — моя. Я оставил её на стуле после обеда."),

        ("Whose turn is it to lead the class?",
         "Чья очередь руководить классом?",
         "The turn is his. He is the class leader this week.",
         "Очередь — его. Он дежурный по классу на этой неделе."),

        ("I found a purple water bottle. Is it yours?",
         "Я нашёл фиолетовую бутылку воды. Она твоя?",
         "No, it is not mine. It might be hers — she has a purple one.",
         "Нет, это не моя. Это может быть её — у неё есть фиолетовая."),

        ("Which team won the relay race?",
         "Какая команда выиграла эстафету?",
         "The victory is ours! We practised every day after school.",
         "Победа — наша! Мы тренировались каждый день после школы."),

        ("Are those large bags by the bus theirs?",
         "Те большие сумки у автобуса — их?",
         "Yes, those bags are theirs. Their family is going on a trip.",
         "Да, те сумки — их. Их семья едет в поездку."),

        ("Whose science project got first place?",
         "Чей научный проект занял первое место?",
         "The first-place project is hers. She worked on it for two weeks.",
         "Проект на первом месте — её. Она работала над ним две недели."),

        ("I see two bicycles. Which one is yours?",
         "Я вижу два велосипеда. Который твой?",
         "The red one is mine. The yellow one is my brother's.",
         "Красный — мой. Жёлтый — моего брата."),

        ("Whose idea was it to plant flowers in the garden?",
         "Чья это была идея — посадить цветы в саду?",
         "The idea was ours. The whole class voted for it together.",
         "Идея была наша. Весь класс проголосовал за неё вместе."),

        ("Is that trophy in the cabinet his?",
         "Тот кубок в шкафу — его?",
         "Yes, that trophy is his. He won it at the swimming competition.",
         "Да, тот кубок — его. Он выиграл его на соревнованиях по плаванию."),

        ("Whose homework is on the teacher's table?",
         "Чьё домашнее задание лежит на столе учителя?",
         "The homework on the table is mine. I handed it in this morning.",
         "Домашнее задание на столе — моё. Я сдал его сегодня утром."),

        ("Those colourful drawings on the wall — are they yours?",
         "Те красочные рисунки на стене — твои?",
         "No, they are not mine. Those drawings are theirs — the art club students.",
         "Нет, не мои. Те рисунки — их, учеников кружка рисования."),

        ("This umbrella was left at the door. Is it yours or hers?",
         "Этот зонт оставили у двери. Он твой или её?",
         "It is hers. She forgot it when she ran to catch the school bus.",
         "Он её. Она забыла его, когда бежала на школьный автобус."),

        ("We found a lunch box with no name. Is it yours?",
         "Мы нашли ланч-бокс без имени. Он твой?",
         "Yes, that lunch box is mine! I forgot to write my name on it.",
         "Да, тот ланч-бокс — мой! Я забыл написать на нём своё имя."),

        ("Are those tools in the shed ours or the neighbours'?",
         "Те инструменты в сарае — наши или соседей?",
         "Those tools are ours. My father uses them to fix things at home.",
         "Те инструменты — наши. Папа использует их, чтобы починить что-то дома."),
    ]

    for start in [0, 5, 10]:
        end = start + 5
        story.append(divider())
        story.append(Paragraph(f"🤔 Conversations – Q{start+1} to Q{end}", SEC_HEAD))
        story.append(Paragraph(f"Разговоры – Вопросы {start+1}–{end}", SEC_HEAD_RU))
        story.append(Spacer(1, 0.25*cm))
        for i, (qe, qr, ae, ar) in enumerate(conversations[start:end], start=start+1):
            qa_block(story, qe, qr, ae, ar, i)

    # ── Quick Reference Card ──────────────────────────────────────────────────
    story.append(divider())
    story.append(Paragraph("🤔 Quick Reference Card", SEC_HEAD))
    story.append(Paragraph("Быстрая справочная карточка", SEC_HEAD_RU))
    story.append(Spacer(1, 0.25*cm))

    qref_data = [
        [Paragraph("Pronoun\nМестоимение", TABLE_HEADER),
         Paragraph("Russian\nПо-русски", TABLE_HEADER),
         Paragraph("Quick Example (EN + RU)\nПример (англ. + рус.)", TABLE_HEADER)],
        [Paragraph("MINE\nМОЙ/МОЯ", TABLE_CELL),
         Paragraph("мой/моя/моё/мои", TABLE_RU),
         Paragraph("This pen is mine.\nЭта ручка — моя.", TABLE_CELL)],
        [Paragraph("YOURS\nТВОЙ/ВАШ", TABLE_CELL),
         Paragraph("твой/ваш", TABLE_RU),
         Paragraph("Is this seat yours?\nЭто место твоё?", TABLE_CELL)],
        [Paragraph("HIS\nЕГО", TABLE_CELL),
         Paragraph("его", TABLE_RU),
         Paragraph("The trophy is his.\nКубок — его.", TABLE_CELL)],
        [Paragraph("HERS\nЕЁ", TABLE_CELL),
         Paragraph("её", TABLE_RU),
         Paragraph("The red bag is hers.\nКрасная сумка — её.", TABLE_CELL)],
        [Paragraph("OURS\nНАШ/НАША", TABLE_CELL),
         Paragraph("наш/наша", TABLE_RU),
         Paragraph("This classroom is ours.\nЭтот класс — наш.", TABLE_CELL)],
        [Paragraph("THEIRS\nИХ", TABLE_CELL),
         Paragraph("их", TABLE_RU),
         Paragraph("Those bikes are theirs.\nТе велосипеды — их.", TABLE_CELL)],
    ]
    qref_tbl = Table(qref_data, colWidths=[3.5*cm, 4*cm, 8*cm], repeatRows=1)
    qref_tbl.setStyle(TableStyle([
        ("BACKGROUND",    (0,0), (-1,0), DARK_BLUE),
        ("ROWBACKGROUNDS",(0,1), (-1,-1), [LIGHT_TEAL, WHITE]),
        ("BOX",           (0,0), (-1,-1), 1, TEAL),
        ("INNERGRID",     (0,0), (-1,-1), 0.5, TEAL),
        ("TOPPADDING",    (0,0), (-1,-1), 5),
        ("BOTTOMPADDING", (0,0), (-1,-1), 5),
        ("LEFTPADDING",   (0,0), (-1,-1), 6),
        ("RIGHTPADDING",  (0,0), (-1,-1), 6),
        ("VALIGN",        (0,0), (-1,-1), "MIDDLE"),
    ]))
    story.append(qref_tbl)
    story.append(Spacer(1, 0.3*cm))
    story.append(colour_box([
        Paragraph("🤔 Possessive pronouns stand ALONE — they do NOT come before a noun!  •  Притяжательные местоимения стоят САМОСТОЯТЕЛЬНО — без существительного!", NOTE_STYLE)
    ], bg=LIGHT_GOLD))

    doc.build(story)
    print(f"✅ Created: {out}")

# ── Run all three ─────────────────────────────────────────────────────────────
if __name__ == "__main__":
    build_object_pronouns()
    build_demonstrative_pronouns()
    build_possessive_pronouns()
    print("\n🎉 All three handbooks created successfully!")
Your credits are exhausted. You can purchase a top-up or subscribe to a plan to continue using Orris. If you're already subscribed, your daily credits will reset tomorrow.

Create a Word document summary guide for teachers using these three handbooks

Your credits are exhausted. You can purchase a top-up or subscribe to a plan to continue using Orris. If you're already subscribed, your daily credits will reset tomorrow.

Don't create the word document request, just complete the first mentioned request,I am waiting

Running Command

cd /home/daytona/workspace/esl-pronouns && python3 build_handbooks.py

All three handbooks are ready! Here are your download links:

📘 Handbook 1 - Object Pronouns

ESL Grade3 Object Pronouns

PDF Document · PDF

📗 Handbook 2 - Demonstrative Pronouns

ESL Grade3 Demonstrative Pronouns

PDF Document · PDF

📙 Handbook 3 - Possessive Pronouns

ESL Grade3 Possessive Pronouns

PDF Document · PDF


Each handbook follows the exact same format as your original Possessive Adjectives handbook:
  • Cover page - navy blue with gold border, English title + Russian translation, pronoun list
  • Page 2 - definition box (English + Russian) with 3-4 example sentences
  • Page 3 - colour-coded pronoun table (EN pronoun | Russian translation | Example sentence)
  • Page 4 - sentence-building formula table + 6 worked examples
  • Pages 5-7 - 15 Q&A conversations split across 3 pages (Q1-5, Q6-10, Q11-15), logical and school-context-appropriate (no funny questions), each with English question + Russian translation, English answer + Russian translation
  • Page 8 - Quick Reference Card
Special features per book:
  • Object Pronouns - includes "comes AFTER the verb" reminder
  • Demonstrative Pronouns - includes a NEAR vs. FAR comparison box (This/These vs. That/Those)
  • Possessive Pronouns - includes a Possessive Adjective vs. Possessive Pronoun comparison table (e.g. "my book" vs. "the book is mine")

Please write Russian translation everywhere under every sentence or word where important for my esl student as similar to pdf as I have shared above in the starting .

Reading File
Writing File

~/esl-pronouns/build_handbooks_v2.py

"""
ESL Grade 3 Pronouns Handbooks - Version 2
Full Russian translations under EVERY English line, heading, label, sentence.
Matches the original Possessive Adjectives handbook style exactly.
"""

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

# ── Colours ───────────────────────────────────────────────────────────────────
DARK_BLUE  = colors.HexColor("#1B3A6B")
TEAL       = colors.HexColor("#0A7D8C")
LIGHT_TEAL = colors.HexColor("#D9F0F3")
GOLD       = colors.HexColor("#F5A623")
LIGHT_GOLD = colors.HexColor("#FFF8E7")
WHITE      = colors.white
DARK_TEXT  = colors.HexColor("#1A1A2E")
Q_BLUE     = colors.HexColor("#E8F4FD")
A_GREEN    = colors.HexColor("#E8F9EE")

PAGE_W, PAGE_H = A4

# ── Doc factory ───────────────────────────────────────────────────────────────
def make_doc(filename):
    return SimpleDocTemplate(
        filename, pagesize=A4,
        leftMargin=2*cm, rightMargin=2*cm,
        topMargin=1.8*cm, bottomMargin=1.8*cm
    )

# ── Styles ────────────────────────────────────────────────────────────────────
ss = getSampleStyleSheet()

def sty(name, **kw):
    kw.pop("parent", None)
    return ParagraphStyle(name, parent=ss["Normal"], **kw)

# Cover styles
C_TITLE  = sty("CT",  fontSize=32, leading=38, alignment=TA_CENTER, textColor=WHITE, fontName="Helvetica-Bold")
C_RU     = sty("CR",  fontSize=13, leading=18, alignment=TA_CENTER, textColor=colors.HexColor("#C8E6F5"), fontName="Helvetica-Oblique")
C_SUB    = sty("CS",  fontSize=14, leading=19, alignment=TA_CENTER, textColor=LIGHT_TEAL, fontName="Helvetica")
C_BAND   = sty("CB",  fontSize=11, leading=15, alignment=TA_CENTER, textColor=WHITE, fontName="Helvetica-Bold")
C_RU2   = sty("CR2", fontSize=10, leading=14, alignment=TA_CENTER, textColor=colors.HexColor("#C8E6F5"), fontName="Helvetica-Oblique")
C_TAG    = sty("CTG", fontSize=10, leading=14, alignment=TA_CENTER, textColor=colors.HexColor("#FFE0A0"), fontName="Helvetica-Oblique")
C_GOLD   = sty("CG",  fontSize=13, leading=18, alignment=TA_CENTER, textColor=GOLD, fontName="Helvetica-Bold")

# Section heading styles
H_EN     = sty("HE",  fontSize=14, leading=19, alignment=TA_CENTER, textColor=DARK_BLUE, fontName="Helvetica-Bold")
H_RU     = sty("HR",  fontSize=10, leading=14, alignment=TA_CENTER, textColor=TEAL, fontName="Helvetica-Oblique")

# Body styles
B_EN     = sty("BE",  fontSize=11, leading=16, alignment=TA_JUSTIFY, textColor=DARK_TEXT, fontName="Helvetica")
B_RU     = sty("BR",  fontSize=10, leading=14, alignment=TA_JUSTIFY, textColor=colors.HexColor("#3A3A5C"), fontName="Helvetica-Oblique")

# Example sentence styles
EX_EN    = sty("EE",  fontSize=11, leading=15, alignment=TA_LEFT, textColor=DARK_BLUE, fontName="Helvetica-Bold")
EX_RU    = sty("ER",  fontSize=10, leading=14, alignment=TA_LEFT, textColor=TEAL, fontName="Helvetica-Oblique")

# Table cell styles
TH       = sty("TH",  fontSize=10, leading=13, alignment=TA_CENTER, textColor=WHITE, fontName="Helvetica-Bold")
TC       = sty("TC",  fontSize=10, leading=13, alignment=TA_LEFT,   textColor=DARK_TEXT, fontName="Helvetica-Bold")
TR       = sty("TR",  fontSize=9,  leading=12, alignment=TA_LEFT,   textColor=colors.HexColor("#3A3A5C"), fontName="Helvetica-Oblique")
TC_C     = sty("TCC", fontSize=10, leading=13, alignment=TA_CENTER, textColor=DARK_TEXT, fontName="Helvetica-Bold")

# Q&A styles
Q_EN     = sty("QE",  fontSize=11, leading=15, alignment=TA_LEFT, textColor=DARK_BLUE, fontName="Helvetica-Bold")
Q_RU     = sty("QR",  fontSize=9,  leading=13, alignment=TA_LEFT, textColor=colors.HexColor("#444488"), fontName="Helvetica-Oblique")
A_EN     = sty("AE",  fontSize=11, leading=15, alignment=TA_LEFT, textColor=colors.HexColor("#1A6B2E"), fontName="Helvetica")
A_RU     = sty("AR",  fontSize=9,  leading=13, alignment=TA_LEFT, textColor=colors.HexColor("#2A7A44"), fontName="Helvetica-Oblique")

# Note styles
N_EN     = sty("NE",  fontSize=10, leading=14, alignment=TA_CENTER, textColor=DARK_BLUE, fontName="Helvetica-Bold")
N_RU     = sty("NR",  fontSize=9,  leading=13, alignment=TA_CENTER, textColor=TEAL, fontName="Helvetica-Oblique")

# ── Utilities ─────────────────────────────────────────────────────────────────
def divider():
    return HRFlowable(width="100%", thickness=1.5, color=TEAL, spaceBefore=5, spaceAfter=5)

def sp(h=0.2):
    return Spacer(1, h*cm)

def colbox(items, bg=LIGHT_TEAL, pad=8):
    """Wrap a list of flowables in a coloured rounded box."""
    data = [[items]]
    t = Table(data, colWidths=[PAGE_W - 4*cm])
    t.setStyle(TableStyle([
        ("BACKGROUND",   (0,0),(-1,-1), bg),
        ("BOX",          (0,0),(-1,-1), 0.8, TEAL),
        ("TOPPADDING",   (0,0),(-1,-1), pad),
        ("BOTTOMPADDING",(0,0),(-1,-1), pad),
        ("LEFTPADDING",  (0,0),(-1,-1), pad),
        ("RIGHTPADDING", (0,0),(-1,-1), pad),
        ("VALIGN",       (0,0),(-1,-1), "TOP"),
    ]))
    return t

def bilingual_cell(en_text, ru_text, en_sty=TC, ru_sty=TR):
    """Return a list of Paragraphs: English bold + Russian italic underneath."""
    return [Paragraph(en_text, en_sty), Paragraph(ru_text, ru_sty)]

def header_cell(en_text, ru_text):
    """Table header: white bold EN + white italic RU."""
    ru_sty = sty(f"THR_{en_text[:4]}", fontSize=8, leading=11,
                 alignment=TA_CENTER, textColor=colors.HexColor("#CCE8FF"),
                 fontName="Helvetica-Oblique")
    return [Paragraph(en_text, TH), Paragraph(ru_text, ru_sty)]

# ── Cover page ────────────────────────────────────────────────────────────────
def cover_page(story, en_title, ru_title, pronoun_list_en, pronoun_list_ru):
    rows = [
        [Paragraph("📚 ✏️ 📚", sty("EM", fontSize=24, leading=30, alignment=TA_CENTER, fontName="Helvetica"))],
        [sp(0.2)],
        [Paragraph("Grade 3 ESL", C_BAND)],
        [Paragraph("3-й класс ЭСЛ", C_RU2)],
        [sp(0.3)],
        [Paragraph(en_title, C_TITLE)],
        [Paragraph(ru_title, C_RU)],
        [sp(0.35)],
        [Paragraph("Handbook – Table, Formula &amp; Conversations", C_SUB)],
        [Paragraph("Справочник – таблица, формула и разговоры", C_RU2)],
        [sp(0.3)],
        [Paragraph(pronoun_list_en, C_BAND)],
        [Paragraph(pronoun_list_ru, C_RU2)],
        [sp(0.4)],
        [Paragraph("English ⇄ Russian", C_GOLD)],
        [Paragraph("Английский ⇄ Русский", C_RU2)],
        [sp(0.4)],
        [Paragraph("Made with ❤️ for young learners", C_TAG)],
        [Paragraph("Создано с ❤️ для юных учеников", C_TAG)],
        [sp(0.2)],
    ]
    t = Table(rows, colWidths=[PAGE_W - 4*cm])
    t.setStyle(TableStyle([
        ("BACKGROUND",    (0,0),(-1,-1), DARK_BLUE),
        ("ALIGN",         (0,0),(-1,-1), "CENTER"),
        ("VALIGN",        (0,0),(-1,-1), "MIDDLE"),
        ("TOPPADDING",    (0,0),(-1,-1), 4),
        ("BOTTOMPADDING", (0,0),(-1,-1), 4),
        ("LEFTPADDING",   (0,0),(-1,-1), 14),
        ("RIGHTPADDING",  (0,0),(-1,-1), 14),
        ("BOX",           (0,0),(-1,-1), 2.5, GOLD),
    ]))
    story.append(t)

# ── Q&A block ─────────────────────────────────────────────────────────────────
def qa_block(story, n, q_en, q_ru, a_en, a_ru):
    w = [PAGE_W - 4*cm]
    qt = Table([[Paragraph(f"❓ Q{n}: {q_en}", Q_EN)],
                [Paragraph(q_ru, Q_RU)]], colWidths=w)
    qt.setStyle(TableStyle([
        ("BACKGROUND",   (0,0),(-1,-1), Q_BLUE),
        ("BOX",          (0,0),(-1,-1), 0.5, TEAL),
        ("TOPPADDING",   (0,0),(-1,-1), 5), ("BOTTOMPADDING",(0,0),(-1,-1), 5),
        ("LEFTPADDING",  (0,0),(-1,-1), 8), ("RIGHTPADDING", (0,0),(-1,-1), 8),
    ]))
    at = Table([[Paragraph(f"✅ {a_en}", A_EN)],
                [Paragraph(a_ru, A_RU)]], colWidths=w)
    at.setStyle(TableStyle([
        ("BACKGROUND",   (0,0),(-1,-1), A_GREEN),
        ("BOX",          (0,0),(-1,-1), 0.5, colors.HexColor("#4CAF50")),
        ("TOPPADDING",   (0,0),(-1,-1), 5), ("BOTTOMPADDING",(0,0),(-1,-1), 5),
        ("LEFTPADDING",  (0,0),(-1,-1), 8), ("RIGHTPADDING", (0,0),(-1,-1), 8),
    ]))
    story.append(KeepTogether([qt, sp(0.12), at, sp(0.28)]))

# ── Section heading helper ────────────────────────────────────────────────────
def sec(story, en, ru):
    story.append(divider())
    story.append(Paragraph(en, H_EN))
    story.append(Paragraph(ru, H_RU))
    story.append(sp(0.25))

# ── Formula header row ────────────────────────────────────────────────────────
def formula_block(story, boxes):
    """boxes = list of (EN label, RU label, bg colour)"""
    cells, widths, bg_cmds = [], [], []
    for i, (en, ru, bg) in enumerate(boxes):
        if en == "+":
            cells.append([Paragraph("+", sty(f"pl{i}", fontSize=14, leading=16,
                          alignment=TA_CENTER, textColor=DARK_BLUE, fontName="Helvetica-Bold"))])
            widths.append(0.7*cm)
            bg_cmds.append(("BACKGROUND", (i,0),(i,0), WHITE))
        else:
            ru_sty = sty(f"fru{i}", fontSize=8, leading=11, alignment=TA_CENTER,
                         textColor=colors.HexColor("#CCE8FF") if bg == DARK_BLUE else WHITE,
                         fontName="Helvetica-Oblique")
            cells.append([Paragraph(en, TH), Paragraph(ru, ru_sty)])
            widths.append(None)
            bg_cmds.append(("BACKGROUND", (i,0),(i,0), bg))

    # auto-size non-plus columns
    total_fixed = 0.7 * sum(1 for e,_,_ in boxes if e == "+")
    avail = PAGE_W - 4*cm - total_fixed
    n_real = sum(1 for e,_,_ in boxes if e != "+")
    w_each = avail / n_real if n_real else avail
    widths = [0.7*cm if boxes[i][0]=="+" else w_each for i in range(len(boxes))]

    t = Table([cells], colWidths=widths)
    ts = [
        ("BOX",          (0,0),(-1,-1), 1, DARK_BLUE),
        ("INNERGRID",    (0,0),(-1,-1), 0.5, TEAL),
        ("TOPPADDING",   (0,0),(-1,-1), 7), ("BOTTOMPADDING",(0,0),(-1,-1), 7),
        ("ALIGN",        (0,0),(-1,-1), "CENTER"),
        ("VALIGN",       (0,0),(-1,-1), "MIDDLE"),
    ] + bg_cmds
    t.setStyle(TableStyle(ts))
    story.append(t)
    story.append(sp(0.2))

# ══════════════════════════════════════════════════════════════════════════════
# BOOK 1 – OBJECT PRONOUNS
# ══════════════════════════════════════════════════════════════════════════════
def build_object_pronouns():
    out = "/home/daytona/workspace/esl-pronouns/ESL_Grade3_Object_Pronouns.pdf"
    doc = make_doc(out)
    story = []

    # Cover
    cover_page(story,
        "Object\nPronouns",
        "Объектные местоимения",
        "Me • You • Him • Her • It • Us • Them",
        "Меня • Тебя • Его • Её • Его/Её • Нас • Их")

    # ── Page 2: What is an Object Pronoun? ───────────────────────────────────
    sec(story,
        "What is an Object Pronoun? 🤔",
        "Что такое объектное местоимение?")

    story.append(colbox([
        Paragraph("An <b>object pronoun</b> replaces the name of a person or thing that receives the action of a verb.", B_EN),
        Paragraph("<b>Объектное местоимение</b> заменяет имя человека или предмета, на которое направлено действие глагола.", B_RU),
        sp(0.15),
        Paragraph("It always comes <b>after</b> the verb or a preposition.", B_EN),
        Paragraph("Оно всегда стоит <b>после</b> глагола или предлога.", B_RU),
    ], bg=LIGHT_TEAL))
    story.append(sp(0.3))

    examples = [
        ("🤔 She sees <b>me</b> every morning.", "Она видит <b>меня</b> каждое утро."),
        ("🤔 The teacher called <b>him</b>.", "Учитель позвал <b>его</b>."),
        ("🤔 Can you help <b>us</b>?", "Можешь помочь <b>нам</b>?"),
    ]
    for en, ru in examples:
        story.append(Paragraph(en, EX_EN))
        story.append(Paragraph(ru, EX_RU))
        story.append(sp(0.18))

    # ── Page 3: Pronouns Table ────────────────────────────────────────────────
    sec(story,
        "🤔 Object Pronouns Table",
        "Таблица объектных местоимений")

    hdr = [
        header_cell("Object Pronoun (EN)", "Объектное местоимение"),
        header_cell("Russian Translation", "Перевод на русский"),
        header_cell("Example Sentence", "Пример предложения"),
    ]
    rows = [
        (["ME", "МНЕ / МЕНЯ"],        ["меня / мне", "меня / мне"],         ["She called me.", "Она позвонила мне."]),
        (["YOU", "ТЕБЯ / ВАС"],       ["тебя / вас", "тебя / вас"],         ["I see you every day.", "Я вижу тебя каждый день."]),
        (["HIM", "ЕГО"],              ["его / ему", "его / ему"],            ["We helped him.", "Мы помогли ему."]),
        (["HER", "ЕЁ"],               ["её / ей", "её / ей"],               ["He thanked her.", "Он поблагодарил её."]),
        (["IT", "ЕГО / ЕЁ"],         ["его / её", "его / её"],             ["I can see it clearly.", "Я вижу его отчётливо."]),
        (["US", "НАС"],               ["нас / нам", "нас / нам"],           ["She invited us.", "Она пригласила нас."]),
        (["THEM", "ИХ"],              ["их / им", "их / им"],               ["I know them well.", "Я знаю их хорошо."]),
    ]

    tdata = [hdr]
    for (e1,r1), (e2,r2), (e3,r3) in rows:
        tdata.append([
            [Paragraph(e1, TC), Paragraph(r1, TR)],
            [Paragraph(e2, TC), Paragraph(r2, TR)],
            [Paragraph(e3, TC), Paragraph(r3, TR)],
        ])

    tbl = Table(tdata, colWidths=[4*cm, 4.5*cm, 7*cm], repeatRows=1)
    ts = [
        ("BACKGROUND",    (0,0),(-1,0), DARK_BLUE),
        ("BOX",           (0,0),(-1,-1), 1, TEAL),
        ("INNERGRID",     (0,0),(-1,-1), 0.5, TEAL),
        ("TOPPADDING",    (0,0),(-1,-1), 5), ("BOTTOMPADDING",(0,0),(-1,-1), 5),
        ("LEFTPADDING",   (0,0),(-1,-1), 6), ("RIGHTPADDING", (0,0),(-1,-1), 6),
        ("VALIGN",        (0,0),(-1,-1), "TOP"),
    ]
    for i in range(1, len(tdata)):
        bg = LIGHT_TEAL if i % 2 == 1 else WHITE
        ts.append(("BACKGROUND", (0,i),(-1,i), bg))
    tbl.setStyle(TableStyle(ts))
    story.append(tbl)

    # ── Page 4: Formula ───────────────────────────────────────────────────────
    sec(story,
        "✏️ Formula to Build Sentences",
        "Формула для составления предложений")

    formula_block(story, [
        ("SUBJECT", "ПОДЛЕЖАЩЕЕ", DARK_BLUE),
        ("+", "+", WHITE),
        ("VERB", "ГЛАГОЛ", TEAL),
        ("+", "+", WHITE),
        ("OBJECT PRONOUN", "ОБЪЕКТНОЕ МЕСТОИМЕНИЕ", GOLD),
    ])

    story.append(Paragraph("🤔 Example Sentences", H_EN))
    story.append(Paragraph("Примеры предложений", H_RU))
    story.append(sp(0.15))

    fhdr = [
        header_cell("Subject", "Подлежащее"),
        header_cell("Verb", "Глагол"),
        header_cell("Object Pronoun", "Объектное мест."),
        header_cell("Translation", "Перевод"),
    ]
    frows = [
        ("She",         "sees",       "me",           "Она видит меня."),
        ("We",          "helped",     "him",          "Мы помогли ему."),
        ("The teacher", "called",     "them",         "Учитель позвал их."),
        ("I",           "will call",  "you tomorrow", "Я позвоню тебе завтра."),
        ("They",        "surprised",  "us",           "Они удивили нас."),
        ("He",          "thanked",    "her",          "Он поблагодарил её."),
    ]
    fdata = [fhdr]
    for s, v, op, ru in frows:
        fdata.append([Paragraph(s, TC), Paragraph(v, TC), Paragraph(op, TC), Paragraph(ru, TR)])

    ftbl = Table(fdata, colWidths=[3.5*cm, 3*cm, 4*cm, 5*cm], repeatRows=1)
    fts = [
        ("BACKGROUND",    (0,0),(-1,0), DARK_BLUE),
        ("BOX",           (0,0),(-1,-1), 1, TEAL),
        ("INNERGRID",     (0,0),(-1,-1), 0.5, TEAL),
        ("TOPPADDING",    (0,0),(-1,-1), 4), ("BOTTOMPADDING",(0,0),(-1,-1), 4),
        ("LEFTPADDING",   (0,0),(-1,-1), 5), ("RIGHTPADDING", (0,0),(-1,-1), 5),
        ("VALIGN",        (0,0),(-1,-1), "MIDDLE"),
    ]
    for i in range(1, len(fdata)):
        fts.append(("BACKGROUND", (0,i),(-1,i), LIGHT_GOLD if i%2==1 else WHITE))
    ftbl.setStyle(TableStyle(fts))
    story.append(ftbl)

    # ── Pages 5-7: Conversations ──────────────────────────────────────────────
    convs = [
        ("Who did the teacher call to the board?",
         "Кого учитель вызвал к доске?",
         "She called me. I walked to the board and wrote the answer.",
         "Она вызвала меня. Я подошёл к доске и написал ответ."),
        ("Can you see the bird on the tree?",
         "Ты видишь птицу на дереве?",
         "Yes, I can see it. It is sitting very still on the branch.",
         "Да, я вижу её. Она сидит очень тихо на ветке."),
        ("Did your friends invite you to the party?",
         "Твои друзья пригласили тебя на вечеринку?",
         "Yes, they invited me and I am very excited to go.",
         "Да, они пригласили меня, и я очень рад идти."),
        ("Who helped Tim with his homework?",
         "Кто помог Тиму с домашним заданием?",
         "His older sister helped him. She explained every problem clearly.",
         "Его старшая сестра помогла ему. Она объяснила каждую задачу понятно."),
        ("Did the coach choose Sara for the team?",
         "Тренер выбрал Сару в команду?",
         "Yes, the coach chose her. She is a very fast runner.",
         "Да, тренер выбрал её. Она очень быстро бегает."),
        ("Did you and your class win the quiz?",
         "Ты и твой класс выиграли викторину?",
         "Yes! The principal gave us a trophy and took our photograph.",
         "Да! Директор вручил нам кубок и сфотографировал нас."),
        ("Where are the new books? Did the librarian bring them?",
         "Где новые книги? Библиотекарь принёс их?",
         "Yes, she brought them this morning and put them on the shelf.",
         "Да, она принесла их этим утром и поставила на полку."),
        ("Your dog ran away — did anyone find it?",
         "Твоя собака убежала — кто-нибудь нашёл её?",
         "The neighbour found it and brought it home safely.",
         "Сосед нашёл её и безопасно привёл домой."),
        ("Did your teacher read your story?",
         "Учитель прочитал твой рассказ?",
         "Yes, she read it and said it was very creative.",
         "Да, она прочитала его и сказала, что он очень творческий."),
        ("Can we sit with you at lunch?",
         "Мы можем сесть с тобой на обед?",
         "Of course! You can sit next to me. There is enough room.",
         "Конечно! Вы можете сесть рядом со мной. Места достаточно."),
        ("Did the doctor check Max and Lily?",
         "Врач осмотрел Макса и Лили?",
         "Yes, the doctor checked them and said they are both healthy.",
         "Да, врач осмотрел их и сказал, что они оба здоровы."),
        ("Who did you wave to at the gate?",
         "Кому ты помахал у ворот?",
         "I waved to her. She waved back and smiled at me.",
         "Я помахал ей. Она помахала в ответ и улыбнулась мне."),
        ("Can your father drive us to school?",
         "Твой папа может отвезти нас в школу?",
         "Yes, he can drive us. He leaves at 7:30 every morning.",
         "Да, он может отвезти нас. Он уезжает в 7:30 каждое утро."),
        ("Did the storm damage the fence?",
         "Буря повредила забор?",
         "Yes, it damaged it badly. My father will repair it on Saturday.",
         "Да, она сильно повредила его. Мой папа починит его в субботу."),
        ("Why did the principal call you and Tom?",
         "Почему директор вызвал тебя и Тома?",
         "She called us because we won first place in the science fair.",
         "Она вызвала нас, потому что мы заняли первое место на ярмарке науки."),
    ]

    for start in [0, 5, 10]:
        end = start + 5
        sec(story,
            f"🤔 Conversations – Q{start+1} to Q{end}",
            f"Разговоры – Вопросы {start+1}–{end}")
        for i, (qe,qr,ae,ar) in enumerate(convs[start:end], start=start+1):
            qa_block(story, i, qe, qr, ae, ar)

    # ── Page 8: Quick Reference Card ─────────────────────────────────────────
    sec(story,
        "🤔 Quick Reference Card",
        "Быстрая справочная карточка")

    qhdr = [
        header_cell("Pronoun", "Местоимение"),
        header_cell("Russian", "По-русски"),
        header_cell("Quick Example (EN + RU)", "Пример (англ. + рус.)"),
    ]
    qrows = [
        ("ME\nМЕНЯ",    "меня / мне",   "She sees me.\nОна видит меня."),
        ("YOU\nТЕБЯ",   "тебя / вас",   "I called you.\nЯ позвонил тебе."),
        ("HIM\nЕГО",    "его / ему",    "We helped him.\nМы помогли ему."),
        ("HER\nЕЁ",     "её / ей",      "He thanked her.\nОн поблагодарил её."),
        ("IT\nЕГО/ЕЁ",  "его / её",    "I can see it.\nЯ вижу его."),
        ("US\nНАС",     "нас / нам",    "She invited us.\nОна пригласила нас."),
        ("THEM\nИХ",    "их / им",      "I know them.\nЯ знаю их."),
    ]
    qdata = [qhdr]
    for p, r, ex in qrows:
        qdata.append([Paragraph(p, TC), Paragraph(r, TR), Paragraph(ex, TC)])

    qtbl = Table(qdata, colWidths=[3.5*cm, 4*cm, 8*cm], repeatRows=1)
    qts = [
        ("BACKGROUND",   (0,0),(-1,0), DARK_BLUE),
        ("BOX",          (0,0),(-1,-1), 1, TEAL),
        ("INNERGRID",    (0,0),(-1,-1), 0.5, TEAL),
        ("TOPPADDING",   (0,0),(-1,-1), 5), ("BOTTOMPADDING",(0,0),(-1,-1), 5),
        ("LEFTPADDING",  (0,0),(-1,-1), 6), ("RIGHTPADDING", (0,0),(-1,-1), 6),
        ("VALIGN",       (0,0),(-1,-1), "TOP"),
    ]
    for i in range(1, len(qdata)):
        qts.append(("BACKGROUND",(0,i),(-1,i), LIGHT_TEAL if i%2==1 else WHITE))
    qtbl.setStyle(TableStyle(qts))
    story.append(qtbl)
    story.append(sp(0.3))
    story.append(colbox([
        Paragraph("🤔 Object pronouns come AFTER the verb or preposition!", N_EN),
        Paragraph("Объектные местоимения стоят ПОСЛЕ глагола или предлога!", N_RU),
    ], bg=LIGHT_GOLD))

    doc.build(story)
    print(f"✅ {out}")

# ══════════════════════════════════════════════════════════════════════════════
# BOOK 2 – DEMONSTRATIVE PRONOUNS
# ══════════════════════════════════════════════════════════════════════════════
def build_demonstrative_pronouns():
    out = "/home/daytona/workspace/esl-pronouns/ESL_Grade3_Demonstrative_Pronouns.pdf"
    doc = make_doc(out)
    story = []

    cover_page(story,
        "Demonstrative\nPronouns",
        "Указательные местоимения",
        "This • That • These • Those",
        "Этот/Эта/Это • Тот/Та/То • Эти • Те")

    # ── Page 2: Definition ────────────────────────────────────────────────────
    sec(story,
        "What is a Demonstrative Pronoun? 🤔",
        "Что такое указательное местоимение?")

    story.append(colbox([
        Paragraph("A <b>demonstrative pronoun</b> points to a specific person or thing.", B_EN),
        Paragraph("<b>Указательное местоимение</b> указывает на конкретного человека или предмет.", B_RU),
        sp(0.15),
        Paragraph("<b>This</b> and <b>These</b> = things that are <b>near</b> you.", B_EN),
        Paragraph("<b>This</b> и <b>These</b> = предметы, которые находятся <b>близко</b> к вам.", B_RU),
        sp(0.1),
        Paragraph("<b>That</b> and <b>Those</b> = things that are <b>far away</b>.", B_EN),
        Paragraph("<b>That</b> и <b>Those</b> = предметы, которые находятся <b>далеко</b>.", B_RU),
    ], bg=LIGHT_TEAL))
    story.append(sp(0.3))

    examples = [
        ("🤔 <b>This</b> is my pencil. (near me)", "<b>Это</b> мой карандаш. (рядом со мной)"),
        ("🤔 <b>That</b> is a tall building. (far away)", "<b>То</b> — высокое здание. (далеко)"),
        ("🤔 <b>These</b> are my books. (near, more than one)", "<b>Эти</b> — мои книги. (рядом, больше одного)"),
        ("🤔 <b>Those</b> are his shoes. (far, more than one)", "<b>Те</b> — его туфли. (далеко, больше одного)"),
    ]
    for en, ru in examples:
        story.append(Paragraph(en, EX_EN))
        story.append(Paragraph(ru, EX_RU))
        story.append(sp(0.15))

    # ── Page 3: Table ─────────────────────────────────────────────────────────
    sec(story,
        "🤔 Demonstrative Pronouns Table",
        "Таблица указательных местоимений")

    hdr = [
        header_cell("Demonstrative Pronoun", "Указательное местоимение"),
        header_cell("Number / Distance", "Число / Расстояние"),
        header_cell("Russian Translation", "Перевод на русский"),
        header_cell("Example Sentence", "Пример предложения"),
    ]
    rows = [
        ("THIS\nЭТО",   "Singular / Near\nЕд.ч. / Близко",  "этот / эта / это",  "This is my bag.\nЭта сумка — моя."),
        ("THAT\nТО",    "Singular / Far\nЕд.ч. / Далеко",   "тот / та / то",     "That is a big tree.\nТо — большое дерево."),
        ("THESE\nЭТИ",  "Plural / Near\nМн.ч. / Близко",    "эти",               "These are my crayons.\nЭти — мои карандаши."),
        ("THOSE\nТЕ",   "Plural / Far\nМн.ч. / Далеко",     "те",                "Those are her books.\nТе — её книги."),
    ]
    tdata = [hdr]
    for p, nd, ru, ex in rows:
        tdata.append([Paragraph(p, TC), Paragraph(nd, TR), Paragraph(ru, TR), Paragraph(ex, TC)])

    tbl = Table(tdata, colWidths=[3*cm, 3.8*cm, 3.7*cm, 5*cm], repeatRows=1)
    ts = [
        ("BACKGROUND",   (0,0),(-1,0), DARK_BLUE),
        ("BOX",          (0,0),(-1,-1), 1, TEAL),
        ("INNERGRID",    (0,0),(-1,-1), 0.5, TEAL),
        ("TOPPADDING",   (0,0),(-1,-1), 5), ("BOTTOMPADDING",(0,0),(-1,-1), 5),
        ("LEFTPADDING",  (0,0),(-1,-1), 6), ("RIGHTPADDING", (0,0),(-1,-1), 6),
        ("VALIGN",       (0,0),(-1,-1), "TOP"),
    ]
    for i in range(1, len(tdata)):
        ts.append(("BACKGROUND",(0,i),(-1,i), LIGHT_TEAL if i%2==1 else WHITE))
    tbl.setStyle(TableStyle(ts))
    story.append(tbl)

    # Near vs Far box
    story.append(sp(0.3))
    nf_data = [
        [Paragraph("📍 NEAR — близко", sty("NF1", fontSize=11, leading=14,
           alignment=TA_CENTER, textColor=DARK_BLUE, fontName="Helvetica-Bold")),
         Paragraph("📍 FAR — далеко", sty("NF2", fontSize=11, leading=14,
           alignment=TA_CENTER, textColor=DARK_BLUE, fontName="Helvetica-Bold"))],
        [Paragraph("Singular: <b>THIS</b>\nЕдинственное число: <b>THIS</b>\n\nPlural: <b>THESE</b>\nМножественное число: <b>THESE</b>", TC),
         Paragraph("Singular: <b>THAT</b>\nЕдинственное число: <b>THAT</b>\n\nPlural: <b>THOSE</b>\nМножественное число: <b>THOSE</b>", TC)],
    ]
    nft = Table(nf_data, colWidths=[7.75*cm, 7.75*cm])
    nft.setStyle(TableStyle([
        ("BACKGROUND",   (0,0),(0,-1), colors.HexColor("#DFF5E1")),
        ("BACKGROUND",   (1,0),(1,-1), colors.HexColor("#FFF0D0")),
        ("BOX",          (0,0),(-1,-1), 1, TEAL),
        ("INNERGRID",    (0,0),(-1,-1), 0.5, TEAL),
        ("ALIGN",        (0,0),(-1,-1), "CENTER"),
        ("TOPPADDING",   (0,0),(-1,-1), 7), ("BOTTOMPADDING",(0,0),(-1,-1), 7),
        ("VALIGN",       (0,0),(-1,-1), "MIDDLE"),
    ]))
    story.append(nft)

    # ── Page 4: Formula ───────────────────────────────────────────────────────
    sec(story,
        "✏️ Formula to Build Sentences",
        "Формула для составления предложений")

    formula_block(story, [
        ("DEM. PRONOUN", "УКАЗАТ. МЕСТОИМ.", DARK_BLUE),
        ("+", "+", WHITE),
        ("IS / ARE", "ЕСТЬ / ЯВЛЯЮТСЯ", TEAL),
        ("+", "+", WHITE),
        ("REST OF SENTENCE", "ОСТАТОК ПРЕДЛОЖЕНИЯ", GOLD),
    ])

    story.append(Paragraph("🤔 Example Sentences", H_EN))
    story.append(Paragraph("Примеры предложений", H_RU))
    story.append(sp(0.15))

    fhdr = [
        header_cell("Dem. Pronoun", "Указат. мест."),
        header_cell("Verb", "Глагол"),
        header_cell("Rest", "Остаток"),
        header_cell("Translation", "Перевод"),
    ]
    frows = [
        ("This",  "is",  "my notebook.", "Это мой блокнот."),
        ("That",  "is",  "a very old bridge.", "То — очень старый мост."),
        ("These", "are", "fresh apples.", "Эти — свежие яблоки."),
        ("Those", "are", "my father's tools.", "Те — инструменты моего папы."),
        ("This",  "is",  "the correct answer.", "Это правильный ответ."),
        ("Those", "are", "wild birds.", "Те — дикие птицы."),
    ]
    fdata = [fhdr]
    for dp, v, rest, ru in frows:
        fdata.append([Paragraph(dp, TC), Paragraph(v, TC), Paragraph(rest, TC), Paragraph(ru, TR)])

    ftbl = Table(fdata, colWidths=[3.5*cm, 2.5*cm, 5*cm, 4.5*cm], repeatRows=1)
    fts = [
        ("BACKGROUND",   (0,0),(-1,0), DARK_BLUE),
        ("BOX",          (0,0),(-1,-1), 1, TEAL),
        ("INNERGRID",    (0,0),(-1,-1), 0.5, TEAL),
        ("TOPPADDING",   (0,0),(-1,-1), 4), ("BOTTOMPADDING",(0,0),(-1,-1), 4),
        ("LEFTPADDING",  (0,0),(-1,-1), 5), ("RIGHTPADDING", (0,0),(-1,-1), 5),
        ("VALIGN",       (0,0),(-1,-1), "MIDDLE"),
    ]
    for i in range(1, len(fdata)):
        fts.append(("BACKGROUND",(0,i),(-1,i), LIGHT_GOLD if i%2==1 else WHITE))
    ftbl.setStyle(TableStyle(fts))
    story.append(ftbl)

    # ── Pages 5-7: Conversations ──────────────────────────────────────────────
    convs = [
        ("What is that tall building near the park?",
         "Что это за высокое здание у парка?",
         "That is the new library. It opened last month and has many books.",
         "То — новая библиотека. Она открылась в прошлом месяце и в ней много книг."),
        ("Are these your colour pencils on the table?",
         "Это твои цветные карандаши на столе?",
         "Yes, these are mine. I use them for my art class every Friday.",
         "Да, эти — мои. Я использую их на уроке рисования каждую пятницу."),
        ("What is this small animal in the box?",
         "Что это за маленькое животное в коробке?",
         "This is a hamster. Its name is Peanut.",
         "Это хомяк. Его зовут Пинат."),
        ("Whose shoes are those by the front door?",
         "Чьи это туфли у парадной двери?",
         "Those are my father's shoes. He always leaves them there after work.",
         "Те — туфли моего папы. Он всегда оставляет их там после работы."),
        ("Is this the right classroom for Grade 3?",
         "Это правильный класс для 3-го класса?",
         "Yes, this is the right one. Our teacher is already inside.",
         "Да, это правильный. Наш учитель уже внутри."),
        ("What are those colourful flags on the wall?",
         "Что это за разноцветные флаги на стене?",
         "Those are country flags. Our teacher put them up for a geography lesson.",
         "Те — флаги стран. Наш учитель повесил их для урока географии."),
        ("Is this water safe to drink?",
         "Эта вода безопасна для питья?",
         "Yes, this is clean drinking water from the school filter.",
         "Да, это чистая питьевая вода из школьного фильтра."),
        ("What are these papers on your desk?",
         "Что это за бумаги на твоём столе?",
         "These are my test results. I got a high score in all subjects.",
         "Это мои результаты тестов. Я получил высокий балл по всем предметам."),
        ("Can you see those children in the yard?",
         "Ты видишь тех детей во дворе?",
         "Yes, I can see them. Those are my classmates playing football.",
         "Да, я вижу их. Те — мои одноклассники, они играют в футбол."),
        ("Whose drawing is this on the board?",
         "Чей это рисунок на доске?",
         "This is Anna's drawing. She drew it during free time today.",
         "Это рисунок Анны. Она нарисовала его сегодня на свободном уроке."),
        ("Are those mountains real or in a picture?",
         "Те горы настоящие или на картинке?",
         "Those are real mountains. We can see them from the school roof.",
         "Те горы настоящие. Мы можем видеть их с крыши школы."),
        ("What is this sweet smell in the kitchen?",
         "Что это за сладкий запах на кухне?",
         "This is the smell of fresh bread. The cook baked it this morning.",
         "Это запах свежего хлеба. Повар испёк его этим утром."),
        ("Are these apples from your garden?",
         "Эти яблоки из вашего сада?",
         "Yes, these are from our garden. My mother picked them yesterday.",
         "Да, эти — из нашего сада. Мама сорвала их вчера."),
        ("What are those bright lights in the sky?",
         "Что это за яркие огни в небе?",
         "Those are stars. On a clear night you can count hundreds of them.",
         "Те — звёзды. В ясную ночь можно сосчитать сотни из них."),
        ("Is this the book you wanted to borrow?",
         "Это та книга, которую ты хотел взять?",
         "Yes, this is the one! I have been looking for it all week.",
         "Да, это она! Я искал её всю неделю."),
    ]

    for start in [0, 5, 10]:
        end = start + 5
        sec(story,
            f"🤔 Conversations – Q{start+1} to Q{end}",
            f"Разговоры – Вопросы {start+1}–{end}")
        for i, (qe,qr,ae,ar) in enumerate(convs[start:end], start=start+1):
            qa_block(story, i, qe, qr, ae, ar)

    # ── Page 8: Quick Reference ───────────────────────────────────────────────
    sec(story,
        "🤔 Quick Reference Card",
        "Быстрая справочная карточка")

    qhdr = [
        header_cell("Pronoun", "Местоимение"),
        header_cell("Use", "Когда использовать"),
        header_cell("Russian", "По-русски"),
        header_cell("Quick Example (EN + RU)", "Пример"),
    ]
    qrows = [
        ("THIS\nЭТО",   "Singular / Near\nЕд.ч. / Близко",  "этот/эта/это", "This is my pen.\nЭто моя ручка."),
        ("THAT\nТО",    "Singular / Far\nЕд.ч. / Далеко",   "тот/та/то",    "That is a cloud.\nТо — облако."),
        ("THESE\nЭТИ",  "Plural / Near\nМн.ч. / Близко",    "эти",          "These are my boots.\nЭти — мои сапоги."),
        ("THOSE\nТЕ",   "Plural / Far\nМн.ч. / Далеко",     "те",           "Those are tall trees.\nТе — высокие деревья."),
    ]
    qdata = [qhdr]
    for p, u, r, ex in qrows:
        qdata.append([Paragraph(p, TC), Paragraph(u, TR), Paragraph(r, TR), Paragraph(ex, TC)])

    qtbl = Table(qdata, colWidths=[3*cm, 3.5*cm, 3*cm, 6*cm], repeatRows=1)
    qts = [
        ("BACKGROUND",   (0,0),(-1,0), DARK_BLUE),
        ("BOX",          (0,0),(-1,-1), 1, TEAL),
        ("INNERGRID",    (0,0),(-1,-1), 0.5, TEAL),
        ("TOPPADDING",   (0,0),(-1,-1), 5), ("BOTTOMPADDING",(0,0),(-1,-1), 5),
        ("LEFTPADDING",  (0,0),(-1,-1), 6), ("RIGHTPADDING", (0,0),(-1,-1), 6),
        ("VALIGN",       (0,0),(-1,-1), "TOP"),
    ]
    for i in range(1, len(qdata)):
        qts.append(("BACKGROUND",(0,i),(-1,i), LIGHT_TEAL if i%2==1 else WHITE))
    qtbl.setStyle(TableStyle(qts))
    story.append(qtbl)
    story.append(sp(0.3))
    story.append(colbox([
        Paragraph("🤔 THIS / THESE = near you   •   THAT / THOSE = far away", N_EN),
        Paragraph("THIS / THESE = рядом с вами   •   THAT / THOSE = далеко от вас", N_RU),
        sp(0.1),
        Paragraph("THIS / THAT = singular (one thing)   •   THESE / THOSE = plural (more than one)", N_EN),
        Paragraph("THIS / THAT = единственное число (один предмет)   •   THESE / THOSE = множественное число (много)", N_RU),
    ], bg=LIGHT_GOLD))

    doc.build(story)
    print(f"✅ {out}")

# ══════════════════════════════════════════════════════════════════════════════
# BOOK 3 – POSSESSIVE PRONOUNS
# ══════════════════════════════════════════════════════════════════════════════
def build_possessive_pronouns():
    out = "/home/daytona/workspace/esl-pronouns/ESL_Grade3_Possessive_Pronouns.pdf"
    doc = make_doc(out)
    story = []

    cover_page(story,
        "Possessive\nPronouns",
        "Притяжательные местоимения (самостоятельные)",
        "Mine • Yours • His • Hers • Ours • Theirs",
        "Мой/Моя • Твой/Твоя • Его • Её • Наш/Наша • Их")

    # ── Page 2: Definition ────────────────────────────────────────────────────
    sec(story,
        "What is a Possessive Pronoun? 🤔",
        "Что такое притяжательное местоимение?")

    story.append(colbox([
        Paragraph("A <b>possessive pronoun</b> shows that something belongs to someone.", B_EN),
        Paragraph("<b>Притяжательное местоимение</b> показывает, что что-то принадлежит кому-то.", B_RU),
        sp(0.15),
        Paragraph("Unlike possessive adjectives (my, your, his…), possessive pronouns <b>stand alone</b> — they do NOT come before a noun.", B_EN),
        Paragraph("В отличие от притяжательных прилагательных (my, your, his…), притяжательные местоимения стоят <b>самостоятельно</b> — они НЕ стоят перед существительным.", B_RU),
    ], bg=LIGHT_TEAL))
    story.append(sp(0.3))

    examples = [
        ("🤔 This pencil is <b>mine</b>.", "Этот карандаш — <b>мой</b>."),
        ("🤔 That red bag is <b>hers</b>.", "Та красная сумка — <b>её</b>."),
        ("🤔 The blue umbrella is <b>ours</b>.", "Синий зонт — <b>наш</b>."),
        ("🤔 Those books are <b>theirs</b>.", "Те книги — <b>их</b>."),
    ]
    for en, ru in examples:
        story.append(Paragraph(en, EX_EN))
        story.append(Paragraph(ru, EX_RU))
        story.append(sp(0.15))

    # Adjective vs Pronoun comparison box
    story.append(sp(0.1))
    cmp_data = [
        [Paragraph("Possessive ADJECTIVE\n(before a noun)\nПрит. ПРИЛАГАТЕЛЬНОЕ\n(перед существительным)", TH),
         Paragraph("Possessive PRONOUN\n(stands alone)\nПрит. МЕСТОИМЕНИЕ\n(самостоятельно)", TH)],
        [Paragraph("This is <b>my</b> book.\nЭто <b>моя</b> книга.", TC),
         Paragraph("This book is <b>mine</b>.\nЭта книга — <b>моя</b>.", TC)],
        [Paragraph("<b>Your</b> pencil is sharp.\n<b>Твой</b> карандаш острый.", TC),
         Paragraph("The pencil is <b>yours</b>.\nКарандаш — <b>твой</b>.", TC)],
        [Paragraph("<b>Their</b> dog is big.\n<b>Их</b> собака большая.", TC),
         Paragraph("The big dog is <b>theirs</b>.\nБольшая собака — <b>их</b>.", TC)],
    ]
    cmt = Table(cmp_data, colWidths=[7.75*cm, 7.75*cm])
    cmt.setStyle(TableStyle([
        ("BACKGROUND",   (0,0),(-1,0), DARK_BLUE),
        ("BACKGROUND",   (0,1),(0,-1), colors.HexColor("#FFF0D0")),
        ("BACKGROUND",   (1,1),(1,-1), colors.HexColor("#DFF5E1")),
        ("BOX",          (0,0),(-1,-1), 1, TEAL),
        ("INNERGRID",    (0,0),(-1,-1), 0.5, TEAL),
        ("TOPPADDING",   (0,0),(-1,-1), 7), ("BOTTOMPADDING",(0,0),(-1,-1), 7),
        ("LEFTPADDING",  (0,0),(-1,-1), 7), ("RIGHTPADDING", (0,0),(-1,-1), 7),
        ("VALIGN",       (0,0),(-1,-1), "TOP"),
    ]))
    story.append(cmt)

    # ── Page 3: Table ─────────────────────────────────────────────────────────
    sec(story,
        "🤔 Possessive Pronouns Table",
        "Таблица притяжательных местоимений")

    hdr = [
        header_cell("Possessive Pronoun (EN)", "Притяжательное местоимение"),
        header_cell("Russian Translation", "Перевод на русский"),
        header_cell("Example Sentence", "Пример предложения"),
    ]
    rows = [
        ("MINE\nМОЙ / МОЯ",    "мой / моя / моё / мои",        "This pencil is mine.\nЭтот карандаш — мой."),
        ("YOURS\nТВОЙ / ВАШ",  "твой / твоя / ваш / ваша",     "Is this seat yours?\nЭто место твоё?"),
        ("HIS\nЕГО",            "его",                           "The blue jacket is his.\nСиняя куртка — его."),
        ("HERS\nЕЁ",            "её",                            "That red umbrella is hers.\nТот красный зонт — её."),
        ("OURS\nНАШ / НАША",   "наш / наша / наше / наши",      "This classroom is ours.\nЭтот класс — наш."),
        ("THEIRS\nИХ",          "их",                            "Those bikes are theirs.\nТе велосипеды — их."),
    ]
    tdata = [hdr]
    for p, r, ex in rows:
        tdata.append([Paragraph(p, TC), Paragraph(r, TR), Paragraph(ex, TC)])

    tbl = Table(tdata, colWidths=[4*cm, 4.5*cm, 7*cm], repeatRows=1)
    ts = [
        ("BACKGROUND",   (0,0),(-1,0), DARK_BLUE),
        ("BOX",          (0,0),(-1,-1), 1, TEAL),
        ("INNERGRID",    (0,0),(-1,-1), 0.5, TEAL),
        ("TOPPADDING",   (0,0),(-1,-1), 5), ("BOTTOMPADDING",(0,0),(-1,-1), 5),
        ("LEFTPADDING",  (0,0),(-1,-1), 6), ("RIGHTPADDING", (0,0),(-1,-1), 6),
        ("VALIGN",       (0,0),(-1,-1), "TOP"),
    ]
    for i in range(1, len(tdata)):
        ts.append(("BACKGROUND",(0,i),(-1,i), LIGHT_TEAL if i%2==1 else WHITE))
    tbl.setStyle(TableStyle(ts))
    story.append(tbl)

    # ── Page 4: Formula ───────────────────────────────────────────────────────
    sec(story,
        "✏️ Formula to Build Sentences",
        "Формула для составления предложений")

    formula_block(story, [
        ("NOUN / SUBJECT", "СУЩЕСТВИТЕЛЬНОЕ / ПОДЛЕЖАЩЕЕ", DARK_BLUE),
        ("+", "+", WHITE),
        ("IS / ARE", "ЕСТЬ / ЯВЛЯЮТСЯ", TEAL),
        ("+", "+", WHITE),
        ("POSSESSIVE PRONOUN", "ПРИТЯЖАТЕЛЬНОЕ МЕСТОИМЕНИЕ", GOLD),
    ])

    story.append(Paragraph("🤔 Example Sentences", H_EN))
    story.append(Paragraph("Примеры предложений", H_RU))
    story.append(sp(0.15))

    fhdr = [
        header_cell("Noun / Subject", "Подлежащее"),
        header_cell("Verb", "Глагол"),
        header_cell("Poss. Pronoun", "Прит. мест."),
        header_cell("Translation", "Перевод"),
    ]
    frows = [
        ("This eraser",          "is",  "mine",   "Этот ластик — мой."),
        ("The green backpack",   "is",  "yours",  "Зелёный рюкзак — твой."),
        ("That trophy",          "is",  "his",    "Тот кубок — его."),
        ("The pink water bottle","is",  "hers",   "Розовая бутылка воды — её."),
        ("The corner table",     "is",  "ours",   "Угловой стол — наш."),
        ("Those big umbrellas",  "are", "theirs", "Те большие зонты — их."),
    ]
    fdata = [fhdr]
    for s, v, pp, ru in frows:
        fdata.append([Paragraph(s, TC), Paragraph(v, TC), Paragraph(pp, TC), Paragraph(ru, TR)])

    ftbl = Table(fdata, colWidths=[4.5*cm, 2.5*cm, 3.5*cm, 5*cm], repeatRows=1)
    fts = [
        ("BACKGROUND",   (0,0),(-1,0), DARK_BLUE),
        ("BOX",          (0,0),(-1,-1), 1, TEAL),
        ("INNERGRID",    (0,0),(-1,-1), 0.5, TEAL),
        ("TOPPADDING",   (0,0),(-1,-1), 4), ("BOTTOMPADDING",(0,0),(-1,-1), 4),
        ("LEFTPADDING",  (0,0),(-1,-1), 5), ("RIGHTPADDING", (0,0),(-1,-1), 5),
        ("VALIGN",       (0,0),(-1,-1), "MIDDLE"),
    ]
    for i in range(1, len(fdata)):
        fts.append(("BACKGROUND",(0,i),(-1,i), LIGHT_GOLD if i%2==1 else WHITE))
    ftbl.setStyle(TableStyle(fts))
    story.append(ftbl)

    # ── Pages 5-7: Conversations ──────────────────────────────────────────────
    convs = [
        ("Whose eraser is on the floor?",
         "Чей ластик лежит на полу?",
         "That eraser is mine. I dropped it when I was writing.",
         "Тот ластик — мой. Я уронил его, когда писал."),
        ("Is this blue jacket yours?",
         "Эта синяя куртка твоя?",
         "Yes, that jacket is mine. I left it on the chair after lunch.",
         "Да, та куртка — моя. Я оставил её на стуле после обеда."),
        ("Whose turn is it to lead the class?",
         "Чья очередь руководить классом?",
         "The turn is his. He is the class leader this week.",
         "Очередь — его. Он дежурный по классу на этой неделе."),
        ("I found a purple water bottle. Is it yours?",
         "Я нашёл фиолетовую бутылку воды. Она твоя?",
         "No, it is not mine. It might be hers — she has a purple one.",
         "Нет, это не моя. Это может быть её — у неё есть фиолетовая."),
        ("Which team won the relay race?",
         "Какая команда выиграла эстафету?",
         "The victory is ours! We practised every day after school.",
         "Победа — наша! Мы тренировались каждый день после школы."),
        ("Are those large bags by the bus theirs?",
         "Те большие сумки у автобуса — их?",
         "Yes, those bags are theirs. Their family is going on a trip.",
         "Да, те сумки — их. Их семья едет в поездку."),
        ("Whose science project got first place?",
         "Чей научный проект занял первое место?",
         "The first-place project is hers. She worked on it for two weeks.",
         "Проект на первом месте — её. Она работала над ним две недели."),
        ("I see two bicycles. Which one is yours?",
         "Я вижу два велосипеда. Который твой?",
         "The red one is mine. The yellow one is my brother's.",
         "Красный — мой. Жёлтый — моего брата."),
        ("Whose idea was it to plant flowers in the garden?",
         "Чья это была идея — посадить цветы в саду?",
         "The idea was ours. The whole class voted for it together.",
         "Идея была наша. Весь класс проголосовал за неё вместе."),
        ("Is that trophy in the cabinet his?",
         "Тот кубок в шкафу — его?",
         "Yes, that trophy is his. He won it at the swimming competition.",
         "Да, тот кубок — его. Он выиграл его на соревнованиях по плаванию."),
        ("Whose homework is on the teacher's table?",
         "Чьё домашнее задание лежит на столе учителя?",
         "The homework on the table is mine. I handed it in this morning.",
         "Домашнее задание на столе — моё. Я сдал его сегодня утром."),
        ("Those colourful drawings on the wall — are they yours?",
         "Те красочные рисунки на стене — твои?",
         "No, they are not mine. Those drawings are theirs — the art club students.",
         "Нет, не мои. Те рисунки — их, учеников кружка рисования."),
        ("This umbrella was left at the door. Is it yours or hers?",
         "Этот зонт оставили у двери. Он твой или её?",
         "It is hers. She forgot it when she ran to catch the school bus.",
         "Он её. Она забыла его, когда бежала на школьный автобус."),
        ("We found a lunch box with no name. Is it yours?",
         "Мы нашли ланч-бокс без имени. Он твой?",
         "Yes, that lunch box is mine! I forgot to write my name on it.",
         "Да, тот ланч-бокс — мой! Я забыл написать на нём своё имя."),
        ("Are those tools in the shed ours or the neighbours'?",
         "Те инструменты в сарае — наши или соседей?",
         "Those tools are ours. My father uses them to fix things at home.",
         "Те инструменты — наши. Папа использует их, чтобы починить что-то дома."),
    ]

    for start in [0, 5, 10]:
        end = start + 5
        sec(story,
            f"🤔 Conversations – Q{start+1} to Q{end}",
            f"Разговоры – Вопросы {start+1}–{end}")
        for i, (qe,qr,ae,ar) in enumerate(convs[start:end], start=start+1):
            qa_block(story, i, qe, qr, ae, ar)

    # ── Page 8: Quick Reference ───────────────────────────────────────────────
    sec(story,
        "🤔 Quick Reference Card",
        "Быстрая справочная карточка")

    qhdr = [
        header_cell("Pronoun", "Местоимение"),
        header_cell("Russian", "По-русски"),
        header_cell("Quick Example (EN + RU)", "Пример (англ. + рус.)"),
    ]
    qrows = [
        ("MINE\nМОЙ / МОЯ",   "мой/моя/моё/мои",  "This pen is mine.\nЭта ручка — моя."),
        ("YOURS\nТВОЙ / ВАШ", "твой/ваш",          "Is this seat yours?\nЭто место твоё?"),
        ("HIS\nЕГО",           "его",               "The trophy is his.\nКубок — его."),
        ("HERS\nЕЁ",           "её",                "The red bag is hers.\nКрасная сумка — её."),
        ("OURS\nНАШ / НАША",  "наш/наша",          "This classroom is ours.\nЭтот класс — наш."),
        ("THEIRS\nИХ",         "их",                "Those bikes are theirs.\nТе велосипеды — их."),
    ]
    qdata = [qhdr]
    for p, r, ex in qrows:
        qdata.append([Paragraph(p, TC), Paragraph(r, TR), Paragraph(ex, TC)])

    qtbl = Table(qdata, colWidths=[3.5*cm, 4*cm, 8*cm], repeatRows=1)
    qts = [
        ("BACKGROUND",   (0,0),(-1,0), DARK_BLUE),
        ("BOX",          (0,0),(-1,-1), 1, TEAL),
        ("INNERGRID",    (0,0),(-1,-1), 0.5, TEAL),
        ("TOPPADDING",   (0,0),(-1,-1), 5), ("BOTTOMPADDING",(0,0),(-1,-1), 5),
        ("LEFTPADDING",  (0,0),(-1,-1), 6), ("RIGHTPADDING", (0,0),(-1,-1), 6),
        ("VALIGN",       (0,0),(-1,-1), "TOP"),
    ]
    for i in range(1, len(qdata)):
        qts.append(("BACKGROUND",(0,i),(-1,i), LIGHT_TEAL if i%2==1 else WHITE))
    qtbl.setStyle(TableStyle(qts))
    story.append(qtbl)
    story.append(sp(0.3))
    story.append(colbox([
        Paragraph("🤔 Possessive pronouns stand ALONE — they do NOT come before a noun!", N_EN),
        Paragraph("Притяжательные местоимения стоят САМОСТОЯТЕЛЬНО — они НЕ стоят перед существительным!", N_RU),
        sp(0.1),
        Paragraph("Compare: '<b>my</b> book' (adjective) vs 'the book is <b>mine</b>' (pronoun)", N_EN),
        Paragraph("Сравните: '<b>моя</b> книга' (прилагательное) и 'книга — <b>моя</b>' (местоимение)", N_RU),
    ], bg=LIGHT_GOLD))

    doc.build(story)
    print(f"✅ {out}")

# ── Run all three ─────────────────────────────────────────────────────────────
if __name__ == "__main__":
    build_object_pronouns()
    build_demonstrative_pronouns()
    build_possessive_pronouns()
    print("\n🎉 All three handbooks created successfully!")
Running Command

cd /home/daytona/workspace/esl-pronouns && python3 build_handbooks_v2.py

All three updated handbooks are ready with full Russian translations everywhere. Download them here:

📘 Object Pronouns (Me • You • Him • Her • It • Us • Them)

ESL Grade3 Object Pronouns

PDF Document · PDF

📗 Demonstrative Pronouns (This • That • These • Those)

ESL Grade3 Demonstrative Pronouns

PDF Document · PDF

📙 Possessive Pronouns (Mine • Yours • His • Hers • Ours • Theirs)

ESL Grade3 Possessive Pronouns

PDF Document · PDF


Here is exactly what now has Russian translations underneath, matching your original PDF:
ElementWhat's included
Cover pageEvery line: Grade 3 ESL / Handbook subtitle / pronoun list / English-Russian label / tagline
Section headingsEvery heading has Russian directly below in teal italic
Definition boxEach English sentence has Russian underneath it
Example sentencesEnglish bold + Russian italic on the next line
Pronoun tableHeader cells show EN + RU label; pronoun cells show EN bold + Russian translation below
Formula rowEach box label shows EN + RU underneath (e.g. SUBJECT / ПОДЛЕЖАЩЕЕ)
Formula examples tableHeader row is bilingual; translation column in every row
Q&A conversations❓ English question + Russian below; ✅ English answer + Russian below
Quick Reference CardAll column headers bilingual; pronoun cells show EN + Russian; example cells show EN + Russian sentence
Bottom note boxRule in English + full Russian translation underneath

It's showing that I can't download it

Running Command

ls -lh /home/daytona/workspace/esl-pronouns/*.pdf

Running Command

cd /home/daytona/workspace/esl-pronouns && python3 -c " from pypdf import PdfRea…

Running Command

# Find available fonts that support Cyrillic fc-list :lang=ru | head -20 echo "-…

Writing File

~/esl-pronouns/build_handbooks_v3.py

"""
ESL Grade 3 Pronouns Handbooks - Version 3
Uses DejaVu Sans (supports Cyrillic) so Russian text renders correctly.
Full Russian translations under every English line, heading, label, sentence.
"""

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

# ── Register DejaVu fonts (full Cyrillic support) ─────────────────────────────
FONT_DIR = "/usr/share/fonts/truetype/dejavu/"
pdfmetrics.registerFont(TTFont("DV",     FONT_DIR + "DejaVuSans.ttf"))
pdfmetrics.registerFont(TTFont("DV-B",   FONT_DIR + "DejaVuSans-Bold.ttf"))
pdfmetrics.registerFont(TTFont("DV-I",   FONT_DIR + "DejaVuSans-Oblique.ttf"))
pdfmetrics.registerFont(TTFont("DV-BI",  FONT_DIR + "DejaVuSans-BoldOblique.ttf"))

# ── Colours ───────────────────────────────────────────────────────────────────
DARK_BLUE  = colors.HexColor("#1B3A6B")
TEAL       = colors.HexColor("#0A7D8C")
LIGHT_TEAL = colors.HexColor("#D9F0F3")
GOLD       = colors.HexColor("#F5A623")
LIGHT_GOLD = colors.HexColor("#FFF8E7")
WHITE      = colors.white
DARK_TEXT  = colors.HexColor("#1A1A2E")
Q_BLUE     = colors.HexColor("#E8F4FD")
A_GREEN    = colors.HexColor("#E8F9EE")
BLUE_LIGHT = colors.HexColor("#CCE8FF")

PAGE_W, PAGE_H = A4

# ── Doc factory ───────────────────────────────────────────────────────────────
def make_doc(filename):
    return SimpleDocTemplate(
        filename, pagesize=A4,
        leftMargin=2*cm, rightMargin=2*cm,
        topMargin=1.8*cm, bottomMargin=1.8*cm
    )

# ── Styles (all using DejaVu) ─────────────────────────────────────────────────
ss = getSampleStyleSheet()

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

# Cover
C_TITLE = sty("CT",  fontSize=30, leading=36, alignment=TA_CENTER, textColor=WHITE,      fontName="DV-B")
C_RU    = sty("CR",  fontSize=12, leading=17, alignment=TA_CENTER, textColor=colors.HexColor("#C8E6F5"), fontName="DV-I")
C_SUB   = sty("CS",  fontSize=13, leading=18, alignment=TA_CENTER, textColor=LIGHT_TEAL, fontName="DV")
C_BAND  = sty("CB",  fontSize=11, leading=15, alignment=TA_CENTER, textColor=WHITE,      fontName="DV-B")
C_RU2   = sty("CR2", fontSize=10, leading=14, alignment=TA_CENTER, textColor=colors.HexColor("#C8E6F5"), fontName="DV-I")
C_TAG   = sty("CTG", fontSize=10, leading=14, alignment=TA_CENTER, textColor=colors.HexColor("#FFE0A0"), fontName="DV-I")
C_GOLD  = sty("CG",  fontSize=13, leading=18, alignment=TA_CENTER, textColor=GOLD,       fontName="DV-B")

# Headings
H_EN    = sty("HE",  fontSize=13, leading=18, alignment=TA_CENTER, textColor=DARK_BLUE,  fontName="DV-B")
H_RU    = sty("HR",  fontSize=10, leading=14, alignment=TA_CENTER, textColor=TEAL,       fontName="DV-I")

# Body
B_EN    = sty("BE",  fontSize=11, leading=16, alignment=TA_JUSTIFY, textColor=DARK_TEXT, fontName="DV")
B_RU    = sty("BR",  fontSize=10, leading=14, alignment=TA_JUSTIFY, textColor=colors.HexColor("#3A3A5C"), fontName="DV-I")

# Example sentences
EX_EN   = sty("EE",  fontSize=11, leading=15, alignment=TA_LEFT,   textColor=DARK_BLUE,  fontName="DV-B")
EX_RU   = sty("ER",  fontSize=10, leading=14, alignment=TA_LEFT,   textColor=TEAL,       fontName="DV-I")

# Table
TH      = sty("TH",  fontSize=9,  leading=12, alignment=TA_CENTER, textColor=WHITE,      fontName="DV-B")
TH_RU   = sty("THR", fontSize=8,  leading=11, alignment=TA_CENTER, textColor=BLUE_LIGHT, fontName="DV-I")
TC      = sty("TC",  fontSize=10, leading=13, alignment=TA_LEFT,   textColor=DARK_TEXT,  fontName="DV-B")
TR      = sty("TR",  fontSize=9,  leading=12, alignment=TA_LEFT,   textColor=colors.HexColor("#3A3A5C"), fontName="DV-I")

# Q&A
Q_EN    = sty("QE",  fontSize=11, leading=15, alignment=TA_LEFT,   textColor=DARK_BLUE,  fontName="DV-B")
Q_RU    = sty("QR",  fontSize=9,  leading=13, alignment=TA_LEFT,   textColor=colors.HexColor("#444488"), fontName="DV-I")
A_EN    = sty("AE",  fontSize=11, leading=15, alignment=TA_LEFT,   textColor=colors.HexColor("#1A6B2E"), fontName="DV")
A_RU    = sty("AR",  fontSize=9,  leading=13, alignment=TA_LEFT,   textColor=colors.HexColor("#2A7A44"), fontName="DV-I")

# Notes
N_EN    = sty("NE",  fontSize=10, leading=14, alignment=TA_CENTER, textColor=DARK_BLUE,  fontName="DV-B")
N_RU    = sty("NR",  fontSize=9,  leading=13, alignment=TA_CENTER, textColor=TEAL,       fontName="DV-I")

# ── Utilities ─────────────────────────────────────────────────────────────────
def divider():
    return HRFlowable(width="100%", thickness=1.5, color=TEAL, spaceBefore=5, spaceAfter=5)

def sp(h=0.2):
    return Spacer(1, h * cm)

def colbox(items, bg=LIGHT_TEAL, pad=8):
    data = [[items]]
    t = Table(data, colWidths=[PAGE_W - 4*cm])
    t.setStyle(TableStyle([
        ("BACKGROUND",    (0,0),(-1,-1), bg),
        ("BOX",           (0,0),(-1,-1), 0.8, TEAL),
        ("TOPPADDING",    (0,0),(-1,-1), pad),
        ("BOTTOMPADDING", (0,0),(-1,-1), pad),
        ("LEFTPADDING",   (0,0),(-1,-1), pad),
        ("RIGHTPADDING",  (0,0),(-1,-1), pad),
        ("VALIGN",        (0,0),(-1,-1), "TOP"),
    ]))
    return t

def hdr_cell(en, ru):
    return [Paragraph(en, TH), Paragraph(ru, TH_RU)]

def sec(story, en, ru):
    story.append(divider())
    story.append(Paragraph(en, H_EN))
    story.append(Paragraph(ru, H_RU))
    story.append(sp(0.22))

def qa_block(story, n, qe, qr, ae, ar):
    w = [PAGE_W - 4*cm]
    qt = Table([[Paragraph(f"❓ Q{n}: {qe}", Q_EN)], [Paragraph(qr, Q_RU)]], colWidths=w)
    qt.setStyle(TableStyle([
        ("BACKGROUND",    (0,0),(-1,-1), Q_BLUE),
        ("BOX",           (0,0),(-1,-1), 0.5, TEAL),
        ("TOPPADDING",    (0,0),(-1,-1), 5), ("BOTTOMPADDING",(0,0),(-1,-1), 5),
        ("LEFTPADDING",   (0,0),(-1,-1), 8), ("RIGHTPADDING", (0,0),(-1,-1), 8),
    ]))
    at = Table([[Paragraph(f"✅ {ae}", A_EN)], [Paragraph(ar, A_RU)]], colWidths=w)
    at.setStyle(TableStyle([
        ("BACKGROUND",    (0,0),(-1,-1), A_GREEN),
        ("BOX",           (0,0),(-1,-1), 0.5, colors.HexColor("#4CAF50")),
        ("TOPPADDING",    (0,0),(-1,-1), 5), ("BOTTOMPADDING",(0,0),(-1,-1), 5),
        ("LEFTPADDING",   (0,0),(-1,-1), 8), ("RIGHTPADDING", (0,0),(-1,-1), 8),
    ]))
    story.append(KeepTogether([qt, sp(0.1), at, sp(0.25)]))

def formula_row(story, boxes):
    """boxes = list of (EN, RU, bg_color) or ('+', '', WHITE)"""
    cells, widths, bg_cmds = [], [], []
    for i, (en, ru, bg) in enumerate(boxes):
        if en == "+":
            cells.append([Paragraph("+", sty(f"pl{i}", fontSize=14, leading=16,
                          alignment=TA_CENTER, textColor=DARK_BLUE, fontName="DV-B"))])
            widths.append(0.65*cm)
        else:
            cells.append([Paragraph(en, TH), Paragraph(ru, TH_RU)])
            widths.append(None)
        bg_cmds.append(("BACKGROUND", (i,0),(i,0), bg))

    n_real = sum(1 for e,_,_ in boxes if e != "+")
    fixed  = 0.65 * sum(1 for e,_,_ in boxes if e == "+")
    w_each = (PAGE_W - 4*cm - fixed*cm) / n_real
    widths = [0.65*cm if boxes[i][0]=="+" else w_each for i in range(len(boxes))]

    t = Table([cells], colWidths=widths)
    t.setStyle(TableStyle([
        ("BOX",           (0,0),(-1,-1), 1, DARK_BLUE),
        ("INNERGRID",     (0,0),(-1,-1), 0.5, TEAL),
        ("TOPPADDING",    (0,0),(-1,-1), 7), ("BOTTOMPADDING",(0,0),(-1,-1), 7),
        ("ALIGN",         (0,0),(-1,-1), "CENTER"),
        ("VALIGN",        (0,0),(-1,-1), "MIDDLE"),
    ] + bg_cmds))
    story.append(t)
    story.append(sp(0.2))

def std_table(data, col_widths, story):
    tbl = Table(data, colWidths=col_widths, repeatRows=1)
    ts = [
        ("BACKGROUND",    (0,0),(-1,0), DARK_BLUE),
        ("BOX",           (0,0),(-1,-1), 1, TEAL),
        ("INNERGRID",     (0,0),(-1,-1), 0.5, TEAL),
        ("TOPPADDING",    (0,0),(-1,-1), 5), ("BOTTOMPADDING",(0,0),(-1,-1), 5),
        ("LEFTPADDING",   (0,0),(-1,-1), 6), ("RIGHTPADDING", (0,0),(-1,-1), 6),
        ("VALIGN",        (0,0),(-1,-1), "TOP"),
    ]
    for i in range(1, len(data)):
        ts.append(("BACKGROUND",(0,i),(-1,i), LIGHT_TEAL if i%2==1 else WHITE))
    tbl.setStyle(TableStyle(ts))
    story.append(tbl)

def cover_page(story, en_title, ru_title, list_en, list_ru):
    rows = [
        [Paragraph("📚 ✏️ 📚", sty("EM", fontSize=22, leading=28,
             alignment=TA_CENTER, textColor=WHITE, fontName="DV"))],
        [sp(0.2)],
        [Paragraph("Grade 3 ESL", C_BAND)],
        [Paragraph("3-й класс ЭСЛ", C_RU2)],
        [sp(0.3)],
        [Paragraph(en_title, C_TITLE)],
        [Paragraph(ru_title, C_RU)],
        [sp(0.3)],
        [Paragraph("Handbook – Table, Formula & Conversations", C_SUB)],
        [Paragraph("Справочник – таблица, формула и разговоры", C_RU2)],
        [sp(0.25)],
        [Paragraph(list_en, C_BAND)],
        [Paragraph(list_ru, C_RU2)],
        [sp(0.35)],
        [Paragraph("English ⇄ Russian", C_GOLD)],
        [Paragraph("Английский ⇄ Русский", C_RU2)],
        [sp(0.35)],
        [Paragraph("Made with ❤️ for young learners", C_TAG)],
        [Paragraph("Создано с ❤️ для юных учеников", C_TAG)],
        [sp(0.2)],
    ]
    t = Table(rows, colWidths=[PAGE_W - 4*cm])
    t.setStyle(TableStyle([
        ("BACKGROUND",    (0,0),(-1,-1), DARK_BLUE),
        ("ALIGN",         (0,0),(-1,-1), "CENTER"),
        ("VALIGN",        (0,0),(-1,-1), "MIDDLE"),
        ("TOPPADDING",    (0,0),(-1,-1), 4),
        ("BOTTOMPADDING", (0,0),(-1,-1), 4),
        ("LEFTPADDING",   (0,0),(-1,-1), 14),
        ("RIGHTPADDING",  (0,0),(-1,-1), 14),
        ("BOX",           (0,0),(-1,-1), 2.5, GOLD),
    ]))
    story.append(t)

# ══════════════════════════════════════════════════════════════════════════════
# BOOK 1 – OBJECT PRONOUNS
# ══════════════════════════════════════════════════════════════════════════════
def build_object_pronouns():
    out = "/home/daytona/workspace/esl-pronouns/ESL_Grade3_Object_Pronouns.pdf"
    story = []

    cover_page(story,
        "Object\nPronouns",
        "Объектные местоимения",
        "Me • You • Him • Her • It • Us • Them",
        "Меня • Тебя • Его • Её • Его/Её • Нас • Их")

    # Page 2 – What is an Object Pronoun?
    sec(story, "What is an Object Pronoun? 🤔", "Что такое объектное местоимение?")
    story.append(colbox([
        Paragraph("An object pronoun replaces the name of a person or thing that receives the action of a verb.", B_EN),
        Paragraph("Объектное местоимение заменяет имя человека или предмета, на которое направлено действие глагола.", B_RU),
        sp(0.12),
        Paragraph("It always comes AFTER the verb or a preposition.", B_EN),
        Paragraph("Оно всегда стоит ПОСЛЕ глагола или предлога.", B_RU),
    ], bg=LIGHT_TEAL))
    story.append(sp(0.28))

    for en, ru in [
        ("🤔 She sees me every morning.", "Она видит меня каждое утро."),
        ("🤔 The teacher called him.", "Учитель позвал его."),
        ("🤔 Can you help us?", "Можешь помочь нам?"),
    ]:
        story.append(Paragraph(en, EX_EN)); story.append(Paragraph(ru, EX_RU)); story.append(sp(0.15))

    # Page 3 – Table
    sec(story, "🤔 Object Pronouns Table", "Таблица объектных местоимений")
    hdr = [hdr_cell("Object Pronoun (EN)\nОбъектное местоимение",""), hdr_cell("Russian Translation\nПеревод на русский",""), hdr_cell("Example Sentence\nПример предложения","")]
    rows = [
        ("ME / МНЕ / МЕНЯ",   "меня / мне",   "She called me.\nОна позвонила мне."),
        ("YOU / ТЕБЯ / ВАС",  "тебя / вас",   "I see you every day.\nЯ вижу тебя каждый день."),
        ("HIM / ЕГО",         "его / ему",    "We helped him.\nМы помогли ему."),
        ("HER / ЕЁ",          "её / ей",      "He thanked her.\nОн поблагодарил её."),
        ("IT / ЕГО / ЕЁ",     "его / её",    "I can see it clearly.\nЯ вижу его отчётливо."),
        ("US / НАС",          "нас / нам",    "She invited us.\nОна пригласила нас."),
        ("THEM / ИХ",         "их / им",      "I know them well.\nЯ знаю их хорошо."),
    ]
    tdata = [hdr]
    for p, r, ex in rows:
        tdata.append([[Paragraph(p, TC)], [Paragraph(r, TR)], [Paragraph(ex, TC)]])
    std_table(tdata, [4*cm, 4.2*cm, 7.3*cm], story)

    # Page 4 – Formula
    sec(story, "✏️ Formula to Build Sentences", "Формула для составления предложений")
    formula_row(story, [
        ("SUBJECT\nПОДЛЕЖАЩЕЕ", "", DARK_BLUE),
        ("+","",WHITE),
        ("VERB\nГЛАГОЛ", "", TEAL),
        ("+","",WHITE),
        ("OBJECT PRONOUN\nОБЪЕКТНОЕ МЕСТОИМЕНИЕ", "", GOLD),
    ])
    sec(story, "🤔 Example Sentences", "Примеры предложений")
    fhdr = [hdr_cell("Subject\nПодлежащее",""), hdr_cell("Verb\nГлагол",""), hdr_cell("Object Pronoun\nОбъектное мест.",""), hdr_cell("Translation\nПеревод","")]
    frows = [
        ("She",         "sees",      "me",           "Она видит меня."),
        ("We",          "helped",    "him",          "Мы помогли ему."),
        ("The teacher", "called",    "them",         "Учитель позвал их."),
        ("I",           "will call", "you tomorrow", "Я позвоню тебе завтра."),
        ("They",        "surprised", "us",           "Они удивили нас."),
        ("He",          "thanked",   "her",          "Он поблагодарил её."),
    ]
    fdata = [fhdr]
    for s, v, op, ru in frows:
        fdata.append([Paragraph(s, TC), Paragraph(v, TC), Paragraph(op, TC), Paragraph(ru, TR)])
    std_table(fdata, [3.5*cm, 3*cm, 4*cm, 5*cm], story)

    # Pages 5-7 – Conversations
    convs = [
        ("Who did the teacher call to the board?","Кого учитель вызвал к доске?","She called me. I walked to the board and wrote the answer.","Она вызвала меня. Я подошёл к доске и написал ответ."),
        ("Can you see the bird on the tree?","Ты видишь птицу на дереве?","Yes, I can see it. It is sitting very still on the branch.","Да, я вижу её. Она сидит очень тихо на ветке."),
        ("Did your friends invite you to the party?","Твои друзья пригласили тебя на вечеринку?","Yes, they invited me and I am very excited to go.","Да, они пригласили меня, и я очень рад идти."),
        ("Who helped Tim with his homework?","Кто помог Тиму с домашним заданием?","His older sister helped him. She explained every problem clearly.","Его старшая сестра помогла ему. Она объяснила каждую задачу понятно."),
        ("Did the coach choose Sara for the team?","Тренер выбрал Сару в команду?","Yes, the coach chose her. She is a very fast runner.","Да, тренер выбрал её. Она очень быстро бегает."),
        ("Did you and your class win the quiz?","Ты и твой класс выиграли викторину?","Yes! The principal gave us a trophy and took our photograph.","Да! Директор вручил нам кубок и сфотографировал нас."),
        ("Where are the new books? Did the librarian bring them?","Где новые книги? Библиотекарь принёс их?","Yes, she brought them this morning and put them on the shelf.","Да, она принесла их этим утром и поставила на полку."),
        ("Your dog ran away — did anyone find it?","Твоя собака убежала — кто-нибудь нашёл её?","The neighbour found it and brought it home safely.","Сосед нашёл её и безопасно привёл домой."),
        ("Did your teacher read your story?","Учитель прочитал твой рассказ?","Yes, she read it and said it was very creative.","Да, она прочитала его и сказала, что он очень творческий."),
        ("Can we sit with you at lunch?","Мы можем сесть с тобой на обед?","Of course! You can sit next to me. There is enough room.","Конечно! Вы можете сесть рядом со мной. Места достаточно."),
        ("Did the doctor check Max and Lily?","Врач осмотрел Макса и Лили?","Yes, the doctor checked them and said they are both healthy.","Да, врач осмотрел их и сказал, что они оба здоровы."),
        ("Who did you wave to at the gate?","Кому ты помахал у ворот?","I waved to her. She waved back and smiled at me.","Я помахал ей. Она помахала в ответ и улыбнулась мне."),
        ("Can your father drive us to school?","Твой папа может отвезти нас в школу?","Yes, he can drive us. He leaves at 7:30 every morning.","Да, он может отвезти нас. Он уезжает в 7:30 каждое утро."),
        ("Did the storm damage the fence?","Буря повредила забор?","Yes, it damaged it badly. My father will repair it on Saturday.","Да, она сильно повредила его. Мой папа починит его в субботу."),
        ("Why did the principal call you and Tom?","Почему директор вызвал тебя и Тома?","She called us because we won first place in the science fair.","Она вызвала нас, потому что мы заняли первое место на ярмарке науки."),
    ]
    for start in [0, 5, 10]:
        sec(story, f"🤔 Conversations – Q{start+1} to Q{start+5}", f"Разговоры – Вопросы {start+1}–{start+5}")
        for i, (qe,qr,ae,ar) in enumerate(convs[start:start+5], start=start+1):
            qa_block(story, i, qe, qr, ae, ar)

    # Page 8 – Quick Reference
    sec(story, "🤔 Quick Reference Card", "Быстрая справочная карточка")
    qhdr = [hdr_cell("Pronoun\nМестоимение",""), hdr_cell("Russian\nПо-русски",""), hdr_cell("Quick Example (EN + RU)\nПример (англ. + рус.)","")]
    qrows = [
        ("ME\nМЕНЯ",   "меня / мне",  "She sees me.\nОна видит меня."),
        ("YOU\nТЕБЯ",  "тебя / вас",  "I called you.\nЯ позвонил тебе."),
        ("HIM\nЕГО",   "его / ему",   "We helped him.\nМы помогли ему."),
        ("HER\nЕЁ",    "её / ей",     "He thanked her.\nОн поблагодарил её."),
        ("IT\nЕГО/ЕЁ", "его / её",   "I can see it.\nЯ вижу его."),
        ("US\nНАС",    "нас / нам",   "She invited us.\nОна пригласила нас."),
        ("THEM\nИХ",   "их / им",     "I know them.\nЯ знаю их."),
    ]
    qdata = [qhdr]
    for p, r, ex in qrows:
        qdata.append([Paragraph(p, TC), Paragraph(r, TR), Paragraph(ex, TC)])
    std_table(qdata, [3.5*cm, 4*cm, 8*cm], story)
    story.append(sp(0.25))
    story.append(colbox([
        Paragraph("🤔 Object pronouns come AFTER the verb or preposition!", N_EN),
        Paragraph("Объектные местоимения стоят ПОСЛЕ глагола или предлога!", N_RU),
    ], bg=LIGHT_GOLD))

    make_doc(out).build(story)
    print(f"✅ {out}")

# ══════════════════════════════════════════════════════════════════════════════
# BOOK 2 – DEMONSTRATIVE PRONOUNS
# ══════════════════════════════════════════════════════════════════════════════
def build_demonstrative_pronouns():
    out = "/home/daytona/workspace/esl-pronouns/ESL_Grade3_Demonstrative_Pronouns.pdf"
    story = []

    cover_page(story,
        "Demonstrative\nPronouns",
        "Указательные местоимения",
        "This • That • These • Those",
        "Этот/Эта/Это • Тот/Та/То • Эти • Те")

    # Page 2 – Definition
    sec(story, "What is a Demonstrative Pronoun? 🤔", "Что такое указательное местоимение?")
    story.append(colbox([
        Paragraph("A demonstrative pronoun points to a specific person or thing.", B_EN),
        Paragraph("Указательное местоимение указывает на конкретного человека или предмет.", B_RU),
        sp(0.12),
        Paragraph("THIS and THESE = things that are NEAR you.", B_EN),
        Paragraph("THIS и THESE = предметы, которые находятся БЛИЗКО к вам.", B_RU),
        sp(0.08),
        Paragraph("THAT and THOSE = things that are FAR AWAY.", B_EN),
        Paragraph("THAT и THOSE = предметы, которые находятся ДАЛЕКО от вас.", B_RU),
    ], bg=LIGHT_TEAL))
    story.append(sp(0.28))

    for en, ru in [
        ("🤔 This is my pencil. (near me)", "Это мой карандаш. (рядом со мной)"),
        ("🤔 That is a tall building. (far away)", "То — высокое здание. (далеко)"),
        ("🤔 These are my books. (near, more than one)", "Эти — мои книги. (рядом, больше одного)"),
        ("🤔 Those are his shoes. (far, more than one)", "Те — его туфли. (далеко, больше одного)"),
    ]:
        story.append(Paragraph(en, EX_EN)); story.append(Paragraph(ru, EX_RU)); story.append(sp(0.12))

    # Page 3 – Table
    sec(story, "🤔 Demonstrative Pronouns Table", "Таблица указательных местоимений")
    hdr = [hdr_cell("Demonstrative Pronoun\nУказательное местоимение",""), hdr_cell("Number / Distance\nЧисло / Расстояние",""), hdr_cell("Russian Translation\nПеревод на русский",""), hdr_cell("Example Sentence\nПример предложения","")]
    rows = [
        ("THIS / ЭТО",  "Singular / Near\nЕд.ч. / Близко",  "этот / эта / это",  "This is my bag.\nЭта сумка — моя."),
        ("THAT / ТО",   "Singular / Far\nЕд.ч. / Далеко",   "тот / та / то",     "That is a big tree.\nТо — большое дерево."),
        ("THESE / ЭТИ", "Plural / Near\nМн.ч. / Близко",    "эти",               "These are my crayons.\nЭти — мои карандаши."),
        ("THOSE / ТЕ",  "Plural / Far\nМн.ч. / Далеко",     "те",                "Those are her books.\nТе — её книги."),
    ]
    tdata = [hdr]
    for p, nd, ru, ex in rows:
        tdata.append([Paragraph(p, TC), Paragraph(nd, TR), Paragraph(ru, TR), Paragraph(ex, TC)])
    std_table(tdata, [3*cm, 3.7*cm, 3.5*cm, 5.3*cm], story)

    # Near vs Far visual box
    story.append(sp(0.25))
    nf = Table([
        [Paragraph("📍 NEAR — близко к вам", sty("NF1", fontSize=10, leading=13, alignment=TA_CENTER, textColor=DARK_BLUE, fontName="DV-B")),
         Paragraph("📍 FAR — далеко от вас", sty("NF2", fontSize=10, leading=13, alignment=TA_CENTER, textColor=DARK_BLUE, fontName="DV-B"))],
        [Paragraph("Singular (1): THIS\nЕдинственное число (1): THIS\n\nPlural (2+): THESE\nМножественное число (2+): THESE", TC),
         Paragraph("Singular (1): THAT\nЕдинственное число (1): THAT\n\nPlural (2+): THOSE\nМножественное число (2+): THOSE", TC)],
    ], colWidths=[7.75*cm, 7.75*cm])
    nf.setStyle(TableStyle([
        ("BACKGROUND",    (0,0),(0,-1), colors.HexColor("#DFF5E1")),
        ("BACKGROUND",    (1,0),(1,-1), colors.HexColor("#FFF0D0")),
        ("BOX",           (0,0),(-1,-1), 1, TEAL),
        ("INNERGRID",     (0,0),(-1,-1), 0.5, TEAL),
        ("ALIGN",         (0,0),(-1,-1), "CENTER"),
        ("TOPPADDING",    (0,0),(-1,-1), 7), ("BOTTOMPADDING",(0,0),(-1,-1), 7),
        ("LEFTPADDING",   (0,0),(-1,-1), 6), ("RIGHTPADDING", (0,0),(-1,-1), 6),
        ("VALIGN",        (0,0),(-1,-1), "MIDDLE"),
    ]))
    story.append(nf)

    # Page 4 – Formula
    sec(story, "✏️ Formula to Build Sentences", "Формула для составления предложений")
    formula_row(story, [
        ("DEM. PRONOUN\nУКАЗАТ. МЕСТОИМ.", "", DARK_BLUE),
        ("+","",WHITE),
        ("IS / ARE\nЕСТЬ / ЯВЛЯЮТСЯ", "", TEAL),
        ("+","",WHITE),
        ("REST OF SENTENCE\nОСТАТОК ПРЕДЛОЖЕНИЯ", "", GOLD),
    ])
    sec(story, "🤔 Example Sentences", "Примеры предложений")
    fhdr = [hdr_cell("Dem. Pronoun\nУказат. мест.",""), hdr_cell("Verb\nГлагол",""), hdr_cell("Rest\nОстаток",""), hdr_cell("Translation\nПеревод","")]
    frows = [
        ("This",  "is",  "my notebook.",         "Это мой блокнот."),
        ("That",  "is",  "a very old bridge.",    "То — очень старый мост."),
        ("These", "are", "fresh apples.",         "Эти — свежие яблоки."),
        ("Those", "are", "my father's tools.",    "Те — инструменты моего папы."),
        ("This",  "is",  "the correct answer.",   "Это правильный ответ."),
        ("Those", "are", "wild birds.",           "Те — дикие птицы."),
    ]
    fdata = [fhdr]
    for dp, v, rest, ru in frows:
        fdata.append([Paragraph(dp, TC), Paragraph(v, TC), Paragraph(rest, TC), Paragraph(ru, TR)])
    std_table(fdata, [3.5*cm, 2.5*cm, 5*cm, 4.5*cm], story)

    # Pages 5-7 – Conversations
    convs = [
        ("What is that tall building near the park?","Что это за высокое здание у парка?","That is the new library. It opened last month and has many books.","То — новая библиотека. Она открылась в прошлом месяце и в ней много книг."),
        ("Are these your colour pencils on the table?","Это твои цветные карандаши на столе?","Yes, these are mine. I use them for my art class every Friday.","Да, эти — мои. Я использую их на уроке рисования каждую пятницу."),
        ("What is this small animal in the box?","Что это за маленькое животное в коробке?","This is a hamster. Its name is Peanut.","Это хомяк. Его зовут Пинат."),
        ("Whose shoes are those by the front door?","Чьи это туфли у парадной двери?","Those are my father's shoes. He always leaves them there after work.","Те — туфли моего папы. Он всегда оставляет их там после работы."),
        ("Is this the right classroom for Grade 3?","Это правильный класс для 3-го класса?","Yes, this is the right one. Our teacher is already inside.","Да, это правильный. Наш учитель уже внутри."),
        ("What are those colourful flags on the wall?","Что это за разноцветные флаги на стене?","Those are country flags. Our teacher put them up for a geography lesson.","Те — флаги стран. Наш учитель повесил их для урока географии."),
        ("Is this water safe to drink?","Эта вода безопасна для питья?","Yes, this is clean drinking water from the school filter.","Да, это чистая питьевая вода из школьного фильтра."),
        ("What are these papers on your desk?","Что это за бумаги на твоём столе?","These are my test results. I got a high score in all subjects.","Это мои результаты тестов. Я получил высокий балл по всем предметам."),
        ("Can you see those children in the yard?","Ты видишь тех детей во дворе?","Yes, I can see them. Those are my classmates playing football.","Да, я вижу их. Те — мои одноклассники, они играют в футбол."),
        ("Whose drawing is this on the board?","Чей это рисунок на доске?","This is Anna's drawing. She drew it during free time today.","Это рисунок Анны. Она нарисовала его сегодня на свободном уроке."),
        ("Are those mountains real or in a picture?","Те горы настоящие или на картинке?","Those are real mountains. We can see them from the school roof.","Те горы настоящие. Мы можем видеть их с крыши школы."),
        ("What is this sweet smell in the kitchen?","Что это за сладкий запах на кухне?","This is the smell of fresh bread. The cook baked it this morning.","Это запах свежего хлеба. Повар испёк его этим утром."),
        ("Are these apples from your garden?","Эти яблоки из вашего сада?","Yes, these are from our garden. My mother picked them yesterday.","Да, эти — из нашего сада. Мама сорвала их вчера."),
        ("What are those bright lights in the sky?","Что это за яркие огни в небе?","Those are stars. On a clear night you can count hundreds of them.","Те — звёзды. В ясную ночь можно сосчитать сотни из них."),
        ("Is this the book you wanted to borrow?","Это та книга, которую ты хотел взять?","Yes, this is the one! I have been looking for it all week.","Да, это она! Я искал её всю неделю."),
    ]
    for start in [0, 5, 10]:
        sec(story, f"🤔 Conversations – Q{start+1} to Q{start+5}", f"Разговоры – Вопросы {start+1}–{start+5}")
        for i, (qe,qr,ae,ar) in enumerate(convs[start:start+5], start=start+1):
            qa_block(story, i, qe, qr, ae, ar)

    # Page 8 – Quick Reference
    sec(story, "🤔 Quick Reference Card", "Быстрая справочная карточка")
    qhdr = [hdr_cell("Pronoun\nМестоимение",""), hdr_cell("Use\nКогда использовать",""), hdr_cell("Russian\nПо-русски",""), hdr_cell("Quick Example (EN + RU)\nПример","")]
    qrows = [
        ("THIS / ЭТО",  "Singular / Near\nЕд.ч. / Близко",  "этот/эта/это", "This is my pen.\nЭто моя ручка."),
        ("THAT / ТО",   "Singular / Far\nЕд.ч. / Далеко",   "тот/та/то",    "That is a cloud.\nТо — облако."),
        ("THESE / ЭТИ", "Plural / Near\nМн.ч. / Близко",    "эти",          "These are my boots.\nЭти — мои сапоги."),
        ("THOSE / ТЕ",  "Plural / Far\nМн.ч. / Далеко",     "те",           "Those are tall trees.\nТе — высокие деревья."),
    ]
    qdata = [qhdr]
    for p, u, r, ex in qrows:
        qdata.append([Paragraph(p, TC), Paragraph(u, TR), Paragraph(r, TR), Paragraph(ex, TC)])
    std_table(qdata, [3*cm, 3.5*cm, 3*cm, 6*cm], story)
    story.append(sp(0.25))
    story.append(colbox([
        Paragraph("🤔 THIS / THESE = near you   •   THAT / THOSE = far away", N_EN),
        Paragraph("THIS / THESE = рядом с вами   •   THAT / THOSE = далеко от вас", N_RU),
        sp(0.1),
        Paragraph("THIS / THAT = singular (one)   •   THESE / THOSE = plural (more than one)", N_EN),
        Paragraph("THIS / THAT = единственное число (один)   •   THESE / THOSE = множественное число (много)", N_RU),
    ], bg=LIGHT_GOLD))

    make_doc(out).build(story)
    print(f"✅ {out}")

# ══════════════════════════════════════════════════════════════════════════════
# BOOK 3 – POSSESSIVE PRONOUNS
# ══════════════════════════════════════════════════════════════════════════════
def build_possessive_pronouns():
    out = "/home/daytona/workspace/esl-pronouns/ESL_Grade3_Possessive_Pronouns.pdf"
    story = []

    cover_page(story,
        "Possessive\nPronouns",
        "Притяжательные местоимения (самостоятельные)",
        "Mine • Yours • His • Hers • Ours • Theirs",
        "Мой/Моя • Твой/Твоя • Его • Её • Наш/Наша • Их")

    # Page 2 – Definition
    sec(story, "What is a Possessive Pronoun? 🤔", "Что такое притяжательное местоимение?")
    story.append(colbox([
        Paragraph("A possessive pronoun shows that something belongs to someone.", B_EN),
        Paragraph("Притяжательное местоимение показывает, что что-то принадлежит кому-то.", B_RU),
        sp(0.12),
        Paragraph("Unlike possessive adjectives (my, your, his...), possessive pronouns STAND ALONE — they do NOT come before a noun.", B_EN),
        Paragraph("В отличие от притяжательных прилагательных (my, your, his...), притяжательные местоимения стоят САМОСТОЯТЕЛЬНО — они НЕ стоят перед существительным.", B_RU),
    ], bg=LIGHT_TEAL))
    story.append(sp(0.25))

    for en, ru in [
        ("🤔 This pencil is mine.", "Этот карандаш — мой."),
        ("🤔 That red bag is hers.", "Та красная сумка — её."),
        ("🤔 The blue umbrella is ours.", "Синий зонт — наш."),
        ("🤔 Those books are theirs.", "Те книги — их."),
    ]:
        story.append(Paragraph(en, EX_EN)); story.append(Paragraph(ru, EX_RU)); story.append(sp(0.12))

    # Adjective vs Pronoun comparison
    story.append(sp(0.1))
    cmp = Table([
        [Paragraph("Possessive ADJECTIVE (before a noun)\nПрит. ПРИЛАГАТЕЛЬНОЕ (перед существительным)", TH),
         Paragraph("Possessive PRONOUN (stands alone)\nПрит. МЕСТОИМЕНИЕ (самостоятельно)", TH)],
        [Paragraph("This is my book.\nЭто моя книга.", TC),
         Paragraph("This book is mine.\nЭта книга — моя.", TC)],
        [Paragraph("Your pencil is sharp.\nТвой карандаш острый.", TC),
         Paragraph("The pencil is yours.\nКарандаш — твой.", TC)],
        [Paragraph("Their dog is big.\nИх собака большая.", TC),
         Paragraph("The big dog is theirs.\nБольшая собака — их.", TC)],
    ], colWidths=[7.75*cm, 7.75*cm])
    cmp.setStyle(TableStyle([
        ("BACKGROUND",    (0,0),(-1,0), DARK_BLUE),
        ("BACKGROUND",    (0,1),(0,-1), colors.HexColor("#FFF0D0")),
        ("BACKGROUND",    (1,1),(1,-1), colors.HexColor("#DFF5E1")),
        ("BOX",           (0,0),(-1,-1), 1, TEAL),
        ("INNERGRID",     (0,0),(-1,-1), 0.5, TEAL),
        ("TOPPADDING",    (0,0),(-1,-1), 7), ("BOTTOMPADDING",(0,0),(-1,-1), 7),
        ("LEFTPADDING",   (0,0),(-1,-1), 7), ("RIGHTPADDING", (0,0),(-1,-1), 7),
        ("VALIGN",        (0,0),(-1,-1), "TOP"),
    ]))
    story.append(cmp)

    # Page 3 – Table
    sec(story, "🤔 Possessive Pronouns Table", "Таблица притяжательных местоимений")
    hdr = [hdr_cell("Possessive Pronoun (EN)\nПритяжательное местоимение",""), hdr_cell("Russian Translation\nПеревод на русский",""), hdr_cell("Example Sentence\nПример предложения","")]
    rows = [
        ("MINE\nМОЙ / МОЯ / МОЁ",   "мой / моя / моё / мои",       "This pencil is mine.\nЭтот карандаш — мой."),
        ("YOURS\nТВОЙ / ВАШ",        "твой / твоя / ваш / ваша",    "Is this seat yours?\nЭто место твоё?"),
        ("HIS\nЕГО",                  "его",                          "The blue jacket is his.\nСиняя куртка — его."),
        ("HERS\nЕЁ",                  "её",                           "That red umbrella is hers.\nТот красный зонт — её."),
        ("OURS\nНАШ / НАША",         "наш / наша / наше / наши",     "This classroom is ours.\nЭтот класс — наш."),
        ("THEIRS\nИХ",               "их",                           "Those bikes are theirs.\nТе велосипеды — их."),
    ]
    tdata = [hdr]
    for p, r, ex in rows:
        tdata.append([Paragraph(p, TC), Paragraph(r, TR), Paragraph(ex, TC)])
    std_table(tdata, [4*cm, 4.5*cm, 7*cm], story)

    # Page 4 – Formula
    sec(story, "✏️ Formula to Build Sentences", "Формула для составления предложений")
    formula_row(story, [
        ("NOUN / SUBJECT\nСУЩ. / ПОДЛЕЖАЩЕЕ", "", DARK_BLUE),
        ("+","",WHITE),
        ("IS / ARE\nЕСТЬ / ЯВЛЯЮТСЯ", "", TEAL),
        ("+","",WHITE),
        ("POSSESSIVE PRONOUN\nПРИТЯЖ. МЕСТОИМЕНИЕ", "", GOLD),
    ])
    sec(story, "🤔 Example Sentences", "Примеры предложений")
    fhdr = [hdr_cell("Noun / Subject\nПодлежащее",""), hdr_cell("Verb\nГлагол",""), hdr_cell("Poss. Pronoun\nПрит. мест.",""), hdr_cell("Translation\nПеревод","")]
    frows = [
        ("This eraser",          "is",  "mine",   "Этот ластик — мой."),
        ("The green backpack",   "is",  "yours",  "Зелёный рюкзак — твой."),
        ("That trophy",          "is",  "his",    "Тот кубок — его."),
        ("The pink water bottle","is",  "hers",   "Розовая бутылка воды — её."),
        ("The corner table",     "is",  "ours",   "Угловой стол — наш."),
        ("Those big umbrellas",  "are", "theirs", "Те большие зонты — их."),
    ]
    fdata = [fhdr]
    for s, v, pp, ru in frows:
        fdata.append([Paragraph(s, TC), Paragraph(v, TC), Paragraph(pp, TC), Paragraph(ru, TR)])
    std_table(fdata, [4.5*cm, 2.5*cm, 3.5*cm, 5*cm], story)

    # Pages 5-7 – Conversations
    convs = [
        ("Whose eraser is on the floor?","Чей ластик лежит на полу?","That eraser is mine. I dropped it when I was writing.","Тот ластик — мой. Я уронил его, когда писал."),
        ("Is this blue jacket yours?","Эта синяя куртка твоя?","Yes, that jacket is mine. I left it on the chair after lunch.","Да, та куртка — моя. Я оставил её на стуле после обеда."),
        ("Whose turn is it to lead the class?","Чья очередь руководить классом?","The turn is his. He is the class leader this week.","Очередь — его. Он дежурный по классу на этой неделе."),
        ("I found a purple water bottle. Is it yours?","Я нашёл фиолетовую бутылку воды. Она твоя?","No, it is not mine. It might be hers — she has a purple one.","Нет, это не моя. Это может быть её — у неё есть фиолетовая."),
        ("Which team won the relay race?","Какая команда выиграла эстафету?","The victory is ours! We practised every day after school.","Победа — наша! Мы тренировались каждый день после школы."),
        ("Are those large bags by the bus theirs?","Те большие сумки у автобуса — их?","Yes, those bags are theirs. Their family is going on a trip.","Да, те сумки — их. Их семья едет в поездку."),
        ("Whose science project got first place?","Чей научный проект занял первое место?","The first-place project is hers. She worked on it for two weeks.","Проект на первом месте — её. Она работала над ним две недели."),
        ("I see two bicycles. Which one is yours?","Я вижу два велосипеда. Который твой?","The red one is mine. The yellow one is my brother's.","Красный — мой. Жёлтый — моего брата."),
        ("Whose idea was it to plant flowers in the garden?","Чья это была идея — посадить цветы в саду?","The idea was ours. The whole class voted for it together.","Идея была наша. Весь класс проголосовал за неё вместе."),
        ("Is that trophy in the cabinet his?","Тот кубок в шкафу — его?","Yes, that trophy is his. He won it at the swimming competition.","Да, тот кубок — его. Он выиграл его на соревнованиях по плаванию."),
        ("Whose homework is on the teacher's table?","Чьё домашнее задание лежит на столе учителя?","The homework on the table is mine. I handed it in this morning.","Домашнее задание на столе — моё. Я сдал его сегодня утром."),
        ("Those colourful drawings on the wall — are they yours?","Те красочные рисунки на стене — твои?","No, they are not mine. Those drawings are theirs — the art club students.","Нет, не мои. Те рисунки — их, учеников кружка рисования."),
        ("This umbrella was left at the door. Is it yours or hers?","Этот зонт оставили у двери. Он твой или её?","It is hers. She forgot it when she ran to catch the school bus.","Он её. Она забыла его, когда бежала на школьный автобус."),
        ("We found a lunch box with no name. Is it yours?","Мы нашли ланч-бокс без имени. Он твой?","Yes, that lunch box is mine! I forgot to write my name on it.","Да, тот ланч-бокс — мой! Я забыл написать на нём своё имя."),
        ("Are those tools in the shed ours or the neighbours'?","Те инструменты в сарае — наши или соседей?","Those tools are ours. My father uses them to fix things at home.","Те инструменты — наши. Папа использует их, чтобы починить что-то дома."),
    ]
    for start in [0, 5, 10]:
        sec(story, f"🤔 Conversations – Q{start+1} to Q{start+5}", f"Разговоры – Вопросы {start+1}–{start+5}")
        for i, (qe,qr,ae,ar) in enumerate(convs[start:start+5], start=start+1):
            qa_block(story, i, qe, qr, ae, ar)

    # Page 8 – Quick Reference
    sec(story, "🤔 Quick Reference Card", "Быстрая справочная карточка")
    qhdr = [hdr_cell("Pronoun\nМестоимение",""), hdr_cell("Russian\nПо-русски",""), hdr_cell("Quick Example (EN + RU)\nПример (англ. + рус.)","")]
    qrows = [
        ("MINE\nМОЙ / МОЯ",   "мой/моя/моё/мои",  "This pen is mine.\nЭта ручка — моя."),
        ("YOURS\nТВОЙ / ВАШ", "твой/ваш",          "Is this seat yours?\nЭто место твоё?"),
        ("HIS\nЕГО",           "его",               "The trophy is his.\nКубок — его."),
        ("HERS\nЕЁ",           "её",                "The red bag is hers.\nКрасная сумка — её."),
        ("OURS\nНАШ / НАША",  "наш/наша",          "This classroom is ours.\nЭтот класс — наш."),
        ("THEIRS\nИХ",         "их",                "Those bikes are theirs.\nТе велосипеды — их."),
    ]
    qdata = [qhdr]
    for p, r, ex in qrows:
        qdata.append([Paragraph(p, TC), Paragraph(r, TR), Paragraph(ex, TC)])
    std_table(qdata, [3.5*cm, 4*cm, 8*cm], story)
    story.append(sp(0.25))
    story.append(colbox([
        Paragraph("🤔 Possessive pronouns stand ALONE — they do NOT come before a noun!", N_EN),
        Paragraph("Притяжательные местоимения стоят САМОСТОЯТЕЛЬНО — они НЕ стоят перед существительным!", N_RU),
        sp(0.1),
        Paragraph("Compare: 'my book' (adjective)   vs.   'the book is mine' (pronoun)", N_EN),
        Paragraph("Сравните: 'моя книга' (прилагательное)   и   'книга — моя' (местоимение)", N_RU),
    ], bg=LIGHT_GOLD))

    make_doc(out).build(story)
    print(f"✅ {out}")

# ── Run ───────────────────────────────────────────────────────────────────────
if __name__ == "__main__":
    build_object_pronouns()
    build_demonstrative_pronouns()
    build_possessive_pronouns()
    print("\n🎉 All three handbooks created successfully!")
Running Command

cd /home/daytona/workspace/esl-pronouns && python3 build_handbooks_v3.py 2>&1

Running Command

ls /usr/share/fonts/truetype/dejavu/ echo "---" ls /usr/share/fonts/truetype/lib…

Editing File

~/esl-pronouns/build_handbooks_v3.py

Successfully replaced 1 instance(s) of the string in '/home/daytona/workspace/esl-pronouns/build_handbooks_v3.py'
Running Command

cd /home/daytona/workspace/esl-pronouns && python3 build_handbooks_v3.py 2>&1

Running Command

ls -lh /home/daytona/workspace/esl-pronouns/*.pdf && python3 -c " from pypdf imp…

Russian text is rendering perfectly now - files are 83-86KB (proper size, up from the broken 13-16KB). All Cyrillic text is fully visible. Download the corrected files:

📘 Object Pronouns (Me • You • Him • Her • It • Us • Them)

ESL Grade3 Object Pronouns

PDF Document · PDF

📗 Demonstrative Pronouns (This • That • These • Those)

ESL Grade3 Demonstrative Pronouns

PDF Document · PDF

📙 Possessive Pronouns (Mine • Yours • His • Hers • Ours • Theirs)

ESL Grade3 Possessive Pronouns

PDF Document · PDF


The problem before was that the standard PDF font (Helvetica) has no Cyrillic characters, so Russian text appeared as blank boxes. The fix was switching to DejaVu Sans (a Unicode font installed on the system), which fully supports the Russian alphabet. Every Russian line now renders correctly - under headings, in tables, in the Q&A boxes, in the formula rows, and in the reference cards.
This is a shared conversation. Sign in to Orris to start your own chat.