diff --git a/docs/MANUALE_UTENTE_NIS2_AGILE.docx b/docs/MANUALE_UTENTE_NIS2_AGILE.docx
new file mode 100644
index 0000000..bb9bffa
Binary files /dev/null and b/docs/MANUALE_UTENTE_NIS2_AGILE.docx differ
diff --git a/scripts/genera-manuale-utente.py b/scripts/genera-manuale-utente.py
new file mode 100644
index 0000000..6a3cc05
--- /dev/null
+++ b/scripts/genera-manuale-utente.py
@@ -0,0 +1,407 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+"""Genera il Manuale d'uso di NIS2 Agile in .docx usando solo stdlib (zipfile+XML)."""
+import zipfile, re, datetime
+from xml.sax.saxutils import escape
+
+OUT = "/projects/nis2-agile/docs/MANUALE_UTENTE_NIS2_AGILE.docx"
+
+# ─────────────────────────────────────────────────────────────────────────
+# CONTENUTO DEL MANUALE (DSL: lista di blocchi)
+# ('title', titolo, sottotitolo, riga_meta)
+# ('h1'|'h2'|'h3', testo) | ('p', testo) | ('note', testo)
+# ('ul', [voci]) | ('ol', [voci])
+# ('table', [intestazioni], [[riga],...])
+# ('pb',) page break
+# Nel testo: **grassetto** supportato.
+# ─────────────────────────────────────────────────────────────────────────
+DATE = "11 giugno 2026"
+C = []
+def add(*b): C.append(b)
+
+add('title', "NIS2 Agile", "Manuale d'uso del prodotto",
+ "Versione piattaforma 1.14.0 · Aggiornato all'%s" % DATE)
+
+# ===== INDICE (statico, i numeri di pagina non sono calcolati) =====
+add('h1', "Indice dei contenuti")
+for n in ["1. Introduzione","2. Primi passi (accesso, registrazione, onboarding)",
+ "3. Dashboard","4. Gap Analysis NIS2 (Art. 21)","5. Gap Analysis ACN (Determinazione 164179/2025)",
+ "6. Modello Organizzativo SGSI (ISO 27001/27017/27018)","7. Gestione dei Rischi",
+ "8. Gestione degli Incidenti (Art. 23)","9. Policy e procedure","10. Supply Chain (fornitori)",
+ "11. Formazione","12. Asset","13. Audit & Report","14. Whistleblowing (Art. 32)",
+ "15. Aggiornamenti normativi","16. Knowledge Base e Assistente AI","17. Segnalazioni (feedback)",
+ "18. Impostazioni","19. Amministrazione","20. Integrazioni e API","21. Glossario","22. Riferimenti normativi"]:
+ add('p', n)
+add('pb')
+
+# ===== 1. INTRODUZIONE =====
+add('h1', "1. Introduzione")
+add('h2', "1.1 Che cos'è NIS2 Agile")
+add('p', "NIS2 Agile è una piattaforma SaaS multi-tenant che supporta le aziende nel percorso di conformità alla **Direttiva (UE) 2022/2555 (NIS2)** e al suo recepimento italiano (**D.Lgs. 138/2024**), comprese le **Determinazioni dell'Agenzia per la Cybersicurezza Nazionale (ACN)**. Integra l'intelligenza artificiale (Claude) per gap analysis, generazione di policy, classificazione degli incidenti e suggerimento dei rischi.")
+add('p', "Dalla versione 1.14.0 la piattaforma include anche un modulo guidato per la costruzione del **Modello Organizzativo SGSI secondo ISO/IEC 27001:2022**, con estensioni cloud ISO/IEC 27017:2015 e 27018:2019.")
+add('h2', "1.2 A chi è rivolto")
+add('ul', ["**PMI** che devono adeguarsi agli obblighi NIS2 con risorse limitate;",
+ "**Grandi imprese / Enterprise** con processi di compliance strutturati;",
+ "**Consulenti e CISO** che gestiscono più organizzazioni clienti tramite uno studio (consulting firm)."])
+add('h2', "1.3 Quadro normativo di riferimento")
+add('table', ["Fonte","Ruolo"],
+ [["Direttiva (UE) 2022/2555 (NIS2)","Principi e obblighi europei di cibersicurezza"],
+ ["D.Lgs. 138/2024","Recepimento italiano della NIS2 (obblighi operativi)"],
+ ["Determinazione ACN 164179/2025","Misure di sicurezza di base, classificazione e notifica incidenti (Allegati)"],
+ ["ISO/IEC 27001:2022","Requisiti del Sistema di Gestione della Sicurezza delle Informazioni (best practice)"],
+ ["ISO/IEC 27017:2015 / 27018:2019","Controlli per servizi cloud / protezione PII in cloud (best practice)"]])
+add('note', "Disclaimer: NIS2 Agile è uno strumento di supporto operativo e pre-audit. Non costituisce consulenza legale né parere professionale vincolante, e non rilascia certificazioni ISO. Le valutazioni proposte (perimetro, applicabilità, significatività) vanno confermate con il referente compliance/legale dell'organizzazione.")
+
+# ===== 2. PRIMI PASSI =====
+add('pb'); add('h1', "2. Primi passi")
+add('h2', "2.1 Accesso e indirizzo")
+add('p', "La piattaforma è raggiungibile all'indirizzo **https://nis2.agile.software/**. L'accesso avviene con email e password (autenticazione JWT). Se la tua organizzazione usa il Single Sign-On centralizzato (AgileHub), le credenziali sono condivise tra i prodotti della suite.")
+add('h2', "2.2 Registrazione")
+add('ol', ["Apri la pagina di **Registrazione** e inserisci i dati richiesti (email, password conforme alla policy di sicurezza).",
+ "Al termine vieni indirizzato automaticamente alla procedura di **onboarding** aziendale.",
+ "Se possiedi un **invito/licenza** (token `inv_...`) fornito da un partner, inseriscilo per attivare l'organizzazione pre-configurata."])
+add('h2', "2.3 Recupero password")
+add('p', "Dalla pagina di login usa **Password dimenticata** per ricevere un link di reset via email. Il cambio password effettuato da AgileHub si propaga automaticamente entro pochi minuti grazie al sync SSO.")
+add('h2', "2.4 Onboarding dell'organizzazione")
+add('p', "Il wizard di onboarding crea l'organizzazione e ne determina la classificazione NIS2. Si articola in quattro passi:")
+add('ol', ["**Dati azienda** — inserimento manuale oppure precompilazione tramite **Partita IVA** (lookup automatico) o caricamento della **visura camerale** (estrazione AI dei dati).",
+ "**Verifica e completamento** — settore (ATECO → settore NIS2), numero dipendenti, fatturato, sede, contatti.",
+ "**Profilo utente** — nome, ruolo, telefono.",
+ "**Classificazione NIS2** — la piattaforma propone se il soggetto è **essenziale**, **importante** o **non applicabile** in base a settore e dimensione; è possibile aderire volontariamente."])
+add('note', "La classificazione (essenziale/importante) determina il perimetro applicabile in più moduli, in particolare la Gap Analysis ACN e gli obblighi sugli incidenti. Puoi rivederla in Impostazioni › Classificazione NIS2.")
+add('h2', "2.5 Ruoli e permessi")
+add('table', ["Ruolo","Descrizione"],
+ [["super_admin","Amministratore di piattaforma (accesso a tutte le organizzazioni)"],
+ ["org_admin","Amministratore dell'organizzazione"],
+ ["compliance_manager","Responsabile compliance: gestisce assessment, rischi, policy, SGSI"],
+ ["board_member","Organo direttivo: visione e approvazioni"],
+ ["auditor","Revisore: lettura e compilazione evidenze/controlli"],
+ ["employee","Dipendente: formazione, segnalazioni"],
+ ["consultant","Consulente di studio che opera su più organizzazioni clienti"]])
+add('h2', "2.6 Multi-organizzazione, lingua e aiuto")
+add('ul', ["Chi appartiene a più organizzazioni (es. consulenti) può **cambiare contesto** dall'intestazione/menu.",
+ "L'interfaccia è disponibile in **Italiano** ed **Inglese** (selettore lingua).",
+ "Ogni pagina dispone di **Aiuto contestuale** (icona ?) con guida e riferimenti normativi certi."])
+
+# ===== 3. DASHBOARD =====
+add('pb'); add('h1', "3. Dashboard")
+add('p', "La Dashboard è la pagina iniziale dopo l'accesso e offre una visione d'insieme dello stato di conformità.")
+add('ul', ["**Avanzamento implementazione misure Art. 21 NIS2** — indicatore complessivo (gauge);",
+ "**Scadenze imminenti** — adempimenti e revisioni in arrivo da più moduli;",
+ "**Attività recenti** — ultime azioni tracciate;",
+ "**Heatmap dei rischi** — distribuzione dei rischi su probabilità × impatto;",
+ "**Benchmark settoriale** (anonimizzato) — confronto con il proprio settore;",
+ "**Compliance Journey** — percorso guidato che indica i prossimi passi consigliati."])
+
+# ===== 4. GAP ANALYSIS NIS2 =====
+add('pb'); add('h1', "4. Gap Analysis NIS2 (Art. 21)")
+add('p', "Analisi di **primo livello** sulle 10 categorie di misure dell'Art. 21.2 NIS2, basata su un questionario di 80 domande (10 categorie), ciascuna collegata anche al controllo ISO 27001 corrispondente.")
+add('h2', "4.1 Come si svolge")
+add('ol', ["Crea un nuovo assessment: la piattaforma pre-popola tutte le domande.",
+ "Per ogni domanda indica lo stato: **Attuato**, **Parziale**, **Non attuato**, **Non applicabile**. Le risposte si salvano automaticamente.",
+ "Completa l'assessment per ottenere un **punteggio** per categoria e complessivo.",
+ "Avvia l'**analisi AI** per ricevere sintesi esecutiva, priorità, quick win e una roadmap di conformità."])
+add('note', "Le risposte della Gap Analysis NIS2 alimentano automaticamente il Modello SGSI (capitolo 6): il loro stato pre-popola lo Statement of Applicability ISO 27001.")
+
+# ===== 5. GAP ANALYSIS ACN =====
+add('pb'); add('h1', "5. Gap Analysis ACN (Determinazione 164179/2025)")
+add('p', "Analisi di **secondo livello** sulle misure e i requisiti puntuali stabiliti dall'ACN, articolati secondo il **Framework Nazionale** (funzioni Governo GV, Identificazione ID, Protezione PR, Rilevamento DE, Risposta RS, Ripristino RC).")
+add('table', ["Classificazione","Perimetro applicabile"],
+ [["Soggetto IMPORTANTE (Allegato 1)","37 misure / 87 requisiti"],
+ ["Soggetto ESSENZIALE (Allegato 2)","43 misure / 116 requisiti"]])
+add('ul', ["Il perimetro è filtrato automaticamente in base alla classificazione NIS2 dell'organizzazione;",
+ "scoring per funzione del Framework Nazionale e punteggio complessivo;",
+ "**piano d'azione** dei requisiti non conformi e **analisi AI** ancorata ai 203 requisiti ACN reali (nessun riferimento inventato);",
+ "**Catalogo requisiti** consultabile in sola lettura."])
+
+# ===== 6. MODELLO SGSI ISO 27001 (NUOVO) =====
+add('pb'); add('h1', "6. Modello Organizzativo SGSI (ISO 27001/27017/27018)")
+add('p', "Procedura guidata per costruire il **Sistema di Gestione della Sicurezza delle Informazioni (SGSI / ISMS)** secondo **ISO/IEC 27001:2022** (clausole 4–10) e il relativo **Statement of Applicability (SoA)** sui 93 controlli dell'Annex A. È uno strumento di supporto e pre-audit, non una certificazione.")
+add('h2', "6.1 Il wizard in 6 passi")
+add('table', ["Passo","Clausola ISO 27001","Contenuto"],
+ [["1. Contesto e Ambito","cl. 4","Scope del SGSI, contesto interno/esterno, parti interessate, confini, esclusioni motivate, attivazione estensioni cloud"],
+ ["2. Leadership","cl. 5","Ruoli e responsabilità con matrice RACI (Responsible, Accountable, Consulted, Informed)"],
+ ["3. Risk","cl. 6","Metodologia di risk assessment e obiettivi del SGSI (il registro rischi resta nel modulo Rischi)"],
+ ["4. Statement of Applicability","cl. 6.1.3","Applicabilità, stato e motivazione dei 93 controlli Annex A + estensioni cloud"],
+ ["5. Documented Information","cl. 7–8","Policy e procedure, con bozze generabili dall'AI"],
+ ["6. Monitoraggio e Miglioramento","cl. 9–10","Audit interni e non conformità (moduli Audit & Report e NCR/CAPA); checklist di completamento"]])
+add('h2', "6.2 SoA pre-popolato dalla Gap Analysis NIS2")
+add('p', "Ogni domanda della Gap Analysis NIS2 è collegata a un controllo ISO 27001 (es. A.5.1). Per questo lo Statement of Applicability viene **pre-compilato** a partire dalle risposte NIS2 già date: i controlli con corrispondenza riportano il badge **\"da NIS2\"** e uno stato proposto (Attuato = 100%, Parziale = 50%, Non attuato = 0%). I controlli non coperti dal NIS2 (es. parte dei controlli fisici A.7) restano da compilare manualmente.")
+add('note', "Il pulsante \"Ri-deriva dal NIS2\" aggiunge soltanto i controlli mancanti e non sovrascrive le modifiche manuali già inserite.")
+add('h2', "6.3 Estensioni cloud (condizionali)")
+add('ul', ["**ISO/IEC 27017:2015** — attivala se usi servizi cloud pubblici o sei un fornitore cloud: aggiunge 7 controlli cloud (CLD.*) al SoA;",
+ "**ISO/IEC 27018:2019** — attivala se tratti dati personali (PII) in cloud pubblico come responsabile: aggiunge i controlli privacy (PII.*), sinergici con il GDPR.",
+ "Le sezioni cloud/PII compaiono nel SoA **solo** se attivi i relativi flag nel passo 1."])
+add('h2', "6.4 Documenti e generazione AI")
+add('p', "Nel passo 5 puoi generare bozze di policy e procedure (Policy SGSI, Dichiarazione di Applicabilità, controllo accessi, gestione incidenti, continuità, sicurezza fornitori). Le bozze sono prodotte dall'AI con ancoraggio alle fonti certe e richiedono **revisione umana** prima dell'approvazione.")
+add('h2', "6.5 Esportazione")
+add('p', "Il pulsante **Esporta SGSI** apre una versione stampabile del modello (ambito, metodologia, SoA con stato dei controlli), utile come evidenza in vista di un audit.")
+
+# ===== 7. RISCHI =====
+add('pb'); add('h1', "7. Gestione dei Rischi")
+add('p', "Registro dei rischi con matrice **Probabilità × Impatto 5×5** e supporto AI, conforme all'Art. 21 NIS2 e alla metodologia ISO 27005.")
+add('ul', ["Creazione del rischio con scala probabilità/impatto (dettagli ISO 27005);",
+ "**Piani di trattamento** (mitigare, accettare, trasferire, evitare) e stato di avanzamento;",
+ "**Suggerimento AI** dei rischi per settore e asset (dati anonimizzati);",
+ "Funzioni avanzate: registro quantitativo **FAIR** (calcolo ALE Monte Carlo) e dashboard **KRI**."])
+
+# ===== 8. INCIDENTI =====
+add('pb'); add('h1', "8. Gestione degli Incidenti (Art. 23)")
+add('p', "Gestione del ciclo di vita degli incidenti significativi e degli obblighi di notifica al CSIRT secondo l'Art. 23 e la Determinazione ACN 164179/2025.")
+add('h2', "8.1 Tempistiche di notifica")
+add('table', ["Adempimento","Termine"],
+ [["Pre-allarme (early warning)","entro 24 ore dalla conoscenza"],
+ ["Notifica completa","entro 72 ore dalla conoscenza"],
+ ["Relazione finale","entro 1 mese dalla notifica delle 72 ore"]])
+add('h2', "8.2 Funzioni")
+add('ul', ["**Albero decisionale** per valutare la significatività (utenti ≥ 500, durata > 4h, cross-border, attacco cyber, danni > €100k);",
+ "**timeline** dell'incidente e metriche (triage, contenimento, eradicazione, ripristino);",
+ "invio di **early warning, notifica e relazione finale** al CSIRT;",
+ "**classificazione AI** (tipo IS-1..IS-4, severità) con citazione della fonte (Allegato 3 = importanti, Allegato 4 = essenziali);",
+ "**PIR** (Post-Incident Review) per l'apprendimento."])
+
+# ===== 9. POLICY =====
+add('pb'); add('h1', "9. Policy e procedure")
+add('ul', ["Creazione di policy da **template** o **generazione AI** (bozze marcate da revisionare);",
+ "flusso di **approvazione** e **versioning** con confronto delle versioni (diff);",
+ "**attestazione** di presa visione da parte del personale e relativo tracciamento."])
+add('note', "Le bozze generate dall'AI riportano un banner di avviso: vanno riviste e approvate da un responsabile prima della pubblicazione.")
+
+# ===== 10. SUPPLY CHAIN =====
+add('pb'); add('h1', "10. Supply Chain (fornitori)")
+add('p', "Gestione della sicurezza della catena di approvvigionamento (Art. 21.2.d).")
+add('ul', ["Anagrafica fornitori, categorie e **import** massivo;",
+ "**questionari** configurabili (categorie, template, domande) inviati ai fornitori;",
+ "**portale fornitore** dedicato con accesso separato via OTP/magic-link (autosalvataggio risposte);",
+ "**campagne** di valutazione e cruscotto del rischio fornitori (risk overview)."])
+
+# ===== 11. FORMAZIONE =====
+add('pb'); add('h1', "11. Formazione")
+add('p', "Gestione della formazione e dell'igiene informatica (Art. 21.2.g) e degli obblighi formativi per gli organi direttivi (Art. 20).")
+add('ul', ["Catalogo **corsi** e **assegnazioni** al personale;",
+ "monitoraggio della **compliance formativa** e dei corsi obbligatori non completati."])
+
+# ===== 12. ASSET =====
+add('pb'); add('h1', "12. Asset")
+add('p', "Inventario degli asset informativi e delle dipendenze.")
+add('ul', ["Anagrafica asset e **import** (CMDB/cloud);",
+ "**scoring di rilevanza NIS2** (0–100, criterio GV.OC-04) e classificazione dei sistemi rilevanti;",
+ "**mappa delle dipendenze** tra asset."])
+
+# ===== 13. AUDIT & REPORT =====
+add('pb'); add('h1', "13. Audit & Report")
+add('ul', ["Gestione dei **controlli di conformità** (framework NIS2 / ISO 27001) con stato ed evidenze;",
+ "caricamento **evidenze** e registro dei **log di audit**;",
+ "**mappature**: NIS2 ↔ ISO 27001 e NIST CSF 2.0; **registro dei sistemi rilevanti** (GV.OC-04);",
+ "**report esecutivo** stampabile ed **export CSV**;",
+ "**catena di integrità (hash chain SHA-256)**: ogni voce del log è concatenata alla precedente; verifica integrità ed **export certificato**."])
+
+# ===== 14. WHISTLEBLOWING =====
+add('pb'); add('h1', "14. Whistleblowing (Art. 32)")
+add('p', "Canale per le segnalazioni, anche anonime.")
+add('ul', ["Invio segnalazione (anche **anonima**, con codice di tracciamento);",
+ "assegnazione, gestione e chiusura della segnalazione;",
+ "consultazione anonima dello stato tramite codice di tracciamento."])
+
+# ===== 15. NORMATIVE =====
+add('pb'); add('h1', "15. Aggiornamenti normativi")
+add('ul', ["Feed degli aggiornamenti **NIS2 / ACN / DORA**;",
+ "presa visione (**ACK**) tracciata per ciascun aggiornamento;",
+ "elenco aggiornamenti **in attesa** di presa visione e statistiche."])
+
+# ===== 16. KB & AI =====
+add('pb'); add('h1', "16. Knowledge Base e Assistente AI")
+add('h2', "16.1 Knowledge Base (RAG)")
+add('p', "La Knowledge Base alimenta le risposte dell'AI tramite ricerca semantica (RAG). Prevede tre livelli di visibilità:")
+add('table', ["Livello","Chi possiede","Chi vede"],
+ [["SYSTEM","Fornitore della piattaforma","Tutti gli utenti"],
+ ["FIRM","Studio di consulenza","Collaboratori dello studio + organizzazioni condivise"],
+ ["ORG","Singola organizzazione","Solo gli utenti di quella organizzazione"]])
+add('ul', ["Caricamento documenti (testo) con scelta dello scope;",
+ "ricerca semantica e cancellazione documenti;",
+ "le fonti normative certe (NIS2, D.Lgs. 138/2024, Determinazioni ACN) e i cataloghi **ISO 27001/27002/27017/27018** sono già indicizzati a livello SYSTEM."])
+add('h2', "16.2 Assistente AI")
+add('p', "L'assistente risponde alle domande pescando dalla Knowledge Base e **cita sempre la fonte normativa pertinente**, senza inventare riferimenti. Le risposte sono di orientamento operativo e non sostituiscono il parere legale.")
+
+# ===== 17. FEEDBACK =====
+add('pb'); add('h1', "17. Segnalazioni (feedback)")
+add('p', "Strumento integrato per segnalare bug o suggerimenti di UX. Le segnalazioni vengono classificate dall'AI e, una volta risolte, l'esito può essere comunicato ai membri dell'organizzazione. Ogni segnalazione cattura automaticamente la **versione del prodotto** e la **superficie** (web/mobile) per facilitare la diagnosi.")
+
+# ===== 18. IMPOSTAZIONI =====
+add('pb'); add('h1', "18. Impostazioni")
+add('ul', ["**Organizzazione** — dati, classificazione NIS2;",
+ "**Profilo** — dati personali, cambio password, preferenze;",
+ "**Membri** — invito e gestione degli utenti e dei ruoli;",
+ "**Sessioni** — gestione dei dispositivi collegati (multi-device) e revoca;",
+ "**Branding** (white-label per studi) — personalizzazione per lo studio di consulenza."])
+
+# ===== 19. AMMINISTRAZIONE =====
+add('pb'); add('h1', "19. Amministrazione")
+add('p', "Area riservata al ruolo **super_admin**: gestione delle organizzazioni, degli utenti e statistiche di piattaforma.")
+
+# ===== 20. INTEGRAZIONI E API =====
+add('pb'); add('h1', "20. Integrazioni e API")
+add('ul', ["**Services API** (autenticazione tramite API Key con scope) per integrazioni esterne, es. GRC/231: gap-analysis, misure, incidenti, formazione, scadenze e snapshot completo;",
+ "**Webhook** con firma HMAC-SHA256 e retry, per notifiche verso sistemi terzi;",
+ "**Licenze/inviti B2B** per provisioning di organizzazioni da parte di partner;",
+ "**SSO** centralizzato della suite AgileHub (sincronizzazione password)."])
+
+# ===== 21. GLOSSARIO =====
+add('pb'); add('h1', "21. Glossario")
+add('table', ["Termine","Significato"],
+ [["NIS2","Direttiva (UE) 2022/2555 sulla cibersicurezza"],
+ ["ACN","Agenzia per la Cybersicurezza Nazionale"],
+ ["SGSI / ISMS","Sistema di Gestione della Sicurezza delle Informazioni (ISO 27001)"],
+ ["SoA","Statement of Applicability: dichiarazione di applicabilità dei controlli"],
+ ["Annex A","Elenco dei 93 controlli di sicurezza di ISO/IEC 27001:2022"],
+ ["RACI","Matrice di responsabilità: Responsible, Accountable, Consulted, Informed"],
+ ["CSIRT","Computer Security Incident Response Team (autorità di notifica)"],
+ ["PIR","Post-Incident Review (revisione post-incidente)"],
+ ["RAG","Retrieval-Augmented Generation: AI con recupero da knowledge base"],
+ ["PII","Personally Identifiable Information (dati personali)"],
+ ["Soggetto essenziale / importante","Categorie NIS2 che determinano gli obblighi applicabili"]])
+
+# ===== 22. RIFERIMENTI NORMATIVI =====
+add('pb'); add('h1', "22. Riferimenti normativi")
+add('ul', ["Direttiva (UE) 2022/2555 (NIS2);",
+ "Direttiva (UE) 2022/2557 (CER);",
+ "D.Lgs. 4 settembre 2024, n. 138;",
+ "Determinazione ACN n. 164179 del 14/04/2025 (misure di base, classificazione e notifica incidenti, Allegati);",
+ "Determinazione ACN n. 333017/2025 (piattaforma ACN, designazione rappresentanti);",
+ "ISO/IEC 27001:2022, 27002:2022, 27017:2015, 27018:2019 (best practice, non vincolanti)."])
+add('note', "Questo manuale descrive le funzionalità della piattaforma NIS2 Agile alla versione 1.14.0. Le schermate e le voci di menu possono variare con gli aggiornamenti. Per l'aiuto contestuale usa l'icona ? presente in ogni pagina.")
+
+# ─────────────────────────────────────────────────────────────────────────
+# EMITTER OOXML
+# ─────────────────────────────────────────────────────────────────────────
+def runs(text):
+ """Converte **bold** in run WordprocessingML."""
+ out = []
+ for i, part in enumerate(re.split(r'\*\*', text)):
+ if part == '':
+ continue
+ bold = (i % 2 == 1)
+ rpr = '' if bold else ''
+ out.append('%s%s' % (rpr, escape(part)))
+ return ''.join(out) or ''
+
+def para(text, style=None):
+ ppr = '' % style if style else ''
+ return '%s%s' % (ppr, runs(text))
+
+def listitem(text, numid):
+ return (''
+ '%s' % (numid, runs(text)))
+
+def cell(text, header=False):
+ shd = '' if header else ''
+ t = ('**%s**' % text) if header else text
+ # nelle intestazioni il testo bianco
+ if header:
+ r = '%s' % escape(text)
+ else:
+ r = runs(text)
+ return ('%s%s' % (shd, r))
+
+def table(headers, rows):
+ borders = ('' + ''.join(
+ '' % s
+ for s in ['top','left','bottom','right','insideH','insideV']) + '')
+ tblpr = '%s' % borders
+ out = ['', tblpr]
+ out.append('' + ''.join(cell(h, True) for h in headers) + '')
+ for row in rows:
+ out.append('' + ''.join(cell(c) for c in row) + '')
+ out.append('')
+ out.append('') # spacing after table
+ return ''.join(out)
+
+def title_block(t, sub, meta):
+ return (para(t, 'Title') + para(sub, 'Subtitle') + para(meta, 'Meta'))
+
+body = []
+for b in C:
+ k = b[0]
+ if k == 'title': body.append(title_block(b[1], b[2], b[3]))
+ elif k == 'h1': body.append(para(b[1], 'Heading1'))
+ elif k == 'h2': body.append(para(b[1], 'Heading2'))
+ elif k == 'h3': body.append(para(b[1], 'Heading3'))
+ elif k == 'p': body.append(para(b[1]))
+ elif k == 'note': body.append(para(b[1], 'Note'))
+ elif k == 'ul': body.append(''.join(listitem(x, 1) for x in b[1]))
+ elif k == 'ol': body.append(''.join(listitem(x, 2) for x in b[1]))
+ elif k == 'table': body.append(table(b[1], b[2]))
+ elif k == 'pb': body.append('')
+
+SECT = (''
+ ''
+ '')
+
+document = (''
+ ''
+ '' + ''.join(body) + SECT + '')
+
+STYLES = (''
+ ''
+ ''
+ ''
+ ''
+ ''
+ ''
+ ''
+ ''
+ ''
+ ''
+ ''
+ '')
+
+NUMBERING = (''
+ ''
+ ''
+ ''
+ ''
+ ''
+ '')
+
+CONTENT_TYPES = (''
+ ''
+ ''
+ ''
+ ''
+ ''
+ ''
+ ''
+ '')
+
+RELS = (''
+ ''
+ ''
+ ''
+ '')
+
+DOC_RELS = (''
+ ''
+ ''
+ ''
+ '')
+
+CORE = (''
+ ''
+ 'Manuale d\'uso NIS2 AgileNIS2 Agile'
+ 'NIS2 Agile'
+ '2026-06-11T00:00:00Z'
+ '2026-06-11T00:00:00Z'
+ '')
+
+with zipfile.ZipFile(OUT, 'w', zipfile.ZIP_DEFLATED) as z:
+ z.writestr('[Content_Types].xml', CONTENT_TYPES)
+ z.writestr('_rels/.rels', RELS)
+ z.writestr('word/document.xml', document)
+ z.writestr('word/styles.xml', STYLES)
+ z.writestr('word/numbering.xml', NUMBERING)
+ z.writestr('word/_rels/document.xml.rels', DOC_RELS)
+ z.writestr('docProps/core.xml', CORE)
+
+print("OK ->", OUT)
+print("blocchi:", len(C))