diff --git a/public/simulate.html b/public/simulate.html index 3c604a5..66d54f0 100644 --- a/public/simulate.html +++ b/public/simulate.html @@ -13,28 +13,29 @@ } body { background: var(--dark); color: #e2e8f0; font-family: -apple-system,BlinkMacSystemFont,'Segoe UI',system-ui,sans-serif; min-height: 100vh; } - .header { background: linear-gradient(135deg,#0c4a6e,#0e7490); padding: 32px 48px; border-bottom: 1px solid #0e7490; } + .header { background: linear-gradient(135deg,#0c4a6e,#0e7490); padding: 28px 48px; border-bottom: 1px solid #0e7490; } .header h1 { font-size: 1.5rem; font-weight: 800; color: #fff; margin-bottom: 4px; } .header p { color: #7dd3fc; font-size: 0.875rem; } .badge { display: inline-block; padding: 2px 10px; border-radius: 20px; font-size: 0.7rem; font-weight: 700; margin-right: 8px; } .badge-cyan { background: rgba(6,182,212,.2); color: #67e8f9; border: 1px solid rgba(6,182,212,.3); } .badge-green { background: rgba(34,197,94,.2); color: #86efac; border: 1px solid rgba(34,197,94,.3); } + .badge-yellow { background: rgba(245,158,11,.2); color: #fcd34d; border: 1px solid rgba(245,158,11,.3); } - .container { max-width: 1100px; margin: 0 auto; padding: 32px 24px; display: grid; grid-template-columns: 320px 1fr; gap: 24px; } + .container { max-width: 1100px; margin: 0 auto; padding: 28px 24px; display: grid; grid-template-columns: 330px 1fr; gap: 24px; } /* Left panel */ - .panel { background: var(--card); border: 1px solid var(--border); border-radius: 12px; padding: 20px; } - .panel h3 { font-size: 0.875rem; font-weight: 700; color: #94a3b8; text-transform: uppercase; letter-spacing: .05em; margin-bottom: 16px; } + .panel { background: var(--card); border: 1px solid var(--border); border-radius: 12px; padding: 18px; } + .panel h3 { font-size: 0.8rem; font-weight: 700; color: #94a3b8; text-transform: uppercase; letter-spacing: .05em; margin-bottom: 14px; } - .sim-card { background: #0f172a; border: 1px solid var(--border); border-radius: 8px; padding: 14px; margin-bottom: 10px; cursor: pointer; transition: border-color .2s; } + .sim-card { background: #0f172a; border: 1px solid var(--border); border-radius: 8px; padding: 12px; margin-bottom: 8px; cursor: pointer; transition: border-color .2s; } .sim-card:hover { border-color: var(--primary); } .sim-card.active { border-color: var(--primary); background: #0c2230; } - .sim-card h4 { font-size: 0.8125rem; font-weight: 700; color: #e2e8f0; margin-bottom: 4px; } - .sim-card p { font-size: 0.75rem; color: #64748b; line-height: 1.5; } - .sim-card .sim-badge { font-size: 0.65rem; padding: 1px 7px; border-radius: 10px; font-weight: 700; margin-bottom: 6px; display: inline-block; } + .sim-card h4 { font-size: 0.8125rem; font-weight: 700; color: #e2e8f0; margin-bottom: 3px; } + .sim-card p { font-size: 0.7375rem; color: #64748b; line-height: 1.5; } + .sim-card .sim-badge { font-size: 0.65rem; padding: 1px 7px; border-radius: 10px; font-weight: 700; margin-bottom: 5px; display: inline-block; } - .company-list { margin-bottom: 20px; } - .company-item { display: flex; align-items: center; gap: 10px; padding: 10px 12px; border-radius: 8px; background: #0f172a; border: 1px solid var(--border); margin-bottom: 8px; } + .company-list { margin-bottom: 16px; } + .company-item { display: flex; align-items: center; gap: 10px; padding: 9px 12px; border-radius: 8px; background: #0f172a; border: 1px solid var(--border); margin-bottom: 6px; } .company-dot { width: 8px; height: 8px; border-radius: 50%; flex-shrink: 0; } .dot-cyan { background: #06b6d4; } .dot-purple { background: #8b5cf6; } @@ -43,8 +44,8 @@ .company-item small { font-size: 0.7rem; color: #64748b; display: block; } /* Controls */ - .controls { display: flex; flex-direction: column; gap: 10px; margin-bottom: 16px; } - .btn { padding: 10px 20px; border: none; border-radius: 8px; font-size: 0.875rem; font-weight: 700; cursor: pointer; transition: all .2s; } + .controls { display: flex; flex-direction: column; gap: 8px; margin-bottom: 12px; } + .btn { padding: 10px 20px; border: none; border-radius: 8px; font-size: 0.875rem; font-weight: 700; cursor: pointer; transition: all .2s; display: flex; align-items: center; justify-content: center; gap: 8px; } .btn-primary { background: var(--primary); color: #0f172a; } .btn-primary:hover:not(:disabled) { background: #0891b2; } .btn-primary:disabled { opacity: .5; cursor: not-allowed; } @@ -53,7 +54,16 @@ .btn-gray { background: #1e293b; color: #94a3b8; border: 1px solid var(--border); } .btn-gray:hover { background: #334155; } - .status-bar { padding: 10px 12px; border-radius: 8px; font-size: 0.8rem; background: #0f172a; border: 1px solid var(--border); } + /* Spinner */ + .spinner { display: none; width: 13px; height: 13px; border: 2px solid rgba(15,23,42,.3); border-top-color: #0f172a; border-radius: 50%; animation: spin .7s linear infinite; flex-shrink: 0; } + .spinner.active { display: inline-block; } + @keyframes spin { to { transform: rotate(360deg); } } + + /* Auto-reset note */ + .auto-reset-note { font-size: 0.7rem; color: #475569; text-align: center; padding: 6px; border: 1px dashed #334155; border-radius: 6px; background: rgba(6,182,212,.03); } + .auto-reset-note span { color: #67e8f9; } + + .status-bar { padding: 9px 12px; border-radius: 8px; font-size: 0.8rem; background: #0f172a; border: 1px solid var(--border); } .status-dot { width: 8px; height: 8px; border-radius: 50%; display: inline-block; margin-right: 6px; } .dot-idle { background: #475569; } .dot-running { background: #22c55e; animation: pulse 1s infinite; } @@ -61,59 +71,88 @@ .dot-error { background: #ef4444; } @keyframes pulse { 0%,100%{opacity:1} 50%{opacity:.4} } - .stats-grid { display: grid; grid-template-columns: repeat(4,1fr); gap: 8px; margin-top: 12px; } - .stat-box { background: #0f172a; border: 1px solid var(--border); border-radius: 6px; padding: 10px; text-align: center; } - .stat-box .num { font-size: 1.25rem; font-weight: 800; } - .stat-box .lbl { font-size: 0.65rem; color: #64748b; text-transform: uppercase; margin-top: 2px; } + .stats-grid { display: grid; grid-template-columns: repeat(4,1fr); gap: 6px; margin-top: 10px; } + .stat-box { background: #0f172a; border: 1px solid var(--border); border-radius: 6px; padding: 8px; text-align: center; } + .stat-box .num { font-size: 1.2rem; font-weight: 800; } + .stat-box .lbl { font-size: 0.6rem; color: #64748b; text-transform: uppercase; margin-top: 2px; } .num-pass { color: var(--green); } .num-skip { color: #94a3b8; } .num-warn { color: var(--yellow); } .num-fail { color: var(--red); } + /* Run History */ + .history-section { margin-top: 14px; } + .history-title { font-size: 0.75rem; font-weight: 700; color: #475569; text-transform: uppercase; letter-spacing: .05em; margin-bottom: 8px; } + .history-item { display: flex; align-items: center; gap: 8px; padding: 7px 10px; border-radius: 6px; background: #0f172a; border: 1px solid var(--border); margin-bottom: 5px; cursor: pointer; transition: border-color .15s; font-size: 0.73rem; } + .history-item:hover { border-color: #475569; } + .hi-dot { width: 7px; height: 7px; border-radius: 50%; flex-shrink: 0; } + .hi-dot.ok { background: #22c55e; } + .hi-dot.fail { background: #ef4444; } + .hi-label { color: #94a3b8; flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } + .hi-time { color: #475569; font-size: 0.65rem; white-space: nowrap; } + .hi-elapsed { color: #67e8f9; font-size: 0.65rem; margin-left: 4px; white-space: nowrap; } + .history-empty { font-size: 0.73rem; color: #475569; text-align: center; padding: 8px; } + /* Right panel — Console */ .console-panel { display: flex; flex-direction: column; gap: 0; } - .console-header { background: #1e293b; border: 1px solid var(--border); border-radius: 12px 12px 0 0; padding: 12px 16px; display: flex; align-items: center; justify-content: space-between; } + .console-header { background: #1e293b; border: 1px solid var(--border); border-radius: 12px 12px 0 0; padding: 11px 16px; display: flex; align-items: center; justify-content: space-between; } .console-header span { font-size: 0.8rem; color: #94a3b8; } .console-dots { display: flex; gap: 6px; } .console-dot { width: 10px; height: 10px; border-radius: 50%; } .console-dot-r { background: #ef4444; } .console-dot-y { background: #f59e0b; } .console-dot-g { background: #22c55e; } - #console { background: #0a0f1a; border: 1px solid var(--border); border-top: none; border-radius: 0 0 12px 12px; padding: 16px; height: 520px; overflow-y: auto; font-family: 'Cascadia Code','Consolas',monospace; font-size: 0.78rem; line-height: 1.7; } - .log-phase { color: #38bdf8; font-weight: 700; border-top: 1px solid #1e3a5f; padding-top: 8px; margin-top: 4px; } + + #console { + background: #0a0f1a; + border: 1px solid var(--border); border-top: none; border-radius: 0 0 12px 12px; + padding: 16px; height: 560px; overflow-y: auto; + font-family: 'Cascadia Code','Consolas','Fira Code',monospace; + font-size: 0.775rem; line-height: 1.75; + } + /* log line colors */ + .log-phase { color: #38bdf8; font-weight: 700; border-top: 1px solid #1e3a5f; padding-top: 8px; margin-top: 6px; } .log-ok { color: #86efac; } .log-skip { color: #64748b; } .log-warn { color: #fcd34d; } .log-error { color: #fca5a5; } .log-email { color: #67e8f9; } .log-info { color: #94a3b8; } - .log-done { color: #a78bfa; font-weight: 700; border-top: 1px solid #3730a3; padding-top: 8px; margin-top: 4px; } + .log-done { color: #a78bfa; font-weight: 700; border-top: 1px solid #3730a3; padding-top: 8px; margin-top: 6px; } + + /* Phase step banner */ + .log-phase-banner { + background: rgba(56,189,248,.07); + border-left: 3px solid #38bdf8; + padding: 4px 10px; margin: 6px 0 4px; + color: #7dd3fc; font-weight: 700; + } /* Progress bar */ - .progress-wrap { height: 4px; background: #1e293b; border-radius: 2px; overflow: hidden; margin-bottom: 16px; } - .progress-bar { height: 100%; background: var(--primary); width: 0%; transition: width .3s; } + .progress-wrap { height: 4px; background: #1e293b; border-radius: 2px; overflow: hidden; margin-bottom: 14px; } + .progress-bar { height: 100%; background: var(--primary); width: 0%; transition: width .4s; } - @media (max-width: 768px) { - .container { grid-template-columns: 1fr; } - } + @media (max-width: 768px) { .container { grid-template-columns: 1fr; } }
Genera dati demo NIS2 realistici tramite API reali — 3 aziende, 5 scenari, audit trail certificato SHA-256
+3 aziende · 6 scenari · reset automatico · audit trail SHA-256 · dati creati via API reali
Esegue tutti e 5 gli scenari in sequenza: onboarding, incidenti, data breach, whistleblowing, audit chain.
+SIM-01→06 in sequenza: onboarding, incidenti, data breach, whistleblowing, audit chain, B2B.
Registra le 3 aziende, classifica NIS2 (Essential/Important), esegue assessment 80 domande Art.21.
+Registra 3 aziende, classifica NIS2, esegue assessment 80 domande Art.21.
Attacco ransomware su infrastruttura cloud. Timeline 24h/72h/30d con notifiche ACN e CSIRT.
+Attacco critico su cloud. Timeline 24h/72h/30d con notifiche CSIRT.
Fornitore LIS compromesso, esfiltrazione 2.340 pazienti. GDPR Art.33 + NIS2 Art.23 in parallelo.
+Fornitore LIS compromesso. GDPR Art.33 + NIS2 Art.23 in parallelo.
Segnalazione anonima accesso non autorizzato SCADA. Token tracking, investigazione, chiusura.
+Segnalazione anonima accesso non autorizzato SCADA. Token tracking.
Verifica integrità SHA-256 hash chain per le 3 org. Export certificato NIS2 + ISO 27001.
+Verifica integrità SHA-256 hash chain per le 3 org. Export certificato.
+Invite token → org + user + API key creati atomicamente. SSO JWT.