diff --git a/src/pages/contact.astro b/src/pages/contact.astro
index 472229c..351e1c7 100644
--- a/src/pages/contact.astro
+++ b/src/pages/contact.astro
@@ -196,11 +196,16 @@ const trustStats = [
class="form-input w-full pl-10 pr-4 py-3 rounded-xl border border-secondary-200 dark:border-secondary-600 focus:border-primary focus:ring-2 focus:ring-primary/20 transition-all duration-200 text-secondary-900 dark:text-secondary-100 placeholder-secondary-400 dark:placeholder-secondary-500 text-sm bg-secondary-50 dark:bg-secondary-700 focus:bg-white dark:focus:bg-secondary-700"
placeholder="John Doe"
/>
-
@@ -231,11 +236,16 @@ const trustStats = [
class="form-input w-full pl-10 pr-4 py-3 rounded-xl border border-secondary-200 dark:border-secondary-600 focus:border-primary focus:ring-2 focus:ring-primary/20 transition-all duration-200 text-secondary-900 dark:text-secondary-100 placeholder-secondary-400 dark:placeholder-secondary-500 text-sm bg-secondary-50 dark:bg-secondary-700 focus:bg-white dark:focus:bg-secondary-700"
placeholder="john@example.com"
/>
-
@@ -267,6 +277,16 @@ const trustStats = [
class="form-input w-full pl-10 pr-4 py-3 rounded-xl border border-secondary-200 dark:border-secondary-600 focus:border-primary focus:ring-2 focus:ring-primary/20 transition-all duration-200 text-secondary-900 dark:text-secondary-100 placeholder-secondary-400 dark:placeholder-secondary-500 text-sm bg-secondary-50 dark:bg-secondary-700 focus:bg-white dark:focus:bg-secondary-700"
placeholder="+1 (555) 123-4567"
/>
+
+
@@ -303,6 +323,16 @@ const trustStats = [
+
+
-
+
Minimum 10 characters. Be as detailed as possible for a faster, more accurate response.
@@ -709,18 +751,34 @@ const trustStats = [
}
}
- /* Form input states */
+ /* Form input states — WCAG AA compliant (≥ 4.5:1 contrast) */
.form-input.is-valid {
- border-color: #10b981;
- background-color: #f0fdf4;
+ border-color: #155724;
+ background-color: #f0fff4;
+ color: #155724;
}
.form-input.is-invalid {
- border-color: #ef4444;
- background-color: #fef2f2;
+ border-color: #721c24;
+ background-color: #fff5f5;
+ color: #721c24;
+ }
+ /* Dark mode validation states */
+ :global(.dark) .form-input.is-valid {
+ border-color: #48bb78;
+ background-color: rgba(72, 187, 120, 0.1);
+ color: #c6f6d5;
+ }
+ :global(.dark) .form-input.is-invalid {
+ border-color: #fc8181;
+ background-color: rgba(252, 129, 129, 0.1);
+ color: #fed7d7;
}
.form-input.is-valid ~ .valid-check {
display: flex;
}
+ .form-input.is-invalid ~ .invalid-check {
+ display: flex;
+ }
/* Budget option - checked state via JS since has-[:checked] may not work in all contexts */
.budget-option.selected {
@@ -857,6 +915,7 @@ const trustStats = [
const errorEl = document.querySelector(`[data-error="${fieldName}"]`);
const inputEl = document.getElementById(fieldName) as HTMLElement | null;
const validCheck = inputEl?.parentElement?.querySelector('.valid-check') as HTMLElement | null;
+ const invalidCheck = inputEl?.parentElement?.querySelector('.invalid-check') as HTMLElement | null;
if (errorEl) errorEl.classList.toggle('hidden', isValid !== false);
@@ -867,6 +926,9 @@ const trustStats = [
if (validCheck) {
validCheck.classList.toggle('hidden', isValid !== true);
}
+ if (invalidCheck) {
+ invalidCheck.classList.toggle('hidden', isValid !== false);
+ }
}
function validateField(field: HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement): boolean {
@@ -1017,6 +1079,7 @@ const trustStats = [
(input as HTMLElement).classList.remove('is-valid', 'is-invalid');
});
form.querySelectorAll('.valid-check').forEach((el) => el.classList.add('hidden'));
+ form.querySelectorAll('.invalid-check').forEach((el) => el.classList.add('hidden'));
form.querySelectorAll('[data-error]').forEach((el) => el.classList.add('hidden'));
if (charCount) charCount.textContent = '0 / 5000';
budgetOptions.forEach((o) => o.classList.remove('selected'));