<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>TruSpeed Car Meet — Registration</title>
<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=Rajdhani:wght@500;700&family=Inter:wght@400;500&display=swap" rel="stylesheet">
<style>
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
body {
font-family: 'Inter', sans-serif;
background: #0a0a0a;
min-height: 100vh;
display: flex;
align-items: center;
justify-content: center;
padding: 40px 16px;
}
/* ── Wrapper ── */
.ts-wrap {
background: #0D0D0D;
border-radius: 16px;
overflow: hidden;
width: 100%;
max-width: 600px;
border: 1px solid #222;
}
/* ── Header ── */
.ts-header {
background: #111;
padding: 36px 40px 28px;
border-bottom: 1px solid #1e1e1e;
position: relative;
overflow: hidden;
}
.speedline {
position: absolute;
bottom: 0;
left: 0;
height: 3px;
background: #F5A623;
width: 0;
animation: sweep 0.7s cubic-bezier(0.4, 0, 0.2, 1) 0.3s forwards;
}
@keyframes sweep {
from { width: 0; }
to { width: 100%; }
}
.ts-eyebrow {
font-family: 'Rajdhani', sans-serif;
font-size: 11px;
font-weight: 700;
letter-spacing: 0.2em;
color: #F5A623;
text-transform: uppercase;
margin-bottom: 8px;
}
.ts-title {
font-family: 'Rajdhani', sans-serif;
font-size: 34px;
font-weight: 700;
color: #F0EDE8;
line-height: 1.1;
margin-bottom: 6px;
}
.ts-subtitle {
font-size: 13px;
color: #666;
line-height: 1.5;
}
/* ── Body ── */
.ts-body {
padding: 32px 40px 36px;
}
.ts-section-label {
font-family: 'Rajdhani', sans-serif;
font-size: 11px;
font-weight: 700;
letter-spacing: 0.18em;
text-transform: uppercase;
color: #555;
margin-bottom: 16px;
}
.ts-row {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 14px;
margin-bottom: 14px;
}
.ts-car-row {
display: grid;
grid-template-columns: 88px 1fr 1fr;
gap: 12px;
margin-bottom: 14px;
}
.ts-field {
display: flex;
flex-direction: column;
gap: 7px;
margin-bottom: 14px;
}
.ts-field.no-mb { margin-bottom: 0; }
label {
font-size: 11px;
font-weight: 500;
letter-spacing: 0.1em;
text-transform: uppercase;
color: #888;
}
.optional-tag {
font-size: 11px;
color: #555;
font-weight: 400;
text-transform: none;
letter-spacing: 0;
}
input[type="text"],
input[type="email"],
input[type="tel"],
textarea {
background: #171717;
border: 1px solid #2a2a2a;
border-radius: 8px;
padding: 11px 14px;
font-size: 14px;
color: #F0EDE8;
font-family: 'Inter', sans-serif;
outline: none;
transition: border-color 0.15s, box-shadow 0.15s;
width: 100%;
-webkit-appearance: none;
appearance: none;
}
input::placeholder,
textarea::placeholder { color: #3d3d3d; }
input:focus,
textarea:focus {
border-color: #F5A623;
box-shadow: 0 0 0 3px rgba(245, 166, 35, 0.12);
}
input.error,
textarea.error {
border-color: #c0392b;
box-shadow: 0 0 0 3px rgba(192, 57, 43, 0.1);
}
textarea {
resize: vertical;
min-height: 80px;
line-height: 1.55;
}
.field-error {
font-size: 11px;
color: #c0392b;
display: none;
margin-top: -4px;
}
.field-error.visible { display: block; }
.ts-divider {
height: 1px;
background: #1e1e1e;
margin: 22px 0;
}
/* ── Submit button ── */
.ts-cta {
width: 100%;
background: #F5A623;
color: #0D0D0D;
border: none;
border-radius: 8px;
padding: 15px;
font-family: 'Rajdhani', sans-serif;
font-size: 17px;
font-weight: 700;
letter-spacing: 0.08em;
text-transform: uppercase;
cursor: pointer;
margin-top: 8px;
transition: background 0.15s, transform 0.1s;
display: flex;
align-items: center;
justify-content: center;
gap: 9px;
}
.ts-cta:hover { background: #f0b940; }
.ts-cta:active { transform: scale(0.99); }
.ts-cta svg {
width: 18px;
height: 18px;
flex-shrink: 0;
}
.ts-fine {
font-size: 11px;
color: #555;
text-align: center;
margin-top: 16px;
line-height: 1.7;
}
.ts-fine a {
color: #F5A623;
text-decoration: none;
}
.ts-fine a:hover { text-decoration: underline; }
/* ── Confirmation screen ── */
.ts-confirm {
display: none;
text-align: center;
padding: 56px 40px;
}
.ts-confirm-icon {
color: #F5A623;
margin-bottom: 18px;
}
.ts-confirm-icon svg {
width: 48px;
height: 48px;
}
.ts-confirm-title {
font-family: 'Rajdhani', sans-serif;
font-size: 30px;
font-weight: 700;
color: #F0EDE8;
margin-bottom: 8px;
}
.ts-confirm-sub {
font-size: 14px;
color: #888;
margin-bottom: 28px;
line-height: 1.6;
}
.ts-redirect-bar {
background: #171717;
border: 1px solid #222;
border-radius: 8px;
padding: 14px 18px;
font-size: 13px;
color: #666;
margin-bottom: 22px;
text-align: left;
display: flex;
align-items: flex-start;
gap: 10px;
line-height: 1.5;
}
.ts-redirect-bar svg {
width: 16px;
height: 16px;
flex-shrink: 0;
margin-top: 1px;
color: #F5A623;
}
.ts-redirect-bar strong { color: #F5A623; font-weight: 500; }
.ts-checkout-btn {
display: inline-flex;
align-items: center;
gap: 9px;
background: #F5A623;
color: #0D0D0D;
border: none;
border-radius: 8px;
padding: 14px 32px;
font-family: 'Rajdhani', sans-serif;
font-size: 17px;
font-weight: 700;
letter-spacing: 0.08em;
text-transform: uppercase;
cursor: pointer;
transition: background 0.15s;
text-decoration: none;
}
.ts-checkout-btn:hover { background: #f0b940; }
.ts-checkout-btn svg {
width: 17px;
height: 17px;
}
/* ── Mobile ── */
@media (max-width: 520px) {
.ts-header,
.ts-body,
.ts-confirm { padding-left: 20px; padding-right: 20px; }
.ts-title { font-size: 28px; }
.ts-row { grid-template-columns: 1fr; }
.ts-car-row { grid-template-columns: 72px 1fr; }
.ts-car-row .ts-field:last-child {
grid-column: 1 / -1;
}
}
</style>
</head>
<body>
<div class="ts-wrap" role="main">
<!-- ── Header ── -->
<div class="ts-header">
<p class="ts-eyebrow">Salt Lake City · July 18, 2025</p>
<h1 class="ts-title">TruSpeed Car Meet</h1>
<p class="ts-subtitle">~70 cars · ~250 attendees · Register your spot below</p>
<div class="speedline" aria-hidden="true"></div>
</div>
<!-- ── Form ── -->
<div class="ts-body" id="formSection">
<p class="ts-section-label">Your info</p>
<div class="ts-row">
<div class="ts-field no-mb">
<label for="firstName">First name</label>
<input type="text" id="firstName" name="firstName" placeholder="Jordan" autocomplete="given-name">
<span class="field-error" id="err-firstName">First name is required.</span>
</div>
<div class="ts-field no-mb">
<label for="lastName">Last name</label>
<input type="text" id="lastName" name="lastName" placeholder="Reyes" autocomplete="family-name">
<span class="field-error" id="err-lastName">Last name is required.</span>
</div>
</div>
<div class="ts-field">
<label for="email">Email</label>
<input type="email" id="email" name="email" placeholder="you@email.com" autocomplete="email">
<span class="field-error" id="err-email">A valid email address is required.</span>
</div>
<div class="ts-field">
<label for="phone">Phone</label>
<input type="tel" id="phone" name="phone" placeholder="(801) 555-0123" autocomplete="tel">
</div>
<div class="ts-divider"></div>
<p class="ts-section-label">Your car</p>
<div class="ts-car-row">
<div class="ts-field no-mb">
<label for="year">Year</label>
<input type="text" id="year" name="year" placeholder="2023" maxlength="4" inputmode="numeric">
</div>
<div class="ts-field no-mb">
<label for="make">Make</label>
<input type="text" id="make" name="make" placeholder="Porsche">
</div>
<div class="ts-field no-mb">
<label for="model">Model</label>
<input type="text" id="model" name="model" placeholder="Taycan Turbo">
</div>
</div>
<div class="ts-field">
<label for="notes">
Build notes
<span class="optional-tag">(optional)</span>
</label>
<textarea id="notes" name="notes" placeholder="Mods, awards, fun facts about your build..."></textarea>
</div>
<button class="ts-cta" id="submitBtn" onclick="handleSubmit()">
<!-- Flag icon -->
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M5 5a5 5 0 0 1 7 0 5 5 0 0 0 7 0v13a5 5 0 0 1-7 0 5 5 0 0 0-7 0V5z"/><line x1="5" y1="21" x2="5" y2="19"/></svg>
Register & Proceed to Checkout
</button>
<p class="ts-fine">
By registering you agree to the event terms.<br>
Questions? <a href="mailto:info@truspeedperformance.com">info@truspeedperformance.com</a>
</p>
</div>
<!-- ── Confirmation screen ── -->
<div class="ts-confirm" id="confirmSection" aria-live="polite">
<div class="ts-confirm-icon" aria-hidden="true">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><path d="m9 12 2 2 4-4"/></svg>
</div>
<h2 class="ts-confirm-title">You're registered!</h2>
<p class="ts-confirm-sub" id="confirmDetails"></p>
<div class="ts-redirect-bar">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="9" cy="21" r="1"/><circle cx="20" cy="21" r="1"/><path d="M1 1h4l2.68 13.39a2 2 0 0 0 2 1.61h9.72a2 2 0 0 0 2-1.61L23 6H6"/></svg>
<span>Complete your registration by checking out below. Your <strong>Event Entry — TruSpeed Car Meet</strong> is waiting in your cart.</span>
</div>
<button class="ts-checkout-btn" id="checkoutBtn" onclick="goToCheckout()">
<!-- Lock icon -->
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="3" y="11" width="18" height="11" rx="2" ry="2"/><path d="M7 11V7a5 5 0 0 1 10 0v4"/></svg>
Complete Checkout
</button>
<p class="ts-fine" style="margin-top: 18px;">Secure checkout via Shopify</p>
</div>
</div>
<script>
// ─────────────────────────────────────────────────────────────
// CONFIGURATION — swap these two values before going live
// ─────────────────────────────────────────────────────────────
// 1. Your Shopify cart URL for the event entry product.
// Format: https://your-store.myshopify.com/cart/VARIANT_ID:1
// Get the variant ID from Shopify Admin › Products › [product] › copy variant ID from URL.
const SHOPIFY_CHECKOUT_URL = 'https://YOUR-STORE.myshopify.com/cart/YOUR-VARIANT-ID:1';
// 2. (Optional) Webhook URL to receive form submissions.
// Paste a Zapier Catch Hook URL, Make webhook, or your own endpoint here.
// Leave as empty string '' to skip (submissions will only log to console).
const WEBHOOK_URL = '';
// ─────────────────────────────────────────────────────────────
function validate() {
let valid = true;
const fields = [
{ id: 'firstName', errId: 'err-firstName', check: v => v.length > 0 },
{ id: 'lastName', errId: 'err-lastName', check: v => v.length > 0 },
{ id: 'email', errId: 'err-email', check: v => /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(v) },
];
fields.forEach(({ id, errId, check }) => {
const el = document.getElementById(id);
const err = document.getElementById(errId);
const ok = check(el.value.trim());
el.classList.toggle('error', !ok);
err.classList.toggle('visible', !ok);
if (!ok) valid = false;
});
return valid;
}
// Clear error state on input
['firstName', 'lastName', 'email'].forEach(id => {
document.getElementById(id).addEventListener('input', function () {
this.classList.remove('error');
document.getElementById('err-' + id).classList.remove('visible');
});
});
async function handleSubmit() {
if (!validate()) return;
const submission = {
firstName : document.getElementById('firstName').value.trim(),
lastName : document.getElementById('lastName').value.trim(),
email : document.getElementById('email').value.trim(),
phone : document.getElementById('phone').value.trim(),
year : document.getElementById('year').value.trim(),
make : document.getElementById('make').value.trim(),
model : document.getElementById('model').value.trim(),
notes : document.getElementById('notes').value.trim(),
timestamp : new Date().toISOString(),
event : 'TruSpeed Car Meet — July 18, 2025',
};
// Log to console (always)
console.log('TruSpeed registration:', JSON.stringify(submission, null, 2));
// Send to webhook if configured
if (WEBHOOK_URL) {
try {
await fetch(WEBHOOK_URL, {
method : 'POST',
headers : { 'Content-Type': 'application/json' },
body : JSON.stringify(submission),
});
} catch (err) {
console.error('Webhook error:', err);
// Still proceed — don't block the user on a network hiccup
}
}
// Flip to confirmation screen
document.getElementById('formSection').style.display = 'none';
const confirm = document.getElementById('confirmSection');
confirm.style.display = 'block';
const carLine = [submission.year, submission.make, submission.model].filter(Boolean).join(' ');
document.getElementById('confirmDetails').textContent =
submission.firstName + ' ' + submission.lastName +
(carLine ? ' · ' + carLine : '') +
' — see you July 18.';
}
function goToCheckout() {
const btn = document.getElementById('checkoutBtn');
btn.textContent = 'Opening checkout…';
btn.style.opacity = '0.7';
btn.style.cursor = 'default';
window.open(SHOPIFY_CHECKOUT_URL, '_blank');
setTimeout(() => {
btn.innerHTML = `
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" style="width:17px;height:17px"><rect x="3" y="11" width="18" height="11" rx="2" ry="2"/><path d="M7 11V7a5 5 0 0 1 10 0v4"/></svg>
Complete Checkout`;
btn.style.opacity = '1';
btn.style.cursor = 'pointer';
}, 2500);
}
</script>
</body>
</html>


