/* Brain Vitamin Mind Gym - JAWS DOM and Focus Stability Engine
   Version 2026-07-11b. Prevents game-board redraws from dropping JAWS at page top. */
(function () {
  'use strict';

  const state = {
    element: null,
    fingerprint: null,
    interactionAt: 0,
    repairing: false,
    repairTimer: 0
  };

  function usable(el) {
    return !!(el && el.isConnected && !el.disabled && el.getAttribute('aria-hidden') !== 'true' && !el.hidden);
  }

  function cssEscape(value) {
    if (window.CSS && CSS.escape) return CSS.escape(value);
    return String(value).replace(/([ #;?%&,.+*~':"!^$[\]()=>|/@])/g, '\\$1');
  }

  function fingerprint(el) {
    if (!el || el.nodeType !== 1) return null;
    const fp = {
      id: el.id || '',
      tag: el.tagName.toLowerCase(),
      name: el.getAttribute('name') || '',
      role: el.getAttribute('role') || '',
      aria: el.getAttribute('aria-label') || '',
      text: (el.textContent || '').replace(/\s+/g, ' ').trim().slice(0, 120),
      data: {},
      index: -1,
      parentId: el.parentElement && el.parentElement.id ? el.parentElement.id : ''
    };
    Array.from(el.attributes || []).forEach(function (a) {
      if (a.name.indexOf('data-') === 0) fp.data[a.name] = a.value;
    });
    if (el.parentElement) fp.index = Array.prototype.indexOf.call(el.parentElement.children, el);
    return fp;
  }

  function remember(el) {
    if (!el || el === document.body || el === document.documentElement) return;
    state.element = el;
    state.fingerprint = fingerprint(el);
    state.interactionAt = Date.now();
  }

  function findReplacement(fp) {
    if (!fp) return null;
    if (fp.id) {
      const byId = document.getElementById(fp.id);
      if (usable(byId)) return byId;
    }
    const dataKeys = Object.keys(fp.data);
    if (dataKeys.length) {
      let selector = fp.tag || '*';
      dataKeys.forEach(function (key) {
        selector += '[' + key + '="' + cssEscape(fp.data[key]) + '"]';
      });
      const byData = document.querySelector(selector);
      if (usable(byData)) return byData;
    }
    if (fp.name) {
      const byName = document.querySelector((fp.tag || '*') + '[name="' + cssEscape(fp.name) + '"]');
      if (usable(byName)) return byName;
    }
    if (fp.aria) {
      const candidates = document.querySelectorAll((fp.tag || '*') + '[aria-label]');
      for (const candidate of candidates) {
        if (candidate.getAttribute('aria-label') === fp.aria && usable(candidate)) return candidate;
      }
    }
    if (fp.parentId && fp.index >= 0) {
      const parent = document.getElementById(fp.parentId);
      const indexed = parent && parent.children[fp.index];
      if (usable(indexed)) return indexed;
    }
    if (fp.text) {
      const candidates = document.querySelectorAll(fp.tag || 'button');
      for (const candidate of candidates) {
        const text = (candidate.textContent || '').replace(/\s+/g, ' ').trim().slice(0, 120);
        if (text === fp.text && usable(candidate)) return candidate;
      }
    }
    const gameArea = document.querySelector('#play:not([hidden]), main, [role="main"]');
    return gameArea && gameArea.querySelector('button:not([disabled]), input:not([disabled]), select:not([disabled]), [tabindex="0"]');
  }

  function focusWithoutScroll(el) {
    if (!usable(el)) return false;
    try { el.focus({ preventScroll: true }); }
    catch (e) { try { el.focus(); } catch (ignored) { return false; } }
    return document.activeElement === el;
  }

  function repairFocus() {
    clearTimeout(state.repairTimer);
    state.repairTimer = setTimeout(function () {
      if (state.repairing || Date.now() - state.interactionAt > 30000) return;
      const active = document.activeElement;
      const lost = !active || active === document.body || active === document.documentElement || !active.isConnected;
      if (!lost) return;
      state.repairing = true;
      const target = usable(state.element) ? state.element : findReplacement(state.fingerprint);
      focusWithoutScroll(target);
      if (target) remember(target);
      setTimeout(function () { state.repairing = false; }, 0);
    }, 35);
  }

  document.addEventListener('focusin', function (e) { remember(e.target); }, true);
  ['keydown', 'pointerdown', 'mousedown', 'touchstart', 'click'].forEach(function (type) {
    document.addEventListener(type, function (e) { remember(e.target); }, true);
  });

  /* Normalize live regions once. Never clear or rebuild them: that was causing extra JAWS buffer refreshes. */
  function normalizeLive(root) {
    const regions = [];
    if (root && root.nodeType === 1 && root.matches('[aria-live]')) regions.push(root);
    if (root && root.querySelectorAll) regions.push.apply(regions, root.querySelectorAll('[aria-live]'));
    regions.forEach(function (region) {
      if (region.getAttribute('aria-live') === 'assertive') region.setAttribute('aria-live', 'polite');
      if (!region.hasAttribute('aria-atomic')) region.setAttribute('aria-atomic', 'true');
      region.setAttribute('aria-relevant', 'text');
    });
  }
  normalizeLive(document);

  const observer = new MutationObserver(function (mutations) {
    let changed = false;
    mutations.forEach(function (m) {
      if (m.type === 'childList') {
        changed = true;
        m.addedNodes.forEach(function (node) { if (node.nodeType === 1) normalizeLive(node); });
      }
      if (m.type === 'attributes' && m.attributeName === 'aria-live' && m.target.getAttribute('aria-live') === 'assertive') {
        m.target.setAttribute('aria-live', 'polite');
      }
    });
    if (changed) repairFocus();
  });
  observer.observe(document.documentElement, { subtree: true, childList: true, attributes: true, attributeFilter: ['aria-live'] });

  document.addEventListener('submit', function (e) {
    const form = e.target;
    if (!form || !form.matches) return;
    const action = (form.getAttribute('action') || '').trim();
    if (!action || action === '#' || action.toLowerCase().startsWith('javascript:')) e.preventDefault();
  }, true);

  function restartGame() {
    const end = document.getElementById('end');
    if (end) end.hidden = true;
    const play = document.getElementById('play');
    if (play) play.hidden = false;
    const start = document.getElementById('start');
    if (start) {
      start.disabled = false;
      focusWithoutScroll(start);
      start.click();
      setTimeout(function () {
        const first = document.querySelector('#play:not([hidden]) button:not([disabled]), #play:not([hidden]) input:not([disabled]), #play:not([hidden]) select:not([disabled])');
        if (first) focusWithoutScroll(first);
      }, 60);
      return false;
    }
    return false;
  }

  window.BVRestartGame = restartGame;
  window.BVAccessibilityStability = {
    repairFocus: repairFocus,
    rememberFocus: remember,
    restartGame: restartGame,
    version: '2026-07-11b'
  };
})();
