@flowengage/react-chatbot 7.0.12 → 7.0.14
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -631,11 +631,11 @@ registerProcessor("scribeAudioProcessor", ScribeAudioProcessor);
|
|
|
631
631
|
<path d="M4 2L19 10.5L11 12.8L8 20L4 2Z"
|
|
632
632
|
fill="white" stroke="#1e1b4b" stroke-width="1.6" stroke-linejoin="round"
|
|
633
633
|
filter="url(#${Q}-csh)"/>
|
|
634
|
-
</svg>`,CO=null,wO=!1;function TO(){return(!CO||!CO.isConnected)&&(CO=document.createElement(`div`),CO.id=`${Q}-cursor`,CO.innerHTML=SO,document.body.appendChild(CO),wO=!1),CO}async function EO(e){if(typeof document>`u`||!e)return;cO();let t;try{t=e.getBoundingClientRect()}catch{return}let n=t.left+Math.min(16,t.width*.2),r=t.top+Math.min(12,t.height*.25),i=TO();wO||=(i.style.transition=`none`,i.style.left=`${window.innerWidth/2}px`,i.style.top=`${window.innerHeight*.4}px`,i.classList.add(`${Q}-cursor-visible`),i.offsetHeight,i.style.transition=`left 0.32s cubic-bezier(0.25,0.46,0.45,0.94), top 0.32s cubic-bezier(0.25,0.46,0.45,0.94), opacity 0.2s ease`,!0),i.style.left=`${n}px`,i.style.top=`${r}px`,await AO(360)}function DO(e=!1){CO&&(e?(CO.classList.remove(`${Q}-cursor-visible`),wO=!1):(CO.classList.remove(`${Q}-cursor-visible`),setTimeout(()=>{wO=!1},250)))}async function OO(e){CO&&(CO.classList.add(`${Q}-cursor-click`),await AO(280),CO.classList.remove(`${Q}-cursor-click`))}function kO(e){if(!e||typeof document>`u`)return;cO();let t;try{t=e.getBoundingClientRect()}catch{return}let n=e.style.position,r=e.style.overflow,i=window.getComputedStyle(e).position;[`relative`,`absolute`,`fixed`,`sticky`].includes(i)||(e.style.position=`relative`),e.style.overflow=`hidden`;let a=document.createElement(`span`);a.className=`${Q}-ripple`;let o=Math.max(t.width,t.height)*1.2;Object.assign(a.style,{width:`${o}px`,height:`${o}px`,left:`${t.width/2-o/2}px`,top:`${t.height/2-o/2}px`}),e.appendChild(a),setTimeout(()=>{a.remove(),e.style.position=n,e.style.overflow=r},650)}function AO(e){return new Promise(t=>setTimeout(t,e))}function $(...e){kn()&&console.log(`[FlowEngage:voice-tools]`,...e)}function jO(e){return new Promise(t=>setTimeout(t,e))}var MO=`#flowengage-root, .flowengage-shell, .flowengage-widget-root`;function NO(e){if(!e||typeof e.closest!=`function`)return!1;try{return!!e.closest(MO)}catch{return!1}}function PO(e){try{let t=e.ownerDocument?.defaultView;if(t)return t.getComputedStyle(e)}catch{}return window.getComputedStyle(e)}function FO(e){let t=new Set;function n(r){if(!r||t.has(r))return;t.add(r),e(r);let i=r.querySelectorAll(`iframe`);for(let e of i)if(!NO(e))try{let t=e.contentDocument;t&&n(t)}catch{}}typeof document<`u`&&n(document)}function IO(e){return e==null?null:String(e).replace(/\u00a0/g,` `).replace(/\s*\*+\s*$/u,``).replace(/\s+/g,` `).trim()}function LO(e){let t=e.ownerDocument||document,n=e.getAttribute(`aria-labelledby`);if(n){let e=n.trim().split(/\s+/).filter(Boolean),r=[];for(let n of e)try{let e=t.getElementById(n);e?.textContent&&r.push(e.textContent.trim())}catch{}if(r.length)return IO(r.join(` `))}if(e.labels&&e.labels.length)return IO(e.labels[0].textContent);let r=e.id;if(r)try{let e=t.querySelector(`label[for="${CSS.escape(r)}"]`);if(e)return IO(e.textContent)}catch{let e=t.querySelector(`label[for="${r.replace(/"/g,`\\"`)}"]`);if(e)return IO(e.textContent)}let i=e.previousElementSibling;for(let e=0;e<6&&i;e+=1){if(i.tagName===`LABEL`)return IO(i.textContent);let e=(i.className||``).toString().toLowerCase();if(/chakra-form__label|formlabel|field-label|form-label|mui-form-label/.test(e)){let e=IO(i.textContent);if(e)return e}i=i.previousElementSibling}let a=e.parentElement;for(let e=0;e<5&&a;e+=1){if(a.tagName===`LABEL`)return IO(a.textContent);let e=a.querySelector?.(`:scope > label, :scope > [class*='FormLabel'], :scope > [class*='form__label']`);if(e?.textContent)return IO(e.textContent);a=a.parentElement}let o=e.getAttribute(`aria-label`);return o?IO(o):null}function RO(){let e=[];return FO(t=>{e.push(...Array.from(t.querySelectorAll(`input, select, textarea`)).filter(e=>{if(NO(e))return!1;let t=(e.type||``).toLowerCase();if([`hidden`,`submit`,`button`,`image`].includes(t)||e.disabled||e.readOnly)return!1;try{let t=PO(e);if(t.display===`none`||t.visibility===`hidden`)return!1}catch{}return!0}))}),e}function zO(){return RO().map((e,t)=>{let n={formIndex:0,fieldIndex:t,tag:e.tagName,type:e.type||`text`,name:e.name||null,id:e.id||null,label:LO(e),placeholder:e.placeholder||null};return e.tagName===`SELECT`&&(n.options=Array.from(e.options).filter(e=>e.value!==``&&!e.disabled).map(e=>({value:e.value,text:e.text.trim()})),n.currentValue=e.value||null),n})}function BO(){let e=[];return FO(t=>{e.push(...Array.from(t.querySelectorAll(`button, [role="button"], input[type="submit"], input[type="button"]`)).filter(e=>{if(NO(e)||e.disabled)return!1;try{let t=PO(e);if(t.display===`none`||t.visibility===`hidden`)return!1}catch{}return!0}))}),e.slice(0,60).map((e,t)=>({index:t,text:(e.textContent||e.value||``).replace(/\s+/g,` `).trim().slice(0,120)||null,ariaLabel:e.getAttribute(`aria-label`),type:e.type||e.tagName}))}function VO(e){return String(e||``).toLowerCase().replace(/\u00a0/g,` `).replace(/\*/g,``).replace(/\s+/g,` `).trim()}function HO(e){let t=VO(e);return t=t.replace(/\s+field\s*$/i,``).trim(),t}function UO(e,t){let n=HO(t);if(!n)return 0;let r=(e.name||``).toLowerCase(),i=(e.id||``).toLowerCase();if(r===`url`&&/url|website|domain|site|audit/.test(n)||(i===`url-input`||i.endsWith(`-url-input`))&&/url|website|domain|site|audit/.test(n))return 100;let a=[e.name,e.id,e.placeholder,LO(e),e.getAttribute(`aria-label`),e.getAttribute(`title`),e.getAttribute(`data-testid`),e.getAttribute(`autocomplete`)].filter(Boolean).map(e=>VO(e)),o=0;for(let e of a){if(!e)continue;if(e.includes(n)||n.includes(e)){o=Math.max(o,100);continue}let t=n.split(/\s+/).filter(e=>e.length>1);if(!t.length)continue;let r=0;for(let n of t)e.includes(n)&&(r+=1);o=Math.max(o,r/t.length*88)}return o}var WO=28;function GO(e,t){let n=null,r=0;for(let i of e){let e=UO(i,t);e>r&&(r=e,n=i)}return!n||r<WO?null:n}function KO(e,t,n){let r=String(t||``).toLowerCase().trim(),i=String(n||``).trim();if(!(/^https?:\/\//i.test(i)||/\.\w{2,}(\/|\s|$)/.test(i)||r.includes(`url`)||r.includes(`website`)||r.includes(`domain`)||r.includes(`site`)))return null;let a=null,o=0;for(let t of e){if(t.tagName!==`INPUT`&&t.tagName!==`TEXTAREA`)continue;let e=(t.type||``).toLowerCase();if([`hidden`,`submit`,`button`,`checkbox`,`radio`].includes(e))continue;let n=0;(e===`url`||e===`text`||e===`search`)&&(n+=45);let r=[t.name,t.id,t.placeholder,LO(t),t.getAttribute(`aria-label`),t.getAttribute(`autocomplete`)].filter(Boolean).join(` `).toLowerCase();/(website|url|domain|site\s*url)/.test(r)&&(n+=55),n>o&&(o=n,a=t)}return!a||o<42?null:a}function qO(e){let t=String(e??``).trim();return t?/^https?:\/\//i.test(t)?!0:/\.\w{2,}(\/|\s|$)/.test(t):!1}function JO(e){let t=String(e??``).toLowerCase().trim();return t?!!(t===`url`||t===`website`||t===`website url`||t===`website_url`||t===`enter website url`||t.includes(`website`)||t.includes(`domain`)||/(enter\s+website|site\s*url|page\s*url)/.test(t)):!1}function YO(e){if(!e||e.tagName!==`INPUT`&&e.tagName!==`TEXTAREA`)return!1;let t=(e.type||``).toLowerCase();return![`hidden`,`submit`,`button`,`checkbox`,`radio`,`file`].includes(t)}function XO(e){if(!YO(e))return!1;let t=(e.name||``).toLowerCase(),n=(e.id||``).toLowerCase(),r=[e.name,e.id,e.placeholder,LO(e),e.getAttribute(`aria-label`)].filter(Boolean).join(` `).toLowerCase();return t===`url`||n===`url-input`||n.endsWith(`-url-input`)||/(website\s*url|enter\s+website|site\s*url)/.test(r)||/(website|domain)/.test(r)&&/(url|site)/.test(r)}function ZO(e,t,n){let r=String(t??``),i=String(n??``),a=ek(e,r)||GO(e,r)||KO(e,r,i);if(!a)return[];let o=new Set([a]);if(qO(i)&&JO(r))for(let t of e)t!==a&&XO(t)&&o.add(t);let s=Array.from(o);return s.sort((e,t)=>{if(e===t)return 0;let n=e.compareDocumentPosition(t);return n&Node.DOCUMENT_POSITION_FOLLOWING?-1:n&Node.DOCUMENT_POSITION_PRECEDING?1:0}),s}function QO(e,t){try{if(!e?.getBoundingClientRect||!t?.getBoundingClientRect)return 1/0;let n=e.getBoundingClientRect(),r=t.getBoundingClientRect(),i={x:n.left+n.width/2,y:n.top+n.height/2},a={x:r.left+r.width/2,y:r.top+r.height/2};return Math.hypot(i.x-a.x,i.y-a.y)}catch{return 1/0}}function $O(e){if(!e||typeof e!=`string`)return null;let t=null;return FO(n=>{try{let r=n.getElementById(e);r&&!NO(r)&&r.matches?.(`input, select, textarea`)&&(t=r)}catch{}}),t}function ek(e,t){let n=String(t??``).trim();if(!n)return null;let r=n.match(/^name:\s*([\w.-]+)$/i);if(r){let t=r[1];for(let n of e)if(n.name===t)return n}let i=n.match(/^id:\s*([\w.-]+)$/i);if(i){let e=$O(i[1]);if(e)return e}let a=n.startsWith(`#`)?n.slice(1):n;if(/^[\w-]+$/.test(a)){let e=$O(a);if(e)return e}let o=n.toLowerCase().replace(/\s+/g,` `);if(o===`url`||o===`website`||o===`website url`||o===`website_url`||o===`enter website url`)for(let t of e){let e=(t.name||``).toLowerCase(),n=(t.id||``).toLowerCase();if(e===`url`||n===`url-input`||n.endsWith(`-url-input`))return t}return null}function tk(e,t){let n=String(t||``).toLowerCase().trim();if(!n)return 0;let r=(e.innerText||e.textContent||``).replace(/\s+/g,` `).trim(),i=[r,e.value,e.getAttribute(`aria-label`),e.getAttribute(`title`),e.getAttribute(`data-text`),e.getAttribute(`data-label`)].filter(Boolean).join(` `).toLowerCase().replace(/\s+/g,` `);if(i.includes(n)||r.toLowerCase()===n)return 100;let a=n.split(/\s+/).filter(e=>e.length>1);if(!a.length)return 0;let o=0;for(let e of a)i.includes(e)&&(o+=1);return o/a.length*92}function nk(e,t){let n=[];FO(e=>{let t=Array.from(e.querySelectorAll(`button, [role="button"], input[type="submit"], input[type="button"], a[href]`));n.push(...t.filter(e=>{if(NO(e)||e.disabled)return!1;try{let t=PO(e);if(t.display===`none`||t.visibility===`hidden`||t.opacity===`0`)return!1}catch{}return!0}))});let r=0,i=n.map(t=>({el:t,s:tk(t,e)}));for(let{s:e}of i)e>r&&(r=e);if(r<28)return null;let a=i.filter(({s:e})=>e===r).map(({el:e})=>e);if(a.length===1)return a[0];let o=Array.isArray(t)?t.filter(e=>e&&e.isConnected):[];if(o.length){let e=a[0],t=1/0;for(let n of a)for(let r of o){let i=QO(n,r);i<t&&(t=i,e=n)}return e}return a[0]}function rk(e){if(e==null)return{};if(typeof e==`string`){let t=e.trim();if(!t)return{};try{return JSON.parse(t)}catch{return{url:t}}}return e}function ik(e){let t=rk(e);if(Array.isArray(t)&&t.length>0){let e=t[0];if(e?.field_key!=null||e?.fieldKey!=null)return t.map(e=>({field_key:e.field_key??e.fieldKey,value:e.value}))}if(!t||typeof t!=`object`)return[];let n=t.fields??t.Fields??t.field_list??t.fieldList??t.data?.fields;if(typeof n==`string`)try{n=JSON.parse(n)}catch{n=null}n&&!Array.isArray(n)&&typeof n==`object`&&(n=Object.values(n)),(!n||n.length===0)&&(t.field_key!=null||t.fieldKey!=null)&&t.value!=null&&(n=[{field_key:t.field_key??t.fieldKey,value:t.value}]);let r=t.website_url??t.websiteUrl??t.url??t.website??t.domain??t.site_url??t.siteUrl;return(!n||n.length===0)&&r!=null&&String(r).trim()&&(n=[{field_key:t.field_key??t.fieldKey??`url`,value:String(r).trim()}]),Array.isArray(n)?n.map(e=>({field_key:e?.field_key??e?.fieldKey,value:e?.value??e?.Value})):[]}function ak(e){if(!e||typeof e!=`string`)return[];let t=e.trim();if(!t||/\b[a-z0-9._%+-]+@[a-z0-9.-]+\.[a-z]{2,}\b/i.test(t))return[];let n=t.match(/https?:\/\/[^\s<>"']+/i);if(n)return[{field_key:`url`,value:n[0].replace(/[.,;:)]+$/,``)}];let r=t.match(/\b(?:[\w-]+\.)+[a-z]{2,}\b/i);if(r){let e=r[0].replace(/[.,;:)]+$/,``);return/^https?:/i.test(e)||(e=`https://${e}`),[{field_key:`url`,value:e}]}return[]}function ok(e){if(!e||typeof e!=`string`)return[];let t=e.trim();if(!t)return[];let n=[],r=new Set,i=/\b([a-z0-9._%+-]+@[a-z0-9.-]+\.[a-z]{2,})\b/i,a=(e,t)=>{let i=String(t??``).trim().replace(/^["']|["']$/g,``);if(!i||i.length>800)return;let a=`${e}\0${i}`;r.has(a)||(r.add(a),n.push({field_key:e,value:i}))},o=t.match(/^\s*([a-z0-9._%+-]+@[a-z0-9.-]+\.[a-z]{2,})\s*$/i);if(o)return a(`Email Address`,o[1]),n;let s=t.match(/\b(?:please\s+)?(?:enter|type|put)\s+(.+?)\s+in(?:to)?\s+(?:the\s+)?(?:full\s*name|full\s*name\s*field|name\s*field)\b/i);if(s&&a(`Full Name`,s[1]),s=t.match(/\bfull\s*name,?\s*(?:please\s+)?(?:enter|type|put)\s+(.+?)(?:\.|$|!|\?)/i),s&&a(`Full Name`,s[1]),s=t.match(/\bfull\s*name\s*(?:is|:|please\s+enter|-)\s*(.+?)(?:\.|$|(?=\s+(?:and|my\s+email|email|message))\b)/i),s&&a(`Full Name`,s[1]),s=t.match(/\b(.+?)\s+for\s+(?:the\s+)?full\s*name\b/i),s){let e=s[1].trim();e.length>1&&e.length<120&&!/@/.test(e)&&a(`Full Name`,e)}if(s=t.match(/\b(?:email|e-mail)(?:\s*address)?\s*(?:is|:|please\s+use|enter|-)\s*([^\s@]+@[^\s@]+\.[^\s,]+)/i),s&&a(`Email Address`,s[1]),s=t.match(/\b(?:enter|type|put)\s+([^\s@]+@[^\s@]+\.[^\s,]+)\s+in(?:to)?\s+(?:the\s+)?(?:email|e-mail)/i),s&&a(`Email Address`,s[1]),s=t.match(/\b(?:message|comment)\s*(?:is|:|please\s+enter|-)\s*(.+)$/is),s){let e=s[1].trim();e.length>0&&a(`Message`,e)}if(!n.some(e=>/email/i.test(String(e.field_key)))){let e=t.match(i);if(e){let r=t.replace(e[0],``).trim().replace(/^(please|it's|it is|use|is|my email is|e-?mail is)\s*/i,``).replace(/[.,;:!?]+$/,``).trim();if(t.length<=96&&r.length<=36)return a(`Email Address`,e[1]),n}}if(n.length===0){let e=t.split(/\s+/).filter(Boolean).length,n=/[.!?]/.test(t)||e>=6||t.length>=24&&e>=5||t.length>=42,r=/^[A-Z][a-z]+\s+[A-Z][a-z]+$/.test(t.trim());n&&t.length>=16&&!i.test(t)&&!r&&a(`Message`,t)}return n}function sk(e){if(!e||typeof e!=`object`)return null;let t=e.url??e.target_url??e.page_url??e.pageUrl??e.link??e.href??e.path;return t==null?null:String(t).trim()||null}function ck(e,t,n){if(!n?.skipScroll)try{e.scrollIntoView({block:`center`,inline:`nearest`})}catch{try{e.scrollIntoView(!0)}catch{}}try{e.focus({preventScroll:!0})}catch{try{e.focus()}catch{}}let r=e.tagName,i=(e.type||``).toLowerCase();if(r===`SELECT`)return e.value=String(t),e.dispatchEvent(new Event(`input`,{bubbles:!0})),e.dispatchEvent(new Event(`change`,{bubbles:!0})),!0;if(i===`checkbox`||i===`radio`)return e.checked=[`1`,`true`,`yes`,`on`].includes(String(t).toLowerCase().trim()),e.dispatchEvent(new Event(`input`,{bubbles:!0})),e.dispatchEvent(new Event(`change`,{bubbles:!0})),!0;let a=String(t);if(r===`INPUT`||r===`TEXTAREA`){let t=e.ownerDocument?.defaultView||window,n=r===`TEXTAREA`?t.HTMLTextAreaElement.prototype:t.HTMLInputElement.prototype,i=Object.getOwnPropertyDescriptor(n,`value`);i?.set?i.set.call(e,a):e.value=a}else e.value=a;let o={bubbles:!0,cancelable:!0,composed:!0};try{e.dispatchEvent(new InputEvent(`input`,{...o,inputType:`insertText`,data:a}))}catch{e.dispatchEvent(new Event(`input`,o))}e.dispatchEvent(new Event(`change`,o));try{queueMicrotask(()=>{try{e.dispatchEvent(new Event(`input`,o)),e.dispatchEvent(new Event(`change`,o))}catch{}})}catch{}return!0}function lk(){let e={};document.querySelectorAll(`h1, h2, h3, h4, h5, h6`).forEach(t=>{if(t.id)return;let n=t.textContent.trim();if(!n)return;let r=n.toLowerCase().replace(/[^a-z0-9]+/g,`-`).replace(/^-|-$/g,``).substring(0,60);if(e[r]){let t=2;for(;e[r+`-`+t];)t++;r=r+`-`+t}e[r]=!0,t.id=r})}function uk(){let e=e=>Array.from(e).filter(e=>!e.closest(`#flowengage-root, .flowengage-shell, .flowengage-widget-root`)).map(e=>e.textContent.replace(/\s+/g,` `).trim()).filter(e=>e.length>2&&e.length<200),t=e((document.querySelector(`main, [role='main']`)||document.body).querySelectorAll(`h1, h2, h3`));return t.length||(t=e(document.body.querySelectorAll(`h1, h2, h3`))),t.length||(t=e(document.body.querySelectorAll(`h4, h5`))),[...new Set(t)].slice(0,15)}function dk(e){let t=e.siteId||null,n=(e.apiBaseUrl||``).replace(/\/$/,``),r=typeof e.getLastUserVoiceText==`function`?e.getLastUserVoiceText:null,i=[],a={"fwh-navigate-mvp":async n=>{$(`fwh-navigate-mvp ▶ raw parameters:`,n);let i=rk(n),a=sk(i),o=i.section_text??i.sectionText??i.section,s=Array.isArray(i.expected_landmarks)?i.expected_landmarks:Array.isArray(i.expectedLandmarks)?i.expectedLandmarks:[];if($(`fwh-navigate-mvp · coerced:`,{url:a,sectionText:o,expectedLandmarks:s}),!a){let e=`Missing url: pass a string url, path like /pricing, or JSON with a url field.`;return $(`fwh-navigate-mvp ✖`,e),e}if(typeof window<`u`)try{let e=new URL(a,window.location.href);e.origin!==window.location.origin&&/^https?:$/i.test(e.protocol)&&(a=e.pathname+e.search+e.hash,$(`fwh-navigate-mvp · normalized cross-origin URL to path:`,a))}catch{}if(typeof window<`u`){try{let e=new URL(a,window.location.href);if(e.pathname===window.location.pathname&&e.search===window.location.search)return $(`fwh-navigate-mvp ✖ already on page, skipping`),`OK_ALREADY_ON_PAGE. The visitor is already on this page. Do not navigate. Proceed directly with highlights, answering the question, or reading page content.`}catch{}let e=window.__fe_user_nav_during_speech;if(e&&Date.now()-e.ts<3e4)try{if(new URL(a,window.location.href).pathname===e.fromPath)return $(`flowengage_navigate ✖ blocked — would navigate back to page visitor just left`,e),`NAV_BLOCKED: The visitor just left "${e.fromPageName}" and is now on "${e.toPageName}". Do NOT navigate them back. If they said "continue", resume verbally from where you left off — no navigation needed. If they want to return, they will navigate themselves.`}catch{}}if(!await fr(a,{siteId:t,apiBaseUrl:e.apiBaseUrl})){let e=`Page "${a}" could not be verified. Try a different URL from your known site pages, or ask the visitor to clarify which page they want.`;return $(`fwh-navigate-mvp ✖ blocked`,e),e}try{fO(`Navigating to ${a}...`,{spinner:!0}),_O(),dD();try{let e=r?r():``;if(e&&t){let n=sO([{sender:`user`,message:e}]);n&&xe(t,n)}}catch{}Te();let e=a;try{e=new URL(a,typeof window<`u`?window.location.href:``).href}catch{}t&&typeof window<`u`&&Me(t,window.location.href,e),hr(e),$(`fwh-navigate-mvp → real navigation`,a);let n=typeof window<`u`&&!!Kn();if(typeof window<`u`&&window.__fe_triggerVoiceNavHooks&&window.__fe_triggerVoiceNavHooks(),n&&Ln(12e3),vr(a,{voiceActive:!0}).catch(()=>{}),n)try{let e=new URL(a,window.location.origin).pathname,t=Date.now()+2e3;for(;Date.now()<t&&!(typeof window<`u`&&window.location.pathname===e);)await new Promise(e=>setTimeout(e,80));let n=typeof window<`u`?window.location.pathname:e,r=typeof window<`u`?window.location.href:a,i=n===e,o=(n.split(`/`).filter(Boolean).pop()||``).replace(/[-_]/g,` `).replace(/\b\w/g,e=>e.toUpperCase())||`Home`;$(`fwh-navigate-mvp → SPA nav complete. target:`,e,`actual:`,n);try{typeof window<`u`&&window.scrollTo(0,0)}catch{}let s=[],c=Date.now()+12e3;for(;Date.now()<c&&(await new Promise(e=>setTimeout(e,300)),s=uk(),!(s.length>=1)););lk(),$(`fwh-navigate-mvp → page headings collected:`,s);let l=s.length?s.join(` | `):`none`,u=s.length?`Use ONLY these exact heading strings for fwh-highlight-mvp — never invent or abbreviate.`:`No headings collected yet — call fwh-get-current-page-mvp immediately (no speech) to get the live headings before speaking or highlighting.`;return i?(gr(),`OK_NAVIGATE_SPA. Visitor is now on: ${r} (page: "${o}") | Section headings: ${l}. ${u} Speak 2-3 sentences about this page from your knowledge. Then ask: "Would you like to know about a specific section, or should I give you a complete overview?" Then STOP — wait for their reply. Do NOT auto-highlight any sections.`):(gr(),`OK_NAVIGATE_SPA. CURRENT PAGE IS: ${r} (page: "${o}") | Section headings: ${l}. ${u} Speak 2-3 sentences about this page from your knowledge. Then ask: "Would you like to know about a specific section, or should I give you a complete overview?" Then STOP — wait for their reply. Do NOT auto-highlight any sections.`)}catch{}return`OK_NAVIGATE_RELOADING. Navigating to the page now; the voice session will resume automatically on the new page. When the session resumes, speak 2-3 sentences about the page, then ask: "Would you like to know about a specific section, or should I give you a complete overview?" Wait for the visitor's reply.`}catch(e){let t=`Navigation error: ${e?.message||String(e)}`;return $(`fwh-navigate-mvp ✖`,t),fO(`Navigation failed`,{spinner:!1,icon:`⚠️`,duration:1800}),t}finally{vO(),pO(900)}},"fwh-highlight-mvp":async e=>{$(`fwh-highlight-mvp ▶`,e);let t=rk(e),n=t?.section_id||t?.sectionId,r=t?.section_text||t?.sectionText;if(typeof window<`u`&&window.__fe_user_nav_during_speech){let e=window.__fe_user_nav_during_speech,t=window.location.pathname;if(Date.now()-e.ts>=3e4)window.__fe_user_nav_during_speech=null;else return $(`flowengage_highlight ✖ blocked — user navigated during speech`,e),`NAV_CHANGED: The visitor navigated from "${e.fromPageName}" to "${e.toPageName}" (current path: ${t}) while you were speaking. STOP the current walkthrough immediately. DO NOT call flowengage_highlight again. Say out loud: "I see you've navigated to the ${e.toPageName} page — do you want me to continue what I was explaining, or shall I guide you through this page?" Wait for the visitor's answer before doing anything else.`}lk();let i=(e=>e&&e.replace(/^\d+\.\s*/,``).replace(/^["']|["']$/g,``).trim())(r),a=sr(n||null,i||null);if(!a&&i){let e=Date.now()+600;for(;!a&&Date.now()<e;)await new Promise(e=>setTimeout(e,50)),lk(),a=sr(null,i)}if(!a){$(`fwh-highlight-mvp ✖ no element for:`,i||n);let e=uk(),t=e.length?`Page headings: ${e.map(e=>`"${e}"`).join(` | `)}. Use one of these EXACT strings for section_text — no numbers, no quotes around them.`:`No headings found — skip highlight and continue speaking.`;return`HIGHLIGHT_NOT_FOUND: "${i||n}" on the current page. ${t}`}return uD(a),$(`fwh-highlight-mvp ✓`,i||n),`OK_HIGHLIGHT: "${i||n}". WALKTHROUGH: continue immediately to the next section — do NOT pause between sections.`},"fwh-read-content-mvp":async e=>{$(`fwh-read-content-mvp ▶`,e);let t=rk(e),n=t?.section_text||t?.sectionText||``;try{let e=``;if(n){let t=sr(null,n);if(!t)return`Could not find section "${n}" on the page.`;let r=[t.textContent.trim()],i=t.nextElementSibling;for(;i&&!/^H[1-3]$/i.test(i.tagName);){let e=i.textContent.trim();e&&r.push(e),i=i.nextElementSibling}e=r.join(`
|
|
634
|
+
</svg>`,CO=null,wO=!1;function TO(){return(!CO||!CO.isConnected)&&(CO=document.createElement(`div`),CO.id=`${Q}-cursor`,CO.innerHTML=SO,document.body.appendChild(CO),wO=!1),CO}async function EO(e){if(typeof document>`u`||!e)return;cO();let t;try{t=e.getBoundingClientRect()}catch{return}let n=t.left+Math.min(16,t.width*.2),r=t.top+Math.min(12,t.height*.25),i=TO();wO||=(i.style.transition=`none`,i.style.left=`${window.innerWidth/2}px`,i.style.top=`${window.innerHeight*.4}px`,i.classList.add(`${Q}-cursor-visible`),i.offsetHeight,i.style.transition=`left 0.32s cubic-bezier(0.25,0.46,0.45,0.94), top 0.32s cubic-bezier(0.25,0.46,0.45,0.94), opacity 0.2s ease`,!0),i.style.left=`${n}px`,i.style.top=`${r}px`,await AO(360)}function DO(e=!1){CO&&(e?(CO.classList.remove(`${Q}-cursor-visible`),wO=!1):(CO.classList.remove(`${Q}-cursor-visible`),setTimeout(()=>{wO=!1},250)))}async function OO(e){CO&&(CO.classList.add(`${Q}-cursor-click`),await AO(280),CO.classList.remove(`${Q}-cursor-click`))}function kO(e){if(!e||typeof document>`u`)return;cO();let t;try{t=e.getBoundingClientRect()}catch{return}let n=e.style.position,r=e.style.overflow,i=window.getComputedStyle(e).position;[`relative`,`absolute`,`fixed`,`sticky`].includes(i)||(e.style.position=`relative`),e.style.overflow=`hidden`;let a=document.createElement(`span`);a.className=`${Q}-ripple`;let o=Math.max(t.width,t.height)*1.2;Object.assign(a.style,{width:`${o}px`,height:`${o}px`,left:`${t.width/2-o/2}px`,top:`${t.height/2-o/2}px`}),e.appendChild(a),setTimeout(()=>{a.remove(),e.style.position=n,e.style.overflow=r},650)}function AO(e){return new Promise(t=>setTimeout(t,e))}function $(...e){kn()&&console.log(`[FlowEngage:voice-tools]`,...e)}function jO(e){return new Promise(t=>setTimeout(t,e))}var MO=`#flowengage-root, .flowengage-shell, .flowengage-widget-root`;function NO(e){if(!e||typeof e.closest!=`function`)return!1;try{return!!e.closest(MO)}catch{return!1}}function PO(e){try{let t=e.ownerDocument?.defaultView;if(t)return t.getComputedStyle(e)}catch{}return window.getComputedStyle(e)}function FO(e){let t=new Set;function n(r){if(!r||t.has(r))return;t.add(r),e(r);let i=r.querySelectorAll(`iframe`);for(let e of i)if(!NO(e))try{let t=e.contentDocument;t&&n(t)}catch{}}typeof document<`u`&&n(document)}function IO(e){return e==null?null:String(e).replace(/\u00a0/g,` `).replace(/\s*\*+\s*$/u,``).replace(/\s+/g,` `).trim()}function LO(e){let t=e.ownerDocument||document,n=e.getAttribute(`aria-labelledby`);if(n){let e=n.trim().split(/\s+/).filter(Boolean),r=[];for(let n of e)try{let e=t.getElementById(n);e?.textContent&&r.push(e.textContent.trim())}catch{}if(r.length)return IO(r.join(` `))}if(e.labels&&e.labels.length)return IO(e.labels[0].textContent);let r=e.id;if(r)try{let e=t.querySelector(`label[for="${CSS.escape(r)}"]`);if(e)return IO(e.textContent)}catch{let e=t.querySelector(`label[for="${r.replace(/"/g,`\\"`)}"]`);if(e)return IO(e.textContent)}let i=e.previousElementSibling;for(let e=0;e<6&&i;e+=1){if(i.tagName===`LABEL`)return IO(i.textContent);let e=(i.className||``).toString().toLowerCase();if(/chakra-form__label|formlabel|field-label|form-label|mui-form-label/.test(e)){let e=IO(i.textContent);if(e)return e}i=i.previousElementSibling}let a=e.parentElement;for(let e=0;e<5&&a;e+=1){if(a.tagName===`LABEL`)return IO(a.textContent);let e=a.querySelector?.(`:scope > label, :scope > [class*='FormLabel'], :scope > [class*='form__label']`);if(e?.textContent)return IO(e.textContent);a=a.parentElement}let o=e.getAttribute(`aria-label`);return o?IO(o):null}function RO(){let e=[];return FO(t=>{e.push(...Array.from(t.querySelectorAll(`input, select, textarea`)).filter(e=>{if(NO(e))return!1;let t=(e.type||``).toLowerCase();if([`hidden`,`submit`,`button`,`image`].includes(t)||e.disabled||e.readOnly)return!1;try{let t=PO(e);if(t.display===`none`||t.visibility===`hidden`)return!1}catch{}return!0}))}),e}function zO(){return RO().map((e,t)=>{let n={formIndex:0,fieldIndex:t,tag:e.tagName,type:e.type||`text`,name:e.name||null,id:e.id||null,label:LO(e),placeholder:e.placeholder||null};return e.tagName===`SELECT`&&(n.options=Array.from(e.options).filter(e=>e.value!==``&&!e.disabled).map(e=>({value:e.value,text:e.text.trim()})),n.currentValue=e.value||null),n})}function BO(){let e=[];return FO(t=>{e.push(...Array.from(t.querySelectorAll(`button, [role="button"], input[type="submit"], input[type="button"]`)).filter(e=>{if(NO(e)||e.disabled)return!1;try{let t=PO(e);if(t.display===`none`||t.visibility===`hidden`)return!1}catch{}return!0}))}),e.slice(0,60).map((e,t)=>({index:t,text:(e.textContent||e.value||``).replace(/\s+/g,` `).trim().slice(0,120)||null,ariaLabel:e.getAttribute(`aria-label`),type:e.type||e.tagName}))}function VO(e){return String(e||``).toLowerCase().replace(/\u00a0/g,` `).replace(/\*/g,``).replace(/\s+/g,` `).trim()}function HO(e){let t=VO(e);return t=t.replace(/\s+field\s*$/i,``).trim(),t}function UO(e,t){let n=HO(t);if(!n)return 0;let r=(e.name||``).toLowerCase(),i=(e.id||``).toLowerCase();if(r===`url`&&/url|website|domain|site|audit/.test(n)||(i===`url-input`||i.endsWith(`-url-input`))&&/url|website|domain|site|audit/.test(n))return 100;let a=[e.name,e.id,e.placeholder,LO(e),e.getAttribute(`aria-label`),e.getAttribute(`title`),e.getAttribute(`data-testid`),e.getAttribute(`autocomplete`)].filter(Boolean).map(e=>VO(e)),o=0;for(let e of a){if(!e)continue;if(e.includes(n)||n.includes(e)){o=Math.max(o,100);continue}let t=n.split(/\s+/).filter(e=>e.length>1);if(!t.length)continue;let r=0;for(let n of t)e.includes(n)&&(r+=1);o=Math.max(o,r/t.length*88)}return o}var WO=28;function GO(e,t){let n=null,r=0;for(let i of e){let e=UO(i,t);e>r&&(r=e,n=i)}return!n||r<WO?null:n}function KO(e,t,n){let r=String(t||``).toLowerCase().trim(),i=String(n||``).trim();if(!(/^https?:\/\//i.test(i)||/\.\w{2,}(\/|\s|$)/.test(i)||r.includes(`url`)||r.includes(`website`)||r.includes(`domain`)||r.includes(`site`)))return null;let a=null,o=0;for(let t of e){if(t.tagName!==`INPUT`&&t.tagName!==`TEXTAREA`)continue;let e=(t.type||``).toLowerCase();if([`hidden`,`submit`,`button`,`checkbox`,`radio`].includes(e))continue;let n=0;(e===`url`||e===`text`||e===`search`)&&(n+=45);let r=[t.name,t.id,t.placeholder,LO(t),t.getAttribute(`aria-label`),t.getAttribute(`autocomplete`)].filter(Boolean).join(` `).toLowerCase();/(website|url|domain|site\s*url)/.test(r)&&(n+=55),n>o&&(o=n,a=t)}return!a||o<42?null:a}function qO(e){let t=String(e??``).trim();return t?/^https?:\/\//i.test(t)?!0:/\.\w{2,}(\/|\s|$)/.test(t):!1}function JO(e){let t=String(e??``).toLowerCase().trim();return t?!!(t===`url`||t===`website`||t===`website url`||t===`website_url`||t===`enter website url`||t.includes(`website`)||t.includes(`domain`)||/(enter\s+website|site\s*url|page\s*url)/.test(t)):!1}function YO(e){if(!e||e.tagName!==`INPUT`&&e.tagName!==`TEXTAREA`)return!1;let t=(e.type||``).toLowerCase();return![`hidden`,`submit`,`button`,`checkbox`,`radio`,`file`].includes(t)}function XO(e){if(!YO(e))return!1;let t=(e.name||``).toLowerCase(),n=(e.id||``).toLowerCase(),r=[e.name,e.id,e.placeholder,LO(e),e.getAttribute(`aria-label`)].filter(Boolean).join(` `).toLowerCase();return t===`url`||n===`url-input`||n.endsWith(`-url-input`)||/(website\s*url|enter\s+website|site\s*url)/.test(r)||/(website|domain)/.test(r)&&/(url|site)/.test(r)}function ZO(e,t,n){let r=String(t??``),i=String(n??``),a=ek(e,r)||GO(e,r)||KO(e,r,i);if(!a)return[];let o=new Set([a]);if(qO(i)&&JO(r))for(let t of e)t!==a&&XO(t)&&o.add(t);let s=Array.from(o);return s.sort((e,t)=>{if(e===t)return 0;let n=e.compareDocumentPosition(t);return n&Node.DOCUMENT_POSITION_FOLLOWING?-1:n&Node.DOCUMENT_POSITION_PRECEDING?1:0}),s}function QO(e,t){try{if(!e?.getBoundingClientRect||!t?.getBoundingClientRect)return 1/0;let n=e.getBoundingClientRect(),r=t.getBoundingClientRect(),i={x:n.left+n.width/2,y:n.top+n.height/2},a={x:r.left+r.width/2,y:r.top+r.height/2};return Math.hypot(i.x-a.x,i.y-a.y)}catch{return 1/0}}function $O(e){if(!e||typeof e!=`string`)return null;let t=null;return FO(n=>{try{let r=n.getElementById(e);r&&!NO(r)&&r.matches?.(`input, select, textarea`)&&(t=r)}catch{}}),t}function ek(e,t){let n=String(t??``).trim();if(!n)return null;let r=n.match(/^name:\s*([\w.-]+)$/i);if(r){let t=r[1];for(let n of e)if(n.name===t)return n}let i=n.match(/^id:\s*([\w.-]+)$/i);if(i){let e=$O(i[1]);if(e)return e}let a=n.startsWith(`#`)?n.slice(1):n;if(/^[\w-]+$/.test(a)){let e=$O(a);if(e)return e}let o=n.toLowerCase().replace(/\s+/g,` `);if(o===`url`||o===`website`||o===`website url`||o===`website_url`||o===`enter website url`)for(let t of e){let e=(t.name||``).toLowerCase(),n=(t.id||``).toLowerCase();if(e===`url`||n===`url-input`||n.endsWith(`-url-input`))return t}return null}function tk(e,t){let n=String(t||``).toLowerCase().trim();if(!n)return 0;let r=(e.innerText||e.textContent||``).replace(/\s+/g,` `).trim(),i=[r,e.value,e.getAttribute(`aria-label`),e.getAttribute(`title`),e.getAttribute(`data-text`),e.getAttribute(`data-label`)].filter(Boolean).join(` `).toLowerCase().replace(/\s+/g,` `);if(i.includes(n)||r.toLowerCase()===n)return 100;let a=n.split(/\s+/).filter(e=>e.length>1);if(!a.length)return 0;let o=0;for(let e of a)i.includes(e)&&(o+=1);return o/a.length*92}function nk(e,t){let n=[];FO(e=>{let t=Array.from(e.querySelectorAll(`button, [role="button"], input[type="submit"], input[type="button"], a[href]`));n.push(...t.filter(e=>{if(NO(e)||e.disabled)return!1;try{let t=PO(e);if(t.display===`none`||t.visibility===`hidden`||t.opacity===`0`)return!1}catch{}return!0}))});let r=0,i=n.map(t=>({el:t,s:tk(t,e)}));for(let{s:e}of i)e>r&&(r=e);if(r<28)return null;let a=i.filter(({s:e})=>e===r).map(({el:e})=>e);if(a.length===1)return a[0];let o=Array.isArray(t)?t.filter(e=>e&&e.isConnected):[];if(o.length){let e=a[0],t=1/0;for(let n of a)for(let r of o){let i=QO(n,r);i<t&&(t=i,e=n)}return e}return a[0]}function rk(e){if(e==null)return{};if(typeof e==`string`){let t=e.trim();if(!t)return{};try{return JSON.parse(t)}catch{return{url:t}}}return e}function ik(e){let t=rk(e);if(Array.isArray(t)&&t.length>0){let e=t[0];if(e?.field_key!=null||e?.fieldKey!=null)return t.map(e=>({field_key:e.field_key??e.fieldKey,value:e.value}))}if(!t||typeof t!=`object`)return[];let n=t.fields??t.Fields??t.field_list??t.fieldList??t.data?.fields;if(typeof n==`string`)try{n=JSON.parse(n)}catch{n=null}n&&!Array.isArray(n)&&typeof n==`object`&&(n=Object.values(n)),(!n||n.length===0)&&(t.field_key!=null||t.fieldKey!=null)&&t.value!=null&&(n=[{field_key:t.field_key??t.fieldKey,value:t.value}]);let r=t.website_url??t.websiteUrl??t.url??t.website??t.domain??t.site_url??t.siteUrl;return(!n||n.length===0)&&r!=null&&String(r).trim()&&(n=[{field_key:t.field_key??t.fieldKey??`url`,value:String(r).trim()}]),Array.isArray(n)?n.map(e=>({field_key:e?.field_key??e?.fieldKey,value:e?.value??e?.Value})):[]}function ak(e){if(!e||typeof e!=`string`)return[];let t=e.trim();if(!t||/\b[a-z0-9._%+-]+@[a-z0-9.-]+\.[a-z]{2,}\b/i.test(t))return[];let n=t.match(/https?:\/\/[^\s<>"']+/i);if(n)return[{field_key:`url`,value:n[0].replace(/[.,;:)]+$/,``)}];let r=t.match(/\b(?:[\w-]+\.)+[a-z]{2,}\b/i);if(r){let e=r[0].replace(/[.,;:)]+$/,``);return/^https?:/i.test(e)||(e=`https://${e}`),[{field_key:`url`,value:e}]}return[]}function ok(e){if(!e||typeof e!=`string`)return[];let t=e.trim();if(!t)return[];let n=[],r=new Set,i=/\b([a-z0-9._%+-]+@[a-z0-9.-]+\.[a-z]{2,})\b/i,a=(e,t)=>{let i=String(t??``).trim().replace(/^["']|["']$/g,``);if(!i||i.length>800)return;let a=`${e}\0${i}`;r.has(a)||(r.add(a),n.push({field_key:e,value:i}))},o=t.match(/^\s*([a-z0-9._%+-]+@[a-z0-9.-]+\.[a-z]{2,})\s*$/i);if(o)return a(`Email Address`,o[1]),n;let s=t.match(/\b(?:please\s+)?(?:enter|type|put)\s+(.+?)\s+in(?:to)?\s+(?:the\s+)?(?:full\s*name|full\s*name\s*field|name\s*field)\b/i);if(s&&a(`Full Name`,s[1]),s=t.match(/\bfull\s*name,?\s*(?:please\s+)?(?:enter|type|put)\s+(.+?)(?:\.|$|!|\?)/i),s&&a(`Full Name`,s[1]),s=t.match(/\bfull\s*name\s*(?:is|:|please\s+enter|-)\s*(.+?)(?:\.|$|(?=\s+(?:and|my\s+email|email|message))\b)/i),s&&a(`Full Name`,s[1]),s=t.match(/\b(.+?)\s+for\s+(?:the\s+)?full\s*name\b/i),s){let e=s[1].trim();e.length>1&&e.length<120&&!/@/.test(e)&&a(`Full Name`,e)}if(s=t.match(/\b(?:email|e-mail)(?:\s*address)?\s*(?:is|:|please\s+use|enter|-)\s*([^\s@]+@[^\s@]+\.[^\s,]+)/i),s&&a(`Email Address`,s[1]),s=t.match(/\b(?:enter|type|put)\s+([^\s@]+@[^\s@]+\.[^\s,]+)\s+in(?:to)?\s+(?:the\s+)?(?:email|e-mail)/i),s&&a(`Email Address`,s[1]),s=t.match(/\b(?:message|comment)\s*(?:is|:|please\s+enter|-)\s*(.+)$/is),s){let e=s[1].trim();e.length>0&&a(`Message`,e)}if(!n.some(e=>/email/i.test(String(e.field_key)))){let e=t.match(i);if(e){let r=t.replace(e[0],``).trim().replace(/^(please|it's|it is|use|is|my email is|e-?mail is)\s*/i,``).replace(/[.,;:!?]+$/,``).trim();if(t.length<=96&&r.length<=36)return a(`Email Address`,e[1]),n}}if(n.length===0){let e=t.split(/\s+/).filter(Boolean).length,n=/[.!?]/.test(t)||e>=6||t.length>=24&&e>=5||t.length>=42,r=/^[A-Z][a-z]+\s+[A-Z][a-z]+$/.test(t.trim());n&&t.length>=16&&!i.test(t)&&!r&&a(`Message`,t)}return n}function sk(e){if(!e||typeof e!=`object`)return null;let t=e.url??e.target_url??e.page_url??e.pageUrl??e.link??e.href??e.path;return t==null?null:String(t).trim()||null}function ck(e,t,n){if(!n?.skipScroll)try{e.scrollIntoView({block:`center`,inline:`nearest`})}catch{try{e.scrollIntoView(!0)}catch{}}try{e.focus({preventScroll:!0})}catch{try{e.focus()}catch{}}let r=e.tagName,i=(e.type||``).toLowerCase();if(r===`SELECT`)return e.value=String(t),e.dispatchEvent(new Event(`input`,{bubbles:!0})),e.dispatchEvent(new Event(`change`,{bubbles:!0})),!0;if(i===`checkbox`||i===`radio`)return e.checked=[`1`,`true`,`yes`,`on`].includes(String(t).toLowerCase().trim()),e.dispatchEvent(new Event(`input`,{bubbles:!0})),e.dispatchEvent(new Event(`change`,{bubbles:!0})),!0;let a=String(t);if(r===`INPUT`||r===`TEXTAREA`){let t=e.ownerDocument?.defaultView||window,n=r===`TEXTAREA`?t.HTMLTextAreaElement.prototype:t.HTMLInputElement.prototype,i=Object.getOwnPropertyDescriptor(n,`value`);i?.set?i.set.call(e,a):e.value=a}else e.value=a;let o={bubbles:!0,cancelable:!0,composed:!0};try{e.dispatchEvent(new InputEvent(`input`,{...o,inputType:`insertText`,data:a}))}catch{e.dispatchEvent(new Event(`input`,o))}e.dispatchEvent(new Event(`change`,o));try{queueMicrotask(()=>{try{e.dispatchEvent(new Event(`input`,o)),e.dispatchEvent(new Event(`change`,o))}catch{}})}catch{}return!0}function lk(){let e={};document.querySelectorAll(`h1, h2, h3, h4, h5, h6`).forEach(t=>{if(t.id)return;let n=t.textContent.trim();if(!n)return;let r=n.toLowerCase().replace(/[^a-z0-9]+/g,`-`).replace(/^-|-$/g,``).substring(0,60);if(e[r]){let t=2;for(;e[r+`-`+t];)t++;r=r+`-`+t}e[r]=!0,t.id=r})}function uk(){let e=e=>Array.from(e).filter(e=>!e.closest(`#flowengage-root, .flowengage-shell, .flowengage-widget-root`)).map(e=>e.textContent.replace(/\s+/g,` `).trim()).filter(e=>e.length>2&&e.length<200),t=e((document.querySelector(`main, [role='main']`)||document.body).querySelectorAll(`h1, h2, h3`));return t.length||(t=e(document.body.querySelectorAll(`h1, h2, h3`))),t.length||(t=e(document.body.querySelectorAll(`h4, h5`))),[...new Set(t)].slice(0,15)}function dk(e){let t=e.siteId||null,n=(e.apiBaseUrl||``).replace(/\/$/,``),r=typeof e.getLastUserVoiceText==`function`?e.getLastUserVoiceText:null,i=[],a={"fwh-navigate-mvp":async n=>{$(`fwh-navigate-mvp ▶ raw parameters:`,n);let i=rk(n),a=sk(i);if($(`fwh-navigate-mvp · coerced:`,{url:a,sectionText:i.section_text??i.sectionText??i.section,expectedLandmarks:Array.isArray(i.expected_landmarks)?i.expected_landmarks:Array.isArray(i.expectedLandmarks)?i.expectedLandmarks:[]}),!a){let e=`Missing url: pass a string url, path like /pricing, or JSON with a url field.`;return $(`fwh-navigate-mvp ✖`,e),e}if(typeof window<`u`)try{let e=new URL(a,window.location.href);if(e.origin!==window.location.origin&&/^https?:$/i.test(e.protocol)){let t=e.hostname;return $(`fwh-navigate-mvp ✖ external URL blocked:`,e.href),`EXTERNAL_LINK_BLOCKED: The URL "${a}" points to an external site (${t}) that opens in a new tab. I cannot open new tabs or navigate to external sites. Tell the visitor exactly this: "That link opens an external app — I'm not able to open it for you, but you can click the link directly in the navigation header."`}}catch{}if(typeof window<`u`){try{let e=new URL(a,window.location.href);if(e.pathname===window.location.pathname&&e.search===window.location.search)return $(`fwh-navigate-mvp ✖ already on page, skipping`),`OK_ALREADY_ON_PAGE. The visitor is already on this page. Do not navigate. Proceed directly with highlights, answering the question, or reading page content.`}catch{}let e=window.__fe_user_nav_during_speech;if(e&&Date.now()-e.ts<3e4)try{if(new URL(a,window.location.href).pathname===e.fromPath)return $(`flowengage_navigate ✖ blocked — would navigate back to page visitor just left`,e),`NAV_BLOCKED: The visitor just left "${e.fromPageName}" and is now on "${e.toPageName}". Do NOT navigate them back. If they said "continue", resume verbally from where you left off — no navigation needed. If they want to return, they will navigate themselves.`}catch{}}if(!await fr(a,{siteId:t,apiBaseUrl:e.apiBaseUrl})){let e=`Page "${a}" could not be verified. Try a different URL from your known site pages, or ask the visitor to clarify which page they want.`;return $(`fwh-navigate-mvp ✖ blocked`,e),e}try{fO(`Navigating to ${a}...`,{spinner:!0}),_O(),dD();try{let e=r?r():``;if(e&&t){let n=sO([{sender:`user`,message:e}]);n&&xe(t,n)}}catch{}Te();let e=a;try{e=new URL(a,typeof window<`u`?window.location.href:``).href}catch{}t&&typeof window<`u`&&Me(t,window.location.href,e),hr(e),$(`fwh-navigate-mvp → real navigation`,a);let n=typeof window<`u`&&!!Kn();if(typeof window<`u`&&window.__fe_triggerVoiceNavHooks&&window.__fe_triggerVoiceNavHooks(),n&&Ln(12e3),vr(a,{voiceActive:!0}).catch(()=>{}),n)try{let e=new URL(a,window.location.origin).pathname,t=Date.now()+2e3;for(;Date.now()<t&&!(typeof window<`u`&&window.location.pathname===e);)await new Promise(e=>setTimeout(e,80));let n=typeof window<`u`?window.location.pathname:e,r=typeof window<`u`?window.location.href:a,i=n===e,o=(n.split(`/`).filter(Boolean).pop()||``).replace(/[-_]/g,` `).replace(/\b\w/g,e=>e.toUpperCase())||`Home`;$(`fwh-navigate-mvp → SPA nav complete. target:`,e,`actual:`,n);try{typeof window<`u`&&window.scrollTo(0,0)}catch{}let s=[],c=Date.now()+12e3;for(;Date.now()<c&&(await new Promise(e=>setTimeout(e,300)),s=uk(),!(s.length>=1)););lk(),$(`fwh-navigate-mvp → page headings collected:`,s);let l=s.length?s.join(` | `):`none`,u=s.length?`Use ONLY these exact heading strings for fwh-highlight-mvp — never invent or abbreviate.`:`No headings collected yet — call fwh-get-current-page-mvp immediately (no speech) to get the live headings before speaking or highlighting.`;return i?(gr(),`OK_NAVIGATE_SPA. Visitor is now on: ${r} (page: "${o}") | Section headings: ${l}. ${u} Speak 2-3 sentences about this page from your knowledge. Then ask: "Would you like to know about a specific section, or should I give you a complete overview?" Then STOP — wait for their reply. Do NOT auto-highlight any sections.`):(gr(),`OK_NAVIGATE_SPA. CURRENT PAGE IS: ${r} (page: "${o}") | Section headings: ${l}. ${u} Speak 2-3 sentences about this page from your knowledge. Then ask: "Would you like to know about a specific section, or should I give you a complete overview?" Then STOP — wait for their reply. Do NOT auto-highlight any sections.`)}catch{}return`OK_NAVIGATE_RELOADING. Navigating to the page now; the voice session will resume automatically on the new page. When the session resumes, speak 2-3 sentences about the page, then ask: "Would you like to know about a specific section, or should I give you a complete overview?" Wait for the visitor's reply.`}catch(e){let t=`Navigation error: ${e?.message||String(e)}`;return $(`fwh-navigate-mvp ✖`,t),fO(`Navigation failed`,{spinner:!1,icon:`⚠️`,duration:1800}),t}finally{vO(),pO(900)}},"fwh-highlight-mvp":async e=>{$(`fwh-highlight-mvp ▶`,e);let t=rk(e),n=t?.section_id||t?.sectionId,r=t?.section_text||t?.sectionText;if(typeof window<`u`&&window.__fe_user_nav_during_speech){let e=window.__fe_user_nav_during_speech,t=window.location.pathname;if(Date.now()-e.ts>=3e4)window.__fe_user_nav_during_speech=null;else return $(`flowengage_highlight ✖ blocked — user navigated during speech`,e),`NAV_CHANGED: The visitor navigated from "${e.fromPageName}" to "${e.toPageName}" (current path: ${t}) while you were speaking. STOP the current walkthrough immediately. DO NOT call flowengage_highlight again. Say out loud: "I see you've navigated to the ${e.toPageName} page — do you want me to continue what I was explaining, or shall I guide you through this page?" Wait for the visitor's answer before doing anything else.`}lk();let i=(e=>e&&e.replace(/^\d+\.\s*/,``).replace(/^["']|["']$/g,``).trim())(r),a=sr(n||null,i||null);if(!a&&i){let e=Date.now()+600;for(;!a&&Date.now()<e;)await new Promise(e=>setTimeout(e,50)),lk(),a=sr(null,i)}if(!a){$(`fwh-highlight-mvp ✖ no element for:`,i||n);let e=uk(),t=e.length?`Page headings: ${e.map(e=>`"${e}"`).join(` | `)}. Use one of these EXACT strings for section_text — no numbers, no quotes around them.`:`No headings found — skip highlight and continue speaking.`;return`HIGHLIGHT_NOT_FOUND: "${i||n}" on the current page. ${t}`}return uD(a),$(`fwh-highlight-mvp ✓`,i||n),`OK_HIGHLIGHT: "${i||n}". WALKTHROUGH: continue immediately to the next section — do NOT pause between sections.`},"fwh-read-content-mvp":async e=>{$(`fwh-read-content-mvp ▶`,e);let t=rk(e),n=t?.section_text||t?.sectionText||``;try{let e=``;if(n){let t=sr(null,n);if(!t)return`Could not find section "${n}" on the page.`;let r=[t.textContent.trim()],i=t.nextElementSibling;for(;i&&!/^H[1-3]$/i.test(i.tagName);){let e=i.textContent.trim();e&&r.push(e),i=i.nextElementSibling}e=r.join(`
|
|
635
635
|
`)}else{let t=(document.querySelector(`main`)||document.querySelector(`article`)||document.querySelector(`[role="main"]`)||document.querySelector(`#content`)||document.querySelector(`.content`)||document.body).cloneNode(!0);t.querySelectorAll(`nav, footer, header, aside, script, style, noscript, .nav, .footer, .header, .sidebar, #flowengage-root, .flowengage-shell, .flowengage-widget-root`).forEach(e=>e.remove()),e=t.textContent.replace(/\s+/g,` `).trim()}return e.length>8e3&&(e=e.substring(0,8e3)+`... (truncated)`),$(`fwh-read-content-mvp ✓`,`${e.length} chars`),e||`No readable content found on this page.`}catch(e){return $(`fwh-read-content-mvp ✖`,e.message),`Could not read page content: ${e.message}`}},flowengage_search:async e=>{$(`flowengage_search ▶`,e);let r=rk(e),i=pickSearchQuery(r);if($(`flowengage_search · query:`,i,`siteId:`,t,`apiBase:`,n||`(empty)`),!i)return $(`flowengage_search ✖ missing query`),`Missing query parameter.`;if(!t)return $(`flowengage_search ✖ no siteId`),`Site is not configured for search.`;if(!n)return $(`flowengage_search ✖ no api base`),`API base URL is missing; cannot search.`;fO(`Searching${i?` for "${i}"`:``}…`,{spinner:!0});try{let e=`${n}/api/site-tools/search`;$(`flowengage_search → POST`,e);let r=await fetch(e,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({siteId:t,query:i,currentUrl:typeof window<`u`?window.location.href:``})}),a=await r.json();if($(`flowengage_search · HTTP`,r.status,`success:`,a.success),!a.success){let e=a.error||`Search failed.`;return $(`flowengage_search ✖`,e),e}let o=a.results||[];return $(`flowengage_search ✓`,`${o.length} result(s)`,o.slice(0,3).map(e=>e?.url||e)),o.length?`SEARCH_RESULTS: ${JSON.stringify(o)}. MANDATORY: Do NOT call fwh-navigate-mvp now. Speak the answer from these results in 2-3 sentences. Then ask the visitor if they want to go to a relevant page — e.g. "Would you like me to take you to that page?" Only navigate if they say yes. NAVIGATION RULE: When navigating to a specific article, case study, blog post, or detail page — always use the most specific URL from the results (e.g. /case-study/cgs-detail), never the generic listing page (e.g. /case-study). If multiple URLs are in the results, pick the one whose path most closely matches the topic.`:`SEARCH_RESULTS: No results found. Answer from your knowledge base.`}catch(e){let t=`Search error: ${e.message||`network`}`;return $(`flowengage_search ✖`,t),t}finally{pO(600)}},"fwh-page-content-mvp":async e=>{$(`fwh-page-content-mvp ▶`,e);let r=rk(e),i=r?.url||r?.page_url||``;if($(`fwh-page-content-mvp · url:`,i,`siteId:`,t,`apiBase:`,n||`(empty)`),!i)return $(`fwh-page-content-mvp ✖ missing url`),`Missing url parameter.`;if(!t)return $(`fwh-page-content-mvp ✖ no siteId`),`Site is not configured.`;if(!n)return $(`fwh-page-content-mvp ✖ no api base`),`API base URL is missing; cannot fetch page content.`;try{let e=`${n}/api/site-tools/page-content`;$(`fwh-page-content-mvp → POST`,e);let r=await fetch(e,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({siteId:t,url:i})}),a=await r.json();if($(`fwh-page-content-mvp · HTTP`,r.status,`success:`,a.success),!a.success){let e=a.error||`Failed to get page content.`;return $(`fwh-page-content-mvp ✖`,e),`${e} FALLBACK REQUIRED: This page is not in the search index. Call fwh-read-content-mvp (no parameters) immediately to read the live page content directly from the visitor's browser — do NOT tell the visitor you cannot access the page.`}return $(`fwh-page-content-mvp ✓`,`title: ${a.title}`,`sections: ${(a.sections||[]).length}`,`content: ${(a.content||``).length} chars`),JSON.stringify({title:a.title,url:a.url,sections:a.sections,content:a.content})}catch(e){let t=`Page content error: ${e.message||`network`}`;return $(`fwh-page-content-mvp ✖`,t),t}},"fwh-search-mvp":async e=>{$(`fwh-search-mvp ▶`,e);let r=rk(e).query;if(!r)return $(`fwh-search-mvp ✖ missing query`),`Missing query parameter.`;if(!t)return $(`fwh-search-mvp ✖ no siteId`),`Search unavailable (no siteId configured).`;if(!n)return $(`fwh-search-mvp ✖ no api base`),`Search unavailable (no API base URL).`;try{let e=`${n}/api/site-tools/search`;$(`fwh-search-mvp → POST`,e);let i=await fetch(e,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({siteId:t,query:r})}),a=await i.json();if($(`fwh-search-mvp · HTTP`,i.status,`success:`,a.success),!a.success||!a.results?.length)return`No results found for that query. Try rephrasing, or use fwh-read-content-mvp to read the current page.`;let o=a.results.slice(0,5).map((e,t)=>`${t+1}. ${e.title||e.url} (${e.url})${e.snippet?` — ${e.snippet}`:``}`).join(`
|
|
636
|
-
`);return $(`fwh-search-mvp ✓`,`${a.results.length} result(s)`),`SEARCH_RESULTS:\n${o}`}catch(e){return $(`fwh-search-mvp ✖`,e.message),`Search failed. Use fwh-read-content-mvp to read the current page instead.`}},"fwh-list-nav-links-mvp":async()=>{if($(`fwh-list-nav-links-mvp ▶`),typeof window>`u`)return`Cannot read navigation (no browser context).`;let e=new Map,t=[],n=[`nav a`,`[role='navigation'] a`,`header a`,`.navbar a`,`.nav a`,`.menu a`,`.navigation a`,`.header a`,`[class*='nav'] a`,`[class*='menu'] a`,`[class*='header'] a`];if(FO(t=>{for(let r of n)try{t.querySelectorAll(r).forEach(t=>{if(NO(t))return;let n=t.getAttribute(`href`),r=(t.textContent||``).replace(/\s+/g,` `).trim();if(!r||!n||n===`#`||n.startsWith(`javascript:`))return;try{let e=
|
|
637
|
-
`);return $(`fwh-list-nav-links-mvp ✓`,`${t.length} links`),`NAV_LINKS (${t.length} total, showing up to 50):\n${r}\n\nIMPORTANT: Use the EXACT text shown above when reading link names to the visitor. Do NOT rename, abbreviate, or invent options not listed here. To navigate, call fwh-navigate-mvp with the href value.`},"fwh-end-session-mvp":async()=>($(`fwh-end-session-mvp ▶`),typeof e.requestEndSession==`function`&&e.requestEndSession(),`Voice session is ending.`),"fwh-get-current-page-mvp":async()=>{if($(`fwh-get-current-page-mvp ▶`),typeof window>`u`)return`Cannot determine current page (no browser context).`;let e=window.location.href,t=window.location.pathname,n=document.title||``,r=uk();if($(`fwh-get-current-page-mvp ✓`,{url:e,path:t,title:n}),$(`fwh-get-current-page-mvp → page headings collected:`,r),!r.length)return`CURRENT_PAGE. URL: ${e} | Title: ${n} | No headings found on this page. Describe the page from your knowledge without calling this tool again.`;let i=r.map(e=>`"${e}"`).join(` | `);return`CURRENT_PAGE. URL: ${e} | Title: ${n} | Page sections (${r.length} total): ${i}. *** IMPORTANT: For fwh-highlight-mvp, pass the heading text EXACTLY as shown above — no numbers, no extra punctuation, no paraphrasing. Example: fwh-highlight-mvp("${r[0]}") not fwh-highlight-mvp("1. ${r[0]}"). DO NOT call this tool again. If the visitor requested a walkthrough: START IT NOW. Pattern for every section: "[short transition]." + fwh-highlight-mvp("exact heading from list") + "[3-4 sentences about that section]." Cover ALL ${r.length} sections. No pauses between sections. ***`},"fwh-list-forms-mvp":async()=>{let e=zO(),t=BO();return $(`fwh-list-forms-mvp ✓`,`${e.length} field(s)`,`${t.length} button(s)`),JSON.stringify({fields:e,buttons:t,hint:`field_key: placeholder/label, name (e.g. url), id (e.g. url-input). If the page has two URL boxes, fwh-fill-form-mvp sets all matching URL inputs. fwh-click-button-mvp picks the Conduct Audit nearest the filled field when labels duplicate.`})},"fwh-fill-form-mvp":async e=>{try{$(`fwh-fill-form-mvp ▶ raw:`,e),yO();let t=ik(e);if(!t.length&&r){let e=r(),n=ak(e);n.length?$(`fwh-fill-form-mvp · inferred URL from last user utterance (model omitted usable fields):`,n):(n=ok(e),n.length&&$(`fwh-fill-form-mvp · inferred contact fields from last user utterance (empty tool params):`,n)),n.length&&(t=n)}if($(`fwh-fill-form-mvp · normalized fields:`,t),!t.length)return`No fields provided. Call fwh-list-forms-mvp for field_key strings, then fwh-fill-form-mvp with { "fields": [ { "field_key": "<label or placeholder from list>", "value": "<user value>" } ] }. Never use empty {}. Pass the value the user just said (email, message, name, URL) in fields.`;let n=[];for(let e of t){let t=e?.field_key,r=e?.value;if(t==null||r==null)continue;fO(`Filling ${String(t)}...`,{spinner:!0});let a=RO(),o=ZO(a,String(t),r);if(o.length){for(let[e,t]of o.entries())bO(t),await EO(t),ck(t,r,{skipScroll:e>0}),xO(t),await jO(120);i=o,n.push(String(t));continue}let s=ek(a,String(t));s||=GO(a,String(t)),s||=KO(a,String(t),r),s&&(bO(s),await EO(s),ck(s,r),xO(s),await jO(120),i=[s],n.push(String(t)))}if(!n.length)return $(`fwh-fill-form-mvp ✖ no matches`),`Could not match any fields. Call fwh-list-forms-mvp and use field_key values that match placeholder, label, name, or id (e.g. Enter Website URL). Ensure the form is on the page, not the chat panel.`;let a=`OK_FILLED: ${n.join(`, `)}`;return $(`fwh-fill-form-mvp ✓`,a),fO(`Form filled`,{spinner:!1,icon:`✅`,duration:1100}),a}catch(e){let t=`FORM_ERROR: ${e?.message||String(e)}`;return $(`fwh-fill-form-mvp ✖`,t),fO(`Failed to fill form`,{spinner:!1,icon:`⚠️`,duration:1800}),t}finally{DO(),yO(),pO(700)}},"fwh-click-button-mvp":async e=>{let t=rk(e),n=(t.button_text??t.buttonText??t.text??``).trim();if($(`fwh-click-button-mvp ▶`,n),!n)return`Missing button_text: pass the visible label, e.g. Conduct Audit.`;let r=nk(n,i);if(!r)return $(`fwh-click-button-mvp ✖ no match`),`Could not find a button matching "${n}". Call fwh-list-forms-mvp to see button texts.`;try{fO(`Clicking ${n}...`,{spinner:!0});try{r.scrollIntoView({block:`center`,inline:`nearest`})}catch{r.scrollIntoView(!0)}await EO(r),r.focus?.(),await OO(r),kO(r),r.click();let e=(r.textContent||r.value||r.getAttribute(`aria-label`)||``).trim().slice(0,80)||`button`,t=`OK_CLICK ${e}`;return $(`fwh-click-button-mvp ✓`,t),fO(`Clicked ${e}`,{spinner:!1,icon:`✅`,duration:1200}),t}catch(e){let t=`Click failed: ${e?.message||String(e)}`;return $(`fwh-click-button-mvp ✖`,t),fO(`Click failed`,{spinner:!1,icon:`⚠️`,duration:1800}),t}finally{DO(),pO(700)}}};return{...a,highlightOnPage:a[`fwh-highlight-mvp`],getPageContent:a[`fwh-page-content-mvp`],endVoiceSession:a[`fwh-end-session-mvp`],listPageForms:a[`fwh-list-forms-mvp`],fillFormFields:a[`fwh-fill-form-mvp`],clickPageButton:a[`fwh-click-button-mvp`]}}function fk(e){return!e||typeof e!=`object`?e:Object.fromEntries(Object.entries(e).map(([e,t])=>[e,async n=>{let r=kn();r?console.log(`[FlowEngage:voice-tool] ▶`,e,n):console.info(`[FlowEngage] voice tool » ${e}`);let i;try{i=await t(n)}catch(t){let n=`Tool error: ${t?.message||String(t)}`;return console.error(`[FlowEngage] voice tool ${e} threw:`,t),n}let a=typeof i==`string`?i.length>220?`${i.slice(0,220)}…`:i:String(i);return r?console.log(`[FlowEngage:voice-tool] ◀`,e,a):console.info(`[FlowEngage] voice tool « ${e}:`,a),i}]))}var pk={blue:`#135bd8`,red:`#ef334b`,yellow:`#ffbd2e`,dark:`#0d1b2a`,highlight:`rgba(255,255,255,0.9)`,green:`#10b981`};function mk(e){if(!Array.isArray(e)||e.length<2)return`linear-gradient(145deg, #dce8f022 0%, #e8dff522 45%, #f5e0e022 100%), #f7f8fa`;let[t,n,r]=e;return e.length>=3&&r?[`radial-gradient(ellipse 80% 70% at -10% 50%, ${t}1a 0%, transparent 70%)`,`radial-gradient(ellipse 70% 80% at 110% 30%, ${n}1a 0%, transparent 70%)`,`radial-gradient(ellipse 80% 60% at 50% 110%, ${r}1a 0%, transparent 70%)`,`#f7f8fa`].join(`, `):[`radial-gradient(ellipse 80% 100% at -10% 50%, ${t}1a 0%, transparent 70%)`,`radial-gradient(ellipse 80% 100% at 110% 50%, ${n}1a 0%, transparent 70%)`,`#f7f8fa`].join(`, `)}function hk(e){if(!e||typeof e!=`string`)return`#1a1a1a`;let t=e.replace(`#`,``),n=t.length===3?t.split(``).map(e=>e+e).join(``):t,r=parseInt(n.slice(0,2),16)/255,i=parseInt(n.slice(2,4),16)/255,a=parseInt(n.slice(4,6),16)/255,o=e=>e<=.04045?e/12.92:((e+.055)/1.055)**2.4;return .2126*o(r)+.7152*o(i)+.0722*o(a)>.179?`#1a1a1a`:`#ffffff`}function gk(e){let[t,n]=d.default.useState(null),r=typeof e==`string`?e.trim():``;return d.default.useEffect(()=>{if(!r){n(null);return}n(null);let e=!1,t=new window.Image;return t.onload=()=>{e||n(r)},t.onerror=()=>{e||n(null)},t.src=r,()=>{e=!0}},[r]),t}function _k({logo:e,style:t}){let n=gk(typeof e==`string`?e:null);if(!e)return null;if(typeof e==`string`)return n?(0,f.jsx)(`img`,{src:n,alt:``,style:{objectFit:`contain`,flexShrink:0,display:`block`,...t}}):null;let r=typeof e==`function`?d.default.createElement(e):d.default.isValidElement(e)?e:null;return r?(0,f.jsx)(`span`,{className:`fe-logo-slot`,style:{display:`inline-flex`,alignItems:`center`,flexShrink:0,overflow:`hidden`,...t},children:r}):null}function vk({title:e}){return(0,f.jsx)(`div`,{style:{width:`100%`,height:`100%`,borderRadius:`16px`,background:`linear-gradient(135deg, rgba(59,130,246,0.16) 0%, rgba(59,130,246,0.08) 100%)`,color:`#2563eb`,display:`flex`,alignItems:`center`,justifyContent:`center`,fontSize:`18px`,fontWeight:700,letterSpacing:`-0.03em`},children:String(e||`FE`).split(/\s+/).filter(Boolean).slice(0,2).map(e=>e[0]?.toUpperCase()||``).join(``)||`FE`})}function yk(e,t){let n=(t||``).trim();return n?!!(/\b(let'?s|let us)\s+(end|stop|finish|wrap up|close)\s+(the\s+)?(voice\s+)?(session|call|chat)\b/i.test(n)||/\bend\s+(this\s+)?(the\s+)?(voice\s+)?(session|call|chat)\b/i.test(n)||/\b(hang\s+up|disconnect)\b/i.test(n)||e===`bot`&&(/\b(that'?s all|we'?re done)\b/i.test(n)||/\b(goodbye|bye)\b/i.test(n)||/\b(I'?ll|I will|Let me|I can|I'?m going to)\s+(end|close)\s+(the\s+)?(voice\s+)?(session|call)\b/i.test(n)||/\b(ending|closing)\s+(the\s+)?(voice\s+)?session\b|\bvoice\s+session\s+(is\s+)?(now\s+)?(ended|over|closing)\b/i.test(n)||/\b(session|call)\s+(is\s+)?(now\s+)?(ended|over)\b/i.test(n)||/\bwe\s+can\s+end\s+(the\s+)?(session|call)?\s*(here|now)\b/i.test(n)||/\b(wrapping\s+up|signing\s+off)\b/i.test(n))):!1}function bk({orbColors:e,...t}){return(0,f.jsx)(QD,{colors:e,...t})}function xk({copy:e,orbColors:t,primaryColor:n,onYes:r,onLater:i,isMobile:a,isClosing:o}){let s=n||pk.green,c=hk(s),l=a?72:94,u=(0,f.jsxs)(`div`,{style:{display:`flex`,alignItems:a?`flex-end`:`center`,gap:a?`7px`:`9px`},children:[(0,f.jsxs)(`div`,{style:{flex:1,minWidth:0},children:[(0,f.jsx)(vm.p,{initial:{x:-16,opacity:0},animate:{x:0,opacity:1},transition:{type:`spring`,stiffness:260,damping:24,delay:.36},style:{margin:`0 0 14px`,fontSize:`14px`,fontWeight:700,color:`white`,lineHeight:1.4,textShadow:`0 1px 4px rgba(0,0,0,0.35)`,maxWidth:a?void 0:`210px`},children:e.entryPrompt}),(0,f.jsxs)(vm.div,{initial:{y:10,opacity:0},animate:{y:0,opacity:1},transition:{type:`spring`,stiffness:260,damping:24,delay:.54},style:{display:`flex`,gap:`16px`,flexWrap:`nowrap`},children:[(0,f.jsx)(`button`,{onClick:r,style:{height:`31px`,boxSizing:`border-box`,padding:`0 16px`,borderRadius:`999px`,background:s,color:c,fontWeight:400,fontSize:`14px`,border:`none`,cursor:`pointer`,whiteSpace:`nowrap`,boxShadow:`0 4px 16px ${s}66`,transition:`transform 0.15s ease`},onMouseEnter:e=>{e.currentTarget.style.transform=`scale(1.04)`},onMouseLeave:e=>{e.currentTarget.style.transform=`scale(1)`},children:e.yesLabel}),(0,f.jsx)(`button`,{onClick:i,style:{height:`31px`,boxSizing:`border-box`,padding:`0 16px`,borderRadius:`999px`,background:`transparent`,color:`white`,fontWeight:400,fontSize:`14px`,border:`2px solid rgba(255,255,255,0.55)`,cursor:`pointer`,whiteSpace:`nowrap`,transition:`border-color 0.15s ease`},onMouseEnter:e=>{e.currentTarget.style.borderColor=`rgba(255,255,255,0.9)`},onMouseLeave:e=>{e.currentTarget.style.borderColor=`rgba(255,255,255,0.55)`},children:e.laterLabel})]})]}),(0,f.jsx)(vm.div,{initial:{x:120,opacity:0},animate:{x:0,opacity:1},transition:{type:`spring`,stiffness:220,damping:22,delay:0},style:{flexShrink:0},children:(0,f.jsx)(bk,{size:l,orbColors:t})})]});return(0,f.jsxs)(f.Fragment,{children:[(0,f.jsx)(vm.div,{initial:{opacity:0},animate:{opacity:o?0:1},transition:{duration:.28},style:{position:`fixed`,inset:0,background:`rgba(0,0,0,0.72)`,zIndex:-1}}),a?(0,f.jsx)(`div`,{style:{position:`absolute`,bottom:0,left:0,right:0,padding:`24px 20px 40px`,overflow:`hidden`,animation:o?`fe-orb-slide-down 0.28s cubic-bezier(0.16,1,0.3,1) forwards`:``},children:u}):(0,f.jsx)(`div`,{style:{animation:o?`fe-orb-slide-down 0.28s cubic-bezier(0.16,1,0.3,1) forwards`:``},children:u})]})}function Sk({copy:e,orbColors:t,primaryColor:n,onVoice:r,onText:i,onClose:a,isMobile:o,isClosing:s}){let c=n||pk.green,l=hk(c);return(0,f.jsxs)(vm.div,{initial:{scale:50/350,borderRadius:`50%`},animate:s?{scale:50/350,opacity:0,borderRadius:`50%`}:{scale:1,borderRadius:`16px`,opacity:1},transition:{type:`spring`,stiffness:260,damping:26},style:{transformOrigin:o?`bottom center`:`bottom right`,background:`white`,width:o?`100%`:`350px`,height:`245px`,padding:`24px 40px 32px`,boxSizing:`border-box`,display:`flex`,flexDirection:`column`,alignItems:`center`,justifyContent:`space-between`,boxShadow:`0 20px 60px rgba(0,0,0,0.2)`,position:`relative`,overflow:`hidden`},children:[(0,f.jsx)(`button`,{onClick:a,style:{position:`absolute`,top:`14px`,right:`14px`,background:`none`,border:`none`,cursor:`pointer`,color:`#9ca3af`,padding:`4px`,display:`flex`,alignItems:`center`,justifyContent:`center`,borderRadius:`50%`,transition:`color 0.15s ease`},onMouseEnter:e=>{e.currentTarget.style.color=`#374151`},onMouseLeave:e=>{e.currentTarget.style.color=`#9ca3af`},children:(0,f.jsx)(`svg`,{width:`20`,height:`20`,viewBox:`0 0 24 24`,fill:`none`,stroke:`currentColor`,strokeWidth:`2.2`,strokeLinecap:`round`,strokeLinejoin:`round`,children:(0,f.jsx)(`polyline`,{points:`6 9 12 15 18 9`})})}),(0,f.jsx)(bk,{size:72,orbColors:t}),(0,f.jsx)(`p`,{style:{margin:0,fontSize:`16px`,fontWeight:400,color:`#111827`,textAlign:`center`,lineHeight:1.4},children:e.connectionTitle}),(0,f.jsxs)(`div`,{style:{display:`flex`,gap:`16px`,width:`100%`},children:[(0,f.jsx)(`button`,{onClick:r,style:{width:`127px`,height:`43px`,borderRadius:`999px`,background:c,color:l,fontWeight:400,fontSize:`16px`,border:`none`,cursor:`pointer`,transition:`transform 0.15s ease`,boxShadow:`0 4px 12px ${c}55`},onMouseEnter:e=>{e.currentTarget.style.transform=`scale(1.03)`},onMouseLeave:e=>{e.currentTarget.style.transform=`scale(1)`},children:e.voiceLabel}),(0,f.jsx)(`button`,{onClick:i,style:{width:`127px`,height:`43px`,borderRadius:`999px`,background:`transparent`,color:`#111827`,fontWeight:400,fontSize:`16px`,border:`1.5px solid #d1d5db`,cursor:`pointer`,transition:`border-color 0.15s ease`},onMouseEnter:e=>{e.currentTarget.style.borderColor=`#6b7280`},onMouseLeave:e=>{e.currentTarget.style.borderColor=`#d1d5db`},children:e.textLabel})]})]})}function Ck({orbColors:e,onEnterChat:t,onEndChat:n,agentId:r,siteId:i,apiBaseUrl:a,chatId:o,historyRef:s,onMessageSync:c,voiceEndCounter:l,websiteName:u}){(0,d.useEffect)(()=>(console.log(`[FlowEngage:VoiceDebug] 🔵 VoiceMode MOUNTED`),()=>console.log(`[FlowEngage:VoiceDebug] 🔴 VoiceMode UNMOUNTED`)),[]);let[p,m]=(0,d.useState)(`idle`),[h,g]=(0,d.useState)(!1),[_,v]=(0,d.useState)(!1),y=(0,d.useRef)(null),b=(0,d.useRef)(``),x=(0,d.useRef)(async()=>{}),S=(0,d.useRef)(!1),ee=(0,d.useRef)(!1),te=(0,d.useRef)(!1),ne=(0,d.useRef)(!1),re=(0,d.useRef)(`minimized`),C=(0,d.useRef)(null),ie=(0,d.useRef)(null),ae=(0,d.useRef)(null),oe=(0,d.useRef)(0),se=(0,d.useRef)(!1),ce=(0,d.useRef)(`idle`),le=(0,d.useRef)(!1),ue=(0,d.useRef)(!1),de=(0,d.useRef)(null),fe=(0,d.useRef)(null),pe=(0,d.useRef)(!1),me=(0,d.useCallback)((e=`minimized`)=>{console.warn(`[FlowEngage:VoiceDebug] 🛑 requestSessionShutdown called`,{destination:e,stack:Error().stack?.split(`
|
|
638
|
-
`).slice(1,4).join(` | `)}),re.current=e,ne.current=!0,queueMicrotask(()=>{S.current||(S.current=!0,x.current?.())})},[s]),he=(0,d.useCallback)(async e=>{ne.current=!0;try{dD()}catch{}if(i)try{Ne(i)}catch{}try{await y.current?.endSession?.()}catch{}let t=C.current,n=ie.current;if(t&&o&&a){let e=n?Math.round((Date.now()-n)/1e3):0;fetch(`${a}/api/voice/save-chat-recording`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({chatId:o,elevenLabsConversationId:t,duration:e,siteId:i})}).catch(e=>console.warn(`[FlowEngage] save-chat-recording failed:`,e.message))}if(C.current=null,ie.current=null,y.current=null,m(`idle`),g(!1),S.current=!1,Sr(),i)try{Ce(i)}catch{}typeof c==`function`&&await c(s.current),e?.()},[s,c,i,o,a]);return x.current=()=>he(re.current===`chat`?t:n),(0,d.useEffect)(()=>{ee.current=h},[h]),(0,d.useEffect)(()=>{l&&me(`chat`)},[l]),(0,d.useEffect)(()=>{let e=!1,l=null,d=null,f=null;return(async()=>{if(!r){m(`error`);return}try{if((await navigator.mediaDevices.getUserMedia({audio:!0})).getTracks().forEach(e=>e.stop()),e)return;s.current=[],b.current=``,S.current=!1,te.current=!1,ne.current=!1,re.current=`minimized`,xr({onBeforeNavigate:()=>{if(i&&s.current.length>0)try{let e=sO(s.current);e&&xe(i,e)}catch{}if(!Kn()){let e=C.current,t=ie.current;if(e&&o&&a)try{let n=t?Math.round((Date.now()-t)/1e3):0,r=JSON.stringify({chatId:o,elevenLabsConversationId:e,duration:n,siteId:i}),s=`${a}/api/voice/save-chat-recording`;fetch(s,{method:`POST`,headers:{"Content-Type":`application/json`},body:r,keepalive:!0}).catch(()=>{}),C.current=null,ie.current=null}catch{}}Te()}});let t=fk(dk({siteId:i||null,apiBaseUrl:a||null,getLastUserVoiceText:()=>b.current,requestEndSession:()=>{se.current=!0}})),n=i?Se(i):null,c=!!n?.transcript,p=!!(i&&Ne(i)),h=typeof window<`u`?window.location.pathname:`/`,_=typeof document<`u`?document.title:``,v=h===`/`||h===``,x=null;try{let e=await fetch(`${a}/api/voice/signed-url?siteId=${encodeURIComponent(i||``)}`,{method:`GET`,headers:{"Content-Type":`application/json`}});if(e.ok)x=(await e.json()).signedUrl||null,x&&console.log(`[FlowEngage] ✅ Using signed ElevenLabs URL`);else if(e.status===429){let t=await e.json().catch(()=>({}));throw Error(t.message||`Too many voice sessions started. Please wait a minute before trying again.`)}else console.warn(`[FlowEngage] ⚠️ Signed URL fetch failed, falling back to agentId`)}catch(e){if(e.message&&e.message.includes(`Too many voice sessions`))throw e;console.warn(`[FlowEngage] ⚠️ Signed URL fetch error:`,e.message)}let ae={clientTools:t,connectionType:`websocket`,minSpeechDurationMs:50,...x?{signedUrl:x}:{agentId:r}},he=(h.split(`/`).filter(Boolean).pop()||``).replace(/[-_]/g,` `).replace(/\b\w/g,e=>e.toUpperCase()),ge=``;_&&_.includes(`|`)&&(ge=_.split(`|`).map(e=>e.trim()).filter(Boolean).reduce((e,t)=>e.length<=t.length?e:t));let _e=ge||he||`this page`;if(x)if(p)ae.overrides={agent:{firstMessage:`Here we are — I've taken you to the ${_e} page.`}},console.log(`[FlowEngage] 🔄 Agent-nav resume: firstMessage set for "${_e}" (${h})`);else if(c)ae.overrides={agent:{firstMessage:`I'm still here. Go ahead!`}};else{let e=u||``;ae.overrides={agent:{firstMessage:v?e?`Hi, welcome to ${e}!`:`Hi, welcome!`:`Welcome to the ${_e} page!`}},v||console.log(`[FlowEngage] 🏠 Page-context override: "${_e}" for ${h}`)}else c&&(ae.overrides={agent:{firstMessage:``}});let ve=!1,ye=p?`NAVIGATION COMPLETE — Your brief intro has been spoken. Now speak 2-3 sentences about this page from your knowledge. Then ask the visitor exactly this: "Would you like to know about a specific section, or should I give you a complete overview?" Then STOP — wait for their reply. Do NOT auto-highlight or auto-walkthrough.`:null,be=!1,Ce=!p&&!c?`Your greeting has been spoken. Wait for the visitor to ask a question or tell you what they need. Do NOT auto-start a walkthrough or highlight any sections — let the visitor lead.`:null,we=await sD.startSession({...ae,onConnect:({conversationId:e})=>{C.current=e,ie.current=Date.now(),console.log(`[FlowEngage] 🎙️ AI chat session connected:`,e)},onUnhandledClientToolCall:e=>console.error(`[FlowEngage] Unhandled tool:`,e?.tool_name),onModeChange:({mode:t})=>{if(!e){if(t===`speaking`){fe.current&&=(clearTimeout(fe.current),null),m(`speaking`),ce.current=`speaking`,le.current=!0,pe.current=!1,de.current&&=(clearTimeout(de.current),null);return}if(ce.current=`listening`,se.current){se.current=!1,me();return}if(ye&&!ve){ve=!0;try{y.current?.sendContextualUpdate?.(ye)}catch{}}if(Ce&&!be){be=!0;try{y.current?.sendContextualUpdate?.(Ce)}catch{}}fe.current&&clearTimeout(fe.current),fe.current=setTimeout(()=>{e||ce.current!==`speaking`&&(pe.current||(fe.current=null,ce.current=`listening`,m(`listening`),le.current&&ue.current&&!ee.current&&(de.current&&clearTimeout(de.current),de.current=setTimeout(()=>{if(!e&&ce.current===`listening`&&!ee.current)try{y.current?.sendContextualUpdate?.(`The visitor has been silent for a while. Ask one short, natural question to re-engage — for example: 'Is there anything specific you'd like to know more about?' or 'What else can I help you with today?' Keep it to one sentence.`)}catch{}},15e3))))},1200)}},onMessage:t=>{if(e)return;let n=t.role===`user`?`user`:`bot`,r=t.message||t.text||t.content||``;if(r){if(n===`user`&&(b.current=r,pe.current=!0,ue.current=!0,fe.current&&=(clearTimeout(fe.current),null),de.current&&=(clearTimeout(de.current),null)),s.current=[...s.current,{sender:n,message:r,timestamp:new Date().toISOString()}],i)try{let e=sO(s.current);e&&xe(i,e)}catch{}if(yk(n,r)){se.current=!0;return}if(ee.current&&n===`bot`&&/are you still there|still there\??|hello\?|anyone there|checking in|you there|are you available|is anyone|did you step away/i.test(r))if(oe.current+=1,oe.current===2)try{y.current?.sendContextualUpdate?.(`IMPORTANT: The visitor is muted and has not responded to your last 2 checks. Make exactly ONE more check. If there is still no response, say: 'I feel like you are not active, so I'm ending this session. You can connect with me anytime.' then immediately call the fwh-end-session-mvp tool to end the voice session. Do NOT ask again after that.`)}catch{}else oe.current>=5&&me(`minimized`)}},onError:t=>{if(!e&&!ne.current&&!te.current&&!Ae()){te.current=!0,console.error(`[FlowEngageVoiceCall] session:error`,{message:t?.message,name:t?.name,raw:t});try{y.current?.setMicMuted?.(!0)}catch{}g(!0),m(`error`),me(`chat`)}},onDisconnect:t=>{if(e||ne.current||te.current||Ae())return;let n=s.current?.length||0;console.warn(`[FlowEngageVoiceCall] session:disconnected`,{historyCount:n,reason:t?.reason,closeCode:t?.context?.code,closeReason:t?.context?.reason||t?.message,lastUserText:b.current||``,wasMuted:ee.current}),te.current=!0;try{y.current?.setMicMuted?.(!0)}catch{}g(!0),me(`chat`)}});if(e){console.warn(`[FlowEngage:VoiceDebug] ❌ cancelled=true after startSession resolved — killing session immediately`),we.endSession().catch(()=>{});return}l=we,y.current=we,m(`listening`);try{let e=typeof window<`u`?window.location.href:``,r=`[]`;try{r=await t[`fwh-list-forms-mvp`]()}catch{}let a=`none`;if(typeof window<`u`&&typeof document<`u`)try{let e=`#flowengage-root, .flowengage-shell, .flowengage-widget-root`,t=document.querySelector(`main, [role='main']`)||document.body,n=Array.from(t.querySelectorAll(`h1, h2, h3`)).filter(t=>!t.closest(e)).map(e=>e.textContent.replace(/\s+/g,` `).trim()).filter(e=>e.length>2&&e.length<200);n.length||(n=Array.from(document.body.querySelectorAll(`h1, h2, h3`)).filter(t=>!t.closest(e)).map(e=>e.textContent.replace(/\s+/g,` `).trim()).filter(e=>e.length>2&&e.length<200)),n.length&&(a=[...new Set(n)].slice(0,15).join(` | `))}catch{}let o=c&&!p?`RESUMING PRIOR SESSION — DO NOT GREET. The visitor is continuing the same conversation after a page reload. Do not introduce yourself or re-state your capabilities. Wait silently until the visitor speaks; if you must speak first, briefly acknowledge where you left off in one short sentence.\nPrior transcript:\n${n?.transcript||``}\n\n`:``;we.sendContextualUpdate(`${o}SESSION_CONTEXT (NOT a tool result — do NOT treat as CURRENT_PAGE): Visitor is on: ${e} | Approx headings for awareness only: ${a}. SiteId: ${i||`unknown`}. Forms: ${r}. The visitor is ALREADY on this page — do NOT offer to navigate there. WALKTHROUGH RULE: If the visitor requests a walkthrough, you MUST call fwh-get-current-page-mvp first (zero speech) to get the exact highlightable headings — do NOT use these approximate headings for highlighting. Voice: call end_voice_session or say you are ending the session to stop.`)}catch{}if(typeof window<`u`){let t=window.location.pathname,n=()=>{if(e)return;let n=window.location.pathname;if(n===t)return;if(Rn()){t=n;return}let r=t;t=n;let i=window.location.href,a=typeof document<`u`?document.title:``,o=typeof document<`u`?Array.from(document.querySelectorAll(`h1, h2, h3, h4`)).filter(e=>!e.closest(`#flowengage-root, .flowengage-shell`)).map(e=>({tag:e.tagName,text:e.textContent.trim()})).filter(e=>e.text.length>0&&e.text.length<200).slice(0,20):[];try{dD()}catch{}let s=e=>(e.split(`/`).filter(Boolean).pop()||``).replace(/[-_]/g,` `).replace(/\b\w/g,e=>e.toUpperCase())||`Home`,c=s(r),l=s(n);typeof window<`u`&&(window.__fe_user_nav_during_speech={fromPath:r,toPath:n,fromPageName:c,toPageName:l,ts:Date.now()});try{y.current?.sendUserMessage?.(`[SYSTEM: I navigated away mid-walkthrough — I am now on the "${l}" page (${i}). Page title: "${a}". Sections: ${JSON.stringify(o)}. STOP everything. Do NOT describe the new page. Say EXACTLY: "I see you've navigated to the ${l} page — would you like me to continue what I was explaining, or shall I walk you through this page?" Then wait for my answer. IF I say continue/yes/carry on: resume speaking verbally from where you left off — do NOT call flowengage_navigate, do NOT call flowengage_highlight, the visitor will navigate themselves if needed. IF I want to hear about this page: call flowengage_highlight for sections of "${l}" only.]`)}catch{}};d=window.history.pushState.bind(window.history),window.history.pushState=(...e)=>{d(...e),setTimeout(n,50)},f=()=>setTimeout(n,50),window.addEventListener(`popstate`,f)}}catch(r){e||(console.error(`[FlowEngage] startSession failed`,r),r.message&&r.message.includes(`Too many voice sessions`)?(alert(r.message),n&&n(`minimized`)):(m(`error`),re.current=`chat`,window.setTimeout(()=>{e||t?.()},0)))}})(),()=>{console.warn(`[FlowEngage:VoiceDebug] ⚠️ useEffect CLEANUP fired — session will be killed`,{agentId:r,siteId:i,apiBaseUrl:a}),e=!0,ne.current=!0;try{dD()}catch{}if(i)try{Ne(i)}catch{}typeof window<`u`&&(window.__fe_user_nav_during_speech=null),Sr(),de.current&&=(clearTimeout(de.current),null),fe.current&&=(clearTimeout(fe.current),null),le.current=!1,pe.current=!1,ce.current=`idle`,d&&typeof window<`u`&&(window.history.pushState=d),f&&typeof window<`u`&&window.removeEventListener(`popstate`,f);let t=l||y.current,n=C.current,u=ie.current;if(t?.endSession?.().catch(()=>{}),n&&o&&a){let e=u?Math.round((Date.now()-u)/1e3):0,t=JSON.stringify({chatId:o,elevenLabsConversationId:n,duration:e,siteId:i}),r=`${a}/api/voice/save-chat-recording`;typeof navigator<`u`&&navigator.sendBeacon&&navigator.sendBeacon(r,new Blob([t],{type:`application/json`}))||fetch(r,{method:`POST`,headers:{"Content-Type":`application/json`},body:t,keepalive:!0}).catch(()=>{}),C.current=null,ie.current=null}typeof c==`function`&&s.current.length>0&&c(s.current).catch?.(()=>{})}},[r,i,a,me]),(0,d.useEffect)(()=>{if(!_)return;let e=e=>{let t=e.composedPath?.()?.[0]||e.target;ae.current&&!ae.current.contains(t)&&v(!1)};return document.addEventListener(`mousedown`,e),()=>document.removeEventListener(`mousedown`,e)},[_]),(0,f.jsxs)(`div`,{ref:ae,style:{position:`relative`,display:`flex`,flexDirection:`column`,alignItems:`center`,gap:`14px`,animation:`fe-orb-slide-up 0.42s cubic-bezier(0.16,1,0.3,1)`},children:[(0,f.jsxs)(`div`,{style:{position:`relative`},children:[p===`listening`&&!h&&(0,f.jsx)(`span`,{style:{position:`absolute`,right:`100%`,marginRight:`18px`,top:`50%`,transform:`translateY(-50%)`,color:`white`,fontSize:`18px`,fontWeight:600,letterSpacing:`0.01em`,textShadow:`0 2px 4px rgba(0,0,0,0.4)`,whiteSpace:`nowrap`},children:`Listening...`}),h&&(0,f.jsx)(`span`,{style:{position:`absolute`,right:`100%`,marginRight:`18px`,top:`50%`,transform:`translateY(-50%)`,color:`#f87171`,fontSize:`16px`,fontWeight:600,letterSpacing:`0.01em`,textShadow:`0 2px 4px rgba(0,0,0,0.4)`,whiteSpace:`nowrap`},children:`Muted`}),(0,f.jsx)(bk,{size:72,voiceState:p,isMuted:h,orbColors:e})]}),p===`error`&&(0,f.jsx)(`span`,{style:{color:`#f87171`,fontSize:`13px`,fontWeight:500},children:`Could not start voice session.`}),(0,f.jsxs)(`div`,{style:{display:`flex`,gap:`12px`,alignItems:`center`},children:[(0,f.jsx)(`button`,{onClick:async()=>{if(y.current)try{if(h){oe.current=0,await y.current.setMicMuted?.(!1),g(!1);try{y.current.sendContextualUpdate?.(`The visitor has unmuted. Resume normal interaction and wait for them to speak.`)}catch{}}else{oe.current=0,await y.current.setMicMuted?.(!0),g(!0);try{y.current.sendContextualUpdate?.(`The visitor has muted their microphone. Do NOT speak, ask if they are there, or prompt them in any way. Stay completely silent until they unmute.`)}catch{}}}catch{}},title:h?`Unmute`:`Mute`,style:{width:`24px`,height:`24px`,borderRadius:`50%`,background:h?`#7f1d1d`:`#1f2937`,border:h?`1.5px solid #ef4444`:`1.5px solid #4b5563`,display:`flex`,alignItems:`center`,justifyContent:`center`,cursor:`pointer`,color:h?`#f87171`:`white`,transition:`all 0.2s ease`,boxShadow:`0 2px 8px rgba(0,0,0,0.4)`,padding:0,flexShrink:0},children:h?(0,f.jsxs)(`svg`,{width:`16`,height:`16`,viewBox:`0 0 24 24`,fill:`none`,stroke:`currentColor`,strokeWidth:`2`,strokeLinecap:`round`,strokeLinejoin:`round`,children:[(0,f.jsx)(`line`,{x1:`1`,y1:`1`,x2:`23`,y2:`23`}),(0,f.jsx)(`path`,{d:`M9 9v3a3 3 0 005.12 2.12M15 9.34V4a3 3 0 00-5.94-.6`}),(0,f.jsx)(`path`,{d:`M17 16.95A7 7 0 015 12v-2m14 0v2a7 7 0 01-.11 1.23`}),(0,f.jsx)(`line`,{x1:`12`,y1:`19`,x2:`12`,y2:`23`}),(0,f.jsx)(`line`,{x1:`8`,y1:`23`,x2:`16`,y2:`23`})]}):(0,f.jsx)(fD,{size:16,color:`currentColor`})}),(0,f.jsx)(`button`,{onClick:()=>v(e=>!e),style:{width:`24px`,height:`24px`,borderRadius:`50%`,background:`#1f2937`,border:`1.5px solid #4b5563`,display:`flex`,alignItems:`center`,justifyContent:`center`,cursor:`pointer`,color:`white`,transition:`background 0.2s ease`,boxShadow:`0 2px 8px rgba(0,0,0,0.4)`,padding:0,flexShrink:0},children:(0,f.jsx)(bD,{size:16,color:`currentColor`})})]}),_&&(0,f.jsxs)(`div`,{style:{position:`absolute`,bottom:0,right:0,width:`230px`,zIndex:9999,background:`rgba(15,22,36,0.96)`,backdropFilter:`blur(14px)`,WebkitBackdropFilter:`blur(14px)`,borderRadius:`16px`,boxShadow:`0 10px 40px rgba(0,0,0,0.45)`,animation:`fe-orb-fade-in 0.18s ease`,padding:`12px 12px 40px`},children:[(0,f.jsxs)(`button`,{onClick:()=>{v(!1),re.current=`chat`,he(t)},style:{display:`flex`,alignItems:`center`,gap:`12px`,width:`100%`,padding:`12px 16px`,background:`none`,border:`none`,color:`white`,fontSize:`14px`,fontWeight:500,cursor:`pointer`,textAlign:`left`,transition:`background 0.15s ease`,borderRadius:`8px`,whiteSpace:`nowrap`},onMouseEnter:e=>{e.currentTarget.style.background=`rgba(255,255,255,0.08)`},onMouseLeave:e=>{e.currentTarget.style.background=`none`},children:[(0,f.jsx)(xD,{}),`Enter Chat Mode`]}),(0,f.jsxs)(`button`,{onClick:()=>{v(!1),re.current=`minimized`,he(n)},style:{display:`flex`,alignItems:`center`,gap:`12px`,width:`100%`,padding:`12px 16px`,background:`none`,border:`none`,color:`#E30C12`,fontSize:`14px`,fontWeight:500,cursor:`pointer`,textAlign:`left`,transition:`background 0.15s ease`,borderRadius:`8px`,whiteSpace:`nowrap`},onMouseEnter:e=>{e.currentTarget.style.background=`rgba(227,12,18,0.1)`},onMouseLeave:e=>{e.currentTarget.style.background=`none`},children:[(0,f.jsx)(SD,{}),`End Conversation`]}),(0,f.jsx)(`button`,{onClick:()=>v(!1),style:{position:`absolute`,bottom:`8px`,right:`8px`,width:`24px`,height:`24px`,borderRadius:`50%`,background:`rgba(255,255,255,0.15)`,border:`none`,display:`flex`,alignItems:`center`,justifyContent:`center`,cursor:`pointer`,color:`white`},onMouseEnter:e=>{e.currentTarget.style.background=`rgba(255,255,255,0.25)`},onMouseLeave:e=>{e.currentTarget.style.background=`rgba(255,255,255,0.15)`},children:(0,f.jsxs)(`svg`,{width:`12`,height:`12`,viewBox:`0 0 24 24`,fill:`none`,stroke:`currentColor`,strokeWidth:`2.5`,strokeLinecap:`round`,strokeLinejoin:`round`,children:[(0,f.jsx)(`line`,{x1:`18`,y1:`6`,x2:`6`,y2:`18`}),(0,f.jsx)(`line`,{x1:`6`,y1:`6`,x2:`18`,y2:`18`})]})})]})]})}function wk({orbColors:e}){let t=Array.isArray(e)&&e.length>0?e:[`#135bd8`,`#ef334b`,`#ffbd2e`],n=t[0],r=t[1]||t[0],i=t[2]||t[0];return(0,f.jsx)(`div`,{style:{width:`32px`,height:`32px`,borderRadius:`50%`,flexShrink:0,background:`
|
|
636
|
+
`);return $(`fwh-search-mvp ✓`,`${a.results.length} result(s)`),`SEARCH_RESULTS:\n${o}`}catch(e){return $(`fwh-search-mvp ✖`,e.message),`Search failed. Use fwh-read-content-mvp to read the current page instead.`}},"fwh-list-nav-links-mvp":async()=>{if($(`fwh-list-nav-links-mvp ▶`),typeof window>`u`)return`Cannot read navigation (no browser context).`;let e=new Map,t=[],n=[`nav a`,`[role='navigation'] a`,`header a`,`.navbar a`,`.nav a`,`.menu a`,`.navigation a`,`.header a`,`[class*='nav'] a`,`[class*='menu'] a`,`[class*='header'] a`];if(FO(t=>{for(let r of n)try{t.querySelectorAll(r).forEach(t=>{if(NO(t))return;let n=t.getAttribute(`href`),r=(t.textContent||``).replace(/\s+/g,` `).trim();if(!r||!n||n===`#`||n.startsWith(`javascript:`))return;try{let e=t.parentElement;if(e&&PO(e).display===`none`&&!e.closest(`nav, [role='navigation'], header, [class*='nav'], [class*='menu']`))return}catch{}let i=r.toLowerCase()+`|`+n;e.has(i)||e.set(i,{text:r,href:n})})}catch{}t.querySelectorAll(`select`).forEach(t=>{if(NO(t))return;let n=LO(t);/nav|menu|page|section|go to/i.test(n||t.name||t.id||``)&&Array.from(t.options).forEach(r=>{if(!r.value||r.disabled)return;let i=r.text.trim();if(!i)return;let a=i.toLowerCase()+`|`+r.value;e.has(a)||e.set(a,{text:i,href:r.value,isSelectOption:!0,selectLabel:n||t.name||`dropdown`})})})}),e.forEach(e=>t.push(e)),!t.length)return`NAV_LINKS: No navigation links found on this page. Use fwh-read-content-mvp to read page content or fwh-search-mvp to search the site.`;let r=t.slice(0,50).map((e,t)=>`${t+1}. "${e.text}"${e.isSelectOption?` (dropdown option in "${e.selectLabel}")`:``} → ${e.href}`).join(`
|
|
637
|
+
`);return $(`fwh-list-nav-links-mvp ✓`,`${t.length} links`),`NAV_LINKS (${t.length} total, showing up to 50):\n${r}\n\nIMPORTANT: Use the EXACT text shown above when reading link names to the visitor. Do NOT rename, abbreviate, or invent options not listed here. To navigate, call fwh-navigate-mvp with the href value.`},"fwh-end-session-mvp":async()=>($(`fwh-end-session-mvp ▶`),typeof e.requestEndSession==`function`&&e.requestEndSession(),`Voice session is ending.`),"fwh-get-current-page-mvp":async()=>{if($(`fwh-get-current-page-mvp ▶`),typeof window>`u`)return`Cannot determine current page (no browser context).`;let e=window.location.href,t=window.location.pathname,n=document.title||``,r=uk();if($(`fwh-get-current-page-mvp ✓`,{url:e,path:t,title:n}),$(`fwh-get-current-page-mvp → page headings collected:`,r),!r.length)return`CURRENT_PAGE. URL: ${e} | Title: ${n} | No headings found on this page. Describe the page from your knowledge without calling this tool again.`;let i=r.map(e=>`"${e}"`).join(` | `);return`CURRENT_PAGE. URL: ${e} | Title: ${n} | Page sections (${r.length} total): ${i}. *** IMPORTANT: For fwh-highlight-mvp, pass the heading text EXACTLY as shown above — no numbers, no extra punctuation, no paraphrasing. Example: fwh-highlight-mvp("${r[0]}") not fwh-highlight-mvp("1. ${r[0]}"). DO NOT call this tool again. If the visitor requested a walkthrough: START IT NOW. Pattern for every section: "[short transition]." + fwh-highlight-mvp("exact heading from list") + "[3-4 sentences about that section]." Cover ALL ${r.length} sections. No pauses between sections. ***`},"fwh-list-forms-mvp":async()=>{let e=zO(),t=BO();$(`fwh-list-forms-mvp ✓`,`${e.length} field(s)`,`${t.length} button(s)`);let n=e.map(e=>({...e,inputCategory:e.tag===`SELECT`?`dropdown_select`:`text_input`}));return JSON.stringify({fields:n,buttons:t,hint:`field_key: use the label/placeholder/name shown above. CRITICAL: fields with inputCategory='dropdown_select' are SELECT elements — their field_key must match the SELECT's own label (e.g. 'Company Size'), NOT the option text (e.g. 'Small Business') and NOT a nearby text input label. Never fill a SELECT option value into a text input.`})},"fwh-fill-form-mvp":async e=>{try{$(`fwh-fill-form-mvp ▶ raw:`,e),yO();let t=ik(e);if(!t.length&&r){let e=r(),n=ak(e);n.length?$(`fwh-fill-form-mvp · inferred URL from last user utterance (model omitted usable fields):`,n):(n=ok(e),n.length&&$(`fwh-fill-form-mvp · inferred contact fields from last user utterance (empty tool params):`,n)),n.length&&(t=n)}if($(`fwh-fill-form-mvp · normalized fields:`,t),!t.length)return`No fields provided. Call fwh-list-forms-mvp for field_key strings, then fwh-fill-form-mvp with { "fields": [ { "field_key": "<label or placeholder from list>", "value": "<user value>" } ] }. Never use empty {}. Pass the value the user just said (email, message, name, URL) in fields.`;let n=[];for(let e of t){let t=e?.field_key,r=e?.value;if(t==null||r==null)continue;fO(`Filling ${String(t)}...`,{spinner:!0});let a=RO(),o=(()=>{let e=VO(r);VO(String(t));let n=null,i=0;for(let r of a){if(r.tagName!==`SELECT`||!Array.from(r.options).find(t=>VO(t.text)===e||VO(t.value)===e))continue;let a=UO(r,String(t));a>=i&&(i=a,n=r)}return n&&i>=0?n:null})();if(o){$(`fwh-fill-form-mvp · SELECT pre-pass matched dropdown:`,o.name||o.id||o.getAttribute(`aria-label`)),bO(o),await EO(o),ck(o,r),xO(o),await jO(120),i=[o],n.push(String(t));continue}let s=ZO(a,String(t),r);if(s.length){for(let[e,t]of s.entries())bO(t),await EO(t),ck(t,r,{skipScroll:e>0}),xO(t),await jO(120);i=s,n.push(String(t));continue}let c=ek(a,String(t));c||=GO(a,String(t)),c||=KO(a,String(t),r),c&&(bO(c),await EO(c),ck(c,r),xO(c),await jO(120),i=[c],n.push(String(t)))}if(!n.length)return $(`fwh-fill-form-mvp ✖ no matches`),`Could not match any fields. Call fwh-list-forms-mvp and use field_key values that match placeholder, label, name, or id (e.g. Enter Website URL). Ensure the form is on the page, not the chat panel.`;let a=`OK_FILLED: ${n.join(`, `)}`;return $(`fwh-fill-form-mvp ✓`,a),fO(`Form filled`,{spinner:!1,icon:`✅`,duration:1100}),a}catch(e){let t=`FORM_ERROR: ${e?.message||String(e)}`;return $(`fwh-fill-form-mvp ✖`,t),fO(`Failed to fill form`,{spinner:!1,icon:`⚠️`,duration:1800}),t}finally{DO(),yO(),pO(700)}},"fwh-click-button-mvp":async e=>{let t=rk(e),n=(t.button_text??t.buttonText??t.text??``).trim();if($(`fwh-click-button-mvp ▶`,n),!n)return`Missing button_text: pass the visible label, e.g. Conduct Audit.`;let r=nk(n,i);if(!r)return $(`fwh-click-button-mvp ✖ no match`),`Could not find a button matching "${n}". Call fwh-list-forms-mvp to see button texts.`;try{fO(`Clicking ${n}...`,{spinner:!0});try{r.scrollIntoView({block:`center`,inline:`nearest`})}catch{r.scrollIntoView(!0)}await EO(r),r.focus?.(),await OO(r),kO(r),r.click();let e=(r.textContent||r.value||r.getAttribute(`aria-label`)||``).trim().slice(0,80)||`button`,t=`OK_CLICK ${e}`;return $(`fwh-click-button-mvp ✓`,t),fO(`Clicked ${e}`,{spinner:!1,icon:`✅`,duration:1200}),t}catch(e){let t=`Click failed: ${e?.message||String(e)}`;return $(`fwh-click-button-mvp ✖`,t),fO(`Click failed`,{spinner:!1,icon:`⚠️`,duration:1800}),t}finally{DO(),pO(700)}}};return{...a,highlightOnPage:a[`fwh-highlight-mvp`],getPageContent:a[`fwh-page-content-mvp`],endVoiceSession:a[`fwh-end-session-mvp`],listPageForms:a[`fwh-list-forms-mvp`],fillFormFields:a[`fwh-fill-form-mvp`],clickPageButton:a[`fwh-click-button-mvp`]}}function fk(e){return!e||typeof e!=`object`?e:Object.fromEntries(Object.entries(e).map(([e,t])=>[e,async n=>{let r=kn();r?console.log(`[FlowEngage:voice-tool] ▶`,e,n):console.info(`[FlowEngage] voice tool » ${e}`);let i;try{i=await t(n)}catch(t){let n=`Tool error: ${t?.message||String(t)}`;return console.error(`[FlowEngage] voice tool ${e} threw:`,t),n}let a=typeof i==`string`?i.length>220?`${i.slice(0,220)}…`:i:String(i);return r?console.log(`[FlowEngage:voice-tool] ◀`,e,a):console.info(`[FlowEngage] voice tool « ${e}:`,a),i}]))}var pk={blue:`#135bd8`,red:`#ef334b`,yellow:`#ffbd2e`,dark:`#0d1b2a`,highlight:`rgba(255,255,255,0.9)`,green:`#10b981`};function mk(e){if(!Array.isArray(e)||e.length<2)return`linear-gradient(145deg, #dce8f022 0%, #e8dff522 45%, #f5e0e022 100%), #f7f8fa`;let[t,n,r]=e;return e.length>=3&&r?[`radial-gradient(ellipse 80% 70% at -10% 50%, ${t}1a 0%, transparent 70%)`,`radial-gradient(ellipse 70% 80% at 110% 30%, ${n}1a 0%, transparent 70%)`,`radial-gradient(ellipse 80% 60% at 50% 110%, ${r}1a 0%, transparent 70%)`,`#f7f8fa`].join(`, `):[`radial-gradient(ellipse 80% 100% at -10% 50%, ${t}1a 0%, transparent 70%)`,`radial-gradient(ellipse 80% 100% at 110% 50%, ${n}1a 0%, transparent 70%)`,`#f7f8fa`].join(`, `)}function hk(e){if(!e||typeof e!=`string`)return`#1a1a1a`;let t=e.replace(`#`,``),n=t.length===3?t.split(``).map(e=>e+e).join(``):t,r=parseInt(n.slice(0,2),16)/255,i=parseInt(n.slice(2,4),16)/255,a=parseInt(n.slice(4,6),16)/255,o=e=>e<=.04045?e/12.92:((e+.055)/1.055)**2.4;return .2126*o(r)+.7152*o(i)+.0722*o(a)>.179?`#1a1a1a`:`#ffffff`}function gk(e){let[t,n]=d.default.useState(null),r=typeof e==`string`?e.trim():``;return d.default.useEffect(()=>{if(!r){n(null);return}n(null);let e=!1,t=new window.Image;return t.onload=()=>{e||n(r)},t.onerror=()=>{e||n(null)},t.src=r,()=>{e=!0}},[r]),t}function _k({logo:e,style:t}){let n=gk(typeof e==`string`?e:null);if(!e)return null;if(typeof e==`string`)return n?(0,f.jsx)(`img`,{src:n,alt:``,style:{objectFit:`contain`,flexShrink:0,display:`block`,...t}}):null;let r=typeof e==`function`?d.default.createElement(e):d.default.isValidElement(e)?e:null;return r?(0,f.jsx)(`span`,{className:`fe-logo-slot`,style:{display:`inline-flex`,alignItems:`center`,flexShrink:0,overflow:`hidden`,...t},children:r}):null}function vk({title:e}){return(0,f.jsx)(`div`,{style:{width:`100%`,height:`100%`,borderRadius:`16px`,background:`linear-gradient(135deg, rgba(59,130,246,0.16) 0%, rgba(59,130,246,0.08) 100%)`,color:`#2563eb`,display:`flex`,alignItems:`center`,justifyContent:`center`,fontSize:`18px`,fontWeight:700,letterSpacing:`-0.03em`},children:String(e||`FE`).split(/\s+/).filter(Boolean).slice(0,2).map(e=>e[0]?.toUpperCase()||``).join(``)||`FE`})}function yk(e,t){let n=(t||``).trim();return n?!!(/\b(let'?s|let us)\s+(end|stop|finish|wrap up|close)\s+(the\s+)?(voice\s+)?(session|call|chat)\b/i.test(n)||/\bend\s+(this\s+)?(the\s+)?(voice\s+)?(session|call|chat)\b/i.test(n)||/\b(hang\s+up|disconnect)\b/i.test(n)||e===`bot`&&(/\b(that'?s all|we'?re done)\b/i.test(n)||/\b(goodbye|bye)\b/i.test(n)||/\b(I'?ll|I will|Let me|I can|I'?m going to)\s+(end|close)\s+(the\s+)?(voice\s+)?(session|call)\b/i.test(n)||/\b(ending|closing)\s+(the\s+)?(voice\s+)?session\b|\bvoice\s+session\s+(is\s+)?(now\s+)?(ended|over|closing)\b/i.test(n)||/\b(session|call)\s+(is\s+)?(now\s+)?(ended|over)\b/i.test(n)||/\bwe\s+can\s+end\s+(the\s+)?(session|call)?\s*(here|now)\b/i.test(n)||/\b(wrapping\s+up|signing\s+off)\b/i.test(n))):!1}function bk({orbColors:e,...t}){return(0,f.jsx)(QD,{colors:e,...t})}function xk({copy:e,orbColors:t,primaryColor:n,onYes:r,onLater:i,isMobile:a,isClosing:o}){let s=n||pk.green,c=hk(s),l=a?72:94,u=(0,f.jsxs)(`div`,{style:{display:`flex`,alignItems:a?`flex-end`:`center`,gap:a?`7px`:`9px`},children:[(0,f.jsxs)(`div`,{style:{flex:1,minWidth:0},children:[(0,f.jsx)(vm.p,{initial:{x:-16,opacity:0},animate:{x:0,opacity:1},transition:{type:`spring`,stiffness:260,damping:24,delay:.36},style:{margin:`0 0 14px`,fontSize:`14px`,fontWeight:700,color:`white`,lineHeight:1.4,textShadow:`0 1px 4px rgba(0,0,0,0.35)`,maxWidth:a?void 0:`210px`},children:e.entryPrompt}),(0,f.jsxs)(vm.div,{initial:{y:10,opacity:0},animate:{y:0,opacity:1},transition:{type:`spring`,stiffness:260,damping:24,delay:.54},style:{display:`flex`,gap:`16px`,flexWrap:`nowrap`},children:[(0,f.jsx)(`button`,{onClick:r,style:{height:`31px`,boxSizing:`border-box`,padding:`0 16px`,borderRadius:`999px`,background:s,color:c,fontWeight:400,fontSize:`14px`,border:`none`,cursor:`pointer`,whiteSpace:`nowrap`,boxShadow:`0 4px 16px ${s}66`,transition:`transform 0.15s ease`},onMouseEnter:e=>{e.currentTarget.style.transform=`scale(1.04)`},onMouseLeave:e=>{e.currentTarget.style.transform=`scale(1)`},children:e.yesLabel}),(0,f.jsx)(`button`,{onClick:i,style:{height:`31px`,boxSizing:`border-box`,padding:`0 16px`,borderRadius:`999px`,background:`transparent`,color:`white`,fontWeight:400,fontSize:`14px`,border:`2px solid rgba(255,255,255,0.55)`,cursor:`pointer`,whiteSpace:`nowrap`,transition:`border-color 0.15s ease`},onMouseEnter:e=>{e.currentTarget.style.borderColor=`rgba(255,255,255,0.9)`},onMouseLeave:e=>{e.currentTarget.style.borderColor=`rgba(255,255,255,0.55)`},children:e.laterLabel})]})]}),(0,f.jsx)(vm.div,{initial:{x:120,opacity:0},animate:{x:0,opacity:1},transition:{type:`spring`,stiffness:220,damping:22,delay:0},style:{flexShrink:0},children:(0,f.jsx)(bk,{size:l,orbColors:t})})]});return(0,f.jsxs)(f.Fragment,{children:[(0,f.jsx)(vm.div,{initial:{opacity:0},animate:{opacity:o?0:1},transition:{duration:.28},style:{position:`fixed`,inset:0,background:`rgba(0,0,0,0.72)`,zIndex:-1}}),a?(0,f.jsx)(`div`,{style:{position:`absolute`,bottom:0,left:0,right:0,padding:`24px 20px 40px`,overflow:`hidden`,animation:o?`fe-orb-slide-down 0.28s cubic-bezier(0.16,1,0.3,1) forwards`:``},children:u}):(0,f.jsx)(`div`,{style:{animation:o?`fe-orb-slide-down 0.28s cubic-bezier(0.16,1,0.3,1) forwards`:``},children:u})]})}function Sk({copy:e,orbColors:t,primaryColor:n,onVoice:r,onText:i,onClose:a,isMobile:o,isClosing:s}){let c=n||pk.green,l=hk(c);return(0,f.jsxs)(vm.div,{initial:{scale:50/350,borderRadius:`50%`},animate:s?{scale:50/350,opacity:0,borderRadius:`50%`}:{scale:1,borderRadius:`16px`,opacity:1},transition:{type:`spring`,stiffness:260,damping:26},style:{transformOrigin:o?`bottom center`:`bottom right`,background:`white`,width:o?`100%`:`350px`,height:`245px`,padding:`24px 40px 32px`,boxSizing:`border-box`,display:`flex`,flexDirection:`column`,alignItems:`center`,justifyContent:`space-between`,boxShadow:`0 20px 60px rgba(0,0,0,0.2)`,position:`relative`,overflow:`hidden`},children:[(0,f.jsx)(`button`,{onClick:a,style:{position:`absolute`,top:`14px`,right:`14px`,background:`none`,border:`none`,cursor:`pointer`,color:`#9ca3af`,padding:`4px`,display:`flex`,alignItems:`center`,justifyContent:`center`,borderRadius:`50%`,transition:`color 0.15s ease`},onMouseEnter:e=>{e.currentTarget.style.color=`#374151`},onMouseLeave:e=>{e.currentTarget.style.color=`#9ca3af`},children:(0,f.jsx)(`svg`,{width:`20`,height:`20`,viewBox:`0 0 24 24`,fill:`none`,stroke:`currentColor`,strokeWidth:`2.2`,strokeLinecap:`round`,strokeLinejoin:`round`,children:(0,f.jsx)(`polyline`,{points:`6 9 12 15 18 9`})})}),(0,f.jsx)(bk,{size:72,orbColors:t}),(0,f.jsx)(`p`,{style:{margin:0,fontSize:`16px`,fontWeight:400,color:`#111827`,textAlign:`center`,lineHeight:1.4},children:e.connectionTitle}),(0,f.jsxs)(`div`,{style:{display:`flex`,gap:`16px`,width:`100%`},children:[(0,f.jsx)(`button`,{onClick:r,style:{width:`127px`,height:`43px`,borderRadius:`999px`,background:c,color:l,fontWeight:400,fontSize:`16px`,border:`none`,cursor:`pointer`,transition:`transform 0.15s ease`,boxShadow:`0 4px 12px ${c}55`},onMouseEnter:e=>{e.currentTarget.style.transform=`scale(1.03)`},onMouseLeave:e=>{e.currentTarget.style.transform=`scale(1)`},children:e.voiceLabel}),(0,f.jsx)(`button`,{onClick:i,style:{width:`127px`,height:`43px`,borderRadius:`999px`,background:`transparent`,color:`#111827`,fontWeight:400,fontSize:`16px`,border:`1.5px solid #d1d5db`,cursor:`pointer`,transition:`border-color 0.15s ease`},onMouseEnter:e=>{e.currentTarget.style.borderColor=`#6b7280`},onMouseLeave:e=>{e.currentTarget.style.borderColor=`#d1d5db`},children:e.textLabel})]})]})}function Ck({orbColors:e,onEnterChat:t,onEndChat:n,agentId:r,siteId:i,apiBaseUrl:a,chatId:o,historyRef:s,onMessageSync:c,voiceEndCounter:l,websiteName:u}){(0,d.useEffect)(()=>(console.log(`[FlowEngage:VoiceDebug] 🔵 VoiceMode MOUNTED`),()=>console.log(`[FlowEngage:VoiceDebug] 🔴 VoiceMode UNMOUNTED`)),[]);let[p,m]=(0,d.useState)(`idle`),[h,g]=(0,d.useState)(!1),[_,v]=(0,d.useState)(!1),y=(0,d.useRef)(null),b=(0,d.useRef)(``),x=(0,d.useRef)(async()=>{}),S=(0,d.useRef)(!1),ee=(0,d.useRef)(!1),te=(0,d.useRef)(!1),ne=(0,d.useRef)(!1),re=(0,d.useRef)(`minimized`),C=(0,d.useRef)(null),ie=(0,d.useRef)(null),ae=(0,d.useRef)(null),oe=(0,d.useRef)(0),se=(0,d.useRef)(!1),ce=(0,d.useRef)(`idle`),le=(0,d.useRef)(!1),ue=(0,d.useRef)(!1),de=(0,d.useRef)(null),fe=(0,d.useRef)(null),pe=(0,d.useRef)(!1),me=(0,d.useCallback)((e=`minimized`)=>{console.warn(`[FlowEngage:VoiceDebug] 🛑 requestSessionShutdown called`,{destination:e,stack:Error().stack?.split(`
|
|
638
|
+
`).slice(1,4).join(` | `)}),re.current=e,ne.current=!0,queueMicrotask(()=>{S.current||(S.current=!0,x.current?.())})},[s]),he=(0,d.useCallback)(async e=>{ne.current=!0;try{dD()}catch{}if(i)try{Ne(i)}catch{}try{await y.current?.endSession?.()}catch{}let t=C.current,n=ie.current;if(t&&o&&a){let e=n?Math.round((Date.now()-n)/1e3):0;fetch(`${a}/api/voice/save-chat-recording`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({chatId:o,elevenLabsConversationId:t,duration:e,siteId:i})}).catch(e=>console.warn(`[FlowEngage] save-chat-recording failed:`,e.message))}if(C.current=null,ie.current=null,y.current=null,m(`idle`),g(!1),S.current=!1,Sr(),i)try{Ce(i)}catch{}typeof c==`function`&&await c(s.current),e?.()},[s,c,i,o,a]);return x.current=()=>he(re.current===`chat`?t:n),(0,d.useEffect)(()=>{ee.current=h},[h]),(0,d.useEffect)(()=>{l&&me(`chat`)},[l]),(0,d.useEffect)(()=>{let e=!1,l=null,d=null,f=null;return(async()=>{if(!r){m(`error`);return}try{if((await navigator.mediaDevices.getUserMedia({audio:!0})).getTracks().forEach(e=>e.stop()),e)return;s.current=[],b.current=``,S.current=!1,te.current=!1,ne.current=!1,re.current=`minimized`,xr({onBeforeNavigate:()=>{if(i&&s.current.length>0)try{let e=sO(s.current);e&&xe(i,e)}catch{}if(!Kn()){let e=C.current,t=ie.current;if(e&&o&&a)try{let n=t?Math.round((Date.now()-t)/1e3):0,r=JSON.stringify({chatId:o,elevenLabsConversationId:e,duration:n,siteId:i}),s=`${a}/api/voice/save-chat-recording`;fetch(s,{method:`POST`,headers:{"Content-Type":`application/json`},body:r,keepalive:!0}).catch(()=>{}),C.current=null,ie.current=null}catch{}}Te()}});let t=fk(dk({siteId:i||null,apiBaseUrl:a||null,getLastUserVoiceText:()=>b.current,requestEndSession:()=>{se.current=!0}})),n=i?Se(i):null,c=!!n?.transcript,p=!!(i&&Ne(i)),h=typeof window<`u`?window.location.pathname:`/`,_=typeof document<`u`?document.title:``,v=h===`/`||h===``,x=null;try{let e=await fetch(`${a}/api/voice/signed-url?siteId=${encodeURIComponent(i||``)}`,{method:`GET`,headers:{"Content-Type":`application/json`}});if(e.ok)x=(await e.json()).signedUrl||null,x&&console.log(`[FlowEngage] ✅ Using signed ElevenLabs URL`);else if(e.status===429){let t=await e.json().catch(()=>({}));throw Error(t.message||`Too many voice sessions started. Please wait a minute before trying again.`)}else console.warn(`[FlowEngage] ⚠️ Signed URL fetch failed, falling back to agentId`)}catch(e){if(e.message&&e.message.includes(`Too many voice sessions`))throw e;console.warn(`[FlowEngage] ⚠️ Signed URL fetch error:`,e.message)}let ae={clientTools:t,connectionType:`websocket`,minSpeechDurationMs:50,...x?{signedUrl:x}:{agentId:r}},he=(h.split(`/`).filter(Boolean).pop()||``).replace(/[-_]/g,` `).replace(/\b\w/g,e=>e.toUpperCase()),ge=``;_&&_.includes(`|`)&&(ge=_.split(`|`).map(e=>e.trim()).filter(Boolean).reduce((e,t)=>e.length<=t.length?e:t));let _e=ge||he||`this page`;if(x)if(p)ae.overrides={agent:{firstMessage:`Here we are — I've taken you to the ${_e} page.`}},console.log(`[FlowEngage] 🔄 Agent-nav resume: firstMessage set for "${_e}" (${h})`);else if(c)ae.overrides={agent:{firstMessage:`I'm still here. Go ahead!`}};else{let e=u||``;ae.overrides={agent:{firstMessage:v?e?`Hi, welcome to ${e}!`:`Hi, welcome!`:`Welcome to the ${_e} page!`}},v||console.log(`[FlowEngage] 🏠 Page-context override: "${_e}" for ${h}`)}else c&&(ae.overrides={agent:{firstMessage:``}});let ve=!1,ye=p?`NAVIGATION COMPLETE — Your brief intro has been spoken. PRIOR CONVERSATION CONTEXT (continue from here — do NOT re-introduce yourself):\n${n?.transcript?`Prior transcript:\n${n.transcript}\n`:`(no prior transcript)`}\nNow speak 2-3 sentences about this page from your knowledge, referring to the visitor's prior context if relevant. Then ask the visitor exactly this: "Would you like to know about a specific section, or should I give you a complete overview?" Then STOP — wait for their reply. Do NOT auto-highlight or auto-walkthrough.`:null,be=!1,Ce=!p&&!c?`Your greeting has been spoken. Wait for the visitor to ask a question or tell you what they need. Do NOT auto-start a walkthrough or highlight any sections — let the visitor lead.`:null,we=await sD.startSession({...ae,onConnect:({conversationId:e})=>{C.current=e,ie.current=Date.now(),console.log(`[FlowEngage] 🎙️ AI chat session connected:`,e)},onUnhandledClientToolCall:e=>console.error(`[FlowEngage] Unhandled tool:`,e?.tool_name),onModeChange:({mode:t})=>{if(!e){if(t===`speaking`){fe.current&&=(clearTimeout(fe.current),null),m(`speaking`),ce.current=`speaking`,le.current=!0,pe.current=!1,de.current&&=(clearTimeout(de.current),null);return}if(ce.current=`listening`,se.current){se.current=!1,me();return}if(ye&&!ve){ve=!0;try{y.current?.sendContextualUpdate?.(ye)}catch{}}if(Ce&&!be){be=!0;try{y.current?.sendContextualUpdate?.(Ce)}catch{}}fe.current&&clearTimeout(fe.current),fe.current=setTimeout(()=>{e||ce.current!==`speaking`&&(pe.current||(fe.current=null,ce.current=`listening`,m(`listening`),le.current&&ue.current&&!ee.current&&(de.current&&clearTimeout(de.current),de.current=setTimeout(()=>{if(!e&&ce.current===`listening`&&!ee.current)try{y.current?.sendContextualUpdate?.(`The visitor has been silent for a while. Ask one short, natural question to re-engage — for example: 'Is there anything specific you'd like to know more about?' or 'What else can I help you with today?' Keep it to one sentence.`)}catch{}},15e3))))},1200)}},onMessage:t=>{if(e)return;let n=t.role===`user`?`user`:`bot`,r=t.message||t.text||t.content||``;if(r){if(n===`user`&&(b.current=r,pe.current=!0,ue.current=!0,fe.current&&=(clearTimeout(fe.current),null),de.current&&=(clearTimeout(de.current),null)),s.current=[...s.current,{sender:n,message:r,timestamp:new Date().toISOString()}],i)try{let e=sO(s.current);e&&xe(i,e)}catch{}if(yk(n,r)){se.current=!0;return}if(ee.current&&n===`bot`&&/are you still there|still there\??|hello\?|anyone there|checking in|you there|are you available|is anyone|did you step away/i.test(r))if(oe.current+=1,oe.current===2)try{y.current?.sendContextualUpdate?.(`IMPORTANT: The visitor is muted and has not responded to your last 2 checks. Make exactly ONE more check. If there is still no response, say: 'I feel like you are not active, so I'm ending this session. You can connect with me anytime.' then immediately call the fwh-end-session-mvp tool to end the voice session. Do NOT ask again after that.`)}catch{}else oe.current>=5&&me(`minimized`)}},onError:t=>{if(!e&&!ne.current&&!te.current&&!Ae()){te.current=!0,console.error(`[FlowEngageVoiceCall] session:error`,{message:t?.message,name:t?.name,raw:t});try{y.current?.setMicMuted?.(!0)}catch{}g(!0),m(`error`),me(`chat`)}},onDisconnect:t=>{if(e||ne.current||te.current||Ae())return;let n=s.current?.length||0;console.warn(`[FlowEngageVoiceCall] session:disconnected`,{historyCount:n,reason:t?.reason,closeCode:t?.context?.code,closeReason:t?.context?.reason||t?.message,lastUserText:b.current||``,wasMuted:ee.current}),te.current=!0;try{y.current?.setMicMuted?.(!0)}catch{}g(!0),me(`chat`)}});if(e){console.warn(`[FlowEngage:VoiceDebug] ❌ cancelled=true after startSession resolved — killing session immediately`),we.endSession().catch(()=>{});return}l=we,y.current=we,m(`listening`);try{let e=typeof window<`u`?window.location.href:``,r=`[]`;try{r=await t[`fwh-list-forms-mvp`]()}catch{}let a=`none`;if(typeof window<`u`&&typeof document<`u`)try{let e=`#flowengage-root, .flowengage-shell, .flowengage-widget-root`,t=document.querySelector(`main, [role='main']`)||document.body,n=Array.from(t.querySelectorAll(`h1, h2, h3`)).filter(t=>!t.closest(e)).map(e=>e.textContent.replace(/\s+/g,` `).trim()).filter(e=>e.length>2&&e.length<200);n.length||(n=Array.from(document.body.querySelectorAll(`h1, h2, h3`)).filter(t=>!t.closest(e)).map(e=>e.textContent.replace(/\s+/g,` `).trim()).filter(e=>e.length>2&&e.length<200)),n.length&&(a=[...new Set(n)].slice(0,15).join(` | `))}catch{}let o=c&&!p?`RESUMING PRIOR SESSION — DO NOT GREET. The visitor is continuing the same conversation after a page reload. Do not introduce yourself or re-state your capabilities. Wait silently until the visitor speaks; if you must speak first, briefly acknowledge where you left off in one short sentence.\nPrior transcript:\n${n?.transcript||``}\n\n`:``;we.sendContextualUpdate(`${o}SESSION_CONTEXT (NOT a tool result — do NOT treat as CURRENT_PAGE): Visitor is on: ${e} | Approx headings for awareness only: ${a}. SiteId: ${i||`unknown`}. Forms: ${r}. The visitor is ALREADY on this page — do NOT offer to navigate there. WALKTHROUGH RULE: If the visitor requests a walkthrough, you MUST call fwh-get-current-page-mvp first (zero speech) to get the exact highlightable headings — do NOT use these approximate headings for highlighting. Voice: call end_voice_session or say you are ending the session to stop.`)}catch{}if(typeof window<`u`){let t=window.location.pathname,n=()=>{if(e)return;let n=window.location.pathname;if(n===t)return;if(Rn()){t=n;return}let r=t;t=n;let i=window.location.href,a=typeof document<`u`?document.title:``,o=typeof document<`u`?Array.from(document.querySelectorAll(`h1, h2, h3, h4`)).filter(e=>!e.closest(`#flowengage-root, .flowengage-shell`)).map(e=>({tag:e.tagName,text:e.textContent.trim()})).filter(e=>e.text.length>0&&e.text.length<200).slice(0,20):[];try{dD()}catch{}let s=e=>(e.split(`/`).filter(Boolean).pop()||``).replace(/[-_]/g,` `).replace(/\b\w/g,e=>e.toUpperCase())||`Home`,c=s(r),l=s(n);typeof window<`u`&&(window.__fe_user_nav_during_speech={fromPath:r,toPath:n,fromPageName:c,toPageName:l,ts:Date.now()});try{y.current?.sendUserMessage?.(`[SYSTEM: I navigated away mid-walkthrough — I am now on the "${l}" page (${i}). Page title: "${a}". Sections: ${JSON.stringify(o)}. STOP everything. Do NOT describe the new page. Say EXACTLY: "I see you've navigated to the ${l} page — would you like me to continue what I was explaining, or shall I walk you through this page?" Then wait for my answer. IF I say continue/yes/carry on: resume speaking verbally from where you left off — do NOT call flowengage_navigate, do NOT call flowengage_highlight, the visitor will navigate themselves if needed. IF I want to hear about this page: call flowengage_highlight for sections of "${l}" only.]`)}catch{}};d=window.history.pushState.bind(window.history),window.history.pushState=(...e)=>{d(...e),setTimeout(n,50)},f=()=>setTimeout(n,50),window.addEventListener(`popstate`,f)}}catch(r){e||(console.error(`[FlowEngage] startSession failed`,r),r.message&&r.message.includes(`Too many voice sessions`)?(alert(r.message),n&&n(`minimized`)):(m(`error`),re.current=`chat`,window.setTimeout(()=>{e||t?.()},0)))}})(),()=>{console.warn(`[FlowEngage:VoiceDebug] ⚠️ useEffect CLEANUP fired — session will be killed`,{agentId:r,siteId:i,apiBaseUrl:a}),e=!0,ne.current=!0;try{dD()}catch{}if(i)try{Ne(i)}catch{}typeof window<`u`&&(window.__fe_user_nav_during_speech=null),Sr(),de.current&&=(clearTimeout(de.current),null),fe.current&&=(clearTimeout(fe.current),null),le.current=!1,pe.current=!1,ce.current=`idle`,d&&typeof window<`u`&&(window.history.pushState=d),f&&typeof window<`u`&&window.removeEventListener(`popstate`,f);let t=l||y.current,n=C.current,u=ie.current;if(t?.endSession?.().catch(()=>{}),n&&o&&a){let e=u?Math.round((Date.now()-u)/1e3):0,t=JSON.stringify({chatId:o,elevenLabsConversationId:n,duration:e,siteId:i}),r=`${a}/api/voice/save-chat-recording`;typeof navigator<`u`&&navigator.sendBeacon&&navigator.sendBeacon(r,new Blob([t],{type:`application/json`}))||fetch(r,{method:`POST`,headers:{"Content-Type":`application/json`},body:t,keepalive:!0}).catch(()=>{}),C.current=null,ie.current=null}typeof c==`function`&&s.current.length>0&&c(s.current).catch?.(()=>{})}},[r,i,a,me]),(0,d.useEffect)(()=>{if(!_)return;let e=e=>{let t=e.composedPath?.()?.[0]||e.target;ae.current&&!ae.current.contains(t)&&v(!1)};return document.addEventListener(`mousedown`,e),()=>document.removeEventListener(`mousedown`,e)},[_]),(0,f.jsxs)(`div`,{ref:ae,style:{position:`relative`,display:`flex`,flexDirection:`column`,alignItems:`center`,gap:`14px`,animation:`fe-orb-slide-up 0.42s cubic-bezier(0.16,1,0.3,1)`},children:[(0,f.jsxs)(`div`,{style:{position:`relative`},children:[p===`listening`&&!h&&(0,f.jsx)(`span`,{style:{position:`absolute`,right:`100%`,marginRight:`18px`,top:`50%`,transform:`translateY(-50%)`,color:`white`,fontSize:`18px`,fontWeight:600,letterSpacing:`0.01em`,textShadow:`0 2px 4px rgba(0,0,0,0.4)`,whiteSpace:`nowrap`},children:`Listening...`}),h&&(0,f.jsx)(`span`,{style:{position:`absolute`,right:`100%`,marginRight:`18px`,top:`50%`,transform:`translateY(-50%)`,color:`#f87171`,fontSize:`16px`,fontWeight:600,letterSpacing:`0.01em`,textShadow:`0 2px 4px rgba(0,0,0,0.4)`,whiteSpace:`nowrap`},children:`Muted`}),(0,f.jsx)(bk,{size:72,voiceState:p,isMuted:h,orbColors:e})]}),p===`error`&&(0,f.jsx)(`span`,{style:{color:`#f87171`,fontSize:`13px`,fontWeight:500},children:`Could not start voice session.`}),(0,f.jsxs)(`div`,{style:{display:`flex`,gap:`12px`,alignItems:`center`},children:[(0,f.jsx)(`button`,{onClick:async()=>{if(y.current)try{if(h){oe.current=0,await y.current.setMicMuted?.(!1),g(!1);try{y.current.sendContextualUpdate?.(`The visitor has unmuted. Resume normal interaction and wait for them to speak.`)}catch{}}else{oe.current=0,await y.current.setMicMuted?.(!0),g(!0);try{y.current.sendContextualUpdate?.(`The visitor has muted their microphone. Do NOT speak, ask if they are there, or prompt them in any way. Stay completely silent until they unmute.`)}catch{}}}catch{}},title:h?`Unmute`:`Mute`,style:{width:`24px`,height:`24px`,borderRadius:`50%`,background:h?`#7f1d1d`:`#1f2937`,border:h?`1.5px solid #ef4444`:`1.5px solid #4b5563`,display:`flex`,alignItems:`center`,justifyContent:`center`,cursor:`pointer`,color:h?`#f87171`:`white`,transition:`all 0.2s ease`,boxShadow:`0 2px 8px rgba(0,0,0,0.4)`,padding:0,flexShrink:0},children:h?(0,f.jsxs)(`svg`,{width:`16`,height:`16`,viewBox:`0 0 24 24`,fill:`none`,stroke:`currentColor`,strokeWidth:`2`,strokeLinecap:`round`,strokeLinejoin:`round`,children:[(0,f.jsx)(`line`,{x1:`1`,y1:`1`,x2:`23`,y2:`23`}),(0,f.jsx)(`path`,{d:`M9 9v3a3 3 0 005.12 2.12M15 9.34V4a3 3 0 00-5.94-.6`}),(0,f.jsx)(`path`,{d:`M17 16.95A7 7 0 015 12v-2m14 0v2a7 7 0 01-.11 1.23`}),(0,f.jsx)(`line`,{x1:`12`,y1:`19`,x2:`12`,y2:`23`}),(0,f.jsx)(`line`,{x1:`8`,y1:`23`,x2:`16`,y2:`23`})]}):(0,f.jsx)(fD,{size:16,color:`currentColor`})}),(0,f.jsx)(`button`,{onClick:()=>v(e=>!e),style:{width:`24px`,height:`24px`,borderRadius:`50%`,background:`#1f2937`,border:`1.5px solid #4b5563`,display:`flex`,alignItems:`center`,justifyContent:`center`,cursor:`pointer`,color:`white`,transition:`background 0.2s ease`,boxShadow:`0 2px 8px rgba(0,0,0,0.4)`,padding:0,flexShrink:0},children:(0,f.jsx)(bD,{size:16,color:`currentColor`})})]}),_&&(0,f.jsxs)(`div`,{style:{position:`absolute`,bottom:0,right:0,width:`230px`,zIndex:9999,background:`rgba(15,22,36,0.96)`,backdropFilter:`blur(14px)`,WebkitBackdropFilter:`blur(14px)`,borderRadius:`16px`,boxShadow:`0 10px 40px rgba(0,0,0,0.45)`,animation:`fe-orb-fade-in 0.18s ease`,padding:`12px 12px 40px`},children:[(0,f.jsxs)(`button`,{onClick:()=>{v(!1),re.current=`chat`,he(t)},style:{display:`flex`,alignItems:`center`,gap:`12px`,width:`100%`,padding:`12px 16px`,background:`none`,border:`none`,color:`white`,fontSize:`14px`,fontWeight:500,cursor:`pointer`,textAlign:`left`,transition:`background 0.15s ease`,borderRadius:`8px`,whiteSpace:`nowrap`},onMouseEnter:e=>{e.currentTarget.style.background=`rgba(255,255,255,0.08)`},onMouseLeave:e=>{e.currentTarget.style.background=`none`},children:[(0,f.jsx)(xD,{}),`Enter Chat Mode`]}),(0,f.jsxs)(`button`,{onClick:()=>{v(!1),re.current=`minimized`,he(n)},style:{display:`flex`,alignItems:`center`,gap:`12px`,width:`100%`,padding:`12px 16px`,background:`none`,border:`none`,color:`#E30C12`,fontSize:`14px`,fontWeight:500,cursor:`pointer`,textAlign:`left`,transition:`background 0.15s ease`,borderRadius:`8px`,whiteSpace:`nowrap`},onMouseEnter:e=>{e.currentTarget.style.background=`rgba(227,12,18,0.1)`},onMouseLeave:e=>{e.currentTarget.style.background=`none`},children:[(0,f.jsx)(SD,{}),`End Conversation`]}),(0,f.jsx)(`button`,{onClick:()=>v(!1),style:{position:`absolute`,bottom:`8px`,right:`8px`,width:`24px`,height:`24px`,borderRadius:`50%`,background:`rgba(255,255,255,0.15)`,border:`none`,display:`flex`,alignItems:`center`,justifyContent:`center`,cursor:`pointer`,color:`white`},onMouseEnter:e=>{e.currentTarget.style.background=`rgba(255,255,255,0.25)`},onMouseLeave:e=>{e.currentTarget.style.background=`rgba(255,255,255,0.15)`},children:(0,f.jsxs)(`svg`,{width:`12`,height:`12`,viewBox:`0 0 24 24`,fill:`none`,stroke:`currentColor`,strokeWidth:`2.5`,strokeLinecap:`round`,strokeLinejoin:`round`,children:[(0,f.jsx)(`line`,{x1:`18`,y1:`6`,x2:`6`,y2:`18`}),(0,f.jsx)(`line`,{x1:`6`,y1:`6`,x2:`18`,y2:`18`})]})})]})]})}function wk({orbColors:e}){let t=Array.isArray(e)&&e.length>0?e:[`#135bd8`,`#ef334b`,`#ffbd2e`],n=t[0],r=t[1]||t[0],i=t[2]||t[0];return(0,f.jsx)(`div`,{style:{width:`32px`,height:`32px`,borderRadius:`50%`,flexShrink:0,background:`
|
|
639
639
|
radial-gradient(circle at 18% 50%, ${n} 0%, ${n}99 35%, transparent 65%),
|
|
640
640
|
radial-gradient(circle at 82% 50%, ${r} 0%, ${r}99 35%, transparent 65%),
|
|
641
641
|
radial-gradient(circle at 50% 82%, ${i} 0%, ${i}99 30%, transparent 58%),
|
|
@@ -29398,18 +29398,21 @@ function wk(e) {
|
|
|
29398
29398
|
let t = e.siteId || null, n = (e.apiBaseUrl || "").replace(/\/$/, ""), r = typeof e.getLastUserVoiceText == "function" ? e.getLastUserVoiceText : null, i = [], a = {
|
|
29399
29399
|
"fwh-navigate-mvp": async (n) => {
|
|
29400
29400
|
$("fwh-navigate-mvp ▶ raw parameters:", n);
|
|
29401
|
-
let i = gk(n), a = bk(i)
|
|
29401
|
+
let i = gk(n), a = bk(i);
|
|
29402
29402
|
if ($("fwh-navigate-mvp · coerced:", {
|
|
29403
29403
|
url: a,
|
|
29404
|
-
sectionText:
|
|
29405
|
-
expectedLandmarks:
|
|
29404
|
+
sectionText: i.section_text ?? i.sectionText ?? i.section,
|
|
29405
|
+
expectedLandmarks: Array.isArray(i.expected_landmarks) ? i.expected_landmarks : Array.isArray(i.expectedLandmarks) ? i.expectedLandmarks : []
|
|
29406
29406
|
}), !a) {
|
|
29407
29407
|
let e = "Missing url: pass a string url, path like /pricing, or JSON with a url field.";
|
|
29408
29408
|
return $("fwh-navigate-mvp ✖", e), e;
|
|
29409
29409
|
}
|
|
29410
29410
|
if (typeof window < "u") try {
|
|
29411
29411
|
let e = new URL(a, window.location.href);
|
|
29412
|
-
e.origin !== window.location.origin && /^https?:$/i.test(e.protocol)
|
|
29412
|
+
if (e.origin !== window.location.origin && /^https?:$/i.test(e.protocol)) {
|
|
29413
|
+
let t = e.hostname;
|
|
29414
|
+
return $("fwh-navigate-mvp ✖ external URL blocked:", e.href), `EXTERNAL_LINK_BLOCKED: The URL "${a}" points to an external site (${t}) that opens in a new tab. I cannot open new tabs or navigate to external sites. Tell the visitor exactly this: "That link opens an external app — I'm not able to open it for you, but you can click the link directly in the navigation header."`;
|
|
29415
|
+
}
|
|
29413
29416
|
} catch {}
|
|
29414
29417
|
if (typeof window < "u") {
|
|
29415
29418
|
try {
|
|
@@ -29627,8 +29630,8 @@ function wk(e) {
|
|
|
29627
29630
|
let n = t.getAttribute("href"), r = (t.textContent || "").replace(/\s+/g, " ").trim();
|
|
29628
29631
|
if (!r || !n || n === "#" || n.startsWith("javascript:")) return;
|
|
29629
29632
|
try {
|
|
29630
|
-
let e =
|
|
29631
|
-
if (e.display === "none"
|
|
29633
|
+
let e = t.parentElement;
|
|
29634
|
+
if (e && qO(e).display === "none" && !e.closest("nav, [role='navigation'], header, [class*='nav'], [class*='menu']")) return;
|
|
29632
29635
|
} catch {}
|
|
29633
29636
|
let i = r.toLowerCase() + "|" + n;
|
|
29634
29637
|
e.has(i) || e.set(i, {
|
|
@@ -29671,10 +29674,15 @@ function wk(e) {
|
|
|
29671
29674
|
},
|
|
29672
29675
|
"fwh-list-forms-mvp": async () => {
|
|
29673
29676
|
let e = QO(), t = $O();
|
|
29674
|
-
|
|
29675
|
-
|
|
29677
|
+
$("fwh-list-forms-mvp ✓", `${e.length} field(s)`, `${t.length} button(s)`);
|
|
29678
|
+
let n = e.map((e) => ({
|
|
29679
|
+
...e,
|
|
29680
|
+
inputCategory: e.tag === "SELECT" ? "dropdown_select" : "text_input"
|
|
29681
|
+
}));
|
|
29682
|
+
return JSON.stringify({
|
|
29683
|
+
fields: n,
|
|
29676
29684
|
buttons: t,
|
|
29677
|
-
hint: "field_key: placeholder/
|
|
29685
|
+
hint: "field_key: use the label/placeholder/name shown above. CRITICAL: fields with inputCategory='dropdown_select' are SELECT elements — their field_key must match the SELECT's own label (e.g. 'Company Size'), NOT the option text (e.g. 'Small Business') and NOT a nearby text input label. Never fill a SELECT option value into a text input."
|
|
29678
29686
|
});
|
|
29679
29687
|
},
|
|
29680
29688
|
"fwh-fill-form-mvp": async (e) => {
|
|
@@ -29691,14 +29699,29 @@ function wk(e) {
|
|
|
29691
29699
|
let t = e?.field_key, r = e?.value;
|
|
29692
29700
|
if (t == null || r == null) continue;
|
|
29693
29701
|
TO(`Filling ${String(t)}...`, { spinner: !0 });
|
|
29694
|
-
let a = ZO(), o =
|
|
29695
|
-
|
|
29696
|
-
|
|
29697
|
-
|
|
29702
|
+
let a = ZO(), o = (() => {
|
|
29703
|
+
let e = ek(r);
|
|
29704
|
+
ek(String(t));
|
|
29705
|
+
let n = null, i = 0;
|
|
29706
|
+
for (let r of a) {
|
|
29707
|
+
if (r.tagName !== "SELECT" || !Array.from(r.options).find((t) => ek(t.text) === e || ek(t.value) === e)) continue;
|
|
29708
|
+
let a = nk(r, String(t));
|
|
29709
|
+
a >= i && (i = a, n = r);
|
|
29710
|
+
}
|
|
29711
|
+
return n && i >= 0 ? n : null;
|
|
29712
|
+
})();
|
|
29713
|
+
if (o) {
|
|
29714
|
+
$("fwh-fill-form-mvp · SELECT pre-pass matched dropdown:", o.name || o.id || o.getAttribute("aria-label")), NO(o), await zO(o), xk(o, r), PO(o), await WO(120), i = [o], n.push(String(t));
|
|
29715
|
+
continue;
|
|
29716
|
+
}
|
|
29717
|
+
let s = uk(a, String(t), r);
|
|
29718
|
+
if (s.length) {
|
|
29719
|
+
for (let [e, t] of s.entries()) NO(t), await zO(t), xk(t, r, { skipScroll: e > 0 }), PO(t), await WO(120);
|
|
29720
|
+
i = s, n.push(String(t));
|
|
29698
29721
|
continue;
|
|
29699
29722
|
}
|
|
29700
|
-
let
|
|
29701
|
-
|
|
29723
|
+
let c = pk(a, String(t));
|
|
29724
|
+
c ||= ik(a, String(t)), c ||= ak(a, String(t), r), c && (NO(c), await zO(c), xk(c, r), PO(c), await WO(120), i = [c], n.push(String(t)));
|
|
29702
29725
|
}
|
|
29703
29726
|
if (!n.length) return $("fwh-fill-form-mvp ✖ no matches"), "Could not match any fields. Call fwh-list-forms-mvp and use field_key values that match placeholder, label, name, or id (e.g. Enter Website URL). Ensure the form is on the page, not the chat panel.";
|
|
29704
29727
|
let a = `OK_FILLED: ${n.join(", ")}`;
|
|
@@ -30294,7 +30317,7 @@ function Ik({ orbColors: e, onEnterChat: t, onEndChat: n, agentId: r, siteId: i,
|
|
|
30294
30317
|
y.overrides = { agent: { firstMessage: g ? e ? `Hi, welcome to ${e}!` : "Hi, welcome!" : `Welcome to the ${T} page!` } }, g || console.log(`[FlowEngage] 🏠 Page-context override: "${T}" for ${m}`);
|
|
30295
30318
|
}
|
|
30296
30319
|
else u && (y.overrides = { agent: { firstMessage: "" } });
|
|
30297
|
-
let oe = !1, he = p ?
|
|
30320
|
+
let oe = !1, he = p ? `NAVIGATION COMPLETE — Your brief intro has been spoken. PRIOR CONVERSATION CONTEXT (continue from here — do NOT re-introduce yourself):\n${n?.transcript ? `Prior transcript:\n${n.transcript}\n` : "(no prior transcript)"}\nNow speak 2-3 sentences about this page from your knowledge, referring to the visitor's prior context if relevant. Then ask the visitor exactly this: "Would you like to know about a specific section, or should I give you a complete overview?" Then STOP — wait for their reply. Do NOT auto-highlight or auto-walkthrough.` : null, ge = !1, _e = !p && !u ? "Your greeting has been spoken. Wait for the visitor to ask a question or tell you what they need. Do NOT auto-start a walkthrough or highlight any sections — let the visitor lead." : null, ve = await bD.startSession({
|
|
30298
30321
|
...y,
|
|
30299
30322
|
onConnect: ({ conversationId: e }) => {
|
|
30300
30323
|
ie.current = e, ae.current = Date.now(), console.log("[FlowEngage] 🎙️ AI chat session connected:", e);
|