#!/usr/bin/env python3
"""PGS-15 Management Presentatie — Phoenix Metals IJmuiden"""

from pptx import Presentation
from pptx.util import Inches, Pt, Emu
from pptx.dml.color import RGBColor
from pptx.enum.text import PP_ALIGN, MSO_ANCHOR
from pptx.enum.shapes import MSO_SHAPE
import os, datetime

# ── Branding ──
PRIMARY = RGBColor(0x00, 0x33, 0x66)
ACCENT  = RGBColor(0x3B, 0x82, 0xF6)
WHITE   = RGBColor(0xFF, 0xFF, 0xFF)
DARK    = RGBColor(0x33, 0x33, 0x33)
RED     = RGBColor(0xDC, 0x26, 0x26)
GREEN   = RGBColor(0x16, 0xA3, 0x5A)
ORANGE  = RGBColor(0xF5, 0x9E, 0x0B)
LIGHT_BG = RGBColor(0xF0, 0xF4, 0xF8)

LOGO_PATH = "/root/projects/jg/2026-pgs15-phoenix-metals/assets/branding/jvg-consultancy-logo.jpg"
DATE_STR = "26 april 2026"
SLIDE_W = Inches(13.333)
SLIDE_H = Inches(7.5)

prs = Presentation()
prs.slide_width = SLIDE_W
prs.slide_height = SLIDE_H

# ── Helpers ──
def add_bg(slide, color=WHITE):
    bg = slide.background
    fill = bg.fill
    fill.solid()
    fill.fore_color.rgb = color

def add_logo(slide, large=False):
    if not os.path.exists(LOGO_PATH):
        return
    w = Inches(2.2) if large else Inches(1.1)
    h = Inches(1.1) if large else Inches(0.55)
    left = SLIDE_W - w - Inches(0.3)
    top = Inches(0.2)
    slide.shapes.add_picture(LOGO_PATH, left, top, w, h)

def add_footer(slide, num):
    tf = slide.shapes.add_textbox(Inches(0.5), SLIDE_H - Inches(0.45), Inches(8), Inches(0.35)).text_frame
    p = tf.paragraphs[0]
    p.text = f"{num}  |  JvG Consultancy | PGS-15  |  {DATE_STR}"
    p.font.size = Pt(9)
    p.font.color.rgb = RGBColor(0x99, 0x99, 0x99)

def add_title_bar(slide, title_text):
    bar = slide.shapes.add_shape(MSO_SHAPE.RECTANGLE, 0, 0, SLIDE_W, Inches(1.1))
    bar.fill.solid()
    bar.fill.fore_color.rgb = PRIMARY
    bar.line.fill.background()
    tf = bar.text_frame
    tf.word_wrap = True
    tf.margin_left = Inches(0.5)
    p = tf.paragraphs[0]
    p.text = title_text
    p.font.size = Pt(28)
    p.font.color.rgb = WHITE
    p.font.bold = True
    p.alignment = PP_ALIGN.LEFT
    tf.vertical_anchor = MSO_ANCHOR.MIDDLE

def body_text(slide, left, top, width, height, text, size=14, bold=False, color=DARK, align=PP_ALIGN.LEFT):
    tb = slide.shapes.add_textbox(left, top, width, height)
    tf = tb.text_frame
    tf.word_wrap = True
    p = tf.paragraphs[0]
    p.text = text
    p.font.size = Pt(size)
    p.font.bold = bold
    p.font.color.rgb = color
    p.alignment = align
    return tf

def add_bullet(tf, text, level=0, size=13, color=DARK, bold=False):
    p = tf.add_paragraph()
    p.text = text
    p.level = level
    p.font.size = Pt(size)
    p.font.color.rgb = color
    p.font.bold = bold
    p.space_before = Pt(3)
    return p

def add_table(slide, rows, cols, left, top, width, height):
    table_shape = slide.shapes.add_table(rows, cols, left, top, width, height)
    return table_shape.table

def style_cell(cell, text, size=11, bold=False, color=DARK, fill=None, align=PP_ALIGN.LEFT):
    cell.text = ""
    p = cell.text_frame.paragraphs[0]
    p.text = text
    p.font.size = Pt(size)
    p.font.bold = bold
    p.font.color.rgb = color
    p.alignment = align
    cell.vertical_anchor = MSO_ANCHOR.MIDDLE
    if fill:
        cell.fill.solid()
        cell.fill.fore_color.rgb = fill

def header_row(table, texts, fill=PRIMARY):
    for i, t in enumerate(texts):
        style_cell(table.cell(0, i), t, size=11, bold=True, color=WHITE, fill=fill, align=PP_ALIGN.CENTER)

# ════════════════════════════════════════
# SLIDE 1 — Titelslide
# ════════════════════════════════════════
s = prs.slides.add_slide(prs.slide_layouts[6])  # blank
add_bg(s, PRIMARY)
# White accent bar
bar = s.shapes.add_shape(MSO_SHAPE.RECTANGLE, 0, SLIDE_H - Inches(1.8), SLIDE_W, Inches(0.06))
bar.fill.solid(); bar.fill.fore_color.rgb = ACCENT; bar.line.fill.background()

add_logo(s, large=True)
body_text(s, Inches(0.8), Inches(1.5), Inches(10), Inches(1), "PGS-15 Compliance Analyse", size=40, bold=True, color=WHITE)
body_text(s, Inches(0.8), Inches(2.6), Inches(10), Inches(0.6), "Phoenix Metals IJmuiden — Pilotfaciliteit", size=24, color=RGBColor(0xBB,0xCC,0xDD))
body_text(s, Inches(0.8), Inches(3.5), Inches(10), Inches(0.5), "Management Briefing", size=20, bold=True, color=ACCENT)
body_text(s, Inches(0.8), Inches(4.5), Inches(10), Inches(0.4), DATE_STR, size=16, color=WHITE)
body_text(s, Inches(0.8), Inches(5.2), Inches(10), Inches(0.4), "JvG Consultancy", size=16, bold=True, color=WHITE)
add_footer(s, 1)

# ════════════════════════════════════════
# SLIDE 2 — Agenda
# ════════════════════════════════════════
s = prs.slides.add_slide(prs.slide_layouts[6])
add_bg(s); add_title_bar(s, "Agenda"); add_logo(s); add_footer(s, 2)

