#!/usr/bin/env python3
"""Generate Stavaza Handleiding v1.1 DOCX - Lions MD110 Nederland"""
from docx import Document
from docx.shared import Pt, Cm, RGBColor
from docx.enum.text import WD_ALIGN_PARAGRAPH
from docx.enum.table import WD_TABLE_ALIGNMENT
from docx.oxml.ns import nsdecls
from docx.oxml import parse_xml
import os

NAVY = RGBColor(0x00, 0x33, 0x66)
BODY = RGBColor(0x1F, 0x29, 0x37)
WHITE = RGBColor(0xFF, 0xFF, 0xFF)
ABLUE = RGBColor(0x1A, 0x73, 0xE8)
ORANGE = RGBColor(0xE8, 0x71, 0x0A)
RED = RGBColor(0xD9, 0x30, 0x25)
GREEN = RGBColor(0x18, 0x80, 0x38)
GREY = RGBColor(0x5F, 0x63, 0x68)
FN = "Calibri"
OUT = "/root/projects/jg/2026-stavaza-portefeuille-template/deliverables/stavaza_handleiding_v1.1.docx"

def shade(cell, hx):
    cell._tc.get_or_add_tcPr().append(parse_xml(f'<w:shd {nsdecls("w")} w:fill="{hx}"/>'))

def borders(cell, c="BFBFBF", s="4"):
    xml = f'<w:tcBorders {nsdecls("w")}><w:top w:val="single" w:sz="{s}" w:color="{c}"/><w:bottom w:val="single" w:sz="{s}" w:color="{c}"/><w:left w:val="single" w:sz="{s}" w:color="{c}"/><w:right w:val="single" w:sz="{s}" w:color="{c}"/></w:tcBorders>'
    cell._tc.get_or_add_tcPr().append(parse_xml(xml))

def sr(run, sz=11, b=False, c=None, i=False):
    if c is None: c = BODY
    run.font.name = FN; run.font.size = Pt(sz); run.font.bold = b; run.font.italic = i; run.font.color.rgb = c

def bp(doc, t, sz=11, b=False, sa=6, c=None):
    if c is None: c = BODY
    p = doc.add_paragraph(); p.paragraph_format.space_after = Pt(sa)
    r = p.add_run(t); sr(r, sz, b, c); return p

def bul(doc, t):
    p = doc.add_paragraph(style='List Bullet')
    p.paragraph_format.left_indent = Cm(1.0); p.paragraph_format.space_after = Pt(3)
    r = p.runs[0] if p.runs else p.add_run(); r.text = t; sr(r, 11); return p

def tip(doc, n, title, desc):
    p = doc.add_paragraph(); p.paragraph_format.space_before = Pt(8); p.paragraph_format.space_after = Pt(4)
    r1 = p.add_run(f"Tip #{n}: "); sr(r1, 11, True, NAVY)
    r2 = p.add_run(title); sr(r2, 11, True)
    r3 = p.add_run(f" - {desc}"); sr(r3, 11)

def callout(doc, title, lines, bg="E8F0FE", bd="003366"):
    t = doc.add_table(rows=1, cols=1); cell = t.cell(0, 0)
    shade(cell, bg); borders(cell, bd, "6")
    p = cell.paragraphs[0]; p.paragraph_format.space_after = Pt(4)
    r = p.add_run(title); sr(r, 11, True, NAVY)
    for ln in lines:
        p = cell.add_paragraph(); p.paragraph_format.space_after = Pt(2)
        r = p.add_run(ln); sr(r, 10)
    doc.add_paragraph().paragraph_format.space_after = Pt(4)

def tbl(doc, headers, rows, cw=None):
    t = doc.add_table(rows=1+len(rows), cols=len(headers)); t.alignment = WD_TABLE_ALIGNMENT.CENTER
    for i, h in enumerate(headers):
        c = t.cell(0, i); shade(c, "003366"); borders(c, "003366", "6")
        r = c.paragraphs[0].add_run(h); sr(r, 10, True, WHITE)
    for ri, rd in enumerate(rows):
        for ci, v in enumerate(rd):
            c = t.cell(ri+1, ci); borders(c)
            if ri % 2 == 1: shade(c, "F0F4FA")
            r = c.paragraphs[0].add_run(str(v)); sr(r, 10)
    if cw:
        for i, w in enumerate(cw):
            for row in t.rows: row.cells[i].width = Cm(w)
    return t

