#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Plan van Aanpak - Ledenontmoetingsavond 13 oktober 2026 (District 110 AN)
DOCX-generator conform MASTER_STYLEGUIDE.md par. 2.3 (Lions DOCX-standaard).
Techniek: python-docx.
"""
import os
from docx import Document
from docx.shared import Pt, Cm, RGBColor, Inches
from docx.enum.text import WD_ALIGN_PARAGRAPH, WD_BREAK
from docx.enum.table import WD_TABLE_ALIGNMENT
from docx.oxml.ns import qn
from docx.oxml import OxmlElement

# ------------------------------------------------------------------ branding
LIONS_BLUE     = RGBColor(0x00, 0x33, 0x66)
LIONS_GOLD_RGB = RGBColor(0xFF, 0xB8, 0x1C)
LIONS_GOLD     = "FFB81C"
TEXT_DARK      = RGBColor(0x1F, 0x29, 0x37)
TEXT_SEC       = RGBColor(0x37, 0x41, 0x51)
WHITE          = RGBColor(0xFF, 0xFF, 0xFF)
ZEBRA          = "F8F9FA"
HEADER_BG      = "003366"
RISK_LOW       = "10B981"
RISK_MED       = "F59E0B"
RISK_HIGH      = "DC2626"

DISTRICT = u"Lions Clubs International \u2014 District 110 AN"
LOGO     = "/root/projects/jg/2026-pbm-ledenontmoetingsavond-13okt/assets/logo_lions_emblem.png"
OUT_DIR  = "/root/projects/jg/2026-pbm-ledenontmoetingsavond-13okt/deliverables/docx"
OUT_FILE = os.path.join(OUT_DIR, "06_Plan_van_Aanpak.docx")
VERSION, DATUM = "1.0", "25 augustus 2026"
BUL = u"\u2022"

# ------------------------------------------------------------------ helpers
def set_cell_bg(cell, hex_color):
    shd = OxmlElement("w:shd")
    shd.set(qn("w:val"), "clear"); shd.set(qn("w:fill"), hex_color)
    cell._tc.get_or_add_tcPr().append(shd)

def para(doc, text="", size=11, bold=False, color=TEXT_DARK, align=None,
         space_after=8, space_before=0, italic=False):
    p = doc.add_paragraph()
    p.paragraph_format.space_after = Pt(space_after)
    p.paragraph_format.space_before = Pt(space_before)
    if align: p.alignment = align
    if text:
        r = p.add_run(text)
        r.font.name = "Calibri"; r.font.size = Pt(size); r.font.bold = bold
        r.font.italic = italic; r.font.color.rgb = color
    return p

def h1(doc, text, first=False):
    p = para(doc, text, size=16, bold=True, color=LIONS_BLUE,
             space_before=18 if not first else 0, space_after=6)
    pPr = p._p.get_or_add_pPr()
    pbdr = OxmlElement("w:pBdr")
    bottom = OxmlElement("w:bottom")
    bottom.set(qn("w:val"), "single"); bottom.set(qn("w:sz"), "12")
    bottom.set(qn("w:space"), "2"); bottom.set(qn("w:color"), LIONS_GOLD)
    pbdr.append(bottom); pPr.append(pbdr)
    p.paragraph_format.keep_with_next = True
    return p

def h2(doc, text):
    p = para(doc, text, size=13, bold=True, color=LIONS_BLUE,
             space_before=12, space_after=4)
    p.paragraph_format.keep_with_next = True
    return p

def bullet(doc, text, bold_prefix=None):
    p = doc.add_paragraph(style="List Bullet")
    p.paragraph_format.space_after = Pt(4)
    if bold_prefix:
        r = p.add_run(bold_prefix); r.bold = True
        r.font.name = "Calibri"; r.font.size = Pt(11); r.font.color.rgb = TEXT_DARK
    r = p.add_run(text)
    r.font.name = "Calibri"; r.font.size = Pt(11); r.font.color.rgb = TEXT_DARK
    return p

def table(doc, headers, rows, widths=None, zebra=True):
    t = doc.add_table(rows=1, cols=len(headers))
    t.style = "Table Grid"; t.alignment = WD_TABLE_ALIGNMENT.CENTER
    for i, htxt in enumerate(headers):
        c = t.rows[0].cells[i]
        set_cell_bg(c, HEADER_BG)
        r = c.paragraphs[0].add_run(htxt)
        r.font.name = "Calibri"; r.font.size = Pt(10.5)
        r.font.bold = True; r.font.color.rgb = WHITE
    for ri, row in enumerate(rows):
        cells = t.add_row().cells
        for ci, val in enumerate(row):
            if zebra and ri % 2 == 1: set_cell_bg(cells[ci], ZEBRA)
            r = cells[ci].paragraphs[0].add_run(val)
            r.font.name = "Calibri"; r.font.size = Pt(10.5)
            r.font.color.rgb = TEXT_DARK
    if widths:
        for ci, w in enumerate(widths):
            for row in t.rows:
                row.cells[ci].width = Cm(w)
    para(doc, "", size=6, space_after=2)
    return t

def risk_color(score):
    if score <= 4:  return RISK_LOW
    if score <= 9:  return RISK_MED
    if score <= 16: return RISK_HIGH
    return "7F1D1D"

def page_break(doc):
    doc.add_paragraph().add_run().add_break(WD_BREAK.PAGE)

def add_page_field(p):
    r = p.add_run(); r.font.name = "Calibri"; r.font.size = Pt(9)
    fld1 = OxmlElement("w:fldChar"); fld1.set(qn("w:fldCharType"), "begin")
    instr = OxmlElement("w:instrText"); instr.set(qn("xml:space"), "preserve")
    instr.text = "PAGE"
    fld2 = OxmlElement("w:fldChar"); fld2.set(qn("w:fldCharType"), "end")
    r._r.append(fld1); r._r.append(instr); r._r.append(fld2)

def add_toc_field(doc):
    p = doc.add_paragraph()
    r = p.add_run()
    fld1 = OxmlElement("w:fldChar"); fld1.set(qn("w:fldCharType"), "begin")
    instr = OxmlElement("w:instrText"); instr.set(qn("xml:space"), "preserve")
    instr.text = 'TOC \\o "1-2" \\h \\z \\u'
    fld2 = OxmlElement("w:fldChar"); fld2.set(qn("w:fldCharType"), "separate")
    t = OxmlElement("w:t")
    t.text = u"Inhoudsopgave: klik met de rechtermuisknop en kies 'Veld bijwerken' (F9)."
    fld3 = OxmlElement("w:fldChar"); fld3.set(qn("w:fldCharType"), "end")
    r._r.append(fld1); r._r.append(instr); r._r.append(fld2)
    r._r.append(t); r._r.append(fld3)

# ------------------------------------------------------------------ document
doc = Document()
for section in doc.sections:
    section.top_margin = Cm(2.2); section.bottom_margin = Cm(2.0)
    section.left_margin = Cm(2.4); section.right_margin = Cm(2.4)

cp = doc.core_properties
cp.title = u"Plan van Aanpak - Ledenontmoetingsavond 13 oktober 2026 - District 110 AN"
cp.author = u"JvG Consultancy namens District 110 AN"
cp.keywords = u"Lions; District 110AN; plan van aanpak; ledenontmoetingsavond; 2e VDG; projectplan"
cp.category = u"Lions District Projectplan"

for section in doc.sections:
    fp = section.footer.paragraphs[0]
    fp.alignment = WD_ALIGN_PARAGRAPH.CENTER
    r = fp.add_run(u"District 110 AN %s Ledenontmoetingsavond 13 oktober 2026  %s  pagina " % (BUL, BUL))
    r.font.name = "Calibri"; r.font.size = Pt(9); r.font.color.rgb = TEXT_SEC
    add_page_field(fp)

# ------------------------------------------------------------------ cover
para(doc, DISTRICT, size=14, bold=True, color=LIONS_BLUE,
     align=WD_ALIGN_PARAGRAPH.CENTER, space_before=36, space_after=18)
if os.path.exists(LOGO):
    lp = doc.add_paragraph(); lp.alignment = WD_ALIGN_PARAGRAPH.CENTER
    lp.add_run().add_picture(LOGO, height=Inches(2.2))
    lp.paragraph_format.space_after = Pt(18)
para(doc, "PLAN VAN AANPAK", size=14, bold=True, color=LIONS_GOLD_RGB,
     align=WD_ALIGN_PARAGRAPH.CENTER, space_after=6)
para(doc, u"Ledenontmoetingsavond 13 oktober 2026", size=26, bold=True,
     color=LIONS_BLUE, align=WD_ALIGN_PARAGRAPH.CENTER, space_after=6)
para(doc, u"Districtsbrede ledenontmoetingsavond met aankondiging van de "
          u"kandidaat 2e Vice District Governor",
     size=13, color=TEXT_SEC, align=WD_ALIGN_PARAGRAPH.CENTER, space_after=24)
para(doc, u"Dinsdag 13 oktober 2026  %s  Locatie: nader te bepalen "
          u"(centrale locatie in het district)" % BUL,
     size=11, italic=True, color=TEXT_SEC,
     align=WD_ALIGN_PARAGRAPH.CENTER, space_after=36)
para(doc, u"Versie %s  %s  %s" % (VERSION, BUL, DATUM), size=11,
     color=TEXT_SEC, align=WD_ALIGN_PARAGRAPH.CENTER, space_after=4)
para(doc, u"Opgesteld door JvG Consultancy namens District 110 AN",
     size=11, color=TEXT_SEC, align=WD_ALIGN_PARAGRAPH.CENTER, space_after=4)
para(doc, u"Status: Definitief", size=11, color=TEXT_SEC,
     align=WD_ALIGN_PARAGRAPH.CENTER)
page_break(doc)

# ------------------------------------------------------- documentbeheer + TOC
h1(doc, u"Documentbeheer", first=True)
table(doc,
      [u"Versie", u"Datum", u"Auteur", u"Wijziging", u"Status"],
      [[u"1.0", DATUM, u"JvG Consultancy", u"Eerste uitgave", u"Definitief"]],
      widths=[2.0, 3.2, 3.6, 5.2, 2.6])

h1(doc, u"Inhoudsopgave")
add_toc_field(doc)
page_break(doc)

# ------------------------------------------------------------------ 1. samenvatting
h1(doc, u"1. Samenvatting", first=True)
para(doc, u"District 110 AN organiseert op dinsdag 13 oktober 2026 een "
          u"ledenontmoetingsavond voor alle leden van de clubs in het district. "
          u"De avond combineert twee doelen: het versterken van de onderlinge "
          u"band en betrokkenheid van de leden, conform het Club Vitaliteit "
          u"Programma v4 (april 2025) [1], en het formeel aankondigen van de "
          u"kandidaat 2e Vice District Governor volgens de benoemingsprocedure "
          u"uit de MD110 Statuten (2021) en het Protocol MD-Organen V1.0 [2][3].")
para(doc, u"Dit Plan van Aanpak (PvA) beschrijft de aanpak, organisatie, "
          u"planning, risico's, kwaliteitscriteria en middelen voor de "
          u"realisatie van deze avond. De voorbereiding loopt van 25 augustus "
          u"tot en met 13 oktober 2026, gevolgd door evaluatie en "
          u"verslaglegging tot en met 31 oktober 2026. De opdracht wordt "
          u"uitgevoerd onder verantwoordelijkheid van de District Governor, "
          u"met ondersteuning van het kabinet 2025-2026 (definitief vastgesteld "
          u"op 11 april 2025) [4] en JvG Consultancy als projectleider.")

h2(doc, u"1.1 Hoofddoelen")
bullet(doc, u" organiseren van een districtsbrede ledenontmoetingsavond op 13 oktober 2026 met deelnemers uit minimaal 60% van de clubs;", u"Betrokkenheid:")
bullet(doc, u" formeel aankondigen van de kandidaat 2e Vice District Governor conform MD110 Statuten en het Protocol MD-Organen;", u"Successie:")
bullet(doc, u" leden informeren over en activeren rond het vitaliteits- en ledenbeleid van Lions Nederland (GMT, 2025);", u"Vitaliteit:")
bullet(doc, u" de onderlinge band tussen clubs en zones versterken als basis voor ledengroei en nieuwe serviceprojecten.", u"Netwerk:")

h2(doc, u"1.2 Belangrijkste deliverables")
bullet(doc, " Definitief eventprogramma (vastgesteld uiterlijk 3 oktober 2026);")
bullet(doc, " Verzonden uitnodigingen en registratieoverzicht (RSVP-statistiek);")
bullet(doc, " Locatie-, catering- en AV-contractering binnen het goedgekeurde budget;")
bullet(doc, " Presentatiemateriaal inclusief de 2e VDG-aankondiging;")
bullet(doc, " Draaiboek voor de avond zelf (tijdlijn, rollen, script aankondiging);")
bullet(doc, " Evaluatierapport met opkomstcijfers, bevindingen en aanbevelingen (uiterlijk 31 oktober 2026).")
page_break(doc)
# ------------------------------------------------------------------ 2. projectomschrijving
h1(doc, u"2. Projectomschrijving", first=True)

h2(doc, u"2.1 Achtergrond")
para(doc, u"Lions District 110 AN kent, net als veel districten van Lions "
          u"Clubs International, een dalende of stabiele ledenontwikkeling; "
          u"de 5 Year Membership Trend en het club health assessment van het "
          u"district geven hiervoor de feitelijke basis [6][7]. Het Werkplan "
          u"110 AN 2025-2026 zet daarom in op clubvitaliteit, ledengroei, "
          u"governance-versterking en ondersteuning van de Global Membership "
          u"Team (GMT) [8]. Een ledenontmoetingsavond - zoals de eerdere "
          u"Inspiratieavond 110AN - is een bewezen instrument om leden te "
          u"activeren en de verbinding tussen district en clubs te versterken [9].")
para(doc, u"Daarnaast vereist de bestuursopvolging een tijdige aankondiging "
          u"van de kandidaat 2e Vice District Governor. Het benoemings- en "
          u"verkiezingsproces is gebonden aan de MD110 Statuten (2021), het "
          u"Huishoudelijk Reglement MD 110 (mei 2021, concept 2025) en de LCI "
          u"International Constitution and By-Laws [2][10][11]. De avond van "
          u"13 oktober 2026 biedt het formele moment voor deze aankondiging.")

h2(doc, u"2.2 Doelstellingen")
table(doc,
      [u"Nr.", u"Doelstelling", u"Meetbaar criterium", u"Bron"],
      [["D1", u"Deelnemersactivering", u"Minimaal 60% van de clubs vertegenwoordigd; indicatief streefbeeld 75+ deelnemers (nader te concretiseren met ledenstatistieken)", u"[6][7]"],
       ["D2", u"Aankondiging 2e VDG", u"Aankondiging conform MD110 Statuten \u00a74.2 en Protocol MD-Organen \u00a73.1, vastgelegd in het verslag van de avond", u"[2][3]"],
       ["D3", u"Vitaliteit en ledenbeleid", u"Minimaal 80% van de deelnemers ervaart na afloop betere informatieverzorging over vitaliteits- en ledenbeleid (evaluatie)", u"[1][5]"],
       ["D4", u"Financi\u00eble beheersing", u"Realisatie binnen het goedgekeurde budget uit de districtbegroting 25-26", u"[12]"],
       ["D5", u"Netwerkversterking", u"Minimaal 5 nieuwe interclub-contactmomenten of -initiatieven gemeld in de evaluatie", u"Project eigen meting"]],
      widths=[1.2, 3.6, 8.0, 1.8])

h2(doc, u"2.3 Scope en grenzen")
para(doc, u"Dit project omvat de volledige organisatie van de "
          u"ledenontmoetingsavond van 13 oktober 2026: locatie en catering, "
          u"uitnodigings- en registratieproces, programma en sprekers, "
          u"presentatiemateriaal, AV-ondersteuning, de formele aankondiging "
          u"van de kandidaat 2e VDG, verslaglegging en evaluatie. De scope "
          u"geldt voor alle clubs en leden van District 110 AN.")
bullet(doc, " Organisatie van locatie, catering en voorzieningen voor circa 75-120 deelnemers (afhankelijk van registratie);")
bullet(doc, " Uitnodiging van alle clubs in het district conform het ledenoverzicht;")
bullet(doc, " Samenstelling van het programma met bijdragen van het kabinet, GMT en de aankondiging 2e VDG;")
bullet(doc, " Communicatie voor, tijdens en na de avond (districtskanalen en clubkanalen);")
bullet(doc, " Evaluatie en rapportage aan de District Governor en het kabinet.")

h2(doc, u"2.4 Uitsluitingen")
bullet(doc, " De formele benoeming/verkiezing zelf; deze geschiedt via de daartoe bestemde organen en procedures, de avond bevat uitsluitend de aankondiging [2][11];")
bullet(doc, " De District Convention en bijbehorende agenda-onderdelen;")
bullet(doc, " Logistiek vervoer en overnachtingen voor deelnemers;")
bullet(doc, " Fondsenwerving of serviceprojecten als zelfstandig programmaonderdeel;")
bullet(doc, " Het ledenbeleid zelf; dit project implementeert het bestaande beleid, wijzigt het niet.")
page_break(doc)

# ------------------------------------------------------------------ 3. projectaanpak
h1(doc, u"3. Projectaanpak", first=True)

h2(doc, u"3.1 Projectorganisatie")
para(doc, u"De projectorganisatie is licht en ingebed in de bestaande "
          u"districtstructuur. De District Governor is opdrachtgever en "
          u"eindverantwoordelijke. JvG Consultancy verzorgt de "
          u"projectleiding en co\u00f6rdinatie. Het projectteam rapporteert "
          u"wekelijks aan de opdrachtgever.")
bullet(doc, " Opdrachtgever: District Governor (kabinet 2025-2026);", "Rol:")
bullet(doc, " Projectleider: JvG Consultancy;", "Rol:")
bullet(doc, " Eventteam: leden kabinet en zonevoorzitters (inzet nader vastgesteld);", "Rol:")
bullet(doc, " Advies: GMT-districtsteun en Communicatieteam district.", "Rol:")

h2(doc, u"3.2 Rollen en verantwoordelijkheden (RACI)")
table(doc,
      [u"Activiteit", u"DG (Opdrachtgever)", u"Projectleider", u"Eventteam", u"Kabinet"],
      [[u"Goedkeuring PvA en budget", "A", "R", "C", "C"],
       [u"Locatie- en cateringcontractering", "A", "R", "C", "I"],
       [u"Programma en sprekers", "A", "R", "R", "C"],
       [u"Uitnodigingen en registratie", "I", "A", "R", "I"],
       [u"Aankondiging 2e VDG (script, protocollair)", "A", "R", "I", "C"],
       [u"AV en presentatiemateriaal", "I", "A", "R", "I"],
       [u"Draaiboek en uitvoering avond", "A", "R", "R", "C"],
       [u"Evaluatie en verslaglegging", "A", "R", "C", "I"]],
      widths=[6.2, 2.6, 2.4, 2.2, 1.8])
para(doc, u"R = Responsible, A = Accountable, C = Consulted, I = Informed.",
     size=9, italic=True, color=TEXT_SEC)

h2(doc, u"3.3 Stakeholderanalyse")
table(doc,
      [u"Stakeholder", u"Belang / invloed", u"Verwachting", u"Aanpak"],
      [[u"District Governor en kabinet", u"Hoog / hoog", u"Fijne organisatie, correcte protocollaire aankondiging 2e VDG", u"Weekelijkse rapportage, formele goedkeuring beslispunten"],
       [u"(Toekomstige) kandidaat 2e VDG", u"Hoog / middel", u"Waardige, correct aankondiging", u"Vroege afstemming script en protocol"],
       [u"Clubbesturen en leden", u"Hoog / middel", u"Inspirerende avond, netwerk, duidelijke informatie", u"Tijdige uitnodigingen, herinneringen, evaluatie"],
       [u"Zonevoorzitters", u"Middel / middel", u"Duidelijke rol bij mobilisatie deelnemers", u"Betrokken bij uitnodigingen en RSVP-monitoring"],
       [u"GMT / Lions Nederland", u"Middel / laag", u"Aansluiting op vitaliteits- en ledenbeleid", u"Afstemming inhoud presentaties [1][5]"],
       [u"Locatie- en cateringspartij", u"Laag / middel", u"Duidelijke opdracht en aantallen", u"Contract met SLA-afspraken, tussentijdse bevestiging"]],
      widths=[3.6, 2.4, 4.6, 5.0])

h2(doc, u"3.4 Communicatieplan")
table(doc,
      [u"Moment", u"Middel", u"Doelgroep", u"Inhoud", u"Verantwoordelijke"],
      [[u"W36 (medio september)", u"E-mail + districtssite", u"Alle clubbesturen", u"Save-the-date en uitnodiging met registratie", u"Projectleider"],
       [u"W38", u"Herinnering e-mail + zonevoorzitters", u"Alle clubs", u"Registratieherinnering, programma", u"Eventteam"],
       [u"W40", u"Kabinetsvergadering", u"Kabinet", u"Statusupdate, definitief programma", u"Projectleider"],
       [u"W41", u"Sluitende communicatie", u"Geregistreerde deelnemers", u"Praktische informatie, locatie, aanvangstijd", u"Eventteam"],
       [u"13 oktober", u"Avond zelf", u"Deelnemers", u"Programma, aankondiging 2e VDG", u"Projectleider / DG"],
       [u"W43", u"E-mail + verslag", u"DG, kabinet, clubs", u"Bedankje, evaluatierapport, verslag", u"Projectleider"]],
      widths=[2.8, 3.4, 2.8, 4.4, 2.4])
page_break(doc)

# ------------------------------------------------------------------ 4. planning
h1(doc, u"4. Projectplanning", first=True)

h2(doc, u"4.1 Fasen")
table(doc,
      [u"Fase", u"Periode", u"Kernactiviteiten", u"Resultaat"],
      [[u"F1 Initiatie", u"25 aug - 5 sep 2026", u"Goedkeuring PvA, vaststellen locatie en budget, aansturen projectteam", u"Vastgesteld PvA, geboekte locatie, budgetkader"],
       [u"F2 Voorbereiding", u"5 - 26 sep 2026", u"Uitnodigingen, programma, sprekers, catering, presentaties, registratieproces", u"Uitnodigingen verzonden, programma concept-definitief"],
       [u"F3 Uitvoeringsgereedmaking", u"26 sep - 12 okt 2026", u"RSVP-monitoring, definitief programma, draaiboek, AV-test, general probe", u"Definitief programma, goedgekeurd draaiboek"],
       [u"F4 Evenement", u"13 okt 2026", u"Ledenontmoetingsavond met aankondiging 2e VDG", u"Succesvol verlopen avond, aanwezigheidsregistratie"],
       [u"F5 Afronding", u"14 - 31 okt 2026", u"Evaluatie, financi\u00eble afwikkeling, verslaglegging, overdracht leerpunten", u"Evaluatierapport, afgeronde administratie"]],
      widths=[3.4, 2.8, 5.6, 4.6])

h2(doc, u"4.2 Mijlpalen")
table(doc,
      [u"Mijlpaal", u"Datum", u"Criterium"],
      [[u"M1 - PvA goedgekeurd", u"1 september 2026", u"Ondertekening door District Governor"],
       [u"M2 - Locatie en budget vastgesteld", u"12 september 2026", u"Getekende overeenkomst locatie/catering binnen budgetkader"],
       [u"M3 - Uitnodigingen verzonden", u"18 september 2026", u"Uitnodiging met registratielink naar alle clubs verstuurd"],
       [u"M4 - Programma definitief", u"3 oktober 2026", u"Programma inclusief script 2e VDG-aankondiging vastgesteld"],
       [u"M5 - Evenement", u"13 oktober 2026", u"Ledenontmoetingsavond inclusief aankondiging uitgevoerd"],
       [u"M6 - Evaluatierapport opgeleverd", u"31 oktober 2026", u"Rapport met opkomstcijfers en aanbevelingen aangeboden"]],
      widths=[5.2, 3.4, 7.8])

h2(doc, u"4.3 Tijdlijn (Gantt-overzicht)")
para(doc, u"Weeknummers conform ISO 8606; periode week 35 t/m week 43 van 2026. \u25a0 = geplande activiteit.", size=9, italic=True, color=TEXT_SEC)
WEEKS = [u"W35", u"W36", u"W37", u"W38", u"W39", u"W40", u"W41", u"W42", u"W43"]
ACTS = [
    (u"Goedkeuring PvA en projectstart",       [1, 0, 0, 0, 0, 0, 0, 0, 0]),
    (u"Locatie-, catering- en AV-contractering", [1, 1, 1, 0, 0, 0, 0, 0, 0]),
    (u"Uitnodigingen en registratieproces",    [0, 1, 1, 1, 1, 0, 0, 0, 0]),
    (u"Programma, sprekers en presentaties",   [0, 1, 1, 1, 1, 1, 0, 0, 0]),
    (u"RSVP-monitoring en herinneringen",      [0, 0, 0, 1, 1, 1, 0, 0, 0]),
    (u"Draaiboek en AV-test / general probe",  [0, 0, 0, 0, 0, 1, 1, 0, 0]),
    (u"Uitvoering ledenontmoetingsavond",      [0, 0, 0, 0, 0, 0, 1, 0, 0]),
    (u"Evaluatie, verslaglegging en afsluiting", [0, 0, 0, 0, 0, 0, 0, 1, 1]),
]
gantt_rows = [[name] + [u"\u25a0" if v else u"" for v in marks] for name, marks in ACTS]
table(doc, [u"Activiteit"] + WEEKS, gantt_rows,
      widths=[6.4] + [1.15] * 9)

h2(doc, u"4.4 Dependencies")
bullet(doc, " Locatiecontractering is voorwaarde voor de uitnodiging (datum en plaats moeten definitief zijn);")
bullet(doc, " Definitieve kandidaat-stelling 2e VDG is voorwaarde voor het script en de programmaregel van de aankondiging;")
bullet(doc, " RSVP-cijfers zijn sturend voor de catering-afname (definitief aantal uiterlijk 7 dagen voor de avond);")
bullet(doc, " AV-test en general probe vereisen een definitief programma;")
bullet(doc, " Evaluatierapport is afhankelijk van volledige aanwezigheids- en evaluatieregistratie op de avond zelf.")
page_break(doc)
# ------------------------------------------------------------------ 5. risicoanalyse
h1(doc, u"5. Risicoanalyse", first=True)

h2(doc, u"5.1 Risicoregister en mitigatie")
table(doc,
      [u"Nr.", u"Risico", u"Kans", u"Impact", u"Score", u"Mitigatiemaatregel"],
      [[u"R1", u"Locatie op 13 oktober niet (meer) beschikbaar of niet geschikt", u"Laag (2)", u"Hoog (5)", u"10", u"Tweede locatie in optie houden; contracteren voor 12 september 2026"],
       [u"R2", u"Kandidaat 2e VDG niet tijdig definitief", u"Middel (3)", u"Hoog (5)", u"15", u"Procesafspraken met DG en kabinet; alternatieve programmaregel voorbereiden"],
       [u"R3", u"Lage opkomst", u"Middel (3)", u"Middel (3)", u"9", u"Zonevoorzitters activeren, herinneringen in W38, persoonlijke follow-up bij clubs zonder registratie"],
       [u"R4", u"Budgetoverschrijding", u"Middel (3)", u"Middel (3)", u"9", u"Budgetkader vaststellen voor contractering; catering flexibel afnemen op basis van RSVP"],
       [u"R5", u"Niet-naleving governancekader (statuten/protocol)", u"Laag (2)", u"Hoog (5)", u"10", u"Compliancecheck van script en agenda tegen MD110 Statuten, HR en Protocol MD-Organen [2][3][10]"],
       [u"R6", u"Techniek/AV-storing tijdens de avond", u"Middel (3)", u"Laag (2)", u"6", u"AV-test en reserve-opstelling (eigen laptop/beamer) tijdens general probe"],
       [u"R7", u"Spreker/programmaonderdeel valt uit", u"Laag (2)", u"Middel (3)", u"6", u"Back-up-inhoud beschikbaar; programma met tijdbuffer opgebouwd"]],
      widths=[1.0, 4.4, 1.8, 1.8, 1.4, 6.0])

h2(doc, u"5.2 Impact-/kansmatrix")
para(doc, u"Scores = kans (1-5) x impact (1-5). Classificering: 1-4 laag "
          u"(groen), 5-9 gemiddeld (amber), 10-16 hoog (rood), 17-25 "
          u"kritiek (donkerrood). R-nummers geven de projectrisico's weer.",
     size=9, italic=True, color=TEXT_SEC)

matrix_risks = {
    (2, 5): u"R1, R5", (3, 5): u"R2", (3, 3): u"R3, R4", (3, 2): u"R6", (2, 3): u"R7",
}
t = doc.add_table(rows=6, cols=6)
t.style = "Table Grid"; t.alignment = WD_TABLE_ALIGNMENT.CENTER
hdr = t.rows[0].cells
hdr[0].paragraphs[0].add_run(u"Impact \\ Kans")
for ci, label in enumerate([u"1 Zeer laag", u"2 Laag", u"3 Middel", u"4 Hoog", u"5 Zeer hoog"], start=1):
    hdr[ci].paragraphs[0].add_run(label)
for c in hdr:
    set_cell_bg(c, HEADER_BG)
    for r in c.paragraphs[0].runs:
        r.font.name = "Calibri"; r.font.size = Pt(10); r.font.bold = True
        r.font.color.rgb = WHITE
impact_labels = [u"5 Zeer hoog", u"4 Hoog", u"3 Middel", u"2 Laag", u"1 Zeer laag"]
for ri, imp_lbl in enumerate(impact_labels, start=1):
    impact = 6 - ri
    row = t.rows[ri].cells
    set_cell_bg(row[0], HEADER_BG)
    r0 = row[0].paragraphs[0].add_run(imp_lbl)
    r0.font.name = "Calibri"; r0.font.size = Pt(10); r0.font.bold = True
    r0.font.color.rgb = WHITE
    for ci in range(1, 6):
        kans = ci
        score = kans * impact
        cell = row[ci]
        set_cell_bg(cell, risk_color(score))
        p = cell.paragraphs[0]; p.alignment = WD_ALIGN_PARAGRAPH.CENTER
        txt = u"%d" % score
        if (kans, impact) in matrix_risks:
            txt += u"\n%s" % matrix_risks[(kans, impact)]
        rr = p.add_run(txt)
        rr.font.name = "Calibri"; rr.font.size = Pt(9.5); rr.font.color.rgb = WHITE
        rr.font.bold = True
para(doc, "", size=6, space_after=2)
page_break(doc)

# ------------------------------------------------------------------ 6. kwaliteit
h1(doc, u"6. Kwaliteit", first=True)

h2(doc, u"6.1 Kwaliteitscriteria")
bullet(doc, " Alle deliverables voldoen aan de huisstijl en terminologie van Lions District 110 AN;")
bullet(doc, " Protocollaire onderdelen (aankondiging 2e VDG) zijn getoetst aan statuten en protocol [2][3];")
bullet(doc, " Communicatie is foutvrij, tijdig en via de offici\u00eble districtskanalen;")
bullet(doc, " Het programma sluit aan bij het vitaliteits- en ledenbeleid [1][5];")
bullet(doc, " Documentatie (draaiboek, registratie, verslag) is volledig en herleidbaar.")

h2(doc, u"6.2 Acceptatiecriteria")
table(doc,
      [u"Deliverable", u"Acceptatiecriterium", u"Acceptatie door"],
      [[u"Plan van Aanpak", u"Ondertekend door District Governor uiterlijk 1 september 2026", u"District Governor"],
       [u"Locatie- en cateringcontract", u"Binnen budgetkader; voorwaarden en annuleringsregeling vastgelegd", u"District Governor / penningmeester"],
       [u"Programma en aankondigingsscript", u"Compliant aan MD110 Statuten en Protocol; akkoord DG en kandidaat", u"District Governor"],
       [u"Draaiboek", u"Volledig, rollen en tijdlijn zonder hiaten; getest in general probe", u"Projectleider"],
       [u"Evaluatierapport", u"Bevat opkomstcijfers, evaluatie-uitslagen en aanbevelingen; uiterlijk 31 oktober 2026", u"District Governor / kabinet"]],
      widths=[4.2, 8.0, 3.2])

h2(doc, u"6.3 Toetsingsprocedure")
para(doc, u"Elk deliverable doorloopt een driestappencontrole: (1) "
          u"inhoudelijke check door de opsteller tegen het Meta-Dossier en "
          u"de brondocumenten; (2) compliance- en protocolcheck op "
          u"governancegevoelige onderdelen (statuten, HR, Protocol "
          u"MD-Organen); (3) formele goedkeuring door de District Governor. "
          u"Afwijkingen worden vastgelegd in het documentbeheer en leiden "
          u"tot een nieuwe versie. Na de avond wordt de kwaliteitscyclus "
          u"afgesloten met een evaluatie conform de succescriteria uit "
          u"hoofdstuk 8.")
page_break(doc)
# ------------------------------------------------------------------ 7. middelen
h1(doc, u"7. Middelen", first=True)

h2(doc, u"7.1 Budget (indicatief kader)")
para(doc, u"Het budget wordt ontleend aan de districtbegroting 25-26 [12]. "
          u"Exacte bedragen worden vastgesteld bij mijlpaal M2 "
          u"(12 september 2026). Onderstaand indicatief kader ter "
          u"besluitvorming:")
table(doc,
      [u"Post", u"Indicatief kader", u"Toelichting"],
      [[u"Locatie en zaalhuur", u"Nader te bepalen", u"Centrale locatie; contractering vereist voor 12 september 2026"],
       [u"Catering", u"Nader te bepalen", u"Afhankelijk van definitieve deelnemersaantallen (RSVP)"],
       [u"AV/techniek", u"Nader te bepalen", u"Beamer, geluid, microfoonie; reserve-opstelling verplicht"],
       [u"Communicatie en drukwerk", u"Nader te bepalen", u"Uitnodigingen, programmabladen, signage"],
       [u"Reserve (10%)", u"Nader te bepalen", u"Buffer voor onvoorziene kosten"]],
      widths=[4.6, 3.4, 7.4])
para(doc, u"Financi\u00eble afwikkeling en controle geschieden conform de "
          u"MD110-regeling onkostenvergoedingen per 1 juli 2023 [13].",
     size=10, italic=True, color=TEXT_SEC)

h2(doc, u"7.2 Menskracht")
table(doc,
      [u"Rol", u"Inzet", u"Betrokkene"],
      [[u"District Governor (opdrachtgever)", u"Beslismomenten en goedkeuringen, circa 2-4 uur per maand", u"Arjan van Ommen"],
       [u"Projectleider", u"Doorlopend; co\u00f6rdinatie en controle", u"JvG Consultancy"],
       [u"Eventteam", u"4-8 uur per week in F2-F3", u"Leden kabinet en zonevoorzitters"],
       [u"Communicatie", u"4 uur per communicatiemoment", u"Communicatieteam district"],
       [u"Avondploeg (13 oktober)", u"Volledige avond inclusief opbouw", u"Eventteam, 6-8 personen"]],
      widths=[5.4, 5.0, 5.0])

h2(doc, u"7.3 Faciliteiten")
bullet(doc, " Zaal voor 75-120 personen met zitgelegenheid en ruimte voor informele ontmoeting;")
bullet(doc, " Catering (drank en lichte hapjes) met aandacht voor dieetwensen via registratieformulier;")
bullet(doc, " AV-voorzieningen: beamer, geluid, microfoons, presentatielaptop met reserve;")
bullet(doc, " Registratiebalie en aanwezigheidsregistratie;")
bullet(doc, " Parkeergelegenheid en bereikbaarheid met openbaar vervoer (centrale ligging in het district).")

h2(doc, u"7.4 Tools en systemen")
table(doc,
      [u"Tool/systeem", u"Gebruik"],
      [[u"Districtscommunicatie (e-mail, districtssite)", u"Uitnodigingen, herinneringen, terugkoppeling"],
       [u"Registratieformulier (online)", u"RSVP en dieetwensen; export naar aanwezigheidslijst"],
       [u"LCI Global Member Portal", u"Club- en ledennamen voor adressering [14]"],
       [u"Presentatiesoftware en templates", u"Presentaties conform Lions-huisstijl"],
       [u"Projectdossier (gedeelde map)", u"Versiebeheer documenten, draaiboek, script, contactenlijsten"]],
      widths=[6.4, 9.0])
page_break(doc)

# ------------------------------------------------------------------ 8. projectresultaten
h1(doc, u"8. Projectresultaten", first=True)

h2(doc, u"8.1 Deliverables")
table(doc,
      [u"Nr.", u"Deliverable", u"Opleverdatum", u"Eigenaar"],
      [[u"L1", u"Plan van Aanpak (dit document)", u"25 augustus 2026", u"JvG Consultancy"],
       [u"L2", u"Uitnodiging en registratieformulier live", u"18 september 2026", u"Eventteam"],
       [u"L3", u"Locatie- en cateringcontractering", u"12 september 2026", u"Projectleider"],
       [u"L4", u"Definitief programma met sprekers", u"3 oktober 2026", u"Projectleider"],
       [u"L5", u"Presentatiemateriaal incl. aankondiging 2e VDG", u"8 oktober 2026", u"Projectleider / kabinet"],
       [u"L6", u"Draaiboek", u"8 oktober 2026", u"JvG Consultancy"],
       [u"L7", u"Ledenontmoetingsavond (uitvoering)", u"13 oktober 2026", u"Projectteam"],
       [u"L8", u"Evaluatierapport en verslag", u"31 oktober 2026", u"JvG Consultancy"]],
      widths=[1.0, 7.0, 3.4, 3.0])

h2(doc, u"8.2 Succescriteria")
bullet(doc, " De avond vindt volledig conform draaiboek plaats binnen het vastgestelde tijdschema;")
bullet(doc, " De aankondiging van de kandidaat 2e VDG verloopt protocollair correct en wordt positief ontvangen;")
bullet(doc, " Minimaal 60% van de clubs is vertegenwoordigd;")
bullet(doc, " De realisatie blijft binnen het goedgekeurde budget;")
bullet(doc, " Evaluatierapport wordt uiterlijk 31 oktober 2026 opgeleverd en door de DG geaccepteerd.")

h2(doc, u"8.3 KPI's")
table(doc,
      [u"KPI", u"Doelstelling", u"Bron van meting"],
      [[u"Clubvertegenwoordiging", u"Minimaal 60% van de clubs", u"Aanwezigheidsregistratie"],
       [u"Deelnemersaantal", u"Minimaal 75 deelnemers (indicatief)", u"Aanwezigheidsregistratie"],
       [u"Tevredenheid deelnemers", u"Minimaal 4,0 op 5,0 in evaluatie", u"Evaluatieformulier avond"],
       [u"Informatie-overdracht vitaliteitsbeleid", u"Minimaal 80% geeft aan beter ge\u00efnformeerd", u"Evaluatieformulier avond"],
       [u"Budgetrealisatie", u"Maximaal 100% van goedgekeurd budget", u"Financi\u00eble administratie district"],
       [u"Tijdige oplevering documenten", u"Alle mijlpalen gehaald (M1-M6)", u"Projectdossier / documentbeheer"]],
      widths=[5.0, 5.0, 5.4])
page_break(doc)
# ------------------------------------------------------------------ 9. bijlagen
h1(doc, u"9. Bijlagen", first=True)

h2(doc, u"9.1 Referenties")
refs = [
    u"[1] Lions Club Vitaliteit Programma v4, Lions Nederland, april 2025",
    u"[2] MD110 Nederland Statuten, versie 2021.12.07",
    u"[3] Protocol MD-Organen, versie V1.0, 18 februari 2025",
    u"[4] Samenstelling kabinet 25-26, definitief vastgesteld 11 april 2025",
    u"[5] Ledenbeleid GMT Lions Nederland, editie 2025",
    u"[6] District 110AN 5 Year Membership Trend",
    u"[7] District 110AN Club Health Assessment",
    u"[8] Werkplan 110 AN 2025-2026",
    u"[9] Inspiratie avond 110AN, presentatie (eerdere ledenontmoetingsavond)",
    u"[10] Huishoudelijk Reglement MD 110, mei 2021 / concept 2025",
    u"[11] LCI International Constitution and By-Laws",
    u"[12] Districtbegroting 110 AN 25-26",
    u"[13] MD110-regeling onkostenvergoedingen, per 1 juli 2023",
    u"[14] LCI Global Member Portal, district- en clubgegevens",
]
for ref in refs:
    para(doc, ref, size=10, space_after=3)

h2(doc, u"9.2 Afkortingenlijst")
table(doc,
      [u"Afkorting", u"Begrip"],
      [[u"DG", u"District Governor"],
       [u"VDG", u"Vice District Governor"],
       [u"IPDG", u"Immediate Past District Governor"],
       [u"MD110", u"Multiple District 110 (Nederland)"],
       [u"LCI", u"Lions Clubs International"],
       [u"GMT", u"Global Membership Team"],
       [u"PvA", u"Plan van Aanpak"],
       [u"RACI", u"Responsible, Accountable, Consulted, Informed"],
       [u"RSVP", u"R\u00e9pondez s'il vous pla\u00eet (aanmelding)"],
       [u"AV", u"Audiovisuele techniek"],
       [u"KPI", u"Key Performance Indicator (prestatie-indicator)"],
       [u"W36 e.d.", u"Weeknummer conform ISO 8601"]],
      widths=[3.0, 12.4])

h2(doc, u"9.3 Bronvermelding en totstandkoming")
para(doc, u"Dit Plan van Aanpak is opgesteld op basis van het Meta-Dossier "
          u"v1.0 (25 augustus 2026) van project 2026-pbm-ledenontmoetingsavond-"
          u"13okt, waarin 33 bronnen uit drie tiers (interne procedures en "
          u"masterdata; wetgeving, governance en protocollen; externe data "
          u"en best practices) zijn samengebracht. Bronverwijzingen tussen "
          u"vierkante haken verwijzen naar de referenties in bijlage 9.1. "
          u"Openstaande punten (locatie, exact budget, definitieve "
          u"kandidaatstelling 2e VDG en deelnemersaantallen) zijn gemarkeerd "
          u"als zodanig en worden afgerond in de fasen F1 en F2.")
para(doc, u"", size=6)
para(doc, u"%s JvG Consultancy, namens District 110 AN %s %s %s Versie %s"
          % (BUL, BUL, DATUM, BUL, VERSION),
     size=10, italic=True, color=TEXT_SEC, align=WD_ALIGN_PARAGRAPH.CENTER)

# ------------------------------------------------------------------ opslaan
os.makedirs(OUT_DIR, exist_ok=True)
doc.save(OUT_FILE)
print("OK:", OUT_FILE)