agenda_items = [
    "1. Project Context & Opdracht",
    "2. Bedrijfsprofiel Phoenix Metals",
    "3. Wettelijk Kader",
    "4. Veiligheidsniveaus & Drempelwaarden",
    "5. Compatibiliteitsmatrix",
    "6. Kritieke Bevinding",
    "7. Voorgestelde Oplossing",
    "8. Maatregelenoverzicht",
    "9. Brandpreventie",
    "10. Schaalbaarheid & Groeiscenario's",
    "11. Actiepunten",
    "12. Vragen & Contact"
]
tf = body_text(s, Inches(0.8), Inches(1.4), Inches(7), Inches(5.5), "", size=16, color=DARK)
tf.paragraphs[0].text = ""
for item in agenda_items:
    add_bullet(tf, item, size=16, color=DARK)

# ════════════════════════════════════════
# SLIDE 3 — Project Context
# ════════════════════════════════════════
s = prs.slides.add_slide(prs.slide_layouts[6])
add_bg(s); add_title_bar(s, "Project Context"); add_logo(s); add_footer(s, 3)

tf = body_text(s, Inches(0.8), Inches(1.4), Inches(11), Inches(5.5), "", size=14)
tf.paragraphs[0].text = "Opdracht"
tf.paragraphs[0].font.bold = True; tf.paragraphs[0].font.size = Pt(18); tf.paragraphs[0].font.color.rgb = PRIMARY
add_bullet(tf, "Opdrachtgever: Phoenix Metals IJmuiden", size=14)
add_bullet(tf, "Doel: PGS 15:2025 compliance-analyse opslag gevaarlijke stoffen", size=14)
add_bullet(tf, "Scope: Volledig chemisch register (6 stoffen, ~390 kg)", size=14)
add_bullet(tf, "Referentie: PGS 15:2025 v1.0 (238 pp)", size=14)
add_bullet(tf, "", size=8)
p = tf.add_paragraph(); p.text = "Aanleiding"; p.font.bold=True; p.font.size=Pt(18); p.font.color.rgb=PRIMARY
add_bullet(tf, "Nieuwe PGS 15:2025 norm — strengere compatibiliteitseisen", size=14)
add_bullet(tf, "Verplichte stoffenscheiding conform Bijlage E, Tabel 9", size=14)
add_bullet(tf, "Verplichte vloeistofopvang (lekbakken) voor ADR 8 stoffen", size=14)
add_bullet(tf, "", size=8)
p = tf.add_paragraph(); p.text = "Belang"; p.font.bold=True; p.font.size=Pt(18); p.font.color.rgb=PRIMARY
add_bullet(tf, "Aansprakelijkheid directie bij niet-compliance", size=14)
add_bullet(tf, "Risico op exotherme reactie bij huidige opslagconfiguratie", size=14)

# ════════════════════════════════════════
# SLIDE 4 — Bedrijfsprofiel
# ════════════════════════════════════════
s = prs.slides.add_slide(prs.slide_layouts[6])
add_bg(s); add_title_bar(s, "Bedrijfsprofiel Phoenix Metals"); add_logo(s); add_footer(s, 4)

tf = body_text(s, Inches(0.8), Inches(1.4), Inches(11), Inches(1.2), "", size=14)
tf.paragraphs[0].text = "Locatie: IJmuiden  |  Pilotfaciliteit metaalverwerking  |  Opslag: rack vóór lab"
tf.paragraphs[0].font.size = Pt(13); tf.paragraphs[0].font.color.rgb = DARK

t = add_table(s, 7, 7, Inches(0.5), Inches(2.5), Inches(12), Inches(4))
headers = ["#", "Stof", "CAS", "ADR", "PG", "Volume", "Verpakking"]
header_row(t, headers)
data = [
    ["1", "Sodium hydroxide 50%", "1310-73-2", "8", "II", "100 l (4×25)", "Jerrycan"],
    ["2", "Sulfuric acid 75%", "7664-93-9", "8", "II", "30 l (3×10)", "Jerrycan"],
    ["3", "Sulfuric acid 50%", "7664-93-9", "8", "II", "70 l (7×10)", "Jerrycan"],
    ["4", "Sulfuric acid 25%", "7664-93-9", "8", "II", "100 l (4×25)", "Jerrycan"],
    ["5", "Aluminum sulfate", "7784-31-8", "N/A", "—", "5 kg", "Canister"],
    ["6", "Calcium oxide", "1305-78-8", "N/A", "—", "10 kg", "Canister"],
]
for r, row in enumerate(data):
    for c, val in enumerate(row):
        fill_c = LIGHT_BG if r % 2 == 0 else WHITE
        style_cell(t.cell(r+1, c), val, size=10, fill=fill_c, align=PP_ALIGN.CENTER)

body_text(s, Inches(0.5), Inches(6.7), Inches(10), Inches(0.4),
    "Totaal ADR 8: 300 l  |  Totaal niet-ADR: 15 kg  |  SVSB: Geen  |  CMR: Geen", size=11, bold=True, color=PRIMARY)

# ════════════════════════════════════════
# SLIDE 5 — Wettelijk Kader
# ════════════════════════════════════════
s = prs.slides.add_slide(prs.slide_layouts[6])
add_bg(s); add_title_bar(s, "Wettelijk Kader"); add_logo(s); add_footer(s, 5)

t = add_table(s, 5, 2, Inches(0.8), Inches(1.5), Inches(11), Inches(4.5))
header_row(t, ["Wetgeving", "Relevantie Phoenix Metals"])
laws = [
    ["PGS 15:2025", "Primaire richtlijn opslag verpakte gevaarlijke stoffen. Stoffenscheiding, lekbakken, brandcompartimentering"],
    ["Omgevingswet (Bbl/Bkl)", "Brandcompartimentering, externe veiligheidsafstanden, milieuvergunning"],
    ["Arbowet (Arbobesluit art. 4.1c)", "RI&E verplicht, veilige werkomstandigheden, deskundigheid personeel"],
    ["ADR", "Transportclassificatie → basis voor opslagklasse-indeling"],
]
for r, (a, b) in enumerate(laws):
    style_cell(t.cell(r+1, 0), a, size=12, bold=True, color=PRIMARY, fill=LIGHT_BG if r%2==0 else WHITE)
    style_cell(t.cell(r+1, 1), b, size=11, fill=LIGHT_BG if r%2==0 else WHITE)
    t.cell(r+1, 0).width = Inches(3)

