Self-Service Accessibility Audit * {
margin: 0;
padding: 0;
box-sizing: border-box;
} :root {
--color-green: #019E72;
--color-forest-green: #006548;
--color-ultramarine: #461DD3;
--color-slate: #1D1D1F;
--color-white: #FFFFFF;
--color-grey: #525255;
--color-chalk: #FAF9F7;
--color-sea-green: #0BFEB9;
--color-light-purple: #734FE7;
--color-white-smoke: #F5F5F7;
--color-sand: #F6F4F1;
} body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
background: linear-gradient(135deg, var(--color-white-smoke) 0%, var(--color-sand) 100%);
padding: px;
min-height: 100vh;
} .widget-container {
max-width: 600px;
margin: 0 auto;
background: var(--color-white);
border-radius: 16px;
box-shadow: 0 4px 24px rgba(29, 29, 31, 0.1);
overflow: hidden;
} .widget-header {
background: var(--color-forest-green);
padding: 40px 32px;
color: var(--color-white);
text-align: center;
} .widget-header h1 {
font-size: 32px;
font-weight: 600;
margin-bottom: 12px;
letter-spacing: -0.5px;
} .widget-header p {
font-size: 16px;
opacity: 0.95;
line-height: 1.5;
max-width: 300px;
margin: 0 auto;
} .widget-content {
padding: 32px;
} .criteria-list {
display: flex;
flex-direction: column;
gap: 16px;
margin-bottom: 32px;
} .criteria-item {
display: flex;
align-items: flex-start;
gap: 12px;
padding: 16px;
border-radius: 12px;
background: var(--color-white-smoke);
transition: all 0.3s ease;
cursor: pointer;
border: 2px solid transparent;
} .criteria-item:hover {
background: var(--color-sand);
border-color: var(--color-sea-green);
} .criteria-item.checked {
border-color: var(--color-green);
background: rgba(1, 158, 114, 0.05);
} .toggle-switch {
width: 44px;
height: 24px;
background: var(--color-grey);
border-radius: 12px;
position: relative;
cursor: pointer;
flex-shrink: 0;
margin-top: 2px;
transition: background 0.3s ease;
border: none;
padding: 0;
} .toggle-switch::after {
content: '';
position: absolute;
width: 20px;
height: 20px;
background: var(--color-white);
border-radius: 10px;
top: 2px;
left: 2px;
transition: all 0.3s ease;
} .toggle-switch.active {
background: var(--color-green);
} .toggle-switch.active::after {
left: 22px;
} .criteria-text {
flex: 1;
} .criteria-title {
font-size: 15px;
font-weight: 600;
color: var(--color-slate);
margin-bottom: 4px;
} .criteria-description {
font-size: 13px;
color: var(--color-grey);
line-height: 1.4;
} .button-group {
display: flex;
gap: 12px;
margin-bottom: 20px;
} .btn-submit {
flex: 1;
padding: 16px 24px;
background: var(--color-light-purple);
color: var(--color-white);
border: none;
border-radius: 12px;
font-size: 15px;
font-weight: 600;
cursor: pointer;
transition: all 0.3s ease;
} .btn-submit:hover:not(:disabled) {
background: var(--color-ultramarine);
transform: translateY(-2px);
box-shadow: 0 8px 16px rgba(70, 29, 211, 0.2);
} .btn-submit:disabled {
opacity: 0.5;
cursor: not-allowed;
} .btn-reset {
padding: 16px 24px;
background: transparent;
color: var(--color-grey);
border: 2px solid var(--color-white-smoke);
border-radius: 12px;
font-size: 15px;
font-weight: 600;
cursor: pointer;
transition: all 0.3s ease;
} .btn-reset:hover {
border-color: var(--color-grey);
color: var(--color-slate);
} /* Results Screen */
.results-container {
display: none;
} .results-container.active {
display: block;
animation: slideIn 0.4s ease;
} @keyframes slideIn {
from {
opacity: 0;
transform: translateY(20px);
}
to {
opacity: 1;
transform: translateY(0);
}
} .results-header {
text-align: center;
margin-bottom: 32px;
} .results-header h2 {
font-size: 24px;
color: var(--color-slate);
margin-bottom: 20px;
font-weight: 600;
} .score-display {
display: flex;
justify-content: center;
align-items: center;
gap: 50px;
margin-bottom: 28px;
} .compliance-score {
text-align: center;
} .score-number {
font-size: 56px;
font-weight: 700;
background: linear-gradient(135deg, var(--color-forest-green), var(--color-green));
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
margin-bottom: 8px;
} .score-label {
font-size: 13px;
color: var(--color-grey);
text-transform: uppercase;
letter-spacing: 0.5px;
font-weight: 600;
} .risk-badge {
padding: 12px 24px;
border-radius: 24px;
font-weight: 600;
font-size: 14px;
text-align: center;
min-width: 140px;
} .risk-badge.low {
background: rgba(1, 158, 114, 0.15);
color: var(--color-forest-green);
border: 2px solid var(--color-green);
} .risk-badge.medium {
background: rgba(115, 79, 231, 0.15);
color: var(--color-light-purple);
border: 2px solid var(--color-light-purple);
} .risk-badge.high {
background: rgba(255, 107, 107, 0.15);
color: #E63946;
border: 2px solid #E63946;
} .impact-section {
margin-bottom: 24px;
} .impact-title {
font-size: 15px;
font-weight: 600;
color: var(--color-slate);
margin-bottom: 16px;
} .disability-categories {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 12px;
} .disability-card {
background: var(--color-sand);
padding: 16px;
border-radius: 12px;
border-left: 4px solid var(--color-sea-green);
} .disability-name {
font-size: 14px;
font-weight: 600;
color: var(--color-slate);
margin-bottom: 6px;
} .disability-impact {
font-size: 13px;
color: var(--color-grey);
line-height: 1.4;
} .missing-features {
background: rgba(230, 57, 70, 0.08);
padding: 20px;
border-radius: 12px;
margin-bottom: 24px;
border-left: 4px solid #E63946;
} .missing-title {
font-size: 14px;
font-weight: 600;
color: #E63946;
margin-bottom: 12px;
} .missing-list {
list-style: none;
} .missing-list li {
font-size: 13px;
color: var(--color-grey);
padding: 6px 0;
padding-left: 20px;
position: relative;
} .missing-list li:before {
content: '⚠';
position: absolute;
left: 0;
} .recommendations {
background: rgba(1, 158, 114, 0.08);
padding: 20px;
border-radius: 12px;
border-left: 4px solid var(--color-green);
} .recommendations-title {
font-size: 14px;
font-weight: 600;
color: var(--color-forest-green);
margin-bottom: 12px;
} .recommendations-list {
list-style: none;
} .recommendations-list li {
font-size: 13px;
color: var(--color-grey);
padding: 8px 0;
padding-left: 20px;
position: relative;
} .recommendations-list li:before {
content: '→';
position: absolute;
left: 0;
color: var(--color-green);
font-weight: 700;
} .action-buttons {
display: flex;
gap: 12px;
margin-top: 24px;
} .btn-back {
flex: 1;
padding: 14px 20px;
background: transparent;
color: var(--color-slate);
border: 2px solid var(--color-white-smoke);
border-radius: 12px;
font-size: 14px;
font-weight: 600;
cursor: pointer;
transition: all 0.3s ease;
} .btn-back:hover {
border-color: var(--color-grey);
background: var(--color-white-smoke);
} .btn-learn {
flex: 1;
padding: 14px 20px;
background: var(--color-light-purple);
color: var(--color-white);
border: none;
border-radius: 12px;
font-size: 14px;
font-weight: 600;
cursor: pointer;
transition: all 0.3s ease;
} .btn-learn:hover {
background: var(--color-ultramarine);
transform: translateY(-2px);
box-shadow: 0 8px 16px rgba(70, 29, 211, 0.2);
} /* Responsive */
@media (max-width: 480px) {
.widget-header {
padding: 32px 24px;
} .widget-header h1 {
font-size: 28px;
} .widget-header p {
font-size: 14px;
} .widget-content {
padding: 24px;
} .criteria-item {
padding: 12px;
gap: 10px;
} .criteria-title {
font-size: 14px;
} .criteria-description {
font-size: 12px;
} .disability-categories {
grid-template-columns: 1fr;
} .score-display {
flex-direction: column;
gap: 16px;
} .btn-submit {
font-size: 14px;
padding: 14px 20px;
}
} /* Accessibility */
.toggle-switch:focus-visible {
outline: 3px solid var(--color-sea-green);
outline-offset: 2px;
} .btn-submit:focus-visible,
.btn-reset:focus-visible,
.btn-back:focus-visible,
.btn-learn:focus-visible {
outline: 3px solid var(--color-ultramarine);
outline-offset: 2px;
} .criteria-item:focus-visible {
outline: 3px solid var(--color-sea-green);
outline-offset: 0;
} @media (prefers-reduced-motion: true) {
* {
animation-duration: 0.01ms !important;
animation-iteration-count: 1 !important;
transition-duration: 0.01ms !important;
}
}
// Criterion data structure
const criteria = {
reach: {
name: 'Physical Reach Range',
category: 'Motor',
impact: 'Wheelchair users cannot access controls positioned outside reach envelope'
},
audio: {
name: 'Audio Output and Private Listening',
category: 'Hearing & Visual',
impact: 'Blind, deaf, and hard-of-hearing users cannot access audio or private listening'
},
tactile: {
name: 'Tactilely Discernible Controls',
category: 'Visual',
impact: 'Blind and low-vision users cannot locate or operate touchscreen-only interfaces'
},
contrast: {
name: 'Adjustable Contrast and Text',
category: 'Visual',
impact: 'Low-vision and color-blind users struggle with poor contrast and small text'
},
motions: {
name: 'One-Handed Operation',
category: 'Motor',
impact: 'Users with limited hand strength or single-hand use cannot operate device'
}
}; // Global disability impact data - WHO and UN official sources
const disabilityImpact = {
'Visual Impairments': {
percentage: '285 million globally',
description: 'Blind/low-vision users cannot use visual-only interfaces'
},
'Motor Disabilities': {
percentage: '1.3 billion globally',
description: 'Wheelchair users and those with limited mobility need accessible reach'
},
'Hearing Impairments': {
percentage: '466 million globally',
description: 'Deaf users require visual alternatives to audio feedback'
},
'Cognitive Disabilities': {
percentage: '200 million globally',
description: 'Users with intellectual disabilities need clear, extended time'
}
}; // State management
let selectedCriteria = new Set(); // DOM elements
const toggles = document.querySelectorAll('.toggle-switch');
const submitBtn = document.getElementById('submitBtn');
const resetBtn = document.getElementById('resetBtn');
const backBtn = document.getElementById('backBtn');
const learnBtn = document.getElementById('learnBtn');
const auditScreen = document.getElementById('auditScreen');
const resultsScreen = document.getElementById('resultsScreen'); // Toggle functionality
toggles.forEach(toggle => {
toggle.addEventListener('click', (e) => {
e.preventDefault();
const criterion = toggle.dataset.criterion;
toggle.classList.toggle('active');
toggle.parentElement.classList.toggle('checked'); if (toggle.classList.contains('active')) {
selectedCriteria.add(criterion);
} else {
selectedCriteria.delete(criterion);
} updateSubmitButton();
});
}); function updateSubmitButton() {
submitBtn.disabled = selectedCriteria.size === 0;
} submitBtn.addEventListener('click', () => {
if (selectedCriteria.size > 0) {
generateResults();
auditScreen.style.display = 'none';
resultsScreen.classList.add('active');
window.scrollTo({ top: 0, behavior: 'smooth' });
}
}); resetBtn.addEventListener('click', () => {
selectedCriteria.clear();
toggles.forEach(toggle => {
toggle.classList.remove('active');
toggle.parentElement.classList.remove('checked');
});
updateSubmitButton();
}); backBtn.addEventListener('click', () => {
resultsScreen.classList.remove('active');
auditScreen.style.display = 'block';
window.scrollTo({ top: 0, behavior: 'smooth' });
}); learnBtn.addEventListener('click', () => {
window.open('https://www.en301549.eu/', '_blank');
}); function generateResults() {
const totalCriteria = Object.keys(criteria).length;
const complianceScore = Math.round((selectedCriteria.size / totalCriteria) * 100); // Update score and risk badge
document.getElementById('scorePercent').textContent = complianceScore + '%'; const riskBadge = document.getElementById('riskBadge');
riskBadge.className = 'risk-badge';
if (complianceScore >= 70) {
riskBadge.className += ' low';
riskBadge.textContent = '✓ Low Risk';
} else if (complianceScore >= 40) {
riskBadge.className += ' medium';
riskBadge.textContent = '⚠ Medium Risk';
} else {
riskBadge.className += ' high';
riskBadge.textContent = '✕ High Risk';
} // Populate impact categories
const impactContainer = document.getElementById('impactCategories');
impactContainer.innerHTML = '';
Object.entries(disabilityImpact).forEach(([category, data]) => {
const card = document.createElement('div');
card.className = 'disability-card';
card.innerHTML = `
${category}
${data.percentage} affected by missing features
`;
impactContainer.appendChild(card);
}); // Generate missing features
const allCriteria = Object.keys(criteria);
const missingCriteria = allCriteria.filter(c => !selectedCriteria.has(c)); if (missingCriteria.length > 0) {
document.getElementById('missingFeaturesContainer').style.display = 'block';
const missingList = document.getElementById('missingList');
missingList.innerHTML = '';
missingCriteria.forEach(criterion => {
const li = document.createElement('li');
li.textContent = criteria[criterion].name;
missingList.appendChild(li);
});
} else {
document.getElementById('missingFeaturesContainer').style.display = 'none';
} // Generate recommendations
const recommendationsList = document.getElementById('recommendationsList');
recommendationsList.innerHTML = ''; if (complianceScore >= 70) {
const recs = [
'Maintain current accessibility standards through regular audits',
'Implement user testing with people with disabilities',
'Stay updated with EN 301 549 and WCAG guidelines'
];
recs.forEach(rec => {
const li = document.createElement('li');
li.textContent = rec;
recommendationsList.appendChild(li);
});
} else if (complianceScore >= 40) {
const recs = [
'Prioritize missing audio/visual feedback systems',
'Implement tactile controls alongside touch interface',
'Conduct accessibility assessment with specialists',
'Plan phased implementation of missing features'
];
recs.forEach(rec => {
const li = document.createElement('li');
li.textContent = rec;
recommendationsList.appendChild(li);
});
} else {
const recs = [
'Schedule comprehensive accessibility audit',
'Partner with accessibility consultants (like Storm Interface)',
'Implement voice interface and audio feedback system',
'Add physical keypad alternative to touchscreen',
'Review and redesign UI for high contrast and legibility'
];
recs.forEach(rec => {
const li = document.createElement('li');
li.textContent = rec;
recommendationsList.appendChild(li);
});
} updateSubmitButton();
} // Keyboard navigation
document.addEventListener('keydown', (e) => {
if (e.key === 'Enter' && submitBtn === document.activeElement) {
submitBtn.click();
}
if (e.key === 'Escape' && resultsScreen.classList.contains('active')) {
backBtn.click();
}
}); // Initialize
updateSubmitButton();