PageSourceSearch

https://enam.com/js/enablestack-widget.js

js enam.com collected 2026-10-08 12:22:28 UTC 356,672 bytes, 5,972 lines download raw bytes

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.