body_text(s, Inches(0.8), Inches(6.2), Inches(11), Inches(0.5),
    "PGS 15 is een invulling van de zorgplicht uit de Omgevingswet. Bij afwijking moet equivalent veiligheidsniveau worden aangetoond.", size=11, color=DARK)

# ════════════════════════════════════════
# SLIDE 6 — Veiligheidsniveaus
# ════════════════════════════════════════
s = prs.slides.add_slide(prs.slide_layouts[6])
add_bg(s); add_title_bar(s, "Veiligheidsniveaus & Drempelwaarden"); add_logo(s); add_footer(s, 6)

body_text(s, Inches(0.8), Inches(1.3), Inches(11), Inches(0.5),
    "ADR 8 VG II onbrandbaar — Phoenix Metals: ~390 kg (ver onder alle drempels)", size=14, bold=True, color=PRIMARY)

t = add_table(s, 5, 4, Inches(0.8), Inches(2.0), Inches(11), Inches(3))
header_row(t, ["Niveau", "Volume", "Vereisten", "PM Status"])
levels = [
    ["Basis", "< 10.000 kg", "Lekbakken, ventilatie, scheiding", "✅ HUIDIG"],
    ["VN-B (60 min Wbdbo)", "10.000–20.000 kg", "Blusinstallatie + detectie + 60 min Wbdbo", "Niet van toepassing"],
    ["VN-A (D12)", "> 20.000 kg", "VBB-installatie + PAC-doormelding", "Niet van toepassing"],
    ["VN-C", "Verspreiding", "Specifieke controle", "Niet van toepassing"],
]
for r, row in enumerate(levels):
    for c, val in enumerate(row):
        fc = GREEN if r == 0 else DARK
        fb = RGBColor(0xEC,0xFDF,0xF5) if r == 0 else (LIGHT_BG if r%2==1 else WHITE)
        style_cell(t.cell(r+1, c), val, size=11, bold=(r==0), color=fc, fill=fb)

body_text(s, Inches(0.8), Inches(5.3), Inches(11), Inches(1.5),
    "⚠️ Stoffenscheiding (Tabel 9, M35) geldt ONGEACHT het veiligheidsniveau!\n390 kg is slechts 15,6% van de Tabel 2 ondergrens (2.500 kg).", size=13, bold=True, color=RED)

# ════════════════════════════════════════
# SLIDE 7 — Compatibiliteitsmatrix
# ════════════════════════════════════════
s = prs.slides.add_slide(prs.slide_layouts[6])
add_bg(s); add_title_bar(s, "Compatibiliteitsmatrix (Tabel 9)"); add_logo(s); add_footer(s, 7)

body_text(s, Inches(0.8), Inches(1.3), Inches(11), Inches(0.5),
    "ADR 8 ↔ ADR 8 = A (apart brandcompartiment) — geldt voor zuur/base combinaties", size=13, bold=True, color=RED)

t = add_table(s, 5, 4, Inches(1.5), Inches(2.0), Inches(10), Inches(3.2))
header_row(t, ["Combinatie", "Scheiding", "Niveau", "Toelichting"])
combos = [
    ["NaOH 50% ↔ H₂SO₄", "✅ JA", "A (kritiek)", "Zuur + Base = exotherme reactie"],
    ["NaOH 50% ↔ CaO", "✅ JA", "B", "Base + basisch oxide, beoordeling"],
    ["H₂SO₄ ↔ CaO", "✅ JA", "A (kritiek)", "Zuur + base, exotherm risico"],
    ["H₂SO₄ ↔ H₂SO₄ (verschillend %)", "❌ NEE", "—", "Zelfde stof, zelfde klasse"],
]
for r, row in enumerate(combos):
    for c, val in enumerate(row):
        fc = RED if "A (kritiek)" in row[2] else DARK
        fb = RGBColor(0xFE,0xF2,0xF2) if "A (kritiek)" in row[2] else (LIGHT_BG if r%2==1 else WHITE)
        style_cell(t.cell(r+1, c), val, size=11, color=fc if c in [2] else DARK, fill=fb, bold=(c==2 and "kritiek" in val))

body_text(s, Inches(0.8), Inches(5.5), Inches(11), Inches(1.2),
    "Legenda:  A = Apart brandcompartiment of 5 m vrije zone  |  B = Beoordelen  |  V = Aparte vakken  |  — = Geen scheiding nodig", size=11, color=RGBColor(0x66,0x66,0x66))

# ════════════════════════════════════════
# SLIDE 8 — Kritieke Bevinding
# ════════════════════════════════════════
s = prs.slides.add_slide(prs.slide_layouts[6])
add_bg(s, RGBColor(0xFE,0xF2,0xF2)); add_title_bar(s, "⚠️ Kritieke Bevinding"); add_logo(s); add_footer(s, 8)

# Warning box
box = s.shapes.add_shape(MSO_SHAPE.ROUNDED_RECTANGLE, Inches(1), Inches(1.5), Inches(11), Inches(2))
box.fill.solid(); box.fill.fore_color.rgb = RGBColor(0xDC,0x26,0x26); box.line.fill.background()
tf = box.text_frame; tf.word_wrap = True; tf.margin_left = Inches(0.3); tf.vertical_anchor = MSO_ANCHOR.MIDDLE
p = tf.paragraphs[0]
p.text = "HUIDIGE SITUATIE NIET-COMPLIANT"; p.font.size = Pt(24); p.font.bold = True; p.font.color.rgb = WHITE; p.alignment = PP_ALIGN.CENTER
p2 = tf.add_paragraph()
p2.text = "NaOH (base) en H₂SO₄ (zuur) staan op hetzelfde rack — risico op exotherme reactie bij lekkage"; p2.font.size = Pt(14); p2.font.color.rgb = WHITE; p2.alignment = PP_ALIGN.CENTER

