diff --git a/.jules/palette.md b/.jules/palette.md
new file mode 100644
index 0000000..be28ce6
--- /dev/null
+++ b/.jules/palette.md
@@ -0,0 +1,3 @@
+## 2025-05-22 - AI Consultation UX & A11y
+**Learning:** In a luxury-themed, Spanish-first interface, inconsistent English text and missing visual feedback during long-running AI operations (1.5s+) break immersion and reduce trust. Also, interactive form elements like the staff password input were missing descriptive `aria-label`s.
+**Action:** Always ensure that loading states use the same primary language as the rest of the section and provide a clear visual indicator (like a spinner) even if the delay is simulated. Use `aria-busy="true"` on submitting buttons to notify screen reader users of the ongoing process. Always check for missing labels on hidden or secondary form inputs like password modals.
diff --git a/index.html b/index.html
index 1ec1ae4..f4d1719 100644
--- a/index.html
+++ b/index.html
@@ -78,7 +78,7 @@
P.A.U. Divineo AI
-
+
Análisis de P.A.U.:
@@ -123,7 +123,7 @@
Catálogo Shopify
PASE PRIVADO SOLICITADO
Contenido restringido para Curadores del Búnker. Por favor, introduce tu credencial de acceso.
-
+
diff --git a/js/main.js b/js/main.js
index 56a1cb6..b551bbc 100644
--- a/js/main.js
+++ b/js/main.js
@@ -116,15 +116,17 @@ class TryOnYouBunker {
const submitBtn = event.target.querySelector('button[type="submit"]');
try {
- submitBtn.innerHTML = ' EXECUTING DIVINEO TOTALITY...';
+ submitBtn.innerHTML = ' EJECUTANDO DIVINEO...';
submitBtn.disabled = true;
+ submitBtn.setAttribute('aria-busy', 'true');
// 1. Handshake de Seguridad (Simulado para el frontend)
const userId = "LAFAYETTE_LEAD_USER";
const ts = Math.floor(Date.now() / 1000);
const token = `${ts}.SIMULATED_SIG`; // En prod se generaría con HMAC
- // 2. Análisis Biométrico
+ // 2. Análisis Biométrico (Simulado con retraso para UX)
+ await new Promise(resolve => setTimeout(resolve, 1500));
const biometricData = await this.biometricAnalyzer.analyzePose(null);
const userWaist = biometricData.measurements.waist;
@@ -155,8 +157,9 @@ class TryOnYouBunker {
} catch (error) {
this.showNotification('Bunker Offline', 'error');
} finally {
- submitBtn.textContent = 'ASK PAU / DIVINEO';
+ submitBtn.textContent = 'PREGUNTAR A P.A.U.';
submitBtn.disabled = false;
+ submitBtn.removeAttribute('aria-busy');
}
}
diff --git a/styles/main.css b/styles/main.css
index 49070c2..5608bd4 100644
--- a/styles/main.css
+++ b/styles/main.css
@@ -376,6 +376,25 @@ body {
.notification-success { border-left: 5px solid #4CAF50; }
.notification-error { border-left: 5px solid #f44336; }
+/* Loading Spinner */
+.loader {
+ width: 16px;
+ height: 16px;
+ border: 2px solid var(--bg-dark);
+ border-bottom-color: transparent;
+ border-radius: 50%;
+ display: inline-block;
+ box-sizing: border-box;
+ animation: rotation 1s linear infinite;
+ margin-right: 10px;
+ vertical-align: middle;
+}
+
+@keyframes rotation {
+ 0% { transform: rotate(0deg); }
+ 100% { transform: rotate(360deg); }
+}
+
/* Accessibility: Focus States */
:focus-visible {
outline: 2px solid var(--accent-gold);
diff --git a/verification/collection.png b/verification/collection.png
deleted file mode 100644
index 8e62084..0000000
Binary files a/verification/collection.png and /dev/null differ
diff --git a/verification/consultation.png b/verification/consultation.png
deleted file mode 100644
index 024bf61..0000000
Binary files a/verification/consultation.png and /dev/null differ
diff --git a/verification/full_page.png b/verification/full_page.png
deleted file mode 100644
index 9e3e628..0000000
Binary files a/verification/full_page.png and /dev/null differ
diff --git a/verification/jules_form_verification.png b/verification/jules_form_verification.png
deleted file mode 100644
index 6d707db..0000000
Binary files a/verification/jules_form_verification.png and /dev/null differ
diff --git a/verification/verify_jules_form.py b/verification/verify_jules_form.py
deleted file mode 100644
index f1addfb..0000000
--- a/verification/verify_jules_form.py
+++ /dev/null
@@ -1,29 +0,0 @@
-from playwright.sync_api import Page, expect, sync_playwright
-
-def verify_jules_form(page: Page):
- # Navigate to the app
- page.goto("http://localhost:5173/")
-
- # Scroll to consultation section
- page.locator("#consultation").scroll_into_view_if_needed()
-
- # Check for the correct labels
- expect(page.get_by_label("Body Shape")).to_be_visible()
- expect(page.get_by_label("Fit Preference")).to_be_visible()
-
- # Ensure "Height (cm)" and "Weight (kg)" are NOT visible
- expect(page.get_by_text("Height (cm)")).not_to_be_visible()
- expect(page.get_by_text("Weight (kg)")).not_to_be_visible()
-
- # Take screenshot of the form
- page.screenshot(path="verification/jules_form_verification.png")
- print("Screenshot taken.")
-
-if __name__ == "__main__":
- with sync_playwright() as p:
- browser = p.chromium.launch(headless=True)
- page = browser.new_page()
- try:
- verify_jules_form(page)
- finally:
- browser.close()
diff --git a/verification/verify_tryonyou.py b/verification/verify_tryonyou.py
deleted file mode 100644
index 9678a4b..0000000
--- a/verification/verify_tryonyou.py
+++ /dev/null
@@ -1,42 +0,0 @@
-from playwright.sync_api import Page, expect, sync_playwright
-
-def verify_tryonyou(page: Page):
- # Go to localhost
- page.goto("http://localhost:8080")
-
- # Check for Jules Consultation Section
- expect(page.locator("#consultation")).to_be_visible()
- expect(page.get_by_role("heading", name="AI Stylist Consultation (Jules)")).to_be_visible()
-
- # Check for Form inputs
- expect(page.locator("#height")).to_be_visible()
- expect(page.locator("#weight")).to_be_visible()
- expect(page.locator("#event_type")).to_be_visible()
-
- # Check for Lafayette Collection
- expect(page.get_by_text("Lafayette x TryOnYou Exclusive")).to_be_visible()
-
- # Check for the specific new items
- expect(page.get_by_text("Cubist Art Jacket")).to_be_visible()
- expect(page.get_by_text("Peacock Couture Blazer")).to_be_visible()
-
- # Take screenshot of the consultation section
- page.locator("#consultation").screenshot(path="verification/consultation.png")
-
- # Take screenshot of the collection section
- page.locator(".exclusive-collection").screenshot(path="verification/collection.png")
-
- # Take full page screenshot
- page.screenshot(path="verification/full_page.png", full_page=True)
-
-if __name__ == "__main__":
- with sync_playwright() as p:
- browser = p.chromium.launch(headless=True)
- page = browser.new_page()
- try:
- verify_tryonyou(page)
- print("Verification successful!")
- except Exception as e:
- print(f"Verification failed: {e}")
- finally:
- browser.close()