#!/usr/bin/env python3
"""WEEK X GENERATOR TEMPLATE - [PHONICS PATTERN]

  HOW TO USE THIS TEMPLATE:
  1. Copy to Week_XX/generate_weekX.py
  2. Replace WEEK_DIR path below
  3. Search for [UPDATE] markers (73 of them) and fill in your week's content
  4. Replace all Week0X_ filenames with your week number
  5. Run: python3 generate_weekX.py

  LAYOUT CONVENTIONS (DO NOT CHANGE):
  - Monday: 4 pages. Header + Learning + Word Cards -> break -> Spelling Story + Grammar + Capitals -> break -> Vowel Sort -> break -> Copy Practice + Fill Blank + Opposites + Sentence Writing
  - Tuesday: 3 pages. Header + Learning + Remember + Word Scramble + Reading + Comprehension -> break -> Pattern Hunt -> break -> Word Swap + Sentence Builder
  - Wednesday: 4 pages. Header + Learning + Reading + Vocab Q -> break -> Synonyms/Antonyms + Word Web + Sentence Sort + Correct + Fill Blank -> break -> Context Clues + Dictation
  - Thursday: 4 pages. Header + Learning + Remember + Story + Comprehension + Sentence Sort -> break -> Spelling Detective + Word Swap + Spelling Map -> break -> Paragraph Builder -> break -> Write Your Own Story + Diary Entry
  - Friday: 5 pages. Test (2 col x 12) -> break -> Review Reading + Story Qs -> break -> Opposites + Sentence Builder -> break -> Show What You Know + Word Journal -> break -> Celebration

Requirements: 12 words, all 6+ letters, all match target phonics pattern
"""

import os
import random
import re
import inspect
from weasyprint import HTML

# Shared modules
from validate import validate_week, report_validation
from helpers import (
    header, sectitle, secnote, write_line, copy_line, page_break,
    word_bank, fill_blank_with_line, word_search, remember_box, fb,
    CSS
)

# [UPDATE]: Change this path to your week directory
WEEK = os.path.expanduser("~/Home_School/2nd_Grade/English_Language_Arts/Week_XX")

# =====================================================================
# STEP 1: Replace these 12 words with your week's vocabulary
# Format: ("word", "vowel_pattern", "kid-friendly_definition")
# Requirements: ALL words 6+ letters, ALL match target phonics pattern
# =====================================================================
WORDS = [
    ("WORD1", "PATTERN", "definition here"),
    ("WORD2", "PATTERN", "definition here"),
    ("WORD3", "PATTERN", "definition here"),
    ("WORD4", "PATTERN", "definition here"),
    ("WORD5", "PATTERN", "definition here"),
    ("WORD6", "PATTERN", "definition here"),
    ("WORD7", "PATTERN", "definition here"),
    ("WORD8", "PATTERN", "definition here"),
    ("WORD9", "PATTERN", "definition here"),
    ("WORD10", "PATTERN", "definition here"),
    ("WORD11", "PATTERN", "definition here"),
    ("WORD12", "PATTERN", "definition here"),
]

WORD_NAMES = [w[0] for w in WORDS]
# [UPDATE]: Adjust these category variable names to match your pattern types
# For silent e: LONG_A, LONG_E, LONG_I, LONG_O
# For r-controlled: R_A, R_E, R_O
# For blends: S_BLENDS, T_BLENDS, etc.
LONG_A = [w[0] for w in WORDS if w[1] == "PATTERN_A"]
LONG_E = [w[0] for w in WORDS if w[1] == "PATTERN_E"]
LONG_I = [w[0] for w in WORDS if w[1] == "PATTERN_I"]
LONG_O = [w[0] for w in WORDS if w[1] == "PATTERN_O"]

CSS = """
@page { size: letter; margin: 0.7in 0.85in; }
body { font-family: 'Comic Neue', 'Comic Sans MS', sans-serif; color: #222; background: #fff; margin: 0; line-height: 1.4; }
p { orphans: 3; widows: 3; }
header { display: flex; justify-content: space-between; align-items: baseline; border-bottom: 3px solid #26A69A; padding-bottom: 6px; margin-bottom: 12px; }
header h1 { font-size: 17px; margin: 0; color: #26A69A; }
header .subtitle { font-size: 12px; color: #666; }
header .name-line { font-size: 12px; }
h2 { font-size: 14px; color: #26A69A; margin: 14px 0 4px 0; border-bottom: 2px solid #B2DFDB; padding-bottom: 2px; break-after: avoid; }
h2.coral { color: #FF7043; border-bottom-color: #FFAB91; }
.note { background: #E8F5E9; border-left: 4px solid #26A69A; padding: 6px 10px; border-radius: 4px; font-size: 11.5px; margin: 4px 0 10px 0; color: #333; break-inside: avoid; }
.activity { break-inside: avoid; page-break-inside: avoid; }
.word-grid { width: 100%; border-collapse: separate; border-spacing: 3px; }
.word-grid td { vertical-align: top; }
.word-card { border: 1.5px solid #B2DFDB; border-radius: 6px; padding: 4px 6px; background: #FAFAFA; break-inside: avoid; }
.word-card .word { font-size: 12px; font-weight: bold; color: #26A69A; margin-bottom: 1px; }
.word-card .def { font-size: 9px; color: #555; line-height: 1.15; }
.write-line {
    position: relative; height: 18px; margin: 1px 0; width: 100%;
}
tr { break-inside: avoid; }
.fb-item { background: #E0F2F1; border: 1.5px solid #80CBC4; border-radius: 6px; padding: 6px 8px; margin-bottom: 6px; font-size: 12px; break-inside: avoid; page-break-inside: avoid; }
.fb-item p { margin: 0 0 4px 0; }
.word-bank { background: #FFF3E0; border: 2px dashed #FFB74D; border-radius: 8px; padding: 8px 12px; margin: 8px 0; }
.word-bank-label { font-size: 11px; font-weight: bold; color: #FF7043; margin-bottom: 4px; }
.word-bank-words { display: flex; flex-wrap: wrap; gap: 6px; }
.word-bank-words span { background: white; border: 1px solid #FFB74D; border-radius: 4px; padding: 2px 8px; font-size: 11px; }
.ws-grid { display: inline-block; font-family: monospace; font-size: 12px; letter-spacing: 2px; line-height: 1.4; background: #F5F5F5; border: 2px solid #B2DFDB; border-radius: 6px; padding: 6px 8px; text-align: left; }
.ws-table { border-collapse: collapse; margin: 8px auto; background: #F5F5F5; border: 2px solid #B2DFDB; break-inside: avoid; page-break-inside: avoid; }
.ws-table td { width: 28px; height: 28px; text-align: center; vertical-align: middle; font-family: monospace; font-size: 14px; font-weight: bold; border: 1px solid #B2DFDB; color: #333; }
.ws-words { display: flex; flex-wrap: wrap; gap: 6px 16px; margin: 8px 0; justify-content: center; }
.ws-words span { font-size: 11px; background: #E0F2F1; border: 1px solid #80CBC4; border-radius: 3px; padding: 2px 6px; }
.mystery-box { background: #FFF8E1; border: 2px solid #FFD54F; border-radius: 8px; padding: 10px; margin: 8px 0; break-inside: avoid; }
.mystery-box .title { font-size: 13px; font-weight: bold; color: #FF7043; margin-bottom: 6px; }
.mystery-box li { font-size: 11px; margin: 3px 0; }
.write-line {
    position: relative; height: 22px; margin: 2px 0; width: 100%;
}
.write-line-sky {
    position: absolute; left: 0; right: 0; top: 0;
    border-top: 0.6pt solid rgb(0,0,255);
}
.write-line-ground {
    position: absolute; left: 0; right: 0; bottom: 0;
    border-bottom: 0.6pt solid rgb(0,0,255);
}
.write-line-fence {
    position: absolute; left: 0; right: 0; bottom: 12px;
    border-bottom: 0.4pt dashed rgb(255,0,0);
}
.copy-line {
    position: relative; height: 22px; margin: 2px 0; width: 100%;
}
.copy-line-sky {
    position: absolute; left: 0; right: 0; top: 0;
    border-top: 0.6pt solid rgb(0,0,255);
}
.copy-line-ground {
    position: absolute; left: 0; right: 0; bottom: 0;
    border-bottom: 0.6pt solid rgb(0,0,255);
}
.copy-line-fence {
    position: absolute; left: 0; right: 0; bottom: 12px;
    border-bottom: 0.4pt dashed rgb(255,0,0);
}
.story-box { background: #F3E5F5; border: 1.5px solid #CE93D8; border-radius: 8px; padding: 10px; font-size: 12px; line-height: 1.5; margin: 8px 0; break-inside: avoid; }
.test-item { display: flex; align-items: center; gap: 8px; font-size: 13px; margin: 6px 0; }
.test-item .num { font-weight: bold; color: #26A69A; min-width: 20px; }
.divider { border-top: 1px dashed #ccc; margin: 12px 0; }
"""


