<!doctype html>
<html lang="en" class="h-full">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>WordPress Training Registration</title>
<script src="https://cdn.tailwindcss.com/3.4.17"></script>
<script src="https://cdn.jsdelivr.net/npm/lucide@0.263.0/dist/umd/lucide.min.js"></script>
<script src="/_sdk/element_sdk.js"></script>
<script src="/_sdk/data_sdk.js"></script>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link href="https://fonts.googleapis.com/css2?family=DM+Sans:ital,opsz,wght@0,9..40,300;0,9..40,400;0,9..40,500;0,9..40,600;0,9..40,700;1,9..40,400&display=swap" rel="stylesheet">
<script>
tailwind.config = {
theme: {
extend: {
colors: {
forest: '#0B3D2E',
lime: '#7ED957',
limeDark: '#5CB838',
cream: '#F8FAF5',
slate: '#1A1A2E',
},
fontFamily: {
display: ['"Playfair Display"', 'Georgia', 'serif'],
body: ['"DM Sans"', 'system-ui', 'sans-serif'],
}
}
}
}
</script>
<style>
html { height: 100%; }
body { height: 100%; margin: 0; }
/* Animations */
@keyframes fadeUp {
from { opacity: 0; transform: translateY(24px); }
to { opacity: 1; transform: translateY(0); }
}
@keyframes fadeIn {
from { opacity: 0; }
to { opacity: 1; }
}
@keyframes scaleIn {
from { opacity: 0; transform: scale(0.92); }
to { opacity: 1; transform: scale(1); }
}
@keyframes shimmer {
0% { background-position: -200% 0; }
100% { background-position: 200% 0; }
}
@keyframes pulse-ring {
0% { transform: scale(0.8); opacity: 1; }
100% { transform: scale(2.2); opacity: 0; }
}
@keyframes checkDraw {
from { stroke-dashoffset: 48; }
to { stroke-dashoffset: 0; }
}
@keyframes float {
0%, 100% { transform: translateY(0); }
50% { transform: translateY(-6px); }
}
.anim-fade-up { animation: fadeUp 0.7s ease-out both; }
.anim-fade-in { animation: fadeIn 0.5s ease-out both; }
.anim-scale-in { animation: scaleIn 0.5s ease-out both; }
.anim-float { animation: float 3s ease-in-out infinite; }
.delay-1 { animation-delay: 0.1s; }
.delay-2 { animation-delay: 0.2s; }
.delay-3 { animation-delay: 0.3s; }
.delay-4 { animation-delay: 0.4s; }
.delay-5 { animation-delay: 0.5s; }
.delay-6 { animation-delay: 0.6s; }
/* Shimmer button */
.btn-shimmer {
background: linear-gradient(110deg, #7ED957 0%, #7ED957 40%, #a8f07a 50%, #7ED957 60%, #7ED957 100%);
background-size: 200% 100%;
animation: shimmer 3s ease-in-out infinite;
}
.btn-shimmer:hover {
background: #5CB838;
animation: none;
}
/* Progress bar transition */
.progress-fill {
transition: width 0.6s cubic-bezier(0.4, 0, 0.2, 1);
}
/* Form transitions */
.step-container {
transition: opacity 0.4s ease, transform 0.4s ease;
}
.step-hidden {
opacity: 0;
transform: translateY(16px);
pointer-events: none;
position: absolute;
visibility: hidden;
}
.step-visible {
opacity: 1;
transform: translateY(0);
pointer-events: auto;
position: relative;
visibility: visible;
}
/* Input styling */
.form-input {
transition: border-color 0.2s, box-shadow 0.2s;
}
.form-input:focus {
border-color: #7ED957;
box-shadow: 0 0 0 3px rgba(126, 217, 87, 0.15);
}
/* Radio/checkbox cards */
.option-card {
transition: all 0.2s ease;
cursor: pointer;
}
.option-card:hover {
border-color: #7ED957;
background: #F8FAF5;
}
.option-card.selected {
border-color: #7ED957;
background: linear-gradient(135deg, #F8FAF5, #eef8e6);
box-shadow: 0 0 0 2px rgba(126, 217, 87, 0.3);
}
/* Error shake */
@keyframes shake {
0%, 100% { transform: translateX(0); }
25% { transform: translateX(-4px); }
75% { transform: translateX(4px); }
}
.shake { animation: shake 0.3s ease; }
/* Success check animation */
.check-circle {
stroke-dasharray: 166;
stroke-dashoffset: 166;
animation: checkDraw 0.6s ease forwards 0.3s;
}
.check-mark {
stroke-dasharray: 48;
stroke-dashoffset: 48;
animation: checkDraw 0.4s ease forwards 0.7s;
}
/* Scrollbar */
::-webkit-scrollbar { width: 6px; }
::-webkit-scrollbar-track { background: transparent; }
::-webkit-scrollbar-thumb { background: #ccc; border-radius: 3px; }
/* Toast */
.toast {
transform: translateY(-20px);
opacity: 0;
transition: all 0.3s ease;
}
.toast.show {
transform: translateY(0);
opacity: 1;
}
/* Highlight card */
.highlight-card {
transition: transform 0.3s ease, box-shadow 0.3s ease;
}
.highlight-card:hover {
transform: translateY(-4px);
box-shadow: 0 12px 32px rgba(11, 61, 46, 0.12);
}
</style>
<style>body { box-sizing: border-box; }</style>
</head>
<body class="h-full">
<div id="app-wrapper" class="w-full h-full overflow-auto bg-white" style="font-family: 'DM Sans', system-ui, sans-serif;">
<!-- Toast notification container -->
<div id="toast-container" class="fixed top-4 right-4 z-50 flex flex-col gap-2"></div><!-- ==================== HERO SECTION ==================== -->
<header id="hero-section" class="relative w-full overflow-hidden" style="background: linear-gradient(135deg, #0B3D2E 0%, #0f5a3e 50%, #0B3D2E 100%);">
<!-- Bold geometric shapes -->
<div class="absolute top-0 right-0 w-96 h-96 rounded-full opacity-20" style="background: radial-gradient(circle, #7ED957, transparent); filter: blur(60px); transform: translate(40%, -40%);"></div>
<div class="absolute -bottom-20 -left-20 w-80 h-80 rounded-full opacity-15" style="background: radial-gradient(circle, #7ED957, transparent); filter: blur(60px);"></div>
<div class="absolute top-1/3 right-1/4 w-64 h-64 opacity-10" style="background: linear-gradient(45deg, #7ED957, transparent); clip-path: polygon(0 0, 100% 0, 50% 100%);"></div>
<div class="relative max-w-6xl mx-auto px-4 sm:px-6 lg:px-8 py-16 sm:py-24 lg:py-32 text-center">
<!-- Announcement badge -->
<div class="anim-fade-up delay-1 flex items-center justify-center gap-2 mb-8 w-full">
<span class="inline-flex items-center gap-2 px-4 py-2 rounded-full text-xs font-bold tracking-widest uppercase" style="background: linear-gradient(135deg, rgba(126, 217, 87, 0.2), rgba(126, 217, 87, 0.1)); color: #7ED957; border: 1px solid rgba(126,217,87,0.3);"> <span class="inline-block w-2 h-2 rounded-full bg-lime animate-pulse"></span> Limited Slots Available </span>
</div><!-- Main headline -->
<h1 id="hero-title" class="anim-fade-up delay-2 text-4xl sm:text-5xl lg:text-7xl xl:text-8xl font-black text-white leading-[1.1] mb-6" style="font-family: Arial, sans-serif; letter-spacing: -0.02em;">Build Professional Websites<br>
in 4 Weeks</h1>
<p id="hero-subtitle" class="anim-fade-up delay-3 text-lg sm:text-xl lg:text-2xl text-emerald-100 mb-3 font-medium max-w-3xl mx-auto" style="font-family: Arial, sans-serif;">Learn WordPress from Beginner to Advanced, hands-on, practical training designed for results.</p>
<p id="hero-tagline" class="anim-fade-up delay-3 text-base sm:text-lg text-emerald-300/80 mb-10 max-w-2xl mx-auto" style="font-family: Arial, sans-serif;">Physical Practical / Online Sessions · 4 Weeks · 12 Hours Total</p><!-- Stats row - Bold layout -->
<div class="anim-fade-up delay-4 grid grid-cols-2 sm:grid-cols-4 gap-3 sm:gap-4 mb-10 max-w-3xl mx-auto">
<div class="highlight-card flex flex-col items-center justify-center px-4 py-4 sm:py-6 rounded-2xl" style="background: linear-gradient(135deg, rgba(126,217,87,0.15), rgba(126,217,87,0.05)); border: 1px solid rgba(126,217,87,0.2); backdrop-filter: blur(10px);">
<div class="text-2xl sm:text-3xl font-black text-lime mb-1">
4
</div>
<div class="text-xs sm:text-sm text-emerald-200 font-semibold">
Week Duration
</div>
</div>
<div class="highlight-card flex flex-col items-center justify-center px-4 py-4 sm:py-6 rounded-2xl" style="background: linear-gradient(135deg, rgba(126,217,87,0.15), rgba(126,217,87,0.05)); border: 1px solid rgba(126,217,87,0.2); backdrop-filter: blur(10px);">
<div class="text-2xl sm:text-3xl font-black text-lime mb-1">
12
</div>
<div class="text-xs sm:text-sm text-emerald-200 font-semibold">
Hours Total
</div>
</div>
<div class="highlight-card flex flex-col items-center justify-center px-4 py-4 sm:py-6 rounded-2xl" style="background: linear-gradient(135deg, rgba(126,217,87,0.15), rgba(126,217,87,0.05)); border: 1px solid rgba(126,217,87,0.2); backdrop-filter: blur(10px);">
<div class="text-2xl sm:text-3xl font-black text-lime mb-1">
3hr
</div>
<div class="text-xs sm:text-sm text-emerald-200 font-semibold">
Per Session
</div>
</div>
<div class="highlight-card flex flex-col items-center justify-center px-4 py-4 sm:py-6 rounded-2xl" style="background: linear-gradient(135deg, rgba(126,217,87,0.15), rgba(126,217,87,0.05)); border: 1px solid rgba(126,217,87,0.2); backdrop-filter: blur(10px);">
<div class="text-2xl sm:text-3xl font-black text-lime mb-1">
Sat
</div>
<div class="text-xs sm:text-sm text-emerald-200 font-semibold">
Every Session
</div>
</div>
</div><!-- Features grid - Bold icons -->
<div class="anim-fade-up delay-4 grid grid-cols-2 lg:grid-cols-4 gap-3 mb-10 max-w-3xl mx-auto">
<div class="highlight-card flex items-center gap-3 px-4 py-3 rounded-xl" style="background: rgba(255,255,255,0.08); border: 1px solid rgba(126,217,87,0.2);">
<div class="flex-shrink-0 w-10 h-10 rounded-xl flex items-center justify-center" style="background: linear-gradient(135deg, rgba(126,217,87,0.3), rgba(126,217,87,0.1));">
<i data-lucide="monitor" style="width:20px;height:20px;color:#7ED957;stroke-width:2.5;"></i>
</div><span class="text-white text-xs sm:text-sm font-semibold">Real Websites</span>
</div>
<div class="highlight-card flex items-center gap-3 px-4 py-3 rounded-xl" style="background: rgba(255,255,255,0.08); border: 1px solid rgba(126,217,87,0.2);">
<div class="flex-shrink-0 w-10 h-10 rounded-xl flex items-center justify-center" style="background: linear-gradient(135deg, rgba(126,217,87,0.3), rgba(126,217,87,0.1));">
<i data-lucide="shopping-cart" style="width:20px;height:20px;color:#7ED957;stroke-width:2.5;"></i>
</div><span class="text-white text-xs sm:text-sm font-semibold">E-commerce</span>
</div>
<div class="highlight-card flex items-center gap-3 px-4 py-3 rounded-xl" style="background: rgba(255,255,255,0.08); border: 1px solid rgba(126,217,87,0.2);">
<div class="flex-shrink-0 w-10 h-10 rounded-xl flex items-center justify-center" style="background: linear-gradient(135deg, rgba(126,217,87,0.3), rgba(126,217,87,0.1));">
<i data-lucide="search" style="width:20px;height:20px;color:#7ED957;stroke-width:2.5;"></i>
</div><span class="text-white text-xs sm:text-sm font-semibold">SEO Basics</span>
</div>
<div class="highlight-card flex items-center gap-3 px-4 py-3 rounded-xl" style="background: rgba(255,255,255,0.08); border: 1px solid rgba(126,217,87,0.2);">
<div class="flex-shrink-0 w-10 h-10 rounded-xl flex items-center justify-center" style="background: linear-gradient(135deg, rgba(126,217,87,0.3), rgba(126,217,87,0.1));">
<i data-lucide="globe" style="width:20px;height:20px;color:#7ED957;stroke-width:2.5;"></i>
</div><span class="text-white text-xs sm:text-sm font-semibold">Hosting</span>
</div>
</div><!-- Key info boxes -->
<div class="anim-fade-up delay-5 flex flex-col sm:flex-row flex-wrap items-center justify-center gap-3 mb-10">
<div class="flex items-center gap-3 px-5 py-3 rounded-xl text-white text-sm font-semibold" style="background: linear-gradient(135deg, rgba(126,217,87,0.15), rgba(126,217,87,0.05)); border: 1px solid rgba(126,217,87,0.2);">
<i data-lucide="calendar" style="width:18px;height:18px;color:#7ED957;"></i> <span>Starts: <strong id="hero-start-date">4th April, 2026</strong></span>
</div>
<div class="flex items-center gap-3 px-5 py-3 rounded-xl text-white text-sm font-semibold" style="background: linear-gradient(135deg, rgba(126,217,87,0.15), rgba(126,217,87,0.05)); border: 1px solid rgba(126,217,87,0.2);">
<i data-lucide="map-pin" style="width:18px;height:18px;color:#7ED957;"></i> <span id="hero-venue">Basy Media, Teshie Rasta Bushroad, Accra</span>
</div>
<div class="flex items-center gap-3 px-5 py-3 rounded-xl text-white text-sm font-semibold" style="background: linear-gradient(135deg, rgba(126,217,87,0.15), rgba(126,217,87,0.05)); border: 1px solid rgba(126,217,87,0.2);">
<i data-lucide="phone" style="width:18px;height:18px;color:#7ED957;"></i> <span id="hero-contact">0539182619</span>
</div>
</div><!-- CTA Section -->
<div class="anim-fade-up delay-6 flex flex-col sm:flex-row items-center justify-center gap-5">
<div class="px-6 py-5 rounded-2xl" style="background: linear-gradient(135deg, rgba(126,217,87,0.2), rgba(126,217,87,0.1)); border: 1px solid rgba(126,217,87,0.3);">
<div class="text-emerald-300 text-xs font-bold uppercase tracking-wider mb-1" style="font-family: Arial, sans-serif;">
Training Investment
</div>
<div id="hero-fee" class="text-white text-3xl sm:text-4xl font-black" style="font-family: Arial, sans-serif;">
GHS 2,000
</div>
</div><button id="hero-cta-btn" onclick="scrollToForm()" class="btn-shimmer px-8 sm:px-10 py-4 sm:py-5 rounded-2xl text-forest font-black text-base sm:text-lg shadow-xl hover:shadow-2xl transition-all transform hover:-translate-y-1 flex items-center gap-2"> <span>Register Now</span> <i data-lucide="arrow-right" style="width:20px;height:20px;"></i> </button>
</div><!-- Trust badge -->
<div class="anim-fade-up delay-6 mt-8 pt-8 border-t border-white/10 max-w-3xl mx-auto">
<p class="text-emerald-300/70 text-xs sm:text-sm font-medium flex items-center justify-center gap-2"><i data-lucide="shield-check" style="width:16px;height:16px;color:#7ED957;"></i> 100% Practical Training · Hands-on Projects · Certificate Upon Completion</p>
</div>
</div>
</header><!-- ==================== FORM SECTION ==================== -->
<section id="form-section" class="w-full" style="background: linear-gradient(180deg, #F8FAF5, #ffffff);">
<div class="max-w-3xl mx-auto px-4 sm:px-6 lg:px-8 py-12 sm:py-16">
<!-- Progress bar -->
<div id="progress-wrapper" class="mb-10">
<div class="flex items-center justify-between mb-3">
<span id="step-label" class="text-sm font-semibold text-forest">Step 1 of 4</span> <span id="step-name" class="text-sm text-gray-500">Personal Details</span>
</div>
<div class="w-full h-2 rounded-full bg-gray-200 overflow-hidden">
<div id="progress-bar" class="progress-fill h-full rounded-full" style="width: 25%; background: linear-gradient(90deg, #0B3D2E, #7ED957);"></div>
</div><!-- Step indicators -->
<div class="flex justify-between mt-3">
<button onclick="goToStep(1)" class="step-dot flex items-center gap-1.5 text-xs font-medium text-forest opacity-100 transition-opacity" data-step="1"> <span class="w-6 h-6 rounded-full bg-forest text-white flex items-center justify-center text-xs font-bold">1</span> <span class="hidden sm:inline">Details</span> </button> <button onclick="goToStep(2)" class="step-dot flex items-center gap-1.5 text-xs font-medium text-gray-400 transition-opacity" data-step="2"> <span class="w-6 h-6 rounded-full bg-gray-300 text-white flex items-center justify-center text-xs font-bold">2</span> <span class="hidden sm:inline">Preferences</span> </button> <button onclick="goToStep(3)" class="step-dot flex items-center gap-1.5 text-xs font-medium text-gray-400 transition-opacity" data-step="3"> <span class="w-6 h-6 rounded-full bg-gray-300 text-white flex items-center justify-center text-xs font-bold">3</span> <span class="hidden sm:inline">Review</span> </button> <button onclick="goToStep(4)" class="step-dot flex items-center gap-1.5 text-xs font-medium text-gray-400 transition-opacity" data-step="4" disabled> <span class="w-6 h-6 rounded-full bg-gray-300 text-white flex items-center justify-center text-xs font-bold">4</span> <span class="hidden sm:inline">Done</span> </button>
</div>
</div><!-- Form container (relative for step positioning) -->
<div id="form-container" class="relative">
<!-- ===== STEP 1: Personal Details ===== -->
<div id="step-1" class="step-container step-visible">
<div class="bg-white rounded-2xl shadow-lg border border-gray-100 p-6 sm:p-8">
<div class="flex items-center gap-3 mb-6">
<div class="w-10 h-10 rounded-xl bg-forest flex items-center justify-center">
<i data-lucide="user" style="width:20px;height:20px;color:#7ED957;"></i>
</div>
<div>
<h2 class="text-xl font-bold text-forest" style="font-family: 'Playfair Display', Georgia, serif;">Personal Details</h2>
<p class="text-sm text-gray-500">Tell us about yourself</p>
</div>
</div>
<div class="grid grid-cols-1 sm:grid-cols-2 gap-4">
<!-- Full Name -->
<div class="sm:col-span-2">
<label for="full_name" class="block text-sm font-medium text-gray-700 mb-1.5">Full Name <span class="text-red-500">*</span></label> <input type="text" id="full_name" name="full_name" required placeholder="e.g. Kwame Asante" class="form-input w-full px-4 py-3 rounded-xl border border-gray-200 text-sm outline-none bg-gray-50/50">
<p class="error-msg text-xs text-red-500 mt-1 hidden" data-for="full_name"></p>
</div><!-- Phone -->
<div>
<label for="phone" class="block text-sm font-medium text-gray-700 mb-1.5">Phone Number <span class="text-red-500">*</span></label> <input type="tel" id="phone" name="phone" required placeholder="e.g. 0241234567" class="form-input w-full px-4 py-3 rounded-xl border border-gray-200 text-sm outline-none bg-gray-50/50">
<p class="error-msg text-xs text-red-500 mt-1 hidden" data-for="phone"></p>
</div><!-- WhatsApp -->
<div>
<label for="whatsapp" class="block text-sm font-medium text-gray-700 mb-1.5">WhatsApp Number</label> <input type="tel" id="whatsapp" name="whatsapp" placeholder="e.g. 0539182619" class="form-input w-full px-4 py-3 rounded-xl border border-gray-200 text-sm outline-none bg-gray-50/50">
<p class="error-msg text-xs text-red-500 mt-1 hidden" data-for="whatsapp"></p>
</div><!-- Email -->
<div class="sm:col-span-2">
<label for="email" class="block text-sm font-medium text-gray-700 mb-1.5">Email Address <span class="text-red-500">*</span></label> <input type="email" id="email" name="email" required placeholder="e.g. kwame@email.com" class="form-input w-full px-4 py-3 rounded-xl border border-gray-200 text-sm outline-none bg-gray-50/50">
<p class="error-msg text-xs text-red-500 mt-1 hidden" data-for="email"></p>
</div><!-- Gender -->
<div>
<label for="gender" class="block text-sm font-medium text-gray-700 mb-1.5">Gender <span class="text-red-500">*</span></label> <select id="gender" name="gender" required class="form-input w-full px-4 py-3 rounded-xl border border-gray-200 text-sm outline-none bg-gray-50/50 appearance-none" style="background-image: url('data:image/svg+xml;utf8,<svg xmlns=%22http://www.w3.org/2000/svg%22 width=%2212%22 height=%2212%22 viewBox=%220 0 24 24%22 fill=%22none%22 stroke=%22%23999%22 stroke-width=%222%22><polyline points=%226 9 12 15 18 9%22/></svg>'); background-repeat: no-repeat; background-position: right 12px center;"> <option value="">Select gender</option> <option value="Male">Male</option> <option value="Female">Female</option> <option value="Other">Other</option> </select>
<p class="error-msg text-xs text-red-500 mt-1 hidden" data-for="gender"></p>
</div><!-- Occupation -->
<div>
<label for="occupation" class="block text-sm font-medium text-gray-700 mb-1.5">Occupation</label> <input type="text" id="occupation" name="occupation" placeholder="e.g. Student, Teacher" class="form-input w-full px-4 py-3 rounded-xl border border-gray-200 text-sm outline-none bg-gray-50/50">
<p class="error-msg text-xs text-red-500 mt-1 hidden" data-for="occupation"></p>
</div><!-- City -->
<div>
<label for="city" class="block text-sm font-medium text-gray-700 mb-1.5">City / Town</label> <input type="text" id="city" name="city" placeholder="e.g. Accra" class="form-input w-full px-4 py-3 rounded-xl border border-gray-200 text-sm outline-none bg-gray-50/50">
<p class="error-msg text-xs text-red-500 mt-1 hidden" data-for="city"></p>
</div><!-- Region -->
<div>
<label for="region" class="block text-sm font-medium text-gray-700 mb-1.5">Region <span class="text-red-500">*</span></label> <select id="region" name="region" required class="form-input w-full px-4 py-3 rounded-xl border border-gray-200 text-sm outline-none bg-gray-50/50 appearance-none" style="background-image: url('data:image/svg+xml;utf8,<svg xmlns=%22http://www.w3.org/2000/svg%22 width=%2212%22 height=%2212%22 viewBox=%220 0 24 24%22 fill=%22none%22 stroke=%22%23999%22 stroke-width=%222%22><polyline points=%226 9 12 15 18 9%22/></svg>'); background-repeat: no-repeat; background-position: right 12px center;"> <option value="">Select region</option> <option>Greater Accra</option> <option>Ashanti</option> <option>Western</option> <option>Eastern</option> <option>Central</option> <option>Northern</option> <option>Volta</option> <option>Upper East</option> <option>Upper West</option> <option>Bono</option> <option>Bono East</option> <option>Ahafo</option> <option>Savannah</option> <option>North East</option> <option>Oti</option> <option>Western North</option> </select>
<p class="error-msg text-xs text-red-500 mt-1 hidden" data-for="region"></p>
</div><!-- How heard -->
<div>
<label for="heard_from" class="block text-sm font-medium text-gray-700 mb-1.5">How did you hear about us?</label> <select id="heard_from" name="heard_from" class="form-input w-full px-4 py-3 rounded-xl border border-gray-200 text-sm outline-none bg-gray-50/50 appearance-none" style="background-image: url('data:image/svg+xml;utf8,<svg xmlns=%22http://www.w3.org/2000/svg%22 width=%2212%22 height=%2212%22 viewBox=%220 0 24 24%22 fill=%22none%22 stroke=%22%23999%22 stroke-width=%222%22><polyline points=%226 9 12 15 18 9%22/></svg>'); background-repeat: no-repeat; background-position: right 12px center;"> <option value="">Select option</option> <option>Social Media</option> <option>Friend / Referral</option> <option>Google Search</option> <option>Flyer / Poster</option> <option>WhatsApp</option> <option>Other</option> </select>
</div><!-- Prior experience -->
<div class="sm:col-span-2">
<label class="block text-sm font-medium text-gray-700 mb-2">Do you have any prior website experience? <span class="text-red-500">*</span></label>
<div class="flex gap-3">
<label class="option-card flex-1 flex items-center gap-3 px-4 py-3 rounded-xl border-2 border-gray-200" id="exp-yes-card"> <input type="radio" name="prior_experience" value="Yes" class="accent-lime w-4 h-4" onchange="selectExpCard(this)"> <span class="text-sm font-medium text-gray-700">Yes</span> </label> <label class="option-card flex-1 flex items-center gap-3 px-4 py-3 rounded-xl border-2 border-gray-200" id="exp-no-card"> <input type="radio" name="prior_experience" value="No" class="accent-lime w-4 h-4" onchange="selectExpCard(this)"> <span class="text-sm font-medium text-gray-700">No</span> </label>
</div>
<p class="error-msg text-xs text-red-500 mt-1 hidden" data-for="prior_experience"></p>
</div>
</div><!-- Next button -->
<div class="mt-8 flex justify-end">
<button onclick="nextStep(1)" class="flex items-center gap-2 px-6 py-3 rounded-xl bg-forest text-white font-semibold text-sm hover:bg-forest/90 transition-colors shadow-md"> Next Step <i data-lucide="arrow-right" style="width:16px;height:16px;"></i> </button>
</div>
</div>
</div><!-- ===== STEP 2: Training Preferences ===== -->
<div id="step-2" class="step-container step-hidden">
<div class="bg-white rounded-2xl shadow-lg border border-gray-100 p-6 sm:p-8">
<div class="flex items-center gap-3 mb-6">
<div class="w-10 h-10 rounded-xl bg-forest flex items-center justify-center">
<i data-lucide="settings" style="width:20px;height:20px;color:#7ED957;"></i>
</div>
<div>
<h2 class="text-xl font-bold text-forest" style="font-family: 'Playfair Display', Georgia, serif;">Training Preferences</h2>
<p class="text-sm text-gray-500">Customize your learning experience</p>
</div>
</div>
<div class="space-y-5">
<!-- Attendance Mode -->
<div>
<label class="block text-sm font-medium text-gray-700 mb-2">Preferred Mode of Attendance <span class="text-red-500">*</span></label>
<div class="grid grid-cols-2 gap-3">
<label class="option-card flex flex-col items-center gap-2 px-4 py-4 rounded-xl border-2 border-gray-200 text-center" id="mode-physical-card"> <i data-lucide="building" style="width:24px;height:24px;color:#0B3D2E;"></i> <input type="radio" name="attendance_mode" value="Physical" class="accent-lime w-4 h-4" onchange="selectModeCard(this)"> <span class="text-sm font-semibold text-gray-700">Physical</span> </label> <label class="option-card flex flex-col items-center gap-2 px-4 py-4 rounded-xl border-2 border-gray-200 text-center" id="mode-online-card"> <i data-lucide="wifi" style="width:24px;height:24px;color:#0B3D2E;"></i> <input type="radio" name="attendance_mode" value="Online" class="accent-lime w-4 h-4" onchange="selectModeCard(this)"> <span class="text-sm font-semibold text-gray-700">Online</span> </label>
</div><!-- Conditional notes -->
<div id="mode-physical-note" class="hidden mt-3 p-3 rounded-xl bg-emerald-50 border border-emerald-200 text-xs text-emerald-800 flex items-start gap-2">
<i data-lucide="map-pin" style="width:14px;height:14px;flex-shrink:0;margin-top:1px;"></i> <span><strong>Venue:</strong> <span id="note-venue">Basy Media, Teshie Rasta Bushroad, Accra</span>. Please arrive 15 minutes before each session.</span>
</div>
<div id="mode-online-note" class="hidden mt-3 p-3 rounded-xl bg-blue-50 border border-blue-200 text-xs text-blue-800 flex items-start gap-2">
<i data-lucide="info" style="width:14px;height:14px;flex-shrink:0;margin-top:1px;"></i> <span>Online access details (Zoom/Google Meet link) will be shared after successful registration and payment.</span>
</div>
<p class="error-msg text-xs text-red-500 mt-1 hidden" data-for="attendance_mode"></p>
</div><!-- Laptop -->
<div>
<label class="block text-sm font-medium text-gray-700 mb-2">Laptop Availability <span class="text-red-500">*</span></label>
<div class="grid grid-cols-1 sm:grid-cols-2 gap-3">
<label class="option-card flex items-center gap-3 px-4 py-3 rounded-xl border-2 border-gray-200" id="laptop-yes-card"> <input type="radio" name="laptop_availability" value="I have a laptop" class="accent-lime w-4 h-4" onchange="selectLaptopCard(this)">
<div class="flex items-center gap-2">
<i data-lucide="laptop" style="width:16px;height:16px;color:#0B3D2E;"></i> <span class="text-sm font-medium text-gray-700">I have a laptop</span>
</div></label> <label class="option-card flex items-center gap-3 px-4 py-3 rounded-xl border-2 border-gray-200" id="laptop-no-card"> <input type="radio" name="laptop_availability" value="I need assistance" class="accent-lime w-4 h-4" onchange="selectLaptopCard(this)">
<div class="flex items-center gap-2">
<i data-lucide="help-circle" style="width:16px;height:16px;color:#0B3D2E;"></i> <span class="text-sm font-medium text-gray-700">I need assistance</span>
</div></label>
</div>
<p class="error-msg text-xs text-red-500 mt-1 hidden" data-for="laptop_availability"></p>
</div><!-- Skill Level -->
<div>
<label class="block text-sm font-medium text-gray-700 mb-2">Skill Level <span class="text-red-500">*</span></label>
<div class="grid grid-cols-3 gap-3">
<label class="option-card flex flex-col items-center gap-1.5 px-3 py-3 rounded-xl border-2 border-gray-200 text-center" id="skill-beginner-card"> <span class="text-lg">🌱</span> <input type="radio" name="skill_level" value="Beginner" class="accent-lime w-4 h-4" onchange="selectSkillCard(this)"> <span class="text-xs font-semibold text-gray-700">Beginner</span> </label> <label class="option-card flex flex-col items-center gap-1.5 px-3 py-3 rounded-xl border-2 border-gray-200 text-center" id="skill-intermediate-card"> <span class="text-lg">🌿</span> <input type="radio" name="skill_level" value="Intermediate" class="accent-lime w-4 h-4" onchange="selectSkillCard(this)"> <span class="text-xs font-semibold text-gray-700">Intermediate</span> </label> <label class="option-card flex flex-col items-center gap-1.5 px-3 py-3 rounded-xl border-2 border-gray-200 text-center" id="skill-advanced-card"> <span class="text-lg">🌳</span> <input type="radio" name="skill_level" value="Advanced" class="accent-lime w-4 h-4" onchange="selectSkillCard(this)"> <span class="text-xs font-semibold text-gray-700">Advanced</span> </label>
</div>
<p class="error-msg text-xs text-red-500 mt-1 hidden" data-for="skill_level"></p>
</div><!-- Main Goal -->
<div>
<label for="main_goal" class="block text-sm font-medium text-gray-700 mb-1.5">Main Goal for Joining <span class="text-red-500">*</span></label> <select id="main_goal" name="main_goal" required class="form-input w-full px-4 py-3 rounded-xl border border-gray-200 text-sm outline-none bg-gray-50/50 appearance-none" style="background-image: url('data:image/svg+xml;utf8,<svg xmlns=%22http://www.w3.org/2000/svg%22 width=%2212%22 height=%2212%22 viewBox=%220 0 24 24%22 fill=%22none%22 stroke=%22%23999%22 stroke-width=%222%22><polyline points=%226 9 12 15 18 9%22/></svg>'); background-repeat: no-repeat; background-position: right 12px center;"> <option value="">Select your main goal</option> <option>Learn for business</option> <option>Learn for freelancing</option> <option>Learn for job opportunities</option> <option>Learn for personal development</option> </select>
<p class="error-msg text-xs text-red-500 mt-1 hidden" data-for="main_goal"></p>
</div><!-- Emergency Contact -->
<div class="grid grid-cols-1 sm:grid-cols-2 gap-4 pt-2 border-t border-gray-100">
<div>
<label for="emergency_name" class="block text-sm font-medium text-gray-700 mb-1.5">Emergency Contact Name</label> <input type="text" id="emergency_name" name="emergency_name" placeholder="e.g. Ama Mensah" class="form-input w-full px-4 py-3 rounded-xl border border-gray-200 text-sm outline-none bg-gray-50/50">
</div>
<div>
<label for="emergency_phone" class="block text-sm font-medium text-gray-700 mb-1.5">Emergency Contact Phone</label> <input type="tel" id="emergency_phone" name="emergency_phone" placeholder="e.g. 0201234567" class="form-input w-full px-4 py-3 rounded-xl border border-gray-200 text-sm outline-none bg-gray-50/50">
</div>
</div><!-- Additional Notes -->
<div>
<label for="additional_notes" class="block text-sm font-medium text-gray-700 mb-1.5">Additional Notes / Questions</label> <textarea id="additional_notes" name="additional_notes" rows="3" placeholder="Any questions or special requests..." class="form-input w-full px-4 py-3 rounded-xl border border-gray-200 text-sm outline-none bg-gray-50/50 resize-none"></textarea>
</div>
</div><!-- Buttons -->
<div class="mt-8 flex justify-between">
<button onclick="prevStep(2)" class="flex items-center gap-2 px-5 py-3 rounded-xl border-2 border-gray-200 text-gray-600 font-semibold text-sm hover:bg-gray-50 transition-colors"> <i data-lucide="arrow-left" style="width:16px;height:16px;"></i> Back </button> <button onclick="nextStep(2)" class="flex items-center gap-2 px-6 py-3 rounded-xl bg-forest text-white font-semibold text-sm hover:bg-forest/90 transition-colors shadow-md"> Review <i data-lucide="arrow-right" style="width:16px;height:16px;"></i> </button>
</div>
</div>
</div><!-- ===== STEP 3: Review & Payment ===== -->
<div id="step-3" class="step-container step-hidden">
<div class="bg-white rounded-2xl shadow-lg border border-gray-100 p-6 sm:p-8">
<div class="flex items-center gap-3 mb-6">
<div class="w-10 h-10 rounded-xl bg-forest flex items-center justify-center">
<i data-lucide="clipboard-check" style="width:20px;height:20px;color:#7ED957;"></i>
</div>
<div>
<h2 class="text-xl font-bold text-forest" style="font-family: 'Playfair Display', Georgia, serif;">Review & Confirm</h2>
<p class="text-sm text-gray-500">Verify your details before proceeding</p>
</div>
</div><!-- Summary card -->
<div id="review-summary" class="space-y-4 mb-8">
<!-- Filled dynamically -->
</div><!-- Payment Instruction Section -->
<div class="mt-6 p-5 rounded-2xl border-2 border-amber-300/50" style="background: linear-gradient(135deg, #fef8e6, #fffbf0);">
<div class="flex items-center gap-2 mb-4">
<i data-lucide="alert-circle" style="width:20px;height:20px;color:#b45309;"></i>
<h3 class="text-lg font-bold text-amber-900" style="font-family: 'Playfair Display', Georgia, serif;">Payment Instructions</h3>
</div>
<div class="space-y-3">
<div class="flex items-start gap-3 p-3 bg-white rounded-lg">
<div class="w-6 h-6 rounded-full bg-amber-100 text-amber-700 font-bold flex items-center justify-center text-xs flex-shrink-0">
1
</div>
<div class="text-sm text-amber-900"><strong>Payment Amount:</strong> GHS 2,000 (bring exact amount or use mobile money)
</div>
</div>
<div class="flex items-start gap-3 p-3 bg-white rounded-lg">
<div class="w-6 h-6 rounded-full bg-amber-100 text-amber-700 font-bold flex items-center justify-center text-xs flex-shrink-0">
2
</div>
<div class="text-sm text-amber-900"><strong>When to Pay:</strong> On your first day of training at the venue
</div>
</div>
<div class="flex items-start gap-3 p-3 bg-white rounded-lg">
<div class="w-6 h-6 rounded-full bg-amber-100 text-amber-700 font-bold flex items-center justify-center text-xs flex-shrink-0">
3
</div>
<div class="text-sm text-amber-900"><strong>Payment Methods Accepted:</strong> Cash and Mobile Money (MTN, Vodafone, AirtelTigo)
</div>
</div>
</div>
</div><!-- Buttons -->
<div class="mt-8 flex flex-col sm:flex-row justify-between gap-3">
<button onclick="prevStep(3)" class="flex items-center justify-center gap-2 px-5 py-3 rounded-xl border-2 border-gray-200 text-gray-600 font-semibold text-sm hover:bg-gray-50 transition-colors"> <i data-lucide="arrow-left" style="width:16px;height:16px;"></i> Back </button> <button id="submit-btn" onclick="submitRegistration()" class="btn-shimmer flex items-center justify-center gap-2 px-8 py-4 rounded-xl text-forest font-bold text-base shadow-lg hover:shadow-xl transition-shadow"> <i data-lucide="check-circle" style="width:18px;height:18px;"></i> <span id="submit-btn-text">Confirm Registration</span>
<div id="submit-spinner" class="hidden w-5 h-5 border-2 border-forest/30 border-t-forest rounded-full animate-spin"></div></button>
</div>
</div>
</div><!-- ===== STEP 4: Success ===== -->
<div id="step-4" class="step-container step-hidden">
<div class="bg-white rounded-2xl shadow-lg border border-gray-100 p-8 sm:p-12 text-center">
<!-- Animated check -->
<div class="anim-float mx-auto w-24 h-24 mb-6">
<svg viewbox="0 0 52 52" class="w-full h-full">
<circle class="check-circle" cx="26" cy="26" r="25" fill="none" stroke="#7ED957" stroke-width="2" /> <path class="check-mark" fill="none" stroke="#0B3D2E" stroke-width="3" stroke-linecap="round" stroke-linejoin="round" d="M14 27l7 7 16-16" />
</svg>
</div>
<h2 class="text-2xl sm:text-3xl font-bold text-forest mb-3" style="font-family: 'Playfair Display', Georgia, serif;">Registration Successful! 🎉</h2>
<p class="text-gray-600 mb-6 max-w-md mx-auto">Your registration for the WordPress Training has been received. We're excited to have you!</p>
<div class="bg-cream rounded-2xl p-6 mb-6 text-left max-w-sm mx-auto">
<h3 class="text-sm font-semibold text-forest mb-3 flex items-center gap-2"><i data-lucide="info" style="width:16px;height:16px;"></i> What's Next?</h3>
<ul class="space-y-2.5 text-sm text-gray-700">
<li class="flex items-start gap-2"><span class="flex-shrink-0 w-5 h-5 rounded-full bg-lime/30 text-forest flex items-center justify-center text-xs font-bold mt-0.5">1</span> <span>Join our WhatsApp group for updates & reminders</span></li>
<li class="flex items-start gap-2"><span class="flex-shrink-0 w-5 h-5 rounded-full bg-lime/30 text-forest flex items-center justify-center text-xs font-bold mt-0.5">2</span> <span>Bring your payment on the first training day</span></li>
<li class="flex items-start gap-2"><span class="flex-shrink-0 w-5 h-5 rounded-full bg-lime/30 text-forest flex items-center justify-center text-xs font-bold mt-0.5">3</span> <span id="success-venue-note">Arrive at Basy Media, Teshie Rasta Bushroad by 9:00 AM</span></li>
</ul>
</div><button onclick="openWhatsAppGroup()" class="w-full flex items-center justify-center gap-2 px-6 py-3 rounded-xl" style="background: #25D366; color: white; font-weight: 600; font-size: 14px;"> <i data-lucide="message-circle" style="width:18px;height:18px;"></i> Join Our WhatsApp Group </button>
<div class="flex flex-col sm:flex-row items-center justify-center gap-3">
<a href="tel:0539182619" id="success-call-link" class="flex items-center gap-2 px-5 py-3 rounded-xl bg-forest text-white font-semibold text-sm hover:bg-forest/90 transition-colors"> <i data-lucide="phone" style="width:16px;height:16px;"></i> Call Us: <span id="success-contact">0539182619</span> </a> <button onclick="resetForm()" class="flex items-center gap-2 px-5 py-3 rounded-xl border-2 border-gray-200 text-gray-600 font-semibold text-sm hover:bg-gray-50 transition-colors"> <i data-lucide="plus" style="width:16px;height:16px;"></i> Register Another Person </button>
</div>
</div>
</div>
</div>
</div>
</section><!-- Footer -->
<footer class="w-full py-6 px-4 text-center bg-forest">
<p class="text-emerald-300/70 text-xs">© 2026 Basy Media. WordPress Training Registration. All rights reserved.</p>
</footer>
</div>
<script>
// ===== STATE =====
let currentStep = 1;
const maxStep = 4;
let registrationCount = 0;
let allRegistrations = [];
const stepNames = {
1: 'Personal Details',
2: 'Training Preferences',
3: 'Review & Payment',
4: 'Confirmation'
};
// ===== DEFAULT CONFIG =====
const defaultConfig = {
hero_title: 'Build Professional Websites in 4 Weeks',
hero_subtitle: 'Learn WordPress from Beginner to Advanced, hands-on, practical training designed for results.',
hero_tagline: 'Physical Practical / Online Sessions',
training_fee: 'GHS 2,000',
start_date: '4th April, 2026',
venue_text: 'Basy Media, Teshie Rasta Bushroad, Accra',
contact_number: '0539182619',
cta_button_text: 'Register Now',
whatsapp_group_link: 'https://chat.whatsapp.com/DUlAZKQp4ISC2J2SOfn8bj?mode=gi_t',
background_color: '#0B3D2E',
surface_color: '#FFFFFF',
text_color: '#1A1A2E',
primary_action_color: '#7ED957',
secondary_action_color: '#0B3D2E',
font_family: 'DM Sans',
font_size: 16
};
// ===== ELEMENT SDK =====
function applyConfig(config) {
const c = Object.assign({}, defaultConfig, config);
const font = c.font_family || defaultConfig.font_family;
const baseSize = c.font_size || defaultConfig.font_size;
const fontStack = `${font}, system-ui, sans-serif`;
// Text content
const heroTitle = document.getElementById('hero-title');
if (heroTitle) heroTitle.innerHTML = (c.hero_title || defaultConfig.hero_title).replace(/ in /, '<br class="hidden sm:block"> in ');
const heroSub = document.getElementById('hero-subtitle');
if (heroSub) heroSub.textContent = c.hero_subtitle || defaultConfig.hero_subtitle;
const heroTag = document.getElementById('hero-tagline');
if (heroTag) heroTag.textContent = c.hero_tagline || defaultConfig.hero_tagline;
const heroFee = document.getElementById('hero-fee');
if (heroFee) heroFee.textContent = c.training_fee || defaultConfig.training_fee;
const heroDate = document.getElementById('hero-start-date');
if (heroDate) heroDate.textContent = c.start_date || defaultConfig.start_date;
const heroVenue = document.getElementById('hero-venue');
if (heroVenue) heroVenue.textContent = c.venue_text || defaultConfig.venue_text;
const noteVenue = document.getElementById('note-venue');
if (noteVenue) noteVenue.textContent = c.venue_text || defaultConfig.venue_text;
const heroContact = document.getElementById('hero-contact');
if (heroContact) heroContact.textContent = c.contact_number || defaultConfig.contact_number;
const ctaBtn = document.getElementById('hero-cta-btn');
if (ctaBtn) {
const txt = c.cta_button_text || defaultConfig.cta_button_text;
ctaBtn.innerHTML = txt + ' <i data-lucide="arrow-right" style="width:18px;height:18px;display:inline;vertical-align:middle;margin-left:6px;"></i>';
lucide.createIcons();
}
const successContact = document.getElementById('success-contact');
if (successContact) successContact.textContent = c.contact_number || defaultConfig.contact_number;
const callLink = document.getElementById('success-call-link');
if (callLink) callLink.href = 'tel:' + (c.contact_number || defaultConfig.contact_number);
const successVenue = document.getElementById('success-venue-note');
if (successVenue) successVenue.textContent = 'Arrive at ' + (c.venue_text || defaultConfig.venue_text) + ' by 9:00 AM';
// Colors
const bgColor = c.background_color || defaultConfig.background_color;
const surfaceColor = c.surface_color || defaultConfig.surface_color;
const textColor = c.text_color || defaultConfig.text_color;
const primaryAction = c.primary_action_color || defaultConfig.primary_action_color;
const secondaryAction = c.secondary_action_color || defaultConfig.secondary_action_color;
const hero = document.getElementById('hero-section');
if (hero) hero.style.background = `linear-gradient(135deg, ${bgColor} 0%, ${bgColor}dd 40%, ${bgColor} 100%)`;
document.querySelectorAll('.bg-white.rounded-2xl.shadow-lg').forEach(el => {
el.style.backgroundColor = surfaceColor;
});
document.body.style.color = textColor;
const appWrap = document.getElementById('app-wrapper');
if (appWrap) appWrap.style.fontFamily = fontStack;
// Font size
document.querySelectorAll('p, span, label, option, select, input, textarea').forEach(el => {
if (!el.closest('h1') && !el.closest('h2') && !el.closest('h3')) {
el.style.fontSize = `${baseSize * 0.875}px`;
}
});
}
if (window.elementSdk) {
window.elementSdk.init({
defaultConfig,
onConfigChange: async (config) => { applyConfig(config); },
mapToCapabilities: (config) => ({
recolorables: [
{ get: () => config.background_color || defaultConfig.background_color, set: (v) => { config.background_color = v; window.elementSdk.setConfig({ background_color: v }); } },
{ get: () => config.surface_color || defaultConfig.surface_color, set: (v) => { config.surface_color = v; window.elementSdk.setConfig({ surface_color: v }); } },
{ get: () => config.text_color || defaultConfig.text_color, set: (v) => { config.text_color = v; window.elementSdk.setConfig({ text_color: v }); } },
{ get: () => config.primary_action_color || defaultConfig.primary_action_color, set: (v) => { config.primary_action_color = v; window.elementSdk.setConfig({ primary_action_color: v }); } },
{ get: () => config.secondary_action_color || defaultConfig.secondary_action_color, set: (v) => { config.secondary_action_color = v; window.elementSdk.setConfig({ secondary_action_color: v }); } },
],
borderables: [],
fontEditable: {
get: () => config.font_family || defaultConfig.font_family,
set: (v) => { config.font_family = v; window.elementSdk.setConfig({ font_family: v }); }
},
fontSizeable: {
get: () => config.font_size || defaultConfig.font_size,
set: (v) => { config.font_size = v; window.elementSdk.setConfig({ font_size: v }); }
}
}),
mapToEditPanelValues: (config) => new Map([
['hero_title', config.hero_title || defaultConfig.hero_title],
['hero_subtitle', config.hero_subtitle || defaultConfig.hero_subtitle],
['hero_tagline', config.hero_tagline || defaultConfig.hero_tagline],
['training_fee', config.training_fee || defaultConfig.training_fee],
['start_date', config.start_date || defaultConfig.start_date],
['venue_text', config.venue_text || defaultConfig.venue_text],
['contact_number', config.contact_number || defaultConfig.contact_number],
['cta_button_text', config.cta_button_text || defaultConfig.cta_button_text],
['whatsapp_group_link', config.whatsapp_group_link || defaultConfig.whatsapp_group_link],
])
});
}
// ===== DATA SDK =====
const dataHandler = {
onDataChanged(data) {
allRegistrations = data;
registrationCount = data.length;
}
};
(async () => {
if (window.dataSdk) {
const result = await window.dataSdk.init(dataHandler);
if (!result.isOk) {
console.error('Data SDK init failed');
}
}
})();
// ===== FORM NAVIGATION =====
function scrollToForm() {
document.getElementById('form-section').scrollIntoView({ behavior: 'smooth' });
}
function updateProgress(step) {
const pct = (step / maxStep) * 100;
document.getElementById('progress-bar').style.width = pct + '%';
document.getElementById('step-label').textContent = `Step ${step} of ${maxStep}`;
document.getElementById('step-name').textContent = stepNames[step];
document.querySelectorAll('.step-dot').forEach(dot => {
const s = parseInt(dot.dataset.step);
const circle = dot.querySelector('span:first-child');
const label = dot.querySelector('span:last-child');
if (s <= step) {
dot.style.opacity = '1';
circle.className = 'w-6 h-6 rounded-full bg-forest text-white flex items-center justify-center text-xs font-bold';
if (label) label.classList.remove('text-gray-400');
} else {
dot.style.opacity = '0.5';
circle.className = 'w-6 h-6 rounded-full bg-gray-300 text-white flex items-center justify-center text-xs font-bold';
}
});
}
function showStep(step) {
for (let i = 1; i <= maxStep; i++) {
const el = document.getElementById('step-' + i);
if (i === step) {
el.classList.remove('step-hidden');
el.classList.add('step-visible');
} else {
el.classList.remove('step-visible');
el.classList.add('step-hidden');
}
}
currentStep = step;
updateProgress(step);
if (step === 3) buildReview();
// Scroll to form top
document.getElementById('progress-wrapper').scrollIntoView({ behavior: 'smooth', block: 'start' });
lucide.createIcons();
}
function goToStep(step) {
if (step > currentStep) return; // Can only go back via dots
if (step === 4) return;
showStep(step);
}
function nextStep(from) {
if (from === 1 && !validateStep1()) return;
if (from === 2 && !validateStep2()) return;
showStep(from + 1);
}
function prevStep(from) {
showStep(from - 1);
}
// ===== VALIDATION =====
function showError(fieldName, msg) {
const el = document.querySelector(`.error-msg[data-for="${fieldName}"]`);
if (el) {
el.textContent = msg;
el.classList.remove('hidden');
}
const input = document.getElementById(fieldName) || document.querySelector(`[name="${fieldName}"]`);
if (input && input.classList) {
input.classList.add('border-red-400');
input.parentElement?.classList.add('shake');
setTimeout(() => input.parentElement?.classList.remove('shake'), 300);
}
}
function clearErrors() {
document.querySelectorAll('.error-msg').forEach(el => el.classList.add('hidden'));
document.querySelectorAll('.border-red-400').forEach(el => el.classList.remove('border-red-400'));
}
function validateEmail(email) {
return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email);
}
function validatePhone(phone) {
const cleaned = phone.replace(/[\s\-\(\)]/g, '');
return /^(0[0-9]{9}|\+233[0-9]{9})$/.test(cleaned);
}
function validateStep1() {
clearErrors();
let valid = true;
const fields = [
{ id: 'full_name', msg: 'Please enter your full name' },
{ id: 'phone', msg: 'Please enter a valid Ghana phone number', custom: (v) => validatePhone(v) ? '' : 'Enter a valid Ghana phone (e.g. 0241234567)' },
{ id: 'email', msg: 'Please enter a valid email', custom: (v) => validateEmail(v) ? '' : 'Enter a valid email address' },
{ id: 'gender', msg: 'Please select your gender' },
{ id: 'region', msg: 'Please select your region' },
];
fields.forEach(f => {
const el = document.getElementById(f.id);
const val = el ? el.value.trim() : '';
if (!val) { showError(f.id, f.msg); valid = false; }
else if (f.custom) {
const errMsg = f.custom(val);
if (errMsg) { showError(f.id, errMsg); valid = false; }
}
});
// Prior experience
const exp = document.querySelector('input[name="prior_experience"]:checked');
if (!exp) { showError('prior_experience', 'Please select an option'); valid = false; }
return valid;
}
function validateStep2() {
clearErrors();
let valid = true;
const radioFields = ['attendance_mode', 'laptop_availability', 'skill_level'];
radioFields.forEach(name => {
const checked = document.querySelector(`input[name="${name}"]:checked`);
if (!checked) {
showError(name, 'Please select an option');
valid = false;
}
});
const goal = document.getElementById('main_goal').value;
if (!goal) { showError('main_goal', 'Please select your main goal'); valid = false; }
return valid;
}
// ===== OPTION CARD SELECTION HELPERS =====
function clearCardSelection(name) {
document.querySelectorAll(`input[name="${name}"]`).forEach(inp => {
inp.closest('.option-card')?.classList.remove('selected');
});
}
function selectExpCard(radio) {
clearCardSelection('prior_experience');
radio.closest('.option-card')?.classList.add('selected');
}
function selectModeCard(radio) {
clearCardSelection('attendance_mode');
radio.closest('.option-card')?.classList.add('selected');
const physical = document.getElementById('mode-physical-note');
const online = document.getElementById('mode-online-note');
physical.classList.add('hidden');
online.classList.add('hidden');
if (radio.value === 'Physical') physical.classList.remove('hidden');
if (radio.value === 'Online') online.classList.remove('hidden');
}
function selectLaptopCard(radio) {
clearCardSelection('laptop_availability');
radio.closest('.option-card')?.classList.add('selected');
}
function selectSkillCard(radio) {
clearCardSelection('skill_level');
radio.closest('.option-card')?.classList.add('selected');
}
// ===== REVIEW =====
function getVal(id) {
const el = document.getElementById(id);
return el ? el.value.trim() : '';
}
function getRadio(name) {
const el = document.querySelector(`input[name="${name}"]:checked`);
return el ? el.value : '';
}
function buildReview() {
const config = window.elementSdk ? window.elementSdk.config : defaultConfig;
const fee = (config && config.training_fee) || defaultConfig.training_fee;
document.getElementById('review-amount').textContent = fee;
const rows = [
{ icon: 'user', label: 'Full Name', value: getVal('full_name') },
{ icon: 'phone', label: 'Phone', value: getVal('phone') },
{ icon: 'message-circle', label: 'WhatsApp', value: getVal('whatsapp') },
{ icon: 'mail', label: 'Email', value: getVal('email') },
{ icon: 'users', label: 'Gender', value: getVal('gender') },
{ icon: 'calendar', label: 'Age Range', value: getVal('age_range') },
{ icon: 'briefcase', label: 'Occupation', value: getVal('occupation') },
{ icon: 'map-pin', label: 'Location', value: `${getVal('city')}, ${getVal('region')}` },
{ icon: 'monitor', label: 'Attendance', value: getRadio('attendance_mode') },
{ icon: 'laptop', label: 'Laptop', value: getRadio('laptop_availability') },
{ icon: 'bar-chart', label: 'Skill Level', value: getRadio('skill_level') },
{ icon: 'target', label: 'Main Goal', value: getVal('main_goal') },
];
const container = document.getElementById('review-summary');
container.innerHTML = '';
const grid = document.createElement('div');
grid.className = 'grid grid-cols-1 sm:grid-cols-2 gap-3';
rows.forEach(r => {
if (!r.value) return;
const div = document.createElement('div');
div.className = 'flex items-start gap-3 p-3 rounded-xl bg-gray-50/80';
div.innerHTML = `
<div class="w-8 h-8 rounded-lg bg-forest/10 flex items-center justify-center flex-shrink-0">
<i data-lucide="${r.icon}" style="width:14px;height:14px;color:#0B3D2E;"></i>
</div>
<div class="min-w-0">
<div class="text-xs text-gray-500">${r.label}</div>
<div class="text-sm font-semibold text-gray-800 truncate">${r.value}</div>
</div>
`;
grid.appendChild(div);
});
container.appendChild(grid);
lucide.createIcons();
}
// ===== SUBMIT =====
async function submitRegistration() {
clearErrors();
const agree = document.getElementById('agree-terms');
if (!agree.checked) {
showError('agree-terms', 'Please confirm before proceeding');
return;
}
if (registrationCount >= 999) {
showToast('Registration limit reached. Please contact us directly.', 'error');
return;
}
const btn = document.getElementById('submit-btn');
const btnText = document.getElementById('submit-btn-text');
const spinner = document.getElementById('submit-spinner');
btn.disabled = true;
btnText.textContent = 'Submitting...';
spinner.classList.remove('hidden');
const registrationId = 'REG-' + Date.now() + '-' + Math.random().toString(36).substr(2, 5).toUpperCase();
const record = {
full_name: getVal('full_name'),
phone: getVal('phone'),
whatsapp: getVal('whatsapp'),
email: getVal('email'),
gender: getVal('gender'),
age_range: getVal('age_range'),
occupation: getVal('occupation'),
city: getVal('city'),
region: getVal('region'),
heard_from: getVal('heard_from'),
prior_experience: getRadio('prior_experience'),
attendance_mode: getRadio('attendance_mode'),
laptop_availability: getRadio('laptop_availability'),
skill_level: getRadio('skill_level'),
main_goal: getVal('main_goal'),
emergency_name: getVal('emergency_name'),
emergency_phone: getVal('emergency_phone'),
additional_notes: getVal('additional_notes'),
registered_at: new Date().toISOString(),
status: 'pending_payment',
registration_id: registrationId
};
// Send email with registration details
const emailSent = await sendRegistrationEmail(record);
if (window.dataSdk) {
const result = await window.dataSdk.create(record);
if (result.isOk) {
populateSuccessScreen(record);
showStep(4);
showToast('Registration submitted successfully!', 'success');
} else {
showToast('Something went wrong. Please try again.', 'error');
}
} else {
// Fallback - just show success
populateSuccessScreen(record);
showStep(4);
}
btn.disabled = false;
btnText.textContent = 'Confirm Registration';
spinner.classList.add('hidden');
}
async function sendRegistrationEmail(record) {
try {
const emailBody = `
New WordPress Training Registration
Registration ID: ${record.registration_id}
PERSONAL DETAILS
Full Name: ${record.full_name}
Email: ${record.email}
Phone: ${record.phone}
WhatsApp: ${record.whatsapp || 'Not provided'}
Gender: ${record.gender}
Occupation: ${record.occupation || 'Not provided'}
City/Town: ${record.city || 'Not provided'}
Region: ${record.region}
TRAINING PREFERENCES
How heard about us: ${record.heard_from || 'Not provided'}
Prior Experience: ${record.prior_experience}
Attendance Mode: ${record.attendance_mode}
Laptop Availability: ${record.laptop_availability}
Skill Level: ${record.skill_level}
Main Goal: ${record.main_goal}
EMERGENCY CONTACT
Name: ${record.emergency_name || 'Not provided'}
Phone: ${record.emergency_phone || 'Not provided'}
ADDITIONAL INFO
Notes: ${record.additional_notes || 'None'}
Status: ${record.status}
Registered: ${new Date(record.registered_at).toLocaleString()}
`;
// Use FormSubmit.co to send email (free service)
const response = await fetch('https://formspree.io/f/xjvkdzpb', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
email: record.email,
message: emailBody,
_subject: `New Registration: ${record.full_name} (ID: ${record.registration_id})`
})
});
return response.ok;
} catch (err) {
console.error('Email send error:', err);
return false;
}
}
function populateSuccessScreen(record) {
const config = window.elementSdk ? window.elementSdk.config : defaultConfig;
// Set registration ID
document.getElementById('success-reg-id').textContent = record.registration_id;
// Set name
document.getElementById('success-name').textContent = record.full_name;
// Set attendance mode
document.getElementById('success-mode').textContent = record.attendance_mode;
// Set start date
document.getElementById('success-start-date').textContent = (config && config.start_date) || defaultConfig.start_date;
// Set venue
document.getElementById('success-venue').textContent = (config && config.venue_text) || defaultConfig.venue_text;
// Set contact
const contact = (config && config.contact_number) || defaultConfig.contact_number;
document.getElementById('success-contact').textContent = contact;
document.getElementById('success-call-link').href = 'tel:' + contact;
}
function openWhatsAppGroup() {
const config = window.elementSdk ? window.elementSdk.config : defaultConfig;
const whatsappLink = (config && config.whatsapp_group_link) || 'https://chat.whatsapp.com/DUlAZKQp4ISC2J2SOfn8bj?mode=gi_t';
window.open(whatsappLink, '_blank', 'noopener,noreferrer');
}
// ===== TOAST =====
function showToast(message, type) {
const container = document.getElementById('toast-container');
const toast = document.createElement('div');
const bgColor = type === 'success' ? 'bg-forest' : 'bg-red-600';
toast.className = `toast ${bgColor} text-white px-5 py-3 rounded-xl shadow-lg text-sm font-medium flex items-center gap-2 max-w-xs`;
const iconName = type === 'success' ? 'check-circle' : 'alert-circle';
toast.innerHTML = `<i data-lucide="${iconName}" style="width:16px;height:16px;flex-shrink:0;"></i><span>${message}</span>`;
container.appendChild(toast);
lucide.createIcons();
requestAnimationFrame(() => toast.classList.add('show'));
setTimeout(() => {
toast.classList.remove('show');
setTimeout(() => toast.remove(), 300);
}, 4000);
}
// ===== RESET =====
function resetForm() {
// Reset all form fields
document.querySelectorAll('input[type="text"], input[type="tel"], input[type="email"], textarea').forEach(el => el.value = '');
document.querySelectorAll('select').forEach(el => el.selectedIndex = 0);
document.querySelectorAll('input[type="radio"]').forEach(el => { el.checked = false; });
document.querySelectorAll('.option-card').forEach(el => el.classList.remove('selected'));
document.getElementById('agree-terms').checked = false;
document.getElementById('mode-physical-note').classList.add('hidden');
document.getElementById('mode-online-note').classList.add('hidden');
clearErrors();
showStep(1);
}
// ===== INIT =====
document.addEventListener('DOMContentLoaded', () => {
lucide.createIcons();
updateProgress(1);
// Add inline validation on blur for step 1 fields
['full_name','phone','whatsapp','email','occupation','city'].forEach(id => {
const el = document.getElementById(id);
if (el) {
el.addEventListener('blur', function() {
const errEl = document.querySelector(`.error-msg[data-for="${id}"]`);
if (this.value.trim()) {
errEl?.classList.add('hidden');
this.classList.remove('border-red-400');
this.style.borderColor = '#7ED957';
setTimeout(() => this.style.borderColor = '', 1500);
}
});
}
});
});
</script>
<script>(function(){function c(){var b=a.contentDocument||a.contentWindow.document;if(b){var d=b.createElement('script');d.innerHTML="window.__CF$cv$params={r:'9df556ff50237f08',t:'MTc3NDAxNjI0Ni4wMDAwMDA='};var a=document.createElement('script');a.nonce='';a.src='/cdn-cgi/challenge-platform/scripts/jsd/main.js';document.getElementsByTagName('head')[0].appendChild(a);";b.getElementsByTagName('head')[0].appendChild(d)}}if(document.body){var a=document.createElement('iframe');a.height=1;a.width=1;a.style.position='absolute';a.style.top=0;a.style.left=0;a.style.border='none';a.style.visibility='hidden';document.body.appendChild(a);if('loading'!==document.readyState)c();else if(window.addEventListener)document.addEventListener('DOMContentLoaded',c);else{var e=document.onreadystatechange||function(){};document.onreadystatechange=function(b){e(b);'loading'!==document.readyState&&(document.onreadystatechange=e,c())}}}})();</script></body>
</html>