Spaces:
Running
Running
| <html lang="en"> | |
| <head> | |
| <meta charset="UTF-8"/> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover, user-scalable=yes"> | |
| <meta name="apple-mobile-web-app-capable" content="yes"> | |
| <meta name="apple-mobile-web-app-status-bar-style" content="black-translucent"> | |
| <meta name="theme-color" content="#0a0e14"> | |
| <title>Sentra Console | Cyber Resilience Command</title> | |
| <meta name="description" content="Cyber Resilience Command platform — threat overview, incident command, 8 immune gates, asset risk, and recovery readiness."/> | |
| <link rel="canonical" href="https://szlholdings-sentra.hf.space/console/"/> | |
| <link rel="preconnect" href="https://fonts.googleapis.com"/> | |
| <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin/> | |
| <link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500&display=swap" rel="stylesheet"/> | |
| <style> | |
| /* ===== Base ===== */ | |
| :root { | |
| --bg: #0f1117; | |
| --surface: #161b27; | |
| --surf2: #1c2236; | |
| --border: #252d40; | |
| --text: #e4e6ef; | |
| --muted: #6b7a99; | |
| --dim: #3d4660; | |
| --gold: #c9b787; | |
| --teal: #3ecfcf; | |
| --red: #e05c5c; | |
| --green: #5aac8e; | |
| --yellow: #e0b84e; | |
| --mono: 'JetBrains Mono', ui-monospace, monospace; | |
| --sans: 'Inter', system-ui, sans-serif; | |
| } | |
| *, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; } | |
| html, body { height: 100%; background: var(--bg); color: var(--text); font-family: var(--sans); font-size: 14px; } | |
| a { color: var(--teal); text-decoration: none; } | |
| a:hover { text-decoration: underline; } | |
| button { cursor: pointer; } | |
| code, .mono { font-family: var(--mono); } | |
| /* ===== Layout ===== */ | |
| .shell { | |
| display: flex; | |
| height: 100vh; | |
| overflow: hidden; | |
| } | |
| /* ===== Sidebar ===== */ | |
| .sidebar { | |
| width: 220px; | |
| min-width: 220px; | |
| background: var(--surface); | |
| border-right: 1px solid var(--border); | |
| display: flex; | |
| flex-direction: column; | |
| overflow-y: auto; | |
| overflow-x: hidden; | |
| } | |
| .sidebar-brand { | |
| padding: 1.25rem 1rem 1rem; | |
| border-bottom: 1px solid var(--border); | |
| display: flex; | |
| align-items: center; | |
| gap: 0.5rem; | |
| } | |
| .sidebar-brand-mark { | |
| width: 1.5rem; | |
| height: 1.5rem; | |
| background: var(--gold); | |
| border-radius: 4px; | |
| display: flex; | |
| align-items: center; | |
| justify-content: center; | |
| font-family: var(--mono); | |
| font-size: 9px; | |
| font-weight: 700; | |
| color: #0a0a0a; | |
| } | |
| .sidebar-brand-name { | |
| font-size: 13px; | |
| font-weight: 600; | |
| letter-spacing: -0.01em; | |
| color: var(--text); | |
| } | |
| .sidebar-brand-tag { | |
| font-family: var(--mono); | |
| font-size: 9px; | |
| color: var(--muted); | |
| } | |
| .sidebar-section { | |
| padding: 1rem 0.75rem 0.5rem; | |
| } | |
| .sidebar-section-label { | |
| font-family: var(--mono); | |
| font-size: 9px; | |
| letter-spacing: 0.1em; | |
| color: var(--dim); | |
| text-transform: uppercase; | |
| padding: 0 0.25rem 0.5rem; | |
| } | |
| .nav-item { | |
| display: flex; | |
| align-items: center; | |
| gap: 0.5rem; | |
| padding: 0.4rem 0.5rem; | |
| border-radius: 6px; | |
| font-size: 12.5px; | |
| color: var(--muted); | |
| transition: background 0.12s ease, color 0.12s ease; | |
| cursor: pointer; | |
| border: none; | |
| background: none; | |
| width: 100%; | |
| text-align: left; | |
| } | |
| .nav-item:hover { background: var(--surf2); color: var(--text); } | |
| .nav-item.active { background: rgba(201,183,135,0.08); color: var(--gold); } | |
| .nav-dot { | |
| width: 6px; height: 6px; | |
| border-radius: 50%; | |
| background: var(--dim); | |
| flex-shrink: 0; | |
| } | |
| .nav-item.active .nav-dot { background: var(--gold); } | |
| /* ===== Main pane ===== */ | |
| .main-pane { | |
| flex: 1; | |
| display: flex; | |
| flex-direction: column; | |
| overflow: hidden; | |
| } | |
| .topbar { | |
| height: 3rem; | |
| border-bottom: 1px solid var(--border); | |
| background: var(--surface); | |
| display: flex; | |
| align-items: center; | |
| padding: 0 1.25rem; | |
| gap: 1rem; | |
| flex-shrink: 0; | |
| } | |
| .topbar-title { | |
| font-size: 13px; | |
| font-weight: 600; | |
| flex: 1; | |
| } | |
| .topbar-badge { | |
| font-family: var(--mono); | |
| font-size: 9px; | |
| padding: 0.2rem 0.5rem; | |
| border-radius: 4px; | |
| background: rgba(94,207,207,0.1); | |
| color: var(--teal); | |
| border: 1px solid rgba(94,207,207,0.2); | |
| letter-spacing: 0.06em; | |
| } | |
| .topbar-link { | |
| font-family: var(--mono); | |
| font-size: 10px; | |
| color: var(--muted); | |
| text-decoration: none; | |
| } | |
| .topbar-link:hover { color: var(--gold); } | |
| .content { | |
| flex: 1; | |
| overflow-y: auto; | |
| padding: 1.5rem; | |
| } | |
| /* ===== Page: overview ===== */ | |
| .kpi-grid { | |
| display: grid; | |
| grid-template-columns: repeat(auto-fill, minmax(180px, 1fr)); | |
| gap: 1px; | |
| background: var(--border); | |
| border: 1px solid var(--border); | |
| border-radius: 8px; | |
| overflow: hidden; | |
| margin-bottom: 1.5rem; | |
| } | |
| .kpi-card { | |
| background: var(--surface); | |
| padding: 1.25rem 1.5rem; | |
| display: flex; | |
| flex-direction: column; | |
| gap: 0.25rem; | |
| } | |
| .kpi-label { | |
| font-family: var(--mono); | |
| font-size: 9px; | |
| letter-spacing: 0.1em; | |
| color: var(--muted); | |
| text-transform: uppercase; | |
| } | |
| .kpi-value { | |
| font-size: 2rem; | |
| font-weight: 700; | |
| letter-spacing: -0.03em; | |
| } | |
| .kpi-delta { | |
| font-family: var(--mono); | |
| font-size: 10px; | |
| color: var(--green); | |
| } | |
| .kpi-red { color: var(--red); } | |
| .kpi-green { color: var(--green); } | |
| .kpi-gold { color: var(--gold); } | |
| .kpi-teal { color: var(--teal); } | |
| /* ===== Section heading ===== */ | |
| .section-heading { | |
| font-size: 13px; | |
| font-weight: 600; | |
| color: var(--text); | |
| margin-bottom: 0.875rem; | |
| display: flex; | |
| align-items: center; | |
| gap: 0.5rem; | |
| } | |
| .section-heading::after { | |
| content: ''; | |
| flex: 1; | |
| height: 1px; | |
| background: var(--border); | |
| } | |
| /* ===== Gates page ===== */ | |
| .gates-list { | |
| display: flex; | |
| flex-direction: column; | |
| gap: 1px; | |
| background: var(--border); | |
| border: 1px solid var(--border); | |
| border-radius: 8px; | |
| overflow: hidden; | |
| margin-bottom: 1.5rem; | |
| } | |
| .gate-row { | |
| background: var(--surface); | |
| padding: 1rem 1.25rem; | |
| display: grid; | |
| grid-template-columns: 2rem 1fr auto; | |
| align-items: center; | |
| gap: 1rem; | |
| cursor: pointer; | |
| transition: background 0.12s ease; | |
| } | |
| .gate-row:hover { background: var(--surf2); } | |
| .gate-row.expanded { background: var(--surf2); } | |
| .gate-num-badge { | |
| font-family: var(--mono); | |
| font-size: 10px; | |
| color: var(--gold); | |
| font-weight: 600; | |
| } | |
| .gate-info h3 { font-size: 13px; font-weight: 600; margin-bottom: 0.2rem; } | |
| .gate-info p { font-size: 11.5px; color: var(--muted); line-height: 1.45; } | |
| .gate-tags { | |
| display: flex; | |
| gap: 0.35rem; | |
| align-items: center; | |
| } | |
| .tag { | |
| font-family: var(--mono); | |
| font-size: 9px; | |
| padding: 0.15rem 0.4rem; | |
| border-radius: 3px; | |
| background: rgba(201,183,135,0.08); | |
| color: var(--gold); | |
| white-space: nowrap; | |
| } | |
| .tag-teal { | |
| background: rgba(62,207,207,0.08); | |
| color: var(--teal); | |
| } | |
| .gate-detail { | |
| display: none; | |
| padding: 1rem 1.25rem 1.25rem; | |
| background: var(--surf2); | |
| border-top: 1px solid var(--border); | |
| font-size: 12px; | |
| color: var(--muted); | |
| line-height: 1.6; | |
| } | |
| .gate-detail.open { display: block; } | |
| .gate-test-btn { | |
| display: inline-flex; | |
| align-items: center; | |
| gap: 0.3rem; | |
| font-family: var(--mono); | |
| font-size: 10px; | |
| padding: 0.35rem 0.75rem; | |
| background: var(--gold); | |
| color: #0a0a0a; | |
| border: none; | |
| border-radius: 4px; | |
| margin-top: 0.75rem; | |
| cursor: pointer; | |
| } | |
| .gate-test-result { | |
| margin-top: 0.625rem; | |
| font-family: var(--mono); | |
| font-size: 11px; | |
| padding: 0.625rem; | |
| background: rgba(0,0,0,0.4); | |
| border-radius: 5px; | |
| display: none; | |
| } | |
| .gate-test-result.visible { display: block; } | |
| .result-allow { color: var(--green); } | |
| .result-deny { color: var(--red); } | |
| /* ===== Verdict tester ===== */ | |
| .verdict-box { | |
| background: var(--surface); | |
| border: 1px solid var(--border); | |
| border-radius: 8px; | |
| padding: 1.5rem; | |
| max-width: 640px; | |
| } | |
| .v-label { | |
| font-family: var(--mono); | |
| font-size: 9px; | |
| letter-spacing: 0.1em; | |
| color: var(--muted); | |
| text-transform: uppercase; | |
| margin-bottom: 0.4rem; | |
| } | |
| .v-textarea { | |
| width: 100%; | |
| background: var(--surf2); | |
| border: 1px solid var(--border); | |
| border-radius: 5px; | |
| color: var(--text); | |
| font-family: var(--mono); | |
| font-size: 12px; | |
| padding: 0.625rem 0.875rem; | |
| outline: none; | |
| resize: vertical; | |
| min-height: 72px; | |
| } | |
| .v-textarea:focus { border-color: var(--gold); } | |
| .v-row { | |
| display: flex; | |
| align-items: center; | |
| gap: 0.875rem; | |
| margin-top: 0.75rem; | |
| } | |
| .v-btn { | |
| font-family: var(--mono); | |
| font-size: 11px; | |
| padding: 0.5rem 1.25rem; | |
| background: var(--gold); | |
| color: #0a0a0a; | |
| border: none; | |
| border-radius: 5px; | |
| } | |
| .v-btn:disabled { opacity: 0.5; } | |
| .v-status { | |
| font-family: var(--mono); | |
| font-size: 10px; | |
| color: var(--muted); | |
| } | |
| .v-output { | |
| margin-top: 1rem; | |
| background: rgba(0,0,0,0.5); | |
| border: 1px solid var(--border); | |
| border-radius: 6px; | |
| padding: 0.875rem 1rem; | |
| font-family: var(--mono); | |
| font-size: 12px; | |
| line-height: 1.7; | |
| display: none; | |
| } | |
| .v-output.visible { display: block; } | |
| /* ===== Audit log ===== */ | |
| .audit-table { | |
| width: 100%; | |
| border-collapse: collapse; | |
| font-size: 11.5px; | |
| margin-bottom: 1.5rem; | |
| } | |
| .audit-table th { | |
| font-family: var(--mono); | |
| font-size: 9px; | |
| letter-spacing: 0.08em; | |
| color: var(--muted); | |
| text-transform: uppercase; | |
| text-align: left; | |
| padding: 0.5rem 0.875rem; | |
| border-bottom: 1px solid var(--border); | |
| } | |
| .audit-table td { | |
| padding: 0.5rem 0.875rem; | |
| border-bottom: 1px solid rgba(255,255,255,0.03); | |
| color: var(--text); | |
| } | |
| .audit-table tr:hover td { background: var(--surf2); } | |
| .badge { | |
| font-family: var(--mono); | |
| font-size: 9px; | |
| padding: 0.15rem 0.4rem; | |
| border-radius: 3px; | |
| } | |
| .badge-allow { background: rgba(90,172,142,0.1); color: var(--green); } | |
| .badge-deny { background: rgba(224,92,92,0.1); color: var(--red); } | |
| /* ===== Threats ===== */ | |
| .threats-list { | |
| display: flex; | |
| flex-direction: column; | |
| gap: 1px; | |
| background: var(--border); | |
| border: 1px solid var(--border); | |
| border-radius: 8px; | |
| overflow: hidden; | |
| } | |
| .threat-row { | |
| background: var(--surface); | |
| padding: 0.875rem 1.25rem; | |
| display: grid; | |
| grid-template-columns: 1fr auto auto; | |
| align-items: center; | |
| gap: 1rem; | |
| } | |
| .threat-sig { font-family: var(--mono); font-size: 12px; color: var(--red); } | |
| .threat-cat { font-family: var(--mono); font-size: 10px; color: var(--muted); } | |
| /* ===== Empty / loading ===== */ | |
| .loading { | |
| font-family: var(--mono); | |
| font-size: 11px; | |
| color: var(--dim); | |
| padding: 2rem 0; | |
| text-align: center; | |
| } | |
| /* ===== Rosie widget ===== */ | |
| #rosie-widget { | |
| position: fixed; | |
| bottom: 1.25rem; | |
| right: 1.25rem; | |
| z-index: 1000; | |
| display: flex; | |
| flex-direction: column; | |
| align-items: flex-end; | |
| gap: 0.625rem; | |
| } | |
| #rosie-bubble { | |
| background: var(--surface); | |
| border: 1px solid rgba(201,183,135,0.2); | |
| border-radius: 10px; | |
| padding: 0.875rem 1rem; | |
| width: 260px; | |
| box-shadow: 0 8px 24px rgba(0,0,0,0.6); | |
| display: none; | |
| flex-direction: column; | |
| gap: 0.5rem; | |
| } | |
| #rosie-bubble.open { display: flex; } | |
| .rosie-title { font-family: var(--mono); font-size: 10px; color: var(--gold); letter-spacing: 0.1em; } | |
| .rosie-msgs { font-family: var(--mono); font-size: 11px; color: var(--muted); line-height: 1.55; max-height: 120px; overflow-y: auto; } | |
| .rmsg-u { color: var(--text); } | |
| .rmsg-b { color: var(--gold); } | |
| .rosie-inp { background: var(--surf2); border: 1px solid var(--border); border-radius: 5px; color: var(--text); font-family: var(--mono); font-size: 11px; padding: 0.4rem 0.625rem; outline: none; width: 100%; } | |
| .rosie-inp:focus { border-color: var(--gold); } | |
| .rosie-send-btn { font-family: var(--mono); font-size: 10px; background: var(--gold); color: #0a0a0a; border: none; border-radius: 4px; padding: 0.3rem 0.75rem; cursor: pointer; align-self: flex-end; } | |
| #rosie-toggle { width: 2.75rem; height: 2.75rem; border-radius: 50%; background: var(--gold); border: none; font-size: 1.1rem; display: flex; align-items: center; justify-content: center; box-shadow: 0 4px 14px rgba(201,183,135,0.25); cursor: pointer; } | |
| @media (max-width: 640px) { | |
| .sidebar { display: none; } | |
| } | |
| </style> | |
| </head> | |
| <body> | |
| <!-- SZL FLAGSHIP HERO v2 (ADDITIVE, prepended before #root) — Sign: Yachay · Perplexity Computer Agent | |
| Anduril×Anthropic×a11oy aesthetic. Kanchay tokens reused (no new tokens). Open-source fonts. | |
| Self-contained: no external CDN, no build step. Canvas wire-mesh animation (Live Wires lineage). | |
| Does NOT touch #root (React SPA) or any /api route — pure prepend. MARKER: data-szl-hero-v2 --> | |
| <section id="szl-flagship-hero" data-szl-hero-v2="sentra" aria-label="sentra command hero"> | |
| <style> | |
| #szl-flagship-hero{position:relative;width:100%;min-height:560px;background:#0a0f1e;color:#f5f7fa; | |
| font-family:"Inter","IBM Plex Sans",ui-sans-serif,system-ui,sans-serif;overflow:hidden; | |
| border-bottom:1px solid #3c4757} | |
| #szl-flagship-hero *{box-sizing:border-box} | |
| #szl-hero-canvas{position:absolute;inset:0;width:100%;height:100%;display:block;z-index:0;opacity:.55} | |
| #szl-hero-grid{position:absolute;inset:0;z-index:1;pointer-events:none; | |
| background-image:linear-gradient(rgba(60,71,87,.18) 1px,transparent 1px),linear-gradient(90deg,rgba(60,71,87,.18) 1px,transparent 1px); | |
| background-size:48px 48px;mask-image:radial-gradient(ellipse 75% 70% at 50% 38%,#000 55%,transparent 100%)} | |
| #szl-hero-inner{position:relative;z-index:2;max-width:1180px;margin:0 auto;padding:30px 34px 26px} | |
| .szl-hero-top{display:flex;align-items:center;gap:12px;font-family:"JetBrains Mono",ui-monospace,monospace; | |
| font-size:11px;letter-spacing:.16em;text-transform:uppercase;color:#76859b} | |
| .szl-hero-top .dot{width:7px;height:7px;border-radius:50%;background:#1f9d57;box-shadow:0 0 0 0 rgba(31,157,87,.6); | |
| animation:szlpulse 2.4s infinite} | |
| @keyframes szlpulse{0%{box-shadow:0 0 0 0 rgba(31,157,87,.55)}70%{box-shadow:0 0 0 9px rgba(31,157,87,0)}100%{box-shadow:0 0 0 0 rgba(31,157,87,0)}} | |
| .szl-hero-top .sep{color:#3c4757} | |
| .szl-hero-top b{color:#d7b96b;font-weight:600} | |
| #szl-flagship-hero h1{font-size:clamp(30px,5vw,52px);line-height:1.02;margin:18px 0 12px;font-weight:680; | |
| letter-spacing:-.02em;max-width:18ch} | |
| #szl-flagship-hero h1 .accent{color:#d7b96b} | |
| .szl-hero-sub{font-size:clamp(14px,1.7vw,17px);line-height:1.5;color:#c9d2df;max-width:60ch;margin:0 0 22px} | |
| .szl-metrics{display:grid;grid-template-columns:repeat(auto-fit,minmax(132px,1fr));gap:1px; | |
| background:#3c4757;border:1px solid #3c4757;border-radius:10px;overflow:hidden;max-width:880px} | |
| .szl-metric{background:#10151c;padding:13px 15px} | |
| .szl-metric .v{font-family:"JetBrains Mono",ui-monospace,monospace;font-size:21px;font-weight:600;color:#f5f7fa;line-height:1} | |
| .szl-metric .v .u{font-size:12px;color:#76859b;margin-left:3px} | |
| .szl-metric .k{font-size:10.5px;letter-spacing:.07em;text-transform:uppercase;color:#76859b;margin-top:7px} | |
| .szl-metric.good .v{color:#5cc4bf} | |
| .szl-hero-cta{display:flex;gap:10px;margin-top:22px;flex-wrap:wrap} | |
| .szl-hero-cta a{font-size:13px;font-weight:600;text-decoration:none;padding:9px 16px;border-radius:8px; | |
| font-family:"Inter",sans-serif;border:1px solid #3c4757;transition:.16s} | |
| .szl-hero-cta a.primary{background:#d7b96b;color:#10151c;border-color:#d7b96b} | |
| .szl-hero-cta a.primary:hover{background:#e4cf99} | |
| .szl-hero-cta a.ghost{background:transparent;color:#c9d2df} | |
| .szl-hero-cta a.ghost:hover{border-color:#5cc4bf;color:#5cc4bf} | |
| .szl-hero-foot{font-family:"JetBrains Mono",monospace;font-size:10.5px;color:#525f73;margin-top:18px;letter-spacing:.04em} | |
| @media(prefers-reduced-motion:reduce){#szl-hero-canvas{animation:none;opacity:.3}.szl-hero-top .dot{animation:none}} | |
| @media(max-width:640px){#szl-flagship-hero{min-height:480px}} | |
| </style> | |
| <canvas id="szl-hero-canvas" aria-hidden="true"></canvas> | |
| <div id="szl-hero-grid"></div> | |
| <div id="szl-hero-inner"> | |
| <div class="szl-hero-top"> | |
| <span class="dot"></span><span>SZL HOLDINGS</span><span class="sep">/</span> | |
| <span>SENTRA</span><span class="sep">/</span> | |
| <span>DOCTRINE v11 · LOCKED</span><span class="sep">/</span> | |
| <b>REPLAY bacf5443…</b> | |
| </div> | |
| <h1>Continuous <span class="accent">defensive assurance</span> for every agent.</h1> | |
| <p class="szl-hero-sub">Sentra watches the watchers: adversarial resilience, alignment review and audit replay on a shared 13-axis doctrine. Defensive posture only — sensor fusion in the Lattice tradition, constitutional gating in the Anthropic tradition.</p> | |
| <div class="szl-metrics"><div class="szl-metric"><div class="v">13<span class="u">axis</span></div><div class="k">doctrine</div></div><div class="szl-metric"><div class="v">163<span class="u">sorries</span></div><div class="k">audited</div></div><div class="szl-metric"><div class="v">14<span class="u">axioms</span></div><div class="k">pinned</div></div><div class="szl-metric good"><div class="v">100%<span class="u">gates</span></div><div class="k">GREEN</div></div><div class="szl-metric good"><div class="v">0<span class="u">RED</span></div><div class="k">routes</div></div></div> | |
| <div class="szl-hero-cta"><a class="primary" href="#root">Open assurance deck</a><a class="ghost" href="/api/sentra/healthz">Health</a></div> | |
| <div class="szl-hero-foot">FRONTIER: Breathing assurance pulse — live posture heartbeat across all monitored organs · governed loop GREEN · additive deploy · sign: Yachay</div> | |
| </div> | |
| <script> | |
| (function(){ | |
| var prefersReduce = window.matchMedia && window.matchMedia('(prefers-reduced-motion: reduce)').matches; | |
| var c = document.getElementById('szl-hero-canvas'); if(!c) return; | |
| var ctx = c.getContext('2d'); var W,H,DPR,nodes=[],t=0; | |
| var ACCENT='#d7b96b', TEAL='#5cc4bf', LINE='rgba(60,71,87,.55)'; | |
| function size(){DPR=Math.min(2,window.devicePixelRatio||1);var r=c.getBoundingClientRect(); | |
| W=c.width=Math.max(1,r.width*DPR);H=c.height=Math.max(1,r.height*DPR);build();} | |
| function build(){nodes=[];var N=Math.round((W*H)/(DPR*DPR)/26000);N=Math.max(26,Math.min(64,N)); | |
| for(var i=0;i<N;i++){nodes.push({x:Math.random()*W,y:Math.random()*H, | |
| vx:(Math.random()-.5)*0.18*DPR,vy:(Math.random()-.5)*0.18*DPR, | |
| r:(1.1+Math.random()*1.8)*DPR,p:Math.random()*6.28});}} | |
| function step(){t+=0.016;ctx.clearRect(0,0,W,H); | |
| for(var i=0;i<nodes.length;i++){var n=nodes[i];n.x+=n.vx;n.y+=n.vy; | |
| if(n.x<0||n.x>W)n.vx*=-1; if(n.y<0||n.y>H)n.vy*=-1;} | |
| var MAX=150*DPR; | |
| for(var i=0;i<nodes.length;i++){for(var j=i+1;j<nodes.length;j++){ | |
| var a=nodes[i],b=nodes[j];var dx=a.x-b.x,dy=a.y-b.y;var d=Math.sqrt(dx*dx+dy*dy); | |
| if(d<MAX){var o=(1-d/MAX);ctx.strokeStyle='rgba(92,196,191,'+(o*0.28).toFixed(3)+')'; | |
| ctx.lineWidth=DPR*0.7;ctx.beginPath();ctx.moveTo(a.x,a.y);ctx.lineTo(b.x,b.y);ctx.stroke();}}} | |
| for(var i=0;i<nodes.length;i++){var n=nodes[i]; | |
| var pulse=0.5+0.5*Math.sin(t*1.3+n.p); | |
| ctx.fillStyle = (i%5===0)?ACCENT:TEAL; | |
| ctx.globalAlpha=0.35+0.45*pulse;ctx.beginPath();ctx.arc(n.x,n.y,n.r*(0.8+0.5*pulse),0,6.2832);ctx.fill();} | |
| ctx.globalAlpha=1; | |
| if(!prefersReduce) requestAnimationFrame(step);} | |
| size();window.addEventListener('resize',size); | |
| if(prefersReduce){step();}else{requestAnimationFrame(step);} | |
| })(); | |
| </script> | |
| </section> | |
| <div class="shell"> | |
| <!-- ===== SIDEBAR ===== --> | |
| <nav class="sidebar" aria-label="Sentra console navigation"> | |
| <div class="sidebar-brand"> | |
| <div class="sidebar-brand-mark">S</div> | |
| <div> | |
| <div class="sidebar-brand-name">sentra</div> | |
| <div class="sidebar-brand-tag">/ cyber resilience command</div> | |
| </div> | |
| </div> | |
| <div class="sidebar-section"> | |
| <div class="sidebar-section-label">Overview</div> | |
| <button class="nav-item active" onclick="showPage('overview')"> | |
| <span class="nav-dot"></span> Decision Center | |
| </button> | |
| <button class="nav-item" onclick="showPage('gates')"> | |
| <span class="nav-dot"></span> 8 Immune Gates | |
| </button> | |
| </div> | |
| <div class="sidebar-section"> | |
| <div class="sidebar-section-label">Wire B</div> | |
| <button class="nav-item" onclick="showPage('verdict')"> | |
| <span class="nav-dot"></span> Verdict Tester | |
| </button> | |
| <button class="nav-item" onclick="showPage('audit')"> | |
| <span class="nav-dot"></span> Audit Log | |
| </button> | |
| <button class="nav-item" onclick="showPage('threats')"> | |
| <span class="nav-dot"></span> Threat Corpus | |
| </button> | |
| </div> | |
| <div class="sidebar-section"> | |
| <div class="sidebar-section-label">Platform</div> | |
| <button class="nav-item" onclick="showPage('incidents')"> | |
| <span class="nav-dot"></span> Incidents | |
| </button> | |
| <button class="nav-item" onclick="showPage('assets')"> | |
| <span class="nav-dot"></span> Asset Risk | |
| </button> | |
| </div> | |
| <div style="margin-top:auto;padding:1rem;border-top:1px solid var(--border);"> | |
| <a href="/" class="nav-item" style="text-decoration:none;color:var(--muted);"> | |
| <span class="nav-dot"></span> ← Landing | |
| </a> | |
| </div> | |
| </nav> | |
| <!-- ===== MAIN PANE ===== --> | |
| <div class="main-pane"> | |
| <div class="topbar"> | |
| <span class="topbar-title" id="topbar-title">Decision Center</span> | |
| <span class="topbar-badge">WIRE B LIVE</span> | |
| <span class="topbar-badge" style="background:rgba(201,183,135,0.08);color:var(--gold);border-color:rgba(201,183,135,0.2);">8 GATES</span> | |
| <a class="topbar-link" href="/api/sentra/docs" target="_blank">API docs →</a> | |
| </div> | |
| <div class="content" id="content"> | |
| <!-- Pages are injected here by JS --> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- ===== ROSIE WIDGET ===== --> | |
| <div id="rosie-widget" role="complementary" aria-label="Rosie assistant"> | |
| <div id="rosie-bubble" role="dialog" aria-modal="false" aria-label="Rosie assistant"> | |
| <div style="display:flex;align-items:center;justify-content:space-between;"> | |
| <span class="rosie-title">ROSIE · SENTRA</span> | |
| <button onclick="toggleRosie()" style="background:none;border:none;color:var(--muted);cursor:pointer;font-size:13px;">✕</button> | |
| </div> | |
| <div class="rosie-msgs" id="rosie-msgs"> | |
| <div class="rmsg-b">Hi, I'm Rosie. Ask about gates, verdicts, Wire B, or threats.</div> | |
| </div> | |
| <input type="text" id="rosie-inp" class="rosie-inp" placeholder="Ask anything…" onkeydown="if(event.key==='Enter')sendRosie()"/> | |
| <button class="rosie-send-btn" onclick="sendRosie()">Send →</button> | |
| </div> | |
| <button id="rosie-toggle" onclick="toggleRosie()" aria-label="Open Rosie">🛡️</button> | |
| </div> | |
| <script> | |
| </script> | |
| </body> | |
| </html> | |