- Add comprehensive health check system with multiple endpoints - Add Prometheus metrics endpoint - Add production logging configurations (5 strategies) - Add complete deployment documentation suite: * QUICKSTART.md - 30-minute deployment guide * DEPLOYMENT_CHECKLIST.md - Printable verification checklist * DEPLOYMENT_WORKFLOW.md - Complete deployment lifecycle * PRODUCTION_DEPLOYMENT.md - Comprehensive technical reference * production-logging.md - Logging configuration guide * ANSIBLE_DEPLOYMENT.md - Infrastructure as Code automation * README.md - Navigation hub * DEPLOYMENT_SUMMARY.md - Executive summary - Add deployment scripts and automation - Add DEPLOYMENT_PLAN.md - Concrete plan for immediate deployment - Update README with production-ready features All production infrastructure is now complete and ready for deployment.
334 lines
8.3 KiB
CSS
334 lines
8.3 KiB
CSS
/**
|
||
* 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,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="%23dc2626" stroke-width="2"><circle cx="12" cy="12" r="10"/><line x1="12" y1="8" x2="12" y2="12"/><line x1="12" y1="16" x2="12.01" y2="16"/></svg>');
|
||
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: "";
|
||
}
|
||
}
|
||
}
|