def header(title, subtitle=""):
    return (f'<header>'
            f'<h1>{title}</h1>'
            f'<div class="subtitle">{subtitle}</div>'
            f'<div class="name-line">Name: ________________</div>'
            f'</header>')

def sectitle(text, color="teal"):
    cls = "coral" if color == "coral" else ""
    return f'<h2 class="{cls}">{text}</h2>'

def secnote(text):
    return f'<div class="note">{text}</div>'

def word_bank(words, seed=99):
    rnd = random.Random(seed)
    shuffled = list(words)
    rnd.shuffle(shuffled)
    word_spans = "".join(f"<span>{w}</span>" for w in shuffled)
    return (f'<div class="word-bank">'
            f'<div class="word-bank-label">Word Bank</div>'
            f'<div class="word-bank-words">{word_spans}</div>'
            f'</div>')

def fill_blank_with_line(sentence):
    return (f'<div class="fb-item">'
            f'<p>{sentence}</p>'
            f'{write_line()}'
            f'</div>')

def word_search(word_list, rows=14, cols=14, seed=42):
    rnd = random.Random(seed)
    grid = [[""] * cols for _ in range(rows)]
    directions = [(0,1),(1,0),(1,1),(1,-1),(0,-1),(-1,0),(-1,-1),(-1,1)]
    for word in word_list:
        upper_word = word.upper()
        placed = False
        attempts = 0
        while not placed and attempts < 500:
            attempts += 1
            dr, dc = rnd.choice(directions)
            sr, sc = rnd.randint(0, rows-1), rnd.randint(0, cols-1)
            er, ec = sr + dr*(len(upper_word)-1), sc + dc*(len(upper_word)-1)
            if er < 0 or er >= rows or ec < 0 or ec >= cols:
                continue
            ok = True
            for i, ch in enumerate(upper_word):
                r, c = sr + dr*i, sc + dc*i
                if grid[r][c] and grid[r][c] != ch:
                    ok = False; break
            if ok:
                for i, ch in enumerate(upper_word):
                    grid[sr + dr*i][sc + dc*i] = ch
                placed = True
    letters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
    for r in range(rows):
        for c in range(cols):
            if not grid[r][c]:
                grid[r][c] = rnd.choice(letters)
    cell_html = ""
    for row in grid:
        cell_html += "<tr>"
        for ch in row:
            cell_html += f'<td>{ch}</td>'
        cell_html += "</tr>"
    word_list_html = "".join(f"<span>{w.upper()}</span>" for w in word_list)
    return (f'<div class="ws-words">{word_list_html}</div>'
            f'<table class="ws-table"><tbody>{cell_html}</tbody></table>')

def remember_box(title, content):
    return (f'<div class="story-box" style="background:#E8F5E9;border-color:#A5D6A7;">'
            f'<strong style="color:#2E7D32;">{title}</strong><br>'
            f'{content}'
            f'</div>')

def write_line():
    return '<div class="write-line"><div class="write-line-sky"></div><div class="write-line-fence"></div><div class="write-line-ground"></div></div>'

def copy_line():
    return '<div class="copy-line"><div class="copy-line-sky"></div><div class="copy-line-fence"></div><div class="copy-line-ground"></div></div>'

def page_break():
    return '<div style="page-break-after:always;"></div>'


# =====================================================================
# MONDAY - Learn It (5 pages)
# =====================================================================