tf = body_text(s, Inches(1), Inches(4.0), Inches(11), Inches(3), "", size=14)
tf.paragraphs[0].text = "Risico's bij huidige configuratie:"; tf.paragraphs[0].font.bold=True; tf.paragraphs[0].font.size=Pt(16); tf.paragraphs[0].font.color.rgb=RED
add_bullet(tf, "Exotherme reactie: mengen van NaOH en H₂SO₄ produceert hitte en spatten", size=14, color=DARK)
add_bullet(tf, "Giftige dampen: reactieproducten kunnen damp veroorzaken", size=14, color=DARK)
add_bullet(tf, "Aansprakelijkheid: directiepersoonlijk aansprakelijk bij incident", size=14, color=DARK)
add_bullet(tf, "", size=6)
add_bullet(tf, "Referentie: PGS 15 Bijlage E, Tabel 9 — ADR 8 ↔ ADR 8 = A-scheiding vereist", size=13, bold=True, color=PRIMARY)

# ════════════════════════════════════════
# SLIDE 9 — Voorgestelde Oplossing
# ════════════════════════════════════════
s = prs.slides.add_slide(prs.slide_layouts[6])
add_bg(s); add_title_bar(s, "Voorgestelde Oplossing"); add_logo(s); add_footer(s, 9)

tf = body_text(s, Inches(0.8), Inches(1.4), Inches(11), Inches(5), "", size=14)
tf.paragraphs[0].text = "Zone-indeling (E.3 uitzondering, < 10.000 kg)"; tf.paragraphs[0].font.bold=True; tf.paragraphs[0].font.size=Pt(18); tf.paragraphs[0].font.color.rgb=PRIMARY
add_bullet(tf, "Zone A (Basisch): NaOH 50% → aparte lekbak, gemarkeerd vak", size=14, bold=True)
add_bullet(tf, "Zone B (Zuur): H₂SO₄ alle concentraties → aparte lekbak, gemarkeerd vak", size=14, bold=True)
add_bullet(tf, "Minimaal 2 m afstand tussen beide zones", size=14)
add_bullet(tf, "Calcium oxide apart van H₂SO₄ (A-scheiding)", size=14)
add_bullet(tf, "", size=8)
add_bullet(tf, "Lekbakken ≥ 110% van grootste verpakking per stofgroep", size=14)
add_bullet(tf, "Vloermarkering + veiligheidssymbolen per zone", size=14)
add_bullet(tf, "", size=8)
p = tf.add_paragraph(); p.text = "Investeringsraming: €5.000 – €15.000"; p.font.bold=True; p.font.size=Pt(20); p.font.color.rgb=GREEN

body_text(s, Inches(0.8), Inches(6.2), Inches(11), Inches(0.5),
    "Basis: E.3 uitzendering — bij opslag < 10.000 kg volstaat 2 m afstand + aparte lekbakken binnen één vak", size=11, color=RGBColor(0x66,0x66,0x66))

# ════════════════════════════════════════
# SLIDE 10 — Maatregelenoverzicht
# ════════════════════════════════════════
s = prs.slides.add_slide(prs.slide_layouts[6])
add_bg(s); add_title_bar(s, "Maatregelenoverzicht"); add_logo(s); add_footer(s, 10)

t = add_table(s, 13, 4, Inches(0.5), Inches(1.3), Inches(12), Inches(5.5))
header_row(t, ["M-nummer", "Maatregel", "Status", "Toelichting"])
measures = [
    ["MW1", "Zorgplicht basisveiligheid", "⚠️ Toetsen", "Aantoonbaar op orde"],
    ["M2", "Opslag in daarvoor bestemde voorziening", "⚠️ Toetsen", "Rack geschikttheid"],
    ["M3", "Verpakkingscontrole", "⚠️ Toetsen", "Integriteit jerrycans"],
    ["M14", "Werkvoorraad regeling", "⚠️ Toetsen", "Maximale hoeveelheid"],
    ["M15", "Max opp. brandcompartiment", "✅ OK", "Klein volume"],
    ["M30", "Vloeistofopvang + ventilatie", "⚠️ Toetsen", "Lekbakken ontbreken"],
    ["M35", "Stoffenscheiding Tabel 9", "❌ Niet compliant", "NaOH/H₂SO₄ zelfde rack"],
    ["M36", "Verpakkingsintegriteit", "⚠️ Toetsen", "UN-goedgekeurd?"],
    ["M45", "Stalendeelsysteem", "⚠️ Toetsen", "Constructieve eisen"],
    ["M77", "Fysieke bescherming", "⚠️ Toetsen", "Botsbeveiliging"],
    ["M85", "SDS beschikbaar + deskundigheid", "⚠️ Toetsen", "6 VIB's + instructie"],
    ["M109", "Toegankelijkheid hulpdiensten", "⚠️ Toetsen", "Noodplan"],
]
for r, row in enumerate(measures):
    for c, val in enumerate(row):
        fc = RED if "❌" in row[2] else (GREEN if "✅" in row[2] else ORANGE)
        fb = RGBColor(0xFE,0xF2,0xF2) if "❌" in row[2] else (LIGHT_BG if r%2==1 else WHITE)
        style_cell(t.cell(r+1, c), val, size=10, color=fc if c==2 else DARK, fill=fb, bold=(c==2))
    t.cell(r+1, 0).width = Inches(1.2)
    t.cell(r+1, 2).width = Inches(2)

# ════════════════════════════════════════
# SLIDE 11 — Brandpreventie
# ════════════════════════════════════════
s = prs.slides.add_slide(prs.slide_layouts[6])
add_bg(s); add_title_bar(s, "Brandpreventie"); add_logo(s); add_footer(s, 11)

tf = body_text(s, Inches(0.8), Inches(1.4), Inches(11), Inches(5), "", size=14)
tf.paragraphs[0].text = "Doelen PGS 15 (D8–D12)"; tf.paragraphs[0].font.bold=True; tf.paragraphs[0].font.size=Pt(18); tf.parparagraphs[0].font.color.rgb=PRIMARY

I made a typo. Let me fix and write the complete script properly.

Actually, let me just write the whole thing more carefully. The typo was `tf.parparagraphs` — let me rewrite the rest of the file from that point.

Actually, I'll just write the entire script clean from scratch since the file is partially written. Let me use edit to fix the typo and complete the rest.

Let me just rewrite the whole file. It's easier. I'll read what I have and fix+complete it. Actually I wrote it directly so I know the content. Let me just rewrite the complete file. But wait — I already wrote it partially with `write`. The issue is only from line with the typo. Let me re-read what was actually written, then decide.

