From 8bc1eacf9637edd9f39e2c9721de914ca9290a16 Mon Sep 17 00:00:00 2001 From: pavsoss Date: Wed, 10 Jun 2026 19:14:46 +0530 Subject: [PATCH 01/16] style: add unified css --- .gitignore | 8 +- landing/src/index.css | 415 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 421 insertions(+), 2 deletions(-) create mode 100644 landing/src/index.css diff --git a/.gitignore b/.gitignore index b7faf40..7e56479 100644 --- a/.gitignore +++ b/.gitignore @@ -202,6 +202,10 @@ cython_debug/ .cursorindexingignore # Marimo -marimo/_static/ -marimo/_lsp/ __marimo__/ + +# Node.js / Frontend +node_modules/ +dist/ +package-lock.json + diff --git a/landing/src/index.css b/landing/src/index.css new file mode 100644 index 0000000..84be8dd --- /dev/null +++ b/landing/src/index.css @@ -0,0 +1,415 @@ +/* ═══════════════════════════════════════════════════════════════ + TENET AI v2 — Landing Page Styles + ═══════════════════════════════════════════════════════════════ */ +@import url('https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700;800;900&family=JetBrains+Mono:wght@300;400;500;600&display=swap'); + +/* ── RESET & VARIABLES ─────────────────────────────────────── */ +*,*::before,*::after{box-sizing:border-box;margin:0;padding:0} +:root{ + --bg:#080C10;--surface:#0f1116;--surface2:#14171f;--surface3:#1a1d28; + --border:#1e2130;--border2:#252a3a; + --cyan:#00E5FF;--cyan-dim:rgba(0,229,255,0.08);--cyan-glow:rgba(0,229,255,0.2); + --red:#FF3B3B;--red-dim:rgba(255,59,59,0.1); + --amber:#FFB800;--amber-dim:rgba(255,184,0,0.1); + --green:#00FF88;--green-dim:rgba(0,255,136,0.1); + --purple:#B47FFF;--purple-dim:rgba(180,127,255,0.1); + --text:#dde1ef;--text2:#8890a8;--text3:#484f66; + --font:'Inter',sans-serif;--mono:'JetBrains Mono',monospace; + --radius:10px; +} +html{scroll-behavior:smooth} +body{background:var(--bg);color:var(--text);font-family:var(--font);-webkit-font-smoothing:antialiased;overflow-x:hidden} +::-webkit-scrollbar{width:4px}::-webkit-scrollbar-track{background:var(--bg)}::-webkit-scrollbar-thumb{background:var(--border2);border-radius:4px} +::-webkit-scrollbar-thumb:hover{background:var(--cyan)} + +/* ── SKIP TO MAIN ──────────────────────────────────────────── */ +.skip-to-main{position:absolute;top:-100px;left:16px;background:var(--cyan);color:var(--bg);padding:8px 16px;border-radius:0 0 6px 6px;font-size:13px;font-weight:600;z-index:9999;text-decoration:none;transition:top 0.2s} +.skip-to-main:focus{top:0;outline:none} + +/* ── LAYOUT ────────────────────────────────────────────────── */ +.page{display:flex;flex-direction:column;min-height:100vh} +.main{margin-top:52px;flex:1} +.container{max-width:1180px;margin:0 auto;padding:0 28px} +.section{padding:80px 0} +.section-alt{background:var(--surface)} + +/* ── TYPOGRAPHY ────────────────────────────────────────────── */ +.eyebrow{display:flex;align-items:center;gap:8px;font-size:10.5px;font-family:var(--mono);color:var(--cyan);letter-spacing:0.14em;text-transform:uppercase;margin-bottom:14px} +.eyebrow::before{content:'';width:18px;height:1px;background:var(--cyan);flex-shrink:0} +.section-title{font-size:32px;font-weight:800;letter-spacing:-0.025em;line-height:1.15;margin-bottom:12px} +.section-sub{font-size:14px;color:var(--text2);max-width:540px;line-height:1.75} +.grad{background:linear-gradient(110deg,#fff 0%,var(--cyan) 50%,#0088aa 100%);-webkit-background-clip:text;-webkit-text-fill-color:transparent;background-clip:text} + +/* ── TOPBAR ────────────────────────────────────────────────── */ +.topbar{position:fixed;top:0;left:0;right:0;z-index:100;height:52px;background:rgba(8,12,16,0.92);border-bottom:1px solid var(--border);backdrop-filter:blur(20px);display:flex;align-items:center;padding:0 32px;gap:0} +.brand{display:flex;align-items:center;gap:10px;text-decoration:none;min-width:200px} +.brand-logo{display:flex;align-items:center;justify-content:center} +.brand-name{font-weight:800;font-size:15px;color:var(--cyan);letter-spacing:-0.01em} +.brand-badge{font-size:9px;background:var(--cyan-dim);color:var(--cyan);border:1px solid rgba(0,229,255,0.2);border-radius:4px;padding:2px 6px;font-family:var(--mono);margin-left:2px} +.nav{display:flex;align-items:center;height:100%;gap:0;margin-left:16px;flex:1} +.nav-link{display:flex;align-items:center;gap:6px;height:100%;padding:0 14px;font-size:12px;font-weight:500;color:var(--text3);text-decoration:none;cursor:pointer;border-bottom:2px solid transparent;transition:color 0.15s,border-color 0.15s;white-space:nowrap;outline:none} +.nav-link:hover{color:var(--text2);background:rgba(255,255,255,0.02)} +.nav-link.active{color:var(--cyan);border-bottom-color:var(--cyan)} +.nav-link:focus-visible{outline:2px solid var(--cyan);outline-offset:-2px;border-radius:2px} +.topbar-right{display:flex;align-items:center;gap:10px;margin-left:auto} +.live-badge{display:flex;align-items:center;gap:6px;font-size:11px;color:var(--green);font-family:var(--mono);background:var(--green-dim);border:1px solid rgba(0,255,136,0.2);padding:4px 10px;border-radius:20px} +.dot{width:6px;height:6px;border-radius:50%;background:var(--green);animation:pulse 2s infinite} +.shortcut-hint{font-size:10px;color:var(--text3);font-family:var(--mono);background:var(--surface2);border:1px solid var(--border);border-radius:4px;padding:2px 6px;cursor:help} + +/* ── BUTTONS ───────────────────────────────────────────────── */ +.btn{display:inline-flex;align-items:center;gap:7px;border:none;cursor:pointer;font-family:var(--font);font-weight:600;border-radius:7px;text-decoration:none;transition:all 0.18s;white-space:nowrap;letter-spacing:-0.01em;outline:none} +.btn:focus-visible{outline:2px solid var(--cyan);outline-offset:2px} +.btn-sm{font-size:12px;padding:7px 14px} +.btn-md{font-size:13px;padding:10px 20px} +.btn-lg{font-size:14px;padding:13px 26px} +.btn-xl{font-size:15px;padding:15px 32px} +.btn-primary{background:var(--cyan);color:#080C10} +.btn-primary:hover{background:#33EBFF;transform:translateY(-1px)} +.btn-outline{background:transparent;color:var(--text);border:1px solid var(--border2)} +.btn-outline:hover{border-color:var(--cyan);color:var(--cyan)} +.btn-ghost{background:transparent;color:var(--text2);border:1px solid var(--border)} +.btn-ghost:hover{color:var(--cyan);border-color:rgba(0,229,255,0.3)} + +/* ── HERO ──────────────────────────────────────────────────── */ +.hero{padding:80px 0 72px;position:relative;overflow:hidden;background:var(--bg)} +.hero-dots{position:absolute;inset:0;background-image:radial-gradient(rgba(0,229,255,0.15) 1px,transparent 1px);background-size:24px 24px;pointer-events:none} +.hero-scanlines{position:absolute;inset:0;background:repeating-linear-gradient(0deg,rgba(0,229,255,0.015) 0px,rgba(0,229,255,0.015) 1px,transparent 1px,transparent 4px);pointer-events:none} +.hero-glow1{position:absolute;top:-160px;left:50%;transform:translateX(-50%);width:1000px;height:500px;background:radial-gradient(ellipse,rgba(0,229,255,0.05) 0%,transparent 65%);pointer-events:none} +.hero-inner{position:relative;display:grid;grid-template-columns:1fr 1fr;gap:64px;align-items:center} + +/* Hero entrance animations */ +.hero-enter-bg{opacity:0;animation:heroFadeIn 0.4s ease both} +.hero-enter-logo{opacity:0;animation:heroFadeSlideUp8 0.6s ease-out both;animation-delay:100ms} +.hero-enter-headline{opacity:0;animation:heroSlideUp16 0.5s ease-out both;animation-delay:200ms} +.hero-enter-sub{opacity:0;animation:heroFadeIn 0.4s ease both;animation-delay:400ms} +.hero-enter-cta1{opacity:0;animation:heroFadeIn 0.4s ease both;animation-delay:600ms} +.hero-enter-cta2{opacity:0;animation:heroFadeIn 0.4s ease both;animation-delay:800ms} +.hero-enter-pills{opacity:0;animation:heroFadeIn 0.4s ease both;animation-delay:800ms} +.hero-enter-terminal{opacity:0;animation:heroSlideFromRight 0.6s ease-out both;animation-delay:1000ms} + +.hero-logo-wrap{position:relative;display:inline-flex;margin-bottom:24px} +.hero-logo-glow{position:absolute;bottom:-8px;left:50%;transform:translateX(-50%);width:80px;height:40px;background:radial-gradient(ellipse,rgba(0,229,255,0.15) 0%,transparent 70%);pointer-events:none;border-radius:50%} + +.hero-title{font-size:54px;font-weight:900;letter-spacing:-0.035em;line-height:1.05;margin-bottom:22px} +.hero-title .fw-firewall{font-weight:900;letter-spacing:-0.04em;border-bottom:1px solid rgba(0,229,255,0.4);padding-bottom:2px} +.hero-cursor{display:inline-block;color:var(--cyan);font-weight:300;animation:blink 1s step-end infinite;margin-left:2px} +.hero-desc{font-size:15px;color:var(--text2);line-height:1.8;margin-bottom:36px;max-width:460px} +.hero-actions{display:flex;gap:12px;flex-wrap:wrap;margin-bottom:44px} +.hero-pills{display:flex;align-items:center;gap:20px;flex-wrap:wrap} +.hero-pill{display:flex;align-items:center;gap:6px;font-size:11.5px;color:var(--text3);font-family:var(--mono)} +.hero-pill-check{flex-shrink:0} + +/* ── PREVIEW / TERMINAL PANEL ──────────────────────────────── */ +.preview{background:var(--surface);border:1px solid var(--border);border-radius:14px;overflow:hidden;transition:border-color 0.6s ease} +.preview.flash-red{border-color:rgba(255,59,59,0.4)} +.preview-bar{background:var(--surface2);border-bottom:1px solid var(--border);padding:10px 16px;display:flex;align-items:center;gap:7px} +.preview-dot{width:10px;height:10px;border-radius:50%} +.preview-title{font-size:11px;color:var(--text3);margin-left:8px;font-family:var(--mono);flex:1} +.preview-live{display:flex;align-items:center;gap:5px;font-size:10px;color:var(--green);font-family:var(--mono)} +.preview-processing{font-size:10px;color:var(--text3);font-family:var(--mono);margin-right:8px;min-width:20px} +.preview-body{padding:14px;display:flex;flex-direction:column;gap:10px} +.p-stats{display:grid;grid-template-columns:repeat(3,1fr);gap:8px} +.p-stat{background:var(--surface2);border:1px solid var(--border);border-radius:8px;padding:12px 14px} +.p-stat-v{font-size:24px;font-weight:700;font-family:var(--mono);line-height:1;margin-bottom:4px} +.p-stat-l{font-size:9.5px;color:var(--text3);text-transform:uppercase;letter-spacing:0.1em} +.p-log{background:var(--bg);border:1px solid var(--border);border-radius:8px;padding:10px 12px;font-family:var(--mono);font-size:10.5px;display:flex;flex-direction:column;gap:5px;min-height:88px} +.p-log-row{display:flex;gap:8px;align-items:center;opacity:0;animation:fadeRow 0.3s ease forwards} +.p-log-time{color:var(--text3);min-width:58px;font-size:10px} +.p-log-tag{font-size:8.5px;font-weight:700;padding:1px 6px;border-radius:3px;min-width:52px;text-align:center;letter-spacing:0.04em} +.p-log-msg{color:#4e5568;flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:10px} +.p-bars{background:var(--surface2);border:1px solid var(--border);border-radius:8px;padding:12px 14px;display:flex;flex-direction:column;gap:7px} +.p-bar-head{font-size:9px;color:var(--text3);font-family:var(--mono);letter-spacing:0.1em;text-transform:uppercase;margin-bottom:2px} +.p-bar-row{display:flex;align-items:center;gap:8px} +.p-bar-lbl{font-size:9.5px;color:var(--text3);min-width:96px;font-family:var(--mono)} +.p-bar-track{flex:1;height:3px;background:var(--border);border-radius:2px;overflow:hidden} +.p-bar-fill{height:100%;border-radius:2px;transition:width 1.8s cubic-bezier(0.4,0,0.2,1)} +.p-bar-val{font-size:9.5px;color:var(--text2);font-family:var(--mono);min-width:30px;text-align:right} + +/* ── STATS STRIP ───────────────────────────────────────────── */ +.stats-strip{background:var(--surface);border-top:1px solid var(--border);border-bottom:1px solid var(--border);padding:0} +.stats-grid{display:grid;grid-template-columns:repeat(5,1fr)} +.stat-block{padding:28px 24px;border-right:1px solid var(--border)} +.stat-block:last-child{border-right:none} +.stat-val{font-size:36px;font-weight:800;font-family:var(--mono);letter-spacing:-0.03em;line-height:1;margin-bottom:6px} +.stat-lbl{font-size:11px;color:var(--text3);text-transform:uppercase;letter-spacing:0.09em;font-weight:500} +.stat-sub{font-size:10px;color:var(--text3);margin-top:3px;font-family:var(--mono)} +.stat-sparkline{margin-top:8px;opacity:0.5} + +/* ── HOW IT WORKS / PIPELINE ───────────────────────────────── */ +.pipeline-flow{display:flex;align-items:center;justify-content:center;gap:0;margin-bottom:48px;position:relative;padding:20px 0} +.pipeline-flow-node{background:var(--surface);border:1px solid var(--border2);border-radius:8px;padding:10px 20px;font-size:12px;font-weight:600;font-family:var(--mono);position:relative;z-index:1;white-space:nowrap} +.pipeline-flow-node.node-app{border-color:var(--cyan);color:var(--cyan)} +.pipeline-flow-node.node-tenet{border-color:var(--amber);color:var(--amber)} +.pipeline-flow-node.node-engine{border-color:var(--purple);color:var(--purple)} +.pipeline-flow-node.node-allow{border-color:var(--green);color:var(--green)} +.pipeline-flow-node.node-block{border-color:var(--red);color:var(--red)} +.pipeline-flow-arrow{width:40px;height:2px;background:var(--border2);position:relative;flex-shrink:0} +.pipeline-flow-arrow::after{content:'›';position:absolute;right:-2px;top:50%;transform:translateY(-50%);color:var(--text3);font-size:14px} +.pipeline-packet{position:absolute;width:6px;height:6px;border-radius:50%;background:var(--cyan);top:50%;transform:translateY(-50%);z-index:2;animation:packetTravel 3s ease-in-out infinite} +.pipeline-packet.packet-block{background:var(--red);animation:packetTravelBlock 6s ease-in-out infinite;animation-delay:3s} + +.how-grid{display:grid;grid-template-columns:repeat(4,1fr);position:relative;gap:0} +.how-line{position:absolute;top:27px;left:calc(12.5% + 13px);right:calc(12.5% + 13px);height:1px;background:linear-gradient(90deg,transparent,var(--cyan),transparent)} +.how-step{padding:0 20px;text-align:center;position:relative;cursor:default} +.how-num{width:54px;height:54px;border-radius:50%;background:var(--surface);border:1px solid var(--border2);display:flex;align-items:center;justify-content:center;font-size:20px;margin:0 auto 20px;position:relative;z-index:1;transition:all 0.22s} +.how-step:hover .how-num{border-color:var(--cyan);background:var(--cyan-dim)} +.how-step-number{position:absolute;top:8px;right:16px;font-size:11px;font-family:var(--mono);color:var(--border2);transition:color 0.22s} +.how-step:hover .how-step-number{color:var(--text3)} +.how-step::before{content:'';position:absolute;top:0;left:0;bottom:0;width:2px;background:var(--cyan);transform:scaleY(0);transform-origin:top;transition:transform 0.3s ease;border-radius:1px} +.how-step:hover::before{transform:scaleY(1)} +.how-tag{font-size:9.5px;font-family:var(--mono);color:var(--cyan);letter-spacing:0.14em;margin-bottom:8px} +.how-title{font-size:14px;font-weight:700;margin-bottom:8px} +.how-desc{font-size:12px;color:var(--text2);line-height:1.65} + +/* Risk score bar (Step 2 Analyze) */ +.risk-score-bar{margin-top:12px;opacity:0;transition:opacity 0.3s} +.how-step:hover .risk-score-bar{opacity:1} +.risk-score-track{width:100%;height:3px;background:var(--border);border-radius:2px;overflow:hidden} +.risk-score-fill{width:0;height:100%;background:var(--amber);border-radius:2px;transition:width 0.6s ease} +.how-step:hover .risk-score-fill{width:87%} +.risk-score-label{font-size:9px;font-family:var(--mono);color:var(--amber);margin-top:4px;opacity:0;transition:opacity 0.3s 0.2s} +.how-step:hover .risk-score-label{opacity:1} + +/* ── FEATURES ──────────────────────────────────────────────── */ +.feat-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:14px} +.feat-card{background:var(--surface);border:1px solid var(--border);border-radius:var(--radius);padding:26px;transition:all 0.22s;position:relative;overflow:hidden;cursor:default} +.feat-card::before{content:'';position:absolute;top:0;left:0;right:0;height:2px;background:linear-gradient(90deg,transparent,var(--cyan),transparent);opacity:0;transition:opacity 0.22s} +.feat-card:hover{border-color:var(--border2);transform:translateY(-3px)} +.feat-card:hover::before{opacity:1} +.feat-icon{width:42px;height:42px;border-radius:9px;display:flex;align-items:center;justify-content:center;font-size:20px;margin-bottom:16px} +.feat-title{font-size:14.5px;font-weight:700;margin-bottom:8px} +.feat-desc{font-size:12.5px;color:var(--text2);line-height:1.7} +.feat-tags{display:flex;flex-wrap:wrap;gap:6px;margin-top:14px} +.tag{font-size:10px;font-family:var(--mono);padding:3px 9px;border-radius:4px;border:1px solid transparent} + +/* ── INTERACTIVE DEMO ──────────────────────────────────────── */ +.demo-grid{display:grid;grid-template-columns:280px 1fr;gap:24px;align-items:start} +.demo-attacks{display:flex;flex-direction:column;gap:8px} +.demo-attack-btn{position:relative;background:var(--surface);border:1px solid var(--border);border-radius:var(--radius);padding:16px 18px;cursor:pointer;text-align:left;transition:all 0.18s;outline:none;font-family:var(--font)} +.demo-attack-btn:focus-visible{outline:2px solid var(--cyan);outline-offset:2px} +.demo-attack-btn:hover,.demo-attack-btn.active{border-color:var(--border2);background:var(--surface2)} +.demo-attack-btn.active{border-left:3px solid} +.demo-attack-name{font-size:13px;font-weight:600;color:var(--text);margin-bottom:4px} +.demo-attack-preview{font-size:10.5px;color:var(--text3);font-family:var(--mono);overflow:hidden;text-overflow:ellipsis;white-space:nowrap} +.demo-copy-btn{position:absolute;top:8px;right:8px;opacity:0;transition:opacity 0.15s;background:transparent;border:1px solid var(--border);color:var(--text3);font-size:10px;padding:3px 8px;border-radius:4px;cursor:pointer;font-family:var(--mono)} +.demo-attack-btn:hover .demo-copy-btn{opacity:1} +.demo-copy-btn:hover{color:var(--cyan);border-color:var(--cyan)} + +.demo-panel{background:var(--surface);border:1px solid var(--border);border-radius:var(--radius);overflow:hidden;min-height:360px} +.demo-panel-header{background:var(--surface2);border-bottom:1px solid var(--border);padding:12px 18px;display:flex;align-items:center;gap:8px} +.demo-panel-dot{width:10px;height:10px;border-radius:50%} +.demo-panel-title{font-size:11px;color:var(--text3);font-family:var(--mono)} +.demo-panel-body{padding:24px} + +.demo-prompt-label{font-size:10px;font-family:var(--mono);color:var(--text3);letter-spacing:0.1em;text-transform:uppercase;margin-bottom:8px} +.demo-prompt-text{font-size:13px;color:var(--text);line-height:1.7;padding:14px;background:var(--bg);border:1px solid var(--border);border-radius:8px;margin-bottom:20px;font-family:var(--mono);font-size:11.5px} + +.demo-analysis{margin-top:16px} +.demo-analyzing{display:flex;align-items:center;gap:10px;font-size:12px;color:var(--text2);font-family:var(--mono)} +.demo-analyzing-dots{color:var(--cyan)} + +.demo-verdict{margin-top:16px;padding:16px;background:var(--red-dim);border:1px solid rgba(255,59,59,0.2);border-radius:8px} +.demo-verdict-badge{display:inline-flex;align-items:center;gap:6px;font-size:11px;font-weight:700;font-family:var(--mono);padding:4px 10px;border-radius:4px;margin-bottom:8px} +.demo-verdict-type{font-size:12px;color:var(--text2);margin-bottom:4px} +.demo-verdict-type span{font-weight:600;color:var(--text)} +.demo-verdict-confidence{font-size:11px;color:var(--text3);font-family:var(--mono)} + +.demo-explanation{margin-top:16px;overflow:hidden} +.demo-explanation-title{font-size:12px;font-weight:600;color:var(--text);margin-bottom:12px} +.demo-explanation-item{display:flex;align-items:flex-start;gap:8px;font-size:12px;color:var(--text2);line-height:1.6;margin-bottom:8px;opacity:0;transform:translateY(8px);transition:all 0.3s ease} +.demo-explanation-item.visible{opacity:1;transform:translateY(0)} +.demo-explanation-bullet{color:var(--cyan);font-size:10px;flex-shrink:0;margin-top:3px} + +.demo-type-badge{display:inline-flex;align-items:center;gap:5px;font-size:10px;font-weight:700;font-family:var(--mono);padding:3px 10px;border-radius:4px;margin-bottom:12px;letter-spacing:0.04em} + +/* ── COMPARISON TABLE ──────────────────────────────────────── */ +.compare-wrap{overflow-x:auto;-webkit-overflow-scrolling:touch} +.compare-table{width:100%;min-width:680px;border-collapse:separate;border-spacing:0;font-size:13px;table-layout:fixed} +.compare-table th:first-child, .compare-table td:first-child{width:37%} +.compare-table th:not(:first-child), .compare-table td:not(:first-child){width:21%} +.compare-table th{text-align:left;padding:14px 18px;font-size:11px;font-family:var(--mono);letter-spacing:0.08em;text-transform:uppercase;color:var(--text3);background:var(--surface);border-bottom:1px solid var(--border);font-weight:600;white-space:nowrap} +.compare-table th:first-child{border-radius:var(--radius) 0 0 0} +.compare-table th:last-child{border-radius:0 var(--radius) 0 0;border-left:2px solid var(--cyan)} +.compare-table td{padding:14px 18px;border-bottom:1px solid var(--border);color:var(--text2);vertical-align:middle;position:relative} +.compare-table tr:last-child td{border-bottom:none} +.compare-table td:first-child{color:var(--text);font-weight:500;position:relative} +.compare-table td:last-child{border-left:2px solid rgba(0,229,255,0.15)} +.compare-table tbody tr{transition:background 0.15s} +.compare-table tbody tr td:first-child::before{content:'';position:absolute;left:0;top:0;bottom:0;width:2px;background:var(--cyan);transform:scaleY(0);transform-origin:top;transition:transform 0.15s ease} +.compare-table tbody tr:hover{background:rgba(0,229,255,0.02)} +.compare-table tbody tr:hover td:first-child::before{transform:scaleY(1)} +.compare-table th.text-center, .compare-table td.text-center{text-align:center} +.compare-table th.text-center > *, .compare-table td.text-center > *{margin:0 auto} +.compare-icon-yes{color:var(--green)} +.compare-icon-no{color:var(--red)} +.compare-icon-partial{color:var(--amber)} + +.compare-summary-row td{padding:18px;background:var(--surface)} +.compare-summary-row td:first-child{font-weight:700;color:var(--text)} +.progress-bar{display:flex;gap:4px;align-items:center} +.progress-pill{width:20px;height:4px;border-radius:2px;background:var(--border)} +.progress-pill.filled{background:currentColor} + +/* ── ARCHITECTURE DIAGRAM ──────────────────────────────────── */ +.arch-svg-wrap{background:var(--surface);border:1px solid var(--border);border-radius:var(--radius);padding:32px;overflow:hidden} +.arch-svg{width:100%;height:auto;max-width:800px;margin:0 auto;display:block} +.arch-svg text{font-family:var(--font)} +.arch-svg .arch-box{fill:var(--surface2);stroke-width:1.5;rx:8;ry:8} +.arch-svg .arch-arrow{fill:none;stroke:var(--border2);stroke-width:1.5;marker-end:url(#arrowhead)} +.arch-svg .arch-label{fill:var(--text);font-size:13px;font-weight:600} +.arch-svg .arch-sublabel{fill:var(--text3);font-size:10px} +.arch-svg .arch-badge{fill:var(--cyan-dim);stroke:rgba(0,229,255,0.3);stroke-width:1;rx:4;ry:4} +.arch-packet{fill:var(--cyan);r:4} +.arch-packet-block{fill:var(--red);r:4} + +/* ── BREACH CARDS / CASE STUDIES ───────────────────────────── */ +.threat-list-wrap{position:relative;padding-left:28px} +.timeline-spine{position:absolute;left:5px;top:0;width:2px;background:var(--border2);height:0;transition:height 0.6s ease} +.timeline-node{position:absolute;left:0;width:10px;height:10px;border-radius:50%;border:2px solid;background:var(--bg);z-index:1;transform:translateY(24px)} +.threat-list{display:flex;flex-direction:column;gap:14px} +.threat{background:var(--surface);border:1px solid var(--border);border-left:3px solid;border-radius:var(--radius);padding:22px;display:grid;grid-template-columns:160px 1fr 90px;gap:20px;align-items:start;transition:all 0.2s;cursor:default} +.threat:hover{background:var(--surface2);transform:translateX(4px)} +.threat-meta{display:flex;flex-direction:column;gap:6px} +.threat-date{font-size:10px;font-family:var(--mono);color:var(--text3)} +.threat-sev{font-size:10.5px;font-weight:700;padding:3px 9px;border-radius:4px;display:inline-flex;align-items:center;gap:4px;width:fit-content} +.threat-type{font-size:9.5px;font-family:var(--mono);color:var(--text3);background:var(--surface3);padding:2px 7px;border-radius:3px;width:fit-content} +.threat-title{font-size:14px;font-weight:700;margin-bottom:6px} +.threat-desc{font-size:12px;color:var(--text2);line-height:1.65;margin-bottom:10px} + +.threat-resp-toggle{display:flex;align-items:center;gap:6px;background:rgba(0,229,255,0.04);border:1px solid rgba(0,229,255,0.12);border-radius:6px;padding:10px 13px;cursor:pointer;width:100%;text-align:left;font-family:var(--font);transition:background 0.15s} +.threat-resp-toggle:hover{background:rgba(0,229,255,0.07)} +.threat-resp-toggle:focus-visible{outline:2px solid var(--cyan);outline-offset:2px} +.threat-resp-arrow{font-size:10px;color:var(--cyan);transition:transform 0.3s;display:inline-block} +.threat-resp-arrow.expanded{transform:rotate(90deg)} +.threat-resp-lbl{font-size:9px;font-family:var(--mono);color:var(--cyan);letter-spacing:0.12em;font-weight:700;flex:1} +.threat-resp-content{max-height:0;overflow:hidden;transition:max-height 0.3s ease} +.threat-resp-content.expanded{max-height:200px} +.threat-resp-text{font-size:11.5px;color:var(--text2);line-height:1.6;padding:10px 13px 2px} +.threat-num{text-align:right} +.threat-num-val{font-size:22px;font-weight:800;font-family:var(--mono);line-height:1} +.threat-num-lbl{font-size:9.5px;color:var(--text3);margin-top:3px} + +/* ── INSTALL ───────────────────────────────────────────────── */ +.install-grid{display:grid;grid-template-columns:repeat(2,1fr);gap:14px} +.install-card{background:var(--surface);border:1px solid var(--border);border-radius:var(--radius);overflow:hidden;transition:all 0.22s} +.install-card:hover{border-color:var(--border2);transform:translateY(-3px)} +.install-head{padding:20px 20px 0;display:flex;align-items:flex-start;justify-content:space-between} +.install-icon{font-size:30px;margin-bottom:10px} +.install-plat{font-size:9.5px;font-family:var(--mono);color:var(--text3);background:var(--surface3);padding:2px 8px;border-radius:4px} +.install-title{font-size:15px;font-weight:700;margin-bottom:4px} +.install-sub{font-size:12px;color:var(--text2);margin-bottom:14px} +.install-cmd{background:var(--bg);border-top:1px solid var(--border);padding:12px 20px;font-family:var(--mono);font-size:12px;color:var(--cyan);display:flex;align-items:center;gap:8px} +.install-prompt{color:var(--text3)} +.install-body{padding:16px 20px 20px} +.install-features{display:flex;flex-direction:column;gap:5px;margin-bottom:14px} +.install-feat{display:flex;align-items:center;gap:7px;font-size:12px;color:var(--text2)} +.install-feat::before{content:'';width:4px;height:4px;border-radius:50%;background:var(--cyan);flex-shrink:0} + +/* ── CODE BLOCK ────────────────────────────────────────────── */ +.code-block{background:var(--bg);border:1px solid var(--border);border-radius:var(--radius);overflow:hidden} +.code-head{background:var(--surface);border-bottom:1px solid var(--border);padding:11px 18px;display:flex;align-items:center;gap:8px} +.code-dot2{width:11px;height:11px;border-radius:50%;flex-shrink:0} +.code-file{font-size:12px;color:var(--text3);font-family:var(--mono);margin-left:8px} +.code-lang-badge{font-size:9.5px;font-family:var(--mono);color:var(--text3);background:var(--surface3);padding:2px 8px;border-radius:3px;margin-left:auto} +.code-body{padding:22px 26px;font-family:var(--mono);font-size:12.5px;line-height:2;overflow-x:auto} +.cc{color:#3d4560}.ck{color:#c792ea}.cs{color:#c3e88d}.cf{color:#82aaff}.cy{color:var(--cyan)}.cd{color:#3d4560} + +/* ── CTA ───────────────────────────────────────────────────── */ +.cta{padding:96px 0;text-align:center;position:relative;overflow:hidden} +.cta-glow{position:absolute;inset:0;background:radial-gradient(ellipse at center,rgba(0,229,255,0.055) 0%,transparent 65%);pointer-events:none} +.cta-title{font-size:44px;font-weight:900;letter-spacing:-0.03em;margin-bottom:16px} +.cta-sub{font-size:15px;color:var(--text2);margin-bottom:40px} +.cta-btns{display:flex;gap:14px;justify-content:center;flex-wrap:wrap;margin-bottom:36px} +.cta-chips{display:flex;gap:10px;justify-content:center;flex-wrap:wrap} +.cta-chip{font-size:11.5px;color:var(--text3);background:var(--surface);border:1px solid var(--border);border-radius:20px;padding:5px 15px;display:flex;align-items:center;gap:6px} +.cta-chip::before{content:'';display:inline-block;width:5px;height:9px;border:solid var(--cyan);border-width:0 2px 2px 0;transform:rotate(45deg);margin-right:8px;margin-bottom:2px} + +/* ── FOOTER ────────────────────────────────────────────────── */ +.footer{background:var(--surface);border-top:1px solid var(--border);padding:48px 0 36px} +.footer-grid{display:grid;grid-template-columns:1.5fr 1fr 1fr 1fr;gap:40px;margin-bottom:36px} +.footer-brand-col{display:flex;flex-direction:column;gap:12px} +.footer-brand{display:flex;align-items:center;gap:10px} +.footer-name{font-weight:700;font-size:14px;color:var(--cyan)} +.footer-brand-desc{font-size:12px;color:var(--text3);line-height:1.6;max-width:260px} +.footer-col-title{font-size:10px;font-family:var(--mono);color:var(--text3);letter-spacing:0.12em;text-transform:uppercase;margin-bottom:14px;font-weight:600} +.footer-col-links{display:flex;flex-direction:column;gap:8px} +.footer-link{font-size:12.5px;color:var(--text3);text-decoration:none;transition:color 0.15s} +.footer-link:hover{color:var(--cyan)} +.footer-bottom{display:flex;align-items:center;justify-content:space-between;border-top:1px solid var(--border);padding-top:24px;flex-wrap:wrap;gap:12px} +.footer-copy{font-size:11px;color:var(--text3);font-family:var(--mono)} +.footer-secured{font-size:11px;color:var(--text3);font-family:var(--mono);text-decoration:none;transition:color 0.15s} +.footer-secured:hover{color:var(--cyan)} + +/* ── BACK TO TOP ───────────────────────────────────────────── */ +.back-to-top{position:fixed;bottom:24px;right:24px;width:36px;height:36px;background:var(--bg);border:1px solid var(--border2);border-radius:6px;display:flex;align-items:center;justify-content:center;cursor:pointer;color:var(--text3);transition:all 0.2s;z-index:90;opacity:0;pointer-events:none;transform:translateY(8px)} +.back-to-top.visible{opacity:1;pointer-events:all;transform:translateY(0)} +.back-to-top:hover{border-color:var(--cyan);color:var(--cyan)} +.back-to-top:focus-visible{outline:2px solid var(--cyan);outline-offset:2px} + +/* ── KEYFRAMES ─────────────────────────────────────────────── */ +@keyframes pulse{0%,100%{opacity:1;transform:scale(1)}50%{opacity:0.5;transform:scale(0.8)}} +@keyframes fadeRow{from{opacity:0;transform:translateX(-6px)}to{opacity:1;transform:translateX(0)}} +@keyframes fadeUp{from{opacity:0;transform:translateY(22px)}to{opacity:1;transform:translateY(0)}} +@keyframes blink{0%,100%{opacity:1}50%{opacity:0}} +@keyframes heroFadeIn{from{opacity:0}to{opacity:1}} +@keyframes heroSlideUp16{from{opacity:0;transform:translateY(16px)}to{opacity:1;transform:translateY(0)}} +@keyframes heroFadeSlideUp8{from{opacity:0;transform:translateY(8px)}to{opacity:1;transform:translateY(0)}} +@keyframes heroSlideFromRight{from{opacity:0;transform:translateX(24px)}to{opacity:1;transform:translateX(0)}} +@keyframes processingDots{0%{content:'.'}33%{content:'..'}66%{content:'...'}100%{content:'.'}} +@keyframes packetTravel{0%{left:0;opacity:1}45%{left:calc(50% - 3px);opacity:1}48%{left:calc(50% - 3px);opacity:1}95%{left:calc(100% - 6px);opacity:1}100%{left:calc(100% - 6px);opacity:0}} +@keyframes drawLine{from{stroke-dashoffset:1000}to{stroke-dashoffset:0}} +.au{animation:fadeUp 0.6s ease both} + +/* ── PREFERS REDUCED MOTION ────────────────────────────────── */ +@media(prefers-reduced-motion:reduce){ + *,*::before,*::after{animation-duration:0.01ms!important;animation-delay:0ms!important;animation-iteration-count:1!important;transition-duration:0.01ms!important} + .hero-enter-bg,.hero-enter-logo,.hero-enter-headline,.hero-enter-sub,.hero-enter-cta1,.hero-enter-cta2,.hero-enter-pills,.hero-enter-terminal{opacity:1;animation:none} + .pipeline-packet,.pipeline-packet.packet-block{animation:none;display:none} + .dot{animation:none} + .hero-cursor{animation:none;opacity:0.7} + html{scroll-behavior:auto} +} + +/* ── RESPONSIVE ────────────────────────────────────────────── */ +@media(min-width:1181px) and (max-width:1380px){ + .nav-link{padding:0 8px;gap:4px;font-size:11.5px} + .nav-link svg{display:none} +} +@media(max-width:1180px){ + .nav{display:none} +} +@media(max-width:1024px){ + .hero-inner{grid-template-columns:1fr}.preview{display:none} + .feat-grid{grid-template-columns:1fr 1fr} + .how-grid{grid-template-columns:1fr 1fr;gap:28px}.how-line{display:none} + .stats-grid{grid-template-columns:repeat(3,1fr)} + .demo-grid{grid-template-columns:1fr} + .pipeline-flow{flex-wrap:wrap;gap:8px} + .footer-grid{grid-template-columns:1fr 1fr} + .arch-svg-wrap{padding:16px} +} +@media(max-width:768px){ + .hero{padding:60px 0 48px} + .hero-title{font-size:38px} + .install-grid{grid-template-columns:1fr} + .feat-grid{grid-template-columns:1fr} + .threat{grid-template-columns:1fr;gap:12px}.threat-num{text-align:left} + .stats-grid{grid-template-columns:repeat(2,1fr)} + .stat-block:nth-child(2n){border-right:none} + .topbar{padding:0 16px} + .nav{display:none} + .section{padding:60px 0} + .footer-grid{grid-template-columns:1fr;gap:24px} + .compare-table{font-size:11px} + .compare-table th,.compare-table td{padding:10px 12px} + .threat-list-wrap{padding-left:20px} +} +@media(max-width:480px){ + .stats-grid{grid-template-columns:1fr} + .stat-block{border-right:none!important;border-bottom:1px solid var(--border)} + .stat-block:last-child{border-bottom:none} + .cta-title{font-size:30px} + .hero-title{font-size:30px} + .hero-actions{flex-direction:column} + .hero-pills{gap:12px} +} From 3c48644973e564b6e7ed22b88bef233014805aca Mon Sep 17 00:00:00 2001 From: pavsoss Date: Wed, 10 Jun 2026 19:15:10 +0530 Subject: [PATCH 02/16] feat: modularize layout and static sections --- landing/index.html | 21 +- .../src/components/ArchitectureDiagram.tsx | 186 ++++++++++++++++ landing/src/components/CtaSection.tsx | 79 +++++++ landing/src/components/FeaturesSection.tsx | 202 ++++++++++++++++++ landing/src/components/PipelineSection.tsx | 196 +++++++++++++++++ landing/src/components/StatsSection.tsx | 155 ++++++++++++++ landing/src/components/TenetLogo.tsx | 45 ++++ landing/src/main.tsx | 1 + 8 files changed, 884 insertions(+), 1 deletion(-) create mode 100644 landing/src/components/ArchitectureDiagram.tsx create mode 100644 landing/src/components/CtaSection.tsx create mode 100644 landing/src/components/FeaturesSection.tsx create mode 100644 landing/src/components/PipelineSection.tsx create mode 100644 landing/src/components/StatsSection.tsx create mode 100644 landing/src/components/TenetLogo.tsx diff --git a/landing/index.html b/landing/index.html index 4668a8d..5ef6427 100644 --- a/landing/index.html +++ b/landing/index.html @@ -3,7 +3,26 @@ - TENET AI – LLM Firewall + + + TENET AI – Real-Time Open Source LLM Firewall & Security Middleware + + + + + + + + + + + + + + + + +
diff --git a/landing/src/components/ArchitectureDiagram.tsx b/landing/src/components/ArchitectureDiagram.tsx new file mode 100644 index 0000000..edf5275 --- /dev/null +++ b/landing/src/components/ArchitectureDiagram.tsx @@ -0,0 +1,186 @@ +import React, { useEffect, useState, useRef } from 'react'; + +export default function ArchitectureDiagram() { + const [cycle, setCycle] = useState(0); // 0 = allow, 1 = allow, 2 = block + const ref = useRef(null); + const [inView, setInView] = useState(false); + + useEffect(() => { + const timer = setInterval(() => { + setCycle(prev => (prev + 1) % 3); + }, 4000); // 4 seconds cycle + + const observer = new IntersectionObserver(([entry]) => { + if (entry.isIntersecting) { + setInView(true); + observer.disconnect(); + } + }, { threshold: 0.1 }); + + if (ref.current) { + observer.observe(ref.current); + } + + return () => { + clearInterval(timer); + observer.disconnect(); + }; + }, []); + + return ( +
+
+
+
System Topology
+

Decentralized, high-performance middleware topology

+

TENET AI coordinates safety actions directly inside your cluster using parallel detection engines.

+
+ +
+ + + + + + + + + + + + + + + + {/* Animated dasharray definitions */} + + + + {/* Background grids inside SVG */} + + + + + + {/* Connecting Paths */} + {/* App to Middleware */} + + + {/* Middleware to 3 Engines */} + + + + + {/* Engines to Decision Point */} + + + + + {/* Decision to Outlets */} + + + {/* Animated Packet Circle */} + {inView && ( + + + + + + )} + + {/* BOX 1: Application Node */} + + + Your App + Python / Node.js + + + {/* BOX 2: TENET Middleware */} + + + TENET SDK + Core Proxy Layer + + {/* <10ms latency badge */} + + <10ms latency + + + {/* BOXES 3: Parallel Detection Engines */} + {/* 3a: Heuristics */} + + + Heuristics Engine + Known signatures + + {/* 3b: ML Classifier */} + + + ML Classifier + Adversarial matching + + {/* 3c: Behavioral Analyzer */} + + + Behavioral tracker + Cross-session chains + + + {/* BOX 4: Decision Node (Diamond / Hexagon visual look) */} + + + Policy + + + {/* BOX 5: Outcomes */} + {/* Block Output */} + + + BLOCK (403) + Heuristic block + + + {/* Allowed/LLM Output */} + + + ALLOW + Forward to LLM + + +
+
+
+ ); +} diff --git a/landing/src/components/CtaSection.tsx b/landing/src/components/CtaSection.tsx new file mode 100644 index 0000000..3df92c9 --- /dev/null +++ b/landing/src/components/CtaSection.tsx @@ -0,0 +1,79 @@ +import React, { useState, useEffect, useRef } from 'react'; + +function FadeUp({ children, delay = 0 }: { children: React.ReactNode; delay?: number }) { + const ref = useRef(null); + const [visible, setVisible] = useState(false); + + useEffect(() => { + const observer = new IntersectionObserver(([entry]) => { + if (entry.isIntersecting) { + setVisible(true); + observer.disconnect(); + } + }, { threshold: 0.05 }); + + if (ref.current) { + observer.observe(ref.current); + } + return () => observer.disconnect(); + }, []); + + return ( +
+ {children} +
+ ); +} + +export default function CtaSection() { + const handleScrollToDownload = (e: React.MouseEvent) => { + e.preventDefault(); + const el = document.getElementById('download'); + if (el) { + el.scrollIntoView({ behavior: 'smooth' }); + } + }; + + return ( +
+
+
+ +

+ Start protecting your
AI applications today +

+

Self-hosted. Open source. Zero vendor lock-in.

+ + + +
+ {['MIT Licensed', 'Docker deployment', 'Developer support'].map((chip, i) => ( + + {chip} + + ))} +
+
+
+
+ ); +} diff --git a/landing/src/components/FeaturesSection.tsx b/landing/src/components/FeaturesSection.tsx new file mode 100644 index 0000000..7d30dec --- /dev/null +++ b/landing/src/components/FeaturesSection.tsx @@ -0,0 +1,202 @@ +import React, { useState, useEffect, useRef } from 'react'; + +interface FeatureItem { + icon: React.ReactNode; + bg: string; + title: string; + desc: string; + tags: { l: string; c: string }[]; +} + +const FEATURES: FeatureItem[] = [ + { + icon: ( + + + + + + ), + bg: 'var(--cyan-dim)', + title: 'Heuristic Detection', + desc: 'Zero-config pattern matching for known attack signatures — prompt injection, jailbreaks, role manipulation out of the box.', + tags: [{ l: '<5ms', c: 'cyan' }, { l: 'zero-config', c: 'dim' }] + }, + { + icon: ( + + + + + + + + + + ), + bg: 'var(--purple-dim)', + title: 'ML-Based Analysis', + desc: 'Trained classifier achieving >90% accuracy on adversarial datasets. Continuously improves from analyst feedback.', + tags: [{ l: '>90% accuracy', c: 'purple' }, { l: 'adaptive', c: 'dim' }] + }, + { + icon: ( + + + + + + + + + ), + bg: 'var(--amber-dim)', + title: 'Behavioral Analysis', + desc: 'Cross-session pattern tracking detects coordinated attacks and multi-turn manipulation chains that single-shot models miss.', + tags: [{ l: 'cross-session', c: 'amber' }, { l: 'anomaly detection', c: 'dim' }] + }, + { + icon: ( + + + + + ), + bg: 'var(--green-dim)', + title: 'Real-Time Policy Engine', + desc: 'Block, sanitize, flag, or allow — configurable rules execute in under 10ms total overhead with zero LLM integration changes.', + tags: [{ l: '<10ms', c: 'green' }, { l: 'configurable', c: 'dim' }] + }, + { + icon: ( + + + + + + + + ), + bg: 'var(--cyan-dim)', + title: 'SOC Dashboard', + desc: 'Live threat feeds, attack timelines, risk score trends, and analyst workflows. Audit-ready for compliance teams.', + tags: [{ l: 'real-time', c: 'cyan' }, { l: 'SOC-ready', c: 'dim' }] + }, + { + icon: ( + + + + + + + ), + bg: 'var(--purple-dim)', + title: 'Universal Integration', + desc: 'LLM-agnostic middleware for OpenAI, Anthropic, Cohere, Ollama, and any local model. One API call in your existing stack.', + tags: [{ l: 'any LLM', c: 'purple' }, { l: 'one API call', c: 'dim' }] + } +]; + +function FadeUp({ children, delay = 0 }: { children: React.ReactNode; delay?: number }) { + const ref = useRef(null); + const [visible, setVisible] = useState(false); + + useEffect(() => { + const observer = new IntersectionObserver(([entry]) => { + if (entry.isIntersecting) { + setVisible(true); + observer.disconnect(); + } + }, { threshold: 0.05 }); + + if (ref.current) { + observer.observe(ref.current); + } + return () => observer.disconnect(); + }, []); + + return ( +
+ {children} +
+ ); +} + +export default function FeaturesSection() { + const tagCss = (c: string) => { + switch (c) { + case 'cyan': + return { + color: 'var(--cyan)', + background: 'var(--cyan-dim)', + borderColor: 'rgba(0, 229, 255, 0.2)' + }; + case 'purple': + return { + color: 'var(--purple)', + background: 'var(--purple-dim)', + borderColor: 'rgba(180, 127, 255, 0.2)' + }; + case 'amber': + return { + color: 'var(--amber)', + background: 'var(--amber-dim)', + borderColor: 'rgba(255, 184, 0, 0.2)' + }; + case 'green': + return { + color: 'var(--green)', + background: 'var(--green-dim)', + borderColor: 'rgba(0, 255, 136, 0.2)' + }; + default: + return { + color: 'var(--text3)', + background: 'var(--surface3)', + borderColor: 'var(--border)' + }; + } + }; + + return ( +
+
+ +
+
Capabilities
+

Everything to secure your AI

+
+
+ +
+ {FEATURES.map((f, i) => ( + +
+
+ {f.icon} +
+
{f.title}
+
{f.desc}
+
+ {f.tags.map((t, j) => ( + + {t.l} + + ))} +
+
+
+ ))} +
+
+
+ ); +} diff --git a/landing/src/components/PipelineSection.tsx b/landing/src/components/PipelineSection.tsx new file mode 100644 index 0000000..6936e5b --- /dev/null +++ b/landing/src/components/PipelineSection.tsx @@ -0,0 +1,196 @@ +import React, { useState, useEffect, useRef } from 'react'; + +function FadeUp({ children, delay = 0 }: { children: React.ReactNode; delay?: number }) { + const ref = useRef(null); + const [visible, setVisible] = useState(false); + + useEffect(() => { + const observer = new IntersectionObserver(([entry]) => { + if (entry.isIntersecting) { + setVisible(true); + observer.disconnect(); + } + }, { threshold: 0.05 }); + + if (ref.current) { + observer.observe(ref.current); + } + return () => observer.disconnect(); + }, []); + + return ( +
+ {children} +
+ ); +} + +export default function PipelineSection() { + const [packetState, setPacketState] = useState<'allow' | 'block'>('allow'); + + useEffect(() => { + const interval = setInterval(() => { + setPacketState(prev => (prev === 'allow' ? 'block' : 'allow')); + }, 3000); // Toggle packet type every 3s to match the loop + return () => clearInterval(interval); + }, []); + + return ( +
+