def generate_monday():
    day_dir = os.path.join(WEEK, "Monday")
    os.makedirs(day_dir, exist_ok=True)

    # Word cards -- table layout: 6 rows, 2 columns
    card_items = '<table class="word-grid">'
    for i in range(0, len(WORDS), 2):
        card_items += '<tr>'
        for j in range(i, min(i+2, len(WORDS))):
            word, vowel, defn = WORDS[j]
            card_items += (f'<td><div class="word-card">'
                           f'<div class="word">{word}</div>'
                           f'<div class="def">{defn}</div>'
                           f'{write_line()}'
                           f'</div></td>')
        card_items += '</tr>'
    card_items += '</table>'

    # Vowel sort - Silent E pattern sort: Long A, Long E, Long I, Long O
    sort_words = list(WORD_NAMES)
    random.Random(42).shuffle(sort_words)
    sort_word_bank = word_bank(sort_words, seed=42)
    
    sort_col_html = ""
    for vlabel in ["Long A (a_e)", "Long E (e_e)", "Long I (i_e)", "Long O (o_e)"]:
        lines = "".join(write_line() for _ in range(3))
        sort_col_html += (f'<td style="width:25%;text-align:center;vertical-align:top;border:1.5px solid #B2DFDB;border-radius:6px;padding:6px;background:#FAFAFA;">'
                          f'<div style="font-weight:bold;font-size:11px;color:#26A69A;margin-bottom:6px;">{vlabel}</div>'
                          f'{lines}</td>')
    
    sort_html = (f'<div class="activity">{sort_word_bank}'
                 f'<table style="width:100%;border-collapse:separate;border-spacing:3px;">'
                 f'<tr>{sort_col_html}</tr></table></div>')

    # Grammar content
    grammar_text = ("A sentence is a group of words that makes a complete thought.<br>"
                    "Every sentence starts with a CAPITAL LETTER and ends with a PERIOD (.), "
                    "QUESTION MARK (?), or EXCLAMATION POINT (!).<br><br>"
                    "Example: <strong>The police officer arrived.</strong> &check;<br>"
                    "Not a sentence: <strong>police officer arrived.</strong> &times;")

    # Copy practice -- 24px words with taller writing lines
    copy_items = ""
    for i, (word, _, _) in enumerate(WORDS):
        copy_items += (f'<div style="display:flex;align-items:center;gap:12px;margin:10px 0;">'
                       f'<span style="font-weight:bold;font-size:24px;min-width:100px;color:#26A69A;line-height:34px;">{word}</span>'
                       f'<div style="flex:1;position:relative;height:34px;margin:2px 0;width:100%;">'
                       f'<div style="position:absolute;left:0;right:0;top:0;border-top:0.6pt solid rgb(0,0,255);"></div>'
                       f'<div style="position:absolute;left:0;right:0;bottom:18px;border-bottom:0.4pt dashed rgb(255,0,0);"></div>'
                       f'<div style="position:absolute;left:0;right:0;bottom:0;border-bottom:0.6pt solid rgb(0,0,255);"></div>'
                       f'</div></div>')

    # Sentence writing (first 4 words)
    sentence_words = WORDS[:4]
    sentence_items = ""
    for word, _, _ in sentence_words:
        sentence_items += (f'<div style="margin:6px 0;">'
                           f'<span style="font-size:11px;font-weight:bold;color:#26A69A;">{word}:</span>{write_line()}</div>')

    # Spelling story
    story_text = (
        'On a <strong>frozen</strong> morning, I <strong>notice</strong> a <strong>strange</strong> package on my doorstep. '
        'I <strong>invite</strong> my friend over to <strong>create</strong> a plan. '
        'We must be <strong>polite</strong> to the <strong>police</strong> officer who delivers it. '
        'Inside is a <strong>delicate</strong> toy. We <strong>separate</strong> the pieces and build it together. '
        'It becomes a <strong>private</strong> game for our afternoon <strong>escape</strong> from homework. '
        'Our project is now <strong>complete</strong> and ready to show!'
    )

    # Fill in the blank
    # [UPDATE: Fill-in-the-blank sentences with answers]
    fill_data = [
        ("[UPDATE: Sentence with ____]", "word1"),
        ("[UPDATE: Sentence with ____]", "word2"),
        ("[UPDATE: Sentence with ____]", "word3"),
        ("[UPDATE: Sentence with ____]", "word4"),
    ]
    fill_answers = [s[1] for s in fill_data]
    fill_bank = word_bank(fill_answers, seed=210)
    fill_items = "".join(fill_blank_with_line(s) for s, _ in fill_data)

    # Opposite match-up (no hints - student thinks of own words)
    # [UPDATE: Opposite match-up words - 2 words]
    opposite_words = ["word1", "word2"]
    opposite_html = ""
    for word in opposite_words:
        opposite_html += (f'<div style="margin:4px 0;font-size:12px;">'
                          f'<strong style="color:#673ab7;font-size:12px;">{word}</strong><br>{write_line()}</div>')

    html = f"""<!DOCTYPE html>
    <html><head><meta charset="utf-8"><style>{CSS}</style></head><body>

    <div>
    {header("English Language Arts", "Week X, Monday -- [PHONICS PATTERN]")}
    {sectitle("Here's What We're Learning")}
    {secnote("Silent E (also called 'Magic E') sits at the end of a word and makes the vowel say its name. The E itself is silent -- it doesn't make a sound!")}</li>
    <ul style="font-size:12px;margin:4px 0 8px 0;">
    <li>Long <strong>a</strong> as in <em>strange</em> -- str-<span style="color:#FF7043;font-weight:bold;">a</span>-n-g-<span style="color:#FF7043;font-weight:bold;">e</span></li>
    <li>Long <strong>i</strong> as in <em>invite</em> -- <span style="color:#FF7043;font-weight:bold;">i</span>-n-v-i-t-<span style="color:#FF7043;font-weight:bold;">e</span></li>
    <li>Long <strong>i</strong> as in <em>police</em> -- p-o-l-<span style="color:#FF7043;font-weight:bold;">i</span>-c-<span style="color:#FF7043;font-weight:bold;">e</span></li>
    </ul>
    {secnote("Grammar: A sentence is a group of words that makes a complete thought. It starts with a capital letter and ends with punctuation.")}</li>
    {sectitle("Word Cards")}
    {secnote("Read each word. Notice the silent E at the end making the vowel say its name.")}</li>
    <div class="word-grid">{card_items}</div>
    </div>
    {page_break()}

    <div>
    {sectitle("Spelling Story")}
    {secnote("Read the story. Circle each spelling word as you find it.")}</li>
    <div class="story-box">{story_text}</div>
    {sectitle("Grammar: What Is a Sentence?")}
    {secnote(grammar_text)}</li>
    {sectitle("Practice: Capital Letters & Periods")}
    {secnote("Add capital letters and periods to these sentences.")}</li>
    <div style="font-size:12px;margin:6px 0;">
    <div style="margin:4px 0;">the police officer arrived quickly.{write_line()}</div>
    <div style="margin:4px 0;">i want to invite you{write_line()}</div>
    <div style="margin:4px 0;">we can create something amazing{write_line()}</div>
    </div>
    </div>

    <div>
    {sectitle("Silent E Pattern Sort")}
    {secnote("Sort each word into the correct vowel column.")}</li>
    {sort_html}
    </div>
    {page_break()}

    <div>
    {sectitle("Copy Practice")}
    {secnote("Read each word carefully, then copy it neatly on the line.")}</li>
    {copy_items}
    </div>
    {page_break()}

    <div>
    {sectitle("Fill in the Blank")}
    {secnote("Choose a word from the word bank to complete each sentence.")}</li>
    {fill_bank}
    {fill_items}
    {sectitle("Opposite Match-Up")}
    {secnote("Write the opposite of each word.")}</li>
    {opposite_html}
    {sectitle("Sentence Writing")}
    {secnote("Write a complete sentence using each word. Remember: capital letter and period!")}</li>
    {sentence_items}
    </div>

    </body></html>"""

    HTML(string=html).write_pdf(os.path.join(day_dir, "Week0X_Monday_[TOPIC].pdf"))
    print("[ok] Monday generated")


# =====================================================================
# TUESDAY - Practice It (3 pages)
# =====================================================================