def pagenum(p):
    r = p.add_run()
    r._r.append(parse_xml(f'<w:fldChar {nsdecls("w")} w:fldCharType="begin"/>'))
    r._r.append(parse_xml(f'<w:instrText {nsdecls("w")} xml:space="preserve"> PAGE </w:instrText>'))
    r._r.append(parse_xml(f'<w:fldChar {nsdecls("w")} w:fldCharType="end"/>'))

def numpages(p):
    r = p.add_run()
    r._r.append(parse_xml(f'<w:fldChar {nsdecls("w")} w:fldCharType="begin"/>'))
    r._r.append(parse_xml(f'<w:instrText {nsdecls("w")} xml:space="preserve"> NUMPAGES </w:instrText>'))
    r._r.append(parse_xml(f'<w:fldChar {nsdecls("w")} w:fldCharType="end"/>'))

def config_styles(doc):
    s = doc.styles
    n = s['Normal']; n.font.name = FN; n.font.size = Pt(11); n.font.color.rgb = BODY
    n.paragraph_format.space_after = Pt(6); n.paragraph_format.line_spacing = 1.15
    h1 = s['Heading 1']; h1.font.name = FN; h1.font.size = Pt(20); h1.font.bold = True; h1.font.color.rgb = NAVY
    h1.paragraph_format.space_before = Pt(18); h1.paragraph_format.space_after = Pt(8); h1.paragraph_format.keep_with_next = True
    h2 = s['Heading 2']; h2.font.name = FN; h2.font.size = Pt(15); h2.font.bold = True; h2.font.color.rgb = NAVY
    h2.paragraph_format.space_before = Pt(14); h2.paragraph_format.space_after = Pt(6); h2.paragraph_format.keep_with_next = True
    h3 = s['Heading 3']; h3.font.name = FN; h3.font.size = Pt(12); h3.font.bold = True; h3.font.color.rgb = ABLUE
    h3.paragraph_format.space_before = Pt(10); h3.paragraph_format.space_after = Pt(4); h3.paragraph_format.keep_with_next = True

