diff --git a/assets/css/custom.css b/assets/css/custom.css index 50e0502..79fa9c5 100644 --- a/assets/css/custom.css +++ b/assets/css/custom.css @@ -1,302 +1,169 @@ +:root { + --primary-color: #0d6efd; + --primary-gradient: linear-gradient(135deg, #0d6efd 0%, #0dcaf0 100%); + --bg-dark: #0b0e14; + --bg-subtle: #161b22; + --border-color: rgba(255, 255, 255, 0.1); + --text-main: #f0f6fc; + --text-secondary: #8b949e; +} + body { - background: linear-gradient(-45deg, #ee7752, #e73c7e, #23a6d5, #23d5ab); - background-size: 400% 400%; - animation: gradient 15s ease infinite; - color: #212529; - font-family: 'Inter', -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif; - font-size: 14px; - margin: 0; + background-color: var(--bg-dark); + color: var(--text-main); + font-family: 'Plus Jakarta Sans', sans-serif; + overflow-x: hidden; min-height: 100vh; } -.main-wrapper { - display: flex; - align-items: center; - justify-content: center; +/* Sidebar Styling */ +#sidebar-wrapper { min-height: 100vh; + width: 280px; + transition: margin 0.25s ease-out; + background-color: var(--bg-subtle) !important; +} + +#sidebar-wrapper .sidebar-heading { + padding: 2rem 1.5rem; + font-size: 1.25rem; +} + +#sidebar-wrapper .list-group { width: 100%; - padding: 20px; - box-sizing: border-box; +} + +#sidebar-wrapper .list-group-item { + color: var(--text-secondary); + transition: all 0.2s ease; + border: none !important; + margin: 0.25rem 1rem; + padding: 0.75rem 1rem; +} + +#sidebar-wrapper .list-group-item:hover { + color: var(--text-main); + background-color: rgba(255, 255, 255, 0.05) !important; +} + +#sidebar-wrapper .list-group-item.active { + background-color: var(--primary-color) !important; + color: white; +} + +/* Page Content Styling */ +#page-content-wrapper { + min-width: 0; + width: 100%; + background-color: var(--bg-dark); +} + +/* Custom Utilities */ +.text-gradient { + background: var(--primary-gradient); + -webkit-background-clip: text; + -webkit-text-fill-color: transparent; +} + +.tracking-wider { + letter-spacing: 0.1em; +} + +.min-vh-75 { + min-height: 75vh; +} + +/* App Sections */ +.app-section { + animation: fadeIn 0.4s ease-out forwards; +} + +@keyframes fadeIn { + from { opacity: 0; transform: translateY(10px); } + to { opacity: 1; transform: translateY(0); } +} + +/* Cards & Components */ +.card { + background-color: var(--bg-subtle); + border: 1px solid var(--border-color); + box-shadow: 0 4px 20px rgba(0, 0, 0, 0.2); + transition: transform 0.2s ease, border-color 0.2s ease; +} + +.card:hover { + border-color: var(--primary-color); +} + +.bg-dark-subtle { + background-color: var(--bg-subtle) !important; +} + +.border-secondary { + border-color: var(--border-color) !important; +} + +/* Range Input Customization */ +.custom-range::-webkit-slider-runnable-track { + background: rgba(255, 255, 255, 0.1); + height: 8px; + border-radius: 4px; +} + +.custom-range::-webkit-slider-thumb { + background: var(--primary-color); + border: 3px solid #fff; + width: 20px; + height: 20px; + margin-top: -6px; + box-shadow: 0 0 10px rgba(13, 110, 253, 0.5); +} + +/* Hover Effects */ +.nav-link { + cursor: pointer; +} + +/* Stats */ +.stat-card { + background: rgba(255, 255, 255, 0.03); + padding: 1rem; + border-radius: 1rem; + border: 1px solid var(--border-color); +} + +/* Chart Styles */ +.chart-container { position: relative; - z-index: 1; -} - -@keyframes gradient { - 0% { - background-position: 0% 50%; - } - 50% { - background-position: 100% 50%; - } - 100% { - background-position: 0% 50%; - } -} - -.chat-container { width: 100%; - max-width: 600px; - background: rgba(255, 255, 255, 0.85); - border: 1px solid rgba(255, 255, 255, 0.3); - border-radius: 20px; - display: flex; - flex-direction: column; - height: 85vh; - box-shadow: 0 20px 40px rgba(0,0,0,0.2); - backdrop-filter: blur(15px); - -webkit-backdrop-filter: blur(15px); - overflow: hidden; + margin-top: 2rem; } -.chat-header { - padding: 1.5rem; - border-bottom: 1px solid rgba(0, 0, 0, 0.05); - background: rgba(255, 255, 255, 0.5); - font-weight: 700; - font-size: 1.1rem; - display: flex; - justify-content: space-between; - align-items: center; -} - -.chat-messages { - flex: 1; - overflow-y: auto; - padding: 1.5rem; - display: flex; - flex-direction: column; - gap: 1.25rem; +/* Responsive */ +@media (max-width: 991.98px) { + #sidebar-wrapper { + margin-left: -280px; + } + #wrapper.toggled #sidebar-wrapper { + margin-left: 0; + } } /* Custom Scrollbar */ ::-webkit-scrollbar { - width: 6px; + width: 8px; } ::-webkit-scrollbar-track { - background: transparent; + background: var(--bg-dark); } ::-webkit-scrollbar-thumb { - background: rgba(255, 255, 255, 0.3); + background: var(--bg-subtle); border-radius: 10px; + border: 2px solid var(--bg-dark); } ::-webkit-scrollbar-thumb:hover { - background: rgba(255, 255, 255, 0.5); + background: var(--text-secondary); } - -.message { - max-width: 85%; - padding: 0.85rem 1.1rem; - border-radius: 16px; - line-height: 1.5; - font-size: 0.95rem; - box-shadow: 0 4px 15px rgba(0,0,0,0.05); - animation: fadeIn 0.4s cubic-bezier(0.175, 0.885, 0.32, 1.275); -} - -@keyframes fadeIn { - from { opacity: 0; transform: translateY(20px) scale(0.95); } - to { opacity: 1; transform: translateY(0) scale(1); } -} - -.message.visitor { - align-self: flex-end; - background: linear-gradient(135deg, #212529 0%, #343a40 100%); - color: #fff; - border-bottom-right-radius: 4px; -} - -.message.bot { - align-self: flex-start; - background: #ffffff; - color: #212529; - border-bottom-left-radius: 4px; -} - -.chat-input-area { - padding: 1.25rem; - background: rgba(255, 255, 255, 0.5); - border-top: 1px solid rgba(0, 0, 0, 0.05); -} - -.chat-input-area form { - display: flex; - gap: 0.75rem; -} - -.chat-input-area input { - flex: 1; - border: 1px solid rgba(0, 0, 0, 0.1); - border-radius: 12px; - padding: 0.75rem 1rem; - outline: none; - background: rgba(255, 255, 255, 0.9); - transition: all 0.3s ease; -} - -.chat-input-area input:focus { - border-color: #23a6d5; - box-shadow: 0 0 0 3px rgba(35, 166, 213, 0.2); -} - -.chat-input-area button { - background: #212529; - color: #fff; - border: none; - padding: 0.75rem 1.5rem; - border-radius: 12px; - cursor: pointer; - font-weight: 600; - transition: all 0.3s ease; -} - -.chat-input-area button:hover { - background: #000; - transform: translateY(-2px); - box-shadow: 0 5px 15px rgba(0,0,0,0.2); -} - -/* Background Animations */ -.bg-animations { - position: fixed; - top: 0; - left: 0; - width: 100%; - height: 100%; - z-index: 0; - overflow: hidden; - pointer-events: none; -} - -.blob { - position: absolute; - width: 500px; - height: 500px; - background: rgba(255, 255, 255, 0.2); - border-radius: 50%; - filter: blur(80px); - animation: move 20s infinite alternate cubic-bezier(0.45, 0, 0.55, 1); -} - -.blob-1 { - top: -10%; - left: -10%; - background: rgba(238, 119, 82, 0.4); -} - -.blob-2 { - bottom: -10%; - right: -10%; - background: rgba(35, 166, 213, 0.4); - animation-delay: -7s; - width: 600px; - height: 600px; -} - -.blob-3 { - top: 40%; - left: 30%; - background: rgba(231, 60, 126, 0.3); - animation-delay: -14s; - width: 450px; - height: 450px; -} - -@keyframes move { - 0% { transform: translate(0, 0) rotate(0deg) scale(1); } - 33% { transform: translate(150px, 100px) rotate(120deg) scale(1.1); } - 66% { transform: translate(-50px, 200px) rotate(240deg) scale(0.9); } - 100% { transform: translate(0, 0) rotate(360deg) scale(1); } -} - -.admin-link { - font-size: 14px; - color: #fff; - text-decoration: none; - background: rgba(0, 0, 0, 0.2); - padding: 0.5rem 1rem; - border-radius: 8px; - transition: all 0.3s ease; -} - -.admin-link:hover { - background: rgba(0, 0, 0, 0.4); - text-decoration: none; -} - -/* Admin Styles */ -.admin-container { - max-width: 900px; - margin: 3rem auto; - padding: 2.5rem; - background: rgba(255, 255, 255, 0.85); - backdrop-filter: blur(20px); - -webkit-backdrop-filter: blur(20px); - border-radius: 24px; - box-shadow: 0 20px 50px rgba(0,0,0,0.15); - border: 1px solid rgba(255, 255, 255, 0.4); - position: relative; - z-index: 1; -} - -.admin-container h1 { - margin-top: 0; - color: #212529; - font-weight: 800; -} - -.table { - width: 100%; - border-collapse: separate; - border-spacing: 0 8px; - margin-top: 1.5rem; -} - -.table th { - background: transparent; - border: none; - padding: 1rem; - color: #6c757d; - font-weight: 600; - text-transform: uppercase; - font-size: 0.75rem; - letter-spacing: 1px; -} - -.table td { - background: #fff; - padding: 1rem; - border: none; -} - -.table tr td:first-child { border-radius: 12px 0 0 12px; } -.table tr td:last-child { border-radius: 0 12px 12px 0; } - -.form-group { - margin-bottom: 1.25rem; -} - -.form-group label { - display: block; - margin-bottom: 0.5rem; - font-weight: 600; - font-size: 0.9rem; -} - -.form-control { - width: 100%; - padding: 0.75rem 1rem; - border: 1px solid rgba(0, 0, 0, 0.1); - border-radius: 12px; - background: #fff; - transition: all 0.3s ease; - box-sizing: border-box; -} - -.form-control:focus { - outline: none; - border-color: #23a6d5; - box-shadow: 0 0 0 3px rgba(35, 166, 213, 0.1); -} \ No newline at end of file diff --git a/assets/js/main.js b/assets/js/main.js index d349598..dc3d40c 100644 --- a/assets/js/main.js +++ b/assets/js/main.js @@ -1,39 +1,381 @@ document.addEventListener('DOMContentLoaded', () => { - const chatForm = document.getElementById('chat-form'); - const chatInput = document.getElementById('chat-input'); - const chatMessages = document.getElementById('chat-messages'); + // 1. Mock Data + const startups = [ + { + id: 1, + name: "FinFlow", + tagline: "Next-gen liquidity management for SMEs", + irr: 25, + pd: 5, + fragility: 15, + revenueConcentration: 20, + sector: "Fintech", + description: "FinFlow uses advanced AI to predict cash flow gaps and automate short-term financing for medium-sized enterprises. They have already secured partnerships with 3 major banks and have a growing user base.", + growth: "15% MoM", + funding: "$4.5M Series A", + burnRate: "$150k/mo" + }, + { + id: 2, + name: "EcoPay", + tagline: "Sustainable payments infrastructure", + irr: 18, + pd: 3, + fragility: 10, + revenueConcentration: 15, + sector: "Payments", + description: "EcoPay provides carbon-neutral payment processing. They offset the carbon footprint of every transaction and offer lower fees for green certified businesses.", + growth: "8% MoM", + funding: "$2.2M Seed", + burnRate: "$60k/mo" + }, + { + id: 3, + name: "CyberShield", + tagline: "Zero-trust cybersecurity for remote teams", + irr: 30, + pd: 12, + fragility: 25, + revenueConcentration: 40, + sector: "Cybersecurity", + description: "CyberShield offers a decentralized zero-trust network access (ZTNA) platform. High growth but operating in a highly competitive market with significant R&D spend.", + growth: "25% MoM", + funding: "$12M Series B", + burnRate: "$450k/mo" + }, + { + id: 4, + name: "DataNexus", + tagline: "Federated learning for enterprise data", + irr: 22, + pd: 7, + fragility: 18, + revenueConcentration: 25, + sector: "Big Data/AI", + description: "DataNexus enables companies to train machine learning models on sensitive data without moving it, preserving privacy and compliance.", + growth: "12% MoM", + funding: "$6M Series A", + burnRate: "$200k/mo" + }, + { + id: 5, + name: "HealthBridge", + tagline: "Telemedicine platform for rural healthcare", + irr: 20, + pd: 4, + fragility: 12, + revenueConcentration: 10, + sector: "Healthtech", + description: "HealthBridge connects rural clinics with specialist doctors via a low-bandwidth, high-security video and diagnostics platform.", + growth: "10% MoM", + funding: "$3.5M Series A", + burnRate: "$110k/mo" + } + ]; - const appendMessage = (text, sender) => { - const msgDiv = document.createElement('div'); - msgDiv.classList.add('message', sender); - msgDiv.textContent = text; - chatMessages.appendChild(msgDiv); - chatMessages.scrollTop = chatMessages.scrollHeight; + // 2. Navigation Control + const sections = ['hero', 'profile', 'results', 'detail']; + const sidebar = document.getElementById('wrapper'); + const sidebarToggle = document.getElementById('sidebarToggle'); + + const showSection = (sectionId) => { + sections.forEach(s => { + const el = document.getElementById(`${s}-section`); + if (el) el.classList.add('d-none'); + const navLink = document.querySelector(`.nav-link[data-section="${s}"]`); + if (navLink) navLink.classList.remove('active'); + }); + + const target = document.getElementById(`${sectionId}-section`); + if (target) { + target.classList.remove('d-none'); + // Re-trigger fade-in animation + target.style.animation = 'none'; + target.offsetHeight; // trigger reflow + target.style.animation = null; + } + + const activeNav = document.querySelector(`.nav-link[data-section="${sectionId}"]`); + if (activeNav) activeNav.classList.add('active'); + + // Scroll to top + window.scrollTo(0, 0); }; - chatForm.addEventListener('submit', async (e) => { - e.preventDefault(); - const message = chatInput.value.trim(); - if (!message) return; + // Sidebar Toggle + if (sidebarToggle) { + sidebarToggle.addEventListener('click', (e) => { + e.preventDefault(); + sidebar.classList.toggle('toggled'); + }); + } - appendMessage(message, 'visitor'); - chatInput.value = ''; - - try { - const response = await fetch('api/chat.php', { - method: 'POST', - headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({ message }) - }); - const data = await response.json(); - - // Artificial delay for realism - setTimeout(() => { - appendMessage(data.reply, 'bot'); - }, 500); - } catch (error) { - console.error('Error:', error); - appendMessage("Sorry, something went wrong. Please try again.", 'bot'); - } + // Nav Link Clicks + document.querySelectorAll('.nav-link, .navigate-btn').forEach(btn => { + btn.addEventListener('click', (e) => { + e.preventDefault(); + const target = btn.dataset.section || btn.dataset.target; + showSection(target); + }); }); + + // 3. Profile Setup + const minIrrInput = document.getElementById('min-irr'); + const maxPdInput = document.getElementById('max-pd'); + const irrValBadge = document.getElementById('irr-val'); + const pdValBadge = document.getElementById('pd-val'); + + minIrrInput.addEventListener('input', () => { + irrValBadge.textContent = `${minIrrInput.value}%`; + }); + maxPdInput.addEventListener('input', () => { + pdValBadge.textContent = `${maxPdInput.value}%`; + }); + + // 4. Matching Logic + const matchBtn = document.getElementById('match-startups-btn'); + const matchesContainer = document.getElementById('matches-container'); + + matchBtn.addEventListener('click', () => { + const minIrr = parseFloat(minIrrInput.value); + const maxPd = parseFloat(maxPdInput.value); + + // Filter & Calculate RAR + let matches = startups.map(s => { + return { + ...s, + rar: (s.irr * (1 - s.pd/100)).toFixed(2) + }; + }); + + // Filter based on user constraints + matches = matches.filter(s => s.irr >= minIrr && s.pd <= maxPd); + + // Sort by RAR descending + matches.sort((a, b) => b.rar - a.rar); + + // Take top 3 + const topMatches = matches.slice(0, 3); + + renderMatches(topMatches); + showSection('results'); + }); + + const renderMatches = (matches) => { + matchesContainer.innerHTML = ''; + if (matches.length === 0) { + matchesContainer.innerHTML = ` +
+
No startups match your current criteria.
+

Try lowering your IRR requirement or increasing your PD allowance.

+
+ `; + return; + } + + matches.forEach((s, index) => { + const card = document.createElement('div'); + card.className = 'col-md-4'; + card.innerHTML = ` +
+
+ Match #${index + 1} +
+
+

${s.name}

+ ${s.sector} +
+ RAR Score + ${s.rar}% +
+
+
+
+ Expected IRR + ${s.irr}% +
+
+
+
+ 12M PD + ${s.pd}% +
+
+
+ +
+
+ `; + matchesContainer.appendChild(card); + }); + + // Attach listeners to "View Details" buttons + document.querySelectorAll('.view-details-btn').forEach(btn => { + btn.addEventListener('click', () => { + const startupId = parseInt(btn.dataset.id); + showStartupDetail(startupId); + }); + }); + }; + + // 5. Detail View + const detailContent = document.getElementById('startup-detail-content'); + + const showStartupDetail = (id) => { + const s = startups.find(item => item.id === id); + const rar = (s.irr * (1 - s.pd/100)).toFixed(2); + + detailContent.innerHTML = ` +
+
+
+
+
+

${s.name}

+

${s.tagline}

+
+
+ ${s.sector} +
+
+ +
+

Executive Summary

+

${s.description}

+
+ +
+
+
+ Growth + ${s.growth} +
+
+
+
+ Funding + ${s.funding} +
+
+
+
+ Burn Rate + ${s.burnRate} +
+
+
+
+ RAR Score + ${rar}% +
+
+
+ +
+

Stress-Test Performance

+
+ +
+

Simulated performance under varying market conditions (Fragility Score: ${s.fragility}).

+
+
+
+ +
+
+

Risk Metrics

+
+
+ Fragility Score + ${s.fragility} +
+
+
+
+
+
+
+ Revenue Concentration + ${s.revenueConcentration}% +
+
+
+
+
+
+
+ Expected 12M PD + ${s.pd}% +
+
+
+
+
+
+ +
+

Interested in ${s.name}?

+

Get direct access to their data room and contact the founding team.

+ +
+
+
+ `; + + showSection('detail'); + renderStressChart(s); + }; + + const renderStressChart = (startup) => { + const ctx = document.getElementById('stressTestChart').getContext('2d'); + + // Generate mock stress data based on startup metrics + const baseReturn = startup.irr; + const labels = ['Stable', 'Moderate Volatility', 'High Volatility', 'Economic Downturn', 'Black Swan']; + const data = [ + baseReturn, + baseReturn * (1 - startup.fragility/200), + baseReturn * (1 - startup.fragility/100), + baseReturn * (1 - startup.fragility/50), + baseReturn * (1 - startup.fragility/25) + ]; + + new Chart(ctx, { + type: 'line', + data: { + labels: labels, + datasets: [{ + label: 'Projected IRR (%)', + data: data, + borderColor: '#0d6efd', + backgroundColor: 'rgba(13, 110, 253, 0.1)', + fill: true, + tension: 0.4, + pointRadius: 6, + pointBackgroundColor: '#0d6efd', + borderWidth: 3 + }] + }, + options: { + responsive: true, + maintainAspectRatio: false, + scales: { + y: { + beginAtZero: false, + grid: { color: 'rgba(255, 255, 255, 0.05)' }, + ticks: { color: '#8b949e' } + }, + x: { + grid: { display: false }, + ticks: { color: '#8b949e' } + } + }, + plugins: { + legend: { display: false } + } + } + }); + }; }); diff --git a/index.php b/index.php index 7205f3d..9fc57b8 100644 --- a/index.php +++ b/index.php @@ -4,147 +4,226 @@ declare(strict_types=1); @error_reporting(E_ALL); @date_default_timezone_set('UTC'); -$phpVersion = PHP_VERSION; -$now = date('Y-m-d H:i:s'); +$projectDescription = $_SERVER['PROJECT_DESCRIPTION'] ?? 'VentureNerve - Match investors with startups based on risk-adjusted return.'; +$projectImageUrl = $_SERVER['PROJECT_IMAGE_URL'] ?? ''; ?> - + - New Style - - - - - + VentureNerve | Risk-Adjusted Venture Capital + + - - - - - - - - + + + + + + + + - - + + + + + -
-
-

Analyzing your requirements and generating your website…

-
- Loading… -
-

AI is collecting your requirements and applying the first changes.

-

This page will update automatically as the plan is implemented.

-

Runtime: PHP — UTC

+ +
+ + -
- + + +
+ + +
+ + +
+
+
+ The Future of VC +

Match with Startups based on Risk-Adjusted Return.

+

VentureNerve uses proprietary Risk-Adjusted Return (RAR) modeling to connect investors with the top 1% of startups that fit their specific risk appetite.

+
+ + +
+
+
+
+
+
+ Avg. IRR + 24.5% +
+
+ Median PD + 5.2% +
+
+
+ + + + +
+
+ Live Risk Feed - Real-time Aggregation +
+
+
+
+
+ + +
+
+
+
+

Configure Your Investor Profile

+

Set your return expectations and risk tolerance to see tailored startup opportunities.

+
+ +
+
+
+ + 15% +
+ +
+ Conservative (5%) + Aggressive (50%) +
+
+ +
+
+ + 10% +
+ +
+ Low Risk (1%) + High Risk (30%) +
+
+ +
+ +
+
+ + +
+
+ + +
+
+ + +
+
+
+ +
+ +
+
+
+
+
+ + +
+
+

Top RAR Matches

+

The highest ranked startups based on your Risk-Adjusted Return requirements.

+
+ +
+ +
+ +
+ +
+
+ + +
+
+
+ +
+
+ +
+ +
+
+ +
+
+ + + + + + + - + \ No newline at end of file