def generate_tuesday():
    day_dir = os.path.join(WEEK, "Tuesday")
    os.makedirs(day_dir, exist_ok=True)

    # 1. Word Scramble -- 12 scrambled words, 2-column table
    scramble_rows = ""
    for i in range(0, len(WORDS), 2):
        scramble_rows += '<tr>'
        for j in range(i, min(i+2, len(WORDS))):
            word, vowel, _ = WORDS[j]
            scrambled = list(word)
            random.Random(hash(word) % 1000).shuffle(scrambled)
            if "".join(scrambled) == word:
                scrambled[0], scrambled[-1] = scrambled[-1], scrambled[0]
            scramble_rows += (f'<td style="padding:4px 8px;vertical-align:top;">'
                             f'<span style="font-family:monospace;font-size:16px;font-weight:bold;color:#FF7043;letter-spacing:2px;">'
                             f'{" ".join(scrambled)}</span>'
                             f'<div style="margin-top:4px;"><div class="write-line"><div class="write-line-sky"></div><div class="write-line-fence"></div><div class="write-line-ground"></div></div></div>'
                             f'</td>')
        scramble_rows += '</tr>'
    scramble_items = f'<table style="width:100%;border-collapse:separate;border-spacing:4px;">{scramble_rows}</table>'

    # 2. Reading Comprehension passage
    # [UPDATE: Reading comprehension passage - use ALL spelling words in <strong> tags]
    reading_text = (
        '[UPDATE: Write a story using all spelling words in <strong> tags]'
    )

    # 3. Comprehension Questions
    # [UPDATE: Comprehension questions about the reading passage]
    comp_questions = [
        "[UPDATE: Question 1]",
        "[UPDATE: Question 2]",
        "[UPDATE: Question 3]",
    ]
    comp_html = ""
    for q in comp_questions:
        comp_html += (f'<div style="margin-bottom:8px;">'
                      f'<strong style="font-size:12px;">{q}</strong><br>'
                      f'{write_line()}</div>')

    # 4. Vowel Pattern Hunt -- check/circle target vowel (Silent E)
    hunt_html = ""
    for word, vowel, _ in WORDS:
        # Highlight the silent e pattern
        hunt_html += (f'<div style="display:inline-block;width:30%;margin-bottom:4px;padding:4px 8px;'
                       f'background:#E0F2F1;border-radius:4px;border-left:3px solid #26A69A;font-size:12px;">'
                      f'<span style="display:inline-block;width:14px;height:14px;border:1.5px solid #80CBC4;'
                      f'border-radius:3px;margin-right:4px;vertical-align:middle;"></span> '
                      f'<span style="color:#FF7043;font-weight:bold;">{word}</span></div>')

    # Word Swap Challenge
    # [UPDATE: Word swap - 2 sentences with word pairs]
    swap_data = [
        ("[original sentence]", ("word1_orig", "word1_swap"), ("word2_orig", "word2_swap")),
        ("[original sentence]", ("word1_orig", "word1_swap"), ("word2_orig", "word2_swap")),
    ]
    swap_html = ""
    for orig, (w1_orig, w1_swap), (w2_orig, w2_swap) in swap_data:
        swap_html += (f'<div style="margin-bottom:10px;padding:6px 8px;background:#FFF3E0;border-radius:5px;border:1px solid #FFB74D;">'
                      f'<div style="font-size:10.5px;font-weight:bold;color:#FF7043;margin-bottom:3px;">Original:</div>'
                      f'<div style="font-size:12px;font-style:italic;margin-bottom:4px;">'
                      f'{orig.replace(w1_orig, f"<strong>{w1_orig}</strong>").replace(w2_orig, f"<strong>{w2_orig}</strong>")}</div>'
                      f'<div style="font-size:10.5px;font-weight:bold;color:#FF7043;margin-bottom:3px;">Now write using <strong>{w1_swap}</strong> and <strong>{w2_swap}</strong>:</div>'
                      f'{write_line()}</div>')

    # Sentence Builder -- 3 prompts
    # [UPDATE: Sentence builder prompts - 3 prompts]
    builder_prompts = [
        ("[UPDATE: Prompt 1]", "word1"),
        ("[UPDATE: Prompt 2]", "word2"),
        ("[UPDATE: Prompt 3]", "word3"),
    ]
    builder_html = ""
    for prompt, keyword in builder_prompts:
        builder_html += (f'<div style="margin-bottom:10px;padding:6px 8px;background:#FFF3E0;border-radius:5px;border:1px solid #FFB74D;">'
                         f'<div style="font-size:11px;color:#888;font-style:italic;margin-bottom:3px;">'
                         f'{prompt} (use: <strong style="color:#26A69A;font-style:normal;">{keyword}</strong>)</div>'
                         f'{write_line()}</div>')

    # Remember This boxes
    # [UPDATE: Remember This box - pattern examples and practice question]
    remember1 = (
        "[UPDATE: Pattern reminder text with examples]<br><br>"
        "<strong>Try This:</strong> [UPDATE: Quick practice question] ___"
    )
    # [UPDATE: Second Remember This box]
    remember3 = (
        "[UPDATE: Pattern breakdown examples]<br><br>"
        "<strong>Try This:</strong> [UPDATE: Quick practice question] ___"
    )

    html = f"""<!DOCTYPE html>
    <html><head><meta charset="utf-8"><style>{CSS}</style></head><body>

    <div>
    {header("English Language Arts", "Week X, Tuesday -- [PHONICS PATTERN] Practice")}
    {sectitle("Here's What We're Learning")}
    {secnote("[UPDATE: Tuesday learning description]")}
    <ul style="font-size:12px;margin:4px 0 8px 0;">
    <li>[UPDATE: Pattern examples for Tuesday]</li>
    </ul>
    {remember_box("Remember This!", remember1)}
    {sectitle("Word Scramble Challenge")}
    {secnote("Unscramble the letters to spell a word from this week.")}
    {scramble_items}
    {page_break()}
    <hr class="divider">
    {sectitle("Reading Comprehension")}
    {secnote("Read the story. Notice each spelling word in bold.")}
    <div class="story-box">{reading_text}</div>
    <hr class="divider">
    {sectitle("Comprehension Questions")}
    {secnote("Answer each question in a complete sentence.")}
    {comp_html}
    <hr class="divider">
    {sectitle("Silent E Pattern Hunt")}
    {secnote("Check each word that has a silent E making the vowel long.")}
    {hunt_html}
    </div>
    {page_break()}

    <div>
    {remember_box("Remember This!", remember3)}
    {sectitle("Word Swap Challenge")}
    {secnote("Read the original sentence, then write your own using the new words.")}
    {swap_html}
    {sectitle("Sentence Builder")}
    {secnote("Write a complete sentence using each topic.")}
    {builder_html}
    </div>

    </body></html>"""

    HTML(string=html).write_pdf(os.path.join(day_dir, "Week0X_Tuesday_[TOPIC].pdf"))
    print("[ok] Tuesday generated")


# =====================================================================
# WEDNESDAY - Word Work (4 pages)
# =====================================================================

