[FEAT] PWA installabile Android/iOS conforme AGID (v1.15.0)

- manifest.webmanifest + service worker (offline shell, /api network-only, asset stale-while-revalidate)
- set icone (192/512 + maskable + apple-touch + favicon), generate zero-deps (pure Node+zlib)
- tag PWA + viewport viewport-fit=cover (zoom mantenuto, WCAG 1.4.4) in 77 pagine HTML
- AGID/WCAG 2.1 AA: touch target >=44px, orientamento/zoom liberi, safe-area standalone
- generatori riproducibili: scripts/gen-pwa-icons.mjs + scripts/inject-pwa-head.mjs
- bump version 1.14.1 -> 1.15.0

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
DevEnv nis2-agile
2026-06-14 21:09:54 +02:00
co-authored by Claude Opus 4.8
parent b80bf2361c
commit 36513fa722
95 changed files with 2050 additions and 78 deletions
+17
View File
@@ -280,6 +280,23 @@ NIS2 Agile e' una piattaforma SaaS multi-tenant per supportare le aziende nella
Target: PMI, Enterprise, Consulenti/CISO. Target: PMI, Enterprise, Consulenti/CISO.
## PWA conforme AGID — v1.15.0 (2026-06-14)
NIS2 e' una **PWA installabile** (Android/Chrome, iOS/iPadOS via "Aggiungi a Home"), responsive, conforme AGID/WCAG 2.1 AA.
**File**:
- `public/manifest.webmanifest` — manifest (theme `#0066CC` blu Italia, `display: standalone`, `orientation: any`, icone any+maskable, shortcuts).
- `public/sw.js` — service worker. Cache `nis2-shell-vX.Y.Z`. **Strategia**: `/api/*` **network-only** (MAI cacheato → no leak cross-utente su device condiviso); navigazioni HTML **network-first** → fallback `/offline.html`; asset statici **stale-while-revalidate**. **Bumpare il nome cache ad ogni release** (e' legato alla versione).
- `public/offline.html` — fallback offline (Bootstrap Italia + CSS inline di riserva).
- `public/js/pwa.js` — registra il SW + banner "Installa app" (Android) + hint "Aggiungi a Home" (iOS), i18n IT/EN (chiave `nis2_lang`).
- `public/assets/icons/*` — set icone (192/512, maskable, apple-touch 180, favicon 16/32, `icon.svg` master).
- `scripts/gen-pwa-icons.mjs` — **genera le icone** senza dipendenze (pure Node + zlib): `node scripts/gen-pwa-icons.mjs`.
- `scripts/inject-pwa-head.mjs` — **inietta i tag PWA** negli `<head>` (idempotente): `node scripts/inject-pwa-head.mjs`. Esclude `offline.html` e i file `* copy`.
**AGID/WCAG**: design system Bootstrap Italia (gia' live); **zoom e orientamento non bloccati**; **touch target ≥44px** (`@media (pointer: coarse)` in `style.css`); safe-area inset in `@media (display-mode: standalone)`. La "Dichiarazione di accessibilita'" AGID e' obbligatoria solo per servizi PA → qui opzionale (non implementata).
**Deploy**: tutto **statico** → live via bind-mount nginx, **nessun `kill -USR2`** (nessun `.php` toccato). Dopo edit a `sw.js`/`pwa.js` o ai tag head ricordarsi il **cache-buster** `?v=` (i tag head usano `pwa.js?v=20260614`) e il bump del nome cache SW.
## Stack Tecnologico ## Stack Tecnologico
- Backend: PHP 8.4 vanilla (no framework, Front Controller pattern) - Backend: PHP 8.4 vanilla (no framework, Front Controller pattern)
- Database: MySQL 8.x (nis2_agile_db) - Database: MySQL 8.x (nis2_agile_db)
+9
View File
@@ -4,6 +4,15 @@
## 2026-06-14 — ✅ SUPERVISORE AUTONOMO TICKET LIVE (cron) + chiusura demo/avatar/feedback ## 2026-06-14 — ✅ SUPERVISORE AUTONOMO TICKET LIVE (cron) + chiusura demo/avatar/feedback
### PWA conforme AGID — v1.15.0 (sessione serale)
NIS2 reso **PWA installabile** su Android (Chrome) e iOS/iPadOS (Safari "Aggiungi a Home"), responsive, **conforme AGID/WCAG 2.1 AA**. Avviato come flotta di agenti in background, completato inline dopo riavvio del processo (gli agenti background erano andati persi).
- **File nuovi**: `public/manifest.webmanifest` (theme `#0066CC` blu Italia, display standalone, orientation any, shortcuts Dashboard/Incidenti) · `public/sw.js` · `public/offline.html` · `public/js/pwa.js` (register SW + banner installazione Android + hint iOS, i18n IT/EN) · `public/assets/icons/*` (icon-192/512 + maskable + apple-touch 180 + favicon 16/32 + `icon.svg` master) · `scripts/gen-pwa-icons.mjs` (generatore icone zero-deps, pure Node+zlib) · `scripts/inject-pwa-head.mjs` (iniezione idempotente tag head).
- **Service worker**: cache `nis2-shell-v1.15.0`; `/api/*` **network-only** (no leak cross-utente su device condiviso), navigazioni HTML **network-first** → `offline.html`, asset **stale-while-revalidate**. Bumpare il nome cache ad ogni release.
- **Head**: tag PWA iniettati in **77 HTML** (64 + 6 admin + 7 subdir, escluso `offline.html`); viewport normalizzato a `viewport-fit=cover` **mantenendo lo zoom** (WCAG 1.4.4).
- **AGID/WCAG**: Bootstrap Italia (già live), zoom+orientamento liberi, **touch target ≥44px** (`@media (pointer: coarse)` in `style.css`), safe-area in standalone. "Dichiarazione di accessibilità" obbligatoria solo per PA → opzionale, non implementata.
- **Rigenerare**: `node scripts/gen-pwa-icons.mjs` (icone) · `node scripts/inject-pwa-head.mjs` (tag head, idempotente). Tutto **statico** → live via bind-mount, nessun USR2.
- Bump `version.json` 1.14.1 → **1.15.0**. **commit/push in attesa di conferma utente** al momento del salvataggio.
### Supervisore autonomo ticket (lavoro principale di oggi) ### Supervisore autonomo ticket (lavoro principale di oggi)
NIS2 = **primo adopter LIVE** dello standard AgileHub `autonomous-supervisor-agent` (`hub_standards` id=32). Un agente `claude -p --model opus` headless (chiave SSH **effimera per ciclo**) fa da supervisore **end-to-end** ai ticket NIS2 → **NIS2 esce dal `ticket-agent-cron` generico**. NIS2 = **primo adopter LIVE** dello standard AgileHub `autonomous-supervisor-agent` (`hub_standards` id=32). Un agente `claude -p --model opus` headless (chiave SSH **effimera per ciclo**) fa da supervisore **end-to-end** ai ticket NIS2 → **NIS2 esce dal `ticket-agent-cron` generico**.
- **Cron LIVE**: `/etc/cron.d/nis2-supervisor` → `17 */4 * * *` (ogni 4h, minuto 17). **Kill switch**: `touch /etc/agilehub/supervisor-nis2.disabled`. **Rollback**: `rm /etc/cron.d/nis2-supervisor`. Audit: `/var/log/nis2-supervisor-audit.jsonl`. - **Cron LIVE**: `/etc/cron.d/nis2-supervisor` → `17 */4 * * *` (ogni 4h, minuto 17). **Kill switch**: `touch /etc/agilehub/supervisor-nis2.disabled`. **Rollback**: `rm /etc/cron.d/nis2-supervisor`. Audit: `/var/log/nis2-supervisor-audit.jsonl`.
+14 -1
View File
@@ -2,7 +2,7 @@
<html lang="it"> <html lang="it">
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
<title>Demo Sidebar BI - NIS2 Agile</title> <title>Demo Sidebar BI - NIS2 Agile</title>
<!-- Bootstrap Italia v2.18.1 SELF-HOSTATO da /vendor (regola "MAI CDN") --> <!-- Bootstrap Italia v2.18.1 SELF-HOSTATO da /vendor (regola "MAI CDN") -->
@@ -23,6 +23,19 @@
.demo-note h1 { font-size: 1.25rem; margin: 0 0 8px; color: #17324d; } .demo-note h1 { font-size: 1.25rem; margin: 0 0 8px; color: #17324d; }
.demo-note p { margin: 0; color: #5b6772; font-size: .9rem; } .demo-note p { margin: 0; color: #5b6772; font-size: .9rem; }
</style> </style>
<!-- PWA:start -->
<link rel="manifest" href="/manifest.webmanifest">
<meta name="theme-color" content="#0066CC">
<link rel="icon" type="image/png" sizes="32x32" href="/assets/icons/favicon-32.png">
<link rel="icon" type="image/png" sizes="16x16" href="/assets/icons/favicon-16.png">
<link rel="apple-touch-icon" sizes="180x180" href="/assets/icons/apple-touch-icon.png">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="default">
<meta name="apple-mobile-web-app-title" content="NIS2 Agile">
<meta name="application-name" content="NIS2 Agile">
<script src="/js/pwa.js?v=20260614" defer></script>
<!-- PWA:end -->
</head> </head>
<body> <body>
<div class="app-shell"> <div class="app-shell">
+14 -1
View File
@@ -2,10 +2,23 @@
<html lang="it"> <html lang="it">
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
<title>Bootstrap Italia self-host — smoke test</title> <title>Bootstrap Italia self-host — smoke test</title>
<!-- SELF-HOSTED Bootstrap Italia v2.18.1 — asset LOCALI da /vendor, ZERO CDN --> <!-- SELF-HOSTED Bootstrap Italia v2.18.1 — asset LOCALI da /vendor, ZERO CDN -->
<link rel="stylesheet" href="/vendor/bootstrap-italia/dist/css/bootstrap-italia.min.css"> <link rel="stylesheet" href="/vendor/bootstrap-italia/dist/css/bootstrap-italia.min.css">
<!-- PWA:start -->
<link rel="manifest" href="/manifest.webmanifest">
<meta name="theme-color" content="#0066CC">
<link rel="icon" type="image/png" sizes="32x32" href="/assets/icons/favicon-32.png">
<link rel="icon" type="image/png" sizes="16x16" href="/assets/icons/favicon-16.png">
<link rel="apple-touch-icon" sizes="180x180" href="/assets/icons/apple-touch-icon.png">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="default">
<meta name="apple-mobile-web-app-title" content="NIS2 Agile">
<meta name="application-name" content="NIS2 Agile">
<script src="/js/pwa.js?v=20260614" defer></script>
<!-- PWA:end -->
</head> </head>
<body> <body>
<main class="container py-4" id="main-content"> <main class="container py-4" id="main-content">
+14 -1
View File
@@ -2,7 +2,7 @@
<html lang="it"> <html lang="it">
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
<title>Gap Analysis ACN (BI) - NIS2 Agile</title> <title>Gap Analysis ACN (BI) - NIS2 Agile</title>
<!-- Bootstrap Italia v2.18.1 self-hostato (regola: MAI CDN). Caricato PRIMA di style.css <!-- Bootstrap Italia v2.18.1 self-hostato (regola: MAI CDN). Caricato PRIMA di style.css
cosi' style.css (design system esistente) resta autorevole per i widget renderizzati cosi' style.css (design system esistente) resta autorevole per i widget renderizzati
@@ -45,6 +45,19 @@
/* icona inline nei bottoni BI */ /* icona inline nei bottoni BI */
.btn .icon { fill:currentColor; vertical-align:-2px; margin-right:6px; } .btn .icon { fill:currentColor; vertical-align:-2px; margin-right:6px; }
</style> </style>
<!-- PWA:start -->
<link rel="manifest" href="/manifest.webmanifest">
<meta name="theme-color" content="#0066CC">
<link rel="icon" type="image/png" sizes="32x32" href="/assets/icons/favicon-32.png">
<link rel="icon" type="image/png" sizes="16x16" href="/assets/icons/favicon-16.png">
<link rel="apple-touch-icon" sizes="180x180" href="/assets/icons/apple-touch-icon.png">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="default">
<meta name="apple-mobile-web-app-title" content="NIS2 Agile">
<meta name="application-name" content="NIS2 Agile">
<script src="/js/pwa.js?v=20260614" defer></script>
<!-- PWA:end -->
</head> </head>
<body> <body>
<div class="app-layout"> <div class="app-layout">
+14 -1
View File
@@ -2,7 +2,7 @@
<html lang="it"> <html lang="it">
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
<title>Gap Analysis ACN - NIS2 Agile</title> <title>Gap Analysis ACN - NIS2 Agile</title>
<!-- Bootstrap Italia v2.18.1 self-hostato (regola: MAI CDN). Caricato PRIMA di style.css <!-- Bootstrap Italia v2.18.1 self-hostato (regola: MAI CDN). Caricato PRIMA di style.css
cosi' style.css (design system esistente) resta autorevole per i widget renderizzati cosi' style.css (design system esistente) resta autorevole per i widget renderizzati
@@ -45,6 +45,19 @@
/* icona inline nei bottoni BI */ /* icona inline nei bottoni BI */
.btn .icon { fill:currentColor; vertical-align:-2px; margin-right:6px; } .btn .icon { fill:currentColor; vertical-align:-2px; margin-right:6px; }
</style> </style>
<!-- PWA:start -->
<link rel="manifest" href="/manifest.webmanifest">
<meta name="theme-color" content="#0066CC">
<link rel="icon" type="image/png" sizes="32x32" href="/assets/icons/favicon-32.png">
<link rel="icon" type="image/png" sizes="16x16" href="/assets/icons/favicon-16.png">
<link rel="apple-touch-icon" sizes="180x180" href="/assets/icons/apple-touch-icon.png">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="default">
<meta name="apple-mobile-web-app-title" content="NIS2 Agile">
<meta name="application-name" content="NIS2 Agile">
<script src="/js/pwa.js?v=20260614" defer></script>
<!-- PWA:end -->
</head> </head>
<body> <body>
<div class="app-layout"> <div class="app-layout">
+14 -1
View File
@@ -2,7 +2,7 @@
<html lang="it"> <html lang="it">
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
<title>Pannello Amministrazione (BI) - NIS2 Agile</title> <title>Pannello Amministrazione (BI) - NIS2 Agile</title>
<!-- Bootstrap Italia v2.18.1 self-hostato (regola: MAI CDN). Caricato PRIMA di style.css <!-- Bootstrap Italia v2.18.1 self-hostato (regola: MAI CDN). Caricato PRIMA di style.css
cosi' style.css resta autorevole per i widget renderizzati via JS -> parita' funzionale. cosi' style.css resta autorevole per i widget renderizzati via JS -> parita' funzionale.
@@ -182,6 +182,19 @@
} }
} }
</style> </style>
<!-- PWA:start -->
<link rel="manifest" href="/manifest.webmanifest">
<meta name="theme-color" content="#0066CC">
<link rel="icon" type="image/png" sizes="32x32" href="/assets/icons/favicon-32.png">
<link rel="icon" type="image/png" sizes="16x16" href="/assets/icons/favicon-16.png">
<link rel="apple-touch-icon" sizes="180x180" href="/assets/icons/apple-touch-icon.png">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="default">
<meta name="apple-mobile-web-app-title" content="NIS2 Agile">
<meta name="application-name" content="NIS2 Agile">
<script src="/js/pwa.js?v=20260614" defer></script>
<!-- PWA:end -->
</head> </head>
<body> <body>
<div class="app-layout"> <div class="app-layout">
+14 -1
View File
@@ -2,7 +2,7 @@
<html lang="it"> <html lang="it">
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
<title>Pannello Amministrazione - NIS2 Agile</title> <title>Pannello Amministrazione - NIS2 Agile</title>
<!-- Bootstrap Italia v2.18.1 self-hostato (regola: MAI CDN). Caricato PRIMA di style.css <!-- Bootstrap Italia v2.18.1 self-hostato (regola: MAI CDN). Caricato PRIMA di style.css
cosi' style.css resta autorevole per i widget renderizzati via JS -> parita' funzionale. cosi' style.css resta autorevole per i widget renderizzati via JS -> parita' funzionale.
@@ -182,6 +182,19 @@
} }
} }
</style> </style>
<!-- PWA:start -->
<link rel="manifest" href="/manifest.webmanifest">
<meta name="theme-color" content="#0066CC">
<link rel="icon" type="image/png" sizes="32x32" href="/assets/icons/favicon-32.png">
<link rel="icon" type="image/png" sizes="16x16" href="/assets/icons/favicon-16.png">
<link rel="apple-touch-icon" sizes="180x180" href="/assets/icons/apple-touch-icon.png">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="default">
<meta name="apple-mobile-web-app-title" content="NIS2 Agile">
<meta name="application-name" content="NIS2 Agile">
<script src="/js/pwa.js?v=20260614" defer></script>
<!-- PWA:end -->
</head> </head>
<body> <body>
<div class="app-layout"> <div class="app-layout">
+14 -1
View File
@@ -2,7 +2,7 @@
<html lang="it"> <html lang="it">
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
<title>Gestione Organizzazioni (BI) - NIS2 Agile</title> <title>Gestione Organizzazioni (BI) - NIS2 Agile</title>
<!-- Bootstrap Italia v2.18.1 self-hostato (regola: MAI CDN). Caricato PRIMA di style.css <!-- Bootstrap Italia v2.18.1 self-hostato (regola: MAI CDN). Caricato PRIMA di style.css
cosi' style.css (design system esistente) resta autorevole per i widget renderizzati cosi' style.css (design system esistente) resta autorevole per i widget renderizzati
@@ -101,6 +101,19 @@
fill: currentColor; fill: currentColor;
} }
</style> </style>
<!-- PWA:start -->
<link rel="manifest" href="/manifest.webmanifest">
<meta name="theme-color" content="#0066CC">
<link rel="icon" type="image/png" sizes="32x32" href="/assets/icons/favicon-32.png">
<link rel="icon" type="image/png" sizes="16x16" href="/assets/icons/favicon-16.png">
<link rel="apple-touch-icon" sizes="180x180" href="/assets/icons/apple-touch-icon.png">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="default">
<meta name="apple-mobile-web-app-title" content="NIS2 Agile">
<meta name="application-name" content="NIS2 Agile">
<script src="/js/pwa.js?v=20260614" defer></script>
<!-- PWA:end -->
</head> </head>
<body> <body>
<div class="app-layout"> <div class="app-layout">
+14 -1
View File
@@ -2,7 +2,7 @@
<html lang="it"> <html lang="it">
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
<title>Gestione Organizzazioni - NIS2 Agile</title> <title>Gestione Organizzazioni - NIS2 Agile</title>
<!-- Bootstrap Italia v2.18.1 self-hostato (regola: MAI CDN). Caricato PRIMA di style.css <!-- Bootstrap Italia v2.18.1 self-hostato (regola: MAI CDN). Caricato PRIMA di style.css
cosi' style.css (design system esistente) resta autorevole per i widget renderizzati cosi' style.css (design system esistente) resta autorevole per i widget renderizzati
@@ -101,6 +101,19 @@
fill: currentColor; fill: currentColor;
} }
</style> </style>
<!-- PWA:start -->
<link rel="manifest" href="/manifest.webmanifest">
<meta name="theme-color" content="#0066CC">
<link rel="icon" type="image/png" sizes="32x32" href="/assets/icons/favicon-32.png">
<link rel="icon" type="image/png" sizes="16x16" href="/assets/icons/favicon-16.png">
<link rel="apple-touch-icon" sizes="180x180" href="/assets/icons/apple-touch-icon.png">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="default">
<meta name="apple-mobile-web-app-title" content="NIS2 Agile">
<meta name="application-name" content="NIS2 Agile">
<script src="/js/pwa.js?v=20260614" defer></script>
<!-- PWA:end -->
</head> </head>
<body> <body>
<div class="app-layout"> <div class="app-layout">
+14 -1
View File
@@ -2,7 +2,7 @@
<html lang="it"> <html lang="it">
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
<title>Gestione Utenti (BI) - NIS2 Agile</title> <title>Gestione Utenti (BI) - NIS2 Agile</title>
<!-- Bootstrap Italia v2.18.1 self-hostato (regola: MAI CDN). Caricato PRIMA di style.css <!-- Bootstrap Italia v2.18.1 self-hostato (regola: MAI CDN). Caricato PRIMA di style.css
cosi' style.css (design system esistente) resta autorevole per i widget renderizzati cosi' style.css (design system esistente) resta autorevole per i widget renderizzati
@@ -123,6 +123,19 @@
color: var(--gray-400); color: var(--gray-400);
} }
</style> </style>
<!-- PWA:start -->
<link rel="manifest" href="/manifest.webmanifest">
<meta name="theme-color" content="#0066CC">
<link rel="icon" type="image/png" sizes="32x32" href="/assets/icons/favicon-32.png">
<link rel="icon" type="image/png" sizes="16x16" href="/assets/icons/favicon-16.png">
<link rel="apple-touch-icon" sizes="180x180" href="/assets/icons/apple-touch-icon.png">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="default">
<meta name="apple-mobile-web-app-title" content="NIS2 Agile">
<meta name="application-name" content="NIS2 Agile">
<script src="/js/pwa.js?v=20260614" defer></script>
<!-- PWA:end -->
</head> </head>
<body> <body>
<div class="app-layout"> <div class="app-layout">
+14 -1
View File
@@ -2,7 +2,7 @@
<html lang="it"> <html lang="it">
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
<title>Gestione Utenti - NIS2 Agile</title> <title>Gestione Utenti - NIS2 Agile</title>
<!-- Bootstrap Italia v2.18.1 self-hostato (regola: MAI CDN). Caricato PRIMA di style.css <!-- Bootstrap Italia v2.18.1 self-hostato (regola: MAI CDN). Caricato PRIMA di style.css
cosi' style.css (design system esistente) resta autorevole per i widget renderizzati cosi' style.css (design system esistente) resta autorevole per i widget renderizzati
@@ -123,6 +123,19 @@
color: var(--gray-400); color: var(--gray-400);
} }
</style> </style>
<!-- PWA:start -->
<link rel="manifest" href="/manifest.webmanifest">
<meta name="theme-color" content="#0066CC">
<link rel="icon" type="image/png" sizes="32x32" href="/assets/icons/favicon-32.png">
<link rel="icon" type="image/png" sizes="16x16" href="/assets/icons/favicon-16.png">
<link rel="apple-touch-icon" sizes="180x180" href="/assets/icons/apple-touch-icon.png">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="default">
<meta name="apple-mobile-web-app-title" content="NIS2 Agile">
<meta name="application-name" content="NIS2 Agile">
<script src="/js/pwa.js?v=20260614" defer></script>
<!-- PWA:end -->
</head> </head>
<body> <body>
<div class="app-layout"> <div class="app-layout">
+14 -1
View File
@@ -2,7 +2,7 @@
<html lang="it"> <html lang="it">
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
<title>Architettura - NIS2 Agile</title> <title>Architettura - NIS2 Agile</title>
<link rel="stylesheet" href="css/style.css?v=20260613b"> <link rel="stylesheet" href="css/style.css?v=20260613b">
<style> <style>
@@ -617,6 +617,19 @@
} }
} }
</style> </style>
<!-- PWA:start -->
<link rel="manifest" href="/manifest.webmanifest">
<meta name="theme-color" content="#0066CC">
<link rel="icon" type="image/png" sizes="32x32" href="/assets/icons/favicon-32.png">
<link rel="icon" type="image/png" sizes="16x16" href="/assets/icons/favicon-16.png">
<link rel="apple-touch-icon" sizes="180x180" href="/assets/icons/apple-touch-icon.png">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="default">
<meta name="apple-mobile-web-app-title" content="NIS2 Agile">
<meta name="application-name" content="NIS2 Agile">
<script src="/js/pwa.js?v=20260614" defer></script>
<!-- PWA:end -->
</head> </head>
<body> <body>
<div class="app-layout"> <div class="app-layout">
+14 -1
View File
@@ -2,13 +2,26 @@
<html lang="it"> <html lang="it">
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
<title>Gap Analysis (BI) - NIS2 Agile</title> <title>Gap Analysis (BI) - NIS2 Agile</title>
<!-- Bootstrap Italia v2.18.1 self-hostato (regola: MAI CDN). Caricato PRIMA di style.css <!-- Bootstrap Italia v2.18.1 self-hostato (regola: MAI CDN). Caricato PRIMA di style.css
cosi' style.css (design system esistente) resta autorevole per i widget renderizzati cosi' style.css (design system esistente) resta autorevole per i widget renderizzati
via JS (wizard/form/gauge) -> parita' funzionale assoluta. BI veste la chrome. --> via JS (wizard/form/gauge) -> parita' funzionale assoluta. BI veste la chrome. -->
<link rel="stylesheet" href="/vendor/bootstrap-italia/dist/css/bootstrap-italia.min.css"> <link rel="stylesheet" href="/vendor/bootstrap-italia/dist/css/bootstrap-italia.min.css">
<link rel="stylesheet" href="/css/style.css?v=20260613b"> <link rel="stylesheet" href="/css/style.css?v=20260613b">
<!-- PWA:start -->
<link rel="manifest" href="/manifest.webmanifest">
<meta name="theme-color" content="#0066CC">
<link rel="icon" type="image/png" sizes="32x32" href="/assets/icons/favicon-32.png">
<link rel="icon" type="image/png" sizes="16x16" href="/assets/icons/favicon-16.png">
<link rel="apple-touch-icon" sizes="180x180" href="/assets/icons/apple-touch-icon.png">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="default">
<meta name="apple-mobile-web-app-title" content="NIS2 Agile">
<meta name="application-name" content="NIS2 Agile">
<script src="/js/pwa.js?v=20260614" defer></script>
<!-- PWA:end -->
</head> </head>
<body> <body>
<div class="app-layout"> <div class="app-layout">
+14 -1
View File
@@ -2,13 +2,26 @@
<html lang="it"> <html lang="it">
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
<title>Gap Analysis - NIS2 Agile</title> <title>Gap Analysis - NIS2 Agile</title>
<!-- Bootstrap Italia v2.18.1 self-hostato (regola: MAI CDN). Caricato PRIMA di style.css <!-- Bootstrap Italia v2.18.1 self-hostato (regola: MAI CDN). Caricato PRIMA di style.css
cosi' style.css (design system esistente) resta autorevole per i widget renderizzati cosi' style.css (design system esistente) resta autorevole per i widget renderizzati
via JS (wizard/form/gauge) -> parita' funzionale assoluta. BI veste la chrome. --> via JS (wizard/form/gauge) -> parita' funzionale assoluta. BI veste la chrome. -->
<link rel="stylesheet" href="/vendor/bootstrap-italia/dist/css/bootstrap-italia.min.css"> <link rel="stylesheet" href="/vendor/bootstrap-italia/dist/css/bootstrap-italia.min.css">
<link rel="stylesheet" href="/css/style.css?v=20260613b"> <link rel="stylesheet" href="/css/style.css?v=20260613b">
<!-- PWA:start -->
<link rel="manifest" href="/manifest.webmanifest">
<meta name="theme-color" content="#0066CC">
<link rel="icon" type="image/png" sizes="32x32" href="/assets/icons/favicon-32.png">
<link rel="icon" type="image/png" sizes="16x16" href="/assets/icons/favicon-16.png">
<link rel="apple-touch-icon" sizes="180x180" href="/assets/icons/apple-touch-icon.png">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="default">
<meta name="apple-mobile-web-app-title" content="NIS2 Agile">
<meta name="application-name" content="NIS2 Agile">
<script src="/js/pwa.js?v=20260614" defer></script>
<!-- PWA:end -->
</head> </head>
<body> <body>
<div class="app-layout"> <div class="app-layout">
+14 -1
View File
@@ -2,7 +2,7 @@
<html lang="it"> <html lang="it">
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
<title>Inventario Asset (BI) - NIS2 Agile</title> <title>Inventario Asset (BI) - NIS2 Agile</title>
<!-- Bootstrap Italia v2.18.1 self-hostato (regola: MAI CDN). Caricato PRIMA di style.css <!-- Bootstrap Italia v2.18.1 self-hostato (regola: MAI CDN). Caricato PRIMA di style.css
cosi' style.css (design system esistente) resta autorevole per i widget renderizzati cosi' style.css (design system esistente) resta autorevole per i widget renderizzati
@@ -258,6 +258,19 @@
.form-grid-2 { grid-template-columns: 1fr; } .form-grid-2 { grid-template-columns: 1fr; }
} }
</style> </style>
<!-- PWA:start -->
<link rel="manifest" href="/manifest.webmanifest">
<meta name="theme-color" content="#0066CC">
<link rel="icon" type="image/png" sizes="32x32" href="/assets/icons/favicon-32.png">
<link rel="icon" type="image/png" sizes="16x16" href="/assets/icons/favicon-16.png">
<link rel="apple-touch-icon" sizes="180x180" href="/assets/icons/apple-touch-icon.png">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="default">
<meta name="apple-mobile-web-app-title" content="NIS2 Agile">
<meta name="application-name" content="NIS2 Agile">
<script src="/js/pwa.js?v=20260614" defer></script>
<!-- PWA:end -->
</head> </head>
<body> <body>
<div class="app-layout"> <div class="app-layout">
+14 -1
View File
@@ -2,7 +2,7 @@
<html lang="it"> <html lang="it">
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
<title>Inventario Asset - NIS2 Agile</title> <title>Inventario Asset - NIS2 Agile</title>
<!-- Bootstrap Italia v2.18.1 self-hostato (regola: MAI CDN). Caricato PRIMA di style.css <!-- Bootstrap Italia v2.18.1 self-hostato (regola: MAI CDN). Caricato PRIMA di style.css
cosi' style.css (design system esistente) resta autorevole per i widget renderizzati cosi' style.css (design system esistente) resta autorevole per i widget renderizzati
@@ -258,6 +258,19 @@
.form-grid-2 { grid-template-columns: 1fr; } .form-grid-2 { grid-template-columns: 1fr; }
} }
</style> </style>
<!-- PWA:start -->
<link rel="manifest" href="/manifest.webmanifest">
<meta name="theme-color" content="#0066CC">
<link rel="icon" type="image/png" sizes="32x32" href="/assets/icons/favicon-32.png">
<link rel="icon" type="image/png" sizes="16x16" href="/assets/icons/favicon-16.png">
<link rel="apple-touch-icon" sizes="180x180" href="/assets/icons/apple-touch-icon.png">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="default">
<meta name="apple-mobile-web-app-title" content="NIS2 Agile">
<meta name="application-name" content="NIS2 Agile">
<script src="/js/pwa.js?v=20260614" defer></script>
<!-- PWA:end -->
</head> </head>
<body> <body>
<div class="app-layout"> <div class="app-layout">
Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 303 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 447 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.4 KiB

