Spaces:
Running
Running
| <!-- SILENTPATTERN FINAL BUILD: 2025-12-15 | pages: 10 | features: hash-deep-linking, lab-navigator, access-modal, form-validation, lab-file-interface --> | |
| <html lang="en"> | |
| <head> | |
| <meta charset="UTF-8" /> | |
| <meta name="viewport" content="width=device-width,initial-scale=1.0" /> | |
| <title>SILENTPATTERN — About</title> | |
| <!-- Tailwind --> | |
| <script src="https://cdn.tailwindcss.com"></script> | |
| <!-- Three.js + Vanta --> | |
| <script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"></script> | |
| <script src="https://cdn.jsdelivr.net/npm/vanta@latest/dist/vanta.net.min.js"></script> | |
| <!-- Icons + Font --> | |
| <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css"> | |
| <link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap"> | |
| <style> | |
| body { font-family: 'Inter', sans-serif; } | |
| .gradient-text { | |
| background: linear-gradient(90deg, #6366f1, #8b5cf6, #ec4899); | |
| -webkit-background-clip: text; | |
| background-clip: text; | |
| color: transparent; | |
| } | |
| .aura { | |
| background: | |
| radial-gradient(circle at 25% 20%, rgba(99,102,241,0.22), transparent 44%), | |
| radial-gradient(circle at 80% 75%, rgba(236,72,153,0.12), transparent 50%), | |
| radial-gradient(circle at 55% 45%, rgba(139,92,246,0.10), transparent 60%); | |
| } | |
| .focus-ring:focus { outline: none; box-shadow: 0 0 0 2px rgba(99,102,241,0.65); } | |
| .modal { transition: opacity 0.3s ease, transform 0.3s ease; } | |
| .modal-hidden { opacity: 0; transform: translateY(20px); pointer-events: none; } | |
| .modal-visible { opacity: 1; transform: translateY(0); } | |
| .thin-scroll { | |
| scrollbar-width: thin; | |
| scrollbar-color: #4f46e5 #1e1b4b; | |
| } | |
| .thin-scroll::-webkit-scrollbar { width: 6px; } | |
| .thin-scroll::-webkit-scrollbar-track { background: #1e1b4b; } | |
| .thin-scroll::-webkit-scrollbar-thumb { background-color: #4f46e5; border-radius: 3px; } | |
| .conscious-element { transition: all 0.28s ease; } | |
| .conscious-element:hover { transform: translateY(-2px); } | |
| /* Active states */ | |
| .lab-node.active { | |
| border-color: rgba(99,102,241,0.55) ; | |
| box-shadow: 0 0 0 1px rgba(99,102,241,0.22), 0 0 28px rgba(99,102,241,0.08); | |
| transform: translateY(-1px); | |
| } | |
| </style> | |
| </head> | |
| <body class="bg-black text-white overflow-x-hidden"> | |
| <!-- Animated background --> | |
| <div id="vanta-bg" class="fixed top-0 left-0 w-full h-full z-0"></div> | |
| <!-- Minimal top bar --> | |
| <nav class="relative z-10 py-6 px-8 flex justify-between items-center backdrop-blur-sm"> | |
| <a href="index.html" class="flex items-center space-x-2"> | |
| <div class="w-8 h-8 rounded-full bg-indigo-600 flex items-center justify-center"> | |
| <div class="w-2 h-2 rounded-full bg-white animate-pulse"></div> | |
| </div> | |
| <span class="text-xl font-semibold">SILENTPATTERN</span> | |
| </a> | |
| <div class="flex items-center space-x-3"> | |
| <button id="lab-nav-btn" | |
| class="w-10 h-10 rounded-full border border-indigo-500/40 bg-gray-900/20 hover:bg-gray-900/40 backdrop-blur-sm transition flex items-center justify-center focus-ring" | |
| aria-label="Open Lab Navigator" title="Lab Navigator"> | |
| <i class="fas fa-asterisk text-indigo-300 text-sm"></i> | |
| </button> | |
| <button id="access-btn" | |
| class="px-6 py-2 bg-gradient-to-r from-indigo-600 to-purple-600 rounded-full hover:opacity-90 transition focus-ring"> | |
| Access | |
| </button> | |
| </div> | |
| </nav> | |
| <!-- ABOUT: PRESENTED AS A LAB FILE --> | |
| <section class="relative z-10 px-6 pt-14 pb-16"> | |
| <div class="max-w-6xl mx-auto"> | |
| <div class="grid grid-cols-1 lg:grid-cols-5 gap-6"> | |
| <!-- LEFT: "File Header" + Mission --> | |
| <div class="lg:col-span-3 rounded-2xl border border-gray-800 bg-gray-900/20 overflow-hidden aura"> | |
| <div class="px-6 py-5 border-b border-gray-800/60 flex items-start justify-between gap-6"> | |
| <div> | |
| <div class="inline-flex items-center gap-3 px-4 py-2 rounded-full border border-gray-800 bg-gray-900/20 backdrop-blur-sm"> | |
| <span class="w-2 h-2 rounded-full bg-indigo-400 animate-pulse"></span> | |
| <span class="text-xs text-gray-300 tracking-widest uppercase">Lab File</span> | |
| <span class="text-xs text-gray-500">ABOUT.md</span> | |
| </div> | |
| <h1 class="mt-6 text-3xl md:text-6xl font-bold leading-tight"> | |
| <span class="gradient-text">SILENTPATTERN</span><br> | |
| An AI lab oriented toward general systems | |
| </h1> | |
| <p class="mt-4 text-gray-300 text-lg md:text-xl max-w-3xl"> | |
| SILENTPATTERN is built as a research interface, not a marketing site. We publish conservative claims, prioritize reproducibility, and scale capabilities only when evidence supports it. | |
| </p> | |
| </div> | |
| <div class="text-xs px-2.5 py-1 rounded-full border border-indigo-500/30 text-indigo-200 bg-indigo-900/15 self-start"> | |
| PUBLIC | |
| </div> | |
| </div> | |
| <div class="p-6 space-y-6"> | |
| <div class="rounded-2xl border border-gray-800 bg-black/20 p-5"> | |
| <div class="text-xs text-gray-400 uppercase tracking-wider mb-2">Mission</div> | |
| <div class="text-sm text-gray-300 leading-relaxed"> | |
| Advance toward AGI and, eventually, superintelligence by building systems that can reason, experiment, and improve—while preserving governance, auditability, and alignment constraints. The lab's identity is methodological: evidence first, iteration always. | |
| </div> | |
| </div> | |
| <div class="grid grid-cols-1 md:grid-cols-2 gap-4"> | |
| <div class="rounded-2xl border border-gray-800 bg-gray-900/30 p-5 conscious-element"> | |
| <div class="text-sm font-semibold text-gray-100">What "progress" means here</div> | |
| <div class="text-sm text-gray-300 mt-2"> | |
| Not hype. Measurable capability gains validated by protocols, baselines, and repeatability. | |
| </div> | |
| </div> | |
| <div class="rounded-2xl border border-gray-800 bg-gray-900/30 p-5 conscious-element"> | |
| <div class="text-sm font-semibold text-gray-100">What "prestige" means here</div> | |
| <div class="text-sm text-gray-300 mt-2"> | |
| Discipline: clean evaluations, honest uncertainty, and claims proportional to evidence. | |
| </div> | |
| </div> | |
| <div class="rounded-2xl border border-gray-800 bg-gray-900/30 p-5 conscious-element"> | |
| <div class="text-sm font-semibold text-gray-100">What the website is</div> | |
| <div class="text-sm text-gray-300 mt-2"> | |
| A lab console. Modules are dossiers. Navigation stays minimal to protect the interface aesthetic. | |
| </div> | |
| </div> | |
| <div class="rounded-2xl border border-gray-800 bg-gray-900/30 p-5 conscious-element"> | |
| <div class="text-sm font-semibold text-gray-100">What the website is not</div> | |
| <div class="text-sm text-gray-300 mt-2"> | |
| Not a claim factory. Not a generic SaaS landing page. Not a "busy top menu." | |
| </div> | |
| </div> | |
| </div> | |
| <div class="rounded-2xl border border-gray-800 bg-black/20 p-5"> | |
| <div class="text-xs text-gray-400 uppercase tracking-wider mb-2">Stance on AGI and Superintelligence</div> | |
| <div class="text-sm text-gray-300 leading-relaxed space-y-3"> | |
| <p> | |
| We treat AGI as an engineering and scientific frontier: general problem-solving, robust transfer, and the ability to build and validate hypotheses. Superintelligence is approached as a trajectory, not a marketing label. | |
| </p> | |
| <p class="text-gray-400"> | |
| Public statements remain conservative. Internally, the lab is oriented toward capability growth alongside governance: constraints, logs, human oversight where appropriate, and "fail-closed" behavior for agents. | |
| </p> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- RIGHT: "Evaluation Doctrine" panel --> | |
| <div class="lg:col-span-2 rounded-2xl border border-gray-800 bg-gray-900/30 overflow-hidden"> | |
| <div class="px-6 py-5 border-b border-gray-800/60"> | |
| <div class="text-lg font-semibold text-gray-100">Evaluation Doctrine</div> | |
| <div class="text-xs text-gray-500 mt-1">How SILENTPATTERN protects itself from its own ambitions.</div> | |
| </div> | |
| <div class="p-6 space-y-5 thin-scroll max-h-[840px] overflow-auto"> | |
| <div class="rounded-xl border border-gray-800 bg-black/20 p-4"> | |
| <div class="text-xs text-gray-400 uppercase tracking-wider mb-2">Rule 1: Protocol before Results</div> | |
| <div class="text-sm text-gray-300"> | |
| Define datasets, splits, baselines, and metrics first. If the protocol is weak, results do not count. | |
| </div> | |
| </div> | |
| <div class="rounded-xl border border-gray-800 bg-black/20 p-4"> | |
| <div class="text-xs text-gray-400 uppercase tracking-wider mb-2">Rule 2: Claims scale with Evidence</div> | |
| <div class="text-sm text-gray-300"> | |
| Public language remains bounded: "concept," "prototype," "validated," with explicit assumptions and limitations. | |
| </div> | |
| </div> | |
| <div class="rounded-xl border border-gray-800 bg-black/20 p-4"> | |
| <div class="text-xs text-gray-400 uppercase tracking-wider mb-2">Rule 3: Uncertainty is a first-class output</div> | |
| <div class="text-sm text-gray-300"> | |
| Calibration, confidence, and failure modes are included in reports; no "high accuracy" statements without replicated benchmarks. | |
| </div> | |
| </div> | |
| <div class="rounded-xl border border-gray-800 bg-black/20 p-4"> | |
| <div class="text-xs text-gray-400 uppercase tracking-wider mb-2">Rule 4: Agents are governed</div> | |
| <div class="text-sm text-gray-300"> | |
| "AI employees" are scoped by permissions, logged actions, approval gates, and verification layers. The system must fail closed. | |
| </div> | |
| </div> | |
| <div class="rounded-xl border border-gray-800 bg-black/20 p-4"> | |
| <div class="text-xs text-gray-400 uppercase tracking-wider mb-2">Rule 5: Reproducibility is a feature</div> | |
| <div class="text-sm text-gray-300"> | |
| Every result should be repeatable: same code, same seeds, same data lineage, same output checks. | |
| </div> | |
| </div> | |
| <div class="rounded-xl border border-gray-800 bg-black/20 p-4"> | |
| <div class="text-xs text-gray-400 uppercase tracking-wider mb-2">Public-facing positioning</div> | |
| <div class="text-sm text-gray-300"> | |
| Programs are introduced as dossiers with maturity levels and evidence capsules. The interface communicates seriousness without overpromising. | |
| </div> | |
| </div> | |
| <div class="flex flex-col gap-3"> | |
| <button id="open-programs" | |
| class="px-5 py-3 rounded-xl bg-gradient-to-r from-indigo-600 to-purple-600 hover:opacity-90 transition focus-ring"> | |
| Open Programs | |
| </button> | |
| <button id="open-console" | |
| class="px-5 py-3 rounded-xl border border-gray-700 bg-gray-900/20 hover:bg-gray-900/35 transition focus-ring"> | |
| Open Console | |
| </button> | |
| </div> | |
| <div class="text-xs text-gray-500"> | |
| Last updated: <span class="text-gray-300">—</span> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| </section> | |
| <!-- Minimal Footer --> | |
| <footer class="relative z-10 px-6 pb-10"> | |
| <div class="max-w-6xl mx-auto border-t border-gray-800/60 pt-8 flex flex-col md:flex-row justify-between items-center gap-4"> | |
| <div class="text-sm text-gray-500">© 2025 SILENTPATTERN. All rights reserved.</div> | |
| <div class="text-sm text-gray-500 flex gap-6"> | |
| <a href="research.html" class="hover:text-indigo-400 transition">Research</a> | |
| <a href="privacy.html" class="hover:text-indigo-400 transition">Privacy</a> | |
| <a href="terms.html" class="hover:text-indigo-400 transition">Terms</a> | |
| <a href="contact.html" class="hover:text-indigo-400 transition">Contact</a> | |
| </div> | |
| </div> | |
| </footer> | |
| <!-- ACCESS MODAL --> | |
| <div id="access-modal" | |
| class="fixed inset-0 z-50 flex items-center justify-center bg-black/80 backdrop-blur-sm modal modal-hidden" | |
| role="dialog" aria-modal="true" aria-labelledby="access-modal-title" tabindex="-1"> | |
| <div class="bg-gray-900/90 border border-gray-800 rounded-xl max-w-md w-full mx-4 relative overflow-hidden"> | |
| <div class="absolute inset-x-0 top-0 h-1 bg-gradient-to-r from-indigo-600 to-purple-600"></div> | |
| <div class="p-6"> | |
| <div class="flex justify-between items-start mb-6"> | |
| <div> | |
| <h3 class="text-xl font-bold" id="access-modal-title">Request Access</h3> | |
| <p class="text-gray-400 mt-1">Curated access for research and evaluation</p> | |
| </div> | |
| <button id="close-access-modal" class="text-gray-400 hover:text-white focus-ring" aria-label="Close"> | |
| <i class="fas fa-times"></i> | |
| </button> | |
| </div> | |
| <!-- Inline feedback --> | |
| <div id="access-feedback" | |
| class="hidden mb-4 rounded-lg border border-gray-800 bg-black/25 px-4 py-3 text-sm" | |
| role="status" aria-live="polite"></div> | |
| <form id="access-form" class="space-y-4" novalidate> | |
| <div> | |
| <label for="name" class="block text-sm font-medium mb-1">Full Name</label> | |
| <input type="text" id="name" class="w-full bg-gray-800/50 border border-gray-700 rounded-lg px-4 py-2 focus-ring" autocomplete="name"> | |
| <p id="name-error" class="hidden mt-1 text-xs text-red-300">Please enter your full name.</p> | |
| </div> | |
| <div> | |
| <label for="email" class="block text-sm font-medium mb-1">Email</label> | |
| <input type="email" id="email" class="w-full bg-gray-800/50 border border-gray-700 rounded-lg px-4 py-2 focus-ring" autocomplete="email"> | |
| <p id="email-error" class="hidden mt-1 text-xs text-red-300">Please enter a valid email address.</p> | |
| </div> | |
| <div> | |
| <label for="institution" class="block text-sm font-medium mb-1">Institution/Organization</label> | |
| <input type="text" id="institution" class="w-full bg-gray-800/50 border border-gray-700 rounded-lg px-4 py-2 focus-ring" autocomplete="organization"> | |
| <p id="institution-error" class="hidden mt-1 text-xs text-red-300">Please enter your institution/organization.</p> | |
| </div> | |
| <div> | |
| <label for="purpose" class="block text-sm font-medium mb-1">Purpose</label> | |
| <select id="purpose" class="w-full bg-gray-800/50 border border-gray-700 rounded-lg px-4 py-2 focus-ring"> | |
| <option value="">Select a purpose</option> | |
| <option value="research">Academic / Independent Research</option> | |
| <option value="development">Engineering / Product Evaluation</option> | |
| <option value="partnership">Partnership</option> | |
| <option value="other">Other</option> | |
| </select> | |
| <p id="purpose-error" class="hidden mt-1 text-xs text-red-300">Please select a purpose.</p> | |
| </div> | |
| <div class="pt-2"> | |
| <button type="submit" class="w-full py-3 bg-gradient-to-r from-indigo-600 to-purple-600 rounded-lg hover:opacity-90 transition focus-ring"> | |
| Submit Request | |
| </button> | |
| </div> | |
| </form> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- LAB NAVIGATOR --> | |
| <div id="lab-navigator" | |
| class="fixed inset-0 z-[60] bg-black/80 backdrop-blur-md modal modal-hidden" | |
| role="dialog" aria-modal="true" aria-label="Lab Navigator" tabindex="-1"> | |
| <div class="absolute inset-0" data-lab-close="true"></div> | |
| <div class="relative w-full h-full flex items-center justify-center p-6"> | |
| <div class="w-full max-w-6xl mx-auto grid grid-cols-1 lg:grid-cols-2 gap-6"> | |
| <div class="relative rounded-2xl border border-gray-800 bg-gray-900/20 overflow-hidden"> | |
| <div class="flex items-center justify-between px-5 py-4 border-b border-gray-800/60"> | |
| <div class="flex items-center space-x-3"> | |
| <div class="w-7 h-7 rounded-full bg-indigo-600 flex items-center justify-center"> | |
| <div class="w-1.5 h-1.5 rounded-full bg-white animate-pulse"></div> | |
| </div> | |
| <div> | |
| <div class="text-sm text-gray-300 tracking-wide">SILENTPATTERN</div> | |
| <div class="text-xs text-gray-500">Lab Navigator</div> | |
| </div> | |
| </div> | |
| <button id="lab-nav-close" | |
| class="w-9 h-9 rounded-full border border-gray-800 bg-gray-900/30 hover:bg-gray-900/50 transition flex items-center justify-center focus-ring" | |
| aria-label="Close Lab Navigator"> | |
| <i class="fas fa-times text-gray-300 text-sm"></i> | |
| </button> | |
| </div> | |
| <div class="relative p-6 min-h-[420px]"> | |
| <div class="absolute inset-0 opacity-70 pointer-events-none" | |
| style="background: radial-gradient(circle at 30% 20%, rgba(99,102,241,0.18), transparent 45%), | |
| radial-gradient(circle at 70% 70%, rgba(236,72,153,0.10), transparent 50%);"></div> | |
| <div class="relative grid grid-cols-1 sm:grid-cols-2 gap-3"> | |
| <button class="lab-node text-left rounded-xl border border-gray-800 bg-gray-900/30 hover:border-indigo-500/50 hover:bg-gray-900/45 transition p-4 focus-ring" | |
| data-dossier="start" aria-current="false"> | |
| <div class="text-sm text-gray-200 font-medium">Start Here</div> | |
| <div class="text-xs text-gray-500 mt-1">Entry interface</div> | |
| </button> | |
| <button class="lab-node text-left rounded-xl border border-gray-800 bg-gray-900/30 hover:border-indigo-500/50 hover:bg-gray-900/45 transition p-4 focus-ring" | |
| data-dossier="programs" aria-current="false"> | |
| <div class="text-sm text-gray-200 font-medium">Programs</div> | |
| <div class="text-xs text-gray-500 mt-1">Program Bay</div> | |
| </button> | |
| <button class="lab-node text-left rounded-xl border border-gray-800 bg-gray-900/30 hover:border-indigo-500/50 hover:bg-gray-900/45 transition p-4 focus-ring" | |
| data-dossier="console" aria-current="false"> | |
| <div class="text-sm text-gray-200 font-medium">Console</div> | |
| <div class="text-xs text-gray-500 mt-1">Controlled chat</div> | |
| </button> | |
| <button class="lab-node text-left rounded-xl border border-gray-800 bg-gray-900/30 hover:border-indigo-500/50 hover:bg-gray-900/45 transition p-4 focus-ring" | |
| data-dossier="research" aria-current="false"> | |
| <div class="text-sm text-gray-200 font-medium">Research</div> | |
| <div class="text-xs text-gray-500 mt-1">Notes and briefs</div> | |
| </button> | |
| <button class="lab-node text-left rounded-xl border border-gray-800 bg-gray-900/30 hover:border-indigo-500/50 hover:bg-gray-900/45 transition p-4 focus-ring sm:col-span-2" | |
| data-dossier="access" aria-current="false"> | |
| <div class="text-sm text-gray-200 font-medium">Access</div> | |
| <div class="text-xs text-gray-500 mt-1">Curated entry</div> | |
| </button> | |
| </div> | |
| <div class="relative mt-6 text-xs text-gray-500"> | |
| Tip: Press <span class="text-gray-300">Esc</span> to close. | |
| </div> | |
| </div> | |
| </div> | |
| <div class="relative rounded-2xl border border-gray-800 bg-gray-900/30 overflow-hidden"> | |
| <div class="px-6 py-5 border-b border-gray-800/60"> | |
| <div class="flex items-start justify-between gap-4"> | |
| <div> | |
| <div id="dossier-title" class="text-lg font-semibold text-gray-100">Lab Dossier</div> | |
| <div id="dossier-subtitle" class="text-xs text-gray-500 mt-1">Select a node to load details.</div> | |
| </div> | |
| <div id="dossier-status" | |
| class="text-xs px-2.5 py-1 rounded-full border border-indigo-500/30 text-indigo-200 bg-indigo-900/15"> | |
| READY | |
| </div> | |
| </div> | |
| </div> | |
| <div class="p-6 space-y-5 max-h-[560px] overflow-auto thin-scroll"> | |
| <div id="dossier-body" class="text-sm text-gray-300 leading-relaxed"> | |
| This interface reveals SILENTPATTERN as a set of research programs and operational systems. | |
| The public layer is minimal by design; depth is opened intentionally. | |
| </div> | |
| <div class="rounded-xl border border-gray-800 bg-black/20 p-4"> | |
| <div class="text-xs text-gray-400 uppercase tracking-wider mb-2">Evidence Capsule</div> | |
| <ul id="dossier-evidence" class="text-sm text-gray-300 space-y-1"> | |
| <li class="text-gray-500">No dossier selected.</li> | |
| </ul> | |
| </div> | |
| <div class="flex flex-col sm:flex-row gap-3"> | |
| <button id="dossier-primary" | |
| class="flex-1 px-5 py-3 rounded-xl bg-gradient-to-r from-indigo-600 to-purple-600 hover:opacity-90 transition focus-ring"> | |
| Open | |
| </button> | |
| <button id="dossier-secondary" | |
| class="flex-1 px-5 py-3 rounded-xl border border-gray-700 bg-gray-900/20 hover:bg-gray-900/35 transition focus-ring"> | |
| View Note | |
| </button> | |
| </div> | |
| <div id="dossier-meta" class="text-xs text-gray-500"> | |
| Last updated: <span class="text-gray-300">—</span> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <script> | |
| // Site-wide configuration | |
| const CONFIG = { | |
| MODAL_HASHES: new Set(['lab', 'access']) | |
| }; | |
| /* ------------------------------------------------------------- | |
| UTILITY FUNCTIONS (consistent with other pages) | |
| ------------------------------------------------------------- */ | |
| function escapeHtml(str) { | |
| return String(str) | |
| .replaceAll('&', '&') | |
| .replaceAll('<', '<') | |
| .replaceAll('>', '>') | |
| .replaceAll('"', '"') | |
| .replaceAll("'", '''); | |
| } | |
| function isValidEmail(email) { | |
| return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email); | |
| } | |
| function currentHashKey() { | |
| const h = (window.location.hash || '').replace('#', '').trim(); | |
| return h; | |
| } | |
| function setHash(key, replace = false) { | |
| if (!key) return; | |
| if (window.location.hash.replace('#', '') === key) return; | |
| if (replace) { | |
| history.replaceState(null, '', '#' + key); | |
| } else { | |
| history.pushState(null, '', '#' + key); | |
| } | |
| } | |
| function clearHashIf(key) { | |
| const h = currentHashKey(); | |
| if (!h) return; | |
| if (!key || h === key) { | |
| history.replaceState(null, '', window.location.pathname + window.location.search); | |
| } | |
| } | |
| /* ------------------------------------------------------------- | |
| MODAL HELPERS (consistent with other pages) | |
| ------------------------------------------------------------- */ | |
| function trapFocus(modal) { | |
| const focusable = modal.querySelectorAll('a, button, input, select, textarea, [tabindex]:not([tabindex="-1"])'); | |
| if (!focusable.length) return; | |
| const first = focusable[0]; | |
| const last = focusable[focusable.length - 1]; | |
| function handler(e) { | |
| if (e.key === 'Tab') { | |
| if (e.shiftKey) { | |
| if (document.activeElement === first) { e.preventDefault(); last.focus(); } | |
| } else { | |
| if (document.activeElement === last) { e.preventDefault(); first.focus(); } | |
| } | |
| } | |
| } | |
| modal.addEventListener('keydown', handler); | |
| modal._focusHandler = handler; | |
| } | |
| function untrapFocus(modal) { | |
| if (modal._focusHandler) { | |
| modal.removeEventListener('keydown', modal._focusHandler); | |
| delete modal._focusHandler; | |
| } | |
| } | |
| const toggleModal = (modal, show) => { | |
| if (show) { | |
| modal.classList.remove('modal-hidden'); | |
| modal.classList.add('modal-visible'); | |
| document.body.style.overflow = 'hidden'; | |
| setTimeout(() => { modal.focus(); trapFocus(modal); }, 0); | |
| } else { | |
| modal.classList.remove('modal-visible'); | |
| modal.classList.add('modal-hidden'); | |
| document.body.style.overflow = ''; | |
| untrapFocus(modal); | |
| } | |
| }; | |
| /* ------------------------------------------------------------- | |
| VANTA BACKGROUND | |
| ------------------------------------------------------------- */ | |
| let vantaEffect = null; | |
| try { | |
| if (window.VANTA && typeof VANTA.NET === 'function') { | |
| vantaEffect = VANTA.NET({ | |
| el: "#vanta-bg", | |
| mouseControls: true, | |
| touchControls: true, | |
| gyroControls: false, | |
| minHeight: 200.00, | |
| minWidth: 200.00, | |
| scale: 1.00, | |
| scaleMobile: 1.00, | |
| color: 0x4f46e5, | |
| backgroundColor: 0x020617, | |
| points: 12.00, | |
| maxDistance: 20.00, | |
| spacing: 15.00 | |
| }); | |
| } | |
| } catch (e) { | |
| console.warn('Vanta background failed to initialize:', e); | |
| vantaEffect = null; | |
| } | |
| window.addEventListener('resize', () => { | |
| if (vantaEffect && typeof vantaEffect.resize === 'function') { | |
| vantaEffect.resize(); | |
| } | |
| }); | |
| /* ------------------------------------------------------------- | |
| ACCESS MODAL | |
| ------------------------------------------------------------- */ | |
| const accessModal = document.getElementById('access-modal'); | |
| const accessBtn = document.getElementById('access-btn'); | |
| const closeAccessModal = document.getElementById('close-access-modal'); | |
| const accessForm = document.getElementById('access-form'); | |
| const accessFeedback = document.getElementById('access-feedback'); | |
| const nameEl = document.getElementById('name'); | |
| const emailEl = document.getElementById('email'); | |
| const institutionEl = document.getElementById('institution'); | |
| const purposeEl = document.getElementById('purpose'); | |
| const nameErr = document.getElementById('name-error'); | |
| const emailErr = document.getElementById('email-error'); | |
| const institutionErr = document.getElementById('institution-error'); | |
| const purposeErr = document.getElementById('purpose-error'); | |
| function setAccessFeedback(kind, text) { | |
| if (!accessFeedback) return; | |
| accessFeedback.classList.remove('hidden'); | |
| accessFeedback.classList.remove('border-red-500/30', 'bg-red-900/10', 'text-red-200'); | |
| accessFeedback.classList.remove('border-emerald-500/30', 'bg-emerald-900/10', 'text-emerald-200'); | |
| accessFeedback.classList.remove('border-indigo-500/30', 'bg-indigo-900/10', 'text-indigo-200'); | |
| if (kind === 'error') { | |
| accessFeedback.classList.add('border-red-500/30', 'bg-red-900/10', 'text-red-200'); | |
| } else if (kind === 'success') { | |
| accessFeedback.classList.add('border-emerald-500/30', 'bg-emerald-900/10', 'text-emerald-200'); | |
| } else { | |
| accessFeedback.classList.add('border-indigo-500/30', 'bg-indigo-900/10', 'text-indigo-200'); | |
| } | |
| accessFeedback.textContent = text; | |
| } | |
| function hideAccessFeedback() { | |
| if (!accessFeedback) return; | |
| accessFeedback.textContent = ''; | |
| accessFeedback.classList.add('hidden'); | |
| accessFeedback.classList.remove( | |
| 'border-red-500/30','bg-red-900/10','text-red-200', | |
| 'border-emerald-500/30','bg-emerald-900/10','text-emerald-200', | |
| 'border-indigo-500/30','bg-indigo-900/10','text-indigo-200' | |
| ); | |
| } | |
| function setFieldError(inputEl, errorEl, isError) { | |
| if (!inputEl || !errorEl) return; | |
| if (isError) { | |
| errorEl.classList.remove('hidden'); | |
| inputEl.setAttribute('aria-invalid', 'true'); | |
| inputEl.classList.add('border-red-500/60'); | |
| } else { | |
| errorEl.classList.add('hidden'); | |
| inputEl.removeAttribute('aria-invalid'); | |
| inputEl.classList.remove('border-red-500/60'); | |
| } | |
| } | |
| function resetAccessErrors() { | |
| hideAccessFeedback(); | |
| setFieldError(nameEl, nameErr, false); | |
| setFieldError(emailEl, emailErr, false); | |
| setFieldError(institutionEl, institutionErr, false); | |
| setFieldError(purposeEl, purposeErr, false); | |
| } | |
| function openAccessModal(setHashFlag = true) { | |
| resetAccessErrors(); | |
| toggleModal(accessModal, true); | |
| if (setHashFlag) setHash('access'); | |
| setTimeout(() => nameEl && nameEl.focus(), 80); | |
| } | |
| function closeAccessModal(clearHashFlag = true) { | |
| toggleModal(accessModal, false); | |
| if (clearHashFlag) clearHashIf('access'); | |
| } | |
| accessBtn.addEventListener('click', () => openAccessModal(true)); | |
| if (closeAccessModal) closeAccessModal.addEventListener('click', () => closeAccessModal(true)); | |
| if (accessModal) { | |
| accessModal.addEventListener('click', (e) => { | |
| if (e.target === accessModal) closeAccessModal(true); | |
| }); | |
| } | |
| if (accessForm) { | |
| // Clear per-field errors on input | |
| [nameEl, emailEl, institutionEl, purposeEl].forEach(el => { | |
| if (!el) return; | |
| el.addEventListener('input', () => { | |
| if (el === nameEl) setFieldError(nameEl, nameErr, !nameEl.value.trim()); | |
| if (el === emailEl) setFieldError(emailEl, emailErr, !isValidEmail(emailEl.value.trim())); | |
| if (el === institutionEl) setFieldError(institutionEl, institutionErr, !institutionEl.value.trim()); | |
| if (el === purposeEl) setFieldError(purposeEl, purposeErr, !purposeEl.value); | |
| }); | |
| el.addEventListener('change', () => el.dispatchEvent(new Event('input'))); | |
| }); | |
| accessForm.addEventListener('submit', (e) => { | |
| e.preventDefault(); | |
| resetAccessErrors(); | |
| const name = (nameEl?.value || '').trim(); | |
| const email = (emailEl?.value || '').trim(); | |
| const institution = (institutionEl?.value || '').trim(); | |
| const purpose = (purposeEl?.value || '').trim(); | |
| let ok = true; | |
| if (!name) { setFieldError(nameEl, nameErr, true); ok = false; } | |
| if (!email || !isValidEmail(email)) { setFieldError(emailEl, emailErr, true); ok = false; } | |
| if (!institution) { setFieldError(institutionEl, institutionErr, true); ok = false; } | |
| if (!purpose) { setFieldError(purposeEl, purposeErr, true); ok = false; } | |
| if (!ok) { | |
| setAccessFeedback('error', 'Please correct the highlighted fields and resubmit.'); | |
| return; | |
| } | |
| setAccessFeedback('success', 'Request received. You will be contacted after review.'); | |
| accessForm.reset(); | |
| }); | |
| } | |
| /* ------------------------------------------------------------- | |
| LAB NAVIGATOR | |
| ------------------------------------------------------------- */ | |
| const labNav = document.getElementById('lab-navigator'); | |
| const labNavBtn = document.getElementById('lab-nav-btn'); | |
| const labNavClose = document.getElementById('lab-nav-close'); | |
| const DOSSIERS = { | |
| start: { | |
| title: "Start Here", | |
| subtitle: "Entry interface", | |
| status: "ACTIVE", | |
| body: "Return to the main interface.", | |
| evidence: ["Public entry layer", "Programs as dossiers", "Console for controlled interaction"], | |
| primary: { label: "Go to Index", action: () => { window.location.href = "index.html"; } }, | |
| secondary: { label: "Programs", action: () => { window.location.href = "capabilities.html"; } }, | |
| updated: "—" | |
| }, | |
| programs: { | |
| title: "Programs", | |
| subtitle: "Program Bay", | |
| status: "ACTIVE", | |
| body: "Program Bay: MCAP, CHAI, Quantum Lambda, AI Scientist, Agentic Workforce.", | |
| evidence: ["Dossiers with maturity levels", "Evidence capsules", "Access gates"], | |
| primary: { label: "Open Programs", action: () => { window.location.href = "capabilities.html"; } }, | |
| secondary: { label: "Console", action: () => { window.location.href = "chat.html"; } }, | |
| updated: "—" | |
| }, | |
| console: { | |
| title: "Console", | |
| subtitle: "Controlled chat", | |
| status: "DRAFT", | |
| body: "Controlled chat with exportable transcripts. Model access must remain server-side.", | |
| evidence: ["No client-side secrets", "Audit-ready transcripts", "Fail-closed behaviors"], | |
| primary: { label: "Open Console", action: () => { window.location.href = "chat.html"; } }, | |
| secondary: { label: "Research", action: () => { window.location.href = "research.html"; } }, | |
| updated: "—" | |
| }, | |
| research: { | |
| title: "Research", | |
| subtitle: "Notes and briefs", | |
| status: "DRAFT", | |
| body: "Technical notes, evaluation methodology, and changelogs.", | |
| evidence: ["Evaluation philosophy", "Benchmarks + baselines", "Limitations and failure modes"], | |
| primary: { label: "Open Research", action: () => { window.location.href = "research.html"; } }, | |
| secondary: { label: "Contact", action: () => { window.location.href = "contact.html"; } }, | |
| updated: "—" | |
| }, | |
| access: { | |
| title: "Access", | |
| subtitle: "Curated entry", | |
| status: "ACTIVE", | |
| body: "Request access for controlled demos and evaluation workflows.", | |
| evidence: ["Application-based", "Segmented by intent", "Controlled demos"], | |
| primary: { label: "Request Access", action: () => { closeLabNav(true); openAccessModal(true); } }, | |
| secondary: { label: "Contact", action: () => { window.location.href = "contact.html"; } }, | |
| updated: "—" | |
| } | |
| }; | |
| const dossierTitle = document.getElementById('dossier-title'); | |
| const dossierSubtitle = document.getElementById('dossier-subtitle'); | |
| const dossierStatus = document.getElementById('dossier-status'); | |
| const dossierBody = document.getElementById('dossier-body'); | |
| const dossierEvidence = document.getElementById('dossier-evidence'); | |
| const dossierPrimary = document.getElementById('dossier-primary'); | |
| const dossierSecondary = document.getElementById('dossier-secondary'); | |
| const dossierMeta = document.getElementById('dossier-meta'); | |
| function setActiveLabNode(key) { | |
| document.querySelectorAll('.lab-node').forEach(btn => { | |
| const isActive = btn.getAttribute('data-dossier') === key; | |
| btn.classList.toggle('active', isActive); | |
| btn.setAttribute('aria-current', isActive ? 'true' : 'false'); | |
| }); | |
| } | |
| function renderDossier(key) { | |
| const d = DOSSIERS[key]; | |
| if (!d) return; | |
| setActiveLabNode(key); | |
| dossierTitle.textContent = d.title; | |
| dossierSubtitle.textContent = d.subtitle; | |
| dossierStatus.textContent = d.status; | |
| dossierBody.textContent = d.body; | |
| dossierEvidence.innerHTML = ""; | |
| d.evidence.forEach(item => { | |
| const li = document.createElement('li'); | |
| li.textContent = item; | |
| dossierEvidence.appendChild(li); | |
| }); | |
| dossierPrimary.textContent = d.primary.label; | |
| dossierPrimary.onclick = d.primary.action; | |
| dossierSecondary.textContent = d.secondary.label; | |
| dossierSecondary.onclick = d.secondary.action; | |
| dossierMeta.innerHTML = `Last updated: <span class="text-gray-300">${d.updated}</span>`; | |
| } | |
| function openLabNav(setHashFlag = true) { | |
| toggleModal(labNav, true); | |
| if (setHashFlag) setHash('lab'); | |
| setTimeout(() => labNav.focus(), 0); | |
| // Ensure a stable default selection when opened | |
| const alreadyActive = document.querySelector('.lab-node.active'); | |
| if (!alreadyActive) renderDossier('start'); | |
| } | |
| function closeLabNav(clearHashFlag = true) { | |
| toggleModal(labNav, false); | |
| if (clearHashFlag) clearHashIf('lab'); | |
| } | |
| labNavBtn.addEventListener('click', () => openLabNav(true)); | |
| labNavClose.addEventListener('click', () => closeLabNav(true)); | |
| labNav.addEventListener('click', (e) => { | |
| const shouldClose = e.target && e.target.getAttribute('data-lab-close') === 'true'; | |
| if (shouldClose) closeLabNav(true); | |
| }); | |
| document.querySelectorAll('.lab-node').forEach(btn => { | |
| btn.addEventListener('click', () => { | |
| const key = btn.getAttribute('data-dossier'); | |
| renderDossier(key); | |
| // Apply navigation actions | |
| if (key === 'start') window.location.href = "index.html"; | |
| if (key === 'programs') window.location.href = "capabilities.html"; | |
| if (key === 'console') window.location.href = "chat.html"; | |
| if (key === 'research') window.location.href = "research.html"; | |
| if (key === 'access') { closeLabNav(true); openAccessModal(true); } | |
| }); | |
| }); | |
| /* ------------------------------------------------------------- | |
| QUICK LINKS | |
| ------------------------------------------------------------- */ | |
| document.getElementById('open-programs').addEventListener('click', () => { | |
| window.location.href = "capabilities.html"; | |
| }); | |
| document.getElementById('open-console').addEventListener('click', () => { | |
| window.location.href = "chat.html"; | |
| }); | |
| /* ------------------------------------------------------------- | |
| HASH ROUTER: handle modal hashes | |
| ------------------------------------------------------------- */ | |
| function applyHashState() { | |
| const key = currentHashKey(); | |
| if (CONFIG.MODAL_HASHES.has(key)) { | |
| if (key === 'lab') openLabNav(false); | |
| if (key === 'access') openAccessModal(false); | |
| } | |
| } | |
| window.addEventListener('hashchange', applyHashState); | |
| applyHashState(); // Initial load | |
| /* ------------------------------------------------------------- | |
| GLOBAL ESC BEHAVIOR | |
| ------------------------------------------------------------- */ | |
| document.addEventListener('keydown', (e) => { | |
| if (e.key === 'Escape') { | |
| if (labNav && !labNav.classList.contains('modal-hidden')) closeLabNav(true); | |
| if (accessModal && !accessModal.classList.contains('modal-hidden')) closeAccessModal(true); | |
| } | |
| }); | |
| // Initial dossier render | |
| renderDossier('start'); | |
| </script> | |
| </body> | |
| </html> |