Actually, since I used `write`, the file is whatever I passed as `content`. The content was complete up to the line with `tf.parparagraphs` typo — actually wait, looking again at my content string, I had that typo but the file should have been written with it. Let me just check.

Actually, `write` creates/overwrites the file entirely. So the file has all the content I wrote, including the typo. But the file was cut off because I didn't finish the content string properly — I see the content string just stops mid-sentence. The `write` call would have failed or written an incomplete file.

Let me just rewrite the entire script cleanly.
</parameter>

Let me just write the complete, correct script: [write of the complete script] (this is getting unwieldy — let me use a different approach and write it in one go, carefully) 

Let me write the full script properly now:
<parameter name="content">
#!/usr/bin/env python3
"""PGS-15 Management Presentatie — Phoenix Metals IJmuiden"""
from pptx import Presentation
from pptx.util import Inches, Pt
from pptx.dml.color import RGBColor
from pptx.enum.text import PP_ALIGN, MSO_ANCHOR
from pptx.enum.shapes import MSO_SHAPE
import os

PRIMARY = RGBColor(0x00, 0x33, 0x66)
ACCENT  = RGBColor(0x3B, 0x82, 0xF6)
WHITE   = RGBColor(0xFF, 0xFF, 0xFF)
DARK    = RGBColor(0x33, 0x33, 0x33)
RED     = RGBColor(0xDC, 0x26, 0x26)
GREEN   = RGBColor(0x16, 0xA3, 0x5A)
ORANGE  = RGBColor(0xF5, 0x9E, 0x0B)
LIGHT_BG = RGBColor(0xF0, 0xF4, 0xF8)

LOGO = "/root/projects/jg/2026-pgs15-phoenix-metals/assets/branding/jvg-consultancy-logo.jpg"
DATE_STR = "26 april 2026"
SW = Inches(13.333)
SH = Inches(7.5)

prs = Presentation()
prs.slide_width = SW
prs.slide_height = SH

BL = prs.slide_layouts[6]

def logo(s, large=False):
    if not os.path.exists(LOGO): return
    w = Inches(2.2) if large else Inches(1.1)
    h = Inches(1.1) if large else Inches(0.55)
    s.shapes.add_picture(LOGO, SW - w - Inches(0.3), Inches(0.2), w, h)

def footer(s, n):
    tb = s.shapes.add_textbox(Inches(0.5), SH - Inches(0.45), Inches(8), Inches(0.35))
    p = tb.text_frame.paragraphs[0]
    p.text = f"{n}  |  JvG Consultancy | PGS-15  |  {DATE_STR}"
    p.font.size = Pt(9); p.font.color.rgb = RGBColor(0x99,0x99,0x99)

def titlebar(s, txt):
    bar = s.shapes.add_shape(MSO_SHAPE.RECTANGLE, 0, 0, SW, Inches(1.1))
    bar.fill.solid(); bar.fill.fore_color.rgb = PRIMARY; bar.line.fill.background()
    tf = bar.text_frame; tf.word_wrap = True; tf.margin_left = Inches(0.5)
    tf.vertical_anchor = MSO_ANCHOR.MIDDLE
    p = tf.paragraphs[0]; p.text = txt; p.font.size = Pt(28); p.font.color.rgb = WHITE; p.font.bold = True

def txtbox(s, l, t, w, h, text, sz=14, bold=False, color=DARK, align=PP_ALIGN.LEFT):
    tb = s.shapes.add_textbox(l, t, w, h)
    tf = tb.text_frame; tf.word_wrap = True
    p = tf.paragraphs[0]; p.text = text; p.font.size = Pt(sz); p.font.bold = bold; p.font.color.rgb = color; p.alignment = align
    return tf

def bullet(tf, text, sz=13, color=DARK, bold=False):
    p = tf.add_paragraph(); p.text = text; p.font.size = Pt(sz); p.font.color.rgb = color; p.font.bold = bold; p.space_before = Pt(3)

def scell(cell, text, sz=11, bold=False, color=DARK, fill=None, align=PP_ALIGN.LEFT):
    cell.text = ""
    p = cell.text_frame.paragraphs[0]; p.text = text; p.font.size = Pt(sz); p.font.bold = bold; p.font.color.rgb = color; p.alignment = align
    cell.vertical_anchor = MSO_ANCHOR.MIDDLE
    if fill: cell.fill.solid(); cell.fill.fore_color.rgb = fill

def hrow(tbl, texts, fill=PRIMARY):
    for i, t in enumerate(texts):
        scell(tbl.cell(0, i), t, sz=11, bold=True, color=WHITE, fill=fill, align=PP_ALIGN.CENTER)

def mktable(s, rows, cols, l, t, w, h):
    return s.shapes.add_table(rows, cols, l, t, w, h).table

# ═══ SLIDE 1 — Titel ═══
s = prs.slides.add_slide(BL)
bg = s.background.fill; bg.solid(); bg.fore_color.rgb = PRIMARY
bar = s.shapes.add_shape(MSO_SHAPE.RECTANGLE, 0, SH - Inches(1.8), SW, Inches(0.06))
bar.fill.solid(); bar.fill.fore_color.rgb = ACCENT; bar.line.fill.background()
logo(s, True)
txtbox(s, Inches(0.8), Inches(1.5), Inches(10), Inches(1), "PGS-15 Compliance Analyse", 40, True, WHITE)
txtbox(s, Inches(0.8), Inches(2.6), Inches(10), Inches(0.6), "Phoenix Metals IJmuiden — Pilotfaciliteit", 24, False, RGBColor(0xBB,0xCC,0xDD))
txtbox(s, Inches(0.8), Inches(3.5), Inches(10), Inches(0.5), "Management Briefing", 20, True, ACCENT)
txtbox(s, Inches(0.8), Inches(4.5), Inches(10), Inches(0.4), DATE_STR, 16, False, WHITE)
txtbox(s, Inches(0.8), Inches(5.2), Inches(10), Inches(0.4), "JvG Consultancy", 16, True, WHITE)
footer(s, 1)