+10
View File
@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" width="512" height="512" viewBox="0 0 512 512" role="img" aria-label="NIS2 Agile">
<title>NIS2 Agile</title>
<!-- Italy-blue rounded tile -->
<rect x="40.96" y="40.96" width="430.08" height="430.08" rx="92.16" ry="92.16" fill="#0066CC"/>
<!-- White shield -->
<polygon points="114.7,99.3 397.3,99.3 395.9,202.2 386.0,263.7 360.6,325.1 315.4,386.6 256.0,428.0 196.6,386.6 151.4,325.1 126.0,263.7 116.1,202.2 114.7,99.3" fill="#FFFFFF"/>
<!-- Negative blue check -->
<polygon points="169.6,269.9 227.6,321.5 254.3,319.2 351.1,196.6 322.2,173.8 225.4,296.3 252.1,294.0 194.1,242.4" fill="#0066CC"/>
</svg>

After

Width:  |  Height:  |  Size: 696 B

+14 -1
View File
@@ -2,7 +2,7 @@
<html lang="it"> <html lang="it">
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
<title>Le Mie Aziende - NIS2 Agile</title> <title>Le Mie Aziende - NIS2 Agile</title>
<!-- Bootstrap Italia v2.18.1 self-hostato (MAI CDN). Caricato PRIMA di style.css: BI veste la chrome/sidebar, style.css resta autorevole per i widget. --> <!-- Bootstrap Italia v2.18.1 self-hostato (MAI CDN). Caricato PRIMA di style.css: BI veste la chrome/sidebar, style.css resta autorevole per i widget. -->
<link rel="stylesheet" href="vendor/bootstrap-italia/dist/css/bootstrap-italia.min.css"> <link rel="stylesheet" href="vendor/bootstrap-italia/dist/css/bootstrap-italia.min.css">
@@ -268,6 +268,19 @@
gap: 16px; gap: 16px;
} }
</style> </style>
<!-- PWA:start -->
<link rel="manifest" href="/manifest.webmanifest">
<meta name="theme-color" content="#0066CC">
<link rel="icon" type="image/png" sizes="32x32" href="/assets/icons/favicon-32.png">
<link rel="icon" type="image/png" sizes="16x16" href="/assets/icons/favicon-16.png">
<link rel="apple-touch-icon" sizes="180x180" href="/assets/icons/apple-touch-icon.png">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="default">
<meta name="apple-mobile-web-app-title" content="NIS2 Agile">
<meta name="application-name" content="NIS2 Agile">
<script src="/js/pwa.js?v=20260614" defer></script>
<!-- PWA:end -->
</head> </head>
<body> <body>
<div class="app-layout"> <div class="app-layout">
+14 -1
View File
@@ -2,7 +2,7 @@
<html lang="it"> <html lang="it">
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
<title>Le Mie Aziende - NIS2 Agile</title> <title>Le Mie Aziende - NIS2 Agile</title>
<!-- Bootstrap Italia v2.18.1 self-hostato (MAI CDN). Caricato PRIMA di style.css: BI veste la chrome/sidebar, style.css resta autorevole per i widget. --> <!-- Bootstrap Italia v2.18.1 self-hostato (MAI CDN). Caricato PRIMA di style.css: BI veste la chrome/sidebar, style.css resta autorevole per i widget. -->
<link rel="stylesheet" href="vendor/bootstrap-italia/dist/css/bootstrap-italia.min.css"> <link rel="stylesheet" href="vendor/bootstrap-italia/dist/css/bootstrap-italia.min.css">
@@ -268,6 +268,19 @@
gap: 16px; gap: 16px;
} }
</style> </style>
<!-- PWA:start -->
<link rel="manifest" href="/manifest.webmanifest">
<meta name="theme-color" content="#0066CC">
<link rel="icon" type="image/png" sizes="32x32" href="/assets/icons/favicon-32.png">
<link rel="icon" type="image/png" sizes="16x16" href="/assets/icons/favicon-16.png">
<link rel="apple-touch-icon" sizes="180x180" href="/assets/icons/apple-touch-icon.png">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="default">
<meta name="apple-mobile-web-app-title" content="NIS2 Agile">
<meta name="application-name" content="NIS2 Agile">
<script src="/js/pwa.js?v=20260614" defer></script>
<!-- PWA:end -->
</head> </head>
<body> <body>
<div class="app-layout"> <div class="app-layout">
+14 -1
View File
@@ -2,7 +2,7 @@
<html lang="it"> <html lang="it">
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
<title>AI Cross-Analysis (BI) — NIS2 Agile</title> <title>AI Cross-Analysis (BI) — NIS2 Agile</title>
<!-- Bootstrap Italia v2.18.1 self-hostato (regola: MAI CDN). Caricato PRIMA di style.css <!-- Bootstrap Italia v2.18.1 self-hostato (regola: MAI CDN). Caricato PRIMA di style.css
cosi' style.css (design system esistente) resta autorevole per i widget renderizzati cosi' style.css (design system esistente) resta autorevole per i widget renderizzati
@@ -272,6 +272,19 @@
.tab-pane { display: none; } .tab-pane { display: none; }
.tab-pane.active { display: block; } .tab-pane.active { display: block; }
</style> </style>
<!-- PWA:start -->
<link rel="manifest" href="/manifest.webmanifest">
<meta name="theme-color" content="#0066CC">
<link rel="icon" type="image/png" sizes="32x32" href="/assets/icons/favicon-32.png">
<link rel="icon" type="image/png" sizes="16x16" href="/assets/icons/favicon-16.png">
<link rel="apple-touch-icon" sizes="180x180" href="/assets/icons/apple-touch-icon.png">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="default">
<meta name="apple-mobile-web-app-title" content="NIS2 Agile">
<meta name="application-name" content="NIS2 Agile">
<script src="/js/pwa.js?v=20260614" defer></script>
<!-- PWA:end -->
</head> </head>
<body> <body>
<div class="app-layout"> <div class="app-layout">
+14 -1
View File
@@ -2,7 +2,7 @@
<html lang="it"> <html lang="it">
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
<title>AI Cross-Analysis — NIS2 Agile</title> <title>AI Cross-Analysis — NIS2 Agile</title>
<!-- Bootstrap Italia v2.18.1 self-hostato (regola: MAI CDN). Caricato PRIMA di style.css <!-- Bootstrap Italia v2.18.1 self-hostato (regola: MAI CDN). Caricato PRIMA di style.css
cosi' style.css (design system esistente) resta autorevole per i widget renderizzati cosi' style.css (design system esistente) resta autorevole per i widget renderizzati
@@ -272,6 +272,19 @@
.tab-pane { display: none; } .tab-pane { display: none; }
.tab-pane.active { display: block; } .tab-pane.active { display: block; }
</style> </style>
<!-- PWA:start -->
<link rel="manifest" href="/manifest.webmanifest">
<meta name="theme-color" content="#0066CC">
<link rel="icon" type="image/png" sizes="32x32" href="/assets/icons/favicon-32.png">
<link rel="icon" type="image/png" sizes="16x16" href="/assets/icons/favicon-16.png">
<link rel="apple-touch-icon" sizes="180x180" href="/assets/icons/apple-touch-icon.png">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="default">
<meta name="apple-mobile-web-app-title" content="NIS2 Agile">
<meta name="application-name" content="NIS2 Agile">
<script src="/js/pwa.js?v=20260614" defer></script>
<!-- PWA:end -->
</head> </head>
<body> <body>
<div class="app-layout"> <div class="app-layout">
+41
View File
@@ -2411,3 +2411,44 @@ tbody tr.clickable:active {
.feedback-resolve-actions { flex-direction: column; } .feedback-resolve-actions { flex-direction: column; }
.feedback-password-row { flex-direction: column; } .feedback-password-row { flex-direction: column; }
} }
/* ── PWA / AGID — Accessibilità mobile ──────────────────────────────
Touch target >= 44x44px (WCAG 2.5.5 / Linee guida di design AGID) e
gestione safe-area in modalità installata (notch). Solo aggiunte. */
@media (pointer: coarse) {
.btn,
button,
input[type="submit"],
input[type="button"],
.nav-link,
.sidebar a,
a.btn,
.icon-btn,
.sidebar-toggle {
min-height: 44px;
}
.btn,
a.btn,
input[type="submit"],
input[type="button"],
.icon-btn {
display: inline-flex;
align-items: center;
justify-content: center;
}
.icon-btn,
.sidebar-toggle {
min-width: 44px;
}
}
/* Safe-area inset quando l'app gira installata (standalone) */
@media all and (display-mode: standalone) {
.content-header { padding-top: max(16px, env(safe-area-inset-top)); }
.main-content {
padding-left: env(safe-area-inset-left);
padding-right: env(safe-area-inset-right);
padding-bottom: env(safe-area-inset-bottom);
}
.sidebar { padding-top: env(safe-area-inset-top); }
}
+14 -1
View File
@@ -2,13 +2,26 @@
<html lang="it"> <html lang="it">
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
<title>Dashboard (BI) - NIS2 Agile</title> <title>Dashboard (BI) - NIS2 Agile</title>
<!-- Bootstrap Italia v2.18.1 self-hostato (regola: MAI CDN). Caricato PRIMA di style.css <!-- Bootstrap Italia v2.18.1 self-hostato (regola: MAI CDN). Caricato PRIMA di style.css
cosi' style.css (design system esistente) resta autorevole per i widget renderizzati cosi' style.css (design system esistente) resta autorevole per i widget renderizzati
via JS (card/gauge/stat/modali) -> parita' funzionale assoluta. BI veste la chrome. --> via JS (card/gauge/stat/modali) -> parita' funzionale assoluta. BI veste la chrome. -->
<link rel="stylesheet" href="/vendor/bootstrap-italia/dist/css/bootstrap-italia.min.css"> <link rel="stylesheet" href="/vendor/bootstrap-italia/dist/css/bootstrap-italia.min.css">
<link rel="stylesheet" href="/css/style.css?v=20260613b"> <link rel="stylesheet" href="/css/style.css?v=20260613b">
<!-- PWA:start -->
<link rel="manifest" href="/manifest.webmanifest">
<meta name="theme-color" content="#0066CC">
<link rel="icon" type="image/png" sizes="32x32" href="/assets/icons/favicon-32.png">
<link rel="icon" type="image/png" sizes="16x16" href="/assets/icons/favicon-16.png">
<link rel="apple-touch-icon" sizes="180x180" href="/assets/icons/apple-touch-icon.png">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="default">
<meta name="apple-mobile-web-app-title" content="NIS2 Agile">
<meta name="application-name" content="NIS2 Agile">
<script src="/js/pwa.js?v=20260614" defer></script>
<!-- PWA:end -->
</head> </head>
<body> <body>
<div class="app-layout"> <div class="app-layout">
+14 -1
View File
@@ -2,13 +2,26 @@
<html lang="it"> <html lang="it">
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
<title>Dashboard - NIS2 Agile</title> <title>Dashboard - NIS2 Agile</title>
<!-- Bootstrap Italia v2.18.1 self-hostato (regola: MAI CDN). Caricato PRIMA di style.css <!-- Bootstrap Italia v2.18.1 self-hostato (regola: MAI CDN). Caricato PRIMA di style.css
cosi' style.css (design system esistente) resta autorevole per i widget renderizzati cosi' style.css (design system esistente) resta autorevole per i widget renderizzati
via JS (card/gauge/stat/modali) -> parita' funzionale assoluta. BI veste la chrome. --> via JS (card/gauge/stat/modali) -> parita' funzionale assoluta. BI veste la chrome. -->
<link rel="stylesheet" href="/vendor/bootstrap-italia/dist/css/bootstrap-italia.min.css"> <link rel="stylesheet" href="/vendor/bootstrap-italia/dist/css/bootstrap-italia.min.css">
<link rel="stylesheet" href="/css/style.css?v=20260613b"> <link rel="stylesheet" href="/css/style.css?v=20260613b">
<!-- PWA:start -->
<link rel="manifest" href="/manifest.webmanifest">
<meta name="theme-color" content="#0066CC">
<link rel="icon" type="image/png" sizes="32x32" href="/assets/icons/favicon-32.png">
<link rel="icon" type="image/png" sizes="16x16" href="/assets/icons/favicon-16.png">
<link rel="apple-touch-icon" sizes="180x180" href="/assets/icons/apple-touch-icon.png">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="default">
<meta name="apple-mobile-web-app-title" content="NIS2 Agile">
<meta name="application-name" content="NIS2 Agile">
<script src="/js/pwa.js?v=20260614" defer></script>
<!-- PWA:end -->
</head> </head>
<body> <body>
<div class="app-layout"> <div class="app-layout">
+14 -1
View File
@@ -2,7 +2,7 @@
<html lang="it"> <html lang="it">
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
<title>NIS2 Agile — API Reference</title> <title>NIS2 Agile — API Reference</title>
<style> <style>
* { box-sizing: border-box; margin: 0; padding: 0; } * { box-sizing: border-box; margin: 0; padding: 0; }
@@ -109,6 +109,19 @@
.content { padding: 24px; } .content { padding: 24px; }
} }
</style> </style>
<!-- PWA:start -->
<link rel="manifest" href="/manifest.webmanifest">
<meta name="theme-color" content="#0066CC">
<link rel="icon" type="image/png" sizes="32x32" href="/assets/icons/favicon-32.png">
<link rel="icon" type="image/png" sizes="16x16" href="/assets/icons/favicon-16.png">
<link rel="apple-touch-icon" sizes="180x180" href="/assets/icons/apple-touch-icon.png">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="default">
<meta name="apple-mobile-web-app-title" content="NIS2 Agile">
<meta name="application-name" content="NIS2 Agile">
<script src="/js/pwa.js?v=20260614" defer></script>
<!-- PWA:end -->
</head> </head>
<body> <body>
<div class="layout"> <div class="layout">
+14 -1
View File
@@ -2,7 +2,7 @@
<html lang="it"> <html lang="it">
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
<title>NIS2 Agile — Sistema di Testing & Simulazione</title> <title>NIS2 Agile — Sistema di Testing & Simulazione</title>
<style> <style>
:root { :root {
@@ -233,6 +233,19 @@
padding: 32px 48px; text-align: center; color: var(--muted); font-size: 0.875rem; padding: 32px 48px; text-align: center; color: var(--muted); font-size: 0.875rem;
} }
</style> </style>
<!-- PWA:start -->
<link rel="manifest" href="/manifest.webmanifest">
<meta name="theme-color" content="#0066CC">
<link rel="icon" type="image/png" sizes="32x32" href="/assets/icons/favicon-32.png">
<link rel="icon" type="image/png" sizes="16x16" href="/assets/icons/favicon-16.png">
<link rel="apple-touch-icon" sizes="180x180" href="/assets/icons/apple-touch-icon.png">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="default">
<meta name="apple-mobile-web-app-title" content="NIS2 Agile">
<meta name="application-name" content="NIS2 Agile">
<script src="/js/pwa.js?v=20260614" defer></script>
<!-- PWA:end -->
</head> </head>
<body> <body>
+14 -1
View File
@@ -2,7 +2,7 @@
<html lang="it"> <html lang="it">
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
<title>Password dimenticata - NIS2 Agile</title> <title>Password dimenticata - NIS2 Agile</title>
<!-- Bootstrap Italia v2.18.1 — self-hostato da /vendor (MAI CDN). Variante "-bi" della forgot-password.html. --> <!-- Bootstrap Italia v2.18.1 — self-hostato da /vendor (MAI CDN). Variante "-bi" della forgot-password.html. -->
<link rel="stylesheet" href="vendor/bootstrap-italia/dist/css/bootstrap-italia.min.css"> <link rel="stylesheet" href="vendor/bootstrap-italia/dist/css/bootstrap-italia.min.css">
@@ -15,6 +15,19 @@
.auth-brand .brand-sub { color: #5a6772; font-size: .9rem; margin-top: 4px; } .auth-brand .brand-sub { color: #5a6772; font-size: .9rem; margin-top: 4px; }
.ico { width: 1em; height: 1em; fill: currentColor; vertical-align: -.125em; } .ico { width: 1em; height: 1em; fill: currentColor; vertical-align: -.125em; }
</style> </style>
<!-- PWA:start -->
<link rel="manifest" href="/manifest.webmanifest">
<meta name="theme-color" content="#0066CC">
<link rel="icon" type="image/png" sizes="32x32" href="/assets/icons/favicon-32.png">
<link rel="icon" type="image/png" sizes="16x16" href="/assets/icons/favicon-16.png">
<link rel="apple-touch-icon" sizes="180x180" href="/assets/icons/apple-touch-icon.png">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="default">
<meta name="apple-mobile-web-app-title" content="NIS2 Agile">
<meta name="application-name" content="NIS2 Agile">
<script src="/js/pwa.js?v=20260614" defer></script>
<!-- PWA:end -->
</head> </head>
<body> <body>
<main class="auth-wrap"> <main class="auth-wrap">
+14 -1
View File
@@ -2,7 +2,7 @@
<html lang="it"> <html lang="it">
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
<title>Password dimenticata - NIS2 Agile</title> <title>Password dimenticata - NIS2 Agile</title>
<!-- Bootstrap Italia v2.18.1 — self-hostato da /vendor (MAI CDN). Variante "-bi" della forgot-password.html. --> <!-- Bootstrap Italia v2.18.1 — self-hostato da /vendor (MAI CDN). Variante "-bi" della forgot-password.html. -->
<link rel="stylesheet" href="vendor/bootstrap-italia/dist/css/bootstrap-italia.min.css"> <link rel="stylesheet" href="vendor/bootstrap-italia/dist/css/bootstrap-italia.min.css">
@@ -15,6 +15,19 @@
.auth-brand .brand-sub { color: #5a6772; font-size: .9rem; margin-top: 4px; } .auth-brand .brand-sub { color: #5a6772; font-size: .9rem; margin-top: 4px; }
.ico { width: 1em; height: 1em; fill: currentColor; vertical-align: -.125em; } .ico { width: 1em; height: 1em; fill: currentColor; vertical-align: -.125em; }
</style> </style>
<!-- PWA:start -->
<link rel="manifest" href="/manifest.webmanifest">
<meta name="theme-color" content="#0066CC">
<link rel="icon" type="image/png" sizes="32x32" href="/assets/icons/favicon-32.png">
<link rel="icon" type="image/png" sizes="16x16" href="/assets/icons/favicon-16.png">
<link rel="apple-touch-icon" sizes="180x180" href="/assets/icons/apple-touch-icon.png">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="default">
<meta name="apple-mobile-web-app-title" content="NIS2 Agile">
<meta name="application-name" content="NIS2 Agile">
<script src="/js/pwa.js?v=20260614" defer></script>
<!-- PWA:end -->
</head> </head>
<body> <body>
<main class="auth-wrap"> <main class="auth-wrap">
+14 -1
View File
@@ -2,7 +2,7 @@
<html lang="it"> <html lang="it">
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
<title>Guida all'uso (BI) - NIS2 Agile</title> <title>Guida all'uso (BI) - NIS2 Agile</title>
<!-- Bootstrap Italia v2.18.1 self-hostato (regola: MAI CDN). Caricato PRIMA di style.css <!-- Bootstrap Italia v2.18.1 self-hostato (regola: MAI CDN). Caricato PRIMA di style.css
cosi' style.css resta autorevole per la chrome (sidebar/widget). BI veste la guida. --> cosi' style.css resta autorevole per la chrome (sidebar/widget). BI veste la guida. -->
@@ -88,6 +88,19 @@
.guide-toc-card { position: static; } .guide-toc-card { position: static; }
} }
</style> </style>
<!-- PWA:start -->
<link rel="manifest" href="/manifest.webmanifest">
<meta name="theme-color" content="#0066CC">
<link rel="icon" type="image/png" sizes="32x32" href="/assets/icons/favicon-32.png">
<link rel="icon" type="image/png" sizes="16x16" href="/assets/icons/favicon-16.png">
<link rel="apple-touch-icon" sizes="180x180" href="/assets/icons/apple-touch-icon.png">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="default">
<meta name="apple-mobile-web-app-title" content="NIS2 Agile">
<meta name="application-name" content="NIS2 Agile">
<script src="/js/pwa.js?v=20260614" defer></script>
<!-- PWA:end -->
</head> </head>
<body> <body>
<div class="app-layout"> <div class="app-layout">
+14 -1
View File
@@ -2,7 +2,7 @@
<html lang="it"> <html lang="it">
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
<title>Guida all'uso - NIS2 Agile</title> <title>Guida all'uso - NIS2 Agile</title>
<!-- Bootstrap Italia v2.18.1 self-hostato (regola: MAI CDN). Caricato PRIMA di style.css <!-- Bootstrap Italia v2.18.1 self-hostato (regola: MAI CDN). Caricato PRIMA di style.css
cosi' style.css resta autorevole per la chrome (sidebar/widget). BI veste la guida. --> cosi' style.css resta autorevole per la chrome (sidebar/widget). BI veste la guida. -->
@@ -88,6 +88,19 @@
.guide-toc-card { position: static; } .guide-toc-card { position: static; }
} }
</style> </style>
<!-- PWA:start -->
<link rel="manifest" href="/manifest.webmanifest">
<meta name="theme-color" content="#0066CC">
<link rel="icon" type="image/png" sizes="32x32" href="/assets/icons/favicon-32.png">
<link rel="icon" type="image/png" sizes="16x16" href="/assets/icons/favicon-16.png">
<link rel="apple-touch-icon" sizes="180x180" href="/assets/icons/apple-touch-icon.png">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="default">
<meta name="apple-mobile-web-app-title" content="NIS2 Agile">
<meta name="application-name" content="NIS2 Agile">
<script src="/js/pwa.js?v=20260614" defer></script>
<!-- PWA:end -->
</head> </head>
<body> <body>
<div class="app-layout"> <div class="app-layout">
+14 -1
View File
@@ -2,7 +2,7 @@
<html lang="it"> <html lang="it">
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
<title>Gestione Incidenti (BI) - NIS2 Agile</title> <title>Gestione Incidenti (BI) - NIS2 Agile</title>
<!-- Bootstrap Italia v2.18.1 self-hostato (regola: MAI CDN). Caricato PRIMA di style.css <!-- Bootstrap Italia v2.18.1 self-hostato (regola: MAI CDN). Caricato PRIMA di style.css
cosi' style.css (design system esistente) resta autorevole per i widget renderizzati cosi' style.css (design system esistente) resta autorevole per i widget renderizzati
@@ -259,6 +259,19 @@
.filters-bar .form-select { min-width: 100%; } .filters-bar .form-select { min-width: 100%; }
} }
</style> </style>
<!-- PWA:start -->
<link rel="manifest" href="/manifest.webmanifest">
<meta name="theme-color" content="#0066CC">
<link rel="icon" type="image/png" sizes="32x32" href="/assets/icons/favicon-32.png">
<link rel="icon" type="image/png" sizes="16x16" href="/assets/icons/favicon-16.png">
<link rel="apple-touch-icon" sizes="180x180" href="/assets/icons/apple-touch-icon.png">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="default">
<meta name="apple-mobile-web-app-title" content="NIS2 Agile">
<meta name="application-name" content="NIS2 Agile">
<script src="/js/pwa.js?v=20260614" defer></script>
<!-- PWA:end -->
</head> </head>
<body> <body>
<div class="app-layout"> <div class="app-layout">
+14 -1
View File
@@ -2,7 +2,7 @@
<html lang="it"> <html lang="it">
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
<title>Gestione Incidenti - NIS2 Agile</title> <title>Gestione Incidenti - NIS2 Agile</title>
<!-- Bootstrap Italia v2.18.1 self-hostato (regola: MAI CDN). Caricato PRIMA di style.css <!-- Bootstrap Italia v2.18.1 self-hostato (regola: MAI CDN). Caricato PRIMA di style.css
cosi' style.css (design system esistente) resta autorevole per i widget renderizzati cosi' style.css (design system esistente) resta autorevole per i widget renderizzati
@@ -259,6 +259,19 @@
.filters-bar .form-select { min-width: 100%; } .filters-bar .form-select { min-width: 100%; }
} }
</style> </style>
<!-- PWA:start -->
<link rel="manifest" href="/manifest.webmanifest">
<meta name="theme-color" content="#0066CC">
<link rel="icon" type="image/png" sizes="32x32" href="/assets/icons/favicon-32.png">
<link rel="icon" type="image/png" sizes="16x16" href="/assets/icons/favicon-16.png">
<link rel="apple-touch-icon" sizes="180x180" href="/assets/icons/apple-touch-icon.png">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="default">
<meta name="apple-mobile-web-app-title" content="NIS2 Agile">
<meta name="application-name" content="NIS2 Agile">
<script src="/js/pwa.js?v=20260614" defer></script>
<!-- PWA:end -->
</head> </head>
<body> <body>
<div class="app-layout"> <div class="app-layout">
+14 -1
View File
@@ -2,7 +2,7 @@
<html lang="it"> <html lang="it">
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
<title>NIS2 Agile — Compliance NIS2 semplificata per aziende e consulenti</title> <title>NIS2 Agile — Compliance NIS2 semplificata per aziende e consulenti</title>
<meta name="description" content="Piattaforma SaaS multi-tenant per la compliance NIS2 (EU 2022/2555 e D.Lgs. 138/2024). Doppia gap analysis Art.21 e misure di base ACN (Det. 164179/2025), risk management, incident response Art.23, portale fornitori e AI consulente ancorata alle fonti normative certe."> <meta name="description" content="Piattaforma SaaS multi-tenant per la compliance NIS2 (EU 2022/2555 e D.Lgs. 138/2024). Doppia gap analysis Art.21 e misure di base ACN (Det. 164179/2025), risk management, incident response Art.23, portale fornitori e AI consulente ancorata alle fonti normative certe.">
<link rel="canonical" href="https://nis2.agile.software/"> <link rel="canonical" href="https://nis2.agile.software/">
@@ -33,6 +33,19 @@
footer.app-footer a { color: #cbd5e1; } footer.app-footer a { color: #cbd5e1; }
</style> </style>
<script defer data-domain="nis2.agile.software" src="https://analytics.agile.software/js/script.js"></script> <script defer data-domain="nis2.agile.software" src="https://analytics.agile.software/js/script.js"></script>
<!-- PWA:start -->
<link rel="manifest" href="/manifest.webmanifest">
<meta name="theme-color" content="#0066CC">
<link rel="icon" type="image/png" sizes="32x32" href="/assets/icons/favicon-32.png">
<link rel="icon" type="image/png" sizes="16x16" href="/assets/icons/favicon-16.png">
<link rel="apple-touch-icon" sizes="180x180" href="/assets/icons/apple-touch-icon.png">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="default">
<meta name="apple-mobile-web-app-title" content="NIS2 Agile">
<meta name="application-name" content="NIS2 Agile">
<script src="/js/pwa.js?v=20260614" defer></script>
<!-- PWA:end -->
</head> </head>
<body> <body>
+14 -1
View File
@@ -2,7 +2,7 @@
<html lang="en"> <html lang="en">
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
<title>NIS2 Agile — Simplified NIS2 compliance for companies and consultants</title> <title>NIS2 Agile — Simplified NIS2 compliance for companies and consultants</title>
<meta name="description" content="Multi-tenant SaaS platform for compliance with the NIS2 Directive (EU 2022/2555) and Legislative Decree 138/2024. AI gap analysis, risk management, Article 23 incident response, policies, training."> <meta name="description" content="Multi-tenant SaaS platform for compliance with the NIS2 Directive (EU 2022/2555) and Legislative Decree 138/2024. AI gap analysis, risk management, Article 23 incident response, policies, training.">
<link rel="canonical" href="https://nis2.agile.software/index-en.html"> <link rel="canonical" href="https://nis2.agile.software/index-en.html">
@@ -678,6 +678,19 @@
<link rel="stylesheet" href="mobile-conversion.css?v=20260519a"> <link rel="stylesheet" href="mobile-conversion.css?v=20260519a">
<!-- Plausible Analytics --> <!-- Plausible Analytics -->
<script defer data-domain="nis2.agile.software" src="https://analytics.agile.software/js/script.js"></script> <script defer data-domain="nis2.agile.software" src="https://analytics.agile.software/js/script.js"></script>
<!-- PWA:start -->
<link rel="manifest" href="/manifest.webmanifest">
<meta name="theme-color" content="#0066CC">
<link rel="icon" type="image/png" sizes="32x32" href="/assets/icons/favicon-32.png">
<link rel="icon" type="image/png" sizes="16x16" href="/assets/icons/favicon-16.png">
<link rel="apple-touch-icon" sizes="180x180" href="/assets/icons/apple-touch-icon.png">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="default">
<meta name="apple-mobile-web-app-title" content="NIS2 Agile">
<meta name="application-name" content="NIS2 Agile">
<script src="/js/pwa.js?v=20260614" defer></script>
<!-- PWA:end -->
</head> </head>
<body> <body>
+14 -1
View File
@@ -2,7 +2,7 @@
<html lang="it"> <html lang="it">
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
<title>NIS2 Agile — Compliance NIS2 semplificata per aziende e consulenti</title> <title>NIS2 Agile — Compliance NIS2 semplificata per aziende e consulenti</title>
<meta name="description" content="Piattaforma SaaS multi-tenant per la compliance NIS2 (EU 2022/2555 e D.Lgs. 138/2024). Doppia gap analysis Art.21 e misure di base ACN (Det. 164179/2025), risk management, incident response Art.23, portale fornitori e AI consulente ancorata alle fonti normative certe."> <meta name="description" content="Piattaforma SaaS multi-tenant per la compliance NIS2 (EU 2022/2555 e D.Lgs. 138/2024). Doppia gap analysis Art.21 e misure di base ACN (Det. 164179/2025), risk management, incident response Art.23, portale fornitori e AI consulente ancorata alle fonti normative certe.">
<link rel="canonical" href="https://nis2.agile.software/"> <link rel="canonical" href="https://nis2.agile.software/">
@@ -693,6 +693,19 @@
<link rel="stylesheet" href="mobile-conversion.css?v=20260519a"> <link rel="stylesheet" href="mobile-conversion.css?v=20260519a">
<!-- Plausible Analytics --> <!-- Plausible Analytics -->
<script defer data-domain="nis2.agile.software" src="https://analytics.agile.software/js/script.js"></script> <script defer data-domain="nis2.agile.software" src="https://analytics.agile.software/js/script.js"></script>
<!-- PWA:start -->
<link rel="manifest" href="/manifest.webmanifest">
<meta name="theme-color" content="#0066CC">
<link rel="icon" type="image/png" sizes="32x32" href="/assets/icons/favicon-32.png">
<link rel="icon" type="image/png" sizes="16x16" href="/assets/icons/favicon-16.png">
<link rel="apple-touch-icon" sizes="180x180" href="/assets/icons/apple-touch-icon.png">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="default">
<meta name="apple-mobile-web-app-title" content="NIS2 Agile">
<meta name="application-name" content="NIS2 Agile">
<script src="/js/pwa.js?v=20260614" defer></script>
<!-- PWA:end -->
</head> </head>
<body> <body>
+14 -1
View File
@@ -2,7 +2,7 @@
<html lang="it"> <html lang="it">
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
<title>AllRisk × NIS2 Agile — Integrazione</title> <title>AllRisk × NIS2 Agile — Integrazione</title>
<style> <style>
* { box-sizing: border-box; margin: 0; padding: 0; } * { box-sizing: border-box; margin: 0; padding: 0; }
@@ -35,6 +35,19 @@
.field-map th { padding: 9px 12px; background: #f1f5f9; font-size: 0.8rem; font-weight: 700; text-align: left; } .field-map th { padding: 9px 12px; background: #f1f5f9; font-size: 0.8rem; font-weight: 700; text-align: left; }
.field-map td { padding: 9px 12px; border-bottom: 1px solid var(--gray-200); font-size: 0.8rem; } .field-map td { padding: 9px 12px; border-bottom: 1px solid var(--gray-200); font-size: 0.8rem; }
</style> </style>
<!-- PWA:start -->
<link rel="manifest" href="/manifest.webmanifest">
<meta name="theme-color" content="#0066CC">
<link rel="icon" type="image/png" sizes="32x32" href="/assets/icons/favicon-32.png">
<link rel="icon" type="image/png" sizes="16x16" href="/assets/icons/favicon-16.png">
<link rel="apple-touch-icon" sizes="180x180" href="/assets/icons/apple-touch-icon.png">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="default">
<meta name="apple-mobile-web-app-title" content="NIS2 Agile">
<meta name="application-name" content="NIS2 Agile">
<script src="/js/pwa.js?v=20260614" defer></script>
<!-- PWA:end -->
</head> </head>
<body> <body>
<div class="header"> <div class="header">
+14 -1
View File
@@ -2,7 +2,7 @@
<html lang="it"> <html lang="it">
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
<title>NIS2 Agile — Integrazioni</title> <title>NIS2 Agile — Integrazioni</title>
<style> <style>
* { box-sizing: border-box; margin: 0; padding: 0; } * { box-sizing: border-box; margin: 0; padding: 0; }
@@ -26,6 +26,19 @@
.card-link:hover { text-decoration: underline; } .card-link:hover { text-decoration: underline; }
.badge { display: inline-flex; padding: 3px 8px; border-radius: 20px; font-size: 0.7rem; font-weight: 700; margin-bottom: 12px; } .badge { display: inline-flex; padding: 3px 8px; border-radius: 20px; font-size: 0.7rem; font-weight: 700; margin-bottom: 12px; }
</style> </style>
<!-- PWA:start -->
<link rel="manifest" href="/manifest.webmanifest">
<meta name="theme-color" content="#0066CC">
<link rel="icon" type="image/png" sizes="32x32" href="/assets/icons/favicon-32.png">
<link rel="icon" type="image/png" sizes="16x16" href="/assets/icons/favicon-16.png">
<link rel="apple-touch-icon" sizes="180x180" href="/assets/icons/apple-touch-icon.png">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="default">
<meta name="apple-mobile-web-app-title" content="NIS2 Agile">
<meta name="application-name" content="NIS2 Agile">
<script src="/js/pwa.js?v=20260614" defer></script>
<!-- PWA:end -->
</head> </head>
<body> <body>
<div class="container"> <div class="container">
+14 -1
View File
@@ -2,7 +2,7 @@
<html lang="it"> <html lang="it">
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
<title>231 Agile × NIS2 Agile — Integrazione</title> <title>231 Agile × NIS2 Agile — Integrazione</title>
<style> <style>
* { box-sizing: border-box; margin: 0; padding: 0; } * { box-sizing: border-box; margin: 0; padding: 0; }
@@ -44,6 +44,19 @@
.metric-val { font-size: 1.25rem; font-weight: 700; color: var(--gray-900); } .metric-val { font-size: 1.25rem; font-weight: 700; color: var(--gray-900); }
.metric-label { font-size: 0.7rem; color: var(--gray-500); margin-top: 2px; } .metric-label { font-size: 0.7rem; color: var(--gray-500); margin-top: 2px; }
</style> </style>
<!-- PWA:start -->
<link rel="manifest" href="/manifest.webmanifest">
<meta name="theme-color" content="#0066CC">
<link rel="icon" type="image/png" sizes="32x32" href="/assets/icons/favicon-32.png">
<link rel="icon" type="image/png" sizes="16x16" href="/assets/icons/favicon-16.png">
<link rel="apple-touch-icon" sizes="180x180" href="/assets/icons/apple-touch-icon.png">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="default">
<meta name="apple-mobile-web-app-title" content="NIS2 Agile">
<meta name="application-name" content="NIS2 Agile">
<script src="/js/pwa.js?v=20260614" defer></script>
<!-- PWA:end -->
</head> </head>
<body> <body>
<div class="header"> <div class="header">
+14 -1
View File
@@ -2,7 +2,7 @@
<html lang="it"> <html lang="it">
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
<title>SIEM × NIS2 Agile — Integrazione</title> <title>SIEM × NIS2 Agile — Integrazione</title>
<style> <style>
* { box-sizing: border-box; margin: 0; padding: 0; } * { box-sizing: border-box; margin: 0; padding: 0; }
@@ -33,6 +33,19 @@
.info-box { padding: 14px 16px; border-radius: var(--radius); margin: 16px 0; font-size: 0.875rem; } .info-box { padding: 14px 16px; border-radius: var(--radius); margin: 16px 0; font-size: 0.875rem; }
.info-purple { background: #f5f3ff; border-left: 3px solid var(--purple); color: #4c1d95; } .info-purple { background: #f5f3ff; border-left: 3px solid var(--purple); color: #4c1d95; }
</style> </style>
<!-- PWA:start -->
<link rel="manifest" href="/manifest.webmanifest">
<meta name="theme-color" content="#0066CC">
<link rel="icon" type="image/png" sizes="32x32" href="/assets/icons/favicon-32.png">
<link rel="icon" type="image/png" sizes="16x16" href="/assets/icons/favicon-16.png">
<link rel="apple-touch-icon" sizes="180x180" href="/assets/icons/apple-touch-icon.png">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="default">
<meta name="apple-mobile-web-app-title" content="NIS2 Agile">
<meta name="application-name" content="NIS2 Agile">
<script src="/js/pwa.js?v=20260614" defer></script>
<!-- PWA:end -->
</head> </head>
<body> <body>
<div class="header"> <div class="header">
+14 -1
View File
@@ -2,7 +2,7 @@
<html lang="it"> <html lang="it">
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
<title>SustainAI × NIS2 Agile — Integrazione</title> <title>SustainAI × NIS2 Agile — Integrazione</title>
<style> <style>
* { box-sizing: border-box; margin: 0; padding: 0; } * { box-sizing: border-box; margin: 0; padding: 0; }
@@ -38,6 +38,19 @@
.esg-e { background: #dcfce7; color: #166534; } .esg-e { background: #dcfce7; color: #166534; }
.esg-s { background: #faf5ff; color: #6b21a8; } .esg-s { background: #faf5ff; color: #6b21a8; }
</style> </style>
<!-- PWA:start -->
<link rel="manifest" href="/manifest.webmanifest">
<meta name="theme-color" content="#0066CC">
<link rel="icon" type="image/png" sizes="32x32" href="/assets/icons/favicon-32.png">
<link rel="icon" type="image/png" sizes="16x16" href="/assets/icons/favicon-16.png">
<link rel="apple-touch-icon" sizes="180x180" href="/assets/icons/apple-touch-icon.png">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="default">
<meta name="apple-mobile-web-app-title" content="NIS2 Agile">
<meta name="application-name" content="NIS2 Agile">
<script src="/js/pwa.js?v=20260614" defer></script>
<!-- PWA:end -->
</head> </head>
<body> <body>
<div class="header"> <div class="header">
+14 -1
View File
@@ -2,7 +2,7 @@
<html lang="it"> <html lang="it">
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1"> <meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
<title>NIS2 Agile — Integrazioni Esterne</title> <title>NIS2 Agile — Integrazioni Esterne</title>
<link rel="stylesheet" href="css/style.css?v=20260613b"> <link rel="stylesheet" href="css/style.css?v=20260613b">
<style> <style>
@@ -203,6 +203,19 @@
.tab-pane { display: none; } .tab-pane { display: none; }
.tab-pane.active { display: block; } .tab-pane.active { display: block; }
</style> </style>
<!-- PWA:start -->
<link rel="manifest" href="/manifest.webmanifest">
<meta name="theme-color" content="#0066CC">
<link rel="icon" type="image/png" sizes="32x32" href="/assets/icons/favicon-32.png">
<link rel="icon" type="image/png" sizes="16x16" href="/assets/icons/favicon-16.png">
<link rel="apple-touch-icon" sizes="180x180" href="/assets/icons/apple-touch-icon.png">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="default">
<meta name="apple-mobile-web-app-title" content="NIS2 Agile">
<meta name="application-name" content="NIS2 Agile">
<script src="/js/pwa.js?v=20260614" defer></script>
<!-- PWA:end -->
</head> </head>
<body> <body>
+14 -1
View File
@@ -2,7 +2,7 @@
<html lang="it"> <html lang="it">
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
<title>Modello Organizzativo SGSI (ISO 27001) (BI) - NIS2 Agile</title> <title>Modello Organizzativo SGSI (ISO 27001) (BI) - NIS2 Agile</title>
<!-- Bootstrap Italia v2.18.1 self-hostato (regola: MAI CDN). Caricato PRIMA di style.css <!-- Bootstrap Italia v2.18.1 self-hostato (regola: MAI CDN). Caricato PRIMA di style.css
cosi' style.css (design system esistente) resta autorevole per i widget renderizzati cosi' style.css (design system esistente) resta autorevole per i widget renderizzati
@@ -47,6 +47,19 @@
/* Allinea l'icona sprite BI nel bottone Esporta col testo */ /* Allinea l'icona sprite BI nel bottone Esporta col testo */
.content-header-actions .btn .icon { vertical-align:text-bottom; margin-right:4px; } .content-header-actions .btn .icon { vertical-align:text-bottom; margin-right:4px; }
</style> </style>
<!-- PWA:start -->
<link rel="manifest" href="/manifest.webmanifest">
<meta name="theme-color" content="#0066CC">
<link rel="icon" type="image/png" sizes="32x32" href="/assets/icons/favicon-32.png">
<link rel="icon" type="image/png" sizes="16x16" href="/assets/icons/favicon-16.png">
<link rel="apple-touch-icon" sizes="180x180" href="/assets/icons/apple-touch-icon.png">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="default">
<meta name="apple-mobile-web-app-title" content="NIS2 Agile">
<meta name="application-name" content="NIS2 Agile">
<script src="/js/pwa.js?v=20260614" defer></script>
<!-- PWA:end -->
</head> </head>
<body> <body>
<div class="app-layout"> <div class="app-layout">
+14 -1
View File
@@ -2,7 +2,7 @@
<html lang="it"> <html lang="it">
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
<title>Modello Organizzativo SGSI (ISO 27001) - NIS2 Agile</title> <title>Modello Organizzativo SGSI (ISO 27001) - NIS2 Agile</title>
<!-- Bootstrap Italia v2.18.1 self-hostato (regola: MAI CDN). Caricato PRIMA di style.css <!-- Bootstrap Italia v2.18.1 self-hostato (regola: MAI CDN). Caricato PRIMA di style.css
cosi' style.css (design system esistente) resta autorevole per i widget renderizzati cosi' style.css (design system esistente) resta autorevole per i widget renderizzati
@@ -47,6 +47,19 @@
/* Allinea l'icona sprite BI nel bottone Esporta col testo */ /* Allinea l'icona sprite BI nel bottone Esporta col testo */
.content-header-actions .btn .icon { vertical-align:text-bottom; margin-right:4px; } .content-header-actions .btn .icon { vertical-align:text-bottom; margin-right:4px; }
</style> </style>
<!-- PWA:start -->
<link rel="manifest" href="/manifest.webmanifest">
<meta name="theme-color" content="#0066CC">
<link rel="icon" type="image/png" sizes="32x32" href="/assets/icons/favicon-32.png">
<link rel="icon" type="image/png" sizes="16x16" href="/assets/icons/favicon-16.png">
<link rel="apple-touch-icon" sizes="180x180" href="/assets/icons/apple-touch-icon.png">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="default">
<meta name="apple-mobile-web-app-title" content="NIS2 Agile">
<meta name="application-name" content="NIS2 Agile">
<script src="/js/pwa.js?v=20260614" defer></script>
<!-- PWA:end -->
</head> </head>
<body> <body>
<div class="app-layout"> <div class="app-layout">
+130
View File
@@ -0,0 +1,130 @@
/*
* NIS2 Agile — PWA bootstrap
* Registra il service worker e gestisce l'UI di installazione (Android + iOS).
* Vanilla JS, nessuna dipendenza. Localizzato IT/EN (chiave i18n: 'nis2_lang').
*/
(function () {
'use strict';
// --- i18n minimale, allineato a i18n.js (localStorage 'nis2_lang') ---
function lang() {
try { return (localStorage.getItem('nis2_lang') || 'it').slice(0, 2); }
catch (e) { return 'it'; }
}
var STR = {
it: {
install: 'Installa app',
banner: 'Installa NIS2 Agile sul dispositivo per un accesso più rapido.',
ios: 'Per installare: tocca Condividi e poi "Aggiungi a Home".',
close: 'Chiudi'
},
en: {
install: 'Install app',
banner: 'Install NIS2 Agile on your device for faster access.',
ios: 'To install: tap Share, then "Add to Home Screen".',
close: 'Close'
}
};
function t(k) { var l = lang(); return (STR[l] && STR[l][k]) || STR.it[k]; }
function isStandalone() {
return (window.matchMedia && window.matchMedia('(display-mode: standalone)').matches)
|| window.navigator.standalone === true;
}
// --- 1. Registrazione service worker ---
if ('serviceWorker' in navigator) {
window.addEventListener('load', function () {
navigator.serviceWorker.register('/sw.js', { scope: '/' })
.catch(function (err) { console.warn('[pwa] SW registration failed', err); });
});
}
// Gia' installata (standalone): niente banner di installazione.
if (isStandalone()) return;
// --- UI banner sobrio, indipendente dal CSS dell'app ---
function makeBanner(message, withInstallBtn) {
var bar = document.createElement('div');
bar.setAttribute('role', 'region');
bar.setAttribute('aria-label', t('install'));
bar.style.cssText = 'position:fixed;left:12px;right:12px;bottom:12px;z-index:9999;'
+ 'background:#0066CC;color:#fff;border-radius:10px;padding:12px 14px;'
+ 'box-shadow:0 6px 24px rgba(0,0,0,.25);display:flex;align-items:center;gap:10px;'
+ 'font-family:system-ui,Arial,sans-serif;font-size:.95rem;max-width:560px;margin:0 auto;';
var txt = document.createElement('span');
txt.style.cssText = 'flex:1;line-height:1.35;';
txt.textContent = message;
bar.appendChild(txt);
var btnInstall = null;
if (withInstallBtn) {
btnInstall = document.createElement('button');
btnInstall.type = 'button';
btnInstall.textContent = t('install');
btnInstall.style.cssText = 'background:#fff;color:#0066CC;border:0;border-radius:8px;'
+ 'padding:10px 16px;font-weight:600;min-height:44px;cursor:pointer;white-space:nowrap;';
bar.appendChild(btnInstall);
}
var btnClose = document.createElement('button');
btnClose.type = 'button';
btnClose.setAttribute('aria-label', t('close'));
btnClose.textContent = '✕';
btnClose.style.cssText = 'background:transparent;color:#fff;border:0;font-size:1.1rem;'
+ 'line-height:1;min-width:44px;min-height:44px;cursor:pointer;';
bar.appendChild(btnClose);
document.body.appendChild(bar);
return { bar: bar, btnInstall: btnInstall, btnClose: btnClose };
}
// --- 2. Android / Chrome: beforeinstallprompt ---
var deferred = null;
var DISMISS_KEY = 'pwa-install-dismissed';
function dismissed() { try { return localStorage.getItem(DISMISS_KEY) === '1'; } catch (e) { return false; } }
function setDismissed() { try { localStorage.setItem(DISMISS_KEY, '1'); } catch (e) {} }
window.addEventListener('beforeinstallprompt', function (e) {
e.preventDefault();
deferred = e;
if (dismissed()) return;
try {
var ui = makeBanner(t('banner'), true);
ui.btnInstall.addEventListener('click', function () {
ui.bar.remove();
if (!deferred) return;
deferred.prompt();
if (deferred.userChoice && deferred.userChoice.finally) {
deferred.userChoice.finally(function () { deferred = null; });
} else { deferred = null; }
});
ui.btnClose.addEventListener('click', function () { ui.bar.remove(); setDismissed(); });
} catch (err) { console.warn('[pwa] banner error', err); }
});
window.addEventListener('appinstalled', function () {
deferred = null;
setDismissed();
});
// --- 3. iOS Safari: nessun beforeinstallprompt -> hint manuale (una volta) ---
try {
var ua = navigator.userAgent || '';
var isIOS = /iphone|ipad|ipod/i.test(ua)
|| (/Macintosh/.test(ua) && 'ontouchend' in document); // iPad iPadOS desktop-mode
var isSafari = /safari/i.test(ua) && !/crios|fxios|edgios|android/i.test(ua);
var IOS_KEY = 'pwa-ios-hint-dismissed';
var iosDismissed = (function () { try { return localStorage.getItem(IOS_KEY) === '1'; } catch (e) { return false; } })();
if (isIOS && isSafari && !iosDismissed) {
window.addEventListener('load', function () {
var ui = makeBanner(t('ios'), false);
ui.btnClose.addEventListener('click', function () {
ui.bar.remove();
try { localStorage.setItem(IOS_KEY, '1'); } catch (e) {}
});
});
}
} catch (err) { console.warn('[pwa] ios hint error', err); }
})();
+14 -1
View File
@@ -2,7 +2,7 @@
<html lang="it"> <html lang="it">
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
<title>Knowledge Base (BI) - NIS2 Agile</title> <title>Knowledge Base (BI) - NIS2 Agile</title>
<!-- Bootstrap Italia v2.18.1 self-hostato (regola: MAI CDN). Caricato PRIMA di style.css <!-- Bootstrap Italia v2.18.1 self-hostato (regola: MAI CDN). Caricato PRIMA di style.css
cosi' style.css (design system esistente) resta autorevole per i widget renderizzati cosi' style.css (design system esistente) resta autorevole per i widget renderizzati
@@ -22,6 +22,19 @@
/* Allinea l'icona sprite BI dentro i bottoni del design system esistente */ /* Allinea l'icona sprite BI dentro i bottoni del design system esistente */
.btn .icon { fill: currentColor; vertical-align: middle; } .btn .icon { fill: currentColor; vertical-align: middle; }
</style> </style>
<!-- PWA:start -->
<link rel="manifest" href="/manifest.webmanifest">
<meta name="theme-color" content="#0066CC">
<link rel="icon" type="image/png" sizes="32x32" href="/assets/icons/favicon-32.png">
<link rel="icon" type="image/png" sizes="16x16" href="/assets/icons/favicon-16.png">
<link rel="apple-touch-icon" sizes="180x180" href="/assets/icons/apple-touch-icon.png">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="default">
<meta name="apple-mobile-web-app-title" content="NIS2 Agile">
<meta name="application-name" content="NIS2 Agile">
<script src="/js/pwa.js?v=20260614" defer></script>
<!-- PWA:end -->
</head> </head>
<body> <body>
<div class="app-layout"> <div class="app-layout">
+14 -1
View File
@@ -2,7 +2,7 @@
<html lang="it"> <html lang="it">
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
<title>Knowledge Base - NIS2 Agile</title> <title>Knowledge Base - NIS2 Agile</title>
<!-- Bootstrap Italia v2.18.1 self-hostato (regola: MAI CDN). Caricato PRIMA di style.css <!-- Bootstrap Italia v2.18.1 self-hostato (regola: MAI CDN). Caricato PRIMA di style.css
cosi' style.css (design system esistente) resta autorevole per i widget renderizzati cosi' style.css (design system esistente) resta autorevole per i widget renderizzati
@@ -22,6 +22,19 @@
/* Allinea l'icona sprite BI dentro i bottoni del design system esistente */ /* Allinea l'icona sprite BI dentro i bottoni del design system esistente */
.btn .icon { fill: currentColor; vertical-align: middle; } .btn .icon { fill: currentColor; vertical-align: middle; }
</style> </style>
<!-- PWA:start -->
<link rel="manifest" href="/manifest.webmanifest">
<meta name="theme-color" content="#0066CC">
<link rel="icon" type="image/png" sizes="32x32" href="/assets/icons/favicon-32.png">
<link rel="icon" type="image/png" sizes="16x16" href="/assets/icons/favicon-16.png">
<link rel="apple-touch-icon" sizes="180x180" href="/assets/icons/apple-touch-icon.png">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="default">
<meta name="apple-mobile-web-app-title" content="NIS2 Agile">
<meta name="application-name" content="NIS2 Agile">
<script src="/js/pwa.js?v=20260614" defer></script>
<!-- PWA:end -->
</head> </head>
<body> <body>
<div class="app-layout"> <div class="app-layout">
+14 -1
View File
@@ -2,7 +2,7 @@
<html lang="it"> <html lang="it">
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1"> <meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
<title>NIS2 Agile — Gestione Licenze</title> <title>NIS2 Agile — Gestione Licenze</title>
<link rel="stylesheet" href="css/style.css?v=20260613b"> <link rel="stylesheet" href="css/style.css?v=20260613b">
<style> <style>
@@ -217,6 +217,19 @@ body { background: var(--bg-main); }
.modal-box h3 { font-size: 1rem; margin-bottom: 1.25rem; } .modal-box h3 { font-size: 1rem; margin-bottom: 1.25rem; }
.modal-close { float: right; background: none; border: none; color: var(--text-secondary); font-size: 1.2rem; cursor: pointer; margin-top: -.2rem; } .modal-close { float: right; background: none; border: none; color: var(--text-secondary); font-size: 1.2rem; cursor: pointer; margin-top: -.2rem; }
</style> </style>
<!-- PWA:start -->
<link rel="manifest" href="/manifest.webmanifest">
<meta name="theme-color" content="#0066CC">
<link rel="icon" type="image/png" sizes="32x32" href="/assets/icons/favicon-32.png">
<link rel="icon" type="image/png" sizes="16x16" href="/assets/icons/favicon-16.png">
<link rel="apple-touch-icon" sizes="180x180" href="/assets/icons/apple-touch-icon.png">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="default">
<meta name="apple-mobile-web-app-title" content="NIS2 Agile">
<meta name="application-name" content="NIS2 Agile">
<script src="/js/pwa.js?v=20260614" defer></script>
<!-- PWA:end -->
</head> </head>
<body> <body>
+14 -1
View File
@@ -2,7 +2,7 @@
<html lang="it"> <html lang="it">
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
<title>Accedi - NIS2 Agile</title> <title>Accedi - NIS2 Agile</title>
<!-- PILOTA Bootstrap Italia v2.18.1 (Opzione B). Self-hostato: asset serviti da /vendor (regola 'MAI CDN'). --> <!-- PILOTA Bootstrap Italia v2.18.1 (Opzione B). Self-hostato: asset serviti da /vendor (regola 'MAI CDN'). -->
<link rel="stylesheet" href="vendor/bootstrap-italia/dist/css/bootstrap-italia.min.css"> <link rel="stylesheet" href="vendor/bootstrap-italia/dist/css/bootstrap-italia.min.css">
@@ -19,6 +19,19 @@
.pw-toggle { position: absolute; right: 8px; top: 8px; background: none; border: none; .pw-toggle { position: absolute; right: 8px; top: 8px; background: none; border: none;
color: #5a6772; cursor: pointer; padding: 6px; } color: #5a6772; cursor: pointer; padding: 6px; }
</style> </style>
<!-- PWA:start -->
<link rel="manifest" href="/manifest.webmanifest">
<meta name="theme-color" content="#0066CC">
<link rel="icon" type="image/png" sizes="32x32" href="/assets/icons/favicon-32.png">
<link rel="icon" type="image/png" sizes="16x16" href="/assets/icons/favicon-16.png">
<link rel="apple-touch-icon" sizes="180x180" href="/assets/icons/apple-touch-icon.png">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="default">
<meta name="apple-mobile-web-app-title" content="NIS2 Agile">
<meta name="application-name" content="NIS2 Agile">
<script src="/js/pwa.js?v=20260614" defer></script>
<!-- PWA:end -->
</head> </head>
<body> <body>
<main class="auth-wrap"> <main class="auth-wrap">
+14 -1
View File
@@ -2,7 +2,7 @@
<html lang="it"> <html lang="it">
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
<title>Accedi - NIS2 Agile</title> <title>Accedi - NIS2 Agile</title>
<!-- PILOTA Bootstrap Italia v2.18.1 (Opzione B). Self-hostato: asset serviti da /vendor (regola 'MAI CDN'). --> <!-- PILOTA Bootstrap Italia v2.18.1 (Opzione B). Self-hostato: asset serviti da /vendor (regola 'MAI CDN'). -->
<link rel="stylesheet" href="vendor/bootstrap-italia/dist/css/bootstrap-italia.min.css"> <link rel="stylesheet" href="vendor/bootstrap-italia/dist/css/bootstrap-italia.min.css">
@@ -19,6 +19,19 @@
.pw-toggle { position: absolute; right: 8px; top: 8px; background: none; border: none; .pw-toggle { position: absolute; right: 8px; top: 8px; background: none; border: none;
color: #5a6772; cursor: pointer; padding: 6px; } color: #5a6772; cursor: pointer; padding: 6px; }
</style> </style>
<!-- PWA:start -->
<link rel="manifest" href="/manifest.webmanifest">
<meta name="theme-color" content="#0066CC">
<link rel="icon" type="image/png" sizes="32x32" href="/assets/icons/favicon-32.png">
<link rel="icon" type="image/png" sizes="16x16" href="/assets/icons/favicon-16.png">
<link rel="apple-touch-icon" sizes="180x180" href="/assets/icons/apple-touch-icon.png">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="default">
<meta name="apple-mobile-web-app-title" content="NIS2 Agile">
<meta name="application-name" content="NIS2 Agile">
<script src="/js/pwa.js?v=20260614" defer></script>
<!-- PWA:end -->
</head> </head>
<body> <body>
<main class="auth-wrap"> <main class="auth-wrap">
+59
View File
@@ -0,0 +1,59 @@
{
"name": "NIS2 Agile — Compliance NIS2 & D.Lgs. 138/2024",
"short_name": "NIS2 Agile",
"description": "Piattaforma per la conformità alla direttiva NIS2 e al D.Lgs. 138/2024.",
"lang": "it",
"dir": "ltr",
"start_url": "/dashboard.html?source=pwa",
"scope": "/",
"display": "standalone",
"display_override": ["standalone", "minimal-ui"],
"orientation": "any",
"theme_color": "#0066CC",
"background_color": "#FFFFFF",
"categories": ["business", "productivity", "security"],
"icons": [
{
"src": "/assets/icons/icon-192.png",
"sizes": "192x192",
"type": "image/png",
"purpose": "any"
},
{
"src": "/assets/icons/icon-512.png",
"sizes": "512x512",
"type": "image/png",
"purpose": "any"
},
{
"src": "/assets/icons/icon-192-maskable.png",
"sizes": "192x192",
"type": "image/png",
"purpose": "maskable"
},
{
"src": "/assets/icons/icon-512-maskable.png",
"sizes": "512x512",
"type": "image/png",
"purpose": "maskable"
}
],
"shortcuts": [
{
"name": "Dashboard",
"short_name": "Dashboard",
"url": "/dashboard.html?source=pwa",
"icons": [
{ "src": "/assets/icons/icon-192.png", "sizes": "192x192", "type": "image/png" }
]
},
{
"name": "Incidenti Art.23",
"short_name": "Incidenti",
"url": "/incidents.html?source=pwa",
"icons": [
{ "src": "/assets/icons/icon-192.png", "sizes": "192x192", "type": "image/png" }
]
}
]
}
+14 -1
View File
@@ -2,7 +2,7 @@
<html lang="it"> <html lang="it">
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1"> <meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
<title>NIS2 Agile — License API · Documentazione Marketing</title> <title>NIS2 Agile — License API · Documentazione Marketing</title>
<link rel="stylesheet" href="css/style.css?v=20260613b"> <link rel="stylesheet" href="css/style.css?v=20260613b">
<style> <style>
@@ -81,6 +81,19 @@ table.resp code { background: rgba(255,255,255,.06); padding: .1rem .3rem; borde
.sc-ro { background: rgba(34,197,94,.15); color: #22c55e; } .sc-ro { background: rgba(34,197,94,.15); color: #22c55e; }
.sc-no { background: rgba(156,163,175,.15); color: #9ca3af; } .sc-no { background: rgba(156,163,175,.15); color: #9ca3af; }
</style> </style>
<!-- PWA:start -->
<link rel="manifest" href="/manifest.webmanifest">
<meta name="theme-color" content="#0066CC">
<link rel="icon" type="image/png" sizes="32x32" href="/assets/icons/favicon-32.png">
<link rel="icon" type="image/png" sizes="16x16" href="/assets/icons/favicon-16.png">
<link rel="apple-touch-icon" sizes="180x180" href="/assets/icons/apple-touch-icon.png">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="default">
<meta name="apple-mobile-web-app-title" content="NIS2 Agile">
<meta name="application-name" content="NIS2 Agile">
<script src="/js/pwa.js?v=20260614" defer></script>
<!-- PWA:end -->
</head> </head>
<body> <body>
<div class="doc-layout"> <div class="doc-layout">
+14 -1
View File
@@ -2,7 +2,7 @@
<html lang="it"> <html lang="it">
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
<title>Aggiornamenti Normativi (BI) - NIS2 Agile</title> <title>Aggiornamenti Normativi (BI) - NIS2 Agile</title>
<!-- Bootstrap Italia v2.18.1 self-hostato (regola: MAI CDN). Caricato PRIMA di style.css <!-- Bootstrap Italia v2.18.1 self-hostato (regola: MAI CDN). Caricato PRIMA di style.css
cosi' style.css (design system esistente) resta autorevole per i widget renderizzati cosi' style.css (design system esistente) resta autorevole per i widget renderizzati
@@ -27,6 +27,19 @@
.ack-progress { height: 6px; background: var(--gray-200); border-radius: 3px; overflow: hidden; } .ack-progress { height: 6px; background: var(--gray-200); border-radius: 3px; overflow: hidden; }
.ack-progress-bar { height: 100%; background: var(--primary); border-radius: 3px; transition: width 0.5s ease; } .ack-progress-bar { height: 100%; background: var(--primary); border-radius: 3px; transition: width 0.5s ease; }
</style> </style>
<!-- PWA:start -->
<link rel="manifest" href="/manifest.webmanifest">
<meta name="theme-color" content="#0066CC">
<link rel="icon" type="image/png" sizes="32x32" href="/assets/icons/favicon-32.png">
<link rel="icon" type="image/png" sizes="16x16" href="/assets/icons/favicon-16.png">
<link rel="apple-touch-icon" sizes="180x180" href="/assets/icons/apple-touch-icon.png">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="default">
<meta name="apple-mobile-web-app-title" content="NIS2 Agile">
<meta name="application-name" content="NIS2 Agile">
<script src="/js/pwa.js?v=20260614" defer></script>
<!-- PWA:end -->
</head> </head>
<body> <body>
<div class="app-layout"> <div class="app-layout">
+14 -1
View File
@@ -2,7 +2,7 @@
<html lang="it"> <html lang="it">
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
<title>Aggiornamenti Normativi - NIS2 Agile</title> <title>Aggiornamenti Normativi - NIS2 Agile</title>
<!-- Bootstrap Italia v2.18.1 self-hostato (regola: MAI CDN). Caricato PRIMA di style.css <!-- Bootstrap Italia v2.18.1 self-hostato (regola: MAI CDN). Caricato PRIMA di style.css
cosi' style.css (design system esistente) resta autorevole per i widget renderizzati cosi' style.css (design system esistente) resta autorevole per i widget renderizzati
@@ -27,6 +27,19 @@
.ack-progress { height: 6px; background: var(--gray-200); border-radius: 3px; overflow: hidden; } .ack-progress { height: 6px; background: var(--gray-200); border-radius: 3px; overflow: hidden; }
.ack-progress-bar { height: 100%; background: var(--primary); border-radius: 3px; transition: width 0.5s ease; } .ack-progress-bar { height: 100%; background: var(--primary); border-radius: 3px; transition: width 0.5s ease; }
</style> </style>
<!-- PWA:start -->
<link rel="manifest" href="/manifest.webmanifest">
<meta name="theme-color" content="#0066CC">
<link rel="icon" type="image/png" sizes="32x32" href="/assets/icons/favicon-32.png">
<link rel="icon" type="image/png" sizes="16x16" href="/assets/icons/favicon-16.png">
<link rel="apple-touch-icon" sizes="180x180" href="/assets/icons/apple-touch-icon.png">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="default">
<meta name="apple-mobile-web-app-title" content="NIS2 Agile">
<meta name="application-name" content="NIS2 Agile">
<script src="/js/pwa.js?v=20260614" defer></script>
<!-- PWA:end -->
</head> </head>
<body> <body>
<div class="app-layout"> <div class="app-layout">
+36
View File
@@ -0,0 +1,36 @@
<!DOCTYPE html>
<html lang="it">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
<meta name="theme-color" content="#0066CC">
<title>Offline - NIS2 Agile</title>
<link rel="icon" type="image/png" sizes="32x32" href="/assets/icons/favicon-32.png">
<link rel="apple-touch-icon" sizes="180x180" href="/assets/icons/apple-touch-icon.png">
<link rel="stylesheet" href="/vendor/bootstrap-italia/dist/css/bootstrap-italia.min.css">
<style>
/* Fallback minimale: la pagina resta leggibile anche se il CSS di
Bootstrap Italia non e' presente nella cache. */
body { margin: 0; min-height: 100vh; display: flex; align-items: center;
justify-content: center; padding: 24px; text-align: center; background: #f5f6f7;
color: #1b1c1d; font-family: 'Titillium Web', system-ui, Arial, sans-serif; }
.offline-card { max-width: 420px; background: #fff; border-radius: 12px;
padding: 32px 28px; box-shadow: 0 4px 24px rgba(0,0,0,.08); }
.offline-card img { width: 72px; height: 72px; margin-bottom: 16px; }
.offline-card h1 { font-size: 1.4rem; margin: 0 0 8px; color: #0066CC; }
.offline-card p { margin: 0 0 24px; color: #5a6772; font-size: 1rem; line-height: 1.5; }
.offline-btn { display: inline-block; background: #0066CC; color: #fff; border: 0;
border-radius: 8px; padding: 12px 24px; font-size: 1rem; min-height: 44px;
cursor: pointer; text-decoration: none; }
.offline-btn:hover { background: #0052a3; }
</style>
</head>
<body>
<main class="offline-card">
<img src="/assets/icons/icon-192.png" alt="NIS2 Agile" width="72" height="72">
<h1>Sei offline</h1>
<p>Controlla la connessione di rete e riprova. Le pagine gi&agrave; visitate restano disponibili anche senza connessione.</p>
<button type="button" class="offline-btn" onclick="location.reload()">Riprova</button>
</main>
</body>
</html>
+14 -1
View File
@@ -2,7 +2,7 @@
<html lang="it"> <html lang="it">
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
<title>Onboarding - NIS2 Agile</title> <title>Onboarding - NIS2 Agile</title>
<!-- Bootstrap Italia v2.18.1 — self-hostato da /vendor (MAI CDN). Variante "-bi" della onboarding.html. --> <!-- Bootstrap Italia v2.18.1 — self-hostato da /vendor (MAI CDN). Variante "-bi" della onboarding.html. -->
<link rel="stylesheet" href="vendor/bootstrap-italia/dist/css/bootstrap-italia.min.css"> <link rel="stylesheet" href="vendor/bootstrap-italia/dist/css/bootstrap-italia.min.css">
@@ -100,6 +100,19 @@
.wizard-step-title { font-size: 1.25rem; } .wizard-step-title { font-size: 1.25rem; }
} }
</style> </style>
<!-- PWA:start -->
<link rel="manifest" href="/manifest.webmanifest">
<meta name="theme-color" content="#0066CC">
<link rel="icon" type="image/png" sizes="32x32" href="/assets/icons/favicon-32.png">
<link rel="icon" type="image/png" sizes="16x16" href="/assets/icons/favicon-16.png">
<link rel="apple-touch-icon" sizes="180x180" href="/assets/icons/apple-touch-icon.png">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="default">
<meta name="apple-mobile-web-app-title" content="NIS2 Agile">
<meta name="application-name" content="NIS2 Agile">
<script src="/js/pwa.js?v=20260614" defer></script>
<!-- PWA:end -->
</head> </head>
<body> <body>
<div class="wizard-page"> <div class="wizard-page">
+14 -1
View File
@@ -2,7 +2,7 @@
<html lang="it"> <html lang="it">
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
<title>Onboarding - NIS2 Agile</title> <title>Onboarding - NIS2 Agile</title>
<!-- Bootstrap Italia v2.18.1 — self-hostato da /vendor (MAI CDN). Variante "-bi" della onboarding.html. --> <!-- Bootstrap Italia v2.18.1 — self-hostato da /vendor (MAI CDN). Variante "-bi" della onboarding.html. -->
<link rel="stylesheet" href="vendor/bootstrap-italia/dist/css/bootstrap-italia.min.css"> <link rel="stylesheet" href="vendor/bootstrap-italia/dist/css/bootstrap-italia.min.css">
@@ -100,6 +100,19 @@
.wizard-step-title { font-size: 1.25rem; } .wizard-step-title { font-size: 1.25rem; }
} }
</style> </style>
<!-- PWA:start -->
<link rel="manifest" href="/manifest.webmanifest">
<meta name="theme-color" content="#0066CC">
<link rel="icon" type="image/png" sizes="32x32" href="/assets/icons/favicon-32.png">
<link rel="icon" type="image/png" sizes="16x16" href="/assets/icons/favicon-16.png">
<link rel="apple-touch-icon" sizes="180x180" href="/assets/icons/apple-touch-icon.png">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="default">
<meta name="apple-mobile-web-app-title" content="NIS2 Agile">
<meta name="application-name" content="NIS2 Agile">
<script src="/js/pwa.js?v=20260614" defer></script>
<!-- PWA:end -->
</head> </head>
<body> <body>
<div class="wizard-page"> <div class="wizard-page">
+14 -1
View File
@@ -2,7 +2,7 @@
<html lang="it"> <html lang="it">
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
<title>Policy (BI) - NIS2 Agile</title> <title>Policy (BI) - NIS2 Agile</title>
<!-- Bootstrap Italia v2.18.1 self-hostato (regola: MAI CDN). Caricato PRIMA di style.css <!-- Bootstrap Italia v2.18.1 self-hostato (regola: MAI CDN). Caricato PRIMA di style.css
cosi' style.css (design system esistente) resta autorevole per i widget renderizzati cosi' style.css (design system esistente) resta autorevole per i widget renderizzati
@@ -239,6 +239,19 @@
gap: 8px; gap: 8px;
} }
</style> </style>
<!-- PWA:start -->
<link rel="manifest" href="/manifest.webmanifest">
<meta name="theme-color" content="#0066CC">
<link rel="icon" type="image/png" sizes="32x32" href="/assets/icons/favicon-32.png">
<link rel="icon" type="image/png" sizes="16x16" href="/assets/icons/favicon-16.png">
<link rel="apple-touch-icon" sizes="180x180" href="/assets/icons/apple-touch-icon.png">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="default">
<meta name="apple-mobile-web-app-title" content="NIS2 Agile">
<meta name="application-name" content="NIS2 Agile">
<script src="/js/pwa.js?v=20260614" defer></script>
<!-- PWA:end -->
</head> </head>
<body> <body>
<div class="app-layout"> <div class="app-layout">
+14 -1
View File
@@ -2,7 +2,7 @@
<html lang="it"> <html lang="it">
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
<title>Policy - NIS2 Agile</title> <title>Policy - NIS2 Agile</title>
<!-- Bootstrap Italia v2.18.1 self-hostato (regola: MAI CDN). Caricato PRIMA di style.css <!-- Bootstrap Italia v2.18.1 self-hostato (regola: MAI CDN). Caricato PRIMA di style.css
cosi' style.css (design system esistente) resta autorevole per i widget renderizzati cosi' style.css (design system esistente) resta autorevole per i widget renderizzati
@@ -239,6 +239,19 @@
gap: 8px; gap: 8px;
} }
</style> </style>
<!-- PWA:start -->
<link rel="manifest" href="/manifest.webmanifest">
<meta name="theme-color" content="#0066CC">
<link rel="icon" type="image/png" sizes="32x32" href="/assets/icons/favicon-32.png">
<link rel="icon" type="image/png" sizes="16x16" href="/assets/icons/favicon-16.png">
<link rel="apple-touch-icon" sizes="180x180" href="/assets/icons/apple-touch-icon.png">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="default">
<meta name="apple-mobile-web-app-title" content="NIS2 Agile">
<meta name="application-name" content="NIS2 Agile">
<script src="/js/pwa.js?v=20260614" defer></script>
<!-- PWA:end -->
</head> </head>
<body> <body>
<div class="app-layout"> <div class="app-layout">
+14 -1
View File
@@ -2,7 +2,7 @@
<html lang="it"> <html lang="it">
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
<title>NIS2 Agile - Compliance NIS2 AI-Powered | Agile Technology SRL</title> <title>NIS2 Agile - Compliance NIS2 AI-Powered | Agile Technology SRL</title>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css"> <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css">
<style> <style>
@@ -835,6 +835,19 @@
.bg-purple { background: var(--purple-dim); } .bg-purple { background: var(--purple-dim); }
.bg-orange { background: var(--orange-dim); } .bg-orange { background: var(--orange-dim); }
</style> </style>
<!-- PWA:start -->
<link rel="manifest" href="/manifest.webmanifest">
<meta name="theme-color" content="#0066CC">
<link rel="icon" type="image/png" sizes="32x32" href="/assets/icons/favicon-32.png">
<link rel="icon" type="image/png" sizes="16x16" href="/assets/icons/favicon-16.png">
<link rel="apple-touch-icon" sizes="180x180" href="/assets/icons/apple-touch-icon.png">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="default">
<meta name="apple-mobile-web-app-title" content="NIS2 Agile">
<meta name="application-name" content="NIS2 Agile">
<script src="/js/pwa.js?v=20260614" defer></script>
<!-- PWA:end -->
</head> </head>
<body> <body>
+14 -1
View File
@@ -2,7 +2,7 @@
<html lang="it"> <html lang="it">
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
<title>Registrazione - NIS2 Agile</title> <title>Registrazione - NIS2 Agile</title>
<!-- Bootstrap Italia v2.18.1 — self-hostato da /vendor (MAI CDN). Variante "-bi" della register.html. --> <!-- Bootstrap Italia v2.18.1 — self-hostato da /vendor (MAI CDN). Variante "-bi" della register.html. -->
<link rel="stylesheet" href="vendor/bootstrap-italia/dist/css/bootstrap-italia.min.css"> <link rel="stylesheet" href="vendor/bootstrap-italia/dist/css/bootstrap-italia.min.css">
@@ -62,6 +62,19 @@
#step-0 { display: block; } #step-0 { display: block; }
.ico { width: 1em; height: 1em; fill: currentColor; vertical-align: -.125em; } .ico { width: 1em; height: 1em; fill: currentColor; vertical-align: -.125em; }
</style> </style>
<!-- PWA:start -->
<link rel="manifest" href="/manifest.webmanifest">
<meta name="theme-color" content="#0066CC">
<link rel="icon" type="image/png" sizes="32x32" href="/assets/icons/favicon-32.png">
<link rel="icon" type="image/png" sizes="16x16" href="/assets/icons/favicon-16.png">
<link rel="apple-touch-icon" sizes="180x180" href="/assets/icons/apple-touch-icon.png">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="default">
<meta name="apple-mobile-web-app-title" content="NIS2 Agile">
<meta name="application-name" content="NIS2 Agile">
<script src="/js/pwa.js?v=20260614" defer></script>
<!-- PWA:end -->
</head> </head>
<body> <body>
<main class="auth-wrap"> <main class="auth-wrap">
+14 -1
View File
@@ -2,7 +2,7 @@
<html lang="it"> <html lang="it">
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
<title>Registrazione - NIS2 Agile</title> <title>Registrazione - NIS2 Agile</title>
<!-- Bootstrap Italia v2.18.1 — self-hostato da /vendor (MAI CDN). Variante "-bi" della register.html. --> <!-- Bootstrap Italia v2.18.1 — self-hostato da /vendor (MAI CDN). Variante "-bi" della register.html. -->
<link rel="stylesheet" href="vendor/bootstrap-italia/dist/css/bootstrap-italia.min.css"> <link rel="stylesheet" href="vendor/bootstrap-italia/dist/css/bootstrap-italia.min.css">
@@ -62,6 +62,19 @@
#step-0 { display: block; } #step-0 { display: block; }
.ico { width: 1em; height: 1em; fill: currentColor; vertical-align: -.125em; } .ico { width: 1em; height: 1em; fill: currentColor; vertical-align: -.125em; }
</style> </style>
<!-- PWA:start -->
<link rel="manifest" href="/manifest.webmanifest">
<meta name="theme-color" content="#0066CC">
<link rel="icon" type="image/png" sizes="32x32" href="/assets/icons/favicon-32.png">
<link rel="icon" type="image/png" sizes="16x16" href="/assets/icons/favicon-16.png">
<link rel="apple-touch-icon" sizes="180x180" href="/assets/icons/apple-touch-icon.png">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="default">
<meta name="apple-mobile-web-app-title" content="NIS2 Agile">
<meta name="application-name" content="NIS2 Agile">
<script src="/js/pwa.js?v=20260614" defer></script>
<!-- PWA:end -->
</head> </head>
<body> <body>
<main class="auth-wrap"> <main class="auth-wrap">
+14 -1
View File
@@ -2,7 +2,7 @@
<html lang="it"> <html lang="it">
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
<title>Audit e Report (BI) - NIS2 Agile</title> <title>Audit e Report (BI) - NIS2 Agile</title>
<!-- Bootstrap Italia v2.18.1 self-hostato (regola: MAI CDN). Caricato PRIMA di style.css <!-- Bootstrap Italia v2.18.1 self-hostato (regola: MAI CDN). Caricato PRIMA di style.css
cosi' style.css (design system esistente) resta autorevole per i widget renderizzati cosi' style.css (design system esistente) resta autorevole per i widget renderizzati
@@ -343,6 +343,19 @@
.report-summary-grid { grid-template-columns: 1fr 1fr; } .report-summary-grid { grid-template-columns: 1fr 1fr; }
} }
</style> </style>
<!-- PWA:start -->
<link rel="manifest" href="/manifest.webmanifest">
<meta name="theme-color" content="#0066CC">
<link rel="icon" type="image/png" sizes="32x32" href="/assets/icons/favicon-32.png">
<link rel="icon" type="image/png" sizes="16x16" href="/assets/icons/favicon-16.png">
<link rel="apple-touch-icon" sizes="180x180" href="/assets/icons/apple-touch-icon.png">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="default">
<meta name="apple-mobile-web-app-title" content="NIS2 Agile">
<meta name="application-name" content="NIS2 Agile">
<script src="/js/pwa.js?v=20260614" defer></script>
<!-- PWA:end -->
</head> </head>
<body> <body>
<div class="app-layout"> <div class="app-layout">
+14 -1
View File
@@ -2,7 +2,7 @@
<html lang="it"> <html lang="it">
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
<title>Audit e Report - NIS2 Agile</title> <title>Audit e Report - NIS2 Agile</title>
<!-- Bootstrap Italia v2.18.1 self-hostato (regola: MAI CDN). Caricato PRIMA di style.css <!-- Bootstrap Italia v2.18.1 self-hostato (regola: MAI CDN). Caricato PRIMA di style.css
cosi' style.css (design system esistente) resta autorevole per i widget renderizzati cosi' style.css (design system esistente) resta autorevole per i widget renderizzati
@@ -343,6 +343,19 @@
.report-summary-grid { grid-template-columns: 1fr 1fr; } .report-summary-grid { grid-template-columns: 1fr 1fr; }
} }
</style> </style>
<!-- PWA:start -->
<link rel="manifest" href="/manifest.webmanifest">
<meta name="theme-color" content="#0066CC">
<link rel="icon" type="image/png" sizes="32x32" href="/assets/icons/favicon-32.png">
<link rel="icon" type="image/png" sizes="16x16" href="/assets/icons/favicon-16.png">
<link rel="apple-touch-icon" sizes="180x180" href="/assets/icons/apple-touch-icon.png">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="default">
<meta name="apple-mobile-web-app-title" content="NIS2 Agile">
<meta name="application-name" content="NIS2 Agile">
<script src="/js/pwa.js?v=20260614" defer></script>
<!-- PWA:end -->
</head> </head>
<body> <body>
<div class="app-layout"> <div class="app-layout">
+14 -1
View File
@@ -2,7 +2,7 @@
<html lang="it"> <html lang="it">
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
<title>Imposta nuova password - NIS2 Agile</title> <title>Imposta nuova password - NIS2 Agile</title>
<!-- Bootstrap Italia v2.18.1 — self-hostato da /vendor (MAI CDN). Variante "-bi" della reset-password.html. --> <!-- Bootstrap Italia v2.18.1 — self-hostato da /vendor (MAI CDN). Variante "-bi" della reset-password.html. -->
<link rel="stylesheet" href="vendor/bootstrap-italia/dist/css/bootstrap-italia.min.css"> <link rel="stylesheet" href="vendor/bootstrap-italia/dist/css/bootstrap-italia.min.css">
@@ -18,6 +18,19 @@
.pw-toggle { position: absolute; right: 8px; top: 8px; background: none; border: none; color: #5a6772; cursor: pointer; padding: 6px; } .pw-toggle { position: absolute; right: 8px; top: 8px; background: none; border: none; color: #5a6772; cursor: pointer; padding: 6px; }
.ico { width: 1em; height: 1em; fill: currentColor; vertical-align: -.125em; } .ico { width: 1em; height: 1em; fill: currentColor; vertical-align: -.125em; }
</style> </style>
<!-- PWA:start -->
<link rel="manifest" href="/manifest.webmanifest">
<meta name="theme-color" content="#0066CC">
<link rel="icon" type="image/png" sizes="32x32" href="/assets/icons/favicon-32.png">
<link rel="icon" type="image/png" sizes="16x16" href="/assets/icons/favicon-16.png">
<link rel="apple-touch-icon" sizes="180x180" href="/assets/icons/apple-touch-icon.png">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="default">
<meta name="apple-mobile-web-app-title" content="NIS2 Agile">
<meta name="application-name" content="NIS2 Agile">
<script src="/js/pwa.js?v=20260614" defer></script>
<!-- PWA:end -->
</head> </head>
<body> <body>
<main class="auth-wrap"> <main class="auth-wrap">
+14 -1
View File
@@ -2,7 +2,7 @@
<html lang="it"> <html lang="it">
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
<title>Imposta nuova password - NIS2 Agile</title> <title>Imposta nuova password - NIS2 Agile</title>
<!-- Bootstrap Italia v2.18.1 — self-hostato da /vendor (MAI CDN). Variante "-bi" della reset-password.html. --> <!-- Bootstrap Italia v2.18.1 — self-hostato da /vendor (MAI CDN). Variante "-bi" della reset-password.html. -->
<link rel="stylesheet" href="vendor/bootstrap-italia/dist/css/bootstrap-italia.min.css"> <link rel="stylesheet" href="vendor/bootstrap-italia/dist/css/bootstrap-italia.min.css">
@@ -18,6 +18,19 @@
.pw-toggle { position: absolute; right: 8px; top: 8px; background: none; border: none; color: #5a6772; cursor: pointer; padding: 6px; } .pw-toggle { position: absolute; right: 8px; top: 8px; background: none; border: none; color: #5a6772; cursor: pointer; padding: 6px; }
.ico { width: 1em; height: 1em; fill: currentColor; vertical-align: -.125em; } .ico { width: 1em; height: 1em; fill: currentColor; vertical-align: -.125em; }
</style> </style>
<!-- PWA:start -->
<link rel="manifest" href="/manifest.webmanifest">
<meta name="theme-color" content="#0066CC">
<link rel="icon" type="image/png" sizes="32x32" href="/assets/icons/favicon-32.png">
<link rel="icon" type="image/png" sizes="16x16" href="/assets/icons/favicon-16.png">
<link rel="apple-touch-icon" sizes="180x180" href="/assets/icons/apple-touch-icon.png">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="default">
<meta name="apple-mobile-web-app-title" content="NIS2 Agile">
<meta name="application-name" content="NIS2 Agile">
<script src="/js/pwa.js?v=20260614" defer></script>
<!-- PWA:end -->
</head> </head>
<body> <body>
<main class="auth-wrap"> <main class="auth-wrap">
+14 -1
View File
@@ -2,7 +2,7 @@
<html lang="it"> <html lang="it">
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
<title>Gestione Rischi (BI) - NIS2 Agile</title> <title>Gestione Rischi (BI) - NIS2 Agile</title>
<!-- Bootstrap Italia v2.18.1 self-hostato (regola: MAI CDN). Caricato PRIMA di style.css <!-- Bootstrap Italia v2.18.1 self-hostato (regola: MAI CDN). Caricato PRIMA di style.css
cosi' style.css (design system esistente) resta autorevole per i widget renderizzati cosi' style.css (design system esistente) resta autorevole per i widget renderizzati
@@ -298,6 +298,19 @@
.filters-bar .form-select { min-width: 100%; } .filters-bar .form-select { min-width: 100%; }
} }
</style> </style>
<!-- PWA:start -->
<link rel="manifest" href="/manifest.webmanifest">
<meta name="theme-color" content="#0066CC">
<link rel="icon" type="image/png" sizes="32x32" href="/assets/icons/favicon-32.png">
<link rel="icon" type="image/png" sizes="16x16" href="/assets/icons/favicon-16.png">
<link rel="apple-touch-icon" sizes="180x180" href="/assets/icons/apple-touch-icon.png">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="default">
<meta name="apple-mobile-web-app-title" content="NIS2 Agile">
<meta name="application-name" content="NIS2 Agile">
<script src="/js/pwa.js?v=20260614" defer></script>
<!-- PWA:end -->
</head> </head>
<body> <body>
<div class="app-layout"> <div class="app-layout">
+14 -1
View File
@@ -2,7 +2,7 @@
<html lang="it"> <html lang="it">
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
<title>Gestione Rischi - NIS2 Agile</title> <title>Gestione Rischi - NIS2 Agile</title>
<!-- Bootstrap Italia v2.18.1 self-hostato (regola: MAI CDN). Caricato PRIMA di style.css <!-- Bootstrap Italia v2.18.1 self-hostato (regola: MAI CDN). Caricato PRIMA di style.css
cosi' style.css (design system esistente) resta autorevole per i widget renderizzati cosi' style.css (design system esistente) resta autorevole per i widget renderizzati
@@ -298,6 +298,19 @@
.filters-bar .form-select { min-width: 100%; } .filters-bar .form-select { min-width: 100%; }
} }
</style> </style>
<!-- PWA:start -->
<link rel="manifest" href="/manifest.webmanifest">
<meta name="theme-color" content="#0066CC">
<link rel="icon" type="image/png" sizes="32x32" href="/assets/icons/favicon-32.png">
<link rel="icon" type="image/png" sizes="16x16" href="/assets/icons/favicon-16.png">
<link rel="apple-touch-icon" sizes="180x180" href="/assets/icons/apple-touch-icon.png">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="default">
<meta name="apple-mobile-web-app-title" content="NIS2 Agile">
<meta name="application-name" content="NIS2 Agile">
<script src="/js/pwa.js?v=20260614" defer></script>
<!-- PWA:end -->
</head> </head>
<body> <body>
<div class="app-layout"> <div class="app-layout">
+14 -1
View File
@@ -2,7 +2,7 @@
<html lang="it"> <html lang="it">
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
<title>Standard Continuita di Servizio (BI) — NIS2 Agile</title> <title>Standard Continuita di Servizio (BI) — NIS2 Agile</title>
<link rel="stylesheet" href="/vendor/bootstrap-italia/dist/css/bootstrap-italia.min.css"> <link rel="stylesheet" href="/vendor/bootstrap-italia/dist/css/bootstrap-italia.min.css">
<style> <style>
@@ -56,6 +56,19 @@
@media print{body{background:#fff}.page{box-shadow:none}} @media print{body{background:#fff}.page{box-shadow:none}}
@media(max-width:700px){.content,.doc-header,.doc-footer{padding:20px}.layer{grid-template-columns:1fr}.layer-num{border-radius:8px 8px 0 0;padding:8px}.layer-body{border-radius:0 0 8px 8px;border-left:1px solid #eee}} @media(max-width:700px){.content,.doc-header,.doc-footer{padding:20px}.layer{grid-template-columns:1fr}.layer-num{border-radius:8px 8px 0 0;padding:8px}.layer-body{border-radius:0 0 8px 8px;border-left:1px solid #eee}}
</style> </style>
<!-- PWA:start -->
<link rel="manifest" href="/manifest.webmanifest">
<meta name="theme-color" content="#0066CC">
<link rel="icon" type="image/png" sizes="32x32" href="/assets/icons/favicon-32.png">
<link rel="icon" type="image/png" sizes="16x16" href="/assets/icons/favicon-16.png">
<link rel="apple-touch-icon" sizes="180x180" href="/assets/icons/apple-touch-icon.png">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="default">
<meta name="apple-mobile-web-app-title" content="NIS2 Agile">
<meta name="application-name" content="NIS2 Agile">
<script src="/js/pwa.js?v=20260614" defer></script>
<!-- PWA:end -->
</head> </head>
<body> <body>
<div class="page"> <div class="page">
+14 -1
View File
@@ -2,7 +2,7 @@
<html lang="it"> <html lang="it">
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
<title>Standard Continuita di Servizio — NIS2 Agile</title> <title>Standard Continuita di Servizio — NIS2 Agile</title>
<link rel="stylesheet" href="/vendor/bootstrap-italia/dist/css/bootstrap-italia.min.css"> <link rel="stylesheet" href="/vendor/bootstrap-italia/dist/css/bootstrap-italia.min.css">
<style> <style>
@@ -56,6 +56,19 @@
@media print{body{background:#fff}.page{box-shadow:none}} @media print{body{background:#fff}.page{box-shadow:none}}
@media(max-width:700px){.content,.doc-header,.doc-footer{padding:20px}.layer{grid-template-columns:1fr}.layer-num{border-radius:8px 8px 0 0;padding:8px}.layer-body{border-radius:0 0 8px 8px;border-left:1px solid #eee}} @media(max-width:700px){.content,.doc-header,.doc-footer{padding:20px}.layer{grid-template-columns:1fr}.layer-num{border-radius:8px 8px 0 0;padding:8px}.layer-body{border-radius:0 0 8px 8px;border-left:1px solid #eee}}
</style> </style>
<!-- PWA:start -->
<link rel="manifest" href="/manifest.webmanifest">
<meta name="theme-color" content="#0066CC">
<link rel="icon" type="image/png" sizes="32x32" href="/assets/icons/favicon-32.png">
<link rel="icon" type="image/png" sizes="16x16" href="/assets/icons/favicon-16.png">
<link rel="apple-touch-icon" sizes="180x180" href="/assets/icons/apple-touch-icon.png">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="default">
<meta name="apple-mobile-web-app-title" content="NIS2 Agile">
<meta name="application-name" content="NIS2 Agile">
<script src="/js/pwa.js?v=20260614" defer></script>
<!-- PWA:end -->
</head> </head>
<body> <body>
<div class="page"> <div class="page">
+14 -1
View File
@@ -2,7 +2,7 @@
<html lang="it"> <html lang="it">
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
<title>Impostazioni (BI) - NIS2 Agile</title> <title>Impostazioni (BI) - NIS2 Agile</title>
<!-- Bootstrap Italia v2.18.1 self-hostato (regola: MAI CDN). Caricato PRIMA di style.css <!-- Bootstrap Italia v2.18.1 self-hostato (regola: MAI CDN). Caricato PRIMA di style.css
cosi' style.css (design system esistente) resta autorevole per i widget renderizzati cosi' style.css (design system esistente) resta autorevole per i widget renderizzati
@@ -196,6 +196,19 @@
height: 16px; height: 16px;
} }
</style> </style>
<!-- PWA:start -->
<link rel="manifest" href="/manifest.webmanifest">
<meta name="theme-color" content="#0066CC">
<link rel="icon" type="image/png" sizes="32x32" href="/assets/icons/favicon-32.png">
<link rel="icon" type="image/png" sizes="16x16" href="/assets/icons/favicon-16.png">
<link rel="apple-touch-icon" sizes="180x180" href="/assets/icons/apple-touch-icon.png">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="default">
<meta name="apple-mobile-web-app-title" content="NIS2 Agile">
<meta name="application-name" content="NIS2 Agile">
<script src="/js/pwa.js?v=20260614" defer></script>
<!-- PWA:end -->
</head> </head>
<body> <body>
<div class="app-layout"> <div class="app-layout">
+14 -1
View File
@@ -2,7 +2,7 @@
<html lang="it"> <html lang="it">
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
<title>Impostazioni - NIS2 Agile</title> <title>Impostazioni - NIS2 Agile</title>
<!-- Bootstrap Italia v2.18.1 self-hostato (regola: MAI CDN). Caricato PRIMA di style.css <!-- Bootstrap Italia v2.18.1 self-hostato (regola: MAI CDN). Caricato PRIMA di style.css
cosi' style.css (design system esistente) resta autorevole per i widget renderizzati cosi' style.css (design system esistente) resta autorevole per i widget renderizzati
@@ -196,6 +196,19 @@
height: 16px; height: 16px;
} }
</style> </style>
<!-- PWA:start -->
<link rel="manifest" href="/manifest.webmanifest">
<meta name="theme-color" content="#0066CC">
<link rel="icon" type="image/png" sizes="32x32" href="/assets/icons/favicon-32.png">
<link rel="icon" type="image/png" sizes="16x16" href="/assets/icons/favicon-16.png">
<link rel="apple-touch-icon" sizes="180x180" href="/assets/icons/apple-touch-icon.png">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="default">
<meta name="apple-mobile-web-app-title" content="NIS2 Agile">
<meta name="application-name" content="NIS2 Agile">
<script src="/js/pwa.js?v=20260614" defer></script>
<!-- PWA:end -->
</head> </head>
<body> <body>
<div class="app-layout"> <div class="app-layout">
+14 -1
View File
@@ -2,9 +2,22 @@
<html lang="it"> <html lang="it">
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
<title>Configura Organizzazione - NIS2 Agile</title> <title>Configura Organizzazione - NIS2 Agile</title>
<link rel="stylesheet" href="css/style.css?v=20260613b"> <link rel="stylesheet" href="css/style.css?v=20260613b">
<!-- PWA:start -->
<link rel="manifest" href="/manifest.webmanifest">
<meta name="theme-color" content="#0066CC">
<link rel="icon" type="image/png" sizes="32x32" href="/assets/icons/favicon-32.png">
<link rel="icon" type="image/png" sizes="16x16" href="/assets/icons/favicon-16.png">
<link rel="apple-touch-icon" sizes="180x180" href="/assets/icons/apple-touch-icon.png">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="default">
<meta name="apple-mobile-web-app-title" content="NIS2 Agile">
<meta name="application-name" content="NIS2 Agile">
<script src="/js/pwa.js?v=20260614" defer></script>
<!-- PWA:end -->
</head> </head>
<body> <body>
<div class="app-layout"> <div class="app-layout">
+14 -1
View File
@@ -2,7 +2,7 @@
<html lang="it"> <html lang="it">
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
<title>Simulazione B2B — NIS2 Agile</title> <title>Simulazione B2B — NIS2 Agile</title>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css"> <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css">
<style> <style>
@@ -70,6 +70,19 @@
.done-title{font-size:1rem;font-weight:800;color:var(--primary);margin-bottom:6px} .done-title{font-size:1rem;font-weight:800;color:var(--primary);margin-bottom:6px}
.done-sub{font-size:.82rem;color:#94a3b8} .done-sub{font-size:.82rem;color:#94a3b8}
</style> </style>
<!-- PWA:start -->
<link rel="manifest" href="/manifest.webmanifest">
<meta name="theme-color" content="#0066CC">
<link rel="icon" type="image/png" sizes="32x32" href="/assets/icons/favicon-32.png">
<link rel="icon" type="image/png" sizes="16x16" href="/assets/icons/favicon-16.png">
<link rel="apple-touch-icon" sizes="180x180" href="/assets/icons/apple-touch-icon.png">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="default">
<meta name="apple-mobile-web-app-title" content="NIS2 Agile">
<meta name="application-name" content="NIS2 Agile">
<script src="/js/pwa.js?v=20260614" defer></script>
<!-- PWA:end -->
</head> </head>
<body> <body>
<div class="header"> <div class="header">
+14 -1
View File
@@ -2,7 +2,7 @@
<html lang="it"> <html lang="it">
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
<title>NIS2 Agile — Simulazione Demo</title> <title>NIS2 Agile — Simulazione Demo</title>
<style> <style>
* { box-sizing: border-box; margin: 0; padding: 0; } * { box-sizing: border-box; margin: 0; padding: 0; }
@@ -134,6 +134,19 @@
@media (max-width: 768px) { .container { grid-template-columns: 1fr; } } @media (max-width: 768px) { .container { grid-template-columns: 1fr; } }
</style> </style>
<!-- PWA:start -->
<link rel="manifest" href="/manifest.webmanifest">
<meta name="theme-color" content="#0066CC">
<link rel="icon" type="image/png" sizes="32x32" href="/assets/icons/favicon-32.png">
<link rel="icon" type="image/png" sizes="16x16" href="/assets/icons/favicon-16.png">
<link rel="apple-touch-icon" sizes="180x180" href="/assets/icons/apple-touch-icon.png">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="default">
<meta name="apple-mobile-web-app-title" content="NIS2 Agile">
<meta name="application-name" content="NIS2 Agile">
<script src="/js/pwa.js?v=20260614" defer></script>
<!-- PWA:end -->
</head> </head>
<body> <body>
+14 -1
View File
@@ -2,7 +2,7 @@
<html lang="it"> <html lang="it">
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
<meta name="robots" content="noindex,nofollow"> <meta name="robots" content="noindex,nofollow">
<title>Questionario di Sicurezza Fornitore — NIS2 Agile</title> <title>Questionario di Sicurezza Fornitore — NIS2 Agile</title>
<style> <style>
@@ -34,6 +34,19 @@
@keyframes spin { to { transform:rotate(360deg); } } @keyframes spin { to { transform:rotate(360deg); } }
.foot { text-align:center; color:var(--muted); font-size:.75rem; margin-top:24px; } .foot { text-align:center; color:var(--muted); font-size:.75rem; margin-top:24px; }
</style> </style>
<!-- PWA:start -->
<link rel="manifest" href="/manifest.webmanifest">
<meta name="theme-color" content="#0066CC">
<link rel="icon" type="image/png" sizes="32x32" href="/assets/icons/favicon-32.png">
<link rel="icon" type="image/png" sizes="16x16" href="/assets/icons/favicon-16.png">
<link rel="apple-touch-icon" sizes="180x180" href="/assets/icons/apple-touch-icon.png">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="default">
<meta name="apple-mobile-web-app-title" content="NIS2 Agile">
<meta name="application-name" content="NIS2 Agile">
<script src="/js/pwa.js?v=20260614" defer></script>
<!-- PWA:end -->
</head> </head>
<body> <body>
<div class="wrap"> <div class="wrap">
+14 -1
View File
@@ -2,7 +2,7 @@
<html lang="it"> <html lang="it">
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
<meta name="robots" content="noindex,nofollow"> <meta name="robots" content="noindex,nofollow">
<title>Portale Fornitori - NIS2 Agile</title> <title>Portale Fornitori - NIS2 Agile</title>
<style> <style>
@@ -55,6 +55,19 @@ textarea{min-height:88px;resize:vertical}
.save-state{font-size:.78rem;color:var(--gray-400);text-align:right;min-height:18px} .save-state{font-size:.78rem;color:var(--gray-400);text-align:right;min-height:18px}
.foot{text-align:center;font-size:.72rem;color:var(--gray-400);margin-top:20px;line-height:1.5} .foot{text-align:center;font-size:.72rem;color:var(--gray-400);margin-top:20px;line-height:1.5}
</style> </style>
<!-- PWA:start -->
<link rel="manifest" href="/manifest.webmanifest">
<meta name="theme-color" content="#0066CC">
<link rel="icon" type="image/png" sizes="32x32" href="/assets/icons/favicon-32.png">
<link rel="icon" type="image/png" sizes="16x16" href="/assets/icons/favicon-16.png">
<link rel="apple-touch-icon" sizes="180x180" href="/assets/icons/apple-touch-icon.png">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="default">
<meta name="apple-mobile-web-app-title" content="NIS2 Agile">
<meta name="application-name" content="NIS2 Agile">
<script src="/js/pwa.js?v=20260614" defer></script>
<!-- PWA:end -->
</head> </head>
<body> <body>
<div class="wrap"> <div class="wrap">
+14 -1
View File
@@ -2,7 +2,7 @@
<html lang="it"> <html lang="it">
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
<title>Supply Chain (BI) - NIS2 Agile</title> <title>Supply Chain (BI) - NIS2 Agile</title>
<!-- Bootstrap Italia v2.18.1 self-hostato (regola: MAI CDN). Caricato PRIMA di style.css <!-- Bootstrap Italia v2.18.1 self-hostato (regola: MAI CDN). Caricato PRIMA di style.css
cosi' style.css (design system esistente) resta autorevole per i widget renderizzati cosi' style.css (design system esistente) resta autorevole per i widget renderizzati
@@ -365,6 +365,19 @@
gap: 8px; gap: 8px;
} }
</style> </style>
<!-- PWA:start -->
<link rel="manifest" href="/manifest.webmanifest">
<meta name="theme-color" content="#0066CC">
<link rel="icon" type="image/png" sizes="32x32" href="/assets/icons/favicon-32.png">
<link rel="icon" type="image/png" sizes="16x16" href="/assets/icons/favicon-16.png">
<link rel="apple-touch-icon" sizes="180x180" href="/assets/icons/apple-touch-icon.png">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="default">
<meta name="apple-mobile-web-app-title" content="NIS2 Agile">
<meta name="application-name" content="NIS2 Agile">
<script src="/js/pwa.js?v=20260614" defer></script>
<!-- PWA:end -->
</head> </head>
<body> <body>
<div class="app-layout"> <div class="app-layout">
+14 -1
View File
@@ -2,7 +2,7 @@
<html lang="it"> <html lang="it">
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
<title>Supply Chain - NIS2 Agile</title> <title>Supply Chain - NIS2 Agile</title>
<!-- Bootstrap Italia v2.18.1 self-hostato (regola: MAI CDN). Caricato PRIMA di style.css <!-- Bootstrap Italia v2.18.1 self-hostato (regola: MAI CDN). Caricato PRIMA di style.css
cosi' style.css (design system esistente) resta autorevole per i widget renderizzati cosi' style.css (design system esistente) resta autorevole per i widget renderizzati
@@ -365,6 +365,19 @@
gap: 8px; gap: 8px;
} }
</style> </style>
<!-- PWA:start -->
<link rel="manifest" href="/manifest.webmanifest">
<meta name="theme-color" content="#0066CC">
<link rel="icon" type="image/png" sizes="32x32" href="/assets/icons/favicon-32.png">
<link rel="icon" type="image/png" sizes="16x16" href="/assets/icons/favicon-16.png">
<link rel="apple-touch-icon" sizes="180x180" href="/assets/icons/apple-touch-icon.png">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="default">
<meta name="apple-mobile-web-app-title" content="NIS2 Agile">
<meta name="application-name" content="NIS2 Agile">
<script src="/js/pwa.js?v=20260614" defer></script>
<!-- PWA:end -->
</head> </head>
<body> <body>
<div class="app-layout"> <div class="app-layout">
+96
View File
@@ -0,0 +1,96 @@
/*
* NIS2 Agile — Service Worker (PWA)
* -----------------------------------------------------------------------------
* Strategia (SaaS autenticato multi-tenant — sicurezza prima di tutto):
* - /api/* -> NETWORK-ONLY, MAI in cache. Nessun dato autenticato
* viene cacheato => zero leak cross-utente su un
* dispositivo condiviso. La sessione resta gestita da
* JWT / auth-gate.js, fuori dal service worker.
* - navigazioni HTML -> NETWORK-FIRST, fallback alla cache e infine /offline.html.
* - asset statici -> STALE-WHILE-REVALIDATE (risposta immediata dalla cache,
* aggiornamento in background).
*
* Il nome cache include la release: va BUMPATO ad ogni rilascio (vedi version.json),
* cosi' activate elimina automaticamente la shell vecchia.
*/
const CACHE = 'nis2-shell-v1.15.0';
const PRECACHE = [
'/offline.html',
'/manifest.webmanifest',
'/css/style.css',
'/js/common.js',
'/js/common-bi.js',
'/js/api.js',
'/js/i18n.js',
'/js/pwa.js',
'/vendor/bootstrap-italia/dist/css/bootstrap-italia.min.css',
'/vendor/bootstrap-italia/dist/js/bootstrap-italia.bundle.min.js',
'/vendor/bootstrap-italia/dist/svg/sprites.svg',
'/assets/icons/icon-192.png',
'/assets/icons/icon-512.png'
];
self.addEventListener('install', (event) => {
event.waitUntil((async () => {
const cache = await caches.open(CACHE);
// add uno-a-uno: un singolo asset mancante non deve far fallire l'install
await Promise.all(PRECACHE.map((url) =>
cache.add(new Request(url, { cache: 'reload' })).catch((err) =>
console.warn('[sw] precache skip', url, err && err.message))
));
await self.skipWaiting();
})());
});
self.addEventListener('activate', (event) => {
event.waitUntil((async () => {
const keys = await caches.keys();
await Promise.all(keys.filter((k) => k !== CACHE).map((k) => caches.delete(k)));
await self.clients.claim();
})());
});
self.addEventListener('fetch', (event) => {
const req = event.request;
if (req.method !== 'GET') return; // non-GET: rete normale
const url = new URL(req.url);
if (url.origin !== self.location.origin) return; // cross-origin: rete normale
// /api/* -> network-only, mai in cache
if (url.pathname.startsWith('/api/')) {
event.respondWith(
fetch(req).catch(() => new Response(
JSON.stringify({ error: 'offline', message: 'Connessione di rete assente' }),
{ status: 503, headers: { 'Content-Type': 'application/json' } }
))
);
return;
}
// navigazioni HTML -> network-first, fallback cache -> offline
if (req.mode === 'navigate') {
event.respondWith((async () => {
try {
return await fetch(req);
} catch (e) {
const cached = await caches.match(req);
return cached || (await caches.match('/offline.html'));
}
})());
return;
}
// asset statici stesso-origin -> stale-while-revalidate
event.respondWith((async () => {
const cache = await caches.open(CACHE);
const cached = await cache.match(req);
const network = fetch(req).then((res) => {
if (res && res.status === 200 && res.type === 'basic') {
cache.put(req, res.clone());
}
return res;
}).catch(() => null);
return cached || (await network) || (await caches.match('/offline.html'));
})());
});
+14 -1
View File
@@ -2,7 +2,7 @@
<html lang="it"> <html lang="it">
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
<title>Formazione (BI) - NIS2 Agile</title> <title>Formazione (BI) - NIS2 Agile</title>
<!-- Bootstrap Italia v2.18.1 self-hostato (regola: MAI CDN). Caricato PRIMA di style.css <!-- Bootstrap Italia v2.18.1 self-hostato (regola: MAI CDN). Caricato PRIMA di style.css
cosi' style.css (design system esistente) resta autorevole per i widget renderizzati cosi' style.css (design system esistente) resta autorevole per i widget renderizzati
@@ -221,6 +221,19 @@
.data-table { font-size: 0.8rem; } .data-table { font-size: 0.8rem; }
} }
</style> </style>
<!-- PWA:start -->
<link rel="manifest" href="/manifest.webmanifest">
<meta name="theme-color" content="#0066CC">
<link rel="icon" type="image/png" sizes="32x32" href="/assets/icons/favicon-32.png">
<link rel="icon" type="image/png" sizes="16x16" href="/assets/icons/favicon-16.png">
<link rel="apple-touch-icon" sizes="180x180" href="/assets/icons/apple-touch-icon.png">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="default">
<meta name="apple-mobile-web-app-title" content="NIS2 Agile">
<meta name="application-name" content="NIS2 Agile">
<script src="/js/pwa.js?v=20260614" defer></script>
<!-- PWA:end -->
</head> </head>
<body> <body>
<div class="app-layout"> <div class="app-layout">
+14 -1
View File
@@ -2,7 +2,7 @@
<html lang="it"> <html lang="it">
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
<title>Formazione - NIS2 Agile</title> <title>Formazione - NIS2 Agile</title>
<!-- Bootstrap Italia v2.18.1 self-hostato (regola: MAI CDN). Caricato PRIMA di style.css <!-- Bootstrap Italia v2.18.1 self-hostato (regola: MAI CDN). Caricato PRIMA di style.css
cosi' style.css (design system esistente) resta autorevole per i widget renderizzati cosi' style.css (design system esistente) resta autorevole per i widget renderizzati
@@ -221,6 +221,19 @@
.data-table { font-size: 0.8rem; } .data-table { font-size: 0.8rem; }
} }
</style> </style>
<!-- PWA:start -->
<link rel="manifest" href="/manifest.webmanifest">
<meta name="theme-color" content="#0066CC">
<link rel="icon" type="image/png" sizes="32x32" href="/assets/icons/favicon-32.png">
<link rel="icon" type="image/png" sizes="16x16" href="/assets/icons/favicon-16.png">
<link rel="apple-touch-icon" sizes="180x180" href="/assets/icons/apple-touch-icon.png">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="default">
<meta name="apple-mobile-web-app-title" content="NIS2 Agile">
<meta name="application-name" content="NIS2 Agile">
<script src="/js/pwa.js?v=20260614" defer></script>
<!-- PWA:end -->
</head> </head>
<body> <body>
<div class="app-layout"> <div class="app-layout">
+1 -1
View File
@@ -1 +1 @@
{"version":"1.14.1","build":"2026-06-14-v1.14.1","date":"2026-06-14","changelog":"Help online: rimossa icona FontAwesome residua (fas fa-comment-alt) non piu renderizzata dopo lo swap a Bootstrap Italia V2, nella guida 'Come aprire una segnalazione' (help.js). Cache-buster ?v di help.js -> 20260614 su 35 pagine. Nessuna modifica a dati o schema DB."} {"version":"1.15.0","build":"2026-06-14-v1.15.0","date":"2026-06-14","changelog":"PWA installabile (Android/iOS): aggiunti manifest.webmanifest, service worker (offline shell, /api network-only, asset stale-while-revalidate), set icone (192/512 + maskable + apple-touch + favicon), tag PWA in tutte le pagine HTML. Conformita AGID/WCAG 2.1 AA: zoom e orientamento non bloccati, touch target >=44px, safe-area in modalita standalone. Nessuna modifica a dati o schema DB."}
+14 -1
View File
@@ -2,7 +2,7 @@
<html lang="it"> <html lang="it">
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
<title>Segnalazioni Sicurezza (BI) - NIS2 Agile</title> <title>Segnalazioni Sicurezza (BI) - NIS2 Agile</title>
<!-- Bootstrap Italia v2.18.1 self-hostato (regola: MAI CDN). Caricato PRIMA di <!-- Bootstrap Italia v2.18.1 self-hostato (regola: MAI CDN). Caricato PRIMA di
style.css cosi' il design system esistente resta autorevole per i widget style.css cosi' il design system esistente resta autorevole per i widget
@@ -30,6 +30,19 @@
/* Icone sprite BI dimensionate inline per i bottoni azione */ /* Icone sprite BI dimensionate inline per i bottoni azione */
.icon-inline { width: 16px; height: 16px; fill: currentColor; vertical-align: text-bottom; } .icon-inline { width: 16px; height: 16px; fill: currentColor; vertical-align: text-bottom; }
</style> </style>
<!-- PWA:start -->
<link rel="manifest" href="/manifest.webmanifest">
<meta name="theme-color" content="#0066CC">
<link rel="icon" type="image/png" sizes="32x32" href="/assets/icons/favicon-32.png">
<link rel="icon" type="image/png" sizes="16x16" href="/assets/icons/favicon-16.png">
<link rel="apple-touch-icon" sizes="180x180" href="/assets/icons/apple-touch-icon.png">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="default">
<meta name="apple-mobile-web-app-title" content="NIS2 Agile">
<meta name="application-name" content="NIS2 Agile">
<script src="/js/pwa.js?v=20260614" defer></script>
<!-- PWA:end -->
</head> </head>
<body> <body>
<div class="app-layout"> <div class="app-layout">
+14 -1
View File
@@ -2,7 +2,7 @@
<html lang="it"> <html lang="it">
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
<title>Segnalazioni Sicurezza - NIS2 Agile</title> <title>Segnalazioni Sicurezza - NIS2 Agile</title>
<!-- Bootstrap Italia v2.18.1 self-hostato (regola: MAI CDN). Caricato PRIMA di <!-- Bootstrap Italia v2.18.1 self-hostato (regola: MAI CDN). Caricato PRIMA di
style.css cosi' il design system esistente resta autorevole per i widget style.css cosi' il design system esistente resta autorevole per i widget
@@ -30,6 +30,19 @@
/* Icone sprite BI dimensionate inline per i bottoni azione */ /* Icone sprite BI dimensionate inline per i bottoni azione */
.icon-inline { width: 16px; height: 16px; fill: currentColor; vertical-align: text-bottom; } .icon-inline { width: 16px; height: 16px; fill: currentColor; vertical-align: text-bottom; }
</style> </style>
<!-- PWA:start -->
<link rel="manifest" href="/manifest.webmanifest">
<meta name="theme-color" content="#0066CC">
<link rel="icon" type="image/png" sizes="32x32" href="/assets/icons/favicon-32.png">
<link rel="icon" type="image/png" sizes="16x16" href="/assets/icons/favicon-16.png">
<link rel="apple-touch-icon" sizes="180x180" href="/assets/icons/apple-touch-icon.png">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="default">
<meta name="apple-mobile-web-app-title" content="NIS2 Agile">
<meta name="application-name" content="NIS2 Agile">
<script src="/js/pwa.js?v=20260614" defer></script>
<!-- PWA:end -->
</head> </head>
<body> <body>
<div class="app-layout"> <div class="app-layout">
+14 -1
View File
@@ -2,7 +2,7 @@
<html lang="it"> <html lang="it">
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
<title>Compliance Journey - NIS2 Agile</title> <title>Compliance Journey - NIS2 Agile</title>
<link rel="stylesheet" href="css/style.css?v=20260613b"> <link rel="stylesheet" href="css/style.css?v=20260613b">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css"> <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css">
@@ -285,6 +285,19 @@
.journey-header { flex-direction: column; } .journey-header { flex-direction: column; }
} }
</style> </style>
<!-- PWA:start -->
<link rel="manifest" href="/manifest.webmanifest">
<meta name="theme-color" content="#0066CC">
<link rel="icon" type="image/png" sizes="32x32" href="/assets/icons/favicon-32.png">
<link rel="icon" type="image/png" sizes="16x16" href="/assets/icons/favicon-16.png">
<link rel="apple-touch-icon" sizes="180x180" href="/assets/icons/apple-touch-icon.png">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="default">
<meta name="apple-mobile-web-app-title" content="NIS2 Agile">
<meta name="application-name" content="NIS2 Agile">
<script src="/js/pwa.js?v=20260614" defer></script>
<!-- PWA:end -->
</head> </head>
<body> <body>
<div class="app-layout"> <div class="app-layout">
+487
View File
@@ -0,0 +1,487 @@
#!/usr/bin/env node
/**
* gen-pwa-icons.mjs — NIS2 Agile PWA icon generator (dependency-free)
*
* Generates the full PWA icon set using ONLY Node v20 built-ins:
* - node:zlib (deflate for PNG IDAT)
* - node:fs (write files)
* - node:path (resolve paths)
*
* Design: Italy-blue (#0066CC) square tile, centered white shield
* (compliance/security silhouette) with a bold "negative" check mark
* cut out of the shield (rendered in #0066CC) so it stays readable
* down to 16px.
*
* Rendering: each icon is drawn at 4x (supersampling) into an RGBA
* buffer using hand-written primitives (rounded rect, scanline polygon
* fill), then box-downsampled to final size for smooth anti-aliased
* edges. PNG is encoded manually (8-bit, color type 6 RGBA).
*
* Run: cd /projects/nis2-agile && node scripts/gen-pwa-icons.mjs
*/
import zlib from 'node:zlib';
import fs from 'node:fs';
import path from 'node:path';
import { fileURLToPath } from 'node:url';
// ---------------------------------------------------------------------------
// Paths
// ---------------------------------------------------------------------------
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
const PROJECT_ROOT = path.resolve(__dirname, '..');
const ICONS_DIR = path.join(PROJECT_ROOT, 'public', 'assets', 'icons');
// ---------------------------------------------------------------------------
// Palette
// ---------------------------------------------------------------------------
const BLUE = [0, 102, 204]; // #0066CC — Italy blue
const WHITE = [255, 255, 255];
// ---------------------------------------------------------------------------
// RGBA canvas helpers
// ---------------------------------------------------------------------------
function makeCanvas(w, h, fill) {
// fill = [r,g,b,a] or null => transparent (0,0,0,0)
const buf = new Uint8Array(w * h * 4);
if (fill) {
for (let i = 0; i < w * h; i++) {
const o = i * 4;
buf[o] = fill[0];
buf[o + 1] = fill[1];
buf[o + 2] = fill[2];
buf[o + 3] = fill[3];
}
}
return { w, h, buf };
}
function setPx(cv, x, y, rgba) {
if (x < 0 || y < 0 || x >= cv.w || y >= cv.h) return;
const o = (y * cv.w + x) * 4;
cv.buf[o] = rgba[0];
cv.buf[o + 1] = rgba[1];
cv.buf[o + 2] = rgba[2];
cv.buf[o + 3] = rgba[3];
}
// Fill the whole canvas with an OPAQUE color.
function fillBackground(cv, rgb) {
for (let i = 0; i < cv.w * cv.h; i++) {
const o = i * 4;
cv.buf[o] = rgb[0];
cv.buf[o + 1] = rgb[1];
cv.buf[o + 2] = rgb[2];
cv.buf[o + 3] = 255;
}
}
// Filled rounded rectangle (opaque). r = corner radius in px (canvas space).
function fillRoundedRect(cv, x0, y0, x1, y1, r, rgb, alpha = 255) {
const minX = Math.max(0, Math.floor(x0));
const minY = Math.max(0, Math.floor(y0));
const maxX = Math.min(cv.w - 1, Math.ceil(x1));
const maxY = Math.min(cv.h - 1, Math.ceil(y1));
const rr = r * r;
for (let y = minY; y <= maxY; y++) {
for (let x = minX; x <= maxX; x++) {
const px = x + 0.5;
const py = y + 0.5;
let inside = true;
// corner clipping
if (px < x0 + r && py < y0 + r) {
const dx = px - (x0 + r), dy = py - (y0 + r);
inside = dx * dx + dy * dy <= rr;
} else if (px > x1 - r && py < y0 + r) {
const dx = px - (x1 - r), dy = py - (y0 + r);
inside = dx * dx + dy * dy <= rr;
} else if (px < x0 + r && py > y1 - r) {
const dx = px - (x0 + r), dy = py - (y1 - r);
inside = dx * dx + dy * dy <= rr;
} else if (px > x1 - r && py > y1 - r) {
const dx = px - (x1 - r), dy = py - (y1 - r);
inside = dx * dx + dy * dy <= rr;
}
if (inside) setPx(cv, x, y, [rgb[0], rgb[1], rgb[2], alpha]);
}
}
}
// Scanline polygon fill. pts = [[x,y],...] in canvas space. Even-odd rule.
function fillPolygon(cv, pts, rgb, alpha = 255) {
let minY = Infinity, maxY = -Infinity;
for (const p of pts) {
if (p[1] < minY) minY = p[1];
if (p[1] > maxY) maxY = p[1];
}
minY = Math.max(0, Math.floor(minY));
maxY = Math.min(cv.h - 1, Math.ceil(maxY));
const n = pts.length;
for (let y = minY; y <= maxY; y++) {
const yc = y + 0.5;
const xs = [];
for (let i = 0; i < n; i++) {
const a = pts[i];
const b = pts[(i + 1) % n];
const ay = a[1], by = b[1];
if ((ay <= yc && by > yc) || (by <= yc && ay > yc)) {
const t = (yc - ay) / (by - ay);
xs.push(a[0] + t * (b[0] - a[0]));
}
}
xs.sort((p, q) => p - q);
for (let i = 0; i + 1 < xs.length; i += 2) {
const xStart = Math.max(0, Math.ceil(xs[i] - 0.5));
const xEnd = Math.min(cv.w - 1, Math.floor(xs[i + 1] - 0.5));
for (let x = xStart; x <= xEnd; x++) setPx(cv, x, y, [rgb[0], rgb[1], rgb[2], alpha]);
}
}
}
// ---------------------------------------------------------------------------
// Shield + check geometry
// ---------------------------------------------------------------------------
// All geometry is expressed in a normalized 0..1 box, then scaled into the
// target region (cx,cy = center, half = half-size of the content square).
// Build shield outline polygon (heraldic shield: flat top, rounded shoulders
// approximated by points, tapering to a point at the bottom).
function shieldPolygon(cx, cy, half) {
// Normalized shield within a square: x in [-0.5,0.5], y in [-0.6,0.6]
// top edge slightly inset, sides curve down, bottom comes to a point.
const W = half * 0.92; // half width
const Htop = -half * 1.02;
const pts = [];
// Top edge
pts.push([cx - W, cy + Htop]);
pts.push([cx + W, cy + Htop]);
// Right side going down with a gentle inward curve, then to the point.
// Approximate the right & bottom with sampled points along a parametric path.
const right = [
[cx + W, cy + Htop],
[cx + W * 0.99, cy - half * 0.35],
[cx + W * 0.92, cy + half * 0.05],
[cx + W * 0.74, cy + half * 0.45],
[cx + W * 0.42, cy + half * 0.85],
[cx + 0, cy + half * 1.12], // bottom point
];
const left = [
[cx - W * 0.42, cy + half * 0.85],
[cx - W * 0.74, cy + half * 0.45],
[cx - W * 0.92, cy + half * 0.05],
[cx - W * 0.99, cy - half * 0.35],
[cx - W, cy + Htop],
];
// Compose: top-left -> top-right -> right path -> bottom -> left path
const poly = [];
poly.push([cx - W, cy + Htop]);
poly.push([cx + W, cy + Htop]);
for (let i = 1; i < right.length; i++) poly.push(right[i]);
for (let i = 0; i < left.length; i++) poly.push(left[i]);
return poly;
}
// Build a bold check-mark polygon (thick stroke as a filled hexagon-ish shape).
// Centered roughly in the shield. `s` scales overall size, `t` is stroke thickness.
function checkPolygon(cx, cy, s, t) {
// Check has a short arm (down-left) and a long arm (up-right).
// Define center vertex (bottom of the V), short tip, long tip.
const vx = cx - s * 0.10, vy = cy + s * 0.34; // inner corner (bottom)
const s1x = cx - s * 0.46, s1y = cy + s * 0.02; // short arm tip
const l1x = cx + s * 0.50, l1y = cy - s * 0.42; // long arm tip
// Build a thick stroke by offsetting perpendicular to each segment.
// Segment A: short tip -> inner corner
// Segment B: inner corner -> long tip
const half = t / 2;
function unit(ax, ay, bx, by) {
const dx = bx - ax, dy = by - ay;
const L = Math.hypot(dx, dy) || 1;
return [dx / L, dy / L];
}
function perp(u) { return [-u[1], u[0]]; }
const uA = unit(s1x, s1y, vx, vy);
const uB = unit(vx, vy, l1x, l1y);
const pA = perp(uA);
const pB = perp(uB);
// Outer & inner offsets for each arm; assemble as a single polygon outline.
// Order: short tip outer -> corner outer -> long tip outer -> long tip inner
// -> corner inner -> short tip inner
const poly = [
[s1x + pA[0] * half, s1y + pA[1] * half], // short tip outer
[vx + pA[0] * half, vy + pA[1] * half], // corner outer (A side)
[vx + pB[0] * half, vy + pB[1] * half], // corner outer (B side)
[l1x + pB[0] * half, l1y + pB[1] * half], // long tip outer
[l1x - pB[0] * half, l1y - pB[1] * half], // long tip inner
[vx - pB[0] * half, vy - pB[1] * half], // corner inner (B side)
[vx - pA[0] * half, vy - pA[1] * half], // corner inner (A side)
[s1x - pA[0] * half, s1y - pA[1] * half], // short tip inner
];
return poly;
}
// ---------------------------------------------------------------------------
// Draw the NIS2 emblem (shield + check) into a canvas region.
// cx,cy: center; half: half content size; simplified: bolder geometry for tiny sizes
// ---------------------------------------------------------------------------
function drawEmblem(cv, cx, cy, half, simplified = false) {
// White shield
const shield = shieldPolygon(cx, cy, half);
fillPolygon(cv, shield, WHITE, 255);
// Negative blue check inside the shield.
const checkScale = half * (simplified ? 1.18 : 1.05);
const stroke = half * (simplified ? 0.32 : 0.24);
const check = checkPolygon(cx, cy - half * 0.02, checkScale, stroke);
fillPolygon(cv, check, BLUE, 255);
}
// ---------------------------------------------------------------------------
// Box downsample (supersampled -> final). factor must divide dimensions.
// ---------------------------------------------------------------------------
function downsample(cv, factor) {
const W = cv.w / factor;
const H = cv.h / factor;
const out = makeCanvas(W, H, null);
const f2 = factor * factor;
for (let y = 0; y < H; y++) {
for (let x = 0; x < W; x++) {
let r = 0, g = 0, b = 0, a = 0;
for (let sy = 0; sy < factor; sy++) {
for (let sx = 0; sx < factor; sx++) {
const o = ((y * factor + sy) * cv.w + (x * factor + sx)) * 4;
const sa = cv.buf[o + 3];
// premultiply for correct edge blending
r += cv.buf[o] * sa;
g += cv.buf[o + 1] * sa;
b += cv.buf[o + 2] * sa;
a += sa;
}
}
const oo = (y * W + x) * 4;
if (a === 0) {
out.buf[oo] = 0; out.buf[oo + 1] = 0; out.buf[oo + 2] = 0; out.buf[oo + 3] = 0;
} else {
out.buf[oo] = Math.round(r / a);
out.buf[oo + 1] = Math.round(g / a);
out.buf[oo + 2] = Math.round(b / a);
out.buf[oo + 3] = Math.round(a / f2);
}
}
}
return out;
}
// ---------------------------------------------------------------------------
// PNG encoding (manual, 8-bit RGBA, color type 6)
// ---------------------------------------------------------------------------
const PNG_SIG = Buffer.from([0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a]);
// CRC32 (standard polynomial 0xEDB88320)
const CRC_TABLE = (() => {
const t = new Uint32Array(256);
for (let n = 0; n < 256; n++) {
let c = n;
for (let k = 0; k < 8; k++) {
c = (c & 1) ? (0xedb88320 ^ (c >>> 1)) : (c >>> 1);
}
t[n] = c >>> 0;
}
return t;
})();
function crc32(buf) {
let c = 0xffffffff;
for (let i = 0; i < buf.length; i++) {
c = CRC_TABLE[(c ^ buf[i]) & 0xff] ^ (c >>> 8);
}
return (c ^ 0xffffffff) >>> 0;
}
function chunk(type, data) {
const len = Buffer.alloc(4);
len.writeUInt32BE(data.length, 0);
const typeBuf = Buffer.from(type, 'ascii');
const body = Buffer.concat([typeBuf, data]);
const crc = Buffer.alloc(4);
crc.writeUInt32BE(crc32(body), 0);
return Buffer.concat([len, body, crc]);
}
function encodePNG(cv) {
const { w, h, buf } = cv;
// IHDR
const ihdr = Buffer.alloc(13);
ihdr.writeUInt32BE(w, 0);
ihdr.writeUInt32BE(h, 4);
ihdr[8] = 8; // bit depth
ihdr[9] = 6; // color type RGBA
ihdr[10] = 0; // compression
ihdr[11] = 0; // filter
ihdr[12] = 0; // interlace
// Filtered raw data: each scanline prefixed with filter byte 0
const stride = w * 4;
const raw = Buffer.alloc((stride + 1) * h);
for (let y = 0; y < h; y++) {
raw[y * (stride + 1)] = 0; // filter: none
buf.subarray(y * stride, y * stride + stride)
.forEach ? null : null; // (Uint8Array subarray copy below)
const srcStart = y * stride;
raw.set(buf.subarray(srcStart, srcStart + stride), y * (stride + 1) + 1);
}
const idat = zlib.deflateSync(raw, { level: 9 });
return Buffer.concat([
PNG_SIG,
chunk('IHDR', ihdr),
chunk('IDAT', idat),
chunk('IEND', Buffer.alloc(0)),
]);
}
// ---------------------------------------------------------------------------
// Icon builders
// ---------------------------------------------------------------------------
const SS = 4; // supersampling factor
// Standard (rounded tile) icon: transparent corners, rounded blue tile,
// margin ~8%, centered emblem.
function buildStandard(size, simplified = false) {
const W = size * SS;
const cv = makeCanvas(W, W, null); // transparent background
const margin = W * 0.08;
const radius = W * 0.18;
fillRoundedRect(cv, margin, margin, W - margin, W - margin, radius, BLUE, 255);
const cx = W / 2, cy = W / 2;
// emblem content sized to ~ inner tile
const half = (W - 2 * margin) * 0.30;
drawEmblem(cv, cx, cy, half, simplified);
return downsample(cv, SS);
}
// Maskable icon: FULL-BLEED blue, square corners, emblem inside the central
// 80% safe-zone.
function buildMaskable(size) {
const W = size * SS;
const cv = makeCanvas(W, W, null);
fillBackground(cv, BLUE); // full bleed, opaque
const cx = W / 2, cy = W / 2;
// safe zone is central 80% => content sized so it stays inside 0.8*W box
const half = W * 0.5 * 0.80 * 0.62; // ~31% of half-canvas
drawEmblem(cv, cx, cy, half, false);
return downsample(cv, SS);
}
// Apple touch icon: fully OPAQUE blue background, square corners, emblem.
function buildAppleTouch(size) {
const W = size * SS;
const cv = makeCanvas(W, W, null);
fillBackground(cv, BLUE); // opaque, no transparency
const cx = W / 2, cy = W / 2;
const half = W * 0.30;
drawEmblem(cv, cx, cy, half, false);
return downsample(cv, SS);
}
// Favicon: rounded blue tile + bolder simplified emblem for legibility.
function buildFavicon(size) {
const W = size * SS;
const cv = makeCanvas(W, W, null);
const margin = W * 0.04;
const radius = W * 0.18;
fillRoundedRect(cv, margin, margin, W - margin, W - margin, radius, BLUE, 255);
const cx = W / 2, cy = W / 2;
const half = W * 0.34;
drawEmblem(cv, cx, cy, half, true); // simplified/bolder
return downsample(cv, SS);
}
// ---------------------------------------------------------------------------
// SVG master (same design, vector)
// ---------------------------------------------------------------------------
function buildSVG() {
// Express the same geometry in a 512 viewBox.
const cx = 256, cy = 256, half = 512 * 0.30; // 153.6
const shield = shieldPolygon(cx, cy, half)
.map(p => `${p[0].toFixed(1)},${p[1].toFixed(1)}`).join(' ');
const check = checkPolygon(cx, cy - half * 0.02, half * 1.05, half * 0.24)
.map(p => `${p[0].toFixed(1)},${p[1].toFixed(1)}`).join(' ');
const margin = 512 * 0.08;
const r = 512 * 0.18;
return `<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" width="512" height="512" viewBox="0 0 512 512" role="img" aria-label="NIS2 Agile">
<title>NIS2 Agile</title>
<!-- Italy-blue rounded tile -->
<rect x="${margin}" y="${margin}" width="${512 - 2 * margin}" height="${512 - 2 * margin}" rx="${r}" ry="${r}" fill="#0066CC"/>
<!-- White shield -->
<polygon points="${shield}" fill="#FFFFFF"/>
<!-- Negative blue check -->
<polygon points="${check}" fill="#0066CC"/>
</svg>
`;
}
// ---------------------------------------------------------------------------
// Main
// ---------------------------------------------------------------------------
function main() {
fs.mkdirSync(ICONS_DIR, { recursive: true });
const outputs = [];
function write(name, cv) {
const png = encodePNG(cv);
const fp = path.join(ICONS_DIR, name);
fs.writeFileSync(fp, png);
outputs.push({ name, bytes: png.length, w: cv.w, h: cv.h });
}
write('icon-192.png', buildStandard(192));
write('icon-512.png', buildStandard(512));
write('icon-192-maskable.png', buildMaskable(192));
write('icon-512-maskable.png', buildMaskable(512));
write('apple-touch-icon.png', buildAppleTouch(180));
write('favicon-32.png', buildFavicon(32));
write('favicon-16.png', buildFavicon(16));
// SVG master
const svg = buildSVG();
fs.writeFileSync(path.join(ICONS_DIR, 'icon.svg'), svg);
// ---- Validation: re-read each PNG, verify signature + IHDR dims ----
console.log('\n=== NIS2 PWA Icon Generation ===');
console.log('Output dir:', ICONS_DIR);
console.log('\nFile | Bytes | Declared | Read(IHDR) | SIG');
console.log('---------------------------|--------|----------|------------|----');
let allOk = true;
for (const o of outputs) {
const data = fs.readFileSync(path.join(ICONS_DIR, o.name));
const sigOk =
data.length >= 8 &&
data[0] === 0x89 && data[1] === 0x50 && data[2] === 0x4e && data[3] === 0x47 &&
data[4] === 0x0d && data[5] === 0x0a && data[6] === 0x1a && data[7] === 0x0a;
// IHDR starts at byte 16 (8 sig + 4 len + 4 'IHDR'); width@16, height@20
const rw = data.readUInt32BE(16);
const rh = data.readUInt32BE(20);
const nonEmpty = data.length > 0;
const ok = sigOk && nonEmpty && rw === o.w && rh === o.h;
if (!ok) allOk = false;
console.log(
`${o.name.padEnd(26)} | ${String(o.bytes).padStart(6)} | ${(o.w + 'x' + o.h).padStart(8)} | ${(rw + 'x' + rh).padStart(10)} | ${ok ? 'OK' : 'KO'}`
);
}
// SVG report
const svgStat = fs.statSync(path.join(ICONS_DIR, 'icon.svg'));
console.log(`${'icon.svg'.padEnd(26)} | ${String(svgStat.size).padStart(6)} | ${'vector'.padStart(8)} | ${'-'.padStart(10)} | ${svgStat.size > 0 ? 'OK' : 'KO'}`);
console.log('\nValidation:', allOk ? 'ALL PNG OK' : 'FAILURES PRESENT');
if (!allOk) process.exitCode = 1;
}
main();
+86
View File
@@ -0,0 +1,86 @@
#!/usr/bin/env node
/*
* Inietta i tag PWA negli <head> di tutte le pagine HTML sotto public/.
* Idempotente: salta i file che contengono gia' il marker <!-- PWA:start -->.
* Normalizza il viewport mantenendo lo zoom abilitato (WCAG 1.4.4 / AGID).
* Esegue solo modifiche additive e mirate; tutto e' git-tracked => reversibile.
*
* Uso: node scripts/inject-pwa-head.mjs
*/
import fs from 'node:fs';
import path from 'node:path';
const ROOT = path.resolve(process.cwd(), 'public');
const EXCLUDE_BASENAMES = new Set(['offline.html']);
const MARKER = '<!-- PWA:start -->';
const VIEWPORT = '<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">';
const BLOCK = [
' <!-- PWA:start -->',
' <link rel="manifest" href="/manifest.webmanifest">',
' <meta name="theme-color" content="#0066CC">',
' <link rel="icon" type="image/png" sizes="32x32" href="/assets/icons/favicon-32.png">',
' <link rel="icon" type="image/png" sizes="16x16" href="/assets/icons/favicon-16.png">',
' <link rel="apple-touch-icon" sizes="180x180" href="/assets/icons/apple-touch-icon.png">',
' <meta name="apple-mobile-web-app-capable" content="yes">',
' <meta name="mobile-web-app-capable" content="yes">',
' <meta name="apple-mobile-web-app-status-bar-style" content="default">',
' <meta name="apple-mobile-web-app-title" content="NIS2 Agile">',
' <meta name="application-name" content="NIS2 Agile">',
' <script src="/js/pwa.js?v=20260614" defer></script>',
' <!-- PWA:end -->'
].join('\n');
function walk(dir) {
let out = [];
for (const e of fs.readdirSync(dir, { withFileTypes: true })) {
const full = path.join(dir, e.name);
if (e.isDirectory()) out = out.concat(walk(full));
else if (e.isFile() && e.name.toLowerCase().endsWith('.html')) out.push(full);
}
return out;
}
const files = walk(ROOT).filter((f) => {
const b = path.basename(f);
if (EXCLUDE_BASENAMES.has(b)) return false;
if (/copy/i.test(b)) return false;
return true;
});
let modified = 0, already = 0, nohead = 0, viewportFixed = 0;
const anomalies = [];
for (const f of files) {
let html = fs.readFileSync(f, 'utf8');
if (html.includes(MARKER)) { already++; continue; }
if (!/<\/head>/i.test(html)) {
nohead++;
anomalies.push('NO </head>: ' + path.relative(process.cwd(), f));
continue;
}
// Normalizza il viewport (zoom SEMPRE consentito: no user-scalable=no / maximum-scale)
const vp = html.match(/<meta\s+name=["']viewport["'][^>]*>/i);
if (vp) {
if (!/viewport-fit=cover/i.test(vp[0])) {
html = html.replace(vp[0], VIEWPORT);
viewportFixed++;
}
}
const inject = (vp ? '' : (' ' + VIEWPORT + '\n')) + BLOCK + '\n';
// replace con funzione per evitare interpretazione di pattern '$' nel testo iniettato
html = html.replace(/<\/head>/i, () => inject + '</head>');
fs.writeFileSync(f, html);
modified++;
}
console.log('HTML trovati:', files.length);
console.log('Modificati:', modified, '| gia col marker:', already,
'| senza </head>:', nohead, '| viewport normalizzati:', viewportFixed);
if (anomalies.length) {
console.log('Anomalie:');
anomalies.forEach((a) => console.log(' -', a));
}