Stackless-Website/contact.html
2026-06-18 12:22:31 +02:00

555 lines
20 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover" />
<title>Start a project — Stackless</title>
<meta name="description" content="Tell us what's eating your week. We'll come back with a fixed quote within one business day." />
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=Inter+Tight:wght@500;600;700&family=JetBrains+Mono:wght@400;500&display=swap" rel="stylesheet" />
<link rel="stylesheet" href="shared.css" />
<style>
/* ---------- contact-page layout ---------- */
.contact-hero { padding: 80px 0 24px; }
.contact-hero h1 { max-width: 22ch; }
.contact-hero p { margin-top: 18px; font-size: 18px; max-width: 60ch; color: var(--muted); }
.contact-grid {
display: grid;
grid-template-columns: 1.4fr 1fr;
gap: 56px;
margin-top: 56px;
}
/* ---------- form ---------- */
.form {
background: var(--surface);
border: 1px solid var(--border);
border-radius: var(--r-lg);
padding: 36px 36px 32px;
box-shadow: var(--shadow-pop);
}
.progress {
display: flex; align-items: center; gap: 10px;
margin-bottom: 28px;
}
.progress .dot {
width: 28px; height: 28px;
border-radius: 50%;
background: var(--bg);
border: 1px solid var(--border);
color: var(--muted);
font: 500 12.5px/1 var(--font-mono);
letter-spacing: 0.02em;
display: grid; place-items: center;
transition: background 0.18s, color 0.18s, border-color 0.18s;
}
.progress .dot.is-on {
background: var(--accent); color: var(--ink-2); border-color: var(--accent);
}
.progress .dot.is-done {
background: var(--ink-2); color: var(--accent); border-color: var(--ink-2);
}
.progress .bar {
flex: 1; height: 1px; background: var(--border);
}
.step { display: none; }
.step.is-active { display: block; }
.step__head { margin-bottom: 22px; }
.step__head h2 {
font: 600 22px/1.2 var(--font-display);
letter-spacing: -0.02em;
color: var(--ink-2);
}
.step__head p { margin-top: 6px; font-size: 14px; color: var(--muted); }
.field { display: block; margin-bottom: 16px; }
.field label {
display: block;
font: 500 13px/1 var(--font-mono);
letter-spacing: 0.04em;
text-transform: uppercase;
color: var(--muted);
margin-bottom: 7px;
}
.field input, .field select, .field textarea {
width: 100%;
padding: 12px 14px;
background: var(--bg);
border: 1px solid var(--border);
border-radius: var(--r-sm);
font: 400 15px/1.4 var(--font-body);
color: var(--ink-2);
transition: border-color 0.15s, background 0.15s;
}
.field textarea { min-height: 110px; resize: vertical; }
.field input:focus, .field select:focus, .field textarea:focus {
outline: none;
border-color: var(--accent);
background: var(--surface);
}
.field.is-invalid input, .field.is-invalid select, .field.is-invalid textarea,
input.is-invalid, select.is-invalid, textarea.is-invalid {
border-color: var(--accent-2);
background: rgba(247, 104, 87, 0.05);
}
.field .hint {
display: block;
margin-top: 6px;
font-size: 12.5px;
color: var(--muted);
}
.field.is-invalid .hint,
.err {
color: var(--accent-2);
}
.services-err {
display: none;
margin: 6px 0 0;
font: 500 12.5px/1.4 var(--font-mono);
color: var(--accent-2);
letter-spacing: 0.02em;
}
.checklist {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 8px 12px;
margin-top: 4px;
}
.check {
display: flex; align-items: center; gap: 10px;
padding: 10px 12px;
border: 1px solid var(--border);
border-radius: var(--r-sm);
background: var(--bg);
font-size: 14px;
color: var(--ink);
cursor: pointer;
transition: border-color 0.15s, background 0.15s;
}
.check input { display: none; }
.check .box {
width: 16px; height: 16px;
border-radius: 4px;
border: 1.5px solid var(--muted);
flex-shrink: 0;
display: grid; place-items: center;
transition: background 0.15s, border-color 0.15s;
}
.check input:checked + .box {
background: var(--accent); border-color: var(--accent);
}
.check input:checked + .box::after {
content: ""; display: block;
width: 8px; height: 4px;
border-left: 2px solid var(--ink-2);
border-bottom: 2px solid var(--ink-2);
transform: rotate(-45deg) translate(1px, -1px);
}
.check:has(input:checked) {
border-color: var(--accent);
background: rgba(29, 184, 151, 0.08);
}
.err-banner {
display: none;
align-items: center; gap: 10px;
padding: 12px 14px;
border-radius: var(--r-sm);
background: rgba(247, 104, 87, 0.10);
border: 1px solid rgba(247, 104, 87, 0.3);
color: #c84434;
font-size: 13.5px;
margin-bottom: 18px;
}
.err-banner svg { width: 16px; height: 16px; flex-shrink: 0; }
.form__nav {
display: flex; justify-content: space-between; gap: 12px;
margin-top: 26px;
padding-top: 20px;
border-top: 1px solid var(--border);
}
.form__nav .btn:disabled { opacity: 0.4; cursor: not-allowed; }
/* ---------- side info ---------- */
.side { padding-top: 8px; }
.side__card {
background: var(--ink-2);
color: #F4F2EC;
border-radius: var(--r-lg);
padding: 32px 30px;
margin-bottom: 18px;
}
.side__card h3 {
font: 600 19px/1.2 var(--font-display);
letter-spacing: -0.015em;
color: #fff;
}
.side__card p {
margin-top: 12px;
font-size: 14.5px;
color: rgba(244, 242, 236, 0.7);
line-height: 1.55;
}
.side__list {
margin-top: 22px;
list-style: none;
border-top: 1px solid rgba(244, 242, 236, 0.15);
padding-top: 16px;
}
.side__list li {
display: flex; gap: 12px;
padding: 10px 0;
font-size: 14px;
color: rgba(244, 242, 236, 0.92);
}
.side__list li::before {
content: "→"; color: var(--accent); flex-shrink: 0;
}
.side__alt {
background: var(--surface);
border: 1px solid var(--border);
border-radius: var(--r-lg);
padding: 24px 26px;
}
.side__alt h4 {
font: 500 12.5px/1 var(--font-mono);
letter-spacing: 0.1em;
text-transform: uppercase;
color: var(--muted);
margin-bottom: 12px;
}
.side__alt a {
display: flex; align-items: center; gap: 10px;
padding: 8px 0;
font-size: 14.5px;
color: var(--ink-2);
}
.side__alt a:hover { color: var(--accent); }
.side__alt a svg { width: 16px; height: 16px; color: var(--accent); }
/* ---------- success state ---------- */
.success {
display: none;
background: var(--surface);
border: 1px solid var(--accent);
border-radius: var(--r-lg);
padding: 56px 40px;
text-align: center;
}
.success__check {
width: 56px; height: 56px;
border-radius: 50%;
background: rgba(29, 184, 151, 0.16);
color: var(--accent);
display: grid; place-items: center;
margin: 0 auto 20px;
}
.success h2 {
font: 600 28px/1.15 var(--font-display);
letter-spacing: -0.02em;
color: var(--ink-2);
max-width: 22ch;
margin: 0 auto;
}
.success p {
margin-top: 14px;
color: var(--muted);
font-size: 16px;
max-width: 50ch;
margin-left: auto;
margin-right: auto;
}
.success__meta {
margin-top: 28px;
display: inline-flex; align-items: center; gap: 10px;
padding: 8px 14px;
background: var(--bg);
border: 1px solid var(--border);
border-radius: 999px;
font: 500 13px/1 var(--font-mono);
color: var(--muted);
letter-spacing: 0.04em;
}
.success__meta .dot {
width: 7px; height: 7px; border-radius: 50%;
background: var(--accent);
box-shadow: 0 0 0 4px rgba(29, 184, 151, 0.18);
}
@media (max-width: 960px) {
.contact-grid { grid-template-columns: 1fr; gap: 36px; }
.form { padding: 28px 24px; }
}
@media (max-width: 520px) {
.checklist { grid-template-columns: 1fr; }
}
</style>
</head>
<body>
<header class="header">
<div class="wrap header__row">
<a href="index.html" class="brand">
<span class="brand__mark"><img src="brand-mark.svg" alt="" width="26" height="26" /></span>
stackless
</a>
<nav class="nav" id="nav">
<a href="index.html#services">Services</a>
<a href="index.html#how">How it works</a>
<a href="pricing.html">Pricing</a>
<a href="index.html#why">Why us</a>
<a href="contact.html" class="nav__cta">Start a project</a>
</nav>
<button class="menu-btn" id="menuBtn" aria-label="Open menu">
<svg width="22" height="22" viewBox="0 0 22 22" fill="none"><path d="M3 6h16M3 11h16M3 16h16" stroke="#212A40" stroke-width="2" stroke-linecap="round"/></svg>
</button>
</div>
</header>
<section class="section contact-hero">
<div class="wrap">
<div style="max-width: 720px;">
<span class="section__kicker">Start a project</span>
<h1>Tell us what's eating your week.</h1>
<p>Three short steps, no marketing fluff. You'll get a fixed quote — or a polite "not a fit" — within one business day. Most replies go out within four hours.</p>
</div>
<div class="contact-grid">
<!-- ============== FORM ============== -->
<form class="form" id="contactForm" novalidate>
<div class="progress" aria-hidden="true">
<span class="dot is-on">1</span>
<span class="bar"></span>
<span class="dot">2</span>
<span class="bar"></span>
<span class="dot">3</span>
</div>
<div class="err-banner" id="errBanner">
<svg viewBox="0 0 16 16" fill="none"><circle cx="8" cy="8" r="7" stroke="currentColor" stroke-width="1.5"/><path d="M8 4v5M8 11.5v.01" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/></svg>
<span>Please fix the highlighted fields before continuing.</span>
</div>
<!-- Step 1 -->
<div class="step is-active" data-step="0">
<div class="step__head">
<h2>What do you need built?</h2>
<p>Pick one or more — we'll route the right team for the mix.</p>
</div>
<div class="field" style="margin-bottom: 20px;">
<label>Which services are you interested in?</label>
<div class="checklist">
<label class="check"><input type="checkbox" name="services" value="website" /><span class="box"></span>Website build or upgrade</label>
<label class="check"><input type="checkbox" name="services" value="agent" /><span class="box"></span>AI agent (chat or voice)</label>
<label class="check"><input type="checkbox" name="services" value="rental" /><span class="box"></span>Rent-an-AI-Agent retainer</label>
<label class="check"><input type="checkbox" name="services" value="automation" /><span class="box"></span>Outreach or lead-gen automation</label>
<label class="check"><input type="checkbox" name="services" value="integrations" /><span class="box"></span>Workflow integrations</label>
<label class="check"><input type="checkbox" name="services" value="apps" /><span class="box"></span>Internal app or dashboard</label>
</div>
<div class="services-err" id="servicesErr">Pick at least one service.</div>
</div>
<div class="field">
<label for="budget">Approximate budget</label>
<select id="budget" name="budget" required>
<option value="">Choose a range…</option>
<option>R10k – R25k · small project</option>
<option>R25k – R80k · standard build</option>
<option>R80k – R250k · multi-week engagement</option>
<option>R250k+ · ongoing studio retainer</option>
<option>Not sure yet</option>
</select>
</div>
<div class="field">
<label for="timeline">Ideal start</label>
<select id="timeline" name="timeline" required>
<option value="">Choose a timeline…</option>
<option>ASAP — within 2 weeks</option>
<option>This month</option>
<option>Next month</option>
<option>Within the quarter</option>
<option>Just exploring</option>
</select>
</div>
</div>
<!-- Step 2 -->
<div class="step" data-step="1">
<div class="step__head">
<h2>Who's it for?</h2>
<p>Just enough to make a useful reply. We never sell or share what you write here.</p>
</div>
<div class="field">
<label for="name">Your name</label>
<input id="name" name="name" type="text" required autocomplete="name" placeholder="Jane Mokoena" />
</div>
<div class="field">
<label for="email">Work email</label>
<input id="email" name="email" type="email" required autocomplete="email" placeholder="jane@yourcompany.co.za" />
<span class="hint">We reply from hello@stackless.app.</span>
</div>
<div class="field">
<label for="company">Company</label>
<input id="company" name="company" type="text" required placeholder="Your business name" />
</div>
<div class="field">
<label for="role">Your role (optional)</label>
<input id="role" name="role" type="text" placeholder="Founder, COO, Head of Ops…" />
</div>
</div>
<!-- Step 3 -->
<div class="step" data-step="2">
<div class="step__head">
<h2>What's the actual problem?</h2>
<p>The more specific, the better your quote. Two sentences is fine.</p>
</div>
<div class="field">
<label for="problem">Describe what you're trying to fix or build</label>
<textarea id="problem" name="problem" required placeholder="e.g. Our support inbox eats 3 hours a day and 60% of tickets are the same three questions. We want an agent that drafts replies and only flags the weird ones for a human."></textarea>
</div>
<div class="field">
<label for="stack">Tools you already use (optional)</label>
<input id="stack" name="stack" type="text" placeholder="HubSpot · Xero · WhatsApp · Shopify" />
<span class="hint">Comma-separated. Helps us skip the discovery questions.</span>
</div>
<div class="field">
<label for="source">How did you find us? (optional)</label>
<select id="source" name="source">
<option value="">Choose one…</option>
<option>Referral</option>
<option>Search</option>
<option>Social</option>
<option>Article or podcast</option>
<option>We've worked together before</option>
</select>
</div>
</div>
<div class="form__nav">
<button type="button" class="btn btn--ghost btn--sm" id="prevBtn" disabled>← Back</button>
<div style="display: flex; gap: 10px;">
<button type="button" class="btn btn--primary btn--sm" id="nextBtn">Continue <span class="arrow">→</span></button>
<button type="submit" class="btn btn--primary btn--sm" id="submitBtn" style="display: none;">Send &amp; request a quote <span class="arrow">→</span></button>
</div>
</div>
</form>
<!-- Success state -->
<div class="success" id="formSuccess">
<div class="success__check">
<svg width="28" height="28" viewBox="0 0 28 28" fill="none"><path d="M6 14.5l5 5 11-11.5" stroke="currentColor" stroke-width="2.6" stroke-linecap="round" stroke-linejoin="round"/></svg>
</div>
<h2>Got it — we're on it.</h2>
<p>You'll get a reply from a real human (probably Gerhard or Mapula) within four working hours. If you'd rather skip the queue, mail us directly.</p>
<div class="success__meta">
<span class="dot"></span> Ref · #SL-<span id="refNum">—</span>
</div>
</div>
<!-- ============== SIDE INFO ============== -->
<aside class="side">
<div class="side__card">
<h3>What happens after you send this?</h3>
<p>Three steps, no surprises. We do the discovery properly so the quote holds up when you sign.</p>
<ul class="side__list">
<li>We read it (within four working hours).</li>
<li>We send a one-page quote — fixed scope, fixed price, fixed deadline.</li>
<li>If we're not a fit, we tell you who is.</li>
</ul>
</div>
<div class="side__alt">
<h4>Prefer email or a call?</h4>
<a href="mailto:hello@stackless.app">
<svg viewBox="0 0 16 16" fill="none"><rect x="2" y="3.5" width="12" height="9" rx="1.5" stroke="currentColor" stroke-width="1.5"/><path d="M2.5 4l5.5 4 5.5-4" stroke="currentColor" stroke-width="1.5" stroke-linejoin="round"/></svg>
hello@stackless.app
</a>
<a href="tel:+27210000000">
<svg viewBox="0 0 16 16" fill="none"><path d="M3 3.5c0 6 3.5 9.5 9.5 9.5l1-2.5-2.5-1-1.2 1.2c-1.4-.7-2.5-1.8-3.2-3.2L8 6.5 9.5 4 7 3l-4 .5z" stroke="currentColor" stroke-width="1.5" stroke-linejoin="round"/></svg>
+27 21 000 0000
</a>
<a href="https://wa.me/27210000000" rel="noopener">
<svg viewBox="0 0 16 16" fill="none"><path d="M8 2a6 6 0 00-5 9l-1 3 3-1A6 6 0 108 2zm3.4 7.6c-.2.5-1 1-1.5 1.1-.4.1-.9.1-1.4-.1-.3-.1-.7-.2-1.2-.4-2.1-.9-3.5-3-3.6-3.2-.1-.2-.9-1.1-.9-2.1s.5-1.5.7-1.7c.2-.2.4-.2.6-.2h.4c.1 0 .3 0 .5.4l.7 1.7c.1.2 0 .4-.1.6l-.3.4c-.1.1-.2.3-.1.4.1.2.5.9 1.1 1.4.7.7 1.4.9 1.6 1 .2.1.3 0 .4-.1l.5-.6c.1-.2.3-.1.5-.1l1.6.8c.2.1.4.2.4.3 0 .1 0 .7-.2 1.2z" fill="currentColor"/></svg>
WhatsApp us
</a>
</div>
</aside>
</div>
</div>
</section>
<footer>
<div class="wrap">
<div class="foot">
<div class="foot__brand">
<a href="index.html" class="brand">
<span class="brand__mark"><img src="brand-mark.svg" alt="" width="26" height="26" /></span>
stackless
</a>
<p>The on-call studio for small and medium businesses. Build, automate, integrate — without hiring an in-house team.</p>
</div>
<div>
<h5>Services</h5>
<ul>
<li><a href="index.html#services">Websites</a></li>
<li><a href="index.html#services">AI agents</a></li>
<li><a href="pricing.html">Rent-an-AI-Agent</a></li>
<li><a href="index.html#services">Integrations</a></li>
<li><a href="index.html#services">Apps &amp; dashboards</a></li>
</ul>
</div>
<div>
<h5>Studio</h5>
<ul>
<li><a href="index.html#how">How we work</a></li>
<li><a href="index.html#why">Why us</a></li>
<li><a href="pricing.html">Pricing</a></li>
<li><a href="contact.html">Start a project</a></li>
</ul>
</div>
<div>
<h5>Reach us</h5>
<ul>
<li><a href="mailto:hello@stackless.app">hello@stackless.app</a></li>
<li><a href="tel:+27210000000">+27 21 000 0000</a></li>
<li>Cape Town · Johannesburg</li>
<li>Mon–Fri, 08:00–17:00 SAST</li>
</ul>
</div>
</div>
<div class="foot__legal">
<span>© 2026 Stackless (Pty) Ltd · Reg. 2024/184256/07</span>
<span>Made on the African continent.</span>
</div>
</div>
</footer>
<script src="header.js"></script>
<script src="contact.js"></script>
<script>
// Generate a fake ref number on success (purely cosmetic for the demo)
document.addEventListener('DOMContentLoaded', function () {
var el = document.getElementById('refNum');
if (el) {
var n = Math.floor(1000 + Math.random() * 9000);
el.textContent = n.toString();
}
});
</script>
</body>
</html>