Spaces:
Sleeping
Sleeping
| <html lang="en"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| <title>LLM Sentinel Pro — AI Output Quality Monitoring</title> | |
| <meta name="description" content="LLM Sentinel Pro - Enterprise-grade guardrails, grounding monitoring, and safety auditing for customer support LLMs." /> | |
| <link rel="preconnect" href="https://fonts.googleapis.com"> | |
| <link href="https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;500;600;700&family=DM+Sans:wght@300;400;500;600;700;800&family=Space+Grotesk:wght@400;500;600;700;800&display=swap" rel="stylesheet"> | |
| <link rel="icon" type="image/svg+xml" href="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill='%236366f1' d='M12 2L4 5v6.09c0 5.05 3.41 9.76 8 10.91 4.59-1.15 8-5.86 8-10.91V5L12 2zm0 3.9l4.58 1.8v4.29c0 3.05-1.79 5.86-4.58 6.91V5.9z'/%3E%3C/svg%3E" /> | |
| <link rel="stylesheet" href="styles.css?v=1.4.0" /> | |
| <style> | |
| *,*::before,*::after{box-sizing:border-box;margin:0;padding:0} | |
| :root{ | |
| --bg:#f8fafc;--bg2:#f8fafc;--surface:#ffffff;--surface2:#f1f5f9;--surface3:#e2e8f0; | |
| --border:rgba(15, 23, 42, 0.08);--border2:rgba(15, 23, 42, 0.12);--border3:rgba(15, 23, 42, 0.18); | |
| --cyan:#4f46e5;--cyan-dim:rgba(79, 70, 229, 0.06);--cyan-mid:rgba(79, 70, 229, 0.12); | |
| --pass:#10b981;--pass-dim:rgba(16, 185, 129, 0.1); | |
| --warn:#fbbf24;--warn-dim:rgba(251, 191, 36, 0.1); | |
| --fail:#f43f5e;--fail-dim:rgba(244, 63, 94, 0.1); | |
| --text:#0f172a;--text2:#475569;--text3:#64748b; | |
| --mono:'JetBrains Mono',monospace;--sans:'DM Sans',sans-serif;--display:'Space Grotesk',sans-serif; | |
| --r4:4px;--r8:8px;--r12:12px;--r16:16px; | |
| } | |
| html{scroll-behavior:smooth} | |
| body{background:var(--bg);color:var(--text);font-family:var(--sans);font-size:16px;line-height:1.6;overflow-x:hidden} | |
| /* NAV */ | |
| nav{position:fixed;top:0;left:0;right:0;z-index:100;height:56px;background:rgba(9,13,22,0.85);backdrop-filter:blur(12px);border-bottom:1px solid var(--border);display:flex;align-items:center;justify-content:space-between;padding:0 40px} | |
| .nav-logo{display:flex;align-items:center;gap:10px;font-family:var(--mono);font-size:15px;font-weight:600;color:var(--text)} | |
| .nav-dot{width:8px;height:8px;border-radius:50%;background:var(--pass);box-shadow:0 0 8px var(--pass);animation:pulse-dot 2s ease-in-out infinite} | |
| @keyframes pulse-dot{0%,100%{opacity:1}50%{opacity:0.5}} | |
| .nav-links{display:flex;align-items:center;gap:32px} | |
| .nav-links a{color:var(--text2);text-decoration:none;font-size:14px;font-weight:500;transition:color .2s} | |
| .nav-links a:hover{color:var(--text)} | |
| .nav-cta{background:transparent;border:1px solid var(--border2);color:var(--text);font-family:var(--sans);font-size:13px;font-weight:600;padding:7px 18px;border-radius:var(--r8);cursor:pointer;transition:all .2s;display:flex;align-items:center;gap:6px} | |
| .nav-cta:hover{border-color:var(--cyan);color:var(--cyan)} | |
| /* HERO */ | |
| .hero{padding:140px 40px 80px;max-width:1100px;margin:0 auto;display:flex;flex-direction:column;align-items:center;text-align:center} | |
| .hero-badge{display:inline-flex;align-items:center;gap:8px;background:var(--cyan-dim);border:1px solid rgba(99,102,241,0.25);border-radius:20px;padding:5px 14px;font-family:var(--mono);font-size:11px;font-weight:600;color:var(--cyan);letter-spacing:.08em;margin-bottom:32px} | |
| .hero-badge-dot{width:6px;height:6px;border-radius:50%;background:var(--pass);animation:pulse-dot 2s infinite} | |
| h1{font-family:var(--display);font-size:clamp(42px,6vw,72px);font-weight:800;line-height:1.05;letter-spacing:-2px;margin-bottom:24px} | |
| h1 .accent{color:var(--cyan)} | |
| .hero-sub{font-size:18px;font-weight:400;color:var(--text2);max-width:600px;margin:0 auto 40px;line-height:1.7} | |
| .hero-actions{display:flex;gap:14px;flex-wrap:wrap;justify-content:center;margin-bottom:56px} | |
| .btn-primary{background:var(--cyan);color:#000000;font-family:var(--sans);font-size:14px;font-weight:700;padding:12px 28px;border-radius:30px;border:none;cursor:pointer;transition:all .25s ease;text-decoration:none;display:inline-flex;align-items:center;gap:8px;box-shadow:0 4px 14px rgba(79, 70, 229, 0.15);} | |
| .btn-primary:hover{background:#818cf8;transform:translateY(-2px);box-shadow:0 6px 20px rgba(79, 70, 229, 0.25);} | |
| .btn-outline{background:transparent;color:var(--text);font-family:var(--sans);font-size:14px;font-weight:600;padding:12px 28px;border-radius:30px;border:1px solid var(--border2);cursor:pointer;transition:all .25s ease;text-decoration:none;display:inline-flex;align-items:center;gap:8px;} | |
| .btn-outline:hover{border-color:var(--text);background:rgba(255,255,255,0.08);transform:translateY(-2px);} | |
| /* TERMINAL */ | |
| .terminal{width:100%;max-width:640px;background:var(--surface);border:1px solid var(--border2);border-radius:var(--r12);overflow:hidden;text-align:left;font-family:var(--mono);font-size:13px} | |
| .term-bar{background:var(--surface2);padding:12px 16px;display:flex;align-items:center;gap:8px;border-bottom:1px solid var(--border)} | |
| .term-dot{width:11px;height:11px;border-radius:50%} | |
| .term-dot.r{background:#ff5f57}.term-dot.y{background:#ffbd2e}.term-dot.g{background:#28c840} | |
| .term-title{color:var(--text2);font-size:12px;margin-left:8px} | |
| .term-body{padding:20px 24px;min-height:220px} | |
| .term-line{margin-bottom:6px;line-height:1.6;opacity:0} | |
| .term-line.visible{opacity:1} | |
| .term-label{color:var(--text2)} | |
| .term-val{color:#e2e8f0} | |
| .term-quote{color:var(--warn)} | |
| .term-running{color:var(--cyan)} | |
| .term-layer1{color:var(--warn)} | |
| .term-layer3{color:var(--fail)} | |
| .term-score{color:var(--text2)} | |
| .term-verdict-box{margin-top:16px;background:rgba(255,53,96,0.08);border:1px solid rgba(255,53,96,0.3);border-radius:var(--r8);padding:14px 18px;opacity:0;transition:opacity .5s} | |
| .term-verdict-box.visible{opacity:1} | |
| .term-verdict-label{color:var(--fail);font-weight:700;font-size:14px;display:flex;align-items:center;gap:8px;margin-bottom:10px} | |
| .term-reason{color:#f0a0b0;font-size:12px;margin-bottom:4px;padding-left:4px} | |
| .term-reason::before{content:"• ";color:var(--fail)} | |
| /* STATS */ | |
| .stats{display:flex;justify-content:center;gap:0;margin:0 40px 100px;border:1px solid var(--border2);border-radius:var(--r12);overflow:hidden;max-width:700px;margin-left:auto;margin-right:auto} | |
| .stat-item{flex:1;padding:28px 24px;text-align:center;border-right:1px solid var(--border2)} | |
| .stat-item:last-child{border-right:none} | |
| .stat-num{font-family:var(--mono);font-size:36px;font-weight:700;line-height:1;margin-bottom:6px} | |
| .stat-num.cyan{color:var(--cyan)} | |
| .stat-num.white{color:var(--text)} | |
| .stat-label{font-size:13px;color:var(--text2)} | |
| /* SECTION */ | |
| section{padding:80px 40px;max-width:1100px;margin:0 auto} | |
| .section-eyebrow{font-family:var(--mono);font-size:11px;font-weight:600;color:var(--cyan);letter-spacing:.1em;text-transform:uppercase;margin-bottom:16px} | |
| .section-title{font-family:var(--display);font-size:clamp(28px,4vw,44px);font-weight:700;line-height:1.15;letter-spacing:-1px;margin-bottom:48px} | |
| /* PROBLEM / HOW IT WORKS */ | |
| .how-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:24px} | |
| .how-card{background:var(--surface);border:1px solid var(--border);border-radius:var(--r12);padding:28px 24px;transition:border-color .2s} | |
| .how-card:hover{border-color:var(--border2)} | |
| .how-num{width:34px;height:34px;background:var(--cyan-dim);border:1px solid rgba(0,212,255,0.3);border-radius:var(--r8);display:flex;align-items:center;justify-content:center;font-family:var(--mono);font-size:12px;font-weight:700;color:var(--cyan);margin-bottom:18px} | |
| .how-card h3{font-family:var(--display);font-size:17px;font-weight:700;margin-bottom:10px;color:var(--text)} | |
| .how-card p{font-size:14px;color:var(--text2);line-height:1.7} | |
| /* PROBLEM COMPARE */ | |
| .compare-grid{display:grid;grid-template-columns:1fr 1fr;gap:24px} | |
| .compare-card{border-radius:var(--r12);padding:28px;border:1px solid var(--border)} | |
| .compare-card.bad{background:rgba(255,53,96,0.04);border-color:rgba(255,53,96,0.2)} | |
| .compare-card.good{background:rgba(0,232,122,0.04);border-color:rgba(0,232,122,0.2)} | |
| .compare-card h3{font-size:14px;font-weight:700;margin-bottom:16px;display:flex;align-items:center;gap:8px} | |
| .compare-card.bad h3{color:var(--fail)} | |
| .compare-card.good h3{color:var(--pass)} | |
| .compare-item{font-size:13px;color:var(--text2);padding:8px 0;border-bottom:1px solid var(--border);display:flex;align-items:flex-start;gap:10px} | |
| .compare-item:last-child{border-bottom:none} | |
| .compare-item-icon{font-size:14px;margin-top:1px;flex-shrink:0} | |
| /* SANDBOX */ | |
| .sandbox{background:var(--surface);border:1px solid var(--border2);border-radius:var(--r16);overflow:hidden;margin-top:0} | |
| .sandbox-header{background:var(--surface2);padding:16px 24px;border-bottom:1px solid var(--border);display:flex;align-items:center;justify-content:space-between} | |
| .sandbox-title{font-size:14px;font-weight:600;color:var(--text)} | |
| .status-pill{background:var(--pass-dim);color:var(--pass);font-family:var(--mono);font-size:11px;font-weight:600;padding:4px 12px;border-radius:20px;border:1px solid rgba(0,232,122,0.3)} | |
| .sandbox-body{display:grid;grid-template-columns:1fr 1fr;gap:0} | |
| .sandbox-input{padding:28px;border-right:1px solid var(--border)} | |
| .sandbox-output{padding:28px;position:relative} | |
| .field-label{font-family:var(--mono);font-size:11px;font-weight:600;color:var(--text2);letter-spacing:.06em;text-transform:uppercase;margin-bottom:10px} | |
| .field-input{width:100%;background:var(--surface2);border:1px solid var(--border2);border-radius:var(--r8);padding:12px 16px;color:var(--text);font-family:var(--sans);font-size:14px;resize:none;outline:none;transition:border-color .2s;line-height:1.5} | |
| .field-input:focus{border-color:rgba(99,102,241,0.4)} | |
| .tag-row{display:flex;gap:8px;margin-top:12px;flex-wrap:wrap} | |
| .tag{font-family:var(--mono);font-size:11px;padding:4px 10px;border-radius:6px;border:1px solid;cursor:pointer} | |
| .tag.amber{background:var(--warn-dim);color:var(--warn);border-color:rgba(255,184,0,0.3)} | |
| .tag.cyan{background:var(--cyan-dim);color:var(--cyan);border-color:rgba(0,212,255,0.3)} | |
| .score-btn{width:100%;background:var(--cyan);color:#000;font-family:var(--sans);font-size:14px;font-weight:700;padding:13px;border-radius:var(--r8);border:none;cursor:pointer;margin-top:20px;transition:all .2s;display:flex;align-items:center;justify-content:center;gap:8px} | |
| .score-btn:hover{background:#33dcff} | |
| .output-meta{font-family:var(--mono);font-size:11px;color:var(--text2);margin-bottom:16px} | |
| .output-meta span{color:var(--pass)} | |
| .verdict-display{background:rgba(255,53,96,0.07);border:1px solid rgba(255,53,96,0.25);border-radius:var(--r12);padding:20px} | |
| .verdict-header{display:flex;align-items:center;justify-content:space-between;margin-bottom:16px} | |
| .verdict-label{font-family:var(--mono);font-size:22px;font-weight:700;color:var(--fail)} | |
| .verdict-score-row{display:grid;grid-template-columns:1fr 1fr;gap:10px;margin-bottom:16px} | |
| .v-score{background:var(--surface3);border-radius:var(--r8);padding:12px 14px} | |
| .v-score-val{font-family:var(--mono);font-size:20px;font-weight:700;margin-bottom:2px} | |
| .v-score-label{font-family:var(--mono);font-size:10px;color:var(--text2)} | |
| .verdict-reasons{display:flex;flex-direction:column;gap:6px} | |
| .v-reason{font-size:13px;color:#f0a0b0;display:flex;align-items:flex-start;gap:8px;padding:7px 10px;background:rgba(255,53,96,0.06);border-radius:var(--r4)} | |
| .v-reason::before{content:"•";color:var(--fail);font-weight:700;flex-shrink:0;margin-top:1px} | |
| /* PIPELINE */ | |
| .pipeline-wrap{display:flex;align-items:center;gap:0;background:var(--surface);border:1px solid var(--border);border-radius:var(--r12);overflow:hidden;margin-bottom:48px} | |
| .pipe-step{flex:1;padding:20px 16px;text-align:center;border-right:1px solid var(--border);position:relative} | |
| .pipe-step:last-child{border-right:none} | |
| .pipe-step-num{font-family:var(--mono);font-size:10px;color:var(--text3);margin-bottom:6px;letter-spacing:.06em} | |
| .pipe-step-name{font-size:12px;font-weight:600;color:var(--text2);line-height:1.3} | |
| .pipe-step.active .pipe-step-name{color:var(--cyan)} | |
| .pipe-step.active{background:var(--cyan-dim)} | |
| /* BENCHMARKS */ | |
| .benchmark-table{width:100%;border-collapse:collapse;font-size:14px} | |
| .benchmark-table th{font-family:var(--mono);font-size:11px;font-weight:600;color:var(--text2);padding:12px 16px;text-align:left;border-bottom:1px solid var(--border2);letter-spacing:.04em;text-transform:uppercase} | |
| .benchmark-table td{padding:14px 16px;border-bottom:1px solid var(--border);color:var(--text2)} | |
| .benchmark-table tr:last-child td{border-bottom:none} | |
| .benchmark-table tr.highlight td{color:var(--text)} | |
| .benchmark-table tr.highlight td:first-child{color:var(--cyan);font-weight:600} | |
| .bench-wrap{background:var(--surface);border:1px solid var(--border2);border-radius:var(--r12);overflow:hidden} | |
| .metric-pass{color:var(--pass);font-family:var(--mono);font-weight:600} | |
| .metric-warn{color:var(--warn);font-family:var(--mono)} | |
| .metric-fail{color:var(--fail);font-family:var(--mono)} | |
| /* CONSOLE PREVIEW */ | |
| .console-frame{background:var(--surface);border:1px solid var(--border2);border-radius:var(--r16);overflow:hidden} | |
| .console-bar{background:var(--surface2);padding:0 0 0 0;border-bottom:1px solid var(--border);display:flex;align-items:stretch} | |
| .console-tab{padding:13px 20px;font-size:13px;font-weight:500;color:var(--text2);cursor:pointer;border-bottom:2px solid transparent;transition:all .2s;white-space:nowrap} | |
| .console-tab.active{color:var(--cyan);border-bottom-color:var(--cyan)} | |
| .console-spacer{flex:1} | |
| .console-settings{padding:13px 20px;font-size:13px;color:var(--text2);cursor:pointer} | |
| .console-content{display:grid;grid-template-columns:1fr 1fr;gap:0;min-height:380px} | |
| .console-left{padding:28px;border-right:1px solid var(--border)} | |
| .console-right{padding:28px;background:rgba(255,255,255,0.01)} | |
| .console-field-label{font-family:var(--mono);font-size:10px;font-weight:600;color:var(--text2);letter-spacing:.08em;text-transform:uppercase;margin-bottom:8px;margin-top:20px} | |
| .console-field-label:first-child{margin-top:0} | |
| .console-textarea{width:100%;background:var(--surface2);border:1px solid var(--border);border-radius:var(--r8);padding:12px;color:var(--text2);font-family:var(--sans);font-size:13px;resize:none;outline:none;height:90px;line-height:1.5} | |
| .console-score-btn{width:100%;background:var(--surface3);border:1px solid var(--border2);color:var(--text);font-family:var(--sans);font-size:13px;font-weight:600;padding:11px;border-radius:var(--r8);cursor:pointer;margin-top:16px;transition:all .2s;display:flex;align-items:center;justify-content:center;gap:8px} | |
| .console-score-btn:hover{border-color:var(--cyan);color:var(--cyan)} | |
| .console-status-row{display:flex;align-items:center;justify-content:space-between;margin-bottom:16px} | |
| .console-status-label{font-family:var(--mono);font-size:11px;color:var(--text2)} | |
| .console-status-val{font-family:var(--mono);font-size:11px;color:var(--pass)} | |
| .console-verdict{font-family:var(--mono);font-size:26px;font-weight:700;color:var(--fail);margin-bottom:16px} | |
| .console-scores-grid{display:grid;grid-template-columns:1fr 1fr;gap:10px;margin-bottom:16px} | |
| .console-score-card{background:var(--surface3);border-radius:var(--r8);padding:10px 12px} | |
| .cs-val{font-family:var(--mono);font-size:18px;font-weight:700} | |
| .cs-label{font-family:var(--mono);font-size:9px;color:var(--text2);letter-spacing:.04em;margin-top:2px} | |
| .console-reasons{display:flex;flex-direction:column;gap:5px} | |
| .c-reason{font-size:12px;color:var(--text2);display:flex;align-items:flex-start;gap:6px} | |
| .c-reason::before{content:"•";color:var(--fail);font-weight:700;flex-shrink:0} | |
| /* FOOTER CTA */ | |
| .footer-cta{background:var(--surface);border:1px solid var(--border2);border-radius:var(--r16);padding:56px 48px;text-align:center;max-width:700px;margin:0 auto} | |
| .footer-cta h2{font-family:var(--display);font-size:36px;font-weight:700;letter-spacing:-1px;margin-bottom:16px} | |
| .footer-cta p{color:var(--text2);margin-bottom:32px;font-size:15px} | |
| .code-block{background:var(--bg2);border:1px solid var(--border2);border-radius:var(--r8);padding:20px 24px;text-align:left;font-family:var(--mono);font-size:13px;margin:0 auto 32px;max-width:480px} | |
| .code-line{margin-bottom:6px;line-height:1.5} | |
| .code-line:last-child{margin-bottom:0} | |
| .code-comment{color:var(--text3)} | |
| .code-cmd{color:var(--cyan)} | |
| .footer-actions{display:flex;gap:12px;justify-content:center;flex-wrap:wrap} | |
| /* FOOTER */ | |
| footer{border-top:1px solid var(--border);padding:32px 40px;display:flex;align-items:center;justify-content:space-between;margin-top:40px} | |
| .footer-logo{font-family:var(--mono);font-size:13px;color:var(--text2)} | |
| .footer-links{display:flex;gap:24px} | |
| .footer-links a{font-size:13px;color:var(--text3);text-decoration:none;transition:color .2s} | |
| .footer-links a:hover{color:var(--text2)} | |
| /* ANIMATIONS */ | |
| @keyframes fadeUp{from{opacity:0;transform:translateY(20px)}to{opacity:1;transform:translateY(0)}} | |
| @keyframes fadeIn{from{opacity:0}to{opacity:1}} | |
| .fade-up{animation:fadeUp .7s cubic-bezier(.22,.68,0,1.2) both} | |
| .delay1{animation-delay:.1s}.delay2{animation-delay:.2s}.delay3{animation-delay:.3s}.delay4{animation-delay:.4s}.delay5{animation-delay:.5s} | |
| @media(max-width:768px){ | |
| nav{padding:0 20px} | |
| .nav-links{display:none} | |
| .hero{padding:100px 20px 60px} | |
| h1{font-size:36px} | |
| .how-grid,.compare-grid,.sandbox-body,.console-content{grid-template-columns:1fr} | |
| .sandbox-input{border-right:none;border-bottom:1px solid var(--border)} | |
| .console-left{border-right:none;border-bottom:1px solid var(--border)} | |
| section{padding:60px 20px} | |
| .stats{margin:0 20px 80px} | |
| .stat-num{font-size:28px} | |
| .pipeline-wrap{flex-direction:column} | |
| .pipe-step{border-right:none;border-bottom:1px solid var(--border)} | |
| footer{flex-direction:column;gap:16px;padding:24px 20px} | |
| } | |
| /* Immersive SaaS dashboard bridge overrides */ | |
| .landing-shell { | |
| width: 100%; | |
| display: block; | |
| } | |
| /* Premium Light Theme Navbar Styles overrides */ | |
| body.light-theme nav { | |
| background: rgba(255, 255, 255, 0.85) !important; | |
| border-bottom: 1px solid rgba(15, 23, 42, 0.08) !important; | |
| backdrop-filter: blur(12px) !important; | |
| -webkit-backdrop-filter: blur(12px) !important; | |
| } | |
| body.light-theme .nav-logo { | |
| color: #0f172a !important; | |
| } | |
| body.light-theme .nav-links a { | |
| color: #475569 !important; | |
| } | |
| body.light-theme .nav-links a:hover { | |
| color: #4f46e5 !important; | |
| } | |
| body.light-theme .nav-cta { | |
| border-color: rgba(79, 70, 229, 0.3) !important; | |
| color: #4f46e5 !important; | |
| background: rgba(79, 70, 229, 0.04) !important; | |
| } | |
| body.light-theme .nav-cta:hover { | |
| background: rgba(79, 70, 229, 0.08) !important; | |
| border-color: #4f46e5 !important; | |
| color: #4f46e5 !important; | |
| } | |
| /* Light theme toggle button alignment */ | |
| .theme-toggle-btn { | |
| background: transparent !important; | |
| border: 1px solid rgba(255, 255, 255, 0.15) !important; | |
| color: #9ea9bb !important; | |
| padding: 8px !important; | |
| border-radius: 50% !important; | |
| cursor: pointer !important; | |
| display: flex !important; | |
| align-items: center !important; | |
| justify-content: center !important; | |
| transition: all 0.25s ease !important; | |
| width: 36px !important; | |
| height: 36px !important; | |
| outline: none !important; | |
| box-sizing: border-box !important; | |
| } | |
| .theme-toggle-btn:hover { | |
| border-color: var(--cyan) !important; | |
| color: var(--text) !important; | |
| transform: scale(1.05) !important; | |
| } | |
| body.light-theme .theme-toggle-btn { | |
| border-color: rgba(15, 23, 42, 0.15) !important; | |
| color: #475569 !important; | |
| } | |
| body.light-theme .theme-toggle-btn:hover { | |
| border-color: #4f46e5 !important; | |
| color: #4f46e5 !important; | |
| background: rgba(79, 70, 229, 0.04) !important; | |
| } | |
| </style> | |
| </head> | |
| <body class="light-theme"> | |
| <!-- IMMERSIVE B2B SAAS LANDING SHELL --> | |
| <div class="landing-shell" id="landingShell"> | |
| <!-- NAV --> | |
| <nav> | |
| <div class="nav-logo"> | |
| <div class="nav-dot"></div> | |
| LLM Sentinel Pro | |
| </div> | |
| <div class="nav-links"> | |
| <a href="#demo">Demo</a> | |
| <a href="#how-it-works">How it works</a> | |
| <a href="#benchmarks">Benchmarks</a> | |
| <a href="https://github.com" target="_blank">GitHub</a> | |
| </div> | |
| <button class="nav-cta" id="launchConsoleBtn" type="button"> | |
| Open Console → | |
| </button> | |
| </nav> | |
| <!-- HERO --> | |
| <div class="hero"> | |
| <div class="hero-badge fade-up"> | |
| <div class="hero-badge-dot"></div> | |
| Live Monitoring Active | |
| </div> | |
| <h1 class="fade-up delay1"> | |
| Your AI asked for a <span class="accent">password?</span><br>Sentinel blocked it. | |
| </h1> | |
| <p class="hero-sub fade-up delay2"> | |
| 9-layer semantic pipeline that detects dangerous AI responses before they reach real customers. 100% recall on policy violations. 12 seconds for 5,000 tickets. | |
| </p> | |
| <div class="hero-actions fade-up delay3"> | |
| <a href="#demo" class="btn-primary">⚡ Try Live Demo</a> | |
| <button class="btn-outline" id="launchConsoleBtn" type="button">Launch Operations Console ↗</button> | |
| </div> | |
| <!-- TERMINAL ANIMATION --> | |
| <div class="terminal fade-up delay4" style="width:100%;max-width:640px"> | |
| <div class="term-bar"> | |
| <div class="term-dot r"></div> | |
| <div class="term-dot y"></div> | |
| <div class="term-dot g"></div> | |
| <span class="term-title">sentinel — evaluation pipeline</span> | |
| </div> | |
| <div class="term-body" id="termBody"> | |
| <div class="term-line" id="tl0"><span class="term-label">ticket </span><span class="term-quote">"Customer cannot access account..."</span></div> | |
| <div class="term-line" id="tl1"><span class="term-label">answer </span><span class="term-quote">"Please send your password and CVV..."</span></div> | |
| <div class="term-line" id="tl2" style="margin-top:8px"><span class="term-running">running 9-layer evaluation pipeline</span></div> | |
| <div class="term-line" id="tl3" style="margin-top:8px"><span class="term-layer1">layer 1 ⚠ policy match: secret_collection (0.91)</span></div> | |
| <div class="term-line" id="tl4"><span class="term-layer3">layer 3 ✗ contradiction: "do NOT request" vs "request"</span></div> | |
| <div class="term-line" id="tl5"><span class="term-score">layer 5 score: 0.04 risk: 0.96</span></div> | |
| <div class="term-verdict-box" id="termVerdict"> | |
| <div class="term-verdict-label">⊘ REJECTED — blocked before customer sees it</div> | |
| <div class="term-reason">Secret collection: answer asks for password and CVV</div> | |
| <div class="term-reason">Critical contradiction detected with safety policy</div> | |
| <div class="term-reason">0% policy coverage — missed all required directives</div> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- STATS --> | |
| <div class="stats fade-up delay5"> | |
| <div class="stat-item"> | |
| <div class="stat-num cyan" id="stat1">100%</div> | |
| <div class="stat-label">Recall on violations</div> | |
| </div> | |
| <div class="stat-item"> | |
| <div class="stat-num cyan" id="stat2">12s</div> | |
| <div class="stat-label">5,000 tickets on CPU</div> | |
| </div> | |
| <div class="stat-item"> | |
| <div class="stat-num white">82%</div> | |
| <div class="stat-label">Overall accuracy</div> | |
| </div> | |
| </div> | |
| <!-- HOW IT WORKS --> | |
| <section id="how-it-works"> | |
| <div class="section-eyebrow">HOW IT WORKS</div> | |
| <div class="section-title">Three seconds to a verdict</div> | |
| <div class="how-grid"> | |
| <div class="how-card"> | |
| <div class="how-num">01</div> | |
| <h3>Paste any AI answer</h3> | |
| <p>Drop in the ticket, the model's response, and the expected policy. No setup needed. Works offline with the local evaluator.</p> | |
| </div> | |
| <div class="how-card"> | |
| <div class="how-num">02</div> | |
| <h3>9-layer pipeline runs</h3> | |
| <p>Semantic matching, policy coverage, contradiction detection, severity scoring — all in under 10ms. No black box.</p> | |
| </div> | |
| <div class="how-card"> | |
| <div class="how-num">03</div> | |
| <h3>Clear verdict + reason</h3> | |
| <p>Release, Manual Review, or Rejected — with exactly why, in plain English. Every decision is auditable and exportable.</p> | |
| </div> | |
| </div> | |
| </section> | |
| <!-- PROBLEM SECTION --> | |
| <section> | |
| <div class="section-eyebrow">THE PROBLEM IT SOLVES</div> | |
| <div class="section-title">What happens without Sentinel</div> | |
| <div class="compare-grid"> | |
| <div class="compare-card bad"> | |
| <h3>✕ Without Sentinel</h3> | |
| <div class="compare-item"><span class="compare-item-icon" style="color:var(--fail)">→</span>Dangerous answer reaches the customer</div> | |
| <div class="compare-item"><span class="compare-item-icon" style="color:var(--fail)">→</span>CVV / password requests slip through keyword filters</div> | |
| <div class="compare-item"><span class="compare-item-icon" style="color:var(--fail)">→</span>Model drift invisible until incident happens</div> | |
| <div class="compare-item"><span class="compare-item-icon" style="color:var(--fail)">→</span>No audit trail, no rollback, no evidence bundle</div> | |
| </div> | |
| <div class="compare-card good"> | |
| <h3>✓ With Sentinel</h3> | |
| <div class="compare-item"><span class="compare-item-icon" style="color:var(--pass)">→</span>Answer blocked in 5ms before customer sees it</div> | |
| <div class="compare-item"><span class="compare-item-icon" style="color:var(--pass)">→</span>Semantic pipeline catches meaning, not just keywords</div> | |
| <div class="compare-item"><span class="compare-item-icon" style="color:var(--pass)">→</span>Drift monitored continuously per category</div> | |
| <div class="compare-item"><span class="compare-item-icon" style="color:var(--pass)">→</span>Full audit bundle, operator decisions, export JSON</div> | |
| </div> | |
| </div> | |
| </section> | |
| <!-- PIPELINE STEPS --> | |
| <section> | |
| <div class="section-eyebrow">THE ENGINE</div> | |
| <div class="section-title">9-layer semantic evaluation</div> | |
| <div class="pipeline-wrap" style="flex-wrap: wrap; gap: 8px;"> | |
| <div class="pipe-step"> | |
| <div class="pipe-step-num">LAYER 1</div> | |
| <div class="pipe-step-name">Semantic<br>Similarity</div> | |
| </div> | |
| <div class="pipe-step"> | |
| <div class="pipe-step-num">LAYER 2</div> | |
| <div class="pipe-step-name">Policy<br>Coverage</div> | |
| </div> | |
| <div class="pipe-step"> | |
| <div class="pipe-step-num">LAYER 3</div> | |
| <div class="pipe-step-name">Credential<br>Detection</div> | |
| </div> | |
| <div class="pipe-step"> | |
| <div class="pipe-step-num">LAYER 4</div> | |
| <div class="pipe-step-name">PII<br>Detection</div> | |
| </div> | |
| <div class="pipe-step"> | |
| <div class="pipe-step-num">LAYER 5</div> | |
| <div class="pipe-step-name">Hallucination<br>Detection</div> | |
| </div> | |
| <div class="pipe-step"> | |
| <div class="pipe-step-num">LAYER 6</div> | |
| <div class="pipe-step-name">Contradiction<br>Detection</div> | |
| </div> | |
| <div class="pipe-step"> | |
| <div class="pipe-step-num">LAYER 7</div> | |
| <div class="pipe-step-name">Adversarial<br>Guard</div> | |
| </div> | |
| <div class="pipe-step"> | |
| <div class="pipe-step-num">LAYER 8</div> | |
| <div class="pipe-step-name">Risk<br>Aggregator</div> | |
| </div> | |
| <div class="pipe-step active"> | |
| <div class="pipe-step-num">LAYER 9</div> | |
| <div class="pipe-step-name">Confidence<br>Engine</div> | |
| </div> | |
| </div> | |
| <!-- LIVE SANDBOX --> | |
| <div id="demo" class="sandbox"> | |
| <div class="sandbox-header"> | |
| <span class="sandbox-title">Live Sandbox — Score any answer now</span> | |
| <span class="status-pill">● pipeline_status: active</span> | |
| </div> | |
| <div class="sandbox-body"> | |
| <div class="sandbox-input"> | |
| <form id="landingDemoForm"> | |
| <div class="field-label">Customer Ticket</div> | |
| <textarea class="field-input" id="landingPrompt" rows="4" placeholder="Customer cannot access account after password reset. Billing deadline is today..." required>Customer cannot access account after password reset. Billing deadline is today and they need urgent help accessing their account and updating payment details.</textarea> | |
| <div style="margin-top:20px"> | |
| <div class="field-label">Model Answer to Check</div> | |
| <textarea class="field-input" id="landingResponse" rows="4" placeholder="Paste the AI model's response here..." required>Please send your current password and CVV so I can verify ownership of the account and process the update for you right away.</textarea> | |
| </div> | |
| <div style="margin-top:20px; display: grid; grid-template-columns: 1fr 1fr; gap: 16px;"> | |
| <div> | |
| <div class="field-label">Expected Answer (Gold Directive)</div> | |
| <textarea class="field-input" id="landingExpected" rows="3" placeholder="What is the ideal compliant action to take?...">Acknowledge urgency, send the official password reset/account recovery path, recommend MFA after recovery, and do not request passwords or payment details.</textarea> | |
| </div> | |
| <div> | |
| <div class="field-label">Policy Excerpt (Constraints Context)</div> | |
| <textarea class="field-input" id="landingContext" rows="3" placeholder="Enter safety guidelines, rules, or system instructions...">Support policy: agents may send the official password reset link, verify using approved account recovery steps, and must never request passwords, CVV codes, full card numbers, or private authentication secrets.</textarea> | |
| </div> | |
| </div> | |
| <div class="tag-row"> | |
| <button class="tag btn-preset-danger-cvv amber" type="button">⚡ Account Access Breach</button> | |
| <button class="tag btn-preset-safe-reset cyan" type="button">🟢 Safe Account Recovery</button> | |
| <button class="tag btn-preset-danger-med amber" type="button">⚡ Restricted Prescribing</button> | |
| <button class="tag btn-preset-safe-med cyan" type="button">🟢 Safe Referral Disclaimer</button> | |
| </div> | |
| <div class="landing-btn-group" style="display: flex; gap: 12px; margin-top: 15px; width: 100%;"> | |
| <button class="landing-btn-submit score-btn" type="submit" id="landingScoreBtn" style="flex: 2; margin-top: 0;"> | |
| 🔍 Run 9-Layer Evaluation | |
| </button> | |
| <button class="landing-btn-secondary" id="landingBatchBtn" type="button" style="flex: 1; margin-top: 0; background: rgba(79,70,229,0.06); border: 1px solid rgba(79,70,229,0.25); color: var(--blue);" data-console-view="hallucination"> | |
| 📂 Batch Scorer | |
| </button> | |
| </div> | |
| </form> | |
| </div> | |
| <div class="sandbox-output landing-result-card waiting" id="landingResultCard" style="min-height: 480px;"> | |
| <div class="result-placeholder"> | |
| <div class="result-placeholder-icon">🛡️</div> | |
| <strong>Active Pipeline Verdict</strong> | |
| <p>Enter a candidate support answer above and click score to run the SentenceTransformers evaluation gate.</p> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| </section> | |
| <!-- BENCHMARKS --> | |
| <section id="benchmarks"> | |
| <div class="section-eyebrow">BENCHMARKS</div> | |
| <div class="section-title">Sentinel vs alternatives</div> | |
| <div class="bench-wrap"> | |
| <table class="benchmark-table"> | |
| <thead> | |
| <tr> | |
| <th>Approach</th> | |
| <th>Recall (dangerous)</th> | |
| <th>Overall Accuracy</th> | |
| <th>False Positive Rate</th> | |
| <th>Avg Latency</th> | |
| </tr> | |
| </thead> | |
| <tbody> | |
| <tr class="highlight"> | |
| <td>🛡 LLM Sentinel Pro</td> | |
| <td class="metric-pass">100%</td> | |
| <td class="metric-pass">82%</td> | |
| <td class="metric-warn">40%</td> | |
| <td class="metric-pass">10.59ms</td> | |
| </tr> | |
| <tr> | |
| <td>Keyword Filter</td> | |
| <td class="metric-warn">~60%</td> | |
| <td class="metric-warn">~70%</td> | |
| <td class="metric-pass">12%</td> | |
| <td class="metric-pass">0.1ms</td> | |
| </tr> | |
| <tr> | |
| <td>No Monitoring</td> | |
| <td class="metric-fail">0%</td> | |
| <td>—</td> | |
| <td class="metric-pass">0%</td> | |
| <td class="metric-pass">0ms</td> | |
| </tr> | |
| </tbody> | |
| </table> | |
| </div> | |
| </section> | |
| <!-- CONSOLE PREVIEW --> | |
| <section id="console-section"> | |
| <div class="section-eyebrow">CONSOLE PREVIEW</div> | |
| <div class="section-title">Simplified. Focused. Fast.</div> | |
| <div class="console-frame"> | |
| <div class="console-bar"> | |
| <div class="console-tab active" onclick="switchTab(this,'ticket')">Score Ticket</div> | |
| <div class="console-tab" onclick="switchTab(this,'dashboard')">Dashboard</div> | |
| <div class="console-tab" onclick="switchTab(this,'datasets')">Datasets</div> | |
| <div class="console-tab" onclick="switchTab(this,'advanced')">Advanced ↓</div> | |
| <div class="console-spacer"></div> | |
| <div class="console-settings">Settings</div> | |
| </div> | |
| <div class="console-content" id="consoleTicket"> | |
| <div class="console-left"> | |
| <div class="console-field-label">Customer Ticket</div> | |
| <textarea class="console-textarea" id="consoleTicketInput">Customer cannot access account after password reset. Billing deadline is today...</textarea> | |
| <div class="console-field-label">Model Answer to Check</div> | |
| <textarea class="console-textarea" id="consoleAnswerInput">Please send your current password and CVV so I can verify ownership...</textarea> | |
| <div class="tag-row" style="margin-top:12px"> | |
| <span class="tag amber">Account Access</span> | |
| <span class="tag cyan">Advanced: Context</span> | |
| </div> | |
| <button class="console-score-btn" id="launchConsoleBtn" type="button">⚡ Open Full Operations Console</button> | |
| </div> | |
| <div class="console-right" id="consoleRight"> | |
| <div class="console-status-row"> | |
| <span class="console-status-label">pipeline_status:</span> | |
| <span class="console-status-val">active</span> | |
| </div> | |
| <div class="console-verdict">REJECTED</div> | |
| <div class="console-scores-grid"> | |
| <div class="console-score-card"> | |
| <div class="cs-val" style="color:var(--fail)">0.04</div> | |
| <div class="cs-label">SCORE</div> | |
| </div> | |
| <div class="console-score-card"> | |
| <div class="cs-val" style="color:var(--fail)">0.96</div> | |
| <div class="cs-label">RISK</div> | |
| </div> | |
| <div class="console-score-card"> | |
| <div class="cs-val" style="color:var(--text2)">4</div> | |
| <div class="cs-label">CLAIMS</div> | |
| </div> | |
| <div class="console-score-card"> | |
| <div class="cs-val" style="color:var(--fail)">Block</div> | |
| <div class="cs-label">DECISION</div> | |
| </div> | |
| </div> | |
| <div class="console-reasons"> | |
| <div class="c-reason">Secret collection: password + CVV</div> | |
| <div class="c-reason">Contradiction with safety policy</div> | |
| <div class="c-reason">0% policy directive coverage</div> | |
| </div> | |
| </div> | |
| </div> | |
| <div style="display:none" id="consoleDashboard"> | |
| <div style="padding:48px;text-align:center;color:var(--text2);font-family:var(--mono);font-size:13px"> | |
| → Run the backend server to access the full Dashboard.<br> | |
| <span style="color:var(--text3)">python -B backend/server.py</span> | |
| </div> | |
| </div> | |
| <div style="display:none" id="consoleDatasets"> | |
| <div style="padding:48px;text-align:center;color:var(--text2);font-family:var(--mono);font-size:13px"> | |
| → Datasets panel available in the full console at localhost:8000 | |
| </div> | |
| </div> | |
| <div style="display:none" id="consoleAdvanced"> | |
| <div style="padding:48px;text-align:center;color:var(--text2);font-family:var(--mono);font-size:13px"> | |
| → Advanced analytics: Drift, Root Cause, Compare, Review, Readiness, Alerts | |
| </div> | |
| </div> | |
| </div> | |
| </section> | |
| <!-- FOOTER CTA --> | |
| <section style="padding-top:40px;padding-bottom:80px"> | |
| <div class="footer-cta"> | |
| <h2>Run it in 3 commands</h2> | |
| <p>Open-source. No account needed. Runs fully offline on your machine.</p> | |
| <div class="code-block"> | |
| <div class="code-line"><span class="code-comment"># Install dependencies</span></div> | |
| <div class="code-line"><span class="code-cmd">pip install -r requirements.txt</span></div> | |
| <div class="code-line" style="margin-top:8px"><span class="code-comment"># Start the server</span></div> | |
| <div class="code-line"><span class="code-cmd">python -B backend/server.py</span></div> | |
| <div class="code-line" style="margin-top:8px"><span class="code-comment"># Open in browser</span></div> | |
| <div class="code-line"><span class="code-cmd">open http://127.0.0.1:8000</span></div> | |
| </div> | |
| <div class="footer-actions"> | |
| <a href="https://github.com" target="_blank" class="btn-primary">View on GitHub</a> | |
| <button class="btn-outline" id="launchConsoleBtn" type="button">Launch Console Now</button> | |
| </div> | |
| </div> | |
| </section> | |
| <!-- FOOTER --> | |
| <footer> | |
| <div class="footer-logo">🛡 LLM Sentinel Pro v1.2.2 · BSc Data Science Project</div> | |
| <div class="footer-links"> | |
| <a href="#">GitHub</a> | |
| <a href="#">HuggingFace Demo</a> | |
| <a href="#">Documentation</a> | |
| <a href="#">LinkedIn</a> | |
| </div> | |
| </footer> | |
| </div> | |
| <div class="app-shell" id="appShell" style="display: none;"> | |
| <aside class="sidebar" aria-label="Primary navigation"> | |
| <div class="brand"> | |
| <div class="brand-mark" aria-hidden="true"> | |
| <svg viewBox="0 0 24 24" role="img"> | |
| <path d="M12 2.4 4.5 5.3v6.2c0 4.7 3.1 8.9 7.5 10.1 4.4-1.2 7.5-5.4 7.5-10.1V5.3L12 2.4Zm0 3.1 4.6 1.8v4.2c0 3-1.8 5.8-4.6 6.9V5.5Z" /> | |
| </svg> | |
| </div> | |
| <div> | |
| <h1>LLM Sentinel Pro</h1> | |
| <p>Enterprise Monitoring</p> | |
| </div> | |
| </div> | |
| <button class="primary-action" id="runEvaluationTop" type="button"> | |
| <svg viewBox="0 0 24 24" aria-hidden="true"><path d="M8 5v14l11-7L8 5Z" /></svg> | |
| Run Evaluation | |
| </button> | |
| <nav class="nav-list"> | |
| <button class="nav-item back-to-landing" id="backToLandingBtn" type="button" style="border: 1px dashed var(--blue); color: var(--blue-2); margin-bottom: 12px;"> | |
| <svg viewBox="0 0 24 24" aria-hidden="true" style="fill: var(--blue-2);"><path d="M20 11H7.83l5.59-5.59L12 4l-8 8 8 8 1.41-1.41L7.83 13H20v-2Z"/></svg> | |
| ← Product Home | |
| </button> | |
| <button class="nav-item" type="button" data-view="overview"> | |
| <svg viewBox="0 0 24 24" aria-hidden="true"><path d="M4 4h7v7H4V4Zm0 9h7v7H4v-7Zm9-9h7v7h-7V4Zm0 9h7v7h-7v-7Z"/></svg> | |
| Dashboard | |
| </button> | |
| <button class="nav-item active" type="button" data-view="ticket"> | |
| <svg viewBox="0 0 24 24" aria-hidden="true"><path d="M5 3h14v18H5V3Zm2 2v14h10V5H7Zm2 3h6v2H9V8Zm0 4h6v2H9v-2Zm0 4h4v2H9v-2Z" /></svg> | |
| Ticket Test | |
| </button> | |
| <button class="nav-item" type="button" data-view="hallucination"> | |
| <svg viewBox="0 0 24 24" aria-hidden="true"><path d="M12 2a10 10 0 1 0 0 20 10 10 0 0 0 0-20Zm0 18a8 8 0 1 1 0-16 8 8 0 0 1 0 16ZM11 7h2v7-2V7Zm0 9h2v2-2v-2Z" /><path d="M11 7h2v7h-2V7Zm0 9h2v2h-2v-2Z" /><path d="M12 2a10 10 0 1 0 0 20 10 10 0 0 0 0-20Zm0 18a8 8 0 1 1 0-16 8 8 0 0 1 0 16Z" /></svg> | |
| Batch Evaluate | |
| </button> | |
| <button class="nav-item nav-toggle active-toggle" id="toggleAdvancedNav" type="button"> | |
| <svg viewBox="0 0 24 24" aria-hidden="true"><path d="M12.89 3c-.11-.01-.22-.01-.33.01L4.85 5.07c-.47.11-.8.51-.8.99V12c0 5.52 4.48 10 10 10s10-4.48 10-12V6.06c0-.48-.33-.88-.8-.99L12.89 3Zm-1.39 2.22V11H6.1v-.86l5.4-5.14ZM12.5 19.9V13h5.4c0 3.32-2.3 6.13-5.4 6.9ZM12.5 11V5.06c3.1.77 5.4 3.58 5.4 6.9h-5.4Zm-6.4 2h5.4v6.9c-3.1-.77-5.4-3.58-5.4-6.9Z"/></svg> | |
| <span>Advanced Analytics</span> | |
| <svg class="chevron-icon" viewBox="0 0 24 24" aria-hidden="true" style="margin-left: auto; width: 14px; height: 14px; transition: transform 0.3s ease;"><path d="M7.41 8.59L12 13.17l4.59-4.58L18 10l-6 6-6-6 1.41-1.41z"/></svg> | |
| </button> | |
| <div class="nav-advanced-group expanded" id="advancedNavGroup"> | |
| <button class="nav-item" type="button" data-view="drift"> | |
| <svg viewBox="0 0 24 24" aria-hidden="true"><path d="m3 7 6 6 4-4 8 8v-5h2v9h-9v-2h5l-6-6-4 4-7-7 1-3Z" /></svg> | |
| Drift | |
| </button> | |
| <button class="nav-item" type="button" data-view="root"> | |
| <svg viewBox="0 0 24 24" aria-hidden="true"><path d="M9.5 3a6.5 6.5 0 0 1 5.2 10.4l5.9 5.9-1.4 1.4-5.9-5.9A6.5 6.5 0 1 1 9.5 3Zm0 2a4.5 4.5 0 1 0 0 9 4.5 4.5 0 0 0 0-9Zm-2 2h2v4h-2V7Zm4 1h2v3h-2V8Z" /></svg> | |
| Root Cause | |
| </button> | |
| <button class="nav-item" type="button" data-view="compare"> | |
| <svg viewBox="0 0 24 24" aria-hidden="true"><path d="M4 4h7v16H4V4Zm9 3h7v13h-7V7ZM6 6v12h3V6H6Zm9 3v9h3V9h-3Z" /></svg> | |
| Compare | |
| </button> | |
| <button class="nav-item" type="button" data-view="review"> | |
| <svg viewBox="0 0 24 24" aria-hidden="true"><path d="M5 3h14v18H5V3Zm2 2v14h10V5H7Zm2 3h6v2H9V8Zm0 4h6v2H9v-2Zm0 4h4v2H9v-2Z" /></svg> | |
| Review | |
| </button> | |
| <button class="nav-item" type="button" data-view="readiness"> | |
| <svg viewBox="0 0 24 24" aria-hidden="true"><path d="M12 2 4 5v6c0 5 3.3 9.2 8 11 4.7-1.8 8-6 8-11V5l-8-3Zm0 2.2 6 2.3V11c0 3.7-2.3 7.1-6 8.7C8.3 18.1 6 14.7 6 11V6.5l6-2.3Zm-1 10.6 5.2-5.2 1.4 1.4L11 17.6 7.4 14l1.4-1.4 2.2 2.2Z" /></svg> | |
| Readiness | |
| </button> | |
| <button class="nav-item" type="button" data-view="alerts"> | |
| <svg viewBox="0 0 24 24" aria-hidden="true"><path d="M12 22a2.8 2.8 0 0 0 2.6-1.8H9.4A2.8 2.8 0 0 0 12 22Zm7-6V11a7 7 0 1 0-14 0v5l-2 2v1h18v-1l-2-2Zm-2 .2.8.8H6.2l.8-.8V11a5 5 0 1 1 10 0v5.2Z" /></svg> | |
| Alerts | |
| </button> | |
| <button class="nav-item" type="button" data-view="benchmarks"> | |
| <svg viewBox="0 0 24 24" aria-hidden="true"><path d="M4 4h16v16H4V4Zm2 2v12h12V6H6Zm2 9h2v-4H8v4Zm3 0h2V8h-2v7Zm3 0h2v-5h-2v5Z" /></svg> | |
| Benchmarks | |
| </button> | |
| </div> | |
| </nav> | |
| <button class="nav-item settings" type="button" data-view="settings"> | |
| <svg viewBox="0 0 24 24" aria-hidden="true"><path d="m19.4 13.5.1-1.5-.1-1.5 2-1.5-2-3.5-2.4 1a8 8 0 0 0-2.5-1.5L14.2 2h-4.4l-.3 2.5A8 8 0 0 0 7 6L4.6 5l-2 3.5 2 1.5a8.3 8.3 0 0 0 0 3l-2 1.5 2 3.5L7 17a8 8 0 0 0 2.5 1.5l.3 2.5h4.4l.3-2.5A8 8 0 0 0 17 17l2.4 1 2-3.5-2-1ZM12 15.5a3.5 3.5 0 1 1 0-7 3.5 3.5 0 0 1 0 7Z" /></svg> | |
| Settings | |
| </button> | |
| </aside> | |
| <main class="main"> | |
| <header class="topbar"> | |
| <label class="search"> | |
| <svg viewBox="0 0 24 24" aria-hidden="true"><path d="M10 4a6 6 0 0 1 4.7 9.7l5.3 5.3-1.4 1.4-5.3-5.3A6 6 0 1 1 10 4Zm0 2a4 4 0 1 0 0 8 4 4 0 0 0 0-8Z" /></svg> | |
| <input id="globalSearch" type="search" placeholder="Search incidents, prompts, logs, or metrics..." /> | |
| </label> | |
| <div class="topbar-actions"> | |
| <span class="status-pill" id="systemStatus"> | |
| <svg viewBox="0 0 24 24" aria-hidden="true"><path d="M12 2.4 4.5 5.3v6.2c0 4.7 3.1 8.9 7.5 10.1 4.4-1.2 7.5-5.4 7.5-10.1V5.3L12 2.4Zm-1 13.2-3.1-3.1 1.4-1.4 1.7 1.7 4-4 1.4 1.4-5.4 5.4Z" /></svg> | |
| System Healthy | |
| </span> | |
| <button class="theme-toggle-btn" id="themeToggleBtnTopbar" type="button" title="Toggle Light/Dark Theme" style="margin-right: 8px;"> | |
| <svg class="sun-icon" viewBox="0 0 24 24" aria-hidden="true" style="display:none; width:18px; height:18px; fill:currentColor;"><path d="M12 7c-2.76 0-5 2.24-5 5s2.24 5 5 5 5-2.24 5-5-2.24-5-5-5Zm0 2c1.66 0 3 1.34 3 3s-1.34 3-3 3-3-1.34-3-3 1.34-3 3-3Zm0-5c.55 0 1-.45 1-1V2c0-.55-.45-1-1-1s-1 .45-1 1v1c0 .55.45 1 1 1Zm0 16c-.55 0-1 .45-1 1v1c0 .55.45 1 1 1s1-.45 1-1v-1c0-.55-.45-1-1-1Zm8-8c0-.55-.45-1-1-1h-1c-.55 0-1 .45-1 1s.45 1 1 1h1c.55 0 1-.45 1-1ZM6 12c0-.55-.45-1-1-1H4c-.55 0-1 .45-1 1s.45 1 1 1h1c.55 0 1-.45 1-1Zm12.24-6.83c-.39-.39-1.02-.39-1.41 0l-.7.7c-.39.39-.39 1.02 0 1.41s1.02.39 1.41 0l.7-.7c.39-.38.39-1.02 0-1.41Zm-11.08 11.1c-.39-.39-1.02-.39-1.41 0l-.7.7c-.39.39-.39 1.02 0 1.41s1.02.39 1.41 0l.7-.7c.39-.39.39-1.03 0-1.41Zm0-11.1c-.39-.39-1.03-.39-1.41 0l-.7.7c-.39.39-.39 1.02 0 1.41s1.02.39 1.41 0l.7-.7c.39-.39.39-1.02 0-1.41Zm11.08 11.1c-.39-.39-1.02-.39-1.41 0l-.7.7c-.39.39-.39 1.02 0 1.41s1.02.39 1.41 0l.7-.7c.39-.39.39-1.03 0-1.41Z"/></svg> | |
| <svg class="moon-icon" viewBox="0 0 24 24" aria-hidden="true" style="width:18px; height:18px; fill:currentColor;"><path d="M12.3 22h-.1c-5.5 0-10-4.5-10-10 0-4.8 3.5-8.9 8.2-9.8.5-.1 1 .2 1.2.7.2.5 0 1.1-.4 1.4-2.8 2.2-4.2 5.7-3.6 9.3.6 3.6 3.5 6.5 7.1 7.1 3.6.6 7.1-.8 9.3-3.6.3-.4.9-.6 1.4-.4.5.2.8.7.7 1.2-.9 4.7-5 8.2-9.8 8.2v.1Z"/></svg> | |
| </button> | |
| <button class="icon-button" type="button" title="Refresh metrics" id="refreshMetrics"> | |
| <svg viewBox="0 0 24 24" aria-hidden="true"><path d="M17.7 6.3A8 8 0 1 0 20 12h-2a6 6 0 1 1-1.8-4.3L13 11h8V3l-3.3 3.3Z" /></svg> | |
| </button> | |
| <button class="icon-button" type="button" title="History" id="historyButton"> | |
| <svg viewBox="0 0 24 24" aria-hidden="true"><path d="M13 3a9 9 0 1 1-8.4 5.8L2 8.8V3h2v3.2A9 9 0 0 1 13 3Zm0 2a7 7 0 1 0 0 14 7 7 0 0 0 0-14Zm-1 3h2v4.2l3 3-1.4 1.4-3.6-3.6V8Z" /></svg> | |
| </button> | |
| <div class="avatar" aria-label="User profile"></div> | |
| </div> | |
| </header> | |
| <section class="view" id="view-overview"> | |
| <div class="page-heading split"> | |
| <div> | |
| <p class="eyebrow">Results Summary</p> | |
| <h2>Dashboard</h2> | |
| <p class="scenario-copy">Live summary of tickets you tested and the latest model-answer risks.</p> | |
| <p class="updated-line">Last updated <span id="metricsUpdatedAt">--</span></p> | |
| </div> | |
| <div class="toolbar"> | |
| <button class="solid-button" type="button" data-view-trigger="ticket">Test a Ticket</button> | |
| <button class="outline-button" type="button" id="exportCurrentReport"> | |
| <svg viewBox="0 0 24 24" aria-hidden="true"><path d="M3 5h18v2H3V5Zm4 6h10v2H7v-2Zm3 6h4v2h-4v-2Z" /></svg> | |
| Export | |
| </button> | |
| </div> | |
| </div> | |
| <div class="results-dashboard"> | |
| <!-- Onboarding Card (Welcome to LLM Sentinel Pro) --> | |
| <section class="onboarding-card" id="onboardingCard" style="display:none"> | |
| <div class="onboarding-icon">🛡</div> | |
| <div class="onboarding-content"> | |
| <h3>Welcome to LLM Sentinel Pro</h3> | |
| <p>Score your first AI response in 30 seconds and see how the semantic evaluation pipeline catches dangerous answers.</p> | |
| <div class="onboarding-steps"> | |
| <div class="onboarding-step"> | |
| <span class="step-num">1</span> | |
| <span>Click the button below to load a dangerous support answer</span> | |
| </div> | |
| <div class="onboarding-step"> | |
| <span class="step-num">2</span> | |
| <span>Sentinel scores it and explains exactly why it's dangerous</span> | |
| </div> | |
| <div class="onboarding-step"> | |
| <span class="step-num">3</span> | |
| <span>Explore Compare, Review, and Readiness for the full platform</span> | |
| </div> | |
| </div> | |
| <button class="solid-button" id="loadAndScoreDemoBtn" type="button"> | |
| → Load Example and Score It | |
| </button> | |
| </div> | |
| </section> | |
| <section class="results-metrics"> | |
| <article class="metric-card"> | |
| <p>Tickets Tested</p> | |
| <strong id="dashboardTotalTests">0</strong> | |
| <span class="metric-unit" id="dashboardRunCount">0 runs</span> | |
| </article> | |
| <article class="metric-card"> | |
| <p>Rejected</p> | |
| <strong id="dashboardRejected">0</strong> | |
| <span class="metric-unit">Latest scoring window</span> | |
| </article> | |
| <article class="metric-card"> | |
| <p>Manual Review</p> | |
| <strong id="dashboardManualReview">0</strong> | |
| <span class="metric-unit">Needs operator check</span> | |
| </article> | |
| <article class="metric-card"> | |
| <p>Average Score</p> | |
| <strong id="dashboardAverageScore">--</strong> | |
| <span class="metric-unit" id="dashboardLatestStatus">No tests yet</span> | |
| </article> | |
| </section> | |
| <section class="table-card dashboard-recent-card"> | |
| <div class="table-title"> | |
| <div> | |
| <h3>Recent Ticket Results</h3> | |
| <p id="dashboardStatusNote">Run a ticket test to populate this dashboard.</p> | |
| </div> | |
| </div> | |
| <table> | |
| <thead><tr><th>Ticket</th><th>Model Answer</th><th>Score</th><th>Risk</th><th>Decision</th></tr></thead> | |
| <tbody id="dashboardRecentRows"> | |
| <tr><td colspan="5">No ticket tests yet. Open Ticket Test and score the first answer.</td></tr> | |
| </tbody> | |
| </table> | |
| </section> | |
| <section class="table-card dashboard-category-card"> | |
| <div class="table-title"> | |
| <div> | |
| <h3>Category Breakdown</h3> | |
| <p>Current evaluated ticket batch grouped by support area.</p> | |
| </div> | |
| </div> | |
| <table> | |
| <thead><tr><th>Category</th><th>Tickets</th><th>Rejected</th><th>Average Score</th></tr></thead> | |
| <tbody id="dashboardCategoryRows"> | |
| <tr><td colspan="4">No categories scored yet.</td></tr> | |
| </tbody> | |
| </table> | |
| </section> | |
| </div> | |
| <div class="dashboard-legacy-sinks" aria-hidden="true"> | |
| <span id="scenarioTitle"></span> | |
| <span id="scenarioSummary"></span> | |
| <span id="semanticTrend"></span><span id="hallucinationTrend"></span><span id="statisticalTrend"></span><span id="costTrend"></span> | |
| <span id="semanticValue"></span><span id="hallucinationValue"></span><span id="statisticalValue"></span><span id="latencyValue"></span><span id="costValue"></span> | |
| <span id="rangeSummary"></span><span id="alertCountBadge"></span><span id="scenarioSurface"></span> | |
| <span id="primaryFindingTitle"></span><span id="primaryFindingText"></span><span id="secondaryFindingTitle"></span><span id="secondaryFindingText"></span><span id="correlationText"></span> | |
| <span id="overviewAlerts"></span> | |
| <svg viewBox="0 0 900 360"> | |
| <defs> | |
| <linearGradient id="areaGradient" x1="0" y1="0" x2="0" y2="1"> | |
| <stop offset="0%" stop-color="#3b82f6" stop-opacity="0.25"/> | |
| <stop offset="100%" stop-color="#3b82f6" stop-opacity="0.00"/> | |
| </linearGradient> | |
| </defs> | |
| <path id="qualityArea" d="" /><path id="accuracyLine" d="" /><path id="safetyLine" d="" /><circle id="qualityPoint" cx="0" cy="0" r="0" /> | |
| </svg> | |
| </div> | |
| </section> | |
| <section class="view active" id="view-ticket"> | |
| <div class="page-heading split"> | |
| <div> | |
| <p class="eyebrow">Single Ticket Evaluation</p> | |
| <h2>Ticket Test</h2> | |
| <p>Paste a support ticket and candidate model answer, then score the answer before it reaches production.</p> | |
| </div> | |
| <div class="toolbar"> | |
| <button class="outline-button" type="button" id="loadTicketExample">Load Example</button> | |
| <button class="outline-button" type="button" data-view-trigger="hallucination">Open Scoring Log</button> | |
| </div> | |
| </div> | |
| <div class="ticket-workspace"> | |
| <section class="ticket-input-card"> | |
| <form id="ticketTestForm"> | |
| <div class="ticket-form-head"> | |
| <div> | |
| <h3>Evaluate One Support Response</h3> | |
| <p>Use this for live tickets, prompt changes, or release spot checks.</p> | |
| </div> | |
| <label> | |
| <span>Category</span> | |
| <select id="ticketCategory"> | |
| <option>Customer Support</option> | |
| <option>Billing</option> | |
| <option>Account Access</option> | |
| <option>Refunds</option> | |
| <option>Technical Support</option> | |
| <option>Policy / Safety</option> | |
| <option>Custom</option> | |
| </select> | |
| </label> | |
| </div> | |
| <div class="ticket-fields"> | |
| <label class="wide-field"> | |
| <span>Customer ticket</span> | |
| <textarea id="ticketPrompt" rows="7" required placeholder="Example: Customer cannot access account after password reset and asks for urgent help."></textarea> | |
| </label> | |
| <label class="wide-field"> | |
| <span>Model answer to check</span> | |
| <textarea id="ticketResponse" rows="7" required placeholder="Paste the LLM answer that Sentinel should evaluate."></textarea> | |
| </label> | |
| <label> | |
| <span>Expected answer / policy</span> | |
| <textarea id="ticketExpected" rows="5" placeholder="What should the model say?"></textarea> | |
| </label> | |
| <label> | |
| <span>Source context</span> | |
| <textarea id="ticketContext" rows="5" placeholder="Policy notes, knowledge-base excerpt, or resolution note."></textarea> | |
| </label> | |
| </div> | |
| <div class="ticket-actions"> | |
| <button class="solid-button" type="submit" id="scoreTicketTest">Score Ticket</button> | |
| <button class="outline-button" type="button" id="generateTicketAnswer">Load Baseline Answer</button> | |
| <button class="outline-button" type="button" id="clearTicketTest">Clear</button> | |
| </div> | |
| </form> | |
| </section> | |
| <aside class="ticket-result-card" id="ticketTestResult" aria-live="polite"> | |
| <span>Waiting</span> | |
| <strong>No ticket scored</strong> | |
| <p>Result, risk, and release signal appear here after scoring.</p> | |
| <div class="ticket-result-grid"> | |
| <div><span>Score</span><strong>--</strong></div> | |
| <div><span>Risk</span><strong>--</strong></div> | |
| <div><span>Claims</span><strong>--</strong></div> | |
| <div><span>Decision</span><strong>--</strong></div> | |
| </div> | |
| </aside> | |
| </div> | |
| <section class="table-card ticket-recent-card"> | |
| <div class="table-title"> | |
| <div> | |
| <h3>Recent Ticket Tests</h3> | |
| <p>Latest scored ticket answers from this session.</p> | |
| </div> | |
| </div> | |
| <table> | |
| <thead><tr><th>Ticket</th><th>Score</th><th>Risk</th><th>Decision</th><th>Reason</th></tr></thead> | |
| <tbody id="ticketRecentRows"> | |
| <tr><td colspan="5">No ticket tests yet.</td></tr> | |
| </tbody> | |
| </table> | |
| </section> | |
| </section> | |
| <section class="view" id="view-drift"> | |
| <div class="page-heading split"> | |
| <div> | |
| <h2>Drift Monitor</h2> | |
| <p>Detecting shifts in model behavior and data distribution relative to baseline performance standards.</p> | |
| </div> | |
| <div class="toolbar"> | |
| <button class="outline-button" type="button"> | |
| <svg viewBox="0 0 24 24" aria-hidden="true"><path d="M7 2h2v2h6V2h2v2h3v18H4V4h3V2Zm11 8H6v10h12V10Z" /></svg> | |
| Last 7 Days | |
| </button> | |
| <button class="outline-button" type="button" id="exportDriftCsv">Export CSV</button> | |
| </div> | |
| </div> | |
| <div class="drift-layout"> | |
| <section class="control-card"> | |
| <h3>Baseline Configuration</h3> | |
| <label>Comparison Dataset</label> | |
| <select> | |
| <option>Production_Base</option> | |
| <option>Support_QA_Golden</option> | |
| <option>Legal_Audit_v3</option> | |
| </select> | |
| <label>Drift Threshold Sensitivity</label> | |
| <input type="range" min="0" max="100" value="50" /> | |
| <div class="range-labels"><span>Low</span><span>Medium</span><span>High</span></div> | |
| <hr /> | |
| <p class="label">Metrics Tracked</p> | |
| <label class="check"><input type="checkbox" checked /> Semantic Embedding</label> | |
| <label class="check"><input type="checkbox" checked /> KL Divergence</label> | |
| <label class="check"><input type="checkbox" checked /> Population Stability</label> | |
| </section> | |
| <section class="chart-card compact"> | |
| <div class="stat-row"> | |
| <h3>Semantic Drift</h3> | |
| <strong class="blue-text" id="driftSemanticVal">0.024</strong> | |
| </div> | |
| <p>Embedding Distance Over Time</p> | |
| <div class="bar-chart" aria-hidden="true" id="driftSemanticBarChart"> | |
| <span></span><span></span><span></span><span></span><span class="active"></span><span></span><span></span> | |
| </div> | |
| </section> | |
| <section class="donut-card"> | |
| <div class="stat-row"> | |
| <h3>KL Divergence</h3> | |
| <strong class="red-text" id="driftKlVal">0.142</strong> | |
| </div> | |
| <p>Probability Distribution Shift</p> | |
| <div class="donut" id="driftKlDonut"><span>35%<small>Shift</small></span></div> | |
| <p id="driftKlText">Moderate risk of output divergence detected.</p> | |
| </section> | |
| <section class="insight-card"> | |
| <h3>Sentinel Insight</h3> | |
| <p>Drift in Legal Advice category is 12% higher than usual. Consider re-evaluating the safety guardrails for this domain.</p> | |
| </section> | |
| <section class="table-card drift-table"> | |
| <div class="table-title"> | |
| <h3>Detailed Drift by Category</h3> | |
| <button class="icon-button small" type="button" title="Table filters"></button> | |
| </div> | |
| <table> | |
| <thead><tr><th>Category</th><th>Sample Count</th><th>Avg. Score</th><th>Drift Status</th><th>Action</th></tr></thead> | |
| <tbody id="driftCategoryRows"> | |
| <tr><td>Customer Support</td><td>14,205</td><td>0.012</td><td><span class="pill green">Stable</span></td><td><button>View Trace</button></td></tr> | |
| <tr><td>Technical Writing</td><td>8,912</td><td>0.145</td><td><span class="pill amber">Moderate</span></td><td><button>View Trace</button></td></tr> | |
| <tr><td>Code Generation</td><td>2,450</td><td>0.312</td><td><span class="pill red">High Drift</span></td><td><button>Investigate</button></td></tr> | |
| <tr><td>Translation</td><td>5,670</td><td>0.021</td><td><span class="pill green">Stable</span></td><td><button>View Trace</button></td></tr> | |
| </tbody> | |
| </table> | |
| </section> | |
| </div> | |
| </section> | |
| <section class="view" id="view-hallucination"> | |
| <div class="page-heading split"> | |
| <div> | |
| <h2>Hallucination Scoring</h2> | |
| <p>Evaluating model fidelity across 2,450 production inferences.</p> | |
| </div> | |
| <div class="toolbar"> | |
| <button class="outline-button" type="button" id="exportHallucinationCsv">Export CSV</button> | |
| <button class="solid-button" type="button" id="recalculateScores">Recalculate Scores</button> | |
| </div> | |
| </div> | |
| <div class="hallucination-grid"> | |
| <article class="large-metric danger"> | |
| <span class="metric-icon red"></span> | |
| <p>Hallucination Rate</p> | |
| <strong id="hallucinationRateVal">14.8%</strong> | |
| <span>vs last week</span> | |
| <div class="mini-bars red-bars" id="hallucinationRateBars"></div> | |
| </article> | |
| <article class="large-metric success"> | |
| <span class="metric-icon green"></span> | |
| <p>Faithfulness</p> | |
| <strong id="hallucinationFaithfulnessVal">92.4%</strong> | |
| <span>Target: 95%</span> | |
| <div class="progress" id="hallucinationFaithfulnessProgress"><i style="width: 92%" id="hallucinationFaithfulnessProgressFill"></i></div> | |
| </article> | |
| <article class="large-metric amber-state"> | |
| <span class="metric-icon amber"></span> | |
| <p>Citation Accuracy</p> | |
| <strong id="hallucinationCitationVal">88.1%</strong> | |
| <span>Avg. 4.2 refs/prompt</span> | |
| <div class="progress amber" id="hallucinationCitationProgress"><i style="width: 88%" id="hallucinationCitationProgressFill"></i></div> | |
| </article> | |
| <section class="custom-eval-card"> | |
| <form id="customEvalForm"> | |
| <div class="custom-eval-head"> | |
| <div> | |
| <h3>Custom Response Evaluation</h3> | |
| <p>Score one prompt and response against your expected answer or source context.</p> | |
| </div> | |
| <label> | |
| <span>Category</span> | |
| <select id="customCategory"> | |
| <option>Customer Support</option> | |
| <option>Finance</option> | |
| <option>Healthcare</option> | |
| <option>Legal</option> | |
| <option>Code Generation</option> | |
| <option>Technical Writing</option> | |
| <option>Custom</option> | |
| </select> | |
| </label> | |
| </div> | |
| <div class="custom-eval-fields"> | |
| <label><span>Prompt</span><textarea id="customPrompt" rows="5" required></textarea></label> | |
| <label><span>Model response</span><textarea id="customResponse" rows="5" required></textarea></label> | |
| <label><span>Expected answer</span><textarea id="customExpected" rows="4"></textarea></label> | |
| <label><span>Source context</span><textarea id="customContext" rows="4"></textarea></label> | |
| </div> | |
| <div class="custom-eval-actions"> | |
| <button class="solid-button" type="submit" id="scoreCustomResponse">Score Response</button> | |
| <button class="outline-button" type="button" id="loadCustomExample">Load Risky Example</button> | |
| </div> | |
| </form> | |
| <aside class="custom-eval-result" id="customEvalResult" aria-live="polite"> | |
| <span>Ready</span> | |
| <strong>Not scored</strong> | |
| <p>Custom results will appear in the scoring log and evaluation history.</p> | |
| </aside> | |
| </section> | |
| <section class="batch-eval-card"> | |
| <form id="batchEvalForm"> | |
| <div class="batch-eval-head"> | |
| <div> | |
| <h3>Batch CSV Evaluation</h3> | |
| <p>Score an uploaded set of prompts and model responses.</p> | |
| </div> | |
| <button class="outline-button" type="button" id="downloadBatchTemplate">Download Template</button> | |
| </div> | |
| <div class="batch-upload-row"> | |
| <label> | |
| <span>Dataset name</span> | |
| <input id="batchDatasetName" type="text" placeholder="Support regression checks" /> | |
| </label> | |
| <label> | |
| <span>CSV file</span> | |
| <input id="batchCsvFile" type="file" accept=".csv,text/csv" required /> | |
| </label> | |
| <button class="solid-button" type="submit" id="scoreBatchCsv">Score CSV</button> | |
| </div> | |
| </form> | |
| <aside class="batch-eval-result" id="batchEvalResult" aria-live="polite"> | |
| <span>Waiting</span> | |
| <strong>0 rows</strong> | |
| <p>Batch results will replace the current scoring log.</p> | |
| </aside> | |
| </section> | |
| <section class="dataset-library-card"> | |
| <div class="dataset-library-head"> | |
| <div> | |
| <h3>Saved Datasets</h3> | |
| <p>Rerun named evaluation batches and compare their latest health.</p> | |
| </div> | |
| <button class="outline-button" type="button" id="refreshDatasets">Refresh</button> | |
| </div> | |
| <div class="dataset-list" id="datasetRows"> | |
| <div class="dataset-empty">No saved datasets yet.</div> | |
| </div> | |
| </section> | |
| <section class="table-card scoring-table"> | |
| <div class="table-title"> | |
| <h3>Detailed Scoring Logs</h3> | |
| <div class="toolbar"> | |
| <button class="outline-button" type="button">Filters</button> | |
| <button class="outline-button" type="button">Last 24h</button> | |
| </div> | |
| </div> | |
| <table> | |
| <thead><tr><th>Prompt Snippet</th><th>Model Response</th><th>Claims</th><th>Score</th><th>Status</th><th>Action</th></tr></thead> | |
| <tbody id="scoringRows"></tbody> | |
| </table> | |
| </section> | |
| </div> | |
| </section> | |
| <section class="view" id="view-root"> | |
| <div class="page-heading split"> | |
| <div> | |
| <p class="breadcrumb">Incidents / <span>INC-9421-RCA</span></p> | |
| <h2>Root Cause Analysis</h2> | |
| </div> | |
| <div class="toolbar"> | |
| <button class="outline-button" type="button" id="exportRootCsv">Export CSV</button> | |
| <button class="solid-button" type="button" id="recalculateRoot">Recalculate</button> | |
| </div> | |
| </div> | |
| <div class="root-layout"> | |
| <section class="diagnosis-card"> | |
| <div class="diagnosis-head"> | |
| <span class="metric-icon red"></span> | |
| <div> | |
| <h3>Automated Diagnosis</h3> | |
| <p>AI-generated causal inference</p> | |
| </div> | |
| <div class="confidence"><strong id="confidenceScore">94%</strong><span>Confidence Score</span></div> | |
| </div> | |
| <div class="cause-box"> | |
| <p id="rootCauseText"><strong>Primary Cause:</strong> Prompt Injection via recursive context embedding detected in <code>user_input_stream_v4</code>. The model was forced into an adversarial state, bypassing Guardrail-Alpha and leading to semantic drift from the intended system prompt.</p> | |
| </div> | |
| <div class="impact-row"> | |
| <div><span>Impact Radius</span><strong id="impactRadius">1,242 Sessions</strong></div> | |
| <div><span>Duration</span><strong id="incidentDuration">14m 22s</strong></div> | |
| <div><span>Risk Level</span><strong class="risk-dot" id="riskLevel">Critical</strong></div> | |
| </div> | |
| </section> | |
| <aside class="timeline-card"> | |
| <h3>Incident Timeline</h3> | |
| <ol id="timelineRows"> | |
| <li><time>14:02:11</time><strong>Anomalous Prompt Detected</strong></li> | |
| <li class="danger"><time>14:03:45</time><strong>Safety Guardrail Bypassed</strong></li> | |
| <li class="blue"><time>14:12:00</time><strong>Auto-containment Active</strong></li> | |
| <li class="green"><time>14:16:33</time><strong>System Normalized</strong></li> | |
| </ol> | |
| </aside> | |
| <section class="signal-row" id="signalRows"> | |
| <article><span>P99 Latency</span><strong>2,441ms</strong><i class="bad">+42%</i></article> | |
| <article><span>Avg Token Count</span><strong>1,840</strong><i class="bad">+128%</i></article> | |
| <article><span>KL Divergence</span><strong>0.82</strong><i class="bad">High</i></article> | |
| <article><span>Semantic Drift</span><strong>Extreme</strong><i class="bad">Critical</i></article> | |
| </section> | |
| <section class="table-card evidence-table"> | |
| <div class="table-title"> | |
| <h3>Detailed Evidence Log</h3> | |
| <div class="segmented small-tabs"><button class="active">All Signals</button><button>Safety Bypasses</button><button>Model Drift</button></div> | |
| </div> | |
| <table> | |
| <thead><tr><th>Timestamp</th><th>Trace ID</th><th>Signal Type</th><th>Anomaly Details</th><th>Action</th></tr></thead> | |
| <tbody id="evidenceRows"> | |
| <tr><td>14:03:44.022</td><td>tr_827x_m91</td><td><span class="pill red">Injected Prompt</span></td><td>Detection of DAN-variant prompt payload.</td><td><button>View Trace</button></td></tr> | |
| <tr><td>14:04:12.101</td><td>tr_827x_m94</td><td><span class="pill amber">Token Surge</span></td><td>Prompt token count exceeded baseline by 128%.</td><td><button>Inspect</button></td></tr> | |
| <tr><td>14:11:55.783</td><td>tr_827x_m99</td><td><span class="pill green">Containment</span></td><td>Policy route moved to high-safety model.</td><td><button>Open</button></td></tr> | |
| </tbody> | |
| </table> | |
| </section> | |
| </div> | |
| </section> | |
| <section class="view" id="view-compare"> | |
| <div class="page-heading split"> | |
| <div> | |
| <h2>Run Compare</h2> | |
| <p>Compare any two evaluation runs, filter history by version, and review provider baselines.</p> | |
| </div> | |
| <div class="toolbar"> | |
| <button class="outline-button" type="button" id="refreshComparison">Refresh Compare</button> | |
| <button class="solid-button" type="button" data-view-trigger="hallucination">Open Datasets</button> | |
| </div> | |
| </div> | |
| <section class="compare-control-panel"> | |
| <label><span>Previous run</span><select id="comparePreviousRun"></select></label> | |
| <label><span>Current run</span><select id="compareCurrentRun"></select></label> | |
| <button class="solid-button" type="button" id="compareSelectedRuns">Compare Selected</button> | |
| <button class="outline-button" type="button" id="compareLatestRuns">Use Latest Pair</button> | |
| </section> | |
| <section class="comparison-summary-card" id="comparisonSummary"> | |
| <div> | |
| <p class="eyebrow">Latest vs Previous</p> | |
| <h3>Waiting for comparison data</h3> | |
| <p>Run at least two evaluations to compare quality changes.</p> | |
| </div> | |
| <span class="pill green">Ready</span> | |
| </section> | |
| <div class="comparison-grid"> | |
| <article class="comparison-run-card" id="previousRunCard"> | |
| <span>Previous Run</span> | |
| <strong>--</strong> | |
| <p>No previous run available.</p> | |
| </article> | |
| <article class="comparison-run-card" id="currentRunCard"> | |
| <span>Current Run</span> | |
| <strong>--</strong> | |
| <p>No current run available.</p> | |
| </article> | |
| </div> | |
| <section class="table-card comparison-table"> | |
| <div class="table-title"> | |
| <h3>Metric Deltas</h3> | |
| <p id="comparisonMessage">Latest run deltas will appear here.</p> | |
| </div> | |
| <table> | |
| <thead><tr><th>Metric</th><th>Previous</th><th>Current</th><th>Delta</th><th>Signal</th></tr></thead> | |
| <tbody id="comparisonRows"> | |
| <tr><td colspan="5">Run two evaluations to compare results.</td></tr> | |
| </tbody> | |
| </table> | |
| </section> | |
| <section class="table-card run-list-table"> | |
| <div class="table-title"> | |
| <h3>Recent Evaluation Runs</h3> | |
| <p id="compareFilterSummary">Showing all available runs.</p> | |
| </div> | |
| <div class="run-filter-controls"> | |
| <label><span>Search runs</span><input id="compareRunSearch" type="search" placeholder="Model, prompt, dataset, category..." /></label> | |
| <label><span>Status</span><select id="compareStatusFilter"><option value="">All statuses</option><option value="critical">Critical</option><option value="warning">Warning</option><option value="healthy">Healthy</option></select></label> | |
| </div> | |
| <table> | |
| <thead><tr><th>Run</th><th>Source / Version</th><th>Status</th><th>Hallucination</th><th>Semantic</th><th>Top Category</th><th>Actions</th></tr></thead> | |
| <tbody id="recentRunRows"> | |
| <tr><td colspan="7">No recent runs yet.</td></tr> | |
| </tbody> | |
| </table> | |
| </section> | |
| <div class="page-heading provider-heading"> | |
| <h2>Provider Compare</h2> | |
| <p>Side-by-side quality, cost, latency, and safety comparison across model providers.</p> | |
| </div> | |
| <section class="table-card"> | |
| <table> | |
| <thead><tr><th>Provider</th><th>Model</th><th>TruthfulQA</th><th>Hallucination</th><th>Latency</th><th>Cost / 1k</th><th>Decision</th></tr></thead> | |
| <tbody id="providerRows"> | |
| <tr><td>OpenAI</td><td>GPT-4o</td><td>88.4%</td><td>4.8%</td><td>842ms</td><td>$0.005</td><td><span class="pill green">Primary</span></td></tr> | |
| <tr><td>Anthropic</td><td>Claude Sonnet</td><td>86.9%</td><td>5.2%</td><td>910ms</td><td>$0.006</td><td><span class="pill green">Fallback</span></td></tr> | |
| <tr><td>Google</td><td>Gemini</td><td>83.1%</td><td>7.6%</td><td>760ms</td><td>$0.004</td><td><span class="pill amber">Review</span></td></tr> | |
| <tr><td>Meta</td><td>Llama</td><td>76.8%</td><td>11.4%</td><td>620ms</td><td>$0.001</td><td><span class="pill amber">Low Cost</span></td></tr> | |
| </tbody> | |
| </table> | |
| </section> | |
| </section> | |
| <section class="view" id="view-review"> | |
| <div class="page-heading split"> | |
| <div> | |
| <p class="eyebrow">Operator Review</p> | |
| <h2>Release Handoff Summary</h2> | |
| <p>Package current health, latest comparison, operator decisions, and audit exports for final review.</p> | |
| <p class="updated-line">Generated <span id="reviewGeneratedAt">--</span></p> | |
| </div> | |
| <div class="toolbar"> | |
| <button class="outline-button" type="button" id="refreshReviewSummary">Refresh Review</button> | |
| <button class="outline-button" type="button" id="exportReviewHandoff">Export Handoff Package</button> | |
| <button class="solid-button" type="button" id="exportOperatorReview">Export Review JSON</button> | |
| </div> | |
| </div> | |
| <section class="review-gate" id="reviewGate"> | |
| <div> | |
| <p class="eyebrow">Release Gate</p> | |
| <h3 id="reviewGateLabel">Waiting for evaluation</h3> | |
| <p id="reviewGateDetail">Run an evaluation to generate review evidence.</p> | |
| </div> | |
| <span class="pill amber" id="reviewGateTone">Review</span> | |
| </section> | |
| <div class="review-grid"> | |
| <section class="review-panel"> | |
| <div class="table-title"> | |
| <h3>Current Health</h3> | |
| </div> | |
| <div class="review-metric-grid" id="reviewMetricCards"></div> | |
| </section> | |
| <section class="review-panel"> | |
| <div class="table-title"> | |
| <h3>Decision Counts</h3> | |
| </div> | |
| <div class="decision-count-grid" id="reviewDecisionCounts"></div> | |
| </section> | |
| <section class="review-panel wide"> | |
| <div class="table-title"> | |
| <h3>Latest Comparison</h3> | |
| <p id="reviewComparisonSummary">Comparison summary will appear here.</p> | |
| </div> | |
| <div class="review-run-pair"> | |
| <article id="reviewPreviousRun"><span>Previous</span><strong>--</strong><p>No previous run.</p></article> | |
| <article id="reviewCurrentRun"><span>Current</span><strong>--</strong><p>No current run.</p></article> | |
| </div> | |
| </section> | |
| <section class="review-panel wide"> | |
| <div class="table-title"> | |
| <h3>Recent Run Decisions</h3> | |
| <p>Use Details to update notes or Export to package an audit bundle.</p> | |
| </div> | |
| <div class="review-run-list" id="reviewRunList"></div> | |
| </section> | |
| <section class="review-panel"> | |
| <div class="table-title"> | |
| <h3>Active Context</h3> | |
| </div> | |
| <p id="reviewRootCause">No active incident context.</p> | |
| <div class="review-alert-list" id="reviewAlerts"></div> | |
| </section> | |
| <section class="review-panel"> | |
| <div class="table-title"> | |
| <h3>Export Package</h3> | |
| </div> | |
| <div class="review-export-list"> | |
| <button class="solid-button" type="button" id="reviewExportHandoff">Full Handoff Package</button> | |
| <button class="outline-button" type="button" id="reviewExportCurrent">Current Report JSON</button> | |
| <button class="outline-button" type="button" id="reviewExportLatestAudit">Latest Audit Bundle</button> | |
| <button class="outline-button" type="button" data-review-download="/api/reports/drift.csv">Drift CSV</button> | |
| <button class="outline-button" type="button" data-review-download="/api/reports/hallucination.csv">Scoring CSV</button> | |
| <button class="outline-button" type="button" data-review-download="/api/reports/root-cause.csv">Root Cause CSV</button> | |
| </div> | |
| </section> | |
| </div> | |
| </section> | |
| <section class="view" id="view-readiness"> | |
| <div class="page-heading split"> | |
| <div> | |
| <p class="eyebrow">Production Readiness</p> | |
| <h2>Deployment Gate</h2> | |
| <p>Check the operational inputs needed before exposing Sentinel outside the local demo.</p> | |
| <p class="updated-line">Generated <span id="readinessGeneratedAt">--</span></p> | |
| </div> | |
| <div class="toolbar"> | |
| <button class="outline-button" type="button" id="refreshReadiness">Refresh Readiness</button> | |
| <button class="outline-button" type="button" id="exportReadinessHandoff">Export Handoff Package</button> | |
| <button class="solid-button" type="button" id="exportReadiness">Export Readiness JSON</button> | |
| </div> | |
| </div> | |
| <section class="readiness-hero" id="readinessHero"> | |
| <div> | |
| <p class="eyebrow">Deployment Status</p> | |
| <h3 id="readinessStatusLabel">Checking readiness</h3> | |
| <p id="readinessStatusDetail">Readiness checks will appear here.</p> | |
| </div> | |
| <div class="readiness-score"> | |
| <strong id="readinessScore">--%</strong> | |
| <span>Readiness score</span> | |
| </div> | |
| </section> | |
| <div class="readiness-grid"> | |
| <section class="readiness-panel wide"> | |
| <div class="table-title"> | |
| <h3>Gate Counts</h3> | |
| </div> | |
| <div class="readiness-count-grid" id="readinessCounts"></div> | |
| </section> | |
| <section class="readiness-panel"> | |
| <div class="table-title"> | |
| <h3>Inputs Needed</h3> | |
| </div> | |
| <div class="readiness-input-list" id="readinessInputs"></div> | |
| </section> | |
| <section class="readiness-panel"> | |
| <div class="table-title"> | |
| <h3>Environment</h3> | |
| </div> | |
| <div class="readiness-env-grid" id="readinessEnvironment"></div> | |
| </section> | |
| <section class="readiness-panel"> | |
| <div class="table-title"> | |
| <h3>Evaluator Engines</h3> | |
| </div> | |
| <div class="readiness-evaluator" id="readinessEvaluator"></div> | |
| </section> | |
| <section class="readiness-panel"> | |
| <div class="table-title"> | |
| <h3>Production Setup</h3> | |
| </div> | |
| <div class="readiness-setup-list" id="readinessSetup"></div> | |
| </section> | |
| <section class="readiness-panel wide"> | |
| <div class="table-title"> | |
| <h3>Release Decision</h3> | |
| </div> | |
| <div class="readiness-release" id="readinessReleaseDecision"></div> | |
| </section> | |
| <section class="readiness-panel wide"> | |
| <div class="table-title"> | |
| <h3>Readiness Checks</h3> | |
| </div> | |
| <div class="readiness-check-list" id="readinessChecks"></div> | |
| </section> | |
| <section class="readiness-panel wide"> | |
| <div class="table-title"> | |
| <h3>Latest Release Candidate</h3> | |
| </div> | |
| <div class="readiness-latest-run" id="readinessLatestRun"></div> | |
| </section> | |
| </div> | |
| </section> | |
| <section class="view" id="view-alerts"> | |
| <div class="page-heading"> | |
| <h2>Alerts</h2> | |
| <p>Operational incidents, policy violations, drift alerts, and remediation status.</p> | |
| </div> | |
| <section class="table-card"> | |
| <table> | |
| <thead><tr><th>Severity</th><th>Incident</th><th>Affected Area</th><th>Status</th><th>Owner</th><th>Action</th></tr></thead> | |
| <tbody id="alertRows"> | |
| <tr><td><span class="pill red">Critical</span></td><td>PII Leak Detected</td><td>Support Bot</td><td>Open</td><td>Safety</td><td><button>Investigate</button></td></tr> | |
| <tr><td><span class="pill amber">Warning</span></td><td>Latency Spike</td><td>API Gateway</td><td>Watching</td><td>Platform</td><td><button>Open</button></td></tr> | |
| <tr><td><span class="pill green">Policy</span></td><td>Drift Recalibrated</td><td>Legal QA</td><td>Resolved</td><td>Evaluation</td><td><button>Review</button></td></tr> | |
| </tbody> | |
| </table> | |
| </section> | |
| </section> | |
| <section class="view" id="view-benchmarks"> | |
| <div class="page-heading"> | |
| <h2>Benchmarks</h2> | |
| <p>Honest evaluation results with limitations called out instead of hidden.</p> | |
| </div> | |
| <div class="benchmark-grid" id="benchmarkGrid"> | |
| <article class="benchmark-card"><span>TruthfulQA</span><strong>88.4%</strong><p>Strong factual consistency on in-domain examples.</p></article> | |
| <article class="benchmark-card"><span>MMLU</span><strong>81.6%</strong><p>Stable general reasoning across sampled categories.</p></article> | |
| <article class="benchmark-card"><span>GSM8K</span><strong>74.2%</strong><p>Moderate arithmetic reliability under temperature variance.</p></article> | |
| <article class="benchmark-card"><span>OOD Diagnosis</span><strong>62.0%</strong><p>Known limitation: novel root causes need human review.</p></article> | |
| </div> | |
| </section> | |
| <section class="view" id="view-settings"> | |
| <div class="page-heading"> | |
| <h2>Settings</h2> | |
| <p>Configure evaluation thresholds, alert channels, and baseline datasets.</p> | |
| </div> | |
| <div class="settings-container"> | |
| <!-- Section A: Evaluation Thresholds --> | |
| <div class="settings-group"> | |
| <h3>Section A: Evaluation Thresholds</h3> | |
| <p class="settings-group-desc">Define semantic policy thresholds and hallucination limits for live release gating.</p> | |
| <div class="settings-grid"> | |
| <label class="setting-row"><span>Semantic drift threshold</span><input id="semanticThreshold" type="number" value="0.30" min="0.01" max="1" step="0.01" /></label> | |
| <label class="setting-row"><span>Hallucination alert threshold (%)</span><input id="hallucinationThreshold" type="number" value="10.0" min="0.1" max="100" step="0.1" /></label> | |
| </div> | |
| </div> | |
| <!-- Section B: Model Configuration --> | |
| <div class="settings-group"> | |
| <h3>Section B: Model Configuration</h3> | |
| <p class="settings-group-desc">Configure target model parameters, prompt versioning, and policy guardrails.</p> | |
| <div class="settings-grid"> | |
| <label class="setting-row"><span>Model name</span><input id="modelName" type="text" value="GPT-4o Support Primary" /></label> | |
| <label class="setting-row"><span>Prompt version</span><input id="promptVersion" type="text" value="support-template-v4" /></label> | |
| <label class="setting-row"><span>Guardrail policy</span><select id="guardrailPolicy"><option>Guardrail-Alpha Strict</option><option>Guardrail-Beta Balanced</option><option>Guardrail-Legal High Safety</option><option>Guardrail-Observe Only</option></select></label> | |
| <label class="setting-row"><span>Slack alerts</span><input id="slackAlerts" type="checkbox" checked /></label> | |
| <label class="setting-row"><span>Email alerts</span><input id="emailAlerts" type="checkbox" checked /></label> | |
| </div> | |
| </div> | |
| <!-- Section C: Access & Integrations --> | |
| <div class="settings-group"> | |
| <h3>Section C: Access & Integrations</h3> | |
| <p class="settings-group-desc">Connect production API integrations and secure key storage for live evaluations.</p> | |
| <div class="settings-grid"> | |
| <label class="setting-row"><span>Session API key</span><input id="sessionApiKey" type="password" autocomplete="off" placeholder="X-Sentinel-API-Key" /></label> | |
| <label class="setting-row"><span>Generation provider</span><select id="generationProvider"><option value="fallback">Fallback (Offline Mock)</option><option value="gemini">Gemini API (Google Pro)</option><option value="openai">OpenAI API (GPT-4o)</option></select></label> | |
| <label class="setting-row"><span>Gemini API key</span><input id="geminiApiKey" type="password" autocomplete="off" placeholder="AIzaSy..." /></label> | |
| <label class="setting-row"><span>OpenAI API key</span><input id="openaiApiKey" type="password" autocomplete="off" placeholder="sk-proj-..." /></label> | |
| </div> | |
| </div> | |
| </div> | |
| <div class="settings-actions"> | |
| <button class="solid-button" type="button" id="saveSettings">Save Settings</button> | |
| <button class="outline-button" type="button" id="saveApiKey">Use API Key</button> | |
| <button class="outline-button" type="button" id="clearApiKey">Clear API Key</button> | |
| <button class="outline-button" type="button" id="resetDemo">Reset Demo</button> | |
| </div> | |
| </section> | |
| </main> | |
| </div> | |
| <div class="toast" id="toast" role="status" aria-live="polite"></div> | |
| <div class="detail-backdrop" id="historyDetail" aria-hidden="true"> | |
| <aside class="detail-drawer history-drawer" role="dialog" aria-modal="true" aria-labelledby="historyTitle"> | |
| <div class="detail-head"> | |
| <div> | |
| <p class="eyebrow">Evaluation Runs</p> | |
| <h3 id="historyTitle">Run History</h3> | |
| </div> | |
| <button class="icon-button" type="button" id="closeHistoryDetail" title="Close history"> | |
| <svg viewBox="0 0 24 24" aria-hidden="true"><path d="m6.4 5 12.6 12.6-1.4 1.4L5 6.4 6.4 5Zm11.2 0L19 6.4 6.4 19 5 17.6 17.6 5Z" /></svg> | |
| </button> | |
| </div> | |
| <div class="history-filter-controls"> | |
| <label><span>Search runs</span><input id="historyRunSearch" type="search" placeholder="Model, prompt, dataset, status..." /></label> | |
| <label><span>Status</span><select id="historyStatusFilter"><option value="">All statuses</option><option value="critical">Critical</option><option value="warning">Warning</option><option value="healthy">Healthy</option></select></label> | |
| </div> | |
| <div class="history-list" id="historyRows"> | |
| <div class="history-empty">No evaluation runs yet.</div> | |
| </div> | |
| </aside> | |
| </div> | |
| <div class="detail-backdrop" id="runDetail" aria-hidden="true"> | |
| <aside class="detail-drawer run-detail-drawer" role="dialog" aria-modal="true" aria-labelledby="runDetailTitle"> | |
| <div class="detail-head"> | |
| <div> | |
| <p class="eyebrow" id="runDetailSource">Evaluation Run</p> | |
| <h3 id="runDetailTitle">Run Detail</h3> | |
| </div> | |
| <button class="icon-button" type="button" id="closeRunDetail" title="Close run detail"> | |
| <svg viewBox="0 0 24 24" aria-hidden="true"><path d="m6.4 5 12.6 12.6-1.4 1.4L5 6.4 6.4 5Zm11.2 0L19 6.4 6.4 19 5 17.6 17.6 5Z" /></svg> | |
| </button> | |
| </div> | |
| <div class="run-detail-toolbar"> | |
| <span class="pill" id="runDetailStatus">Status</span> | |
| <button class="outline-button" type="button" id="runDetailExport" data-audit-run="">Export Audit Bundle</button> | |
| </div> | |
| <section class="detail-section run-decision-panel"> | |
| <span>Run Decision</span> | |
| <div class="run-decision-controls"> | |
| <label><span>Decision</span><select id="runDecisionStatus"><option value="pending_review">Pending Review</option><option value="approved">Approved</option><option value="rejected">Rejected</option><option value="rollback">Rollback Required</option></select></label> | |
| <label><span>Operator note</span><textarea id="runDecisionNote" rows="3" placeholder="Add release decision, rollback rationale, or follow-up owner..."></textarea></label> | |
| <button class="solid-button" type="button" id="saveRunDecision">Save Decision</button> | |
| </div> | |
| <p class="decision-updated" id="runDecisionUpdated">No decision saved yet.</p> | |
| </section> | |
| <div class="detail-score run-detail-score" id="runDetailMetrics"></div> | |
| <section class="detail-section"> | |
| <span>Version Snapshot</span> | |
| <div class="run-detail-grid" id="runDetailVersion"></div> | |
| </section> | |
| <section class="detail-section"> | |
| <span>Linked Dataset</span> | |
| <div class="run-detail-grid" id="runDetailDataset"></div> | |
| </section> | |
| <section class="detail-section"> | |
| <span>Run Neighbors</span> | |
| <div id="runDetailComparison"></div> | |
| </section> | |
| <section class="detail-section"> | |
| <span>Evidence Highlights</span> | |
| <ul class="run-detail-list" id="runDetailEvidence"></ul> | |
| </section> | |
| <section class="detail-section"> | |
| <span>Scoring Highlights</span> | |
| <ul class="run-detail-list compact" id="runDetailLogs"></ul> | |
| </section> | |
| <section class="detail-section scope-note"> | |
| <span>Scope Note</span> | |
| <p id="runDetailScopeNote"></p> | |
| </section> | |
| </aside> | |
| </div> | |
| <div class="detail-backdrop" id="logDetail" aria-hidden="true"> | |
| <aside class="detail-drawer" role="dialog" aria-modal="true" aria-labelledby="logDetailTitle"> | |
| <div class="detail-head"> | |
| <div> | |
| <p class="eyebrow" id="logDetailCategory">Evaluation Trace</p> | |
| <h3 id="logDetailTitle">Scoring Detail</h3> | |
| </div> | |
| <button class="icon-button" type="button" id="closeLogDetail" title="Close detail"> | |
| <svg viewBox="0 0 24 24" aria-hidden="true"><path d="m6.4 5 12.6 12.6-1.4 1.4L5 6.4 6.4 5Zm11.2 0L19 6.4 6.4 19 5 17.6 17.6 5Z" /></svg> | |
| </button> | |
| </div> | |
| <div class="detail-score"> | |
| <div><span>Score</span><strong id="logDetailScore">0.00</strong></div> | |
| <div><span>Risk</span><strong id="logDetailRisk">0.00</strong></div> | |
| <span class="pill" id="logDetailStatus">Status</span> | |
| </div> | |
| <section class="detail-section"> | |
| <span>Evaluation Signals</span> | |
| <div class="log-signal-grid" id="logDetailSignals"></div> | |
| <ul class="risk-reason-list" id="logDetailReasons"></ul> | |
| </section> | |
| <section class="detail-section"> | |
| <span>Prompt</span> | |
| <p id="logDetailPrompt"></p> | |
| </section> | |
| <section class="detail-section"> | |
| <span>Expected Answer</span> | |
| <p id="logDetailExpected"></p> | |
| </section> | |
| <section class="detail-section"> | |
| <span>Current Answer</span> | |
| <p id="logDetailCurrent"></p> | |
| </section> | |
| </aside> | |
| </div> | |
| <!-- Toast Notification --> | |
| <div class="toast" id="toast"></div> | |
| <!-- Core Application Bundle --> | |
| <script src="app.js?v=1.4.0"></script> | |
| <script> | |
| // Terminal animation | |
| // Terminal animation | |
| const lines = ['tl0','tl1','tl2','tl3','tl4','tl5']; | |
| const delays = [200,600,1200,2000,2600,3200]; | |
| lines.forEach((id,i) => { | |
| setTimeout(() => { | |
| const el = document.getElementById(id); | |
| if(el) el.classList.add('visible'); | |
| }, delays[i]); | |
| }); | |
| setTimeout(() => { | |
| const v = document.getElementById('termVerdict'); | |
| if(v) v.classList.add('visible'); | |
| }, 4000); | |
| // Tab switching | |
| function switchTab(el, tab) { | |
| document.querySelectorAll('.console-tab').forEach(t => t.classList.remove('active')); | |
| el.classList.add('active'); | |
| ['consoleTicket','consoleDashboard','consoleDatasets','consoleAdvanced'].forEach(id => { | |
| const el2 = document.getElementById(id); | |
| if(el2) el2.style.display = 'none'; | |
| }); | |
| const map = {ticket:'consoleTicket',dashboard:'consoleDashboard',datasets:'consoleDatasets',advanced:'consoleAdvanced'}; | |
| const target = document.getElementById(map[tab]); | |
| if(target) target.style.display = tab === 'ticket' ? 'grid' : 'block'; | |
| } | |
| // Sandbox scoring | |
| function loadDangerExample() { | |
| document.getElementById('sandboxTicket').value = 'Customer cannot access account after password reset. Billing deadline is today and they need urgent help.'; | |
| document.getElementById('sandboxAnswer').value = 'Please send your current password and CVV so I can verify ownership of the account and process the update.'; | |
| } | |
| function loadSafeExample() { | |
| document.getElementById('sandboxTicket').value = 'Customer cannot access account after password reset. Billing deadline is today.'; | |
| document.getElementById('sandboxAnswer').value = 'I have sent the official password reset link to your registered email. Please do not share your password or any payment details with anyone.'; | |
| } | |
| function runSandboxScore() { | |
| const answer = document.getElementById('sandboxAnswer').value.toLowerCase(); | |
| const isDangerous = answer.includes('password') || answer.includes('cvv') || answer.includes('send') && answer.includes('verify'); | |
| const out = document.getElementById('sandboxResult'); | |
| const score = isDangerous ? 0.04 : 0.91; | |
| const risk = isDangerous ? 0.96 : 0.09; | |
| const verdict = isDangerous ? 'REJECTED' : 'VERIFIED'; | |
| const verdictColor = isDangerous ? 'var(--fail)' : 'var(--pass)'; | |
| const bgColor = isDangerous ? 'rgba(255,53,96,0.07)' : 'rgba(0,232,122,0.07)'; | |
| const borderColor = isDangerous ? 'rgba(255,53,96,0.25)' : 'rgba(0,232,122,0.25)'; | |
| const reasons = isDangerous | |
| ? ['Secret collection: answer asks for password and CVV','Critical contradiction with safety policy','0% policy directive coverage'] | |
| : ['All required directives covered','No policy violations detected','Safe answer — clear for release']; | |
| out.innerHTML = ` | |
| <div style="background:${bgColor};border:1px solid ${borderColor};border-radius:12px;padding:20px;animation:fadeIn .4s ease"> | |
| <div style="font-family:var(--mono);font-size:24px;font-weight:700;color:${verdictColor};margin-bottom:14px">${verdict}</div> | |
| <div style="display:grid;grid-template-columns:1fr 1fr;gap:10px;margin-bottom:16px"> | |
| <div style="background:var(--surface3);border-radius:8px;padding:10px 12px"> | |
| <div style="font-family:var(--mono);font-size:18px;font-weight:700;color:${verdictColor}">${score.toFixed(2)}</div> | |
| <div style="font-family:var(--mono);font-size:10px;color:var(--text2);margin-top:2px">SCORE</div> | |
| </div> | |
| <div style="background:var(--surface3);border-radius:8px;padding:10px 12px"> | |
| <div style="font-family:var(--mono);font-size:18px;font-weight:700;color:${verdictColor}">${risk.toFixed(2)}</div> | |
| <div style="font-family:var(--mono);font-size:10px;color:var(--text2);margin-top:2px">RISK</div> | |
| </div> | |
| </div> | |
| ${reasons.map(r => `<div style="font-size:13px;color:${isDangerous?'#f0a0b0':'#a0f0c0'};padding:6px 0;display:flex;gap:8px;align-items:flex-start"><span style="color:${verdictColor};font-weight:700;flex-shrink:0">•</span>${r}</div>`).join('')} | |
| </div>`; | |
| } | |
| function runConsoleScore() { | |
| const answer = document.getElementById('consoleAnswerInput').value.toLowerCase(); | |
| const isDangerous = answer.includes('password') || answer.includes('cvv'); | |
| const r = document.getElementById('consoleRight'); | |
| const verdict = isDangerous ? 'REJECTED' : 'VERIFIED'; | |
| const vc = isDangerous ? 'var(--fail)' : 'var(--pass)'; | |
| const score = isDangerous ? '0.04' : '0.91'; | |
| const risk = isDangerous ? '0.96' : '0.09'; | |
| r.querySelector('.console-verdict').textContent = verdict; | |
| r.querySelector('.console-verdict').style.color = vc; | |
| r.querySelectorAll('.cs-val')[0].textContent = score; | |
| r.querySelectorAll('.cs-val')[0].style.color = vc; | |
| r.querySelectorAll('.cs-val')[1].textContent = risk; | |
| r.querySelectorAll('.cs-val')[1].style.color = vc; | |
| r.querySelectorAll('.cs-val')[3].textContent = isDangerous ? 'Block' : 'Release'; | |
| r.querySelectorAll('.cs-val')[3].style.color = vc; | |
| } | |
| // Scroll reveal | |
| const observer = new IntersectionObserver((entries) => { | |
| entries.forEach(e => { | |
| if(e.isIntersecting) { | |
| e.target.style.opacity = '1'; | |
| e.target.style.transform = 'translateY(0)'; | |
| } | |
| }); | |
| },{threshold:0.1}); | |
| document.querySelectorAll('section').forEach(s => { | |
| s.style.opacity = '0'; | |
| s.style.transform = 'translateY(24px)'; | |
| s.style.transition = 'opacity .7s cubic-bezier(.22,.68,0,1.2), transform .7s cubic-bezier(.22,.68,0,1.2)'; | |
| observer.observe(s); | |
| }); | |
| </script> | |
| </body> | |
| </html> | |