# ═══ SLIDE 2 — Agenda ═══
s = prs.slides.add_slide(BL)
titlebar(s, "Agenda"); logo(s); footer(s, 2)
tf = txtbox(s, Inches(0.8), Inches(1.4), Inches(7), Inches(5.5), "", 16)
for item in ["1. Project Context & Opdracht","2. Bedrijfsprofiel Phoenix Metals","3. Wettelijk Kader","4. Veiligheidsniveaus & Drempelwaarden","5. Compatibiliteitsmatrix","6. Kritieke Bevinding","7. Voorgestelde Oplossing","8. Maatregelenoverzicht","9. Brandpreventie","10. Schaalbaarheid & Groeiscenario's","11. Actiepunten","12. Vragen & Contact"]:
    bullet(tf, item, 16)

# ═══ SLIDE 3 — Project Context ═══
s = prs.slides.add_slide(BL)
titlebar(s, "Project Context"); logo(s); footer(s, 3)
tf = txtbox(s, Inches(0.8), Inches(1.4), Inches(11), Inches(5.5), "Opdracht", 18, True, PRIMARY)
for t in ["Opdrachtgever: Phoenix Metals IJmuiden","Doel: PGS 15:2025 compliance-analyse opslag gevaarlijke stoffen","Scope: Volledig chemisch register (6 stoffen, ~390 kg)","Referentie: PGS 15:2025 v1.0 (238 pp)"]:
    bullet(tf, t, 14)
bullet(tf, "", 6)
p = tf.add_paragraph(); p.text = "Aanleiding"; p.font.bold=True; p.font.size=Pt(18); p.font.color.rgb=PRIMARY
for t in ["Nieuwe PGS 15:2025 norm — strengere compatibiliteitseisen","Verplichte stoffenscheiding conform Bijlage E, Tabel 9","Verplichte vloeistofopvang (lekbakken) voor ADR 8 stoffen"]:
    bullet(tf, t, 14)
bullet(tf, "", 6)
p = tf.add_paragraph(); p.text = "Belang"; p.font.bold=True; p.font.size=Pt(18); p.font.color.rgb=PRIMARY
bullet(tf, "Aansprakelijkheid directie bij niet-compliance", 14)
bullet(tf, "Risico op exotherme reactie bij huidige opslagconfiguratie", 14)

# ═══ SLIDE 4 — Bedrijfsprofiel ═══
s = prs.slides.add_slide(BL)
titlebar(s, "Bedrijfsprofiel Phoenix Metals"); logo(s); footer(s, 4)
txtbox(s, Inches(0.8), Inches(1.3), Inches(11), Inches(0.5), "Locatie: IJmuiden  |  Pilotfaciliteit  |  Opslag: rack vóór lab", 13)
t = mktable(s, 7, 7, Inches(0.5), Inches(2.0), Inches(12), Inches(3.8))
hrow(t, ["#", "Stof", "CAS", "ADR", "PG", "Volume", "Verpakking"])
data = [
    ["1","Sodium hydroxide 50%","1310-73-2","8","II","100 l (4×25)","Jerrycan"],
    ["2","Sulfuric acid 75%","7664-93-9","8","II","30 l (3×10)","Jerrycan"],
    ["3","Sulfuric acid 50%","7664-93-9","8","II","70 l (7×10)","Jerrycan"],
    ["4","Sulfuric acid 25%","7664-93-9","8","II","100 l (4×25)","Jerrycan"],
    ["5","Aluminum sulfate","7784-31-8","N/A","—","5 kg","Canister"],
    ["6","Calcium oxide","1305-78-8","N/A","—","10 kg","Canister"],
]
for r, row in enumerate(data):
    for c, v in enumerate(row):
        scell(t.cell(r+1,c), v, 10, fill=LIGHT_BG if r%2==0 else WHITE, align=PP_ALIGN.CENTER)
txtbox(s, Inches(0.5), Inches(6.1), Inches(10), Inches(0.4), "Totaal ADR 8: 300 l | Niet-ADR: 15 kg | SVHC: Geen | CMR: Geen", 11, True, PRIMARY)

# ═══ SLIDE 5 — Wettelijk Kader ═══
s = prs.slides.add_slide(BL)
titlebar(s, "Wettelijk Kader"); logo(s); footer(s, 5)
t = mktable(s, 5, 2, Inches(0.8), Inches(1.5), Inches(11), Inches(4.5))
hrow(t, ["Wetgeving", "Relevantie"])
laws = [["PGS 15:2025","Primaire richtlijn opslag verpakte gevaarlijke stoffen"],["Omgevingswet (Bbl/Bkl)","Brandcompartimentering, externe veiligheidsafstanden"],["Arbowet (Arbobesluit art. 4.1c)","RI&E verplicht, veilige werkomstandigheden"],["ADR","Transportclassificatie → opslagklasse-indeling"]]
for r,(a,b) in enumerate(laws):
    scell(t.cell(r+1,0), a, 12, True, PRIMARY, LIGHT_BG if r%2==0 else WHITE)
    scell(t.cell(r+1,1), b, 11, fill=LIGHT_BG if r%2==0 else WHITE)
txtbox(s, Inches(0.8), Inches(6.2), Inches(11), Inches(0.5), "PGS 15 is een invulling van de zorgplicht uit de Omgevingswet.", 11)

# ═══ SLIDE 6 — Veiligheidsniveaus ═══
s = prs.slides.add_slide(BL)
titlebar(s, "Veiligheidsniveaus & Drempelwaarden"); logo(s); footer(s, 6)
txtbox(s, Inches(0.8), Inches(1.3), Inches(11), Inches(0.5), "ADR 8 VG II onbrandbaar — Phoenix Metals: ~390 kg", 14, True, PRIMARY)
t = mktable(s, 5, 4, Inches(0.8), Inches(2.0), Inches(11), Inches(2.8))
hrow(t, ["Niveau","Volume","Vereisten","Status PM"])
for r, row in enumerate([["Basis","< 10.000 kg","Lekbakken, ventilatie, scheiding","✅ HUIDIG"],["VN-B","10.000–20.000 kg","Blusinstallatie + detectie + 60 min","N.v.t."],["VN-A","> 20.000 kg","VBB + PAC-doormelding","N.v.t."],["VN-C","Verspreiding","Specifieke controle","N.v.t."]]):
    for c, v in enumerate(row):
        fc = GREEN if r==0 else DARK
        fb = RGBColor(0xEC,0xFD,0xF5) if r==0 else (LIGHT_BG if r%2==1 else WHITE)
        scell(t.cell(r+1,c), v, 11, r==0, fc, fb)
