Files
vibe-brutalism/vibe-brutalism.js
2025-11-05 08:36:56 -05:00

926 lines
28 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* VIBE BRUTALISM - JavaScript Component Library
* Interactive functionality for neo-brutalist components
* Version: 2.0.0
* WCAG 2.1 AA & Section 508 Compliant
*/
(function() {
'use strict';
// ============================================
// ACCESSIBILITY UTILITIES
// ============================================
const a11y = {
// Create ARIA live region for announcements
createLiveRegion() {
if (!document.getElementById('vb-live-region')) {
const liveRegion = document.createElement('div');
liveRegion.id = 'vb-live-region';
liveRegion.className = 'vb-sr-only';
liveRegion.setAttribute('aria-live', 'polite');
liveRegion.setAttribute('aria-atomic', 'true');
document.body.appendChild(liveRegion);
}
return document.getElementById('vb-live-region');
},
// Announce message to screen readers
announce(message, priority = 'polite') {
const liveRegion = this.createLiveRegion();
liveRegion.setAttribute('aria-live', priority);
liveRegion.textContent = message;
// Clear after announcement
setTimeout(() => {
liveRegion.textContent = '';
}, 1000);
},
// Trap focus within element
trapFocus(element) {
const focusableElements = element.querySelectorAll(
'a[href], button:not([disabled]), textarea:not([disabled]), input:not([disabled]), select:not([disabled]), [tabindex]:not([tabindex="-1"])'
);
if (focusableElements.length === 0) return null;
const firstFocusable = focusableElements[0];
const lastFocusable = focusableElements[focusableElements.length - 1];
const handler = (e) => {
if (e.key === 'Tab') {
if (e.shiftKey && document.activeElement === firstFocusable) {
e.preventDefault();
lastFocusable.focus();
} else if (!e.shiftKey && document.activeElement === lastFocusable) {
e.preventDefault();
firstFocusable.focus();
}
}
};
element.addEventListener('keydown', handler);
firstFocusable.focus();
// Return cleanup function
return () => element.removeEventListener('keydown', handler);
}
};
// ============================================
// MODAL FUNCTIONALITY (WCAG 2.1 AA)
// ============================================
class VBModal {
constructor(element) {
this.modal = element;
this.closeButtons = this.modal.querySelectorAll('.vb-modal-close, [data-vb-modal-close]');
this.previousActiveElement = null;
this.focusTrapCleanup = null;
this.escHandler = this.handleEscape.bind(this);
this.clickHandler = this.handleBackdropClick.bind(this);
this.init();
}
init() {
// Set ARIA attributes
this.modal.setAttribute('role', 'dialog');
this.modal.setAttribute('aria-modal', 'true');
if (!this.modal.getAttribute('aria-labelledby')) {
const title = this.modal.querySelector('.vb-modal-title');
if (title && !title.id) {
title.id = `modal-title-${Math.random().toString(36).substr(2, 9)}`;
}
if (title) {
this.modal.setAttribute('aria-labelledby', title.id);
}
}
// Close button events
this.closeButtons.forEach(btn => {
btn.setAttribute('aria-label', 'Close dialog');
btn.addEventListener('click', () => this.close());
});
// Close on outside click
this.modal.addEventListener('click', this.clickHandler);
}
handleBackdropClick(e) {
if (e.target === this.modal) {
this.close();
}
}
handleEscape(e) {
if (e.key === 'Escape' && this.modal.classList.contains('active')) {
this.close();
}
}
open() {
this.previousActiveElement = document.activeElement;
this.modal.classList.add('active');
document.body.style.overflow = 'hidden';
// Trap focus and store cleanup function
this.focusTrapCleanup = a11y.trapFocus(this.modal);
// Add ESC key handler
document.addEventListener('keydown', this.escHandler);
a11y.announce('Dialog opened');
}
close() {
this.modal.classList.remove('active');
document.body.style.overflow = '';
// Cleanup focus trap
if (this.focusTrapCleanup) {
this.focusTrapCleanup();
this.focusTrapCleanup = null;
}
// Remove ESC key handler
document.removeEventListener('keydown', this.escHandler);
// Return focus
if (this.previousActiveElement) {
this.previousActiveElement.focus();
}
a11y.announce('Dialog closed');
}
}
// Initialize all modals
const modals = {};
document.querySelectorAll('.vb-modal').forEach(modal => {
const id = modal.id;
if (id) {
modals[id] = new VBModal(modal);
}
});
// Modal trigger buttons
document.querySelectorAll('[data-vb-modal-target]').forEach(btn => {
btn.addEventListener('click', () => {
const targetId = btn.dataset.vbModalTarget;
if (modals[targetId]) {
modals[targetId].open();
}
});
});
// ============================================
// HAMBURGER MENU FUNCTIONALITY (WCAG 2.1 AA)
// ============================================
class VBHamburgerMenu {
constructor(navbar) {
this.navbar = navbar;
this.toggle = navbar.querySelector('.vb-navbar-toggle');
this.menu = navbar.querySelector('.vb-navbar-menu');
this.escHandler = this.handleEscape.bind(this);
if (this.toggle && this.menu) {
this.init();
}
}
init() {
// Set ARIA attributes
this.toggle.setAttribute('aria-label', 'Toggle navigation menu');
this.toggle.setAttribute('aria-expanded', 'false');
this.toggle.setAttribute('aria-controls', this.menu.id || 'navbar-menu');
if (!this.menu.id) {
this.menu.id = 'navbar-menu';
}
// Toggle on click
this.toggle.addEventListener('click', () => {
this.toggleMenu();
});
// Close on ESC - using bound handler for proper cleanup
document.addEventListener('keydown', this.escHandler);
}
handleEscape(e) {
if (e.key === 'Escape' && this.menu.classList.contains('active')) {
this.closeMenu();
this.toggle.focus();
}
}
toggleMenu() {
const isOpen = this.menu.classList.toggle('active');
this.toggle.classList.toggle('active');
this.toggle.setAttribute('aria-expanded', isOpen);
a11y.announce(isOpen ? 'Menu opened' : 'Menu closed');
}
closeMenu() {
this.menu.classList.remove('active');
this.toggle.classList.remove('active');
this.toggle.setAttribute('aria-expanded', 'false');
}
}
// Initialize hamburger menus
document.querySelectorAll('.vb-navbar').forEach(navbar => {
new VBHamburgerMenu(navbar);
});
// ============================================
// DROPDOWN FUNCTIONALITY (WCAG 2.1 AA)
// ============================================
class VBDropdown {
constructor(element) {
this.dropdown = element;
this.toggle = this.dropdown.querySelector('.vb-dropdown-toggle');
this.menu = this.dropdown.querySelector('.vb-dropdown-menu');
if (!this.toggle || !this.menu) {
console.warn('Vibe Brutalism: Dropdown requires .vb-dropdown-toggle and .vb-dropdown-menu');
return;
}
this.items = this.menu.querySelectorAll('.vb-dropdown-item');
this.outsideClickHandler = this.handleOutsideClick.bind(this);
this.init();
}
init() {
// Set ARIA attributes
this.toggle.setAttribute('aria-haspopup', 'true');
this.toggle.setAttribute('aria-expanded', 'false');
this.menu.setAttribute('role', 'menu');
this.items.forEach(item => {
item.setAttribute('role', 'menuitem');
item.setAttribute('tabindex', '-1');
});
// Toggle on click
this.toggle.addEventListener('click', (e) => {
e.stopPropagation();
this.toggleDropdown();
});
// Keyboard navigation
this.toggle.addEventListener('keydown', (e) => {
if (e.key === 'ArrowDown' || e.key === 'Enter' || e.key === ' ') {
e.preventDefault();
this.open();
this.items[0]?.focus();
}
});
this.items.forEach((item, index) => {
item.addEventListener('keydown', (e) => {
if (e.key === 'ArrowDown') {
e.preventDefault();
this.items[(index + 1) % this.items.length]?.focus();
} else if (e.key === 'ArrowUp') {
e.preventDefault();
this.items[(index - 1 + this.items.length) % this.items.length]?.focus();
} else if (e.key === 'Escape') {
e.preventDefault();
this.close();
this.toggle.focus();
}
});
});
// Prevent closing when clicking inside menu
this.menu.addEventListener('click', (e) => {
e.stopPropagation();
});
}
handleOutsideClick() {
this.close();
}
toggleDropdown() {
const isOpen = this.dropdown.classList.toggle('active');
this.toggle.setAttribute('aria-expanded', isOpen);
if (isOpen) {
this.items.forEach(item => item.setAttribute('tabindex', '0'));
// Add outside click handler when open
setTimeout(() => {
document.addEventListener('click', this.outsideClickHandler);
}, 0);
} else {
this.items.forEach(item => item.setAttribute('tabindex', '-1'));
// Remove outside click handler when closed
document.removeEventListener('click', this.outsideClickHandler);
}
}
open() {
this.dropdown.classList.add('active');
this.toggle.setAttribute('aria-expanded', 'true');
this.items.forEach(item => item.setAttribute('tabindex', '0'));
// Add outside click handler when open
setTimeout(() => {
document.addEventListener('click', this.outsideClickHandler);
}, 0);
}
close() {
this.dropdown.classList.remove('active');
this.toggle.setAttribute('aria-expanded', 'false');
this.items.forEach(item => item.setAttribute('tabindex', '-1'));
// Remove outside click handler when closed
document.removeEventListener('click', this.outsideClickHandler);
}
}
// Initialize all dropdowns
document.querySelectorAll('.vb-dropdown').forEach(dropdown => {
new VBDropdown(dropdown);
});
// ============================================
// TABS FUNCTIONALITY (WCAG 2.1 AA)
// ============================================
class VBTabs {
constructor(element) {
this.tabs = element;
this.buttons = this.tabs.querySelectorAll('.vb-tab-button');
this.contents = this.tabs.querySelectorAll('.vb-tab-content');
this.init();
}
init() {
// Set ARIA attributes
const tablist = this.tabs.querySelector('.vb-tab-list');
if (tablist) {
tablist.setAttribute('role', 'tablist');
}
this.buttons.forEach((button, index) => {
const tabId = `tab-${Math.random().toString(36).substr(2, 9)}`;
const panelId = `panel-${Math.random().toString(36).substr(2, 9)}`;
button.setAttribute('role', 'tab');
button.setAttribute('id', tabId);
button.setAttribute('aria-controls', panelId);
button.setAttribute('tabindex', '-1');
this.contents[index].setAttribute('role', 'tabpanel');
this.contents[index].setAttribute('id', panelId);
this.contents[index].setAttribute('aria-labelledby', tabId);
this.contents[index].setAttribute('tabindex', '0');
// Click event
button.addEventListener('click', () => {
this.switchTab(index);
});
// Keyboard navigation
button.addEventListener('keydown', (e) => {
let newIndex = index;
if (e.key === 'ArrowRight' || e.key === 'ArrowDown') {
e.preventDefault();
newIndex = (index + 1) % this.buttons.length;
} else if (e.key === 'ArrowLeft' || e.key === 'ArrowUp') {
e.preventDefault();
newIndex = (index - 1 + this.buttons.length) % this.buttons.length;
} else if (e.key === 'Home') {
e.preventDefault();
newIndex = 0;
} else if (e.key === 'End') {
e.preventDefault();
newIndex = this.buttons.length - 1;
}
if (newIndex !== index) {
this.switchTab(newIndex);
this.buttons[newIndex].focus();
}
});
});
// Activate first tab by default
if (this.buttons.length > 0 && !this.tabs.querySelector('.vb-tab-button.active')) {
this.switchTab(0);
}
}
switchTab(index) {
// Remove active class and update ARIA
this.buttons.forEach((btn, i) => {
btn.classList.remove('active');
btn.setAttribute('aria-selected', 'false');
btn.setAttribute('tabindex', '-1');
});
this.contents.forEach(content => {
content.classList.remove('active');
});
// Add active class to selected button and content
this.buttons[index].classList.add('active');
this.buttons[index].setAttribute('aria-selected', 'true');
this.buttons[index].setAttribute('tabindex', '0');
this.contents[index].classList.add('active');
a11y.announce(`Tab ${index + 1} selected`);
}
}
// Initialize all tabs
document.querySelectorAll('.vb-tabs').forEach(tabs => {
new VBTabs(tabs);
});
// ============================================
// ACCORDION FUNCTIONALITY (WCAG 2.1 AA)
// ============================================
class VBAccordion {
constructor(element) {
this.accordion = element;
this.items = this.accordion.querySelectorAll('.vb-accordion-item');
this.init();
}
init() {
this.items.forEach((item, index) => {
const header = item.querySelector('.vb-accordion-header');
const body = item.querySelector('.vb-accordion-body');
// Set ARIA attributes
const headerId = `accordion-header-${Math.random().toString(36).substr(2, 9)}`;
const bodyId = `accordion-body-${Math.random().toString(36).substr(2, 9)}`;
header.setAttribute('id', headerId);
header.setAttribute('aria-expanded', 'false');
header.setAttribute('aria-controls', bodyId);
body.setAttribute('id', bodyId);
body.setAttribute('role', 'region');
body.setAttribute('aria-labelledby', headerId);
// Click event
header.addEventListener('click', () => {
this.toggle(header, body);
});
// Keyboard support
header.addEventListener('keydown', (e) => {
if (e.key === 'ArrowDown') {
e.preventDefault();
const nextHeader = this.items[index + 1]?.querySelector('.vb-accordion-header');
nextHeader?.focus();
} else if (e.key === 'ArrowUp') {
e.preventDefault();
const prevHeader = this.items[index - 1]?.querySelector('.vb-accordion-header');
prevHeader?.focus();
} else if (e.key === 'Home') {
e.preventDefault();
this.items[0]?.querySelector('.vb-accordion-header')?.focus();
} else if (e.key === 'End') {
e.preventDefault();
this.items[this.items.length - 1]?.querySelector('.vb-accordion-header')?.focus();
}
});
});
}
toggle(header, body) {
const isActive = header.classList.contains('active');
// Close all items
this.accordion.querySelectorAll('.vb-accordion-header').forEach(h => {
h.classList.remove('active');
h.setAttribute('aria-expanded', 'false');
});
this.accordion.querySelectorAll('.vb-accordion-body').forEach(b => {
b.classList.remove('active');
});
// Toggle current item
if (!isActive) {
header.classList.add('active');
header.setAttribute('aria-expanded', 'true');
body.classList.add('active');
a11y.announce('Section expanded');
} else {
a11y.announce('Section collapsed');
}
}
}
// Initialize all accordions
document.querySelectorAll('.vb-accordion').forEach(accordion => {
new VBAccordion(accordion);
});
// ============================================
// CAROUSEL FUNCTIONALITY (WCAG 2.1 AA)
// ============================================
class VBCarousel {
constructor(element) {
this.carousel = element;
this.track = this.carousel.querySelector('.vb-carousel-track');
this.items = this.carousel.querySelectorAll('.vb-carousel-item');
this.prevBtn = this.carousel.querySelector('.vb-carousel-control-prev');
this.nextBtn = this.carousel.querySelector('.vb-carousel-control-next');
this.indicators = this.carousel.querySelectorAll('.vb-carousel-indicator');
this.currentIndex = 0;
this.autoplayInterval = null;
this.touchStartX = 0;
this.touchEndX = 0;
this.init();
}
init() {
if (this.items.length === 0 || !this.track) {
console.warn('Vibe Brutalism: Carousel requires .vb-carousel-track and at least one .vb-carousel-item');
return;
}
// Set ARIA attributes
this.carousel.setAttribute('role', 'region');
this.carousel.setAttribute('aria-label', 'Carousel');
this.carousel.setAttribute('aria-roledescription', 'carousel');
this.items.forEach((item, index) => {
item.setAttribute('role', 'group');
item.setAttribute('aria-roledescription', 'slide');
item.setAttribute('aria-label', `Slide ${index + 1} of ${this.items.length}`);
});
// Previous button
if (this.prevBtn) {
this.prevBtn.setAttribute('aria-label', 'Previous slide');
this.prevBtn.addEventListener('click', () => this.prev());
}
// Next button
if (this.nextBtn) {
this.nextBtn.setAttribute('aria-label', 'Next slide');
this.nextBtn.addEventListener('click', () => this.next());
}
// Indicators
this.indicators.forEach((indicator, index) => {
indicator.setAttribute('aria-label', `Go to slide ${index + 1}`);
indicator.setAttribute('role', 'button');
indicator.addEventListener('click', () => this.goTo(index));
});
// Keyboard navigation
this.carousel.addEventListener('keydown', (e) => {
if (e.key === 'ArrowLeft') {
e.preventDefault();
this.prev();
} else if (e.key === 'ArrowRight') {
e.preventDefault();
this.next();
}
});
// Pause autoplay on hover/focus
this.carousel.addEventListener('mouseenter', () => this.pauseAutoplay());
this.carousel.addEventListener('mouseleave', () => this.startAutoplay());
this.carousel.addEventListener('focusin', () => this.pauseAutoplay());
this.carousel.addEventListener('focusout', () => this.startAutoplay());
// Touch/Swipe support
this.carousel.addEventListener('touchstart', (e) => {
this.touchStartX = e.changedTouches[0].screenX;
}, { passive: true });
this.carousel.addEventListener('touchend', (e) => {
this.touchEndX = e.changedTouches[0].screenX;
this.handleSwipe();
}, { passive: true });
// Initialize
this.goTo(0);
// Start autoplay if enabled
if (this.carousel.dataset.autoplay === 'true') {
this.startAutoplay();
}
}
handleSwipe() {
const swipeThreshold = 50;
const diff = this.touchStartX - this.touchEndX;
if (Math.abs(diff) > swipeThreshold) {
if (diff > 0) {
// Swipe left - go to next
this.next();
} else {
// Swipe right - go to previous
this.prev();
}
}
}
goTo(index) {
this.currentIndex = index;
const offset = -index * 100;
this.track.style.transform = `translateX(${offset}%)`;
// Update indicators
this.indicators.forEach((indicator, i) => {
indicator.classList.toggle('active', i === index);
indicator.setAttribute('aria-current', i === index ? 'true' : 'false');
});
// Update items
this.items.forEach((item, i) => {
item.setAttribute('aria-hidden', i !== index);
});
a11y.announce(`Slide ${index + 1} of ${this.items.length}`);
}
next() {
const nextIndex = (this.currentIndex + 1) % this.items.length;
this.goTo(nextIndex);
}
prev() {
const prevIndex = (this.currentIndex - 1 + this.items.length) % this.items.length;
this.goTo(prevIndex);
}
startAutoplay() {
const interval = parseInt(this.carousel.dataset.interval) || 5000;
this.autoplayInterval = setInterval(() => this.next(), interval);
}
pauseAutoplay() {
if (this.autoplayInterval) {
clearInterval(this.autoplayInterval);
this.autoplayInterval = null;
}
}
}
// Initialize all carousels
const carousels = {};
document.querySelectorAll('.vb-carousel').forEach(carousel => {
const id = carousel.id || `carousel-${Math.random().toString(36).substr(2, 9)}`;
carousel.id = id;
carousels[id] = new VBCarousel(carousel);
});
// ============================================
// TOAST NOTIFICATIONS (WCAG 2.1 AA)
// ============================================
class VBToastManager {
constructor() {
this.container = null;
this.toasts = [];
}
getContainer(position = 'top-right') {
const containerId = `vb-toast-container-${position}`;
let container = document.getElementById(containerId);
if (!container) {
container = document.createElement('div');
container.id = containerId;
container.className = `vb-toast-container ${position}`;
container.setAttribute('aria-live', 'polite');
container.setAttribute('aria-atomic', 'false');
document.body.appendChild(container);
}
return container;
}
show(message, type = 'info', duration = 5000, position = 'top-right') {
const container = this.getContainer(position);
const toast = document.createElement('div');
toast.className = `vb-toast vb-toast-${type}`;
toast.setAttribute('role', 'status');
toast.setAttribute('aria-live', 'polite');
// Icon
const icons = {
success: '✓',
warning: '⚠',
danger: '✕',
info: ''
};
toast.innerHTML = `
<span class="vb-toast-icon" aria-hidden="true">${icons[type] || icons.info}</span>
<div class="vb-toast-content">${message}</div>
<button class="vb-toast-close" aria-label="Close notification">×</button>
`;
// Close button
const closeBtn = toast.querySelector('.vb-toast-close');
closeBtn.addEventListener('click', () => this.remove(toast));
container.appendChild(toast);
this.toasts.push(toast);
// Announce to screen readers
a11y.announce(message, 'polite');
// Auto remove
if (duration > 0) {
setTimeout(() => this.remove(toast), duration);
}
return toast;
}
remove(toast) {
toast.classList.add('removing');
setTimeout(() => {
toast.remove();
const index = this.toasts.indexOf(toast);
if (index > -1) {
this.toasts.splice(index, 1);
}
}, 300);
}
}
const toastManager = new VBToastManager();
// ============================================
// SNACKBAR FUNCTIONALITY (WCAG 2.1 AA)
// ============================================
class VBSnackbar {
constructor() {
this.snackbar = null;
this.timeout = null;
}
show(message, actionText = null, actionCallback = null, duration = 5000) {
// Remove existing snackbar
if (this.snackbar) {
this.hide();
}
// Create snackbar
this.snackbar = document.createElement('div');
this.snackbar.className = 'vb-snackbar';
this.snackbar.setAttribute('role', 'status');
this.snackbar.setAttribute('aria-live', 'polite');
let html = `<div class="vb-snackbar-message">${message}</div>`;
if (actionText && actionCallback) {
html += `<button class="vb-snackbar-action">${actionText}</button>`;
}
html += `<button class="vb-snackbar-close" aria-label="Close">×</button>`;
this.snackbar.innerHTML = html;
// Action button
if (actionText && actionCallback) {
const actionBtn = this.snackbar.querySelector('.vb-snackbar-action');
actionBtn.addEventListener('click', () => {
actionCallback();
this.hide();
});
}
// Close button
const closeBtn = this.snackbar.querySelector('.vb-snackbar-close');
closeBtn.addEventListener('click', () => this.hide());
document.body.appendChild(this.snackbar);
// Show with animation
setTimeout(() => {
this.snackbar.classList.add('show');
}, 10);
// Announce to screen readers
a11y.announce(message, 'polite');
// Auto hide
if (duration > 0) {
this.timeout = setTimeout(() => this.hide(), duration);
}
}
hide() {
if (this.snackbar) {
this.snackbar.classList.remove('show');
setTimeout(() => {
this.snackbar?.remove();
this.snackbar = null;
}, 300);
}
if (this.timeout) {
clearTimeout(this.timeout);
this.timeout = null;
}
}
}
const snackbar = new VBSnackbar();
// ============================================
// ALERT CLOSE FUNCTIONALITY
// ============================================
document.querySelectorAll('[data-vb-alert-close]').forEach(btn => {
btn.addEventListener('click', () => {
const alert = btn.closest('.vb-alert');
if (alert) {
alert.style.opacity = '0';
setTimeout(() => {
alert.remove();
}, 300);
}
});
});
// ============================================
// PROGRESS BAR
// ============================================
window.VBSetProgress = function(elementId, percentage) {
const progressBar = document.querySelector(`#${elementId} .vb-progress-bar`);
if (progressBar) {
progressBar.style.width = `${percentage}%`;
progressBar.textContent = `${percentage}%`;
progressBar.setAttribute('aria-valuenow', percentage);
a11y.announce(`Progress: ${percentage}%`);
}
};
// ============================================
// FORM VALIDATION
// ============================================
window.VBValidateForm = function(formElement) {
const inputs = formElement.querySelectorAll('.vb-input[required], .vb-textarea[required]');
let isValid = true;
inputs.forEach(input => {
if (!input.value.trim()) {
input.style.borderColor = 'var(--vb-danger)';
input.setAttribute('aria-invalid', 'true');
isValid = false;
} else {
input.style.borderColor = 'var(--vb-black)';
input.setAttribute('aria-invalid', 'false');
}
});
return isValid;
};
// ============================================
// GLOBAL API
// ============================================
window.VB = {
modals,
carousels,
Toast: (message, type, duration, position) => toastManager.show(message, type, duration, position),
Snackbar: (message, actionText, actionCallback, duration) => snackbar.show(message, actionText, actionCallback, duration),
SetProgress: window.VBSetProgress,
ValidateForm: window.VBValidateForm,
announce: (message, priority) => a11y.announce(message, priority)
};
// Initialize accessibility features
if (document.body) {
a11y.createLiveRegion();
console.log('🎨 Vibe Brutalism v2.0.0 initialized with WCAG 2.1 AA compliance!');
} else {
console.warn('Vibe Brutalism: document.body not available. Retrying on DOMContentLoaded...');
document.addEventListener('DOMContentLoaded', () => {
a11y.createLiveRegion();
console.log('🎨 Vibe Brutalism v2.0.0 initialized with WCAG 2.1 AA compliance!');
});
}
})();