Compare commits

..

18 Commits

Author SHA1 Message Date
Flatlogic Bot
e2d6252a41 12/22/25 V.15 2025-12-23 03:10:47 +00:00
Flatlogic Bot
a13b34f98c 12/22/25 V.14 2025-12-23 02:37:10 +00:00
Flatlogic Bot
be2c47faae 12/22/25 V.13 2025-12-23 01:58:18 +00:00
Flatlogic Bot
dc1fef6309 12/22/25 V.12 2025-12-22 21:52:43 +00:00
Flatlogic Bot
b61ed836a6 Revert to version f800e10 2025-12-22 02:26:30 +00:00
Flatlogic Bot
70d8c64caa Revert to version d532c98 2025-12-22 02:25:56 +00:00
Flatlogic Bot
596121b8dd Revert to version f800e10 2025-12-22 02:03:13 +00:00
Flatlogic Bot
98bb56cb79 12/21/25 V.11 2025-12-21 17:25:45 +00:00
Flatlogic Bot
f800e10a76 12/21/25 V.10 2025-12-21 17:14:25 +00:00
Flatlogic Bot
d532c98853 12/20/25 V.9 2025-12-21 15:54:28 +00:00
Flatlogic Bot
08816375b1 12/19/25 V.8 2025-12-19 13:36:07 +00:00
Flatlogic Bot
d9d90d51f1 12/19/25 V.7 2025-12-19 13:06:58 +00:00
Flatlogic Bot
7af97cfb6c 12/19/25 V.6 2025-12-19 06:10:49 +00:00
Flatlogic Bot
bf88d26075 12/19/25 V.5 2025-12-19 06:02:52 +00:00
Flatlogic Bot
17f25edfba 12/19/25 V.4 2025-12-19 05:38:20 +00:00
Flatlogic Bot
9e956531ac 12/19/25 V.3 2025-12-19 05:30:16 +00:00
Flatlogic Bot
da7e44a74e 12/19/25 V.2 2025-12-19 05:09:22 +00:00
Flatlogic Bot
5c4ffc3cf4 12/18/25 - V.1 2025-12-19 04:59:06 +00:00
6 changed files with 912 additions and 146 deletions

65
apply.php Normal file
View File

@ -0,0 +1,65 @@
<?php
require_once 'db/config.php';
require_once 'mail/MailService.php';
// 1. Validation
$name = trim($_POST['name'] ?? '');
$company = trim($_POST['company'] ?? '');
$email = trim($_POST['email'] ?? '');
$role = trim($_POST['role'] ?? '');
$error = '';
if (empty($name) || empty($company) || empty($email) || empty($role)) {
$error = 'All fields are required.';
} elseif (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
$error = 'Please enter a valid email address.';
}
if ($error) {
header('Location: index.php?error=' . urlencode($error) . '#apply');
exit;
}
// 2. Database Insert
try {
$pdo = db();
$stmt = $pdo->prepare(
'INSERT INTO applications (name, company, email, role) VALUES (?, ?, ?, ?)'
);
$stmt->execute([$name, $company, $email, $role]);
} catch (PDOException $e) {
// In a real app, log this error. For now, redirect with a generic error.
error_log('DB Error: ' . $e->getMessage());
header('Location: index.php?error=' . urlencode('A database error occurred.') . '#apply');
exit;
}
// 3. Email Notification
$to = getenv('MAIL_TO') ?: null; // Use admin email from .env
$subject = 'New FinMox Founding Access Application';
$htmlBody = "
<h1>New Application Received</h1>
<p>A new application has been submitted for FinMox founding access:</p>
<ul>
<li><strong>Name:</strong> " . htmlspecialchars($name) . "</li>
<li><strong>Company:</strong> " . htmlspecialchars($company) . "</li>
<li><strong>Email:</strong> " . htmlspecialchars($email) . "</li>
<li><strong>Role:</strong> " . htmlspecialchars($role) . "</li>
</ul>
";
$textBody = "New Application:\nName: $name\nCompany: $company\nEmail: $email\nRole: $role";
// Use MailService, but don't block the user if it fails
try {
MailService::sendMail($to, $subject, $htmlBody, $textBody);
} catch (Exception $e) {
// Log email error but don't prevent user from seeing success
error_log('MailService Error: ' . $e->getMessage());
}
// 4. Redirect to Success
header('Location: index.php?status=applied#apply');
exit;

53
assets/css/custom.css Normal file
View File

