1/* Enablestack widget â themed build. Primary: #005da3 · Icon: default 2 Regenerate anytime with: npx enablestack-widget-theme <hexcolor> [icon] */ 3(function () { 4 var g = (typeof window !== "undefined") ? window : this; 5 if (!g) { return; } 6 g.ENABLESTACK_CONFIG = g.ENABLESTACK_CONFIG || {}; 7 var c = g.ENABLESTACK_CONFIG.colors; 8 if (!c || !c.primary) { 9 g.ENABLESTACK_CONFIG.colors = Object.assign({}, c, { primary: "#005da3" }); 10 } 11 if (!g.ENABLESTACK_CONFIG.icon) { 12 g.ENABLESTACK_CONFIG.icon = "default"; 13 } 14})(); 15 16/* =========================================== 17 18 ENABLESTACK WIDGET 19 Enterprise Accessibility Infrastructure 20 21 Owned and maintained by enableuser 22 https://www.enableuser.com 23 24=========================================== */ 25 26// Skip execution in non-browser environments (Node.js, SSR, etc.) 27if (typeof window === 'undefined' || typeof document === 'undefined') { 28 // no-op: widget requires a browser environment 29} else { 30// --- Browser-only code begins --- 31 32// =========================================== 33// TRANSLATIONS 34// =========================================== 35 36const TRANSLATIONS = { 37 en: { 38 accessibilityMenu: 'Accessibility Menu', 39 closeAccessibilityMenu: 'Close Accessibility Menu', 40 accessibilityTools: 'Accessibility Tools', 41 resetAllSettings: 'Reset All Settings', 42 screenReader: 'Read Aloud', 43 voiceCommand: 'Voice Command', 44 textSpacing: 'Text Spacing', 45 pauseAnimations: 'Pause Animations', 46 hideImages: 'Hide Images', 47 dyslexiaFriendly: 'Dyslexia Friendly', 48 biggerCursor: 'Bigger Cursor', 49 lineHeight: 'Line Height', 50 fontSelection: 'Font Selection', 51 colorFilter: 'Color Filter', 52 textAlign: 'Text Align', 53 textSize: 'Text Size', 54 highContrast: 'High Contrast', 55 defaultFont: 'Default Font', 56 noFilter: 'No Filter', 57 default: 'Default', 58 screenReaderOn: 'Read aloud on', 59 screenReaderOff: 'Read aloud off', 60 voiceControlActivated: 'Voice control activated', 61 notSupportedBrowser: 'is not supported in this browser', 62 close: 'Close', 63 reset: 'Reset', 64 saturation: 'Saturation', 65 selectLanguage: 'Select Language', 66 personalizeExperience: 'Personalize Your Experience', 67 navigatePageStructure: 'Navigate by Page Structure', 68 landmarks: 'Landmarks', 69 headings: 'Headings', 70 links: 'Links', 71 noItemsFound: 'No items found', 72 focus: 'Focus', 73 cursor: 'Cursor', 74 highlight: 'Highlight', 75 contrast: 'Contrast', 76 colorShift: 'Color Shift', 77 animation: 'Animation', 78 spacing: 'Spacing', 79 font: 'Font', 80 guide: 'Guide', 81 window: 'Window', 82 images: 'Images', 83 showShortcuts: 'Show shortcuts', 84 additionalShortcuts: 'Additional Keyboard Shortcuts', 85 resetVisualToolkit: 'Reset Visual Toolkit', 86 resetIssue: 'Reset Issue', 87 navigatePageStructureShortcut: 'Navigate by Page Structure', 88 profiles: 'Accessibility Profiles', 89 profileSeizure: 'Seizure Safe', 90 profileVision: 'Low Vision', 91 profileAdhd: 'ADHD Friendly', 92 profileDyslexia: 'Dyslexia', 93 align: 'Align', 94 readAloudShort: 'Read Aloud', 95 voice: 'Voice', 96 altText: 'Alt Text', 97 noAltText: 'Missing alt text', 98 openHelpDesk: 'Open Help Desk', // kept for internal use 99 closeHelpDesk: 'Close Help Desk', // kept for internal use 100 // Enhanced features (v1.3.0) 101 hoverHighlight: 'Hover Highlight', 102 enlargeButtons: 'Big Buttons', 103 muteMedia: 'Mute Media', 104 readableFont: 'Readable Font', 105 magnifier: 'Magnifier', 106 textMagnifier: 'Text Magnifier', 107 readFocus: 'Read Focus', 108 virtualKeyboard: 'Keyboard', 109 readableMode: 'Reader View', 110 dictionary: 'Dictionary', 111 customColor: 'Custom Color', 112 customColorBackground: 'Background', 113 customColorText: 'Text', 114 customColorHeadings: 'Headings', 115 customColorApply: 'Apply', 116 customColorReset: 'Reset colors', 117 accessibilityStatement: 'Accessibility Statement', 118 sendFeedback: 'Send Feedback', 119 hideForNow: 'Hide button', 120 dictionarySelectPrompt: 'Select a word on the page to look it up', 121 dictionaryNotFound: 'No definition found', 122 dictionaryLoading: 'Looking upâ¦', 123 readerViewEmpty: 'No readable content found on this page', 124 resizeWidget: 'Resize widget (drag, or use arrow keys)' 125 }, 126 de: { 127 accessibilityMenu: 'Barrierefreiheit-Menü', closeAccessibilityMenu: 'Barrierefreiheit-Menü schlieÃen', resetAllSettings: 'Alle Einstellungen zurücksetzen', 128 screenReader: 'Vorlesen', voiceCommand: 'Sprachbefehl', textSpacing: 'Zeichenabstand', pauseAnimations: 'Animationen anhalten', hideImages: 'Bilder ausblenden',
129 dyslexiaFriendly: 'Legasthenie-freundlich', biggerCursor: 'GroÃer Cursor', lineHeight: 'Zeilenhöhe', fontSelection: 'Schriftauswahl', colorFilter: 'Farbfilter', 130 textAlign: 'Textausrichtung', textSize: 'TextgröÃe', highContrast: 'Hoher Kontrast', default: 'Standard', screenReaderOn: 'Vorlesen aktiviert', screenReaderOff: 'Vorlesen deaktiviert', 131 voiceControlActivated: 'Sprachsteuerung aktiviert', notSupportedBrowser: 'wird in diesem Browser nicht unterstützt', close: 'SchlieÃen', reset: 'Zurücksetzen', 132 saturation: 'Sättigung', navigatePageStructure: 'Nach Seitenstruktur navigieren', landmarks: 'Orientierungspunkte', headings: 'Ãberschriften', links: 'Links', 133 noItemsFound: 'Keine Einträge gefunden', focus: 'Fokus', cursor: 'Cursor', highlight: 'Hervorheben', contrast: 'Kontrast', colorShift: 'Farbverschiebung', 134 animation: 'Animation', spacing: 'Abstand', font: 'Schrift', guide: 'Leselineal', window: 'Lesefenster', images: 'Bilder', showShortcuts: 'Tastenkürzel anzeigen', 135 additionalShortcuts: 'Weitere Tastenkürzel', resetVisualToolkit: 'Visuelles Toolkit zurücksetzen', resetIssue: 'Markierung zurücksetzen', 136 profiles: 'Barrierefreiheit-Profile', profileSeizure: 'Epilepsie-sicher', profileVision: 'Sehschwäche', profileAdhd: 'ADHS-freundlich', profileDyslexia: 'Legasthenie', 137 align: 'Ausrichten', voice: 'Stimme', altText: 'Alt-Text', noAltText: 'Alt-Text fehlt' 138 }, 139 es: { 140 accessibilityMenu: 'Menú de accesibilidad', closeAccessibilityMenu: 'Cerrar menú de accesibilidad', resetAllSettings: 'Restablecer todos los ajustes', 141 screenReader: 'Leer en voz alta', voiceCommand: 'Comando de voz', textSpacing: 'Espaciado de texto', pauseAnimations: 'Pausar animaciones', hideImages: 'Ocultar imágenes', 142 dyslexiaFriendly: 'Apto para dislexia', biggerCursor: 'Cursor grande', lineHeight: 'Altura de lÃnea', fontSelection: 'Selección de fuente', colorFilter: 'Filtro de color', 143 textAlign: 'Alineación de texto', textSize: 'Tamaño de texto', highContrast: 'Alto contraste', default: 'Predeterminado', screenReaderOn: 'Lectura en voz alta activada', screenReaderOff: 'Lectura en voz alta desactivada', 144 voiceControlActivated: 'Control por voz activado', notSupportedBrowser: 'no es compatible con este navegador', close: 'Cerrar', reset: 'Restablecer', 145 saturation: 'Saturación', navigatePageStructure: 'Navegar por la estructura de la página', landmarks: 'Puntos de referencia', headings: 'Encabezados', links: 'Enlaces', 146 noItemsFound: 'No se encontraron elementos', focus: 'Foco', cursor: 'Cursor', highlight: 'Resaltar', contrast: 'Contraste', colorShift: 'Cambio de color', 147 animation: 'Animación', spacing: 'Espaciado', font: 'Fuente', guide: 'GuÃa', window: 'Ventana', images: 'Imágenes', showShortcuts: 'Mostrar atajos', 148 additionalShortcuts: 'Atajos de teclado adicionales', resetVisualToolkit: 'Restablecer kit visual', resetIssue: 'Restablecer resaltado', 149 profiles: 'Perfiles de accesibilidad', profileSeizure: 'Seguro para epilepsia', profileVision: 'Baja visión', profileAdhd: 'Apto para TDAH', profileDyslexia: 'Dislexia', 150 align: 'Alinear', voice: 'Voz', altText: 'Texto alternativo', noAltText: 'Falta texto alternativo' 151 }, 152 it: { 153 accessibilityMenu: 'Menu accessibilità ', closeAccessibilityMenu: 'Chiudi menu accessibilità ', resetAllSettings: 'Ripristina tutte le impostazioni', 154 screenReader: 'Leggi ad alta voce', voiceCommand: 'Comando vocale', textSpacing: 'Spaziatura testo', pauseAnimations: 'Pausa animazioni', hideImages: 'Nascondi immagini', 155 dyslexiaFriendly: 'Adatto alla dislessia', biggerCursor: 'Cursore grande', lineHeight: 'Interlinea', fontSelection: 'Selezione carattere', colorFilter: 'Filtro colore', 156 textAlign: 'Allineamento testo', textSize: 'Dimensione testo', highContrast: 'Contrasto elevato', default: 'Predefinito', screenReaderOn: 'Lettura ad alta voce attiva', screenReaderOff: 'Lettura ad alta voce disattivata', 157 voiceControlActivated: 'Controllo vocale attivato', notSupportedBrowser: 'non è supportato in questo browser', close: 'Chiudi', reset: 'Ripristina', 158 saturation: 'Saturazione', navigatePageStructure: 'Naviga per struttura della pagina', landmarks: 'Punti di riferimento', headings: 'Intestazioni', links: 'Collegamenti', 159 noItemsFound: 'Nessun elemento trovato', focus: 'Focus', cursor: 'Cursore', highlight: 'Evidenzia', contrast: 'Contrasto', colorShift: 'Variazione colore', 160 animation: 'Animazione', spacing: 'Spaziatura', font: 'Carattere', guide: 'Guida', window: 'Finestra', images: 'Immagini', showShortcuts: 'Mostra scorciatoie', 161 additionalShortcuts: 'Altre scorciatoie da tastiera', resetVisualToolkit: 'Ripristina toolkit visivo', resetIssue: 'Ripristina evidenziazione', 162 profiles: 'Profili di accessibilità ', profileSeizure: 'Sicuro per epilessia', profileVision: 'Ipovisione', profileAdhd: 'Adatto ad ADHD', profileDyslexia: 'Dislessia', 163 align: 'Allinea', voice: 'Voce', altText: 'Testo alternativo', noAltText: 'Testo alternativo mancante' 164 }, 165 fr: { 166 accessibilityMenu: 'Menu d\'accessibilité', closeAccessibilityMenu: 'Fermer le menu d\'accessibilité', resetAllSettings: 'Réinitialiser tous les réglages', 167 screenReader: 'Lecture à voix haute', voiceCommand: 'Commande vocale', textSpacing: 'Espacement du texte', pauseAnimations: 'Suspendre les animations', hideImages: 'Masquer les images',
168 dyslexiaFriendly: 'Adapté à la dyslexie', biggerCursor: 'Grand curseur', lineHeight: 'Hauteur de ligne', fontSelection: 'Choix de police', colorFilter: 'Filtre de couleur', 169 textAlign: 'Alignement du texte', textSize: 'Taille du texte', highContrast: 'Contraste élevé', default: 'Par défaut', screenReaderOn: 'Lecture à voix haute activée', screenReaderOff: 'Lecture à voix haute désactivée', 170 voiceControlActivated: 'Contrôle vocal activé', notSupportedBrowser: 'n\'est pas pris en charge par ce navigateur', close: 'Fermer', reset: 'Réinitialiser', 171 saturation: 'Saturation', navigatePageStructure: 'Naviguer par structure de page', landmarks: 'Points de repère', headings: 'Titres', links: 'Liens', 172 noItemsFound: 'Aucun élément trouvé', focus: 'Focus', cursor: 'Curseur', highlight: 'Surligner', contrast: 'Contraste', colorShift: 'Décalage des couleurs', 173 animation: 'Animation', spacing: 'Espacement', font: 'Police', guide: 'Guide', window: 'Fenêtre', images: 'Images', showShortcuts: 'Afficher les raccourcis', 174 additionalShortcuts: 'Raccourcis clavier supplémentaires', resetVisualToolkit: 'Réinitialiser la boîte à outils visuelle', resetIssue: 'Réinitialiser le surlignage', 175 profiles: 'Profils d\'accessibilité', profileSeizure: 'Anti-épilepsie', profileVision: 'Basse vision', profileAdhd: 'Adapté au TDAH', profileDyslexia: 'Dyslexie', 176 align: 'Aligner', voice: 'Voix', altText: 'Texte alternatif', noAltText: 'Texte alternatif manquant' 177 }, 178 ru: { 179 accessibilityMenu: 'ÐÐµÐ½Ñ Ð´Ð¾ÑÑÑпноÑÑи', closeAccessibilityMenu: 'ÐакÑÑÑÑ Ð¼ÐµÐ½Ñ Ð´Ð¾ÑÑÑпноÑÑи', resetAllSettings: 'СбÑоÑиÑÑ Ð²Ñе наÑÑÑойки', 180 screenReader: 'ЧÑение вÑлÑÑ ', voiceCommand: 'ÐолоÑÐ¾Ð²Ð°Ñ ÐºÐ¾Ð¼Ð°Ð½Ð´Ð°', textSpacing: 'ÐнÑеÑвал ÑекÑÑа', pauseAnimations: 'ÐÑÑановиÑÑ Ð°Ð½Ð¸Ð¼Ð°ÑиÑ', hideImages: 'СкÑÑÑÑ Ð¸Ð·Ð¾Ð±ÑажениÑ', 181 dyslexiaFriendly: 'ÐÐ»Ñ Ð´Ð¸ÑлекÑии', biggerCursor: 'ÐолÑÑой кÑÑÑоÑ', lineHeight: 'ÐÑÑоÑа ÑÑÑоки', fontSelection: 'ÐÑÐ±Ð¾Ñ ÑÑиÑÑа', colorFilter: 'ЦвеÑовой ÑилÑÑÑ', 182 textAlign: 'ÐÑÑавнивание ÑекÑÑа', textSize: 'Ð Ð°Ð·Ð¼ÐµÑ ÑекÑÑа', highContrast: 'ÐÑÑÐ¾ÐºÐ°Ñ ÐºÐ¾Ð½ÑÑаÑÑноÑÑÑ', default: 'Ðо ÑмолÑаниÑ', screenReaderOn: 'ЧÑение вÑлÑÑ Ð²ÐºÐ»ÑÑено', screenReaderOff: 'ЧÑение вÑлÑÑ Ð²ÑклÑÑено', 183 voiceControlActivated: 'ÐолоÑовое ÑпÑавление вклÑÑено', notSupportedBrowser: 'не поддеÑживаеÑÑÑ Ð² ÑÑом бÑаÑзеÑе', close: 'ÐакÑÑÑÑ', reset: 'СбÑоÑиÑÑ', 184 saturation: 'ÐаÑÑÑенноÑÑÑ', navigatePageStructure: 'ÐавигаÑÐ¸Ñ Ð¿Ð¾ ÑÑÑÑкÑÑÑе ÑÑÑаниÑÑ', landmarks: 'ÐÑиенÑиÑÑ', headings: 'Ðаголовки', links: 'СÑÑлки', 185 noItemsFound: 'ÐиÑего не найдено', focus: 'ФокÑÑ', cursor: 'ÐÑÑÑоÑ', highlight: 'ÐодÑвеÑка', contrast: 'ÐонÑÑаÑÑ', colorShift: 'Сдвиг ÑвеÑа', 186 animation: 'ÐнимаÑиÑ', spacing: 'ÐнÑеÑвал', font: 'ШÑиÑÑ', guide: 'Ðинейка', window: 'Ðкно', images: 'ÐзобÑажениÑ', showShortcuts: 'ÐоказаÑÑ ÐºÐ»Ð°Ð²Ð¸Ñи', 187 additionalShortcuts: 'ÐополниÑелÑнÑе ÑоÑеÑÐ°Ð½Ð¸Ñ ÐºÐ»Ð°Ð²Ð¸Ñ', resetVisualToolkit: 'СбÑоÑиÑÑ Ð²Ð¸Ð·ÑалÑнÑе наÑÑÑойки', resetIssue: 'СбÑоÑиÑÑ Ð¿Ð¾Ð´ÑвеÑкÑ', 188 profiles: 'ÐÑоÑили доÑÑÑпноÑÑи', profileSeizure: 'ÐаÑиÑа Ð¾Ñ ÑпилепÑии', profileVision: 'Слабое зÑение', profileAdhd: 'ÐÐ»Ñ Ð¡ÐÐÐ', profileDyslexia: 'ÐиÑлекÑиÑ', 189 align: 'ÐÑÑовнÑÑÑ', voice: 'ÐолоÑ', altText: 'ÐлÑÑ-ÑекÑÑ', noAltText: 'ÐÐµÑ Ð°Ð»ÑÑ-ÑекÑÑа' 190 }, 191 tr: { 192 accessibilityMenu: 'EriÅilebilirlik Menüsü', closeAccessibilityMenu: 'EriÅilebilirlik menüsünü kapat', resetAllSettings: 'Tüm ayarları sıfırla', 193 screenReader: 'Sesli Oku', voiceCommand: 'Sesli Komut', textSpacing: 'Metin AralıÄı', pauseAnimations: 'Animasyonları Durdur', hideImages: 'Görselleri Gizle',
194 dyslexiaFriendly: 'Disleksi Dostu', biggerCursor: 'Büyük İmleç', lineHeight: 'Satır YüksekliÄi', fontSelection: 'Yazı Tipi Seçimi', colorFilter: 'Renk Filtresi', 195 textAlign: 'Metin Hizalama', textSize: 'Metin Boyutu', highContrast: 'Yüksek Kontrast', default: 'Varsayılan', screenReaderOn: 'Sesli okuma açık', screenReaderOff: 'Sesli okuma kapalı', 196 voiceControlActivated: 'Ses kontrolü etkin', notSupportedBrowser: 'bu tarayıcıda desteklenmiyor', close: 'Kapat', reset: 'Sıfırla', 197 saturation: 'Doygunluk', navigatePageStructure: 'Sayfa Yapısına Göre Gezin', landmarks: 'Yer İÅaretleri', headings: 'BaÅlıklar', links: 'BaÄlantılar', 198 noItemsFound: 'ÃÄe bulunamadı', focus: 'Odak', cursor: 'İmleç', highlight: 'Vurgula', contrast: 'Kontrast', colorShift: 'Renk Kaydırma', 199 animation: 'Animasyon', spacing: 'Aralık', font: 'Yazı Tipi', guide: 'Kılavuz', window: 'Pencere', images: 'Görseller', showShortcuts: 'Kısayolları göster', 200 additionalShortcuts: 'Ek Klavye Kısayolları', resetVisualToolkit: 'Görsel araçları sıfırla', resetIssue: 'Vurguyu sıfırla', 201 profiles: 'EriÅilebilirlik Profilleri', profileSeizure: 'Nöbet Güvenli', profileVision: 'Az Gören', profileAdhd: 'DEHB Dostu', profileDyslexia: 'Disleksi', 202 align: 'Hizala', voice: 'Ses', altText: 'Alternatif Metin', noAltText: 'Alternatif metin yok' 203 }, 204 ar: { 205 accessibilityMenu: 'ÙØ§Ø¦Ù Ø© Ø¥Ù ÙØ§ÙÙØ© اÙÙØµÙÙ', closeAccessibilityMenu: 'Ø¥ØºÙØ§Ù ÙØ§Ø¦Ù Ø© Ø¥Ù ÙØ§ÙÙØ© اÙÙØµÙÙ', resetAllSettings: 'إعادة تعÙÙÙ Ø¬Ù ÙØ¹ Ø§ÙØ¥Ø¹Ø¯Ø§Ø¯Ø§Øª', 206 screenReader: 'ÙØ±Ø§Ø¡Ø© Ø¨ØµÙØª عاÙÙ', voiceCommand: 'أ٠ر ØµÙØªÙ', textSpacing: 'تباعد اÙÙØµ', pauseAnimations: 'Ø¥ÙÙØ§Ù Ø§ÙØØ±ÙØ§Øª', hideImages: 'Ø¥Ø®ÙØ§Ø¡ Ø§ÙØµÙر', 207 dyslexiaFriendly: 'Ù ÙØ§Ø³Ø¨ ÙØ¹Ø³Ø± اÙÙØ±Ø§Ø¡Ø©', biggerCursor: '٠ؤشر ÙØ¨Ùر', lineHeight: 'Ø§Ø±ØªÙØ§Ø¹ Ø§ÙØ³Ø·Ø±', fontSelection: 'Ø§Ø®ØªÙØ§Ø± Ø§ÙØ®Ø·', colorFilter: 'Ù Ø±Ø´Ø Ø§ÙØ£ÙÙØ§Ù', 208 textAlign: 'Ù ØØ§Ø°Ø§Ø© اÙÙØµ', textSize: 'ØØ¬Ù اÙÙØµ', highContrast: 'تباÙ٠عاÙÙ', default: 'Ø§ÙØªØ±Ø§Ø¶Ù', screenReaderOn: 'اÙÙØ±Ø§Ø¡Ø© Ø¨ØµÙØª عاÙÙ Ù ÙØ¹ÙÙØ©', screenReaderOff: 'اÙÙØ±Ø§Ø¡Ø© Ø¨ØµÙØª عاÙ٠٠تÙÙÙØ©', 209 voiceControlActivated: 'ØªÙ ØªÙØ¹ÙÙ Ø§ÙØªØÙÙ Ø§ÙØµÙتÙ', notSupportedBrowser: 'ØºÙØ± ٠دعÙÙ ÙÙ ÙØ°Ø§ اÙÙ ØªØµÙØ', close: 'Ø¥ØºÙØ§Ù', reset: 'إعادة تعÙÙÙ', 210 saturation: 'Ø§ÙØªØ´Ø¨Ø¹', navigatePageStructure: 'Ø§ÙØªÙÙÙ ØØ³Ø¨ بÙÙØ© Ø§ÙØµÙØØ©', landmarks: '٠عاÙÙ ', headings: 'Ø¹ÙØ§ÙÙÙ', links: 'Ø±ÙØ§Ø¨Ø·', 211 noItemsFound: 'ÙÙ ÙØªÙ Ø§ÙØ¹Ø«Ùر عÙÙ Ø¹ÙØ§ØµØ±', focus: 'ترÙÙØ²', cursor: '٠ؤشر', highlight: 'ت٠ÙÙØ²', contrast: 'تباÙÙ', colorShift: 'تØÙÙÙ Ø§ÙØ£ÙÙØ§Ù', 212 animation: 'ØØ±ÙØ©', spacing: 'تباعد', font: 'خط', guide: 'دÙÙÙ', window: 'ÙØ§Ùذة', images: 'ØµÙØ±', showShortcuts: 'Ø¥Ø¸ÙØ§Ø± Ø§ÙØ§Ø®ØªØµØ§Ø±Ø§Øª', 213 additionalShortcuts: 'اختصارات ÙÙØØ© Ù ÙØ§ØªÙØ Ø¥Ø¶Ø§ÙÙØ©', resetVisualToolkit: 'إعادة تعÙÙÙ Ø§ÙØ£Ø¯Ùات اÙÙ Ø±Ø¦ÙØ©', resetIssue: 'إعادة تعÙÙÙ Ø§ÙØªÙ ÙÙØ²', 214 profiles: 'Ù ÙÙØ§Øª Ø¥Ù ÙØ§ÙÙØ© اÙÙØµÙÙ', profileSeizure: 'آ٠٠٠٠اÙÙÙØ¨Ø§Øª', profileVision: 'Ø¶Ø¹Ù Ø§ÙØ¨ØµØ±', profileAdhd: 'Ù ÙØ§Ø³Ø¨ ÙÙØ±Ø· Ø§ÙØØ±ÙØ©', profileDyslexia: 'عسر اÙÙØ±Ø§Ø¡Ø©', 215 align: 'Ù ØØ§Ø°Ø§Ø©', voice: 'ØµÙØª', altText: 'ÙØµ بدÙÙ', noAltText: 'ÙØ§ ÙÙØ¬Ø¯ ÙØµ بدÙÙ' 216 }, 217 hi: { 218 accessibilityMenu: 'सà¥à¤à¤®à¥à¤¯à¤¤à¤¾ मà¥à¤¨à¥', closeAccessibilityMenu: 'सà¥à¤à¤®à¥à¤¯à¤¤à¤¾ मà¥à¤¨à¥ बà¤à¤¦ à¤à¤°à¥à¤', resetAllSettings: 'सà¤à¥ सà¥à¤à¤¿à¤à¤à¥à¤¸ रà¥à¤¸à¥à¤ à¤à¤°à¥à¤', 219 screenReader: 'à¤à¤¼à¥à¤° सॠपढ़à¥à¤', voiceCommand: 'वà¥à¤à¤¸ à¤à¤®à¤¾à¤à¤¡', textSpacing: 'à¤à¥à¤à¥à¤¸à¥à¤ सà¥à¤ªà¥à¤¸à¤¿à¤à¤', pauseAnimations: 'à¤à¤¨à¤¿à¤®à¥à¤¶à¤¨ रà¥à¤à¥à¤', hideImages: 'à¤à¤¿à¤¤à¥à¤° à¤à¤¿à¤ªà¤¾à¤à¤', 220 dyslexiaFriendly: 'डिसà¥à¤²à¥à¤à¥à¤¸à¤¿à¤¯à¤¾ ठनà¥à¤à¥à¤²', biggerCurs
220or: 'बड़ा à¤à¤°à¥à¤¸à¤°', lineHeight: 'पà¤à¤à¥à¤¤à¤¿ à¤à¤à¤à¤¾à¤', fontSelection: 'फ़à¥à¤¨à¥à¤ à¤à¤¯à¤¨', colorFilter: 'रà¤à¤ फ़िलà¥à¤à¤°', 221 textAlign: 'à¤à¥à¤à¥à¤¸à¥à¤ सà¤à¤°à¥à¤à¤£', textSize: 'à¤à¥à¤à¥à¤¸à¥à¤ à¤à¤à¤¾à¤°', highContrast: 'à¤à¤à¥à¤ à¤à¤à¤à¥à¤°à¤¾à¤¸à¥à¤', default: 'डिफ़à¥à¤²à¥à¤', screenReaderOn: 'à¤à¤¼à¥à¤° सॠपढ़ना à¤à¤¾à¤²à¥', screenReaderOff: 'à¤à¤¼à¥à¤° सॠपढ़ना बà¤à¤¦', 222 voiceControlActivated: 'वà¥à¤à¤¸ नियà¤à¤¤à¥à¤°à¤£ सà¤à¥à¤°à¤¿à¤¯', notSupportedBrowser: 'à¤à¤¸ बà¥à¤°à¤¾à¤à¤à¤¼à¤° मà¥à¤ समरà¥à¤¥à¤¿à¤¤ नहà¥à¤ हà¥', close: 'बà¤à¤¦ à¤à¤°à¥à¤', reset: 'रà¥à¤¸à¥à¤', 223 saturation: 'सà¤à¤¤à¥à¤ªà¥à¤¤à¤¿', navigatePageStructure: 'पà¥à¤·à¥à¤ सà¤à¤°à¤à¤¨à¤¾ सॠनà¥à¤µà¤¿à¤à¥à¤ à¤à¤°à¥à¤', landmarks: 'लà¥à¤à¤¡à¤®à¤¾à¤°à¥à¤', headings: 'शà¥à¤°à¥à¤·à¤', links: 'लिà¤à¤', 224 noItemsFound: 'à¤à¥à¤ à¤à¤à¤à¤® नहà¥à¤ मिला', focus: 'फ़à¥à¤à¤¸', cursor: 'à¤à¤°à¥à¤¸à¤°', highlight: 'हाà¤à¤²à¤¾à¤à¤', contrast: 'à¤à¤à¤à¥à¤°à¤¾à¤¸à¥à¤', colorShift: 'रà¤à¤ परिवरà¥à¤¤à¤¨', 225 animation: 'à¤à¤¨à¤¿à¤®à¥à¤¶à¤¨', spacing: 'सà¥à¤ªà¥à¤¸à¤¿à¤à¤', font: 'फ़à¥à¤¨à¥à¤', guide: 'à¤à¤¾à¤à¤¡', window: 'विà¤à¤¡à¥', images: 'à¤à¤¿à¤¤à¥à¤°', showShortcuts: 'शà¥à¤°à¥à¤à¤à¤ दिà¤à¤¾à¤à¤', 226 additionalShortcuts: 'ठतिरिà¤à¥à¤¤ à¤à¥à¤¬à¥à¤°à¥à¤¡ शà¥à¤°à¥à¤à¤à¤', resetVisualToolkit: 'विà¤à¤¼à¥à¤ ल à¤à¥à¤²à¤à¤¿à¤ रà¥à¤¸à¥à¤ à¤à¤°à¥à¤', resetIssue: 'हाà¤à¤²à¤¾à¤à¤ रà¥à¤¸à¥à¤ à¤à¤°à¥à¤', 227 profiles: 'सà¥à¤à¤®à¥à¤¯à¤¤à¤¾ पà¥à¤°à¥à¤«à¤¼à¤¾à¤à¤²', profileSeizure: 'दà¥à¤°à¤¾-सà¥à¤°à¤à¥à¤·à¤¿à¤¤', profileVision: 'à¤à¤® दà¥à¤·à¥à¤à¤¿', profileAdhd: 'ADHD ठनà¥à¤à¥à¤²', profileDyslexia: 'डिसà¥à¤²à¥à¤à¥à¤¸à¤¿à¤¯à¤¾', 228 align: 'सà¤à¤°à¥à¤à¤¿à¤¤ à¤à¤°à¥à¤', voice: 'à¤à¤µà¤¾à¤à¤¼', altText: 'वà¥à¤à¤²à¥à¤ªà¤¿à¤ à¤à¥à¤à¥à¤¸à¥à¤', noAltText: 'वà¥à¤à¤²à¥à¤ªà¤¿à¤ à¤à¥à¤à¥à¤¸à¥à¤ नहà¥à¤ हà¥' 229 }, 230 zh: { 231 accessibilityMenu: 'æ éç¢èå', closeAccessibilityMenu: 'å ³éæ éç¢èå', resetAllSettings: 'éç½®ææè®¾ç½®', 232 screenReader: 'æè¯»', voiceCommand: 'è¯é³æä»¤', textSpacing: 'æåé´è·', pauseAnimations: 'æåå¨ç»', hideImages: 'éèå¾ç', 233 dyslexiaFriendly: 'é 读éç¢å好', biggerCursor: 'å¤§å æ ', lineHeight: 'è¡é«', fontSelection: 'åä½éæ©', colorFilter: 'è²å½©æ»¤é', 234 textAlign: 'ææ¬å¯¹é½', textSize: 'æå大å°', highContrast: 'é«å¯¹æ¯åº¦', default: 'é»è®¤', screenReaderOn: 'æè¯»å·²å¼å¯', screenReaderOff: 'æè¯»å·²å ³é', 235 voiceControlActivated: 'è¯é³æ§å¶å·²å¯ç¨', notSupportedBrowser: '卿¤æµè§å¨ä¸ä¸åæ¯æ', close: 'å ³é', reset: 'éç½®', 236 saturation: '饱å度', navigatePageStructure: 'æé¡µé¢ç»æå¯¼èª', landmarks: 'å°æ ', headings: 'æ é¢', links: '龿¥', 237 noItemsFound: 'æªæ¾å°é¡¹ç®', focus: 'ç¦ç¹', cursor: 'å æ ', highlight: 'é«äº®', contrast: '对æ¯åº¦', colorShift: 'è²å½©åç§»', 238 animation: 'å¨ç»', spacing: 'é´è·', font: 'åä½', guide: 'é 读æå¼', window: 'é 读çªå£', images: 'å¾ç', showShortcuts: 'æ¾ç¤ºå¿«æ·é®', 239 additionalShortcuts: 'æ´å¤é®çå¿«æ·é®', resetVisualToolkit: 'éç½®è§è§å·¥å ·å ', resetIssue: 'éç½®é«äº®', 240 profiles: 'æ éç¢é ç½®', profileSeizure: 'ç«ç«å®å ¨', profileVision: 'ä½è§å', profileAdhd: 'ADHD å好', profileDyslexia: 'é 读éç¢', 241 align: '对é½', voice: 'è¯é³', altText: 'æ¿ä»£ææ¬', noAltText: 'ç¼ºå°æ¿ä»£ææ¬' 242 }, 243 ja: { 244 accessibilityMenu: 'ã¢ã¯ã»ã·ããªãã£ã¡ãã¥ã¼', closeAccessibilityMenu: 'ã¢ã¯ã»ã·ããªãã£ã¡ãã¥ã¼ãéãã', resetAllSettings: 'ãã¹ã¦ã®è¨å®ããªã»ãã', 245 screenReader: 'èªã¿ä¸ã', voiceCommand: 'é³å£°ã³ãã³ã', textSpacing: 'æåéé', pauseAnimations: 'ã¢ãã¡ã¼ã·ã§ã³åæ¢', hideImages: 'ç»åãé表示',
246 dyslexiaFriendly: 'ãã£ã¹ã¬ã¯ã·ã¢å¯¾å¿', biggerCursor: '大ããã«ã¼ã½ã«', lineHeight: 'è¡ã®é«ã', fontSelection: 'ãã©ã³ã鏿', colorFilter: 'ã«ã©ã¼ãã£ã«ã¿ã¼', 247 textAlign: 'ããã¹ãé ç½®', textSize: 'æåãµã¤ãº', highContrast: 'ãã¤ã³ã³ãã©ã¹ã', default: 'ããã©ã«ã', screenReaderOn: 'èªã¿ä¸ããªã³', screenReaderOff: 'èªã¿ä¸ããªã', 248 voiceControlActivated: 'é³å£°æä½ãæå¹', notSupportedBrowser: 'ã¯ãã®ãã©ã¦ã¶ã§ã¯å¯¾å¿ãã¦ãã¾ãã', close: 'éãã', reset: 'ãªã»ãã', 249 saturation: '彩度', navigatePageStructure: 'ãã¼ã¸æ§é ã§ããã²ã¼ã', landmarks: 'ã©ã³ããã¼ã¯', headings: 'è¦åºã', links: 'ãªã³ã¯', 250 noItemsFound: 'é ç®ãè¦ã¤ããã¾ãã', focus: 'ãã©ã¼ã«ã¹', cursor: 'ã«ã¼ã½ã«', highlight: 'ãã¤ã©ã¤ã', contrast: 'ã³ã³ãã©ã¹ã', colorShift: 'è²å¤æ', 251 animation: 'ã¢ãã¡ã¼ã·ã§ã³', spacing: 'éé', font: 'ãã©ã³ã', guide: 'ã¬ã¤ã', window: 'ã¦ã£ã³ãã¦', images: 'ç»å', showShortcuts: 'ã·ã§ã¼ãã«ãã表示', 252 additionalShortcuts: 'ãã®ä»ã®ãã¼ãã¼ãã·ã§ã¼ãã«ãã', resetVisualToolkit: 'ãã¸ã¥ã¢ã«ãã¼ã«ããªã»ãã', resetIssue: 'ãã¤ã©ã¤ãããªã»ãã', 253 profiles: 'ã¢ã¯ã»ã·ããªãã£ãããã¡ã¤ã«', profileSeizure: 'çºä½å¯¾ç', profileVision: 'ãã¼ãã¸ã§ã³', profileAdhd: 'ADHD 対å¿', profileDyslexia: 'ãã£ã¹ã¬ã¯ã·ã¢', 254 align: 'é ç½®', voice: 'é³å£°', altText: '代æ¿ããã¹ã', noAltText: '代æ¿ããã¹ããªã' 255 }, 256 pt: { 257 accessibilityMenu: 'Menu de acessibilidade', closeAccessibilityMenu: 'Fechar menu de acessibilidade', resetAllSettings: 'Redefinir todas as configurações', 258 screenReader: 'Ler em voz alta', voiceCommand: 'Comando de voz', textSpacing: 'Espaçamento do texto', pauseAnimations: 'Pausar animações', hideImages: 'Ocultar imagens', 259 dyslexiaFriendly: 'Adequado para dislexia', biggerCursor: 'Cursor grande', lineHeight: 'Altura da linha', fontSelection: 'Seleção de fonte', colorFilter: 'Filtro de cor', 260 textAlign: 'Alinhamento do texto', textSize: 'Tamanho do texto', highContrast: 'Alto contraste', default: 'Padrão', screenReaderOn: 'Leitura em voz alta ativada', screenReaderOff: 'Leitura em voz alta desativada', 261 voiceControlActivated: 'Controle por voz ativado', notSupportedBrowser: 'não é compatÃvel com este navegador', close: 'Fechar', reset: 'Redefinir', 262 saturation: 'Saturação', navigatePageStructure: 'Navegar pela estrutura da página', landmarks: 'Marcos', headings: 'TÃtulos', links: 'Links', 263 noItemsFound: 'Nenhum item encontrado', focus: 'Foco', cursor: 'Cursor', highlight: 'Destacar', contrast: 'Contraste', colorShift: 'Mudança de cor', 264 animation: 'Animação', spacing: 'Espaçamento', font: 'Fonte', guide: 'Guia', window: 'Janela', images: 'Imagens', showShortcuts: 'Mostrar atalhos', 265 additionalShortcuts: 'Atalhos de teclado adicionais', resetVisualToolkit: 'Redefinir kit visual', resetIssue: 'Redefinir destaque', 266 profiles: 'Perfis de acessibilidade', profileSeizure: 'Seguro contra convulsões', profileVision: 'Baixa visão', profileAdhd: 'Adequado para TDAH', profileDyslexia: 'Dislexia', 267 align: 'Alinhar', voice: 'Voz', altText: 'Texto alternativo', noAltText: 'Sem texto alternativo' 268 }, 269 bn: { 270 accessibilityMenu: 'ঠà§à¦¯à¦¾à¦à§à¦¸à§à¦¸à¦¿à¦¬à¦¿à¦²à¦¿à¦à¦¿ মà§à¦¨à§', closeAccessibilityMenu: 'ঠà§à¦¯à¦¾à¦à§à¦¸à§à¦¸à¦¿à¦¬à¦¿à¦²à¦¿à¦à¦¿ মà§à¦¨à§ বনà§à¦§ à¦à¦°à§à¦¨', resetAllSettings: 'সব সà§à¦à¦¿à¦à¦¸ রিসà§à¦ à¦à¦°à§à¦¨', 271 screenReader: 'à¦à§à¦°à§ পড়à§à¦¨', voiceCommand: 'à¦à¦¯à¦¼à§à¦¸ à¦à¦®à¦¾à¦¨à§à¦¡', textSpacing: 'à¦à§à¦à§à¦¸à¦ সà§à¦ªà§à¦¸à¦¿à¦', pauseAnimations: 'ঠà§à¦¯à¦¾à¦¨à¦¿à¦®à§à¦¶à¦¨ থামান', hideImages: 'à¦à¦¬à¦¿ লà§à¦à¦¾à¦¨', 272 dyslexiaFriendly: 'ডিসলà§à¦à§à¦¸à¦¿à¦¯à¦¼à¦¾-বানà§à¦§à¦¬', biggerCursor: 'বড় à¦à¦¾à¦°à§à¦¸à¦¾à¦°', lineHeight: 'লাà¦à¦¨à§à¦° à¦à¦à§à¦à¦¤à¦¾', fontSelection: 'ফনà§à¦ নিরà§à¦¬à¦¾à¦à¦¨', colorFilter: 'রঠফিলà§à¦à¦¾à¦°', 273 textAlign: 'à¦à§à¦à§à¦¸à¦ সারিবদà§à¦§à¦à¦°à¦£', textSize: 'à¦à§à¦à§à¦¸à¦à§à¦° à¦à¦à¦¾à¦°', highContrast: 'à¦à¦à§à¦ à¦à¦¨à¦à§à¦°à¦¾à¦¸à§à¦', default: 'ডিফলà§à¦', screenReaderOn: 'à¦à§à¦°à§ পড়া à¦à¦¾à¦²à§', screenReaderOff: 'à¦à§à¦°à§ পড়া বনà§à¦§', 274 voiceControlActivated: 'à¦à¦¯à¦¼à§à¦¸ নিয়নà§à¦¤à§à¦°à¦£ সà¦à§à¦°à¦¿à¦¯à¦¼', notSupportedBrowser: 'à¦à¦ বà§à¦°à¦¾à¦à¦à¦¾à¦°à§ সমরà§à¦¥à¦¿à¦¤ নয়', close: 'বনà§à¦§ à¦à¦°à§à¦¨', reset: 'রিসà§à¦', 275 saturation: 'সà§à¦¯à¦¾à¦à§à¦°à§à¦¶à¦¨', navigatePageStructure: 'পà§à¦·à§à¦ ার à¦à¦¾à¦ ামৠঠনà§à¦¯à¦¾à¦¯à¦¼à§ নà§à¦à¦¿à¦à§à¦ à¦à¦°à§à¦¨', landmarks: 'লà§à¦¯à¦¾à¦¨à§à¦¡à¦®à¦¾à¦°à§à¦', headings: 'শিরà§à¦¨à¦¾à¦®', links: 'লিà¦à¦', 276 noItemsFound: 'à¦à§à¦¨à§ à¦à¦à¦à§à¦® পাà¦à¦¯à¦¼à¦¾ যায়নি', focus: 'ফà§à¦à¦¾à¦¸', cursor: 'à¦à¦¾à¦°à§à¦¸à¦¾à¦°', highlight: 'হাà¦à¦²à¦¾à¦à¦', contrast: 'à¦à¦¨à¦à§à¦°à¦¾à¦¸à§à¦', colorShift: 'রঠপরিবরà§à¦¤à¦¨', 277 animation: 'ঠà§à¦¯à¦¾à¦¨à¦¿à¦®à§à¦¶à¦¨', spacing: 'সà§à¦ªà§à¦¸à¦¿à¦', font: 'ফনà§à¦', guide: 'à¦à¦¾à¦à¦¡', window: 'à¦à¦à¦¨à§à¦¡à§', images: 'à¦à¦¬à¦¿', showShortcuts: 'শরà§à¦à¦à¦¾à¦ দà§à¦à¦¾à¦¨', 278 additionalShortcuts: 'ঠতিরিà¦à§à¦¤ à¦à§à¦¬à§à¦°à§à¦¡ শরà§à¦à¦à¦¾à¦', resetVisualToolkit: 'à¦à¦¿à¦à§à¦¯à§à¦¯à¦¼à¦¾à¦² à¦à§à¦²à¦à¦¿à¦ রিসà§à¦ à¦à¦°à§à¦¨', resetIssue: 'হাà¦à¦²à¦¾à¦à¦ রিসà§à¦ à¦à¦°à§à¦¨', 279 profiles: 'ঠà§à¦¯à¦¾à¦à§à¦¸à§à¦¸à¦¿à¦¬à¦¿à¦²à¦¿à¦à¦¿ পà§à¦°à§à¦«à¦¾à¦à¦²', profileSeizure: 'à¦à¦¿à¦à¦à§à¦¨à¦¿-নিরাপদ', profileVision: 'à¦à§à¦·à§à¦£ দà§à¦·à§à¦à¦¿', profileAdhd: 'ADHD-বানà§à¦§à¦¬', profileDyslexia: 'ডিসলà§à¦à§à¦¸à¦¿à¦¯à¦¼à¦¾', 280 align: 'সারিবদà§à¦§ à¦à¦°à§à¦¨', voice: 'à¦à¦¯à¦¼à§à¦¸', altText: 'বিà¦à¦²à§à¦ª à¦à§à¦à§à¦¸à¦', noAltText: 'বিà¦à¦²à§à¦ª à¦à§à¦à§à¦¸à¦ নà§à¦' 281 }, 282 ko: { 283 accessibilityMenu: 'ì ê·¼ì± ë©ë´', closeAccessibilityMenu: 'ì ê·¼ì± ë©ë´ ë«ê¸°', resetAllSettings: '모ë ì¤ì ì´ê¸°í', 284 screenReader: 'ì리 ë´ì´ ì½ê¸°', voiceCommand: 'ìì± ëª ë ¹', textSpacing: 'í ì¤í¸ ê°ê²©', pauseAnimations: 'ì ëë©ì´ì ì¼ìì ì§', hideImages: 'ì´ë¯¸ì§ ì¨ê¸°ê¸°',
285 dyslexiaFriendly: 'ëë ì¦ ì¹í', biggerCursor: 'í° ì»¤ì', lineHeight: 'ì¤ ëì´', fontSelection: 'ê¸ê¼´ ì í', colorFilter: 'ìì íí°', 286 textAlign: 'í ì¤í¸ ì ë ¬', textSize: 'í ì¤í¸ í¬ê¸°', highContrast: 'ê³ ëë¹', default: '기본ê°', screenReaderOn: 'ì리 ë´ì´ ì½ê¸° ì¼ì§', screenReaderOff: 'ì리 ë´ì´ ì½ê¸° 꺼ì§', 287 voiceControlActivated: 'ìì± ì ì´ íì±íë¨', notSupportedBrowser: 'ì´ ë¸ë¼ì°ì ìì ì§ìëì§ ììµëë¤', close: 'ë«ê¸°', reset: 'ì´ê¸°í', 288 saturation: 'ì±ë', navigatePageStructure: 'íì´ì§ êµ¬ì¡°ë¡ íì', landmarks: 'ëëë§í¬', headings: 'ì 목', links: 'ë§í¬', 289 noItemsFound: 'í목ì ì°¾ì ì ììµëë¤', focus: 'í¬ì»¤ì¤', cursor: '커ì', highlight: 'ê°ì¡°', contrast: 'ëë¹', colorShift: 'ìì ë³í', 290 animation: 'ì ëë©ì´ì ', spacing: 'ê°ê²©', font: 'ê¸ê¼´', guide: 'ê°ì´ë', window: 'ì°½', images: 'ì´ë¯¸ì§', showShortcuts: 'ë¨ì¶í¤ íì', 291 additionalShortcuts: 'ì¶ê° í¤ë³´ë ë¨ì¶í¤', resetVisualToolkit: 'ìê° ë구 ì´ê¸°í', resetIssue: 'ê°ì¡° ì´ê¸°í', 292 profiles: 'ì ê·¼ì± íë¡í', profileSeizure: 'ë°ì ìì ', profileVision: 'ì ìë ¥', profileAdhd: 'ADHD ì¹í', profileDyslexia: 'ëë ì¦', 293 align: 'ì ë ¬', voice: 'ìì±', altText: 'ëì²´ í ì¤í¸', noAltText: 'ëì²´ í ì¤í¸ ìì' 294 }, 295 vi: { 296 accessibilityMenu: 'Menu trợ nÄng', closeAccessibilityMenu: 'Äóng menu trợ nÄng', resetAllSettings: 'Äặt lại tất cả cà i Äặt', 297 screenReader: 'Äá»c to', voiceCommand: 'Lá»nh thoại', textSpacing: 'Giãn cách chữ', pauseAnimations: 'Tạm dừng hoạt ảnh', hideImages: 'Ẩn hình ảnh', 298 dyslexiaFriendly: 'Thân thiá»n vá»i chứng khó Äá»c', biggerCursor: 'Con trá» lá»n', lineHeight: 'Chiá»u cao dòng', fontSelection: 'Chá»n phông chữ', colorFilter: 'Bá» lá»c mà u', 299 textAlign: 'CÄn chá»nh vÄn bản', textSize: 'Cỡ chữ', highContrast: 'Tương phản cao', default: 'Mặc Äá»nh', screenReaderOn: 'Äã báºt Äá»c to', screenReaderOff: 'Äã tắt Äá»c to', 300 voiceControlActivated: 'Äã kÃch hoạt Äiá»u khiá»n giá»ng nói', notSupportedBrowser: 'không ÄÆ°á»£c há» trợ trên trình duyá»t nà y', close: 'Äóng', reset: 'Äặt lại', 301 saturation: 'Äá» bão hòa', navigatePageStructure: 'Äiá»u hưá»ng theo cấu trúc trang', landmarks: 'Má»c trang', headings: 'Tiêu Äá»', links: 'Liên kết', 302 noItemsFound: 'Không tìm thấy mục nà o', focus: 'Tiêu Äiá»m', cursor: 'Con trá»', highlight: 'Tô sáng', contrast: 'Tương phản', colorShift: 'Äá»i mà u', 303 animation: 'Hoạt ảnh', spacing: 'Giãn cách', font: 'Phông chữ', guide: 'Thưá»c Äá»c', window: 'Cá»a sá» Äá»c', images: 'Hình ảnh', showShortcuts: 'Hiá»n phÃm tắt', 304 additionalShortcuts: 'PhÃm tắt bá» sung', resetVisualToolkit: 'Äặt lại công cụ hiá»n thá»', resetIssue: 'Äặt lại tô sáng', 305 profiles: 'Há» sÆ¡ trợ nÄng', profileSeizure: 'An toà n co giáºt', profileVision: 'Thá» lá»±c kém', profileAdhd: 'Thân thiá»n ADHD', profileDyslexia: 'Chứng khó Äá»c', 306 align: 'CÄn chá»nh', voice: 'Giá»ng nói', altText: 'VÄn bản thay thế', noAltText: 'Thiếu vÄn bản thay thế' 307 }, 308 id: { 309 accessibilityMenu: 'Menu Aksesibilitas', closeAccessibilityMenu: 'Tutup menu aksesibilitas', resetAllSettings: 'Atur ulang semua pengaturan', 310 screenReader: 'Baca Nyaring', voiceCommand: 'Perintah Suara', textSpacing: 'Jarak Teks', pauseAnimations: 'Jeda Animasi', hideImages: 'Sembunyikan Gambar', 311 dyslexiaFriendly: 'Ramah Disleksia', biggerCursor: 'Kursor Besar', lineHeight: 'Tinggi Baris', fontSelection: 'Pilihan Font', colorFilter: 'Filter Warna', 312 textAlign: 'Perataan Teks', textSize: 'Ukuran Teks', highContrast: 'Kontras Tinggi', default: 'Bawaan', screenReaderOn: 'Baca nyaring aktif', screenReaderOff: 'Baca nyaring nonaktif', 313 voiceControlActivated: 'Kontrol suara diaktifkan', notSupportedBrowser: 'tidak didukung di peramban ini', close: 'Tutup', reset: 'Atur ulang', 314 saturation: 'Saturasi', navigatePageStructure: 'Navigasi menurut struktur halaman', landmarks: 'Penanda', headings: 'Judul', links: 'Tautan', 315 noItemsFound: 'Tidak ada item ditemukan', focus: 'Fokus', cursor: 'Kursor', highlight: 'Sorot', contrast: 'Kontras', colorShift: 'Pergeseran Warna', 316 animation: 'Animasi', spacing: 'Jarak', font: 'Font', guide: 'Panduan', window: 'Jendela', images: 'Gambar', showShortcuts: 'Tampilkan pintasan', 317 additionalShortcuts: 'Pintasan keyboard tambahan', resetVisualToolkit: 'Atur ulang perangkat visual', resetIssue: 'Atur ulang sorotan', 318 profiles: 'Profil Aksesibilitas', profileSeizure: 'Aman Kejang', profileVision: 'Penglihatan Rendah', profileAdhd: 'Ramah ADHD', profileDyslexia: 'Disleksia', 319 align: 'Ratakan', voice: 'Suara', altText: 'Teks Alternatif', noAltText: 'Tidak ada teks alternatif' 320 }, 321 th: { 322 accessibilityMenu: 'à¹à¸¡à¸à¸¹à¸à¸²à¸£à¸à¹à¸§à¸¢à¸à¸²à¸£à¹à¸à¹à¸²à¸à¸¶à¸', closeAccessibilityMenu: 'à¸à¸´à¸à¹à¸¡à¸à¸¹à¸à¸²à¸£à¸à¹à¸§à¸¢à¸à¸²à¸£à¹à¸à¹à¸²à¸à¸¶à¸', resetAllSettings: 'รีà¹à¸à¹à¸à¸à¸²à¸£à¸à¸±à¹à¸à¸à¹à¸²à¸à¸±à¹à¸à¸«à¸¡à¸', 323 screenReader: 'à¸à¹à¸²à¸à¸à¸à¸à¹à¸ªà¸µà¸¢à¸', voiceCommand: 'à¸à¸³à¸ªà¸±à¹à¸à¹à¸ªà¸µà¸¢à¸', textSpacing: 'ระยะหà¹à¸²à¸à¸à¹à¸à¸à¸§à¸²à¸¡', pauseAnimations: 'หยุà¸à¹à¸à¸à¸´à¹à¸¡à¸à¸±à¸', hideImages: 'à¸à¹à¸à¸à¸£à¸¹à¸à¸ าà¸', 324 dyslexiaFriendly: 'à¹à¸«à¸¡à¸²à¸°à¸ªà¸³à¸«à¸£à¸±à¸à¸à¸¹à¹à¸à¸
324à¸à¸£à¹à¸à¸à¸à¹à¸²à¸à¸à¸²à¸£à¸à¹à¸²à¸', biggerCursor: 'à¹à¸à¸à¸£à¹à¹à¸à¸à¸£à¹à¹à¸«à¸à¹', lineHeight: 'à¸à¸§à¸²à¸¡à¸ªà¸¹à¸à¸à¸£à¸£à¸à¸±à¸', fontSelection: 'à¹à¸¥à¸·à¸à¸à¹à¸à¸à¸à¸±à¸à¸©à¸£', colorFilter: 'à¸à¸´à¸¥à¹à¸à¸à¸£à¹à¸ªà¸µ', 325 textAlign: 'à¸à¸²à¸£à¸à¸±à¸à¸à¹à¸à¸à¸§à¸²à¸¡', textSize: 'à¸à¸à¸²à¸à¸à¹à¸à¸à¸§à¸²à¸¡', highContrast: 'à¸à¸§à¸²à¸¡à¸à¹à¸²à¸à¸ªà¸µà¸ªà¸¹à¸', default: 'à¸à¹à¸²à¹à¸£à¸´à¹à¸¡à¸à¹à¸', screenReaderOn: 'à¹à¸à¸´à¸à¸à¸²à¸£à¸à¹à¸²à¸à¸à¸à¸à¹à¸ªà¸µà¸¢à¸', screenReaderOff: 'à¸à¸´à¸à¸à¸²à¸£à¸à¹à¸²à¸à¸à¸à¸à¹à¸ªà¸µà¸¢à¸', 326 voiceControlActivated: 'à¹à¸à¸´à¸à¹à¸à¹à¸à¸²à¸£à¸à¸§à¸à¸à¸¸à¸¡à¸à¹à¸§à¸¢à¹à¸ªà¸µà¸¢à¸', notSupportedBrowser: 'à¹à¸¡à¹à¸£à¸à¸à¸£à¸±à¸à¹à¸à¹à¸à¸£à¸²à¸§à¹à¹à¸à¸à¸£à¹à¸à¸µà¹', close: 'à¸à¸´à¸', reset: 'รีà¹à¸à¹à¸', 327 saturation: 'à¸à¸§à¸²à¸¡à¸à¸´à¹à¸¡à¸à¸±à¸§à¸à¸à¸à¸ªà¸µ', navigatePageStructure: 'à¸à¸³à¸à¸²à¸à¸à¸²à¸¡à¹à¸à¸£à¸à¸ªà¸£à¹à¸²à¸à¸«à¸à¹à¸²', landmarks: 'à¸à¸¸à¸à¸ªà¸±à¸à¹à¸à¸', headings: 'หัวà¸à¹à¸', links: 'ลิà¸à¸à¹', 328 noItemsFound: 'à¹à¸¡à¹à¸à¸à¸£à¸²à¸¢à¸à¸²à¸£', focus: 'à¹à¸à¸à¸±à¸ª', cursor: 'à¹à¸à¸à¸£à¹à¹à¸à¸à¸£à¹', highlight: 'à¹à¸®à¹à¸¥à¸à¹', contrast: 'à¸à¸§à¸²à¸¡à¸à¹à¸²à¸à¸ªà¸µ', colorShift: 'à¸à¸²à¸£à¹à¸à¸¥à¸µà¹à¸¢à¸à¸ªà¸µ', 329 animation: 'à¹à¸à¸à¸´à¹à¸¡à¸à¸±à¸', spacing: 'ระยะหà¹à¸²à¸', font: 'à¹à¸à¸à¸à¸±à¸à¸©à¸£', guide: 'à¹à¸ªà¹à¸à¸à¸³à¸ªà¸²à¸¢à¸à¸²', window: 'หà¸à¹à¸²à¸à¹à¸²à¸à¸à¹à¸²à¸', images: 'รูà¸à¸ าà¸', showShortcuts: 'à¹à¸ªà¸à¸à¸à¸¸à¹à¸¡à¸¥à¸±à¸', 330 additionalShortcuts: 'à¸à¸¸à¹à¸¡à¸¥à¸±à¸à¹à¸à¸´à¹à¸¡à¹à¸à¸´à¸¡', resetVisualToolkit: 'รีà¹à¸à¹à¸à¹à¸à¸£à¸·à¹à¸à¸à¸¡à¸·à¸à¸ าà¸', resetIssue: 'รีà¹à¸à¹à¸à¹à¸®à¹à¸¥à¸à¹', 331 profiles: 'à¹à¸à¸£à¹à¸à¸¥à¹à¸à¸²à¸£à¸à¹à¸§à¸¢à¸à¸²à¸£à¹à¸à¹à¸²à¸à¸¶à¸', profileSeizure: 'à¸à¸¥à¸à¸à¸ ัยà¸à¸²à¸à¸à¸²à¸à¸²à¸£à¸à¸±à¸', profileVision: 'สายà¸à¸²à¹à¸¥à¸·à¸à¸à¸£à¸²à¸', profileAdhd: 'à¹à¸«à¸¡à¸²à¸°à¸ªà¸³à¸«à¸£à¸±à¸ ADHD', profileDyslexia: 'à¸à¸à¸à¸£à¹à¸à¸à¸à¹à¸²à¸à¸à¸²à¸£à¸à¹à¸²à¸', 332 align: 'à¸à¸±à¸à¹à¸à¸§', voice: 'à¹à¸ªà¸µà¸¢à¸', altText: 'à¸à¹à¸à¸à¸§à¸²à¸¡à¹à¸à¸', noAltText: 'à¹à¸¡à¹à¸¡à¸µà¸à¹à¸à¸à¸§à¸²à¸¡à¹à¸à¸' 333 }, 334 pl: { 335 accessibilityMenu: 'Menu dostÄpnoÅci', closeAccessibilityMenu: 'Zamknij menu dostÄpnoÅci', resetAllSettings: 'Zresetuj wszystkie ustawienia', 336 screenReader: 'Czytaj na gÅos', voiceCommand: 'Polecenie gÅosowe', textSpacing: 'OdstÄpy tekstu', pauseAnimations: 'Wstrzymaj animacje', hideImages: 'Ukryj obrazy', 337 dyslexiaFriendly: 'Przyjazny dysleksji', biggerCursor: 'Duży kursor', lineHeight: 'WysokoÅÄ wiersza', fontSelection: 'Wybór czcionki', colorFilter: 'Filtr kolorów', 338 textAlign: 'Wyrównanie tekstu', textSize: 'Rozmiar tekstu', highContrast: 'Wysoki kontrast', default: 'DomyÅlne', screenReaderOn: 'Czytanie na gÅos wÅÄ czone', screenReaderOff: 'Czytanie na gÅos wyÅÄ czone', 339 voiceControlActivated: 'Sterowanie gÅosowe wÅÄ czone', notSupportedBrowser: 'nie jest obsÅugiwane w tej przeglÄ darce', close: 'Zamknij', reset: 'Resetuj', 340 saturation: 'Nasycenie', navigatePageStructure: 'Nawiguj wedÅug struktury strony', landmarks: 'Punkty orientacyjne', headings: 'NagÅówki', links: 'Linki', 341 noItemsFound: 'Nie znaleziono elementów', focus: 'Fokus', cursor: 'Kursor', highlight: 'PodÅwietl', contrast: 'Kontrast', colorShift: 'PrzesuniÄcie kolorów', 342 animation: 'Animacja', spacing: 'OdstÄpy', font: 'Czcionka', guide: 'Linijka', window: 'Okno', images: 'Obrazy', showShortcuts: 'Pokaż skróty', 343 additionalShortcuts: 'Dodatkowe skróty klawiszowe', resetVisualToolkit: 'Zresetuj narzÄdzia wizualne', resetIssue: 'Zresetuj podÅwietlenie', 344 profiles: 'Profile dostÄpnoÅci', profileSeizure: 'Bezpieczny dla epilepsji', profileVision: 'SÅabowidzÄ cy', profileAdhd: 'Przyjazny ADHD', profileDyslexia: 'Dysleksja', 345 align: 'Wyrównaj', voice: 'GÅos', altText: 'Tekst alternatywny', noAltText: 'Brak tekstu alternatywnego' 346 }, 347 nl: { 348 accessibilityMenu: 'Toegankelijkheidsmenu', closeAccessibilityMenu: 'Toegankelijkheidsmenu sluiten', resetAllSettings: 'Alle instellingen resetten', 349 screenReader: 'Voorlezen', voiceCommand: 'Spraakopdracht', textSpacing: 'Tekstafstand', pauseAnimations: 'Animaties pauzeren', hideImages: 'Afbeeldingen verbergen',
350 dyslexiaFriendly: 'Dyslexievriendelijk', biggerCursor: 'Grote cursor', lineHeight: 'Regelhoogte', fontSelection: 'Lettertypekeuze', colorFilter: 'Kleurfilter', 351 textAlign: 'Tekstuitlijning', textSize: 'Tekstgrootte', highContrast: 'Hoog contrast', default: 'Standaard', screenReaderOn: 'Voorlezen aan', screenReaderOff: 'Voorlezen uit', 352 voiceControlActivated: 'Spraakbediening geactiveerd', notSupportedBrowser: 'wordt niet ondersteund in deze browser', close: 'Sluiten', reset: 'Resetten', 353 saturation: 'Verzadiging', navigatePageStructure: 'Navigeren op paginastructuur', landmarks: 'Oriëntatiepunten', headings: 'Koppen', links: 'Links', 354 noItemsFound: 'Geen items gevonden', focus: 'Focus', cursor: 'Cursor', highlight: 'Markeren', contrast: 'Contrast', colorShift: 'Kleurverschuiving', 355 animation: 'Animatie', spacing: 'Afstand', font: 'Lettertype', guide: 'Leesliniaal', window: 'Leesvenster', images: 'Afbeeldingen', showShortcuts: 'Sneltoetsen tonen', 356 additionalShortcuts: 'Extra sneltoetsen', resetVisualToolkit: 'Visuele toolkit resetten', resetIssue: 'Markering resetten', 357 profiles: 'Toegankelijkheidsprofielen', profileSeizure: 'Epilepsieveilig', profileVision: 'Slechtziend', profileAdhd: 'ADHD-vriendelijk', profileDyslexia: 'Dyslexie', 358 align: 'Uitlijnen', voice: 'Stem', altText: 'Alt-tekst', noAltText: 'Alt-tekst ontbreekt' 359 }, 360 el: { 361 accessibilityMenu: 'ÎÎµÎ½Î¿Ï ÏÏοÏβαÏιμÏÏηÏαÏ', closeAccessibilityMenu: 'ÎλείÏιμο Î¼ÎµÎ½Î¿Ï ÏÏοÏβαÏιμÏÏηÏαÏ', resetAllSettings: 'ÎÏαναÏοÏά ÏλÏν ÏÏν ÏÏ Î¸Î¼Î¯ÏεÏν', 362 screenReader: 'ÎκÏÏνηÏη', voiceCommand: 'ΦÏνηÏική ενÏολή', textSpacing: 'ÎÏÏÏÏαÏη κειμÎÎ½Î¿Ï ', pauseAnimations: 'ΠαÏÏη κινήÏεÏν', hideImages: 'ÎÏÏκÏÏ Ïη εικÏνÏν', 363 dyslexiaFriendly: 'Î¦Î¹Î»Î¹ÎºÏ ÏÏÎ¿Ï Ïη Î´Ï Ïλεξία', biggerCursor: 'ÎÎµÎ³Î¬Î»Î¿Ï Î´ÎµÎ¯ÎºÏηÏ', lineHeight: 'ÎÏÎ¿Ï Î³ÏαμμήÏ', fontSelection: 'ÎÏιλογή γÏαμμαÏοÏειÏάÏ', colorFilter: 'ΦίλÏÏο ÏÏÏμαÏοÏ', 364 textAlign: 'ΣÏοίÏιÏη κειμÎÎ½Î¿Ï ', textSize: 'ÎÎÎ³ÎµÎ¸Î¿Ï ÎºÎµÎ¹Î¼ÎÎ½Î¿Ï ', highContrast: 'Î¥Ïηλή ανÏίθεÏη', default: 'Î ÏοεÏιλογή', screenReaderOn: 'ÎκÏÏνηÏη ενεÏγή', screenReaderOff: 'ÎκÏÏνηÏη ανενεÏγή', 365 voiceControlActivated: 'ΦÏνηÏικÏÏ ÎλεγÏÎ¿Ï ÎµÎ½ÎµÏγÏÏ', notSupportedBrowser: 'δεν Ï ÏοÏÏηÏίζεÏαι Ïε Î±Ï ÏÏ Ïο ÏÏÏγÏαμμα ÏεÏιήγηÏηÏ', close: 'ÎλείÏιμο', reset: 'ÎÏαναÏοÏά', 366 saturation: 'ÎοÏεÏμÏÏ', navigatePageStructure: 'ΠλοήγηÏη καÏά δομή ÏελίδαÏ', landmarks: 'ÎÏÏÏημα', headings: 'ÎÏικεÏαλίδεÏ', links: 'ΣÏνδεÏμοι', 367 noItemsFound: 'Îεν βÏÎθηκαν ÏÏοιÏεία', focus: 'ÎÏÏίαÏη', cursor: 'ÎείκÏηÏ', highlight: 'ÎÏιÏήμανÏη', contrast: 'ÎνÏίθεÏη', colorShift: 'ÎεÏαÏÏÏιÏη ÏÏÏμαÏοÏ', 368 animation: 'ÎίνηÏη', spacing: 'ÎÏÏÏÏαÏη', font: 'ÎÏαμμαÏοÏειÏά', guide: 'ÎδηγÏÏ', window: 'ΠαÏÎ¬Î¸Ï Ïο', images: 'ÎικÏνεÏ', showShortcuts: 'ÎμÏάνιÏη ÏÏ Î½ÏομεÏÏεÏν', 369 additionalShortcuts: 'Î ÏÏÏθεÏÎµÏ ÏÏ Î½ÏομεÏÏÎµÎ¹Ï ÏληκÏÏÎ¿Î»Î¿Î³Î¯Î¿Ï ', resetVisualToolkit: 'ÎÏαναÏοÏά οÏÏικÏν εÏγαλείÏν', resetIssue: 'ÎÏαναÏοÏά εÏιÏήμανÏηÏ', 370 profiles: 'Î ÏοÏίλ ÏÏοÏβαÏιμÏÏηÏαÏ', profileSeizure: 'ÎÏÏαλÎÏ Î³Î¹Î± εÏιληÏία', profileVision: 'ÎειÏμÎνη ÏÏαÏη', profileAdhd: 'Î¦Î¹Î»Î¹ÎºÏ ÏÏÎ¿Ï ÎÎΠΥ', profileDyslexia: 'ÎÏ Ïλεξία', 371 align: 'ΣÏοίÏιÏη', voice: 'ΦÏνή', altText: 'ÎναλλακÏÎ¹ÎºÏ ÎºÎµÎ¯Î¼ÎµÎ½Î¿', noAltText: 'ÎείÏει εναλλακÏÎ¹ÎºÏ ÎºÎµÎ¯Î¼ÎµÎ½Î¿' 372 }, 373 sv: { 374 accessibilityMenu: 'Tillgänglighetsmeny', closeAccessibilityMenu: 'Stäng tillgänglighetsmenyn', resetAllSettings: 'à terställ alla inställningar', 375 screenReader: 'Läs upp', voiceCommand: 'Röstkommando', textSpacing: 'TextavstÃ¥nd', pauseAnimations: 'Pausa animationer', hideImages: 'Dölj bilder',
376 dyslexiaFriendly: 'Dyslexivänlig', biggerCursor: 'Stor markör', lineHeight: 'Radhöjd', fontSelection: 'Typsnittsval', colorFilter: 'Färgfilter', 377 textAlign: 'Textjustering', textSize: 'Textstorlek', highContrast: 'Hög kontrast', default: 'Standard', screenReaderOn: 'Uppläsning pÃ¥', screenReaderOff: 'Uppläsning av', 378 voiceControlActivated: 'Röststyrning aktiverad', notSupportedBrowser: 'stöds inte i den här webbläsaren', close: 'Stäng', reset: 'à terställ', 379 saturation: 'Mättnad', navigatePageStructure: 'Navigera efter sidstruktur', landmarks: 'Landmärken', headings: 'Rubriker', links: 'Länkar', 380 noItemsFound: 'Inga objekt hittades', focus: 'Fokus', cursor: 'Markör', highlight: 'Markera', contrast: 'Kontrast', colorShift: 'Färgskifte', 381 animation: 'Animation', spacing: 'AvstÃ¥nd', font: 'Typsnitt', guide: 'Läslinjal', window: 'Läsfönster', images: 'Bilder', showShortcuts: 'Visa kortkommandon', 382 additionalShortcuts: 'Fler kortkommandon', resetVisualToolkit: 'à terställ visuella verktyg', resetIssue: 'à terställ markering', 383 profiles: 'Tillgänglighetsprofiler', profileSeizure: 'Anfallssäker', profileVision: 'Nedsatt syn', profileAdhd: 'ADHD-vänlig', profileDyslexia: 'Dyslexi', 384 align: 'Justera', voice: 'Röst', altText: 'Alt-text', noAltText: 'Alt-text saknas' 385 }, 386 no: { 387 accessibilityMenu: 'Tilgjengelighetsmeny', closeAccessibilityMenu: 'Lukk tilgjengelighetsmenyen', resetAllSettings: 'Tilbakestill alle innstillinger', 388 screenReader: 'Les høyt', voiceCommand: 'Talekommando', textSpacing: 'Tekstavstand', pauseAnimations: 'Pause animasjoner', hideImages: 'Skjul bilder', 389 dyslexiaFriendly: 'Dysleksivennlig', biggerCursor: 'Stor markør', lineHeight: 'Linjehøyde', fontSelection: 'Skriftvalg', colorFilter: 'Fargefilter', 390 textAlign: 'Tekstjustering', textSize: 'Tekststørrelse', highContrast: 'Høy kontrast', default: 'Standard', screenReaderOn: 'Høytlesing pÃ¥', screenReaderOff: 'Høytlesing av', 391 voiceControlActivated: 'Talestyring aktivert', notSupportedBrowser: 'støttes ikke i denne nettleseren', close: 'Lukk', reset: 'Tilbakestill', 392 saturation: 'Metning', navigatePageStructure: 'Naviger etter sidestruktur', landmarks: 'Landemerker', headings: 'Overskrifter', links: 'Lenker', 393 noItemsFound: 'Ingen elementer funnet', focus: 'Fokus', cursor: 'Markør', highlight: 'Uthev', contrast: 'Kontrast', colorShift: 'Fargeskifte', 394 animation: 'Animasjon', spacing: 'Avstand', font: 'Skrift', guide: 'Leselinjal', window: 'Lesevindu', images: 'Bilder', showShortcuts: 'Vis snarveier', 395 additionalShortcuts: 'Flere hurtigtaster', resetVisualToolkit: 'Tilbakestill visuelle verktøy', resetIssue: 'Tilbakestill utheving', 396 profiles: 'Tilgjengelighetsprofiler', profileSeizure: 'Anfallssikker', profileVision: 'Svaksynt', profileAdhd: 'ADHD-vennlig', profileDyslexia: 'Dysleksi', 397 align: 'Juster', voice: 'Stemme', altText: 'Alt-tekst', noAltText: 'Alt-tekst mangler' 398 }, 399 da: { 400 accessibilityMenu: 'Tilgængelighedsmenu', closeAccessibilityMenu: 'Luk tilgængelighedsmenuen', resetAllSettings: 'Nulstil alle indstillinger', 401 screenReader: 'Læs højt', voiceCommand: 'Stemmekommando', textSpacing: 'Tekstafstand', pauseAnimations: 'Sæt animationer pÃ¥ pause', hideImages: 'Skjul billeder', 402 dyslexiaFriendly: 'Ordblindevenlig', biggerCursor: 'Stor markør', lineHeight: 'Linjehøjde', fontSelection: 'Skriftvalg', colorFilter: 'Farvefilter', 403 textAlign: 'Tekstjustering', textSize: 'Tekststørrelse', highContrast: 'Høj kontrast', default: 'Standard', screenReaderOn: 'Højtlæsning til', screenReaderOff: 'Højtlæsning fra', 404 voiceControlActivated: 'Stemmestyring aktiveret', notSupportedBrowser: 'understøttes ikke i denne browser', close: 'Luk', reset: 'Nulstil', 405 saturation: 'Mætning', navigatePageStructure: 'Naviger efter sidestruktur', landmarks: 'Kendemærker', headings: 'Overskrifter', links: 'Links', 406 noItemsFound: 'Ingen elementer fundet', focus: 'Fokus', cursor: 'Markør', highlight: 'Fremhæv', contrast: 'Kontrast', colorShift: 'Farveskift', 407 animation: 'Animation', spacing: 'Afstand', font: 'Skrift', guide: 'Læselineal', window: 'Læsevindue', images: 'Billeder', showShortcuts: 'Vis genveje', 408 additionalShortcuts: 'Flere tastaturgenveje', resetVisualToolkit: 'Nulstil visuelle værktøjer', resetIssue: 'Nulstil fremhævning', 409 profiles: 'Tilgængelighedsprofiler', profileSeizure: 'Anfaldssikker', profileVision: 'Svagtseende', profileAdhd: 'ADHD-venlig', profileDyslexia: 'Ordblindhed', 410 align: 'Juster', voice: 'Stemme', altText: 'Alt-tekst', noAltText: 'Alt-tekst mangler' 411 }, 412 fi: { 413 accessibilityMenu: 'Saavutettavuusvalikko', closeAccessibilityMenu: 'Sulje saavutettavuusvalikko', resetAllSettings: 'Palauta kaikki asetukset', 414 screenReader: 'Lue ääneen', voiceCommand: 'Ãänikomento', textSpacing: 'Tekstin välistys', pauseAnimations: 'Pysäytä animaatiot', hideImages: 'Piilota kuvat',
415 dyslexiaFriendly: 'Lukihäiriöystävällinen', biggerCursor: 'Suuri kohdistin', lineHeight: 'Rivikorkeus', fontSelection: 'Fontin valinta', colorFilter: 'Värisuodatin', 416 textAlign: 'Tekstin tasaus', textSize: 'Tekstin koko', highContrast: 'Suuri kontrasti', default: 'Oletus', screenReaderOn: 'Ãäneen luku päällä', screenReaderOff: 'Ãäneen luku pois', 417 voiceControlActivated: 'Ãäniohjaus käytössä', notSupportedBrowser: 'ei ole tuettu tässä selaimessa', close: 'Sulje', reset: 'Palauta', 418 saturation: 'Kylläisyys', navigatePageStructure: 'Selaa sivun rakenteen mukaan', landmarks: 'Maamerkit', headings: 'Otsikot', links: 'Linkit', 419 noItemsFound: 'Kohteita ei löytynyt', focus: 'Kohdistus', cursor: 'Kohdistin', highlight: 'Korosta', contrast: 'Kontrasti', colorShift: 'Värinsiirto', 420 animation: 'Animaatio', spacing: 'Välistys', font: 'Fontti', guide: 'Lukuviiva', window: 'Lukuikkuna', images: 'Kuvat', showShortcuts: 'Näytä pikanäppäimet', 421 additionalShortcuts: 'Lisäpikanäppäimet', resetVisualToolkit: 'Palauta visuaaliset työkalut', resetIssue: 'Palauta korostus', 422 profiles: 'Saavutettavuusprofiilit', profileSeizure: 'Kohtausturvallinen', profileVision: 'Heikko näkö', profileAdhd: 'ADHD-ystävällinen', profileDyslexia: 'Lukihäiriö', 423 align: 'Tasaa', voice: 'Ãäni', altText: 'Vaihtoehtoinen teksti', noAltText: 'Vaihtoehtoinen teksti puuttuu' 424 }, 425 cs: { 426 accessibilityMenu: 'NabÃdka pÅÃstupnosti', closeAccessibilityMenu: 'ZavÅÃt nabÃdku pÅÃstupnosti', resetAllSettings: 'Obnovit vÅ¡echna nastavenÃ', 427 screenReader: 'ÄÃst nahlas', voiceCommand: 'Hlasový pÅÃkaz', textSpacing: 'Rozestupy textu', pauseAnimations: 'Pozastavit animace', hideImages: 'Skrýt obrázky', 428 dyslexiaFriendly: 'Vhodné pro dyslexii', biggerCursor: 'Velký kurzor', lineHeight: 'Výška Åádku', fontSelection: 'VýbÄr pÃsma', colorFilter: 'Barevný filtr', 429 textAlign: 'Zarovnánà textu', textSize: 'Velikost textu', highContrast: 'Vysoký kontrast', default: 'VýchozÃ', screenReaderOn: 'Ätenà nahlas zapnuto', screenReaderOff: 'Ätenà nahlas vypnuto', 430 voiceControlActivated: 'Hlasové ovládánà aktivováno', notSupportedBrowser: 'nenà v tomto prohlÞeÄi podporováno', close: 'ZavÅÃt', reset: 'Obnovit', 431 saturation: 'Sytost', navigatePageStructure: 'Navigace podle struktury stránky', landmarks: 'OrientaÄnà body', headings: 'Nadpisy', links: 'Odkazy', 432 noItemsFound: 'Nebyly nalezeny žádné položky', focus: 'ZamÄÅenÃ', cursor: 'Kurzor', highlight: 'Zvýraznit', contrast: 'Kontrast', colorShift: 'Posun barev', 433 animation: 'Animace', spacing: 'Rozestupy', font: 'PÃsmo', guide: 'VodÃtko', window: 'Okno', images: 'Obrázky', showShortcuts: 'Zobrazit zkratky', 434 additionalShortcuts: 'Dalšà klávesové zkratky', resetVisualToolkit: 'Obnovit vizuálnà nástroje', resetIssue: 'Obnovit zvýraznÄnÃ', 435 profiles: 'Profily pÅÃstupnosti', profileSeizure: 'BezpeÄné pÅi epilepsii', profileVision: 'Slabý zrak', profileAdhd: 'Vhodné pro ADHD', profileDyslexia: 'Dyslexie', 436 align: 'Zarovnat', voice: 'Hlas', altText: 'Alternativnà text', noAltText: 'Chybà alternativnà text' 437 }, 438 hu: { 439 accessibilityMenu: 'AkadálymentesÃtési menü', closeAccessibilityMenu: 'AkadálymentesÃtési menü bezárása', resetAllSettings: 'Ãsszes beállÃtás visszaállÃtása', 440 screenReader: 'Felolvasás', voiceCommand: 'Hangparancs', textSpacing: 'Szövegköz', pauseAnimations: 'Animációk szüneteltetése', hideImages: 'Képek elrejtése', 441 dyslexiaFriendly: 'Diszlexiabarát', biggerCursor: 'Nagy kurzor', lineHeight: 'Sormagasság', fontSelection: 'BetűtÃpus választás', colorFilter: 'SzÃnszűrÅ', 442 textAlign: 'SzövegigazÃtás', textSize: 'Szövegméret', highContrast: 'Nagy kontraszt', default: 'Alapértelmezett', screenReaderOn: 'Felolvasás bekapcsolva', screenReaderOff: 'Felolvasás kikapcsolva', 443 voiceControlActivated: 'Hangvezérlés aktiválva', notSupportedBrowser: 'nem támogatott ebben a böngészÅben', close: 'Bezárás', reset: 'VisszaállÃtás', 444 saturation: 'TelÃtettség', navigatePageStructure: 'Navigálás az oldal szerkezete szerint', landmarks: 'Tájékozódási pontok', headings: 'CÃmsorok', links: 'Hivatkozások', 445 noItemsFound: 'Nincs találat', focus: 'Fókusz', cursor: 'Kurzor', highlight: 'Kiemelés', contrast: 'Kontraszt', colorShift: 'SzÃneltolás', 446 animation: 'Animáció', spacing: 'Térköz', font: 'BetűtÃpus', guide: 'Olvasóvonal', window: 'Olvasóablak', images: 'Képek', showShortcuts: 'Gy
446orsbillentyűk megjelenÃtése', 447 additionalShortcuts: 'További gyorsbillentyűk', resetVisualToolkit: 'Vizuális eszközök visszaállÃtása', resetIssue: 'Kiemelés visszaállÃtása', 448 profiles: 'AkadálymentesÃtési profilok', profileSeizure: 'Rohambiztos', profileVision: 'Gyengénlátó', profileAdhd: 'ADHD-barát', profileDyslexia: 'Diszlexia', 449 align: 'IgazÃtás', voice: 'Hang', altText: 'AlternatÃv szöveg', noAltText: 'Hiányzó alternatÃv szöveg' 450 }, 451 ro: { 452 accessibilityMenu: 'Meniu de accesibilitate', closeAccessibilityMenu: 'Ãnchide meniul de accesibilitate', resetAllSettings: 'ReseteazÄ toate setÄrile', 453 screenReader: 'CiteÈte cu voce tare', voiceCommand: 'ComandÄ vocalÄ', textSpacing: 'SpaÈiere text', pauseAnimations: 'PauzÄ animaÈii', hideImages: 'Ascunde imaginile', 454 dyslexiaFriendly: 'Prietenos cu dislexia', biggerCursor: 'Cursor mare', lineHeight: 'ÃnÄlÈimea rândului', fontSelection: 'Selectare font', colorFilter: 'Filtru de culoare', 455 textAlign: 'Aliniere text', textSize: 'Dimensiune text', highContrast: 'Contrast ridicat', default: 'Implicit', screenReaderOn: 'Citire cu voce tare activatÄ', screenReaderOff: 'Citire cu voce tare dezactivatÄ', 456 voiceControlActivated: 'Control vocal activat', notSupportedBrowser: 'nu este acceptat în acest browser', close: 'Ãnchide', reset: 'ReseteazÄ', 457 saturation: 'SaturaÈie', navigatePageStructure: 'Navigare dupÄ structura paginii', landmarks: 'Repere', headings: 'Titluri', links: 'Linkuri', 458 noItemsFound: 'Nu s-au gÄsit elemente', focus: 'Focalizare', cursor: 'Cursor', highlight: 'EvidenÈiere', contrast: 'Contrast', colorShift: 'Schimbare culoare', 459 animation: 'AnimaÈie', spacing: 'SpaÈiere', font: 'Font', guide: 'Ghid', window: 'FereastrÄ', images: 'Imagini', showShortcuts: 'AfiÈeazÄ scurtÄturile', 460 additionalShortcuts: 'ScurtÄturi suplimentare de tastaturÄ', resetVisualToolkit: 'ReseteazÄ instrumentele vizuale', resetIssue: 'ReseteazÄ evidenÈierea', 461 profiles: 'Profiluri de accesibilitate', profileSeizure: 'Sigur pentru epilepsie', profileVision: 'Vedere slabÄ', profileAdhd: 'Prietenos cu ADHD', profileDyslexia: 'Dislexie', 462 align: 'AliniazÄ', voice: 'Voce', altText: 'Text alternativ', noAltText: 'LipseÈte textul alternativ' 463 }, 464 he: { 465 accessibilityMenu: 'תפר×× × ××ש×ת', closeAccessibilityMenu: 'ס××ר תפר×× × ××ש×ת', resetAllSettings: '××פ×ס ×× ××××ר×ת', 466 screenReader: '×קר××', voiceCommand: 'פק××× ×§×××ת', textSpacing: 'ר×××× ×קס×', pauseAnimations: '×ש×××ת ×× ××צ××ת', hideImages: '×סתרת ת××× ×ת', 467 dyslexiaFriendly: '××××××ª× ×××ס×קצ××', biggerCursor: 'ס×× ××××', lineHeight: '×××× ×©×ר×', fontSelection: '×××רת ××פ×', colorFilter: '××¡× × ×¦××¢', 468 textAlign: '××ש×ר ×קס×', textSize: '×××× ×קס×', highContrast: '× ××××××ת ×××××', default: '×ר×רת ××××', screenReaderOn: '×קר×× ×¤××¢×ת', screenReaderOff: '×קר×× ×××××', 469 voiceControlActivated: 'ש×××× ×§×××ת ××פע××', notSupportedBrowser: '××× × × ×ª×× ××פ××¤× ××', close: 'ס××ר', reset: '××פ×ס', 470 saturation: 'ר××××', navigatePageStructure: '× ×××× ××¤× ××× × ××¢×××', landmarks: 'צ××× × ×ר×', headings: '××תר×ת', links: '×§×ש×ר××', 471 noItemsFound: '×× × ×צ×× ×¤×¨××××', focus: '×××§××', cursor: 'ס××', highlight: '×××ש×', contrast: '× ××××××ת', colorShift: '×ס×ת צ××¢', 472 animation: '×× ××צ××', spacing: 'ר××××', font: '××פ×', guide: 'סר×× ×§×¨×××', window: '×××× ×§×¨×××', images: 'ת××× ×ת', showShortcuts: '××¦× ×§×צ××¨× ×ר×', 473 additionalShortcuts: '×§×צ××¨× ××§××ת × ×ספ××', resetVisualToolkit: '××פ×ס ×××× ×××ת×××', resetIssue: '××פ×ס ×××ש×', 474 profiles: 'פר×פ××× × ××ש×ת', profileSeizure: '×××× ××פ××פס××', profileVision: 'ר×××× ××§×××', profileAdhd: '××××××ª× ×-ADHD', profileDyslexia: '××ס×קצ××', 475 align: '××ש×ר', voice: '×§××', altText: '××§×¡× ×××פ×', noAltText: '×סר ××§×¡× ×××פ×' 476 }, 477 fa: { 478 accessibilityMenu: 'Ù ÙÙÛ Ø¯Ø³ØªØ±Ø³âÙ¾Ø°ÛØ±Û', closeAccessibilityMenu: 'بست٠٠ÙÙÛ Ø¯Ø³ØªØ±Ø³âÙ¾Ø°ÛØ±Û', resetAllSettings: 'Ø¨Ø§Ø²ÙØ´Ø§ÙÛ ÙÙ Ù ØªÙØ¸Û٠ات', 479 screenReader: 'Ø®ÙØ§Ùد٠با ØµØ¯Ø§Û Ø¨ÙÙØ¯', voiceCommand: 'ÙØ±Ù Ø§Ù ØµÙØªÛ', textSpacing: 'ÙØ§ØµÙ٠٠تÙ', pauseAnimations: 'تÙÙ٠اÙÛÙ ÛØ´ÙâÙØ§', hideImages: 'Ù¾ÙÙØ§Ù کرد٠تصاÙÛØ±', 480 dyslexiaFriendly: 'Ù ÙØ§Ø³Ø¨ ÙØ§Ø±Ø³Ø§Ø®ÙاÙÛ', biggerCurs
480or: 'ÙØ´Ø§Ùگر بزرگ', lineHeight: 'Ø§Ø±ØªÙØ§Ø¹ خط', fontSelection: 'Ø§ÙØªØ®Ø§Ø¨ ÙÙÙ ', colorFilter: 'ÙÛÙØªØ± رÙÚ¯', 481 textAlign: 'تراز ٠تÙ', textSize: 'Ø§ÙØ¯Ø§Ø²Ù ٠تÙ', highContrast: 'Ú©ÙØªØ±Ø§Ø³Øª Ø¨Ø§ÙØ§', default: 'Ù¾ÛØ´âÙØ±Ø¶', screenReaderOn: 'Ø®ÙØ§Ùد٠با ØµØ¯Ø§Û Ø¨ÙÙØ¯ Ø±ÙØ´Ù', screenReaderOff: 'Ø®ÙØ§Ùد٠با ØµØ¯Ø§Û Ø¨ÙÙØ¯ Ø®Ø§Ù ÙØ´', 482 voiceControlActivated: 'Ú©ÙØªØ±Ù ØµÙØªÛ ÙØ¹Ø§Ù شد', notSupportedBrowser: 'در اÛÙ Ù Ø±ÙØ±Ú¯Ø± Ù¾Ø´ØªÛØ¨Ø§ÙÛ ÙÙ ÛâØ´ÙØ¯', close: 'بستÙ', reset: 'Ø¨Ø§Ø²ÙØ´Ø§ÙÛ', 483 saturation: 'اشباع رÙÚ¯', navigatePageStructure: 'Ù¾ÛÙ Ø§ÛØ´ بر اساس ساختار ØµÙØÙ', landmarks: 'ÙØ´Ø§ÙÙâÙØ§', headings: 'Ø³Ø±ÙØµÙâÙØ§', links: 'Ù¾ÛÙÙØ¯Ùا', 484 noItemsFound: 'Ù ÙØ±Ø¯Û ÛØ§Ùت ÙØ´Ø¯', focus: 'ت٠رکز', cursor: 'ÙØ´Ø§Ùگر', highlight: 'برجستÙâØ³Ø§Ø²Û', contrast: 'Ú©ÙØªØ±Ø§Ø³Øª', colorShift: 'تغÛÛØ± رÙÚ¯', 485 animation: 'اÙÛÙ ÛØ´Ù', spacing: 'ÙØ§ØµÙÙ', font: 'ÙÙÙ ', guide: 'خطâÚ©Ø´ Ø®ÙØ§ÙدÙ', window: 'Ù¾ÙØ¬Ø±Ù Ø®ÙØ§ÙدÙ', images: 'تصاÙÛØ±', showShortcuts: 'ÙÙ Ø§ÛØ´ Ù ÛØ§ÙØ¨Ø±ÙØ§', 486 additionalShortcuts: 'Ù ÛØ§ÙØ¨Ø±ÙØ§Û Ø¨ÛØ´ØªØ± ØµÙØÙâÚ©ÙÛØ¯', resetVisualToolkit: 'Ø¨Ø§Ø²ÙØ´Ø§ÙÛ Ø§Ø¨Ø²Ø§Ø±ÙØ§Û بصرÛ', resetIssue: 'Ø¨Ø§Ø²ÙØ´Ø§ÙÛ Ø¨Ø±Ø¬Ø³ØªÙâØ³Ø§Ø²Û', 487 profiles: 'Ù٠اÛÙâÙØ§Û دسترسâÙ¾Ø°ÛØ±Û', profileSeizure: 'اÛÙ Ù Ø¨Ø±Ø§Û ØµØ±Ø¹', profileVision: 'Ú©Ù âØ¨ÛÙØ§ÛÛ', profileAdhd: 'Ù ÙØ§Ø³Ø¨ ADHD', profileDyslexia: 'ÙØ§Ø±Ø³Ø§Ø®ÙاÙÛ', 488 align: 'تراز', voice: 'صدا', altText: '٠ت٠جاÛگزÛÙ', noAltText: '٠ت٠جاÛگزÛÙ ÙØ¯Ø§Ø±Ø¯' 489 }, 490 ur: { 491 accessibilityMenu: 'Ø±Ø³Ø§Ø¦Û Ù ÛÙÙ', closeAccessibilityMenu: 'Ø±Ø³Ø§Ø¦Û Ù ÛÙÙ Ø¨ÙØ¯ کرÛÚº', resetAllSettings: 'ØªÙ Ø§Ù ØªØ±ØªÛØ¨Ø§Øª Ø±Û Ø³ÛÙ¹ کرÛÚº', 492 screenReader: 'بÙÙØ¯ Ø¢ÙØ§Ø² Ù ÛÚº Ù¾ÚÚ¾ÛÚº', voiceCommand: 'ØµÙØªÛ ØÚ©Ù ', textSpacing: '٠ت٠کا ÙØ§ØµÙÛ', pauseAnimations: 'اÛÙÛÙ ÛØ´Ù رÙÚ©ÛÚº', hideImages: 'تصاÙÛØ± ÚھپائÛÚº', 493 dyslexiaFriendly: 'ÚØ³ÙÛÚ©Ø³ÛØ§ Ø¯ÙØ³Øª', biggerCursor: 'Ø¨ÚØ§ کرسر', lineHeight: 'سطر Ú©Û Ø§ÙÙÚØ§Ø¦Û', fontSelection: 'ÙÙÙÙ¹ کا Ø§ÙØªØ®Ø§Ø¨', colorFilter: 'رÙÚ¯ ÙÙٹر', 494 textAlign: 'Ù ØªÙ Ú©Û Ø³ÛØ¯Ú¾', textSize: '٠ت٠کا سائز', highContrast: 'اعÙÛ Ú©Ùٹراسٹ', default: 'Ø·Û Ø´Ø¯Û', screenReaderOn: 'بÙÙØ¯ Ø®ÙØ§ÙÛ Ø¢Ù', screenReaderOff: 'بÙÙØ¯ Ø®ÙØ§ÙÛ Ø¢Ù', 495 voiceControlActivated: 'ØµÙØªÛ Ú©ÙٹرÙÙ ÙØ¹Ø§Ù', notSupportedBrowser: 'اس براؤزر Ù ÛÚº ٠عاÙÙ ÙÛÛÚº', close: 'Ø¨ÙØ¯ کرÛÚº', reset: 'Ø±Û Ø³ÛÙ¹', 496 saturation: 'رÙگت', navigatePageStructure: 'ØµÙØÛ Ú©Û Ø³Ø§Ø®Øª Ø³Û ÙÛÙÛÚ¯ÛÙ¹ کرÛÚº', landmarks: 'ÙØ´Ø§Ùات', headings: 'Ø³Ø±Ø®ÛØ§Úº', links: 'Ø±ÙØ§Ø¨Ø·', 497 noItemsFound: 'Ú©ÙØ¦Û آئٹ٠ÙÛÛÚº Ù ÙØ§', focus: 'ÙÙکس', cursor: 'کرسر', highlight: 'ÙÙ Ø§ÛØ§Úº کرÛÚº', contrast: 'Ú©Ùٹراسٹ', colorShift: 'رÙÚ¯ Ú©Û ØªØ¨Ø¯ÛÙÛ', 498 animation: 'اÛÙÛÙ ÛØ´Ù', spacing: 'ÙØ§ØµÙÛ', font: 'ÙÙÙÙ¹', guide: 'رÛÙ٠ا', window: 'ÙÙÚÙ', images: 'تصاÙÛØ±', showShortcuts: 'شارٹ Ú©Ù¹ دکھائÛÚº', 499 additionalShortcuts: 'اضاÙÛ Ú©Û Ø¨ÙØ±Ú شارٹ کٹس', resetVisualToolkit: 'Ø¨ØµØ±Û Ù¹ÙÙ Ú©Ù¹ Ø±Û Ø³ÛÙ¹ کرÛÚº', resetIssue: 'ÙÙ Ø§ÛØ§Úº Ú©Ø§Ø±Û Ø±Û Ø³ÛÙ¹ کرÛÚº', 500 profiles: 'Ø±Ø³Ø§Ø¦Û Ù¾Ø±ÙÙØ§Ø¦Ùز', profileSeizure: 'Ø¯ÙØ±Û Ø³Û Ù ØÙÙØ¸', profileVision: 'Ú©Ù Ø²ÙØ± بÛÙØ§Ø¦Û', profileAdhd: 'ADHD Ø¯ÙØ³Øª', profileDyslexia: 'ÚØ³ÙÛÚ©Ø³ÛØ§', 501 align: 'Ø³ÛØ¯Ú¾ کرÛÚº', voice: 'Ø¢ÙØ§Ø²', altText: '٠تباد٠٠تÙ', noAltText: 'Ù ØªØ¨Ø§Ø¯Ù Ù ØªÙ Ù ÙØ¬Ùد ÙÛÛÚº' 502 }, 503 pa: { 504 accessibilityMenu: 'ਪਹà©à©°à¨à¨¯à©à¨à¨¤à¨¾ ਮà©à¨¨à©', closeAccessibilityMenu: 'ਪਹà©à©°à¨à¨¯à©à¨à¨¤à¨¾ ਮà©à¨¨à© ਬੰਦ à¨à¨°à©', resetAllSettings: 'ਸਾਰà©à¨à¨ ਸà©à¨à¨¿à©°à¨à¨¾à¨ ਰà©à¨¸à©à¨ à¨à¨°à©', 505 screenReader: 'à¨à©±à¨à© ਪà©à©à¨¹à©', voiceCommand: 'à¨à¨µà¨¾à¨à¨¼ à¨à¨®à¨¾à¨à¨¡', textSpacing: 'à¨à©à¨à¨¸à¨ ਸਪà©à¨¸à¨¿à©°à¨', pauseAnimations: 'à¨à¨¨à©à¨®à©à¨¸à¨¼à¨¨ ਰà©à¨à©', hideImages: 'ਤਸਵà©à¨°à¨¾à¨ ਲà©à¨à¨¾à¨',
506 dyslexiaFriendly: 'ਡਿਸਲà©à¨à¨¸à©à¨ ਠਨà©à¨à©à¨²', biggerCursor: 'ਵੱਡਾ à¨à¨°à¨¸à¨°', lineHeight: 'ਲਾà¨à¨¨ à¨à¨à¨¾à¨', fontSelection: 'ਫà©à¨à¨ à¨à©à¨£', colorFilter: 'ਰੰਠਫਿਲà¨à¨°', 507 textAlign: 'à¨à©à¨à¨¸à¨ ਠਲਾà¨à¨¨à¨®à©à¨à¨', textSize: 'à¨à©à¨à¨¸à¨ à¨à¨à¨¾à¨°', highContrast: 'à¨à©±à¨ à¨à©°à¨à©à¨°à¨¾à¨¸à¨', default: 'ਡਿਫà©à¨²à¨', screenReaderOn: 'à¨à©±à¨à© ਪà©à©à¨¹à¨¨à¨¾ à¨à¨¾à¨²à©', screenReaderOff: 'à¨à©±à¨à© ਪà©à©à¨¹à¨¨à¨¾ ਬੰਦ', 508 voiceControlActivated: 'à¨à¨µà¨¾à¨à¨¼ à¨à©°à¨à¨°à©à¨² ਸਰà¨à¨°à¨®', notSupportedBrowser: 'à¨à¨¸ ਬà©à¨°à¨¾à¨à¨à¨¼à¨° ਵਿੱਠਸਮਰਥਿਤ ਨਹà©à¨', close: 'ਬੰਦ à¨à¨°à©', reset: 'ਰà©à¨¸à©à¨', 509 saturation: 'ਸੰਤà©à¨°à¨¿à¨ªà¨¤à¨¾', navigatePageStructure: 'ਪੰਨਾ ਢਾà¨à¨à© ਠਨà©à¨¸à¨¾à¨° ਨà©à¨µà©à¨à©à¨ à¨à¨°à©', landmarks: 'ਲà©à¨à¨¡à¨®à¨¾à¨°à¨', headings: 'ਸਿਰਲà©à¨', links: 'ਲਿੰà¨', 510 noItemsFound: 'à¨à©à¨ à¨à¨à¨à¨® ਨਹà©à¨ ਮਿਲà©', focus: 'ਫà©à¨à¨¸', cursor: 'à¨à¨°à¨¸à¨°', highlight: 'ਹਾà¨à¨²à¨¾à¨à¨', contrast: 'à¨à©°à¨à©à¨°à¨¾à¨¸à¨', colorShift: 'ਰੰਠਤਬਦà©à¨²à©', 511 animation: 'à¨à¨¨à©à¨®à©à¨¸à¨¼à¨¨', spacing: 'ਸਪà©à¨¸à¨¿à©°à¨', font: 'ਫà©à¨à¨', guide: 'à¨à¨¾à¨à¨¡', window: 'ਵਿੰਡà©', images: 'ਤਸਵà©à¨°à¨¾à¨', showShortcuts: 'ਸ਼ਾਰà¨à¨à©±à¨ ਦਿà¨à¨¾à¨', 512 additionalShortcuts: 'ਵਾਧ੠à¨à©à¨¬à©à¨°à¨¡ ਸ਼ਾਰà¨à¨à©±à¨', resetVisualToolkit: 'ਵਿà¨à¨¼à©à¨ ਲ à¨à©à¨²à¨à¨¿à©±à¨ ਰà©à¨¸à©à¨ à¨à¨°à©', resetIssue: 'ਹਾà¨à¨²à¨¾à¨à¨ ਰà©à¨¸à©à¨ à¨à¨°à©', 513 profiles: 'ਪਹà©à©°à¨à¨¯à©à¨à¨¤à¨¾ ਪà©à¨°à©à¨«à¨¾à¨à¨²', profileSeizure: 'ਦà©à¨°à¨¾-ਸà©à¨°à©±à¨à¨¿à¨ ਤ', profileVision: 'à¨à©±à¨ ਨà¨à¨¼à¨°', profileAdhd: 'ADHD ਠਨà©à¨à©à¨²', profileDyslexia: 'ਡਿਸਲà©à¨à¨¸à©à¨', 514 align: 'ਠਲਾà¨à¨¨ à¨à¨°à©', voice: 'à¨à¨µà¨¾à¨à¨¼', altText: 'ਵਿà¨à¨²à¨ªà¨¿à¨ à¨à©à¨à¨¸à¨', noAltText: 'ਵਿà¨à¨²à¨ªà¨¿à¨ à¨à©à¨à¨¸à¨ ਨਹà©à¨ ਹà©' 515 }, 516 mr: { 517 accessibilityMenu: 'पà¥à¤°à¤µà¥à¤¶à¤¯à¥à¤à¥à¤¯à¤¤à¤¾ मà¥à¤¨à¥', closeAccessibilityMenu: 'पà¥à¤°à¤µà¥à¤¶à¤¯à¥à¤à¥à¤¯à¤¤à¤¾ मà¥à¤¨à¥ बà¤à¤¦ à¤à¤°à¤¾', resetAllSettings: 'सरà¥à¤µ सà¥à¤à¤¿à¤à¤à¥à¤ रà¥à¤¸à¥à¤ à¤à¤°à¤¾', 518 screenReader: 'मà¥à¤ à¥à¤¯à¤¾à¤¨à¥ वाà¤à¤¾', voiceCommand: 'वà¥à¤¹à¥à¤à¤¸ à¤à¤®à¤¾à¤à¤¡', textSpacing: 'मà¤à¤à¥à¤° ठà¤à¤¤à¤°', pauseAnimations: 'ठâॠनिमà¥à¤¶à¤¨ थाà¤à¤¬à¤µà¤¾', hideImages: 'पà¥à¤°à¤¤à¤¿à¤®à¤¾ लपवा', 519 dyslexiaFriendly: 'डिसà¥à¤²à¥à¤à¥à¤¸à¤¿à¤¯à¤¾-ठनà¥à¤à¥à¤²', biggerCursor: 'मà¥à¤ ा à¤à¤°à¥à¤¸à¤°', lineHeight: 'à¤à¤³ à¤à¤à¤à¥', fontSelection: 'फà¥à¤¨à¥à¤ निवड', colorFilter: 'रà¤à¤ फिलà¥à¤à¤°', 520 textAlign: 'मà¤à¤à¥à¤° सà¤à¤°à¥à¤à¤¨', textSize: 'मà¤à¤à¥à¤° à¤à¤à¤¾à¤°', highContrast: 'à¤à¤à¥à¤ à¤à¥à¤¨à¥à¤à¥à¤°à¤¾à¤¸à¥à¤', default: 'डà¥à¤«à¥à¤²à¥à¤', screenReaderOn: 'मà¥à¤ à¥à¤¯à¤¾à¤¨à¥ वाà¤à¤¨ सà¥à¤°à¥', screenReaderOff: 'मà¥à¤ à¥à¤¯à¤¾à¤¨à¥ वाà¤à¤¨ बà¤à¤¦', 521 voiceControlActivated: 'वà¥à¤¹à¥à¤à¤¸ नियà¤à¤¤à¥à¤°à¤£ सà¤à¥à¤°à¤¿à¤¯', notSupportedBrowser: 'या बà¥à¤°à¤¾à¤à¤à¤°à¤®à¤§à¥à¤¯à¥ समरà¥à¤¥à¤¿à¤¤ नाहà¥', close: 'बà¤à¤¦ à¤à¤°à¤¾', reset: 'रà¥à¤¸à¥à¤', 522 saturation: 'सà¤à¤ªà¥à¤à¥à¤¤à¤¤à¤¾', navigatePageStructure: 'पà¥à¤·à¥à¤ रà¤à¤¨à¥à¤¨à¥à¤¸à¤¾à¤° नà¥à¤µà¥à¤¹à¤¿à¤à¥à¤ à¤à¤°à¤¾', landmarks: 'लà¤à¤¡à¤®à¤¾à¤°à¥à¤', headings: 'शà¥à¤°à¥à¤·à¤à¥', links: 'दà¥à¤µà¥', 523 noItemsFound: 'à¤à¥à¤£à¤¤à¥à¤¹à¥ à¤à¤¯à¤à¤® à¤à¤¢à¤³à¤²à¥ नाहà¥à¤¤', focus: 'फà¥à¤à¤¸', cursor: 'à¤à¤°à¥à¤¸à¤°', highlight: 'हायलाà¤à¤', contrast: 'à¤à¥à¤¨à¥à¤à¥à¤°à¤¾à¤¸à¥à¤', colorShift: 'रà¤à¤ बदल', 524 animation: 'ठâॠनिमà¥à¤¶à¤¨', spacing: 'ठà¤à¤¤à¤°', font: 'फà¥à¤¨à¥à¤', guide: 'मारà¥à¤à¤¦à¤°à¥à¤¶à¤', window: 'विà¤à¤¡à¥', images: 'पà¥à¤°à¤¤à¤¿à¤®à¤¾', showShortcuts: 'शà¥à¤°à¥à¤à¤à
524¤ दाà¤à¤µà¤¾', 525 additionalShortcuts: 'ठतिरिà¤à¥à¤¤ à¤à¥à¤¬à¥à¤°à¥à¤¡ शà¥à¤°à¥à¤à¤à¤', resetVisualToolkit: 'वà¥à¤¹à¤¿à¤à¥à¤¯à¥à¤ ल à¤à¥à¤²à¤à¤¿à¤ रà¥à¤¸à¥à¤ à¤à¤°à¤¾', resetIssue: 'हायलाà¤à¤ रà¥à¤¸à¥à¤ à¤à¤°à¤¾', 526 profiles: 'पà¥à¤°à¤µà¥à¤¶à¤¯à¥à¤à¥à¤¯à¤¤à¤¾ पà¥à¤°à¥à¤«à¤¾à¤à¤²', profileSeizure: 'फà¥à¤«à¤°à¥-सà¥à¤°à¤à¥à¤·à¤¿à¤¤', profileVision: 'à¤à¤®à¥ दà¥à¤·à¥à¤à¥', profileAdhd: 'ADHD ठनà¥à¤à¥à¤²', profileDyslexia: 'डिसà¥à¤²à¥à¤à¥à¤¸à¤¿à¤¯à¤¾', 527 align: 'सà¤à¤°à¥à¤à¤¿à¤¤ à¤à¤°à¤¾', voice: 'à¤à¤µà¤¾à¤', altText: 'परà¥à¤¯à¤¾à¤¯à¥ मà¤à¤à¥à¤°', noAltText: 'परà¥à¤¯à¤¾à¤¯à¥ मà¤à¤à¥à¤° नाहà¥' 528 }, 529 te: { 530 accessibilityMenu: 'యాà°à±à°¸à±à°¸à°¿à°¬à°¿à°²à°¿à°à± à°®à±à°¨à±', closeAccessibilityMenu: 'యాà°à±à°¸à±à°¸à°¿à°¬à°¿à°²à°¿à°à± à°®à±à°¨à± à°®à±à°¸à°¿à°µà±à°¯à°à°¡à°¿', resetAllSettings: 'à° à°¨à±à°¨à°¿ à°¸à±à°à±à°à°¿à°à°à±âలనౠరà±à°¸à±à°à± à°à±à°¯à°à°¡à°¿', 531 screenReader: 'బిà°à±à°à°°à°à°¾ à°à°¦à°µà°à°¡à°¿', voiceCommand: 'వాయిసౠà°à°®à°¾à°à°¡à±', textSpacing: 'à°à±à°à±à°¸à±à°à± à°¸à±à°ªà±à°¸à°¿à°à°à±', pauseAnimations: 'యానిమà±à°·à°¨à±âలనౠà°à°ªà°à°¡à°¿', hideImages: 'à°à°¿à°¤à±à°°à°¾à°²à°¨à± దాà°à°à°¡à°¿', 532 dyslexiaFriendly: 'à°¡à°¿à°¸à±à°²à±à°à±à°¸à°¿à°¯à°¾ à° à°¨à±à°à±à°²à°', biggerCursor: 'à°ªà±à°¦à±à°¦ à°à°°à±à°¸à°°à±', lineHeight: 'à°²à±à°¨à± à°à°¤à±à°¤à±', fontSelection: 'à°«à°¾à°à°à± à°à°à°ªà°¿à°', colorFilter: 'à°°à°à°à± à°«à°¿à°²à±à°à°°à±', 533 textAlign: 'à°à±à°à±à°¸à±à°à± ఠమరిà°', textSize: 'à°à±à°à±à°¸à±à°à± పరిమాణà°', highContrast: 'à° à°§à°¿à° à°à°¾à°à°à±à°°à°¾à°¸à±à°à±', default: 'డిఫాలà±à°à±', screenReaderOn: 'బిà°à±à°à°°à°à°¾ à°à°¦à°µà°¡à° à°à°¨à±', screenReaderOff: 'బిà°à±à°à°°à°à°¾ à°à°¦à°µà°¡à° à°à°«à±', 534 voiceControlActivated: 'వాయిసౠనియà°à°¤à±à°°à°£ à°¸à°à±à°°à°¿à°¯à°', notSupportedBrowser: 'à° à°¬à±à°°à±à°à°°à±âలౠమదà±à°¦à°¤à± à°²à±à°¦à±', close: 'à°®à±à°¸à°¿à°µà±à°¯à°à°¡à°¿', reset: 'à°°à±à°¸à±à°à±', 535 saturation: 'à°¸à°à°¤à±à°ªà±à°¤à°¤', navigatePageStructure: 'à°ªà±à°à± నిరà±à°®à°¾à°£à° à°¦à±à°µà°¾à°°à°¾ నావిà°à±à°à± à°à±à°¯à°à°¡à°¿', landmarks: 'à°²à±à°¯à°¾à°à°¡à±âమారà±à°à±âà°²à±', headings: 'à°¶à±à°°à±à°·à°¿à°à°²à±', links: 'లిà°à°à±âà°²à±', 536 noItemsFound: 'à° à°à°¶à°¾à°²à± à°à°¨à±à°à±à°¨à°¬à°¡à°²à±à°¦à±', focus: 'à°«à±à°à°¸à±', cursor: 'à°à°°à±à°¸à°°à±', highlight: 'à°¹à±à°²à±à°à±', contrast: 'à°à°¾à°à°à±à°°à°¾à°¸à±à°à±', colorShift: 'à°°à°à°à± మారà±à°ªà±', 537 animation: 'యానిమà±à°·à°¨à±', spacing: 'à°¸à±à°ªà±à°¸à°¿à°à°à±', font: 'à°«à°¾à°à°à±', guide: 'à°à±à°¡à±', window: 'విà°à°¡à±', images: 'à°à°¿à°¤à±à°°à°¾à°²à±', showShortcuts: 'షారà±à°à±âà°à°à±âలనౠà°à±à°ªà°¿à°à°à°à°¡à°¿', 538 additionalShortcuts: 'ఠదనపౠà°à±à°¬à±à°°à±à°¡à± షారà±à°à±âà°à°à±âà°²à±', resetVisualToolkit: 'విà°à±à°µà°²à± à°à±à°²à±âà°à°¿à°à± à°°à±à°¸à±à°à± à°à±à°¯à°à°¡à°¿', resetIssue: 'à°¹à±à°²à±à°à± à°°à±à°¸à±à°à± à°à±à°¯à°à°¡à°¿', 539 profiles: 'యాà°à±à°¸à±à°¸à°¿à°¬à°¿à°²à°¿à°à± à°ªà±à°°à±à°«à±à°²à±âà°²à±', profileSeizure: 'à°®à±à°°à±à°-à°¸à±à°°à°à±à°·à°¿à°¤à°', profileVision: 'à°¤à°à±à°à±à°µ à°¦à±à°·à±à°à°¿', profileAdhd: 'ADHD à° à°¨à±à°à±à°²à°', profileDyslexia: 'à°¡à°¿à°¸à±à°²à±à°à±à°¸à°¿à°¯à°¾', 540 align: 'ఠమరà±à°à°à°¡à°¿', voice: 'వాయిసà±', altText: 'à°ªà±à°°à°¤à±à°¯à°¾à°®à±à°¨à°¾à°¯ à°µà°à°¨à°', noAltText: 'à°ªà±à°°à°¤à±à°¯à°¾à°®à±à°¨à°¾à°¯ à°µà°à°¨à° à°²à±à°¦à±' 541 }, 542 ta: { 543 accessibilityMenu: '஠ணà¯à®à®²à¯à®¤à®©à¯à®®à¯ à®®à¯à®©à¯', closeAccessibilityMenu: '஠ணà¯à®à®²à¯à®¤à®©à¯à®®à¯ à®®à¯à®©à¯à®µà¯ à®®à¯à®à¯', resetAllSettings: 'à®à®²à¯à®²à®¾ à® à®®à¯à®ªà¯à®ª
543à¯à®à®³à¯à®¯à¯à®®à¯ à®®à¯à®à¯à®à®®à¯', 544 screenReader: 'à®à®°à®à¯à®à®ªà¯ பà®à®¿', voiceCommand: 'à®à¯à®°à®²à¯ à®à®à¯à®à®³à¯', textSpacing: 'à®à®°à¯ à®à®à¯à®µà¯à®³à®¿', pauseAnimations: 'à® à®à¯à®µà¯à®à¯à®à®à¯à®à®³à¯ நிறà¯à®¤à¯à®¤à¯', hideImages: 'பà®à®à¯à®à®³à¯ மறà¯', 545 dyslexiaFriendly: 'à®à®¿à®¸à¯à®²à¯à®à¯à®¸à®¿à®¯à®¾ நà®à¯à®ªà¯', biggerCursor: 'பà¯à®°à®¿à®¯ à®à®°à¯à®à®°à¯', lineHeight: 'வரி à®à®¯à®°à®®à¯', fontSelection: 'à®à®´à¯à®¤à¯à®¤à¯à®°à¯ தà¯à®°à¯à®µà¯', colorFilter: 'நிற வà®à®¿à®ªà¯à®ªà®¾à®©à¯', 546 textAlign: 'à®à®°à¯ à®à¯à®°à®®à¯à®ªà¯à®ªà¯', textSize: 'à®à®°à¯ ஠ளவà¯', highContrast: '஠தி஠மாறà¯à®ªà®¾à®à¯', default: 'à®à®¯à®²à¯à®ªà¯à®¨à®¿à®²à¯', screenReaderOn: 'à®à®°à®à¯à®à®ªà¯ பà®à®¿à®¤à¯à®¤à®²à¯ à®à®¯à®à¯à®à®®à¯', screenReaderOff: 'à®à®°à®à¯à®à®ªà¯ பà®à®¿à®¤à¯à®¤à®²à¯ நிறà¯à®¤à¯à®¤à®®à¯', 547 voiceControlActivated: 'à®à¯à®°à®²à¯ à®à®à¯à®à¯à®ªà¯à®ªà®¾à®à¯ à®à¯à®¯à®²à¯à®ªà®à¯à®¤à¯à®¤à®ªà¯à®ªà®à¯à®à®¤à¯', notSupportedBrowser: 'à®à®¨à¯à®¤ à®à®²à®¾à®µà®¿à®¯à®¿à®²à¯ à®à®¤à®°à®¿à®à¯à®à®ªà¯à®ªà®à®µà®¿à®²à¯à®²à¯', close: 'à®®à¯à®à¯', reset: 'à®®à¯à®à¯à®à®®à¯', 548 saturation: 'நிறà®à¯à®à¯à®±à®¿à®µà¯', navigatePageStructure: 'பà®à¯à® à® à®®à¯à®ªà¯à®ªà®¿à®©à¯à®ªà®à®¿ வழிà®à¯à®²à¯à®¤à¯à®¤à¯', landmarks: 'à® à®à¯à®¯à®¾à®³à®à¯à®à®³à¯', headings: 'தலà¯à®ªà¯à®ªà¯à®à®³à¯', links: 'à®à®£à¯à®ªà¯à®ªà¯à®à®³à¯', 549 noItemsFound: 'à®à®°à¯à®ªà¯à®ªà®à®¿à®à®³à¯ à®à®¤à¯à®µà¯à®®à¯ à®à®²à¯à®²à¯', focus: 'à®à¯à®µà®¿à®¯à®®à¯', cursor: 'à®à®°à¯à®à®°à¯', highlight: 'தனிபà¯à®ªà®à¯à®¤à¯à®¤à¯', contrast: 'மாறà¯à®ªà®¾à®à¯', colorShift: 'நிற மாறà¯à®±à®®à¯', 550 animation: 'à® à®à¯à®µà¯à®à¯à®à®®à¯', spacing: 'à®à®à¯à®µà¯à®³à®¿', font: 'à®à®´à¯à®¤à¯à®¤à¯à®°à¯', guide: 'வழிà®à®¾à®à¯à®à®¿', window: 'à®à®¾à®³à®°à®®à¯', images: 'பà®à®à¯à®à®³à¯', showShortcuts: 'à®à¯à®±à¯à®à¯à®à¯à®µà®´à®¿à®à®³à¯à®à¯ à®à®¾à®à¯à®à¯', 551 additionalShortcuts: 'à®à¯à®à¯à®¤à®²à¯ விà®à¯à®ªà¯à®ªà®²à®à¯ à®à¯à®±à¯à®à¯à®à¯à®µà®´à®¿à®à®³à¯', resetVisualToolkit: 'à®à®¾à®à¯à®à®¿ à®à®°à¯à®µà®¿à®à®³à¯ à®®à¯à®à¯à®à®®à¯', resetIssue: 'தனிபà¯à®ªà®à¯à®¤à¯à®¤à®²à¯ à®®à¯à®à¯à®à®®à¯', 552 profiles: '஠ணà¯à®à®²à¯à®¤à®©à¯à®®à¯ à®à¯à®¯à®µà®¿à®µà®°à®à¯à®à®³à¯', profileSeizure: 'வலிபà¯à®ªà¯-பாதà¯à®à®¾à®ªà¯à®ªà¯', profileVision: 'à®à¯à®±à¯à®¨à¯à®¤ பாரà¯à®µà¯', profileAdhd: 'ADHD நà®à¯à®ªà¯', profileDyslexia: 'à®à®¿à®¸à¯à®²à¯à®à¯à®¸à®¿à®¯à®¾', 553 align: 'à®à¯à®°à®®à¯', voice: 'à®à¯à®°à®²à¯', altText: 'மாறà¯à®±à¯ à®à®°à¯', noAltText: 'மாறà¯à®±à¯ à®à®°à¯ à®à®²à¯à®²à¯' 554 }, 555 ms: { 556 accessibilityMenu: 'Menu Kebolehcapaian', closeAccessibilityMenu: 'Tutup menu kebolehcapaian', resetAllSettings: 'Tetapkan semula semua tetapan', 557 screenReader: 'Baca Kuat', voiceCommand: 'Arahan Suara', textSpacing: 'Jarak Teks', pauseAnimations: 'Jeda Animasi', hideImages: 'Sembunyikan Imej', 558 dyslexiaFriendly: 'Mesra Disleksia', biggerCursor: 'Kursor Besar', lineHeight: 'Tinggi Baris', fontSelection: 'Pilihan Fon', colorFilter: 'Penapis Warna', 559 textAlign: 'Penjajaran Teks', textSize: 'Saiz Teks', highContrast: 'Kontras Tinggi', default: 'Lalai', screenReaderOn: 'Baca kuat dihidupkan', screenReaderOff: 'Baca kuat dimatikan', 560 voiceControlActivated: 'Kawalan suara diaktifkan', notSupportedBrowser: 'tidak disokong dalam pelayar ini', close: 'Tutup', reset: 'Tetapkan semula', 561 saturation: 'Ketepuan', navigatePageStructure: 'Navigasi mengikut struktur halaman', landmarks: 'Mercu tanda', headings: 'Tajuk', links: 'Pautan', 562 noItemsFound: 'Tiada item dijumpai', focus: 'Fokus', cursor: 'Kursor', highlight: 'Serlahkan', contrast: 'Kontras', colorShift: 'Anjakan Warna', 563 animation: 'Animasi', spacing: 'Jarak', font: 'Fon', guide: 'Panduan', window: 'Tetingkap', images: 'Imej', showShortcuts: 'Tunjukkan pintasan', 564 additionalShortcuts: 'Pintasan papan kekunci tambahan', resetVisualToolkit: 'Tetapkan semula kit visual', resetIssue: 'Tetapkan semula serlahan', 565 profiles: 'Profil Kebolehcapaian', profileSeizure: 'Selamat Sawan', profileVision: 'Penglihatan Terhad', profileAdhd: 'Mesra ADHD', profileDyslexia: 'Disleksia', 566 align: 'Jajarkan', voice: 'Suara', altText: 'Teks Alternatif', noAltText: 'Tiada teks alternatif' 567 }, 568 fil: { 569 accessibilityMenu: 'Menu ng Accessibility', closeAccessibilityMenu: 'Isara ang menu ng accessibility', resetAllSettings: 'I-reset ang lahat ng setting', 570 screenReader: 'Basahin nang Malakas', voiceCommand: 'Voice Command', textSpacing: 'Espasyo ng Teksto', pauseAnimations: 'I-pause ang mga Animation', hideImages: 'Itago ang mga Larawan',
571 dyslexiaFriendly: 'Angkop sa Dyslexia', biggerCursor: 'Malaking Cursor', lineHeight: 'Taas ng Linya', fontSelection: 'Pagpili ng Font', colorFilter: 'Filter ng Kulay', 572 textAlign: 'Pagkakahanay ng Teksto', textSize: 'Laki ng Teksto', highContrast: 'Mataas na Contrast', default: 'Default', screenReaderOn: 'Naka-on ang pagbasa nang malakas', screenReaderOff: 'Naka-off ang pagbasa nang malakas', 573 voiceControlActivated: 'Naka-activate ang voice control', notSupportedBrowser: 'ay hindi suportado sa browser na ito', close: 'Isara', reset: 'I-reset', 574 saturation: 'Saturation', navigatePageStructure: 'Mag-navigate ayon sa istruktura ng pahina', landmarks: 'Mga Landmark', headings: 'Mga Heading', links: 'Mga Link', 575 noItemsFound: 'Walang nahanap na item', focus: 'Focus', cursor: 'Cursor', highlight: 'I-highlight', contrast: 'Contrast', colorShift: 'Pagbabago ng Kulay', 576 animation: 'Animation', spacing: 'Espasyo', font: 'Font', guide: 'Gabay', window: 'Window', images: 'Mga Larawan', showShortcuts: 'Ipakita ang mga shortcut', 577 additionalShortcuts: 'Karagdagang keyboard shortcut', resetVisualToolkit: 'I-reset ang visual toolkit', resetIssue: 'I-reset ang highlight', 578 profiles: 'Mga Profile ng Accessibility', profileSeizure: 'Ligtas sa Seizure', profileVision: 'Mahina ang Paningin', profileAdhd: 'Angkop sa ADHD', profileDyslexia: 'Dyslexia', 579 align: 'Ihanay', voice: 'Boses', altText: 'Alt Text', noAltText: 'Walang alt text' 580 } 581}; 582 583 584// =========================================== 585// LANGUAGE DETECTION 586// Priority: ENABLESTACK_CONFIG.language > <html lang> > navigator.language > 'en' 587// Any string missing from a language falls back to English automatically. 588// =========================================== 589function detectWidgetLanguage() { 590 let requested = 'en'; 591 try { 592 requested = (window.ENABLESTACK_CONFIG && window.ENABLESTACK_CONFIG.language) || 593 document.documentElement.getAttribute('lang') || 594 navigator.language || 'en'; 595 } catch (e) { requested = 'en'; } 596 requested = String(requested).toLowerCase().trim(); 597 // Legacy / regional aliases 598 const aliases = { iw: 'he', in: 'id', nb: 'no', nn: 'no' }; 599 if (TRANSLATIONS[requested]) return requested; 600 if (aliases[requested] && TRANSLATIONS[aliases[requested]]) return aliases[requested]; 601 const base = requested.split(/[-_]/)[0]; 602 if (TRANSLATIONS[base]) return base; 603 if (aliases[base] && TRANSLATIONS[aliases[base]]) return aliases[base]; 604 return 'en'; 605} 606 607const currentLanguage = detectWidgetLanguage(); 608 609// Map each UI language to a full BCP-47 locale for speech synthesis / recognition. 610const SPEECH_LOCALES = { 611 en: 'en-US', es: 'es-ES', fr: 'fr-FR', de: 'de-DE', it: 'it-IT', pt: 'pt-BR', 612 hi: 'hi-IN', ru: 'ru-RU', zh: 'zh-CN', ja: 'ja-JP', ar: 'ar-SA', ko: 'ko-KR', 613 nl: 'nl-NL', pl: 'pl-PL', tr: 'tr-TR', sv: 'sv-SE', he: 'he-IL', fa: 'fa-IR', 614 id: 'id-ID', th: 'th-TH', vi: 'vi-VN', el: 'el-GR', cs: 'cs-CZ', hu: 'hu-HU', 615 ro: 'ro-RO', da: 'da-DK', fi: 'fi-FI', no: 'nb-NO', bn: 'bn-IN' 616}; 617const SPEECH_LANG = SPEECH_LOCALES[currentLanguage] || (currentLanguage === 'en' ? 'en-US' : currentLanguage); 618 619// Languages that read right-to-left â the panel flips its layout for these. 620const RTL_LANGUAGES = ['ar', 'he', 'fa', 'ur']; 621const IS_RTL = RTL_LANGUAGES.indexOf(currentLanguage) !== -1; 622 623function getTranslation(key) { 624 // 1. Explicit per-string override via ENABLESTACK_CONFIG.lang 625 try { 626 const userLang = window.ENABLESTACK_CONFIG && window.ENABLESTACK_CONFIG.lang; 627 if (userLang && typeof userLang[key] === 'string') return userLang[key]; 628 } catch (e) { /* ignore */ } 629 // 2. Detected language, 3. English fallback, 4. raw key 630 const table = TRANSLATIONS[currentLanguage] || TRANSLATIONS.en; 631 return table[key] || TRANSLATIONS.en[key] || key; 632} 633 634// =========================================== 635// CONFIGURATION VARIABLES 636// =========================================== 637 638// Default configuration - can be overridden by user 639const DEFAULT_WIDGET_CONFIG = { 640 // Core Features 641 enableHighContrast: true, 642 enableBiggerText: true, 643 enableTextSpacing: true, // Now has 3 levels 644 enablePauseAnimations: true, // Enhanced to include reduced motion features 645 enableHideImages: true, 646 enableDyslexiaFont: true,
647 enableBiggerCursor: true, 648 enableLineHeight: true, // Now has 3 levels (2em, 3em, 4em) 649 enableTextAlign: true, 650 651 // Advanced Features 652 enableScreenReader: true, 653 enableVoiceControl: true, 654 enableFontSelection: true, 655 enableColorFilter: true, 656 enableFocusIndicator: true, 657 enableHighlightLinks: true, 658 enableReadingGuide: true, 659 enableReadingWindow: true, 660 enableSaturation: true, 661 enableAltText: true, 662 enableProfiles: true, 663 664 // Enhanced features (added v1.3.0) 665 enableHighlightHover: true, 666 enableEnlargeButtons: true, 667 enableMuteMedia: true, 668 enableReadableFont: true, 669 enablePageMagnifier: true, 670 enableTextMagnifier: true, 671 enableReadFocus: true, 672 enableVirtualKeyboard: true, 673 enableReadableMode: true, 674 enableCustomColor: true, 675 enableDictionary: true, // NOTE: makes an external call to api.dictionaryapi.dev on demand 676 677 // Optional footer link (leave empty to hide the link) 678 accessibilityStatementUrl: '', // e.g. 'https://example.com/accessibility' 679 680 // Launcher button icon â chosen once at integration time (npm prompt or 681 // WordPress admin). One of: 'default', 'wheelchair', 'person', 'eye'. 682 icon: 'default', 683 684 // Widget Styling 685 widgetWidth: '340px', 686 widgetPosition: { 687 side: 'left', // 'left' or 'right' 688 right: '20px', 689 left: '20px', 690 bottom: '20px' 691 }, 692 693 // Colors â EnableUser brand purple (#54467D). Shades are derived from the 694 // primary; change just `primary` (or pass ENABLESTACK_CONFIG.colors.primary) 695 // to re-theme the whole widget. 696 colors: { 697 primary: '#54467d', // Accent/active color â brand purple 698 primaryBright: '#736794', // Gradient start (lighter purple) = lighten(primary, 0.18) 699 primaryDeep: '#3b3158', // Gradient end (deeper purple) = darken(primary, 0.30) 700 brandGradient: 'linear-gradient(135deg, #736794 0%, #3b3158 100%)', 701 secondary: '#ffffff', // Icon/text color on the accent (launcher button, active chips) 702 optionBg: '#f7f4fc', // Option/card background â light lavender (light theme) 703 optionText: '#2c2542', // Option/card text color â dark ink 704 optionIcon: '#54467d' // Option/card icon color â brand purple 705 }, 706 707 // Button styling 708 button: { 709 size: '55px', 710 borderRadius: '100px', 711 iconSize: '40px', 712 shadow: '0 4px 8px rgba(0, 0, 0, 0.2)' 713 }, 714 715 // Menu styling 716 menu: { 717 headerHeight: '70px', 718 padding: '0 10px 10px 10px', 719 optionPadding: '20px 10px', 720 optionMargin: '10px', 721 borderRadius: '8px', 722 fontSize: '16px', 723 titleFontSize: '16px', 724 closeButtonSize: '44px' 725 }, 726 727 // Typography 728 typography: { 729 fontFamily: 'Arial, sans-serif', 730 fontSize: '17px', 731 titleFontSize: '22px', 732 titleFontWeight: '700', 733 lineHeight: '1' 734 }, 735 736 // Animation 737 animation: { 738 transition: '0.2s', 739 hoverScale: '1.05' 740 }, 741 742 // Language/Text Configuration 743 lang: { 744 accessibilityMenu: 'Accessibility Menu', 745 closeAccessibilityMenu: 'Close Accessibility Menu', 746 accessibilityTools: 'Accessibility Tools', 747 resetAllSettings: 'Reset All Settings', 748 screenReader: 'Screen Reader', 749 voiceCommand: 'Voice Command', 750 textSpacing: 'Text Spacing', 751 pauseAnimations: 'Pause Animations', 752 hideImages: 'Hide Images', 753 dyslexiaFriendly: 'Dyslexia Friendly', 754 biggerCursor: 'Bigger Cursor', 755 lineHeight: 'Line Height', 756 fontSelection: 'Font Selection', 757 colorFilter: 'Color Filter', 758 textAlign: 'Text Align', 759 textSize: 'Text Size', 760 highContrast: 'High Contrast', 761 defaultFont: 'Default Font', 762 noFilter: 'No Filter', 763 default: 'Default', 764 screenReaderOn: 'Screen reader on', 765 screenReaderOff: 'Screen reader off', 766 voiceControlActivated: 'Voice control activated', 767 notSupportedBrowser: 'is not supported in this browser', 768 close: 'Close', 769 reset: 'Reset' 770 }, 771 772 // Read Aloud (speech synthesis) tuning 773 speech: { 774 rate: 1, // speaking rate, 0.1â10 775 pitch: 1 // voice pitch, 0â2 776 }, 777 778 // Voice Command Configuration - built-in sets for major languages. 779 // Developers can add/override locales; unlisted languages fall back to English. 780 voiceCommands: { 781 en: { 782 showMenu: ['show menu', 'open menu', 'accessibility menu', 'access menu'], 783 highContrast: ['high contrast', 'contrast', 'dark mode', 'increase contrast'], 784 biggerText: ['bigger text', 'large text', 'text size', 'increase text', 'bigger', 'larger text', 'text bigger', 'make text bigger', 'enlarge text'], 785 textSpacing: ['text spacing', 'spacing', 'letter spacing', 'text space'], 786 pauseAnimations: ['pause animations', 'stop animations', 'disable animations', 'no animations'], 787 hideImages: ['hide images', 'remove images', 'no images'],
788 biggerCursor: ['bigger cursor', 'large cursor', 'cursor size', 'big cursor'], 789 lineHeight: ['line height', 'line spacing', 'space between lines', 'line space'], 790 textAlign: ['align text', 'text align', 'center text', 'alignment'], 791 saturation: ['saturation', 'color saturation', 'saturate', 'desaturate', 'grayscale'], 792 fontSelection: ['font selection', 'change font', 'select font', 'font', 'dyslexia font', 'readable font'], 793 colorFilter: ['color filter', 'color blind', 'colorblind', 'filter'], 794 screenReader: ['screen reader', 'read aloud', 'voice reader'], 795 voiceControl: ['voice command', 'voice control', 'voice commands'], 796 showAltText: ['alt text', 'show alt text', 'image description', 'image descriptions'], 797 resetAll: ['reset all', 'reset everything', 'clear all', 'reset settings', 'reset'] 798 }, 799 es: { 800 showMenu: ['abrir menú', 'menú de accesibilidad', 'mostrar menú'], 801 highContrast: ['alto contraste', 'contraste'], 802 biggerText: ['texto más grande', 'agrandar texto', 'tamaño de texto', 'aumentar texto'], 803 textSpacing: ['espaciado de texto', 'espaciado'], 804 pauseAnimations: ['pausar animaciones', 'detener animaciones', 'sin animaciones'], 805 hideImages: ['ocultar imágenes', 'quitar imágenes', 'sin imágenes'], 806 biggerCursor: ['cursor más grande', 'cursor grande'], 807 lineHeight: ['altura de lÃnea', 'interlineado'], 808 textAlign: ['alinear texto', 'alineación', 'centrar texto'], 809 saturation: ['saturación', 'escala de grises', 'desaturar'], 810 fontSelection: ['cambiar fuente', 'seleccionar fuente', 'fuente', 'fuente para dislexia'], 811 colorFilter: ['filtro de color', 'daltónico', 'daltonismo'], 812 screenReader: ['lector de pantalla', 'leer en voz alta'], 813 voiceControl: ['control por voz', 'comando de voz'], 814 showAltText: ['texto alternativo', 'mostrar texto alternativo', 'descripción de imagen'], 815 resetAll: ['restablecer todo', 'reiniciar', 'restablecer', 'borrar todo'] 816 }, 817 fr: { 818 showMenu: ['ouvrir le menu', "menu d'accessibilité", 'afficher le menu'], 819 highContrast: ['contraste élevé', 'contraste'], 820 biggerText: ['texte plus grand', 'agrandir le texte', 'taille du texte', 'augmenter le texte'], 821 textSpacing: ['espacement du texte', 'espacement'], 822 pauseAnimations: ['pause animations', 'arrêter les animations', 'suspendre les animations', 'sans animations'], 823 hideImages: ['masquer les images', 'cacher les images', 'sans images'], 824 biggerCursor: ['curseur plus grand', 'grand curseur'], 825 lineHeight: ['hauteur de ligne', 'interligne'], 826 textAlign: ['aligner le texte', 'alignement', 'centrer le texte'], 827 saturation: ['saturation', 'niveaux de gris', 'désaturer'], 828 fontSelection: ['changer de police', 'choisir la police', 'police', 'police dyslexie'], 829 colorFilter: ['filtre de couleur', 'daltonien', 'daltonisme'], 830 screenReader: ["lecteur d'écran", 'lecture à voix haute', 'lire à voix haute'], 831 voiceControl: ['commande vocale', 'contrôle vocal'], 832 showAltText: ['texte alternatif', 'afficher le texte alternatif', "description de l'image"], 833 resetAll: ['tout réinitialiser', 'réinitialiser', 'effacer tout'] 834 }, 835 de: { 836 showMenu: ['menü öffnen', 'barrierefreiheit menü', 'menü anzeigen'], 837 highContrast: ['hoher kontrast', 'kontrast'], 838 biggerText: ['gröÃerer text', 'text vergröÃern', 'textgröÃe', 'text gröÃer'], 839 textSpacing: ['zeichenabstand', 'abstand', 'textabstand'], 840 pauseAnimations: ['animationen anhalten', 'animationen stoppen', 'keine animationen'], 841 hideImages: ['bilder ausblenden', 'bilder verstecken', 'keine bilder'], 842 biggerCursor: ['gröÃerer cursor', 'groÃer cursor'], 843 lineHeight: ['zeilenhöhe', 'zeilenabstand'], 844 textAlign: ['text ausrichten', 'ausrichtung', 'text zentrieren'], 845 saturation: ['sättigung', 'graustufen', 'entsättigen'], 846 fontSelection: ['schrift ändern', 'schrift wählen', 'schrift', 'legasthenie schrift'], 847 colorFilter: ['farbfilter', 'farbenblind', 'farbenblindheit'], 848 screenReader: ['bildschirmleser', 'vorlesen', 'laut vorlesen'], 849 voiceControl: ['sprachbefehl', 'sprachsteuerung'], 850 showAltText: ['alternativtext', 'alt text anzeigen', 'bildbeschreibung'], 851 resetAll: ['alles zurücksetzen', 'zurücksetzen', 'alles löschen'] 852 }, 853 it: { 854 showMenu: ['apri menu', 'menu accessibilità ', 'mostra menu'], 855 highContrast: ['contrasto elevato', 'contrasto'], 856 biggerText: ['testo più grande', 'ingrandisci testo', 'dimensione testo', 'aumenta testo'], 857 textSpacing: ['spaziatura testo', 'spaziatura'], 858 pauseAnimations: ['pausa animazioni', 'ferma animazioni', 'niente animazioni'], 859 hideImages: ['nascondi immagini', 'rimuovi immagini', 'niente immagini'],
860 biggerCursor: ['cursore più grande', 'cursore grande'], 861 lineHeight: ['interlinea', 'altezza riga'], 862 textAlign: ['allinea testo', 'allineamento', 'centra testo'], 863 saturation: ['saturazione', 'scala di grigi', 'desatura'], 864 fontSelection: ['cambia carattere', 'seleziona carattere', 'carattere', 'carattere dislessia'], 865 colorFilter: ['filtro colore', 'daltonico', 'daltonismo'], 866 screenReader: ['lettore schermo', 'leggi ad alta voce'], 867 voiceControl: ['comando vocale', 'controllo vocale'], 868 showAltText: ['testo alternativo', 'mostra testo alternativo', 'descrizione immagine'], 869 resetAll: ['ripristina tutto', 'ripristina', 'cancella tutto'] 870 }, 871 pt: { 872 showMenu: ['abrir menu', 'menu de acessibilidade', 'mostrar menu'], 873 highContrast: ['alto contraste', 'contraste'], 874 biggerText: ['texto maior', 'aumentar texto', 'tamanho do texto'], 875 textSpacing: ['espaçamento do texto', 'espaçamento'], 876 pauseAnimations: ['pausar animações', 'parar animações', 'sem animações'], 877 hideImages: ['ocultar imagens', 'remover imagens', 'sem imagens'], 878 biggerCursor: ['cursor maior', 'cursor grande'], 879 lineHeight: ['altura da linha', 'espaçamento entre linhas'], 880 textAlign: ['alinhar texto', 'alinhamento', 'centralizar texto'], 881 saturation: ['saturação', 'escala de cinza', 'dessaturar'], 882 fontSelection: ['mudar fonte', 'selecionar fonte', 'fonte', 'fonte para dislexia'], 883 colorFilter: ['filtro de cor', 'daltônico', 'daltonismo'], 884 screenReader: ['leitor de tela', 'ler em voz alta'], 885 voiceControl: ['comando de voz', 'controle por voz'], 886 showAltText: ['texto alternativo', 'mostrar texto alternativo', 'descrição da imagem'], 887 resetAll: ['redefinir tudo', 'redefinir', 'limpar tudo'] 888 }, 889 hi: { 890 showMenu: ['मà¥à¤¨à¥ à¤à¥à¤²à¥à¤', 'सà¥à¤à¤®à¥à¤¯à¤¤à¤¾ मà¥à¤¨à¥'], 891 highContrast: ['à¤à¤à¥à¤ à¤à¤à¤à¥à¤°à¤¾à¤¸à¥à¤', 'à¤à¤à¤à¥à¤°à¤¾à¤¸à¥à¤'], 892 biggerText: ['बड़ा à¤à¥à¤à¥à¤¸à¥à¤', 'à¤à¥à¤à¥à¤¸à¥à¤ बड़ा à¤à¤°à¥à¤', 'à¤à¥à¤à¥à¤¸à¥à¤ à¤à¤à¤¾à¤°'], 893 textSpacing: ['à¤à¥à¤à¥à¤¸à¥à¤ सà¥à¤ªà¥à¤¸à¤¿à¤à¤', 'सà¥à¤ªà¥à¤¸à¤¿à¤à¤'], 894 pauseAnimations: ['à¤à¤¨à¤¿à¤®à¥à¤¶à¤¨ रà¥à¤à¥à¤', 'à¤à¤¨à¤¿à¤®à¥à¤¶à¤¨ बà¤à¤¦ à¤à¤°à¥à¤'], 895 hideImages: ['à¤à¤¿à¤¤à¥à¤° à¤à¤¿à¤ªà¤¾à¤à¤', 'à¤à¤®à¥à¤ à¤à¤¿à¤ªà¤¾à¤à¤'], 896 biggerCursor: ['बड़ा à¤à¤°à¥à¤¸à¤°'], 897 lineHeight: ['पà¤à¤à¥à¤¤à¤¿ à¤à¤à¤à¤¾à¤', 'लाà¤à¤¨ सà¥à¤ªà¥à¤¸à¤¿à¤à¤'], 898 textAlign: ['à¤à¥à¤à¥à¤¸à¥à¤ सà¤à¤°à¥à¤à¤¿à¤¤ à¤à¤°à¥à¤', 'à¤à¥à¤à¥à¤¸à¥à¤ सà¥à¤à¤à¤° à¤à¤°à¥à¤'], 899 saturation: ['सà¤à¤¤à¥à¤ªà¥à¤¤à¤¿', 'à¤à¥à¤°à¥à¤¸à¥à¤à¥à¤²'], 900 fontSelection: ['फ़à¥à¤¨à¥à¤ बदलà¥à¤', 'फ़à¥à¤¨à¥à¤ à¤à¥à¤¨à¥à¤', 'फ़à¥à¤¨à¥à¤'], 901 colorFilter: ['रà¤à¤ फ़िलà¥à¤à¤°', 'à¤à¤²à¤° बà¥à¤²à¤¾à¤à¤à¤¡'], 902 screenReader: ['सà¥à¤à¥à¤°à¥à¤¨ रà¥à¤¡à¤°', 'à¤à¤¼à¥à¤° सॠपढ़à¥à¤'], 903 voiceControl: ['वà¥à¤à¤¸ à¤à¤®à¤¾à¤à¤¡', 'वà¥à¤à¤¸ à¤à¤à¤à¥à¤°à¥à¤²'], 904 showAltText: ['वà¥à¤à¤²à¥à¤ªà¤¿à¤ à¤à¥à¤à¥à¤¸à¥à¤', 'à¤à¤²à¥à¤ à¤à¥à¤à¥à¤¸à¥à¤'], 905 resetAll: ['सब रà¥à¤¸à¥à¤ à¤à¤°à¥à¤', 'रà¥à¤¸à¥à¤ à¤à¤°à¥à¤'] 906 } 907 }, 908 909 // Grid Layout Configuration 910 // Grid Layout Configuration 911 gridLayout: { 912 columns: '1fr 1fr 1fr', // 3-column layout 913 gap: '10px' // Gap between grid items 914 } 915}; 916 917// Function to deep merge user configuration with defaults 918function mergeConfigs(defaultConfig, userConfig) { 919 const result = { ...defaultConfig }; 920 921 if (!userConfig) return result; 922 923 for (const key in userConfig) { 924 if (!Object.prototype.hasOwnProperty.call(userConfig, key)) continue; 925 // Block prototype-pollution vectors 926 if (key === '__proto__' || key === 'constructor' || key === 'prototype') continue; 927 928 const userVal = userConfig[key]; 929 const defVal = defaultConfig[key]; 930 931 if (typeof userVal === 'object' && userVal !== null && !Array.isArray(userVal)) { 932 const base = (typeof defVal === 'object' && defVal !== null && !Array.isArray(defVal)) ? defVal : {}; 933 result[key] = mergeConfigs(base, userVal); 934 } else { 935 // If the default defines this key, only accept a value of the same shape 936 if (defVal !== undefined) { 937 if (Array.isArray(defVal) !== Array.isArray(userVal)) continue; 938 if (!Array.isArray(defVal) && typeof defVal !== typeof userVal) continue; 939 } 940 result[key] = userVal; 941 } 942 } 943 944 return result; 945} 946 947// Merge user configuration with defaults 948const WIDGET_CONFIG = mergeConfigs(DEFAULT_WIDGET_CONFIG, window.ENABLESTACK_CONFIG || {}); 949 950// Bump when the localStorage schema changes so stale settings can be migrated. 951const EU_SETTINGS_VERSION = '1.2'; 952 953// =========================================== 954// THEME / BRANDING COLORS 955// =========================================== 956// The widget's colour is decided once, at integration time â NOT by visitors: 957// ⢠WordPress: the plugin auto-matches your theme on activation (adjustable 958// from Settings â Enablestack Widget). 959// ⢠npm: you enter your brand hex at install time; it is baked into the build.
960// ⢠Manual embed: set ENABLESTACK_CONFIG.colors.primary (or .theme). 961// From a single primary colour the widget derives its full accent palette 962// (bright/deep/gradient/glows) so one choice re-themes the whole widget. 963// The built-in default is the EnableUser brand purple, #54467D. 964 965const EU_THEME_PRESETS = { 966 purple: '#54467D', 967 teal: '#14b8a6', 968 blue: '#2563eb', 969 indigo: '#4f46e5', 970 violet: '#7c3aed', 971 rose: '#e11d48', 972 orange: '#ea580c', 973 green: '#16a34a', 974 slate: '#475569', 975 dark: '#111827' 976}; 977 978function euHexToRgb(hex) { 979 let h = String(hex == null ? '' : hex).trim().replace(/^#/, ''); 980 if (h.length === 3) h = h.split('').map(function (c) { return c + c; }).join(''); 981 if (!/^[0-9a-fA-F]{6}$/.test(h)) return null; 982 return { r: parseInt(h.slice(0, 2), 16), g: parseInt(h.slice(2, 4), 16), b: parseInt(h.slice(4, 6), 16) }; 983} 984function euClampByte(v) { return Math.max(0, Math.min(255, Math.round(v))); } 985function euRgbToHex(r, g, b) { 986 return '#' + [r, g, b].map(function (x) { return euClampByte(x).toString(16).padStart(2, '0'); }).join(''); 987} 988function euLighten(hex, amt) { 989 const c = euHexToRgb(hex); if (!c) return hex; 990 return euRgbToHex(c.r + (255 - c.r) * amt, c.g + (255 - c.g) * amt, c.b + (255 - c.b) * amt); 991} 992function euDarken(hex, amt) { 993 const c = euHexToRgb(hex); if (!c) return hex; 994 return euRgbToHex(c.r * (1 - amt), c.g * (1 - amt), c.b * (1 - amt)); 995} 996function euRgba(hex, a) { 997 const c = euHexToRgb(hex); if (!c) return 'rgba(0, 0, 0, ' + a + ')'; 998 return 'rgba(' + c.r + ', ' + c.g + ', ' + c.b + ', ' + a + ')'; 999} 1000// Blend `amt` (0..1) of `hex2` into `hex`. 1001function euMix(hex, hex2, amt) { 1002 const a = euHexToRgb(hex), b = euHexToRgb(hex2); if (!a || !b) return hex; 1003 return euRgbToHex(a.r + (b.r - a.r) * amt, a.g + (b.g - a.g) * amt, a.b + (b.b - a.b) * amt); 1004} 1005 1006// Build the full widget palette from one primary colour. Structural (dark 1007// surface) colours come from explicit overrides/defaults; accent shades are 1008// always derived from the primary so the widget stays colour-consistent. 1009function euDerivePalette(primary, overrides) { 1010 overrides = overrides || {}; 1011 const base = DEFAULT_WIDGET_CONFIG.colors; 1012 const bright = euLighten(primary, 0.18); 1013 const deep = euDarken(primary, 0.30); 1014 return { 1015 primary: primary, 1016 primaryBright: bright, 1017 primaryDeep: deep, 1018 brandGradient: 'linear-gradient(135deg, ' + bright + ' 0%, ' + deep + ' 100%)', 1019 secondary: overrides.secondary || base.secondary, 1020 optionBg: overrides.optionBg || base.optionBg, 1021 optionText: overrides.optionText || base.optionText, 1022 optionIcon: overrides.optionIcon || base.optionIcon 1023 }; 1024} 1025 1026// Which primary should the widget use? 1027// configured colors.primary > configured theme preset > built-in default (#54467D). 1028function euResolveInitialPrimary() { 1029 const uc = (window.ENABLESTACK_CONFIG && window.ENABLESTACK_CONFIG.colors) || {}; 1030 if (uc.primary && euHexToRgb(uc.primary)) return uc.primary; 1031 const ut = window.ENABLESTACK_CONFIG && window.ENABLESTACK_CONFIG.theme; 1032 if (ut && EU_THEME_PRESETS[ut]) return EU_THEME_PRESETS[ut]; 1033 return null; // keep the built-in default palette 1034} 1035 1036// Apply the resolved palette so every build-time interpolation reflects it. 1037const euInitialPrimary = euResolveInitialPrimary(); 1038if (euInitialPrimary) { 1039 const euUserColors = (window.ENABLESTACK_CONFIG && window.ENABLESTACK_CONFIG.colors) || {}; 1040 WIDGET_CONFIG.colors = euDerivePalette(euInitialPrimary, euUserColors); 1041} 1042 1043// Map a palette to the CSS custom properties the stylesheet reads from. 1044function euThemeVarMap(colors) { 1045 return { 1046 // Accent (themeable) â derived from the chosen primary 1047 '--eu-primary': colors.primary, 1048 '--eu-primary-bright': colors.primaryBright, 1049 '--eu-primary-deep': colors.primaryDeep, 1050 '--eu-gradient': colors.brandGradient, 1051 '--eu-secondary': colors.secondary, // on-accent (white) 1052 '--eu-option-icon': colors.primary, // card icons follow the accent 1053 // Light-theme surfaces (fixed, high-contrast) 1054 '--eu-surface': '#ffffff', // panel / white items 1055 '--eu-option-bg': '#f7f4fc', // cards / sections 1056 '--eu-surface-2': '#f2eefa', 1057 '--eu-hover': '#ece5f7', 1058 '--eu-border': '#e7e0f2', 1059 '--eu-border-strong': '#d6cce8', 1060 '--eu-header-bg': '#ffffff', 1061 '--eu-option-text': '#2c2542', // main ink 1062 '--eu-text': '#2c2542', 1063 '--eu-text-muted': '#726b8c', 1064 // Accent tints / glows (rgba so they read softly on light) 1065 '--eu-active-bg': euMix('#ffffff', colors.primary, 0.10), 1066 '--eu-active-tint': euRgba(colors.primary, 0.10), 1067 '--eu-glow-deep': euRgba(colors.primaryDeep, 0.32), 1068 '--eu-glow': euRgba(colors.primary, 0.42), 1069 '--eu-glow-mid': euRgba(colors.primary, 0.30), 1070 '--eu-glow-soft': euRgba(colors.primary, 0.12), 1071 '--eu-glow-header': euRgba(colors.primary, 0.16), 1072 '--eu-logo-shadow': euRgba(colors.primaryDeep, 0.45) 1073 }; 1074} 1075 1076// Serialize the var map for baking into :host / :root at build time. 1077function euBuildCssVars(colors) {
1078 const map = euThemeVarMap(colors); 1079 return Object.keys(map).map(function (k) { return k + ': ' + map[k] + ';'; }).join('\n '); 1080} 1081const euCssVars = euBuildCssVars(WIDGET_CONFIG.colors); 1082 1083// =========================================== 1084// STYLES & VISUAL ASSETS 1085// =========================================== 1086 1087// Widget styles (will go inside Shadow DOM - NOT affected by page styles or accessibility features) 1088const widgetStyles = ` 1089 :host { 1090 all: initial; 1091 font-family: ${WIDGET_CONFIG.typography.fontFamily}; 1092 /* Theme colours â override any of these to re-skin the widget live */ 1093 ${euCssVars} 1094 } 1095 1096 * { 1097 box-sizing: border-box; 1098 } 1099 1100 #eu-accessibility-fixed-button { 1101 position: fixed !important; 1102 ${WIDGET_CONFIG.widgetPosition.side}: ${WIDGET_CONFIG.widgetPosition[WIDGET_CONFIG.widgetPosition.side]} !important; 1103 bottom: ${WIDGET_CONFIG.widgetPosition.bottom} !important; 1104 z-index: 9999; 1105 background: transparent; 1106 padding: 0; 1107 border-radius: 100%; 1108 } 1109 1110 #eu-accessibility-button { 1111 background: var(--eu-gradient); 1112 border: solid 2px rgba(255, 255, 255, 0.92); 1113 border-radius: ${WIDGET_CONFIG.button.borderRadius}; 1114 cursor: pointer; 1115 width: ${WIDGET_CONFIG.button.size}; 1116 height: ${WIDGET_CONFIG.button.size}; 1117 box-shadow: 0 8px 22px var(--eu-glow-deep), 0 2px 6px rgba(0, 0, 0, 0.28); 1118 transition: transform ${WIDGET_CONFIG.animation.transition}, box-shadow ${WIDGET_CONFIG.animation.transition} !important; 1119 display: flex; 1120 justify-content: center; 1121 align-items: center; 1122 } 1123 1124 #eu-accessibility-button:hover { 1125 transform: scale(${WIDGET_CONFIG.animation.hoverScale}) translateY(-1px); 1126 box-shadow: 0 12px 28px var(--eu-glow), 0 3px 8px rgba(0, 0, 0, 0.3); 1127 } 1128 1129 #eu-accessibility-button:focus { 1130 outline: 3px solid var(--eu-primary-bright); 1131 outline-offset: 3px; 1132 } 1133 1134 #eu-accessibility-button svg { 1135 width: ${WIDGET_CONFIG.button.iconSize}; 1136 height: ${WIDGET_CONFIG.button.iconSize}; 1137 fill: var(--eu-secondary); 1138 pointer-events: none; 1139 } 1140 1141 #eu-accessibility-menu { 1142 position: fixed; 1143 bottom: 20px; 1144 ${WIDGET_CONFIG.widgetPosition.side}: ${WIDGET_CONFIG.widgetPosition[WIDGET_CONFIG.widgetPosition.side]}; 1145 width: ${WIDGET_CONFIG.widgetWidth}; 1146 max-height: calc(100vh - 90px); 1147 overflow-y: auto; 1148 background-color: var(--eu-surface); 1149 padding: 0; 1150 display: none; 1151 font-family: ${WIDGET_CONFIG.typography.fontFamily}; 1152 z-index: 999999; 1153 scrollbar-width: thin; 1154 line-height:1 !important; 1155 border-radius: 14px; 1156 box-shadow: 0 16px 44px rgba(44, 37, 66, 0.16), 0 4px 14px rgba(44, 37, 66, 0.10); 1157 } 1158 1159 .eu-accessibility-option { 1160 font-size: ${WIDGET_CONFIG.menu.fontSize}; 1161 display: flex; 1162 flex-direction: column; 1163 align-items: center; 1164 justify-content: space-around; 1165 padding: 5px; 1166 width: 100%; 1167 background-color: var(--eu-option-bg); 1168 color: var(--eu-option-text); 1169 border: 1px solid var(--eu-border); 1170 cursor: pointer; 1171 border-radius: ${WIDGET_CONFIG.menu.borderRadius}; 1172 transition: background-color ${WIDGET_CONFIG.animation.transition}, border-color ${WIDGET_CONFIG.animation.transition}; 1173 line-height: ${WIDGET_CONFIG.typography.lineHeight} !important; 1174 gap: 3px; 1175 min-height: 80px; 1176 } 1177 1178 .eu-accessibility-option:hover { 1179 border-color: var(--eu-border-strong); 1180 background-color: var(--eu-hover); 1181 } 1182 1183 .eu-accessibility-option.active { 1184 border-color: var(--eu-primary); 1185 background: linear-gradient(160deg, var(--eu-active-bg) 0%, var(--eu-option-bg) 100%); 1186 box-shadow: inset 0 0 0 1px var(--eu-glow-mid), 0 0 12px var(--eu-glow-soft); 1187 } 1188 1189 .eu-accessibility-option.active .eu-icon { 1190 color: var(--eu-primary); 1191 } 1192 1193 .eu-accessibility-option:disabled { 1194 opacity: 0.5; 1195 cursor: not-allowed; 1196 } 1197 1198 .eu-icon { 1199 width: 28px; 1200 height: 28px; 1201 color: var(--eu-primary); 1202 fill: var(--eu-primary); 1203 flex-shrink: 0; 1204 } 1205 1206 .eu-icon svg { 1207 width: 100%; 1208 height: 100%; 1209 fill: currentColor; 1210 } 1211 1212 .eu-button-text { 1213 text-align: center; 1214 line-height: 1.2; 1215 font-size: 12px; 1216 font-weight: 600; 1217 } 1218 1219 .eu-option-steps { 1220 display: flex; 1221 gap: 4px; 1222 align-items: center; 1223 justify-content: center; 1224 margin-top: 2px; 1225 } 1226 1227 .eu-option-step { 1228 width: 22px; 1229 height: 4px; 1230 border-radius: 2px; 1231 background-color: var(--eu-border); 1232 transition: background-color ${WIDGET_CONFIG.animation.transition}; 1233 } 1234 1235 .eu-option-step.active { 1236 background-color: var(--eu-primary); 1237 } 1238 1239 .eu-close { 1240 background: none; 1241 border: none; 1242 font-size: 30px; 1243 color: var(--eu-text); 1244 cursor: pointer; 1245 line-height: ${WIDGET_CONFIG.typography.lineHeight}; 1246 border-radius: ${WIDGET_CONFIG.button.borderRadius}; 1247 width: 32px; 1248 height: 32px; 1249 position: relative; 1250 display: flex; 1251 align-items: center; 1252 justify-content: center; 1253 flex-shrink: 0; 1254 } 1255 1256 .eu-close::before { 1257 content: 'Ã'; 1258 position: absolute; 1259 top: 50%; 1260 left: 50%; 1261 transform: translate(-50%, -50%); 1262 font-size: 28px; 1263 line-height: 1; 1264 } 1265 1266 /* Reset shown as a clearly-labelled box (not just an icon) */ 1267 .eu-reset-button { 1268 background: #ffffff; 1269 border: 1px solid var(--eu-primary); 1270 color: var(--eu-primary); 1271 cursor: pointer; 1272 border-radius: 7px; 1273 padding: 6px 12px; 1274 flex-shrink: 0; 1275 display: inline-flex; 1276 align-items: center; 1277 justify-content: center; 1278 transition: background-color ${WIDGET_CONFIG.animation.transition}, border-color ${WIDGET_CONFIG.animation.transition}; 1279 } 1280 1281 .eu-reset-label { 1282 font-family: ${WIDGET_CONFIG.typography.fontFamily}; 1283 font-size: 13px; 1284 font-weight: 700; 1285 letter-spacing: 0.3px; 1286 line-height: 1; 1287 color: var(--eu-primary); 1288 text-transform: uppercase; 1289 white-space: nowrap; 1290 } 1291 1292 .eu-close:focus, .eu-reset-button:focus { 1293 outline: solid 2px var(--eu-primary); 1294 outline-offset: 1px; 1295 } 1296 1297 .eu-close:hover { 1298 color: var(--eu-text); 1299 background: var(--eu-hover); 1300 } 1301 1302 .eu-reset-button:hover { 1303 background: var(--eu-active-tint); 1304 border-color: var(--eu-primary-deep); 1305 } 1306 1307 /* Tooltip styles */ 1308 .eu-tooltip { 1309 position: absolute; 1310 bottom: -35px; 1311 left: 50%; 1312 transform: translateX(-50%); 1313 background-color: rgba(0, 0, 0, 0.8); 1314 color: white; 1315 padding: 6px 10px; 1316 border-radius: 4px; 1317 font-size: 12px; 1318 white-space: nowrap; 1319 pointer-events: none; 1320 opacity: 0; 1321 transition: opacity 0.2s; 1322 z-index: 1000; 1323 } 1324 1325 .eu-tooltip::before { 1326 content: ''; 1327 position: absolute; 1328 top: -4px; 1329 left: 50%; 1330 transform: translateX(-50%); 1331 width: 0; 1332 height: 0; 1333 border-left: 5px solid transparent; 1334 border-right: 5px solid transparent; 1335 border-bottom: 5px solid rgba(0, 0, 0, 0.8); 1336 } 1337 1338 .eu-close:hover .eu-tooltip, 1339 .eu-close:focus .eu-tooltip, 1340 .eu-reset-button:hover .eu-tooltip, 1341 .eu-reset-button:focus .eu-tooltip { 1342 opacity: 1; 1343 } 1344 1345 .eu-header { 1346 display: flex; 1347 flex-direction: row; 1348 align-items: center; 1349 padding: 8px 12px; 1350 background: var(--eu-header-bg); 1351 position: sticky; 1352 top: 0; 1353 z-index: 10; 1354 box-shadow: inset 0 -1px 0 var(--eu-border); 1355 gap: 8px; 1356 border-radius: 14px 14px 0 0; 1357 } 1358 1359 /* Full enableuser logo â left-aligned, takes the remaining width, never clipped */ 1360 .eu-header-logo { 1361 flex: 1 1 auto; 1362 min-width: 0; 1363 height: auto; 1364 width: auto; 1365 max-width: 100%; 1366 max-height: clamp(34px, calc(30px + var(--eu-scale, 1) * 8px), 52px); 1367 object-fit: contain; 1368 object-position: left center; 1369 user-select: none;
1370 -webkit-user-drag: none; 1371 } 1372 1373 /* Resize / expand handle â an inline control in the top row */ 1374 .eu-resize-handle { 1375 flex-shrink: 0; 1376 width: 30px; 1377 height: 30px; 1378 display: inline-flex; 1379 align-items: center; 1380 justify-content: center; 1381 border-radius: 7px; 1382 color: var(--eu-text-muted); 1383 opacity: 0.8; 1384 cursor: nwse-resize; 1385 background: transparent; 1386 border: none; 1387 transition: opacity 0.15s, background-color 0.15s; 1388 touch-action: none; 1389 } 1390 .eu-resize-handle:hover { opacity: 1; background: var(--eu-hover); } 1391 .eu-resize-handle:focus { outline: none; opacity: 1; } 1392 .eu-resize-handle:focus-visible { outline: 2px solid var(--eu-primary); } 1393 .eu-resize-handle svg { 1394 width: 16px; 1395 height: 16px; 1396 fill: none; 1397 stroke: currentColor; 1398 stroke-width: 1.7; 1399 stroke-linecap: round; 1400 stroke-linejoin: round; 1401 } 1402 #eu-accessibility-menu.eu-side-right .eu-resize-handle { transform: scaleX(-1); } 1403 #eu-accessibility-menu.eu-resizing { user-select: none; } 1404 1405 .eu-content { 1406 padding: 12px 12px 0px 12px; 1407 } 1408 1409 .eu-options-grid { 1410 display: grid; 1411 grid-template-columns: ${WIDGET_CONFIG.gridLayout.columns}; 1412 gap: 8px; 1413 margin-bottom: 10px; 1414 } 1415 1416 .eu-title { 1417 margin: 0; 1418 color: var(--eu-secondary); 1419 line-height: 1 !important; 1420 font-weight: ${WIDGET_CONFIG.typography.titleFontWeight}; 1421 flex: 1; 1422 text-align: left; 1423 display: flex; 1424 flex-direction: column; 1425 gap: 3px; 1426 letter-spacing: 0px !important; 1427 word-spacing: 0px !important; 1428 } 1429 1430 .eu-title-main { 1431 font-size: 16px; 1432 font-weight: 800; 1433 color: var(--eu-secondary); 1434 letter-spacing: 0.2px; 1435 line-height: 1.15; 1436 } 1437 1438 .eu-title-main .eu-title-accent { 1439 background: linear-gradient(90deg, var(--eu-primary-bright), var(--eu-primary)); 1440 -webkit-background-clip: text; 1441 background-clip: text; 1442 -webkit-text-fill-color: transparent; 1443 color: var(--eu-primary-bright); 1444 } 1445 1446 .eu-title-sub { 1447 font-size: 10.5px; 1448 font-weight: 600; 1449 color: var(--eu-primary-bright); 1450 letter-spacing: 1.2px; 1451 text-transform: uppercase; 1452 line-height: 1.2; 1453 } 1454 1455 .eu-footer { 1456 text-align: center; 1457 padding: 10px 12px 14px; 1458 font-size: 11.5px; 1459 color: var(--eu-text-muted); 1460 border-top: 1px solid var(--eu-hover); 1461 margin-top: 5px; 1462 letter-spacing: 0.2px; 1463 } 1464 1465 .eu-footer a { 1466 color: var(--eu-primary); 1467 text-decoration: none; 1468 font-weight: 600; 1469 } 1470 1471 .eu-footer a:hover { 1472 text-decoration: underline; 1473 } 1474 1475 .eu-footer .eu-brand-name { 1476 font-weight: 800; 1477 letter-spacing: 0.3px; 1478 background: linear-gradient(90deg, var(--eu-primary-bright), var(--eu-primary)); 1479 -webkit-background-clip: text; 1480 background-clip: text; 1481 -webkit-text-fill-color: transparent; 1482 color: var(--eu-primary-bright); 1483 } 1484 1485 /* EnableUser logo in the footer (same wordmark as the header) */ 1486 .eu-footer-brand { 1487 display: inline-flex; 1488 align-items: center; 1489 vertical-align: middle; 1490 } 1491 .eu-footer-logo { 1492 height: 21px; 1493 width: auto; 1494 max-width: 190px; 1495 object-fit: contain; 1496 vertical-align: middle; 1497 user-select: none; 1498 } 1499 1500 /* Footer utility links (Accessibility Statement / Send Feedback) */ 1501 .eu-footer-links { 1502 display: flex; 1503 flex-wrap: wrap; 1504 justify-content: center; 1505 gap: 6px 14px; 1506 padding: 8px 12px 0; 1507 } 1508 .eu-footer-links a { 1509 color: var(--eu-primary); 1510 text-decoration: none; 1511 font-size: 12px; 1512 font-weight: 600; 1513 } 1514 .eu-footer-links a:hover { text-decoration: underline; } 1515 1516 /* Custom Color inline panel */ 1517 .eu-custom-color-panel { 1518 background: var(--eu-option-bg); 1519 border: 1px solid var(--eu-border); 1520 border-radius: 8px; 1521 padding: 12px; 1522 margin-bottom: 10px; 1523 display: none; 1524 } 1525 .eu-custom-color-panel.eu-open { display: block; } 1526 .eu-ccp-row { 1527 display: flex; 1528 align-items: center; 1529 justify-content: space-between; 1530 margin-bottom: 8px; 1531 color: var(--eu-option-text); 1532 font-size: 13px; 1533 } 1534 .eu-ccp-row input[type="color"] { 1535 width: 44px; 1536 height: 28px; 1537 border: none; 1538 background: none; 1539 padding: 0; 1540 cursor: pointer; 1541 } 1542 .eu-ccp-actions { display: flex; gap: 8px; margin-top: 4px; } 1543 .eu-ccp-btn { 1544 flex: 1; 1545 padding: 8px; 1546 border: none; 1547 border-radius: 6px; 1548 font-size: 13px; 1549 font-weight: 600; 1550 cursor: pointer; 1551 color: #fff; 1552 background: var(--eu-primary); 1553 } 1554 .eu-ccp-btn.eu-ccp-reset { background: var(--eu-border-strong); } 1555 1556 /* Personalize Your Experience Section */ 1557 .eu-profiles-section { 1558 background: var(--eu-option-bg); 1559 border-radius: 8px; 1560 margin-bottom: 10px; 1561 padding: 10px; 1562 border: 1px solid var(--eu-border); 1563 } 1564 1565 .eu-profiles-title { 1566 color: var(--eu-option-text); 1567 font-size: 13px; 1568 font-weight: 700; 1569 margin-bottom: 8px; 1570 } 1571 1572 .eu-profiles-row { 1573 display: grid; 1574 grid-template-columns: 1fr 1fr; 1575 gap: 8px; 1576 } 1577 1578 .eu-profile-chip { 1579 background: transparent; 1580 color: var(--eu-option-text); 1581 border: 1px solid var(--eu-border); 1582 border-radius: 20px; 1583 padding: 8px 10px; 1584 font-size: 13px; 1585 font-family: inherit; 1586 cursor: pointer; 1587 transition: all ${WIDGET_CONFIG.animation.transition}; 1588 } 1589 1590 .eu-profile-chip:hover, 1591 .eu-profile-chip:focus { 1592 border-color: var(--eu-primary); 1593 outline: none; 1594 } 1595 1596 .eu-profile-chip.active { 1597 background: var(--eu-primary); 1598 color: #ffffff; 1599 border-color: var(--eu-primary); 1600 font-weight: 700; 1601 } 1602 1603 .eu-personalize-section { 1604 background: var(--eu-option-bg); 1605 border-radius: 8px; 1606 margin-bottom: 10px; 1607 overflow: hidden; 1608 border: 1px solid var(--eu-border); 1609 } 1610 1611 .eu-personalize-header { 1612 display: flex; 1613 align-items: center; 1614 justify-content: space-between; 1615 padding: 9px 12px; 1616 background: transparent; 1617 color: var(--eu-text); 1618 cursor: pointer; 1619 border: none; 1620 width: 100%; 1621 font-family: ${WIDGET_CONFIG.typography.fontFamily}; 1622 font-size: 13px; 1623 font-weight: 700; 1624 letter-spacing: 0.3px; 1625 transition: background 0.2s; 1626 } 1627 1628 .eu-personalize-header:hover { 1629 opacity: 0.92; 1630 } 1631 1632 .eu-personalize-header:focus { 1633 outline: 2px solid var(--eu-primary); 1634 outline-offset: -2px; 1635 } 1636 1637 .eu-personalize-chevron { 1638 transition: transform 0.25s ease; 1639 width: 18px; 1640 height: 18px; 1641 fill: var(--eu-text); 1642 flex-shrink: 0; 1643 } 1644 1645 .eu-personalize-header[aria-expanded="true"] .eu-personalize-chevron { 1646 transform: rotate(180deg); 1647 } 1648 1649 .eu-personalize-body { 1650 display: none; 1651 padding: 0; 1652 } 1653 1654 .eu-personalize-body.eu-open { 1655 display: block; 1656 } 1657 1658 .eu-page-structure-label { 1659 font-size: 13px; 1660 font-weight: 600; 1661 color: var(--eu-text); 1662 padding: 12px 14px 8px; 1663 display: flex; 1664 align-items: center; 1665 gap: 6px; 1666 } 1667 1668 .eu-page-structure-label svg { 1669 width: 16px; 1670 height: 16px; 1671 fill: var(--eu-primary); 1672 } 1673 1674 .eu-structure-tabs { 1675 display: flex; 1676 gap: 0; 1677 border-bottom: 2px solid var(--eu-border); 1678 margin: 0 10px; 1679 } 1680 1681 .eu-structure-tab { 1682 flex: 1; 1683 padding: 9px 6px; 1684 font-size: 13px; 1685 font-weight: 600; 1686 font-family: ${WIDGET_CONFIG.typography.fontFamily}; 1687 background: none; 1688 border: none; 1689 border-bottom: 3px solid transparent; 1690 color: var(--eu-text-muted); 1691 cursor: pointer; 1692 transition: color 0.2s, border-color 0.2s; 1693 text-align: center; 1694 display: flex; 1695 align-items: center; 1696 justify-content: center; 1697 gap: 5px; 1698 } 1699 1700 .eu-structure-tab:hover { 1701 color: var(--eu-text); 1702 } 1703 1704 .eu-structure-tab:focus { 1705 outline: 2px solid var(--eu-primary); 1706 outline-offset: -2px; 1707 } 1708 1709 .eu-structure-tab.eu-active { 1710 color: var(--eu-primary); 1711 border-bottom-color: var(--eu-primary); 1712 } 1713 1714 .eu-structure-tab .eu-tab-count { 1715 background: var(--eu-border); 1716 color: var(--eu-text-muted); 1717 font-size: 11px; 1718 font-weight: 700; 1719 border-radius: 10px; 1720 padding: 1px 7px;
1721 min-width: 20px; 1722 text-align: center; 1723 } 1724 1725 .eu-structure-tab.eu-active .eu-tab-count { 1726 background: var(--eu-primary); 1727 color: var(--eu-secondary); 1728 } 1729 1730 .eu-structure-panel { 1731 display: none; 1732 max-height: 220px; 1733 overflow-y: auto; 1734 padding: 6px 10px 10px; 1735 scrollbar-width: thin; 1736 } 1737 1738 .eu-structure-panel.eu-active { 1739 display: block; 1740 } 1741 1742 .eu-structure-item { 1743 display: flex; 1744 align-items: center; 1745 gap: 8px; 1746 padding: 8px 10px; 1747 margin: 3px 0; 1748 border-radius: 6px; 1749 cursor: pointer; 1750 font-size: 13px; 1751 color: var(--eu-text); 1752 background: var(--eu-surface); 1753 border: 1px solid var(--eu-border); 1754 transition: background 0.15s, border-color 0.15s; 1755 text-align: left; 1756 width: 100%; 1757 font-family: ${WIDGET_CONFIG.typography.fontFamily}; 1758 line-height: 1.35; 1759 } 1760 1761 .eu-structure-item:hover { 1762 background: var(--eu-hover); 1763 border-color: var(--eu-primary); 1764 } 1765 1766 .eu-structure-item:focus { 1767 outline: 2px solid var(--eu-primary); 1768 outline-offset: -1px; 1769 } 1770 1771 .eu-structure-item-tag { 1772 font-size: 10px; 1773 font-weight: 700; 1774 color: var(--eu-primary); 1775 background: var(--eu-active-tint); 1776 padding: 2px 6px; 1777 border-radius: 4px; 1778 flex-shrink: 0; 1779 text-transform: uppercase; 1780 letter-spacing: 0.5px; 1781 } 1782 1783 .eu-structure-item-text { 1784 overflow: hidden; 1785 text-overflow: ellipsis; 1786 white-space: nowrap; 1787 flex: 1; 1788 min-width: 0; 1789 } 1790 1791 .eu-structure-empty { 1792 padding: 16px 10px; 1793 text-align: center; 1794 color: var(--eu-text-muted); 1795 font-size: 13px; 1796 font-style: italic; 1797 } 1798 1799 /* Show Shortcuts Toggle Bar */ 1800 .eu-shortcuts-bar { 1801 display: flex; 1802 align-items: center; 1803 justify-content: space-between; 1804 background: transparent; 1805 border-radius: 8px; 1806 padding: 9px 4px; 1807 margin-bottom: 10px; 1808 } 1809 1810 .eu-shortcuts-label { 1811 font-size: 13px; 1812 font-weight: 500; 1813 color: var(--eu-text); 1814 letter-spacing: 0.2px; 1815 } 1816 1817 .eu-toggle-switch { 1818 position: relative; 1819 width: 46px; 1820 height: 26px; 1821 flex-shrink: 0; 1822 cursor: pointer; 1823 background: none; 1824 border: none; 1825 padding: 0; 1826 } 1827 1828 .eu-toggle-track { 1829 position: absolute; 1830 top: 0; 1831 left: 0; 1832 width: 46px; 1833 height: 26px; 1834 border-radius: 13px; 1835 background: var(--eu-border); 1836 transition: background 0.25s; 1837 } 1838 1839 .eu-toggle-switch[aria-checked="true"] .eu-toggle-track { 1840 background: var(--eu-primary); 1841 } 1842 1843 .eu-toggle-thumb { 1844 position: absolute; 1845 top: 3px; 1846 left: 3px; 1847 width: 20px; 1848 height: 20px; 1849 border-radius: 50%; 1850 background: #fff; 1851 transition: left 0.25s; 1852 box-shadow: 0 1px 3px rgba(0,0,0,0.3); 1853 } 1854 1855 .eu-toggle-switch[aria-checked="true"] .eu-toggle-thumb { 1856 left: 23px; 1857 } 1858 1859 .eu-toggle-switch:focus { 1860 outline: 2px solid var(--eu-primary); 1861 outline-offset: 2px; 1862 border-radius: 13px; 1863 } 1864 1865 /* Additional Keyboard Shortcuts Section */ 1866 .eu-additional-shortcuts { 1867 background: var(--eu-option-bg); 1868 border: 1px solid var(--eu-border); 1869 border-radius: 8px; 1870 margin-top: 10px; 1871 margin-bottom: 6px; 1872 padding: 2px 0; 1873 } 1874 1875 .eu-additional-shortcuts-title { 1876 font-size: 12px; 1877 font-weight: 600; 1878 color: var(--eu-text); 1879 padding: 8px 12px 4px; 1880 letter-spacing: 0.2px; 1881 } 1882 1883 .eu-shortcut-row { 1884 display: flex; 1885 align-items: center; 1886 justify-content: space-between; 1887 padding: 7px 12px; 1888 border-bottom: 1px solid var(--eu-border); 1889 } 1890 1891 .eu-shortcut-row:last-child { 1892 border-bottom: none; 1893 } 1894 1895 .eu-shortcut-action { 1896 font-size: 12px; 1897 color: var(--eu-text); 1898 font-weight: 400; 1899 } 1900 1901 .eu-shortcut-key { 1902 display: inline-flex; 1903 align-items: center; 1904 justify-content: center; 1905 min-width: 24px; 1906 height: 22px; 1907 padding: 0 6px; 1908 background: var(--eu-hover); 1909 color: var(--eu-text); 1910 font-size: 11px; 1911 font-weight: 700; 1912 font-family: monospace; 1913 border-radius: 5px; 1914 border: 1px solid var(--eu-border-strong); 1915 letter-spacing: 0.5px; 1916 text-transform: uppercase; 1917 } 1918 1919 /* Visually-hidden live region for screen-reader announcements */ 1920 .eu-sr-only { 1921 position: absolute !important; 1922 width: 1px !important; 1923 height: 1px !important; 1924 padding: 0 !important; 1925 margin: -1px !important; 1926 overflow: hidden !important; 1927 clip: rect(0 0 0 0) !important; 1928 white-space: nowrap !important; 1929 border: 0 !important; 1930 } 1931 1932 /* Draggable launcher */ 1933 #eu-accessibility-fixed-button.eu-dragging { transition: none !important; } 1934 #eu-accessibility-fixed-button.eu-dragging #eu-accessibility-button { cursor: grabbing !important; } 1935 1936 /* Right-to-left panel layout */ 1937 #eu-accessibility-menu[dir="rtl"] { direction: rtl; text-align: right; } 1938`; 1939 1940// Page accessibility styles (will go in main document - these affect the page, NOT the widget) 1941const pageStyles = ` 1942 /* Theme colours for widget-owned page overlays (keyboard, reader, lensâ¦) */ 1943 :root { 1944 ${euCssVars} 1945 } 1946 /* Page Structure Navigation Highlight */ 1947 @keyframes eu-highlight-pulse { 1948 0% { outline-color: rgba(11, 114, 133, 0.9); outline-offset: 2px; } 1949 50% { outline-color: rgba(11, 114, 133, 0.4); outline-offset: 4px; } 1950 100% { outline-color: rgba(11, 114, 133, 0.9); outline-offset: 2px; } 1951 } 1952 .eu-structure-highlight { 1953 outline: 3px solid rgba(11, 114, 133, 0.9) !important; 1954 outline-offset: 2px; 1955 animation: eu-highlight-pulse 1s ease-in-out 2; 1956 scroll-margin-top: 80px; 1957 } 1958 1959 /* High Contrast Modes */ 1960 .eu-high-contrast-medium { 1961 filter: none !important; 1962 } 1963 .eu-high-contrast-medium *:not(#eu-accessibility-widget-container):not(#eu-accessibility-widget-container *) { 1964 filter: contrast(1.3) !important; 1965 } 1966 1967 .eu-high-contrast-high { 1968 background-color: #000 !important; 1969 color: #fff !important; 1970 filter: none !important; 1971 } 1972 .eu-high-contrast-high *:not(#eu-accessibility-widget-container):not(#eu-accessibility-widget-container *) { 1973 background-color: #000 !important; 1974 color: #fff !important; 1975 filter: contrast(1.5) !important; 1976 } 1977 1978 .eu-high-contrast-ultra { 1979 background-color: #000 !important; 1980 color: #ffff00 !important; 1981 filter: none !important; 1982 } 1983 .eu-high-contrast-ultra *:not(#eu-accessibility-widget-container):not(#eu-accessibility-widget-container *) { 1984 background-color: #000 !important; 1985 color: #ffff00 !important; 1986 filter: contrast(2.0) !important; 1987 } 1988 1989 /* Text Size */ 1990 .eu-bigger-text-medium * { 1991 font-size: 20px !important; 1992 } 1993 .eu-bigger-text-large * { 1994 font-size: 24px !important; 1995 } 1996 .eu-bigger-text-xlarge * { 1997 font-size: 28px !important; 1998 } 1999 2000 /* Text Spacing - 3 Options */ 2001 .eu-text-spacing-light * { 2002 letter-spacing: 0.1em !important; 2003 word-spacing: 0.5em !important; 2004 } 2005 .eu-text-spacing-medium * { 2006 letter-spacing: 0.15em !important; 2007 word-spacing: 1em !important; 2008 } 2009 .eu-text-spacing-heavy * { 2010 letter-spacing: 0.25em !important; 2011 word-spacing: 2em !important; 2012 } 2013 2014 /* Pause Animations (Enhanced to include Reduced Motion features) */ 2015 .eu-pause-animations * { 2016 animation: none !important; 2017 transition: none !important; 2018 } 2019 .eu-pause-animations *::before { 2020 animation: none !important; 2021 transition: none !important; 2022 } 2023 .eu-pause-animations *::after { 2024 animation: none !important; 2025 transition: none !important; 2026 } 2027 2028 /* Dyslexia Font â OpenDyslexic (SIL OFL), loaded lazily by the browser only when used */ 2029 @font-face { 2030 font-family: 'OpenDyslexic'; 2031 src: url('https://cdn.jsdelivr.net/npm/[email protected]/woff/OpenDyslexic-Regular.woff') format('woff'); 2032 font-weight: normal; 2033 font-style: normal; 2034 font-display: swap; 2035 } 2036 @font-face { 2037 font-family: 'OpenDyslexic'; 2038 src: url('https://cdn.jsdelivr.net/npm/[email protected]/woff/OpenDyslexic-Bold.woff') format('woff'); 2039 font-weight: bold; 2040 font-style: normal; 2041 font-display: swap; 2042 } 2043 .eu-dyslexia-font { 2044 font-family: 'OpenDyslexic', 'Comic Sans MS', 'Chalkboard SE', Verdana, sans-serif !important; 2045 } 2046 .eu-dyslexia-font * { 2047 font-family: 'OpenDyslexic', 'Comic Sans MS', 'Chalkboard SE', Verdana, sans-serif !important; 2048 } 2049 .eu-font-dyslexic { 2050 font-family: 'OpenDyslexic', 'Comic Sans MS', 'Chalkboard SE', Verdana, sans-serif !important; 2051 } 2052 .eu-font-dyslexic * { 2053 font-family: 'OpenDyslexic', 'Comic Sans MS', 'Chalkboard SE', Verdana, sans-serif !important; 2054 } 2055 2056 /* Line Height - 3 Options */ 2057 .eu-line-height-2em * { 2058 line-height: 2 !important; 2059 } 2060 .eu-line-height-3em * { 2061 line-height: 3 !important; 2062 } 2063 .eu-line-height-4em * { 2064 line-height: 4 !important; 2065 } 2066 2067 /* Text Alignment */ 2068 .eu-text-align-left * { 2069 text-align: left !important; 2070 } 2071 .eu-text-align-center * { 2072 text-align: center !important; 2073 } 2074 .eu-text-align-right * { 2075 text-align: right !important; 2076 } 2077 2078 /* Bigger Cursor */ 2079 .eu-bigger-cursor { 2080 cursor: url('data:image/svg+xml;
2080base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz48IURPQ1RZUEUgc3ZnIFBVQkxJQyAiLS8vVzNDLy9EVEQgU1ZHIDEuMS8vRU4iICJodHRwOi8vd3d3LnczLm9yZy9HcmFwaGljcy9TVkcvMS4xL0RURC9zdmcxMS5kdGQiPjxzdmcgdmVyc2lvbj0iMS4xIiBpZD0iTGF5ZXJfMSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIgeD0iMHB4IiB5PSIwcHgiIHdpZHRoPSIyOS4xODhweCIgaGVpZ2h0PSI0My42MjVweCIgdmlld0JveD0iMCAwIDI5LjE4OCA0My42MjUiIGVuYWJsZS1iYWNrZ3JvdW5kPSJuZXcgMCAwIDI5LjE4OCA0My42MjUiIHhtbDpzcGFjZT0icHJlc2VydmUiPjxnPjxwb2x5Z29uIGZpbGw9IiNGRkZGRkYiIHN0cm9rZT0iI0Q5REFEOSIgc3Ryb2tlLXdpZHRoPSIxLjE0MDYiIHN0cm9rZS1taXRlcmxpbWl0PSIxMCIgcG9pbnRzPSIyLjgsNC41NDkgMjYuODQ3LDE5LjkwMiAxNi45NjQsMjIuNzAxIDI0LjIzOSwzNy43NDkgMTguMjc4LDQyLjAxNyA5Ljc0MSwzMC43MjQgMS4xMzgsMzUuODA5ICIvPjxnPjxnPjxnPjxwYXRoIGZpbGw9IiMyMTI2MjciIGQ9Ik0yOS4xNzUsMjEuMTU1YzAuMDcxLTAuNjEzLTAuMTY1LTEuMjUzLTAuNjM1LTEuNTczTDIuMTY1LDAuMjU4Yy0wLjQyNC0wLjMyLTAuOTg4LTAuMzQ2LTEuNDM1LTAuMDUzQzAuMjgyLDAuNDk3LDAsMS4wMywwLDEuNjE3djM0LjE3MWMwLDAuNjEzLDAuMzA2LDEuMTQ2LDAuNzc2LDEuNDM5YzAuNDcxLDAuMjY3LDEuMDU5LDAuMjEzLDEuNDgyLTAuMTZsNy40ODItNi4zNDRsNi44NDcsMTIuMTU1YzAuMjU5LDAuNDgsMC43MjksMC43NDYsMS4yLDAuNzQ2YzAuMjM1LDAsMC40OTQtMC4wOCwwLjcwNi0wLjIxM2w2Ljk4OC00LjU4NWMwLjMyOS0wLjIxMywwLjU2NS0wLjU4NiwwLjY1OS0xLjAxM2MwLjA5NC0wLjQyNiwwLjAyNC0wLjg4LTAuMTg4LTEuMjI2bC02LjM3Ni0xMS4zODJsOC42MTEtMi43NDVDMjguNzA1LDIyLjI3NCwyOS4xMDUsMjEuNzY4LDI5LjE3NSwyMS4xNTV6IE0xNi45NjQsMjIuNzAxYy0wLjQyNCwwLjEzMy0wLjc3NiwwLjUwNi0wLjk0MSwwLjk2Yy0wLjE2NSwwLjQ4LTAuMTE4LDEuMDEzLDAuMTE4LDEuNDM5bDYuNTg4LDExLjc4MWwtNC41NDEsMi45ODVsLTYuODk0LTEyLjMxNWMtMC4yMTItMC4zNzMtMC41NDEtMC42NC0wLjk0MS0wLjcyYy0wLjA5NC0wLjAyNy0wLjE2NS0wLjAyNy0wLjI1OS0wLjAyN2MtMC4zMDYsMC0wLjU4OCwwLjEwNy0wLjg0NywwLjMyTDIuOCwzMi41OVY0LjU0OWwyMS41OTksMTUuODA2TDE2Ljk2NCwyMi43MDF6Ii8+PC9nPjwvZz48L2c+PC9nPjwvc3ZnPg=='), auto !important; 2081 } 2082 .eu-bigger-cursor * { 2083 cursor: url('data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz48IURPQ1RZUEUgc3ZnIFBVQkxJQyAiLS8vVzNDLy9EVEQgU1ZHIDEuMS8vRU4iICJodHRwOi8vd3d3LnczLm9yZy9HcmFwaGljcy9TVkcvMS4xL0RURC9zdmcxMS5kdGQiPjxzdmcgdmVyc2lvbj0iMS4xIiBpZD0iTGF5ZXJfMSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIgeD0iMHB4IiB5PSIwcHgiIHdpZHRoPSIyOS4xODhweCIgaGVpZ2h0PSI0My42MjVweCIgdmlld0JveD0iMCAwIDI5LjE4OCA0My42MjUiIGVuYWJsZS1iYWNrZ3JvdW5kPSJuZXcgMCAwIDI5LjE4OCA0My42MjUiIHhtbDpzcGFjZT0icHJlc2VydmUiPjxnPjxwb2x5Z29uIGZpbGw9IiNGRkZGRkYiIHN0cm9rZT0iI0Q5REFEOSIgc3Ryb2tlLXdpZHRoPSIxLjE0MDYiIHN0cm9rZS1taXRlcmxpbWl0PSIxMCIgcG9pbnRzPSIyLjgsNC41NDkgMjYuODQ3LDE5LjkwMiAxNi45NjQsMjIuNzAxIDI0LjIzOSwzNy43NDkgMTguMjc4LDQyLjAxNyA5Ljc0MSwzMC43MjQgMS4xMzgsMzUuODA5ICIvPjxnPjxnPjxnPjxwYXRoIGZpbGw9IiMyMTI2MjciIGQ9Ik0yOS4xNzUsMjEuMTU1YzAuMDcxLTAuNjEzLTAuMTY1LTEuMjUzLTAuNjM1LTEuNTczTDIuMTY1LDAuMjU4Yy0wLjQyNC0wLjMyLTAuOTg4LTAuMzQ2LTEuNDM1LTAuMDUzQzAuMjgyLDAuNDk3LDAsMS4wMywwLDEuNjE3djM0LjE3MWMwLDAuNjEzLDAuMzA2LDEuMTQ2LDAuNzc2LDEuNDM5YzAuNDcxLDAuMjY3LDEuMDU5LDAuMjEzLDEuNDgyLTAuMTZsNy40ODItNi4zNDRsNi44NDcsMTIuMTU1YzAuMjU5LDAuNDgsMC43MjksMC43NDYsMS4yLDAuNzQ2YzAuMjM1LDAsMC40OTQtMC4wOCwwLjcwNi0wLjIxM2w2Ljk4OC00LjU4NWMwLjMyOS0wLjIxMywwLjU2NS0wLjU4NiwwLjY1OS0xLjAxM2MwLjA5NC0wLjQyNiwwLjAyNC0wLjg4LTAuMTg4LTEuMjI2bC02LjM3Ni0xMS4zODJsOC42MTEtMi43NDVDMjguNzA1LDIyLjI3NCwyOS4xMDUsMjEuNzY4LDI5LjE3NSwyMS4xNTV6IE0xNi45NjQsMjIuNzAxYy0wLjQyNCwwLjEzMy0wLjc3NiwwLjUwNi0wLjk0MSwwLjk2Yy0wLjE2NSwwLjQ4LTAuMTE4LDEuMDEzLDAuMTE4LDEuNDM5bDYuNTg4LDExLjc4MWwtNC41NDEsMi45ODVsLTYuODk0LTEyLjMxNWMtMC4yMTItMC4zNzMtMC41NDEtMC42NC0wLjk0MS0wLjcyYy0wLjA5NC0wLjAyNy0wLjE2NS0wLjAyNy0wLjI1OS0wLjAyN2MtMC4zMDYsMC0wLjU4OCwwLjEwNy0wLjg0NywwLjMyTDIuOCwzMi41OVY0LjU0OWwyMS41OTksMTUuODA2TDE2Ljk2NCwyMi43MDF6Ii8+PC9nPjwvZz48L2c+PC9nPjwvc3ZnPg=='), auto !important; 2084 } 2085 2086 /* Font Selection */ 2087 .eu-font-arial { 2088 font-family: Arial, sans-serif !important; 2089 } 2090 .eu-font-arial * { 2091 font-family: Arial, sans-serif !important; 2092 } 2093 .eu-font-times { 2094 font-family: 'Times New Roman', serif !important; 2095 } 2096 .eu-font-times * { 2097 font-family: 'Times New Roman', serif !important; 2098 } 2099 .eu-font-verdana { 2100 font-family: Verdana, sans-serif !important; 2101 } 2102 .eu-font-verdana * { 2103 font-family: Verdana, sans-serif !important; 2104 } 2105 2106 /* Color Filters */ 2107 .eu-filter-protanopia { 2108 filter: none !important; 2109 } 2110 .eu-filter-protanopia body > *:not(#eu-accessibility-widget-container) { 2111 filter: url('#protanopia-filter') !important; 2112 } 2113 .eu-filter-deuteranopia { 2114 filter: none !important; 2115 } 2116 .eu-filter-deuteranopia body > *:not(#eu-accessibility-widget-container) { 2117 filter: url('#deuteranopia-filter') !important; 2118 } 2119 .eu-filter-tritanopia { 2120 filter: none !important; 2121 } 2122 .eu-filter-tritanopia body > *:not(#eu-accessibility-widget-container) { 2123 filter: url('#tritanopia-filter') !important; 2124 } 2125 .eu-filter-grayscale { 2126 filter: none !important; 2127 } 2128 .eu-filter-grayscale body > *:not(#eu-accessibility-widget-container) { 2129 filter: grayscale(100%) !important; 2130 } 2131 2132 /* Saturation Filters */ 2133 .eu-saturation-low { 2134 filter: none !important; 2135 } 2136 .eu-saturation-low body > *:not(#eu-accessibility-widget-container) { 2137 filter: saturate(0.5) !important; 2138 } 2139 .eu-saturation-high { 2140 filter: none !important; 2141 } 2142 .eu-saturation-high body > *:not(#eu-accessibility-widget-container) { 2143 filter: saturate(10) !important; 2144 } 2145 .eu-saturation-none { 2146 filter: none !important; 2147 } 2148 .eu-saturation-none body > *:not(#eu-accessibility-widget-container) { 2149 filter: grayscale(100%) saturate(0) !important; 2150 } 2151 2152 /* Alt Text Viewer tooltip */ 2153 .eu-alt-tooltip { 2154 position: absolute; 2155 z-index: 2147483647; 2156 display: none; 2157 background: #111827; 2158 color: #ffffff; 2159 padding: 5px 10px; 2160 border-radius: 6px; 2161 font-family: Arial, sans-serif; 2162 font-size: 13px; 2163 line-height: 1.4; 2164 max-width: 320px; 2165 box-shadow: 0 2px 8px rgba(0, 0, 0, 0.4); 2166 pointer-events: none; 2167 } 2168 .eu-alt-tooltip.eu-alt-missing { 2169 background: #b00020; 2170 } 2171 2172 /* Focus Indicator */ 2173 .eu-focus-indicator *:focus { 2174 outline: 3px solid #1a73e8 !important; 2175 outline-offset: 3px !important; 2176 box-shadow: 0 0 0 6px rgba(26, 115, 232, 0.25) !important; 2177 } 2178 .eu-focus-indicator a:focus, 2179 .eu-focus-indicator button:focus,
2180 .eu-focus-indicator input:focus, 2181 .eu-focus-indicator select:focus, 2182 .eu-focus-indicator textarea:focus, 2183 .eu-focus-indicator [tabindex]:focus { 2184 outline: 3px solid #1a73e8 !important; 2185 outline-offset: 3px !important; 2186 box-shadow: 0 0 0 6px rgba(26, 115, 232, 0.25) !important; 2187 } 2188 2189 /* Highlight Links */ 2190 .eu-highlight-links a { 2191 background-color: rgba(255, 255, 0, 0.4) !important; 2192 outline: 2px solid rgba(255, 200, 0, 0.6) !important; 2193 border-radius: 2px !important; 2194 } 2195 .eu-highlight-links h1, 2196 .eu-highlight-links h2, 2197 .eu-highlight-links h3, 2198 .eu-highlight-links h4, 2199 .eu-highlight-links h5, 2200 .eu-highlight-links h6 { 2201 background-color: rgba(0, 200, 255, 0.15) !important; 2202 outline: 2px solid rgba(0, 180, 230, 0.4) !important; 2203 border-radius: 2px !important; 2204 } 2205 2206 /* Reading Guide */ 2207 #eu-reading-guide { 2208 position: fixed; 2209 left: 0; 2210 width: 100%; 2211 height: 3px; 2212 background: linear-gradient(90deg, transparent, #e63946, #e63946, transparent); 2213 pointer-events: none; 2214 z-index: 999998; 2215 transition: top 0.08s ease-out; 2216 box-shadow: 0 0 8px rgba(230, 57, 70, 0.5); 2217 } 2218 2219 /* Reading Window */ 2220 .eu-reading-window-top, 2221 .eu-reading-window-bottom { 2222 position: fixed; 2223 left: 0; 2224 width: 100%; 2225 background: rgba(0, 0, 0, 0.65); 2226 pointer-events: none; 2227 z-index: 999997; 2228 transition: top 0.08s ease-out, height 0.08s ease-out; 2229 } 2230 .eu-reading-window-top { 2231 top: 0; 2232 } 2233 2234 /* ===== Enhanced features (v1.3.0) ===== */ 2235 2236 /* Enlarge Buttons â meet WCAG 2.5.5 target size */ 2237 .eu-enlarge-buttons a, 2238 .eu-enlarge-buttons button, 2239 .eu-enlarge-buttons input[type="button"], 2240 .eu-enlarge-buttons input[type="submit"], 2241 .eu-enlarge-buttons input[type="reset"], 2242 .eu-enlarge-buttons [role="button"] { 2243 min-width: 44px !important; 2244 min-height: 44px !important; 2245 padding: 8px 14px !important; 2246 font-size: 1.05em !important; 2247 line-height: 1.4 !important; 2248 } 2249 2250 /* Readable Font */ 2251 .eu-readable-font, 2252 .eu-readable-font * { 2253 font-family: Verdana, Tahoma, 'Segoe UI', Arial, sans-serif !important; 2254 letter-spacing: 0.02em !important; 2255 } 2256 2257 /* Hover Highlight (applied to hovered element via JS) */ 2258 .eu-hover-highlight-target { 2259 outline: 3px solid var(--eu-primary) !important; 2260 outline-offset: 2px !important; 2261 background-color: rgba(124, 108, 255, 0.12) !important; 2262 } 2263 2264 /* Read Focus â spotlight the hovered block of text */ 2265 .eu-read-focus-target { 2266 background-color: rgba(255, 244, 150, 0.85) !important; 2267 box-shadow: 0 0 0 4px rgba(255, 235, 120, 0.9) !important; 2268 border-radius: 3px !important; 2269 color: #111 !important; 2270 } 2271 2272 /* Read Aloud â outline the block being read + highlight the current word */ 2273 .eu-read-current-block { 2274 outline: 2px solid var(--eu-primary, #54467d) !important; 2275 outline-offset: 2px !important; 2276 } 2277 .eu-read-word-active { 2278 background-color: rgba(255, 213, 74, 0.95) !important; 2279 box-shadow: 0 0 0 2px rgba(255, 213, 74, 0.95) !important; 2280 color: #111 !important; 2281 border-radius: 3px !important; 2282 } 2283 2284 /* Text Magnifier lens */ 2285 .eu-text-magnifier-lens { 2286 position: fixed; 2287 z-index: 2147483646; 2288 display: none; 2289 max-width: 480px; 2290 background: #ffffff; 2291 color: #111827; 2292 border: 2px solid var(--eu-primary); 2293 border-radius: 8px; 2294 padding: 10px 14px; 2295 font-family: Arial, sans-serif; 2296 font-size: 26px; 2297 line-height: 1.4; 2298 box-shadow: 0 6px 20px rgba(0, 0, 0, 0.3); 2299 pointer-events: none; 2300 } 2301 2302 /* Dictionary popup */ 2303 .eu-dictionary-popup { 2304 position: fixed; 2305 z-index: 2147483646; 2306 display: none; 2307 width: 300px; 2308 max-height: 260px; 2309 overflow-y: auto; 2310 background: #ffffff; 2311 color: #111827; 2312 border: 1px solid #d1d5db; 2313 border-radius: 10px; 2314 padding: 14px 16px; 2315 font-family: Arial, sans-serif; 2316 font-size: 15px; 2317 line-height: 1.5; 2318 box-shadow: 0 8px 28px rgba(0, 0, 0, 0.28); 2319 } 2320 .eu-dictionary-popup .eu-dict-word { 2321 font-size: 18px; 2322 font-weight: 700; 2323 margin: 0 0 2px; 2324 text-transform: capitalize; 2325 } 2326 .eu-dictionary-popup .eu-dict-phon { 2327 color: #6b7280; 2328 font-style: italic; 2329 margin: 0 0 8px; 2330 } 2331 .eu-dictionary-popup .eu-dict-pos { 2332 font-weight: 700; 2333 color: var(--eu-primary); 2334 margin: 8px 0 2px; 2335 } 2336 .eu-dictionary-popup ol { 2337 margin: 0; 2338 padding-left: 18px; 2339 } 2340 2341 /* Reader View overlay */ 2342 .eu-reader-overlay { 2343 position: fixed; 2344 inset: 0; 2345 z-index: 2147483644; 2346 background: #fbfbf8; 2347 color: #1a1a1a; 2348 overflow-y: auto; 2349 display: none; 2350 padding: 48px 20px 80px; 2351 } 2352 .eu-reader-inner { 2353 max-width: 720px; 2354 margin: 0 auto; 2355 font-family: Georgia, 'Times New Roman', serif; 2356 font-size: 20px; 2357 line-height: 1.7; 2358 } 2359 .eu-reader-inner h1, .eu-reader-inner h2, .eu-reader-inner h3 { 2360 font-family: Georgia, serif; 2361 line-height: 1.3; 2362 } 2363 .eu-reader-inner img { max-width: 100%; height: auto; } 2364 .eu-reader-inner p, .eu-reader-inner li { margin: 0 0 1em; } 2365 .eu-reader-close { 2366 position: fixed; 2367 top: 16px; 2368 right: 20px; 2369 z-index: 2147483645; 2370 background: var(--eu-primary); 2371 color: #fff; 2372 border: none; 2373 border-radius: 8px; 2374 padding: 10px 18px; 2375 font-size: 16px; 2376 font-family: Arial, sans-serif; 2377 cursor: pointer; 2378 } 2379 2380 /* Virtual Keyboard */ 2381 .eu-virtual-keyboard { 2382 position: fixed; 2383 left: 50%; 2384 bottom: 0; 2385 transform: translateX(-50%); 2386 z-index: 2147483645; 2387 display: none; 2388 width: min(760px, 100%); 2389 background: #ffffff; 2390 padding: 10px; 2391 box-sizing: border-box; 2392 box-shadow: 0 -6px 24px rgba(44, 37, 66, 0.18); 2393 border-radius: 12px 12px 0 0; 2394 border: 1px solid var(--eu-border); 2395 border-bottom: none; 2396 user-select: none; 2397 } 2398 .eu-vk-row { display: flex; gap: 6px; margin-bottom: 6px; justify-content: center; } 2399 .eu-vk-key { 2400 flex: 1 1 0; 2401 min-width: 0; 2402 height: 44px; 2403 background: var(--eu-option-bg); 2404 color: var(--eu-text); 2405 border: 1px solid var(--eu-border); 2406 border-radius: 6px; 2407 font-size: 16px; 2408 font-family: Arial, sans-serif; 2409 cursor: pointer; 2410 } 2411 .eu-vk-key:hover { background: var(--eu-hover); border-color: var(--eu-border-strong); } 2412 .eu-vk-key:active { background: var(--eu-primary); color: #fff; } 2413 .eu-vk-key.eu-vk-wide { flex: 2 1 0; } 2414 .eu-vk-key.eu-vk-space { flex: 6 1 0; } 2415 .eu-vk-key.eu-vk-active { background: var(--eu-primary); color: #fff; border-color: var(--eu-primary); } 2416 2417 /* Protect widget container + overlay host from page styles */ 2418 #eu-accessibility-widget-container, 2419 #eu-accessibility-widget-container *, 2420 #eu-accessibility-overlays { 2421 filter: none !important; 2422 } 2423 #eu-accessibility-widget-container, 2424 #eu-accessibility-widget-container * { 2425 background-color: initial !important; 2426 color: initial !important; 2427 } 2428`; 2429 2430// =========================================== 2431// SVG ICONS 2432// =========================================== 2433 2434const icons = { 2435 buttonsvg: `<svg xmlns="http://www.w3.org/2000/svg" style="fill:white;" viewBox="0 0 24 24" width="30px" height="30px"><path d="M0 0h24v24H0V0z" fill="none"></path><path d="M20.5 6c-2.61 0.7-5.67 1-8.5 1s-5.89-0.3-8.5-1L3 8c1.86 0.5 4 0.83 6 1v13h2v-6h2v6h2V9c2-0.17 4.14-0.5 6-1l-0.5-2zM12 6c1.1 0 2-0.9 2-2s-0.9-2-2-2-2 0.9-2 2 0.9 2 2 2z"></path></svg>`,
vendor: 3,425 bytes, lines 2435-2436
2435 2436 highContrast: `<svg xmlns="http://www.w3.org/2000/svg" fill="none" version="1.2" viewBox="0 0 35 35"><path fill="currentColor" fill-rule="evenodd" d="M1.89998 15.6285c0-7.58203 6.14649-13.72852 13.72852-13.72852 7.5821 0 13.7286 6.14649 13.7286 13.72852 0 0.6081-0.0395 1.2069-0.1161 1.794 0.5933 0.2913 1.1478 0.6497 1.6534 1.0654 0.1725-0.9268 0.2627-1.8825 0.2627-2.8594 0-8.57615-6.9524-15.5285244-15.5286-15.5285244C7.05235 0.0999756 0.0999756 7.05235 0.0999756 15.6285c0 8.5762 6.9523744 15.5286 15.5285244 15.5286 1.2241 0 2.415-0.1416 3.5574-0.4093-0.4388-0.4866-0.8222-1.0242-1.1402-1.6028-0.7847 0.1394-1.5924 0.2121-2.4172 0.2121-7.58203 0-13.72852-6.1465-13.72852-13.7286Z" clip-rule="evenodd"/><path fill="currentColor" fill-rule="evenodd" d="M2.35 15.6286C2.35 8.29502 8.29502 2.35 15.6286 2.35c7.3335 0 13.2785 5.94502 13.2785 13.2786 0 0.5408-0.0323 1.0741-0.0951 1.5979 0.444 0.1881 0.8687 0.4128 1.2703 0.6703 0.1151-0.7392 0.1748-1.4967 0.1748-2.2682C30.2571 7.54943 23.7077 1 15.6286 1 7.54943 1 1 7.54943 1 15.6286c0 8.0791 6.54943 14.6285 14.6286 14.6285 1.0033 0 1.9831-0.101 2.9297-0.2934-0.276-0.3898-0.52-0.8038-0.7282-1.2382-0.716 0.1195-1.4515 0.1816-2.2015 0.1816-7.33358 0-13.2786-5.945-13.2786-13.2785Z" clip-rule="evenodd"/><path fill="currentColor" fill-rule="evenodd" d="M15.6286 1C7.54943 1 1 7.54943 1 15.6286c0 8.0791 6.54943 14.6285 14.6286 14.6285" clip-rule="evenodd"/><path stroke="currentColor" stroke-width="1.8" d="M15.6286 1C7.54943 1 1 7.54943 1 15.6286c0 8.0791 6.54943 14.6285 14.6286 14.6285"/><path fill="currentColor" fill-rule="evenodd" d="M22.8729 25.114c0-1.3811 1.0901-2.5007 2.4359-2.5007 1.3459 0 2.436 1.1196 2.436 2.5007 0 1.38-1.0901 2.4997-2.436 2.4997-1.3458 0-2.4359-1.1197-2.4359-2.4997Zm7.2258-2.0373c-0.0899-0.2248-0.071-0.4785 0.0512-0.6875l0.912-1.5598c0.0898-0.1532 0.0668-0.3504-0.0574-0.4779l-1.0556-1.0832c-0.1232-0.1264-0.3153-0.1511-0.4657-0.0589l-1.5225 0.9374c-0.201 0.1237-0.4495 0.1427-0.667 0.051-0.2181-0.092-0.3797-0.2819-0.4358-0.5118l-0.4329-1.7763c-0.0428-0.1735-0.1953-0.2957-0.3696-0.2957h-1.4931c-0.1744 0-0.3268 0.1222-0.3696 0.2957l-0.433 1.7763c-0.056 0.2299-0.2177 0.4198-0.4357 0.5118-0.2176 0.0917-0.466 0.0727-0.6671-0.051l-1.5225-0.9374c-0.1503-0.0922-0.3424-0.0675-0.4656 0.0589l-1.0556 1.0832c-0.1243 0.1275-0.1473 0.3247-0.0575 0.4779l0.9121 1.5598c0.1222 0.209 0.1411 0.4627 0.0511 0.6875-0.0895 0.2239-0.2806 0.3916-0.5142 0.4514l-1.7165 0.4395c-0.1692 0.0439-0.2882 0.2003-0.2882 0.3803v1.5311c0 0.18 0.119 0.3364 0.2882 0.3804l1.7165 0.4394c0.2336 0.0599 0.4247 0.2276 0.5142 0.4515 0.09 0.2247 0.0711 0.4785-0.0511 0.6874l-0.9121 1.5599c-0.0898 0.1532-0.0668 0.3503 0.0575 0.4778l1.0556 1.0833c0.1232 0.1264 0.3153 0.151 0.4656 0.0589l1.5225-0.9374c0.2011-0.1238 0.4495-0.1428 0.6671-0.051 0.218 0.092 0.3797 0.2818 0.4357 0.5118l0.433 1.7762c0.0428 0.1736 0.1952 0.2968 0.3696 0.2968h1.4931c0.1743 0 0.3268-0.1232 0.3696-0.2968l0.4329-1.7762c0.0561-0.23 0.2177-0.4198 0.4358-0.5118 0.2175-0.0918 0.466-0.0728 0.667 0.051l1.5225 0.9374c0.1504 0.0921 0.3425 0.0675 0.4657-0.0589l1.0556-1.0833c0.1242-0.1275 0.1472-0.3246 0.0574-0.4778l-0.912-1.5599c-0.1222-0.2089-0.1411-0.4627-0.0512-0.6874 0.0896-0.2239 0.2806-0.3916 0.5142-0.4515l1.7166-0.4394c0.1691-0.044 0.2881-0.2004 0.2881-0.3804v-1.5311c0-0.18-0.119-0.3364-0.2881-0.3803l-1.7166-0.4395c-0.2336-0.0598-0.4246-0.2275-0.5142-0.4514Z" clip-rule="evenodd"/></svg>`,
2436 2437 biggerText: `<svg xmlns="http://www.w3.org/2000/svg" version="1.2" viewBox="0 0 36 23"><g fill="none" fill-rule="evenodd" stroke="currentColor" stroke-linecap="round" stroke-width="2"><path stroke-linejoin="round" d="M26.58 21.3225806V1m-7.92 4.06451613V1H34.5v4.06451613"/><path d="M22.62 21.3225806h7.92"/><path stroke-linejoin="round" d="M6.78 18.6129032V5.06451613M1.5 7.77419355V5.06451613h10.56v2.70967742"/><path d="M4.14 18.6129032h5.28"/></g></svg>`, 2438 textSpacing: `<svg xmlns="http://www.w3.org/2000/svg" width="800px" height="800px" viewBox="0 0 15 15" fill="none"><path fill-rule="evenodd" clip-rule="evenodd" d="M4.55293 0.999969C4.75295 0.999969 4.93372 1.11917 5.0125 1.30301L8.01106 8.29982C8.11984 8.55363 8.00226 8.84757 7.74844 8.95635C7.49463 9.06512 7.20069 8.94754 7.09191 8.69373L6.11613 6.41685H2.98973L2.01395 8.69373C1.90517 8.94754 1.61123 9.06512 1.35742 8.95635C1.1036 8.84757 0.986023 8.55363 1.0948 8.29982L4.09336 1.30301C4.17214 1.11917 4.35291 0.999969 4.55293 0.999969ZM4.55293 2.76929L5.75186 5.56685H3.354L4.55293 2.76929ZM11.0562 9.00214C11.2617 9.00214 11.4463 8.87633 11.5215 8.68502L14.2733 1.68299C14.3743 1.42598 14.2478 1.13575 13.9908 1.03475C13.7338 0.933747 13.4436 1.06021 13.3426 1.31722L11.0562 7.13514L8.76973 1.31722C8.66873 1.06021 8.3785 0.933747 8.1215 1.03475C7.86449 1.13575 7.73802 1.42598 7.83902 1.68299L10.5908 8.68502C10.666 8.87633 10.8506 9.00214 11.0562 9.00214ZM14.9537 12.4999C14.9537 12.606 14.9115 12.7077 14.8365 12.7828L12.8365 14.7828C12.6803 14.939 12.4271 14.939 12.2708 14.7828C12.1146 14.6265 12.1146 14.3733 12.2708 14.2171L13.588 12.8999H1.51937L2.83653 14.2171C2.99274 14.3733 2.99274 14.6265 2.83653 14.7828C2.68032 14.939 2.42705 14.939 2.27084 14.7828L0.270843 12.7828C0.195828 12.7077 0.153687 12.606 0.153687 12.4999C0.153687 12.3938 0.195828 12.2921 0.270843 12.2171L2.27084 10.2171C2.42705 10.0609 2.68032 10.0609 2.83653 10.2171C2.99274 10.3733 2.99274 10.6265 2.83653 10.7828L1.51937 12.0999L13.588 12.0999L12.2708 10.7828C12.1146 10.6265 12.1146 10.3733 12.2708 10.2171C12.4271 10.0609 12.6803 10.0609 12.8365 10.2171L14.8365 12.2171C14.9115 12.2921 14.9537 12.3938 14.9537 12.4999Z" fill="#000000"/></svg>`, 2439 pauseAnimations: `<svg xmlns="http://www.w3.org/2000/svg" version="1.2" viewBox="0 0 37 36"><g fill="none" fill-rule="evenodd"><path fill="currentColor" d="M15.8087111 23.6666667h-1.2702778c-.4429444 0-.8018333-.3598334-.8018333-.8027778v-9.7277778c0-.4429444.3588889-.8027778.8018333-.8027778h1.2702778c.4429445 0 .8027778.3598334.8027778.8027778v9.7277778c0 .4429444-.3598333.8027778-.8027778.8027778m6.6525722 0h-1.2702777c-.442 0-.8018334-.3598334-.8018334-.8027778v-9.7277778c0-.4429444.3598334-.8027778.8018334-.8027778h1.2702777c.4438889 0 .8027778.3598334.8027778.8027778v9.7277778c0 .4429444-.3588889.8027778-.8027778.8027778"/><path stroke="currentColor" stroke-linecap="round" stroke-width="1.88888889" d="M18.5 4.77777778V1m0 34v-3.7777778M31.7222222 18H35.5m-34 0h3.77777778m3.87278889-9.34943333L6.47873333 5.97967778M30.5204167 30.0204167l-2.6708889-2.6708889m-.0000945-18.69896113 2.6708889-2.67088889M6.47911111 30.0204167l2.67183333-2.6708889M23.5542889 5.78219444l1.4440555-3.49066666M12.0013722 33.7087556l1.4440556-3.4906667m17.2723778-7.1638 3.4906666 1.4440555M2.79124444 11.5013722l3.49066667 1.4440556m7.15274999-7.15860558L11.9877722 2.2971m13.0246445 31.4061778-1.4468889-3.4897222m7.14765-17.2788945L34.2029 11.4877722M2.79672222 24.5124167l3.48972222-1.4468889"/></g></svg>`, 2440 hideImages: `<svg width="100%" height="100%" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64"><path d="M32 12C16 12 4 32 4 32s12 20 28 20 28-20 28-20S48 12 32 12zm0 32a12 12 0 1112-12 12 12 0 01-12 12z"/><circle cx="32" cy="32" r="8"/></svg>`, 2441 dyslexiaFont: `<svg xmlns="http://www.w3.org/2000/svg" version="1.2" viewBox="0 0 31 22"><path fill="currentColor" fill-rule="evenodd" d="M.5 22V1.0083333h7.2421899c6.8051611 0 11.6124768 4.3388889 11.6124768 10.4805556C19.3546667 17.6305556 14.547351 22 7.7421899 22H.5Zm2.4348742-4.31h4.8073157c5.3692097 0 9.1463863-2.8616703 9.1463863-7.27 0-4.3807776-3.7771766-7.2422222-9.1463863-7.2422222H2.9348742V17.69ZM26.2735913 4.0333333l.0114609 2.1694445h4.0126191V8.25h-4.001719L26.77 22h-3.535416L23.78 8.25h-2.4238344V6.2027778h2.55923l.0751088-2.1694445C24.0706908 1.6805556 25.6007488 0 27.697782 0 28.6896221 0 29.677687.3666667 30.5 1.0083333l-.9
2441627285 1.6805556c-.3479788-.3666667-.9515992-.6416667-1.627768-.6416667-.8819593 0-1.6420082.825-1.6359122 1.9861111Z"/></svg>`, 2442 biggerCursor: `<svg xmlns="http://www.w3.org/2000/svg" version="1.2" viewBox="0 0 27 27"><path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="m15.9983464 11.5517813 9.5269972 9.52699721-4.4465655 4.44656549-9.5269972-9.52699717-4.05145413 9.06403815L1 1.0000004l24.0623846 6.5003268z"/></svg>`, 2443 lineHeight: `<svg xmlns="http://www.w3.org/2000/svg" version="1.2" viewBox="0 0 47 25"><g fill="none" fill-rule="evenodd"><path stroke="currentColor" stroke-linecap="round" stroke-width="2" d="M3.99999962 2.71042226V22.7104223"/><path fill="currentColor" d="m.16814235 20.5270412 3.44487862 4.2104072c.17486379.2137224.48987514.2452235.70359754.0703597a.4999988.4999988 0 0 0 .07035976-.0703597l3.44487862-4.2104072c.17486378-.2137225.14336265-.5287338-.07035976-.7035976-.08933106-.073089-.20119771-.1130213-.31661889-.1130213H.555121c-.27614238 0-.5.2238576-.5.5 0 .1154211.0399323.2272878.11302135.3166189Zm0-161332381L3.61302097.18339592c.17486379-.21372241.48987514-.24522355.703597
244354-.07035976a.49999975.49999975 0 0 1 .07035976.07035976l3.44487862 4.2104072c.17486378.2137224.14336265.52873375-.07035976.70359754-.08933106.07308905-.20119771.11302135-.31661889.11302135H.555121c-.27614237 0-.5-.22385762-.5-.5 0-.11542118.0399323-.22728783.11302135-.3166189Z"/><path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15.4999996 1.71042226h30m-30 7h30m-30 7.00000004h30m-30 7h24"/></g></svg>`, 2444 textAlign: `<svg width="100%" height="100%" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64"><path d="M10 16h44v4H10zm0 12h44v4H10zm0 12h44v4H10zm0 12h44v4H10z"/></svg>`, 2445 screenReader: `<svg width="100%" height="100%" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64"><path d="M16 24 L24 24 L32 16 L32 48 L24 40 L16 40 Z" fill="#333" stroke="#555" stroke-width="2"/><path d="M36 20 C42 24, 42 40, 36 44" fill="none" stroke="#fff" stroke-width="2" stroke-linecap="round"/><path d="M36 12 C48 24, 48 40, 36 52" fill="none" stroke="#555" stroke-width="2" stroke-linecap="round"/><rect x="28" y="48" width="8" height="8" fill="#ccc"/></svg>`, 2446 resetAll: `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 18 17" width="100%" height="100%"><g fill="none" fill-rule="evenodd" stroke="currentColor" stroke-linecap="round" stroke-width="1.84"><path d="M16.20106 8c0 .9667-.189683 1.8872-.5324673 2.7251-.3427843.8372-.8386698 1.5911-1.4517524 2.2246-.6130825.6335-1.3426846 1.1459-2.152902 1.5001-.8108948.3542-1.70172746.5502-2.6372711.5502-.93554365 0-1.8263763-.196-2.63727112-.5502-.81021738-.3542-1.53981948-.8666-2.15290203-1.5001M2.6522744 8c0-.9667.189683-1.8872.53246728-2.7251.34278427-.8372.83866982-1.5911 1.45175237-2.2246.61308255-.6335 1.34268465-1.1459 2.15290203-1.5001C7.6002909 1.196 8.49112355 1 9.4266672 1c.93554364 0 1.8263763.196 2.6372711.5502.8102174.3542 1.5398195.8666 2.152902 1.5001"></path><path stroke-linejoin="round" d="m4.92576062 6.96092-2.48958935 1.484L1 5.87242m13.0125924 2.93832 2.3886509-1.652L18 9.62694"></path></g></svg>`, 2447 voiceControl: `<svg width="100%" height="100%" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64"><path d="M32 44a12 12 0 0012-12V20a12 12 0 10-24 0v12a12 12 0 0012 12z" fill="#333"/><path d="M20 32h24v4H20z" fill="#555"/><path d="M32 48v8" stroke="#555" stroke-width="4" stroke-linecap="round"/></svg>`, 2448 fontSelection: `<svg width="100%" height="100%" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64"><text x="32" y="40" font-family="serif" font-size="24" text-anchor="middle" fill="#333">Aa</text><path d="M8 48h48v2H8z"/></svg>`, 2449 colorFilter: `<svg width="100%" height="100%" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64"><circle cx="32" cy="32" r="24" fill="none" stroke="#333" stroke-width="2"/><path d="M32 8a24 24 0 000 48V8z" fill="#f00" opacity="0.3"/><path d="M32 8a24 24 0 000 48" fill="none" stroke="#333" stroke-width="2" stroke-dasharray="4,2"/></svg>`, 2450 saturation: `<svg width="100%" height="100%" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64"><circle cx="20" cy="32" r="12" fill="#ff0000" opacity="0.7"/><circle cx="32" cy="32" r="12" fill="#00ff00" opacity="0.7"/><circle cx="44" cy="32" r="12" fill="#0000ff" opacity="0.7"/></svg>`, 2451 reducedMotion: `<svg width="100%" height="100%" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64"><rect x="16" y="24" width="8" height="16" fill="#333"/><rect x="28" y="24" width="8" height="16" fill="#333"/><rect x="40" y="24" width="8" height="16" fill="#333"/></svg>`, 2452 focusIndicator: `<svg width="100%" height="100%" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64"><rect x="12" y="12" width="40" height="40" rx="4" fill="none" stroke="currentColor" stroke-width="3" stroke-dasharray="6,3"/><circle cx="32" cy="32" r="8" fill="currentColor"/></svg>`, 2453 highlightLinks: `<svg width="100%" height="100%" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64"><rect x="8" y="14" width="48" height="10" rx="2" fill="currentColor" opacity="0.25"/><rect x="8" y="28" width="36" height="10" rx="2" fill="currentColor" opacity="0.25"/><rect x="8" y="42" width="42" height="10" rx="2" fill="currentColor" opacity="0.25"/><line x1="8" y1="23" x2="56" y2="23" stroke="currentColor" stroke-width="2"/><line x1="8" y1="37" x2="44" y2="37" stroke="currentColor" stroke-width="2"/><line x1="8" y1="51" x2="50" y2="51" stroke="currentColor" stroke-width="2"/></svg>`, 2454 readingGuide: `<svg width="100%" height="100%" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64"><line x1="4" y1="32" x2="60" y2="32" stroke="currentColor" stroke-width="3" opacity="0.7"/><line x1="4" y1="32" x2="60" y2="32" stroke="currentColor" stroke-width="1" stroke-dasharray="4,2"/><polygon points="32,22 28,28 36,28" fill="currentColor"/></svg>`, 2455 readingWindow: `<svg width="100%" height="100%" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64"><rect x="4" y="4" width="56" height="56" rx="4" fill="currentColor" opacity="0.3"/><rect x="4" y="22" width="56" height="20" rx="2" fill="none" stroke="currentColor" stroke-width="2.5"/><rect x="6" y="24" width="52" height="16" fill="white" opacity="0.9"/></svg>`, 2456 altText: `<svg width="100%" height="100%" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64"><rect x="6" y="10" width="52" height="36" rx="4" fill="none" stroke="currentColor" stroke-width="3"/><circle cx="20" cy="22" r="5" fill="currentColor"/><path d="M10 40l12-12 8 8 10-10 14 14" fill="none" stroke="currentColor" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"/><rect x="18" y="48" width="28" height="10" rx="2" fill="currentColor"/><text x="32" y="56" text-anchor="middle" font-family="Arial" font-size="8" font-weight="bold" fill="white">ALT</text></svg>`, 2457 // Enhanced feature icons (v1.3.0) 2458 hoverHighlight: `<svg width="100%" height="100%" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64"><rect x="10" y="12" width="34" height="26" rx="3" fill="none" stroke="currentColor" stroke-width="3"/><rect x="14" y="16" width="26" height="6" rx="2" fill="currentColor" opacity="0.5"/><path d="M38 40l6 16 4-7 7 3z" fill="currentColor" stroke="currentColor" stroke-width="2" stroke-linejoin="round"/></svg>`, 2459 enlargeButtons: `<svg width="100%" height="100%" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64"><rect x="8" y="20" width="48" height="24" rx="6" fill="none" stroke="currentColor" stroke-width="3"/><path d="M20 32h24M20 32l6-6M20 32l6 6M44 32l-6-6M44 32l-6 6" fill="none" stroke="currentColor" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"/></svg>`, 2460 muteMedia: `<svg width="100%" height="100%" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64"><path d="M12 24h10l12-10v36L22 40H12z" fill="currentColor"/><path d="M44 24l14 16M58 24L44 40" fill="none" stroke="currentColor" stroke-width="4" stroke-linecap="round"/></svg>`, 2461 readableFont: `<svg width="100%" height="100%" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64"><text x="32" y="42" font-family="Verdana, sans-serif" font-size="34" text-anchor="middle" fill="currentColor">Aa</text><path d="M10 52h44" stroke="currentColor" stroke-width="3" stroke-linecap="round"/></svg>`, 2462 magnifier: `<svg width="100%" height="100%" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64"><circle cx="26" cy="26" r="16" fill="none" stroke="currentColor" stroke-width="4"/><path d="M38 38l16 16" stroke="currentColor" stroke-width="5" stroke-linecap="round"/>
2462<path d="M26 18v16M18 26h16" stroke="currentColor" stroke-width="3" stroke-linecap="round"/></svg>`, 2463 textMagnifier: `<svg width="100%" height="100%" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64"><circle cx="26" cy="26" r="16" fill="none" stroke="currentColor" stroke-width="4"/><path d="M38 38l16 16" stroke="currentColor" stroke-width="5" stroke-linecap="round"/><text x="26" y="33" font-family="serif" font-size="18" text-anchor="middle" fill="currentColor">T</text></svg>`, 2464 readFocus: `<svg width="100%" height="100%" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64"><rect x="6" y="26" width="52" height="14" rx="3" fill="currentColor" opacity="0.25"/><path d="M10 20h44M10 46h34" stroke="currentColor" stroke-width="3" stroke-linecap="round" opacity="0.4"/><rect x="6" y="26" width="52" height="14" rx="3" fill="none" stroke="currentColor" stroke-width="3"/></svg>`, 2465 virtualKeyboard: `<svg width="100%" height="100%" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64"><rect x="4" y="16" width="56" height="32" rx="4" fill="none" stroke="currentColor" stroke-width="3"/><path d="M12 24h2M20 24h2M28 24h2M36 24h2M44 24h2M52 24h0M12 32h2M20 32h2M28 32h2M36 32h2M44 32h2M22 40h20" stroke="currentColor" stroke-width="3" stroke-linecap="round"/></svg>`, 2466 readableMode: `<svg width="100%" height="100%" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64"><rect x="10" y="8" width="44" height="48" rx="3" fill="none" stroke="currentColor" stroke-width="3"/><path d="M18 20h28M18 28h28M18 36h20M18 44h24" stroke="currentColor" stroke-width="3" stroke-linecap="round"/></svg>`, 2467 dictionary: `<svg width="100%" height="100%" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64"><path d="M14 10h30a6 6 0 016 6v38a4 4 0 00-4-4H14z" fill="none" stroke="currentColor" stroke-width="3" stroke-linejoin="round"/><path d="M14 50a4 4 0 014-4h32" fill="none" stroke="currentColor" stroke-width="3"/><text x="30" y="38" font-family="serif" font-size="20" text-anchor="middle" fill="currentColor">A</text></svg>`, 2468 customColor: `<svg width="100%" height="100%" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64"><path d="M32 8a24 24 0 000 48c4 0 6-3 6-6 0-3-2-4-2-7 0-2 2-4 5-4h5a10 10 0 0010-10C56 18 45 8 32 8z" fill="none" stroke="currentColor" stroke-width="3"/><circle cx="22" cy="24" r="3" fill="currentColor"/><circle cx="32" cy="18" r="3" fill="currentColor"/><circle cx="42" cy="24" r="3" fill="currentColor"/></svg>`, 2469}; 2470 2471// Selectable launcher-button icons. The integrator picks one at setup time 2472// (npm install prompt or WordPress admin) via ENABLESTACK_CONFIG.icon. 2473// Paths carry no fill so they inherit the button's white fill from CSS. 2474const EU_LAUNCHER_ICONS = { 2475 // Classic accessibility person (unchanged default) 2476 default: icons.buttonsvg, 2477 // Wheelchair â International Symbol of Access 2478 wheelchair: `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="30px" height="30px"><circle cx="12" cy="4" r="2"></circle><path d="M19 13v-2c-1.54.02-3.09-.75-4.07-1.83l-1.29-1.43c-.17-.19-.38-.34-.61-.45-.01 0-.01-.01-.02-.01H13c-.35-.2-.75-.3-1.19-.26C10.76 6.05 10 6.99 10 8.04V14c0 1.1.9 2 2 2h5v6h2v-7c0-1.1-.9-2-2-2h-3V9.66c1.07.98 2.57 1.54 4 1.54z"></path><path d="M12.83 18c-.41 1.16-1.52 2-2.83 2-1.66 0-3-1.34-3-3 0-1.31.84-2.42 2-2.83V12.1c-2.28.46-4 2.48-4 4.9 0 2.76 2.24 5 5 5 2.42 0 4.44-1.72 4.9-4h-2.07z"></path></svg>`, 2479 // Active person (accessibility "new" â striding with raised arm) 2480 person: `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="30px" height="30px"><circle cx="12" cy="4" r="2"></circle><path d="m15.89 8.11-.01-.01c-.4-.4-1.07-1.1-2.36-1.1h-3.13C8.24 6.99 6 4.75 6 2H4c0 3.16 2.11 5.84 5 6.71V22h2v-6h2v6h2V10.05L18.95 14l1.41-1.41-4.47-4.48z"></path></svg>`, 2481 // Eye â vision / visibility 2482 eye: `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="30px" height="30px"><path d="M12 4.5C7 4.5 2.73 7.61 1 12c1.73 4.39 6 7.5 11 7.5s9.27-3.11 11-7.5c-1.73-4.39-6-7.5-11-7.5zM12 17c-2.76 0-5-2.24-5-5s2.24-5 5-5 5 2.24 5 5-2.24 5-5 5zm0-8c-1.66 0-3 1.34-3 3s1.34 3 3 3 3-1.34 3-3-1.34-3-3-3z"></path></svg>` 2483}; 2484 2485// EnableUser wordmark logo (transparent PNG data URI) shown in the panel header. 2486const EU_LOGO = 'data:image/png;
2486base64,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'; 2487 2488// Resolve the configured launcher icon (falls back to the default). 2489function euLauncherIconSvg() { 2490 const key = (typeof WIDGET_CONFIG !== 'undefined' && WIDGET_CONFIG.icon) || 'default'; 2491 return EU_LAUNCHER_ICONS[key] || EU_LAUNCHER_ICONS.default; 2492} 2493 2494// =========================================== 2495// SHADOW DOM SETUP 2496// =========================================== 2497 2498let shadowRoot = null; 2499 2500// Inject styles into the page (NOT the widget) 2501function injectPageStyles() { 2502 const styleSheet = document.createElement('style'); 2503 styleSheet.innerText = pageStyles; 2504 styleSheet.id = 'eu-accessibility-page-styles'; 2505 document.head.appendChild(styleSheet); 2506 2507 // Add SVG color blindness filters to main document 2508 const svgFilters = document.createElementNS('http://www.w3.org/2000/svg', 'svg'); 2509 svgFilters.style.position = 'absolute'; 2510 svgFilters.style.width = '0'; 2511 svgFilters.setAttribute('class', 'eu-accessibility-filters'); 2512 svgFilters.style.height = '0'; 2513 svgFilters.innerHTML = ` 2514 <defs> 2515 <filter id="protanopia-filter"> 2516 <feColorMatrix type="matrix" values="0.567,0.433,0,0,0 0.558,0.442,0,0,0 0,0.242,0.758,0,0 0,0,0,1,0"/> 2517 </filter> 2518 <filter id="deuteranopia-filter"> 2519 <feColorMatrix type="matrix" values="0.625,0.375,0,0,0 0.7,0.3,0,0,0 0,0.3,0.7,0,0 0,0,0,1,0"/> 2520 </filter> 2521 <filter id="tritanopia-filter"> 2522 <feColorMatrix type="matrix" values="0.95,0.05,0,0,0 0,0.433,0.567,0,0 0,0.475,0.525,0,0 0,0,0,1,0"/> 2523 </filter> 2524 </defs> 2525 `; 2526 document.body.appendChild(svgFilters); 2527} 2528 2529// Visually-hidden aria-live region so tool changes are announced to screen readers. 2530const euAnnouncer = { 2531 region: null, 2532 attach: function (root) { 2533 if (this.region) return; 2534 const el = document.createElement('div'); 2535 el.className = 'eu-sr-only'; 2536 el.setAttribute('aria-live', 'polite'); 2537 el.setAttribute('aria-atomic', 'true'); 2538 root.appendChild(el); 2539 this.region = el; 2540 }, 2541 say: function (message) { 2542 if (!this.region || !message) return; 2543 // Clear then set (after a tick) so repeated identical messages re-announce. 2544 this.region.textContent = ''; 2545 const region = this.region; 2546 setTimeout(function () { region.textContent = message; }, 40); 2547 } 2548}; 2549 2550// Create shadow DOM container 2551function createShadowContainer() { 2552 const container = document.createElement('div'); 2553 container.id = 'eu-accessibility-widget-container'; 2554 document.body.appendChild(container); 2555 2556 // Create shadow root 2557 shadowRoot = container.attachShadow({ mode: 'open' }); 2558 2559 // Add widget styles to shadow DOM 2560 const styleElement = document.createElement('style'); 2561 styleElement.textContent = widgetStyles; 2562 shadowRoot.appendChild(styleElement); 2563 2564 // Live region for screen-reader announcements 2565 euAnnouncer.attach(shadowRoot); 2566 2567 return shadowRoot; 2568} 2569 2570// =========================================== 2571// CORE UTILITY FUNCTIONS 2572// =========================================== 2573 2574// Cache for DOM elements to improve performance 2575const domCache = { 2576 get body() { 2577 return document.body; 2578 }, 2579 get documentElement() { 2580 return document.documentElement; 2581 }, 2582 images: null, 2583 lastImageUpdate: 0, 2584 getImages: function () { 2585 const now = Date.now(); 2586 if (!this.images || now - this.lastImageUpdate > 5000) { 2587 this.images = document.querySelectorAll('img'); 2588 this.lastImageUpdate = now; 2589 } 2590 return this.images; 2591 } 2592}; 2593 2594// Apply saved settings from localStorage (optimized) 2595function applySettings() { 2596 // Check if body element exists 2597 if (!domCache.body || !domCache.documentElement) { 2598 console.warn('Body or document element not ready yet'); 2599 return; 2600 } 2601 2602 // Simple boolean toggles that map directly to a body class. Multi-level 2603 // features (text size, contrast, alignment, etc.) are handled separately below. 2604 const settings = [
vendor: 4,477 bytes, lines 2605-2721
2605 { key: 'biggerCursor', className: 'eu-bigger-cursor' }, 2606 { key: 'pauseAnimations', className: 'eu-pause-animations' }, 2607 { key: 'enlargeButtons', className: 'eu-enlarge-buttons' }, 2608 { key: 'readableFont', className: 'eu-readable-font' }, 2609 ]; 2610 2611 // Batch DOM operations for better performance 2612 const bodyClassesToAdd = []; 2613 const bodyClassesToRemove = []; 2614 const docClassesToAdd = []; 2615 const docClassesToRemove = []; 2616 2617 settings.forEach(({ key, className, target = domCache.body }) => { 2618 const isActive = localStorage.getItem(key) === 'true'; 2619 if (className) { 2620 if (target === domCache.documentElement) { 2621 if (isActive) { 2622 docClassesToAdd.push(className); 2623 } else { 2624 docClassesToRemove.push(className); 2625 } 2626 } else { 2627 if (isActive) { 2628 bodyClassesToAdd.push(className); 2629 } else { 2630 bodyClassesToRemove.push(className); 2631 } 2632 } 2633 } 2634 }); 2635 2636 // Apply all class changes at once - ONLY remove classes that start with 'eu-' 2637 if (bodyClassesToAdd.length > 0) { 2638 domCache.body.classList.add(...bodyClassesToAdd); 2639 } 2640 if (bodyClassesToRemove.length > 0) { 2641 // Only remove our own classes, never remove classes that don't start with 'eu-' 2642 bodyClassesToRemove.forEach(className => { 2643 if (className.startsWith('eu-')) { 2644 domCache.body.classList.remove(className); 2645 } 2646 }); 2647 } 2648 if (docClassesToAdd.length > 0) { 2649 domCache.documentElement.classList.add(...docClassesToAdd); 2650 } 2651 if (docClassesToRemove.length > 0) { 2652 // Only remove our own classes, never remove classes that don't start with 'eu-' 2653 docClassesToRemove.forEach(className => { 2654 if (className.startsWith('eu-')) { 2655 domCache.documentElement.classList.remove(className); 2656 } 2657 }); 2658 } 2659 2660 // Handle font selection - only remove widget's own font classes 2661 const fontClasses = ['eu-font-arial', 'eu-font-times', 'eu-font-verdana', 'eu-font-dyslexic']; 2662 fontClasses.forEach(className => { 2663 if (domCache.body.classList.contains(className)) { 2664 domCache.body.classList.remove(className); 2665 } 2666 }); 2667 const selectedFont = localStorage.getItem('fontSelection'); 2668 if (selectedFont) { 2669 domCache.body.classList.add(`eu-font-${selectedFont}`); 2670 } 2671 2672 // Handle color filters - only remove widget's own filter classes 2673 const filterClasses = ['eu-filter-protanopia', 'eu-filter-deuteranopia', 'eu-filter-tritanopia', 'eu-filter-grayscale']; 2674 filterClasses.forEach(className => { 2675 if (domCache.documentElement.classList.contains(className)) { 2676 domCache.documentElement.classList.remove(className); 2677 } 2678 }); 2679 const selectedFilter = localStorage.getItem('colorFilter'); 2680 if (selectedFilter) { 2681 domCache.documentElement.classList.add(`eu-filter-${selectedFilter}`); 2682 } 2683 2684 // Handle saturation filters - only remove widget's own saturation classes 2685 const saturationClasses = ['eu-saturation-low', 'eu-saturation-high', 'eu-saturation-none']; 2686 saturationClasses.forEach(className => { 2687 if (domCache.documentElement.classList.contains(className)) { 2688 domCache.documentElement.classList.remove(className); 2689 } 2690 }); 2691 const selectedSaturation = localStorage.getItem('saturation'); 2692 if (selectedSaturation) { 2693 domCache.documentElement.classList.add(`eu-saturation-${selectedSaturation}`); 2694 } 2695 2696 // Handle text alignment - only remove widget's own alignment classes 2697 const alignClasses = ['eu-text-align-left', 'eu-text-align-center', 'eu-text-align-right']; 2698 alignClasses.forEach(className => { 2699 if (domCache.body.classList.contains(className)) { 2700 domCache.body.classList.remove(className); 2701 } 2702 }); 2703 const selectedAlign = localStorage.getItem('textAlign'); 2704 if (selectedAlign) { 2705 domCache.body.classList.add(`eu-text-align-${selectedAlign}`); 2706 } 2707 2708 // Handle bigger text - only remove widget's own text size classes 2709 const textClasses = ['eu-bigger-text-medium', 'eu-bigger-text-large', 'eu-bigger-text-xlarge']; 2710 textClasses.forEach(className => { 2711 if (domCache.body.classList.contains(className)) { 2712 domCache.body.classList.remove(className); 2713 } 2714 }); 2715 const selectedTextSize = localStorage.getItem('biggerText'); 2716 if (selectedTextSize) { 2717 domCache.body.classList.add(`eu-bigger-text-${selectedTextSize}`); 2718 } 2719 2720 // Handle high contrast - only remove widget's own contrast classes 2721 const contrastClasses = ['eu-high-contrast-medium', 'eu-high-contrast-high', 'eu-high-contrast-ultra'];
2722 contrastClasses.forEach(className => { 2723 if (domCache.body.classList.contains(className)) { 2724 domCache.body.classList.remove(className); 2725 } 2726 }); 2727 const selectedContrast = localStorage.getItem('highContrast'); 2728 if (selectedContrast) { 2729 domCache.body.classList.add(`eu-high-contrast-${selectedContrast}`); 2730 } 2731 2732 // Handle Text Spacing (3 Levels) - only remove widget's own spacing classes 2733 const spacingClasses = ['eu-text-spacing-light', 'eu-text-spacing-medium', 'eu-text-spacing-heavy']; 2734 spacingClasses.forEach(className => { 2735 if (domCache.body.classList.contains(className)) { 2736 domCache.body.classList.remove(className); 2737 } 2738 }); 2739 const selectedSpacing = localStorage.getItem('textSpacing'); 2740 if (selectedSpacing) { 2741 domCache.body.classList.add(`eu-text-spacing-${selectedSpacing}`); 2742 } 2743 2744 // Handle Line Height (3 Levels) - only remove widget's own line height classes 2745 const lineHeightClasses = ['eu-line-height-2em', 'eu-line-height-3em', 'eu-line-height-4em']; 2746 lineHeightClasses.forEach(className => { 2747 if (domCache.body.classList.contains(className)) { 2748 domCache.body.classList.remove(className); 2749 } 2750 }); 2751 const selectedLineHeight = localStorage.getItem('lineHeight'); 2752 if (selectedLineHeight) { 2753 domCache.body.classList.add(`eu-line-height-${selectedLineHeight}`); 2754 } 2755 2756 // Handle images with cached query 2757 const hideImages = localStorage.getItem('hideImages') === 'true'; 2758 const displayStyle = hideImages ? 'none' : '';
2759 domCache.getImages().forEach((img) => { 2760 img.style.display = displayStyle; 2761 }); 2762 2763 // Restore new toggle features 2764 if (localStorage.getItem('focusIndicator') === 'true') { 2765 toggleFocusIndicator(true); 2766 } 2767 if (localStorage.getItem('highlightLinks') === 'true') { 2768 toggleHighlightLinks(true); 2769 } 2770 if (localStorage.getItem('readingGuide') === 'true') { 2771 readingGuide.toggle(true); 2772 } 2773 if (localStorage.getItem('readingWindow') === 'true') { 2774 readingWindow.toggle(true); 2775 } 2776 if (localStorage.getItem('showAltText') === 'true' && !altTextViewer.active) { 2777 altTextViewer.toggle(true); 2778 } 2779 2780 // Restore enhanced features (v1.3.0) 2781 if (localStorage.getItem('hoverHighlight') === 'true') hoverHighlight.toggle(true); 2782 if (localStorage.getItem('muteMedia') === 'true') muteMedia.toggle(true); 2783 if (localStorage.getItem('textMagnifier') === 'true') textMagnifier.toggle(true); 2784 if (localStorage.getItem('readFocus') === 'true') readFocus.toggle(true); 2785 if (localStorage.getItem('pauseAnimations') === 'true') mediaFreeze.enable(); 2786 if (localStorage.getItem('virtualKeyboard') === 'true') virtualKeyboard.toggle(true); 2787 if (localStorage.getItem('dictionary') === 'true') dictionary.toggle(true); 2788 applyPageMagnifier(localStorage.getItem('pageMagnifier')); 2789 customColor.restore(); 2790 // Reader View is an on-demand overlay â never auto-reopen it on load. 2791 localStorage.removeItem('readableMode'); 2792 2793 if (screenReader.active && screenReader.isSupported) { 2794 document.addEventListener('focusin', screenReader.handleFocus); 2795 document.addEventListener('mouseover', screenReader.handleHover); 2796 } 2797 2798 if (voiceControl.isActive && voiceControl.isSupported) { 2799 voiceControl.startListening(); 2800 } 2801} 2802 2803// =========================================== 2804// UI COMPONENTS 2805// =========================================== 2806 2807// Create the accessibility button 2808function createAccessibilityButton() { 2809 const buttonContainer = document.createElement('div'); 2810 buttonContainer.id = 'eu-accessibility-fixed-button'; 2811 2812 const button = document.createElement('button'); 2813 button.id = 'eu-accessibility-button'; 2814 button.innerHTML = euLauncherIconSvg(); 2815 button.setAttribute('aria-label', getTranslation('accessibilityMenu')); 2816 2817 // --- Draggable launcher (a plain click still opens the menu) --- 2818 let dragState = null; 2819 let didDrag = false; 2820 const DRAG_THRESHOLD = 5; 2821 2822 button.addEventListener('click', function () { 2823 // Ignore the click that ends a drag so dragging never opens the menu. 2824 if (didDrag) { didDrag = false; return; } 2825 toggleMenu(); 2826 }); 2827 2828 button.addEventListener('keydown', function (e) { 2829 if (e.key === 'Enter' || e.key === ' ') { 2830 e.preventDefault(); 2831 toggleMenu(); 2832 } 2833 }); 2834 2835 function clampAndPlace(left, top) { 2836 const size = buttonContainer.getBoundingClientRect(); 2837 left = Math.max(0, Math.min(left, window.innerWidth - size.width)); 2838 top = Math.max(0, Math.min(top, window.innerHeight - size.height)); 2839 // The base stylesheet positions the launcher with !important, so inline 2840 // values must also be !important to take effect while dragging. 2841 buttonContainer.style.setProperty('left', left + 'px', 'important'); 2842 buttonContainer.style.setProperty('top', top + 'px', 'important'); 2843 buttonContainer.style.setProperty('right', 'auto', 'important'); 2844 buttonContainer.style.setProperty('bottom', 'auto', 'important'); 2845 } 2846 2847 button.addEventListener('pointerdown', function (e) { 2848 if (e.button !== 0) return; 2849 const rect = buttonContainer.getBoundingClientRect(); 2850 dragState = { startX: e.clientX, startY: e.clientY, originLeft: rect.left, originTop: rect.top }; 2851 didDrag = false; 2852 }); 2853 2854 window.addEventListener('pointermove', function (e) { 2855 if (!dragState) return; 2856 const dx = e.clientX - dragState.startX; 2857 const dy = e.clientY - dragState.startY; 2858 if (!didDrag && (Math.abs(dx) + Math.abs(dy)) < DRAG_THRESHOLD) return; 2859 didDrag = true; 2860 buttonContainer.classList.add('eu-dragging'); 2861 clampAndPlace(dragState.originLeft + dx, dragState.originTop + dy); 2862 }); 2863 2864 window.addEventListener('pointerup', function () { 2865 if (!dragState) return; 2866 if (didDrag) { 2867 buttonContainer.classList.remove('eu-dragging'); 2868 const rect = buttonContainer.getBoundingClientRect();
2869 try { 2870 localStorage.setItem('euButtonPos', JSON.stringify({ left: Math.round(rect.left), top: Math.round(rect.top) })); 2871 } catch (e) { /* ignore */ } 2872 } 2873 dragState = null; 2874 }); 2875 2876 buttonContainer.appendChild(button); 2877 shadowRoot.appendChild(buttonContainer); 2878 2879 // Restore a previously dragged position 2880 try { 2881 const saved = JSON.parse(localStorage.getItem('euButtonPos') || 'null'); 2882 if (saved && typeof saved.left === 'number' && typeof saved.top === 'number') { 2883 clampAndPlace(saved.left, saved.top); 2884 } 2885 } catch (e) { /* ignore */ } 2886 2887 // Reposition on resize so the launcher never lands off-screen 2888 window.addEventListener('resize', function () { 2889 if (buttonContainer.style.left) { 2890 clampAndPlace(parseInt(buttonContainer.style.left, 10) || 0, parseInt(buttonContainer.style.top, 10) || 0); 2891 } 2892 }); 2893} 2894 2895// Reset all accessibility settings 2896function resetAccessibilitySettings() { 2897 const keys = [ 2898 'biggerCursor', 2899 'biggerText', 2900 'dyslexiaFont', 2901 'hideImages', 2902 'lineHeight', 2903 'pauseAnimations', 2904 'screenReader', 2905 'textAlign', 2906 'textSpacing', 2907 'highContrast', 2908 'voiceControl', 2909 'fontSelection', 2910 'colorFilter', 2911 'saturation', 2912 'focusIndicator', 2913 'highlightLinks', 2914 'readingGuide', 2915 'readingWindow', 2916 'showAltText', 2917 'euActiveProfile', 2918 // Enhanced features (v1.3.0) 2919 'hoverHighlight', 2920 'enlargeButtons', 2921 'muteMedia', 2922 'readableFont', 2923 'pageMagnifier', 2924 'textMagnifier', 2925 'readFocus', 2926 'virtualKeyboard', 2927 'readableMode', 2928 'dictionary', 2929 'customColorBg', 2930 'customColorText', 2931 'customColorHead', 2932 ]; 2933 keys.forEach((key) => localStorage.removeItem(key)); 2934 2935 // Remove only widget's own CSS classes - never touch existing body/document classes 2936 // Check if body and documentElement exist first 2937 if (!document.body || !document.documentElement) { 2938 console.warn('Body or document element not ready during reset'); 2939 return; 2940 } 2941 2942 // Remove body classes only if they exist and start with 'eu-' 2943 const cssClasses = [ 2944 'eu-bigger-cursor', 2945 'eu-bigger-text', 2946 'eu-dyslexia-font', 2947 'eu-pause-animations', 2948 'eu-text-align', 2949 'eu-font-arial', 2950 'eu-font-times', 2951 'eu-font-verdana', 2952 'eu-font-dyslexic', 2953 'eu-high-contrast-medium', 2954 'eu-high-contrast-high', 2955 'eu-high-contrast-ultra', 2956 'eu-bigger-text-medium', 2957 'eu-bigger-text-large', 2958 'eu-bigger-text-xlarge', 2959 'eu-text-spacing-light', 2960 'eu-text-spacing-medium', 2961 'eu-text-spacing-heavy', 2962 'eu-line-height-2em', 2963 'eu-line-height-3em', 2964 'eu-line-height-4em', 2965 'eu-text-align-left', 2966 'eu-text-align-center', 2967 'eu-text-align-right', 2968 'eu-focus-indicator', 2969 'eu-highlight-links', 2970 'eu-enlarge-buttons', 2971 'eu-readable-font' 2972 ]; 2973 cssClasses.forEach(cls => { 2974 if (document.body.classList.contains(cls)) { 2975 document.body.classList.remove(cls); 2976 } 2977 }); 2978 2979 // Remove document element classes only if they exist and start with 'eu-' 2980 const documentClasses = [ 2981 'eu-filter-protanopia', 2982 'eu-filter-deuteranopia', 2983 'eu-filter-tritanopia', 2984 'eu-filter-grayscale', 2985 'eu-saturation-low', 2986 'eu-saturation-high', 2987 'eu-saturation-none' 2988 ]; 2989 documentClasses.forEach(cls => { 2990 if (document.documentElement.classList.contains(cls)) { 2991 document.documentElement.classList.remove(cls); 2992 } 2993 }); 2994
2995 domCache.getImages().forEach((img) => (img.style.display = '')); 2996 2997 if (screenReader.active) { 2998 screenReader.toggle(false); 2999 } 3000 3001 if (voiceControl.isActive) { 3002 voiceControl.toggle(false); 3003 } 3004 3005 // Reset new features 3006 toggleFocusIndicator(false); 3007 toggleHighlightLinks(false); 3008 readingGuide.toggle(false); 3009 readingWindow.toggle(false); 3010 altTextViewer.toggle(false); 3011 3012 // Reset enhanced features (v1.3.0) 3013 hoverHighlight.toggle(false); 3014 muteMedia.toggle(false); 3015 mediaFreeze.disable(); 3016 textMagnifier.toggle(false); 3017 readFocus.toggle(false); 3018 virtualKeyboard.toggle(false); 3019 readableMode.toggle(false); 3020 dictionary.toggle(false); 3021 applyPageMagnifier(null); 3022 customColor.clear(); 3023 if (customColor.panel) customColor.panel.classList.remove('eu-open'); 3024 3025 applySettings(); 3026 3027 const buttons = shadowRoot.querySelectorAll('#eu-accessibility-menu .eu-accessibility-option'); 3028 buttons.forEach((button) => { 3029 button.classList.remove('active'); 3030 button.setAttribute('aria-pressed', 'false'); 3031 3032 // Reset step indicators 3033 const steps = button.querySelectorAll('.eu-option-step'); 3034 steps.forEach(step => step.classList.remove('active')); 3035 }); 3036 3037 // Clear profile chips and re-derive all button states 3038 refreshMenuButtonStates(); 3039} 3040 3041// Create toggle buttons for accessibility options 3042function createToggleButton( 3043 buttonText, 3044 localStorageKey, 3045 className, 3046 targetElement = document.body, 3047 customToggleFunction = null, 3048 iconSVG = '', 3049 requiresFeature = null, 3050 optionId = null 3051) { 3052 const button = document.createElement('button'); 3053 button.innerHTML = ` 3054 <span class="eu-icon">${iconSVG}</span> 3055 <span class="eu-button-text">${buttonText}</span> 3056 `; 3057 button.setAttribute('data-key', localStorageKey); 3058 button.setAttribute('aria-label', buttonText); 3059 button.classList.add('eu-accessibility-option'); 3060 if (optionId) { 3061 button.setAttribute('data-accessibility-option-id', optionId); 3062 } 3063 3064 // Check if feature is supported 3065 if (requiresFeature && !requiresFeature.isSupported) { 3066 button.disabled = true; 3067 button.setAttribute('title', `${buttonText} ${getTranslation('notSupportedBrowser')}`); 3068 button.style.opacity = '0.5'; 3069 return button; 3070 } 3071 3072 const isActive = localStorage.getItem(localStorageKey) === 'true'; 3073 button.setAttribute('aria-pressed', isActive); 3074 button.setAttribute('role', 'switch'); 3075 if (isActive) { 3076 button.classList.add('active'); 3077 } 3078 3079 button.addEventListener('click', function () { 3080 handleToggle(); 3081 }); 3082 3083 button.addEventListener('keydown', function (e) { 3084 if (e.key === 'Enter' || e.key === ' ') { 3085 e.preventDefault(); 3086 handleToggle(); 3087 } 3088 }); 3089 3090 function handleToggle() { 3091 const newIsActive = localStorage.getItem(localStorageKey) !== 'true'; 3092 3093 // If there's a custom toggle function, call it and check if it succeeded 3094 if (customToggleFunction) { 3095 const success = customToggleFunction(newIsActive); 3096 if (success === false) { 3097 // Feature not supported or failed 3098 return; 3099 } 3100 } 3101 3102 localStorage.setItem(localStorageKey, newIsActive); 3103 button.setAttribute('aria-pressed', newIsActive); 3104 3105 if (newIsActive) { 3106 button.classList.add('active'); 3107 if (className) { 3108 targetElement.classList.add(className); 3109 } 3110 } else { 3111 button.classList.remove('active'); 3112 if (className) { 3113 targetElement.classList.remove(className); 3114 } 3115 } 3116 } 3117 3118 return button; 3119} 3120 3121// Create special action buttons (for cycling through options) 3122function createActionButton(buttonText, actionFunction, iconSVG, optionsConfig = null, optionId = null) { 3123 const button = document.createElement('button'); 3124 3125 let buttonHTML = ` 3126 <span class="eu-icon">${iconSVG}</span> 3127 <span class="eu-button-text">${buttonText}</span> 3128 `; 3129 3130 // Add option steps if configured 3131 if (optionsConfig) { 3132 buttonHTML += '<div class="eu-option-steps">'; 3133 for (let i = 0; i < optionsConfig.count; i++) { 3134 buttonHTML += '<div class="eu-option-step"></div>'; 3135 } 3136 buttonHTML += '</div>'; 3137 } 3138 3139 button.innerHTML = buttonHTML; 3140 button.setAttribute('aria-label', buttonText); 3141 button.classList.add('eu-accessibility-option'); 3142 button.setAttribute('data-options-config', optionsConfig ? JSON.stringify(optionsConfig) : ''); 3143 if (optionId) { 3144 button.setAttribute('data-accessibility-option-id', optionId); 3145 button.setAttribute('data-key', optionId); // Add data-key for voice commands 3146 } 3147 3148 // Update initial status 3149 updateActionButtonStatus(button, optionId, optionsConfig); 3150 3151 button.addEventListener('click', function () { 3152 const result = actionFunction(); 3153 if (result) { 3154 updateActionButtonStatus(button, optionId, optionsConfig); 3155 euAnnouncer.say(buttonText + ': ' + result); 3156 } 3157 }); 3158 3159 button.addEventListener('keydown', function (e) { 3160 if (e.key === 'Enter' || e.key === ' ') { 3161 e.preventDefault(); 3162 const result = actionFunction(); 3163 if (result) { 3164 updateActionButtonStatus(button, optionId, optionsConfig); 3165 euAnnouncer.say(buttonText + ': ' + result); 3166 } 3167 } 3168 }); 3169 3170 return button; 3171} 3172 3173// Update action button status on page load 3174function updateActionButtonStatus(button, optionId, optionsConfig) { 3175 if (!optionsConfig) return; 3176 3177 const steps = button.querySelectorAll('.eu-option-step'); 3178 let currentIndex = -1; 3179 3180 if (optionId === 'fontSelection') { 3181 const currentFont = localStorage.getItem('fontSelection'); 3182 const fonts = ['arial', 'times', 'verdana', 'dyslexic']; 3183 currentIndex = currentFont ? fonts.indexOf(currentFont) : -1; 3184 } else if (optionId === 'colorFilter') { 3185 const currentFilter = localStorage.getItem('colorFilter'); 3186 const filters = ['protanopia', 'deuteranopia', 'tritanopia', 'grayscale']; 3187 currentIndex = currentFilter ? filters.indexOf(currentFilter) : -1; 3188 } else if (optionId === 'textAlign') { 3189 const currentAlign = localStorage.getItem('textAlign'); 3190 const alignments = ['left', 'center', 'right']; 3191 currentIndex = currentAlign ? alignments.indexOf(currentAlign) : -1; 3192 } else if (optionId === 'biggerText') { 3193 const currentSize = localStorage.getItem('biggerText'); 3194 const sizes = ['medium', 'large', 'xlarge']; 3195 currentIndex = currentSize ? sizes.indexOf(currentSize) : -1; 3196 } else if (optionId === 'highContrast') { 3197 const currentContrast = localStorage.getItem('highContrast'); 3198 const contrasts = ['medium', 'high', 'ultra']; 3199 currentIndex = currentContrast ? contrasts.indexOf(currentContrast) : -1; 3200 } else if (optionId === 'textSpacing') { 3201 const currentSpacing = localStorage.getItem('textSpacing'); 3202 const spacings = ['light', 'medium', 'heavy']; 3203 currentIndex = currentSpacing ? spacings.indexOf(currentSpacing) : -1; 3204 } else if (optionId === 'lineHeight') { 3205 const currentLineHeight = localStorage.getItem('lineHeight'); 3206 const heights = ['2em', '3em', '4em']; 3207 currentIndex = currentLineHeight ? heights.indexOf(currentLineHeight) : -1; 3208 } else if (optionId === 'saturation') { 3209 const currentSaturation = localStorage.getItem('saturation'); 3210 const saturations = ['low', 'high', 'none']; 3211 currentIndex = currentSaturation ? saturations.indexOf(currentSaturation) : -1; 3212 } else if (optionId === 'pageMagnifier') { 3213 const currentMag = localStorage.getItem('pageMagnifier'); 3214 const mags = ['1.25', '1.5', '2']; 3215 currentIndex = currentMag ? mags.indexOf(currentMag) : -1; 3216 } 3217 3218 // Update step indicators - show all previous steps as active 3219 steps.forEach((step, index) => { 3220 if (index <= currentIndex) { 3221 step.classList.add('active'); 3222 } else { 3223 step.classList.remove('active'); 3224 } 3225 }); 3226 3227 // Toggle active class on button itself if any option is selected 3228 if (currentIndex !== -1) { 3229 button.classList.add('active'); 3230 button.setAttribute('aria-pressed', 'true'); 3231 } else { 3232 button.classList.remove('active'); 3233 button.setAttribute('aria-pressed', 'false'); 3234 } 3235} 3236 3237// =========================================== 3238// FEATURE TOGGLE FUNCTIONS 3239// =========================================== 3240 3241// Function to hide or show images (optimized) 3242function toggleHideImages(isActive) { 3243 const displayStyle = isActive ? 'none' : '';
vendor: 4,936 bytes, lines 3244-3368
3244 domCache.getImages().forEach((img) => { 3245 img.style.display = displayStyle; 3246 }); 3247} 3248 3249// Font selection handler (optimized) 3250function handleFontSelection() { 3251 const fonts = ['arial', 'times', 'verdana', 'dyslexic']; 3252 const currentFont = localStorage.getItem('fontSelection') || 'default'; 3253 const currentIndex = fonts.indexOf(currentFont); 3254 const nextIndex = (currentIndex + 1) % (fonts.length + 1); // +1 for default 3255 3256 // Remove only widget's own font classes 3257 const fontClasses = ['eu-font-arial', 'eu-font-times', 'eu-font-verdana', 'eu-font-dyslexic']; 3258 fontClasses.forEach(className => { 3259 if (domCache.body.classList.contains(className)) { 3260 domCache.body.classList.remove(className); 3261 } 3262 }); 3263 3264 if (nextIndex === fonts.length) { 3265 // Default font 3266 localStorage.removeItem('fontSelection'); 3267 return getTranslation('defaultFont'); 3268 } else { 3269 const selectedFont = fonts[nextIndex]; 3270 localStorage.setItem('fontSelection', selectedFont); 3271 domCache.body.classList.add(`eu-font-${selectedFont}`); 3272 return selectedFont.charAt(0).toUpperCase() + selectedFont.slice(1); 3273 } 3274} 3275 3276// Saturation handler with 3 states (low, high, none/grayscale) 3277function handleSaturation() { 3278 const saturations = ['low', 'high', 'none']; 3279 const currentSaturation = localStorage.getItem('saturation') || 'default'; 3280 const currentIndex = saturations.indexOf(currentSaturation); 3281 const nextIndex = (currentIndex + 1) % (saturations.length + 1); // +1 for default 3282 3283 // Remove only widget's own saturation classes 3284 const saturationClasses = ['eu-saturation-low', 'eu-saturation-high', 'eu-saturation-none']; 3285 saturationClasses.forEach(className => { 3286 if (domCache.documentElement.classList.contains(className)) { 3287 domCache.documentElement.classList.remove(className); 3288 } 3289 }); 3290 3291 if (nextIndex === saturations.length) { 3292 // Default saturation 3293 localStorage.removeItem('saturation'); 3294 return 'Default'; 3295 } else { 3296 const selectedSaturation = saturations[nextIndex]; 3297 localStorage.setItem('saturation', selectedSaturation); 3298 domCache.documentElement.classList.add(`eu-saturation-${selectedSaturation}`); 3299 if (selectedSaturation === 'none') { 3300 return 'No Saturation'; 3301 } 3302 return selectedSaturation.charAt(0).toUpperCase() + selectedSaturation.slice(1) + ' Saturation'; 3303 } 3304} 3305 3306// Color filter handler (optimized) 3307function handleColorFilter() { 3308 const filters = ['protanopia', 'deuteranopia', 'tritanopia', 'grayscale']; 3309 const currentFilter = localStorage.getItem('colorFilter') || 'none'; 3310 const currentIndex = filters.indexOf(currentFilter); 3311 const nextIndex = (currentIndex + 1) % (filters.length + 1); // +1 for none 3312 3313 // Remove only widget's own filter classes 3314 const filterClasses = ['eu-filter-protanopia', 'eu-filter-deuteranopia', 'eu-filter-tritanopia', 'eu-filter-grayscale']; 3315 filterClasses.forEach(className => { 3316 if (domCache.documentElement.classList.contains(className)) { 3317 domCache.documentElement.classList.remove(className); 3318 } 3319 }); 3320 3321 if (nextIndex === filters.length) { 3322 // No filter 3323 localStorage.removeItem('colorFilter'); 3324 return getTranslation('noFilter'); 3325 } else { 3326 const selectedFilter = filters[nextIndex]; 3327 localStorage.setItem('colorFilter', selectedFilter); 3328 domCache.documentElement.classList.add(`eu-filter-${selectedFilter}`); 3329 return selectedFilter.charAt(0).toUpperCase() + selectedFilter.slice(1); 3330 } 3331} 3332 3333// Text align handler with 3 states 3334function handleTextAlign() { 3335 const alignments = ['left', 'center', 'right']; 3336 const currentAlign = localStorage.getItem('textAlign') || 'none'; 3337 const currentIndex = alignments.indexOf(currentAlign); 3338 const nextIndex = (currentIndex + 1) % (alignments.length + 1); // +1 for none 3339 3340 // Remove only widget's own alignment classes 3341 const alignClasses = ['eu-text-align-left', 'eu-text-align-center', 'eu-text-align-right']; 3342 alignClasses.forEach(className => { 3343 if (domCache.body.classList.contains(className)) { 3344 domCache.body.classList.remove(className); 3345 } 3346 }); 3347 3348 if (nextIndex === alignments.length) { 3349 // Default alignment 3350 localStorage.removeItem('textAlign'); 3351 return getTranslation('default'); 3352 } else { 3353 const selectedAlign = alignments[nextIndex]; 3354 localStorage.setItem('textAlign', selectedAlign); 3355 domCache.body.classList.add(`eu-text-align-${selectedAlign}`); 3356 return selectedAlign.charAt(0).toUpperCase() + selectedAlign.slice(1); 3357 } 3358} 3359 3360// Bigger text handler with 3 states 3361function handleBiggerText() { 3362 const textSizes = ['medium', 'large', 'xlarge']; 3363 const currentSize = localStorage.getItem('biggerText') || 'none'; 3364 const currentIndex = textSizes.indexOf(currentSize); 3365 const nextIndex = (currentIndex + 1) % (textSizes.length + 1); // +1 for none 3366 3367 // Remove only widget's own text size classes 3368 const textClasses = ['eu-bigger-text-medium', 'eu-bigger-text-large', 'eu-bigger-text-xlarge'];
3369 textClasses.forEach(className => { 3370 if (domCache.body.classList.contains(className)) { 3371 domCache.body.classList.remove(className); 3372 } 3373 }); 3374 3375 if (nextIndex === textSizes.length) { 3376 // Default text size 3377 localStorage.removeItem('biggerText'); 3378 return getTranslation('default'); 3379 } else { 3380 const selectedSize = textSizes[nextIndex]; 3381 localStorage.setItem('biggerText', selectedSize); 3382 domCache.body.classList.add(`eu-bigger-text-${selectedSize}`); 3383 return selectedSize === 'xlarge' ? 'X-Large' : selectedSize.charAt(0).toUpperCase() + selectedSize.slice(1); 3384 } 3385} 3386 3387// High contrast handler with 3 states 3388function handleHighContrast() { 3389 const contrastLevels = ['medium', 'high', 'ultra']; 3390 const currentContrast = localStorage.getItem('highContrast') || 'none'; 3391 const currentIndex = contrastLevels.indexOf(currentContrast); 3392 const nextIndex = (currentIndex + 1) % (contrastLevels.length + 1); // +1 for none 3393 3394 // Remove only widget's own contrast classes 3395 const contrastClasses = ['eu-high-contrast-medium', 'eu-high-contrast-high', 'eu-high-contrast-ultra']; 3396 contrastClasses.forEach(className => { 3397 if (domCache.body.classList.contains(className)) { 3398 domCache.body.classList.remove(className); 3399 } 3400 }); 3401 3402 if (nextIndex === contrastLevels.length) { 3403 // Default contrast 3404 localStorage.removeItem('highContrast'); 3405 return getTranslation('default'); 3406 } else { 3407 const selectedContrast = contrastLevels[nextIndex]; 3408 localStorage.setItem('highContrast', selectedContrast); 3409 domCache.body.classList.add(`eu-high-contrast-${selectedContrast}`); 3410 return selectedContrast.charAt(0).toUpperCase() + selectedContrast.slice(1); 3411 } 3412} 3413 3414// Text Spacing Handler with 3 states (1em, 2em, 4em equivalents) 3415function handleTextSpacing() { 3416 const spacings = ['light', 'medium', 'heavy']; // Maps to 1, 2, 4 approx 3417 const currentSpacing = localStorage.getItem('textSpacing') || 'none'; 3418 const currentIndex = spacings.indexOf(currentSpacing); 3419 const nextIndex = (currentIndex + 1) % (spacings.length + 1); // +1 for none 3420 3421 // Remove only widget's own spacing classes 3422 const spacingClasses = ['eu-text-spacing-light', 'eu-text-spacing-medium', 'eu-text-spacing-heavy']; 3423 spacingClasses.forEach(className => { 3424 if (domCache.body.classList.contains(className)) { 3425 domCache.body.classList.remove(className); 3426 } 3427 }); 3428 3429 if (nextIndex === spacings.length) { 3430 // Default 3431 localStorage.removeItem('textSpacing'); 3432 return getTranslation('default'); 3433 } else { 3434 const selectedSpacing = spacings[nextIndex]; 3435 localStorage.setItem('textSpacing', selectedSpacing); 3436 domCache.body.classList.add(`eu-text-spacing-${selectedSpacing}`); 3437 return selectedSpacing.charAt(0).toUpperCase() + selectedSpacing.slice(1); 3438 } 3439} 3440 3441// Line Height Handler with 3 states (2em, 3em, 4em) 3442function handleLineHeight() { 3443 const heights = ['2em', '3em', '4em']; 3444 const currentHeight = localStorage.getItem('lineHeight') || 'none'; 3445 const currentIndex = heights.indexOf(currentHeight); 3446 const nextIndex = (currentIndex + 1) % (heights.length + 1); // +1 for none 3447 3448 // Remove only widget's own line height classes 3449 const heightClasses = ['eu-line-height-2em', 'eu-line-height-3em', 'eu-line-height-4em']; 3450 heightClasses.forEach(className => { 3451 if (domCache.body.classList.contains(className)) { 3452 domCache.body.classList.remove(className); 3453 } 3454 }); 3455 3456 if (nextIndex === heights.length) { 3457 // Default 3458 localStorage.removeItem('lineHeight'); 3459 return getTranslation('default'); 3460 } else { 3461 const selectedHeight = heights[nextIndex]; 3462 localStorage.setItem('lineHeight', selectedHeight); 3463 domCache.body.classList.add(`eu-line-height-${selectedHeight}`); 3464 return selectedHeight; 3465 } 3466} 3467 3468// =========================================== 3469// FOCUS INDICATOR, HIGHLIGHT, READING GUIDE, READING WINDOW 3470// =========================================== 3471 3472// Focus Indicator toggle 3473function toggleFocusIndicator(isActive) { 3474 if (isActive) { 3475 domCache.body.classList.add('eu-focus-indicator'); 3476 } else { 3477 domCache.body.classList.remove('eu-focus-indicator'); 3478 } 3479} 3480 3481// Highlight Links toggle 3482function toggleHighlightLinks(isActive) { 3483 if (isActive) { 3484 domCache.body.classList.add('eu-highlight-links'); 3485 } else { 3486 domCache.body.classList.remove('eu-highlight-links'); 3487 } 3488} 3489 3490// Reading Guide toggle 3491const readingGuide = { 3492 element: null, 3493 handler: null, 3494 toggle(isActive) { 3495 if (isActive) { 3496 if (!readingGuide.element) { 3497 const guide = document.createElement('div'); 3498 guide.id = 'eu-reading-guide'; 3499 document.body.appendChild(guide); 3500 readingGuide.element = guide; 3501 } 3502 readingGuide.element.style.display = 'block'; 3503 if (readingGuide.handler) { 3504 document.removeEventListener('mousemove', readingGuide.handler); 3505 } 3506 readingGuide.handler = function (e) { 3507 readingGuide.element.style.top = e.clientY + 'px'; 3508 }; 3509 document.addEventListener('mousemove', readingGuide.handler); 3510 } else { 3511 if (readingGuide.handler) { 3512 document.removeEventListener('mousemove', readingGuide.handler); 3513 readingGuide.handler = null; 3514 } 3515 if (readingGuide.element) { 3516 readingGuide.element.style.display = 'none'; 3517 } 3518 } 3519 } 3520}; 3521 3522// Reading Window toggle 3523const readingWindow = { 3524 topMask: null, 3525 bottomMask: null, 3526 handler: null, 3527 windowHeight: 120, 3528 toggle(isActive) { 3529 if (isActive) { 3530 if (!readingWindow.topMask) { 3531 const top = document.createElement('div'); 3532 top.classList.add('eu-reading-window-top'); 3533 const bottom = document.createElement('div'); 3534 bottom.classList.add('eu-reading-window-bottom'); 3535 document.body.appendChild(top); 3536 document.body.appendChild(bottom); 3537 readingWindow.topMask = top; 3538 readingWindow.bottomMask = bottom; 3539 } 3540 readingWindow.topMask.style.display = 'block'; 3541 readingWindow.bottomMask.style.display = 'block'; 3542 if (readingWindow.handler) { 3543 document.removeEventListener('mousemove', readingWindow.handler); 3544 } 3545 readingWindow.handler = function (e) { 3546 const y = e.clientY; 3547 const half = readingWindow.windowHeight / 2; 3548 const topH = Math.max(0, y - half); 3549 const bottomTop = y + half; 3550 readingWindow.topMask.style.height = topH + 'px'; 3551 readingWindow.bottomMask.style.top = bottomTop + 'px'; 3552 readingWindow.bottomMask.style.height = (window.innerHeight - bottomTop) + 'px'; 3553 }; 3554 document.addEventListener('mousemove', readingWindow.handler); 3555 // Paint an initial centered window so masks are visible before the mouse moves. 3556 readingWindow.handler({ clientY: Math.round(window.innerHeight / 2) }); 3557 } else { 3558 if (readingWindow.handler) { 3559 document.removeEventListener('mousemove', readingWindow.handler); 3560 readingWindow.handler = null; 3561 } 3562 if (readingWindow.topMask) { 3563 readingWindow.topMask.style.display = 'none'; 3564 } 3565 if (readingWindow.bottomMask) { 3566 readingWindow.bottomMask.style.display = 'none'; 3567 } 3568 } 3569 } 3570}; 3571 3572// =========================================== 3573// ENHANCED FEATURES (v1.3.0) 3574// =========================================== 3575 3576// Shared host for widget-owned overlays (virtual keyboard, dictionary, lens, 3577// reader view). Excluded from Custom Color / filters so overlays stay legible. 3578function euOverlayHost() { 3579 let host = document.getElementById('eu-accessibility-overlays'); 3580 if (!host) { 3581 host = document.createElement('div'); 3582 host.id = 'eu-accessibility-overlays'; 3583 document.body.appendChild(host); 3584 } 3585 return host; 3586} 3587 3588// Hover Highlight â outline whatever element is under the cursor 3589const hoverHighlight = { 3590 handler: null, 3591 last: null, 3592 toggle(isActive) { 3593 if (isActive) { 3594 hoverHighlight.handler = function (e) { 3595 const el = e.target; 3596 if (!el || (el.closest && el.closest('#eu-accessibility-widget-container'))) return; 3597 if (hoverHighlight.last && hoverHighlight.last !== el) { 3598 hoverHighlight.last.classList.remove('eu-hover-highlight-target'); 3599 } 3600 el.classList.add('eu-hover-highlight-target'); 3601 hoverHighlight.last = el; 3602 }; 3603 document.addEventListener('mouseover', hoverHighlight.handler, true); 3604 } else { 3605 if (hoverHighlight.handler) { 3606 document.removeEventListener('mouseover', hoverHighlight.handler, true); 3607 hoverHighlight.handler = null; 3608 } 3609 if (hoverHighlight.last) { 3610 hoverHighlight.last.classList.remove('eu-hover-highlight-target'); 3611 hoverHighlight.last = null; 3612 } 3613 } 3614 } 3615}; 3616 3617// Mute Media â silence all audio/video (and any added later) 3618const muteMedia = { 3619 observer: null, 3620 muteAll() { 3621 document.querySelectorAll('video, audio').forEach((m) => { m.muted = true; }); 3622 }, 3623 toggle(isActive) { 3624 if (isActive) { 3625 muteMedia.muteAll();
3626 try { 3627 muteMedia.observer = new MutationObserver(() => muteMedia.muteAll()); 3628 muteMedia.observer.observe(document.body, { childList: true, subtree: true }); 3629 } catch (e) { /* ignore */ } 3630 } else { 3631 if (muteMedia.observer) { muteMedia.observer.disconnect(); muteMedia.observer = null; } 3632 document.querySelectorAll('video, audio').forEach((m) => { m.muted = false; }); 3633 } 3634 } 3635}; 3636 3637// Media Freeze â companion to Pause Animations. 3638// The .eu-pause-animations class already kills every CSS animation/transition. 3639// This controller stops the motion CSS can't reach: playing videos, animated 3640// GIF/WebP images, and legacy <marquee> "running strips". A MutationObserver 3641// re-applies it to media that loads later (lazy-load, SPA navigation, new GIFs). 3642const mediaFreeze = { 3643 observer: null, 3644 playGuard: null, 3645 frozenImgs: [], // { img, src, srcset } so we can restore on disable 3646 pausedVideos: new Set(), // only the videos WE paused, so we can resume just those 3647 isActive: false, 3648 3649 // Pause every <video>; best-effort pause for embedded YouTube / Vimeo iframes. 3650 pauseVideos() { 3651 document.querySelectorAll('video').forEach((v) => { 3652 try { 3653 v.removeAttribute('autoplay'); 3654 if (!v.paused) { mediaFreeze.pausedVideos.add(v); v.pause(); } 3655 } catch (e) { /* ignore */ } 3656 }); 3657 document.querySelectorAll('iframe').forEach((f) => { 3658 const src = f.getAttribute('src') || ''; 3659 try { 3660 if (/youtube(-nocookie)?\.com|youtu\.be/.test(src)) { 3661 f.contentWindow.postMessage('{"event":"command","func":"pauseVideo","args":""}', '*'); 3662 } else if (/player\.vimeo\.com/.test(src)) { 3663 f.contentWindow.postMessage('{"method":"pause"}', '*'); 3664 } 3665 } catch (e) { /* ignore */ } 3666 }); 3667 }, 3668 3669 // Snapshot an animated raster image's current frame onto a canvas and swap it 3670 // in, so it stops looping. Cross-origin images without CORS taint the canvas 3671 // and can't be snapshotted â those are marked and skipped. 3672 freezeImage(img) { 3673 if (img.dataset.euFrozen === '1' || img.dataset.euFrozenFail === '1') return; 3674 const url = (img.currentSrc || img.src || '').toLowerCase(); 3675 const animatable = /\.(gif|webp|apng)(\?|#|$)/.test(url) || 3676 /^data:image\/(gif|webp|apng)/.test(url) || img.dataset.euAnimated === '1'; 3677 if (!animatable) return; 3678 if (!img.complete || !img.naturalWidth) { 3679 img.addEventListener('load', () => { if (mediaFreeze.isActive) mediaFreeze.freezeImage(img); }, { once: true }); 3680 return; 3681 } 3682 try { 3683 const canvas = document.createElement('canvas'); 3684 canvas.width = img.naturalWidth; 3685 canvas.height = img.naturalHeight; 3686 canvas.getContext('2d').drawImage(img, 0, 0); 3687 const frozen = canvas.toDataURL(); // throws if the image is cross-origin tainted 3688 mediaFreeze.frozenImgs.push({ img: img, src: img.getAttribute('src'), srcset: img.getAttribute('srcset') }); 3689 img.setAttribute('src', frozen); 3690 img.removeAttribute('srcset'); 3691 img.dataset.euFrozen = '1'; 3692 } catch (e) { 3693 img.dataset.euFrozenFail = '1'; // don't retry every mutation 3694 } 3695 }, 3696 3697 freezeAllImages() { 3698 document.querySelectorAll('img').forEach((img) => mediaFreeze.freezeImage(img)); 3699 }, 3700 3701 // Legacy <marquee> scrolling strips. 3702 toggleMarquees(stop) { 3703 document.querySelectorAll('marquee').forEach((m) => { 3704 try { stop ? m.stop() : m.start(); } catch (e) { /* ignore */ } 3705 }); 3706 }, 3707 3708 enable() { 3709 if (mediaFreeze.isActive) return; 3710 mediaFreeze.isActive = true; 3711 mediaFreeze.pauseVideos(); 3712 mediaFreeze.freezeAllImages(); 3713 mediaFreeze.toggleMarquees(true); 3714 3715 // Keep videos paused if the page tries to restart them while the feature is on. 3716 mediaFreeze.playGuard = function (e) { 3717 const t = e.target; 3718 if (mediaFreeze.isActive && t && t.tagName === 'VIDEO') { 3719 mediaFreeze.pausedVideos.add(t); 3720 try { t.pause(); } catch (err) { /* ignore */ } 3721 } 3722 }; 3723 document.addEventListener('play', mediaFreeze.playGuard, true); 3724 3725 try { 3726 mediaFreeze.observer = new MutationObserver(() => { 3727 if (!mediaFreeze.isActive) return; 3728 mediaFreeze.pauseVideos(); 3729 mediaFreeze.freezeAllImages(); 3730 mediaFreeze.toggleMarquees(true); 3731 }); 3732 mediaFreeze.observer.observe(document.body, { childList: true, subtree: true }); 3733 } catch (e) { /* ignore */ } 3734 }, 3735 3736 disable() { 3737 if (!mediaFreeze.isActive) return; 3738 mediaFreeze.isActive = false;
3739 if (mediaFreeze.observer) { mediaFreeze.observer.disconnect(); mediaFreeze.observer = null; } 3740 if (mediaFreeze.playGuard) { document.removeEventListener('play', mediaFreeze.playGuard, true); mediaFreeze.playGuard = null; } 3741 3742 // Restore animated images to their original (animating) source. 3743 mediaFreeze.frozenImgs.forEach((rec) => { 3744 if (rec.src !== null) rec.img.setAttribute('src', rec.src); 3745 if (rec.srcset) rec.img.setAttribute('srcset', rec.srcset); 3746 delete rec.img.dataset.euFrozen; 3747 }); 3748 mediaFreeze.frozenImgs = []; 3749 document.querySelectorAll('img[data-eu-frozen-fail]').forEach((img) => { delete img.dataset.euFrozenFail; }); 3750 3751 mediaFreeze.toggleMarquees(false); 3752 3753 // Resume the videos we paused (leave any the user had already paused alone). 3754 mediaFreeze.pausedVideos.forEach((v) => { 3755 try { const p = v.play(); if (p && p.catch) p.catch(function () {}); } catch (e) { /* ignore */ } 3756 }); 3757 mediaFreeze.pausedVideos.clear(); 3758 // Best-effort resume for embedded YouTube / Vimeo players. 3759 document.querySelectorAll('iframe').forEach((f) => { 3760 const src = f.getAttribute('src') || ''; 3761 try { 3762 if (/youtube(-nocookie)?\.com|youtu\.be/.test(src)) { 3763 f.contentWindow.postMessage('{"event":"command","func":"playVideo","args":""}', '*'); 3764 } else if (/player\.vimeo\.com/.test(src)) { 3765 f.contentWindow.postMessage('{"method":"play"}', '*'); 3766 } 3767 } catch (e) { /* ignore */ } 3768 }); 3769 }, 3770 3771 toggle(isActive) { isActive ? mediaFreeze.enable() : mediaFreeze.disable(); } 3772}; 3773 3774// Page Magnifier â zoom the whole page (3 levels then off) 3775function applyPageMagnifier(val) { 3776 const container = document.getElementById('eu-accessibility-widget-container'); 3777 const overlays = document.getElementById('eu-accessibility-overlays'); 3778 if (val) { 3779 document.body.style.zoom = val; 3780 const inv = String(1 / parseFloat(val)); // keep widget UI + overlays at normal size 3781 if (container) container.style.zoom = inv; 3782 if (overlays) overlays.style.zoom = inv; 3783 } else { 3784 document.body.style.zoom = ''; 3785 if (container) container.style.zoom = ''; 3786 if (overlays) overlays.style.zoom = ''; 3787 } 3788} 3789function handlePageMagnifier() { 3790 const levels = ['1.25', '1.5', '2']; 3791 const cur = localStorage.getItem('pageMagnifier'); 3792 let idx = cur ? levels.indexOf(cur) : -1; 3793 idx = (idx + 1) % (levels.length + 1); // extra step = off 3794 if (idx === levels.length) { 3795 localStorage.removeItem('pageMagnifier'); 3796 applyPageMagnifier(null); 3797 return getTranslation('default'); 3798 } 3799 const val = levels[idx]; 3800 localStorage.setItem('pageMagnifier', val); 3801 applyPageMagnifier(val); 3802 return val + 'Ã'; 3803} 3804 3805// Text Magnifier â floating lens showing enlarged text under the cursor 3806const textMagnifier = { 3807 lens: null, 3808 handler: null, 3809 toggle(isActive) { 3810 if (isActive) { 3811 if (!textMagnifier.lens) { 3812 const l = document.createElement('div'); 3813 l.className = 'eu-text-magnifier-lens'; 3814 euOverlayHost().appendChild(l); 3815 textMagnifier.lens = l; 3816 } 3817 textMagnifier.handler = function (e) { 3818 const el = document.elementFromPoint(e.clientX, e.clientY); 3819 const lens = textMagnifier.lens; 3820 if (!el || (el.closest && el.closest('#eu-accessibility-widget-container'))) { lens.style.display = 'none'; return; } 3821 const txt = (el.textContent || '').trim().replace(/\s+/g, ' ').slice(0, 160); 3822 if (!txt) { lens.style.display = 'none'; return; } 3823 lens.textContent = txt; 3824 lens.style.display = 'block'; 3825 let x = e.clientX + 18, y = e.clientY + 18; 3826 const rect = lens.getBoundingClientRect(); 3827 if (x + rect.width > window.innerWidth) x = window.innerWidth - rect.width - 10; 3828 if (y + rect.height > window.innerHeight) y = e.clientY - rect.height - 18; 3829 lens.style.left = Math.max(6, x) + 'px'; 3830 lens.style.top = Math.max(6, y) + 'px'; 3831 }; 3832 document.addEventListener('mousemove', textMagnifier.handler); 3833 } else { 3834 if (textMagnifier.handler) { document.removeEventListener('mousemove', textMagnifier.handler); textMagnifier.handler = null; } 3835 if (textMagnifier.lens) textMagnifier.lens.style.display = 'none'; 3836 } 3837 } 3838}; 3839 3840// Read Focus â highlight the block of text under the cursor 3841const readFocus = { 3842 handler: null, 3843 last: null, 3844 blockSelector: 'p, li, h1, h2, h3, h4, h5, h6, blockquote, td, th, dd, dt, figcaption', 3845 toggle(isActive) { 3846 if (isActive) { 3847 readFocus.handler = function (e) { 3848 const el = e.target; 3849 if (!el || (el.closest && el.closest('#eu-accessibility-widget-container'))) return; 3850 const block = el.closest(readFocus.blockSelector); 3851 if (!block) return; 3852 if (readFocus.last && readFocus.last !== block) readFocus.last.classList.remove('eu-read-focus-target'); 3853 block.classList.add('eu-read-focus-target'); 3854 readFocus.last = block; 3855 }; 3856 document.addEventListener('mouseover', readFocus.handler, true); 3857 } else { 3858 if (readFocus.handler) { document.removeEventListener('mouseover', readFocus.handler, true); readFocus.handler = null; } 3859 if (readFocus.last) { readFocus.last.classList.remove('eu-read-focus-target'); readFocus.last = null; } 3860 } 3861 } 3862}; 3863 3864// Virtual Keyboard â on-screen keyboard that types into the focused field 3865const virtualKeyboard = { 3866 el: null, 3867 target: null, 3868 shift: false, 3869 mode: 'alpha', // 'alpha' | 'symbol' 3870 keysEl: null, 3871 focusHandler: null, 3872 alphaLayout: [ 3873 '1 2 3 4 5 6 7 8 9 0'.split(' '), 3874 'q w e r t y u i o p'.split(' '), 3875 'a s d f g h j k l'.split(' '), 3876 'z x c v b n m'.split(' ') 3877 ], 3878 symbolLayout: [ 3879 ['!', '@', '#', '$', '%', '^', '&', '*', '(', ')'], 3880 ['~', '`', '_', '-', '+', '=', '{', '}', '[', ']'], 3881 ['|', '\\', ':', ';', '"', '\'', '<', '>', '?'], 3882 ['/', '.', ',', 'â¬', '£', 'Â¥', 'â¢', '§'] 3883 ], 3884 // Shifted characters for the number row while in the alpha layer (matches a 3885 // physical keyboard: Shift+1 â !, Shift+2 â @, â¦). 3886 numShiftMap: { '1': '!', '2': '@', '3': '#', '4': '$', '5': '%', '6': '^', '7': '&', '8': '*', '9': '(', '0': ')' }, 3887 toggle(isActive) { 3888 if (isActive) { 3889 virtualKeyboard.build(); 3890 virtualKeyboard.el.style.display = 'block'; 3891 virtualKeyboard.focusHandler = function (e) { 3892 const t = e.target;
3893 if (t && t.matches && t.matches('input:not([type="checkbox"]):not([type="radio"]), textarea, [contenteditable="true"]') && !(t.closest && t.closest('#eu-accessibility-widget-container'))) { 3894 virtualKeyboard.target = t; 3895 } 3896 }; 3897 document.addEventListener('focusin', virtualKeyboard.focusHandler); 3898 } else { 3899 if (virtualKeyboard.focusHandler) { document.removeEventListener('focusin', virtualKeyboard.focusHandler); virtualKeyboard.focusHandler = null; } 3900 if (virtualKeyboard.el) virtualKeyboard.el.style.display = 'none'; 3901 } 3902 }, 3903 build() { 3904 if (virtualKeyboard.el) return; 3905 const kb = document.createElement('div'); 3906 kb.className = 'eu-virtual-keyboard'; 3907 const keys = document.createElement('div'); 3908 keys.className = 'eu-vk-keys'; 3909 kb.appendChild(keys); 3910 virtualKeyboard.keysEl = keys; 3911 euOverlayHost().appendChild(kb); 3912 virtualKeyboard.el = kb; 3913 virtualKeyboard.render(); 3914 }, 3915 // (Re)draw the keys for the active layer (letters/numbers or symbols). 3916 render() { 3917 const keys = virtualKeyboard.keysEl; 3918 if (!keys) return; 3919 keys.textContent = ''; 3920 const layout = virtualKeyboard.mode === 'symbol' ? virtualKeyboard.symbolLayout : virtualKeyboard.alphaLayout; 3921 layout.forEach((row) => { 3922 const r = document.createElement('div'); 3923 r.className = 'eu-vk-row'; 3924 row.forEach((k) => r.appendChild(virtualKeyboard.makeKey(k, k))); 3925 keys.appendChild(r); 3926 }); 3927 const last = document.createElement('div'); 3928 last.className = 'eu-vk-row'; 3929 last.appendChild(virtualKeyboard.makeKey(virtualKeyboard.mode === 'symbol' ? 'ABC' : '?#$', 'mode', 'eu-vk-wide')); 3930 last.appendChild(virtualKeyboard.makeKey('â§', 'shift', 'eu-vk-wide')); 3931 last.appendChild(virtualKeyboard.makeKey('Space', 'space', 'eu-vk-space')); 3932 last.appendChild(virtualKeyboard.makeKey('â«', 'back', 'eu-vk-wide')); 3933 last.appendChild(virtualKeyboard.makeKey('â', 'enter', 'eu-vk-wide')); 3934 keys.appendChild(last); 3935 virtualKeyboard.updateCase(); 3936 }, 3937 makeKey(label, val, extra) { 3938 const b = document.createElement('button'); 3939 b.className = 'eu-vk-key' + (extra ? ' ' + extra : ''); 3940 b.type = 'button'; 3941 b.textContent = label; 3942 b.setAttribute('data-val', val); 3943 // mousedown + preventDefault keeps focus/selection on the target field 3944 b.addEventListener('mousedown', function (e) { e.preventDefault(); virtualKeyboard.press(val); }); 3945 return b; 3946 }, 3947 press(val) { 3948 // Layer/modifier keys act on the keyboard itself, no target field needed. 3949 if (val === 'mode') { 3950 virtualKeyboard.mode = virtualKeyboard.mode === 'symbol' ? 'alpha' : 'symbol'; 3951 virtualKeyboard.shift = false; 3952 virtualKeyboard.render(); 3953 return; 3954 } 3955 if (val === 'shift') { virtualKeyboard.shift = !virtualKeyboard.shift; virtualKeyboard.updateCase(); return; } 3956 const t = virtualKeyboard.target; 3957 if (!t) return; 3958 t.focus(); 3959 if (val === 'space') return virtualKeyboard.insert(' '); 3960 if (val === 'enter') return virtualKeyboard.insert('\n'); 3961 if (val === 'back') return virtualKeyboard.backspace(); 3962 let ch = val; 3963 if (virtualKeyboard.shift) { 3964 if (/[a-z]/.test(ch)) ch = ch.toUpperCase(); 3965 else if (virtualKeyboard.numShiftMap[ch]) ch = virtualKeyboard.numShiftMap[ch]; 3966 } 3967 virtualKeyboard.insert(ch); 3968 }, 3969 insert(ch) { 3970 const t = virtualKeyboard.target; 3971 if (!t) return; 3972 if (t.isContentEditable) { document.execCommand('insertText', false, ch); return; } 3973 const start = t.selectionStart != null ? t.selectionStart : t.value.length; 3974 const end = t.selectionEnd != null ? t.selectionEnd : t.value.length; 3975 t.value = t.value.slice(0, start) + ch + t.value.slice(end); 3976 const pos = start + ch.length; 3977 try { t.setSelectionRange(pos, pos); } catch (e) { /* some input types disallow */ } 3978 t.dispatchEvent(new Event('input', { bubbles: true })); 3979 }, 3980 backspace() { 3981 const t = virtualKeyboard.target; 3982 if (!t) return; 3983 if (t.isContentEditable) { document.execCommand('delete'); return; } 3984 const start = t.selectionStart != null ? t.selectionStart : t.value.length; 3985 const end = t.selectionEnd != null ? t.selectionEnd : t.value.length; 3986 if (start === end && start > 0) { 3987 t.value = t.value.slice(0, start - 1) + t.value.slice(end);
3988 try { t.setSelectionRange(start - 1, start - 1); } catch (e) { /* ignore */ } 3989 } else { 3990 t.value = t.value.slice(0, start) + t.value.slice(end); 3991 try { t.setSelectionRange(start, start); } catch (e) { /* ignore */ } 3992 } 3993 t.dispatchEvent(new Event('input', { bubbles: true })); 3994 }, 3995 updateCase() { 3996 if (!virtualKeyboard.el) return; 3997 virtualKeyboard.el.querySelectorAll('.eu-vk-key').forEach((k) => { 3998 const val = k.getAttribute('data-val'); 3999 if (val && /^[a-z]$/i.test(val)) { 4000 k.textContent = virtualKeyboard.shift ? val.toUpperCase() : val.toLowerCase(); 4001 } else if (val && virtualKeyboard.numShiftMap[val]) { 4002 k.textContent = virtualKeyboard.shift ? virtualKeyboard.numShiftMap[val] : val; 4003 } 4004 }); 4005 const shiftKey = virtualKeyboard.el.querySelector('.eu-vk-key[data-val="shift"]'); 4006 if (shiftKey) shiftKey.classList.toggle('eu-vk-active', virtualKeyboard.shift); 4007 } 4008}; 4009 4010// Readable Mode â clean, single-column reader view of the main content 4011const readableMode = { 4012 overlay: null, 4013 savedMagnifier: null, 4014 toggle(isActive) { 4015 if (isActive) { 4016 // Suspend page magnifier while the reader is open (nested zoom + fixed overlay don't mix) 4017 readableMode.savedMagnifier = localStorage.getItem('pageMagnifier'); 4018 if (readableMode.savedMagnifier) applyPageMagnifier(null); 4019 readableMode.build(); 4020 readableMode.overlay.style.display = 'block'; 4021 document.documentElement.style.overflow = 'hidden'; 4022 } else { 4023 if (readableMode.overlay) readableMode.overlay.style.display = 'none'; 4024 document.documentElement.style.overflow = ''; 4025 if (readableMode.savedMagnifier) { applyPageMagnifier(readableMode.savedMagnifier); readableMode.savedMagnifier = null; } 4026 } 4027 }, 4028 turnOffButton() { 4029 localStorage.setItem('readableMode', 'false'); 4030 if (shadowRoot) { 4031 const btn = shadowRoot.querySelector('[data-accessibility-option-id="readableMode"]'); 4032 if (btn) { btn.classList.remove('active'); btn.setAttribute('aria-pressed', 'false'); } 4033 } 4034 readableMode.toggle(false); 4035 }, 4036 build() { 4037 if (readableMode.overlay) { readableMode.overlay.remove(); readableMode.overlay = null; } 4038 const overlay = document.createElement('div'); 4039 overlay.className = 'eu-reader-overlay'; 4040 const close = document.createElement('button'); 4041 close.className = 'eu-reader-close'; 4042 close.type = 'button'; 4043 close.textContent = 'â ' + getTranslation('close'); 4044 close.addEventListener('click', readableMode.turnOffButton); 4045 const inner = document.createElement('div'); 4046 inner.className = 'eu-reader-inner'; 4047 const html = readableMode.pickContent(); 4048 inner.innerHTML = html || ('<p>' + getTranslation('readerViewEmpty') + '</p>'); 4049 overlay.appendChild(close); 4050 overlay.appendChild(inner); 4051 euOverlayHost().appendChild(overlay); 4052 readableMode.overlay = overlay; 4053 }, 4054 pickContent() { 4055 let best = null, bestLen = 0; 4056 document.querySelectorAll('article, main, [role="main"]').forEach((c) => { 4057 const l = (c.innerText || '').length; 4058 if (l > bestLen) { bestLen = l; best = c; } 4059 }); 4060 if (!best) { 4061 document.querySelectorAll('section, div').forEach((c) => { 4062 if (c.closest && c.closest('#eu-accessibility-widget-container')) return; 4063 const l = (c.innerText || '').length; 4064 if (l > bestLen && l < 60000) { bestLen = l; best = c; } 4065 }); 4066 } 4067 const source = best ? best.innerHTML : (document.body ? document.body.innerHTML : ''); 4068 return readableMode.sanitize(source); 4069 }, 4070 sanitize(html) { 4071 const tmp = document.createElement('div'); 4072 tmp.innerHTML = html; 4073 tmp.querySelectorAll('script, style, noscript, iframe, form, input, button, select, textarea, svg, nav, footer, aside, [id^="eu-accessibility"]').forEach((n) => n.remove()); 4074 return tmp.innerHTML; 4075 } 4076}; 4077 4078// Dictionary â look up a selected word (uses api.dictionaryapi.dev on demand) 4079const dictionary = { 4080 popup: null, 4081 handler: null, 4082 outsideHandler: null, 4083 toggle(isActive) { 4084 if (isActive) { 4085 if (!dictionary.popup) { 4086 const p = document.createElement('div'); 4087 p.className = 'eu-dictionary-popup'; 4088 euOverlayHost().appendChild(p); 4089 dictionary.popup = p; 4090 } 4091 dictionary.handler = function () { 4092 const sel = (window.getSelection ? window.getSelection().toString() : '').trim(); 4093 if (!sel || sel.split(/\s+/).length > 3 || sel.length > 40) return; 4094 dictionary.lookup(sel); 4095 }; 4096 dictionary.outsideHandler = function (e) { 4097 if (dictionary.popup && dictionary.popup.style.display === 'block' && !dictionary.popup.contains(e.target)) { 4098 setTimeout(function () { 4099 const s = (window.getSelection ? window.getSelection().toString() : '').trim(); 4100 if (!s) dictionary.popup.style.display = 'none'; 4101 }, 10); 4102 } 4103 }; 4104 document.addEventListener('mouseup', dictionary.handler); 4105 document.addEventListener('mousedown', dictionary.outsideHandler); 4106 } else { 4107 if (dictionary.handler) { document.removeEventListener('mouseup', dictionary.handler); dictionary.handler = null; } 4108 if (dictionary.outsideHandler) { document.removeEventListener('mousedown', dictionary.outsideHandler); dictionary.outsideHandler = null; } 4109 if (dictionary.popup) dictionary.popup.style.display = 'none'; 4110 } 4111 }, 4112 esc(s) { const d = document.createElement('div'); d.textContent = s == null ? '' : String(s); return d.innerHTML; }, 4113 show(html) { 4114 const p = dictionary.popup; 4115 if (!p) return; 4116 p.innerHTML = html; 4117 p.style.display = 'block'; 4118 let x = window.innerWidth / 2 - 150, y = 100; 4119 const sel = window.getSelection ? window.getSelection() : null; 4120 if (sel && sel.rangeCount) { 4121 const r = sel.getRangeAt(0).getBoundingClientRect(); 4122 if (r.width || r.height) { x = Math.min(r.left, window.innerWidth - 320);
4122 y = Math.min(r.bottom + 8, window.innerHeight - 280); } 4123 } 4124 p.style.left = Math.max(10, x) + 'px'; 4125 p.style.top = Math.max(10, y) + 'px'; 4126 }, 4127 lookup(word) { 4128 dictionary.show('<div class="eu-dict-word">' + dictionary.esc(word) + '</div><div>' + getTranslation('dictionaryLoading') + '</div>'); 4129 fetch('https://api.dictionaryapi.dev/api/v2/entries/en/' + encodeURIComponent(word.toLowerCase())) 4130 .then((r) => (r.ok ? r.json() : Promise.reject(new Error('not found')))) 4131 .then((data) => { 4132 const entry = Array.isArray(data) ? data[0] : null; 4133 if (!entry) throw new Error('empty'); 4134 let html = '<div class="eu-dict-word">' + dictionary.esc(entry.word) + '</div>'; 4135 let phon = entry.phonetic; 4136 if (!phon && Array.isArray(entry.phonetics)) { const f = entry.phonetics.find((p) => p.text); if (f) phon = f.text; } 4137 if (phon) html += '<div class="eu-dict-phon">' + dictionary.esc(phon) + '</div>'; 4138 (entry.meanings || []).slice(0, 3).forEach((m) => { 4139 html += '<div class="eu-dict-pos">' + dictionary.esc(m.partOfSpeech || '') + '</div><ol>'; 4140 (m.definitions || []).slice(0, 2).forEach((d) => { html += '<li>' + dictionary.esc(d.definition || '') + '</li>'; }); 4141 html += '</ol>'; 4142 }); 4143 dictionary.show(html); 4144 }) 4145 .catch(() => { 4146 dictionary.show('<div class="eu-dict-word">' + dictionary.esc(word) + '</div><div>' + getTranslation('dictionaryNotFound') + '</div>'); 4147 }); 4148 } 4149}; 4150 4151// Custom Color â user-chosen background / text / heading colors 4152const customColor = { 4153 panel: null, 4154 apply(bg, text, head) {
4155 let css = ''; 4156 const guard = ':not(#eu-accessibility-widget-container):not(#eu-accessibility-widget-container *):not(#eu-accessibility-overlays):not(#eu-accessibility-overlays *)'; 4157 if (bg) css += 'body, body *' + guard + '{background-color:' + bg + ' !important;}'; 4158 if (text) css += 'body, body :is(p, span, li, td, a, div, label)' + guard + '{color:' + text + ' !important;}'; 4159 if (head) css += 'body :is(h1, h2, h3, h4, h5, h6)' + guard + '{color:' + head + ' !important;}'; 4160 let st = document.getElementById('eu-custom-color-style'); 4161 if (!st) { st = document.createElement('style'); st.id = 'eu-custom-color-style'; document.head.appendChild(st); } 4162 st.textContent = css; 4163 }, 4164 clear() { 4165 const st = document.getElementById('eu-custom-color-style'); 4166 if (st) st.textContent = ''; 4167 localStorage.removeItem('customColorBg'); 4168 localStorage.removeItem('customColorText'); 4169 localStorage.removeItem('customColorHead'); 4170 }, 4171 restore() { 4172 const bg = localStorage.getItem('customColorBg'); 4173 const text = localStorage.getItem('customColorText'); 4174 const head = localStorage.getItem('customColorHead'); 4175 if (bg || text || head) customColor.apply(bg, text, head); 4176 }, 4177 createPanel() { 4178 const panel = document.createElement('div'); 4179 panel.className = 'eu-custom-color-panel'; 4180 panel.id = 'eu-custom-color-panel'; 4181 const mkRow = (labelKey, key, def) => { 4182 const row = document.createElement('div'); 4183 row.className = 'eu-ccp-row'; 4184 const lbl = document.createElement('span'); 4185 lbl.textContent = getTranslation(labelKey); 4186 const inp = document.createElement('input'); 4187 inp.type = 'color'; 4188 inp.value = localStorage.getItem(key) || def; 4189 inp.setAttribute('data-cc', key); 4190 row.appendChild(lbl); 4191 row.appendChild(inp); 4192 return row; 4193 }; 4194 panel.appendChild(mkRow('customColorBackground', 'customColorBg', '#ffffff')); 4195 panel.appendChild(mkRow('customColorText', 'customColorText', '#000000')); 4196 panel.appendChild(mkRow('customColorHeadings', 'customColorHead', '#0b7285')); 4197 const actions = document.createElement('div'); 4198 actions.className = 'eu-ccp-actions'; 4199 const applyBtn = document.createElement('button'); 4200 applyBtn.className = 'eu-ccp-btn'; 4201 applyBtn.type = 'button'; 4202 applyBtn.textContent = getTranslation('customColorApply'); 4203 const resetBtn = document.createElement('button'); 4204 resetBtn.className = 'eu-ccp-btn eu-ccp-reset'; 4205 resetBtn.type = 'button'; 4206 resetBtn.textContent = getTranslation('customColorReset'); 4207 applyBtn.addEventListener('click', () => { 4208 const bg = panel.querySelector('[data-cc="customColorBg"]').value; 4209 const text = panel.querySelector('[data-cc="customColorText"]').value; 4210 const head = panel.querySelector('[data-cc="customColorHead"]').value; 4211 localStorage.setItem('customColorBg', bg); 4212 localStorage.setItem('customColorText', text); 4213 localStorage.setItem('customColorHead', head); 4214 customColor.apply(bg, text, head); 4215 euAnnouncer.say(getTranslation('customColor')); 4216 }); 4217 resetBtn.addEventListener('click', () => { customColor.clear(); euAnnouncer.say(getTranslation('customColorReset')); }); 4218 actions.appendChild(applyBtn); 4219 actions.appendChild(resetBtn); 4220 panel.appendChild(actions); 4221 customColor.panel = panel; 4222 return panel; 4223 }, 4224 togglePanel() { 4225 if (!customColor.panel) return ''; 4226 customColor.panel.classList.toggle('eu-open'); 4227 return getTranslation('customColor'); 4228 } 4229}; 4230 4231// =========================================== 4232// ACCESSIBILITY FEATURES 4233// =========================================== 4234 4235// Screen reader functionality 4236const screenReader = { 4237 active: localStorage.getItem('screenReader') === 'true', 4238 isSupported: 'speechSynthesis' in window, 4239 4240 // --- word-highlight state --- 4241 currentRoot: null, // the element currently being read 4242 currentWords: [], // <span class="eu-read-word"> nodes in reading order 4243 wordStarts: [], // char offset of each word inside the spoken string 4244 lastWordIdx: -1, 4245 currentUtterance: null, // guards stale onend/onerror from a cancelled utterance 4246 4247 // --- hover-to-read state --- 4248 blockSelector: 'p, li, h1, h2, h3, h4, h5, h6, blockquote, td, th, dd, dt, figcaption, a, button, label, summary', 4249 hoverBlock: null, // block currently under the cursor (so we don't re-read it) 4250 hoverTimer: null, // dwell timer before a hovered block starts reading 4251 4252 // Is this element visible and not hidden from assistive tech? Used to skip 4253 // inactive carousel slides (aria-hidden / display:none / opacity:0) so read 4254 // aloud doesn't run on and on through off-screen slides. 4255 isVisibleEl: function (el) { 4256 if (!el || el.nodeType !== 1) return false;
4257 if (el.getAttribute && el.getAttribute('aria-hidden') === 'true') return false; 4258 var cs; 4259 try { cs = window.getComputedStyle(el); } catch (e) { return true; } 4260 if (!cs) return true; 4261 if (cs.display === 'none' || cs.visibility === 'hidden' || parseFloat(cs.opacity) === 0) return false; 4262 return true; 4263 }, 4264 4265 // Wrap each visible word of `root` in a <span> so we can highlight it while 4266 // it is spoken. Returns the word spans in order. Skips hidden / aria-hidden 4267 // subtrees, scripts/styles, and the widget's own UI. 4268 wrapWords: function (root) { 4269 var words = []; 4270 if (!root || root.nodeType !== 1) return words; 4271 try { 4272 var walker = document.createTreeWalker(root, NodeFilter.SHOW_TEXT, { 4273 acceptNode: function (node) { 4274 if (!node.nodeValue || !node.nodeValue.trim()) return NodeFilter.FILTER_REJECT; 4275 var p = node.parentNode; 4276 if (!p || p.nodeType !== 1) return NodeFilter.FILTER_REJECT; 4277 var tag = p.nodeName; 4278 if (tag === 'SCRIPT' || tag === 'STYLE' || tag === 'NOSCRIPT') return NodeFilter.FILTER_REJECT; 4279 if (p.closest && p.closest('[aria-hidden="true"], #eu-accessibility-widget-container, #eu-accessibility-overlays')) return NodeFilter.FILTER_REJECT; 4280 if (!screenReader.isVisibleEl(p)) return NodeFilter.FILTER_REJECT; 4281 return NodeFilter.FILTER_ACCEPT; 4282 } 4283 }); 4284 var nodes = [], n; 4285 while ((n = walker.nextNode())) nodes.push(n); 4286 nodes.forEach(function (tn) { 4287 var parts = tn.nodeValue.split(/(\s+)/); 4288 var frag = document.createDocumentFragment(); 4289 parts.forEach(function (part) { 4290 if (part === '') return; 4291 if (/^\s+$/.test(part)) { frag.appendChild(document.createTextNode(part)); return; } 4292 var span = document.createElement('span'); 4293 span.className = 'eu-read-word'; 4294 span.textContent = part; 4295 frag.appendChild(span); 4296 words.push(span); 4297 }); 4298 if (tn.parentNode) tn.parentNode.replaceChild(frag, tn); 4299 }); 4300 } catch (e) { /* ignore */ } 4301 return words; 4302 }, 4303 4304 // Remove all highlight state and un-wrap the word spans (restoring the 4305 // element's original text nodes, keeping its listeners intact). 4306 clearWordHighlight: function () { 4307 try { 4308 var root = screenReader.currentRoot; 4309 if (root) { 4310 if (root.classList) root.classList.remove('eu-read-current-block'); 4311 if (root.querySelectorAll) { 4312 root.querySelectorAll('span.eu-read-word').forEach(function (s) { 4313 if (s.parentNode) s.replaceWith(document.createTextNode(s.textContent)); 4314 }); 4315 } 4316 if (root.normalize) root.normalize(); 4317 } 4318 } catch (e) { /* ignore */ } 4319 screenReader.currentRoot = null; 4320 screenReader.currentWords = []; 4321 screenReader.wordStarts = []; 4322 screenReader.lastWordIdx = -1; 4323 }, 4324 4325 // Speak one element, highlighting each word as it is read. 4326 speakElement: function (el) { 4327 if (!el || el.nodeType !== 1 || !screenReader.active || !screenReader.isSupported) return; 4328 if (el.closest && el.closest('#eu-accessibility-widget-container, #eu-accessibility-overlays')) return; 4329 try { 4330 window.speechSynthesis.cancel(); 4331 screenReader.clearWordHighlight(); 4332 4333 // Guard against reading a huge container (e.g. a whole carousel or <body>): 4334 // don't word-wrap giant blocks â just read a capped snippet with a block outline. 4335 var bigText = (el.innerText || ''); 4336 var tooBig = (el === document.body || el === document.documentElement || bigText.length > 2000); 4337 4338 var words = tooBig ? [] : screenReader.wrapWords(el); 4339 var text; 4340 if (words.length) { 4341 text = words.map(function (w) { return w.textContent; }).join(' '); 4342 } else { 4343 text = ((el.getAttribute && (el.getAttribute('aria-label') || el.getAttribute('alt') || el.getAttribute('title'))) || bigText || '').trim(); 4344 } 4345 4346 var MAX = 4000; // hard cap so a stray big click can't read forever 4347 if (text.length > MAX) text = text.slice(0, MAX); 4348 if (!text.trim()) { screenReader.clearWordHighlight(); return; } 4349 4350 screenReader.currentRoot = el; 4351 screenReader.currentWords = words; 4352 var starts = [], acc = 0; 4353 words.forEach(function (w) { starts.push(acc); acc += w.textContent.length + 1; }); 4354 screenReader.wordStarts = starts; 4355 screenReader.lastWordIdx = -1; 4356 if (el.classList) el.classList.add('eu-read-current-block'); 4357 4358 var u = new SpeechSynthesisUtterance(text); 4359 u.lang = document.documentElement.lang || SPEECH_LANG; 4360 u.rate = WIDGET_CONFIG.speech.rate; 4361 u.pitch = WIDGET_CONFIG.speech.pitch; 4362 u.onboundary = function (ev) { 4363 if (ev.name && ev.name !== 'word') return; 4364 if (!screenReader.currentWords.length) return; 4365 var ci = ev.charIndex || 0; 4366 var idx = -1; 4367 for (var i = 0; i < starts.length; i++) { if (starts[i] <= ci) idx = i; else break; } 4368 if (idx !== screenReader.lastWordIdx) { 4369 var prev = screenReader.currentWords[screenReader.lastWordIdx]; 4370 if (prev && prev.classList) prev.classList.remove('eu-read-word-active'); 4371 var cur = screenReader.currentWords[idx]; 4372 if (cur && cur.classList) cur.classList.add('eu-read-word-active'); 4373 screenReader.lastWordIdx = idx; 4374 } 4375 }; 4376 // Only clear if THIS utterance is still the active one â cancel() fires a 4377 // late onend on the previous utterance after we've already started a new read. 4378 u.onend = function () { if (u === screenReader.currentUtterance) { screenReader.currentUtterance = null; screenReader.clearWordHighlight(); } }; 4379 u.onerror = function (e) { console.warn('Speech synthesis error:', e.error); if (u === screenReader.currentUtterance) { screenReader.currentUtterance = null; screenReader.clearWordHighlight(); } }; 4380 screenReader.currentUtterance = u; 4381 window.speechSynthesis.speak(u); 4382 } catch (error) { 4383 console.warn('Screen reader error:', error); 4384 screenReader.clearWordHighlight(); 4385 } 4386 }, 4387 4388 // Read whatever the user focuses (keyboard navigation). 4389 handleFocus: function (event) { 4390 if (screenReader.active && screenReader.isSupported) screenReader.speakElement(event.target); 4391 }, 4392 4393 // Read whatever block the user hovers. A short dwell delay means skimming the 4394 // mouse across the page doesn't read every block you pass over â it reads the 4395 // one you settle on. Reading only fires when the hovered block changes, so 4396 // moving the cursor within a block never restarts it. 4397 handleHover: function (event) { 4398 if (!screenReader.active || !screenReader.isSupported) return; 4399 var t = event.target; 4400 if (!t || t.nodeType !== 1) return; 4401 if (t.closest && t.closest('#eu-accessibility-widget-container, #eu-accessibility-overlays')) return; 4402 var block = (t.closest && t.closest(screenReader.blockSelector)) || t;
4403 if (block === screenReader.hoverBlock) return; // still within the same block 4404 screenReader.hoverBlock = block; 4405 if (screenReader.hoverTimer) { clearTimeout(screenReader.hoverTimer); screenReader.hoverTimer = null; } 4406 screenReader.hoverTimer = setTimeout(function () { 4407 screenReader.hoverTimer = null; 4408 if (screenReader.hoverBlock === block) screenReader.speakElement(block); 4409 }, 250); 4410 }, 4411 4412 toggle: function (isActive) { 4413 if (!screenReader.isSupported) { 4414 console.warn(`Speech synthesis ${getTranslation('notSupportedBrowser')}`); 4415 return false; 4416 } 4417 4418 screenReader.active = isActive; 4419 localStorage.setItem('screenReader', isActive); 4420 4421 try { 4422 if (isActive) { 4423 document.addEventListener('focusin', screenReader.handleFocus); 4424 document.addEventListener('mouseover', screenReader.handleHover); 4425 const feedbackSpeech = new SpeechSynthesisUtterance(getTranslation('screenReaderOn')); 4426 feedbackSpeech.lang = SPEECH_LANG; 4427 feedbackSpeech.rate = WIDGET_CONFIG.speech.rate; 4428 feedbackSpeech.pitch = WIDGET_CONFIG.speech.pitch; 4429 feedbackSpeech.onerror = function (event) { 4430 console.warn('Speech synthesis feedback error:', event.error); 4431 }; 4432 window.speechSynthesis.speak(feedbackSpeech); 4433 } else { 4434 document.removeEventListener('focusin', screenReader.handleFocus); 4435 document.removeEventListener('mouseover', screenReader.handleHover); 4436 if (screenReader.hoverTimer) { clearTimeout(screenReader.hoverTimer); screenReader.hoverTimer = null; } 4437 screenReader.hoverBlock = null; 4438 screenReader.currentUtterance = null; 4439 window.speechSynthesis.cancel(); 4440 screenReader.clearWordHighlight(); 4441 const feedbackSpeech = new SpeechSynthesisUtterance(getTranslation('screenReaderOff')); 4442 feedbackSpeech.lang = SPEECH_LANG; 4443 feedbackSpeech.rate = WIDGET_CONFIG.speech.rate; 4444 feedbackSpeech.pitch = WIDGET_CONFIG.speech.pitch; 4445 feedbackSpeech.onerror = function (event) { 4446 console.warn('Speech synthesis feedback error:', event.error); 4447 }; 4448 window.speechSynthesis.speak(feedbackSpeech); 4449 } 4450 } catch (error) { 4451 console.warn('Screen reader toggle error:', error); 4452 return false; 4453 } 4454 4455 return true; 4456 }, 4457}; 4458 4459// Voice control functionality 4460const voiceControl = { 4461 isActive: localStorage.getItem('voiceControl') === 'true', 4462 recognition: null, 4463 isSupported: 'SpeechRecognition' in window || 'webkitSpeechRecognition' in window, 4464 retryCount: 0, 4465 maxRetries: 3, 4466 toggle: function (isActive) { 4467 if (!voiceControl.isSupported) { 4468 console.warn(`Speech Recognition API ${getTranslation('notSupportedBrowser')}`); 4469 return false; 4470 } 4471 4472 voiceControl.isActive = isActive; 4473 localStorage.setItem('voiceControl', isActive); 4474 4475 try { 4476 if (isActive) { 4477 voiceControl.startListening(); 4478 } else { 4479 if (voiceControl.recognition) { 4480 voiceControl.recognition.stop(); 4481 voiceControl.recognition = null; 4482 } 4483 voiceControl.retryCount = 0; 4484 } 4485 } catch (error) { 4486 console.warn('Voice control toggle error:', error); 4487 return false; 4488 } 4489 4490 return true; 4491 }, 4492 startListening: function () { 4493 if (!voiceControl.isSupported) { 4494 return; 4495 } 4496 4497 if (voiceControl.recognition) { 4498 return; 4499 } 4500 4501 try { 4502 const SpeechRecognition = window.SpeechRecognition || window.webkitSpeechRecognition; 4503 voiceControl.recognition = new SpeechRecognition(); 4504 voiceControl.recognition.interimResults = false; 4505 4506 // Recognize in the detected language when we ship commands for it; otherwise English. 4507 voiceControl.recognition.lang = WIDGET_CONFIG.voiceCommands[currentLanguage] ? SPEECH_LANG : 'en-US'; 4508 voiceControl.recognition.continuous = false; 4509 4510 voiceControl.recognition.onstart = function () { 4511 console.log(getTranslation('voiceControlActivated')); 4512 voiceControl.retryCount = 0; 4513 }; 4514 4515 voiceControl.recognition.onresult = function (event) { 4516 try { 4517 const command = event.results[0][0].transcript.toLowerCase(); 4518 voiceControl.handleVoiceCommand(command); 4519 } catch (error) { 4520 console.warn('Voice command processing error:', error); 4521 } 4522 }; 4523 4524 voiceControl.recognition.onerror = function (event) { 4525 console.warn('Speech recognition error:', event.error); 4526 if (event.error === 'no-speech' && voiceControl.retryCount < voiceControl.maxRetries) { 4527 voiceControl.retryCount++; 4528 setTimeout(() => { 4529 if (voiceControl.isActive) { 4530 voiceControl.startListening(); 4531 } 4532 }, 1000); 4533 } 4534 }; 4535 4536 voiceControl.recognition.onend = function () { 4537 voiceControl.recognition = null; 4538 if (voiceControl.isActive && voiceControl.retryCount < voiceControl.maxRetries) { 4539 setTimeout(() => { 4540 if (voiceControl.isActive) { 4541 voiceControl.startListening(); 4542 } 4543 }, 100); 4544 } 4545 }; 4546 4547 voiceControl.recognition.start(); 4548 } catch (error) { 4549 console.warn('Voice control initialization error:', error); 4550 } 4551 }, 4552 handleVoiceCommand: function (command) { 4553 console.log(`Received command: ${command}`); 4554 4555 try { 4556 // Normalize the command by removing extra spaces and making it lowercase 4557 const normalizedCommand = command.toLowerCase().trim().replace(/\s+/g, ' '); 4558 4559 // Get voice commands for current language, fallback to English 4560 const languageCommands = WIDGET_CONFIG.voiceCommands[currentLanguage] || WIDGET_CONFIG.voiceCommands['en']; 4561
4562 // Check for show menu commands 4563 if (languageCommands.showMenu.some(cmd => normalizedCommand.includes(cmd))) { 4564 if (!menuCache.button) menuCache.init(); 4565 if (menuCache.button) { 4566 menuCache.button.click(); 4567 console.log('Successfully opened menu'); 4568 } 4569 return; 4570 } 4571 4572 // Check for reset all commands 4573 if (languageCommands.resetAll.some(cmd => normalizedCommand.includes(cmd))) { 4574 resetAccessibilitySettings(); 4575 console.log('Successfully reset all settings'); 4576 return; 4577 } 4578 4579 // Build dynamic command map based on configuration 4580 let localStorageKey = null; 4581 let matchedCommand = null; 4582 4583 // Check each command group with better matching 4584 for (const [key, commands] of Object.entries(languageCommands)) { 4585 if (key === 'showMenu' || key === 'resetAll') continue; // Already handled above 4586 4587 const isMatch = commands.some(cmd => { 4588 // Check for exact matches first 4589 if (normalizedCommand.includes(cmd.toLowerCase())) { 4590 matchedCommand = cmd; 4591 return true; 4592 } 4593 // Check for partial word matches (at least 3 characters) 4594 const cmdWords = cmd.toLowerCase().split(' '); 4595 const inputWords = normalizedCommand.split(' '); 4596 return cmdWords.some(cmdWord => 4597 cmdWord.length >= 3 && inputWords.some(inputWord => 4598 inputWord.includes(cmdWord) || cmdWord.includes(inputWord) 4599 ) 4600 ); 4601 }); 4602 4603 if (isMatch) { 4604 localStorageKey = key; 4605 break; 4606 } 4607 } 4608 4609 if (localStorageKey) { 4610 // Use cached menu reference if available 4611 if (!menuCache.menu) menuCache.init(); 4612 4613 // Try to find button by data-key first (toggle buttons) 4614 let button = menuCache.menu?.querySelector( 4615 `.eu-accessibility-option[data-key='${localStorageKey}']` 4616 ); 4617 4618 // If not found, try to find by data-accessibility-option-id (action buttons) 4619 if (!button) { 4620 button = menuCache.menu?.querySelector( 4621 `.eu-accessibility-option[data-accessibility-option-id='${localStorageKey}']` 4622 ); 4623 } 4624 4625 if (button) { 4626 button.click(); 4627 console.log(`Successfully executed command: ${command} (matched: ${matchedCommand || localStorageKey})`); 4628 } else { 4629 console.log('Button not found for command:', command, '(key:', localStorageKey, ')'); 4630 } 4631 } else { 4632 console.log('Command not recognized:', command); 4633 // Provide helpful suggestions 4634 const availableCommands = Object.values(languageCommands).flat(); 4635 const suggestions = availableCommands.filter(cmd => 4636 cmd.toLowerCase().includes(normalizedCommand.split(' ')[0]) || 4637 normalizedCommand.split(' ')[0].includes(cmd.toLowerCase().split(' ')[0]) 4638 ); 4639 if (suggestions.length > 0) { 4640 console.log('Did you mean one of these?', suggestions.slice(0, 3)); 4641 } 4642 } 4643 } catch (error) { 4644 console.warn('Voice command handling error:', error); 4645 } 4646 }, 4647}; 4648 4649// =========================================== 4650// ALT TEXT VIEWER 4651// Shows an element's alternative text on hover and flags 4652// images that are missing alt text (useful for everyone, 4653// including content editors and auditors). 4654// =========================================== 4655const altTextViewer = { 4656 active: false, // attached via toggle(); applySettings restores from localStorage 4657 tooltip: null, 4658 handleOver: function (event) { 4659 if (!event.target || !event.target.closest) return; 4660 const target = event.target.closest('img, [role="img"], svg, area, input[type="image"], button, a'); 4661 if (!target || (target.closest && target.closest('#eu-accessibility-widget-container'))) return; 4662 4663 let text = null; 4664 let missing = false; 4665 const isImage = target.matches('img, [role="img"], svg, area, input[type="image"]'); 4666 4667 if (isImage) { 4668 text = target.getAttribute('alt') || target.getAttribute('aria-label') || target.getAttribute('title'); 4669 if (!text && target.tagName.toLowerCase() === 'svg') { 4670 const titleEl = target.querySelector('title'); 4671 text = titleEl ? titleEl.textContent : null; 4672 } 4673 if (!text || !text.trim()) missing = true; 4674 } else {
4675 // Buttons/links: only surface hidden names (aria-label/title) 4676 text = target.getAttribute('aria-label') || target.getAttribute('title'); 4677 if (!text || !text.trim()) return; 4678 } 4679 4680 altTextViewer.show(target, missing ? getTranslation('noAltText') : text.trim(), missing); 4681 }, 4682 handleOut: function () { 4683 altTextViewer.hide(); 4684 }, 4685 show: function (target, text, missing) { 4686 if (!altTextViewer.tooltip) { 4687 altTextViewer.tooltip = document.createElement('div'); 4688 altTextViewer.tooltip.className = 'eu-alt-tooltip'; 4689 altTextViewer.tooltip.setAttribute('role', 'status'); 4690 document.body.appendChild(altTextViewer.tooltip); 4691 } 4692 const tip = altTextViewer.tooltip; 4693 tip.textContent = (missing ? 'â ' : 'ALT: ') + text; 4694 tip.classList.toggle('eu-alt-missing', !!missing); 4695 const rect = target.getBoundingClientRect(); 4696 tip.style.top = Math.max(4, rect.top + window.scrollY - 36) + 'px'; 4697 tip.style.left = Math.max(4, rect.left + window.scrollX) + 'px'; 4698 tip.style.display = 'block'; 4699 }, 4700 hide: function () { 4701 if (altTextViewer.tooltip) altTextViewer.tooltip.style.display = 'none'; 4702 }, 4703 toggle: function (isActive) { 4704 altTextViewer.active = isActive; 4705 if (isActive) { 4706 document.addEventListener('mouseover', altTextViewer.handleOver, true); 4707 document.addEventListener('mouseout', altTextViewer.handleOut, true); 4708 } else { 4709 document.removeEventListener('mouseover', altTextViewer.handleOver, true); 4710 document.removeEventListener('mouseout', altTextViewer.handleOut, true); 4711 altTextViewer.hide(); 4712 } 4713 return true; 4714 } 4715}; 4716 4717// =========================================== 4718// SAME-ORIGIN IFRAME SUPPORT 4719// Mirrors the widget's accessibility classes and page styles 4720// into same-origin iframes so features extend to embedded 4721// content. Cross-origin frames cannot be reached (browser 4722// security model). 4723// =========================================== 4724const frameSync = { 4725 getAccessibleFrameDocs: function () { 4726 const docs = []; 4727 document.querySelectorAll('iframe').forEach(function (fr) { 4728 try { 4729 if (fr.contentDocument && fr.contentDocument.body) docs.push(fr.contentDocument); 4730 } catch (e) { /* cross-origin frame â skip */ } 4731 }); 4732 return docs; 4733 }, 4734 syncNow: function () { 4735 const bodyClasses = Array.prototype.filter.call(document.body.classList, function (c) { return c.indexOf('eu-') === 0; }); 4736 const docClasses = Array.prototype.filter.call(document.documentElement.classList, function (c) { return c.indexOf('eu-') === 0; }); 4737 frameSync.getAccessibleFrameDocs().forEach(function (doc) { 4738 try { 4739 if (!doc.getElementById('eu-page-styles-frame')) { 4740 const style = doc.createElement('style'); 4741 style.id = 'eu-page-styles-frame'; 4742 style.textContent = pageStyles; 4743 (doc.head || doc.documentElement).appendChild(style); 4744 } 4745 [doc.body, doc.documentElement].forEach(function (el) { 4746 Array.prototype.filter.call(el.classList, function (c) { return c.indexOf('eu-') === 0; }) 4747 .forEach(function (c) { el.classList.remove(c); }); 4748 }); 4749 bodyClasses.forEach(function (c) { doc.body.classList.add(c); }); 4750 docClasses.forEach(function (c) { doc.documentElement.classList.add(c); }); 4751 } catch (e) { /* ignore */ } 4752 }); 4753 }, 4754 start: function () { 4755 try { 4756 const observer = new MutationObserver(function () { frameSync.syncNow(); }); 4757 observer.observe(document.body, { attributes: true, attributeFilter: ['class'] }); 4758 observer.observe(document.documentElement, { attributes: true, attributeFilter: ['class'] }); 4759 window.addEventListener('load', frameSync.syncNow); 4760 setTimeout(frameSync.syncNow, 1500); // catch late-loading frames 4761 } catch (e) { /* ignore */ } 4762 } 4763}; 4764 4765// =========================================== 4766// ACCESSIBILITY PROFILES 4767// One-click presets that compose existing tools for common 4768// needs. Applying a profile replaces the previous profile; 4769// clicking the active profile turns it off. 4770// =========================================== 4771const ACCESSIBILITY_PROFILES = { 4772 seizureSafe: { 4773 labelKey: 'profileSeizure', 4774 cycles: { saturation: 'low' }, 4775 toggles: { pauseAnimations: true } 4776 }, 4777 lowVision: { 4778 labelKey: 'profileVision', 4779 cycles: { biggerText: 'large', highContrast: 'medium' },
4780 toggles: { biggerCursor: true, focusIndicator: true, highlightLinks: true } 4781 }, 4782 adhdFriendly: { 4783 labelKey: 'profileAdhd', 4784 cycles: { saturation: 'low' }, 4785 toggles: { readingWindow: true, pauseAnimations: true } 4786 }, 4787 dyslexia: { 4788 labelKey: 'profileDyslexia', 4789 cycles: { fontSelection: 'dyslexic', lineHeight: '2em', textSpacing: 'light' }, 4790 toggles: { readingGuide: true } 4791 } 4792}; 4793 4794// Set a boolean tool on/off, keeping localStorage and side effects in sync 4795function euSetToggleState(key, isActive) { 4796 if (isActive) { 4797 localStorage.setItem(key, 'true'); 4798 } else { 4799 localStorage.removeItem(key); 4800 } 4801 switch (key) { 4802 case 'focusIndicator': toggleFocusIndicator(isActive); break; 4803 case 'highlightLinks': toggleHighlightLinks(isActive); break; 4804 case 'readingGuide': readingGuide.toggle(isActive); break; 4805 case 'readingWindow': readingWindow.toggle(isActive); break; 4806 case 'hideImages': toggleHideImages(isActive); break; 4807 case 'showAltText': altTextViewer.toggle(isActive); break; 4808 case 'pauseAnimations': document.body.classList.toggle('eu-pause-animations', isActive); mediaFreeze.toggle(isActive); break; 4809 case 'biggerCursor': document.body.classList.toggle('eu-bigger-cursor', isActive); break; 4810 default: break; 4811 } 4812} 4813 4814function applyAccessibilityProfile(name) { 4815 const prev = localStorage.getItem('euActiveProfile'); 4816 4817 // Clear previous profile 4818 if (prev && ACCESSIBILITY_PROFILES[prev]) { 4819 const prevDef = ACCESSIBILITY_PROFILES[prev]; 4820 Object.keys(prevDef.toggles || {}).forEach(function (k) { euSetToggleState(k, false); }); 4821 Object.keys(prevDef.cycles || {}).forEach(function (k) { localStorage.removeItem(k); }); 4822 } 4823 4824 // Apply new profile (clicking the active one just turns it off) 4825 if (name && name !== prev && ACCESSIBILITY_PROFILES[name]) { 4826 const def = ACCESSIBILITY_PROFILES[name]; 4827 Object.keys(def.toggles || {}).forEach(function (k) { euSetToggleState(k, def.toggles[k]); }); 4828 Object.keys(def.cycles || {}).forEach(function (k) { localStorage.setItem(k, def.cycles[k]); }); 4829 localStorage.setItem('euActiveProfile', name); 4830 } else { 4831 localStorage.removeItem('euActiveProfile'); 4832 } 4833 4834 applySettings(); 4835 refreshMenuButtonStates(); 4836} 4837 4838// Re-derive every menu button's visual state from localStorage 4839function refreshMenuButtonStates() { 4840 if (typeof shadowRoot === 'undefined' || !shadowRoot) return; 4841 const menu = shadowRoot.getElementById('eu-accessibility-menu'); 4842 if (!menu) return; 4843 4844 menu.querySelectorAll('.eu-accessibility-option').forEach(function (btn) { 4845 const optionId = btn.getAttribute('data-accessibility-option-id'); 4846 const optionsConfigAttr = btn.getAttribute('data-options-config'); 4847 if (optionsConfigAttr) { 4848 try { updateActionButtonStatus(btn, optionId, JSON.parse(optionsConfigAttr)); } catch (e) { /* ignore */ } 4849 } else { 4850 const key = btn.getAttribute('data-key'); 4851 const isActive = localStorage.getItem(key) === 'true'; 4852 btn.classList.toggle('active', isActive); 4853 btn.setAttribute('aria-pressed', String(isActive)); 4854 } 4855 }); 4856 4857 const activeProfile = localStorage.getItem('euActiveProfile'); 4858 menu.querySelectorAll('.eu-profile-chip').forEach(function (chip) { 4859 const isOn = chip.getAttribute('data-profile') === activeProfile; 4860 chip.classList.toggle('active', isOn); 4861 chip.setAttribute('aria-pressed', String(isOn)); 4862 }); 4863} 4864 4865// =========================================== 4866// PAGE STRUCTURE SCANNER 4867// =========================================== 4868 4869const pageStructureScanner = { 4870 // Landmark role mapping 4871 landmarkSelectors: [ 4872 { selector: 'header, [role="banner"]', label: 'Banner' }, 4873 { selector: 'nav, [role="navigation"]', label: 'Navigation' }, 4874 { selector: 'main, [role="main"]', label: 'Main' }, 4875 { selector: 'aside, [role="complementary"]', label: 'Complementary' }, 4876 { selector: 'footer, [role="contentinfo"]', label: 'Content Info' }, 4877 { selector: '[role="search"]', label: 'Search' }, 4878 { selector: '[role="form"]', label: 'Form' }, 4879 { selector: '[role="region"][aria-label], [role="region"][aria-labelledby], section[aria-label], section[aria-labelledby]', label: 'Region' } 4880 ], 4881 4882 getLandmarks() { 4883 const results = []; 4884 const seen = new Set();
4885 this.landmarkSelectors.forEach(({ selector, label }) => { 4886 document.querySelectorAll(selector).forEach(el => { 4887 if (seen.has(el) || el.closest('#eu-accessibility-widget-container')) return; 4888 seen.add(el); 4889 const name = el.getAttribute('aria-label') 4890 || (el.getAttribute('aria-labelledby') && document.getElementById(el.getAttribute('aria-labelledby'))?.textContent?.trim()) 4891 || ''; 4892 results.push({ element: el, tag: label, text: name || label }); 4893 }); 4894 }); 4895 return results; 4896 }, 4897 4898 getHeadings() { 4899 const results = []; 4900 document.querySelectorAll('h1, h2, h3, h4, h5, h6').forEach(el => { 4901 if (el.closest('#eu-accessibility-widget-container')) return; 4902 const level = el.tagName.toLowerCase(); 4903 const text = el.textContent.trim(); 4904 if (text) { 4905 results.push({ element: el, tag: level, text }); 4906 } 4907 }); 4908 return results; 4909 }, 4910 4911 getLinks() { 4912 const results = []; 4913 document.querySelectorAll('a[href]').forEach(el => { 4914 if (el.closest('#eu-accessibility-widget-container')) return; 4915 const text = (el.textContent.trim() || el.getAttribute('aria-label') || el.href).substring(0, 80); 4916 if (text) { 4917 results.push({ element: el, tag: 'a', text }); 4918 } 4919 }); 4920 return results; 4921 }, 4922 4923 highlightAndNavigate(element) { 4924 // Remove any previous highlight 4925 const prev = document.querySelector('.eu-structure-highlight'); 4926 if (prev) prev.classList.remove('eu-structure-highlight'); 4927 4928 // Scroll into view and highlight 4929 element.scrollIntoView({ behavior: 'smooth', block: 'center' }); 4930 element.classList.add('eu-structure-highlight'); 4931 element.focus({ preventScroll: true }); 4932 4933 // Remove highlight after animation completes 4934 setTimeout(() => { 4935 element.classList.remove('eu-structure-highlight'); 4936 }, 2500); 4937 } 4938}; 4939 4940// Make the panel resizable by dragging the corner grip (or arrow keys when focused). 4941function euSetupResize(menu, handle) { 4942 const side = WIDGET_CONFIG.widgetPosition.side === 'right' ? 'right' : 'left'; 4943 const MINW = 300; 4944 const MINH = 300; 4945 const maxW = function () { return Math.min(window.innerWidth - 40, 680); }; 4946 const maxH = function () { return window.innerHeight - 40; }; 4947 const clamp = function (v, lo, hi) { return Math.min(Math.max(v, lo), hi); }; 4948 4949 // Restore a previously chosen size. 4950 try { 4951 const saved = JSON.parse(localStorage.getItem('euWidgetSize') || 'null'); 4952 if (saved && saved.w) menu.style.width = clamp(saved.w, MINW, maxW()) + 'px'; 4953 if (saved && saved.h) menu.style.maxHeight = clamp(saved.h, MINH, maxH()) + 'px'; 4954 } catch (e) { /* ignore */ } 4955 4956 const persist = function () { 4957 try { 4958 localStorage.setItem('euWidgetSize', JSON.stringify({ 4959 w: menu.offsetWidth, 4960 h: Math.round(menu.getBoundingClientRect().height) 4961 })); 4962 } catch (e) { /* ignore */ } 4963 }; 4964 4965 let startX, startY, startW, startH, active = false; 4966 const onMove = function (e) { 4967 if (!active) return; 4968 const dx = e.clientX - startX; 4969 const dy = e.clientY - startY; 4970 const wDelta = side === 'right' ? -dx : dx; 4971 menu.style.width = clamp(startW + wDelta, MINW, maxW()) + 'px'; 4972 menu.style.maxHeight = clamp(startH - dy, MINH, maxH()) + 'px'; // drag up = taller 4973 }; 4974 const onUp = function (e) { 4975 if (!active) return; 4976 active = false; 4977 menu.classList.remove('eu-resizing'); 4978 try { handle.releasePointerCapture(e.pointerId); } catch (er) { /* ignore */ } 4979 document.removeEventListener('pointermove', onMove); 4980 document.removeEventListener('pointerup', onUp); 4981 persist(); 4982 }; 4983 handle.addEventListener('pointerdown', function (e) { 4984 e.preventDefault(); 4985 active = true; 4986 startX = e.clientX; 4987 startY = e.clientY; 4988 startW = menu.offsetWidth; 4989 startH = Math.round(menu.getBoundingClientRect().height); 4990 menu.classList.add('eu-resizing'); 4991 try { handle.setPointerCapture(e.pointerId); } catch (er) { /* ignore */ } 4992 document.addEventListener('pointermove', onMove); 4993 document.addEventListener('pointerup', onUp); 4994 }); 4995 4996 // Keyboard resizing for non-mouse users. 4997 handle.addEventListener('keydown', function (e) { 4998 const step = 24; 4999 let w = menu.offsetWidth; 5000 let h = Math.round(menu.getBoundingClientRect().height); 5001 let used = true; 5002 if (e.key === 'ArrowRight') w += side === 'right' ? -step : step; 5003 else if (e.key === 'ArrowLeft') w += side === 'right' ? step : -step; 5004 else if (e.key === 'ArrowUp') h += step; 5005 else if (e.key === 'ArrowDown') h -= step; 5006 else used = false;
5007 if (used) { 5008 e.preventDefault(); 5009 menu.style.width = clamp(w, MINW, maxW()) + 'px'; 5010 menu.style.maxHeight = clamp(h, MINH, maxH()) + 'px'; 5011 persist(); 5012 } 5013 }); 5014} 5015 5016// Create the accessibility menu 5017function createAccessibilityMenu() { 5018 const menu = document.createElement('div'); 5019 menu.id = 'eu-accessibility-menu'; 5020 menu.style.display = 'none'; 5021 menu.setAttribute('role', 'dialog'); 5022 menu.setAttribute('aria-labelledby', 'eu-accessibility-title'); 5023 menu.setAttribute('aria-hidden', 'true'); 5024 menu.setAttribute('dir', IS_RTL ? 'rtl' : 'ltr'); 5025 menu.classList.add('eu-side-' + (WIDGET_CONFIG.widgetPosition.side === 'right' ? 'right' : 'left')); 5026 5027 const header = document.createElement('div'); 5028 header.classList.add('eu-header'); 5029 5030 // Brand: the full enableuser logo, left-aligned on the single header row 5031 const brandLogo = document.createElement('img'); 5032 brandLogo.className = 'eu-header-logo'; 5033 brandLogo.id = 'eu-accessibility-title'; 5034 brandLogo.src = EU_LOGO; 5035 brandLogo.alt = 'enableuser â ' + getTranslation('accessibilityMenu'); 5036 brandLogo.setAttribute('draggable', 'false'); 5037 5038 // Create reset button 5039 const resetButton = document.createElement('button'); 5040 resetButton.classList.add('eu-reset-button'); 5041 resetButton.innerHTML = `<span class="eu-reset-label">${getTranslation('reset')}</span>`; 5042 resetButton.title = getTranslation('resetAllSettings'); 5043 resetButton.setAttribute('aria-label', getTranslation('resetAllSettings')); 5044 resetButton.addEventListener('click', resetAccessibilitySettings); 5045 5046 // Create close button 5047 const closeButton = document.createElement('button'); 5048 closeButton.className = 'eu-close'; 5049 closeButton.innerHTML = `<span class="eu-tooltip">${getTranslation('close')}</span>`; 5050 closeButton.setAttribute('aria-label', getTranslation('closeAccessibilityMenu')); 5051 5052 closeButton.addEventListener('click', function () { 5053 closeMenu(); 5054 }); 5055 5056 closeButton.addEventListener('keydown', function (e) { 5057 if (e.key === 'Enter' || e.key === ' ') { 5058 e.preventDefault(); 5059 closeMenu(); 5060 } 5061 }); 5062 5063 // Resize / expand grip â an inline control (drag, or focus it and use arrow keys) 5064 const resizeHandle = document.createElement('div'); 5065 resizeHandle.className = 'eu-resize-handle'; 5066 resizeHandle.setAttribute('role', 'slider'); 5067 resizeHandle.setAttribute('tabindex', '0'); 5068 resizeHandle.setAttribute('aria-label', getTranslation('resizeWidget')); 5069 resizeHandle.title = getTranslation('resizeWidget'); 5070 resizeHandle.innerHTML = '<svg viewBox="0 0 16 16" aria-hidden="true"><path d="M14 2 L2 14 M14 7 L7 14 M14 12 L12 14"/></svg>'; 5071 5072 // Assemble a single header row: logo on the left, controls on the right 5073 header.appendChild(brandLogo); 5074 header.appendChild(resizeHandle); 5075 header.appendChild(resetButton); 5076 header.appendChild(closeButton); 5077 menu.appendChild(header); 5078 5079 euSetupResize(menu, resizeHandle); 5080 5081 // Create content wrapper 5082 const content = document.createElement('div'); 5083 content.classList.add('eu-content'); 5084 5085 // =========================================== 5086 // PERSONALIZE YOUR EXPERIENCE SECTION 5087 // =========================================== 5088 const personalizeSection = document.createElement('div'); 5089 personalizeSection.classList.add('eu-personalize-section'); 5090 5091 // Collapsible header button 5092 const personalizeHeader = document.createElement('button'); 5093 personalizeHeader.classList.add('eu-personalize-header'); 5094 personalizeHeader.setAttribute('aria-expanded', 'false'); 5095 personalizeHeader.setAttribute('aria-controls', 'eu-personalize-body'); 5096 personalizeHeader.innerHTML = `<span>${getTranslation('navigatePageStructure')}</span><svg class="eu-personalize-chevron" viewBox="0 0 24 24"><path d="M7.41 8.59L12 13.17l4.59-4.58L18 10l-6 6-6-6z"/></svg>`; 5097 5098 const personalizeBody = document.createElement('div'); 5099 personalizeBody.classList.add('eu-personalize-body'); 5100 personalizeBody.id = 'eu-personalize-body'; 5101 5102 personalizeHeader.addEventListener('click', () => { 5103 const expanded = personalizeHeader.getAttribute('aria-expanded') === 'true'; 5104 personalizeHeader.setAttribute('aria-expanded', String(!expanded)); 5105 personalizeBody.classList.toggle('eu-open'); 5106 // Scan page structure on first open 5107 if (!expanded && !personalizeBody.dataset.scanned) { 5108 personalizeBody.dataset.scanned = 'true'; 5109 refreshPageStructureTabs(); 5110 } 5111 }); 5112 5113 // Tab bar
5114 const tabBar = document.createElement('div'); 5115 tabBar.classList.add('eu-structure-tabs'); 5116 tabBar.setAttribute('role', 'tablist'); 5117 5118 const tabDefs = [ 5119 { id: 'landmarks', label: getTranslation('landmarks'), getter: () => pageStructureScanner.getLandmarks() }, 5120 { id: 'headings', label: getTranslation('headings'), getter: () => pageStructureScanner.getHeadings() }, 5121 { id: 'links', label: getTranslation('links'), getter: () => pageStructureScanner.getLinks() } 5122 ]; 5123 5124 const panels = {}; 5125 5126 tabDefs.forEach((def, i) => { 5127 // Tab button 5128 const tab = document.createElement('button'); 5129 tab.classList.add('eu-structure-tab'); 5130 if (i === 0) tab.classList.add('eu-active'); 5131 tab.setAttribute('role', 'tab'); 5132 tab.setAttribute('aria-selected', i === 0 ? 'true' : 'false'); 5133 tab.setAttribute('aria-controls', `eu-panel-${def.id}`); 5134 tab.id = `eu-tab-${def.id}`; 5135 tab.innerHTML = `<span>${def.label}</span><span class="eu-tab-count" id="eu-count-${def.id}">0</span>`; 5136 5137 tab.addEventListener('click', () => { 5138 // Deactivate all tabs 5139 tabBar.querySelectorAll('.eu-structure-tab').forEach(t => { 5140 t.classList.remove('eu-active'); 5141 t.setAttribute('aria-selected', 'false'); 5142 }); 5143 // Hide all panels 5144 Object.values(panels).forEach(p => p.classList.remove('eu-active')); 5145 // Activate clicked tab 5146 tab.classList.add('eu-active'); 5147 tab.setAttribute('aria-selected', 'true'); 5148 panels[def.id].classList.add('eu-active'); 5149 }); 5150 5151 tabBar.appendChild(tab); 5152 5153 // Panel 5154 const panel = document.createElement('div'); 5155 panel.classList.add('eu-structure-panel'); 5156 if (i === 0) panel.classList.add('eu-active'); 5157 panel.setAttribute('role', 'tabpanel'); 5158 panel.setAttribute('aria-labelledby', `eu-tab-${def.id}`); 5159 panel.id = `eu-panel-${def.id}`; 5160 panels[def.id] = panel; 5161 }); 5162 5163 // Function to populate tabs with scanned data 5164 function refreshPageStructureTabs() { 5165 tabDefs.forEach(def => { 5166 const panel = panels[def.id]; 5167 const items = def.getter(); 5168 // Update count badge 5169 const countEl = personalizeBody.querySelector(`#eu-count-${def.id}`); 5170 if (countEl) countEl.textContent = items.length; 5171 5172 panel.innerHTML = ''; 5173 if (items.length === 0) { 5174 const empty = document.createElement('div'); 5175 empty.classList.add('eu-structure-empty'); 5176 empty.textContent = getTranslation('noItemsFound'); 5177 panel.appendChild(empty); 5178 return; 5179 } 5180 5181 items.forEach(item => { 5182 const btn = document.createElement('button'); 5183 btn.classList.add('eu-structure-item'); 5184 const tagSpan = document.createElement('span'); 5185 tagSpan.classList.add('eu-structure-item-tag'); 5186 tagSpan.textContent = item.tag; 5187 const textSpan = document.createElement('span'); 5188 textSpan.classList.add('eu-structure-item-text'); 5189 textSpan.textContent = item.text; 5190 textSpan.title = item.text; 5191 btn.appendChild(tagSpan); 5192 btn.appendChild(textSpan); 5193 btn.addEventListener('click', () => { 5194 pageStructureScanner.highlightAndNavigate(item.element); 5195 }); 5196 panel.appendChild(btn); 5197 }); 5198 }); 5199 } 5200 5201 // Assemble the personalize section 5202 personalizeBody.appendChild(tabBar); 5203 tabDefs.forEach(def => { 5204 personalizeBody.appendChild(panels[def.id]); 5205 }); 5206 5207 personalizeSection.appendChild(personalizeHeader); 5208 personalizeSection.appendChild(personalizeBody); 5209 5210 // =========================================== 5211 // ACCESSIBILITY PROFILES SECTION (top of menu) 5212 // =========================================== 5213 if (WIDGET_CONFIG.enableProfiles) { 5214 const profilesSection = document.createElement('div'); 5215 profilesSection.classList.add('eu-profiles-section'); 5216 5217 const profilesTitle = document.createElement('div'); 5218 profilesTitle.classList.add('eu-profiles-title'); 5219 profilesTitle.textContent = getTranslation('profiles'); 5220 profilesSection.appendChild(profilesTitle); 5221 5222 const chipRow = document.createElement('div'); 5223 chipRow.classList.add('eu-profiles-row'); 5224
5225 Object.keys(ACCESSIBILITY_PROFILES).forEach(function (name) { 5226 const def = ACCESSIBILITY_PROFILES[name]; 5227 const chip = document.createElement('button'); 5228 chip.classList.add('eu-profile-chip'); 5229 chip.setAttribute('data-profile', name); 5230 chip.setAttribute('role', 'switch'); 5231 chip.textContent = getTranslation(def.labelKey); 5232 const isOn = localStorage.getItem('euActiveProfile') === name; 5233 chip.setAttribute('aria-pressed', String(isOn)); 5234 if (isOn) chip.classList.add('active'); 5235 chip.addEventListener('click', function () { 5236 applyAccessibilityProfile(name); 5237 }); 5238 chipRow.appendChild(chip); 5239 }); 5240 5241 profilesSection.appendChild(chipRow); 5242 content.appendChild(profilesSection); 5243 } 5244 5245 content.appendChild(personalizeSection); 5246 5247 // =========================================== 5248 // SHOW SHORTCUTS TOGGLE 5249 // =========================================== 5250 const shortcutKeyMap = { 5251 focusIndicator: 'z', 5252 biggerCursor: 'm', 5253 highlightLinks: 'y', 5254 highContrast: 'c', 5255 colorFilter: 'i', 5256 saturation: 's', 5257 pauseAnimations: 'q', 5258 biggerText: '=', 5259 textSpacing: 'k', 5260 lineHeight: 'l', 5261 textAlign: 't', 5262 fontSelection: 'f', 5263 readingGuide: 'g', 5264 readingWindow: 'e', 5265 hideImages: 'a', 5266 screenReader: 'p', 5267 voiceControl: 'v', 5268 showAltText: 'd' 5269 }; 5270 5271 let shortcutsVisible = false; 5272 5273 const shortcutsBar = document.createElement('div'); 5274 shortcutsBar.classList.add('eu-shortcuts-bar'); 5275 5276 const shortcutsLabel = document.createElement('span'); 5277 shortcutsLabel.classList.add('eu-shortcuts-label'); 5278 shortcutsLabel.textContent = getTranslation('showShortcuts'); 5279 5280 const toggleSwitch = document.createElement('button'); 5281 toggleSwitch.classList.add('eu-toggle-switch'); 5282 toggleSwitch.setAttribute('role', 'switch'); 5283 toggleSwitch.setAttribute('aria-checked', 'false'); 5284 toggleSwitch.setAttribute('aria-label', getTranslation('showShortcuts')); 5285 toggleSwitch.innerHTML = '<div class="eu-toggle-track"></div><div class="eu-toggle-thumb"></div>'; 5286 5287 function updateShortcutLabels(show) { 5288 const buttons = optionsGrid.querySelectorAll('.eu-accessibility-option'); 5289 buttons.forEach(btn => { 5290 const optionId = btn.getAttribute('data-accessibility-option-id'); 5291 const key = shortcutKeyMap[optionId]; 5292 if (!key) return; 5293 const textEl = btn.querySelector('.eu-button-text'); 5294 if (!textEl) return; 5295 // Store original text on first call 5296 if (!textEl.dataset.originalText) { 5297 textEl.dataset.originalText = textEl.textContent; 5298 } 5299 textEl.textContent = show 5300 ? `${textEl.dataset.originalText} (${key})` 5301 : textEl.dataset.originalText; 5302 }); 5303 } 5304 5305 toggleSwitch.addEventListener('click', () => { 5306 shortcutsVisible = !shortcutsVisible; 5307 toggleSwitch.setAttribute('aria-checked', String(shortcutsVisible)); 5308 updateShortcutLabels(shortcutsVisible); 5309 }); 5310 5311 shortcutsBar.appendChild(shortcutsLabel); 5312 shortcutsBar.appendChild(toggleSwitch); 5313 content.appendChild(shortcutsBar); 5314 5315 // Keyboard shortcuts listener (works when menu is open) 5316 document.addEventListener('keydown', function (e) { 5317 // Don't trigger if user is typing in an input/textarea/select 5318 const tag = e.target.tagName; 5319 if (tag === 'INPUT' || tag === 'TEXTAREA' || tag === 'SELECT' || e.target.isContentEditable) return; 5320 // Don't trigger with modifier keys 5321 if (e.ctrlKey || e.altKey || e.metaKey) return; 5322 5323 const pressedKey = e.key.toLowerCase(); 5324 5325 const menuEl = shadowRoot.getElementById('eu-accessibility-menu'); 5326 if (!menuEl || menuEl.style.display !== 'block') return; 5327 5328 // Additional shortcuts (active when menu is open) 5329 switch (pressedKey) { 5330 case 'r': // Reset Visual Toolkit 5331 e.preventDefault(); 5332 resetAccessibilitySettings(); 5333 return; 5334 case 'x': // Reset Issue â clears highlights and re-scans page structure 5335 e.preventDefault(); 5336 const prevHighlight = document.querySelector('.eu-structure-highlight'); 5337 if (prevHighlight) prevHighlight.classList.remove('eu-structure-highlight'); 5338 // Re-scan page structure if personalize section is open 5339 const persBody = shadowRoot.getElementById('eu-personalize-body'); 5340 if (persBody && persBody.classList.contains('eu-open')) { 5341 persBody.dataset.scanned = ''; 5342 persBody.dataset.scanned = 'true'; 5343 if (typeof refreshPageStructureTabs === 'function') refreshPageStructureTabs(); 5344 } 5345 return; 5346 case 'n': // Navigate by Page Structure â toggle the personalize section open 5347 e.preventDefault(); 5348 const persHeader = personalizeSection.querySelector('.eu-personalize-header'); 5349 if (persHeader) persHeader.click(); 5350 return; 5351 } 5352 5353 // Tool grid shortcuts 5354 const optionId = Object.keys(shortcutKeyMap).find(id => shortcutKeyMap[id] === pressedKey); 5355 if (!optionId) return; 5356 5357 const btn = menuEl.querySelector(`[data-accessibility-option-id="${optionId}"]`); 5358 if (btn) { 5359 e.preventDefault(); 5360 btn.click(); 5361 } 5362 }); 5363 5364 // Create grid wrapper for accessibility options 5365 const optionsGrid = document.createElement('div'); 5366 optionsGrid.classList.add('eu-options-grid'); 5367 5368 // =================================================================== 5369 // UNIFIED BUTTON CONFIGURATION â 4 rows à 3 columns 5370 // Order: Focus, Cursor, Highlight, Contrast, Color Shift, Animation, 5371 // Text Size, Spacing, Font, Guide, Window, Images 5372 // =================================================================== 5373 const allButtonConfigs = [ 5374 // Row 1 5375 { 5376 order: 1, 5377 type: 'toggle', 5378 text: getTranslation('focus'), 5379 key: 'focusIndicator', 5380 customToggleFunction: toggleFocusIndicator, 5381 icon: icons.focusIndicator, 5382 enabled: WIDGET_CONFIG.enableFocusIndicator, 5383 optionId: 'focusIndicator' 5384 }, 5385 { 5386 order: 2, 5387 type: 'toggle', 5388 text: getTranslation('cursor'),
5389 key: 'biggerCursor', 5390 className: 'eu-bigger-cursor', 5391 icon: icons.biggerCursor, 5392 enabled: WIDGET_CONFIG.enableBiggerCursor, 5393 optionId: 'biggerCursor' 5394 }, 5395 { 5396 order: 3, 5397 type: 'toggle', 5398 text: getTranslation('highlight'), 5399 key: 'highlightLinks', 5400 customToggleFunction: toggleHighlightLinks, 5401 icon: icons.highlightLinks, 5402 enabled: WIDGET_CONFIG.enableHighlightLinks, 5403 optionId: 'highlightLinks' 5404 }, 5405 5406 // Row 2 5407 { 5408 order: 4, 5409 type: 'action', 5410 text: getTranslation('contrast'), 5411 actionFunction: handleHighContrast, 5412 icon: icons.highContrast, 5413 enabled: WIDGET_CONFIG.enableHighContrast, 5414 optionsConfig: { count: 3 }, 5415 optionId: 'highContrast' 5416 }, 5417 { 5418 order: 5, 5419 type: 'action', 5420 text: getTranslation('colorShift'), 5421 actionFunction: handleColorFilter, 5422 icon: icons.colorFilter, 5423 enabled: WIDGET_CONFIG.enableColorFilter, 5424 optionsConfig: { count: 4 }, 5425 optionId: 'colorFilter' 5426 }, 5427 { 5428 order: 5.5, 5429 type: 'action', 5430 text: getTranslation('saturation'), 5431 actionFunction: handleSaturation, 5432 icon: icons.saturation, 5433 enabled: WIDGET_CONFIG.enableSaturation, 5434 optionsConfig: { count: 3 }, 5435 optionId: 'saturation' 5436 }, 5437 { 5438 order: 6, 5439 type: 'toggle', 5440 text: getTranslation('animation'), 5441 key: 'pauseAnimations', 5442 className: 'eu-pause-animations', 5443 icon: icons.pauseAnimations, 5444 enabled: WIDGET_CONFIG.enablePauseAnimations, 5445 optionId: 'pauseAnimations', 5446 // Also freeze non-CSS motion (videos, animated GIFs, <marquee>) in step 5447 // with the CSS animation/transition kill done via the className. 5448 customToggleFunction: function (isActive) { mediaFreeze.toggle(isActive); return true; } 5449 }, 5450 5451 // Row 3 5452 { 5453 order: 7, 5454 type: 'action', 5455 text: getTranslation('textSize'), 5456 actionFunction: handleBiggerText, 5457 icon: icons.biggerText, 5458 enabled: WIDGET_CONFIG.enableBiggerText, 5459 optionsConfig: { count: 3 }, 5460 optionId: 'biggerText' 5461 }, 5462 { 5463 order: 8, 5464 type: 'action', 5465 text: getTranslation('spacing'), 5466 actionFunction: handleTextSpacing, 5467 icon: icons.textSpacing, 5468 enabled: WIDGET_CONFIG.enableTextSpacing, 5469 optionsConfig: { count: 3 }, 5470 optionId: 'textSpacing' 5471 }, 5472 { 5473 order: 8.3, 5474 type: 'action', 5475 text: getTranslation('lineHeight'), 5476 actionFunction: handleLineHeight, 5477 icon: icons.lineHeight, 5478 enabled: WIDGET_CONFIG.enableLineHeight, 5479 optionsConfig: { count: 3 }, 5480 optionId: 'lineHeight' 5481 }, 5482 { 5483 order: 8.6, 5484 type: 'action', 5485 text: getTranslation('align'), 5486 actionFunction: handleTextAlign, 5487 icon: icons.textAlign, 5488 enabled: WIDGET_CONFIG.enableTextAlign, 5489 optionsConfig: { count: 3 }, 5490 optionId: 'textAlign' 5491 }, 5492 { 5493 order: 9, 5494 type: 'action', 5495 text: getTranslation('font'), 5496 actionFunction: handleFontSelection, 5497 icon: icons.fontSelection, 5498 enabled: WIDGET_CONFIG.enableFontSelection, 5499 optionsConfig: { count: 4 }, 5500 optionId: 'fontSelection' 5501 }, 5502 5503 // Row 4 5504 { 5505 order: 10, 5506 type: 'toggle', 5507 text: getTranslation('guide'), 5508 key: 'readingGuide', 5509 customToggleFunction: readingGuide.toggle, 5510 icon: icons.readingGuide, 5511 enabled: WIDGET_CONFIG.enableReadingGuide, 5512 optionId: 'readingGuide' 5513 }, 5514 { 5515 order: 11, 5516 type: 'toggle', 5517 text: getTranslation('window'), 5518 key: 'readingWindow', 5519 customToggleFunction: readingWindow.toggle, 5520 icon: icons.readingWindow, 5521 enabled: WIDGET_CONFIG.enableReadingWindow, 5522 optionId: 'readingWindow' 5523 }, 5524 { 5525 order: 12, 5526 type: 'toggle', 5527 text: getTranslation('images'), 5528 key: 'hideImages', 5529 icon: icons.hideImages, 5530 customToggleFunction: toggleHideImages, 5531 enabled: WIDGET_CONFIG.enableHideImages, 5532 optionId: 'hideImages' 5533 }, 5534 5535 // Row 6 â assistive tools 5536 { 5537 order: 16, 5538 type: 'toggle', 5539 text: getTranslation('screenReader'), 5540 key: 'screenReader', 5541 customToggleFunction: screenReader.toggle, 5542 icon: icons.screenReader, 5543 enabled: WIDGET_CONFIG.enableScreenReader, 5544 requiresFeature: screenReader, 5545 optionId: 'screenReader' 5546 }, 5547 { 5548 order: 17, 5549 type: 'toggle', 5550 text: getTranslation('voice'), 5551 key: 'voiceControl', 5552 customToggleFunction: voiceControl.toggle, 5553 icon: icons.voiceControl, 5554 enabled: WIDGET_CONFIG.enableVoiceControl, 5555 requiresFeature: voiceControl, 5556 optionId: 'voiceControl' 5557 }, 5558 { 5559 order: 18, 5560 type: 'toggle', 5561 text: getTranslation('altText'), 5562 key: 'showAltText', 5563 customToggleFunction: altTextViewer.toggle, 5564 icon: icons.altText, 5565 enabled: WIDGET_CONFIG.enableAltText, 5566 optionId: 'showAltText' 5567 }, 5568 5569 // Row 7 â enhanced tools (v1.3.0) 5570 { 5571 order: 19, 5572 type: 'toggle', 5573 text: getTranslation('hoverHighlight'), 5574 key: 'hoverHighlight', 5575 customToggleFunction: hoverHighlight.toggle, 5576 icon: icons.hoverHighlight, 5577 enabled: WIDGET_CONFIG.enableHighlightHover, 5578 optionId: 'hoverHighlight' 5579 }, 5580 { 5581 order: 20, 5582 type: 'toggle', 5583 text: getTranslation('enlargeButtons'),
5584 key: 'enlargeButtons', 5585 className: 'eu-enlarge-buttons', 5586 icon: icons.enlargeButtons, 5587 enabled: WIDGET_CONFIG.enableEnlargeButtons, 5588 optionId: 'enlargeButtons' 5589 }, 5590 { 5591 order: 21, 5592 type: 'toggle', 5593 text: getTranslation('muteMedia'), 5594 key: 'muteMedia', 5595 customToggleFunction: muteMedia.toggle, 5596 icon: icons.muteMedia, 5597 enabled: WIDGET_CONFIG.enableMuteMedia, 5598 optionId: 'muteMedia' 5599 }, 5600 { 5601 order: 22, 5602 type: 'toggle', 5603 text: getTranslation('readableFont'), 5604 key: 'readableFont', 5605 className: 'eu-readable-font', 5606 icon: icons.readableFont, 5607 enabled: WIDGET_CONFIG.enableReadableFont, 5608 optionId: 'readableFont' 5609 }, 5610 { 5611 order: 23, 5612 type: 'action', 5613 text: getTranslation('magnifier'), 5614 actionFunction: handlePageMagnifier, 5615 icon: icons.magnifier, 5616 enabled: WIDGET_CONFIG.enablePageMagnifier, 5617 optionsConfig: { count: 3 }, 5618 optionId: 'pageMagnifier' 5619 }, 5620 { 5621 order: 24, 5622 type: 'toggle', 5623 text: getTranslation('textMagnifier'), 5624 key: 'textMagnifier', 5625 customToggleFunction: textMagnifier.toggle, 5626 icon: icons.textMagnifier, 5627 enabled: WIDGET_CONFIG.enableTextMagnifier, 5628 optionId: 'textMagnifier' 5629 }, 5630 { 5631 order: 25, 5632 type: 'toggle', 5633 text: getTranslation('readFocus'), 5634 key: 'readFocus', 5635 customToggleFunction: readFocus.toggle, 5636 icon: icons.readFocus, 5637 enabled: WIDGET_CONFIG.enableReadFocus, 5638 optionId: 'readFocus' 5639 }, 5640 { 5641 order: 26, 5642 type: 'toggle', 5643 text: getTranslation('readableMode'), 5644 key: 'readableMode', 5645 customToggleFunction: readableMode.toggle, 5646 icon: icons.readableMode, 5647 enabled: WIDGET_CONFIG.enableReadableMode, 5648 optionId: 'readableMode' 5649 }, 5650 { 5651 order: 27, 5652 type: 'toggle', 5653 text: getTranslation('virtualKeyboard'), 5654 key: 'virtualKeyboard', 5655 customToggleFunction: virtualKeyboard.toggle, 5656 icon: icons.virtualKeyboard, 5657 enabled: WIDGET_CONFIG.enableVirtualKeyboard, 5658 optionId: 'virtualKeyboard' 5659 }, 5660 { 5661 order: 28, 5662 type: 'toggle', 5663 text: getTranslation('dictionary'), 5664 key: 'dictionary', 5665 customToggleFunction: dictionary.toggle, 5666 icon: icons.dictionary, 5667 enabled: WIDGET_CONFIG.enableDictionary, 5668 optionId: 'dictionary' 5669 }, 5670 { 5671 order: 29, 5672 type: 'action', 5673 text: getTranslation('customColor'), 5674 actionFunction: customColor.togglePanel, 5675 icon: icons.customColor, 5676 enabled: WIDGET_CONFIG.enableCustomColor, 5677 optionId: 'customColor' 5678 }, 5679 ]; 5680 5681 // Sort buttons by order and add only enabled ones to the grid 5682 allButtonConfigs 5683 .filter(config => config.enabled) 5684 .sort((a, b) => a.order - b.order) 5685 .forEach((config) => { 5686 let button; 5687 5688 if (config.type === 'action') { 5689 button = createActionButton(config.text, config.actionFunction, config.icon, config.optionsConfig, config.optionId); 5690 } else if (config.type === 'toggle') { 5691 button = createToggleButton( 5692 config.text, 5693 config.key, 5694 config.className, 5695 config.target || document.body, 5696 config.customToggleFunction, 5697 config.icon, 5698 config.requiresFeature, 5699 config.optionId 5700 ); 5701 } 5702 5703 if (button) { 5704 optionsGrid.appendChild(button); 5705 } 5706 }); 5707 5708 // Add grid to content 5709 content.appendChild(optionsGrid); 5710 5711 // Custom Color inline panel (toggled open by the Custom Color tool button) 5712 if (WIDGET_CONFIG.enableCustomColor) { 5713 content.appendChild(customColor.createPanel()); 5714 } 5715 5716 // =========================================== 5717 // ADDITIONAL KEYBOARD SHORTCUTS (flat list below tools) 5718 // =========================================== 5719 const additionalShortcutDefs = [ 5720 { label: getTranslation('resetVisualToolkit'), key: 'r' }, 5721 { label: getTranslation('resetIssue'), key: 'x' }, 5722 { label: getTranslation('navigatePageStructureShortcut'), key: 'n' } 5723 ]; 5724 5725 const additionalSection = document.createElement('div'); 5726 additionalSection.classList.add('eu-additional-shortcuts'); 5727 5728 const sectionTitle = document.createElement('div'); 5729 sectionTitle.classList.add('eu-additional-shortcuts-title'); 5730 sectionTitle.textContent = getTranslation('additionalShortcuts'); 5731 additionalSection.appendChild(sectionTitle); 5732
5733 additionalShortcutDefs.forEach(def => { 5734 const row = document.createElement('div'); 5735 row.classList.add('eu-shortcut-row'); 5736 row.innerHTML = `<span class="eu-shortcut-action">${def.label}</span><kbd class="eu-shortcut-key">${def.key}</kbd>`; 5737 additionalSection.appendChild(row); 5738 }); 5739 5740 content.appendChild(additionalSection); 5741 5742 // Utility links: Accessibility Statement, Hide button 5743 const footerLinks = document.createElement('div'); 5744 footerLinks.classList.add('eu-footer-links'); 5745 5746 if (WIDGET_CONFIG.accessibilityStatementUrl) { 5747 const a = document.createElement('a'); 5748 a.href = WIDGET_CONFIG.accessibilityStatementUrl; 5749 a.target = '_blank'; 5750 a.rel = 'noopener noreferrer'; 5751 a.textContent = getTranslation('accessibilityStatement'); 5752 footerLinks.appendChild(a); 5753 } 5754 // Hide-button control â hides the launcher until the next page load 5755 const hideLink = document.createElement('a'); 5756 hideLink.href = '#'; 5757 hideLink.textContent = getTranslation('hideForNow'); 5758 hideLink.addEventListener('click', function (e) { 5759 e.preventDefault(); 5760 closeMenu(); 5761 const btnContainer = shadowRoot.getElementById('eu-accessibility-fixed-button'); 5762 if (btnContainer) btnContainer.style.display = 'none'; // hidden until the next page load 5763 }); 5764 footerLinks.appendChild(hideLink); 5765 content.appendChild(footerLinks); 5766 5767 // Add footer 5768 const footer = document.createElement('div'); 5769 footer.classList.add('eu-footer'); 5770 footer.innerHTML = 'Powered by <a href="https://www.enableuser.com" target="_blank" rel="noopener noreferrer" class="eu-footer-brand" aria-label="EnableUser"><img src="' + EU_LOGO + '" alt="EnableUser" class="eu-footer-logo" draggable="false"></a>'; 5771 content.appendChild(footer); 5772 5773 // Add content to menu 5774 menu.appendChild(content); 5775 5776 shadowRoot.appendChild(menu); 5777} 5778 5779// =========================================== 5780// MENU MANAGEMENT 5781// =========================================== 5782 5783// Cache for menu elements 5784const menuCache = { 5785 menu: null, 5786 button: null, 5787 closeButton: null, 5788 init: function () { 5789 this.menu = shadowRoot.getElementById('eu-accessibility-menu'); 5790 this.button = shadowRoot.getElementById('eu-accessibility-button'); 5791 this.closeButton = this.menu?.querySelector('.eu-close'); 5792 } 5793}; 5794 5795// Menu control functions (optimized) 5796function toggleMenu() { 5797 if (!menuCache.menu) menuCache.init(); 5798 const isOpen = menuCache.menu.style.display === 'block'; 5799 5800 if (isOpen) { 5801 closeMenu(); 5802 } else { 5803 openMenu(); 5804 } 5805} 5806 5807function openMenu() { 5808 if (!menuCache.menu) menuCache.init(); 5809 menuCache.menu.style.display = 'block'; 5810 menuCache.menu.setAttribute('aria-hidden', 'false'); 5811 5812 // Hide the trigger button while menu is open 5813 const btnContainer = shadowRoot.getElementById('eu-accessibility-fixed-button'); 5814 if (btnContainer) btnContainer.style.display = 'none'; 5815 5816 // Focus on the first tool button 5817 const firstOption = menuCache.menu.querySelector('.eu-accessibility-option'); 5818 if (firstOption) { 5819 firstOption.focus(); 5820 } else if (menuCache.closeButton) { 5821 menuCache.closeButton.focus(); 5822 } 5823 5824 // Add keyboard navigation 5825 document.addEventListener('keydown', handleMenuKeyboard); 5826} 5827 5828function closeMenu() { 5829 if (!menuCache.menu) menuCache.init(); 5830 menuCache.menu.style.display = 'none'; 5831 menuCache.menu.setAttribute('aria-hidden', 'true'); 5832 5833 // Show the trigger button again 5834 const btnContainer = shadowRoot.getElementById('eu-accessibility-fixed-button'); 5835 if (btnContainer) btnContainer.style.display = ''; 5836 5837 if (menuCache.button) { 5838 menuCache.button.focus(); 5839 } 5840 5841 // Remove keyboard navigation 5842 document.removeEventListener('keydown', handleMenuKeyboard); 5843} 5844 5845// Cache for keyboard navigation elements 5846let keyboardCache = { 5847 focusableElements: null, 5848 lastUpdate: 0, 5849 getFocusableElements: function () { 5850 const now = Date.now(); 5851 if (!this.focusableElements || now - this.lastUpdate > 1000) { 5852 if (menuCache.menu) { 5853 this.focusableElements = { 5854 all: menuCache.menu.querySelectorAll('button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])'), 5855 options: Array.from(menuCache.menu.querySelectorAll('.eu-accessibility-option, .eu-close, .eu-reset-button')) 5856 }; 5857 this.lastUpdate = now; 5858 } 5859 } 5860 return this.focusableElements; 5861 } 5862}; 5863 5864function handleMenuKeyboard(e) { 5865 if (!menuCache.menu || menuCache.menu.style.display !== 'block') return; 5866 5867 if (e.key === 'Escape') { 5868 e.preventDefault(); 5869 closeMenu(); 5870 return; 5871 } 5872 5873 const elements = keyboardCache.getFocusableElements(); 5874 if (!elements) return; 5875 5876 if (e.key === 'Tab') { 5877 const firstElement = elements.all[0]; 5878 const lastElement = elements.all[elements.all.length - 1]; 5879 const focused = shadowRoot.activeElement; 5880 5881 if (e.shiftKey) { 5882 if (focused === firstElement) { 5883 e.preventDefault(); 5884 lastElement.focus(); 5885 } 5886 } else { 5887 if (focused === lastElement) { 5888 e.preventDefault(); 5889 firstElement.focus(); 5890 } 5891 } 5892 } 5893 5894 if (e.key === 'ArrowDown' || e.key === 'ArrowUp') { 5895 e.preventDefault(); 5896 const currentIndex = elements.options.indexOf(shadowRoot.activeElement); 5897 let nextIndex; 5898 5899 if (e.key === 'ArrowDown') { 5900 nextIndex = currentIndex === elements.options.length - 1 ? 0 : currentIndex + 1; 5901 } else { 5902 nextIndex = currentIndex === 0 ? elements.options.length - 1 : currentIndex - 1; 5903 } 5904 5905 elements.options[nextIndex].focus(); 5906 } 5907} 5908 5909// =========================================== 5910// INITIALIZATION 5911// =========================================== 5912 5913// Initialize the widget 5914function initAccessibilityWidget() { 5915 // Create shadow DOM first 5916 createShadowContainer(); 5917 5918 // Inject page styles (for accessibility features) 5919 injectPageStyles(); 5920 5921 // Respect OS-level reduced-motion preference on first visit 5922 // (auto-enables Pause Animations unless the user has chosen otherwise) 5923 try { 5924 if (window.matchMedia && window.matchMedia('(prefers-reduced-motion: reduce)').matches && 5925 localStorage.getItem('pauseAnimations') === null) { 5926 localStorage.setItem('pauseAnimations', 'true'); 5927 } 5928 } catch (e) { /* ignore */ } 5929 5930 // Stamp / migrate the localStorage settings schema version. 5931 try { 5932 if (localStorage.getItem('euSettingsVersion') !== EU_SETTINGS_VERSION) { 5933 localStorage.setItem('euSettingsVersion', EU_SETTINGS_VERSION); 5934 } 5935 } catch (e) { /* ignore */ } 5936 5937 // Apply saved settings 5938 applySettings(); 5939 5940 // Create widget UI inside shadow DOM 5941 createAccessibilityButton(); 5942 createAccessibilityMenu(); 5943 5944 // Global shortcut: Alt+A toggles the accessibility panel from anywhere on the page. 5945 document.addEventListener('keydown', function (e) { 5946 if (!e.altKey || e.ctrlKey || e.metaKey) return; 5947 const tag = e.target && e.target.tagName; 5948 if (tag === 'INPUT' || tag === 'TEXTAREA' || tag === 'SELECT' || (e.target && e.target.isContentEditable)) return; 5949 if ((e.key || '').toLowerCase() === 'a') { 5950 e.preventDefault(); 5951 toggleMenu(); 5952 } 5953 }); 5954 5955 // Extend accessibility classes/styles into same-origin iframes 5956 frameSync.start(); 5957 frameSync.syncNow(); 5958} 5959 5960// =========================================== 5961// WIDGET BOOTSTRAP 5962// =========================================== 5963 5964// Load the widget when the DOM is fully loaded 5965if (document.readyState === 'loading') { 5966 document.addEventListener('DOMContentLoaded', initAccessibilityWidget); 5967} else { 5968 initAccessibilityWidget(); 5969} 5970 5971// --- Browser-only code ends --- 5972}
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.