Components
Closer Form
The quote-request form used at the bottom of most pages and again on the Contact page — text fields, a radio-pill fieldset, and a success-state swap.
Markup
<section class="closer on-dark" id="contact">
<div class="grid">
<div>
<h2 class="d sec-head mb-0">Tell us<br><em>what broke.</em></h2>
<p class="lede">Two minutes, no account, no spam.</p>
</div>
<div class="formwrap rv">
<form class="quoteform" novalidate>
<div class="two">
<div class="field">
<label for="f-name">Your name</label>
<input type="text" id="f-name" name="name" autocomplete="name">
</div>
<div class="field">
<label for="f-street">Street or neighborhood</label>
<input type="text" id="f-street" name="street">
</div>
</div>
<div class="field">
<label for="f-phone">Phone</label>
<input type="tel" id="f-phone" name="phone" required aria-describedby="f-phone-err" aria-invalid="false">
<span class="help">WE CALL. WE DON’T SPAM.</span>
<span class="err" id="f-phone-err">We need a number to call you back.</span>
</div>
<fieldset class="field">
<legend>How soon?</legend>
<div class="pills">
<input type="radio" name="soon" id="s1" value="today"><label for="s1">Today</label>
<input type="radio" name="soon" id="s2" value="week" checked><label for="s2">This week</label>
</div>
</fieldset>
<button class="btn" type="submit">Get my quote</button>
</form>
<div class="success" role="status" aria-live="polite">
<span class="no">Nº 31,407</span>
<p>Got it — you’re work order Nº 31,407 in the book.</p>
</div>
</div>
</div>
</section>Text fields
.field wraps a label plus its input/textarea, with an optional .help hint
line and an .err validation message (hidden by default, shown by JavaScript via the
.err-visible class — see Javascript below). .two lays two fields side by
side.
Radio pills
.pills renders a <fieldset> of radio inputs as rounded pill toggles
— each <input> is visually hidden and its paired <label>
carries the pill styling, switching to a solid amber fill when its input is :checked. The
same pill markup pattern (checked/pressed pill styling) is reused, driven differently, by
Filter Rail.
Success state
.success is hidden by default; when its parent .formwrap (or
.form-done on the parent, for the footer newsletter form) gets the .form-done
class, the form itself hides and the success block appears in its place, announced to assistive tech via
role="status"/aria-live="polite".
Javascript
main.js intercepts the quote form's submit, validates that the phone field isn't empty
(setting aria-invalid and toggling the .err-visible class atomically together,
rather than relying on the browser's native :user-invalid pseudo-class, which can flip on
independently of and before the matching message text is set), and on a valid submit adds
.form-done to the closest .formwrap to reveal the success state. The same
submit-intercept-then-swap pattern, without the phone validation, handles the footer's newsletter form
(see Footer). Since this is a static template with no server-side endpoint,
wiring the <form>'s action to a real form-handling service is a required
step before launch — see FAQ.