@ -0,0 +1,53 @@
:root{
--ink:#0b0b0c;
--paper:#fbfaf7;
--warm:#f2efe7;
--warm2:#ebe6da;
--line: rgba(11,11,12,.08);
--shadow: 0 18px 48px rgba(11,11,12,.10);
--shadow2: 0 10px 26px rgba(11,11,12,.10);
--radius: 28px;
}
html, body { height: 100%; }
body { font-family: 'Inter', sans-serif; background: var(--paper); color: var(--ink); }
/* page routing */
.page.hidden { display: none; }
/* warm glass cards */
.panel { border: 1px solid var(--line); border-radius: var(--radius); background: rgba(255,255,255,.70); box-shadow: var(--shadow2); backdrop-filter: blur(10px); }
.panel-strong { border: 1px solid var(--line); border-radius: var(--radius); background: rgba(255,255,255,.92); box-shadow: var(--shadow); }
.chip { border: 1px solid var(--line); border-radius: 999px; background: rgba(255,255,255,.75); }
.softline { border-color: var(--line); }
/* hero background */
.bg-warm {
background:
radial-gradient(1200px 520px at 20% 15%, rgba(243,236,223,.95), rgba(251,250,247,0) 60%),
radial-gradient(900px 520px at 85% 20%, rgba(236,232,219,.9), rgba(251,250,247,0) 55%),
radial-gradient(900px 520px at 55% 90%, rgba(241,238,230,.9), rgba(251,250,247,0) 60%),
var(--paper);
}
/* subtle motion */
.fade { transition: opacity .18s ease, transform .18s ease; }
.hoverlift { transition: transform .18s ease, box-shadow .18s ease; }
.hoverlift:hover { transform: translateY(-2px); box-shadow: var(--shadow); }
/* nav active state */
.navlink.active { font-weight: 700; }
/* mobile menu */
.drawer.hidden { display:none; }
/* details */
details[open] summary { font-weight: 700; }
summary { cursor: pointer; }
summary::-webkit-details-marker { display:none; }
/* input focus */
.chip:focus-within {
outline: 2px solid var(--ink);
outline-offset: 2px;
}

121
assets/js/main.js Normal file
View File

@ -0,0 +1,121 @@
const pages = ['home','problem','why','how','roi','pricing','who','trust','roadmap','faq','signin','apply'];
function openPage(pageId) {
if (!pages.includes(pageId)) {
console.warn(`Attempted to navigate to a non-existent page: ${pageId}`);
return; // Do not proceed if the page is not in the allowed list
}
// Hide all pages
document.querySelectorAll('.page').forEach(p => {
p.classList.add('hidden');
});
// Show the active page
const activePage = document.getElementById('page-' + pageId);
if (activePage) {
activePage.classList.remove('hidden');
} else {
// If no specific page content, default to home
document.getElementById('page-home').classList.remove('hidden');
}
// Update active link styling
document.querySelectorAll('.navlink').forEach(link => {
if (link.dataset.page === pageId) {
link.classList.add('active');
} else {
link.classList.remove('active');
}
});
// Smooth scroll to top
window.scrollTo({ top: 0, behavior: 'smooth' });
}
document.addEventListener('DOMContentLoaded', () => {
const navLinksContainer = document.getElementById('nav-links');
const mobileMenuContainer = document.getElementById('mobile-menu');
const footerLinksContainer = document.getElementById('footer-links');
const menuButton = document.getElementById('menu-button');
// Generate navigation links
let navHTML = '';
pages.forEach(page => {
let link = `#${page}`;
if (page === 'faq' || page === 'trust') {
link = `#${page}`;
}
navHTML += `<a href="${link}" class="navlink px-3 py-2 rounded-full hover:bg-gray-100" data-page="${page}">${page.charAt(0).toUpperCase() + page.slice(1)}</a>`;
});
navLinksContainer.innerHTML = navHTML;
mobileMenuContainer.innerHTML = navHTML.replace(/class="/g, 'class="block w-full text-left ');
// Generate footer links
if (footerLinksContainer) {
let footerHTML = '';
const footerPages = ['apply', 'signin', 'trust', 'faq'];
footerPages.forEach((page, index) => {
let link = `#${page}`;
if (page === 'faq' || page === 'trust') {
link = `#${page}`;
}
footerHTML += `<a href="${link}" class="underline navlink" data-page="${page}">${page.charAt(0).toUpperCase() + page.slice(1)}</a>`;
if (index < footerPages.length - 1) {
footerHTML += `<span class="opacity-50">·</span>`;
}
});
footerLinksContainer.innerHTML = footerHTML;
}
// Toggle mobile menu
menuButton.addEventListener('click', () => {
mobileMenuContainer.classList.toggle('hidden');
});
if (document.getElementById('page-home')) {
// Handle navigation clicks for SPA
document.querySelectorAll('.navlink').forEach(link => {
link.addEventListener('click', (e) => {
const page = link.dataset.page;
e.preventDefault();
openPage(link.dataset.page);
});
});
// Open page based on hash or default to 'home'
const initialPage = window.location.hash.substring(1) || 'home';
openPage(initialPage);
// Tab functionality for 'Why FinMox' page
const whyTabs = document.querySelectorAll('.why-tab');
const whyContents = document.querySelectorAll('.why-content');
whyTabs.forEach(tab => {
tab.addEventListener('click', () => {
const tabId = tab.dataset.tab;
// Update tab styles
whyTabs.forEach(t => {
if (t.dataset.tab === tabId) {
t.classList.add('bg-white', 'text-gray-900');
t.classList.remove('bg-gray-200', 'text-gray-500');
} else {
t.classList.remove('bg-white', 'text-gray-900');
t.classList.add('bg-gray-200', 'text-gray-500');
}
});
// Update content visibility
whyContents.forEach(c => {
if (c.dataset.content === tabId) {
c.classList.remove('hidden');
} else {
c.classList.add('hidden');
}
});
});
});
}
});

1
db/migration_ran.flag Normal file
View File

@ -0,0 +1 @@
ran

View File

@ -0,0 +1,8 @@
CREATE TABLE IF NOT EXISTS `applications` (
`id` INT AUTO_INCREMENT PRIMARY KEY,
`name` VARCHAR(255) NOT NULL,
`company` VARCHAR(255) NOT NULL,
`email` VARCHAR(255) NOT NULL,
`role` VARCHAR(255) NOT NULL,
`applied_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

810
index.php

File diff suppressed because one or more lines are too long