= htmlspecialchars($project['type']) ?>
= htmlspecialchars($project['title']) ?>
= htmlspecialchars($project['summary']) ?>
$apiUrl, CURLOPT_RETURNTRANSFER => true, CURLOPT_TIMEOUT => 5, ]); $resp = curl_exec($ch); curl_close($ch); return json_decode($resp ?: '[]', true) ?: []; } $projectDescription = $_SERVER['PROJECT_DESCRIPTION'] ?? ''; $projectImageUrl = $_SERVER['PROJECT_IMAGE_URL'] ?? ''; $now = date('Y-m-d H:i:s'); // Fetch images for sections $heroImages = get_images('studio,workspace,creative,editorial'); $workImages = get_images('design,code,analytics'); $testimonialImages = get_images('person,professional,business'); $formData = [ 'name' => '', 'email' => '', 'message' => '', ]; $errors = []; $toast = null; $toastType = 'success'; $mailWarning = null; function ensure_contact_table(): void { db()->exec( "CREATE TABLE IF NOT EXISTS contact_requests ( id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY, name VARCHAR(120) NOT NULL, email VARCHAR(160) NOT NULL, message TEXT NOT NULL, status VARCHAR(30) NOT NULL DEFAULT 'new', ip_address VARCHAR(45) DEFAULT NULL, user_agent VARCHAR(255) DEFAULT NULL, created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4" ); } if ($_SERVER['REQUEST_METHOD'] === 'POST') { $formData['name'] = trim($_POST['name'] ?? ''); $formData['email'] = trim($_POST['email'] ?? ''); $formData['message'] = trim($_POST['message'] ?? ''); if (mb_strlen($formData['name']) < 2) { $errors[] = 'Please enter your name.'; } if (!filter_var($formData['email'], FILTER_VALIDATE_EMAIL)) { $errors[] = 'Please provide a valid email address.'; } if (mb_strlen($formData['message']) < 10) { $errors[] = 'Please add a brief message (at least 10 characters).'; } if (!$errors) { try { ensure_contact_table(); $stmt = db()->prepare( 'INSERT INTO contact_requests (name, email, message, ip_address, user_agent) VALUES (:name, :email, :message, :ip, :agent)' ); $stmt->execute([ ':name' => $formData['name'], ':email' => $formData['email'], ':message' => $formData['message'], ':ip' => $_SERVER['REMOTE_ADDR'] ?? null, ':agent' => $_SERVER['HTTP_USER_AGENT'] ?? null, ]); $to = getenv('MAIL_TO') ?: null; $mailRes = MailService::sendContactMessage( $formData['name'], $formData['email'], $formData['message'], $to, 'New portfolio inquiry' ); if (empty($mailRes['success'])) { $mailWarning = 'Saved your message, but email delivery failed. Please confirm SMTP settings.'; } $toast = 'Thanks for reaching out! I will reply within 1–2 business days.'; $toastType = $mailWarning ? 'warning' : 'success'; $formData = ['name' => '', 'email' => '', 'message' => '']; } catch (Throwable $e) { $errors[] = 'Something went wrong while saving your message. Please try again.'; } } } ?>
Product & Brand Designer
I help modern teams turn complex ideas into elegant product experiences. Focused on UX strategy, UI systems, and launch-ready web design.
Current focus
Visual systems, motion, and product storytelling
Designed to keep the page lively without overpowering the content.
A handful of case studies covering product strategy, UX, and UI design.
= htmlspecialchars($project['type']) ?>
= htmlspecialchars($project['summary']) ?>
I’m a multidisciplinary designer with 9+ years building digital products for startups and enterprise teams. I specialize in UX direction, visual systems, and stakeholder alignment that turns ideas into shipped work.
Clients
Stripe, Calm, Notion
Engagements
Strategy · Design · Launch
Short notes from founders and product leads.
= htmlspecialchars($item['quote']) ?>
= htmlspecialchars($item['name']) ?>
Send a short note about your project or role. I’ll reply with availability, timing, and next steps.
This is for testing purposes only — Flatlogic does not guarantee usage of the mail server. Please set up your own SMTP in .env (MAIL_/SMTP_ vars) with out AI Agent.
Admin view: View contact requests