def generate_wednesday():
    day_dir = os.path.join(WEEK, "Wednesday")
    os.makedirs(day_dir, exist_ok=True)

    # 1. Reading passage
    # [UPDATE: Reading passage for Wednesday - use ALL spelling words in <strong> tags]
    reading_passage = (
        '[UPDATE: Write a reading passage using all spelling words]'
    )

    # 2. Vocabulary question
    # [UPDATE: Vocabulary multiple choice question]
    vocab_q = (
        "In the sentence '[sentence],' what does <strong>[word]</strong> mean?<br><br>"
        "A) [wrong option]<br>"
        "B) [correct option]<br>"
        "C) [wrong option]<br>"
        "D) [wrong option]"
    )

    # 3. Synonyms & Antonyms
    # [UPDATE: Synonyms & Antonyms word list]
    syn_ant_words = ["word1", "word2", "word3", "word4", "word5", "word6"]
    syn_ant_html = ""
    for w in syn_ant_words:
        syn_ant_html += (f'<div style="display:inline-block;width:30%;margin:4px;padding:6px 8px;'
                         f'background:#E0F2F1;border-radius:6px;border:1.5px solid #80CBC4;break-inside:avoid;">'
                         f'<div style="font-weight:bold;color:#26A69A;font-size:12px;margin-bottom:4px;">{w}</div>'
                         f'<div style="font-size:10.5px;">Synonym: _____________</div>'
                         f'<div style="font-size:10.5px;">Antonym: _____________</div>'
                         f'{write_line()}</div>')

    # 4. Word Web
    word_web_html = (f'<div style="text-align:center;margin:8px 0;">'\
                     f'<div style="display:inline-block;padding:8px 16px;background:#26A69A;color:white;border-radius:20px;font-weight:bold;font-size:13px;">'\
                     f'create</div>'\
                     f'<div style="margin-top:12px;">'\
                     f'<table style="width:100%;border-collapse:separate;border-spacing:4px;">'\
                     f'<tr>'\
                     f'<td style="text-align:center;"><div style="height:36px;border:2px dashed #B2DFDB;border-radius:8px;text-align:center;line-height:36px;font-size:11px;color:#888;">word 1</div></td>'\
                     f'<td style="text-align:center;"><div style="height:36px;border:2px dashed #B2DFDB;border-radius:8px;text-align:center;line-height:36px;font-size:11px;color:#888;">word 2</div></td>'\
                     f'</tr>'\
                     f'<tr>'\
                     f'<td style="text-align:center;"><div style="height:36px;border:2px dashed #B2DFDB;border-radius:8px;text-align:center;line-height:36px;font-size:11px;color:#888;">word 3</div></td>'\
                     f'<td style="text-align:center;"><div style="height:36px;border:2px dashed #B2DFDB;border-radius:8px;text-align:center;line-height:36px;font-size:11px;color:#888;">word 4</div></td>'\
                     f'</tr></table></div></div>')

    # 5. Sentence Sort -- 2 sentences to sort from mixed-up words
    # [UPDATE: Sentence sort - 2 sentences]
    sentence_sort_1 = "[UPDATE: Sentence 1]".split()
    sentence_sort_2 = "[UPDATE: Sentence 2]".split()
    random.Random(42).shuffle(sentence_sort_1)
    random.Random(43).shuffle(sentence_sort_2)
    sentence_sort_html = ""
    for idx, words in enumerate([sentence_sort_1, sentence_sort_2], 1):
        word_tags = "".join(f'<span style="display:inline-block;background:#FFF3E0;border:1px solid #FFB74D;padding:2px 8px;margin:2px;border-radius:3px;font-size:11px;">{w}</span>' for w in words)
        sentence_sort_html += (f'<div style="margin:8px 0;padding:6px 8px;background:#FAFAFA;border:1.5px solid #B2DFDB;border-radius:6px;">'
                               f'<div style="font-size:11px;font-weight:bold;color:#FF7043;margin-bottom:4px;">Sentence {idx}:</div>'
                               f'<div style="margin-bottom:4px;">{word_tags}</div>'
                               f'<div style="font-size:10px;color:#888;margin-bottom:4px;">Your answer:</div>'
                               f'{write_line()}</div>')

    # 6. Correct the Sentences
    # [UPDATE: Incorrect sentences for correction practice]
    incorrect_sentences = [
        "[UPDATE: sentence with missing caps/period]",
        "[UPDATE: sentence with missing caps/period]",
        "[UPDATE: sentence with missing caps/period]",
    ]
    correct_html = ""
    for s in incorrect_sentences:
        correct_html += (f'<div style="margin:6px 0;font-size:12px;">'
                         f'<span style="color:#E53935;text-decoration:line-through;">{s}</span><br>'
                         f'{write_line()}</div>')

    # 7. Fill-in-the-blank with context
    # [UPDATE: Fill-in-the-blank with answers]
    fill_context_data = [
        ("[UPDATE: sentence with ____]", "word"),
        ("[UPDATE: sentence with ____]", "word"),
        ("[UPDATE: sentence with ____]", "word"),
    ]
    fill_context_bank_words = [a for _, a in fill_context_data]
    fill_context_bank = word_bank(fill_context_bank_words, seed=340)
    fill_context_items = "".join(fill_blank_with_line(s) for s, _ in fill_context_data)

    # 8. Context Clues
    # [UPDATE: Context clues question]
    context_clue = (
        'Read this sentence: "[UPDATE: sentence with <strong>word</strong>]"<br><br>'
        "What does <strong>[word]</strong> mean?<br>"
        "A) [wrong]<br>B) [correct]<br>C) [wrong]<br>D) [wrong]"
    )

    # 9. Dictation practice
    # [UPDATE: Dictation word list]
    dictation_words = ["word1", "word2", "word3", "word4", "word5", "word6"]
    dictation_html = ""
    for w in dictation_words:
        dictation_html += (f'<div style="margin:6px 0;font-size:12px;">'\
                           f'<span style="color:#888;">{w}</span>{write_line()}</div>')

    remember_html2 = secnote("Write 4 words connected to the center word.")
    html = f"""<!DOCTYPE html>
    <html><head><meta charset="utf-8"><style>{CSS}</style></head><body>

    <div>
    {header("English Language Arts", "Week X, Wednesday -- Word Work &amp; Application")}
    {sectitle("Here's What We're Learning")}
    {secnote("Today we use our Silent E words in reading, writing, and thinking. Each activity helps you understand how these words work in different contexts.")}</div>
    <ul style="font-size:12px;margin:4px 0 8px 0;">
    <li><strong>Reading</strong> &mdash; understand vocabulary in context</li>
    <li><strong>Synonyms &amp; Antonyms</strong> &mdash; words with similar and opposite meanings</li>
    <li><strong>Word Webs</strong> &mdash; connecting related vocabulary</li>
    </ul>
    {sectitle("Reading Passage")}
    {secnote("Read the passage. Notice each spelling word in bold.")}</div>
    <div class="story-box">{reading_passage}</div>
    {sectitle("Vocabulary Question")}
    {secnote("Choose the correct answer.")}
    <div class="fb-item"><p>{vocab_q}</p><div style="font-size:12px;">Answer: _______________</div></div>
    {page_break()}
    {sectitle("Synonyms & Antonyms")}
    {secnote("Think of a word that means the SAME thing and a word that means the OPPOSITE.")}
    {syn_ant_html}
    </div>

    <div>
    {sectitle("Word Web")}
    {remember_html2}
    {word_web_html}
    {sectitle("Sentence Sort")}
    {secnote("Unscramble the words to form a correct sentence.")}
    {sentence_sort_html}
    {sectitle("Correct the Sentences")}
    {secnote("Each sentence has a capital letter or punctuation mistake. Rewrite it correctly.")}
    {correct_html}
    {sectitle("Fill in the Blank")}
    {secnote("Choose the correct word from the bank.")}
    {fill_context_bank}
    {fill_context_items}
    </div>
    {page_break()}

    <div>
    {sectitle("Context Clues")}
    {secnote("Use the sentence to figure out the word meaning.")}
    <div class="fb-item"><p>{context_clue}</p><div style="font-size:12px;">Answer: _______________</div></div>
    {sectitle("Dictation Practice")}
    {secnote("Have a partner say each word. Write it correctly, then check your spelling.")}
    {dictation_html}
    </div>

    </body></html>"""

    HTML(string=html).write_pdf(os.path.join(day_dir, "Week0X_Wednesday_[TOPIC].pdf"))
    print("[ok] Wednesday generated")


