Add low-friction 3-step lead form to contact section (posts to n8n)
Soft conversion path alongside booking; SW steel/Georgia styling. Posts JSON to https://n8n.shopwisdom.ca/webhook/sw-lead, honeypot-protected, email fallback. Staging branch only. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
+84
@@ -271,6 +271,37 @@
|
|||||||
<h2>Start with a conversation</h2>
|
<h2>Start with a conversation</h2>
|
||||||
<p>No pitch. No proposal until we've had a real conversation. Describe the friction — even roughly. The more context you share, the more useful our first conversation will be.</p>
|
<p>No pitch. No proposal until we've had a real conversation. Describe the friction — even roughly. The more context you share, the more useful our first conversation will be.</p>
|
||||||
<p>I read every message personally and usually reply within one business day. If your problem isn't something I can help with, I'll tell you honestly — and point you somewhere that can.</p>
|
<p>I read every message personally and usually reply within one business day. If your problem isn't something I can help with, I'll tell you honestly — and point you somewhere that can.</p>
|
||||||
|
|
||||||
|
<form class="lf" data-endpoint="https://n8n.shopwisdom.ca/webhook/sw-lead" data-source="shopwisdom" novalidate>
|
||||||
|
<div class="lf-progress" aria-hidden="true"><span class="lf-dot is-active"></span><span class="lf-dot"></span><span class="lf-dot"></span></div>
|
||||||
|
<fieldset class="lf-step is-active" data-step="1">
|
||||||
|
<legend class="lf-q">What's the situation in your shop?</legend>
|
||||||
|
<div class="lf-choices">
|
||||||
|
<label class="lf-choice"><input type="radio" name="topic" value="A key person is retiring soon" required> A key person is retiring soon</label>
|
||||||
|
<label class="lf-choice"><input type="radio" name="topic" value="Know-how lives in a few heads"> Know-how lives in just a few heads</label>
|
||||||
|
<label class="lf-choice"><input type="radio" name="topic" value="A process or tool needs building"> A process or tool needs building</label>
|
||||||
|
<label class="lf-choice"><input type="radio" name="topic" value="Just exploring"> Just exploring for now</label>
|
||||||
|
</div>
|
||||||
|
<div class="lf-nav"><button type="button" class="btn lf-next" data-next>Continue →</button></div>
|
||||||
|
</fieldset>
|
||||||
|
<fieldset class="lf-step" data-step="2">
|
||||||
|
<legend class="lf-q">Anything you want me to know? <span class="lf-opt">(optional)</span></legend>
|
||||||
|
<textarea class="lf-input" name="detail" rows="3" placeholder="Even a rough sentence helps."></textarea>
|
||||||
|
<div class="lf-nav"><button type="button" class="btn ghost lf-back" data-back>← Back</button><button type="button" class="btn lf-next" data-next>Continue →</button></div>
|
||||||
|
</fieldset>
|
||||||
|
<fieldset class="lf-step" data-step="3">
|
||||||
|
<legend class="lf-q">Where do I reach you?</legend>
|
||||||
|
<input class="lf-input" type="text" name="name" placeholder="Your name" required autocomplete="name">
|
||||||
|
<input class="lf-input" type="email" name="email" placeholder="Email" required autocomplete="email">
|
||||||
|
<input class="lf-input" type="tel" name="phone" placeholder="Phone (optional)" autocomplete="tel">
|
||||||
|
<input type="text" name="company_website" class="lf-hp" tabindex="-1" autocomplete="off" aria-hidden="true">
|
||||||
|
<div class="lf-nav"><button type="button" class="btn ghost lf-back" data-back>← Back</button><button type="submit" class="btn lf-submit">Send it →</button></div>
|
||||||
|
<p class="lf-err" hidden>Hmm — that didn't go through. Please <a href="mailto:michael@opencommunications.consulting">email me directly</a> and I'll get right back to you.</p>
|
||||||
|
</fieldset>
|
||||||
|
<div class="lf-done" hidden><p class="lf-done-msg">Got it — thanks. I read every message personally and usually reply within a business day.</p></div>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
<p class="lf-alt">Prefer to reach out directly?</p>
|
||||||
<p class="contact-action">
|
<p class="contact-action">
|
||||||
<a class="btn" href="mailto:michael@opencommunications.consulting?subject=Fit%20call%20—%20Shop%20Wisdom">Email Michael</a>
|
<a class="btn" href="mailto:michael@opencommunications.consulting?subject=Fit%20call%20—%20Shop%20Wisdom">Email Michael</a>
|
||||||
<a class="btn ghost tel" data-p1="778" data-p2="985" data-p3="6736" href="mailto:michael@opencommunications.consulting">Call 778‑985‑OPEN (6736)</a>
|
<a class="btn ghost tel" data-p1="778" data-p2="985" data-p3="6736" href="mailto:michael@opencommunications.consulting">Call 778‑985‑OPEN (6736)</a>
|
||||||
@@ -320,6 +351,59 @@
|
|||||||
})();
|
})();
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<!-- Lead form: 3-step navigation + submit to the n8n webhook (honeypot-protected) -->
|
||||||
|
<script>
|
||||||
|
(function () {
|
||||||
|
document.querySelectorAll('form.lf').forEach(function (form) {
|
||||||
|
var steps = [].slice.call(form.querySelectorAll('.lf-step'));
|
||||||
|
var dots = [].slice.call(form.querySelectorAll('.lf-dot'));
|
||||||
|
var done = form.querySelector('.lf-done');
|
||||||
|
var err = form.querySelector('.lf-err');
|
||||||
|
var progress = form.querySelector('.lf-progress');
|
||||||
|
var cur = 0;
|
||||||
|
function show(i) {
|
||||||
|
steps.forEach(function (s, k) { s.classList.toggle('is-active', k === i); });
|
||||||
|
dots.forEach(function (d, k) { d.classList.toggle('is-active', k <= i); });
|
||||||
|
cur = i;
|
||||||
|
var fld = steps[i].querySelector('input:not([type=radio]),textarea'); if (fld) { try { fld.focus(); } catch (e) {} }
|
||||||
|
}
|
||||||
|
function valid(i) {
|
||||||
|
var reqs = steps[i].querySelectorAll('[required]');
|
||||||
|
for (var j = 0; j < reqs.length; j++) { if (!reqs[j].checkValidity()) { reqs[j].reportValidity(); return false; } }
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
form.addEventListener('click', function (e) {
|
||||||
|
if (e.target.closest('[data-next]')) { if (valid(cur)) show(Math.min(cur + 1, steps.length - 1)); }
|
||||||
|
else if (e.target.closest('[data-back]')) { show(Math.max(cur - 1, 0)); }
|
||||||
|
});
|
||||||
|
form.addEventListener('submit', function (e) {
|
||||||
|
e.preventDefault();
|
||||||
|
if (!valid(cur)) return;
|
||||||
|
var hp = form.querySelector('.lf-hp');
|
||||||
|
if (hp && hp.value) { return; }
|
||||||
|
if (err) err.hidden = true;
|
||||||
|
var data = {};
|
||||||
|
new FormData(form).forEach(function (v, k) { if (k !== 'company_website') data[k] = v; });
|
||||||
|
data.source = form.getAttribute('data-source') || location.hostname;
|
||||||
|
data.submittedAt = new Date().toISOString();
|
||||||
|
var btn = form.querySelector('.lf-submit'); var label = btn.textContent;
|
||||||
|
btn.disabled = true; btn.textContent = 'Sending…';
|
||||||
|
fetch(form.getAttribute('data-endpoint'), {
|
||||||
|
method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(data)
|
||||||
|
}).then(function (r) {
|
||||||
|
if (!r.ok) throw new Error('status ' + r.status);
|
||||||
|
steps.forEach(function (s) { s.style.display = 'none'; });
|
||||||
|
if (progress) progress.style.display = 'none';
|
||||||
|
if (done) done.hidden = false;
|
||||||
|
}).catch(function () {
|
||||||
|
btn.disabled = false; btn.textContent = label;
|
||||||
|
if (err) err.hidden = false;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
})();
|
||||||
|
</script>
|
||||||
|
|
||||||
<!-- Cal.com booking embed (opens the booking popup on-brand; href is the no-JS fallback) -->
|
<!-- Cal.com booking embed (opens the booking popup on-brand; href is the no-JS fallback) -->
|
||||||
<script>
|
<script>
|
||||||
(function (C, A, L) { let p = function (a, ar) { a.q.push(ar); }; let d = C.document; C.Cal = C.Cal || function () { let cal = C.Cal; let ar = arguments; if (!cal.loaded) { cal.ns = {}; cal.q = cal.q || []; d.head.appendChild(d.createElement("script")).src = A; cal.loaded = true; } if (ar[0] === L) { const api = function () { p(api, arguments); }; const namespace = ar[1]; api.q = api.q || []; if (typeof namespace === "string") { cal.ns[namespace] = cal.ns[namespace] || api; p(cal.ns[namespace], ar); p(cal, ["initNamespace", namespace]); } else p(cal, ar); return; } p(cal, ar); }; })(window, "https://cal.shopwisdom.ca/embed/embed.js", "init");
|
(function (C, A, L) { let p = function (a, ar) { a.q.push(ar); }; let d = C.document; C.Cal = C.Cal || function () { let cal = C.Cal; let ar = arguments; if (!cal.loaded) { cal.ns = {}; cal.q = cal.q || []; d.head.appendChild(d.createElement("script")).src = A; cal.loaded = true; } if (ar[0] === L) { const api = function () { p(api, arguments); }; const namespace = ar[1]; api.q = api.q || []; if (typeof namespace === "string") { cal.ns[namespace] = cal.ns[namespace] || api; p(cal.ns[namespace], ar); p(cal, ["initNamespace", namespace]); } else p(cal, ar); return; } p(cal, ar); }; })(window, "https://cal.shopwisdom.ca/embed/embed.js", "init");
|
||||||
|
|||||||
@@ -241,3 +241,28 @@ blockquote p { margin: 0; font-style: italic; color: var(--ink-soft); }
|
|||||||
.hero { padding: 56px 0 44px; }
|
.hero { padding: 56px 0 44px; }
|
||||||
section { padding: 48px 0; }
|
section { padding: 48px 0; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ── Lead form: low-friction 3-step ─────────────────────────────────────── */
|
||||||
|
.lf { max-width: 30rem; margin: 2rem auto 1.4rem; text-align: left; }
|
||||||
|
.lf-progress { display: flex; gap: 8px; justify-content: center; margin-bottom: 1.6rem; }
|
||||||
|
.lf-dot { width: 30px; height: 4px; border-radius: 2px; background: var(--line); transition: background-color 0.3s ease; }
|
||||||
|
.lf-dot.is-active { background: var(--steel); }
|
||||||
|
.lf-step { display: none; border: 0; padding: 0; margin: 0; min-inline-size: 0; }
|
||||||
|
.lf-step.is-active { display: block; animation: lfIn 0.25s ease; }
|
||||||
|
@keyframes lfIn { from { opacity: 0; transform: translateY(6px); } to { opacity: 1; transform: none; } }
|
||||||
|
.lf-q { font-family: Georgia, serif; font-weight: 700; font-size: 1.2rem; line-height: 1.3; color: var(--ink); margin: 0 0 1rem; padding: 0; }
|
||||||
|
.lf-opt { font-family: Verdana, Geneva, sans-serif; font-size: 0.78rem; color: var(--ink-soft); font-weight: normal; }
|
||||||
|
.lf-choices { display: flex; flex-direction: column; gap: 10px; }
|
||||||
|
.lf-choice { display: flex; align-items: center; gap: 12px; padding: 13px 16px; border: 1px solid var(--line); border-radius: 6px; font-family: Georgia, serif; font-size: 0.98rem; color: var(--ink); background: var(--panel); cursor: pointer; transition: border-color 0.2s ease, background-color 0.2s ease; }
|
||||||
|
.lf-choice:hover { border-color: var(--steel); }
|
||||||
|
.lf-choice input { accent-color: var(--steel); width: 16px; height: 16px; flex: none; }
|
||||||
|
.lf-choice:has(input:checked) { border-color: var(--steel); background: rgba(44, 93, 124, 0.06); }
|
||||||
|
.lf-input { width: 100%; box-sizing: border-box; padding: 12px 14px; border: 1px solid var(--line); border-radius: 6px; font-family: Georgia, serif; font-size: 1rem; color: var(--ink); background: var(--panel); margin-bottom: 12px; }
|
||||||
|
.lf-input:focus { outline: none; border-color: var(--steel); box-shadow: 0 0 0 3px rgba(44, 93, 124, 0.12); }
|
||||||
|
.lf-hp { position: absolute !important; left: -9999px; width: 1px; height: 1px; opacity: 0; }
|
||||||
|
.lf-nav { display: flex; justify-content: flex-end; align-items: center; gap: 14px; margin-top: 1.2rem; }
|
||||||
|
.lf-nav .lf-back { margin-right: auto; }
|
||||||
|
.lf-done-msg { font-family: Georgia, serif; font-size: 1.1rem; line-height: 1.6; color: var(--ink); text-align: center; padding: 1.4rem 0; margin: 0; }
|
||||||
|
.lf-err { font-family: Verdana, Geneva, sans-serif; font-size: 0.85rem; color: #b4452f; margin: 1rem 0 0; }
|
||||||
|
.lf-err a { color: #b4452f; }
|
||||||
|
.lf-alt { font-family: Verdana, Geneva, sans-serif; font-size: 0.8rem; letter-spacing: 0.04em; text-transform: uppercase; color: var(--ink-soft); text-align: center; margin: 0.4rem 0 0.7rem; }
|
||||||
|
|||||||
Reference in New Issue
Block a user