/******/ (() => { // webpackBootstrap
/*!******************************************************!*\
  !*** ./src/assets/public/ai_chat_preview_runtime.js ***!
  \******************************************************/
function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof(o); }
/**
 * Preview-side runtime — loaded inside the chat iframe when `?fluent-form-ai=ID`
 * is rendered with `design_mode=1`.
 *
 * Responsibilities:
 *   1. Honor admin `postMessage` updates without resetting playback step:
 *        - `ff-ai-chat-preview-update`        instant CSS/DOM patch
 *        - `ff-ai-chat-preview-remount-current` re-mount current step bubble
 *        - `ff-ai-chat-preview-focus`         seek to step N, play, then resume
 *   2. Run a 3s auto-cycle through detected step bubbles in the chat (the
 *      "keep playing" feel the user explicitly asked for).
 *   3. Coalesce incoming messages within a single rAF (last write wins per key).
 *   4. Respond to `ff-ai-chat:speed-change` from the public header pill by
 *      setting `--ff-ai-chat-anim-duration-ms` on the root element. The chat
 *      shell's typing animation reads this variable to scale character delay.
 *
 * Reduced motion: auto-cycle is disabled when `prefers-reduced-motion: reduce`.
 */
(function () {
  'use strict';

  var TICK_MS = 3000;
  var SPEED_DEFAULT = 2;
  var BASE_DURATION_MS = 40;
  var pendingUpdates = {};
  var rafId = null;
  var cycleTimer = null;
  var focusedTimer = null;
  var inForcedFocus = false;
  var currentStep = 0;
  var currentState = 'welcome';
  function applySpeed(speed) {
    var n = parseInt(speed, 10);
    if (isNaN(n) || n < 1 || n > 4) n = SPEED_DEFAULT;
    var perChar = Math.max(8, Math.round(BASE_DURATION_MS / n));
    document.documentElement.style.setProperty('--ff-ai-chat-anim-duration-ms', perChar + 'ms');
    document.documentElement.style.setProperty('--ff-ai-chat-anim-speed', String(n));
  }
  function reducedMotion() {
    return window.matchMedia && window.matchMedia('(prefers-reduced-motion: reduce)').matches;
  }
  function detectSteps() {
    // The chat shell uses message bubbles; we treat each visible AI bubble as a step.
    // Fall back to .ff_ai_chat_step or .ffc_question if neither bubble class is present.
    var candidates = document.querySelectorAll('.ff-ai-chat-message.is-ai, .ff_ai_chat_message_ai, .ffc_question, .ff_ai_chat_step');
    return Array.prototype.slice.call(candidates);
  }
  function highlightStep(idx) {
    var steps = detectSteps();
    if (!steps.length) return;
    steps.forEach(function (el, i) {
      el.classList.toggle('is-current-preview-step', i === idx);
    });
    currentStep = idx;
    var el = steps[idx];
    if (el && typeof el.scrollIntoView === 'function') {
      el.scrollIntoView({
        behavior: reducedMotion() ? 'auto' : 'smooth',
        block: 'center'
      });
    }
  }
  function setPreviewState(state, stepIndex) {
    var steps = detectSteps();
    currentState = state || 'welcome';
    document.documentElement.setAttribute('data-ff-ai-preview-state', currentState);
    if (!steps.length) {
      try {
        window.dispatchEvent(new CustomEvent('ff-ai-chat:preview-state', {
          detail: {
            state: currentState,
            stepIndex: stepIndex
          }
        }));
      } catch (e) {}
      return;
    }
    var targetIndex = 0;
    switch (currentState) {
      case 'end':
        targetIndex = Math.max(steps.length - 1, 0);
        break;
      case 'focused_field':
        targetIndex = Number(stepIndex);
        if (isNaN(targetIndex)) {
          targetIndex = currentStep;
        }
        targetIndex = Math.max(0, Math.min(targetIndex, steps.length - 1));
        break;
      case 'first_field':
        targetIndex = steps.length > 1 ? 1 : 0;
        break;
      case 'privacy':
      case 'welcome':
      default:
        targetIndex = 0;
        break;
    }
    highlightStep(targetIndex);
    try {
      window.dispatchEvent(new CustomEvent('ff-ai-chat:preview-state', {
        detail: {
          state: currentState,
          stepIndex: targetIndex
        }
      }));
    } catch (e) {}
  }
  function replayCurrentState(stepIndex) {
    setPreviewState(currentState, stepIndex);
    try {
      window.dispatchEvent(new CustomEvent('ff-ai-chat:replay-current', {
        detail: {
          state: currentState,
          stepIndex: stepIndex
        }
      }));
    } catch (e) {}
  }
  function startAutoCycle() {
    if (reducedMotion()) return;
    stopAutoCycle();
    cycleTimer = setInterval(function () {
      if (inForcedFocus) return;
      var steps = detectSteps();
      if (!steps.length) return;
      var next = (currentStep + 1) % steps.length;
      highlightStep(next);
    }, TICK_MS);
  }
  function stopAutoCycle() {
    if (cycleTimer) {
      clearInterval(cycleTimer);
      cycleTimer = null;
    }
  }
  function flushUpdates() {
    rafId = null;
    var keys = Object.keys(pendingUpdates);
    keys.forEach(function (k) {
      var v = pendingUpdates[k];
      if (k === 'speed') {
        applySpeed(v);
      } else if (k === 'config' && v && _typeof(v) === 'object') {
        // `update` with key=config: apply chrome-level changes via the existing
        // `ff_ai_chat_preview_config` listener path (already in place for backward compat).
        try {
          window.dispatchEvent(new CustomEvent('ff-ai-chat:config-update', {
            detail: v
          }));
        } catch (e) {}
      }
      delete pendingUpdates[k];
    });
  }
  function queueUpdate(key, value) {
    pendingUpdates[key] = value;
    if (rafId === null) {
      rafId = window.requestAnimationFrame(flushUpdates);
    }
  }
  function handleMessage(e) {
    var data = e && e.data;
    if (!data || _typeof(data) !== 'object' || !data.type) return;
    switch (data.type) {
      case 'ff-ai-chat-preview-update':
        queueUpdate(data.key || 'config', data.value);
        break;
      case 'ff-ai-chat-preview-remount-current':
        // Trigger a soft re-render of the current step's bubble without resetting playback.
        try {
          window.dispatchEvent(new CustomEvent('ff-ai-chat:remount-current', {
            detail: data.payload || {}
          }));
        } catch (err) {}
        break;
      case 'ff-ai-chat-preview-focus':
        // Seek to a specific step, play it, then resume free-play after 4 ticks.
        inForcedFocus = true;
        highlightStep(Number(data.stepIndex) || 0);
        currentState = 'focused_field';
        clearTimeout(focusedTimer);
        focusedTimer = setTimeout(function () {
          inForcedFocus = false;
        }, TICK_MS + 1000);
        break;
      case 'ff-ai-chat-preview-state':
        setPreviewState(data.state, data.stepIndex);
        break;
      case 'ff-ai-chat-preview-replay':
        replayCurrentState(data.stepIndex);
        break;
    }
  }
  function init() {
    // Seed speed from CSS var (set by ai_chat_public_header.js) or default to 2x.
    var seeded = parseInt(document.documentElement.style.getPropertyValue('--ff-ai-chat-anim-speed'), 10);
    applySpeed(isNaN(seeded) ? SPEED_DEFAULT : seeded);
    window.addEventListener('message', handleMessage);
    document.addEventListener('ff-ai-chat:speed-change', function (e) {
      queueUpdate('speed', e.detail && e.detail.speed || SPEED_DEFAULT);
    });

    // Wait for the chat shell to render bubbles before starting cycle.
    var attempt = 0;
    var poll = setInterval(function () {
      attempt++;
      if (detectSteps().length || attempt > 40) {
        clearInterval(poll);
        highlightStep(0);
        startAutoCycle();
      }
    }, 500);
  }
  if (document.readyState === 'loading') {
    document.addEventListener('DOMContentLoaded', init);
  } else {
    init();
  }
})();
/******/ })()
;