# =====================================================================
# THURSDAY - Write It (4 pages)
# =====================================================================

def generate_thursday():
    day_dir = os.path.join(WEEK, "Thursday")
    os.makedirs(day_dir, exist_ok=True)

    # Spelling story
    # [UPDATE: Thursday spelling story - use ALL words in <strong> tags]
    story_text = (
        '[UPDATE: Write a spelling story using all spelling words]'
    )

    # Comprehension
    # [UPDATE: Thursday comprehension questions]
    comp_qs = [
        "[UPDATE: Question 1]",
        "[UPDATE: Question 2]",
        "[UPDATE: Question 3]",
    ]
    comp_html = ""
    for q in comp_qs:
        comp_html += (f'<div style="margin-bottom:8px;">'
                      f'<strong style="font-size:12px;">{q}</strong><br>'
                      f'{write_line()}'
                      f'</div>')

    # Sentence Sort
    # [UPDATE: Thursday sentence sort - 2 sentences]
    sent_sort_1 = "[UPDATE: Sentence 1]".split()
    sent_sort_2 = "[UPDATE: Sentence 2]".split()
    random.Random(50).shuffle(sent_sort_1)
    random.Random(51).shuffle(sent_sort_2)
    sort_html = ""
    for idx, words in enumerate([sent_sort_1, sent_sort_2], 1):
        word_tags = "".join(f'<span style="display:inline-block;background:#FFF3E0;border:1px solid #FFB74D;padding:2px 8px;margin:2px;border-radius:3px;font-size:11px;">{w}</span>' for w in words)
        sort_html += (f'<div style="margin:8px 0;padding:6px 8px;background:#FAFAFA;border:1.5px solid #B2DFDB;border-radius:6px;">'
                      f'<div style="font-size:11px;font-weight:bold;color:#FF7043;margin-bottom:4px;">Sentence {idx}:</div>'
                      f'<div style="margin-bottom:4px;">{word_tags}</div>'
                      f'{write_line()}</div>')

    # Spelling Detective
    # [UPDATE: Spelling Detective - 8 misspelled words + correct answers]
    detective_words = ["[wrong1]", "[wrong2]", "[wrong3]", "[wrong4]", "[wrong5]", "[wrong6]", "[wrong7]", "[wrong8]"]
    detective_answers = ["[right1]", "[right2]", "[right3]", "[right4]", "[right5]", "[right6]", "[right7]", "[right8]"]
    detective_html = ""
    for wrong, right in zip(detective_words, detective_answers):
        detective_html += (f'<div style="display:inline-block;width:30%;margin:4px;padding:4px 8px;'
                           f'background:#FFF8E1;border-radius:4px;border:1px solid #FFD54F;font-size:12px;">'
                           f'<span style="text-decoration:line-through;color:#E53935;">{wrong}</span> '
                           f'<span style="color:#888;">&rarr;</span> '
                           f'<div style="position:relative;height:18px;margin:2px 0;display:inline-block;width:100%;">'
                           f'<div style="position:absolute;left:0;right:0;top:0;border-top:0.6pt solid rgb(0,0,255);"></div>'
                           f'<div style="position:absolute;left:0;right:0;bottom:12px;border-bottom:0.4pt dashed rgb(255,0,0);"></div>'
                           f'<div style="position:absolute;left:0;right:0;bottom:0;border-bottom:0.6pt solid rgb(0,0,255);"></div>'
                           f'</div></div>')

    # Word Swap
    # [UPDATE: Thursday word swap - 2 sentences]
    swap_data = [
        ("[UPDATE: original sentence 1]", ("word1_orig", "word1_swap"), ("word2_orig", "word2_swap")),
        ("[UPDATE: original sentence 2]", ("word1_orig", "word1_swap"), ("word2_orig", "word2_swap")),
    ]
    swap_html = ""
    for orig, (w1_orig, w1_swap), (w2_orig, w2_swap) in swap_data:
        swap_html += (f'<div style="margin-bottom:10px;padding:6px 8px;background:#FFF3E0;border-radius:5px;border:1px solid #FFB74D;">'
                      f'<div style="font-size:10.5px;font-weight:bold;color:#FF7043;margin-bottom:3px;">Original:</div>'
                      f'<div style="font-size:12px;font-style:italic;margin-bottom:4px;">'
                      f'{orig.replace(w1_orig, f"<strong>{w1_orig}</strong>").replace(w2_orig, f"<strong>{w2_orig}</strong>")}</div>'
                      f'<div style="font-size:10.5px;font-weight:bold;color:#FF7043;margin-bottom:3px;">Now write using <strong>{w1_swap}</strong> and <strong>{w2_swap}</strong>:</div>'
                      f'{write_line()}</div>')

  # Spelling Map
    # [UPDATE: Featured word for Spelling Map]
    map_word = "WORD"
    map_html = (f'<div style="text-align:center;margin:12px 0;padding:12px;background:#E8F5E9;border-radius:8px;border:2px solid #A5D6A7;">'
                f'<div style="font-weight:bold;font-size:14px;color:#2E7D32;margin-bottom:8px;">{map_word}</div>'
                f'<table style="margin:0 auto;border-collapse:separate;border-spacing:4px;width:auto;">'
                f'<tr><td style="padding:4px 8px;background:#FFF3E0;border:1px solid #FFB74D;border-radius:4px;font-size:11px;">Meaning:</td>'
                f'<td style="padding:4px 8px;border:1px solid #ccc;border-radius:4px;font-size:11px;min-width:200px;">'
                f'<div style="position:relative;height:22px;margin:2px 0;">'
                f'<div style="position:absolute;left:0;right:0;top:0;border-top:0.6pt solid rgb(0,0,255);"></div>'
                f'<div style="position:absolute;left:0;right:0;bottom:12px;border-bottom:0.4pt dashed rgb(255,0,0);"></div>'
                f'<div style="position:absolute;left:0;right:0;bottom:0;border-bottom:0.6pt solid rgb(0,0,255);"></div>'
                f'</div></td></tr>'
                f'<tr><td style="padding:4px 8px;background:#FFF3E0;border:1px solid #FFB74D;border-radius:4px;font-size:11px;">Long vowel:</td>'
                f'<td style="padding:4px 8px;border:1px solid #ccc;border-radius:4px;font-size:11px;min-width:200px;">'
                f'<div style="position:relative;height:22px;margin:2px 0;">'
                f'<div style="position:absolute;left:0;right:0;top:0;border-top:0.6pt solid rgb(0,0,255);"></div>'
                f'<div style="position:absolute;left:0;right:0;bottom:12px;border-bottom:0.4pt dashed rgb(255,0,0);"></div>'
                f'<div style="position:absolute;left:0;right:0;bottom:0;border-bottom:0.6pt solid rgb(0,0,255);"></div>'
                f'</div></td></tr>'
                f'<tr><td style="padding:4px 8px;background:#FFF3E0;border:1px solid #FFB74D;border-radius:4px;font-size:11px;">Sentence:</td>'
                f'<td style="padding:4px 8px;border:1px solid #ccc;border-radius:4px;font-size:11px;min-width:200px;">'
                f'<div style="position:relative;height:22px;margin:2px 0;">'
                f'<div style="position:absolute;left:0;right:0;top:0;border-top:0.6pt solid rgb(0,0,255);"></div>'
                f'<div style="position:absolute;left:0;right:0;bottom:12px;border-bottom:0.4pt dashed rgb(255,0,0);"></div>'
                f'<div style="position:absolute;left:0;right:0;bottom:0;border-bottom:0.6pt solid rgb(0,0,255);"></div>'
                f'</div></td></tr>'
                f'</table></div>')

    # Paragraph Builder
    para_prompts = [
        "Write a paragraph about your dream escape.",
        "Write a paragraph about being polite to others.",
    ]
    para_html = ""
    for p in para_prompts:
        para_html += (f'<div style="margin:8px 0;padding:6px 8px;background:#E0F2F1;border:1.5px solid #80CBC4;border-radius:6px;">'
                      f'<div style="font-size:11px;font-weight:bold;color:#FF7043;margin-bottom:4px;">{p}</div>'
                      f'{write_line()}'
                      f'{write_line()}'
                      f'{write_line()}</div>')

    # Write Your Own Story
    story_prompt = "Write a story using at least 5 of your spelling words."

    # Remember This
    remember = (
        "Silent E (Magic E) Rules:<br><br>"
        "1. The vowel before the silent E says its name.<br>"
        "2. The E at the end is silent -- it doesn't make a sound.<br>"
        "3. Look for the pattern: VOWEL + consonant + E<br><br>"
        "Examples: cr<strong>a</strong>t<strong>e</strong>, <strong>i</strong>nvit<strong>e</strong>, p-o-l-<strong>i</strong>-c-<strong>e</strong>"
    )

    html = f"""<!DOCTYPE html>
    <html><head><meta charset="utf-8"><style>{CSS}</style></head><body>

    <div>
    {header("English Language Arts", "Week X, Thursday -- Write It")}
    {sectitle("Here's What We're Learning")}
    {secnote("Today we use our Silent E words in stories and writing. Use each word correctly in your sentences and stories.")}
    {remember_box("Remember This!", remember)}
    {sectitle("Spelling Story")}
    {secnote("Read the story. Circle each spelling word.")}
    <div class="story-box">{story_text}</div>
    {sectitle("Comprehension Questions")}
    {secnote("Answer each question in a complete sentence.")}
    {comp_html}
    </div>
    {page_break()}

    <div>
    {sectitle("Sentence Sort")}
    {secnote("Unscramble the words to form correct sentences.")}
    {sort_html}
    {sectitle("Spelling Detective")}
    {secnote("Each word has a mistake. Write the correct spelling.")}
    {detective_html}
    {sectitle("Word Swap")}
    {secnote("Read the original, then write your own using the new words.")}
    {swap_html}
    </div>

    <div>
    {sectitle("Spelling Map")}
    {secnote("Fill in the details for this week's featured word.")}
    {map_html}
    {sectitle("Paragraph Builder")}
    {secnote("Write a short paragraph for each prompt. Use at least 2 spelling words in each.")}
    {para_html}
    </div>

    <div>
    {sectitle("Write Your Own Story")}
    {secnote("Write a story using at least 5 of your spelling words. Use capital letters and periods!")}
    <div style="font-size:11px;font-weight:bold;color:#FF7043;margin-bottom:8px;">{story_prompt}</div>
    {write_line()}
    {write_line()}
    {write_line()}
    {write_line()}
    {write_line()}
    {write_line()}
    {write_line()}
    {write_line()}
    </div>

    </body></html>"""

    HTML(string=html).write_pdf(os.path.join(day_dir, "Week0X_Thursday_[TOPIC].pdf"))
    print("[ok] Thursday generated")