def build():
    doc = Document()
    for sec in doc.sections:
        sec.top_margin = Cm(2.5); sec.bottom_margin = Cm(2.5); sec.left_margin = Cm(2.5); sec.right_margin = Cm(2.5)
    config_styles(doc)

    # 1. TITELPAGINA
    for _ in range(6): doc.add_paragraph()
    p = doc.add_paragraph(); p.alignment = WD_ALIGN_PARAGRAPH.CENTER; r = p.add_run("Handleiding"); sr(r, 28, True, NAVY)
    p = doc.add_paragraph(); p.alignment = WD_ALIGN_PARAGRAPH.CENTER; r = p.add_run("Stavaza Portefeuille Update"); sr(r, 24, True, NAVY)
    doc.add_paragraph()
    p = doc.add_paragraph(); p.alignment = WD_ALIGN_PARAGRAPH.CENTER; r = p.add_run("Versie 1.1 - Augustus 2026"); sr(r, 14, c=ABLUE)
    doc.add_paragraph(); doc.add_paragraph()
    p = doc.add_paragraph(); p.alignment = WD_ALIGN_PARAGRAPH.CENTER; r = p.add_run("Lions MD110 Nederland"); sr(r, 14, True)
    p = doc.add_paragraph(); p.alignment = WD_ALIGN_PARAGRAPH.CENTER; r = p.add_run("Gouverneursraad"); sr(r, 12, c=GREY)
    doc.add_paragraph(); doc.add_paragraph()
    p = doc.add_paragraph(); p.alignment = WD_ALIGN_PARAGRAPH.CENTER; r = p.add_run("JvG Consultancy"); sr(r, 12, i=True, c=GREY)
    doc.add_page_break()

    # 2. INHOUDSOPGAVE
    doc.add_heading("Inhoudsopgave", level=1)
    toc = [("1. Introductie","3"),("2. Nieuw in Versie 1.1","5"),("3. Voor Wie is Deze Handleiding?","6"),
           ("4. Het Excel Bestand - Overzicht","7"),("5. Stap-voor-Stap: Het Formulier Invullen","8"),
           ("6. Veld-to-Veld Uitleg","11"),("7. Het Lijsten Werkblad - Dropdowns Aanpassen","13"),
           ("8. Automatische Kleurcodering","14"),("9. Het Samenvattings-Dashboard","15"),
           ("10. Escalatie Protocol","16"),("11. Tips & Best Practices","17"),
           ("12. Veelgemaakte Fouten","18"),("13. Versiebeheer","19")]
    for title, page in toc:
        p = doc.add_paragraph(); p.paragraph_format.space_after = Pt(4)
        p.paragraph_format.tab_stops.add_tab_stop(Cm(15.5), WD_ALIGN_PARAGRAPH.RIGHT, leader=2)
        r = p.add_run(title); sr(r, 11); r2 = p.add_run("\t"+page); sr(r2, 11)
    doc.add_page_break()

    # 3. INTRODUCTIE
    doc.add_heading("1. Introductie", level=1)
    doc.add_heading("Wat is een Stavaza?", level=2)
    bp(doc, "Een Stavaza (stand-van-zaken) is een gestructureerde rapportage waarmee een portefeuillehouder binnen de Gouverneursraad van Lions MD110 Nederland in een oogopslag de status van zijn of haar portefeuille toont. Het format brengt de essentie samen: wat gaat goed, wat vraagt aandacht, en welke actie wordt er verwacht.")
    doc.add_heading("Waarom gestructureerde rapportage?", level=2)
    bp(doc, "De Gouverneursraad vergadert regelmatig over zeven portefeuilles. Zonder gestructureerd format leidt dit vaak tot lange verhalen, onduidelijke actiepunten en onvoldoende tijd voor echte besluitvorming. Het Stavaza-format dwingt portefeuillehouders om vooraf na te denken over:")
    bul(doc, "De actuele status per onderwerp (groen, geel of rood)")
    bul(doc, "De prioriteit en urgentie van elk punt")
    bul(doc, "Concrete acties met een duidelijke eigenaar en een deadline")
    bul(doc, "Of een punt escalatie naar de Gouverneursraad vereist")
    doc.add_heading("De workflow: Commissie > Portefeuillehouder > Gouverneursraad", level=2)
    bp(doc, "Het Stavaza-proces kent drie niveaus:")
    bul(doc, "Commissieleden en werkgroepleiders vullen hun deel in en sturen dit 48 uur voor de vergadering naar de portefeuillehouder.")
    bul(doc, "De portefeuillehouder integreert alle input tot een Stavaza-formulier per portefeuille en beoordeelt escalaties.")
    bul(doc, "In de Gouverneursraad worden de Stavaza-formulieren als leidraad gebruikt - escalaties krijgen prioriteit.")
    doc.add_heading("Best practices voor effectief vergaderen", level=2)
    bp(doc, "Deze handleiding sluit aan bij de tips van bar-beton.nl/effectief-vergaderen. De volgende tips zijn direct vertaald naar het Stavaza-format:")
    tip(doc, "1", "Goede voorbereiding", "Het formulier wordt vooraf ingevuld en gedeeld - niet pas tijdens de vergadering.")
    tip(doc, "6", "Maximaal 1,5 uur", "Gestructureerde updates houden de vergadering efficient en binnen de tijd.")
    tip(doc, "9", "Een actiepunt = een eigenaar", "Elk actiepunt in het formulier heeft exact een verantwoordelijke persoon.")
    tip(doc, "21", "Verzamel feedback", "Evalueer na de vergadering of het format en de vergadering aan verwachtingen voldeden.")
    doc.add_page_break()

    # 4. NIEUW IN V1.1
    doc.add_heading("2. Nieuw in Versie 1.1", level=1)
    bp(doc, "Versie 1.1 brengt belangrijke verbeteringen ten opzichte van de initielle release (v1.0). De upgrade is gebaseerd op feedback vanuit de Gouverneursraad en commissievoorzitters. Onderstaand overzicht toont alle wijzigingen:")
    nouv = [
        ["Dropdown menus","Portefeuille, Status, Prioriteit, Categorie, Commissie en Houder zijn nu dropdowns - geen typfouten meer."],
        ["Instelbaar Lijsten werkblad","Pas dropdown-waarden aan zonder Excel-kennis. Open tabblad Lijsten en typ nieuwe waarden."],
        ["Automatische kleurcodering","Deadlines kleuren automatisch rood/oranje/geel op basis van de huidige datum."],
        ["Samenvattings-dashboard","Automatische tellers voor Groen/Geel/Rood, escalaties en urgente items."],
        ["Escalatie-kolom","Nieuwe kolom L: geef expliciet aan of een punt in de Gouverneursraad besproken moet worden."],
        ["Lions MD110 branding","Het formulier is geoptimaliseerd voor de MD110-structuur met 7 portefeuilles."],
    ]
    tbl(doc, ["Functie","Beschrijving"], nouv, [5.5, 11.0])
    doc.add_paragraph()
    callout(doc, "Upgrade-pad", ["Bestaande v1.0 formulieren blijven gewoon werken.", "Kopieer je data naar de nieuwe v1.1 template om de extra functies te gebruiken.", "De veldnamen en kolomindeling zijn backwards-compatible."])
    doc.add_page_break()

    # 5. VOOR WIE
    doc.add_heading("3. Voor Wie is Deze Handleiding?", level=1)
    bp(doc, "Deze handleiding is geschreven voor iedereen die betrokken is bij het Stavaza-proces binnen Lions MD110 Nederland. Dat zijn in het bijzonder:")
    roles = [
        ["Portefeuillehouders (GR-leden)","Eindverantwoordelijk voor de inhoud van het Stavaza-formulier. Beoordelen escalaties en presenteren in de Gouverneursraad."],
        ["Commissievoorzitters / werkgroepleiders","Vullen het formulier in voor hun commissie/werkgroep. Leveren 48 uur voor de vergadering in."],
        ["De vergadervoorzitter","Gebruikt het Samenvattings-dashboard als agenda-checklist. Stuurt de bespreking van escalaties."],
        ["De notulist / secretaresse","Archiveert de formulieren met de notulen. Legt actiepunten vast met eigenaar en deadline."],
    ]
    tbl(doc, ["Rol","Verantwoordelijkheid"], roles, [6.0, 10.5])
    doc.add_page_break()

    # 6. EXCEL OVERZICHT
    doc.add_heading("4. Het Excel Bestand - Overzicht", level=1)
    bp(doc, "Het Excel-bestand 'Stavaza_Portefeuille_Update_v1.1.xlsx' bevat vier werkbladen die samen het complete formulier vormen:")
    sheets = [
        ["1. Stavaza Update","Hoofdformulier","12 kolommen, 20 rijen. Bevat dropdowns, kleurcodering en automatische berekeningen."],
        ["2. Samenvatting","Dashboard","Automatische telling van statussen, escalaties, urgente items en kritieke deadlines."],
        ["3. Lijsten","Instelbaar","Alle dropdown-waarden op een plek. Pas namen en categorieen aan zonder formules."],
        ["4. Toelichting","Referentie","Korte gebruiksaanwijzing direct in Excel."],
    ]
    tbl(doc, ["Werkblad","Type","Beschrijving"], sheets, [4.5, 3.0, 9.0])
    doc.add_paragraph()
    callout(doc, "Tip", ["Open bij de eerste keer eerst het werkblad Lijsten om je naam en commissie toe te voegen.", "Daarna verschijnen deze automatisch in de dropdowns."], bg="FEF7E0", bd="E8710A")
    doc.add_page_break()

    # 7. STAP-VOOR-STAP
    doc.add_heading("5. Stap-voor-Stap: Het Formulier Invullen", level=1)
    bp(doc, "Hieronder volgt een complete wandeling door het formulier, van header tot indienen.")
    doc.add_heading("Stap 1: Headergegevens", level=2)
    bp(doc, "Bovenaan het formulier vul je vier velden in:")
    bul(doc, "Portefeuille - selecteer uit de dropdown (bijv. Ledenbeleid, Financien, Activiteiten)")
    bul(doc, "Portefeuillehouder - selecteer je naam uit de dropdown")
    bul(doc, "Commissie/Werkgroep - selecteer de relevante groep")
    bul(doc, "Vergaderdatum en datum van invullen - dd-mm-jjjj")
    bp(doc, "Deze velden zijn gekoppeld aan het Lijsten-werkblad. Zie je je naam niet? Voeg deze dan toe op tabblad Lijsten.", sz=10, c=GREY)
    doc.add_heading("Stap 2: Onderwerpen toevoegen", level=2)
    bp(doc, "Een rij per onderwerp, activiteit of actiepunt. Wees specifiek en concreet:")
    callout(doc, "Voorbeelden", ["Goed: Werving nieuwe leden Q3 - Regio Utrecht", "Vermijd: Ledenwerving (te algemeen)", "Goed: Goedkeuring jaarrekening 2025", "Vermijd: Financien (zegt niets)"], bg="E6F4EA", bd="188038")
    doc.add_heading("Stap 3: Categorie en Status bepalen", level=2)
    bp(doc, "Wijs elke rij een categorie en status toe via de dropdowns:")
    cat_rows = [["Bestuurlijk","Bestuurszaken, statuten, beleid, governance"],["Financieel","Budget, jaarrekening, subsidies, contributies"],
        ["Operationeel","Uitvoering van activiteiten, logistiek, planning"],
        ["Communicatie","PR, website, nieuwsbrief, social media"],
        ["Strategisch","Meerjarenvisie, groei, innovatie"],
        ["Juridisch","Contracten, aansprakelijkheid, compliance"]]
    tbl(doc, ["Categorie","Voorbeelden"], cat_rows, [4.0, 12.5])
    bp(doc, ""); bp(doc, "Status-opties:", b=True)
    bul(doc, "Groen - op schema, geen zorgen")
    bul(doc, "Geel - aandacht nodig, risico op vertraging")
    bul(doc, "Rood - kritiek, blokkade of escalatie")
    bul(doc, "N.v.t. - niet van toepassing voor dit item")
    doc.add_heading("Stap 4: Prioriteit instellen", level=2)
    callout(doc, "NIEUW in v1.1", ["De prioriteitskolom helpt de vergadervoorzitter om tijd te verdelen over onderwerpen."])
    prio_data = [["Urgent","Onmiddellijk - blokkeert alles. Moet voor andere punten worden opgelost."],
        ["Hoog","Deze week aandacht. Belangrijk voor de voortgang van de portefeuille."],
        ["Gemiddeld","Deze maand aandacht. Normale planning, geen directe druk."],
        ["Laag","Routinematig. Kan wachten zonder consequenties."]]
    tbl(doc, ["Prioriteit","Betekenis"], prio_data, [4.0, 12.5])
    doc.add_page_break()

    doc.add_heading("Stap 5: Velden invullen", level=2)
    bp(doc, "Per rij vul je drie tekstvelden in:")
    field_data = [
        ["Wat gaat goed","Successen en behaalde milestones","Voorbeeld: 15 nieuwe aanmeldingen via open dag"],
        ["Aandacht nodig","Risico's, punten die aandacht vragen","Voorbeeld: Onboarding vertraagd door beperkte capaciteit"],
        ["Kritieke punten","Blokkades die externe hulp nodig hebben","Voorbeeld: Budgetgoedkeuring EUR 2.500 nog open"],
    ]
    tbl(doc, ["Veld","Wat vul je in?","Voorbeeld"], field_data, [4.0, 6.5, 6.0])
    doc.add_heading("Stap 6: Actie formuleren", level=2)
    bp(doc, "Drie velden bepalen de actie:")
    bul(doc, "Actie/Beslissing gevraagd - wees expliciet. Niet 'aandacht' maar 'goedkeuring budget EUR 2.500'.")
    bul(doc, "Actie-eigenaar - een persoon (bar-beton.nl Tip #9).")
    bul(doc, "Deadline - vul in als dd-mm-jjjj. De kleurcodering doet de rest!")
    doc.add_heading("Stap 7: Escalatie beoordelen", level=2)
    callout(doc, "NIEUW in v1.1 - Kolom L: Escalatie naar GR?", ["Ja - direct in de Gouverneursraad bespreken.", "Nee - routinematige update. Niet besproken tenzij tijd over.", "Overleg - portefeuillehouder beoordeelt tijdens vergadering."])
    doc.add_heading("Stap 8: Indienen", level=2)
    bp(doc, "Lever het ingevulde formulier 48 uur voor de vergadering digitaal in bij:")
    bul(doc, "De portefeuillehouder (indien ingevuld door commissievoorzitter)")
    bul(doc, "De vergadervoorzitter")
    bul(doc, "De notulist/secretaresse voor archivering")
    bp(doc, "Te laat ingediende formulieren komen niet op de agenda van de huidige vergadering.", sz=10, c=GREY)
    doc.add_page_break()

    # 8. VELD-TO-VELD
    doc.add_heading("6. Veld-to-Veld Uitleg", level=1)
    bp(doc, "Onderstaande tabel geeft een volledige uitleg van alle 12 kolommen in het hoofdformulier.")
    fe = [
        ["A","Nr.","Volgnummer van het item. Wordt automatisch ingevuld.","1, 2, 3"],
        ["B","Onderwerp/Activiteit","Korte, specifieke beschrijving van het onderwerp.","Werving nieuwe leden Regio Utrecht Q3"],
        ["C","Categorie","Typering van het onderwerp (dropdown).","Operationeel"],
        ["D","Status","Actuele toestand: Groen, Geel, Rood, N.v.t. (dropdown).","Geel"],
        ["E","Prioriteit","Urgentie: Urgent, Hoog, Gemiddeld, Laag (dropdown).","Hoog"],
        ["F","Wat gaat goed","Successen, behaalde milestones, positieve ontwikkelingen.","15 nieuwe aanmeldingen"],
        ["G","Aandacht nodig","Risico's, vertragingen, punten die monitoring vereisen.","Onboarding vertraagd"],
        ["H","Kritieke punten","Blokkades die externe hulp of besluitvorming nodig hebben.","Budgetgoedkeuring open"],
        ["I","Actie gevraagd","Expliciete vraag of beslissing die je van de GR wilt.","Goedkeuring budget EUR 2.500"],
        ["J","Actie-eigenaar","Een persoon verantwoordelijk voor uitvoering.","J. de Vries"],
        ["K","Deadline","Uiterste datum (dd-mm-jjjj). Automatische kleurcodering.","15-09-2026"],
        ["L","Escalatie naar GR?","Ja/Nee/Overleg (dropdown). Bepaalt agendaprioriteit.","Ja"],
    ]
    tbl(doc, ["Kolom","Naam","Uitleg","Voorbeeld"], fe, [1.5, 3.5, 6.5, 5.0])
    doc.add_page_break()

    # 9. LIJSTEN WERKBLAD
    doc.add_heading("7. Het Lijsten Werkblad - Dropdowns Aanpassen", level=1)
    callout(doc, "NIEUW in v1.1", ["Alle dropdown-waarden zijn nu instelbaar via een apart werkblad.", "Geen Excel-kennis of formule-aanpassingen meer nodig!"])
    bp(doc, "Zo pas je de dropdown-waarden aan:")
    steps = ["Open het werkblad Lijsten (tabblad onderaan het Excel-bestand).",
        "Je ziet meerdere kolommen, elk met een lijst van waarden voor een dropdown-veld.",
        "Zoek de kolom die overeenkomt met de dropdown die je wilt aanpassen.",
        "Wijzig bestaande waarden of typ nieuwe waarden direct onder de bestaande lijst.",
        "Keer terug naar Stavaza Update - de dropdowns zijn automatisch bijgewerkt."]
    for i, stp in enumerate(steps):
        p = doc.add_paragraph(); p.paragraph_format.space_after = Pt(4)
        r1 = p.add_run(f"{i+1}. "); sr(r1, 11, True, NAVY); r2 = p.add_run(stp); sr(r2, 11)
    bp(doc, ""); bp(doc, "Beschikbare lijsten in het werkblad:", b=True)
    li = [["Portefeuille","Secretariaat, Financien, Activiteiten (GST), Ledenbeleid (GMT), Opleidingen (GLT), Jeugd"],
        ["Portefeuillehouder","Namen van de 7 GR-leden (pas aan bij wijziging)"],
        ["Commissie/Werkgroep","Alle commissies en werkgroepen per portefeuille"],
        ["Status","Groen, Geel, Rood, N.v.t."],
        ["Prioriteit","Urgent, Hoog, Gemiddeld, Laag"],
        ["Categorie","Bestuurlijk, Financieel, Operationeel, Communicatie, Strategisch, Juridisch"],
        ["Escalatie","Ja, Nee, Overleg"]]
    tbl(doc, ["Lijst","Huidige waarden"], li, [4.5, 12.0])
    doc.add_page_break()

    # 10. KLEURCODERING
    doc.add_heading("8. Automatische Kleurcodering", level=1)
    bp(doc, "Het formulier past automatisch kleuren toe op basis van drie systemen. Je hoeft hier niets voor te doen.")
    doc.add_heading("Status kleuren", level=2)
    sc = [["Groen","Op schema, geen worries","188038"],["Geel","Aandacht nodig","E8710A"],["Rood","Kritiek, blokkade","D93025"]]
    t = doc.add_table(rows=4, cols=3); t.alignment = WD_TABLE_ALIGNMENT.CENTER
    for i, h in enumerate(["Status","Betekenis","Weergave"]):
        c = t.cell(0, i); shade(c, "003366"); borders(c, "003366", "6"); r = c.paragraphs[0].add_run(h); sr(r, 10, True, WHITE)
    for ri, (st, bm, hx) in enumerate(sc):
        for ci, val in enumerate([st, bm, ""]):
            c = t.cell(ri+1, ci); borders(c)
            if ci == 2: shade(c, hx)
            elif ri % 2 == 1: shade(c, "F0F4FA")
            r = c.paragraphs[0].add_run(val if val else "  "); sr(r, 10, b=(ci==0), c=(WHITE if ci==2 else BODY))
    for row in t.rows: row.cells[0].width = Cm(3.5); row.cells[1].width = Cm(8.0); row.cells[2].width = Cm(5.0)

    doc.add_heading("Prioriteit kleuren", level=2)
    pc = [["Urgent","D93025"],["Hoog","E8710A"],["Gemiddeld","1A73E8"],["Laag","5F6368"]]
    t = doc.add_table(rows=5, cols=2); t.alignment = WD_TABLE_ALIGNMENT.CENTER
    for i, h in enumerate(["Prioriteit","Weergave"]):
        c = t.cell(0, i); shade(c, "003366"); borders(c, "003366", "6"); r = c.paragraphs[0].add_run(h); sr(r, 10, True, WHITE)
    for ri, (pr, hx) in enumerate(pc):
        for ci, val in enumerate([pr, ""]):
            c = t.cell(ri+1, ci); borders(c)
            if ci == 1: shade(c, hx)
            r = c.paragraphs[0].add_run(val if val else "  "); sr(r, 10, b=(ci==0), c=(WHITE if ci==1 else BODY))
    for row in t.rows: row.cells[0].width = Cm(5.0); row.cells[1].width = Cm(11.5)

    doc.add_heading("Deadline kleuren (automatisch op basis van vandaag)", level=2)
    dc = [["Verlopen (voor vandaag)","Rood, vetgedrukt","D93025","Directe actie vereist"],
          ["Binnen 7 dagen","Oranje","E8710A","Deze week oppakken"],
          ["Binnen 30 dagen","Geel","F9AB00","In de gaten houden"],
          ["Meer dan 30 dagen","Geen extra opmaak","—","Normale planning"]]
    t = doc.add_table(rows=5, cols=4); t.alignment = WD_TABLE_ALIGNMENT.CENTER
    for i, h in enumerate(["Deadline","Weergave","Kleur","Actie"]):
        c = t.cell(0, i); shade(c, "003366"); borders(c, "003366", "6"); r = c.paragraphs[0].add_run(h); sr(r, 10, True, WHITE)
    for ri, (dl, ds, hx, ac) in enumerate(dc):
        for ci, val in enumerate([dl, ds, "", ac]):
            c = t.cell(ri+1, ci); borders(c)
            if ci == 2 and hx != "—": shade(c, hx); val = "   "
            elif ri % 2 == 1: shade(c, "F0F4FA")
            r = c.paragraphs[0].add_run(val); sr(r, 10, b=(ci==0), c=(WHITE if ci==2 and hx!="—" else BODY))
    for row in t.rows: row.cells[0].width = Cm(4.5); row.cells[1].width = Cm(4.0); row.cells[2].width = Cm(2.0); row.cells[3].width = Cm(6.0)
    doc.add_page_break()

    # 11. SAMENVATTING
    doc.add_heading("9. Het Samenvattings-Dashboard", level=1)
    bp(doc, "Het werkblad Samenvatting toont automatisch het overzicht van alle ingevulde rijen. Je hoeft hier niets voor in te vullen.")
    doc.add_heading("Wat zie je in het dashboard?", level=2)
    bul(doc, "Aantal items per status: Groen, Geel, Rood, N.v.t.")
    bul(doc, "Totaal aantal escalaties naar de Gouverneursraad (Ja/Overleg)")
    bul(doc, "Aantal urgente items (Prioriteit = Urgent)")
    bul(doc, "Kritieke deadlines binnen 7 dagen")
    callout(doc, "Zo gebruik je het dashboard in de vergadering", ["Print of projecteer het dashboard als eerste slide.", "De voorzitter scant welke portefeuilles aandacht nodig hebben.", "Behandel eerst alle Rood-statussen en escalaties.", "Groene items worden slechts genoemd, niet besproken."], bg="E6F4EA", bd="188038")
    doc.add_page_break()

    # 12. ESCALATIE
    doc.add_heading("10. Escalatie Protocol", level=1)
    callout(doc, "NIEUW in v1.1", ["Het escalatieprotocol geeft de Gouverneursraad een heldere procedure voor kritieke punten."])
    doc.add_heading("Wanneer escaleren?", level=2)
    bp(doc, "Een punt wordt geescaleerd wanneer:")
    bul(doc, "Status = Rood en Escalatie = Ja")
    bul(doc, "Er een beslissing nodig is van de Gouverneursraad als geheel")
    bul(doc, "Er sprake is van een conflict tussen portefeuilles")
    bul(doc, "Budgettaire overschrijdingen of juridische risico's")
    doc.add_heading("Procedure in de Gouverneursraad", level=2)
    es = ["De portefeuillehouder introduceert het punt (maximaal 3 minuten).",
        "Toon het betreffende rij-item uit het Stavaza-formulier.",
        "De portefeuillehouder stelt expliciet de vraag: wat wordt er besloten?",
        "De Gouverneursraad bespreekt en neemt een besluit.",
        "De notulist legt vast: besluit, eigenaar en deadline.",
        "In de volgende vergadering wordt de status gecontroleerd."]
    for i, stp in enumerate(es):
        p = doc.add_paragraph(); p.paragraph_format.space_after = Pt(4)
        r1 = p.add_run(f"{i+1}. "); sr(r1, 11, True, RED); r2 = p.add_run(stp); sr(r2, 11)
    doc.add_page_break()

    # 13. TIPS
    doc.add_heading("11. Tips & Best Practices", level=1)
    tips = [
        ("Wees beknopt","Maximaal 2-3 zinnen per veld. Het is een statusupdate, geen volledig rapport."),
        ("Status is objectief","Groen betekent op schema - niet ik hoop dat het goed komt. Wees eerlijk."),
        ("SMART actiepunten","Specifiek, Meetbaar, Acceptabel, Realistisch, Tijdgebonden."),
        ("Een eigenaar per actie","Tip #9 van bar-beton.nl: een actiepunt = een eigenaar. Nooit team of commissie."),
        ("Meld Rood-statussen vooraf","Bel of mail de vergadervoorzitter voor de vergadering bij Rood+escalatie."),
        ("Gebruik het dashboard","Het Samenvattings-dashboard is je agenda-checklist."),
        ("Archiveer oude formulieren","Bewaar formulieren per vergadering voor trend-analyse."),
    ]
    for title, desc in tips:
        p = doc.add_paragraph(); p.paragraph_format.space_after = Pt(6)
        r1 = p.add_run(f"{title}: "); sr(r1, 11, True, NAVY); r2 = p.add_run(desc); sr(r2, 11)
    doc.add_page_break()

    # 14. FOUTEN
    doc.add_heading("12. Veelgemaakte Fouten", level=1)
    bp(doc, "Onderstaande fouten komen regelmatig voor. Houd ze in de gaten bij het invullen.")
    mistakes = [
        ("Te veel detail","Het formulier is een statusupdate, geen volledig rapport."),
        ("Vage beschrijvingen","Gaat wel zegt niets. Wees concreet."),
        ("Geen actie-eigenaar","Een actie zonder eigenaar is geen actie. Wijs altijd een persoon aan."),
        ("Te laat indienen","Na de 48-uur deadline komt je punt niet op de agenda."),
        ("Escalatie niet vooraf gemeld","Een escalatie moet de voorzitter weten voor de vergadering."),
        ("Dropdowns niet via Lijsten aanpassen","Typ geen nieuwe waarden direct in de cel. Gebruik tabblad Lijsten."),
    ]
    for title, desc in mistakes:
        p = doc.add_paragraph(style='List Bullet'); p.paragraph_format.space_after = Pt(4)
        r = p.runs[0] if p.runs else p.add_run(); r.text = f"{title}: "; sr(r, 11, True, RED)
        r2 = p.add_run(desc); sr(r2, 11)
    doc.add_page_break()

    # 15. VERSIEBEHEER
    doc.add_heading("13. Versiebeheer", level=1)
    vr = [
        ["1.0","Augustus 2026","Initielle release. Basisformulier met 12 kolommen, handmatige invulling."],
        ["1.1","Augustus 2026","Dropdowns voor alle sleutelvelden. Instelbaar Lijsten-werkblad. Automatische kleurcodering. Samenvattings-dashboard. Escalatie-kolom (L). Lions MD110 branding. Uitgebreide handleiding."],
    ]
    tbl(doc, ["Versie","Datum","Wijzigingen"], vr, [2.5, 3.5, 10.5])
    doc.add_paragraph(); doc.add_paragraph()
    p = doc.add_paragraph(); p.alignment = WD_ALIGN_PARAGRAPH.CENTER
    r = p.add_run("JvG Consultancy - Lions MD110 Nederland"); sr(r, 10, i=True, c=GREY)

    # FOOTER
    for section in doc.sections:
        footer = section.footer; footer.is_linked_to_previous = False
        fp = footer.paragraphs[0] if footer.paragraphs else footer.add_paragraph()
        fp.text = ""; fp.alignment = WD_ALIGN_PARAGRAPH.CENTER
        r = fp.add_run("Lions MD110 Nederland - Stavaza Handleiding v1.1  |  Pagina "); sr(r, 9, c=GREY)
        pagenum(fp)
        r2 = fp.add_run(" van "); sr(r2, 9, c=GREY)
        numpages(fp)

    # SAVE
    os.makedirs(os.path.dirname(OUT), exist_ok=True)
    doc.save(OUT)
    sz = os.path.getsize(OUT)
    print(f"OK: {OUT}")
    print(f"Size: {sz} bytes ({sz/1024:.1f} KB)")

if __name__ == "__main__":
    build()
