PageSourceSearch

https://prdconstruction.ca/wp-content/plugins/kraken-accessibility/public/assets/js/public.js

js prdconstruction.ca collected 2026-10-04 08:16:32 UTC 108,526 bytes, 2,699 lines download raw bytes

1// Create an empty object to hold accessibility-related methods and data.
2const Accessibility = {};
3
4// Select the root element of the document.
5const content = document.documentElement;
6
7// Define profiles with settings for specific accessibility needs.
8const profiles = {
9    "p-motor-impaired": {
10        pauseAnimations: 1,
11        linkNotices: 1,
12    },
13    "p-blind": {
14        screenReader: 1,
15    },
16    "p-color-blind": {
17        saturation: 2,
18    },
19    "p-dyslexia": {
20        dyslexiaFont: 1,
21        pauseAnimations: 1,
22    },
23    "p-low-vision": {
24        biggerText: 1,
25        dyslexiaFont: 2,
26        pauseAnimations: 1,
27        saturation: 2,
28        cursor: 1,
29        linkNotices: 1,
30    },
31    "p-cognitive-learning": {
32        biggerText: 1,
33        pauseAnimations: 1,
34        linkNotices: 1,
35        cursor: 3,
36    },
37    "p-seizure-epileptic": {
38        pauseAnimations: 1,
39        saturation: 1,
40    },
41    "p-adhd": {
42        pauseAnimations: 1,
43        saturation: 1,
44        cursor: 2,
45    },
46};
47
48// Key used to store state in localStorage.
49const stateKey = "accessibilityState";
50
51// Load saved state or initialize default state.
52let state = JSON.parse(localStorage.getItem(stateKey)) || {
53    activeProfile: null,
54    contrast: 0,
55    biggerText: 0,
56    cursor: 0,
57    pauseAnimations: 0,
58    screenReader: 0,
59    highlightHeadings: 0,
60    highlightLinks: 0,
61    saturation: 0,
62    dyslexiaFont: 0,
63    textSpacing: 0,
64    readMode: 0,
65    textAlign: 0,
66    lineHeight: 0,
67    muteSounds: 0,
68    hideImages: 0,
69    linkNotices: 0,
70    dictionary: 0,
71};
72
73// Map feature names to their initialization functions for dynamic invocation.
74const featureFunctions = {
75    contrast: initializeContrast,
76    biggerText: initializeBiggerText,
77    cursor: initializeCursor,
78    pauseAnimations: initializePauseAnimations,
79    screenReader: initializeScreenReader,
80    highlightHeadings: initializeHighlightHeadings,
81    highlightLinks: initializeHighlightLinks,
82    saturation: initializeSaturation,
83    dyslexiaFont: initializeDyslexiaFont,
84    textSpacing: initializeTextSpacing,
85    readMode: initializeReadMode,
86    textAlign: initializeTextAlign,
87    lineHeight: initializeLineHeight,
88    muteSounds: initializeMuteSounds,
89    hideImages: initializeHideImages,
90    linkNotices: initializeLinkNotices,
91    dictionary: initializeDictionary,
92};
93  
94// Save the current state to localStorage.
95function saveStateToLocalStorage() {
96    localStorage.setItem("accessibilityState", JSON.stringify(state));
97}
98
99// Apply a specific function based on a key and value.
100function applyFunctionByKey(key, value) {
101    if (featureFunctions.hasOwnProperty(key)) {
102      try {
103        featureFunctions[key](value);
104      } catch (error) {
105        console.error(`Error occurred while applying function for key: '${key}'.`, error);
106      }
107    } else {
108      console.warn(`Invalid key: '${key}'. This key is not supported by applyFunctionByKey. 
109  Possible Causes:
110  1. Typo in the key name.
111  2. New functionality added but not included in the featureFunctions mapping.
112  Action Steps:
113  - Verify the key name in the call.
114  - If this is a new feature, update the featureFunctions mapping accordingly.`);
115    }
116}  
117
118// Activate a specific profile by applying its settings.
119function activateProfile(profileId) {
120    const settings = profiles[profileId];
121
122    // Apply each setting in the profile.
123    Object.entries(settings).forEach(([key, value]) => {
124        state[key] = value;
125
126        applyFunctionByKey(key, value);
127    });
128
129    // Set the active profile.
130    state.activeProfile = profileId;
131    saveStateToLocalStorage();
132}
133
134// Deactivate a specific profile by resetting its settings.
135function deactivateProfile(profileId) {
136    const settings = profiles[profileId];
137
138    Object.keys(settings).forEach((key) => {
139        if (state[key] > 0) {
140            switch (key) {
141                case 'contrast':
142                    Accessibility.resetContrast();
143                    break;
144                case 'saturation':
145                    Accessibility.resetSaturation();
146                    break;
147                case 'screenReader':
148                    Accessibility.resetScreenReader();
149                    break;
150                case 'highlightLinks':
151                    Accessibility.resetHighlightToLinks();
152                    break;
153                case 'highlightHeadings':
154                    Accessibility.resetHighlightToHeadings();
155                    break;
156                case 'biggerText':
157                    Accessibility.resetBiggerText();
158                    break;
159                case 'textSpacing':
160                    Accessibility.resetTextSpacing();
161                    break;
162                case 'hideImages':
163                    Accessibility.resetHideImages();
164                    break;
165                case 'dyslexiaFont':
166                    Accessibility.resetDyslexiaFont();
167                    break;
168                case 'cursor':
169                    Accessibility.resetCursorState();
170                    break;
171                case 'lineHeight':
172                    Accessibility.resetLineHeight();
173                    break;
174                case 'textAlign':
175                    Accessibility.resetTextAlign();
176                    break;
177                case 'pauseAnimations':
178                    Accessibility.resetPauseAnimations();
179                    break;
180                case 'readMode':
181                    Accessibility.resetReadMode();
182                    break;
183                case 'muteSounds':
184                    Accessibility.resetMuteSounds();
185                    break;
186                case 'linkNotices':
187                    Accessibility.resetLinkNotices();
188                    break;
189                case 'dictionary':
190                    Accessibility.resetDictionary();
191                    break;
192                default:
193                    console.warn(`No reset function defined for ${key}`);
194            }
195
196            state[key] = 0;
197        }
198    });
199
200    // Clear the active profile.
201    state.activeProfile = null;
202
203    saveStateToLocalStorage();
204
205     // Update UI button state.
206    const button = document.getElementById(profileId);
207    if (button) {
208        button.setAttribute("aria-pressed", false);
209        button.classList.remove("aw-button--active");
210    }
211}
212
213// Toggle a profile on or off.
214function toggleProfile(profileId) {
215    if (state.activeProfile === profileId) {
216        deactivateProfile(profileId);
217    } else {
218        if (state.activeProfile) deactivateProfile(state.activeProfile);
219        activateProfile(profileId);
220    }
221}
222
223// Initialize profile buttons and reset functionality.
224function initializeProfiles() {
225    document.querySelectorAll(".aw-button--profile").forEach((button) => {
226        button.addEventListener("click", () => {
227            const profileId = button.id;
228            toggleProfile(profileId);
229
230            // Update the button states based on the active profile.
231            document.querySelectorAll(".aw-button--profile").forEach((btn) => {
232                const isActive = state.activeProfile === btn.id;
233                btn.setAttribute("aria-pressed", isActive);
234                btn.classList.toggle("aw-button--active", isActive);
235            });
236        });
237    });
238
239     // Add event listener to the reset button.
240    const resetButton = document.getElementById("aw_reset");
241    resetButton.addEventListener("click", () => {
242        if (state.activeProfile) deactivateProfile(state.activeProfile);
243
244        // Reset all profile button states.
245        document.querySelectorAll(".aw-button--profile").forEach((btn) => {
246            btn.setAttribute("aria-pressed", false);
247            btn.classList.remove("aw-button--active");
248        });
249    });
250}
251
252// Initialize profiles and apply saved settings on page load.
253document.addEventListener("DOMContentLoaded", () => {
254    initializeProfiles();
255
256    if (state.activeProfile) {
257        activateProfile(state.activeProfile);
258
259        document.querySelectorAll(".aw-button--profile").forEach((btn) => {
260            const isActive = state.activeProfile === btn.id;
261            btn.setAttribute("aria-pressed", isActive);
262            btn.classList.toggle("aw-button--active", isActive);
263        });
264    }
265});
266
267function saveStateToLocalStorage() {
268    localStorage.setItem(stateKey, JSON.stringify(state));
269}
270
271// Modal Window
272function initializeModal({
273    modalId, 
274    toggleButtonId, 
275    closeButtonId
276}) {
277    const modal = document.getElementById(modalId);
278    const toggleButton = document.getElementById(toggleButtonId);
279    const closeButton = document.getElementById(closeButtonId);
280
281    document.addEventListener('keydown', (e) => {
282        if (e.ctrlKey && e.key === 'u') {
283            e.preventDefault();
284            toggleModal();
285        }
286    });
287
288    toggleButton.addEventListener('click', () => {
289        toggleModal();
290    });
291
292    closeButton.addEventListener('click', () => {
293        toggleModal();
294    });
295
296    document.addEventListener('click', (e) => {
297        const isInsideModal = modal.contains(e.target);
298        const isToggleButton = toggleButton.contains(e.target);
299
300        if (!isInsideModal && !isToggleButton && !modal.classList.contains('aw-modal-hidden')) {
301            toggleModal();
302        }
303    });
304
305    function toggleModal() {
306        const isHidden = modal.classList.contains('aw-modal-hidden');
307        const focusableElements = modal.querySelectorAll(
308            'button, [href], input, select, textarea, [tabindex]:not
308([tabindex="-1"]):not(svg):not(svg *)'
309        );
310        const firstFocusableElement = focusableElements[0];
311        const lastFocusableElement = focusableElements[focusableElements.length - 1];
312        const closeButton = document.getElementById('aw-close-modal'); // Use the correct close button ID.
313    
314        if (isHidden) {
315            modal.classList.remove('aw-modal-hidden');
316            modal.setAttribute('aria-hidden', 'false');
317            toggleButton.setAttribute('aria-expanded', 'true');
318            modal.setAttribute('aria-label', 'Accessibility Menu opened');
319            if (closeButton) {
320                closeButton.focus(); // Focus the close button when the modal is opened.
321            }
322        } else {
323            modal.classList.add('aw-modal-hidden');
324            modal.setAttribute('aria-hidden', 'true');
325            toggleButton.setAttribute('aria-expanded', 'false');
326            modal.setAttribute('aria-label', 'Accessibility Menu closed');
327            toggleButton.focus(); // Return focus to the toggle button when the modal is closed.
328        }
329    
330        modal.addEventListener('keydown', (e) => {
331            if (e.key === 'Tab') {
332                if (e.shiftKey) { // Shift + Tab
333                    if (document.activeElement === firstFocusableElement) {
334                        e.preventDefault();
335                        lastFocusableElement.focus();
336                    }
337                } else { // Tab
338                    if (document.activeElement === lastFocusableElement) {
339                        e.preventDefault();
340                        firstFocusableElement.focus();
341                    }
342                }
343            }
344    
345            if (e.key === 'Escape') { // Close the modal on Escape key press.
346                modal.classList.add('aw-modal-hidden');
347                modal.setAttribute('aria-hidden', 'true');
348                toggleButton.setAttribute('aria-expanded', 'false');
349                modal.setAttribute('aria-label', 'Accessibility Menu closed');
350                toggleButton.focus();
351            }
352        });
353    }       
354}
355
356// Toggle Active Class and Press Arial
357function toggleActiveClass(buttonId, isActive) {
358    const button = document.getElementById(buttonId);
359    if (isActive) {
360        button.classList.add('aw-button--active');
361        button.setAttribute('aria-pressed', 'true');
362    } else {
363        button.classList.remove('aw-button--active');
364        button.setAttribute('aria-pressed', 'false');
365    }
366}
367
368// Toggle Aria Label
369function updateAriaLabel(buttonId, ariaLabels, state) {
370    const button = document.getElementById(buttonId);
371    button.setAttribute('aria-label', ariaLabels[state]);
372}
373
374// Toggle States
375function toggleState(stateKey, maxStates) {
376    if (maxStates <= 1) {
377        console.warn(`Invalid maxStates value for ${stateKey}.`);
378        return state[stateKey];
379    }
380    state[stateKey] = (state[stateKey] + 1) % maxStates;
381    saveStateToLocalStorage();
382    return state[stateKey];
383}
384
385// Update Button State
386function updateButtonState(buttonId, isActive, ariaLabels, currentState, stateLabelId = null, stateLabels = null) {
387    const button = document.getElementById(buttonId);
388    if (button) {
389        // Update active class and aria-pressed attribute
390        button.classList.toggle('aw-button--active', isActive);
391        button.setAttribute('aria-pressed', isActive);
392        button.setAttribute('aria-label', ariaLabels[currentState]);
393    }
394
395    // Optionally update the state label text if provided
396    if (stateLabelId && stateLabels) {
397        const stateLabel = document.getElementById(stateLabelId);
398        if (stateLabel) {
399            stateLabel.textContent = stateLabels[currentState];
400        }
401    }
402}
403
404// Initialize the screen reader functionality.
405function initializeScreenReader(savedState = 0) {
406    // Check if the browser supports speech synthesis.
407    if (!window.speechSynthesis) {
408        console.warn('Speech synthesis is not supported in this browser.');
409        return;
410    }
411
412    // Attach methods to the Accessibility object for external access.
413    Accessibility.enableScreenReader = enableScreenReader;
414    Accessibility.disableScreenReader = disableScreenReader;
415    Accessibility.resetScreenReader = resetScreenReader;
416
417    // Define constants for the screen reader functionality.
418    const screenReaderButton = document.getElementById('screen-reader');
419    const screenReaderSpeeds = [0, 1, 1.2, 0.75]; // Speed options for the screen reader.
420    const labels = [
421        krakenAccessibilityTranslations.screenReader, 
422        krakenAccessibilityTranslations.normalReading, 
423        krakenAccessibilityTranslations.fastReading, 
424        krakenAccessibilityTranslations.slowReading
425    ];
426    const ariaLabels = [
427        krakenAccessibilityTranslations.screenReaderDescription,
428        krakenAccessibilityTranslations.normalReadingActivated,
429        krakenAccessibilityTranslations.fastReadingActivated,
430        krakenAccessibilityTranslations.slowReadingActivated
431    ];
432    const focusableSelectors = `
433        [aria-label], [aria-labelledby], [aria-describedby], 
434        h1, h2, h3, h4, h5, h6, 
435        p, strong, ul, li, blockquote, address,
436        header, nav, main, footer, article, section, aside, span,
437        a, button, input, textarea, select, img
438    `; // Elements the screen reader can focus on.
439    const landmarks = ['header', 'nav', 'main', 'footer', 'article', 'section', 'aside']; // Landmark elements.
440    const speechSynthesis = window.speechSynthesis;
441    const utterance = new SpeechSynthesisUtterance();
442
443    // Initialize the screen reader state if saved.
444    if (savedState > 0) {
445        updateButtonState(
446            'screen-reader',             // Button ID
447            true,                        // Is Active
448            ariaLabels,                  // ARIA Labels
449            savedState,                  // Current State
450            'screen-reader-state',       // State Label ID
451            labels                       // State Labels
452        );
453
454        enableScreenReader(screenReaderSpeeds[savedState]); // Enable screen reader with the saved speed.
455    }
456    
457
458    // Add event listener to the screen reader button.
459    screenReaderButton.addEventListener('click', () => {
460        const currentState = toggleState('screenReader', labels.length);
461        updateButtonState(
462            'screen-reader',               // Button ID
463            currentState > 0,              // Is Active
464            ariaLabels,                    // ARIA Labels
465            currentState,                  // Current State
466            'screen-reader-state',         // Optional State Label ID
467            labels                         // Optional State Labels
468        );
469
470        if (currentState === 0) {
471            disableScreenReader();
472        } else {
473            enableScreenReader(screenReaderSpeeds[currentState]);
474        }
475
476        saveStateToLocalStorage(); // Save the current state.
477    });
478
479    // Enable the screen reader and set the reading speed.
480    function enableScreenReader(speed) {
481        disableScreenReader(); // Cancel any ongoing speech synthesis.
482        utterance.rate = speed;
483
484        // Add event listeners for focus and click events.
485        document.addEventListener('focusin', handleFocus);
486        document.addEventListener('click', handleClick);
487        document.addEventListener('touchstart', handleClick);
488    }
489
490    // Disable the screen reader and remove event listeners.
491    function disableScreenReader() {
492        speechSynthesis.cancel(); // Stop any ongoing speech.
493        resetHighlighting(); // Remove any element highlighting.
494        document.removeEventListener('focusin', handleFocus);
495        document.removeEventListener('click', handleClick);
496        document.removeEventListener('touchstart', handleClick);
497    }
498
499    // Reset the screen reader to its initial state.
500    function resetScreenReader() {
501        disableScreenReader();
502        state.screenReader = 0;
503        document.getElementById('screen-reader-state').textContent = labels[0];
504        toggleActiveClass('screen-reader', false);
505        saveStateToLocalStorage();
506    }
507
508    // Handle focus events and announce focused elements.
509    function handleFocus(event) {
510        const element = event.target.closest(focusableSelectors);
511        if (element) {
512            announceElement(element);
513        }
514    }
515
516    // Handle click and touch events to announce elements.
517    function handleClick(event) {
518        const element = event.target.closest(focusableSelectors);
519        const landmark = event.target.closest(landmarks.join(','));
520
521        if (landmark && landmark === element) {
522            announceElement(landmark);
523        } else if (element) {
524            announceElement(element);
525        }
526    }
527
528    // Announce a given element using speech synthesis.
529    function announceElement(element) {
530        speechSynthesis.cancel(); // Stop ongoing announcements.
531        resetHighlighting(); // Clear previous highlights.
532        highlightElement(element); // Highlight the current element.
533
534        const tagName = element.tagName.toLowerCase();
535        const ariaLabel = element.getAttribute('aria-label');
536        const ariaLabelledBy = element.getAttribute('aria-labelledby');
537        const ariaDescribedBy = element.getAttribute('aria-describedby');
538
539        const labelText = ariaLabel || (ariaLabelledBy && document.getElementById(ariaLabelledBy)?.textContent.trim()) || '';
540        const descriptionText = ariaDescribedBy && document.getElementById(ariaDescribedBy)?.textContent.trim();
541
542        let announcement = '';
543
544        // Determine the announcement text based on the element type.
545        if (landmarks.includes(tagName)) {
546            announcement = `${labelText ? labelText + ', ' : ''}${tagName} landmark`;
547        } else if (/^h[1-6]$/.test(tagName)) {
548            announcement = `${element.textContent.trim()}, header`;
549        } else if (tagName === 'a') {
550            announcement = `${labelText ? labelText + ', ' : ''}${element.textContent.trim()}, link`;
551        } else if (tagName === 'button') {
552            announcement = `${labelText ? labelText + ', ' : ''}${element.textContent.trim()}, button`;
553        } else if (['input', 'textarea', 'select'].includes(tagName)) {
554            announcement = `${labelText || 'Field'}, ${getFieldType(element)}${descriptionText ? ', ' + descriptionText : ''}`;
555        } else if (tagName === 'img') {
556            const altText = element.getAttribute('alt');
557            announcement = altText ? altText.trim() : 'Image without description';
558        } else {
559            announcement = element.textContent.trim();
560        }
561
562        // Speak the announcement text if available.
563        if (announcement) {
564            utterance.text = announcement;
565            speechSynthesis.speak(utterance);
566        }
567    }
568
569    // Determine the type of input field for announcements.
570    function getFieldType(element) {
571        const type = element.getAttribute('type');
572        if (element.tagName.toLowerCase() === 'textarea') return 'textarea field';
573        if (element.tagName.toLowerCase() === 'select') return 'select dropdown';
574        if (type) {
575            switch (type) {
576                case 'text':
577                    return 'text input field';
578                case 'email':
579                    return 'email input field';
580                case 'password':
581                    return 'password input field';
582                case 'checkbox':
583                    return 'checkbox field';
584                case 'radio':
585                    return 'radio button';
586            }
587        }
588        return 'input field';
589    }
590
591    // Highlight an element visually.
592    function highlightElement(element) {
593        element.classList.add('aw-highlight');
594    }
595
596    // Remove highlighting from all elements.
597    function resetHighlighting() {
598        document.querySelectorAll('.aw-highlight').forEach(el => el.classList.remove('aw-highlight'));
599    }
600}
601
602// Initialize the contrast functionality.
603function initializeContrast(savedState = 0) {
604    // Attach methods to the Accessibility object for external access.
605    Accessibility.enableContrast = enableContrast;
606    Accessibility.disableContrast = disableContrast;
607    Accessibility.resetContrast = resetContrast;
608
609    // Define constants for the contrast functionality.
610    const contrastButton = document.getElementById('contrast');
611    const contrastStates = [
612        krakenAccessibilityTranslations.contrast,
613        krakenAccessibilityTranslations.invertedColors,
614        krakenAccessibilityTranslations.darkContrast,
615        krakenAccessibilityTranslations.lightContrast
616    ]; 
617    const ariaLabels = [
618        krakenAccessibilityTranslations.contrastDescription,
619        krakenAccessibilityTranslations.invertColorsActivated,
620        krakenAccessibilityTranslations.darkContrastActivated,
621        krakenAccessibilityTranslations.lightContrastActivated
622    ];
623
624    const textSelectors = '*:not(#aw-widget):not(#aw-widget *)'; // Selectors for text elements.
625    const linkSelectors = 'a:not(#aw-widget a)'; // Selectors for link elements.
626    const originalStyles = new Map(); // Store original styles for reset purposes.
627
628    // Initialize the contrast state if saved.
629    if (savedState > 0) {
630        toggleActiveClass('contrast', true);
631        updateAriaLabel('contrast', ariaLabels, savedState);
632        enableContrast(savedState);
633        document.getElementById('contrast-state').textContent = contrastStates[savedState];
634    }
635
636    // Add event listener to the contrast button.
637    contrastButton.addEventListener('click', () => {
638        const currentState = toggleState('contrast', contrastStates.length);
639        updateButtonState(
640            'contrast',                 // Button ID
641            currentState > 0,           // Is Active
642            ariaLabels,                 // ARIA Labels
643            currentState,               // Current State
644            'contrast-state',           // State Label ID
645            contrastStates              // State Labels
646        );
647        
648        saveStateToLocalStorage(); // Save the current state.
649        enableContrast(currentState);
650    });
651
652    // Enable a specific contrast mode based on the state.
653    function enableContrast(state) {
654        const htmlTag = document.documentElement; // Reference to the HTML element.
655
656        if (state === 0) {
657            disableContrast(); // Reset contrast if state is 0.
658            return;
659        }
660
661        if (state === 1) { // Inverted Colors mode.
662            htmlTag.classList.add('aw-modifier__invert');
663            htmlTag.style.backgroundColor = '';
664        } else {
665            htmlTag.classList.remove('aw-modifier__invert');
666
667            // Apply styles to text elements based on contrast mode.
668            document.querySelectorAll(textSelectors).forEach(el => {
669                if (!originalStyles.has(el)) {
670                    originalStyles.set(el, {
671                        backgroundColor: el.style.backgroundColor,
672                        borderColor: el.style.borderColor,
673                        color: el.style.color,
674                    });
675                }
676
677                if (state === 2) { // Dark Contrast mode.
678                    el.style.backgroundColor = 'rgb(0, 0, 0)';
679                    el.style.borderColor = 'rgb(255, 255, 255)';
680                    el.style.color = 'rgb(80, 208, 160)';
681                } else if (state === 3) { // Light Contrast mode.
682                    el.style.backgroundColor = 'rgb(255, 255, 255)';
683                    el.style.borderColor = 'rgb(0, 0, 0)';
684                    el.style.color = 'rgb(0, 0, 0)';
685                }
686
687                el.setAttribute('data-contrast-modified', 'true');
688            });
689
690            // Apply styles to link elements based on contrast mode.
691            document.querySelectorAll(linkSelectors).forEach(link => {
692                if (!originalStyles.has(link)) {
693                    originalStyles.set(link, {
694                        backgroundColor: link.style.backgroundColor,
695                        color: link.style.color,
696                    });
697                }
698
699                if (state === 2) { // Dark Contrast mode.
700                    link.style.backgroundColor = 'rgb(0, 0, 0)';
701                    link.style.borderColor = 'rgb(255, 255, 255)';
702                    link.style.color = 'rgb(252, 255, 60)';
703                } else if (state === 3) { // Light Contrast mode.
704                    link.style.backgroundColor = 'rgb(255, 255, 255)';
705                    link.style.borderColor = 'rgb(0, 0, 0)';
706                    link.style.color = 'rgb(0, 0, 211)';
707                }
708
709                link.setAttribute('data-contrast-modified', 'true');
710            });
711        }
712    }
713
714    // Reset contrast settings to default.
715    function resetContrast() {
716        disableContrast();
717        state.contrast = 0; 
718        document.getElementById('contrast-state').textContent = contrastStates[0];
719        toggleActiveClass('contrast', false);
720        saveStateToLocalStorage();
721    }
722
723    // Disable all contrast modifications and restore original styles.
724    function disableContrast() {
725        const htmlTag = document.documentElement;
726        htmlTag.classList.remove('aw-modifier__invert');
727        htmlTag.style.backgroundColor = '';
728
729        // Restore original styles for text elements.
730        document.querySelectorAll(textSelectors).forEach(el => {
731            if (el.getAttribute('data-contrast-modified') === 'true') {
732                const original = originalStyles.get(el);
733                if (original) {
734                    Object.keys(original).forEach(prop => {
735                        el.style[prop] = original[prop];
736                    });
737                }
738                el.removeAttribute('data-contrast-modified');
739            }
740        });
741
742        // Restore original styles for link elements.
743        document.querySelectorAll(linkSelectors).forEach(link => {
744            if (link.getAttribute('data-contrast-modified') === 'true') {
745                const original = originalStyles.get(link);
746                if (original) {
747                    Object.keys(original).forEach(prop => {
748                        link.style[prop] = original[prop];
749                    });
750                }
751                link.removeAttribute('data-contrast-modified');
752            }
753        });
754
755        // Reapply highlight settings if active.
756        if (state.highlightLinks) {
757            applyHighlightToLinks(true);
758        }
759        if (state.highlightHeadings) {
760            enableHighlightToHeadings(true);
761        }
762    }
763
764    // Highlight or unhighlight link elements.
765    function applyHighlightToLinks(isHighlighted) {
766        document.querySelectorAll(linkSelectors).forEach(link => {
767            link.style.backgroundColor = isHighlighted ? '#000000' : '';
768            link.style.color = isHighlighted ? '#fff300' : '';
769        });
770    }
771
772    // Highlight or unhighlight heading elements.
773    function enableHighlightToHeadings(isHighlighted) {
774        document.querySelectorAll('h1, h2, h3, h4, h5, h6').forEach(heading => {
775            const hasAnchor = heading.querySelector('a');
776
777            if (hasAnchor) {
778                hasAnchor.style.backgroundColor = isHighlighted ? '#000000' : '';
779                hasAnchor.style.color = isHighlighted ? '#ff9900' : '';
780            } else {
781                heading.style.backgroundColor = isHighlighted ? '#000000' : '';
782                heading.style.color = isHighlighted ? '#ff9900' : '';
783            }
784        });
785    }
786}
787
788// Initialize the highlight links functionality.
789function initializeHighlightLinks(savedState = 0) {
790    // Attach methods to the Accessibility object for external access.
791    Accessibility.enableHighlightToLinks = enableHighlightToLinks;
792    Accessibility.resetHighlightToLinks = resetHighlightToLinks;
793
794    // Define constants for the highlight links functionality.
795    const highlightLinksButton = document.getElementById('highlight-links'); // Button to toggle link highlighting.
796    const highlightStates = [
797        krakenAccessibilityTranslations.highlightLinks,
798        krakenAccessibilityTranslations.linksHighlighted
799    ];
800    const linkAriaLabels = [
801        krakenAccessibilityTranslations.highlightLinksDescription,
802        krakenAccessibilityTranslations.linksHighlightedState
803    ]; 
804
805    // Initialize the highlight links state if saved.
806    if (savedState > 0) {
807        updateButtonState(
808            'highlight-links',          // Button ID
809            true,                       // Is Active
810            linkAriaLabels,             // ARIA Labels
811            savedState,                 // Current State
812            'highlight-links-state',    // State Label ID
813            highlightStates             // State Labels
814        );
815
816        enableHighlightToLinks(true); // Enable highlighting if a saved state exists.
817    }
818
819    // Add event listener to the highlight links button.
820    highlightLinksButton.addEventListener('click', () => {
821        const currentState = toggleState('highlightLinks', highlightStates.length);
822
823        updateButtonState(
824            'highlight-links',          // Button ID
825            currentState > 0,           // Is Active
826            linkAriaLabels,             // ARIA Labels
827            currentState,               // Current State
828            'highlight-links-state',    // State Label ID
829            highlightStates             // State Labels
830        );        
831
832        enableHighlightToLinks(currentState > 0); // Enable or disable highlighting based on state.
833
834        saveStateToLocalStorage(); // Save the current state.
835    });
836
837    // Enable or disable link highlighting based on the provided flag.
838    function enableHighlightToLinks(isHighlighted) {
839        document.querySelectorAll('a').forEach(link => {
840            link.style.backgroundColor = isHighlighted ? '#000000' : ''; // Highlight background color.
841            link.style.color = isHighlighted ? '#fff300' : ''; // Highlight text color.
842        });
843    }
844
845    // Reset link highlighting to default state.
846    function resetHighlightToLinks(isHighlighted) {
847        enableHighlightToLinks(false); // Disable link highlighting.
848        state.highlightLinks = 0; // Reset state.
849        toggleActiveClass('highlight-links', false);
850        updateAriaLabel('highlight-links', linkAriaLabels, 0);
851        document.getElementById('highlight-links-state').textContent = highlightStates[0];
852
853        saveStateToLocalStorage(); // Save the reset state.
854    }
855}
856
857// Initialize the highlight headings functionality.
858function initializeHighlightHeadings(savedState = 0) {
859    // Attach methods to the Accessibility object for external access.
860    Accessibility.enableHighlightToHeadings = enableHighlightToHeadings;
861    Accessibility.resetHighlightToHeadings = resetHighlightToHeadings; 
862
863    // Define constants for the highlight headings functionality.
864    const highlightHeadingsButton = document.getElementById('highlight-headings'); // Button to toggle heading highlighting.
865    const highlightStates = [
866        krakenAccessibilityTranslations.highlightHeadings,
867        krakenAccessibilityTranslations.headingsHighlighted
868    ];
869    const headingAriaLabels = [
870        krakenAccessibilityTranslations.highlightHeadingsDescription,
871        krakenAccessibilityTranslations.headingsHighlightedState
872    ];
873
874    // Initialize the highlight headings state if saved.
875    if (savedState > 0) {
876        updateButtonState(
877            'highlight-headings',       // Button ID
878            true,                       // Is Active
879            headingAriaLabels,          // ARIA Labels
880            savedState,                 // Current State
881            'highlight-headings-state', // State Label ID
882            highlightStates             // State Labels
883        );
884        
885        enableHighlightToHeadings(true); // Enable highlighting if a saved state exists.
886    }
887
888    // Add event listener to the highlight headings button.
889    highlightHeadingsButton.addEventListener('click', () => {
890        const currentState = toggleState('highlightHeadings', highlightStates.length);
891        updateButtonState(
892            'highlight-headings',       // Button ID
893            currentState > 0,           // Is Active
894            headingAriaLabels,          // ARIA Labels
895            currentState,               // Current State
896            'highlight-headings-state', // State Label ID
897            highlightStates             // State Labels
898        );        
899
900        enableHighlightToHeadings(currentState > 0); // Enable or disable highlighting based on state.
901
902        saveStateToLocalStorage(); // Save the current state.
903    });
904
905    // Enable or disable heading highlighting based on the provided flag.
906    function enableHighlightToHeadings(isHighlighted) {
907        document.querySelectorAll('h1, h2, h3, h4, h5, h6').forEach(heading => {
908            const hasAnchor = heading.querySelector('a'); // Check if the heading contains an anchor.
909
910            if (hasAnchor) {
911                hasAnchor.style.backgroundColor = isHighlighted ? '#000000' : ''; // Highlight background color for anchor.
912                hasAnchor.style.color = isHighlighted ? '#ff9900' : ''; // Highlight text color for anchor.
913            } else {
914                heading.style.backgroundColor = isHighlighted ? '#000000' : ''; // Highlight background color for heading.
915                heading.style.color = isHighlighted ? '#ff9900' : ''; // Highlight text color for heading.
916            }
917        });
918    }
919
920    // Reset heading highlighting to default state.
921    function resetHighlightToHeadings(){
922        enableHighlightToHeadings(false); // Disable heading highlighting.
923        state.highlightHeadings = 0; // Reset state.
924        toggleActiveClass('highlight-headings', false);
925        updateAriaLabel('highlight-headings', headingAriaLabels, 0);
926        document.getElementById('highlight-headings-state').textContent = highlightStates[0];
927
928        saveStateToLocalStorage(); // Save the reset state.
929    }
930}
931
932// Initialize the bigger text functionality.
933function initializeBiggerText(savedState = 0) {
934    // Attach methods to the Accessibility object for external access.
935    Accessibility.enableBiggerTexts = enableBiggerText;
936    Accessibility.resetBiggerText = resetBiggerText; 
937
938    // Define constants for the bigger text functionality.
939    const biggerTextButton = document.getElementById('bigger-text'); // Button to toggle bigger text.
940    const biggerTextStates = [
941        krakenAccessibilityTranslations.biggerText,
942        krakenAccessibilityTranslations.bigTextLevel1,
943        krakenAccessibilityTranslations.bigTextLevel2,
944        krakenAccessibilityTranslations.bigTextLevel3,
945        krakenAccessibilityTranslations.bigTextLevel4
946    ];
947    const biggerTextAriaLabels = [
948        krakenAccessibilityTranslations.biggerTextDescription,
949        krakenAccessibilityTranslations.bigTextLevel1Activated,
950        krakenAccessibilityTranslations.bigTextLevel2Activated,
951        krakenAccessibilityTranslations.bigTextLevel3Activated,
952        krakenAccessibilityTranslations.bigTextLevel4Activated
953    ]; 
954    const zoomClasses = [
955        '',                    // Default
956        'aw-modifier__zoom-1', // 1.2x
957        'aw-modifier__zoom-2', // 1.3x
958        'aw-modifier__zoom-3', // 1.5x
959        'aw-modifier__zoom-4'  // 1.6x
960    ];
961
962    // Initialize the bigger text state if saved.
963    if (savedState > 0) {
964        updateButtonState(
965            'bigger-text',              // Button ID
966            true,                       // Is Active
967            biggerTextAriaLabels,       // ARIA Labels
968            savedState,                 // Current State
969            'bigger-text-state',        // State Label ID
970            biggerTextStates            // State Labels
971        );
972        enableBiggerText(savedState); // Enable text resizing based on saved state.
973    }
974    
975    // Add event listener to the bigger text button.
976    biggerTextButton.addEventListener('click', () => {
977        const currentState = toggleState('biggerText', biggerTextStates.length);
978        updateButtonState(
979            'bigger-text',              // Button ID
980            currentState > 0,           // Is Active
981            biggerTextAriaLabels,       // ARIA Labels
982            currentState,               // Current State
983            'bigger-text-state',        // State Label ID
984            biggerTextStates            // State Labels
985        );        
986
987        enableBiggerText(currentState); // Enable or disable text resizing.
988
989        saveStateToLocalStorage(); // Save the current state.
990    });
991
992    // Enable or disable text resizing by adding/removing a class.
993    function enableBiggerText(level) {
994        // Remove all zoom classes, but filter out empty strings to prevent errors
995        document.body.classList.remove(...zoomClasses.filter(cls => cls));
996
997        // Apply the new zoom class if level is greater than 0
998        if (level > 0) {
999            document.body.classList.add(zoomClasses[level]);
1000        }
1001    }
1002
1003    // Reset text resizing to default state.
1004    function resetBiggerText() {
1005        enableBiggerText(0); // Reset text size to default.
1006        state.biggerText = 0; // Reset state.
1007        toggleActiveClass('bigger-text', false);
1008        updateAriaLabel('bigger-text', biggerTextAriaLabels, 0);
1009        document.getElementById('bigger-text-state').textContent = biggerTextStates[0];
1010
1011        saveStateToLocalStorage(); // Save the reset state.
1012    }
1013}
1014
1015// Initialize the text spacing functionality.
1016function initializeTextSpacing(savedState = 0) {
1017    // Attach methods to the Accessibility object for external access.
1018    Accessibility.resetTextSpacing = resetTextSpacing;
1019
1020    // Define constants for the text spacing functionality.
1021    const textSpacingButton = document.getElementById('text-spacing'); // Button to toggle text spacing.
1022    const spacingClasses = ['aw-modifier__lp-1', 'aw-modifier__lp-2', 'aw-modifier__lp-3']; // CSS classes for spacing levels.
1023    const spacingLabels = [
1024        krakenAccessibilityTranslations.changeTextSpacing,
1025        krakenAccessibilityTranslations.slightSpacing,
1026        krakenAccessibilityTranslations.moderateSpacing,
1027        krakenAccessibilityTranslations.heavySpacing
1028    ]; 
1029    const ariaLabels = [
1030        krakenAccessibilityTranslations.changeTextSpacingDescription,
1031        krakenAccessibilityTranslations.slightSpacingActivated,
1032        krakenAccessibilityTranslations.moderateSpacingActivated,
1033        krakenAccessibilityTranslations.heavySpacingActivated
1034    ];
1035
1036    // Initialize the text spacing state if saved.
1037    if (savedState > 0) {
1038        updateButtonState(
1039            'text-spacing',            // Button ID
1040            true,                      // Is Active
1041            ariaLabels,                // ARIA Labels
1042            savedState,                // Current State
1043            'text-spacing-state',      // State Label ID
1044            spacingLabels              // State Labels
1045        );
1046        document.documentElement.classList.add(spacingClasses[savedState - 1]); // Apply saved spacing class.
1047    }
1048
1049    // Add event listener to the text spacing button.
1050    textSpacingButton.addEventListener('click', () => {
1051        const currentState = toggleState('textSpacing', spacingLabels.length); 
1052        const isActive = currentState > 0; // Check if text spacing should be enabled.
1053        updateButtonState(
1054            'text-spacing',          // Button ID
1055            currentState > 0,        // Is Active
1056            ariaLabels,              // ARIA Labels
1057            currentState,            // Current State
1058            null,                    // No State Label ID (if none exists)
1059            null                     // No State Labels (if none exist)
1060        );        
1061
1062        document.documentElement.classList.remove(...spacingClasses); // Remove all spacing classes.
1063
1064        if (isActive) {
1065            document.documentElement.classList.add(spacingClasses[currentState - 1]); // Add the current spacing class.
1066        }
1067
1068        document.getElementById('text-spacing-state').textContent = spacingLabels[currentState];
1069
1070        saveStateToLocalStorage(); // Save the current state.
1071    });
1072
1073    // Reset text spacing to default state.
1074    function resetTextSpacing() {
1075        document.documentElement.classList.remove(...spacingClasses); // Remove all spacing classes.
1076        state.textSpacing = 0; // Reset state.
1077        toggleActiveClass('text-spacing', false);
1078        updateAriaLabel('text-spacing', ariaLabels, 0);
1079        document.getElementById('text-spacing-state').textContent = spacingLabels[0];
1080
1081        saveStateToLocalStorage(); // Save the reset state.
1082    }
1083}
1084
1085// Initialize the hide images functionality.
1086function initializeHideImages(savedState = 0) {
1087    // Attach methods to the Accessibility object for external access.
1088    Accessibility.enableHideImages = enableHideImages;
1089    Accessibility.resetHideImages = resetHideImages;
1090
1091    // Define constants for the hide images functionality.
1092    const hideImagesButton = document.getElementById('hide-images'); // Button to toggle image visibility.
1093    const hideImagesStates = [
1094        krakenAccessibilityTranslations.hideImages,
1095        krakenAccessibilityTranslations.imagesHidden
1096    ];
1097    const hideImagesAriaLabels = [
1098        krakenAccessibilityTranslations.hideImagesDescription,
1099        krakenAccessibilityTranslations.imagesHiddenState        
1100    ]; 
1101
1102    const originalBackgroundImages = new Map(); // Store original background images for reset purposes.
1103
1104    // Initialize the hide images state if saved.
1105    if (savedState === 1) {
1106        updateButtonState(
1107            'hide-images',             // Button ID
1108            true,                      // Is Active
1109            hideImagesAriaLabels,      // ARIA Labels
1110            savedState,                // Current State
1111            'hide-images-state',       // State Label ID
1112            hideImagesStates           // State Labels
1113        );
1114        enableHideImages(true); // Enable hiding images based on saved state.
1115    }    
1116
1117    // Add event listener to the hide images button.
1118    hideImagesButton.addEventListener('click', () => {
1119        const currentState = toggleState('hideImages', hideImagesStates.length);
1120        updateButtonState(
1121            'hide-images',              // Button ID
1122            currentState > 0,           // Is Active
1123            hideImagesAriaLabels,       // ARIA Labels
1124            currentState,               // Current State
1125            'hide-images-state',        // State Label ID
1126            hideImagesStates            // State Labels
1127        );
1128        
1129        enableHideImages(currentState === 1); // Enable or disable hiding images based on state.
1130
1131        saveStateToLocalStorage(); // Save the current state.
1132    });
1133
1134    // Enable or disable hiding images.
1135    function enableHideImages(hide) {
1136        const elements = document.querySelectorAll('*'); // Select all elements on the page.
1137
1138        elements.forEach(element => {
1139            // Skip elements inside .aw-widget
1140            if (element.closest('.aw-widget')) {
1141                return;
1142            }
1143
1144            if (element.tagName.toLowerCase() === 'img' || element.tagName.toLowerCase() === 'svg') {
1145                element.style.visibility = hide ? 'hidden' : 'visible'; // Hide or show image elements while keeping their space.
1146            }
1147
1148            const computedStyle = getComputedStyle(element);
1149            const backgroundImage = computedStyle.backgroundImage; // Get background image style.
1150
1151            if (hide) {
1152                if (!originalBackgroundImages.has(element) && backgroundImage !== 'none') {
1153                    originalBackgroundImages.set(element, backgroundImage); // Store the original background image.
1154                }
1155                element.style.backgroundImage = 'none'; // Hide background images.
1156            } else {
1157                if (originalBackgroundImages.has(element)) {
1158                    element.style.backgroundImage = originalBackgroundImages.get(element); // Restore background images.
1159                }
1160            }
1161        });
1162
1163        if (!hide) {
1164            originalBackgroundImages.clear(); // Clear stored background images when not hiding.
1165        }
1166    }
1167
1168    // Reset image visibility to default state.
1169    function resetHideImages () {
1170        enableHideImages(false); // Disable hiding images.
1171        state.hideImages = 0; // Reset state.
1172        toggleActiveClass('hide-images', false);
1173        updateAriaLabel('hide-images', hideImagesAriaLabels, 0);
1174        document.getElementById('hide-images-state').textContent = hideImagesStates[0];
1175
1176        saveStateToLocalStorage(); // Save the reset state.
1177    }
1178}
1179
1180// Initialize the Dyslexia Friendly Font functionality.
1181function initializeDyslexiaFont(savedState = 0) {
1182    // Attach methods to the Accessibility object for external access.
1183    Accessibility.enableDyslexiaFont = enableDyslexiaFont;
1184    Accessibility.resetDyslexiaFont = resetDyslexiaFont;
1185
1186    // Define constants for the Dyslexia Font functionality.
1187    const dyslexiaFontButton = document.getElementById('dyslexia-font'); // Button to toggle dyslexia-friendly fonts.
1188    const dyslexiaFontStates = [
1189        krakenAccessibilityTranslations.dyslexiaFriendly,
1190        krakenAccessibilityTranslations.dyslexiaFriendlyFont,
1191        krakenAccessibilityTranslations.legibleFont
1192    ]; 
1193    const dyslexiaFontAriaLabels = [
1194        krakenAccessibilityTranslations.dyslexiaFriendlyDescription,
1195        krakenAccessibilityTranslations.dyslexiaFriendlyActivated,
1196        krakenAccessibilityTranslations.legibleFontActivated
1197    ]; 
1198
1199    // Initialize the dyslexia font state if saved.
1200    if (savedState > 0) {
1201        updateButtonState(
1202            'dyslexia-font',             // Button ID
1203            true,                        // Is Active
1204            dyslexiaFontAriaLabels,      // ARIA Labels
1205            savedState,                  // Current State
1206            'dyslexia-font-state',       // State Label ID
1207            dyslexiaFontStates           // State Labels
1208        );
1209
1210        enableDyslexiaFont(savedState); // Enable dyslexia font based on saved state.
1211    }
1212
1213    // Add event listener to the Dyslexia Font button.
1214    dyslexiaFontButton.addEventListener('click', () => {
1215        const currentState = toggleState('dyslexiaFont', dyslexiaFontStates.length);
1216        updateButtonState(
1217            'dyslexia-font',             // Button ID
1218            currentState > 0,            // Is Active
1219            dyslexiaFontAriaLabels,      // ARIA Labels
1220            currentState,                // Current State
1221            'dyslexia-font-state',       // State Label ID
1222            dyslexiaFontStates           // State Labels
1223        );        
1224
1225        enableDyslexiaFont(currentState); // Enable or disable dyslexia font based on state.
1226
1227        saveStateToLocalStorage(); // Save the current state.
1228    });
1229
1230    // Enable or disable dyslexia-friendly font styles.
1231    function enableDyslexiaFont(state) {
1232        const textElements = document.querySelectorAll(
1233            'h1, h2, h3, h4, h5, h6, p, strong, a, ul, ol, li, span, blockquote, button, label'
1234        ); // Elements to apply font styles.
1235
1236        const fontLinkId = 'dyslexic-font-style'; // ID for the font stylesheet.
1237
1238        const existingFontLink = document.getElementById(fontLinkId);
1239        if (existingFontLink) existingFontLink.remove(); // Remove existing font link if present.
1240
1241        textElements.forEach(el => {
1242            el.style.fontFamily = ''; // Reset font styles.
1243        });
1244
1245        if (state === 1) { // Apply Dyslexia Friendly Font.
1246            if (!document.getElementById(fontLinkId)) {
1247                const fontLink = document.createElement('link');
1248                fontLink.id = fontLinkId;
1249                fontLink.rel = 'stylesheet';
1250                fontLink.href = 'https://cdn.jsdelivr.net/npm/[email protected]/open-dyslexic-regular.min.css';
1251                document.head.appendChild(fontLink); // Add the dyslexia-friendly font stylesheet.
1252            }
1253            textElements.forEach(el => {
1254                el.style.fontFamily = '"OpenDyslexicRegular", Arial, sans-serif'; // Apply the font to elements.
1255            });
1256        } else if (state === 2) { // Apply Legible Font.
1257            textElements.forEach(el => {
1258                el.style.fontFamily = 'Arial, serif'; // Apply a legible font to elements.
1259            });
1260        }
1261    }
1262
1263    // Reset font styles to default.
1264    function resetDyslexiaFont() {
1265        enableDyslexiaFont(0); // Reset font to default.
1266        state.dyslexiaFont = 0; // Reset state.
1267        toggleActiveClass('dyslexia-font', false);
1268        updateAriaLabel('dyslexia-font', dyslexiaFontAriaLabels, 0);
1269        document.getElementById('dyslexia-font-state').textContent = dyslexiaFontStates[0];
1270
1271        saveStateToLocalStorage(); // Save the reset state.
1272    }
1273}
1274
1275// Initialize the cursor functionality.
1276function initializeCursor(savedState = 0) {
1277    // Attach methods to the Accessibility object for external access.
1278    Accessibility.enableCursorState = enableCursorState;
1279    Accessibility.resetCursorState = resetCursorState;
1280
1281    // Define constants for the cursor functionality.
1282    const cursorButton = document.getElementById('cursor'); // Button to toggle cursor states.
1283    const cursorStates = [
1284        krakenAccessibilityTranslations.defaultCursor,
1285        krakenAccessibilityTranslations.bigCursor,
1286        krakenAccessibilityTranslations.readingMask,
1287        krakenAccessibilityTranslations.readingGuide
1288    ];
1289    const cursorAriaLabels = [
1290        krakenAccessibilityTranslations.cursorDescription,
1291        krakenAccessibilityTranslations.bigCursorActivated,
1292        krakenAccessibilityTranslations.cursorReadingMaskActivated,
1293        krakenAccessibilityTranslations.cursorReadingGuideActivated
1294    ];
1295
1296    // Initialize the cursor state if saved.
1297    if (savedState > 0) {
1298        updateButtonState(
1299            'cursor',                  // Button ID
1300            true,                      // Is Active
1301            cursorAriaLabels,          // ARIA Labels
1302            savedState,                // Current State
1303            'cursor-state',            // State Label ID
1304            cursorStates               // State Labels
1305        );
1306        enableCursorState(savedState); // Enable cursor state based on saved state.
1307    }
1308
1309    // Add event listener to the cursor button.
1310    cursorButton.addEventListener('click', () => {
1311        const currentState = toggleState('cursor', cursorStates.length);
1312        updateButtonState(
1313            'cursor',                // Button ID
1314            currentState > 0,        // Is Active
1315            cursorAriaLabels,        // ARIA Labels
1316            currentState,            // Current State
1317            'cursor-state',          // State Label ID
1318            cursorStates             // State Labels
1319        );
1320        
1321        enableCursorState(currentState); // Enable or disable cursor modifications based on state.
1322
1323        saveStateToLocalStorage(); // Save the current state.
1324    });
1325
1326    // Enable or disable cursor modifications based on state.
1327    function enableCursorState(state) {
1328        const cursorOverlayTopId = 'aw-overlay-top'; // ID for the top overlay element.
1329        const cursorOverlayBottomId = 'aw-overlay-bottom'; // ID for the bottom overlay element.
1330        const cursorLineId = 'aw-cursor-line'; // ID for the cursor line element.
1331
1332        // Remove previous cursor modifications.
1333        document.documentElement.classList.remove('aw-modifier__cursor');
1334        removeElementById(cursorOverlayTopId);
1335        removeElementById(cursorOverlayBottomId);
1336        removeElementById(cursorLineId);
1337        document.removeEventListener('mousemove', handleCursorWindow);
1338        document.removeEventListener('mousemove', handleCursorLine);
1339
1340        // Apply new cursor modifications based on state.
1341        if (state === 1) {
1342            document.documentElement.classList.add('aw-modifier__cursor'); // Add big cursor class.
1343        } else if (state === 2) {
1344            createCursorOverlay(cursorOverlayTopId, cursorOverlayBottomId); // Create overlay elements for Reading Mask.
1345            document.addEventListener('mousemove', handleCursorWindow); // Adjust overlay position dynamically.
1346        } else if (state === 3) {
1347            createCursorLine(cursorLineId); // Create Reading Guide line.
1348            document.addEventListener('mousemove', handleCursorLine); // Adjust line position dynamically.
1349        }
1350    }
1351
1352    // Reset cursor modifications to default state.
1353    function resetCursorState() {
1354        enableCursorState(0); // Reset to default cursor.
1355        state.cursor = 0; // Reset state.
1356        toggleActiveClass('cursor', false);
1357        updateAriaLabel('cursor', cursorAriaLabels, 0);
1358        document.getElementById('cursor-state').textContent = curs
1358orStates[0];
1359
1360        saveStateToLocalStorage(); // Save the reset state.
1361    }
1362
1363    // Create overlay elements for the Reading Mask.
1364    function createCursorOverlay(topId, bottomId) {
1365        const overlayTop = document.createElement('div');
1366        overlayTop.id = topId;
1367        Object.assign(overlayTop.style, {
1368            position: 'fixed',
1369            top: '0',
1370            left: '0',
1371            width: '100%',
1372            height: '50%',
1373            backgroundColor: 'rgba(0, 0, 0, 0.5)',
1374            pointerEvents: 'none',
1375            zIndex: '9999'
1376        });
1377
1378        const overlayBottom = document.createElement('div');
1379        overlayBottom.id = bottomId;
1380        Object.assign(overlayBottom.style, {
1381            position: 'fixed',
1382            bottom: '0',
1383            left: '0',
1384            width: '100%',
1385            height: '50%',
1386            backgroundColor: 'rgba(0, 0, 0, 0.5)',
1387            pointerEvents: 'none',
1388            zIndex: '9999'
1389        });
1390
1391        document.body.appendChild(overlayTop); // Add top overlay to the DOM.
1392        document.body.appendChild(overlayBottom); // Add bottom overlay to the DOM.
1393    }
1394
1395    // Adjust overlay positions based on mouse movement.
1396    function handleCursorWindow(e) {
1397        const overlayTop = document.getElementById('aw-overlay-top');
1398        const overlayBottom = document.getElementById('aw-overlay-bottom');
1399        if (overlayTop && overlayBottom) {
1400            const windowHeight = 100; // Height of the Reading Mask window.
1401            overlayTop.style.height = `${e.clientY - windowHeight / 2}px`;
1402            overlayBottom.style.height = `calc(100% - ${e.clientY + windowHeight / 2}px)`;
1403        }
1404    }
1405
1406    // Create the Reading Guide line element.
1407    function createCursorLine(lineId) {
1408        const cursorLine = document.createElement('div');
1409        cursorLine.id = lineId;
1410        cursorLine.classList.add('aw-reading-guide');
1411
1412        const arrow = document.createElement('div');
1413        arrow.classList.add('aw-reading-guide__arrow'); // Add arrow indicator.
1414
1415        cursorLine.appendChild(arrow); // Append arrow to the line.
1416
1417        document.body.appendChild(cursorLine); // Add the line to the DOM.
1418    }
1419
1420    // Adjust the Reading Guide line position based on mouse movement.
1421    function handleCursorLine(e) {
1422        const cursorLine = document.getElementById('aw-cursor-line');
1423        if (cursorLine) {
1424            cursorLine.style.left = `${e.clientX}px`;
1425            cursorLine.style.top = `${e.clientY}px`;
1426        }
1427    }
1428
1429    // Remove an element by its ID.
1430    function removeElementById(elementId) {
1431        const element = document.getElementById(elementId);
1432        if (element) element.remove(); // Remove the element if it exists.
1433    }
1434}
1435
1436// Initialize the line height functionality.
1437function initializeLineHeight(savedState = 0) {
1438    // Attach methods to the Accessibility object for external access.
1439    Accessibility.enableLineHeight = enableLineHeight;
1440    Accessibility.resetLineHeight = resetLineHeight;
1441
1442    // Define constants for the line height functionality.
1443    const lineHeightButton = document.getElementById('line-height'); // Button to toggle line height.
1444    const lineHeightStates = [
1445        krakenAccessibilityTranslations.lineHeight,
1446        krakenAccessibilityTranslations.lineHeight15x,
1447        krakenAccessibilityTranslations.lineHeight175x,
1448        krakenAccessibilityTranslations.lineHeight2x
1449    ];
1450    const lineHeightAriaLabels = [
1451        krakenAccessibilityTranslations.defaultLineHeight,
1452        krakenAccessibilityTranslations.lineHeight15xActivated,
1453        krakenAccessibilityTranslations.lineHeight175xActivated,
1454        krakenAccessibilityTranslations.lineHeight2xActivated
1455    ]; 
1456
1457    // Initialize the line height state if saved.
1458    if (savedState > 0) {
1459        updateButtonState(
1460            'line-height',             // Button ID
1461            true,                      // Is Active
1462            lineHeightAriaLabels,      // ARIA Labels
1463            savedState,                // Current State
1464            'line-height-state',       // State Label ID
1465            lineHeightStates           // State Labels
1466        );
1467        enableLineHeight(savedState); // Enable line height based on saved state.
1468    }    
1469
1470    // Add event listener to the line height button.
1471    lineHeightButton.addEventListener('click', () => {
1472        const currentState = toggleState('lineHeight', lineHeightStates.length);
1473        updateButtonState(
1474            'line-height',              // Button ID
1475            currentState > 0,           // Is Active
1476            lineHeightAriaLabels,       // ARIA Labels
1477            currentState,               // Current State
1478            'line-height-state',        // State Label ID
1479            lineHeightStates            // State Labels
1480        );        
1481
1482        enableLineHeight(currentState); // Enable or disable line height adjustments.
1483
1484        saveStateToLocalStorage(); // Save the current state.
1485    });
1486
1487    // Enable or disable line height adjustments.
1488    function enableLineHeight(state) {
1489        // Define line height values for different states.
1490        const lineHeightValues = ['', '1.5', '1.75', '2'];
1491        const h1Values = ['', '120px', '140px', '160px']; // Specific line height values for H1 elements.
1492        const h2Values = ['', '102px', '119px', '136px']; // Specific line height values for H2 elements.
1493
1494        // Select text elements and headings for line height adjustments.
1495        const textElements = document.querySelectorAll('p, ul, ol, li, span, h3, h4, h5, h6, blockquote');
1496        const h1Elements = document.querySelectorAll('h1');
1497        const h2Elements = document.querySelectorAll('h2');
1498
1499        // Reset line height for all elements.
1500        textElements.forEach(el => (el.style.lineHeight = ''));
1501        h1Elements.forEach(el => (el.style.lineHeight = ''));
1502        h2Elements.forEach(el => (el.style.lineHeight = ''));
1503
1504        // Apply new line height values based on the current state.
1505        if (state > 0) {
1506            const lineHeight = lineHeightValues[state]; // Get the line height value for the current state.
1507            textElements.forEach(el => (el.style.lineHeight = lineHeight)); // Apply line height to text elements.
1508            h1Elements.forEach(el => (el.style.lineHeight = h1Values[state])); // Apply line height to H1 elements.
1509            h2Elements.forEach(el => (el.style.lineHeight = h2Values[state])); // Apply line height to H2 elements.
1510        }
1511    }
1512
1513    // Reset line height adjustments to default state.
1514    function resetLineHeight() {
1515        enableLineHeight(0); // Reset line height to default.
1516        state.lineHeight = 0; // Reset state.
1517        toggleActiveClass('line-height', false); // Remove active class from the button.
1518        updateAriaLabel('line-height', lineHeightAriaLabels, 0); // Reset ARIA label.
1519        document.getElementById('line-height-state').textContent = lineHeightStates[0]; // Reset displayed state.
1520
1521        saveStateToLocalStorage(); // Save the reset state.
1522    }
1523}
1524
1525// Initialize the text alignment functionality.
1526function initializeTextAlign(savedState = 0) {
1527    // Attach methods to the Accessibility object for external access.
1528    Accessibility.enableTextAlign = enableTextAlign;
1529    Accessibility.resetTextAlign = resetTextAlign;
1530
1531    // Define constants for the text alignment functionality.
1532    const textAlignButton = document.getElementById('text-align'); // Button to toggle text alignment.
1533    const textAlignStates = [
1534        krakenAccessibilityTranslations.changeTextAlign,
1535        krakenAccessibilityTranslations.alignLeft,
1536        krakenAccessibilityTranslations.alignRight,
1537        krakenAccessibilityTranslations.alignCenter,
1538        krakenAccessibilityTranslations.alignJustified
1539    ]; 
1540    const textAlignAriaLabels = [
1541        krakenAccessibilityTranslations.changeTextAlignDescription,
1542        krakenAccessibilityTranslations.alignLeftActivated,
1543        krakenAccessibilityTranslations.alignRightActivated,
1544        krakenAccessibilityTranslations.alignCenterActivated,
1545        krakenAccessibilityTranslations.alignJustifiedActivated
1546    ]; 
1547    const textAlignValues = ['', 'left', 'right', 'center', 'justify']; // CSS text alignment values.
1548
1549    // Initialize the text alignment state if saved.
1550    if (savedState > 0) {
1551        updateButtonState(
1552            'text-align',              // Button ID
1553            true,                      // Is Active
1554            textAlignAriaLabels,       // ARIA Labels
1555            savedState,                // Current State
1556            'text-align-state',        // State Label ID
1557            textAlignStates            // State Labels
1558        );
1559        enableTextAlign(savedState); // Enable text alignment based on saved state.
1560    }    
1561
1562    // Add event listener to the text alignment button.
1563    textAlignButton.addEventListener('click', () => {
1564        const currentState = toggleState('textAlign', textAlignStates.length);
1565        updateButtonState(
1566            'text-align',              // Button ID
1567            currentState > 0,          // Is Active
1568            textAlignAriaLabels,       // ARIA Labels
1569            currentState,              // Current State
1570            'text-align-state',        // State Label ID
1571            textAlignStates            // State Labels
1572        );        
1573
1574        enableTextAlign(currentState); // Enable or disable text alignment.
1575
1576        saveStateToLocalStorage(); // Save the current state.
1577    });
1578
1579    // Enable or disable text alignment based on state.
1580    function enableTextAlign(state) {
1581        const textAlign = textAlignValues[state]; // Get the text alignment value for the current state.
1582        
1583        // Select all target elements but exclude those inside <nav>
1584        document.querySelectorAll('h1, h2, h3, h4, h5, h6, p, ul, li, pre')
1585            .forEach(el => {
1586                if (!el.closest('nav')) { // Ensure elements inside <nav> are not affected
1587                    el.style.setProperty('text-align', textAlign, 'important');
1588                }
1589            });
1590    }
1591
1592    // Reset text alignment to the default state.
1593    function resetTextAlign() {
1594        enableTextAlign(0); // Reset text alignment to default.
1595        state.textAlign = 0; // Reset state.
1596        toggleActiveClass('text-align', false); // Remove active class from the button.
1597        updateAriaLabel('text-align', textAlignAriaLabels, 0); // Reset ARIA label.
1598        document.getElementById('text-align-state').textContent = textAlignStates[0]; // Reset displayed state.
1599
1600        saveStateToLocalStorage(); // Save the reset state.
1601    }
1602}
1603
1604// Initialize the saturation functionality.
1605function initializeSaturation(savedState = 0) {
1606    // Attach the resetSaturation method to the Accessibility object for external access.
1607    Accessibility.resetSaturation = resetSaturation;
1608
1609    // Define constants for the saturation functionality.
1610    const saturationButton = document.getElementById('saturation'); // Button to toggle saturation levels.
1611    const saturationClasses = ['aw-modifier__sat-low', 'aw-modifier__sat-high', 'aw-modifier__sat-desaturate']; // CSS classes for saturation levels.
1612    const saturationStates = [
1613        krakenAccessibilityTranslations.changeSaturation,
1614        krakenAccessibilityTranslations.lowSaturation,
1615        krakenAccessibilityTranslations.highSaturation,
1616        krakenAccessibilityTranslations.desaturate
1617    ];
1618    const ariaLabels = [
1619        krakenAccessibilityTranslations.changeSaturationDescription,
1620        krakenAccessibilityTranslations.lowSaturationActivated,
1621        krakenAccessibilityTranslations.highSaturationActivated,
1622        krakenAccessibilityTranslations.desaturateActivated
1623    ]; 
1624
1625    // Initialize the saturation state if saved.
1626    if (savedState > 0) {
1627        updateButtonState(
1628            'saturation',              // Button ID
1629            true,                      // Is Active
1630            ariaLabels,                // ARIA Labels
1631            savedState,                // Current State
1632            'saturation-state',        // State Label ID
1633            saturationStates           // State Labels
1634        );
1635        document.documentElement.classList.add(saturationClasses[savedState - 1]); // Apply the saved saturation class.
1636    }    
1637
1638    // Add event listener to the saturation button.
1639    saturationButton.addEventListener('click', () => {
1640        const currentState = toggleState('saturation', saturationStates.length);
1641        updateButtonState(
1642            'saturation',              // Button ID
1643            currentState > 0,          // Is Active
1644            ariaLabels,                // ARIA Labels
1645            currentState,              // Current State
1646            'saturation-state',        // State Label ID
1647            saturationStates           // State Labels
1648        );
1649                
1650        const isActive = currentState > 0;
1651
1652        document.documentElement.classList.remove(...saturationClasses); // Remove all existing saturation classes.
1653
1654        if (isActive) {
1655            document.documentElement.classList.add(saturationClasses[currentState - 1]); // Apply the selected saturation class.
1656        }
1657
1658        saveStateToLocalStorage(); // Save the current state.
1659    });
1660
1661    // Reset saturation adjustments to default state.
1662    function resetSaturation() {
1663        document.documentElement.classList.remove(...saturationClasses); // Remove all existing saturation classes.
1664        toggleActiveClass('saturation', false); // Remove active class from the button.
1665        updateAriaLabel('saturation', ariaLabels, 0); // Reset ARIA label.
1666        document.getElementById('saturation-state').textContent = saturationStates[0]; // Reset displayed state.
1667        state.saturation = 0; // Reset state.
1668
1669        saveStateToLocalStorage(); // Save the reset state.
1670    }
1671}
1672
1673// Initialize the pause animations functionality.
1674function initializePauseAnimations(savedState = 0) {
1675    Accessibility.enablePauseAnimations = enablePauseAnimations;
1676    Accessibility.resetPauseAnimations = resetPauseAnimations;
1677
1678    const pauseAnimationsButton = document.getElementById('pause-animations');
1679    const animationStates = [
1680        krakenAccessibilityTranslations.pauseAnimations,
1681        krakenAccessibilityTranslations.animationsPaused
1682    ];
1683    const animationAriaLabels = [
1684        krakenAccessibilityTranslations.pauseAnimationsDescription,
1685        krakenAccessibilityTranslations.animationsPausedState
1686    ];
1687
1688    if (savedState > 0) {
1689        updateButtonState(
1690            'pause-animations',
1691            true,
1692            animationAriaLabels,
1693            savedState,
1694            'pause-animations-state',
1695            animationStates
1696        );
1697        enablePauseAnimations(savedState);
1698    }
1699
1700    pauseAnimationsButton.addEventListener('click', () => {
1701        const currentState = toggleState('pauseAnimations', animationStates.length);
1702        updateButtonState(
1703            'pause-animations',
1704            currentState > 0,
1705            animationAriaLabels,
1706            currentState,
1707            'pause-animations-state',
1708            animationStates
1709        );
1710
1711        enablePauseAnimations(currentState);
1712        saveStateToLocalStorage();
1713    });
1714
1715    function enablePauseAnimations(state) {
1716        const animationStyleTagId = 'aw-animation-style';
1717        let animationStyleTag = document.getElementById(animationStyleTagId);
1718
1719        if (state === 1) {
1720            if (!animationStyleTag) {
1721                animationStyleTag = document.createElement('style');
1722                animationStyleTag.id = animationStyleTagId;
1723                animationStyleTag.textContent = `
1724                    * {
1725                        animation: none !important;
1726                        transition: none !important;
1727                    }
1728                `;
1729                document.head.appendChild(animationStyleTag);
1730            }
1731
1732            disableGSAPAnimations();
1733            disableOtherAnimations();
1734        } else {
1735            if (animationStyleTag) {
1736                animationStyleTag.remove();
1737            }
1738
1739            enableGSAPAnimations();
1740            enableOtherAnimations();
1741        }
1742    }
1743
1744    function resetPauseAnimations() {
1745        toggleActiveClass('pause-animations', false);
1746        updateAriaLabel('pause-animations', animationAriaLabels, 0);
1747        document.getElementById('pause-animations-state').textContent = animationStates[0];
1748        enablePauseAnimations(0);
1749        state.pauseAnimations = 0;
1750        saveStateToLocalStorage();
1751    }
1752}
1753
1754// Pause GSAP animations globally.
1755function disableGSAPAnimations() {
1756    if (window.gsap && gsap.globalTimeline) {
1757        try {
1758            gsap.globalTimeline.pause();
1759            //console.log('GSAP animations paused.');
1760        } catch (error) {
1761            //console.error('Error pausing GSAP animations:', error);
1762        }
1763    } else {
1764        //console.warn('GSAP is not loaded or detected.');
1765    }
1766}
1767
1768// Resume GSAP animations globally.
1769function enableGSAPAnimations() {
1770    if (window.gsap && gsap.globalTimeline) {
1771        try {
1772            gsap.globalTimeline.resume();
1773            //console.log('GSAP animations resumed.');
1774        } catch (error) {
1775            //console.error('Error resuming GSAP animations:', error);
1776        }
1777    } else {
1778        //console.warn('GSAP is not loaded or detected.');
1779    }
1780}
1781
1782// Disable animations from common libraries.
1783function disableOtherAnimations() {
1784    //console.log('Disabling third-party animations...');
1785
1786    // Animate.css - Remove animation classes
1787    document.querySelectorAll('.animate__animated').forEach(el => {
1788        el.classList.remove('animate__animated');
1789    });
1790
1791    // AOS (Animate on Scroll)
1792    if (window.AOS) {
1793        try {
1794            AOS.refreshHard(); // Remove all instances
1795            AOS.init({ disable: true }); // Disable AOS
1796            //console.log('AOS animations disabled.');
1797        } catch (error) {
1798            //console.error('Error disabling AOS:', error);
1799        }
1800    }
1801
1802    // WOW.js - Remove animation classes
1803    document.querySelectorAll('.wow').forEach(el => {
1804        el.classList.remove('wow');
1805    });
1806
1807    // Remove inline styles that contain animations
1808    document.querySelectorAll('[style]').forEach(el => {
1809        if (el.style.animation || el.style.transition) {
1810            el.style.animation = 'none';
1811            el.style.transition = 'none';
1812        }
1813    });
1814
1815    // Remove CSS keyframes animations
1816    const keyframeStyles = document.querySelectorAll('style');
1817    keyframeStyles.forEach(styleTag => {
1818        if (styleTag.innerHTML.includes('@keyframes') || styleTag.innerHTML.includes('animation')) {
1819            styleTag.remove();
1820        }
1821    });
1822
1823    //console.log('All animations disabled.');
1824}
1825
1826// Enable animations from common libraries.
1827function enableOtherAnimations() {
1828    //console.log('Re-enabling third-party animations...');
1829
1830    // AOS (Animate on Scroll)
1831    if (window.AOS) {
1832        try {
1833            AOS.refresh(); // Re-enable AOS
1834            //console.log('AOS animations enabled.');
1835        } catch (error) {
1836            //console.error('Error enabling AOS:', error);
1837        }
1838    }
1839
1840    // WOW.js - Reapply animation classes
1841    document.querySelectorAll('[data-wow]').forEach(el => {
1842        el.classList.add('wow');
1843    });
1844
1845    //console.log('All animations re-enabled.');
1846}
1847
1848
1849// Initialize the Read Mode functionality.
1850function initializeReadMode(savedState = 0) {
1851    // Attach methods to the Accessibility object for external access.
1852    Accessibility.enableReadMode = enableReadMode;
1853    Accessibility.resetReadMode = resetReadMode;
1854
1855    // Define constants for the Read Mode functionality.
1856    const readModeButton = document.getElementById('read-mode'); // Button to toggle Read Mode.
1857    const readModeStates = [
1858        krakenAccessibilityTranslations.enableReadMode,
1859        krakenAccessibilityTranslations.readModeActivated,
1860    ];
1861    const readModeAriaLabels = [
1862        krakenAccessibilityTranslations.readModeDescription,
1863        krakenAccessibilityTranslations.readModeEnabled
1864    ];
1865
1866    // Initialize the Read Mode state if saved.
1867    if (savedState > 0) {
1868        updateButtonState(
1869            'read-mode',               // Button ID
1870            true,                      // Is Active
1871            readModeAriaLabels,        // ARIA Labels
1872            savedState,                // Current State
1873            'read-mode-state',         // State Label ID
1874            readModeStates             // State Labels
1875        );
1876        enableReadMode(savedState); // Enable Read Mode based on saved state.
1877    }    
1878
1879    // Add event listener to the Read Mode button.
1880    readModeButton.addEventListener('click', () => {
1881        const currentState = toggleState('readMode', readModeStates.length);
1882        updateButtonState(
1883            'read-mode',               // Button ID
1884            currentState > 0,          // Is Active
1885            readModeAriaLabels,        // ARIA Labels
1886            currentState,              // Current State
1887            'read-mode-state',         // State Label ID
1888            readModeStates             // State Labels
1889        );        
1890
1891        enableReadMode(currentState); // Enable or disable Read Mode.
1892
1893        saveStateToLocalStorage(); // Save the current state.
1894    });
1895
1896    // Enable or disable Read Mode based on the state.
1897    function enableReadMode(state) {
1898        const body = document.querySelector('body'); // Select the body element.
1899        const firstDiv = document.querySelector('div'); // Select the first div element.
1900
1901        if (state === 1) {
1902            body.classList.add('aw-modifier__read-mode-body'); // Add Read Mode class to the body.
1903
1904            if (firstDiv) {
1905                const wrapperDiv = document.createElement('div'); // Create a wrapper div.
1906                wrapperDiv.classList.add('aw-modifier__read-mode'); // Add Read Mode class to the wrapper.
1907                firstDiv.parentNode.insertBefore(wrapperDiv, firstDiv); // Insert wrapper before the first div.
1908                wrapperDiv.appendChild(firstDiv); // Move the first div into the wrapper.
1909            }
1910
1911            const header = document.querySelector('header'); // Select the header element.
1912            if (header) {
1913                simplifyHeader(header); // Simplify the header content.
1914            }
1915
1916            removeUnnecessaryElements(); // Remove unnecessary elements for a cleaner view.
1917        } else {
1918            location.reload(); // Reload the page to reset the view.
1919        }
1920    }
1921
1922    // Reset Read Mode to default state.
1923    function resetReadMode() {
1924        if (state.readMode > 0) {
1925            toggleActiveClass('read-mode', false); // Remove active class from the button.
1926            updateAriaLabel('read-mode', readModeAriaLabels, 0); // Reset ARIA label.
1927            document.getElementById('read-mode-state').textContent = readModeStates[0]; // Reset displayed state.
1928            state.readMode = 0; // Reset state.
1929            location.reload(); // Reload the page to reset the view.
1930            saveStateToLocalStorage(); // Save the reset state.
1931        }
1932    }
1933
1934    // Simplify the header content for Read Mode.
1935    function simplifyHeader(header) {
1936        const navElements = Array.from(header.querySelectorAll('nav')); // Get all navigation elements in the header.
1937        const navWithMostLinks = navElements.reduce((mostLinks, currentNav) => {
1938            const currentLinksCount = currentNav.querySelectorAll('a').length; // Count links in the current navigation.
1939            return currentLinksCount > mostLinks.linksCount
1940                ? { element: currentNav, linksCount: currentLinksCount } // Keep the navigation with the most links.
1941                : mostLinks;
1942        }, { element: null, linksCount: 0 });
1943
1944        const storedNav = navWithMostLinks.element ? navWithMostLinks.element.cloneNode(true) : null; // Clone the selected navigation.
1945
1946        const images = Array.from(header.querySelectorAll('img')); // Get all images in the header.
1947        const largestImage = images.reduce((largest, img) => {
1948            if (!largest || img.naturalWidth > largest.naturalWidth) {
1949                return img; // Select the largest image.
1950            }
1951            return largest;
1952        }, null);
1953
1954        header.innerHTML = ''; // Clear the header content.
1955
1956        if (largestImage) {
1957            const parentLink = largestImage.closest('a'); // Check if the largest image is inside a link.
1958            if (parentLink) {
1959                const linkClone = document.createElement('a'); // Create a new link.
1960                linkClone.href = parentLink.href;
1961                linkClone.target = parentLink.target || '_self';
1962                linkClone.appendChild(largestImage.cloneNode(false)); // Append the image to the link.
1963                header.appendChild(linkClone); // Add the link to the header.
1964            } else {
1965                header.appendChild(largestImage.cloneNode(false)); // Add the image directly to the header.
1966            }
1967        }
1968
1969        if (storedNav) {
1970            header.appendChild(storedNav); // Add the cloned navigation to the header.
1971        }
1972    }
1973
1974    // Remove unnecessary elements from the page for Read Mode.
1975    function removeUnnecessaryElements() {
1976        document.querySelectorAll('form').forEach((form) => form.remove()); // Remove all form elements.
1977
1978        document.querySelectorAll('img, video, iframe, svg').forEach((element) => {
1979            // Ignore SVGs inside #aw-widget
1980            if (!element.closest('header') && !(element.closest('#aw-widget') && element.tagName.toLowerCase() === 'svg')) {
1981                element.remove(); // Remove images, videos, iframes, and SVGs not in header or #aw-widget
1982            }
1983        });
1984
1985        const mainFooter = document.querySelector('footer:not(main footer)'); // Select footers not inside the main footer.
1986        if (mainFooter) {
1987            mainFooter.remove(); // Remove the additional footers.
1988        }
1989
1990        const readModeElements = document.querySelectorAll('.aw-modifier__read-mode *'); // Get all elements in Read Mode wrapper.
1991        readModeElements.forEach((element) => {
1992            element.removeAttribute('class'); // Remove class attributes for a cleaner view.
1993            element.removeAttribute('style'); // Remove inline styles for consistency.
1994        });
1995
1996        // Remove all <style> and <script> tags inside <body>
1997        document.body.querySelectorAll('style, script').forEach((tag) => tag.remove());
1998    }
1999}
2000
2001// Initialize the Mute Sounds functionality.
2002function initializeMuteSounds(savedState = 0) {
2003    // Attach methods to the Accessibility object for external access.
2004    Accessibility.enableMuteSounds = enableMuteSounds;
2005    Accessibility.disableMuteSounds = disableMuteSounds;
2006    Accessibility.resetMuteSounds = resetMuteSounds;
2007
2008    // Define constants for the Mute Sounds functionality.
2009    const muteSoundsButton = document.getElementById('mute-sounds'); // Button to toggle sound muting.
2010    const muteStates = [
2011        krakenAccessibilityTranslations.muteSounds,
2012        krakenAccessibilityTranslations.soundsMuted
2013    ];
2014    const muteAriaLabels = [
2015        krakenAccessibilityTranslations.muteSoundsDescription,
2016        krakenAccessibilityTranslations.soundsMutedState
2017    ];
2018
2019    // Initialize the Mute Sounds state if saved.
2020    if (savedState > 0) {
2021        updateButtonState(
2022            'mute-sounds',             // Button ID
2023            true,                      // Is Active
2024            muteAriaLabels,            // ARIA Labels
2025            savedState,                // Current State
2026            'mute-sounds-state',       // State Label ID
2027            muteStates                 // State Labels
2028        );
2029    
2030        if (savedState === 1) {
2031            enableMuteSounds(); // Enable muting sounds based on saved state.
2032        }
2033    }    
2034
2035    // Add event listener to the Mute Sounds button.
2036    muteSoundsButton.addEventListener('click', () => {
2037        state.muteSounds = (state.muteSounds + 1) % muteStates.length; // Toggle between mute states.
2038        const isMuted = state.muteSounds === 1; // Check if sounds should be muted.
2039
2040        updateButtonState(
2041            'mute-sounds',             // Button ID
2042            state.muteSounds > 0,      // Is Active
2043            muteAriaLabels,            // ARIA Labels
2044            state.muteSounds,          // Current State
2045            'mute-sounds-state',       // State Label ID
2046            muteStates                 // State Labels
2047        );
2048
2049        if (isMuted) {
2050            enableMuteSounds(); // Mute all sounds.
2051        } else {
2052            disableMuteSounds(); // Unmute all sounds.
2053        }
2054
2055        saveStateToLocalStorage(); // Save the current state.
2056    });
2057
2058    // Enable muting of all sounds.
2059    function enableMuteSounds() {
2060        document.querySelectorAll('audio, video').forEach((media) => {
2061            media.muted = true; // Mute the media element.
2062            media.pause(); // Pause the media playback.
2063        });
2064
2065        document.querySelectorAll('iframe').forEach((iframe) => {
2066            const src = iframe.src; // Get the source of the iframe.
2067            if (src && (src.includes('youtube.com') || src.includes('vimeo.com'))) {
2068                const muteParam = src.includes('?') ? '&mute=1' : '?mute=1'; // Add mute parameter to the URL.
2069                iframe.src = src + muteParam; // Update the iframe source.
2070            }
2071        });
2072    }
2073
2074    // Disable muting and restore sound playback.
2075    function disableMuteSounds() {
2076        const mediaElements = document.querySelectorAll("audio, video");
2077        const failedMedia = [];
2078    
2079        mediaElements.forEach((media) => {
2080            try {
2081                media.muted = false; // Unmute the media element.
2082                media.play().catch((err) => {
2083                    console.warn(`Playback failed for media element:`, media, err);
2084                    failedMedia.push({ element: media, error: err });
2085                });
2086            } catch (err) {
2087                console.error(`Error unmuting or playing media element:`, media, err);
2088                failedMedia.push({ element: media, error: err });
2089            }
2090        });
2091    
2092        if (failedMedia.length > 0) {
2093            console.warn(`${failedMedia.length} media elements failed to play. Retrying...`);
2094            retryFailedMedia(failedMedia);
2095        }
2096    
2097        document.querySelectorAll("iframe").forEach((iframe) => {
2098            try {
2099                const src = iframe.src;
2100                if (src) {
2101                    iframe.src = src.replace("&mute=1", "").replace("?mute=1", ""); // Remove mute parameter.
2102                }
2103            } catch (err) {
2104                console.error(`Error resetting iframe source:`, iframe, err);
2105            }
2106        });
2107    }
2108    
2109    function retryFailedMedia(failedMedia) {
2110        failedMedia.forEach(({ element, error }) => {
2111            try {
2112                element.play().catch((err) => {
2113                    console.error(`Retry failed for media element:`, element, err);
2114                });
2115            } catch (err) {
2116                console.error(`Retry attempt failed:`, element, err);
2117            }
2118        });
2119    }    
2120
2121    // Reset muting state to default (unmuted).
2122    function resetMuteSounds() {
2123        toggleActiveClass('mute-sounds', false); // Remove active class from the button.
2124        updateAriaLabel('mute-sounds', muteAriaLabels, 0); // Reset ARIA label.
2125        document.getElementById('mute-sounds-state').textContent = muteStates[0]; // Reset displayed state.
2126        state.muteSounds = 0; // Reset state.
2127        disableMuteSounds(); // Unmute all sounds.
2128        saveStateToLocalStorage(); // Save the reset state.
2129    }
2130}
2131
2132// Initialize the Link Notices functionality.
2133function initializeLinkNotices(savedState = 0) {
2134    // Attach methods to the Accessibility object for external access.
2135    Accessibility.enableLinkNotices = enableLinkNotices;
2136    Accessibility.disableLinkNotices = disableLinkNotices;
2137    Accessibility.resetLinkNotices = resetLinkNotices;
2138
2139    // Define constants for the Link Notices functionality.
2140    const linkNoticesButton = document.getElementById('link-notices'); // Button to toggle link notices.
2141    const linkNoticesStates = [
2142        krakenAccessibilityTranslations.enableLinkNotices,
2143        krakenAccessibilityTranslations.linkNoticesOn
2144    ];
2145    const linkNoticesAriaLabels = [
2146        krakenAccessibilityTranslations.linkNoticesDescription,
2147        krakenAccessibilityTranslations.linkNoticesEnabled
2148    ];
2149
2150    // Initialize the link notices state if saved.
2151    if (savedState > 0) {
2152        updateButtonState(
2153            'link-notices',            // Button ID
2154            true,                      // Is Active
2155            linkNoticesAriaLabels,     // ARIA Labels
2156            savedState,                // Current State
2157            'link-notices-state',      // State Label ID
2158            linkNoticesStates          // State Labels
2159        );
2160
2161        enableLinkNotices(); // Enable link notices based on saved state.
2162    }
2163
2164    // Add event listener to the Link Notices button.
2165    linkNoticesButton.addEventListener('click', () => {
2166        const currentState = toggleState('linkNotices', linkNoticesStates.length);
2167        const isActive = currentState > 0;
2168        updateButtonState(
2169            'link-notices',             // Button ID
2170            currentState > 0,           // Is Active
2171            linkNoticesAriaLabels,      // ARIA Labels
2172            currentState,               // Current State
2173            'link-notices-state',       // State Label ID
2174            linkNoticesStates           // State Labels
2175        );
2176        
2177        if (isActive) {
2178            enableLinkNotices(); // Enable link notices.
2179        } else {
2180            disableLinkNotices(); // Disable link notices.
2181        }
2182
2183        saveStateToLocalStorage(); // Save the current state.
2184    });
2185
2186    // Enable link notices by adding tooltips and ARIA labels to links.
2187    function enableLinkNotices() {
2188        const links = document.querySelectorAll('a'); // Select all link elements.
2189
2190        links.forEach(link => {
2191            const linkName = link.textContent.trim() || link.href; // Use the link's text or URL as its name.
2192            const isNewTab = link.target === '_blank'; // Check if the link opens in a new tab.
2193
2194            if (isNewTab) {
2195                const additionalText = ', opens in a new window';
2195 // Text to describe the link's behavior.
2196                const ariaLabel = `${linkName}${additionalText}`; // Create a descriptive ARIA label.
2197                link.setAttribute('aria-label', ariaLabel); // Add ARIA label to the link.
2198
2199                if (!link.classList.contains('aw-tooltip')) {
2200                    const tooltip = document.createElement('span'); // Create a tooltip element.
2201                    tooltip.className = 'aw-tooltip-text'; // Add a class for styling the tooltip.
2202                    tooltip.textContent = `${linkName}${additionalText}`; // Set the tooltip text.
2203
2204                    link.classList.add('aw-tooltip'); // Add a class to indicate the link has a tooltip.
2205                    link.appendChild(tooltip); // Append the tooltip to the link.
2206
2207                    // Add event listeners to show or hide the tooltip on focus, blur, mouseenter, or mouseleave.
2208                    link.addEventListener('focus', showTooltip);
2209                    link.addEventListener('blur', hideTooltip);
2210                    link.addEventListener('mouseenter', showTooltip);
2211                    link.addEventListener('mouseleave', hideTooltip);
2212                }
2213            }
2214        });
2215    }
2216
2217    // Disable link notices by removing tooltips and ARIA labels.
2218    function disableLinkNotices() {
2219        const links = document.querySelectorAll('a'); // Select all link elements.
2220
2221        links.forEach(link => {
2222            link.removeAttribute('aria-label'); // Remove the ARIA label.
2223
2224            if (link.classList.contains('aw-tooltip')) {
2225                const tooltip = link.querySelector('.aw-tooltip-text'); // Select the tooltip element.
2226                if (tooltip) tooltip.remove(); // Remove the tooltip element.
2227
2228                link.classList.remove('aw-tooltip'); // Remove the tooltip class from the link.
2229                link.removeEventListener('focus', showTooltip); // Remove event listeners for the tooltip.
2230                link.removeEventListener('blur', hideTooltip);
2231                link.removeEventListener('mouseenter', showTooltip);
2232                link.removeEventListener('mouseleave', hideTooltip);
2233            }
2234        });
2235    }
2236
2237    // Reset link notices to the default state.
2238    function resetLinkNotices() {
2239        disableLinkNotices(); // Disable link notices.
2240        state.linkNotices = 0; // Reset state.
2241        toggleActiveClass('link-notices', false); // Remove active class from the button.
2242        updateAriaLabel('link-notices', linkNoticesAriaLabels, 0); // Reset ARIA label.
2243        document.getElementById('link-notices-state').textContent = linkNoticesStates[0]; // Reset displayed state.
2244
2245        saveStateToLocalStorage(); // Save the reset state.
2246    }
2247
2248    // Show the tooltip when the link gains focus or the mouse hovers over it.
2249    function showTooltip(event) {
2250        const tooltip = event.target.querySelector('.aw-tooltip-text'); // Get the tooltip element.
2251        if (tooltip) tooltip.style.visibility = 'visible'; // Make the tooltip visible.
2252    }
2253
2254    // Hide the tooltip when the link loses focus or the mouse leaves it.
2255    function hideTooltip(event) {
2256        const tooltip = event.target.querySelector('.aw-tooltip-text'); // Get the tooltip element.
2257        if (tooltip) tooltip.style.visibility = 'hidden'; // Hide the tooltip.
2258    }
2259}
2260
2261// Initialize the Dictionary functionality.
2262function initializeDictionary(savedState = 0) {
2263    Accessibility.enableDictionary = enableDictionary;
2264    Accessibility.disableDictionary = disableDictionary;
2265    Accessibility.resetDictionary = resetDictionary;
2266
2267    const dictionaryButton = document.getElementById('dictionary');
2268    const dictionarySearchInput = document.getElementById('dictionary-search');
2269    const dictionarySearchButton = document.getElementById('dictionary-search-button');
2270    const dictionaryModal = document.getElementById("dictionary-modal");
2271
2272    const dictionaryStates = [
2273        krakenAccessibilityTranslations.enableDictionary,
2274        krakenAccessibilityTranslations.dictionaryOn,
2275    ];
2276    const dictionaryAriaLabels = [
2277        krakenAccessibilityTranslations.dictionaryDescription,
2278        krakenAccessibilityTranslations.dictionaryEnabled,
2279    ];
2280
2281    if (savedState > 0) {
2282        updateButtonState(
2283            'dictionary',
2284            true,
2285            dictionaryAriaLabels,
2286            savedState,
2287            'dictionary-state',
2288            dictionaryStates
2289        );
2290        enableDictionary();
2291    }
2292
2293    dictionaryButton.addEventListener("click", (e) => {
2294        if (e.target.classList.contains("aw-dictionary-close")) return;
2295
2296        const currentState = toggleState('dictionary', dictionaryStates.length);
2297        const isActive = currentState > 0;
2298        updateButtonState(
2299            'dictionary',
2300            isActive,
2301            dictionaryAriaLabels,
2302            currentState,
2303            'dictionary-state',
2304            dictionaryStates
2305        );
2306
2307        if (isActive) {
2308            enableDictionary();
2309        } else {
2310            disableDictionary();
2311        }
2312
2313        saveStateToLocalStorage();
2314    });
2315
2316    function enableDictionary() {
2317        document.body.addEventListener("mouseup", handleTextSelection);
2318        document.body.addEventListener("touchend", handleTouchSelection);
2319        document.body.addEventListener("dblclick", handleDoubleClickSelection);
2320    }
2321
2322    function disableDictionary() {
2323        document.body.removeEventListener("mouseup", handleTextSelection);
2324        document.body.removeEventListener("touchend", handleTouchSelection);
2325        document.body.removeEventListener("dblclick", handleDoubleClickSelection);
2326    }
2327
2328    function resetDictionary() {
2329        const currentState = toggleState('dictionary', dictionaryStates.length);
2330        updateButtonState(
2331            'dictionary',
2332            currentState > 0,
2333            dictionaryAriaLabels,
2334            currentState,
2335            'dictionary-state',
2336            dictionaryStates
2337        );
2338        disableDictionary();
2339        saveStateToLocalStorage();
2340    }
2341
2342    function handleTextSelection(event) {
2343        if (event.target.closest("#dictionary-modal")) return;
2344
2345        const selectedText = window.getSelection().toString().trim();
2346        if (selectedText.length > 0) {
2347            dictionarySearchInput.value = selectedText;
2348            fetchDefinition(selectedText);
2349        }
2350    }
2351
2352    function handleTouchSelection(event) {
2353        if (event.target.closest("#dictionary-modal")) return;
2354
2355        const selectedText = window.getSelection().toString().trim();
2356        if (selectedText.length > 0) {
2357            dictionarySearchInput.value = selectedText;
2358            fetchDefinition(selectedText);
2359        }
2360    }
2361
2362    function handleDoubleClickSelection(event) {
2363        if (event.target.closest("#dictionary-modal")) return;
2364
2365        const selectedText = window.getSelection().toString().trim();
2366        if (selectedText.length > 0) {
2367            dictionarySearchInput.value = selectedText;
2368            fetchDefinition(selectedText);
2369        }
2370    }
2371
2372    function fetchDefinition(selectedText) {
2373        if (selectedText.length > 0) {
2374            fetch(`https://api.dictionaryapi.dev/api/v2/entries/en/${encodeURIComponent(selectedText)}`)
2375                .then(response => {
2376                    if (!response.ok) {
2377                        throw new Error("Word not found.");
2378                    }
2379                    return response.json();
2380                })
2381                .then(data => {
2382                    if (!data || !data[0] || !data[0].meanings || data[0].meanings.length === 0) {
2383                        throw new Error("Invalid response format.");
2384                    }
2385
2386                    const word = data[0].word;
2387                    const meanings = data[0].meanings.flatMap(meaning =>
2388                        meaning.definitions.map(def => ({
2389                            partOfSpeech: meaning.partOfSpeech,
2390                            definition: def.definition
2391                        }))
2392                    );
2393
2394                    if (meanings.length === 0) {
2395                        throw new Error("No definitions available.");
2396                    }
2397
2398                    showDictionaryModal(word, meanings);
2399                    window.getSelection().removeAllRanges();
2400                })
2401                .catch(error => {
2402                    console.error("Dictionary Error:", error.message);
2403                });
2404        }
2405    }
2406
2407    function showDictionaryModal(word, definitions) {
2408        const definitionElement = document.getElementById("dictionary-definition");
2409        const counter = document.getElementById("definition-counter");
2410        const prevButton = document.getElementById("prev-definition");
2411        const nextButton = document.getElementById("next-definition");
2412        const readButton = document.getElementById("read-definition");
2413        const spellButton = document.getElementById("spell-word");
2414    
2415        let currentDefinitionIndex = 0;
2416    
2417        function updateDefinition() {
2418            const currentDefinition = definitions[currentDefinitionIndex];
2419            definitionElement.innerHTML = `<strong>${word} (${currentDefinition.partOfSpeech}):</strong> ${currentDefinition.definition}`;
2420            counter.textContent = `${currentDefinitionIndex + 1} of ${definitions.length}`;
2421        }
2422    
2423        prevButton.onclick = () => {
2424            currentDefinitionIndex = (currentDefinitionIndex - 1 + definitions.length) % definitions.length;
2425            updateDefinition();
2426        };
2427    
2428        nextButton.onclick = () => {
2429            currentDefinitionIndex = (currentDefinitionIndex + 1) % definitions.length;
2430            updateDefinition();
2431        };
2432    
2433        readButton.onclick = () => {
2434            const currentDefinition = definitions[currentDefinitionIndex];
2435            speakDefinition(word, currentDefinition.partOfSpeech, currentDefinition.definition);
2436        };
2437
2438        spellButton.onclick = () => {
2439            spellWord(word);
2440        };
2441
2442        if (definitions.length <= 1) {
2443            prevButton.style.display = "none";
2444            nextButton.style.display = "none";
2445            counter.style.display = "none";
2446        } else {
2447            prevButton.style.display = "flex";
2448            nextButton.style.display = "flex";
2449            counter.style.display = "flex";
2450        }
2451    
2452        updateDefinition();
2453        dictionaryModal.removeAttribute("inert");
2454        dictionaryModal.classList.remove("aw-dm-hidden");
2455    
2456        dictionarySearchInput.focus();
2457        dictionarySearchInput.setSelectionRange(dictionarySearchInput.value.length, dictionarySearchInput.value.length);
2458    }
2459
2460    // Function to read the definition aloud
2461    function speakDefinition(word, partOfSpeech, definition) {
2462        if ("speechSynthesis" in window) {
2463            speechSynthesis.cancel(); 
2464            
2465            const text = `${word}, ${partOfSpeech}. ${definition}`;
2466            const utterance = new SpeechSynthesisUtterance(text);
2467            utterance.lang = "en-US";
2468            utterance.rate = 1; 
2469            utterance.pitch = 1;
2470    
2471            speechSynthesis.speak(utterance);
2472        } else {
2473            console.warn("Speech synthesis not supported in this browser.");
2474        }
2475    }
2476
2477    // Function to spell the word aloud
2478    function spellWord(word) {
2479        if ("speechSynthesis" in window) {
2480            speechSynthesis.cancel();
2481    
2482            const spelledOut = word.split("").join(". ");
2483    
2484            const utterance = new SpeechSynthesisUtterance(`Spelling: ${spelledOut}`);
2485            utterance.lang = "en-US";
2486            utterance.rate = 0.8; 
2487            utterance.pitch = 1;
2488    
2489            speechSynthesis.speak(utterance);
2490        } else {
2491            console.warn("Speech synthesis not supported in this browser.");
2492        }
2493    }  
2494    
2495    // Close dictionary modal on click
2496    document.querySelector("#aw-dictionary").addEventListener("click", () => {
2497        dictionaryModal.setAttribute("inert", "true");
2498        dictionaryModal.classList.add("aw-dm-hidden");
2499    });
2500
2501    // Close dictionary modal when clicking outside of it
2502    dictionaryModal.addEventListener("click", (event) => {
2503        if (event.target === dictionaryModal) {
2504            dictionaryModal.setAttribute("inert", "true");
2505            dictionaryModal.classList.add("aw-dm-hidden");
2506        }
2507    });
2508
2509    // Close modal when the Escape key is pressed
2510    document.addEventListener("keydown", (event) => {
2511        if (event.key === "Escape" && !dictionaryModal.classList.contains("aw-dm-hidden")) {
2512            dictionaryModal.setAttribute("inert", "true");
2513            dictionaryModal.classList.add("aw-dm-hidden");
2514        }
2515    });
2516
2517    // Execute search on Enter key press
2518    dictionarySearchButton.addEventListener("click", () => {
2519        fetchDefinition(dictionarySearchInput.value.trim());
2520    });
2521
2522    dictionarySearchInput.addEventListener("keypress", (event) => {
2523        if (event.key === "Enter") {
2524            event.preventDefault();
2525            fetchDefinition(dictionarySearchInput.value.trim());
2526        }
2527    });
2528}
2529
2530// Reset all settings to their default state.
2531function resetAllSettings() {
2532    // Iterate through each key in the state object and reset it.
2533    Object.keys(state).forEach((key) => {
2534        if (state[key] > 0) {
2535            switch (key) {
2536                case 'contrast':
2537                    Accessibility.resetContrast();
2538                    break;
2539                case 'saturation':
2540                    Accessibility.resetSaturation();    
2541                    break;
2542                case 'screenReader':
2543                    Accessibility.resetScreenReader();
2544                    break;
2545                case 'highlightLinks':
2546                    Accessibility.resetHighlightToLinks();
2547                    break;
2548                case 'highlightHeadings':
2549                    Accessibility.resetHighlightToHeadings();
2550                    break;
2551                case 'biggerText':
2552                    Accessibility.resetBiggerText();
2553                    break;
2554                case 'textSpacing':
2555                    Accessibility.resetTextSpacing();
2556                    break;
2557                case 'hideImages':
2558                    Accessibility.resetHideImages();
2559                    break;
2560                case 'dyslexiaFont':
2561                    Accessibility.resetDyslexiaFont();
2562                    break;
2563                case 'cursor':
2564                    Accessibility.resetCursorState();
2565                    break;
2566                case 'lineHeight':
2567                    Accessibility.resetLineHeight();
2568                    break;
2569                case 'textAlign':
2570                    Accessibility.resetTextAlign();
2571                    break;
2572                case 'pauseAnimations':
2573                    Accessibility.resetPauseAnimations();
2574                    break;
2575                case 'readMode':
2576                    Accessibility.resetReadMode();
2577                    break;
2578                case 'muteSounds':
2579                    Accessibility.resetMuteSounds();
2580                    break;
2581                case 'linkNotices':
2582                    Accessibility.resetLinkNotices();
2583                    break;
2584                case 'dictionary':
2585                    Accessibility.resetDictionary();
2586                    break;
2587                default:
2588                    console.warn(`No reset function defined for ${key}`);
2589            }
2590
2591            // Reset the state for the key.
2592            state[key] = 0;
2593        }
2594    });
2595
2596    // Clear the active profile.
2597    state.activeProfile = null;
2598
2599    // Save the updated state to localStorage.
2600    saveStateToLocalStorage();
2601
2602    // Update UI elements (e.g., buttons).
2603    document.querySelectorAll(".aw-button").forEach((button) => {
2604        button.setAttribute("aria-pressed", false);
2605        button.classList.remove("aw-button--active");
2606    });
2607}
2608
2609// Reset all settings when a "reset all" button is clicked.
2610const resetAllButton = document.getElementById('aw_reset');
2611if (resetAllButton) {
2612    resetAllButton.addEventListener('click', () => {
2613        resetAllSettings();
2614
2615        // Add feedback logic
2616        const feedbackMessage = document.getElementById('aw-feedback');
2617        if (feedbackMessage) {
2618            feedbackMessage.classList.remove('aw-feedback-hidden');
2619
2620            // Automatically hide the feedback message after 3 seconds
2621            setTimeout(() => {
2622                feedbackMessage.classList.add('aw-feedback-hidden');
2623            }, 2000);
2624        }
2625    });
2626}
2627
2628// Main Initialization
2629function initializeAccessibility() {
2630    initializeModal({
2631        modalId: 'aw-modal',
2632        toggleButtonId: 'aw-toggle-modal',
2633        closeButtonId: 'aw-close-modal',
2634    });
2635    initializeScreenReader(state.screenReader);
2636    initializeContrast(state.contrast);
2637    initializeHighlightLinks(state.highlightLinks);
2638    initializeHighlightHeadings(state.highlightHeadings);
2639    initializeBiggerText(state.biggerText);
2640    initializeTextSpacing(state.textSpacing);
2641    initializeHideImages(state.hideImages);
2642    initializeDyslexiaFont(state.dyslexiaFont);
2643    initializeCursor(state.cursor);
2644    initializeLineHeight(state.lineHeight);
2645    initializeTextAlign(state.textAlign);
2646    initializeSaturation(state.saturation);
2647    initializePauseAnimations(state.pauseAnimations);
2648    initializeReadMode(state.readMode);
2649    initializeMuteSounds(state.muteSounds);
2650    initializeLinkNotices(state.linkNotices);
2651    initializeDictionary(state.dictionary);
2652    updateToggleButtonState();
2653}
2654
2655// Function to update the toggle button state based on active features
2656function updateToggleButtonState() {
2657    const toggleButton = document.getElementById("aw-toggle-modal");
2658    if (!toggleButton) return;
2659
2660    const hasActiveFeature = Object.values(state).some(value => value > 0);
2661
2662    if (hasActiveFeature) {
2663        toggleButton.classList.add("aw-widget__trigger--active");
2664        toggleButton.setAttribute("aria-label", "Accessibility Widget Options are Active");
2665    } else {
2666        toggleButton.classList.remove("aw-widget__trigger--active");
2667        toggleButton.setAttribute("aria-label", "Accessibility Widget");
2668    }
2669}
2670
2671// Ensure the toggle button state updates when any setting is changed
2672function saveStateToLocalStorage() {
2673    localStorage.setItem(stateKey, JSON.stringify(state));
2674    updateToggleButtonState(); // Update the button state after saving changes
2675}
2676
2677// Initialization logic on page load
2678document.addEventListener('DOMContentLoaded', () => {
2679  initializeAccessibility();
2680  updateToggleButtonState();
2681});
2682
2683// Add accessibly menu skip link.
2684document.addEventListener("DOMContentLoaded", function () {
2685    let skipNav = document.querySelector("nav.kraken-skip-links ul.kraken-skip-links__list");
2686    if (skipNav) {
2687        let newListItem = document.createElement("li");
2688        newListItem.classList.add("kraken-skip-links__item");
2689
2690        let newLink = document.createElement("a");
2691        newLink.classList.add("kraken-skip-links__link");
2692        newLink.href = "#aw-toggle-modal";
2693        newLink.textContent = "Skip to Accessibility Menu";
2694
2695        newListItem.appendChild(newLink);
2696        skipNav.appendChild(newListItem);
2697    }
2698});
2699

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.