695 lines
16 KiB
Svelte
695 lines
16 KiB
Svelte
<script lang="ts">
|
||
export let idPrefix: string;
|
||
export let lead = '';
|
||
export let submitLabel = 'Book a free Meet & Greet';
|
||
export let tone: 'default' | 'conversational' | 'minimal' = 'default';
|
||
export let layout: 'stacked' | 'carded' = 'stacked';
|
||
export let eyebrow = 'Free Meet & Greet';
|
||
export let title = 'Tell us about your dog';
|
||
export let subtitle =
|
||
'A guided first step so we can recommend the right walk, visit, or calmer starting point.';
|
||
|
||
let submitted = false;
|
||
let step = 1;
|
||
let ownerStepUnlocked = false;
|
||
|
||
function handleSubmit() {
|
||
if (step === 1) {
|
||
ownerStepUnlocked = true;
|
||
step = 2;
|
||
return;
|
||
}
|
||
|
||
submitted = true;
|
||
}
|
||
|
||
function goToStep(nextStep: number) {
|
||
if (nextStep === 2 && !ownerStepUnlocked) {
|
||
return;
|
||
}
|
||
|
||
step = nextStep;
|
||
}
|
||
</script>
|
||
|
||
<form
|
||
class={`vf-form vf-form--${tone} vf-form--${layout}`}
|
||
on:submit|preventDefault={handleSubmit}
|
||
novalidate
|
||
>
|
||
<div class="vf-header">
|
||
<span class="vf-eyebrow">{eyebrow}</span>
|
||
<h3 class="vf-title">{title}</h3>
|
||
<p class="vf-subtitle">{subtitle}</p>
|
||
|
||
<div class="vf-stepper" aria-label="Application steps">
|
||
<button
|
||
type="button"
|
||
class:active={step === 1}
|
||
class="vf-step"
|
||
on:click={() => goToStep(1)}
|
||
>
|
||
<span class="vf-step-number">1</span>
|
||
<span class="vf-step-label">Dog details</span>
|
||
</button>
|
||
<span class="vf-step-divider" aria-hidden="true"></span>
|
||
<button
|
||
type="button"
|
||
class:active={step === 2}
|
||
class="vf-step"
|
||
disabled={!ownerStepUnlocked}
|
||
aria-disabled={!ownerStepUnlocked}
|
||
on:click={() => goToStep(2)}
|
||
>
|
||
<span class="vf-step-number">2</span>
|
||
<span class="vf-step-label">Owner details</span>
|
||
</button>
|
||
</div>
|
||
</div>
|
||
|
||
{#if lead}
|
||
<p class="vf-lead">{lead}</p>
|
||
{/if}
|
||
|
||
{#if step === 1}
|
||
<section class="vf-group" aria-labelledby={`${idPrefix}-dog-group`}>
|
||
<div class="vf-group-head">
|
||
<p class="vf-kicker" id={`${idPrefix}-dog-group`}>Dog details</p>
|
||
<p class="vf-group-copy">
|
||
A few calm details first so we can judge fit, pace, and the right kind of outing.
|
||
</p>
|
||
</div>
|
||
|
||
<div class="vf-grid vf-grid--two">
|
||
<label class="vf-field">
|
||
<span class="vf-label">Dog name</span>
|
||
<input id={`${idPrefix}-dog-name`} name="dogName" type="text" placeholder="Maya" />
|
||
</label>
|
||
|
||
<label class="vf-field">
|
||
<span class="vf-label">Suburb / location</span>
|
||
<input
|
||
id={`${idPrefix}-location`}
|
||
name="location"
|
||
type="text"
|
||
placeholder="Mt Eden, Grey Lynn, Ponsonby…"
|
||
/>
|
||
</label>
|
||
</div>
|
||
|
||
<fieldset class="vf-choice-group">
|
||
<legend class="vf-label">What feels closest right now?</legend>
|
||
<p class="vf-helper">
|
||
Not sure is completely fine. We can sort that out at the Meet & Greet.
|
||
</p>
|
||
<div class="vf-choices">
|
||
<label class="vf-choice">
|
||
<input type="radio" name={`${idPrefix}-service-fit`} value="tiny-gang" />
|
||
<span>Tiny Gang Pack Walks</span>
|
||
</label>
|
||
<label class="vf-choice">
|
||
<input type="radio" name={`${idPrefix}-service-fit`} value="one-to-one" />
|
||
<span>Solo Walks</span>
|
||
</label>
|
||
<label class="vf-choice">
|
||
<input type="radio" name={`${idPrefix}-service-fit`} value="puppy-visits" />
|
||
<span>Puppy Visits</span>
|
||
</label>
|
||
<label class="vf-choice">
|
||
<input type="radio" name={`${idPrefix}-service-fit`} value="not-sure" checked />
|
||
<span>Not sure yet</span>
|
||
</label>
|
||
</div>
|
||
</fieldset>
|
||
|
||
<label class="vf-field vf-field--full">
|
||
<span class="vf-label">About your dog</span>
|
||
<textarea
|
||
id={`${idPrefix}-about-dog`}
|
||
name="aboutDog"
|
||
rows="5"
|
||
placeholder="Tell us about age, size, confidence, leash manners, how they feel around other dogs, and anything that helps us make the right recommendation."
|
||
></textarea>
|
||
</label>
|
||
|
||
<div class="vf-note-row" aria-label="Helpful notes">
|
||
<article class="vf-note">
|
||
<span class="vf-note-title">Nervous dogs</span>
|
||
<p>
|
||
If your dog is shy, easily overwhelmed, or still building confidence, mention it here.
|
||
That often points us toward a calmer first step.
|
||
</p>
|
||
</article>
|
||
<article class="vf-note">
|
||
<span class="vf-note-title">Tiny Gang suitability</span>
|
||
<p>
|
||
Our small-group walks work best for dogs who enjoy the right company, gentle
|
||
structure, and a routine they can settle into.
|
||
</p>
|
||
</article>
|
||
</div>
|
||
</section>
|
||
{/if}
|
||
|
||
{#if step === 2}
|
||
<section class="vf-group" aria-labelledby={`${idPrefix}-owner-group`}>
|
||
<div class="vf-group-head">
|
||
<p class="vf-kicker" id={`${idPrefix}-owner-group`}>Owner details</p>
|
||
<p class="vf-group-copy">
|
||
So Aless can reply properly and arrange a free Meet & Greet without back-and-forth.
|
||
</p>
|
||
</div>
|
||
|
||
<div class="vf-grid vf-grid--three">
|
||
<label class="vf-field">
|
||
<span class="vf-label">Owner name</span>
|
||
<input id={`${idPrefix}-owner-name`} name="ownerName" type="text" placeholder="Your full name" />
|
||
</label>
|
||
|
||
<label class="vf-field">
|
||
<span class="vf-label">Email</span>
|
||
<input id={`${idPrefix}-email`} name="email" type="email" placeholder="you@example.com" />
|
||
</label>
|
||
|
||
<label class="vf-field">
|
||
<span class="vf-label">Phone</span>
|
||
<input id={`${idPrefix}-phone`} name="phone" type="tel" placeholder="021 123 4567" />
|
||
</label>
|
||
</div>
|
||
|
||
<article class="vf-owner-note">
|
||
<span class="vf-note-title">What happens next</span>
|
||
<p>
|
||
We’ll reply personally, talk through fit, and arrange the free Meet & Greet if it
|
||
feels like the right next step.
|
||
</p>
|
||
</article>
|
||
</section>
|
||
{/if}
|
||
|
||
<div class="vf-footer">
|
||
<p class="vf-reassurance">
|
||
Free Meet & Greet. No pressure. Just the right starting point for your dog.
|
||
</p>
|
||
<div class="vf-actions">
|
||
{#if step === 2}
|
||
<button type="button" class="vf-secondary" on:click={() => goToStep(1)}>Back</button>
|
||
{/if}
|
||
<button type="submit" class="vf-submit">
|
||
{step === 1 ? 'Next: owner details' : submitLabel}
|
||
</button>
|
||
</div>
|
||
</div>
|
||
|
||
{#if submitted}
|
||
<p class="vf-success" role="status">
|
||
Demo only: this variant would hand the enquiry to Aless and prompt a free Meet & Greet.
|
||
</p>
|
||
{/if}
|
||
</form>
|
||
|
||
<style>
|
||
.vf-form {
|
||
display: grid;
|
||
gap: 24px;
|
||
}
|
||
|
||
.vf-form--carded {
|
||
gap: 18px;
|
||
}
|
||
|
||
.vf-header {
|
||
display: grid;
|
||
gap: 12px;
|
||
}
|
||
|
||
.vf-eyebrow {
|
||
display: inline-flex;
|
||
align-items: center;
|
||
width: fit-content;
|
||
min-height: 30px;
|
||
padding: 0 12px;
|
||
border-radius: 999px;
|
||
background: rgba(33, 48, 33, 0.07);
|
||
box-shadow: inset 0 0 0 1px rgba(17, 20, 24, 0.05);
|
||
color: var(--gw-green);
|
||
font-family: var(--font-head);
|
||
font-size: 11px;
|
||
font-weight: 700;
|
||
letter-spacing: 0.08em;
|
||
text-transform: uppercase;
|
||
}
|
||
|
||
.vf-title {
|
||
margin: 0;
|
||
color: #11171b;
|
||
font-family: var(--font-head);
|
||
font-size: clamp(26px, 3vw, 34px);
|
||
line-height: 1.06;
|
||
letter-spacing: -0.04em;
|
||
}
|
||
|
||
.vf-subtitle {
|
||
margin: 0;
|
||
color: #59606d;
|
||
font-size: 15px;
|
||
line-height: 1.6;
|
||
}
|
||
|
||
.vf-stepper {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 10px;
|
||
margin-top: 4px;
|
||
}
|
||
|
||
.vf-step {
|
||
display: inline-flex;
|
||
align-items: center;
|
||
gap: 10px;
|
||
min-height: 44px;
|
||
padding: 0 14px 0 10px;
|
||
border: none;
|
||
border-radius: 999px;
|
||
background: rgba(255, 255, 255, 0.84);
|
||
box-shadow: inset 0 0 0 1px rgba(17, 20, 24, 0.06);
|
||
color: #50555c;
|
||
cursor: pointer;
|
||
transition:
|
||
background 0.18s ease,
|
||
color 0.18s ease,
|
||
transform 0.18s cubic-bezier(0.22, 1, 0.36, 1);
|
||
}
|
||
|
||
.vf-step.active {
|
||
background: rgba(33, 48, 33, 0.08);
|
||
color: #11171b;
|
||
}
|
||
|
||
.vf-step:disabled {
|
||
cursor: default;
|
||
opacity: 0.55;
|
||
}
|
||
|
||
.vf-step-number {
|
||
display: inline-flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
width: 28px;
|
||
height: 28px;
|
||
border-radius: 10px;
|
||
background: var(--gw-green);
|
||
color: var(--yellow);
|
||
font-family: var(--font-head);
|
||
font-size: 12px;
|
||
font-weight: 700;
|
||
}
|
||
|
||
.vf-step-label {
|
||
font-family: var(--font-head);
|
||
font-size: 12px;
|
||
font-weight: 700;
|
||
line-height: 1.2;
|
||
}
|
||
|
||
.vf-step-divider {
|
||
width: 26px;
|
||
height: 1px;
|
||
background: rgba(17, 20, 24, 0.1);
|
||
}
|
||
|
||
.vf-lead {
|
||
margin: 0;
|
||
color: #4c5056;
|
||
font-size: 15px;
|
||
line-height: 1.65;
|
||
}
|
||
|
||
.vf-group {
|
||
display: grid;
|
||
gap: 18px;
|
||
}
|
||
|
||
.vf-form--carded .vf-group {
|
||
padding: 22px;
|
||
border-radius: 24px;
|
||
background: linear-gradient(180deg, rgba(251, 251, 251, 0.98) 0%, rgba(247, 248, 246, 1) 100%);
|
||
box-shadow:
|
||
inset 0 0 0 1px rgba(17, 20, 24, 0.06),
|
||
0 12px 28px rgba(17, 20, 24, 0.06);
|
||
}
|
||
|
||
.vf-group-head {
|
||
display: grid;
|
||
gap: 6px;
|
||
}
|
||
|
||
.vf-kicker {
|
||
margin: 0;
|
||
color: var(--gw-green);
|
||
font-family: var(--font-head);
|
||
font-size: 11px;
|
||
font-weight: 700;
|
||
letter-spacing: 0.08em;
|
||
text-transform: uppercase;
|
||
}
|
||
|
||
.vf-group-copy {
|
||
margin: 0;
|
||
color: #59606d;
|
||
font-size: 14px;
|
||
line-height: 1.55;
|
||
}
|
||
|
||
.vf-grid {
|
||
display: grid;
|
||
gap: 14px;
|
||
}
|
||
|
||
.vf-grid--two {
|
||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||
}
|
||
|
||
.vf-grid--three {
|
||
grid-template-columns: repeat(3, minmax(0, 1fr));
|
||
}
|
||
|
||
.vf-field {
|
||
display: grid;
|
||
gap: 8px;
|
||
}
|
||
|
||
.vf-field--full {
|
||
width: 100%;
|
||
}
|
||
|
||
.vf-label,
|
||
.vf-choice-group legend {
|
||
color: #16181d;
|
||
font-size: 14px;
|
||
font-weight: 700;
|
||
line-height: 1.35;
|
||
}
|
||
|
||
.vf-field input,
|
||
.vf-field textarea {
|
||
width: 100%;
|
||
border: none;
|
||
border-radius: 18px;
|
||
background: rgba(255, 255, 255, 0.96);
|
||
box-shadow:
|
||
inset 0 0 0 1px rgba(17, 20, 24, 0.08),
|
||
0 1px 0 rgba(255, 255, 255, 0.3);
|
||
color: #1f2421;
|
||
padding: 15px 16px;
|
||
font-size: 15px;
|
||
line-height: 1.45;
|
||
outline: none;
|
||
transition:
|
||
box-shadow 0.18s ease,
|
||
transform 0.18s cubic-bezier(0.22, 1, 0.36, 1),
|
||
background 0.18s ease;
|
||
}
|
||
|
||
.vf-field textarea {
|
||
resize: vertical;
|
||
min-height: 132px;
|
||
}
|
||
|
||
.vf-field input:focus-visible,
|
||
.vf-field textarea:focus-visible,
|
||
.vf-choice input:focus-visible + span,
|
||
.vf-step:focus-visible,
|
||
.vf-secondary:focus-visible {
|
||
box-shadow:
|
||
inset 0 0 0 2px rgba(255, 209, 0, 0.7),
|
||
0 0 0 4px rgba(255, 209, 0, 0.14);
|
||
background: #fff;
|
||
outline: none;
|
||
}
|
||
|
||
.vf-choice-group {
|
||
display: grid;
|
||
gap: 10px;
|
||
min-width: 0;
|
||
margin: 0;
|
||
padding: 0;
|
||
border: none;
|
||
}
|
||
|
||
.vf-helper {
|
||
margin: 0;
|
||
color: #687076;
|
||
font-size: 13px;
|
||
line-height: 1.5;
|
||
}
|
||
|
||
.vf-choices {
|
||
display: flex;
|
||
flex-wrap: wrap;
|
||
gap: 10px;
|
||
}
|
||
|
||
.vf-choice {
|
||
position: relative;
|
||
}
|
||
|
||
.vf-choice input {
|
||
position: absolute;
|
||
opacity: 0;
|
||
pointer-events: none;
|
||
}
|
||
|
||
.vf-choice span {
|
||
display: inline-flex;
|
||
align-items: center;
|
||
min-height: 42px;
|
||
padding: 0 14px;
|
||
border-radius: 999px;
|
||
background: rgba(255, 255, 255, 0.9);
|
||
box-shadow: inset 0 0 0 1px rgba(17, 20, 24, 0.08);
|
||
color: #2f3134;
|
||
font-size: 13px;
|
||
font-weight: 600;
|
||
line-height: 1.2;
|
||
transition:
|
||
box-shadow 0.18s ease,
|
||
background 0.18s ease,
|
||
color 0.18s ease,
|
||
transform 0.18s cubic-bezier(0.22, 1, 0.36, 1);
|
||
}
|
||
|
||
.vf-choice input:checked + span {
|
||
background: rgba(255, 209, 0, 0.18);
|
||
box-shadow: inset 0 0 0 1px rgba(255, 209, 0, 0.34);
|
||
color: #16181d;
|
||
}
|
||
|
||
.vf-note-row {
|
||
display: grid;
|
||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||
gap: 12px;
|
||
}
|
||
|
||
.vf-note,
|
||
.vf-owner-note {
|
||
padding: 16px 16px 15px;
|
||
border-radius: 20px;
|
||
}
|
||
|
||
.vf-note {
|
||
background: rgba(33, 48, 33, 0.05);
|
||
box-shadow: inset 0 0 0 1px rgba(33, 48, 33, 0.06);
|
||
}
|
||
|
||
.vf-owner-note {
|
||
background: rgba(255, 209, 0, 0.12);
|
||
box-shadow: inset 0 0 0 1px rgba(255, 209, 0, 0.16);
|
||
}
|
||
|
||
.vf-note-title {
|
||
display: block;
|
||
margin-bottom: 6px;
|
||
color: var(--gw-green);
|
||
font-family: var(--font-head);
|
||
font-size: 11px;
|
||
font-weight: 700;
|
||
letter-spacing: 0.08em;
|
||
text-transform: uppercase;
|
||
}
|
||
|
||
.vf-note p,
|
||
.vf-owner-note p {
|
||
margin: 0;
|
||
color: #4c5056;
|
||
font-size: 13px;
|
||
line-height: 1.55;
|
||
}
|
||
|
||
.vf-footer {
|
||
display: grid;
|
||
gap: 14px;
|
||
}
|
||
|
||
.vf-actions {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 12px;
|
||
}
|
||
|
||
.vf-reassurance {
|
||
margin: 0;
|
||
color: #59606d;
|
||
font-size: 13px;
|
||
line-height: 1.5;
|
||
}
|
||
|
||
.vf-secondary {
|
||
display: inline-flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
min-height: 52px;
|
||
padding: 0 18px;
|
||
border: none;
|
||
border-radius: 999px;
|
||
background: rgba(33, 48, 33, 0.07);
|
||
box-shadow: inset 0 0 0 1px rgba(17, 20, 24, 0.06);
|
||
color: var(--gw-green);
|
||
font-family: var(--font-head);
|
||
font-size: 14px;
|
||
font-weight: 700;
|
||
line-height: 1.2;
|
||
cursor: pointer;
|
||
}
|
||
|
||
.vf-submit {
|
||
display: inline-flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
min-height: 52px;
|
||
width: fit-content;
|
||
padding: 0 22px;
|
||
border: none;
|
||
border-radius: 999px;
|
||
background: linear-gradient(135deg, #ffd54a, var(--yellow-soft));
|
||
box-shadow:
|
||
inset 0 -2px 0 rgba(0, 0, 0, 0.08),
|
||
0 12px 24px rgba(17, 20, 24, 0.1);
|
||
color: #111;
|
||
font-family: var(--font-head);
|
||
font-size: 14px;
|
||
font-weight: 700;
|
||
line-height: 1.2;
|
||
cursor: pointer;
|
||
transition:
|
||
transform 0.18s cubic-bezier(0.22, 1, 0.36, 1),
|
||
box-shadow 0.18s ease,
|
||
filter 0.18s ease;
|
||
}
|
||
|
||
.vf-submit:focus-visible {
|
||
outline: 3px solid rgba(255, 209, 0, 0.28);
|
||
outline-offset: 3px;
|
||
}
|
||
|
||
.vf-success {
|
||
margin: 0;
|
||
padding: 14px 16px;
|
||
border-radius: 18px;
|
||
background: rgba(33, 48, 33, 0.07);
|
||
box-shadow: inset 0 0 0 1px rgba(33, 48, 33, 0.08);
|
||
color: var(--gw-green);
|
||
font-size: 14px;
|
||
line-height: 1.55;
|
||
}
|
||
|
||
.vf-form--conversational .vf-label,
|
||
.vf-form--conversational .vf-choice-group legend {
|
||
font-family: var(--font-head);
|
||
font-size: 16px;
|
||
letter-spacing: -0.02em;
|
||
}
|
||
|
||
.vf-form--conversational .vf-field input,
|
||
.vf-form--conversational .vf-field textarea {
|
||
border-radius: 22px;
|
||
padding: 17px 18px;
|
||
font-size: 16px;
|
||
}
|
||
|
||
.vf-form--minimal .vf-group-copy,
|
||
.vf-form--minimal .vf-helper,
|
||
.vf-form--minimal .vf-reassurance,
|
||
.vf-form--minimal .vf-subtitle {
|
||
color: #6b7077;
|
||
}
|
||
|
||
.vf-form--minimal .vf-field input,
|
||
.vf-form--minimal .vf-field textarea,
|
||
.vf-form--minimal .vf-choice span {
|
||
box-shadow: inset 0 0 0 1px rgba(17, 20, 24, 0.06);
|
||
}
|
||
|
||
@media (hover: hover) {
|
||
.vf-step:hover,
|
||
.vf-secondary:hover,
|
||
.vf-choice:hover span,
|
||
.vf-submit:hover {
|
||
transform: translateY(-1px);
|
||
}
|
||
|
||
.vf-submit:hover {
|
||
box-shadow:
|
||
inset 0 -2px 0 rgba(0, 0, 0, 0.08),
|
||
0 16px 28px rgba(17, 20, 24, 0.12);
|
||
filter: brightness(1.02);
|
||
}
|
||
}
|
||
|
||
@media (max-width: 768px) {
|
||
.vf-grid--two,
|
||
.vf-grid--three,
|
||
.vf-note-row {
|
||
grid-template-columns: 1fr;
|
||
}
|
||
|
||
.vf-stepper {
|
||
align-items: stretch;
|
||
gap: 8px;
|
||
}
|
||
|
||
.vf-step {
|
||
flex: 1 1 0;
|
||
min-width: 0;
|
||
}
|
||
|
||
.vf-step-divider {
|
||
display: none;
|
||
}
|
||
|
||
.vf-form {
|
||
gap: 20px;
|
||
}
|
||
|
||
.vf-form--carded .vf-group {
|
||
padding: 18px;
|
||
border-radius: 22px;
|
||
}
|
||
|
||
.vf-field input,
|
||
.vf-field textarea {
|
||
font-size: 16px;
|
||
}
|
||
|
||
.vf-actions {
|
||
flex-direction: column-reverse;
|
||
align-items: stretch;
|
||
}
|
||
|
||
.vf-secondary,
|
||
.vf-submit {
|
||
width: 100%;
|
||
}
|
||
}
|
||
</style>
|