{% include '@Application/inc/central_header.html.twig' %}
<style>
:root {
--n-cream: #F7F5F0;
--n-cream-2: #F0EDE5;
--n-cream-3: #E8E3D9;
--n-white: #FFFFFF;
--n-dark: #1A1D2E;
--n-dark-2: #252840;
--n-amber: #C07D2A;
--n-amber-lt: #D4954A;
--n-amber-dim: rgba(192,125,42,.10);
--n-sage: #3D6B52;
--n-muted: #6B6E7F;
--n-muted-2: #9395A5;
--n-border: rgba(26,29,46,.07);
--n-border-md: rgba(26,29,46,.12);
--n-shadow-sm: 0 2px 12px rgba(26,29,46,.07);
--n-shadow-md: 0 8px 32px rgba(26,29,46,.09);
--n-radius: 12px;
--n-radius-sm: 8px;
--n-font: 'DM Sans', 'Poppins', system-ui, sans-serif;
}
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
body { background: var(--n-cream); font-family: var(--n-font); color: var(--n-dark); }
a { text-decoration: none; }
.navbar {
background: rgba(247,245,240,.96) !important;
backdrop-filter: blur(16px) saturate(180%);
border-bottom: 1px solid var(--n-border) !important;
box-shadow: none !important;
}
.navbar .nav-link { color: var(--n-dark) !important; font-size: 13.5px; font-weight: 500; opacity: .8; }
.navbar .nav-link:hover { opacity: 1; }
.navbar .login-btn { background: var(--n-dark) !important; color: #fff !important; border-radius: 8px !important; padding: 8px 20px !important; font-size: 13px !important; font-weight: 600 !important; }
/* ── Layout ─────────────────────────────────────────── */
.n-wrap { max-width: 1100px; margin: 0 auto; padding: 0 28px; }
.n-sec { padding: 80px 0 100px; }
/* ── Hero ────────────────────────────────────────────── */
.bk-hero {
background: linear-gradient(135deg, var(--n-dark) 0%, var(--n-dark-2) 100%);
padding: 80px 0 60px;
text-align: center;
color: #fff;
}
.bk-hero__badge {
display: inline-block;
background: var(--n-amber-dim);
color: var(--n-amber-lt);
border: 1px solid rgba(192,125,42,.3);
border-radius: 20px;
padding: 5px 16px;
font-size: 12.5px;
font-weight: 600;
letter-spacing: .5px;
text-transform: uppercase;
margin-bottom: 22px;
}
.bk-hero h1 {
font-family: 'Montserrat', sans-serif;
font-size: clamp(30px,4vw,50px);
font-weight: 800;
line-height: 1.15;
margin-bottom: 16px;
}
.bk-hero h1 em { color: var(--n-amber-lt); font-style: normal; }
.bk-hero p {
color: rgba(255,255,255,.7);
font-size: 16px;
max-width: 500px;
margin: 0 auto;
line-height: 1.6;
}
/* ── Booking card ─────────────────────────────────────── */
.bk-card {
background: var(--n-white);
border-radius: var(--n-radius);
box-shadow: var(--n-shadow-md);
padding: 40px;
margin-top: -40px;
position: relative;
z-index: 10;
max-width: 820px;
margin-left: auto;
margin-right: auto;
}
/* ── Steps indicator ──────────────────────────────────── */
.bk-steps {
display: flex;
gap: 0;
margin-bottom: 36px;
border-bottom: 1px solid var(--n-border-md);
padding-bottom: 24px;
}
.bk-step {
flex: 1;
display: flex;
align-items: center;
gap: 10px;
font-size: 13.5px;
font-weight: 500;
color: var(--n-muted);
padding-bottom: 16px;
border-bottom: 2px solid transparent;
margin-bottom: -25px;
transition: all .2s;
}
.bk-step.active { color: var(--n-amber); border-color: var(--n-amber); }
.bk-step.done { color: var(--n-sage); border-color: var(--n-sage); }
.bk-step__num {
width: 26px; height: 26px;
border-radius: 50%;
background: var(--n-cream-2);
display: flex; align-items: center; justify-content: center;
font-size: 12px; font-weight: 700;
flex-shrink: 0;
}
.bk-step.active .bk-step__num { background: var(--n-amber); color: #fff; }
.bk-step.done .bk-step__num { background: var(--n-sage); color: #fff; }
/* ── Calendar ──────────────────────────────────────────── */
.bk-cal {
display: none;
flex-direction: column;
gap: 20px;
}
.bk-cal.active { display: flex; }
.bk-cal__nav {
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 12px;
}
.bk-cal__nav button {
background: none; border: 1px solid var(--n-border-md);
border-radius: var(--n-radius-sm);
padding: 6px 14px; cursor: pointer;
color: var(--n-dark); font-size: 13px;
transition: background .15s;
}
.bk-cal__nav button:hover { background: var(--n-cream-2); }
.bk-cal__month { font-weight: 700; font-size: 15px; }
.bk-cal__grid {
display: grid;
grid-template-columns: repeat(7, 1fr);
gap: 4px;
text-align: center;
}
.bk-cal__wd {
font-size: 11px;
font-weight: 600;
color: var(--n-muted-2);
padding: 4px 0 8px;
text-transform: uppercase;
letter-spacing: .4px;
}
.bk-cal__day {
padding: 9px 4px;
border-radius: var(--n-radius-sm);
font-size: 13.5px;
cursor: pointer;
transition: all .15s;
border: 1px solid transparent;
}
.bk-cal__day:hover:not(.past):not(.empty) { background: var(--n-amber-dim); border-color: var(--n-amber); color: var(--n-amber); }
.bk-cal__day.selected { background: var(--n-amber); color: #fff !important; border-color: var(--n-amber); }
.bk-cal__day.past { color: var(--n-muted-2); cursor: default; }
.bk-cal__day.empty { cursor: default; }
.bk-cal__day.today { font-weight: 700; }
/* ── Slots ─────────────────────────────────────────────── */
.bk-slots { display: none; flex-direction: column; gap: 20px; }
.bk-slots.active { display: flex; }
.bk-slots__heading {
font-size: 14px;
font-weight: 600;
color: var(--n-muted);
margin-bottom: 4px;
}
.bk-slots__grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(90px, 1fr));
gap: 8px;
}
.bk-slot {
padding: 10px 6px;
border: 1.5px solid var(--n-border-md);
border-radius: var(--n-radius-sm);
text-align: center;
cursor: pointer;
font-size: 13px;
font-weight: 500;
transition: all .15s;
position: relative;
user-select: none;
}
.bk-slot:hover:not(.unavailable):not(.selected) { border-color: var(--n-amber); color: var(--n-amber); background: var(--n-amber-dim); }
.bk-slot.selected { background: var(--n-amber); color: #fff; border-color: var(--n-amber); }
.bk-slot.selected .bk-slot__priority { display: inline-flex; }
.bk-slot.unavailable { opacity: .38; cursor: not-allowed; text-decoration: line-through; }
.bk-slot__priority {
display: none;
position: absolute;
top: -8px; right: -8px;
width: 18px; height: 18px;
background: var(--n-dark); color: #fff;
border-radius: 50%; font-size: 10px; font-weight: 700;
align-items: center; justify-content: center;
}
.bk-slots__tip { font-size: 12.5px; color: var(--n-muted-2); margin-top: 8px; }
/* ── Form ──────────────────────────────────────────────── */
.bk-form { display: none; flex-direction: column; gap: 20px; }
.bk-form.active { display: flex; }
.bk-form__row { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; }
.bk-form__field { display: flex; flex-direction: column; gap: 6px; }
.bk-form__field label { font-size: 13px; font-weight: 600; color: var(--n-dark); }
.bk-form__field input,
.bk-form__field select {
height: 44px;
border: 1.5px solid var(--n-border-md);
border-radius: var(--n-radius-sm);
padding: 0 14px;
font-size: 14px;
font-family: var(--n-font);
color: var(--n-dark);
background: var(--n-cream);
outline: none;
transition: border-color .15s;
}
.bk-form__field input:focus,
.bk-form__field select:focus { border-color: var(--n-amber); background: #fff; }
.bk-form__field input.error { border-color: #e53e3e; }
/* ── Buttons ───────────────────────────────────────────── */
.bk-btn-row { display: flex; gap: 12px; margin-top: 12px; justify-content: flex-end; }
.bk-btn {
display: inline-flex; align-items: center; justify-content: center; gap: 7px;
padding: 12px 28px;
border-radius: var(--n-radius-sm);
font-size: 14px; font-weight: 600;
cursor: pointer; border: none;
transition: all .15s;
font-family: var(--n-font);
}
.bk-btn--primary { background: var(--n-amber); color: #fff; }
.bk-btn--primary:hover { background: var(--n-amber-lt); }
.bk-btn--secondary { background: var(--n-cream-2); color: var(--n-dark); }
.bk-btn--secondary:hover { background: var(--n-cream-3); }
.bk-btn:disabled { opacity: .5; cursor: not-allowed; }
/* ── Selected slots summary ────────────────────────────── */
.bk-summary {
background: var(--n-cream);
border-radius: var(--n-radius-sm);
padding: 16px 20px;
font-size: 13.5px;
color: var(--n-muted);
border: 1px solid var(--n-border-md);
}
.bk-summary__slot { display: flex; align-items: center; gap: 8px; margin-top: 6px; color: var(--n-dark); font-weight: 500; }
.bk-summary__slot::before { content: ''; display: block; width: 8px; height: 8px; border-radius: 50%; background: var(--n-amber); flex-shrink: 0; }
/* ── Success state ─────────────────────────────────────── */
.bk-success {
display: none;
flex-direction: column;
align-items: center;
text-align: center;
gap: 16px;
padding: 40px 20px;
}
.bk-success.show { display: flex; }
.bk-success__icon { font-size: 52px; }
.bk-success h2 { font-size: 22px; font-weight: 700; }
.bk-success p { color: var(--n-muted); font-size: 15px; max-width: 420px; }
/* ── Alert ─────────────────────────────────────────────── */
.bk-alert {
padding: 12px 16px;
border-radius: var(--n-radius-sm);
font-size: 13.5px;
display: none;
}
.bk-alert.error { background: #fff5f5; border: 1px solid #feb2b2; color: #c53030; }
.bk-alert.success { background: #f0fff4; border: 1px solid #9ae6b4; color: #276749; }
.bk-alert.show { display: block; }
/* ── Loading spinner ───────────────────────────────────── */
.bk-spinner {
display: none;
width: 20px; height: 20px;
border: 2px solid rgba(255,255,255,.4);
border-top-color: #fff;
border-radius: 50%;
animation: spin .6s linear infinite;
}
@keyframes spin { to { transform: rotate(360deg); } }
/* ── Responsive ────────────────────────────────────────── */
@media (max-width: 600px) {
.bk-card { padding: 24px 18px; }
.bk-form__row { grid-template-columns: 1fr; }
.bk-steps { gap: 4px; }
.bk-step span:not(.bk-step__num) { display: none; }
}
</style>
<!-- Hero -->
<section class="bk-hero">
<div class="n-wrap">
<div class="bk-hero__badge">20-Minute Live Demo</div>
<h1>Book Your <em>Free</em><br>HoneyBee ERP Demo</h1>
<p>See exactly how HoneyBee can transform your business — live, personalised, no sales pressure.</p>
</div>
</section>
<!-- Booking card -->
<section class="n-sec">
<div class="n-wrap">
<div class="bk-card">
<!-- Steps -->
<div class="bk-steps">
<div class="bk-step active" id="step-ind-1">
<div class="bk-step__num">1</div>
<span>Pick Date & Slots</span>
</div>
<div class="bk-step" id="step-ind-2">
<div class="bk-step__num">2</div>
<span>Your Details</span>
</div>
<div class="bk-step" id="step-ind-3">
<div class="bk-step__num">3</div>
<span>Confirm</span>
</div>
</div>
<!-- Alert -->
<div class="bk-alert" id="bk-alert"></div>
<!-- Step 1: Calendar + slots -->
<div class="bk-cal active" id="step-1">
<div>
<div class="bk-cal__nav">
<button id="cal-prev">←</button>
<span class="bk-cal__month" id="cal-month-label"></span>
<button id="cal-next">→</button>
</div>
<div class="bk-cal__grid" id="cal-grid"></div>
</div>
<!-- Time slots for selected date -->
<div class="bk-slots active" id="slots-panel">
<div class="bk-slots__heading" id="slots-heading">Select a date to see available slots</div>
<div class="bk-slots__grid" id="slots-grid"></div>
<div class="bk-slots__tip" id="slots-tip"></div>
</div>
<div class="bk-btn-row">
<button class="bk-btn bk-btn--primary" id="btn-to-step2" disabled>
Next: Your Details →
</button>
</div>
</div>
<!-- Step 2: Personal details form -->
<div class="bk-form" id="step-2">
<!-- Selected slots summary -->
<div class="bk-summary">
<strong>Your selected slots:</strong>
<div id="summary-slots"></div>
</div>
<div class="bk-form__row">
<div class="bk-form__field">
<label for="f-name">Full Name <span style="color:#e53e3e">*</span></label>
<input type="text" id="f-name" placeholder="Jane Smith" required>
</div>
<div class="bk-form__field">
<label for="f-email">Work Email <span style="color:#e53e3e">*</span></label>
<input type="email" id="f-email" placeholder="jane@company.com" required>
</div>
</div>
<div class="bk-form__row">
<div class="bk-form__field">
<label for="f-phone">Phone Number</label>
<input type="tel" id="f-phone" placeholder="+44 7700 900000">
</div>
<div class="bk-form__field">
<label for="f-company">Company Name <span style="color:#e53e3e">*</span></label>
<input type="text" id="f-company" placeholder="Acme Ltd" required>
</div>
</div>
<div class="bk-form__field">
<label for="f-type">Business Type</label>
<select id="f-type">
<option value="">— Select —</option>
<option value="retail">Retail</option>
<option value="manufacturing">Manufacturing</option>
<option value="services">Services</option>
<option value="wholesale">Wholesale</option>
<option value="construction">Construction</option>
<option value="hospitality">Hospitality</option>
<option value="healthcare">Healthcare</option>
<option value="other">Other</option>
</select>
</div>
<div class="bk-btn-row">
<button class="bk-btn bk-btn--secondary" id="btn-back-step1">← Back</button>
<button class="bk-btn bk-btn--primary" id="btn-submit">
<span id="btn-submit-text">Request Demo</span>
<span class="bk-spinner" id="btn-submit-spinner"></span>
</button>
</div>
</div>
<!-- Success state -->
<div class="bk-success" id="step-success">
<div class="bk-success__icon">🎉</div>
<h2>Request Received!</h2>
<p>Thank you. We've sent a confirmation to your email. Our team will confirm your preferred slot shortly.</p>
<a href="{{ url('honeybee_about_us') }}" class="bk-btn bk-btn--primary">Back to Home</a>
</div>
</div>
</div>
</section>
<script>
(function () {
'use strict';
// ── State ──────────────────────────────────────────────────────
const today = new Date(); today.setHours(0,0,0,0);
let curYear = today.getFullYear();
let curMonth = today.getMonth();
let selectedDate = null;
let selectedSlots = []; // [{date, time, label}]
const MAX_SLOTS = 3;
const SLOTS_URL = '{{ path("book_demo_slots", {"date": "__DATE__"}) }}';
const SUBMIT_URL = '{{ path("book_demo_submit") }}';
// ── DOM refs ───────────────────────────────────────────────────
const calGrid = document.getElementById('cal-grid');
const calLabel = document.getElementById('cal-month-label');
const slotsPanel = document.getElementById('slots-panel');
const slotsGrid = document.getElementById('slots-grid');
const slotsHeading = document.getElementById('slots-heading');
const slotsTip = document.getElementById('slots-tip');
const alertEl = document.getElementById('bk-alert');
const step1 = document.getElementById('step-1');
const step2 = document.getElementById('step-2');
const stepSuccess = document.getElementById('step-success');
const btnToStep2 = document.getElementById('btn-to-step2');
const btnBack = document.getElementById('btn-back-step1');
const btnSubmit = document.getElementById('btn-submit');
const summaryEl = document.getElementById('summary-slots');
const MONTHS = ['January','February','March','April','May','June',
'July','August','September','October','November','December'];
const WDS = ['Sun','Mon','Tue','Wed','Thu','Fri','Sat'];
// ── Calendar render ────────────────────────────────────────────
function renderCalendar() {
calLabel.textContent = MONTHS[curMonth] + ' ' + curYear;
calGrid.innerHTML = '';
WDS.forEach(d => {
const el = document.createElement('div');
el.className = 'bk-cal__wd';
el.textContent = d;
calGrid.appendChild(el);
});
const first = new Date(curYear, curMonth, 1).getDay();
const days = new Date(curYear, curMonth + 1, 0).getDate();
for (let i = 0; i < first; i++) {
const el = document.createElement('div');
el.className = 'bk-cal__day empty';
calGrid.appendChild(el);
}
for (let d = 1; d <= days; d++) {
const dt = new Date(curYear, curMonth, d);
const dow = dt.getDay();
const el = document.createElement('div');
el.className = 'bk-cal__day';
el.textContent = d;
if (dt < today || dow === 0 || dow === 6) {
el.classList.add('past');
} else {
if (dt.toDateString() === today.toDateString()) el.classList.add('today');
const ds = fmt(dt);
if (selectedDate === ds) el.classList.add('selected');
el.addEventListener('click', () => selectDate(ds));
}
calGrid.appendChild(el);
}
}
function fmt(dt) {
const y = dt.getFullYear();
const m = String(dt.getMonth()+1).padStart(2,'0');
const d = String(dt.getDate()).padStart(2,'0');
return `${y}-${m}-${d}`;
}
// ── Date select ────────────────────────────────────────────────
function selectDate(dateStr) {
selectedDate = dateStr;
renderCalendar();
loadSlots(dateStr);
}
function loadSlots(dateStr) {
slotsHeading.textContent = 'Loading slots…';
slotsGrid.innerHTML = '';
slotsTip.textContent = '';
const url = SLOTS_URL.replace('__DATE__', dateStr);
fetch(url)
.then(r => r.json())
.then(data => renderSlots(dateStr, data.slots || []))
.catch(() => { slotsHeading.textContent = 'Error loading slots. Please try again.'; });
}
function renderSlots(dateStr, slots) {
const dt = new Date(dateStr + 'T00:00:00');
const label = dt.toLocaleDateString('en-GB', {weekday:'long', day:'numeric', month:'long'});
slotsHeading.textContent = 'Available slots for ' + label + ':';
if (!slots.length) {
slotsGrid.innerHTML = '<p style="color:var(--n-muted-2);font-size:13px;">No slots available on this date.</p>';
return;
}
slotsGrid.innerHTML = '';
slots.forEach(slot => {
const el = document.createElement('div');
const key = dateStr + '|' + slot.time;
const alreadySel = selectedSlots.find(s => s.key === key);
el.className = 'bk-slot' + (!slot.available ? ' unavailable' : '') + (alreadySel ? ' selected' : '');
el.textContent = slot.time;
const badge = document.createElement('span');
badge.className = 'bk-slot__priority';
if (alreadySel) badge.textContent = selectedSlots.indexOf(alreadySel) + 1;
el.appendChild(badge);
if (slot.available) {
el.addEventListener('click', () => toggleSlot(dateStr, slot.time, el, badge));
}
slotsGrid.appendChild(el);
});
updateTip();
}
function toggleSlot(dateStr, time, el, badge) {
const key = dateStr + '|' + time;
const idx = selectedSlots.findIndex(s => s.key === key);
if (idx > -1) {
selectedSlots.splice(idx, 1);
el.classList.remove('selected');
} else {
if (selectedSlots.length >= MAX_SLOTS) {
showAlert('You can select up to 3 preferred slots.', 'error');
return;
}
const dt = new Date(dateStr + 'T' + time + ':00');
const lbl = dt.toLocaleDateString('en-GB', {weekday:'short', day:'numeric', month:'short'}) + ' at ' + time;
selectedSlots.push({key, date: dateStr, time, label: lbl});
el.classList.add('selected');
}
// Re-render all badges
document.querySelectorAll('.bk-slot.selected .bk-slot__priority').forEach(b => b.textContent = '');
selectedSlots.forEach((s, i) => {
const k = s.key.replace('|', '\\|');
const sl = slotsGrid.querySelector('.bk-slot.selected');
// refresh current view
});
renderSlots(dateStr, Array.from(slotsGrid.querySelectorAll('.bk-slot')).map(el => ({
time: el.textContent.replace(/\d$/, '').trim(),
available: !el.classList.contains('unavailable'),
})));
// reload properly
loadSlots(dateStr);
btnToStep2.disabled = selectedSlots.length === 0;
updateTip();
hideAlert();
}
function updateTip() {
slotsTip.textContent = selectedSlots.length > 0
? `${selectedSlots.length} of ${MAX_SLOTS} slots selected (priority order).`
: 'Pick up to 3 preferred time slots. First = highest priority.';
}
// ── Step navigation ────────────────────────────────────────────
btnToStep2.addEventListener('click', () => {
if (selectedSlots.length === 0) return;
step1.classList.remove('active');
step2.classList.add('active');
setStep(2);
summaryEl.innerHTML = '';
selectedSlots.forEach((s, i) => {
const el = document.createElement('div');
el.className = 'bk-summary__slot';
el.textContent = `#${i+1} — ${s.label}`;
summaryEl.appendChild(el);
});
});
btnBack.addEventListener('click', () => {
step2.classList.remove('active');
step1.classList.add('active');
setStep(1);
hideAlert();
});
function setStep(n) {
document.querySelectorAll('.bk-step').forEach((el, i) => {
el.classList.remove('active', 'done');
if (i + 1 < n) el.classList.add('done');
if (i + 1 === n) el.classList.add('active');
});
}
// ── Submit ─────────────────────────────────────────────────────
btnSubmit.addEventListener('click', () => {
const name = document.getElementById('f-name').value.trim();
const email = document.getElementById('f-email').value.trim();
const company = document.getElementById('f-company').value.trim();
if (!name || !email || !company) {
showAlert('Please fill in all required fields.', 'error');
return;
}
if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email)) {
showAlert('Please enter a valid email address.', 'error');
return;
}
btnSubmit.disabled = true;
document.getElementById('btn-submit-spinner').style.display = 'inline-block';
document.getElementById('btn-submit-text').textContent = 'Sending…';
hideAlert();
const body = new URLSearchParams();
body.append('name', name);
body.append('email', email);
body.append('phone', document.getElementById('f-phone').value.trim());
body.append('company_name', company);
body.append('business_type', document.getElementById('f-type').value);
selectedSlots.forEach(s => body.append('slots[]', s.key));
fetch(SUBMIT_URL, {method: 'POST', body, headers: {'X-Requested-With': 'XMLHttpRequest'}})
.then(r => r.json())
.then(data => {
if (data.success) {
step2.classList.remove('active');
stepSuccess.classList.add('show');
document.querySelector('.bk-steps').style.display = 'none';
} else {
showAlert(data.message || 'Something went wrong. Please try again.', 'error');
resetBtn();
}
})
.catch(() => {
showAlert('Network error. Please check your connection.', 'error');
resetBtn();
});
});
function resetBtn() {
btnSubmit.disabled = false;
document.getElementById('btn-submit-spinner').style.display = 'none';
document.getElementById('btn-submit-text').textContent = 'Request Demo';
}
// ── Alert helpers ──────────────────────────────────────────────
function showAlert(msg, type) {
alertEl.textContent = msg;
alertEl.className = 'bk-alert ' + type + ' show';
}
function hideAlert() {
alertEl.className = 'bk-alert';
}
// ── Month nav ──────────────────────────────────────────────────
document.getElementById('cal-prev').addEventListener('click', () => {
curMonth--;
if (curMonth < 0) { curMonth = 11; curYear--; }
renderCalendar();
});
document.getElementById('cal-next').addEventListener('click', () => {
curMonth++;
if (curMonth > 11) { curMonth = 0; curYear++; }
renderCalendar();
});
// ── Init ───────────────────────────────────────────────────────
renderCalendar();
updateTip();
slotsHeading.textContent = 'Select a date above to see available time slots.';
})();
</script>
{% include '@HoneybeeWeb/footer/central_footer.html.twig' %}