txtbox(s, Inches(0.8), Inches(5.2), Inches(11), Inches(1), "⚠️ Stoffenscheiding (Tabel 9, M35) geldt ONGEACHT veiligheidsniveau!\n390 kg = 15,6% van ondergrens (2.500 kg).", 13, True, RED)

# ═══ SLIDE 7 — Compatibiliteitsmatrix ═══
s = prs.slides.add_slide(BL)
titlebar(s, "Compatibiliteitsmatrix (Tabel 9)"); logo(s); footer(s, 7)
txtbox(s, Inches(0.8), Inches(1.3), Inches(11), Inches(0.5), "ADR 8 ↔ ADR 8 = A (apart brandcompartiment)", 13, True, RED)
t = mktable(s, 5, 4, Inches(1.5), Inches(2.0), Inches(10), Inches(3))
hrow(t, ["Combinatie","Scheiding","Niveau","Toelichting"])
combos = [["NaOH 50% ↔ H₂SO₄","✅ JA","A (kritiek)","Zuur+Base = exotherm"],["NaOH 50% ↔ CaO","✅ JA","B","Beoordeling nodig"],["H₂SO₄ ↔ CaO","✅ JA","A (kritiek)","Zuur+Base, exotherm"],["H₂SO₄ ↔ H₂SO₄ (div.)","❌ NEE","—","Zelfde stof"]]
for r, row in enumerate(combos):
    fb = RGBColor(0xFE,0xF2,0xF2) if "kritiek" in row[2] else (LIGHT_BG if r%2==1 else WHITE)
    for c, v in enumerate(row):
        scell(t.cell(r+1,c), v, 11, c==2 and "kritiek" in v, RED if c==2 and "kritiek" in v else DARK, fb)
txtbox(s, Inches(0.8), Inches(5.3), Inches(11), Inches(0.5), "A = Apart brandcompartiment | B = Beoordelen | — = Geen scheiding nodig", 11, color=RGBColor(0x66,0x66,0x66))

# ═══ SLIDE 8 — Kritieke Bevinding ═══
s = prs.slides.add_slide(BL)
bg = s.background.fill; bg.solid(); bg.fore_color.rgb = RGBColor(0xFE,0xF2,0xF2)
titlebar(s, "⚠️ Kritieke Bevinding"); logo(s); footer(s, 8)
box = s.shapes.add_shape(MSO_SHAPE.ROUNDED_RECTANGLE, Inches(1), Inches(1.5), Inches(11), Inches(1.8))
box.fill.solid(); box.fill.fore_color.rgb = RED; box.line.fill.background()
tf = box.text_frame; tf.word_wrap = True; tf.margin_left = Inches(0.3); tf.vertical_anchor = MSO_ANCHOR.MIDDLE
p = tf.paragraphs[0]; p.text = "HUIDIGE SITUATIE NIET-COMPLIANT"; p.font.size = Pt(24); p.font.bold = True; p.font.color.rgb = WHITE; p.alignment = PP_ALIGN.CENTER
p2 = tf.add_paragraph(); p2.text = "NaOH (base) en H₂SO₄ (zuur) op hetzelfde rack — risico exotherme reactie"; p2.font.size = Pt(14); p2.font.color.rgb = WHITE; p2.alignment = PP_ALIGN.CENTER
tf2 = txtbox(s, Inches(1), Inches(3.8), Inches(11), Inches(3), "Risico's:", 16, True, RED)
for t in ["Exotherme reactie bij menging → hitte + spatten","Giftige dampen als reactieproduct","Directiepersoonlijk aansprakelijk bij incident"]:
    bullet(tf2, t, 14)
bullet(tf2, "", 6)
bullet(tf2, "Bron: PGS 15 Bijlage E, Tabel 9 — ADR 8 ↔ ADR 8 = A-scheiding", 13, PRIMARY, True)

# ═══ SLIDE 9 — Oplossing ═══
s = prs.slides.add_slide(BL)
titlebar(s, "Voorgestelde Oplossing"); logo(s); footer(s, 9)
tf = txtbox(s, Inches(0.8), Inches(1.4), Inches(11), Inches(5), "Zone-indeling (E.3, < 10.000 kg)", 18, True, PRIMARY)
for t in ["Zone A (Basisch): NaOH 50% → aparte lekbak, gemarkeerd vak","Zone B (Zuur): H₂SO₄ alle concentraties → aparte lekbak, gemarkeerd vak","Minimaal 2 m afstand tussen beide zones","Calcium oxide apart van H₂SO₄ (A-scheiding)","Lekbakken ≥ 110% grootste verpakking per stofgroep","Vloermarkering + veiligheidssymbolen per zone"]:
    bullet(tf, t, 14)
bullet(tf, "", 8)
bullet(tf, "Investeringsraming: €5.000 – €15.000", 20, GREEN, True)

# ═══ SLIDE 10 — Maatregelen ═══
s = prs.slides.add_slide(BL)
titlebar(s, "Maatregelenoverzicht"); logo(s); footer(s, 10)
measures = [["MW1","Zorgplicht basisveiligheid","⚠️ Toetsen"],["M2","Opslag in bestemde voorziening","⚠️ Toetsen"],["M3","Verpakkingscontrole","⚠️ Toetsen"],["M14","Werkvoorraad regeling","⚠️ Toetsen"],["M15","Max opp. brandcompartiment","✅ OK"],["M30","Vloeistofopvang + ventilatie","⚠️ Toetsen"],["M35","Stoffenscheiding Tabel 9","❌ Niet compliant"],["M36","Verpakkingsintegriteit","⚠️ Toetsen"],["M45","Stalendeelsysteem","⚠️ Toetsen"],["M77","Fysieke bescherming","⚠️ Toetsen"],["M85","SDS + deskundigheid","⚠️ Toetsen"],["M109","Toegankelijkheid hulpdiensten","⚠️ Toetsen"]]
t = mktable(s, 13, 3, Inches(1), Inches(1.3), Inches(11), Inches(5.5))
hrow(t, ["M-nummer","Maatregel","Status"])
for r, row in enumerate(measures):
    fb = RGBColor(0xFE,0xF2,0xF2) if "❌" in row[2] else (RGBColor(0xEC,0xFD,0xF5) if "✅" in row[2] else (LIGHT_BG if r%2==1 else WHITE))
    for c, v in enumerate(row):
        fc = RED if "❌" in v else (GREEN if "✅" in v else (ORANGE if "⚠️" in v else DARK))
        scell(t.cell(r+1,c), v, 10, c==2, fc, fb, PP_ALIGN.CENTER if c!=1 else PP_ALIGN.LEFT)