# =====================================================================
# FRIDAY - Show What You Know (3 pages)
# =====================================================================

def generate_friday():
    day_dir = os.path.join(WEEK, "Friday")
    os.makedirs(day_dir, exist_ok=True)

    # 1. Spelling Test -- 12 words
    test_html = ""
    for i, (word, _, _) in enumerate(WORDS, 1):
        test_html += (f'<div class="test-item">'
                      f'<span class="num">{i}.</span>'
                      f'<div style="flex:1;">'
                      f'<div style="margin-bottom:6px;"></div>'
                      f'{write_line()}</div></div>')

    # 2. Reading review
    review_story = (
        'On our last <strong>escape</strong>, I <strong>notice</strong>d something <strong>strange</strong> at the beach. '
        'A small <strong>delicate</strong> shell was <strong>frozen</strong> in ice! I wanted to <strong>invite</strong> my friend to see it. '
        'We <strong>create</strong>d a <strong>private</strong> collection of shells. The <strong>police</strong> said it was a new discovery. '
        'We were very <strong>polite</strong> to the scientists. Their project was <strong>complete</strong> with our help. '
        'We <strong>separate</strong>d the shells into groups. What a perfect escape!'
    )

    # Story questions
    story_qs = [
        "What strange thing did they find at the beach?",
        "What did they create together?",
        "Why were the scientists happy?",
    ]
    story_q_html = ""
    for q in story_qs:
        story_q_html += (f'<div style="margin-bottom:8px;">'
                         f'<strong style="font-size:12px;">{q}</strong><br>'
                         f'{write_line()}</div>')

    # Opposite pairs
    # [UPDATE: Opposite words - 3 words]
    opposite_words = ["word1", "word2", "word3"]
    opp_html = ""
    for word in opposite_words:
        opp_html += (f'<div style="margin:4px 0;font-size:12px;">'
                     f'<strong style="color:#673ab7;font-size:12px;">{word}</strong><br>{write_line()}</div>')

    # Sentence Builder
    # [UPDATE: Sentence builder words - 4 words]
    builder_words = ["word1", "word2", "word3", "word4"]
    builder_html = ""
    for w in builder_words:
        builder_html += (f'<div style="margin:6px 0;">'
                         f'<span style="font-size:11px;font-weight:bold;color:#26A69A;">{w}:</span>{write_line()}</div>')

    # Word Journal
    # [UPDATE: Word journal words - 4 words]
    journal_words = ["word1", "word2", "word3", "word4"]
    journal_html = ""
    for w in journal_words:
        journal_html += (f'<div style="margin:8px 0;padding:6px 8px;background:#FAFAFA;border:1.5px solid #B2DFDB;border-radius:6px;">'
                         f'<div style="font-weight:bold;color:#26A69A;font-size:12px;margin-bottom:4px;">{w}</div>'
                         f'<div style="font-size:10.5px;color:#888;">Meaning: _______________</div>'
                         f'{write_line()}</div>')

    # Celebration
    celebration = (
        '<div style="text-align:center;margin:16px 0;padding:12px;background:#FFF8E1;border:2px solid #FFD54F;border-radius:8px;">'
        '<div style="font-size:16px;font-weight:bold;color:#FF7043;">Great Job This Week!</div>'
        '<div style="font-size:12px;color:#555;margin-top:4px;">You practiced Silent E words all week. Keep up the amazing work!</div>'
        '</div>'
    )

    html = f"""<!DOCTYPE html>
    <html><head><meta charset="utf-8"><style>{CSS}</style></head><body>

    <div>
    {header("English Language Arts", "Week X, Friday -- Show What You Know")}
    {sectitle("Spelling Test")}
    {secnote("Listen as your partner says each word, a sentence, then the word again. Write it correctly.")}
    {test_html}
    </div>
    {page_break()}

    <div>
    {sectitle("Review Reading")}
    {secnote("Read the story. Circle each spelling word you find.")}
    <div class="story-box">{review_story}</div>
    {sectitle("Story Questions")}
    {secnote("Answer each question in a complete sentence.")}
    {story_q_html}
    {sectitle("Opposite Pairs")}
    {secnote("Write the opposite of each word.")}
    {opp_html}
    </div>
    {page_break()}

    <div>
    {sectitle("Sentence Builder")}
    {secnote("Write a complete sentence using each word.")}
    {builder_html}
    {sectitle("Show What You Know")}
    {secnote("Write the meaning of each word and copy it neatly.")}
    {journal_html}
    {celebration}
    </div>

    </body></html>"""

    HTML(string=html).write_pdf(os.path.join(day_dir, "Week0X_Friday_[TOPIC].pdf"))
    print("[ok] Friday generated")


