]*role\s*=\s*[\"']button[\"'][^>]*>", content, re.DOTALL):
+ lowered_tag = div_tag.lower()
+ if "tabindex=" not in lowered_tag or ("onkeydown=" not in lowered_tag and "onkeyup=" not in lowered_tag):
+ issues.append("role='button' requires tabIndex and a keyboard handler")
+ break
+
+ return issues
+
+
+def main() -> int:
+ project_path = Path(sys.argv[1] if len(sys.argv) > 1 else ".").resolve()
+ if not project_path.is_dir():
+ print(json.dumps({"error": f"Directory not found: {project_path}"}))
+ return 2
+
+ print(f"\n{'=' * 60}\n[ACCESSIBILITY CHECKER] WCAG Static Audit\n{'=' * 60}")
+ print(f"Project: {project_path}")
+ print(f"Time: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}\n" + "-" * 60)
+
+ files = find_html_files(project_path)
+ print(f"Found {len(files)} HTML/JSX/TSX files")
+ all_issues = []
+ for file_path in files:
+ issues = check_accessibility(file_path)
+ if issues:
+ all_issues.append({"file": str(file_path.relative_to(project_path)), "issues": issues})
+
+ print("\n" + "=" * 60 + "\nACCESSIBILITY ISSUES\n" + "=" * 60)
+ if all_issues:
+ for item in all_issues[:20]:
+ print(f"\n{item['file']}:")
+ for issue in item["issues"]:
+ print(f" - {issue}")
+ else:
+ print("No statically detectable accessibility issues found.")
+
+ total_issues = sum(len(item["issues"]) for item in all_issues)
+ output = {
+ "script": "accessibility_checker",
+ "project": str(project_path),
+ "files_checked": len(files),
+ "files_with_issues": len(all_issues),
+ "issues_found": total_issues,
+ "passed": total_issues == 0,
+ }
+ print("\n" + json.dumps(output, indent=2))
+ return 0 if output["passed"] else 1
+
+
+if __name__ == "__main__":
+ raise SystemExit(main())
diff --git a/.agents/skills/frontend-design/scripts/ux_audit.py b/.agents/skills/frontend-design/scripts/ux_audit.py
new file mode 100644
index 000000000..05c8a1ee8
--- /dev/null
+++ b/.agents/skills/frontend-design/scripts/ux_audit.py
@@ -0,0 +1,722 @@
+#!/usr/bin/env python3
+"""
+UX Audit Script - Full Frontend Design Coverage
+
+Analyzes code for compliance with:
+
+1. CORE PSYCHOLOGY LAWS:
+ - Hick's Law (nav items, form complexity)
+ - Fitts' Law (target sizes, touch targets)
+ - Miller's Law (chunking, memory limits)
+ - Von Restorff Effect (primary CTA visibility)
+ - Serial Position Effect (important items at start/end)
+
+2. EMOTIONAL DESIGN (Don Norman):
+ - Visceral (first impressions, gradients, animations)
+ - Behavioral (feedback, usability, performance)
+ - Reflective (brand story, values, identity)
+
+3. TRUST BUILDING:
+ - Security signals (SSL, encryption on forms)
+ - Social proof (testimonials, reviews, logos)
+ - Authority indicators (certifications, awards, media)
+
+4. COGNITIVE LOAD MANAGEMENT:
+ - Progressive disclosure (accordion, tabs, "Advanced")
+ - Visual noise (too many colors/borders)
+ - Familiar patterns (labels, standard conventions)
+
+5. PERSUASIVE DESIGN (Ethical):
+ - Smart defaults (pre-selected options)
+ - Anchoring (original vs discount price)
+ - Social proof (live indicators, numbers)
+ - Progress indicators (progress bars, steps)
+
+6. TYPOGRAPHY SYSTEM (9 sections):
+ - Font Pairing (max 3 families)
+ - Line Length (45-75ch)
+ - Line Height (proper ratios)
+ - Letter Spacing (uppercase, display text)
+ - Weight and Emphasis (contrast levels)
+ - Responsive Typography (clamp())
+ - Hierarchy (sequential headings)
+ - Modular Scale (consistent ratios)
+ - Readability (chunking, subheadings)
+
+7. VISUAL EFFECTS (10 sections):
+ - Glassmorphism (blur + transparency)
+ - Neomorphism (dual shadows, inset)
+ - Shadow Hierarchy (elevation levels)
+ - Gradients (usage, overuse)
+ - Border Effects (complexity check)
+ - Glow Effects (text-shadow, box-shadow)
+ - Overlay Techniques (image text readability)
+ - GPU Acceleration (transform/opacity vs layout)
+ - Performance (will-change usage)
+ - Effect Selection (purpose over decoration)
+
+8. COLOR SYSTEM (7 sections):
+ - PURPLE BAN (Critical Maestro rule - #8B5CF6, #A855F7, etc.)
+ - 60-30-10 Rule (dominant, secondary, accent)
+ - Color Scheme Patterns (monochromatic, analogous)
+ - Dark Mode Compliance (no pure black/white)
+ - WCAG Contrast (low-contrast detection)
+ - Color Psychology Context (food + blue = bad)
+ - HSL-Based Palettes (recommended approach)
+
+9. ANIMATION GUIDE (6 sections):
+ - Duration Appropriateness (50ms minimum, 1s max transitions)
+ - Easing Functions (ease-out for entry, ease-in for exit)
+ - Micro-interactions (hover/focus feedback)
+ - Loading States (skeleton, spinner, progress)
+ - Page Transitions (fade/slide for routing)
+ - Scroll Animation Performance (no layout properties)
+
+10. MOTION GRAPHICS (7 sections):
+ - Lottie Animations (reduced motion fallbacks)
+ - GSAP Memory Leaks (kill/revert on unmount)
+ - SVG Animation Performance (stroke-dashoffset sparingly)
+ - 3D Transforms (perspective parent, mobile warning)
+ - Particle Effects (mobile fallback)
+ - Scroll-Driven Animations (throttle with rAF)
+ - Motion Decision Tree (functional vs decorative)
+
+11. ACCESSIBILITY:
+ - Alt text for images
+ - Reduced motion checks
+ - Form labels
+
+Total: 80+ checks across all design principles
+"""
+
+import sys
+import os
+import re
+import json
+from pathlib import Path
+
+class UXAuditor:
+ def __init__(self):
+ self.issues = []
+ self.warnings = []
+ self.passed_count = 0
+ self.files_checked = 0
+
+ def audit_file(self, filepath: str) -> None:
+ try:
+ with open(filepath, 'r', encoding='utf-8', errors='replace') as f:
+ content = f.read()
+ except: return
+
+ self.files_checked += 1
+ filename = os.path.basename(filepath)
+
+ # Pre-calculate common flags
+ has_long_text = bool(re.search(r'
7:
+ self.warnings.append(f"[Hick's Law] {filename}: {nav_items} nav items (Max 7). Consider grouping into categorized submenus.")
+
+ # Fitts' Law
+ if re.search(r'height:\s*([0-3]\d)px', content) or re.search(r'h-[1-9]\b|h-10\b', content):
+ self.warnings.append(f"[Fitts' Law] {filename}: Small targets (< 44px)")
+
+ # Miller's Law
+ form_fields = len(re.findall(r' 7 and not re.search(r'step|wizard|stage', content, re.IGNORECASE):
+ self.warnings.append(f"[Miller's Law] {filename}: Complex form ({form_fields} fields)")
+
+ # Von Restorff
+ if 'button' in content.lower() and not re.search(r'primary|bg-primary|Button.*primary|variant=["\']primary', content, re.IGNORECASE):
+ self.warnings.append(f"[Von Restorff] {filename}: No primary CTA")
+
+ # Serial Position Effect - Important items at beginning/end
+ if nav_items > 3:
+ # Check if last nav item is important (contact, login, etc.)
+ nav_content = re.findall(r']*>([^<]+)', content, re.IGNORECASE)
+ if nav_content and len(nav_content) > 2:
+ last_item = nav_content[-1].lower() if nav_content else ''
+ if not any(x in last_item for x in ['contact', 'login', 'sign', 'get started', 'cta', 'button']):
+ self.warnings.append(f"[Serial Position] {filename}: Last nav item may not be important. Place key actions at start/end.")
+
+ # --- 1.5 EMOTIONAL DESIGN (Don Norman) ---
+
+ # Visceral: First impressions (aesthetics, gradients, animations)
+ has_hero = bool(re.search(r'hero| 0:
+ self.passed_count += 1
+ else:
+ if has_long_text:
+ self.warnings.append(f"[Trust] {filename}: No social proof detected. Consider adding testimonials, ratings, or 'Trusted by' logos.")
+
+ # Authority indicators
+ has_footer = bool(re.search(r'footer|