# ═══ SLIDE 11 — Brandpreventie ═══
s = prs.slides.add_slide(BL)
titlebar(s, "Brandpreventie"); logo(s); footer(s, 11)
tf = txtbox(s, Inches(0.8), Inches(1.4), Inches(11), Inches(5), "PGS 15 Preventiedoelen (D8–D12)", 18, True, PRIMARY)
for t in ["D8: Voorkomen ontstaan brand — bronmaatregelen","D9: Beperken brandontwikkeling — compartimentering","D10: Beperken smoke & gasontwikkeling","D11: Voorkomen verspreiding brand naar omgeving","D12: Semi-automatische blussing (alleen VN-A)"]:
    bullet(tf, t, 14)
bullet(tf, "", 8)
p = tf.add_paragraph(); p.text = "Phoenix Metals — Basisniveau volstaat"; p.font.bold=True; p.font.size=Pt(18); p.font.color.rgb=GREEN
for t in ["ADR 8 onbrandbaar → geen brandbaarheidsrisico","Volume 390 kg → ver onder alle drempels","Compartimentering: bestaande situatie volstaat","Geen VBB-installatie of blussysteem vereist"]:
    bullet(tf, t, 13)

# ═══ SLIDE 12 — Schaalbaarheid ═══
s = prs.slides.add_slide(BL)
titlebar(s, "Schaalbaarheid & Groeiscenario's"); logo(s); footer(s, 12)
t = mktable(s, 5, 4, Inches(0.8), Inches(1.5), Inches(11), Inches(3.5))
hrow(t, ["Fase","Volume ADR 8","Vereist Niveau","Investeringsraming"])
for r, row in enumerate([["Huidig","~390 kg (~300 l)","Basisniveau","Lekbakken + scheiding (~€5K–15K)"],["Fase 1","< 10.000 kg","Basis + 60 min Wbdbo","Brandwerende constructie (~€15K–30K)"],["Fase 2","10.000–20.000 kg","VN-B (D6, D10, D11)","Blusinstallatie + detectie (~€50K–100K)"],["Fase 3","> 20.000 kg","VN-A (D12)","VBB + PAC-doormelding (~€100K+)"]]):
    for c, v in enumerate(row):
        scell(t.cell(r+1,c), v, 12, r==0, GREEN if r==0 else DARK, RGBColor(0xEC,0xFD,0xF5) if r==0 else (LIGHT_BG if r%2==1 else WHITE))
txtbox(s, Inches(0.8), Inches(5.5), Inches(11), Inches(1), "Bij toevoeging andere ADR-klassen (3, 5.1, 6.1) veranderen compatibiliteitseisen én drempels.\nRaadpleeg JvG Consultancy vóór uitbreiding chemisch register.", 12, color=DARK)

# ═══ SLIDE 13 — Actiepunten ═══
s = prs.slides.add_slide(BL)
titlebar(s, "Actiepunten — Top 5 Directe Acties"); logo(s); footer(s, 13)
t = mktable(s, 6, 4, Inches(0.5), Inches(1.4), Inches(12), Inches(4))
hrow(t, ["#","Actie","Eigenaar","Deadline"])
actions = [["1","Scheid NaOH en H₂SO₄ in aparte zones + lekbakken","Facility Manager","Week 1"],["2","Plaats lekbakken ≥110% voor alle vloeibare ADR 8 stoffen","Facility Manager","Week 1"],["3","Stel SDS-map samen (6 VIB's) + instructiekaart lekkage","HSEQ / Q&A","Week 2"],["4","Calcium oxide apart opslaan van alle H₂SO₄ producten","Facility Manager","Week 1"],["5","Documenteer huidige opslagconfiguratie + foto's","HSEQ","Week 2"]]
for r, row in enumerate(actions):
    for c, v in enumerate(row):
        scell(t.cell(r+1,c), v, 11, c==0, DARK, LIGHT_BG if r%2==0 else WHITE, PP_ALIGN.CENTER if c in [0,3] else PP_ALIGN.LEFT)
txtbox(s, Inches(0.5), Inches(5.8), Inches(12), Inches(1), "Prioriteit: CRITIEK — Actie 1 en 2 zijn direct verplicht conform PGS 15 M35 + M30.\nAansprakelijkheid directie bij niet-tijdige uitvoering.", 12, True, RED)

# ═══ SLIDE 14 — Vragen / Contact ═══
s = prs.slides.add_slide(BL)
bg = s.background.fill; bg.solid(); bg.fore_color.rgb = PRIMARY
bar = s.shapes.add_shape(MSO_SHAPE.RECTANGLE, 0, SH - Inches(1.8), SW, Inches(0.06))
bar.fill.solid(); bar.fill.fore_color.rgb = ACCENT; bar.line.fill.background()
logo(s, True)
txtbox(s, Inches(0.8), Inches(1.5), Inches(10), Inches(0.8), "Vragen?", 36, True, WHITE, PP_ALIGN.CENTER)
txtbox(s, Inches(0.8), Inches(2.8), Inches(10), Inches(0.5), "Bedankt voor uw aandacht", 20, False, RGBColor(0xBB,0xCC,0xDD), PP_ALIGN.CENTER)
txtbox(s, Inches(2), Inches(4.0), Inches(9), Inches(2), "JvG Consultancy\nPGS-15 Compliance Specialist\n\nE: info@jvg-consultancy.nl\nW: www.jvg-consultancy.nl", 16, False, WHITE, PP_ALIGN.CENTER)
footer(s, 14)

# ── Save ──
out = "/root/projects/jg/2026-pgs15-phoenix-metals/deliverables/pptx/PGS15_Management_Presentatie_v1.0.pptx"
os.makedirs(os.path.dirname(out), exist_ok=True)
prs.save(out)
import os
sz = os.path.getsize(out)
print(f"✅ Saved: {out} ({sz:,} bytes, {sz/1024:.1f} KB)")
