From 9af1854a7e35785a8e86426c4fb1edd465f164a3 Mon Sep 17 00:00:00 2001
From: Elizabeth Hunt <me@liz.coffee>
Date: Thu, 1 Jan 2026 18:32:49 -0800
Subject: Massive refactor courtesy of 5 dollars of AI tokens

---
 src/routes/contact/+page.svelte | 325 ++++++++++++++++++++++++++++++++++++++++
 1 file changed, 325 insertions(+)
 create mode 100644 src/routes/contact/+page.svelte

(limited to 'src/routes/contact/+page.svelte')

diff --git a/src/routes/contact/+page.svelte b/src/routes/contact/+page.svelte
new file mode 100644
index 0000000..c66d9df
--- /dev/null
+++ b/src/routes/contact/+page.svelte
@@ -0,0 +1,325 @@
+<script>
+	import { browser } from '$app/environment';
+	import HCaptcha from 'svelte-hcaptcha';
+
+	const mapsUrl = 'https://maps.app.goo.gl/s1AFqfKvUKgXDCrq5';
+
+	let submission = {
+		name: '',
+		email: '',
+		message: '',
+		phone: '',
+		captchaToken: ''
+	};
+
+	let captcha;
+	let noticeType = 'info';
+	let noticeMessage = '';
+
+	function setNotice(type, message) {
+		noticeType = type;
+		noticeMessage = message;
+	}
+
+	function handleSubmit(e) {
+		e.preventDefault();
+
+		if (!browser) return;
+		if (!submission.captchaToken) {
+			setNotice('error', 'Please complete the captcha first.');
+			return;
+		}
+
+		setNotice('info', 'Sending...');
+		fetch('/contact/submit', {
+			method: 'POST',
+			body: JSON.stringify(submission)
+		})
+			.then((x) => x.json())
+			.then((x) => {
+				if (x.success) {
+					setNotice('success', 'Success! Reloading...');
+					setTimeout(() => window.location.reload(), 1000);
+				} else {
+					setNotice('error', x.error ?? 'Something went wrong. Please try again.');
+				}
+			})
+			.catch((err) => {
+				console.log(err);
+				setNotice('error', 'Network error. Please try again.');
+			});
+	}
+
+	function onCaptchaError() {
+		setNotice('error', 'Failed to verify captcha, try again.');
+		captcha?.reset();
+		submission.captchaToken = '';
+	}
+
+	function onCaptchaSuccess({ detail: { token } }) {
+		submission.captchaToken = token;
+	}
+</script>
+
+<div class="contact">
+	<header class="contact__header">
+		<h1>Contact</h1>
+	</header>
+
+	{#if noticeMessage}
+		<div
+			class={'notice notice--' + noticeType}
+			role={noticeType === 'error' ? 'alert' : 'status'}
+			aria-live={noticeType === 'error' ? 'assertive' : 'polite'}
+		>
+			{noticeMessage}
+		</div>
+	{/if}
+
+	<div class="contact__grid">
+		<div class="contact__sidebar">
+			<section class="card" aria-label="Contact details">
+				<h2>Details</h2>
+
+				<div class="contact__methods">
+					<a class="contact__method" href={mapsUrl} target="_blank" rel="noopener noreferrer">
+						<span class="contact__icon" aria-hidden="true"><i class="bi bi-pin-map"></i></span>
+						<span class="contact__methodBody">
+							<span class="contact__methodTitle">Office</span>
+							<span class="contact__methodText">
+								534 Trejo Street, Suite 200F<br />Rexburg, ID 83440
+							</span>
+						</span>
+					</a>
+
+					<a class="contact__method" href="tel:12084994517">
+						<span class="contact__icon" aria-hidden="true"><i class="bi bi-telephone"></i></span>
+						<span class="contact__methodBody">
+							<span class="contact__methodTitle">Phone</span>
+							<span class="contact__methodText">(208) 499 - 4517</span>
+						</span>
+					</a>
+
+					<a class="contact__method" href="mailto:contact@mistymountainstherapy.com">
+						<span class="contact__icon" aria-hidden="true"><i class="bi bi-envelope"></i></span>
+						<span class="contact__methodBody">
+							<span class="contact__methodTitle">Email</span>
+							<span class="contact__methodText">contact@mistymountainstherapy.com</span>
+						</span>
+					</a>
+				</div>
+			</section>
+
+			<section class="card card--warn" aria-label="Crisis resources">
+				<h2>In a crisis?</h2>
+				<p style="margin: 0">
+					We do not have a crisis line. If you or someone you know is in danger please call 911, visit your
+					nearest emergency room, call the National Suicide Prevention Lifeline at
+					<a href="tel:18002738255">(800)273-TALK</a> (8255), or text HELLO to 741-741.
+				</p>
+			</section>
+		</div>
+
+		<section class="card" aria-label="Send a message">
+			<h2>Send a message</h2>
+			<form class="contact__form" on:submit|preventDefault={handleSubmit}>
+				<div class="contact__fields">
+					<label class="field">
+						<span class="field__label">Email *</span>
+						<input
+							type="email"
+							class="form-control"
+							bind:value={submission.email}
+							placeholder="johnnyappleseed@example.com"
+							required
+						/>
+					</label>
+
+					<label class="field">
+						<span class="field__label">Name *</span>
+						<input
+							type="text"
+							class="form-control"
+							bind:value={submission.name}
+							placeholder="Johnny Appleseed"
+							required
+						/>
+					</label>
+
+					<label class="field">
+						<span class="field__label">Phone</span>
+						<input
+							type="text"
+							class="form-control"
+							bind:value={submission.phone}
+							placeholder="(208) 123-4567"
+						/>
+					</label>
+
+					<label class="field">
+						<span class="field__label">Message *</span>
+						<textarea
+							class="form-control"
+							bind:value={submission.message}
+							rows="6"
+							placeholder="Hello! I would like to schedule a free 15-minute consultation..."
+							required
+						></textarea>
+					</label>
+				</div>
+
+				<div class="contact__captcha">
+					<HCaptcha
+						sitekey={import.meta.env.VITE_HCAPTCHA_KEY}
+						bind:this={captcha}
+						on:success={onCaptchaSuccess}
+						on:error={onCaptchaError}
+					/>
+				</div>
+
+				<div class="contact__actions">
+					<button type="submit" class="button button--primary" disabled={!submission.captchaToken}>
+						Submit
+					</button>
+					<p class="text-muted" style="margin: 0">
+						Please watch spam for replies.
+					</p>
+				</div>
+			</form>
+		</section>
+	</div>
+</div>
+
+<style>
+	.contact {
+		display: grid;
+		gap: var(--space-5);
+	}
+
+	.contact__header {
+		display: grid;
+		gap: var(--space-2);
+	}
+
+	.contact__lede {
+		margin: 0;
+		color: var(--color-muted);
+	}
+
+	.contact__grid {
+		display: grid;
+		grid-template-columns: 1fr;
+		gap: var(--space-5);
+		align-items: start;
+	}
+
+	@media (min-width: 900px) {
+		.contact__grid {
+			grid-template-columns: 1fr minmax(0, 320px);
+		}
+
+		.contact__sidebar {
+			order: 2;
+		}
+	}
+
+	.contact__sidebar {
+		display: grid;
+		gap: var(--space-5);
+		min-width: 0;
+	}
+
+	.contact__methods {
+		display: grid;
+		grid-template-columns: 1fr;
+		gap: var(--space-3);
+	}
+
+	.contact__method {
+		display: grid;
+		grid-template-columns: 2.25rem 1fr;
+		gap: var(--space-3);
+		align-items: start;
+		padding: var(--space-3);
+		border-radius: var(--radius-sm);
+		border: 1px solid var(--color-border);
+		text-decoration: none;
+		background: rgba(255, 255, 255, 0.55);
+	}
+
+	.contact__method:hover {
+		border-color: var(--color-accent);
+	}
+
+	.contact__icon {
+		display: inline-flex;
+		align-items: center;
+		justify-content: center;
+		width: 2.25rem;
+		height: 2.25rem;
+		border-radius: 999px;
+		background: color-mix(in srgb, var(--color-accent) 10%, transparent);
+		color: var(--color-accent-strong);
+	}
+
+	.contact__icon i {
+		font-size: 1.1rem;
+	}
+
+	.contact__methodBody {
+		display: grid;
+		gap: 0.15rem;
+	}
+
+	.contact__methodTitle {
+		font-weight: 700;
+	}
+
+	.contact__methodText {
+		color: var(--color-muted);
+		line-height: 1.35;
+		word-break: break-word;
+	}
+
+	.contact__form {
+		display: grid;
+		gap: var(--space-4);
+	}
+
+	.contact__fields {
+		display: grid;
+		grid-template-columns: 1fr;
+		gap: var(--space-3);
+	}
+
+	@media (min-width: 700px) {
+		.contact__fields {
+			grid-template-columns: 1fr;
+		}
+
+		.field--full {
+			grid-column: 1 / -1;
+		}
+	}
+
+	.field {
+		display: grid;
+		gap: var(--space-2);
+	}
+
+	.field__label {
+		font-weight: 650;
+	}
+
+	.contact__captcha {
+		display: grid;
+		justify-content: start;
+	}
+
+	.contact__actions {
+		display: flex;
+		flex-wrap: wrap;
+		gap: var(--space-3);
+		align-items: center;
+	}
+</style>
-- 
cgit v1.2.3-70-g09d2

