Created
November 19, 2025 14:51
-
-
Save danialhasan/5f4445fc65be133f9ad53f64e2fa55d3 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <!DOCTYPE html> | |
| <html lang="en"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| <title>SQUAD v1.1.0 | Agent Orchestration</title> | |
| <script src="https://cdn.tailwindcss.com"></script> | |
| <link href="https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@300;400;500;700&family=Inter:wght@300;400;500;600&display=swap" rel="stylesheet"> | |
| <script> | |
| tailwind.config = { | |
| theme: { | |
| extend: { | |
| colors: { | |
| bg: { dark: '#09090b', panel: '#18181b', card: '#121215' }, | |
| border: '#27272a', | |
| accent: { | |
| primary: '#06b6d4', // Cyan | |
| success: '#10b981', // Emerald | |
| warning: '#f59e0b', // Amber | |
| danger: '#ef4444', // Red | |
| } | |
| }, | |
| fontFamily: { | |
| sans: ['Inter', 'sans-serif'], | |
| mono: ['JetBrains Mono', 'monospace'], | |
| }, | |
| animation: { | |
| 'pulse-fast': 'pulse 1.5s cubic-bezier(0.4, 0, 0.6, 1) infinite', | |
| 'scan': 'scan 8s linear infinite', | |
| }, | |
| keyframes: { | |
| scan: { | |
| '0%': { top: '0%', opacity: '0' }, | |
| '10%': { opacity: '1' }, | |
| '90%': { opacity: '1' }, | |
| '100%': { top: '100%', opacity: '0' }, | |
| } | |
| } | |
| } | |
| } | |
| } | |
| </script> | |
| <style> | |
| /* Custom Scrollbar */ | |
| ::-webkit-scrollbar { width: 6px; height: 6px; } | |
| ::-webkit-scrollbar-track { background: #09090b; } | |
| ::-webkit-scrollbar-thumb { background: #3f3f46; border-radius: 3px; } | |
| ::-webkit-scrollbar-thumb:hover { background: #52525b; } | |
| /* Scanline Effect */ | |
| .scan-line { | |
| width: 100%; height: 100px; | |
| background: linear-gradient(to bottom, transparent, rgba(6, 182, 212, 0.03), transparent); | |
| position: absolute; top: 0; left: 0; | |
| pointer-events: none; z-index: 50; | |
| animation: scan 8s linear infinite; | |
| } | |
| /* Utilities */ | |
| .nav-btn.active { @apply text-white bg-zinc-800 border-l-2 border-cyan-500; } | |
| .nav-btn.active svg { @apply text-cyan-500; } | |
| /* Swimlane Bars */ | |
| .bar-planning { background: repeating-linear-gradient(45deg, #3f3f46, #3f3f46 10px, #27272a 10px, #27272a 20px); } | |
| </style> | |
| </head> | |
| <body class="h-screen flex flex-col overflow-hidden bg-bg-dark text-zinc-300 font-sans text-sm selection:bg-cyan-900 selection:text-cyan-100"> | |
| <!-- TOP HEADER --> | |
| <header class="h-12 bg-[#0f0f12] border-b border-border flex items-center justify-between px-4 z-20 shrink-0 select-none"> | |
| <div class="flex items-center space-x-4"> | |
| <div class="flex items-center space-x-2 group cursor-pointer"> | |
| <div class="w-8 h-8 bg-cyan-500/10 rounded border border-cyan-500/30 flex items-center justify-center group-hover:border-cyan-500/60 transition-colors"> | |
| <svg class="w-5 h-5 text-cyan-500" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 11H5m14 0a2 2 0 012 2v6a2 2 0 01-2 2H5a2 2 0 01-2-2v-6a2 2 0 012-2m14 0V9a2 2 0 00-2-2M5 11V9a2 2 0 012-2m0 0V5a2 2 0 012-2h6a2 2 0 012 2v2M7 7h10"></path></svg> | |
| </div> | |
| <div> | |
| <h1 class="font-mono font-bold text-white tracking-tight leading-none">SQUAD <span class="text-[10px] text-zinc-500 font-normal ml-1">v1.1.0</span></h1> | |
| <div class="text-[10px] text-zinc-500 font-mono">ORCHESTRATION_LAYER</div> | |
| </div> | |
| </div> | |
| <div class="h-6 w-px bg-zinc-800"></div> | |
| <div class="flex items-center space-x-2 text-zinc-400 hover:text-white cursor-pointer transition-colors group"> | |
| <span class="font-medium text-zinc-300">HasanLabs</span> | |
| <span class="text-zinc-600">/</span> | |
| <span class="font-medium text-cyan-400 group-hover:underline decoration-cyan-500/30 underline-offset-4">CarGO Health</span> | |
| <svg class="w-3 h-3 text-zinc-600" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7"></path></svg> | |
| </div> | |
| </div> | |
| <div class="flex items-center space-x-6 font-mono text-xs"> | |
| <div class="flex items-center space-x-2" title="Meta-MCP System Status"> | |
| <span class="w-1.5 h-1.5 rounded-full bg-emerald-500 animate-pulse"></span> | |
| <span class="text-zinc-400">Meta-MCP: <span class="text-emerald-400">Online</span></span> | |
| </div> | |
| <div class="flex items-center space-x-2"> | |
| <span class="text-zinc-400">Harness: <span class="text-purple-400">Claude 3.5 (Pro)</span></span> | |
| </div> | |
| <div class="flex items-center space-x-2 px-3 py-1.5 bg-zinc-900 border border-zinc-800 rounded hover:border-cyan-500/30 transition-colors cursor-help"> | |
| <svg class="w-3 h-3 text-cyan-500" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 10V3L4 14h7v7l9-11h-7z"></path></svg> | |
| <span class="text-zinc-300"><span id="token-counter" class="text-white font-bold">145,202</span> / 200k</span> | |
| </div> | |
| </div> | |
| </header> | |
| <div class="flex-1 flex overflow-hidden relative"> | |
| <!-- SIDEBAR NAVIGATION --> | |
| <nav class="w-16 bg-[#0f0f12] border-r border-border flex flex-col items-center py-4 gap-4 z-20 shrink-0"> | |
| <button onclick="switchView('dashboard')" id="btn-dashboard" class="nav-btn active w-10 h-10 rounded-lg flex items-center justify-center text-zinc-400 hover:bg-zinc-800 hover:text-white transition-all group relative"> | |
| <svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 6a2 2 0 012-2h2a2 2 0 012 2v2a2 2 0 01-2 2H6a2 2 0 01-2-2V6zM14 6a2 2 0 012-2h2a2 2 0 012 2v2a2 2 0 01-2 2h-2a2 2 0 01-2-2V6zM4 16a2 2 0 012-2h2a2 2 0 012 2v2a2 2 0 01-2 2H6a2 2 0 01-2-2v-2zM14 16a2 2 0 012-2h2a2 2 0 012 2v2a2 2 0 01-2 2h-2a2 2 0 01-2-2v-2z"></path></svg> | |
| <span class="absolute left-12 bg-zinc-800 text-white text-xs px-2 py-1 rounded opacity-0 group-hover:opacity-100 transition-opacity whitespace-nowrap border border-zinc-700 z-50 pointer-events-none">Overview</span> | |
| </button> | |
| <button onclick="switchView('console')" id="btn-console" class="nav-btn w-10 h-10 rounded-lg flex items-center justify-center text-zinc-400 hover:bg-zinc-800 hover:text-white transition-all group relative"> | |
| <svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 9l3 3-3 3m5 0h3M5 20h14a2 2 0 002-2V6a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 002 2z"></path></svg> | |
| <span class="absolute left-12 bg-zinc-800 text-white text-xs px-2 py-1 rounded opacity-0 group-hover:opacity-100 transition-opacity whitespace-nowrap border border-zinc-700 z-50 pointer-events-none">Director Console</span> | |
| </button> | |
| <button onclick="switchView('squad-ops')" id="btn-squad-ops" class="nav-btn w-10 h-10 rounded-lg flex items-center justify-center text-zinc-400 hover:bg-zinc-800 hover:text-white transition-all group relative"> | |
| <svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 19v-6a2 2 0 00-2-2H5a2 2 0 00-2 2v6a2 2 0 002 2h2a2 2 0 002-2zm0 0V9a2 2 0 012-2h2a2 2 0 012 2v10m-6 0a2 2 0 002 2h2a2 2 0 002-2m0 0V5a2 2 0 012-2h2a2 2 0 012 2v14a2 2 0 01-2 2h-2a2 2 0 01-2-2z"></path></svg> | |
| <span class="absolute left-12 bg-zinc-800 text-white text-xs px-2 py-1 rounded opacity-0 group-hover:opacity-100 transition-opacity whitespace-nowrap border border-zinc-700 z-50 pointer-events-none">Squad Ops</span> | |
| </button> | |
| <button onclick="switchView('psm')" id="btn-psm" class="nav-btn w-10 h-10 rounded-lg flex items-center justify-center text-zinc-400 hover:bg-zinc-800 hover:text-white transition-all group relative"> | |
| <svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 10h18M3 14h18m-9-4v8m-7 0h14a2 2 0 002-2V8a2 2 0 00-2-2H5a2 2 0 00-2 2v8a2 2 0 002 2z"></path></svg> | |
| <span class="absolute left-12 bg-zinc-800 text-white text-xs px-2 py-1 rounded opacity-0 group-hover:opacity-100 transition-opacity whitespace-nowrap border border-zinc-700 z-50 pointer-events-none">Product Map</span> | |
| </button> | |
| <button onclick="switchView('bridge')" id="btn-bridge" class="nav-btn w-10 h-10 rounded-lg flex items-center justify-center text-zinc-400 hover:bg-zinc-800 hover:text-white transition-all group relative"> | |
| <svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M17 8h2a2 2 0 012 2v6a2 2 0 01-2 2h-2v4l-4-4H9a1.994 1.994 0 01-1.414-.586m0 0L11 14h4a2 2 0 002-2V6a2 2 0 00-2-2H5a2 2 0 00-2 2v6a2 2 0 002 2h2v4l.586-.586z"></path></svg> | |
| <span class="absolute left-12 bg-zinc-800 text-white text-xs px-2 py-1 rounded opacity-0 group-hover:opacity-100 transition-opacity whitespace-nowrap border border-zinc-700 z-50 pointer-events-none">Bridge</span> | |
| </button> | |
| <div class="mt-auto mb-4"> | |
| <div class="w-10 h-10 rounded-full bg-gradient-to-br from-cyan-600 to-blue-700 border border-white/10 flex items-center justify-center text-white font-bold text-xs shadow-lg shadow-cyan-900/20"> | |
| HL | |
| </div> | |
| </div> | |
| </nav> | |
| <!-- MAIN CONTENT STAGE --> | |
| <main id="main-container" class="flex-1 overflow-y-auto relative scroll-smooth"> | |
| <div class="scan-line"></div> | |
| <!-- VIEW: DASHBOARD --> | |
| <div id="view-dashboard" class="view-section p-6 max-w-[1600px] mx-auto space-y-6 animate-fade-in block"> | |
| <!-- Morning Report --> | |
| <div class="bg-bg-panel border border-border rounded-lg p-5 relative overflow-hidden shadow-sm"> | |
| <div class="absolute top-0 left-0 w-1 h-full bg-cyan-500"></div> | |
| <h2 class="text-lg font-medium text-white mb-1 flex items-center font-mono"> | |
| <svg class="w-5 h-5 mr-2 text-cyan-500" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 6v6m0 0v6m0-6h6m-6 0H6"></path></svg> | |
| Director's Morning Report | |
| </h2> | |
| <p class="text-zinc-500 mb-4 text-xs font-mono">SESSION_ID: 8F3A-29B1 • 09:15 AM EST</p> | |
| <div class="font-mono text-sm text-zinc-300 leading-loose bg-black/40 p-4 rounded border border-zinc-800/50 shadow-inner"> | |
| > <span class="text-cyan-400 font-bold">STATUS:</span> 3 Squads active. Total daily burn $4.20.<br> | |
| > <span class="text-accent-warning font-bold">ALERT:</span> Billing-Squad blocked on Stripe API verification. Engagement dropping (Recovering).<br> | |
| > <span class="text-accent-success font-bold">READY:</span> Auth-Squad has requested FIRE review for "JWT Refactor".<br> | |
| > <span class="text-zinc-500">ACTION:</span> 12 new receipts generated overnight. 2 pending RCX threads. | |
| </div> | |
| </div> | |
| <!-- Dashboard Grid --> | |
| <div class="grid grid-cols-12 gap-6"> | |
| <!-- Active Squads (Left 8) --> | |
| <div class="col-span-12 lg:col-span-8 space-y-4"> | |
| <div class="flex items-center justify-between"> | |
| <h3 class="text-zinc-500 text-xs font-bold uppercase tracking-wider font-mono">Active Squads</h3> | |
| <button class="text-cyan-500 text-xs hover:text-cyan-400 font-mono flex items-center">+ NEW_SQUAD</button> | |
| </div> | |
| <!-- Squad Card: FIRE GATE --> | |
| <div class="bg-bg-card border border-emerald-500/30 rounded-lg p-5 hover:border-emerald-500/60 transition-colors group relative shadow-lg shadow-emerald-900/5"> | |
| <div class="absolute top-4 right-4"> | |
| <span class="px-2 py-1 rounded bg-emerald-500/10 text-emerald-400 text-[10px] font-mono border border-emerald-500/20 animate-pulse tracking-wide">FIRE GATE: READY</span> | |
| </div> | |
| <div class="flex items-start justify-between mb-4"> | |
| <div> | |
| <h4 class="text-white font-medium text-lg group-hover:text-emerald-400 transition-colors">Auth Refactor</h4> | |
| <p class="text-zinc-500 text-xs mt-1 font-mono">ID: SQD-AUTH-001 • Age: 3d 4h</p> | |
| </div> | |
| </div> | |
| <div class="grid grid-cols-3 gap-4 mb-5"> | |
| <div class="bg-black/20 p-3 rounded border border-zinc-800"> | |
| <div class="text-[10px] text-zinc-500 mb-1 font-mono uppercase">Staffing</div> | |
| <div class="flex -space-x-2"> | |
| <div class="w-7 h-7 rounded-full bg-purple-900/80 border border-zinc-800 flex items-center justify-center text-[10px] text-purple-200 font-bold z-30" title="Director">D</div> | |
| <div class="w-7 h-7 rounded-full bg-blue-900/80 border border-zinc-800 flex items-center justify-center text-[10px] text-blue-200 font-bold z-20" title="Manager">M</div> | |
| <div class="w-7 h-7 rounded-full bg-zinc-800 border border-zinc-700 flex items-center justify-center text-[10px] font-mono z-10">E1</div> | |
| <div class="w-7 h-7 rounded-full bg-zinc-800 border border-zinc-700 flex items-center justify-center text-[10px] font-mono z-0">E2</div> | |
| </div> | |
| </div> | |
| <div class="bg-black/20 p-3 rounded border border-zinc-800"> | |
| <div class="text-[10px] text-zinc-500 mb-1 font-mono uppercase">Tests</div> | |
| <div class="text-emerald-400 font-mono text-sm font-bold">142/142 PASS</div> | |
| </div> | |
| <div class="bg-black/20 p-3 rounded border border-zinc-800"> | |
| <div class="text-[10px] text-zinc-500 mb-1 font-mono uppercase">Cost Today</div> | |
| <div class="text-zinc-300 font-mono text-sm">$1.25</div> | |
| </div> | |
| </div> | |
| <div class="flex gap-3"> | |
| <button onclick="openFireGate()" class="flex-1 bg-emerald-600/90 hover:bg-emerald-500 text-white py-2 rounded text-xs font-bold uppercase tracking-wide transition-all hover:shadow-lg hover:shadow-emerald-900/40 border border-transparent hover:border-emerald-400/50"> | |
| Review Gate & Deploy | |
| </button> | |
| <button class="px-4 py-2 bg-zinc-800 hover:bg-zinc-700 text-zinc-300 rounded text-xs font-mono border border-zinc-700">LOGS</button> | |
| </div> | |
| </div> | |
| <!-- Squad Card: BLOCKED --> | |
| <div class="bg-bg-card border border-border rounded-lg p-5 hover:border-amber-500/40 transition-colors group relative"> | |
| <div class="absolute top-4 right-4"> | |
| <span class="px-2 py-1 rounded bg-amber-500/10 text-amber-400 text-[10px] font-mono border border-amber-500/20 tracking-wide">STALLED</span> | |
| </div> | |
| <div class="flex items-start justify-between mb-4"> | |
| <div> | |
| <h4 class="text-zinc-200 font-medium text-lg group-hover:text-amber-400 transition-colors">Stripe Integration</h4> | |
| <p class="text-zinc-500 text-xs mt-1 font-mono">ID: SQD-PAY-009 • Age: 1d 12h</p> | |
| </div> | |
| </div> | |
| <div class="grid grid-cols-3 gap-4 mb-2"> | |
| <div class="bg-black/20 p-3 rounded border border-zinc-800"> | |
| <div class="text-[10px] text-zinc-500 mb-1 font-mono uppercase">Staffing</div> | |
| <div class="flex -space-x-2"> | |
| <div class="w-7 h-7 rounded-full bg-purple-900/80 border border-zinc-800 flex items-center justify-center text-[10px] text-purple-200 font-bold z-30">D</div> | |
| <div class="w-7 h-7 rounded-full bg-blue-900/80 border border-zinc-800 flex items-center justify-center text-[10px] text-blue-200 font-bold z-20">M</div> | |
| <div class="w-7 h-7 rounded-full bg-red-900/50 border border-red-500/50 flex items-center justify-center text-[10px] font-mono z-10 text-red-200 animate-pulse">E1</div> | |
| </div> | |
| </div> | |
| <div class="col-span-2 bg-black/20 p-3 rounded border border-zinc-800 flex items-center justify-between"> | |
| <div> | |
| <div class="text-[10px] text-zinc-500 mb-1 font-mono uppercase">Blocker</div> | |
| <div class="text-amber-400 font-mono text-xs truncate">Stripe API Verification Failure (403)</div> | |
| </div> | |
| <button class="text-xs bg-amber-500/10 text-amber-500 px-2 py-1 rounded hover:bg-amber-500/20 border border-amber-500/20">NUDGE</button> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Live Stream (Right 4) --> | |
| <div class="col-span-12 lg:col-span-4 flex flex-col h-[500px] bg-bg-panel border border-border rounded-lg overflow-hidden"> | |
| <div class="p-3 border-b border-border bg-[#121215] flex justify-between items-center"> | |
| <h3 class="text-zinc-400 text-xs font-bold font-mono uppercase">Live Receipts</h3> | |
| <span class="flex h-2 w-2"> | |
| <span class="animate-ping absolute inline-flex h-2 w-2 rounded-full bg-cyan-400 opacity-75"></span> | |
| <span class="relative inline-flex rounded-full h-2 w-2 bg-cyan-500"></span> | |
| </span> | |
| </div> | |
| <div class="flex-1 overflow-y-auto p-0 font-mono text-xs" id="receipt-stream"> | |
| <!-- Populated by JS --> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- VIEW: CONSOLE --> | |
| <div id="view-console" class="view-section hidden h-full flex"> | |
| <!-- Main Chat --> | |
| <div class="flex-1 flex flex-col bg-bg-dark relative"> | |
| <div class="flex-1 overflow-y-auto p-6 space-y-6"> | |
| <!-- User Message --> | |
| <div class="flex justify-end"> | |
| <div class="max-w-2xl bg-[#27272a] rounded-lg p-4 text-zinc-100 shadow-sm"> | |
| <p class="leading-relaxed">Spin up a new squad to handle 'User Profile Image Uploads'. Needs to support S3 and have a max size of 5MB.</p> | |
| </div> | |
| </div> | |
| <!-- Director Response --> | |
| <div class="flex justify-start items-start space-x-4"> | |
| <div class="w-8 h-8 rounded-full bg-purple-900/80 border border-purple-500/30 flex items-center justify-center text-[10px] font-bold text-purple-200 shrink-0 mt-1">AI</div> | |
| <div class="max-w-3xl bg-[#18181b] border border-zinc-800 rounded-lg p-5 shadow-sm"> | |
| <div class="text-sm space-y-3 text-zinc-300 leading-relaxed"> | |
| <p>Understood. Initializing <span class="text-cyan-400 font-mono bg-cyan-900/10 px-1 rounded">Profile-Media-Squad</span>.</p> | |
| <div class="bg-black/30 rounded p-3 border border-zinc-800 font-mono text-xs space-y-2"> | |
| <div class="flex items-center text-zinc-400"> | |
| <span class="w-1.5 h-1.5 bg-cyan-500 rounded-full mr-2"></span> | |
| Phase: <span class="text-cyan-500 ml-1">DISCOVER</span> <span class="text-zinc-600 mx-2">|</span> Scanning <span class="text-zinc-300">apps/backend/src/storage</span>... | |
| </div> | |
| <div class="flex items-center text-zinc-400"> | |
| <span class="w-1.5 h-1.5 bg-emerald-500 rounded-full mr-2"></span> | |
| Memory Hit: <span class="text-emerald-500 ml-1">Found pattern 'S3 Bucket Policy'</span> | |
| </div> | |
| </div> | |
| <p class="font-medium text-white mt-2">Proposed Plan:</p> | |
| <ol class="list-decimal list-inside space-y-1 text-zinc-400 pl-2"> | |
| <li>Define PSM Surface: <code class="text-xs bg-zinc-800 px-1 rounded">user.profile.upload</code></li> | |
| <li>Spawn Manager + 2 Engineers (Frontend/Backend)</li> | |
| <li>Acceptance Criteria: JPG/PNG only, <5MB, 200ms latency.</li> | |
| </ol> | |
| <div class="pt-2 text-sm italic text-zinc-500">Does this look correct?</div> | |
| </div> | |
| <div class="mt-4 flex gap-2"> | |
| <button class="px-3 py-1.5 bg-cyan-600/20 text-cyan-400 border border-cyan-500/30 rounded text-xs hover:bg-cyan-600/30 transition-colors">Approve & Proceed</button> | |
| <button class="px-3 py-1.5 bg-zinc-800 text-zinc-400 border border-zinc-700 rounded text-xs hover:bg-zinc-700 transition-colors">Edit Plan</button> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Input Area --> | |
| <div class="p-4 bg-bg-panel border-t border-border"> | |
| <div class="max-w-4xl mx-auto relative"> | |
| <input type="text" placeholder="Message Director..." class="w-full bg-black/40 border border-zinc-700 rounded-lg pl-4 pr-12 py-3 text-sm text-white focus:outline-none focus:border-cyan-500 focus:ring-1 focus:ring-cyan-500 transition-all placeholder-zinc-600 font-mono"> | |
| <button class="absolute right-2 top-2 p-1.5 bg-cyan-600 hover:bg-cyan-500 text-white rounded transition-colors"> | |
| <svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M14 5l7 7m0 0l-7 7m7-7H3"></path></svg> | |
| </button> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Context Shelf Sidebar --> | |
| <div class="w-80 bg-bg-panel border-l border-border flex flex-col"> | |
| <div class="p-4 border-b border-border bg-[#121215]"> | |
| <h3 class="text-xs font-bold text-zinc-500 uppercase font-mono tracking-wider">Context Shelf</h3> | |
| </div> | |
| <div class="p-4 space-y-6 overflow-y-auto"> | |
| <!-- Token Budget --> | |
| <div> | |
| <div class="flex justify-between text-xs mb-2"> | |
| <span class="text-zinc-400">Session Tokens</span> | |
| <span class="text-zinc-200 font-mono">12,450 / 20k</span> | |
| </div> | |
| <div class="w-full bg-zinc-800 rounded-full h-1.5 overflow-hidden"> | |
| <div class="bg-gradient-to-r from-cyan-500 to-blue-500 h-1.5 rounded-full" style="width: 62%"></div> | |
| </div> | |
| </div> | |
| <!-- Active Files --> | |
| <div> | |
| <h4 class="text-[10px] font-bold text-zinc-600 uppercase mb-3">Active Context</h4> | |
| <div class="space-y-2"> | |
| <div class="flex items-center text-xs text-zinc-300 group cursor-pointer"> | |
| <svg class="w-4 h-4 mr-2 text-amber-500" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 7v10a2 2 0 002 2h14a2 2 0 002-2V9a2 2 0 00-2-2h-6l-2-2H5a2 2 0 00-2 2z"></path></svg> | |
| <span class="group-hover:text-white transition-colors">apps/desktop/src-tauri/</span> | |
| </div> | |
| <div class="flex items-center text-xs text-zinc-300 group cursor-pointer"> | |
| <svg class="w-4 h-4 mr-2 text-blue-400" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z"></path></svg> | |
| <span class="group-hover:text-white transition-colors">package.json</span> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Actions --> | |
| <div class="pt-4 border-t border-zinc-800"> | |
| <button class="w-full py-2 bg-zinc-800 border border-zinc-700 hover:bg-zinc-700 text-zinc-300 text-xs rounded mb-2 transition-colors flex items-center justify-center"> | |
| <svg class="w-3 h-3 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 11H5m14 0a2 2 0 012 2v6a2 2 0 01-2 2H5a2 2 0 01-2-2v-6a2 2 0 012-2m14 0V9a2 2 0 00-2-2M5 11V9a2 2 0 012-2m0 0V5a2 2 0 012-2h6a2 2 0 012 2v2M7 7h10"></path></svg> | |
| Compact Context | |
| </button> | |
| <button class="w-full py-2 bg-zinc-800 border border-zinc-700 hover:bg-zinc-700 text-zinc-300 text-xs rounded transition-colors flex items-center justify-center"> | |
| <svg class="w-3 h-3 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 7H5a2 2 0 00-2 2v9a2 2 0 002 2h14a2 2 0 002-2V9a2 2 0 00-2-2h-3m-1 4l-3 3m0 0l-3-3m3 3V4"></path></svg> | |
| Generate Handoff | |
| </button> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- VIEW: SQUAD OPS --> | |
| <div id="view-squad-ops" class="view-section hidden p-6 animate-fade-in"> | |
| <div class="max-w-7xl mx-auto"> | |
| <h2 class="text-xl font-mono font-medium text-white mb-6 flex items-center"> | |
| <span class="text-cyan-500 mr-2">///</span> AGENT_OBSERVABILITY | |
| </h2> | |
| <!-- Swimlanes Container --> | |
| <div class="bg-bg-panel border border-border rounded-lg p-6 mb-6"> | |
| <h3 class="text-xs font-bold text-zinc-500 uppercase tracking-wider mb-6">Execution Swimlanes (Real-time)</h3> | |
| <div class="space-y-8 relative"> | |
| <!-- Time Marker (Vertical Line) --> | |
| <div class="absolute top-0 bottom-0 left-[70%] w-px bg-cyan-500/50 z-10"> | |
| <div class="absolute -top-1 -left-1 w-2 h-2 bg-cyan-500 rounded-full"></div> | |
| </div> | |
| <!-- Row: Director --> | |
| <div class="flex items-center group"> | |
| <div class="w-32 text-xs font-mono text-purple-300 shrink-0">Director</div> | |
| <div class="flex-1 h-8 bg-zinc-900/50 rounded relative flex items-center px-1 overflow-hidden"> | |
| <div class="h-6 bg-purple-900/40 border border-purple-500/30 rounded w-1/4 flex items-center justify-center text-[10px] text-purple-200 mr-1">Planning</div> | |
| <div class="h-6 bg-zinc-800 border border-zinc-700 rounded w-3/4 flex items-center justify-center text-[10px] text-zinc-400">Observing</div> | |
| </div> | |
| </div> | |
| <!-- Row: Manager --> | |
| <div class="flex items-center group"> | |
| <div class="w-32 text-xs font-mono text-blue-300 shrink-0">Manager</div> | |
| <div class="flex-1 h-8 bg-zinc-900/50 rounded relative flex items-center px-1 overflow-hidden"> | |
| <div class="h-6 bg-blue-900/40 border border-blue-500/30 rounded w-32 mr-1 flex items-center justify-center text-[10px] text-blue-200">Spawn Eng1</div> | |
| <div class="h-6 bg-blue-900/40 border border-blue-500/30 rounded w-32 mr-1 flex items-center justify-center text-[10px] text-blue-200">Spawn Eng2</div> | |
| <div class="h-6 bg-blue-900/20 border border-blue-500/20 rounded w-48 flex items-center justify-center text-[10px] text-blue-300">Reviewing Receipt</div> | |
| </div> | |
| </div> | |
| <!-- Row: Engineer FE --> | |
| <div class="flex items-center group"> | |
| <div class="w-32 text-xs font-mono text-zinc-400 shrink-0">Engineer-FE</div> | |
| <div class="flex-1 h-8 bg-zinc-900/50 rounded relative flex items-center px-1 overflow-hidden"> | |
| <div class="h-6 bg-red-900/40 border border-red-500/30 rounded w-24 mr-1 flex items-center justify-center text-[10px] text-red-200">RED (Fail)</div> | |
| <div class="h-6 bar-planning bg-zinc-800 border border-zinc-700 rounded w-32 mr-1 flex items-center justify-center text-[10px] text-zinc-400">RESEARCH</div> | |
| <div class="h-6 bg-emerald-900/40 border border-emerald-500/30 rounded w-24 mr-1 flex items-center justify-center text-[10px] text-emerald-200">GREEN</div> | |
| <div class="h-6 bg-purple-500/20 border border-purple-500/40 rounded w-24 animate-pulse flex items-center justify-center text-[10px] text-purple-200">MCP Tool</div> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Engagement Radar --> | |
| <div class="grid grid-cols-3 gap-6"> | |
| <div class="bg-bg-panel border border-border rounded-lg p-5"> | |
| <h3 class="text-xs font-bold text-zinc-500 uppercase tracking-wider mb-4">Engagement Radar</h3> | |
| <div class="space-y-3"> | |
| <div class="flex items-center justify-between p-2 bg-zinc-900/50 rounded border border-zinc-800"> | |
| <div class="flex items-center"> | |
| <div class="w-2 h-2 bg-emerald-500 rounded-full mr-3"></div> | |
| <span class="text-sm text-zinc-300">Engineer-FE</span> | |
| </div> | |
| <span class="text-xs font-mono text-emerald-500">ACTIVE (2s)</span> | |
| </div> | |
| <div class="flex items-center justify-between p-2 bg-zinc-900/50 rounded border border-zinc-800"> | |
| <div class="flex items-center"> | |
| <div class="w-2 h-2 bg-amber-500 rounded-full mr-3 animate-pulse"></div> | |
| <span class="text-sm text-zinc-300">Engineer-BE</span> | |
| </div> | |
| <span class="text-xs font-mono text-amber-500">RECOVERING</span> | |
| </div> | |
| <div class="flex items-center justify-between p-2 bg-zinc-900/50 rounded border border-zinc-800 opacity-60"> | |
| <div class="flex items-center"> | |
| <div class="w-2 h-2 bg-zinc-500 rounded-full mr-3"></div> | |
| <span class="text-sm text-zinc-300">Manager</span> | |
| </div> | |
| <span class="text-xs font-mono text-zinc-500">QUIET (5m)</span> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- VIEW: BRIDGE --> | |
| <div id="view-bridge" class="view-section hidden p-6 animate-fade-in h-full"> | |
| <div class="h-full flex flex-col max-w-7xl mx-auto"> | |
| <div class="flex justify-between items-center mb-6"> | |
| <h2 class="text-xl font-mono font-medium text-white flex items-center"> | |
| <span class="text-cyan-500 mr-2">///</span> BRIDGE_COMMS | |
| </h2> | |
| <button class="px-4 py-2 bg-zinc-800 hover:bg-zinc-700 text-white text-xs rounded font-medium border border-zinc-700 transition-colors"> | |
| + New Request (RCX) | |
| </button> | |
| </div> | |
| <div class="flex-1 grid grid-cols-3 gap-6 min-h-0"> | |
| <!-- Column 1 --> | |
| <div class="bg-bg-panel border border-border rounded-lg flex flex-col"> | |
| <div class="p-3 border-b border-border bg-[#121215] flex justify-between items-center"> | |
| <h3 class="text-xs font-bold text-zinc-400 uppercase tracking-wider">New Requests</h3> | |
| <span class="bg-zinc-800 text-zinc-400 text-[10px] px-2 py-0.5 rounded-full">1</span> | |
| </div> | |
| <div class="p-3 flex-1 overflow-y-auto bg-bg-dark/50"> | |
| <div class="bg-bg-card border border-zinc-800 p-4 rounded hover:border-cyan-500/30 cursor-pointer transition-colors"> | |
| <div class="flex justify-between items-start mb-2"> | |
| <span class="text-[10px] font-mono text-cyan-500 border border-cyan-500/20 bg-cyan-900/10 px-1 rounded">RFC</span> | |
| <span class="text-[10px] text-zinc-500">10m ago</span> | |
| </div> | |
| <p class="text-sm text-zinc-200 mb-3 font-medium">Add scope to JWT for 'finance-admin'</p> | |
| <div class="flex items-center justify-between text-xs text-zinc-500"> | |
| <span>Billing-Squad</span> | |
| <svg class="w-3 h-3" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M14 5l7 7m0 0l-7 7m7-7H3"></path></svg> | |
| <span>Auth-Squad</span> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Column 2 --> | |
| <div class="bg-bg-panel border border-border rounded-lg flex flex-col"> | |
| <div class="p-3 border-b border-border bg-[#121215] flex justify-between items-center"> | |
| <h3 class="text-xs font-bold text-cyan-500 uppercase tracking-wider">Awaiting Receipts</h3> | |
| <span class="bg-cyan-900/30 text-cyan-400 text-[10px] px-2 py-0.5 rounded-full">1</span> | |
| </div> | |
| <div class="p-3 flex-1 overflow-y-auto bg-bg-dark/50"> | |
| <div class="bg-bg-card border border-cyan-500/30 p-4 rounded hover:border-cyan-500/50 cursor-pointer transition-colors"> | |
| <div class="flex justify-between items-start mb-2"> | |
| <span class="text-[10px] font-mono text-emerald-500 border border-emerald-500/20 bg-emerald-900/10 px-1 rounded">RCX: REPLY</span> | |
| <span class="text-[10px] text-zinc-500">2m ago</span> | |
| </div> | |
| <p class="text-sm text-zinc-200 mb-3 font-medium">Scope added. Receipt attached.</p> | |
| <div class="bg-black/30 p-2 rounded border border-zinc-800 flex items-center mb-3"> | |
| <svg class="w-4 h-4 text-emerald-500 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z"></path></svg> | |
| <span class="text-xs font-mono text-emerald-400 truncate">token_gen_test.json</span> | |
| </div> | |
| <div class="flex items-center justify-between text-xs text-zinc-500"> | |
| <span>Auth-Squad</span> | |
| <svg class="w-3 h-3" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M14 5l7 7m0 0l-7 7m7-7H3"></path></svg> | |
| <span>Billing-Squad</span> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Column 3 --> | |
| <div class="bg-bg-panel border border-border rounded-lg flex flex-col"> | |
| <div class="p-3 border-b border-border bg-[#121215] flex justify-between items-center"> | |
| <h3 class="text-xs font-bold text-zinc-500 uppercase tracking-wider">Resolved</h3> | |
| <span class="bg-zinc-800 text-zinc-400 text-[10px] px-2 py-0.5 rounded-full">14</span> | |
| </div> | |
| <div class="p-3 flex-1 overflow-y-auto bg-bg-dark/50 opacity-60"> | |
| <div class="bg-bg-card border border-zinc-800 p-4 rounded mb-3"> | |
| <div class="flex justify-between items-start mb-2"> | |
| <span class="text-[10px] font-mono text-zinc-500 border border-zinc-700 px-1 rounded">FYI</span> | |
| </div> | |
| <p class="text-sm text-zinc-400 mb-1 line-through">Update dependency lockfile</p> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- VIEW: PSM (Placeholder) --> | |
| <div id="view-psm" class="view-section hidden p-6 animate-fade-in"> | |
| <div class="flex items-center justify-center h-96 border border-zinc-800 border-dashed rounded-lg text-zinc-500 font-mono"> | |
| // PRODUCT SURFACE MAP EXPLORER NOT INITIALIZED | |
| </div> | |
| </div> | |
| </main> | |
| </div> | |
| <!-- FIRE GATE MODAL --> | |
| <div id="modal-fire-gate" class="fixed inset-0 bg-black/80 backdrop-blur-sm z-50 hidden flex items-center justify-center opacity-0 transition-opacity duration-300"> | |
| <div class="bg-[#18181b] border border-emerald-500/50 w-[800px] rounded-lg shadow-2xl transform scale-95 transition-transform duration-300" id="modal-content"> | |
| <!-- Header --> | |
| <div class="bg-[#121215] border-b border-zinc-800 p-4 flex justify-between items-center rounded-t-lg"> | |
| <div class="flex items-center space-x-3"> | |
| <div class="w-2 h-2 bg-emerald-500 rounded-full animate-pulse"></div> | |
| <h2 class="text-lg font-medium text-white">GATE: Auth Refactor Deployment</h2> | |
| </div> | |
| <button onclick="closeFireGate()" class="text-zinc-500 hover:text-white"> | |
| <svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"></path></svg> | |
| </button> | |
| </div> | |
| <!-- Content --> | |
| <div class="p-6"> | |
| <h3 class="text-xs font-bold text-zinc-500 uppercase tracking-wider mb-4">Evidence Locker (Receipts)</h3> | |
| <div class="space-y-3 mb-8"> | |
| <!-- Item 1 --> | |
| <div class="flex items-center justify-between bg-black/20 p-3 rounded border border-zinc-800/50"> | |
| <div class="flex items-center space-x-3"> | |
| <div class="w-6 h-6 rounded-full bg-emerald-900/30 flex items-center justify-center text-emerald-500 border border-emerald-500/20"> | |
| <svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"></path></svg> | |
| </div> | |
| <span class="text-sm text-zinc-200">All Tests Pass</span> | |
| </div> | |
| <span class="text-xs font-mono text-emerald-500 underline cursor-pointer">receipt-test-runner-x99.json</span> | |
| </div> | |
| <!-- Item 2 --> | |
| <div class="flex items-center justify-between bg-black/20 p-3 rounded border border-zinc-800/50"> | |
| <div class="flex items-center space-x-3"> | |
| <div class="w-6 h-6 rounded-full bg-emerald-900/30 flex items-center justify-center text-emerald-500 border border-emerald-500/20"> | |
| <svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"></path></svg> | |
| </div> | |
| <span class="text-sm text-zinc-200">PR Reviewed</span> | |
| </div> | |
| <span class="text-xs font-mono text-emerald-500 underline cursor-pointer">receipt-github-review-88.json</span> | |
| </div> | |
| <!-- Item 3 --> | |
| <div class="flex items-center justify-between bg-black/20 p-3 rounded border border-zinc-800/50"> | |
| <div class="flex items-center space-x-3"> | |
| <div class="w-6 h-6 rounded-full bg-amber-900/20 flex items-center justify-center text-amber-500 border border-amber-500/20"> | |
| <svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z"></path></svg> | |
| </div> | |
| <span class="text-sm text-zinc-200">DB Migration Proof</span> | |
| </div> | |
| <div class="text-right"> | |
| <span class="text-xs font-mono text-amber-500 block">⚠️ Missing Evidence</span> | |
| <span class="text-[10px] text-zinc-500 italic">"Migration script generated but dry-run receipt not found."</span> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Footer --> | |
| <div class="flex items-center justify-between pt-4 border-t border-zinc-800"> | |
| <button onclick="closeFireGate()" class="text-sm text-zinc-400 hover:text-white">Cancel</button> | |
| <div class="flex space-x-3"> | |
| <button class="px-4 py-2 bg-zinc-800 hover:bg-zinc-700 text-zinc-300 rounded text-sm border border-zinc-700">Reject</button> | |
| <button class="px-4 py-2 bg-emerald-600 hover:bg-emerald-500 text-white rounded text-sm font-medium shadow-lg shadow-emerald-900/20 flex items-center opacity-50 cursor-not-allowed" title="Blocked by Missing Evidence"> | |
| <svg class="w-4 h-4 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 10V3L4 14h7v7l9-11h-7z"></path></svg> | |
| Execute Deploy | |
| </button> | |
| <button class="text-xs text-zinc-500 hover:text-zinc-300 underline decoration-zinc-700 underline-offset-4">Force Approve</button> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <script> | |
| // View Switching Logic | |
| function switchView(viewId) { | |
| // Hide all views | |
| document.querySelectorAll('.view-section').forEach(el => { | |
| el.classList.add('hidden'); | |
| el.classList.remove('block'); | |
| }); | |
| // Show selected view | |
| const target = document.getElementById('view-' + viewId); | |
| if (target) { | |
| target.classList.remove('hidden'); | |
| target.classList.add('block'); | |
| } | |
| // Update Nav Buttons | |
| document.querySelectorAll('.nav-btn').forEach(btn => { | |
| btn.classList.remove('active', 'text-white', 'bg-zinc-800'); | |
| btn.classList.add('text-zinc-400'); | |
| }); | |
| const activeBtn = document.getElementById('btn-' + viewId); | |
| if (activeBtn) { | |
| activeBtn.classList.add('active', 'text-white', 'bg-zinc-800'); | |
| activeBtn.classList.remove('text-zinc-400'); | |
| } | |
| } | |
| // Live Receipt Stream Simulation | |
| const receiptStream = document.getElementById('receipt-stream'); | |
| const events = [ | |
| { type: 'TEST_PASS', file: 'tests/auth/login.spec.ts', time: '40ms', color: 'text-emerald-400' }, | |
| { type: 'GIT_COMMIT', file: 'feat: add jwt validation', time: 'Engineer-01', color: 'text-blue-400' }, | |
| { type: 'HAR_CAPTURE', file: 'POST /api/login', time: '180ms', color: 'text-purple-400' }, | |
| { type: 'DB_QUERY', file: 'SELECT * FROM users', time: '12ms', color: 'text-amber-400' }, | |
| ]; | |
| function addReceipt() { | |
| const evt = events[Math.floor(Math.random() * events.length)]; | |
| const now = new Date().toLocaleTimeString('en-US', { hour12: false, hour: '2-digit', minute:'2-digit', second:'2-digit' }); | |
| const div = document.createElement('div'); | |
| div.className = 'receipt-line px-3 py-2 border-b border-zinc-800 hover:bg-zinc-800/50 transition-colors cursor-pointer flex items-center justify-between group animate-fade-in'; | |
| div.innerHTML = ` | |
| <div class="flex items-center min-w-0"> | |
| <span class="text-zinc-600 mr-3 shrink-0 select-none">${now}</span> | |
| <span class="text-[10px] font-bold font-mono ${evt.color} w-20 shrink-0">[${evt.type}]</span> | |
| <span class="text-zinc-300 truncate group-hover:text-white transition-colors">${evt.file}</span> | |
| </div> | |
| <span class="text-zinc-600 text-[10px] ml-2 shrink-0">${evt.time}</span> | |
| `; | |
| receiptStream.insertBefore(div, receiptStream.firstChild); | |
| if (receiptStream.children.length > 20) { | |
| receiptStream.lastChild.remove(); | |
| } | |
| } | |
| // Start simulation | |
| setInterval(addReceipt, 2500); | |
| // Add initial mock data | |
| for(let i=0; i<5; i++) addReceipt(); | |
| // FIRE Gate Logic | |
| function openFireGate() { | |
| const modal = document.getElementById('modal-fire-gate'); | |
| const content = document.getElementById('modal-content'); | |
| modal.classList.remove('hidden'); | |
| // Small delay for animation | |
| setTimeout(() => { | |
| modal.classList.remove('opacity-0'); | |
| content.classList.remove('scale-95'); | |
| content.classList.add('scale-100'); | |
| }, 10); | |
| } | |
| function closeFireGate() { | |
| const modal = document.getElementById('modal-fire-gate'); | |
| const content = document.getElementById('modal-content'); | |
| modal.classList.add('opacity-0'); | |
| content.classList.remove('scale-100'); | |
| content.classList.add('scale-95'); | |
| setTimeout(() => { | |
| modal.classList.add('hidden'); | |
| }, 300); | |
| } | |
| </script> | |
| </body> | |
| </html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment