/** * Accessibility Utilities - Admin Interface * * WCAG 2.1 AA Compliance: * - Enhanced focus indicators (minimum 2px outline, 3:1 contrast) * - Skip links and screen reader utilities * - Reduced motion preferences * - Keyboard navigation enhancements */ @layer admin-utilities { /** * Focus Visible Enhancement (WCAG 2.1 Level AA) * * Requirement: 2.4.7 Focus Visible - All focusable elements * must have a visible focus indicator with min 3:1 contrast ratio. */ :focus-visible { outline: var(--admin-focus-ring-width, 2px) solid var(--admin-focus-ring); outline-offset: var(--admin-focus-ring-offset, 2px); border-radius: var(--admin-radius-sm); } /** * Skip to Content Link (WCAG 2.4.1) * * Requirement: Bypass Blocks - Provide a mechanism to bypass * repeated navigation blocks. */ .admin-skip-link { position: absolute; top: -9999px; left: -9999px; z-index: var(--admin-z-toast); padding: var(--admin-spacing-md) var(--admin-spacing-lg); background-color: var(--admin-accent-primary); color: white; text-decoration: none; font-weight: var(--admin-font-weight-semibold); border-radius: var(--admin-radius-md); box-shadow: var(--admin-shadow-lg); &:focus { top: var(--admin-spacing-md); left: var(--admin-spacing-md); } } /** * Screen Reader Only * * Visually hidden but accessible to screen readers. */ .sr-only, .admin-sr-only, .visually-hidden { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0, 0, 0, 0); white-space: nowrap; border-width: 0; } /** * Focus Visible for Not Screen Reader Only * * Show element when focused (for skip links). */ .sr-only-focusable:focus, .sr-only-focusable:active { position: static; width: auto; height: auto; overflow: visible; clip: auto; white-space: normal; } /** * Reduced Motion (WCAG 2.3.3) * * Respect user's motion preferences. */ @media (prefers-reduced-motion: reduce) { *, *::before, *::after { animation-duration: 0.01ms !important; animation-iteration-count: 1 !important; transition-duration: 0.01ms !important; scroll-behavior: auto !important; } } /** * Focus Within Enhancement * * Show focus state for container when child is focused. */ .admin-nav__item:focus-within { position: relative; &::before { content: ''; position: absolute; left: -2px; right: -2px; top: -2px; bottom: -2px; border: 2px solid var(--admin-focus-ring); border-radius: var(--admin-radius-md); pointer-events: none; } } /** * Keyboard Navigation Indicator * * Show clear visual feedback for keyboard users. */ body.user-is-tabbing *:focus { outline: 3px solid var(--admin-accent-info); outline-offset: 3px; } /** * High Contrast Mode Support * * Ensure borders are visible in Windows High Contrast Mode. */ @media (prefers-contrast: high) { .admin-card, .admin-sidebar, .admin-header { border: 2px solid currentColor; } button, .admin-action-btn, .admin-nav__link { border: 2px solid currentColor !important; } } /** * Touch Target Size (WCAG 2.5.5 Level AAA, but good practice) * * Minimum 44x44px touch targets for mobile. */ @media (pointer: coarse) { button, a, input[type="checkbox"], input[type="radio"], .admin-action-btn, .admin-nav__link { min-width: 44px; min-height: 44px; } } /** * Accessible Color Contrast Helpers * * WCAG AA requires: * - Normal text: 4.5:1 contrast ratio * - Large text (18pt+): 3:1 contrast ratio * - UI components: 3:1 contrast ratio */ .text-contrast-aa { /* Ensures minimum 4.5:1 contrast */ color: var(--admin-content-text); } .text-contrast-large { /* Large text can use lower contrast */ font-size: 1.125rem; color: var(--admin-content-text); opacity: 0.9; } /** * Error Identification (WCAG 3.3.1) * * Errors must be communicated with more than just color. */ .admin-error, .admin-form-error { color: var(--admin-accent-error); &::before { content: '⚠ '; font-weight: bold; margin-right: 0.25rem; } } [aria-invalid="true"] { border-color: var(--admin-accent-error) !important; border-width: 2px !important; /* Error icon */ background-image: url('data:image/svg+xml,'); background-repeat: no-repeat; background-position: right 0.75rem center; background-size: 1.25rem; padding-right: 2.5rem; } /** * Success/Warning States with Icons * * Not relying solely on color for state communication. */ .admin-success::before { content: '✓ '; font-weight: bold; color: var(--admin-accent-success); margin-right: 0.25rem; } .admin-warning::before { content: '⚠ '; font-weight: bold; color: var(--admin-accent-warning); margin-right: 0.25rem; } .admin-info::before { content: 'ℹ '; font-weight: bold; color: var(--admin-accent-info); margin-right: 0.25rem; } /** * Accessible Button States */ button:disabled, [aria-disabled="true"] { opacity: 0.5; cursor: not-allowed; position: relative; /* Pattern to indicate disabled state (not just opacity) */ &::after { content: ''; position: absolute; inset: 0; background-image: repeating-linear-gradient( 45deg, transparent, transparent 5px, oklch(0% 0 0 / 0.05) 5px, oklch(0% 0 0 / 0.05) 10px ); pointer-events: none; } } /** * Live Region Announcements * * For dynamic content updates. */ .admin-live-region { position: absolute; left: -10000px; width: 1px; height: 1px; overflow: hidden; } [aria-live="polite"], [aria-live="assertive"] { /* Screen reader will announce these */ } /** * Accessible Table Improvements */ table { caption { font-weight: var(--admin-font-weight-semibold); text-align: left; padding: var(--admin-spacing-md); background-color: var(--admin-bg-secondary); } th { font-weight: var(--admin-font-weight-semibold); text-align: left; } /* Zebra striping for better readability */ tbody tr:nth-child(even) { background-color: var(--admin-bg-secondary); } } /** * Print Styles (Accessibility includes print) */ @media print { .admin-sidebar, .admin-header__actions, .admin-mobile-overlay, .admin-sidebar__mobile-toggle { display: none !important; } .admin-content { max-width: 100% !important; padding: 0 !important; } a[href]::after { content: " (" attr(href) ")"; font-size: 0.875em; color: var(--admin-content-text); } /* Don't show internal links */ a[href^="#"]::after, a[href^="javascript:"]::after { content: ""; } } }