# =====================================================================
# CONTENT VALIDATION — Run before generating PDFs
# =====================================================================

import re

def validate_content():
    """Validate content correctness before generating PDFs."""
    errors = []

    # 1. Validate all words are 6+ letters
    for word, pattern, _ in WORDS:
        if len(word) < 6:
            errors.append(f"Word '{word}' has {len(word)} letters (need 6+)")

    # 2. Validate phonetic patterns match actual pronunciation
    # [UPDATE]: Note: Some words may have special patterns (e.g., unstressed final CVCe, past participles)
    # have long vowels but don't follow strict CVCe. We flag these as warnings, not errors.
    pattern_checks = {
        "long a": lambda w: re.search(r'a.{0,3}e$|a.{0,1}[aeiou]', w, re.I),  # a_e or open syllable
        "long e": lambda w: re.search(r'e.{0,3}e$|ea|e.{0,1}[aeiou]', w, re.I),  # e_e, ea, or open
        "long i": lambda w: re.search(r'i.{0,3}e$|i.{0,1}[aeiou]', w, re.I),  # i_e or open syllable
        "long o": lambda w: re.search(r'o.{0,3}e$|o.{0,1}[aeiou]', w, re.I),  # o_e or open syllable
    }

    for word, pattern, _ in WORDS:
        for vowel_type, check_fn in pattern_checks.items():
            if vowel_type in pattern.lower():
                if not check_fn(word):
                    errors.append(f"'{word}' claims {vowel_type} but doesn't match pattern")
                break

    # 3. Validate fill-in-blank answers fit context
    # [UPDATE: Fill-in-the-blank sentences with answers]
    fill_data = [
        ("[UPDATE: Sentence with ____]", "word1"),
        ("[UPDATE: Sentence with ____]", "word2"),
        ("[UPDATE: Sentence with ____]", "word3"),
        ("[UPDATE: Sentence with ____]", "word4"),
    ]
    for sentence, answer in fill_data:
        if answer not in WORD_NAMES:
            errors.append(f"Fill-in answer '{answer}' not in word list")
        filled = sentence.replace("____", answer)
        if "the" not in filled.lower() and "i" not in filled.lower():
            errors.append(f"Fill-in sentence may be ungrammatical: {filled}")

    # 4. Validate Spelling Detective misspellings
    # [UPDATE: Spelling Detective - 8 misspelled words + correct answers]
    detective_words = ["[wrong1]", "[wrong2]", "[wrong3]", "[wrong4]", "[wrong5]", "[wrong6]", "[wrong7]", "[wrong8]"]
    detective_answers = ["[right1]", "[right2]", "[right3]", "[right4]", "[right5]", "[right6]", "[right7]", "[right8]"]
    for i, (misspelled, original) in enumerate(zip(detective_words, detective_answers)):
        if misspelled == original:
            errors.append(f"Spelling Detective word {i+1}: '{misspelled}' is identical to original (must be misspelled)")
        if original not in WORD_NAMES:
            errors.append(f"Spelling Detective answer '{original}' not in word list")

    # 5. Validate opposite pairs are actual antonyms
    # [UPDATE: Opposite pairs with answers for validation]
    opposite_pairs = [
        ("word1", "opposite1"),
        ("word2", "opposite2"),
        ("word3", "opposite3"),
        ("word4", "opposite4"),
    ]
    for word, opp in opposite_pairs:
        if word not in WORD_NAMES:
            errors.append(f"Opposite word '{word}' not in word list")

    # 6. Validate "Here's What We're Learning" examples
    # [UPDATE: Learning examples for validation]
    learning_examples = ["word1", "word2", "word3"]
    for example in learning_examples:
        if example not in WORD_NAMES:
            errors.append(f"Learning example '{example}' not in word list")

    # 7. Validate letter breakdowns spell actual words
    # [UPDATE: Letter breakdowns for learning examples]
    breakdowns = {
        "word1": "w-o-r-d-1",
        "word2": "w-o-r-d-2",
        "word3": "w-o-r-d-3",
    }
    for word, breakdown in breakdowns.items():
        spelled = breakdown.replace("-", "").lower()
        if spelled != word.lower():
            errors.append(f"Breakdown '{breakdown}' spells '{spelled}', not '{word}'")

    # 8. Validate Friday has no learning/remember boxes
    # (This is checked by ensuring generate_friday() doesn't include sectitle("Here's What We're Learning"))
    # Manual check: search the function for learning box patterns
    import inspect
    friday_source = inspect.getsource(generate_friday)
    if "Here's What We're Learning" in friday_source:
        errors.append("Friday contains learning box (should be assessment only)")
    if "Remember This" in friday_source:
        errors.append("Friday contains remember box (should be assessment only)")

    return errors


def run_validation():
    """Run content validation and report results."""
    print("Running content validation...")
    errors = validate_content()

    if errors:
        print("\nāŒ VALIDATION FAILED — Fix these errors before generating:")
        for i, error in enumerate(errors, 1):
            print(f"   {i}. {error}")
        print(f"\nTotal: {len(errors)} error(s)\n")
        return False
    else:
        print("āœ… All content checks passed!\n")
        return True


# =====================================================================
# MAIN
# =====================================================================

if __name__ == "__main__":
    print("=" * 50)
    print("Week X Generator - [PHONICS PATTERN]")
    print("=" * 50)

    # 1. Phonetic audit (verifies words against database)
    try:
        from audit.run_audit import validate_before_generate
        validate_before_generate(__file__)
    except ImportError:
        print("  [warn] audit system unavailable — skipping phonetic check")
    except Exception as e:
        print(f"\n  AUDIT FAILED: {e}")
        exit(1)

    # 2. Content validation (structural checks)
    if not run_validation():
        print("Aborting generation. Fix validation errors first.")
        exit(1)

    generate_monday()
    generate_tuesday()
    generate_wednesday()
    generate_thursday()
    generate_friday()
    print("\nAll done! Check Week_02/ for PDFs.")