@sphoro/bugcatch-web-sdk 0.14.4 → 0.15.0

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.
@@ -1,10 +1,10 @@
1
- (function(N,te){typeof exports=="object"&&typeof module<"u"?module.exports=te():typeof define=="function"&&define.amd?define(te):(N=typeof globalThis<"u"?globalThis:N||self,N.BugCatch=te())})(this,function(){"use strict";var jn=N=>{throw TypeError(N)};var Io=(N,te,we)=>te.has(N)||jn("Cannot "+we);var zn=(N,te,we)=>te.has(N)?jn("Cannot add the same private member more than once"):te instanceof WeakSet?te.add(N):te.set(N,we);var _=(N,te,we)=>(Io(N,te,"access private method"),we);var B,ye,lt,On,Hn,qn,dt,Dn;const N="[REDACTED]",te=new Set(["auth","bearer","session","sid","phpsessid","otp","pass","passwd","pwd","sig","codeverifier"]),we=["token","secret","password","passwd","apikey","signature","credential","sessionid","privatekey","accesskey","authorization"],Nn=new Set(["key","code","state","nonce","salt","hash"]),Rt=[/eyJ[\w-]{8,}\.[\w-]{8,}\.[\w-]+/g,/(?:AKIA|ASIA|AROA|AIDA|AGPA|ANPA|ANVA|APKA)[0-9A-Z]{16}/g,/AIza[\w-]{35}/g,/gh[pousr]_[A-Za-z0-9]{36,}/g,/github_pat_\w{22,}/g,/[sprk]k_(?:live|test)_[0-9A-Za-z]{10,}/g,/xox[abposr]-[A-Za-z0-9-]{10,}/g,/sk-ant-[\w-]{20,}/g,/sk-[\w-]{20,}/g,/glpat-[\w-]{20,}/g,/shp(?:at|ss|ca|pa)_[A-Za-z0-9]{32}/g],Un=/\bBearer\s+[\w.~+/=-]{8,}/gi,Vn=/^([A-Za-z][A-Za-z0-9+.-]*:\/\/)([^/?#@]+)@/;function Qt(t){try{return decodeURIComponent(t.replace(/\+/g," "))}catch{return t}}function Kn(t){return Qt(t).toLowerCase().replace(/[^a-z0-9]/g,"")}function Pn(t){return t.length>=20?!0:Rt.some(e=>(e.lastIndex=0,e.test(t)))}function _n(t,e){const n=Kn(t);if(!n)return!1;if(te.has(n))return!0;for(const a of we)if(n.includes(a))return!0;return Nn.has(n)?Pn(Qt(e)):!1}function ut(t){return t.split("&").map(e=>{const n=e.indexOf("=");if(n===-1)return e;const a=e.slice(0,n),i=e.slice(n+1);return i&&_n(a,i)?`${a}=${N}`:e}).join("&")}function jt(t){let e=t;for(const n of Rt)n.lastIndex=0,e=e.replace(n,N);return e}function zt(t){if(t==null)return t;let e=String(t);if(!e)return e;e=e.replace(Vn,`$1${N}@`);const n=e.indexOf("#");let a=n===-1?e:e.slice(0,n),i=n===-1?"":e.slice(n);const r=a.indexOf("?");if(r!==-1&&(a=a.slice(0,r+1)+ut(a.slice(r+1))),i.length>1){const s=i.slice(1),l=s.indexOf("?");l!==-1?i=`#${s.slice(0,l+1)}${ut(s.slice(l+1))}`:s.includes("=")&&(i=`#${ut(s)}`)}return jt(a+i)}function Fn(t){if(t==null)return t;let e=String(t);return e&&(e=e.replace(/[A-Za-z][A-Za-z0-9+.-]{0,30}:\/\/[^\s"'<>)\]]+/g,n=>zt(n)),e=e.replace(Un,`Bearer ${N}`),jt(e))}function Pe(t){const e=[];return{push(n){e.push(n),e.length>t&&e.splice(0,e.length-t)},all:()=>e.slice(),clear:()=>{e.length=0},get size(){return e.length}}}const Ot=["log","info","warn","error","debug"];function Wn(t,{levels:e=["warn","error","log","info"]}={}){const n={};for(const a of Ot)n[a]=console[a],e.includes(a)&&(console[a]=(...i)=>{try{t.push({level:a,text:i.map(Dt).join(" ").slice(0,2e3),at:new Date().toISOString()})}catch{}n[a].apply(console,i)});return()=>{for(const a of Ot)console[a]=n[a]}}function Yn(t,{slowMs:e=2e3}={}){const n=window.fetch,a=XMLHttpRequest.prototype.open,i=XMLHttpRequest.prototype.send;return n&&(window.fetch=async function(...s){var y,h,b;const l=performance.now(),p=typeof s[0]=="string"?s[0]:(y=s[0])==null?void 0:y.url,f=((h=s[1])==null?void 0:h.method)||(typeof s[0]=="object"?(b=s[0])==null?void 0:b.method:"GET")||"GET";try{const g=await n.apply(this,s);return pt(t,{url:p,method:f,status:g.status,ms:Math.round(performance.now()-l),slowMs:e}),g}catch(g){throw pt(t,{url:p,method:f,status:0,error:String((g==null?void 0:g.message)||g),ms:Math.round(performance.now()-l),slowMs:e}),g}}),XMLHttpRequest.prototype.open=function(s,l,...p){return this.__bc={method:s,url:l,started:0},a.call(this,s,l,...p)},XMLHttpRequest.prototype.send=function(...s){return this.__bc&&(this.__bc.started=performance.now(),this.addEventListener("loadend",()=>{pt(t,{url:this.__bc.url,method:this.__bc.method,status:this.status,ms:Math.round(performance.now()-this.__bc.started),slowMs:e})})),i.apply(this,s)},()=>{n&&(window.fetch=n),XMLHttpRequest.prototype.open=a,XMLHttpRequest.prototype.send=i}}function pt(t,{url:e,method:n,status:a,ms:i,error:r,slowMs:s}){try{t.push({url:zt(String(e)).slice(0,500),method:n,status:a,ms:i,error:r===void 0?void 0:Fn(r),failed:a===0||a>=400,slow:i>=s,at:new Date().toISOString()})}catch{}}function Xn(t){const e=a=>{const i=String(a.message||"Error"),r=a.filename?` (${a.filename}:${a.lineno}:${a.colno})`:"";t.push({level:"error",text:(/^uncaught/i.test(i)?i:`Uncaught ${i}`)+r,at:new Date().toISOString()})},n=a=>{t.push({level:"error",text:`Unhandled rejection: ${Dt(a.reason)}`,at:new Date().toISOString()})};return window.addEventListener("error",e),window.addEventListener("unhandledrejection",n),()=>{window.removeEventListener("error",e),window.removeEventListener("unhandledrejection",n)}}async function Ht(){const t=qt();try{if(navigator.getBattery){const e=await navigator.getBattery();t.battery=Math.round(e.level*100),t.charging=e.charging}}catch{}return t}function qt(){var e,n,a,i,r,s,l,p,f;const t=window.navigator||{};return{userAgent:t.userAgent,platform:t.platform,language:t.language,languages:t.languages?[...t.languages]:null,online:t.onLine,cookieEnabled:t.cookieEnabled,maxTouchPoints:t.maxTouchPoints??null,viewport:{width:window.innerWidth,height:window.innerHeight},screen:{width:(e=window.screen)==null?void 0:e.width,height:(n=window.screen)==null?void 0:n.height,availWidth:(a=window.screen)==null?void 0:a.availWidth,availHeight:(i=window.screen)==null?void 0:i.availHeight,colorDepth:(r=window.screen)==null?void 0:r.colorDepth,orientation:((l=(s=window.screen)==null?void 0:s.orientation)==null?void 0:l.type)||null},devicePixelRatio:window.devicePixelRatio,referrer:document.referrer||null,title:document.title,capturedAt:new Date().toISOString(),timezone:Intl.DateTimeFormat().resolvedOptions().timeZone,timezoneOffsetMinutes:new Date().getTimezoneOffset(),browserMode:t.webdriver?"Automated":"Normal",doNotTrack:t.doNotTrack||null,hardwareConcurrency:t.hardwareConcurrency??null,deviceMemory:t.deviceMemory??null,connection:t.connection?{effectiveType:t.connection.effectiveType,downlink:t.connection.downlink,rtt:t.connection.rtt,saveData:t.connection.saveData}:null,prefersColorScheme:(p=window.matchMedia)!=null&&p.call(window,"(prefers-color-scheme: dark)").matches?"dark":"light",prefersReducedMotion:((f=window.matchMedia)==null?void 0:f.call(window,"(prefers-reduced-motion: reduce)").matches)||!1}}function Dt(t){if(typeof t=="string")return t;if(t instanceof Error)return`${t.name}: ${t.message}`;try{return JSON.stringify(t)}catch{return String(t)}}const Zn=typeof window<"u"&&window.fetch?window.fetch.bind(window):null,Jn=typeof XMLHttpRequest<"u"?XMLHttpRequest.prototype.open:null,Gn=typeof XMLHttpRequest<"u"?XMLHttpRequest.prototype.send:null,Nt=["image/png","image/jpeg","image/webp","image/gif","video/webm","video/mp4","audio/webm","audio/ogg","audio/mpeg","audio/mp4","audio/wav","application/pdf","text/plain","text/csv","application/json","application/zip","application/msword","application/vnd.openxmlformats-officedocument.wordprocessingml.document","application/vnd.ms-excel","application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"],_e=["image/png","image/jpeg","image/webp","video/webm","video/mp4"],ea=()=>{var t;return!!((t=navigator==null?void 0:navigator.mediaDevices)!=null&&t.getUserMedia&&typeof MediaRecorder<"u")},ta=()=>{var t;return!!((t=navigator==null?void 0:navigator.mediaDevices)!=null&&t.getDisplayMedia&&typeof MediaRecorder<"u")},na=()=>{var t;return!!((t=navigator==null?void 0:navigator.mediaDevices)!=null&&t.getDisplayMedia)};function Fe(t,e=Nt){const n=String(t||"").split(";")[0].trim().toLowerCase();return e.includes(n)?n:null}async function aa(){const t=await navigator.mediaDevices.getDisplayMedia({video:{frameRate:1},audio:!1});try{const e=t.getVideoTracks()[0],n=document.createElement("video");n.srcObject=t,n.muted=!0,n.playsInline=!0,await n.play(),await new Promise(l=>requestAnimationFrame(()=>requestAnimationFrame(l)));const{width:a,height:i}=e.getSettings(),r=document.createElement("canvas");r.width=a||n.videoWidth,r.height=i||n.videoHeight,r.getContext("2d").drawImage(n,0,0,r.width,r.height);const s=await new Promise(l=>r.toBlob(l,"image/png"));if(!s)throw new Error("The browser returned an empty screenshot.");return{blob:s,mime:"image/png",kind:"SCREENSHOT"}}finally{t.getTracks().forEach(e=>e.stop())}}async function oa({maxMs:t=12e4,onTick:e,onAutoStop:n}={}){const a=await navigator.mediaDevices.getDisplayMedia({video:{frameRate:15},audio:!1}),i=["video/webm;codecs=vp9","video/webm;codecs=vp8","video/webm"].find(g=>MediaRecorder.isTypeSupported(g))||"video/webm",r=new MediaRecorder(a,{mimeType:i,videoBitsPerSecond:25e5}),s=[];r.ondataavailable=g=>{g.data.size&&s.push(g.data)},r.start(1e3);const l=Date.now(),p=setInterval(()=>e==null?void 0:e(Math.floor((Date.now()-l)/1e3)),500),f=()=>{clearInterval(p),clearTimeout(b),a.getTracks().forEach(g=>g.stop())},y=new Promise(g=>{r.onstop=()=>{f(),g(new Blob(s,{type:i}))}}),h=()=>{r.state!=="inactive"&&r.stop(),n==null||n()};a.getVideoTracks()[0].addEventListener("ended",h);const b=setTimeout(h,t);return{mime:i,maxMs:t,async stop(){return clearTimeout(b),r.state!=="inactive"&&r.stop(),{blob:await y,mime:i,kind:"VIDEO"}},cancel(){f(),r.state!=="inactive"&&r.stop()}}}async function ra({maxMs:t=12e4,onTick:e,onAutoStop:n}={}){const a=await navigator.mediaDevices.getUserMedia({audio:!0}),i=["audio/webm;codecs=opus","audio/webm","audio/mp4","audio/ogg"].find(g=>MediaRecorder.isTypeSupported(g))||"",r=new MediaRecorder(a,i?{mimeType:i}:void 0),s=[];r.ondataavailable=g=>{g.data.size&&s.push(g.data)},r.start(1e3);const l=Date.now(),p=setInterval(()=>e==null?void 0:e(Math.floor((Date.now()-l)/1e3)),500),f=()=>{clearInterval(p),clearTimeout(b),a.getTracks().forEach(g=>g.stop())},y=new Promise(g=>{r.onstop=()=>{f(),g(new Blob(s,{type:r.mimeType||i}))}}),b=setTimeout(()=>{r.state!=="inactive"&&r.stop(),n==null||n()},t);return{mime:r.mimeType||i,maxMs:t,async stop(){clearTimeout(b),r.state!=="inactive"&&r.stop();const g=await y;return{blob:g,mime:g.type||r.mimeType||i,kind:"AUDIO"}},cancel(){f(),r.state!=="inactive"&&r.stop()}}}async function ia({apiBase:t,apiKey:e,blob:n,mime:a,onProgress:i}){const r=Fe(a||n.type);if(!r)throw new Error(`[BugCatch] ${a||n.type||"that file"} can't be attached.`);const s=await Zn(`${t}/ingest/presign`,{method:"POST",headers:{"Content-Type":"application/json","X-BugCatch-Key":e},body:JSON.stringify({mime:r})});if(!s.ok)throw new Error(`[BugCatch] could not start the upload (HTTP ${s.status}).`);const{key:l,uploadUrl:p}=await s.json();return await sa(p,n,r,i),{storageKey:l,mime:r}}function sa(t,e,n,a){return new Promise((i,r)=>{const s=new XMLHttpRequest;Jn.call(s,"PUT",t,!0),s.setRequestHeader("Content-Type",n),s.upload.onprogress=l=>{l.lengthComputable&&(a==null||a(l.loaded/l.total))},s.onload=()=>{s.status>=200&&s.status<300?i():r(new Error(`[BugCatch] upload failed (HTTP ${s.status}).`))},s.onerror=()=>r(new Error("[BugCatch] the browser blocked the upload to storage. If this is a new environment, the media bucket is probably missing its CORS policy.")),s.onabort=()=>r(new Error("[BugCatch] upload cancelled.")),Gn.call(s,e)})}function Me(t){return t<1024?`${t} B`:t<1024*1024?`${(t/1024).toFixed(0)} KB`:`${(t/1024/1024).toFixed(1)} MB`}function We(t){const e=Math.floor(t/60),n=t%60;return`${e}:${String(n).padStart(2,"0")}`}const ca=7*24*60*60*1e3;let Ye;function la(){return Ye||(Ye=new Promise((t,e)=>{const n=indexedDB.open("bugcatch-drafts",1);n.onupgradeneeded=()=>n.result.createObjectStore("drafts"),n.onsuccess=()=>t(n.result),n.onerror=()=>e(n.error),n.onblocked=()=>e(new Error("Draft storage is blocked."))}).catch(t=>{throw Ye=null,t})),Ye}function da(t,e){var n,a;return JSON.stringify([t.apiBase,t.projectId,e||((n=t.user)==null?void 0:n.email)||((a=t.user)==null?void 0:a.id)||"anonymous"])}async function Xe(t,e){const n=await la();return new Promise((a,i)=>{const r=n.transaction("drafts",e===void 0?"readonly":"readwrite"),s=r.objectStore("drafts"),l=e===void 0?s.get(t):e===null?s.delete(t):s.put({...e,savedAt:Date.now()},t);r.oncomplete=()=>a(l.result),r.onerror=()=>i(r.error),r.onabort=()=>i(r.error||new Error("Draft was not saved."))})}async function ua(t){const e=await Xe(t);return e&&Date.now()-e.savedAt>ca?(await Xe(t,null),null):e||null}const pa="bugcatch.session.",ht=t=>`${pa}${t}`,ft=new Map;function fe(t){var e;if(!t)return null;try{const n=(e=window.localStorage)==null?void 0:e.getItem(ht(t));if(n){const a=JSON.parse(n);if(a!=null&&a.token)return a}}catch{}return ft.get(t)||null}function ha(t,e){var a;if(!t||!(e!=null&&e.token))return;const n={token:e.token,email:e.email||null,name:e.name||null};ft.set(t,n);try{(a=window.localStorage)==null||a.setItem(ht(t),JSON.stringify(n))}catch{}}function gt(t){var e;if(t){ft.delete(t);try{(e=window.localStorage)==null||e.removeItem(ht(t))}catch{}}}function Ze({apiKey:t,token:e}){return{"Content-Type":"application/json","X-BugCatch-Key":t,...e?{"X-BugCatch-Session":e}:{}}}async function Ut(t){try{const e=await t.json(),n=Array.isArray(e.message)?e.message.join(", "):e.message;if(n)return n}catch{}return`Request failed (HTTP ${t.status})`}async function fa({apiBase:t,apiKey:e,projectId:n,token:a}){const i={mode:"off",signedIn:null,signedOutReason:null};try{const r=await fetch(`${t}/ingest/login?projectId=${encodeURIComponent(n)}`,{headers:Ze({apiKey:e,token:a})});if(!r.ok)return i;const s=await r.json();return{mode:s.mode==="optional"||s.mode==="required"?s.mode:"off",signedIn:s.signedIn||null,signedOutReason:s.signedOutReason||null}}catch{return i}}async function ga({apiBase:t,apiKey:e,projectId:n,email:a,name:i}){const r=await fetch(`${t}/ingest/login/start`,{method:"POST",headers:Ze({apiKey:e}),body:JSON.stringify({projectId:n,email:a,...i?{name:i}:{}})});if(!r.ok)throw new Error(await Ut(r));return r.json()}async function ma({apiBase:t,apiKey:e,projectId:n,email:a,code:i}){const r=await fetch(`${t}/ingest/login`,{method:"POST",headers:Ze({apiKey:e}),body:JSON.stringify({projectId:n,email:a,code:i})});if(!r.ok)throw new Error(await Ut(r));const s=await r.json(),l={token:s.sessionToken,email:s.email,name:s.name};return ha(n,l),l}async function ba({apiBase:t,apiKey:e,projectId:n,token:a}){if(gt(n),!a)return{signedOut:!0};try{await fetch(`${t}/ingest/logout`,{method:"POST",headers:Ze({apiKey:e,token:a}),body:JSON.stringify({projectId:n})})}catch{}return{signedOut:!0}}const mt="bugcatch.watch",Vt=[2e3,5e3,15e3,3e4,6e4],ya=5e3;function re(){var t;try{return((t=window.localStorage)==null?void 0:t.getItem(mt))||null}catch{return null}}function bt(t){var e;if(t)try{(e=window.localStorage)==null||e.setItem(mt,t)}catch{}}function ve(){var t;try{(t=window.localStorage)==null||t.removeItem(mt)}catch{}Kt()}const Je="bugcatch.unread";function wa(t){return[(t==null?void 0:t.bugId)||"report",(t==null?void 0:t.kind)||"status",(t==null?void 0:t.at)||""].join("|")}function qe(){var t;try{const e=(t=window.localStorage)==null?void 0:t.getItem(Je),n=e?JSON.parse(e):[];return Array.isArray(n)?n.filter(a=>a&&typeof a.id=="string"):[]}catch{return[]}}function Ge(t){var e,n;try{t.length?(e=window.localStorage)==null||e.setItem(Je,JSON.stringify(t)):(n=window.localStorage)==null||n.removeItem(Je)}catch{}}function va(t){const e={...t,id:wa(t)},n=qe().filter(a=>a.id!==e.id);return n.push(e),Ge(n.slice(-20)),e}function xa(t){const e=qe().filter(n=>n.id!==t);return Ge(e),e}function ka(t){const e=qe().filter(n=>n.bugId!==t);return Ge(e),e}function Kt(){return Ge([]),[]}function Sa(t,e){let n=t,a=n.indexOf(`
1
+ (function(Y,se){typeof exports=="object"&&typeof module<"u"?module.exports=se():typeof define=="function"&&define.amd?define(se):(Y=typeof globalThis<"u"?globalThis:Y||self,Y.BugCatch=se())})(this,function(){"use strict";var oo=Y=>{throw TypeError(Y)};var hr=(Y,se,Ee)=>se.has(Y)||oo("Cannot "+Ee);var ao=(Y,se,Ee)=>se.has(Y)?oo("Cannot add the same private member more than once"):se instanceof WeakSet?se.add(Y):se.set(Y,Ee);var H=(Y,se,Ee)=>(hr(Y,se,"access private method"),Ee);var E,vt,Te,ro,Yt,xt,kt,io,so,co,St,lo;const Y="[REDACTED]",se=new Set(["auth","bearer","session","sid","phpsessid","otp","pass","passwd","pwd","sig","codeverifier"]),Ee=["token","secret","password","passwd","apikey","signature","credential","sessionid","privatekey","accesskey","authorization"],uo=new Set(["key","code","state","nonce","salt","hash"]),Xt=[/eyJ[\w-]{8,}\.[\w-]{8,}\.[\w-]+/g,/(?:AKIA|ASIA|AROA|AIDA|AGPA|ANPA|ANVA|APKA)[0-9A-Z]{16}/g,/AIza[\w-]{35}/g,/gh[pousr]_[A-Za-z0-9]{36,}/g,/github_pat_\w{22,}/g,/[sprk]k_(?:live|test)_[0-9A-Za-z]{10,}/g,/xox[abposr]-[A-Za-z0-9-]{10,}/g,/sk-ant-[\w-]{20,}/g,/sk-[\w-]{20,}/g,/glpat-[\w-]{20,}/g,/shp(?:at|ss|ca|pa)_[A-Za-z0-9]{32}/g],po=/\bBearer\s+[\w.~+/=-]{8,}/gi,ho=/^([A-Za-z][A-Za-z0-9+.-]*:\/\/)([^/?#@]+)@/;function Jt(t){try{return decodeURIComponent(t.replace(/\+/g," "))}catch{return t}}function fo(t){return Jt(t).toLowerCase().replace(/[^a-z0-9]/g,"")}function go(t){return t.length>=20?!0:Xt.some(e=>(e.lastIndex=0,e.test(t)))}function bo(t,e){const n=fo(t);if(!n)return!1;if(se.has(n))return!0;for(const o of Ee)if(n.includes(o))return!0;return uo.has(n)?go(Jt(e)):!1}function $t(t){return t.split("&").map(e=>{const n=e.indexOf("=");if(n===-1)return e;const o=e.slice(0,n),i=e.slice(n+1);return i&&bo(o,i)?`${o}=${Y}`:e}).join("&")}function Zt(t){let e=t;for(const n of Xt)n.lastIndex=0,e=e.replace(n,Y);return e}function Gt(t){if(t==null)return t;let e=String(t);if(!e)return e;e=e.replace(ho,`$1${Y}@`);const n=e.indexOf("#");let o=n===-1?e:e.slice(0,n),i=n===-1?"":e.slice(n);const a=o.indexOf("?");if(a!==-1&&(o=o.slice(0,a+1)+$t(o.slice(a+1))),i.length>1){const s=i.slice(1),l=s.indexOf("?");l!==-1?i=`#${s.slice(0,l+1)}${$t(s.slice(l+1))}`:s.includes("=")&&(i=`#${$t(s)}`)}return Zt(o+i)}function mo(t){if(t==null)return t;let e=String(t);return e&&(e=e.replace(/[A-Za-z][A-Za-z0-9+.-]{0,30}:\/\/[^\s"'<>)\]]+/g,n=>Gt(n)),e=e.replace(po,`Bearer ${Y}`),Zt(e))}function et(t){const e=[];return{push(n){e.push(n),e.length>t&&e.splice(0,e.length-t)},all:()=>e.slice(),clear:()=>{e.length=0},get size(){return e.length}}}const en=["log","info","warn","error","debug"];function yo(t,{levels:e=["warn","error","log","info"]}={}){const n={};for(const o of en)n[o]=console[o],e.includes(o)&&(console[o]=(...i)=>{try{t.push({level:o,text:i.map(on).join(" ").slice(0,2e3),at:new Date().toISOString()})}catch{}n[o].apply(console,i)});return()=>{for(const o of en)console[o]=n[o]}}function wo(t,{slowMs:e=2e3}={}){const n=window.fetch,o=XMLHttpRequest.prototype.open,i=XMLHttpRequest.prototype.send;return n&&(window.fetch=async function(...s){var b,f,m;const l=performance.now(),p=typeof s[0]=="string"?s[0]:(b=s[0])==null?void 0:b.url,h=((f=s[1])==null?void 0:f.method)||(typeof s[0]=="object"?(m=s[0])==null?void 0:m.method:"GET")||"GET";try{const g=await n.apply(this,s);return Ct(t,{url:p,method:h,status:g.status,ms:Math.round(performance.now()-l),slowMs:e}),g}catch(g){throw Ct(t,{url:p,method:h,status:0,error:String((g==null?void 0:g.message)||g),ms:Math.round(performance.now()-l),slowMs:e}),g}}),XMLHttpRequest.prototype.open=function(s,l,...p){return this.__bc={method:s,url:l,started:0},o.call(this,s,l,...p)},XMLHttpRequest.prototype.send=function(...s){return this.__bc&&(this.__bc.started=performance.now(),this.addEventListener("loadend",()=>{Ct(t,{url:this.__bc.url,method:this.__bc.method,status:this.status,ms:Math.round(performance.now()-this.__bc.started),slowMs:e})})),i.apply(this,s)},()=>{n&&(window.fetch=n),XMLHttpRequest.prototype.open=o,XMLHttpRequest.prototype.send=i}}function Ct(t,{url:e,method:n,status:o,ms:i,error:a,slowMs:s}){try{t.push({url:Gt(String(e)).slice(0,500),method:n,status:o,ms:i,error:a===void 0?void 0:mo(a),failed:o===0||o>=400,slow:i>=s,at:new Date().toISOString()})}catch{}}function vo(t){const e=o=>{const i=String(o.message||"Error"),a=o.filename?` (${o.filename}:${o.lineno}:${o.colno})`:"";t.push({level:"error",text:(/^uncaught/i.test(i)?i:`Uncaught ${i}`)+a,at:new Date().toISOString()})},n=o=>{t.push({level:"error",text:`Unhandled rejection: ${on(o.reason)}`,at:new Date().toISOString()})};return window.addEventListener("error",e),window.addEventListener("unhandledrejection",n),()=>{window.removeEventListener("error",e),window.removeEventListener("unhandledrejection",n)}}async function tn(){const t=nn();try{if(navigator.getBattery){const e=await navigator.getBattery();t.battery=Math.round(e.level*100),t.charging=e.charging}}catch{}return t}function nn(){var e,n,o,i,a,s,l,p,h;const t=window.navigator||{};return{userAgent:t.userAgent,platform:t.platform,language:t.language,languages:t.languages?[...t.languages]:null,online:t.onLine,cookieEnabled:t.cookieEnabled,maxTouchPoints:t.maxTouchPoints??null,viewport:{width:window.innerWidth,height:window.innerHeight},screen:{width:(e=window.screen)==null?void 0:e.width,height:(n=window.screen)==null?void 0:n.height,availWidth:(o=window.screen)==null?void 0:o.availWidth,availHeight:(i=window.screen)==null?void 0:i.availHeight,colorDepth:(a=window.screen)==null?void 0:a.colorDepth,orientation:((l=(s=window.screen)==null?void 0:s.orientation)==null?void 0:l.type)||null},devicePixelRatio:window.devicePixelRatio,referrer:document.referrer||null,title:document.title,capturedAt:new Date().toISOString(),timezone:Intl.DateTimeFormat().resolvedOptions().timeZone,timezoneOffsetMinutes:new Date().getTimezoneOffset(),browserMode:t.webdriver?"Automated":"Normal",doNotTrack:t.doNotTrack||null,hardwareConcurrency:t.hardwareConcurrency??null,deviceMemory:t.deviceMemory??null,connection:t.connection?{effectiveType:t.connection.effectiveType,downlink:t.connection.downlink,rtt:t.connection.rtt,saveData:t.connection.saveData}:null,prefersColorScheme:(p=window.matchMedia)!=null&&p.call(window,"(prefers-color-scheme: dark)").matches?"dark":"light",prefersReducedMotion:((h=window.matchMedia)==null?void 0:h.call(window,"(prefers-reduced-motion: reduce)").matches)||!1}}function on(t){if(typeof t=="string")return t;if(t instanceof Error)return`${t.name}: ${t.message}`;try{return JSON.stringify(t)}catch{return String(t)}}const xo=typeof window<"u"&&window.fetch?window.fetch.bind(window):null,ko=typeof XMLHttpRequest<"u"?XMLHttpRequest.prototype.open:null,So=typeof XMLHttpRequest<"u"?XMLHttpRequest.prototype.send:null,an=["image/png","image/jpeg","image/webp","image/gif","video/webm","video/mp4","audio/webm","audio/ogg","audio/mpeg","audio/mp4","audio/wav","application/pdf","text/plain","text/csv","application/json","application/zip","application/msword","application/vnd.openxmlformats-officedocument.wordprocessingml.document","application/vnd.ms-excel","application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"],tt=["image/png","image/jpeg","image/webp","video/webm","video/mp4"],$o=()=>{var t;return!!((t=navigator==null?void 0:navigator.mediaDevices)!=null&&t.getUserMedia&&typeof MediaRecorder<"u")},Co=()=>{var t;return!!((t=navigator==null?void 0:navigator.mediaDevices)!=null&&t.getDisplayMedia&&typeof MediaRecorder<"u")},To=()=>{var t;return!!((t=navigator==null?void 0:navigator.mediaDevices)!=null&&t.getDisplayMedia)};function nt(t,e=an){const n=String(t||"").split(";")[0].trim().toLowerCase();return e.includes(n)?n:null}async function Eo(){const t=await navigator.mediaDevices.getDisplayMedia({video:{frameRate:1},audio:!1});try{const e=t.getVideoTracks()[0],n=document.createElement("video");n.srcObject=t,n.muted=!0,n.playsInline=!0,await n.play(),await new Promise(l=>requestAnimationFrame(()=>requestAnimationFrame(l)));const{width:o,height:i}=e.getSettings(),a=document.createElement("canvas");a.width=o||n.videoWidth,a.height=i||n.videoHeight,a.getContext("2d").drawImage(n,0,0,a.width,a.height);const s=await new Promise(l=>a.toBlob(l,"image/png"));if(!s)throw new Error("The browser returned an empty screenshot.");return{blob:s,mime:"image/png",kind:"SCREENSHOT"}}finally{t.getTracks().forEach(e=>e.stop())}}async function Io({maxMs:t=12e4,onTick:e,onAutoStop:n}={}){const o=await navigator.mediaDevices.getDisplayMedia({video:{frameRate:15},audio:!1}),i=["video/webm;codecs=vp9","video/webm;codecs=vp8","video/webm"].find(g=>MediaRecorder.isTypeSupported(g))||"video/webm",a=new MediaRecorder(o,{mimeType:i,videoBitsPerSecond:25e5}),s=[];a.ondataavailable=g=>{g.data.size&&s.push(g.data)},a.start(1e3);const l=Date.now(),p=setInterval(()=>e==null?void 0:e(Math.floor((Date.now()-l)/1e3)),500),h=()=>{clearInterval(p),clearTimeout(m),o.getTracks().forEach(g=>g.stop())},b=new Promise(g=>{a.onstop=()=>{h(),g(new Blob(s,{type:i}))}}),f=()=>{a.state!=="inactive"&&a.stop(),n==null||n()};o.getVideoTracks()[0].addEventListener("ended",f);const m=setTimeout(f,t);return{mime:i,maxMs:t,async stop(){return clearTimeout(m),a.state!=="inactive"&&a.stop(),{blob:await b,mime:i,kind:"VIDEO"}},cancel(){h(),a.state!=="inactive"&&a.stop()}}}async function Mo({maxMs:t=12e4,onTick:e,onAutoStop:n}={}){const o=await navigator.mediaDevices.getUserMedia({audio:!0}),i=["audio/webm;codecs=opus","audio/webm","audio/mp4","audio/ogg"].find(g=>MediaRecorder.isTypeSupported(g))||"",a=new MediaRecorder(o,i?{mimeType:i}:void 0),s=[];a.ondataavailable=g=>{g.data.size&&s.push(g.data)},a.start(1e3);const l=Date.now(),p=setInterval(()=>e==null?void 0:e(Math.floor((Date.now()-l)/1e3)),500),h=()=>{clearInterval(p),clearTimeout(m),o.getTracks().forEach(g=>g.stop())},b=new Promise(g=>{a.onstop=()=>{h(),g(new Blob(s,{type:a.mimeType||i}))}}),m=setTimeout(()=>{a.state!=="inactive"&&a.stop(),n==null||n()},t);return{mime:a.mimeType||i,maxMs:t,async stop(){clearTimeout(m),a.state!=="inactive"&&a.stop();const g=await b;return{blob:g,mime:g.type||a.mimeType||i,kind:"AUDIO"}},cancel(){h(),a.state!=="inactive"&&a.stop()}}}async function Ao({apiBase:t,apiKey:e,blob:n,mime:o,onProgress:i}){const a=nt(o||n.type);if(!a)throw new Error(`[BugCatch] ${o||n.type||"that file"} can't be attached.`);const s=await xo(`${t}/ingest/presign`,{method:"POST",headers:{"Content-Type":"application/json","X-BugCatch-Key":e},body:JSON.stringify({mime:a})});if(!s.ok)throw new Error(`[BugCatch] could not start the upload (HTTP ${s.status}).`);const{key:l,uploadUrl:p}=await s.json();return await Lo(p,n,a,i),{storageKey:l,mime:a}}function Lo(t,e,n,o){return new Promise((i,a)=>{const s=new XMLHttpRequest;ko.call(s,"PUT",t,!0),s.setRequestHeader("Content-Type",n),s.upload.onprogress=l=>{l.lengthComputable&&(o==null||o(l.loaded/l.total))},s.onload=()=>{s.status>=200&&s.status<300?i():a(new Error(`[BugCatch] upload failed (HTTP ${s.status}).`))},s.onerror=()=>a(new Error("[BugCatch] the browser blocked the upload to storage. If this is a new environment, the media bucket is probably missing its CORS policy.")),s.onabort=()=>a(new Error("[BugCatch] upload cancelled.")),So.call(s,e)})}function Be(t){return t<1024?`${t} B`:t<1024*1024?`${(t/1024).toFixed(0)} KB`:`${(t/1024/1024).toFixed(1)} MB`}function ot(t){const e=Math.floor(t/60),n=t%60;return`${e}:${String(n).padStart(2,"0")}`}const Bo=7*24*60*60*1e3;let at;function Ro(){return at||(at=new Promise((t,e)=>{const n=indexedDB.open("bugcatch-drafts",1);n.onupgradeneeded=()=>n.result.createObjectStore("drafts"),n.onsuccess=()=>t(n.result),n.onerror=()=>e(n.error),n.onblocked=()=>e(new Error("Draft storage is blocked."))}).catch(t=>{throw at=null,t})),at}function jo(t,e){var n,o;return JSON.stringify([t.apiBase,t.projectId,e||((n=t.user)==null?void 0:n.email)||((o=t.user)==null?void 0:o.id)||"anonymous"])}async function rt(t,e){const n=await Ro();return new Promise((o,i)=>{const a=n.transaction("drafts",e===void 0?"readonly":"readwrite"),s=a.objectStore("drafts"),l=e===void 0?s.get(t):e===null?s.delete(t):s.put({...e,savedAt:Date.now()},t);a.oncomplete=()=>o(l.result),a.onerror=()=>i(a.error),a.onabort=()=>i(a.error||new Error("Draft was not saved."))})}async function zo(t){const e=await rt(t);return e&&Date.now()-e.savedAt>Bo?(await rt(t,null),null):e||null}const Qo="bugcatch.session.",Tt=t=>`${Qo}${t}`,Et=new Map;function ke(t){var e;if(!t)return null;try{const n=(e=window.localStorage)==null?void 0:e.getItem(Tt(t));if(n){const o=JSON.parse(n);if(o!=null&&o.token)return o}}catch{}return Et.get(t)||null}function Oo(t,e){var o;if(!t||!(e!=null&&e.token))return;const n={token:e.token,email:e.email||null,name:e.name||null};Et.set(t,n);try{(o=window.localStorage)==null||o.setItem(Tt(t),JSON.stringify(n))}catch{}}function It(t){var e;if(t){Et.delete(t);try{(e=window.localStorage)==null||e.removeItem(Tt(t))}catch{}}}function it({apiKey:t,token:e}){return{"Content-Type":"application/json","X-BugCatch-Key":t,...e?{"X-BugCatch-Session":e}:{}}}async function rn(t){try{const e=await t.json(),n=Array.isArray(e.message)?e.message.join(", "):e.message;if(n)return n}catch{}return`Request failed (HTTP ${t.status})`}async function Ho({apiBase:t,apiKey:e,projectId:n,token:o}){const i={mode:"off",signedIn:null,signedOutReason:null};try{const a=await fetch(`${t}/ingest/login?projectId=${encodeURIComponent(n)}`,{headers:it({apiKey:e,token:o})});if(!a.ok)return i;const s=await a.json();return{mode:s.mode==="optional"||s.mode==="required"?s.mode:"off",signedIn:s.signedIn||null,signedOutReason:s.signedOutReason||null}}catch{return i}}async function qo({apiBase:t,apiKey:e,projectId:n,email:o,name:i}){const a=await fetch(`${t}/ingest/login/start`,{method:"POST",headers:it({apiKey:e}),body:JSON.stringify({projectId:n,email:o,...i?{name:i}:{}})});if(!a.ok)throw new Error(await rn(a));return a.json()}async function Do({apiBase:t,apiKey:e,projectId:n,email:o,code:i}){const a=await fetch(`${t}/ingest/login`,{method:"POST",headers:it({apiKey:e}),body:JSON.stringify({projectId:n,email:o,code:i})});if(!a.ok)throw new Error(await rn(a));const s=await a.json(),l={token:s.sessionToken,email:s.email,name:s.name};return Oo(n,l),l}async function No({apiBase:t,apiKey:e,projectId:n,token:o}){if(It(n),!o)return{signedOut:!0};try{await fetch(`${t}/ingest/logout`,{method:"POST",headers:it({apiKey:e,token:o}),body:JSON.stringify({projectId:n})})}catch{}return{signedOut:!0}}const Mt="bugcatch.watch",sn=[2e3,5e3,15e3,3e4,6e4],Uo=5e3;function ce(){var t;try{return((t=window.localStorage)==null?void 0:t.getItem(Mt))||null}catch{return null}}function At(t){var e;if(t)try{(e=window.localStorage)==null||e.setItem(Mt,t)}catch{}}function Ie(){var t;try{(t=window.localStorage)==null||t.removeItem(Mt)}catch{}cn()}const st="bugcatch.unread";function Ko(t){return[(t==null?void 0:t.bugId)||"report",(t==null?void 0:t.kind)||"status",(t==null?void 0:t.at)||""].join("|")}function qe(){var t;try{const e=(t=window.localStorage)==null?void 0:t.getItem(st),n=e?JSON.parse(e):[];return Array.isArray(n)?n.filter(o=>o&&typeof o.id=="string"):[]}catch{return[]}}function ct(t){var e,n;try{t.length?(e=window.localStorage)==null||e.setItem(st,JSON.stringify(t)):(n=window.localStorage)==null||n.removeItem(st)}catch{}}function Po(t){const e={...t,id:Ko(t)},n=qe().filter(o=>o.id!==e.id);return n.push(e),ct(n.slice(-20)),e}function _o(t){const e=qe().filter(n=>n.id!==t);return ct(e),e}function Vo(t){const e=qe().filter(n=>n.bugId!==t);return ct(e),e}function cn(){return ct([]),[]}function Fo(t,e){let n=t,o=n.indexOf(`
2
2
 
3
- `);for(;a!==-1;){const i=n.slice(0,a);n=n.slice(a+2);const r=i.split(`
3
+ `);for(;o!==-1;){const i=n.slice(0,o);n=n.slice(o+2);const a=i.split(`
4
4
  `).filter(s=>s.startsWith("data:")).map(s=>s.slice(5).trim()).join(`
5
- `);if(r)try{e(JSON.parse(r))}catch{}a=n.indexOf(`
5
+ `);if(a)try{e(JSON.parse(a))}catch{}o=n.indexOf(`
6
6
 
7
- `)}return n}async function Ca({apiBase:t}){const e=re();if(!e)return{reporter:null,reports:[]};const n=await fetch(`${t}/ingest/watch/reports`,{headers:{Authorization:`Bearer ${e}`}});if(n.status===401)return ve(),{reporter:null,reports:[]};if(!n.ok)throw new Error(`[BugCatch] could not load your reports (HTTP ${n.status})`);return n.json()}async function $a({apiBase:t,bugId:e}){const n=re();if(!n)return null;const a=await fetch(`${t}/ingest/watch/reports/${encodeURIComponent(e)}`,{headers:{Authorization:`Bearer ${n}`}});if(a.status===401)return ve(),null;if(a.status===404)return null;if(!a.ok)throw new Error(`[BugCatch] could not load that report (HTTP ${a.status})`);return a.json()}async function Pt({apiBase:t,bugId:e,body:n,attachments:a}){const i=re();if(!i)throw new Error("[BugCatch] nothing filed from this browser yet.");const r=await fetch(`${t}/ingest/watch/reports/${encodeURIComponent(e)}/messages`,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${i}`},body:JSON.stringify({...n?{body:n}:{},...a!=null&&a.length?{attachments:a}:{}})});if(r.status===401)throw ve(),new Error("[BugCatch] this browser can no longer prove it filed that report.");if(!r.ok){let s="";try{const l=await r.json();s=Array.isArray(l.message)?l.message.join(", "):l.message||""}catch{}throw new Error(s||`[BugCatch] could not send that (HTTP ${r.status}).`)}return r.json()}async function Ea({apiBase:t,apiKey:e,projectId:n}){const a={agent:!1,live:!1};try{const i=await fetch(`${t}/ingest/calls?projectId=${encodeURIComponent(n)}`,{headers:{"X-BugCatch-Key":e}});if(!i.ok)return a;const r=await i.json();return r!=null&&r.available?r.kinds&&typeof r.kinds=="object"?{agent:!1,live:!!r.kinds.live}:{agent:!1,live:r.kind==="live"}:a}catch{return a}}async function Ta({apiBase:t,apiKey:e,token:n,payload:a}){const i=await fetch(`${t}/ingest/calls`,{method:"POST",headers:{"Content-Type":"application/json","X-BugCatch-Key":e,...n?{"X-BugCatch-Session":n}:{}},body:JSON.stringify(a)});if(!i.ok){let r="";try{const l=await i.json();r=Array.isArray(l.message)?l.message.join(", "):l.message||""}catch{}const s=new Error(r||`[BugCatch] the call could not be started (HTTP ${i.status}).`);throw s.status=i.status,s}return i.json()}async function _t({apiBase:t,bugId:e}){const n=re();if(!n)return!1;try{const a=await fetch(`${t}/ingest/watch/reports/${encodeURIComponent(e)}/live-call`,{headers:{Authorization:`Bearer ${n}`}});if(!a.ok)return!1;const i=await a.json();return!!(i!=null&&i.offered)}catch{return!1}}async function Ia({apiBase:t,bugId:e}){const n=re();if(!n)throw new Error("[BugCatch] nothing filed from this browser yet.");const a=await fetch(`${t}/ingest/watch/reports/${encodeURIComponent(e)}/live-call`,{method:"POST",headers:{Authorization:`Bearer ${n}`}});if(a.status===401)throw ve(),new Error("[BugCatch] this browser can no longer prove it filed that report.");if(!a.ok){let i="";try{const r=await a.json();i=Array.isArray(r.message)?r.message.join(", "):r.message||""}catch{}throw new Error(i||`[BugCatch] the call could not be started (HTTP ${a.status}).`)}return a.json()}async function Ma({apiBase:t,bugId:e,callId:n}){const a=re();if(a)try{await fetch(`${t}/ingest/watch/reports/${encodeURIComponent(e)}/live-call/${encodeURIComponent(n)}/give-up`,{method:"POST",headers:{Authorization:`Bearer ${a}`}})}catch{}}async function La({apiBase:t,bugId:e,callId:n}){const a=re();if(!a)throw new Error("[BugCatch] nothing filed from this browser yet.");const i=await fetch(`${t}/ingest/watch/reports/${encodeURIComponent(e)}/live-call/${encodeURIComponent(n)}/answer`,{method:"POST",headers:{Authorization:`Bearer ${a}`}});if(i.status===401)throw ve(),new Error("[BugCatch] this browser can no longer prove it filed that report.");if(i.status===409)throw new Error("[BugCatch] that call is no longer ringing.");if(!i.ok){let r="";try{const s=await i.json();r=Array.isArray(s.message)?s.message.join(", "):s.message||""}catch{}throw new Error(r||`[BugCatch] the call could not be answered (HTTP ${i.status}).`)}return i.json()}async function Ft({apiBase:t,bugId:e,callId:n}){const a=re();if(a)try{await fetch(`${t}/ingest/watch/reports/${encodeURIComponent(e)}/live-call/${encodeURIComponent(n)}/decline`,{method:"POST",headers:{Authorization:`Bearer ${a}`}})}catch{}}function Ba({apiBase:t,onUpdate:e}){let n=!0,a=0,i=null;async function r(){const s=re();if(!s)throw new Error("nothing filed from this browser yet");i=new AbortController;const l=await fetch(`${t}/ingest/watch/stream`,{headers:{Authorization:`Bearer ${s}`,Accept:"text/event-stream"},signal:i.signal});if(l.status===401)throw n=!1,ve(),new Error("subscription no longer valid");if(!l.ok||!l.body)throw new Error(`stream failed (${l.status})`);const p=Date.now(),f=l.body.getReader(),y=new TextDecoder;let h="";try{for(;;){const{value:b,done:g}=await f.read();if(g)break;h+=y.decode(b,{stream:!0}),h=Sa(h,S=>{if(S.type!=="ping")try{e(S)}catch{}})}}finally{Date.now()-p>=ya&&(a=0)}}return(async()=>{for(;n;){try{await r()}catch(l){if((l==null?void 0:l.name)==="AbortError")return}if(!n)return;const s=Vt[Math.min(a,Vt.length-1)];a+=1,await new Promise(l=>setTimeout(l,s))}})(),()=>{n=!1,i==null||i.abort(),i=null}}const Aa={OPEN:"is open",IN_PROGRESS:"is being worked on",RESOLVED:"has been fixed",CLOSED:"has been closed"},Ra={status:null,severity:"#e8912a",assignment:"#4da3ff",reply:"#35b87f"};function Wt(t){return t!=null&&t.summary?t.summary:`Your report ${Aa[t==null?void 0:t.status]||"was updated"}`}function Qa(t){var e;return(t==null?void 0:t.kind)==="reply"&&((e=t.reply)!=null&&e.body)?`${t.reply.author?`${t.reply.author}: `:""}${t.reply.body}`:(t==null?void 0:t.title)||""}function ja(t){const e=Date.parse(t||"");if(!Number.isFinite(e))return"";const n=Math.round((Date.now()-e)/6e4);if(n<1)return"just now";if(n<60)return`${n}m ago`;const a=Math.round(n/60);if(a<24)return`${a}h ago`;const i=Math.round(a/24);return i===1?"yesterday":`${i}d ago`}function za(){var t;try{const e=document.querySelector('[data-bugcatch="widget"]'),n=(t=e==null?void 0:e.shadowRoot)==null?void 0:t.querySelector(".dock"),a=(n==null?void 0:n.getBoundingClientRect().height)||0;return a?Math.round(a)+12:0}catch{return 0}}function Oa({accent:t="#4F46E5",position:e="bottom-right",onRead:n=null,onReadAll:a=null,onCall:i=null}={}){const[r,s]=String(e).split("-"),l=r==="top",p=s==="left",f=new Map;let y=null,h=null;function b(){return y!=null&&y.isConnected||(y=document.createElement("div"),y.setAttribute("data-bugcatch","updates"),y.style.cssText=["position:fixed",`${l?"top":"bottom"}:${20+za()}px`,`${p?"left":"right"}:20px`,"z-index:2147482998","display:flex","flex-direction:column","gap:10px",`align-items:${p?"flex-start":"flex-end"}`,"width:min(320px,calc(100vw - 40px))","pointer-events:none"].join(";"),document.body.appendChild(y)),y}function g(C){if(!C._bcShown){C.remove();return}C.style.opacity="0",C.style.transform=`translateY(${l?-8:8}px)`,setTimeout(()=>C.remove(),250)}function S(C,$){const T=document.createElement("button");return T.type="button",T.textContent=C,T.style.cssText=["padding:5px 11px",`border:${$?"0":"1px solid rgba(236,238,242,.24)"}`,"border-radius:6px",`background:${$?t:"transparent"}`,`color:${$?"#fff":"#eceef2"}`,"font:600 12px/1.4 inherit","cursor:pointer","white-space:nowrap"].join(";"),T}function A(C){var V;const $=document.createElement("div");$.setAttribute("role","status"),$.style.cssText=["box-sizing:border-box","width:100%","padding:12px 14px","border-radius:10px","background:#1b1e26","color:#eceef2",'font:13px/1.5 -apple-system,BlinkMacSystemFont,"Segoe UI",sans-serif',"box-shadow:0 12px 30px rgba(0,0,0,0.45)",`border-left:3px solid ${Ra[C==null?void 0:C.kind]||t}`,"opacity:0",`transform:translateY(${l?-8:8}px)`,"transition:opacity .2s ease,transform .2s ease","pointer-events:auto"].join(";");const T=document.createElement("div");T.style.cssText="font-weight:600;margin-bottom:2px",T.textContent=Wt(C);const L=document.createElement("div");L.style.cssText=(C==null?void 0:C.kind)==="reply"?"color:#a4abba;display:-webkit-box;-webkit-line-clamp:3;-webkit-box-orient:vertical;overflow:hidden":"color:#a4abba",L.textContent=Qa(C);const X=document.createElement("div");X.style.cssText="display:flex;align-items:center;gap:8px;margin-top:10px;flex-wrap:wrap";const U=document.createElement("span");U.style.cssText="color:#7b8394;font-size:11px;margin-right:auto",U.textContent=ja(C==null?void 0:C.at);const j=S("Mark as read",!1);if(j.setAttribute("aria-label",`Mark as read: ${Wt(C)}`),j.addEventListener("click",()=>n==null?void 0:n(C.id)),X.append(U,j),(V=C==null?void 0:C.call)!=null&&V.offered&&typeof i=="function"){const E=S("Talk it through",!0);E.addEventListener("click",()=>i(C)),X.insertBefore(E,j)}return $.append(T,L,X),$}function ie(C){const $=document.createElement("div");$.style.cssText=["box-sizing:border-box","width:100%","display:flex","align-items:center","gap:8px","padding:8px 12px","border-radius:10px","background:#1b1e26","color:#a4abba",'font:12px/1.4 -apple-system,BlinkMacSystemFont,"Segoe UI",sans-serif',"box-shadow:0 12px 30px rgba(0,0,0,0.45)","pointer-events:auto"].join(";");const T=document.createElement("span");T.style.cssText="margin-right:auto",T.textContent=`${C} more update${C===1?"":"s"}`;const L=S("Mark all as read",!1);return L.style.cssText+=";padding:4px 9px",L.addEventListener("click",()=>a==null?void 0:a()),$.append(T,L),$}return{render(C){const $=Array.isArray(C)?C:[];if(!$.length){for(const E of f.values())g(E);f.clear(),h==null||h.remove(),h=null,y==null||y.remove(),y=null;return}const T=$.slice(-3),L=new Set(T.map(E=>E.id)),X=b();for(const[E,se]of f)L.has(E)||(g(se),f.delete(E));const U=[];for(const E of T){if(f.has(E.id))continue;const se=A(E);f.set(E.id,se),U.push(se)}const j=l?[...T].reverse():T;for(const E of j)X.appendChild(f.get(E.id));const V=$.length-T.length;V>0?(h==null||h.remove(),h=ie(V),l?X.appendChild(h):X.insertBefore(h,X.firstChild)):(h==null||h.remove(),h=null),requestAnimationFrame(()=>{for(const E of U)E.isConnected&&(E._bcShown=!0,E.style.opacity="1",E.style.transform="translateY(0)")})},destroy(){f.clear(),h=null,y==null||y.remove(),y=null}}}async function Ha({apiBase:t,apiKey:e,projectId:n,sessionToken:a}){try{const i=await fetch(`${t}/ingest/known-issues?projectId=${encodeURIComponent(n)}`,{headers:yt(e,a)});if(!i.ok)return[];const r=await i.json();return Array.isArray(r==null?void 0:r.issues)?r.issues:[]}catch{return[]}}async function qa({apiBase:t,apiKey:e,projectId:n,q:a,sessionToken:i,signal:r}){try{const s=`${t}/ingest/known-issues/match?projectId=${encodeURIComponent(n)}&q=${encodeURIComponent(a)}`,l=await fetch(s,{headers:yt(e,i),signal:r});if(!l.ok)return[];const p=await l.json();return Array.isArray(p==null?void 0:p.issues)?p.issues:[]}catch{return[]}}async function Da({apiBase:t,apiKey:e,projectId:n,bugId:a,reporterEmail:i,reporterName:r,metadata:s,logs:l,sessionToken:p}){const f=await fetch(`${t}/ingest/known-issues/${encodeURIComponent(a)}/join`,{method:"POST",headers:yt(e,p),body:JSON.stringify({projectId:n,reporterEmail:i,reporterName:r,metadata:s,logs:l})});if(!f.ok)throw new Error(await Na(f));const y=await f.json();return y!=null&&y.watchToken&&bt(y.watchToken),y}function yt(t,e){return{"Content-Type":"application/json","X-BugCatch-Key":t,...e?{"X-BugCatch-Session":e}:{}}}async function Na(t){try{const e=await t.json(),n=Array.isArray(e.message)?e.message.join(", "):e.message;if(n)return n}catch{}return`Could not add you to this issue (HTTP ${t.status})`}async function Ua({apiBase:t,bugId:e,...n}){const a=re();if(!a)throw new Error("This browser cannot access that report.");const i=await fetch(`${t}/ingest/watch/reports/${encodeURIComponent(e)}/verification`,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${a}`},body:JSON.stringify(n)}),r=await i.json().catch(()=>({}));if(!i.ok)throw new Error(r.message||"Could not record feedback. Please refresh and try again.");return r}const Va=2e4,Yt=120,Xt=200;function Zt(t){if(typeof t!="string"||!t.trim()||t.length>400)return null;try{return new RegExp(t.trim(),"gi")}catch{return null}}const Ka=t=>String(t).replace(/\s+/g," ").trim().slice(0,Yt);function Jt(t){const e=t.length>1&&t[1]!==void 0?t[1]:t[0];return typeof e!="string"||!e.trim()?null:{value:Ka(e),start:t.index,end:t.index+t[0].length}}function Pa(t,e){const n=[],a=new Set;for(const i of e||[]){const r=typeof i=="string"?i.slice(0,Va):"";if(!r)continue;const s=[],l=(p,f)=>s.some(([y,h])=>p<h&&f>y);for(const p of t||[]){if(!p||p.scan===!1)continue;const f=Zt(p.pattern);if(!f)continue;let y,h=0;for(f.lastIndex=0;(y=f.exec(r))!==null&&!(++h>Xt);){if(y[0]===""){f.lastIndex+=1;continue}const b=Jt(y);if(b&&!l(b.start,b.end)){s.push([b.start,b.end]);const g=`${p.key}:${b.value.toLowerCase()}`;a.has(g)||(a.add(g),n.push({key:p.key,label:p.label,value:b.value}))}}}}return n}function _a(t,e){const n=typeof e=="string"?e.trim():"";if(!n||n.length>Yt)return null;const a=Zt(t&&(t.valuePattern||t.pattern));if(!a)return null;let i,r=0;for(a.lastIndex=0;(i=a.exec(n))!==null&&!(++r>Xt);){if(i[0]===""){a.lastIndex+=1;continue}const s=i.index+i[0].length===n.length,l=i.index===0||i.index===1;if(s&&l){const p=Jt(i);if(p)return p.value}}return null}async function Fa({apiBase:t,apiKey:e,projectId:n}){const a={policy:"off",fields:[]};try{const i=await fetch(`${t}/ingest/reference-fields?projectId=${encodeURIComponent(n)}`,{headers:{"X-BugCatch-Key":e}});if(!i.ok)return a;const r=await i.json(),s=r.policy==="optional"||r.policy==="required"?r.policy:"off",l=Array.isArray(r.fields)?r.fields:[];return l.length?{policy:s,fields:l}:a}catch{return a}}const Gt={"bottom-right":"bottom:20px;right:20px;","bottom-left":"bottom:20px;left:20px;","top-right":"top:20px;right:20px;","top-left":"top:20px;left:20px;"},en=[{value:"LOW",label:"Low"},{value:"MEDIUM",label:"Medium"},{value:"HIGH",label:"High"},{value:"CRITICAL",label:"Critical"}],Q={camera:'<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M3 8.5A1.5 1.5 0 0 1 4.5 7h2.2a1 1 0 0 0 .83-.45l.94-1.4A1 1 0 0 1 9.3 4.7h5.4a1 1 0 0 1 .83.45l.94 1.4a1 1 0 0 0 .83.45h2.2A1.5 1.5 0 0 1 21 8.5v9A1.5 1.5 0 0 1 19.5 19h-15A1.5 1.5 0 0 1 3 17.5z"/><circle cx="12" cy="13" r="3.4"/></svg>',video:'<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="6" width="12.5" height="12" rx="2.2"/><path d="M15.5 10.8l4.2-2.6a.6.6 0 0 1 .92.5v6.6a.6.6 0 0 1-.92.5l-4.2-2.6z"/></svg>',paperclip:'<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M20 11.5l-7.6 7.6a4.6 4.6 0 0 1-6.5-6.5l8-8a3.2 3.2 0 0 1 4.5 4.5l-8 8a1.8 1.8 0 0 1-2.5-2.5l7.1-7.1"/></svg>',close:'<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"><path d="M6 6l12 12M18 6L6 18"/></svg>',mic:'<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><rect x="9" y="2.5" width="6" height="11" rx="3"/><path d="M5.5 11a6.5 6.5 0 0 0 13 0M12 17.5V21M9 21h6"/></svg>',send:'<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.9" stroke-linecap="round" stroke-linejoin="round"><path d="M4 12l16-8-6 16-2.6-6.2L4 12Z"/></svg>',stopSquare:'<svg viewBox="0 0 24 24" fill="currentColor"><rect x="7" y="7" width="10" height="10" rx="2"/></svg>',back:'<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M14.5 5.5L8 12l6.5 6.5"/></svg>',phone:'<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M6.2 3.5h3l1.5 3.7-2 1.4a11.5 11.5 0 0 0 5.7 5.7l1.4-2 3.7 1.5v3a1.8 1.8 0 0 1-2 1.8A15.6 15.6 0 0 1 4.4 5.5a1.8 1.8 0 0 1 1.8-2z"/></svg>',phoneOff:'<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M6.2 3.5h3l1.5 3.7-2 1.4a11.5 11.5 0 0 0 5.7 5.7l1.4-2 3.7 1.5v3a1.8 1.8 0 0 1-2 1.8A15.6 15.6 0 0 1 4.4 5.5a1.8 1.8 0 0 1 1.8-2z"/><path d="M3 21L21 3"/></svg>',bug:'<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M8 6a4 4 0 0 1 8 0"/><rect x="7" y="7.5" width="10" height="12" rx="5"/><path d="M7 11H3.5M7 15.5H4M17 11h3.5M17 15.5h3M12 8v11.5"/></svg>',check:'<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.4" stroke-linecap="round" stroke-linejoin="round"><path d="M5 12.8l4.6 4.4L19 7"/></svg>',retry:'<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M20 12a8 8 0 1 1-2.6-5.9M20 4v4.5h-4.5"/></svg>',sun:'<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.9" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="4.2"/><path d="M12 2.6v2.2M12 19.2v2.2M2.6 12h2.2M19.2 12h2.2M5.4 5.4l1.6 1.6M17 17l1.6 1.6M18.6 5.4L17 7M7 17l-1.6 1.6"/></svg>',moon:'<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.9" stroke-linecap="round" stroke-linejoin="round"><path d="M20 13.4A8.2 8.2 0 1 1 10.6 4a6.6 6.6 0 0 0 9.4 9.4z"/></svg>',auto:'<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.9" stroke-linecap="round" stroke-linejoin="round"><rect x="2.8" y="4.4" width="18.4" height="12.6" rx="2.2"/><path d="M8.6 20.2h6.8"/><path d="M12 4.4v12.6"/><path d="M12 7.2a3.6 3.6 0 0 1 0 7.2z" fill="currentColor" stroke="none"/></svg>'},Wa='<svg class="bc-brand" viewBox="0 0 254 60" fill="none" role="img" aria-label="sphoro BugCatch"><g fill="currentColor"><path transform="translate(0.00 40.00) scale(0.04000 -0.04000)" d="M276.00 -14.00Q179.00 -14.00 117.00 28.00Q55.00 70.00 42.00 148.00L158.00 178.00Q165.00 143.00 181.50 123.00Q198.00 103.00 222.50 94.50Q247.00 86.00 276.00 86.00Q320.00 86.00 341.00 101.50Q362.00 117.00 362.00 140.00Q362.00 163.00 342.00 175.50Q322.00 188.00 278.00 196.00L250.00 201.00Q198.00 211.00 155.00 228.50Q112.00 246.00 86.00 277.00Q60.00 308.00 60.00 357.00Q60.00 431.00 114.00 470.50Q168.00 510.00 256.00 510.00Q339.00 510.00 394.00 473.00Q449.00 436.00 466.00 376.00L349.00 340.00Q341.00 378.00 316.50 394.00Q292.00 410.00 256.00 410.00Q220.00 410.00 201.00 397.50Q182.00 385.00 182.00 363.00Q182.00 339.00 202.00 327.50Q222.00 316.00 256.00 310.00L284.00 305.00Q340.00 295.00 385.50 278.50Q431.00 262.00 457.50 231.50Q484.00 201.00 484.00 149.00Q484.00 71.00 427.50 28.50Q371.00 -14.00 276.00 -14.00Z"/><path transform="translate(19.56 40.00) scale(0.04000 -0.04000)" d="M70.00 -200.00V496.00H194.00V436.00H212.00Q229.00 465.00 265.00 487.50Q301.00 510.00 368.00 510.00Q428.00 510.00 479.00 480.50Q530.00 451.00 561.00 394.00Q592.00 337.00 592.00 256.00V240.00Q592.00 159.00 561.00 102.00Q530.00 45.00 479.00 15.50Q428.00 -14.00 368.00 -14.00Q323.00 -14.00 292.50 -3.50Q262.00 7.00 243.50 23.50Q225.00 40.00 214.00 57.00H196.00V-200.00ZM330.00 96.00Q389.00 96.00 427.50 133.50Q466.00 171.00 466.00 243.00V253.00Q466.00 325.00 427.00 362.50Q388.00 400.00 330.00 400.00Q272.00 400.00 233.00 362.50Q194.00 325.00 194.00 253.00V243.00Q194.00 171.00 233.00 133.50Q272.00 96.00 330.00 96.00Z"/><path transform="translate(43.68 40.00) scale(0.04000 -0.04000)" d="M70.00 0.00V700.00H196.00V435.00H214.00Q222.00 451.00 239.00 467.00Q256.00 483.00 284.50 493.50Q313.00 504.00 357.00 504.00Q415.00 504.00 458.50 477.50Q502.00 451.00 526.00 404.50Q550.00 358.00 550.00 296.00V0.00H424.00V286.00Q424.00 342.00 396.50 370.00Q369.00 398.00 318.00 398.00Q260.00 398.00 228.00 359.50Q196.00 321.00 196.00 252.00V0.00Z"/><path transform="translate(66.92 40.00) scale(0.04000 -0.04000)" d="M306.00 -14.00Q232.00 -14.00 173.00 16.00Q114.00 46.00 80.00 103.00Q46.00 160.00 46.00 240.00V256.00Q46.00 336.00 80.00 393.00Q114.00 450.00 173.00 480.00Q232.00 510.00 306.00 510.00Q380.00 510.00 439.00 480.00Q498.00 450.00 532.00 393.00Q566.00 336.00 566.00 256.00V240.00Q566.00 160.00 532.00 103.00Q498.00 46.00 439.00 16.00Q380.00 -14.00 306.00 -14.00ZM306.00 98.00Q364.00 98.00 402.00 135.50Q440.00 173.00 440.00 243.00V253.00Q440.00 323.00 402.50 360.50Q365.00 398.00 306.00 398.00Q248.00 398.00 210.00 360.50Q172.00 323.00 172.00 253.00V243.00Q172.00 173.00 210.00 135.50Q248.00 98.00 306.00 98.00Z"/><path transform="translate(90.00 40.00) scale(0.04000 -0.04000)" d="M70.00 0.00V496.00H194.00V440.00H212.00Q223.00 470.00 248.50 484.00Q274.00 498.00 308.00 498.00H368.00V386.00H306.00Q258.00 386.00 227.00 360.50Q196.00 335.00 196.00 282.00V0.00Z"/><path transform="translate(104.44 40.00) scale(0.04000 -0.04000)" d="M306.00 -14.00Q232.00 -14.00 173.00 16.00Q114.00 46.00 80.00 103.00Q46.00 160.00 46.00 240.00V256.00Q46.00 336.00 80.00 393.00Q114.00 450.00 173.00 480.00Q232.00 510.00 306.00 510.00Q380.00 510.00 439.00 480.00Q498.00 450.00 532.00 393.00Q566.00 336.00 566.00 256.00V240.00Q566.00 160.00 532.00 103.00Q498.00 46.00 439.00 16.00Q380.00 -14.00 306.00 -14.00ZM306.00 98.00Q364.00 98.00 402.00 135.50Q440.00 173.00 440.00 243.00V253.00Q440.00 323.00 402.50 360.50Q365.00 398.00 306.00 398.00Q248.00 398.00 210.00 360.50Q172.00 323.00 172.00 253.00V243.00Q172.00 173.00 210.00 135.50Q248.00 98.00 306.00 98.00Z"/></g><rect x="139.52" y="16" width="1.6" height="26" rx="0.8" fill="var(--bc-brand-mark, #5647ee)" opacity="0.4"/><g fill="var(--bc-brand-mark, #5647ee)"><path transform="translate(154.52 35.00) scale(0.01400 -0.01400)" d="M46.35 0.00V105.85H139.75V594.15H46.35V700.00H404.08Q467.38 700.00 514.79 678.41Q562.20 656.83 588.70 617.33Q615.20 577.83 615.20 523.35V513.70Q615.20 465.52 597.03 434.76Q578.85 404.00 553.91 387.24Q528.98 370.48 506.28 363.30V346.35Q528.98 340.35 555.24 323.50Q581.50 306.65 600.00 275.48Q618.50 244.30 618.50 194.48V184.48Q618.50 126.65 591.41 85.24Q564.33 43.83 516.83 21.91Q469.33 0.00 406.85 0.00ZM259.85 109.15H392.60Q441.20 109.15 469.80 132.60Q498.40 156.05 498.40 198.55V208.20Q498.40 250.70 470.21 274.15Q442.02 297.60 392.60 297.60H259.85ZM259.85 406.75H391.65Q437.55 406.75 466.32 430.11Q495.10 453.48 495.10 493.80V503.80Q495.10 544.95 466.74 567.90Q438.37 590.85 391.65 590.85H259.85Z"/><path transform="translate(167.00 35.00) scale(0.01400 -0.01400)" d="M335.30 -14.00Q251.22 -14.00 190.60 16.63Q129.97 47.25 97.56 104.96Q65.15 162.68 65.15 243.03V700.00H185.25V239.73Q185.25 170.48 224.03 131.99Q262.80 93.50 335.30 93.50Q407.80 93.50 446.57 131.99Q485.35 170.48 485.35 239.73V700.00H605.45V243.03Q605.45 162.68 573.13 104.96Q540.80 47.25 480.09 16.63Q419.38 -14.00 335.30 -14.00Z"/><path transform="translate(179.60 35.00) scale(0.01400 -0.01400)" d="M311.85 -14.00Q238.45 -14.00 179.69 18.50Q120.92 51.00 86.69 113.67Q52.45 176.35 52.45 266.87V433.13Q52.45 569.00 128.01 641.50Q203.57 714.00 332.35 714.00Q460.13 714.00 529.23 645.59Q598.33 577.17 598.33 460.87V456.70H479.87V464.52Q479.87 504.67 463.76 536.86Q447.65 569.05 414.99 587.77Q382.32 606.50 332.35 606.50Q257.63 606.50 215.09 560.70Q172.55 514.90 172.55 435.13V264.87Q172.55 185.93 215.09 138.89Q257.63 91.85 334.00 91.85Q410.02 91.85 445.12 132.83Q480.22 173.80 480.22 237.92V249.67H302.85V351.88H598.33V0.00H487.52V69.10H470.57Q462.70 50.87 446.06 31.44Q429.42 12.00 397.64 -1.00Q365.85 -14.00 311.85 -14.00Z"/><path transform="translate(192.05 35.00) scale(0.01400 -0.01400)" d="M332.35 -14.00Q203.57 -14.00 128.01 58.50Q52.45 131.00 52.45 266.87V433.13Q52.45 569.00 128.01 641.50Q203.57 714.00 332.35 714.00Q460.13 714.00 529.58 643.85Q599.03 573.70 599.03 451.57V445.75H480.57V455.22Q480.57 521.42 444.15 563.96Q407.72 606.50 332.35 606.50Q257.63 606.50 215.09 560.70Q172.55 514.90 172.55 435.13V264.87Q172.55 185.93 215.09 139.71Q257.63 93.50 332.35 93.50Q407.72 93.50 444.15 136.45Q480.57 179.40 480.57 244.78V262.25H599.03V248.43Q599.03 126.30 529.58 56.15Q460.13 -14.00 332.35 -14.00Z"/><path transform="translate(204.25 35.00) scale(0.01400 -0.01400)" d="M19.75 0.00 211.62 700.00H421.33L613.20 0.00H489.27L447.42 159.60H185.53L143.68 0.00ZM214.25 270.40H418.70L324.95 624.87H308.00Z"/><path transform="translate(216.31 35.00) scale(0.01400 -0.01400)" d="M233.95 0.00V590.85H24.70V700.00H563.30V590.85H354.05V0.00Z"/><path transform="translate(227.75 35.00) scale(0.01400 -0.01400)" d="M332.35 -14.00Q203.57 -14.00 128.01 58.50Q52.45 131.00 52.45 266.87V433.13Q52.45 569.00 128.01 641.50Q203.57 714.00 332.35 714.00Q460.13 714.00 529.58 643.85Q599.03 573.70 599.03 451.57V445.75H480.57V455.22Q480.57 521.42 444.15 563.96Q407.72 606.50 332.35 606.50Q257.63 606.50 215.09 560.70Q172.55 514.90 172.55 435.13V264.87Q172.55 185.93 215.09 139.71Q257.63 93.50 332.35 93.50Q407.72 93.50 444.15 136.45Q480.57 179.40 480.57 244.78V262.25H599.03V248.43Q599.03 126.30 529.58 56.15Q460.13 -14.00 332.35 -14.00Z"/><path transform="translate(239.95 35.00) scale(0.01400 -0.01400)" d="M69.50 0.00V700.00H189.60V405.58H466.40V700.00H586.50V0.00H466.40V296.42H189.60V0.00Z"/></g></svg>',tn=[{value:"light",label:"Light",icon:Q.sun},{value:"dark",label:"Dark",icon:Q.moon},{value:"auto",label:"System default",icon:Q.auto}],nn="bugcatch:theme";function Ya(){try{const t=localStorage.getItem(nn);return tn.some(e=>e.value===t)?t:null}catch{return null}}function Xa(t){try{localStorage.setItem(nn,t)}catch{}}const Za=t=>`
7
+ `)}return n}async function Wo({apiBase:t}){const e=ce();if(!e)return{reporter:null,reports:[]};const n=await fetch(`${t}/ingest/watch/reports`,{headers:{Authorization:`Bearer ${e}`}});if(n.status===401)return Ie(),{reporter:null,reports:[]};if(!n.ok)throw new Error(`[BugCatch] could not load your reports (HTTP ${n.status})`);return n.json()}async function Yo({apiBase:t,bugId:e}){const n=ce();if(!n)return null;const o=await fetch(`${t}/ingest/watch/reports/${encodeURIComponent(e)}`,{headers:{Authorization:`Bearer ${n}`}});if(o.status===401)return Ie(),null;if(o.status===404)return null;if(!o.ok)throw new Error(`[BugCatch] could not load that report (HTTP ${o.status})`);return o.json()}async function ln({apiBase:t,bugId:e,body:n,attachments:o}){const i=ce();if(!i)throw new Error("[BugCatch] nothing filed from this browser yet.");const a=await fetch(`${t}/ingest/watch/reports/${encodeURIComponent(e)}/messages`,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${i}`},body:JSON.stringify({...n?{body:n}:{},...o!=null&&o.length?{attachments:o}:{}})});if(a.status===401)throw Ie(),new Error("[BugCatch] this browser can no longer prove it filed that report.");if(!a.ok){let s="";try{const l=await a.json();s=Array.isArray(l.message)?l.message.join(", "):l.message||""}catch{}throw new Error(s||`[BugCatch] could not send that (HTTP ${a.status}).`)}return a.json()}async function Xo({apiBase:t,apiKey:e,projectId:n}){const o={agent:!1,live:!1};try{const i=await fetch(`${t}/ingest/calls?projectId=${encodeURIComponent(n)}`,{headers:{"X-BugCatch-Key":e}});if(!i.ok)return o;const a=await i.json();return a!=null&&a.available?a.kinds&&typeof a.kinds=="object"?{agent:!1,live:!!a.kinds.live}:{agent:!1,live:a.kind==="live"}:o}catch{return o}}async function Jo({apiBase:t,apiKey:e,token:n,payload:o}){const i=await fetch(`${t}/ingest/calls`,{method:"POST",headers:{"Content-Type":"application/json","X-BugCatch-Key":e,...n?{"X-BugCatch-Session":n}:{}},body:JSON.stringify(o)});if(!i.ok){let a="";try{const l=await i.json();a=Array.isArray(l.message)?l.message.join(", "):l.message||""}catch{}const s=new Error(a||`[BugCatch] the call could not be started (HTTP ${i.status}).`);throw s.status=i.status,s}return i.json()}async function dn({apiBase:t,bugId:e}){const n=ce();if(!n)return!1;try{const o=await fetch(`${t}/ingest/watch/reports/${encodeURIComponent(e)}/live-call`,{headers:{Authorization:`Bearer ${n}`}});if(!o.ok)return!1;const i=await o.json();return!!(i!=null&&i.offered)}catch{return!1}}async function Zo({apiBase:t,bugId:e}){const n=ce();if(!n)throw new Error("[BugCatch] nothing filed from this browser yet.");const o=await fetch(`${t}/ingest/watch/reports/${encodeURIComponent(e)}/live-call`,{method:"POST",headers:{Authorization:`Bearer ${n}`}});if(o.status===401)throw Ie(),new Error("[BugCatch] this browser can no longer prove it filed that report.");if(!o.ok){let i="";try{const a=await o.json();i=Array.isArray(a.message)?a.message.join(", "):a.message||""}catch{}throw new Error(i||`[BugCatch] the call could not be started (HTTP ${o.status}).`)}return o.json()}async function Go({apiBase:t,bugId:e,callId:n}){const o=ce();if(o)try{await fetch(`${t}/ingest/watch/reports/${encodeURIComponent(e)}/live-call/${encodeURIComponent(n)}/give-up`,{method:"POST",headers:{Authorization:`Bearer ${o}`}})}catch{}}async function ea({apiBase:t,bugId:e,callId:n}){const o=ce();if(!o)throw new Error("[BugCatch] nothing filed from this browser yet.");const i=await fetch(`${t}/ingest/watch/reports/${encodeURIComponent(e)}/live-call/${encodeURIComponent(n)}/answer`,{method:"POST",headers:{Authorization:`Bearer ${o}`}});if(i.status===401)throw Ie(),new Error("[BugCatch] this browser can no longer prove it filed that report.");if(i.status===409)throw new Error("[BugCatch] that call is no longer ringing.");if(!i.ok){let a="";try{const s=await i.json();a=Array.isArray(s.message)?s.message.join(", "):s.message||""}catch{}throw new Error(a||`[BugCatch] the call could not be answered (HTTP ${i.status}).`)}return i.json()}async function un({apiBase:t,bugId:e,callId:n}){const o=ce();if(o)try{await fetch(`${t}/ingest/watch/reports/${encodeURIComponent(e)}/live-call/${encodeURIComponent(n)}/decline`,{method:"POST",headers:{Authorization:`Bearer ${o}`}})}catch{}}function ta({apiBase:t,onUpdate:e}){let n=!0,o=0,i=null;async function a(){const s=ce();if(!s)throw new Error("nothing filed from this browser yet");i=new AbortController;const l=await fetch(`${t}/ingest/watch/stream`,{headers:{Authorization:`Bearer ${s}`,Accept:"text/event-stream"},signal:i.signal});if(l.status===401)throw n=!1,Ie(),new Error("subscription no longer valid");if(!l.ok||!l.body)throw new Error(`stream failed (${l.status})`);const p=Date.now(),h=l.body.getReader(),b=new TextDecoder;let f="";try{for(;;){const{value:m,done:g}=await h.read();if(g)break;f+=b.decode(m,{stream:!0}),f=Fo(f,T=>{if(T.type!=="ping")try{e(T)}catch{}})}}finally{Date.now()-p>=Uo&&(o=0)}}return(async()=>{for(;n;){try{await a()}catch(l){if((l==null?void 0:l.name)==="AbortError")return}if(!n)return;const s=sn[Math.min(o,sn.length-1)];o+=1,await new Promise(l=>setTimeout(l,s))}})(),()=>{n=!1,i==null||i.abort(),i=null}}const na={OPEN:"is open",IN_PROGRESS:"is being worked on",RESOLVED:"has been fixed",CLOSED:"has been closed"},oa={status:null,severity:"#e8912a",assignment:"#4da3ff",reply:"#35b87f"};function pn(t){return t!=null&&t.summary?t.summary:`Your report ${na[t==null?void 0:t.status]||"was updated"}`}function aa(t){var e;return(t==null?void 0:t.kind)==="reply"&&((e=t.reply)!=null&&e.body)?`${t.reply.author?`${t.reply.author}: `:""}${t.reply.body}`:(t==null?void 0:t.title)||""}function ra(t){const e=Date.parse(t||"");if(!Number.isFinite(e))return"";const n=Math.round((Date.now()-e)/6e4);if(n<1)return"just now";if(n<60)return`${n}m ago`;const o=Math.round(n/60);if(o<24)return`${o}h ago`;const i=Math.round(o/24);return i===1?"yesterday":`${i}d ago`}function ia(){var t;try{const e=document.querySelector('[data-bugcatch="widget"]'),n=(t=e==null?void 0:e.shadowRoot)==null?void 0:t.querySelector(".dock"),o=(n==null?void 0:n.getBoundingClientRect().height)||0;return o?Math.round(o)+12:0}catch{return 0}}function sa({accent:t="#4F46E5",position:e="bottom-right",onRead:n=null,onReadAll:o=null,onCall:i=null}={}){const[a,s]=String(e).split("-"),l=a==="top",p=s==="left",h=new Map;let b=null,f=null;function m(){return b!=null&&b.isConnected||(b=document.createElement("div"),b.setAttribute("data-bugcatch","updates"),b.style.cssText=["position:fixed",`${l?"top":"bottom"}:${20+ia()}px`,`${p?"left":"right"}:20px`,"z-index:2147482998","display:flex","flex-direction:column","gap:10px",`align-items:${p?"flex-start":"flex-end"}`,"width:min(320px,calc(100vw - 40px))","pointer-events:none"].join(";"),document.body.appendChild(b)),b}function g($){if(!$._bcShown){$.remove();return}$.style.opacity="0",$.style.transform=`translateY(${l?-8:8}px)`,setTimeout(()=>$.remove(),250)}function T($,L){const B=document.createElement("button");return B.type="button",B.textContent=$,B.style.cssText=["padding:5px 11px",`border:${L?"0":"1px solid rgba(236,238,242,.24)"}`,"border-radius:6px",`background:${L?t:"transparent"}`,`color:${L?"#fff":"#eceef2"}`,"font:600 12px/1.4 inherit","cursor:pointer","white-space:nowrap"].join(";"),B}function Q($){var q;const L=document.createElement("div");L.setAttribute("role","status"),L.style.cssText=["box-sizing:border-box","width:100%","padding:12px 14px","border-radius:10px","background:#1b1e26","color:#eceef2",'font:13px/1.5 -apple-system,BlinkMacSystemFont,"Segoe UI",sans-serif',"box-shadow:0 12px 30px rgba(0,0,0,0.45)",`border-left:3px solid ${oa[$==null?void 0:$.kind]||t}`,"opacity:0",`transform:translateY(${l?-8:8}px)`,"transition:opacity .2s ease,transform .2s ease","pointer-events:auto"].join(";");const B=document.createElement("div");B.style.cssText="font-weight:600;margin-bottom:2px",B.textContent=pn($);const j=document.createElement("div");j.style.cssText=($==null?void 0:$.kind)==="reply"?"color:#a4abba;display:-webkit-box;-webkit-line-clamp:3;-webkit-box-orient:vertical;overflow:hidden":"color:#a4abba",j.textContent=aa($);const N=document.createElement("div");N.style.cssText="display:flex;align-items:center;gap:8px;margin-top:10px;flex-wrap:wrap";const S=document.createElement("span");S.style.cssText="color:#7b8394;font-size:11px;margin-right:auto",S.textContent=ra($==null?void 0:$.at);const U=T("Mark as read",!1);if(U.setAttribute("aria-label",`Mark as read: ${pn($)}`),U.addEventListener("click",()=>n==null?void 0:n($.id)),N.append(S,U),(q=$==null?void 0:$.call)!=null&&q.offered&&typeof i=="function"){const I=T("Talk it through",!0);I.addEventListener("click",()=>i($)),N.insertBefore(I,U)}return L.append(B,j,N),L}function V($){const L=document.createElement("div");L.style.cssText=["box-sizing:border-box","width:100%","display:flex","align-items:center","gap:8px","padding:8px 12px","border-radius:10px","background:#1b1e26","color:#a4abba",'font:12px/1.4 -apple-system,BlinkMacSystemFont,"Segoe UI",sans-serif',"box-shadow:0 12px 30px rgba(0,0,0,0.45)","pointer-events:auto"].join(";");const B=document.createElement("span");B.style.cssText="margin-right:auto",B.textContent=`${$} more update${$===1?"":"s"}`;const j=T("Mark all as read",!1);return j.style.cssText+=";padding:4px 9px",j.addEventListener("click",()=>o==null?void 0:o()),L.append(B,j),L}return{render($){const L=Array.isArray($)?$:[];if(!L.length){for(const I of h.values())g(I);h.clear(),f==null||f.remove(),f=null,b==null||b.remove(),b=null;return}const B=L.slice(-3),j=new Set(B.map(I=>I.id)),N=m();for(const[I,Z]of h)j.has(I)||(g(Z),h.delete(I));const S=[];for(const I of B){if(h.has(I.id))continue;const Z=Q(I);h.set(I.id,Z),S.push(Z)}const U=l?[...B].reverse():B;for(const I of U)N.appendChild(h.get(I.id));const q=L.length-B.length;q>0?(f==null||f.remove(),f=V(q),l?N.appendChild(f):N.insertBefore(f,N.firstChild)):(f==null||f.remove(),f=null),requestAnimationFrame(()=>{for(const I of S)I.isConnected&&(I._bcShown=!0,I.style.opacity="1",I.style.transform="translateY(0)")})},destroy(){h.clear(),f=null,b==null||b.remove(),b=null}}}async function ca({apiBase:t,apiKey:e,projectId:n,sessionToken:o}){try{const i=await fetch(`${t}/ingest/known-issues?projectId=${encodeURIComponent(n)}`,{headers:Lt(e,o)});if(!i.ok)return[];const a=await i.json();return Array.isArray(a==null?void 0:a.issues)?a.issues:[]}catch{return[]}}async function la({apiBase:t,apiKey:e,projectId:n,q:o,sessionToken:i,signal:a}){try{const s=`${t}/ingest/known-issues/match?projectId=${encodeURIComponent(n)}&q=${encodeURIComponent(o)}`,l=await fetch(s,{headers:Lt(e,i),signal:a});if(!l.ok)return[];const p=await l.json();return Array.isArray(p==null?void 0:p.issues)?p.issues:[]}catch{return[]}}async function da({apiBase:t,apiKey:e,projectId:n,bugId:o,reporterEmail:i,reporterName:a,metadata:s,logs:l,sessionToken:p}){const h=await fetch(`${t}/ingest/known-issues/${encodeURIComponent(o)}/join`,{method:"POST",headers:Lt(e,p),body:JSON.stringify({projectId:n,reporterEmail:i,reporterName:a,metadata:s,logs:l})});if(!h.ok)throw new Error(await ua(h));const b=await h.json();return b!=null&&b.watchToken&&At(b.watchToken),b}function Lt(t,e){return{"Content-Type":"application/json","X-BugCatch-Key":t,...e?{"X-BugCatch-Session":e}:{}}}async function ua(t){try{const e=await t.json(),n=Array.isArray(e.message)?e.message.join(", "):e.message;if(n)return n}catch{}return`Could not add you to this issue (HTTP ${t.status})`}async function pa({apiBase:t,bugId:e,...n}){const o=ce();if(!o)throw new Error("This browser cannot access that report.");const i=await fetch(`${t}/ingest/watch/reports/${encodeURIComponent(e)}/verification`,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${o}`},body:JSON.stringify(n)}),a=await i.json().catch(()=>({}));if(!i.ok)throw new Error(a.message||"Could not record feedback. Please refresh and try again.");return a}const ha=2e4,hn=120,fn=200;function gn(t){if(typeof t!="string"||!t.trim()||t.length>400)return null;try{return new RegExp(t.trim(),"gi")}catch{return null}}const fa=t=>String(t).replace(/\s+/g," ").trim().slice(0,hn);function bn(t){const e=t.length>1&&t[1]!==void 0?t[1]:t[0];return typeof e!="string"||!e.trim()?null:{value:fa(e),start:t.index,end:t.index+t[0].length}}function ga(t,e){const n=[],o=new Set;for(const i of e||[]){const a=typeof i=="string"?i.slice(0,ha):"";if(!a)continue;const s=[],l=(p,h)=>s.some(([b,f])=>p<f&&h>b);for(const p of t||[]){if(!p||p.scan===!1)continue;const h=gn(p.pattern);if(!h)continue;let b,f=0;for(h.lastIndex=0;(b=h.exec(a))!==null&&!(++f>fn);){if(b[0]===""){h.lastIndex+=1;continue}const m=bn(b);if(m&&!l(m.start,m.end)){s.push([m.start,m.end]);const g=`${p.key}:${m.value.toLowerCase()}`;o.has(g)||(o.add(g),n.push({key:p.key,label:p.label,value:m.value}))}}}}return n}function ba(t,e){const n=typeof e=="string"?e.trim():"";if(!n||n.length>hn)return null;const o=gn(t&&(t.valuePattern||t.pattern));if(!o)return null;let i,a=0;for(o.lastIndex=0;(i=o.exec(n))!==null&&!(++a>fn);){if(i[0]===""){o.lastIndex+=1;continue}const s=i.index+i[0].length===n.length,l=i.index===0||i.index===1;if(s&&l){const p=bn(i);if(p)return p.value}}return null}async function ma({apiBase:t,apiKey:e,projectId:n}){const o={policy:"off",fields:[]};try{const i=await fetch(`${t}/ingest/reference-fields?projectId=${encodeURIComponent(n)}`,{headers:{"X-BugCatch-Key":e}});if(!i.ok)return o;const a=await i.json(),s=a.policy==="optional"||a.policy==="required"?a.policy:"off",l=Array.isArray(a.fields)?a.fields:[];return l.length?{policy:s,fields:l}:o}catch{return o}}const mn={"bottom-right":"bottom:20px;right:20px;","bottom-left":"bottom:20px;left:20px;","top-right":"top:20px;right:20px;","top-left":"top:20px;left:20px;"},yn=[{value:"LOW",label:"Low"},{value:"MEDIUM",label:"Medium"},{value:"HIGH",label:"High"},{value:"CRITICAL",label:"Critical"}],M={camera:'<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M3 8.5A1.5 1.5 0 0 1 4.5 7h2.2a1 1 0 0 0 .83-.45l.94-1.4A1 1 0 0 1 9.3 4.7h5.4a1 1 0 0 1 .83.45l.94 1.4a1 1 0 0 0 .83.45h2.2A1.5 1.5 0 0 1 21 8.5v9A1.5 1.5 0 0 1 19.5 19h-15A1.5 1.5 0 0 1 3 17.5z"/><circle cx="12" cy="13" r="3.4"/></svg>',video:'<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="6" width="12.5" height="12" rx="2.2"/><path d="M15.5 10.8l4.2-2.6a.6.6 0 0 1 .92.5v6.6a.6.6 0 0 1-.92.5l-4.2-2.6z"/></svg>',paperclip:'<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M20 11.5l-7.6 7.6a4.6 4.6 0 0 1-6.5-6.5l8-8a3.2 3.2 0 0 1 4.5 4.5l-8 8a1.8 1.8 0 0 1-2.5-2.5l7.1-7.1"/></svg>',close:'<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"><path d="M6 6l12 12M18 6L6 18"/></svg>',mic:'<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><rect x="9" y="2.5" width="6" height="11" rx="3"/><path d="M5.5 11a6.5 6.5 0 0 0 13 0M12 17.5V21M9 21h6"/></svg>',send:'<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.9" stroke-linecap="round" stroke-linejoin="round"><path d="M4 12l16-8-6 16-2.6-6.2L4 12Z"/></svg>',stopSquare:'<svg viewBox="0 0 24 24" fill="currentColor"><rect x="7" y="7" width="10" height="10" rx="2"/></svg>',back:'<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M14.5 5.5L8 12l6.5 6.5"/></svg>',phone:'<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M6.2 3.5h3l1.5 3.7-2 1.4a11.5 11.5 0 0 0 5.7 5.7l1.4-2 3.7 1.5v3a1.8 1.8 0 0 1-2 1.8A15.6 15.6 0 0 1 4.4 5.5a1.8 1.8 0 0 1 1.8-2z"/></svg>',phoneOff:'<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M6.2 3.5h3l1.5 3.7-2 1.4a11.5 11.5 0 0 0 5.7 5.7l1.4-2 3.7 1.5v3a1.8 1.8 0 0 1-2 1.8A15.6 15.6 0 0 1 4.4 5.5a1.8 1.8 0 0 1 1.8-2z"/><path d="M3 21L21 3"/></svg>',bug:'<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M8 6a4 4 0 0 1 8 0"/><rect x="7" y="7.5" width="10" height="12" rx="5"/><path d="M7 11H3.5M7 15.5H4M17 11h3.5M17 15.5h3M12 8v11.5"/></svg>',check:'<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.4" stroke-linecap="round" stroke-linejoin="round"><path d="M5 12.8l4.6 4.4L19 7"/></svg>',retry:'<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M20 12a8 8 0 1 1-2.6-5.9M20 4v4.5h-4.5"/></svg>',sun:'<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.9" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="4.2"/><path d="M12 2.6v2.2M12 19.2v2.2M2.6 12h2.2M19.2 12h2.2M5.4 5.4l1.6 1.6M17 17l1.6 1.6M18.6 5.4L17 7M7 17l-1.6 1.6"/></svg>',moon:'<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.9" stroke-linecap="round" stroke-linejoin="round"><path d="M20 13.4A8.2 8.2 0 1 1 10.6 4a6.6 6.6 0 0 0 9.4 9.4z"/></svg>',auto:'<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.9" stroke-linecap="round" stroke-linejoin="round"><rect x="2.8" y="4.4" width="18.4" height="12.6" rx="2.2"/><path d="M8.6 20.2h6.8"/><path d="M12 4.4v12.6"/><path d="M12 7.2a3.6 3.6 0 0 1 0 7.2z" fill="currentColor" stroke="none"/></svg>',sparkle:'<svg viewBox="0 0 24 24" fill="currentColor"><path d="M12 2.5c.5 4.6 2.9 7 7.5 7.5v.1c-4.6.5-7 2.9-7.5 7.5h-.1c-.5-4.6-2.9-7-7.5-7.5V10c4.6-.5 7-2.9 7.5-7.5z"/><path d="M18.6 15.2c.2 1.9 1.2 2.9 3.1 3.1v.1c-1.9.2-2.9 1.2-3.1 3.1h-.1c-.2-1.9-1.2-2.9-3.1-3.1v-.1c1.9-.2 2.9-1.2 3.1-3.1z" opacity=".7"/></svg>',chat:'<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.9" stroke-linecap="round" stroke-linejoin="round"><path d="M4 11.5a7.5 7 0 0 1 7.5-7h1a7.5 7 0 0 1 0 14H9l-4.2 2.6a.5.5 0 0 1-.76-.5l.5-3.1A7 7 0 0 1 4 11.5z"/><path d="M8.5 11.5h.01M12 11.5h.01M15.5 11.5h.01" stroke-width="2.6"/></svg>',chevronDown:'<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"><path d="M6 9.5l6 6 6-6"/></svg>',chevronRight:'<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M9.5 6l6 6-6 6"/></svg>',alert:'<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="9"/><path d="M12 7.5v5.2M12 16.3h.01"/></svg>',inbox:'<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M3.5 13.5l2.6-7.2A1.5 1.5 0 0 1 7.5 5.3h9a1.5 1.5 0 0 1 1.4 1L20.5 13.5V18a1.5 1.5 0 0 1-1.5 1.5H5A1.5 1.5 0 0 1 3.5 18z"/><path d="M3.5 13.5h4.8l1.2 2.2h5l1.2-2.2h4.8"/></svg>'},ya='<svg class="bc-brand" viewBox="0 0 254 60" fill="none" role="img" aria-label="sphoro BugCatch"><g fill="currentColor"><path transform="translate(0.00 40.00) scale(0.04000 -0.04000)" d="M276.00 -14.00Q179.00 -14.00 117.00 28.00Q55.00 70.00 42.00 148.00L158.00 178.00Q165.00 143.00 181.50 123.00Q198.00 103.00 222.50 94.50Q247.00 86.00 276.00 86.00Q320.00 86.00 341.00 101.50Q362.00 117.00 362.00 140.00Q362.00 163.00 342.00 175.50Q322.00 188.00 278.00 196.00L250.00 201.00Q198.00 211.00 155.00 228.50Q112.00 246.00 86.00 277.00Q60.00 308.00 60.00 357.00Q60.00 431.00 114.00 470.50Q168.00 510.00 256.00 510.00Q339.00 510.00 394.00 473.00Q449.00 436.00 466.00 376.00L349.00 340.00Q341.00 378.00 316.50 394.00Q292.00 410.00 256.00 410.00Q220.00 410.00 201.00 397.50Q182.00 385.00 182.00 363.00Q182.00 339.00 202.00 327.50Q222.00 316.00 256.00 310.00L284.00 305.00Q340.00 295.00 385.50 278.50Q431.00 262.00 457.50 231.50Q484.00 201.00 484.00 149.00Q484.00 71.00 427.50 28.50Q371.00 -14.00 276.00 -14.00Z"/><path transform="translate(19.56 40.00) scale(0.04000 -0.04000)" d="M70.00 -200.00V496.00H194.00V436.00H212.00Q229.00 465.00 265.00 487.50Q301.00 510.00 368.00 510.00Q428.00 510.00 479.00 480.50Q530.00 451.00 561.00 394.00Q592.00 337.00 592.00 256.00V240.00Q592.00 159.00 561.00 102.00Q530.00 45.00 479.00 15.50Q428.00 -14.00 368.00 -14.00Q323.00 -14.00 292.50 -3.50Q262.00 7.00 243.50 23.50Q225.00 40.00 214.00 57.00H196.00V-200.00ZM330.00 96.00Q389.00 96.00 427.50 133.50Q466.00 171.00 466.00 243.00V253.00Q466.00 325.00 427.00 362.50Q388.00 400.00 330.00 400.00Q272.00 400.00 233.00 362.50Q194.00 325.00 194.00 253.00V243.00Q194.00 171.00 233.00 133.50Q272.00 96.00 330.00 96.00Z"/><path transform="translate(43.68 40.00) scale(0.04000 -0.04000)" d="M70.00 0.00V700.00H196.00V435.00H214.00Q222.00 451.00 239.00 467.00Q256.00 483.00 284.50 493.50Q313.00 504.00 357.00 504.00Q415.00 504.00 458.50 477.50Q502.00 451.00 526.00 404.50Q550.00 358.00 550.00 296.00V0.00H424.00V286.00Q424.00 342.00 396.50 370.00Q369.00 398.00 318.00 398.00Q260.00 398.00 228.00 359.50Q196.00 321.00 196.00 252.00V0.00Z"/><path transform="translate(66.92 40.00) scale(0.04000 -0.04000)" d="M306.00 -14.00Q232.00 -14.00 173.00 16.00Q114.00 46.00 80.00 103.00Q46.00 160.00 46.00 240.00V256.00Q46.00 336.00 80.00 393.00Q114.00 450.00 173.00 480.00Q232.00 510.00 306.00 510.00Q380.00 510.00 439.00 480.00Q498.00 450.00 532.00 393.00Q566.00 336.00 566.00 256.00V240.00Q566.00 160.00 532.00 103.00Q498.00 46.00 439.00 16.00Q380.00 -14.00 306.00 -14.00ZM306.00 98.00Q364.00 98.00 402.00 135.50Q440.00 173.00 440.00 243.00V253.00Q440.00 323.00 402.50 360.50Q365.00 398.00 306.00 398.00Q248.00 398.00 210.00 360.50Q172.00 323.00 172.00 253.00V243.00Q172.00 173.00 210.00 135.50Q248.00 98.00 306.00 98.00Z"/><path transform="translate(90.00 40.00) scale(0.04000 -0.04000)" d="M70.00 0.00V496.00H194.00V440.00H212.00Q223.00 470.00 248.50 484.00Q274.00 498.00 308.00 498.00H368.00V386.00H306.00Q258.00 386.00 227.00 360.50Q196.00 335.00 196.00 282.00V0.00Z"/><path transform="translate(104.44 40.00) scale(0.04000 -0.04000)" d="M306.00 -14.00Q232.00 -14.00 173.00 16.00Q114.00 46.00 80.00 103.00Q46.00 160.00 46.00 240.00V256.00Q46.00 336.00 80.00 393.00Q114.00 450.00 173.00 480.00Q232.00 510.00 306.00 510.00Q380.00 510.00 439.00 480.00Q498.00 450.00 532.00 393.00Q566.00 336.00 566.00 256.00V240.00Q566.00 160.00 532.00 103.00Q498.00 46.00 439.00 16.00Q380.00 -14.00 306.00 -14.00ZM306.00 98.00Q364.00 98.00 402.00 135.50Q440.00 173.00 440.00 243.00V253.00Q440.00 323.00 402.50 360.50Q365.00 398.00 306.00 398.00Q248.00 398.00 210.00 360.50Q172.00 323.00 172.00 253.00V243.00Q172.00 173.00 210.00 135.50Q248.00 98.00 306.00 98.00Z"/></g><rect x="139.52" y="16" width="1.6" height="26" rx="0.8" fill="var(--bc-brand-mark, #5647ee)" opacity="0.4"/><g fill="var(--bc-brand-mark, #5647ee)"><path transform="translate(154.52 35.00) scale(0.01400 -0.01400)" d="M46.35 0.00V105.85H139.75V594.15H46.35V700.00H404.08Q467.38 700.00 514.79 678.41Q562.20 656.83 588.70 617.33Q615.20 577.83 615.20 523.35V513.70Q615.20 465.52 597.03 434.76Q578.85 404.00 553.91 387.24Q528.98 370.48 506.28 363.30V346.35Q528.98 340.35 555.24 323.50Q581.50 306.65 600.00 275.48Q618.50 244.30 618.50 194.48V184.48Q618.50 126.65 591.41 85.24Q564.33 43.83 516.83 21.91Q469.33 0.00 406.85 0.00ZM259.85 109.15H392.60Q441.20 109.15 469.80 132.60Q498.40 156.05 498.40 198.55V208.20Q498.40 250.70 470.21 274.15Q442.02 297.60 392.60 297.60H259.85ZM259.85 406.75H391.65Q437.55 406.75 466.32 430.11Q495.10 453.48 495.10 493.80V503.80Q495.10 544.95 466.74 567.90Q438.37 590.85 391.65 590.85H259.85Z"/><path transform="translate(167.00 35.00) scale(0.01400 -0.01400)" d="M335.30 -14.00Q251.22 -14.00 190.60 16.63Q129.97 47.25 97.56 104.96Q65.15 162.68 65.15 243.03V700.00H185.25V239.73Q185.25 170.48 224.03 131.99Q262.80 93.50 335.30 93.50Q407.80 93.50 446.57 131.99Q485.35 170.48 485.35 239.73V700.00H605.45V243.03Q605.45 162.68 573.13 104.96Q540.80 47.25 480.09 16.63Q419.38 -14.00 335.30 -14.00Z"/><path transform="translate(179.60 35.00) scale(0.01400 -0.01400)" d="M311.85 -14.00Q238.45 -14.00 179.69 18.50Q120.92 51.00 86.69 113.67Q52.45 176.35 52.45 266.87V433.13Q52.45 569.00 128.01 641.50Q203.57 714.00 332.35 714.00Q460.13 714.00 529.23 645.59Q598.33 577.17 598.33 460.87V456.70H479.87V464.52Q479.87 504.67 463.76 536.86Q447.65 569.05 414.99 587.77Q382.32 606.50 332.35 606.50Q257.63 606.50 215.09 560.70Q172.55 514.90 172.55 435.13V264.87Q172.55 185.93 215.09 138.89Q257.63 91.85 334.00 91.85Q410.02 91.85 445.12 132.83Q480.22 173.80 480.22 237.92V249.67H302.85V351.88H598.33V0.00H487.52V69.10H470.57Q462.70 50.87 446.06 31.44Q429.42 12.00 397.64 -1.00Q365.85 -14.00 311.85 -14.00Z"/><path transform="translate(192.05 35.00) scale(0.01400 -0.01400)" d="M332.35 -14.00Q203.57 -14.00 128.01 58.50Q52.45 131.00 52.45 266.87V433.13Q52.45 569.00 128.01 641.50Q203.57 714.00 332.35 714.00Q460.13 714.00 529.58 643.85Q599.03 573.70 599.03 451.57V445.75H480.57V455.22Q480.57 521.42 444.15 563.96Q407.72 606.50 332.35 606.50Q257.63 606.50 215.09 560.70Q172.55 514.90 172.55 435.13V264.87Q172.55 185.93 215.09 139.71Q257.63 93.50 332.35 93.50Q407.72 93.50 444.15 136.45Q480.57 179.40 480.57 244.78V262.25H599.03V248.43Q599.03 126.30 529.58 56.15Q460.13 -14.00 332.35 -14.00Z"/><path transform="translate(204.25 35.00) scale(0.01400 -0.01400)" d="M19.75 0.00 211.62 700.00H421.33L613.20 0.00H489.27L447.42 159.60H185.53L143.68 0.00ZM214.25 270.40H418.70L324.95 624.87H308.00Z"/><path transform="translate(216.31 35.00) scale(0.01400 -0.01400)" d="M233.95 0.00V590.85H24.70V700.00H563.30V590.85H354.05V0.00Z"/><path transform="translate(227.75 35.00) scale(0.01400 -0.01400)" d="M332.35 -14.00Q203.57 -14.00 128.01 58.50Q52.45 131.00 52.45 266.87V433.13Q52.45 569.00 128.01 641.50Q203.57 714.00 332.35 714.00Q460.13 714.00 529.58 643.85Q599.03 573.70 599.03 451.57V445.75H480.57V455.22Q480.57 521.42 444.15 563.96Q407.72 606.50 332.35 606.50Q257.63 606.50 215.09 560.70Q172.55 514.90 172.55 435.13V264.87Q172.55 185.93 215.09 139.71Q257.63 93.50 332.35 93.50Q407.72 93.50 444.15 136.45Q480.57 179.40 480.57 244.78V262.25H599.03V248.43Q599.03 126.30 529.58 56.15Q460.13 -14.00 332.35 -14.00Z"/><path transform="translate(239.95 35.00) scale(0.01400 -0.01400)" d="M69.50 0.00V700.00H189.60V405.58H466.40V700.00H586.50V0.00H466.40V296.42H189.60V0.00Z"/></g></svg>',wn=[{value:"light",label:"Light",icon:M.sun},{value:"dark",label:"Dark",icon:M.moon},{value:"auto",label:"System default",icon:M.auto}],vn="bugcatch:theme";function wa(){try{const t=localStorage.getItem(vn);return wn.some(e=>e.value===t)?t:null}catch{return null}}function va(t){try{localStorage.setItem(vn,t)}catch{}}const xa=t=>`
8
8
  :host { all: initial; }
9
9
  :host {
10
10
  --bc-accent: ${t};
@@ -12,10 +12,10 @@
12
12
  --bc-bg: #fff;
13
13
  --bc-elevated: #fff;
14
14
  --bc-fg: #14161c;
15
- --bc-muted: #6b7280;
15
+ --bc-muted: #5f6673;
16
16
  --bc-faint: #9aa1ad;
17
- --bc-border: #e3e6ec;
18
- --bc-subtle: #f5f6f8;
17
+ --bc-border: #e6e8ee;
18
+ --bc-subtle: #f4f5f8;
19
19
  --bc-raised: #fff;
20
20
  --bc-danger: #dc2626;
21
21
  --bc-ok: #059669;
@@ -25,36 +25,56 @@
25
25
  identifies itself without out-shouting the host's page. */
26
26
  --bc-brand-ink: #4b5563;
27
27
  --bc-brand-mark: #5647ee;
28
- --bc-shadow: 0 24px 60px rgba(10,12,16,.28), 0 2px 8px rgba(10,12,16,.08);
28
+ --bc-shadow: 0 24px 64px rgba(10,12,16,.22), 0 4px 14px rgba(10,12,16,.08);
29
+ --bc-shadow-sm: 0 1px 2px rgba(10,12,16,.06), 0 1px 1px rgba(10,12,16,.04);
29
30
  --bc-dur: 240ms;
30
31
  --bc-ease: cubic-bezier(.22,1,.36,1);
32
+ /* The system everything below is drawn from. Derived tokens are written in
33
+ terms of the ones above, so a host that overrides --bc-accent or the
34
+ palette gets a coherent result without touching these. */
35
+ --bc-accent-soft: color-mix(in srgb, var(--bc-accent) 10%, var(--bc-bg));
36
+ --bc-accent-line: color-mix(in srgb, var(--bc-accent) 32%, var(--bc-border));
37
+ --bc-ring: 0 0 0 3px color-mix(in srgb, var(--bc-accent) 22%, transparent);
38
+ --bc-r-sm: 8px;
39
+ --bc-r-md: 12px;
40
+ --bc-r-lg: 18px;
41
+ --bc-r-xl: 22px;
42
+ --bc-fs-xs: 11.5px;
43
+ --bc-fs-sm: 12.5px;
44
+ --bc-fs-md: 14px;
45
+ --bc-fs-lg: 16px;
46
+ --bc-pad: 18px;
31
47
  }
32
48
  :host(.bc-dark) {
33
49
  --bc-bg: #14161c;
34
50
  --bc-elevated: #1c1f27;
35
51
  --bc-fg: #eef0f4;
36
- --bc-muted: #9aa1ad;
37
- --bc-faint: #6b7280;
38
- --bc-border: #2b2f39;
39
- --bc-subtle: #21242c;
52
+ --bc-muted: #a3aab6;
53
+ --bc-faint: #6f7682;
54
+ --bc-border: #2a2e38;
55
+ --bc-subtle: #1f222a;
40
56
  --bc-raised: #363d4b;
41
57
  --bc-brand-ink: #9aa1ad;
42
58
  --bc-brand-mark: #9b8fff;
43
- --bc-shadow: 0 24px 60px rgba(0,0,0,.6), 0 2px 8px rgba(0,0,0,.4);
59
+ --bc-shadow: 0 24px 64px rgba(0,0,0,.6), 0 4px 14px rgba(0,0,0,.4);
60
+ --bc-shadow-sm: 0 1px 2px rgba(0,0,0,.4);
61
+ --bc-accent-soft: color-mix(in srgb, var(--bc-accent) 18%, var(--bc-bg));
44
62
  }
45
63
  @media (prefers-color-scheme: dark) {
46
64
  :host(.bc-auto) {
47
65
  --bc-bg: #14161c;
48
66
  --bc-elevated: #1c1f27;
49
67
  --bc-fg: #eef0f4;
50
- --bc-muted: #9aa1ad;
51
- --bc-faint: #6b7280;
52
- --bc-border: #2b2f39;
53
- --bc-subtle: #21242c;
68
+ --bc-muted: #a3aab6;
69
+ --bc-faint: #6f7682;
70
+ --bc-border: #2a2e38;
71
+ --bc-subtle: #1f222a;
54
72
  --bc-raised: #363d4b;
55
73
  --bc-brand-ink: #9aa1ad;
56
74
  --bc-brand-mark: #9b8fff;
57
- --bc-shadow: 0 24px 60px rgba(0,0,0,.6), 0 2px 8px rgba(0,0,0,.4);
75
+ --bc-shadow: 0 24px 64px rgba(0,0,0,.6), 0 4px 14px rgba(0,0,0,.4);
76
+ --bc-shadow-sm: 0 1px 2px rgba(0,0,0,.4);
77
+ --bc-accent-soft: color-mix(in srgb, var(--bc-accent) 18%, var(--bc-bg));
58
78
  }
59
79
  }
60
80
 
@@ -65,6 +85,16 @@ svg { width: 1em; height: 1em; display: block; }
65
85
  — which is why .dock and .launcher each had to say so themselves. Said once,
66
86
  for all of them, so the next element hidden from JavaScript works. */
67
87
  [hidden] { display: none !important; }
88
+ .sr-only {
89
+ position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
90
+ overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
91
+ }
92
+
93
+ /* One focus ring for everything clickable, so keyboard users never have to
94
+ guess where they are. Fields draw their own ring (a glow, not an outline). */
95
+ button:focus-visible, a:focus-visible, select:focus-visible, [tabindex]:focus-visible {
96
+ outline: 2px solid var(--bc-accent); outline-offset: 2px;
97
+ }
68
98
 
69
99
  /* Motion is decoration here — every animation below is an entrance or a state
70
100
  hint, so switching them off costs nothing but the polish. */
@@ -78,14 +108,19 @@ svg { width: 1em; height: 1em; display: block; }
78
108
 
79
109
  @keyframes bc-fade-in { from { opacity: 0 } to { opacity: 1 } }
80
110
  @keyframes bc-fade-out { to { opacity: 0 } }
81
- @keyframes bc-panel-in { from { opacity: 0; transform: translateY(16px) scale(.97) } to { opacity: 1; transform: none } }
82
- @keyframes bc-panel-out { to { opacity: 0; transform: translateY(8px) scale(.985) } }
111
+ @keyframes bc-panel-in { from { opacity: 0; transform: translateY(14px) scale(.965) } to { opacity: 1; transform: none } }
112
+ @keyframes bc-panel-out { to { opacity: 0; transform: translateY(10px) scale(.975) } }
113
+ @keyframes bc-sheet-in { from { transform: translateY(100%) } to { transform: none } }
114
+ @keyframes bc-sheet-out { to { transform: translateY(100%) } }
83
115
  @keyframes bc-launcher-in { from { opacity: 0; transform: translateY(12px) scale(.86) } to { opacity: 1; transform: none } }
84
- @keyframes bc-item-in { from { opacity: 0; transform: translateY(8px) scale(.92) } to { opacity: 1; transform: none } }
116
+ @keyframes bc-item-in { from { opacity: 0; transform: translateY(8px) scale(.96) } to { opacity: 1; transform: none } }
117
+ @keyframes bc-rise { from { opacity: 0; transform: translateY(6px) } to { opacity: 1; transform: none } }
85
118
  @keyframes bc-pulse { 0%, 100% { opacity: 1; transform: scale(1) } 50% { opacity: .3; transform: scale(.78) } }
86
119
  @keyframes bc-spin { to { transform: rotate(360deg) } }
87
120
  @keyframes bc-pop { 0% { transform: scale(.5); opacity: 0 } 65% { transform: scale(1.1) } 100% { transform: scale(1); opacity: 1 } }
88
121
  @keyframes bc-nudge { 25% { transform: translateX(-3px) } 75% { transform: translateX(3px) } }
122
+ @keyframes bc-typing { 0%, 60%, 100% { transform: translateY(0); opacity: .45 } 30% { transform: translateY(-3px); opacity: 1 } }
123
+ @keyframes bc-shimmer { from { background-position: 200% 0 } to { background-position: -200% 0 } }
89
124
 
90
125
  /* ---------- dock: theme switch stacked above the launcher ---------- */
91
126
  .dock {
@@ -106,7 +141,7 @@ svg { width: 1em; height: 1em; display: block; }
106
141
  display: inline-flex; align-items: center; gap: 2px;
107
142
  padding: 3px; border-radius: 999px;
108
143
  background: var(--bc-elevated); border: 1px solid var(--bc-border);
109
- box-shadow: 0 6px 18px rgba(10,12,16,.16), 0 1px 3px rgba(10,12,16,.10);
144
+ box-shadow: 0 6px 18px rgba(10,12,16,.14), 0 1px 3px rgba(10,12,16,.08);
110
145
  animation: bc-launcher-in 420ms var(--bc-ease) both;
111
146
  }
112
147
  .themer button {
@@ -121,88 +156,152 @@ svg { width: 1em; height: 1em; display: block; }
121
156
  .themer button:active { transform: scale(.92); }
122
157
  .themer button[aria-pressed="true"] { background: var(--bc-accent); color: var(--bc-on-accent); }
123
158
  .themer button[aria-pressed="true"]:hover { background: var(--bc-accent); filter: brightness(1.06); }
124
- .themer button:focus-visible { outline: 2px solid var(--bc-accent); outline-offset: 2px; }
125
159
 
126
160
  /* ---------- launcher ---------- */
127
161
  .launcher {
128
- display: inline-flex; align-items: center; gap: 8px;
129
- padding: 11px 17px; border: none; border-radius: 999px;
162
+ position: relative;
163
+ display: inline-flex; align-items: center; gap: 9px;
164
+ height: 48px; padding: 0 20px 0 16px; border: none; border-radius: 999px;
130
165
  background: var(--bc-accent); color: var(--bc-on-accent);
131
- font-size: 14px; font-weight: 600; line-height: 1; letter-spacing: -.01em;
166
+ font-size: var(--bc-fs-md); font-weight: 620; line-height: 1; letter-spacing: -.01em;
132
167
  cursor: pointer;
133
- box-shadow: 0 6px 18px rgba(10,12,16,.22), 0 1px 3px rgba(10,12,16,.16);
134
- transition: transform var(--bc-dur) var(--bc-ease), box-shadow var(--bc-dur) var(--bc-ease), filter 160ms linear;
168
+ box-shadow: 0 10px 28px color-mix(in srgb, var(--bc-accent) 34%, rgba(10,12,16,.2)), 0 2px 6px rgba(10,12,16,.16);
169
+ transition: transform var(--bc-dur) var(--bc-ease), box-shadow var(--bc-dur) var(--bc-ease), filter 160ms linear, padding var(--bc-dur) var(--bc-ease);
135
170
  animation: bc-launcher-in 420ms var(--bc-ease) both;
136
171
  }
137
- .launcher svg { font-size: 17px; }
138
- .launcher:hover { transform: translateY(-2px); box-shadow: 0 12px 28px rgba(10,12,16,.26), 0 2px 6px rgba(10,12,16,.18); filter: brightness(1.06); }
172
+ /* Two glyphs in one box: the bubble when closed, a chevron when open, turned
173
+ into each other so the button reads as the panel's own handle. */
174
+ .launcher .ico { position: relative; width: 20px; height: 20px; flex: none; }
175
+ .launcher .ico > span {
176
+ position: absolute; inset: 0;
177
+ transition: transform 320ms var(--bc-ease), opacity 200ms ease;
178
+ }
179
+ .launcher .ico svg { width: 20px; height: 20px; }
180
+ .launcher .ico .when-open { opacity: 0; transform: rotate(-90deg) scale(.6); }
181
+ .launcher[aria-expanded="true"] .ico .when-closed { opacity: 0; transform: rotate(90deg) scale(.6); }
182
+ .launcher[aria-expanded="true"] .ico .when-open { opacity: 1; transform: none; }
183
+ .launcher:hover { transform: translateY(-2px); filter: brightness(1.06); }
139
184
  .launcher:active { transform: translateY(0) scale(.97); transition-duration: 90ms; }
140
- .launcher:focus-visible { outline: 2px solid var(--bc-accent); outline-offset: 3px; }
185
+ .launcher:focus-visible { outline-offset: 3px; }
141
186
  .launcher[hidden] { display: none; }
142
187
 
143
188
  /* ---------- scrim + panel ---------- */
144
189
  .scrim {
145
190
  position: fixed; inset: 0; z-index: 2147483001;
146
- background: rgba(10,12,16,.5);
191
+ background: rgba(10,12,16,.32);
147
192
  animation: bc-fade-in 200ms ease both;
148
193
  }
149
- .scrim.closing { animation: bc-fade-out 150ms ease both; }
194
+ .scrim.closing { animation: bc-fade-out 170ms ease both; }
150
195
 
151
196
  /* The panel belongs to the launcher, so it opens out of that corner rather
152
197
  than in the middle of the screen. --bc-dock-h is measured at open time
153
- because the dock's height depends on whether the launcher is showing. */
198
+ because the dock's height depends on whether the launcher is showing.
199
+ A column: the header and footer stay put and only the middle scrolls. */
154
200
  .panel {
155
201
  position: fixed;
156
- width: calc(100vw - 40px); max-width: 440px;
202
+ display: flex; flex-direction: column;
203
+ width: calc(100vw - 40px); max-width: 420px;
157
204
  max-height: calc(100vh - var(--bc-dock-h, 84px) - 52px);
158
- overflow-y: auto; overscroll-behavior: contain;
205
+ overflow: hidden;
159
206
  background: var(--bc-bg); color: var(--bc-fg);
160
- border-radius: 16px; box-shadow: var(--bc-shadow);
161
- animation: bc-panel-in 320ms var(--bc-ease) both;
162
- }
163
- .scrim.at-right .panel { right: 20px; }
164
- .scrim.at-left .panel { left: 20px; }
207
+ border-radius: var(--bc-r-xl); box-shadow: var(--bc-shadow);
208
+ border: 1px solid color-mix(in srgb, var(--bc-border) 70%, transparent);
209
+ animation: bc-panel-in 340ms var(--bc-ease) both;
210
+ }
211
+ /* A conversation wants a height of its own, so the thread fills the panel
212
+ rather than shrinking to its first two messages. */
213
+ .panel.is-chat { height: 640px; }
214
+ .scrim.at-right .panel { right: 20px; transform-origin: bottom right; }
215
+ .scrim.at-left .panel { left: 20px; transform-origin: bottom left; }
165
216
  .scrim.at-bottom .panel { bottom: calc(20px + var(--bc-dock-h, 84px) + 12px); }
166
- .scrim.at-top .panel { top: calc(20px + var(--bc-dock-h, 84px) + 12px); }
167
- .scrim.closing .panel { animation: bc-panel-out 150ms ease both; }
217
+ .scrim.at-top .panel { top: calc(20px + var(--bc-dock-h, 84px) + 12px); transform-origin: top right; }
218
+ .scrim.closing .panel { animation: bc-panel-out 170ms ease both; }
168
219
 
169
- .head { display: flex; align-items: flex-start; gap: 11px; padding: 18px 18px 0; }
170
- .head .mark {
171
- flex: none; display: grid; place-items: center;
172
- width: 32px; height: 32px; border-radius: 9px;
173
- background: color-mix(in srgb, var(--bc-accent) 13%, transparent);
174
- color: var(--bc-accent); font-size: 18px;
220
+ /* ---------- header ---------- */
221
+ .head {
222
+ flex: none; position: relative;
223
+ display: flex; align-items: center; gap: 12px;
224
+ padding: 16px 14px 14px var(--bc-pad);
225
+ background: linear-gradient(180deg, var(--bc-accent-soft), var(--bc-bg));
226
+ border-bottom: 1px solid var(--bc-border);
227
+ }
228
+ .head .mark, .avatar {
229
+ flex: none; display: grid; place-items: center; position: relative;
230
+ width: 38px; height: 38px; border-radius: 50%;
231
+ background: linear-gradient(140deg, var(--bc-accent), color-mix(in srgb, var(--bc-accent) 60%, #fff));
232
+ color: var(--bc-on-accent); font-size: 19px;
233
+ box-shadow: 0 4px 12px color-mix(in srgb, var(--bc-accent) 30%, transparent);
234
+ }
235
+ /* The little "online" dot says someone — or something — is on the other end. */
236
+ .head .mark::after {
237
+ content: ''; position: absolute; right: -1px; bottom: -1px;
238
+ width: 11px; height: 11px; border-radius: 50%;
239
+ background: #22c55e; border: 2px solid var(--bc-bg);
175
240
  }
176
241
  .head .titles { flex: 1; min-width: 0; }
177
- .head h2 { margin: 1px 0 3px; font-size: 16px; font-weight: 650; letter-spacing: -.015em; }
178
- .head p { margin: 0; font-size: 12.5px; line-height: 1.45; color: var(--bc-muted); }
242
+ .head h2 {
243
+ margin: 0 0 2px; font-size: var(--bc-fs-lg); font-weight: 680; letter-spacing: -.02em; line-height: 1.25;
244
+ overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
245
+ }
246
+ .head p { margin: 0; font-size: var(--bc-fs-sm); line-height: 1.45; color: var(--bc-muted); }
179
247
  .icon-btn {
180
248
  flex: none; display: grid; place-items: center;
181
- width: 28px; height: 28px; padding: 0; font-size: 15px;
182
- border: none; border-radius: 8px; background: none; color: var(--bc-faint);
183
- cursor: pointer; transition: background 160ms, color 160ms;
249
+ width: 32px; height: 32px; padding: 0; font-size: 16px;
250
+ border: none; border-radius: 10px; background: none; color: var(--bc-muted);
251
+ cursor: pointer; transition: background 160ms, color 160ms, transform 160ms var(--bc-ease);
184
252
  }
185
- .icon-btn:hover { background: var(--bc-subtle); color: var(--bc-fg); }
186
- .icon-btn:focus-visible { outline: 2px solid var(--bc-accent); outline-offset: 1px; }
187
-
188
- .body { padding: 16px 18px 0; }
253
+ .icon-btn:hover { background: color-mix(in srgb, var(--bc-fg) 7%, transparent); color: var(--bc-fg); }
254
+ .icon-btn:active { transform: scale(.92); }
255
+ .icon-btn.back { margin: 0 -6px 0 -8px; }
189
256
 
257
+ .body {
258
+ flex: 1 1 auto; min-height: 0; overflow-y: auto; overscroll-behavior: contain;
259
+ padding: 16px var(--bc-pad) 6px;
260
+ }
190
261
 
191
- label { display: block; font-size: 12px; font-weight: 600; color: var(--bc-fg); margin-bottom: 6px; }
262
+ label { display: block; font-size: var(--bc-fs-sm); font-weight: 620; color: var(--bc-fg); margin-bottom: 7px; }
263
+ label .opt { font-weight: 450; color: var(--bc-faint); }
192
264
  input[type=text], input[type=email], textarea {
193
- width: 100%; padding: 10px 12px; font-size: 14px; line-height: 1.45;
265
+ width: 100%; padding: 11px 13px; font-size: var(--bc-fs-md); line-height: 1.45;
194
266
  color: var(--bc-fg); background: var(--bc-elevated);
195
- border: 1px solid var(--bc-border); border-radius: 10px;
196
- transition: border-color 160ms, box-shadow 160ms;
267
+ border: 1px solid var(--bc-border); border-radius: var(--bc-r-md);
268
+ transition: border-color 160ms, box-shadow 160ms, background 160ms;
197
269
  }
198
270
  input[type=text]::placeholder, input[type=email]::placeholder, textarea::placeholder { color: var(--bc-faint); }
271
+ input[type=text]:hover, input[type=email]:hover, textarea:hover { border-color: color-mix(in srgb, var(--bc-fg) 18%, var(--bc-border)); }
199
272
  input[type=text]:focus, input[type=email]:focus, textarea:focus {
200
- outline: none; border-color: var(--bc-accent);
201
- box-shadow: 0 0 0 3px color-mix(in srgb, var(--bc-accent) 18%, transparent);
202
- }
203
- input.invalid { border-color: var(--bc-danger); animation: bc-nudge 240ms ease; }
204
- textarea { min-height: 84px; resize: vertical; }
205
- .field { margin-bottom: 14px; }
273
+ outline: none; border-color: var(--bc-accent); box-shadow: var(--bc-ring);
274
+ }
275
+ input.invalid, input.invalid:focus, textarea.invalid {
276
+ border-color: var(--bc-danger); animation: bc-nudge 240ms ease;
277
+ box-shadow: 0 0 0 3px color-mix(in srgb, var(--bc-danger) 16%, transparent);
278
+ }
279
+ .field-err {
280
+ display: flex; align-items: center; gap: 6px;
281
+ margin: 7px 0 0; font-size: var(--bc-fs-xs); font-weight: 550; color: var(--bc-danger);
282
+ animation: bc-rise 200ms var(--bc-ease) both;
283
+ }
284
+ .field-err svg { font-size: 13px; flex: none; }
285
+ textarea { min-height: 88px; resize: vertical; }
286
+ .field { margin-bottom: 16px; }
287
+ .field-head { display: flex; align-items: baseline; justify-content: space-between; gap: 8px; }
288
+ .field-head .count { font-size: var(--bc-fs-xs); color: var(--bc-faint); font-variant-numeric: tabular-nums; }
289
+
290
+ /* The draft line: a quiet note, or a card offering to pick up where they left off. */
291
+ .compose > .note { font-size: var(--bc-fs-xs); color: var(--bc-faint); margin: -4px 0 10px; }
292
+ .compose > .note:empty { display: none; }
293
+ .compose > .note:has(button) {
294
+ display: flex; flex-wrap: wrap; align-items: center; gap: 6px 10px;
295
+ margin: 0 0 14px; padding: 10px 12px; border-radius: var(--bc-r-md);
296
+ background: var(--bc-accent-soft); border: 1px solid var(--bc-accent-line);
297
+ font-size: var(--bc-fs-sm); color: var(--bc-fg);
298
+ }
299
+ .compose > .note button {
300
+ padding: 5px 11px; font: inherit; font-size: var(--bc-fs-xs); font-weight: 620;
301
+ border-radius: 999px; cursor: pointer;
302
+ border: 1px solid var(--bc-accent); background: var(--bc-accent); color: var(--bc-on-accent);
303
+ }
304
+ .compose > .note button[data-discard] { background: transparent; color: var(--bc-muted); border-color: var(--bc-border); }
206
305
 
207
306
  /* ---------- what is already known ----------
208
307
  A help surface in front of the form, not a step in it. Everything here is
@@ -210,34 +309,35 @@ textarea { min-height: 84px; resize: vertical; }
210
309
  leave, tap "this is happening to me too" and leave, or type straight past all
211
310
  of it and file the report they came to file. Nothing is ever in their way,
212
311
  because a reporter who feels handled rather than helped stops reporting. */
213
- .known { margin-bottom: 14px; }
312
+ .known { margin-bottom: 16px; }
214
313
  .known .known-h {
215
- margin: 0 0 8px; font-size: 12px; font-weight: 650; letter-spacing: .02em;
314
+ margin: 0 0 8px; font-size: 11px; font-weight: 680; letter-spacing: .06em;
216
315
  text-transform: uppercase; color: var(--bc-faint);
217
316
  }
218
317
  .known .issue {
219
- display: flex; align-items: flex-start; gap: 10px;
318
+ display: flex; align-items: center; gap: 10px;
220
319
  padding: 10px 12px; margin-bottom: 6px;
221
- background: var(--bc-subtle); border: 1px solid transparent; border-radius: 10px;
320
+ background: var(--bc-subtle); border: 1px solid var(--bc-border); border-radius: var(--bc-r-md);
321
+ animation: bc-rise 240ms var(--bc-ease) both;
222
322
  }
223
- .known .issue.is-joined { border-color: var(--bc-ok); }
323
+ .known .issue.is-joined { border-color: color-mix(in srgb, var(--bc-ok) 55%, var(--bc-border)); }
224
324
  .known .issue .who { flex: 1; min-width: 0; }
225
325
  .known .issue .t {
226
326
  display: block; font-size: 13px; font-weight: 620; line-height: 1.4;
227
327
  color: var(--bc-fg); overflow-wrap: anywhere;
228
328
  }
229
329
  .known .issue .meta {
230
- display: block; margin-top: 3px; font-size: 12px; line-height: 1.45; color: var(--bc-muted);
330
+ display: block; margin-top: 3px; font-size: var(--bc-fs-xs); line-height: 1.45; color: var(--bc-muted);
231
331
  }
232
332
  .known .issue .join {
233
- flex: none; padding: 6px 10px; font-size: 12px; font-weight: 620;
333
+ flex: none; padding: 7px 12px; font-size: 12px; font-weight: 620;
234
334
  color: var(--bc-accent); background: var(--bc-bg);
235
- border: 1px solid var(--bc-border); border-radius: 8px; cursor: pointer;
335
+ border: 1px solid var(--bc-accent-line); border-radius: 999px; cursor: pointer;
336
+ transition: background 160ms, border-color 160ms;
236
337
  }
237
- .known .issue .join:hover { border-color: var(--bc-accent); }
238
- .known .issue .join:disabled { color: var(--bc-ok); border-color: var(--bc-border); cursor: default; }
239
- .known .issue .join:focus-visible { outline: 2px solid var(--bc-accent); outline-offset: 2px; }
240
- .known .ask { display: flex; gap: 8px; margin-top: 8px; }
338
+ .known .issue .join:hover { border-color: var(--bc-accent); background: var(--bc-accent-soft); }
339
+ .known .issue .join:disabled { color: var(--bc-ok); border-color: var(--bc-border); background: var(--bc-bg); cursor: default; opacity: 1; }
340
+ .known .ask { display: flex; gap: 8px; margin: 2px 0 8px; }
241
341
  .known .ask input { flex: 1; min-width: 0; }
242
342
  .known .ask button { flex: none; }
243
343
  .known .err { margin: 6px 0 0; font-size: 12px; line-height: 1.45; color: var(--bc-danger); }
@@ -249,97 +349,109 @@ textarea { min-height: 84px; resize: vertical; }
249
349
  strip is the whole panel. */
250
350
  .whoami {
251
351
  display: flex; align-items: center; flex-wrap: wrap; gap: 8px;
252
- margin-bottom: 14px; padding: 10px 12px;
253
- font-size: 12.5px; line-height: 1.45; color: var(--bc-muted);
254
- background: var(--bc-subtle); border-radius: 10px;
352
+ margin-bottom: 16px; padding: 10px 12px;
353
+ font-size: var(--bc-fs-sm); line-height: 1.45; color: var(--bc-muted);
354
+ background: var(--bc-subtle); border: 1px solid var(--bc-border); border-radius: var(--bc-r-md);
255
355
  }
256
- .whoami.asking { display: block; }
356
+ .whoami.asking { display: block; padding: 14px; }
257
357
  .whoami .who { flex: 1; min-width: 0; }
258
358
  .whoami .who strong { color: var(--bc-fg); font-weight: 620; word-break: break-all; }
259
- .whoami .link {
260
- padding: 0; font-size: 12.5px; font-weight: 600; line-height: 1.45;
261
- color: var(--bc-accent); background: none; border: none; cursor: pointer;
262
- }
263
- .whoami .link:hover { text-decoration: underline; }
264
- .whoami .link:disabled { color: var(--bc-faint); cursor: default; text-decoration: none; }
265
- .whoami .link:focus-visible { outline: 2px solid var(--bc-accent); outline-offset: 2px; border-radius: 4px; }
266
- .whoami .why { margin: 0 0 10px; font-size: 12.5px; line-height: 1.5; color: var(--bc-muted); }
359
+ .link {
360
+ padding: 0; font: inherit; font-size: var(--bc-fs-sm); font-weight: 620; line-height: 1.45;
361
+ color: var(--bc-accent); background: none; border: none; cursor: pointer; border-radius: 4px;
362
+ }
363
+ .link:hover { text-decoration: underline; text-underline-offset: 2px; }
364
+ .link:disabled { color: var(--bc-faint); cursor: default; text-decoration: none; }
365
+ .whoami .why { margin: 0 0 10px; font-size: var(--bc-fs-sm); line-height: 1.5; color: var(--bc-muted); }
267
366
  .whoami .why strong { color: var(--bc-fg); font-weight: 620; word-break: break-all; }
268
367
  .whoami .row { display: flex; gap: 8px; align-items: stretch; }
269
368
  .whoami .row input { flex: 1; min-width: 0; }
270
369
  .whoami .row button { flex: none; }
271
- .whoami .after { display: flex; gap: 12px; align-items: center; margin-top: 9px; }
370
+ .whoami .after { display: flex; gap: 14px; align-items: center; margin-top: 9px; }
272
371
  .whoami .err { color: var(--bc-danger); }
273
372
  .whoami .code { letter-spacing: .28em; font-variant-numeric: tabular-nums; }
274
373
 
275
374
  /* ---------- which record is this about ----------
276
- Shaped like .whoami on purpose: both are the widget asking for something
277
- rather than the reporter telling us something, and a reporter who has learnt
278
- what the grey block means once should not have to learn it twice. Drawn only
279
- after Send has been pressed and only when what they wrote did not already
280
- answer it, so most people never see this at all. */
375
+ Drawn only after Send has been pressed and only when what they wrote did not
376
+ already answer it, so most people never see this at all. Presented as the
377
+ assistant asking one friendly follow-up, not as a form field that appeared. */
281
378
  .refs {
282
- margin-bottom: 14px; padding: 10px 12px;
283
- font-size: 12.5px; line-height: 1.45; color: var(--bc-muted);
284
- background: var(--bc-subtle); border-radius: 10px;
285
- }
286
- .refs .why { margin: 0 0 10px; font-size: 12.5px; line-height: 1.5; color: var(--bc-muted); }
379
+ position: relative;
380
+ margin-bottom: 16px; padding: 14px;
381
+ font-size: var(--bc-fs-sm); line-height: 1.45; color: var(--bc-muted);
382
+ background: var(--bc-accent-soft);
383
+ border: 1px solid var(--bc-accent-line); border-radius: var(--bc-r-lg);
384
+ animation: bc-item-in 280ms var(--bc-ease) both;
385
+ }
386
+ .refs .ask-head { display: flex; align-items: flex-start; gap: 10px; margin-bottom: 11px; }
387
+ .refs .ask-head .avatar { width: 28px; height: 28px; font-size: 14px; box-shadow: none; }
388
+ .refs .ask-head strong { display: block; font-size: 13.5px; font-weight: 650; color: var(--bc-fg); margin-bottom: 1px; }
389
+ .refs .why { margin: 0; font-size: var(--bc-fs-sm); line-height: 1.5; color: var(--bc-muted); }
287
390
  .refs .row { display: flex; gap: 8px; align-items: stretch; }
288
- .refs .row input { flex: 1; min-width: 0; }
391
+ .refs .row input { flex: 1; min-width: 0; background: var(--bc-bg); }
289
392
  .refs select {
290
393
  flex: none; max-width: 45%; padding: 10px 10px; font-size: 13px;
291
- color: var(--bc-fg); background: var(--bc-elevated);
292
- border: 1px solid var(--bc-border); border-radius: 10px;
293
- }
294
- .refs select:focus {
295
- outline: none; border-color: var(--bc-accent);
296
- box-shadow: 0 0 0 3px color-mix(in srgb, var(--bc-accent) 18%, transparent);
297
- }
298
- .refs .hint { margin: 8px 0 0; font-size: 12px; line-height: 1.45; color: var(--bc-faint); }
394
+ color: var(--bc-fg); background: var(--bc-bg);
395
+ border: 1px solid var(--bc-border); border-radius: var(--bc-r-md);
396
+ }
397
+ .refs select:focus { outline: none; border-color: var(--bc-accent); box-shadow: var(--bc-ring); }
398
+ .refs .chips { display: flex; flex-wrap: wrap; gap: 6px; margin-bottom: 9px; }
399
+ .refs .chips button {
400
+ padding: 5px 11px; font: inherit; font-size: 12px; font-weight: 600; border-radius: 999px; cursor: pointer;
401
+ color: var(--bc-muted); background: var(--bc-bg); border: 1px solid var(--bc-border);
402
+ transition: background 160ms, color 160ms, border-color 160ms;
403
+ }
404
+ .refs .chips button[aria-pressed="true"] { color: var(--bc-on-accent); background: var(--bc-accent); border-color: var(--bc-accent); }
405
+ .refs .hint { margin: 8px 0 0; font-size: 12px; line-height: 1.45; color: var(--bc-muted); }
299
406
  .refs .after { display: flex; gap: 12px; align-items: center; margin-top: 9px; }
300
- .refs .err { color: var(--bc-danger); }
301
- .refs .link {
302
- margin-top: 9px; padding: 0; font-size: 12.5px; font-weight: 600; line-height: 1.45;
303
- color: var(--bc-accent); background: none; border: none; cursor: pointer;
304
- }
305
- .refs .link:hover { text-decoration: underline; }
306
- .refs .link:focus-visible { outline: 2px solid var(--bc-accent); outline-offset: 2px; border-radius: 4px; }
407
+ .refs .err { color: var(--bc-danger); font-weight: 550; }
408
+ .refs .link { margin-top: 10px; font-size: 12px; color: var(--bc-muted); }
409
+ .refs .link:hover { color: var(--bc-fg); }
307
410
 
308
411
  /* ---------- severity ---------- */
309
- .seg { display: grid; grid-template-columns: repeat(4, 1fr); gap: 3px; padding: 3px; background: var(--bc-subtle); border-radius: 10px; }
412
+ .seg { display: grid; grid-template-columns: repeat(4, 1fr); gap: 3px; padding: 3px; background: var(--bc-subtle); border: 1px solid var(--bc-border); border-radius: var(--bc-r-md); }
310
413
  .seg button {
311
- padding: 7px 4px; font-size: 12.5px; font-weight: 550; line-height: 1;
312
- color: var(--bc-muted); background: none; border: none; border-radius: 7px;
313
- cursor: pointer; transition: background 180ms var(--bc-ease), color 180ms, box-shadow 180ms, font-weight 180ms;
314
- }
414
+ display: inline-flex; align-items: center; justify-content: center; gap: 6px;
415
+ padding: 8px 4px; font-size: var(--bc-fs-sm); font-weight: 550; line-height: 1;
416
+ color: var(--bc-muted); background: none; border: none; border-radius: 9px;
417
+ cursor: pointer; transition: background 180ms var(--bc-ease), color 180ms, box-shadow 180ms;
418
+ }
419
+ .seg button::before { content: ''; width: 7px; height: 7px; border-radius: 50%; background: var(--sev, var(--bc-faint)); opacity: .55; transition: opacity 180ms; }
420
+ .seg button[data-prio="LOW"] { --sev: #94a3b8; }
421
+ .seg button[data-prio="MEDIUM"] { --sev: #3b82f6; }
422
+ .seg button[data-prio="HIGH"] { --sev: #f59e0b; }
423
+ .seg button[data-prio="CRITICAL"] { --sev: #ef4444; }
315
424
  .seg button:hover { color: var(--bc-fg); }
316
425
  .seg button[aria-pressed=true] {
317
- background: var(--bc-raised); color: var(--bc-accent); font-weight: 680;
318
- box-shadow: 0 1px 3px rgba(10,12,16,.14);
426
+ background: var(--bc-raised); color: var(--bc-fg); font-weight: 650;
427
+ box-shadow: 0 1px 3px rgba(10,12,16,.14), 0 0 0 1px color-mix(in srgb, var(--bc-border) 60%, transparent);
319
428
  }
320
- .seg button:focus-visible { outline: 2px solid var(--bc-accent); outline-offset: -1px; }
429
+ .seg button[aria-pressed=true]::before { opacity: 1; }
430
+ .seg button:focus-visible { outline-offset: -2px; }
321
431
 
322
432
  /* ---------- attachments ---------- */
323
- .tools { display: flex; flex-wrap: wrap; gap: 6px; }
433
+ .tools { display: grid; grid-template-columns: repeat(auto-fit, minmax(0, 1fr)); gap: 8px; }
324
434
  .tool {
325
- display: inline-flex; align-items: center; gap: 6px;
326
- padding: 8px 12px; font-size: 12.5px; font-weight: 550; line-height: 1;
435
+ display: inline-flex; flex-direction: column; align-items: center; justify-content: center; gap: 6px;
436
+ padding: 12px 8px; font-size: 12px; font-weight: 600; line-height: 1;
327
437
  color: var(--bc-fg); background: var(--bc-elevated);
328
- border: 1px solid var(--bc-border); border-radius: 9px; cursor: pointer;
329
- transition: border-color 160ms, background 160ms, transform 160ms var(--bc-ease);
438
+ border: 1px dashed color-mix(in srgb, var(--bc-fg) 20%, var(--bc-border)); border-radius: var(--bc-r-md); cursor: pointer;
439
+ transition: border-color 160ms, background 160ms, color 160ms, transform 160ms var(--bc-ease);
330
440
  }
331
- .tool svg { font-size: 15px; color: var(--bc-muted); transition: color 160ms; }
332
- .tool:hover:not(:disabled) { border-color: var(--bc-accent); transform: translateY(-1px); }
441
+ .tool svg { font-size: 19px; color: var(--bc-muted); transition: color 160ms; }
442
+ .tool:hover:not(:disabled) { border-color: var(--bc-accent); border-style: solid; background: var(--bc-accent-soft); transform: translateY(-1px); }
333
443
  .tool:hover:not(:disabled) svg { color: var(--bc-accent); }
334
444
  .tool:active:not(:disabled) { transform: translateY(0) scale(.98); }
335
- .tool:focus-visible { outline: 2px solid var(--bc-accent); outline-offset: 1px; }
336
445
  .tool:disabled { opacity: .45; cursor: not-allowed; }
446
+ .attach-hint { margin: 8px 0 0; font-size: var(--bc-fs-xs); color: var(--bc-faint); }
337
447
 
338
448
  .thumbs { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 10px; }
449
+ .thumbs:empty { display: none; }
339
450
  .thumb {
340
- position: relative; width: 74px; height: 74px; flex: none;
341
- border-radius: 10px; overflow: hidden;
451
+ position: relative; width: 76px; height: 76px; flex: none;
452
+ border-radius: var(--bc-r-md); overflow: hidden;
342
453
  border: 1px solid var(--bc-border); background: var(--bc-subtle);
454
+ box-shadow: var(--bc-shadow-sm);
343
455
  animation: bc-item-in 300ms var(--bc-ease) both;
344
456
  }
345
457
  .thumb img, .thumb video { width: 100%; height: 100%; object-fit: cover; display: block; }
@@ -350,11 +462,11 @@ textarea { min-height: 84px; resize: vertical; }
350
462
  background: rgba(10,12,16,.72); color: #fff; font-size: 9.5px; font-weight: 600; line-height: 1.3;
351
463
  }
352
464
  .thumb .drop {
353
- position: absolute; top: 3px; right: 3px;
354
- width: 19px; height: 19px; font-size: 11px; border-radius: 6px;
355
- background: rgba(10,12,16,.68); color: #fff; border: none;
465
+ position: absolute; top: 4px; right: 4px;
466
+ width: 20px; height: 20px; font-size: 11px; border-radius: 50%;
467
+ background: rgba(10,12,16,.7); color: #fff; border: none;
356
468
  display: grid; place-items: center; cursor: pointer;
357
- opacity: 0; transition: opacity 160ms;
469
+ opacity: 0; transition: opacity 160ms, background 160ms;
358
470
  }
359
471
  .thumb:hover .drop, .thumb:focus-within .drop { opacity: 1; }
360
472
  .thumb .drop:hover { background: var(--bc-danger); }
@@ -378,354 +490,533 @@ textarea { min-height: 84px; resize: vertical; }
378
490
 
379
491
  /* ---------- messages ---------- */
380
492
  .msg {
381
- display: flex; align-items: flex-start; gap: 7px;
382
- font-size: 12.5px; line-height: 1.45; padding: 9px 11px; border-radius: 9px; margin-bottom: 12px;
493
+ display: flex; align-items: flex-start; gap: 8px;
494
+ font-size: var(--bc-fs-sm); line-height: 1.45; padding: 10px 12px; border-radius: var(--bc-r-md); margin-bottom: 14px;
383
495
  animation: bc-item-in 240ms var(--bc-ease) both;
384
496
  }
385
- .msg.err { background: color-mix(in srgb, var(--bc-danger) 11%, transparent); color: var(--bc-danger); }
386
- .msg.info { background: var(--bc-subtle); color: var(--bc-muted); }
497
+ .msg svg { flex: none; font-size: 15px; margin-top: 1px; }
498
+ .msg.err { background: color-mix(in srgb, var(--bc-danger) 10%, var(--bc-bg)); color: var(--bc-danger); border: 1px solid color-mix(in srgb, var(--bc-danger) 30%, transparent); }
499
+ .msg.info { background: var(--bc-subtle); color: var(--bc-muted); border: 1px solid var(--bc-border); }
387
500
 
388
501
  /* ---------- footer ---------- */
389
502
  .foot {
390
- display: flex; align-items: center; gap: 9px;
391
- margin-top: 16px; padding: 14px 18px; border-top: 1px solid var(--bc-border);
392
- background: var(--bc-subtle);
503
+ flex: none;
504
+ display: flex; align-items: center; flex-wrap: wrap; gap: 8px;
505
+ padding: 12px var(--bc-pad); border-top: 1px solid var(--bc-border);
506
+ background: var(--bc-bg);
393
507
  }
394
508
  .foot .spacer { flex: 1; }
395
- .foot .note { font-size: 11.5px; color: var(--bc-faint); }
509
+ .foot .note { flex-basis: 100%; order: -1; font-size: var(--bc-fs-xs); color: var(--bc-muted); }
510
+ .foot .note:empty { display: none; }
396
511
  /* Quiet, but still legible: this sits in someone else's product, so it identifies
397
512
  where the report goes without competing with their interface. Quiet is bought
398
513
  with colour (--bc-brand-ink sits a step below body text) rather than with a
399
514
  blanket opacity — the BUGCATCH half is only about 3px of cap height at this
400
515
  size, and dimming it on top of that left it as a smudge in both themes. */
401
- .brand-credit { display: flex; align-items: center; transition: color 0.15s; }
402
- .bc-brand { height: 18px; width: auto; display: block; color: var(--bc-brand-ink); }
516
+ .powered {
517
+ flex: none; display: flex; align-items: center; justify-content: center; gap: 6px;
518
+ padding: 7px var(--bc-pad) 9px; font-size: 10.5px; color: var(--bc-faint);
519
+ background: var(--bc-subtle); border-top: 1px solid var(--bc-border);
520
+ }
521
+ .brand-credit { display: flex; align-items: center; transition: color 0.15s; border-radius: 4px; }
522
+ .bc-brand { height: 16px; width: auto; display: block; color: var(--bc-brand-ink); }
403
523
  .brand-credit:hover .bc-brand { color: var(--bc-fg); }
404
- .brand-credit:focus-visible { outline: 2px solid var(--bc-accent); outline-offset: 3px; border-radius: 4px; }
405
524
  button.ghost, button.primary {
406
- padding: 9px 15px; font-size: 13px; font-weight: 600; line-height: 1;
407
- border-radius: 9px; cursor: pointer;
408
- transition: transform 160ms var(--bc-ease), filter 160ms, background 160ms, border-color 160ms;
409
- }
410
- button.ghost { background: none; border: 1px solid var(--bc-border); color: var(--bc-muted); }
411
- button.ghost:hover { color: var(--bc-fg); border-color: var(--bc-faint); }
525
+ display: inline-flex; align-items: center; justify-content: center; gap: 7px;
526
+ height: 38px; padding: 0 15px; font: inherit; font-size: 13px; font-weight: 620; line-height: 1;
527
+ border-radius: 999px; cursor: pointer; white-space: nowrap;
528
+ transition: transform 160ms var(--bc-ease), filter 160ms, background 160ms, border-color 160ms, color 160ms, box-shadow 160ms;
529
+ }
530
+ button.ghost { background: var(--bc-bg); border: 1px solid var(--bc-border); color: var(--bc-fg); }
531
+ button.ghost:hover:not(:disabled) { background: var(--bc-subtle); border-color: color-mix(in srgb, var(--bc-fg) 20%, var(--bc-border)); }
532
+ button.ghost svg, button.primary svg { font-size: 15px; }
412
533
  button.primary {
413
- display: inline-flex; align-items: center; gap: 7px;
534
+ padding: 0 18px;
414
535
  background: var(--bc-accent); border: 1px solid var(--bc-accent); color: var(--bc-on-accent);
536
+ box-shadow: 0 4px 12px color-mix(in srgb, var(--bc-accent) 30%, transparent);
415
537
  }
416
538
  button.primary:hover:not(:disabled) { transform: translateY(-1px); filter: brightness(1.07); }
417
539
  button.primary:active:not(:disabled) { transform: none; }
418
- button.ghost:focus-visible, button.primary:focus-visible { outline: 2px solid var(--bc-accent); outline-offset: 2px; }
419
540
  button:disabled { opacity: .5; cursor: not-allowed; }
420
- button.primary .spinner { border-color: rgba(255,255,255,.4); border-top-color: #fff; width: 13px; height: 13px; }
541
+ button.primary:disabled { box-shadow: none; }
542
+ button.primary .spinner { border-color: rgba(255,255,255,.4); border-top-color: #fff; width: 14px; height: 14px; }
543
+ button.quiet {
544
+ padding: 0 4px; height: 38px; font: inherit; font-size: 13px; font-weight: 600;
545
+ border: none; background: none; color: var(--bc-muted); cursor: pointer; border-radius: 8px;
546
+ }
547
+ button.quiet:hover { color: var(--bc-accent); }
421
548
 
422
- /* ---------- success ---------- */
423
549
  /* ---------- your reports ---------- */
424
- .history { padding: 6px 20px 18px; max-height: 340px; overflow-y: auto; }
550
+ .history {
551
+ flex: 1 1 auto; min-height: 0; overflow-y: auto; overscroll-behavior: contain;
552
+ padding: 8px 12px 14px;
553
+ }
425
554
  /* On the conversation screen the inner thread does the scrolling, so this
426
555
  wrapper must not — two nested scrollers means the composer drifts out of
427
556
  reach exactly when someone reaches for it. */
428
557
  .history.chatting {
429
- max-height: none; overflow: visible; display: flex; flex-direction: column;
558
+ overflow: hidden; display: flex; flex-direction: column; padding: 0;
430
559
  }
431
560
  .history .row {
432
- display: flex; align-items: flex-start; gap: 10px;
433
- padding: 11px 0; border-bottom: 1px solid var(--bc-border);
561
+ display: flex; align-items: center; gap: 12px;
562
+ padding: 12px 10px; border-bottom: 1px solid var(--bc-border);
434
563
  }
435
564
  .history .row:last-child { border-bottom: 0; }
436
565
  .history .who { flex: 1; min-width: 0; }
437
566
  .history .ttl {
438
- display: block; font-size: 13px; font-weight: 550; color: var(--bc-fg);
567
+ display: block; font-size: 13.5px; font-weight: 600; color: var(--bc-fg);
439
568
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
440
569
  }
441
- .history .sub { display: block; margin-top: 2px; font-size: 11.5px; color: var(--bc-faint); }
442
- .history .empty { padding: 26px 0; text-align: center; font-size: 12.5px; color: var(--bc-muted); }
570
+ .history .sub { display: block; margin-top: 3px; font-size: var(--bc-fs-xs); color: var(--bc-faint); }
571
+ .history .row-ico {
572
+ flex: none; display: grid; place-items: center; width: 34px; height: 34px; border-radius: 10px;
573
+ background: var(--bc-subtle); color: var(--bc-muted); font-size: 16px;
574
+ }
575
+ .history .chev { flex: none; color: var(--bc-faint); font-size: 15px; transition: transform 160ms var(--bc-ease), color 160ms; }
576
+ .empty {
577
+ display: flex; flex-direction: column; align-items: center; gap: 10px;
578
+ padding: 40px 16px; text-align: center; font-size: var(--bc-fs-sm); color: var(--bc-muted);
579
+ }
580
+ .empty .empty-ico {
581
+ display: grid; place-items: center; width: 44px; height: 44px; border-radius: 50%;
582
+ background: var(--bc-accent-soft); color: var(--bc-accent); font-size: 20px;
583
+ }
584
+ .skel {
585
+ display: block; height: 12px; border-radius: 6px; margin: 6px 0;
586
+ background: linear-gradient(90deg, var(--bc-subtle) 25%, color-mix(in srgb, var(--bc-fg) 8%, var(--bc-subtle)) 50%, var(--bc-subtle) 75%);
587
+ background-size: 200% 100%; animation: bc-shimmer 1.4s linear infinite;
588
+ }
443
589
  /* A history row is a button now — it opens the report — so the UA styling has
444
590
  to go, and the hit area has to read as one. */
445
591
  .history button.row {
446
- width: 100%; background: none; border: 0; border-bottom: 1px solid var(--bc-border);
592
+ width: 100%; background: none; border: 0; margin-bottom: 2px;
447
593
  font: inherit; color: inherit; text-align: left; cursor: pointer;
448
- border-radius: 8px; padding: 11px 8px; margin: 0 -8px; width: calc(100% + 16px);
594
+ border-radius: var(--bc-r-md); transition: background 160ms;
595
+ animation: bc-rise 260ms var(--bc-ease) both;
449
596
  }
450
597
  .history button.row:hover { background: var(--bc-subtle); }
451
- .history button.row:focus-visible { outline: 2px solid var(--bc-accent); outline-offset: -2px; }
598
+ .history button.row:hover .chev { transform: translateX(2px); color: var(--bc-accent); }
599
+ .history button.row:focus-visible { outline-offset: -2px; }
452
600
 
453
601
  /* ---------- one report, and what happened to it ---------- */
454
602
  .report-head {
455
- display: grid; grid-template-columns: 1fr auto; gap: 2px 10px;
456
- padding: 4px 0 14px; border-bottom: 1px solid var(--bc-border);
603
+ flex: none;
604
+ display: grid; grid-template-columns: 1fr auto; gap: 2px 10px; align-items: center;
605
+ padding: 10px var(--bc-pad); border-bottom: 1px solid var(--bc-border);
606
+ background: var(--bc-bg);
457
607
  }
458
- .report-head .ttl { font-size: 13.5px; font-weight: 600; color: var(--bc-fg); }
459
- .report-head .sub { font-size: 11.5px; color: var(--bc-faint); }
460
- .report-head .pill { grid-row: 1 / span 2; align-self: center; }
608
+ .report-head .ttl { font-size: 13px; font-weight: 620; color: var(--bc-fg); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0; }
609
+ .report-head .sub { font-size: var(--bc-fs-xs); color: var(--bc-faint); }
610
+ .report-head .pill { grid-row: 1 / span 2; grid-column: 2; align-self: center; }
461
611
 
462
612
  /* The thread scrolls; the composer under it does not. Both live inside the
463
613
  panel, which stops scrolling as a whole on this screen — a composer that
464
614
  scrolls away is a composer people think isn't there. */
465
615
  .thread {
466
- display: flex; flex-direction: column; gap: 10px;
467
- padding: 14px 0 8px; overflow-y: auto; overscroll-behavior: contain;
468
- max-height: min(46vh, 330px);
616
+ flex: 1 1 auto; min-height: 140px;
617
+ display: flex; flex-direction: column; gap: 4px;
618
+ padding: 14px var(--bc-pad) 12px; overflow-y: auto; overscroll-behavior: contain;
619
+ }
620
+
621
+ /* The day a run of messages happened on, as a centred label on a rule. */
622
+ .day-sep {
623
+ display: flex; align-items: center; gap: 10px; margin: 10px 0 6px;
624
+ font-size: 11px; font-weight: 620; letter-spacing: .02em; color: var(--bc-faint);
469
625
  }
626
+ .day-sep::before, .day-sep::after { content: ''; flex: 1; height: 1px; background: var(--bc-border); }
470
627
 
471
628
  /* A status change is not a message and is not drawn as one: no side, no
472
629
  bubble, no author. Centred and quiet, the way every chat marks the things
473
630
  that happened rather than the things that were said. */
474
631
  .sys {
475
- align-self: center; max-width: 90%; text-align: center;
476
- font-size: 11.5px; line-height: 1.45; color: var(--bc-faint);
632
+ align-self: center; max-width: 90%; text-align: center; margin: 6px 0;
633
+ padding: 4px 10px; border-radius: 999px; background: var(--bc-subtle);
634
+ font-size: var(--bc-fs-xs); line-height: 1.45; color: var(--bc-muted);
635
+ animation: bc-fade-in 240ms ease both;
477
636
  }
478
637
  .sys .dot {
479
638
  display: inline-block; width: 6px; height: 6px; margin-right: 6px;
480
639
  border-radius: 50%; background: var(--bc-muted); vertical-align: middle;
481
640
  }
641
+ .sys .t { color: var(--bc-faint); }
482
642
  .sys.k-status .dot { background: #4da3ff; }
483
643
  .sys.k-severity .dot { background: #e8912a; }
484
644
  .sys.k-assignment .dot { background: #8b7dff; }
485
645
  .sys.k-filed .dot { background: var(--bc-faint); }
486
- .icon-btn.back { margin-right: 2px; }
487
646
 
488
647
  /* ---------- the conversation ----------
489
648
 
490
649
  A status change and a message are different things and are drawn as such: a
491
650
  change is a line on the rail above, a message is a bubble with a side. The
492
- reporter's own words sit right and accented, the team's left and neutral —
493
- the arrangement every chat has taught people to read without a legend. */
494
- .msgs { display: flex; flex-direction: column; gap: 10px; padding: 4px 0 6px; }
495
- .msg-row { display: flex; flex-direction: column; max-width: 84%; gap: 4px; }
496
- .msg-row.mine { align-self: flex-end; align-items: flex-end; }
497
- .msg-row.theirs { align-self: flex-start; }
498
- .msg-who { font-size: 11px; font-weight: 600; color: var(--bc-faint); padding: 0 2px; }
651
+ reporter's own words sit right and accented, the other side's left beside an
652
+ avatar that says who it is — the arrangement every chat has taught people to
653
+ read without a legend. */
654
+ .msg-row, .typing-row {
655
+ display: grid; grid-template-columns: 28px minmax(0, 1fr); column-gap: 8px;
656
+ max-width: 88%; margin-top: 10px;
657
+ animation: bc-rise 260ms var(--bc-ease) both;
658
+ }
659
+ .msg-row.cont { margin-top: 3px; }
660
+ .msg-row > *, .typing-row > * { grid-column: 2; }
661
+ /* Fixed rows, so the avatar lines up with the bubble whatever else the
662
+ message carries (a name above it, answers or a time below it). */
663
+ .msg-row > .msg-who, .typing-row > .msg-who { grid-row: 1; }
664
+ .msg-row > .bubble, .typing-row > .bubble { grid-row: 2; }
665
+ .msg-row > .quick { grid-row: 3; }
666
+ .msg-row > .msg-when { grid-row: 4; }
667
+ .msg-row > .av, .typing-row > .av { grid-column: 1; grid-row: 2; align-self: end; }
668
+ /* In a run of messages the avatar sits by the last bubble and the time under
669
+ it, the way a chat marks where one turn ends. */
670
+ .msg-row:has(+ .msg-row.cont) > .av { visibility: hidden; }
671
+ .msg-row:has(+ .msg-row.cont) > .msg-when { display: none; }
672
+ .msg-row.theirs, .typing-row { align-self: flex-start; }
673
+ .msg-row.mine { align-self: flex-end; grid-template-columns: minmax(0, 1fr); justify-items: end; }
674
+ .msg-row.mine > * { grid-column: 1; }
675
+ .av {
676
+ display: grid; place-items: center; width: 28px; height: 28px; border-radius: 50%;
677
+ font-size: 11px; font-weight: 700; letter-spacing: .02em;
678
+ background: color-mix(in srgb, var(--bc-fg) 10%, var(--bc-bg)); color: var(--bc-fg);
679
+ }
680
+ .av.bot {
681
+ background: linear-gradient(140deg, var(--bc-accent), color-mix(in srgb, var(--bc-accent) 60%, #fff));
682
+ color: var(--bc-on-accent); font-size: 14px;
683
+ }
684
+ .msg-who { font-size: var(--bc-fs-xs); font-weight: 620; color: var(--bc-muted); padding: 0 4px 4px; }
685
+ .msg-who.auto { color: var(--bc-accent); display: inline-flex; align-items: center; gap: 5px; }
686
+ .msg-who .tag {
687
+ padding: 1px 6px; border-radius: 999px; font-size: 9.5px; font-weight: 700; letter-spacing: .04em;
688
+ text-transform: uppercase; background: var(--bc-accent-soft); color: var(--bc-accent);
689
+ }
499
690
  .bubble {
500
- padding: 8px 11px; border-radius: 12px; font-size: 12.5px; line-height: 1.5;
691
+ justify-self: start; max-width: 100%;
692
+ padding: 9px 13px; border-radius: 18px; font-size: 13.5px; line-height: 1.5;
501
693
  background: var(--bc-subtle); color: var(--bc-fg);
502
694
  border: 1px solid var(--bc-border);
695
+ border-bottom-left-radius: 6px;
503
696
  }
504
697
  /* pre-wrap belongs to the text, not the box — on the box it would also render
505
698
  the markup's own indentation. */
506
699
  .msg-text { display: block; white-space: pre-wrap; overflow-wrap: anywhere; }
507
700
  .msg-row.mine .bubble {
701
+ justify-self: end;
508
702
  background: var(--bc-accent); border-color: var(--bc-accent); color: var(--bc-on-accent);
509
- border-bottom-right-radius: 4px;
510
- }
511
- .msg-row.theirs .bubble { border-bottom-left-radius: 4px; }
512
- /* A reply nobody wrote. Outlined rather than recoloured — it is still the
513
- team's side of the conversation — with the label above carrying the meaning,
514
- so it reads the same to someone who cannot see the border at all. */
515
- .msg-row.auto .bubble { border-style: dashed; }
516
- .msg-who.auto { color: var(--bc-accent); }
703
+ border-bottom-left-radius: 18px; border-bottom-right-radius: 6px;
704
+ }
705
+ .msg-row.cont.theirs .bubble { border-top-left-radius: 6px; }
706
+ .msg-row.cont.mine .bubble { border-top-right-radius: 6px; }
707
+ /* A reply nobody wrote: tinted with the accent and labelled "Assistant" above
708
+ it, so it reads the same to someone who cannot see the colour at all. */
709
+ .msg-row.auto .bubble { background: var(--bc-accent-soft); border-color: var(--bc-accent-line); }
517
710
  /* An attachment-only message has no text to wrap, so the bubble would be an
518
711
  empty coloured box around it. */
519
- .bubble.silent { padding: 0; background: none; border: 0; }
520
- .msg-when { font-size: 10.5px; color: var(--bc-faint); padding: 0 2px; }
521
- .msg-row.pending { opacity: .55; }
712
+ .bubble.silent { padding: 0; background: none !important; border: 0; }
713
+ .msg-when { font-size: 10.5px; color: var(--bc-faint); padding: 4px 4px 0; }
714
+ .msg-row.pending { opacity: .6; }
715
+ .msg-row.pending .msg-when::after { content: ' · Sending…'; }
522
716
  .msg-row.failed .bubble { border: 1px solid var(--bc-danger); }
717
+ .msg-row.failed .msg-when { color: var(--bc-danger); }
718
+ .msg-row.failed .msg-when::after { content: ' · Not sent'; }
719
+
720
+ /* The assistant, thinking. Three dots in a bubble where its next message will be. */
721
+ .typing { display: inline-flex; align-items: center; gap: 4px; padding: 12px 14px; justify-self: start; }
722
+ .typing i {
723
+ width: 7px; height: 7px; border-radius: 50%; background: var(--bc-accent); opacity: .45;
724
+ animation: bc-typing 1.2s ease-in-out infinite;
725
+ }
726
+ .typing i:nth-child(2) { animation-delay: .15s; }
727
+ .typing i:nth-child(3) { animation-delay: .3s; }
728
+ .typing-row .msg-when { padding-top: 4px; }
523
729
 
524
730
  .att { display: flex; flex-direction: column; gap: 6px; margin-top: 6px; }
525
731
  .bubble.silent .att { margin-top: 0; }
526
732
  .att img {
527
- display: block; max-width: 100%; max-height: 190px; border-radius: 9px;
733
+ display: block; max-width: 100%; max-height: 190px; border-radius: var(--bc-r-md);
528
734
  border: 1px solid var(--bc-border); object-fit: cover; cursor: zoom-in;
529
735
  }
530
736
  .att audio { width: 232px; max-width: 100%; height: 34px; }
531
- .att video { max-width: 100%; max-height: 190px; border-radius: 9px; }
737
+ .att video { max-width: 100%; max-height: 190px; border-radius: var(--bc-r-md); }
532
738
  .att .file {
533
739
  display: flex; align-items: center; gap: 8px; text-decoration: none;
534
- padding: 8px 10px; border-radius: 9px; font-size: 12px;
740
+ padding: 8px 10px; border-radius: 10px; font-size: 12px;
535
741
  background: var(--bc-elevated); border: 1px solid var(--bc-border); color: var(--bc-fg);
536
742
  }
537
743
  .att .file:hover { border-color: var(--bc-accent); }
538
744
  .att .file .nm { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
539
745
  .att .file .sz { flex: none; color: var(--bc-faint); font-size: 11px; }
540
746
 
541
- /* The assistant's live card, above the conversation. */
542
- .assistant { margin: 8px 12px 4px; padding: 10px 12px; border-radius: 12px; border: 1px solid var(--bc-border); background: var(--bc-subtle); }
543
- .assistant.analyzing, .assistant.confirming, .assistant.needs_info { border-color: color-mix(in srgb, var(--bc-accent) 45%, transparent); }
544
- .as-top { display: flex; gap: 10px; align-items: flex-start; }
545
- .as-orb { flex: none; width: 26px; height: 26px; border-radius: 50%; display: grid; place-items: center; color: #fff; font-size: 12px; background: var(--bc-accent); }
546
- .as-spin { width: 14px; height: 14px; border-radius: 50%; border: 2px solid rgba(255,255,255,.4); border-top-color: #fff; animation: as-rot .8s linear infinite; }
747
+ /* ---------- the assistant's live card ----------
748
+ A status header pinned between the report and the conversation: where the
749
+ investigation is, as words and as a stepper. It does not scroll with the
750
+ thread, because "is anything happening?" is the question on screen the
751
+ whole time. */
752
+ .assistant {
753
+ flex: none; position: relative; overflow: hidden;
754
+ margin: 10px 12px 0; padding: 12px 14px 12px;
755
+ border-radius: var(--bc-r-lg); border: 1px solid var(--bc-border);
756
+ background: var(--bc-subtle);
757
+ transition: background 400ms ease, border-color 400ms ease;
758
+ }
759
+ .assistant.analyzing, .assistant.confirming, .assistant.needs_info {
760
+ background: var(--bc-accent-soft); border-color: var(--bc-accent-line);
761
+ }
762
+ .assistant.resolved { background: color-mix(in srgb, var(--bc-ok) 9%, var(--bc-bg)); border-color: color-mix(in srgb, var(--bc-ok) 35%, var(--bc-border)); }
763
+ .as-body.entering { animation: bc-rise 360ms var(--bc-ease) both; }
764
+ .as-top { display: flex; gap: 11px; align-items: center; }
765
+ .as-orb {
766
+ flex: none; width: 32px; height: 32px; border-radius: 50%; display: grid; place-items: center;
767
+ color: var(--bc-on-accent); font-size: 15px;
768
+ background: linear-gradient(140deg, var(--bc-accent), color-mix(in srgb, var(--bc-accent) 60%, #fff));
769
+ }
770
+ .assistant.resolved .as-orb { background: var(--bc-ok); }
771
+ .assistant.reviewing .as-orb { background: color-mix(in srgb, var(--bc-fg) 55%, var(--bc-bg)); }
772
+ .as-spin { width: 16px; height: 16px; border-radius: 50%; border: 2px solid rgba(255,255,255,.4); border-top-color: #fff; animation: as-rot .8s linear infinite; }
547
773
  @keyframes as-rot { to { transform: rotate(360deg); } }
548
- .as-title { font-weight: 600; font-size: 14px; }
549
- .assistant.analyzing .as-title::after { content: ''; animation: as-dots 1.4s steps(4) infinite; }
550
- @keyframes as-dots { 0% { content: ''; } 25% { content: '.'; } 50% { content: '..'; } 75% { content: '...'; } }
551
- .as-detail { font-size: 12.5px; color: var(--bc-muted); margin-top: 2px; }
552
- .as-steps { list-style: none; display: flex; gap: 6px; margin: 10px 0 0; padding: 0; flex-wrap: wrap; font-size: 11.5px; color: var(--bc-muted); }
553
- .as-steps li { display: flex; align-items: center; gap: 4px; }
554
- .as-steps li span { width: 8px; height: 8px; border-radius: 50%; border: 1.5px solid currentColor; }
555
- .as-steps li.done { color: var(--bc-accent); }
556
- .as-steps li.done span { background: var(--bc-accent); border-color: var(--bc-accent); }
557
- .as-steps li.active { color: var(--bc-fg); font-weight: 600; }
558
- .as-steps li.active span { border-color: var(--bc-accent); animation: as-pulse 1s ease-in-out infinite; }
774
+ .as-text { min-width: 0; flex: 1; }
775
+ .as-title { font-weight: 650; font-size: 13.5px; letter-spacing: -.01em; color: var(--bc-fg); }
776
+ .as-detail { font-size: 12px; line-height: 1.45; color: var(--bc-muted); margin-top: 2px; }
777
+ .as-progress {
778
+ height: 4px; margin: 12px 0 0; border-radius: 999px; overflow: hidden;
779
+ background: color-mix(in srgb, var(--bc-fg) 9%, transparent);
780
+ }
781
+ .as-progress i {
782
+ display: block; height: 100%; border-radius: inherit; background: var(--bc-accent);
783
+ transition: width 700ms var(--bc-ease);
784
+ }
785
+ .assistant.resolved .as-progress i { background: var(--bc-ok); }
786
+ .assistant.analyzing .as-progress i {
787
+ background: linear-gradient(90deg, var(--bc-accent) 0%, color-mix(in srgb, var(--bc-accent) 45%, #fff) 50%, var(--bc-accent) 100%);
788
+ background-size: 200% 100%; animation: bc-shimmer 1.6s linear infinite;
789
+ }
790
+ .as-steps {
791
+ list-style: none; display: grid; grid-template-columns: repeat(4, 1fr); gap: 4px;
792
+ margin: 8px 0 0; padding: 0; font-size: 10.5px; color: var(--bc-faint);
793
+ }
794
+ .as-steps li { display: flex; align-items: center; gap: 5px; min-width: 0; white-space: nowrap; }
795
+ .as-steps li .lbl { min-width: 0; overflow: hidden; text-overflow: ellipsis; }
796
+ .as-steps li .dot { flex: none; width: 8px; height: 8px; border-radius: 50%; border: 1.5px solid currentColor; }
797
+ .as-steps li.done { color: var(--bc-muted); }
798
+ .as-steps li.done .dot { background: var(--bc-accent); border-color: var(--bc-accent); }
799
+ .assistant.resolved .as-steps li.done .dot { background: var(--bc-ok); border-color: var(--bc-ok); }
800
+ .as-steps li.active { color: var(--bc-fg); font-weight: 650; }
801
+ .as-steps li.active .dot { border-color: var(--bc-accent); background: var(--bc-bg); animation: as-pulse 1.2s ease-in-out infinite; }
559
802
  @keyframes as-pulse { 50% { box-shadow: 0 0 0 4px color-mix(in srgb, var(--bc-accent) 25%, transparent); } }
560
- @media (prefers-reduced-motion: reduce) { .as-spin, .as-steps li.active span, .assistant.analyzing .as-title::after { animation: none; } }
803
+ @media (prefers-reduced-motion: reduce) { .as-spin, .as-steps li.active .dot, .assistant.analyzing .as-progress i, .typing i { animation: none; } }
561
804
 
562
805
  /* Quick answers under the confirm question — only on the latest message. */
563
- .msg-row .quick { display: none; gap: 6px; flex-wrap: wrap; margin-top: 6px; }
806
+ .msg-row .quick { display: none; gap: 6px; flex-wrap: wrap; margin-top: 8px; }
564
807
  .msg-row:last-child .quick { display: flex; }
565
808
  .quick button {
566
- font: inherit; font-size: 13px; padding: 6px 12px; border-radius: 999px; cursor: pointer;
567
- border: 1px solid var(--bc-accent); background: transparent; color: var(--bc-accent);
809
+ display: inline-flex; align-items: center; gap: 6px;
810
+ font: inherit; font-size: 13px; font-weight: 600; padding: 8px 14px; border-radius: 999px; cursor: pointer;
811
+ border: 1px solid var(--bc-accent); background: var(--bc-bg); color: var(--bc-accent);
812
+ transition: background 160ms, color 160ms, transform 160ms var(--bc-ease);
813
+ animation: bc-item-in 300ms var(--bc-ease) both;
568
814
  }
569
- .quick button:hover { background: color-mix(in srgb, var(--bc-accent) 12%, transparent); }
815
+ .quick button:first-child { background: var(--bc-accent); color: var(--bc-on-accent); }
816
+ .quick button:nth-child(2) { animation-delay: 60ms; }
817
+ .quick button svg { font-size: 13px; }
818
+ .quick button:hover { transform: translateY(-1px); background: var(--bc-accent-soft); }
819
+ .quick button:first-child:hover { background: var(--bc-accent); filter: brightness(1.07); }
570
820
 
571
821
  /* ---------- the composer ---------- */
572
822
  .composer {
573
- position: sticky; bottom: 0; margin-top: auto;
574
- padding: 10px 0 2px;
823
+ flex: none; position: relative;
824
+ padding: 10px 12px max(12px, env(safe-area-inset-bottom, 0px));
575
825
  /* The panel's own background, not --bc-elevated: the two are the same white
576
826
  in light mode but differ in dark, where a raised composer reads as a band
577
827
  laid over the panel rather than the foot of it. */
578
828
  background: var(--bc-bg);
579
829
  border-top: 1px solid var(--bc-border);
580
830
  }
581
- .composer .row { display: flex; align-items: flex-end; gap: 8px; }
831
+ /* One rounded field holding the tools, the text and the send button — the
832
+ shape every chat box has, so nobody has to look for where to type. */
833
+ .composer .row {
834
+ display: flex; align-items: flex-end; gap: 4px;
835
+ padding: 5px; border-radius: 22px;
836
+ background: var(--bc-subtle); border: 1px solid var(--bc-border);
837
+ transition: border-color 160ms, box-shadow 160ms;
838
+ }
839
+ .composer .row:focus-within { border-color: var(--bc-accent); box-shadow: var(--bc-ring); }
582
840
  .composer textarea {
583
- flex: 1; min-height: 38px; max-height: 120px; resize: none; padding: 9px 11px;
584
- font: inherit; font-size: 12.5px; line-height: 1.45;
585
- color: var(--bc-fg); background: var(--bc-subtle);
586
- border: 1px solid var(--bc-border); border-radius: 10px;
841
+ flex: 1; min-width: 0; min-height: 34px; max-height: 120px; resize: none; padding: 7px 6px;
842
+ font: inherit; font-size: 13.5px; line-height: 1.45;
843
+ color: var(--bc-fg); background: transparent; border: 0; border-radius: 0;
587
844
  }
588
- .composer textarea:focus { outline: none; border-color: var(--bc-accent); }
589
- .composer .tools { display: flex; gap: 4px; }
845
+ .composer textarea:hover, .composer textarea:focus { border: 0; box-shadow: none; outline: none; }
846
+ .composer .tools { display: flex; gap: 0; grid-template-columns: none; }
590
847
  .composer .tool {
591
- width: 34px; height: 34px; display: grid; place-items: center; cursor: pointer;
592
- border-radius: 9px; border: 1px solid transparent; background: none;
848
+ width: 34px; height: 34px; min-height: 0; padding: 0; display: grid; place-items: center; cursor: pointer;
849
+ border-radius: 50%; border: 0; background: none; font-size: 17px;
593
850
  color: var(--bc-muted);
594
851
  }
595
- .composer .tool:hover { background: var(--bc-subtle); color: var(--bc-fg); }
852
+ .composer .tool svg { font-size: 17px; }
853
+ .composer .tool:hover:not(:disabled) { background: color-mix(in srgb, var(--bc-fg) 8%, transparent); color: var(--bc-fg); border: 0; transform: none; }
854
+ .composer .tool:hover:not(:disabled) svg { color: var(--bc-fg); }
596
855
  .composer .tool:disabled { opacity: .4; cursor: default; }
597
856
  .composer .tool.recording { color: var(--bc-danger); background: color-mix(in srgb, var(--bc-danger) 12%, transparent); }
857
+ .composer .tool.recording svg { color: var(--bc-danger); }
598
858
  .composer .send {
599
- width: 34px; height: 34px; flex: none; border-radius: 9px; cursor: pointer;
600
- background: var(--bc-accent); border: 1px solid var(--bc-accent); color: #fff;
859
+ width: 34px; height: 34px; flex: none; border-radius: 50%; cursor: pointer; font-size: 16px;
860
+ background: var(--bc-accent); border: 0; color: var(--bc-on-accent);
601
861
  display: grid; place-items: center;
862
+ transition: transform 160ms var(--bc-ease), opacity 160ms, filter 160ms;
602
863
  }
603
- .composer .send:disabled { opacity: .4; cursor: default; }
864
+ .composer .send:hover:not(:disabled) { filter: brightness(1.08); transform: scale(1.05); }
865
+ .composer .send:disabled { opacity: .35; cursor: default; background: var(--bc-faint); }
604
866
  .composer .staged { display: flex; flex-wrap: wrap; gap: 6px; padding: 0 0 8px; }
605
867
  .composer .chip {
606
- display: flex; align-items: center; gap: 6px; max-width: 190px;
607
- padding: 5px 7px; border-radius: 8px; font-size: 11.5px;
868
+ display: flex; align-items: center; gap: 6px; max-width: 200px;
869
+ padding: 5px 7px 5px 10px; border-radius: 999px; font-size: var(--bc-fs-xs);
608
870
  background: var(--bc-subtle); border: 1px solid var(--bc-border); color: var(--bc-muted);
871
+ animation: bc-item-in 240ms var(--bc-ease) both;
609
872
  }
610
- .composer .chip .nm { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
873
+ .composer .chip .nm { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: var(--bc-fg); }
611
874
  .composer .chip button {
612
- flex: none; width: 16px; height: 16px; display: grid; place-items: center;
613
- border: 0; border-radius: 4px; background: none; color: var(--bc-faint); cursor: pointer;
875
+ flex: none; width: 18px; height: 18px; display: grid; place-items: center;
876
+ border: 0; border-radius: 50%; background: none; color: var(--bc-faint); cursor: pointer;
614
877
  }
615
878
  .composer .chip button:hover { color: var(--bc-danger); }
616
879
  .composer .chip.uploading { border-style: dashed; }
617
- .composer .note { padding: 6px 2px 0; font-size: 11.5px; color: var(--bc-faint); }
880
+ .composer .note { padding: 6px 6px 0; font-size: var(--bc-fs-xs); color: var(--bc-muted); }
618
881
  .composer .note.err { color: var(--bc-danger); }
619
882
  .reccount { font-variant-numeric: tabular-nums; }
620
883
 
621
884
  /* Status carries the only colour in this list, so it is the thing the eye
622
885
  lands on — which is what someone opening this screen came to check. */
623
886
  .pill {
624
- flex: none; font-size: 10.5px; font-weight: 650; letter-spacing: .03em;
625
- padding: 3px 8px; border-radius: 999px; text-transform: uppercase;
626
- border: 1px solid currentColor;
627
- }
628
- .pill.open { color: #e8912a; }
629
- .pill.in_progress { color: #4da3ff; }
630
- .pill.resolved { color: #35b87f; }
631
- .pill.closed { color: var(--bc-faint); }
887
+ flex: none; display: inline-flex; align-items: center; gap: 5px;
888
+ font-size: 11px; font-weight: 650;
889
+ padding: 3px 9px; border-radius: 999px;
890
+ color: var(--bc-muted); background: var(--bc-subtle);
891
+ }
892
+ .pill::before { content: ''; width: 6px; height: 6px; border-radius: 50%; background: currentColor; }
893
+ .pill.open { color: #c2410c; background: color-mix(in srgb, #f59e0b 14%, var(--bc-bg)); }
894
+ .pill.in_progress { color: #1d6fd1; background: color-mix(in srgb, #3b82f6 14%, var(--bc-bg)); }
895
+ .pill.resolved { color: #0f8a5a; background: color-mix(in srgb, #10b981 14%, var(--bc-bg)); }
896
+ .pill.closed { color: var(--bc-muted); }
897
+ :host(.bc-dark) .pill.open { color: #fbbf24; }
898
+ :host(.bc-dark) .pill.in_progress { color: #7cb8ff; }
899
+ :host(.bc-dark) .pill.resolved { color: #4ade9a; }
900
+ @media (prefers-color-scheme: dark) {
901
+ :host(.bc-auto) .pill.open { color: #fbbf24; }
902
+ :host(.bc-auto) .pill.in_progress { color: #7cb8ff; }
903
+ :host(.bc-auto) .pill.resolved { color: #4ade9a; }
904
+ }
905
+
906
+ /* ---------- does the fix work ---------- */
907
+ .fix-verification {
908
+ flex: none; margin: 10px 12px 0; padding: 12px 14px;
909
+ border-radius: var(--bc-r-lg); border: 1px solid color-mix(in srgb, var(--bc-ok) 35%, var(--bc-border));
910
+ background: color-mix(in srgb, var(--bc-ok) 8%, var(--bc-bg));
911
+ font-size: var(--bc-fs-sm); color: var(--bc-fg);
912
+ animation: bc-rise 280ms var(--bc-ease) both;
913
+ }
914
+ .fix-verification p { margin: 0 0 8px; font-weight: 620; }
915
+ .fix-verification textarea { min-height: 56px; margin-bottom: 8px; font-size: 13px; background: var(--bc-bg); }
916
+ .fix-verification button {
917
+ padding: 7px 13px; font: inherit; font-size: 12.5px; font-weight: 620; border-radius: 999px; cursor: pointer;
918
+ border: 1px solid var(--bc-border); background: var(--bc-bg); color: var(--bc-fg);
919
+ }
920
+ .fix-verification button[data-result="CONFIRMED"] { background: var(--bc-ok); border-color: var(--bc-ok); color: #fff; }
921
+ .fix-verification .feedback-status { margin: 6px 0 0; font-weight: 450; color: var(--bc-danger); font-size: var(--bc-fs-xs); }
922
+ .fix-verification .feedback-status:empty { display: none; }
632
923
 
633
924
  /* A call in progress, in place of the form.
634
925
  ---------------------------------------------------------------------------
635
926
  Deliberately not styled as a chat. Nothing arrives here to read — the
636
927
  conversation is happening out loud — so this is a state, a line of
637
928
  reassurance about the report, and a way to hang up. */
638
- .call { padding: 20px 22px 14px; animation: bc-fade-in 240ms ease both; }
639
- .call-head { display: flex; align-items: center; gap: 8px; margin-bottom: 8px; }
640
- .call-head strong { font-size: 14.5px; font-weight: 650; }
929
+ .call { display: flex; flex-direction: column; padding: 26px 0 0; animation: bc-fade-in 240ms ease both; }
930
+ .call-head, .call-note { padding: 0 var(--bc-pad); }
931
+ .call-head { display: flex; align-items: center; gap: 9px; margin-bottom: 8px; }
932
+ .call-head strong { font-size: 15.5px; font-weight: 680; letter-spacing: -.01em; }
641
933
  .call-dot {
642
- width: 8px; height: 8px; border-radius: 50%; background: var(--bc-accent);
934
+ width: 9px; height: 9px; border-radius: 50%; background: var(--bc-accent);
643
935
  animation: bc-call-pulse 1.6s ease-in-out infinite;
644
936
  }
645
937
  .call-dot.off { background: var(--bc-faint); animation: none; }
646
938
  @keyframes bc-call-pulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.25; } }
647
939
  /* Said while it is still ringing, because that is when somebody is deciding
648
940
  whether it is worth waiting. */
649
- .call-note { margin: 0 0 12px; font-size: 12px; color: var(--bc-muted); line-height: 1.5; }
941
+ .call-note { margin: 0 0 18px; font-size: 13px; color: var(--bc-muted); line-height: 1.55; }
650
942
 
651
943
  /* ---------- the same call, on top of the report it is about ---------- */
652
944
  /* A bar rather than its own screen, unlike the one the composer opens. The
653
945
  thread underneath is exactly what both people are talking about, so taking it
654
946
  off screen would be taking away the only shared reference. */
655
947
  .livecall {
948
+ flex: none;
656
949
  display: flex; align-items: center; gap: 9px;
657
- margin: 12px 0 0; padding: 9px 11px;
658
- border: 1px solid var(--bc-border); border-radius: 10px;
659
- background: var(--bc-subtle); font-size: 12.5px; color: var(--bc-fg);
950
+ margin: 10px 12px 0; padding: 9px 11px;
951
+ border: 1px solid var(--bc-accent-line); border-radius: var(--bc-r-md);
952
+ background: var(--bc-accent-soft); font-size: var(--bc-fs-sm); color: var(--bc-fg);
953
+ animation: bc-rise 240ms var(--bc-ease) both;
660
954
  }
661
955
  .livecall .who { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
662
956
  .livecall .secs { font-variant-numeric: tabular-nums; color: var(--bc-muted); }
663
957
  .livecall .act {
664
- padding: 5px 10px; border-radius: 999px; border: 1px solid var(--bc-border);
665
- background: var(--bc-elevated); color: var(--bc-fg);
666
- font: inherit; font-size: 12px; cursor: pointer;
958
+ padding: 5px 11px; border-radius: 999px; border: 1px solid var(--bc-border);
959
+ background: var(--bc-bg); color: var(--bc-fg);
960
+ font: inherit; font-size: 12px; font-weight: 600; cursor: pointer;
667
961
  }
668
962
  .livecall .act:hover { background: var(--bc-subtle); }
669
963
  .livecall .act.danger { border-color: transparent; background: var(--bc-danger); color: #fff; }
670
- .livecall.over { color: var(--bc-muted); }
964
+ .livecall.over { color: var(--bc-muted); background: var(--bc-subtle); border-color: var(--bc-border); }
671
965
  .call-note code { font-size: 11px; }
672
966
  @media (prefers-reduced-motion: reduce) { .call-dot { animation: none; } }
673
967
 
674
- .done { padding: 34px 24px 38px; text-align: center; animation: bc-fade-in 240ms ease both; }
968
+ /* div.done, not .done: the assistant's stepper marks finished steps li.done,
969
+ and this screen's padding was landing on every one of them. */
970
+ div.done { padding: 44px 26px 44px; text-align: center; animation: bc-fade-in 240ms ease both; }
675
971
  .done .tick {
676
- width: 46px; height: 46px; margin: 0 auto 14px; border-radius: 50%;
677
- display: grid; place-items: center; font-size: 24px;
972
+ width: 56px; height: 56px; margin: 0 auto 16px; border-radius: 50%;
973
+ display: grid; place-items: center; font-size: 26px;
678
974
  background: color-mix(in srgb, var(--bc-ok) 14%, transparent); color: var(--bc-ok);
975
+ box-shadow: 0 0 0 8px color-mix(in srgb, var(--bc-ok) 6%, transparent);
679
976
  animation: bc-pop 420ms var(--bc-ease) both;
680
977
  }
681
- .done h3 { margin: 0 0 5px; font-size: 15.5px; font-weight: 650; }
682
- .done p { margin: 0; font-size: 12.5px; color: var(--bc-muted); }
683
- .done code { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: 12px; }
978
+ .done h3 { margin: 0 0 6px; font-size: 17px; font-weight: 680; letter-spacing: -.015em; }
979
+ .done p { margin: 0; font-size: 13px; line-height: 1.5; color: var(--bc-muted); }
980
+ .done code { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: 12px; padding: 1px 5px; border-radius: 5px; background: var(--bc-subtle); color: var(--bc-fg); }
684
981
  /* The likely wait. Set apart from the reference line above it by a rule rather
685
982
  than by weight: one is bookkeeping and the other is the answer to the
686
983
  question the reporter actually has, and they should not read as one
687
984
  paragraph. */
688
985
  .done .eta {
689
- margin: 12px auto 0;
690
- padding-top: 11px;
691
- border-top: 1px solid var(--bc-line);
986
+ margin: 14px auto 0;
987
+ padding-top: 12px;
988
+ border-top: 1px solid var(--bc-border);
692
989
  max-width: 30ch;
693
990
  line-height: 1.5;
694
991
  }
695
- .done .eta strong { color: var(--bc-ink); font-weight: 600; }
992
+ .done .eta strong { color: var(--bc-fg); font-weight: 620; }
696
993
  /* The same figure on the report the reporter came back to. Sits under the
697
994
  status pill in the header block, muted — it is context, not the headline the
698
995
  status is. */
699
996
  .report-head .eta-line {
700
997
  grid-column: 1 / -1;
701
- font-size: 11.5px;
998
+ font-size: var(--bc-fs-xs);
702
999
  color: var(--bc-muted);
703
1000
  margin-top: 2px;
704
1001
  }
705
1002
 
706
1003
  /* ---------- recording bar ---------- */
707
1004
  .recbar {
708
- position: fixed; left: 50%; bottom: 24px; transform: translateX(-50%);
1005
+ position: fixed; left: 50%; bottom: calc(24px + env(safe-area-inset-bottom, 0px)); transform: translateX(-50%);
709
1006
  z-index: 2147483002;
710
1007
  display: flex; align-items: center; gap: 12px;
711
- padding: 10px 12px 10px 15px; border-radius: 999px;
1008
+ padding: 8px 8px 8px 16px; border-radius: 999px;
712
1009
  background: var(--bc-elevated); color: var(--bc-fg);
713
1010
  border: 1px solid var(--bc-border); box-shadow: var(--bc-shadow);
714
1011
  animation: bc-item-in 300ms var(--bc-ease) both;
715
1012
  }
716
1013
  .recbar .dot { width: 9px; height: 9px; border-radius: 50%; background: var(--bc-danger); animation: bc-pulse 1.4s ease-in-out infinite; }
717
- .recbar .time { font-variant-numeric: tabular-nums; font-size: 13px; font-weight: 600; min-width: 38px; }
1014
+ .recbar .time { font-variant-numeric: tabular-nums; font-size: 13px; font-weight: 650; min-width: 38px; }
718
1015
  .recbar .hint { font-size: 12px; color: var(--bc-muted); }
719
- .recbar button { padding: 7px 13px; font-size: 12.5px; font-weight: 600; border-radius: 999px; cursor: pointer; }
1016
+ .recbar button { height: 34px; padding: 0 14px; font-size: 12.5px; font-weight: 620; border-radius: 999px; cursor: pointer; }
720
1017
  .recbar .stop { background: var(--bc-danger); border: 1px solid var(--bc-danger); color: #fff; }
721
1018
  .recbar .stop:hover { filter: brightness(1.08); }
722
1019
 
723
- @media (max-width: 520px) {
724
- .panel { width: calc(100vw - 24px); max-width: none; }
725
- .scrim.at-right .panel, .scrim.at-left .panel { left: 12px; right: 12px; }
726
- .recbar .hint { display: none; }
727
- }
728
-
729
1020
  /* ---------- phones ----------------------------------------------------------
730
1021
  This widget runs inside a shadow root on somebody else's site, so its own
731
1022
  stylesheet is the whole story: the host page cannot correct any of this, and
@@ -750,6 +1041,32 @@ button.primary .spinner { border-color: rgba(255,255,255,.4); border-top-color:
750
1041
  padding-left: env(safe-area-inset-left, 0px);
751
1042
  }
752
1043
 
1044
+ /* Short desktop windows: the chat height gives way to the space there is. */
1045
+ @media (max-height: 820px) { .panel.is-chat { height: calc(100vh - var(--bc-dock-h, 84px) - 52px); } }
1046
+
1047
+ /* A phone gets the whole screen: a sheet that slides up from the bottom, with
1048
+ the notch and the home indicator kept clear. The dock steps aside while it
1049
+ is open — the sheet has its own close button, and a launcher floating over
1050
+ the send button would be in the way of the one thing that matters. */
1051
+ @media (max-width: 480px) {
1052
+ .scrim { background: rgba(10,12,16,.4); }
1053
+ .panel, .scrim.at-right .panel, .scrim.at-left .panel, .scrim.at-bottom .panel, .scrim.at-top .panel {
1054
+ inset: 0; width: 100%; max-width: none; height: 100%; max-height: none;
1055
+ border-radius: 0; border: 0;
1056
+ animation: bc-sheet-in 380ms var(--bc-ease) both;
1057
+ }
1058
+ @supports (height: 100dvh) { .panel { height: 100dvh; max-height: none; } }
1059
+ .panel.is-chat { height: 100%; }
1060
+ .scrim.closing .panel { animation: bc-sheet-out 200ms ease both; }
1061
+ .head { padding-top: max(14px, env(safe-area-inset-top, 0px)); padding-left: max(var(--bc-pad), env(safe-area-inset-left, 0px)); padding-right: max(12px, env(safe-area-inset-right, 0px)); }
1062
+ .foot, .powered { padding-bottom: max(10px, env(safe-area-inset-bottom, 0px)); }
1063
+ .foot + .powered { padding-bottom: max(9px, env(safe-area-inset-bottom, 0px)); }
1064
+ .foot:has(+ .powered) { padding-bottom: 12px; }
1065
+ .dock.over { display: none; }
1066
+ .recbar .hint { display: none; }
1067
+ .msg-row, .typing-row { max-width: 92%; }
1068
+ }
1069
+
753
1070
  @media (pointer: coarse) {
754
1071
  /* iOS zooms the whole page when a field it focuses is under 16px, and does
755
1072
  not zoom back out. On the host's site that is not the widget's page to
@@ -761,70 +1078,51 @@ button.primary .spinner { border-color: rgba(255,255,255,.4); border-top-color:
761
1078
  /* 44px is the floor a thumb hits reliably. Every control in this form was
762
1079
  under it, on the one surface in the product designed for someone who is
763
1080
  not an operator and gets no second attempt. */
764
- .launcher { min-height: 48px; padding: 14px 20px; }
765
- .seg button { min-height: 44px; padding: 12px 8px; }
766
- .tool { min-height: 44px; padding: 12px 14px; }
767
- button.primary, .foot button { min-height: 44px; padding: 12px 18px; }
1081
+ .seg button { min-height: 44px; }
1082
+ .tool { min-height: 56px; }
1083
+ button.primary, button.ghost { height: 44px; }
1084
+ .composer .send, .composer .tool { width: 40px; height: 40px; min-height: 0; }
768
1085
  textarea { min-height: 104px; }
1086
+ .composer textarea { min-height: 40px; }
769
1087
 
770
- /* The theme switch and the close button are 28px glyphs whose boxes cannot
1088
+ /* The theme switch and the close button are small glyphs whose boxes cannot
771
1089
  grow without moving the header text beside them, so each keeps its size
772
1090
  and gets an invisible target drawn around it instead. */
773
- .themer button, .head .icon-btn, .thumb .x, .brand-credit { position: relative; }
774
- .themer button::after, .head .icon-btn::after, .thumb .x::after, .brand-credit::after {
1091
+ .themer button, .head .icon-btn, .thumb .drop, .brand-credit { position: relative; }
1092
+ .thumb .drop { position: absolute; opacity: 1; }
1093
+ .themer button::after, .head .icon-btn::after, .thumb .drop::after, .brand-credit::after {
775
1094
  content: '';
776
1095
  position: absolute;
777
- inset: -9px;
1096
+ inset: -8px;
778
1097
  }
779
- /* The close button is the one people reach for in a hurry, and it sits in
780
- the corner where a thumb is least accurate. */
781
- .head .icon-btn::after { inset: -12px; }
782
1098
  /* The themer's three buttons sit side by side, so their expanders would
783
1099
  overlap each other without a gap to grow into. */
784
1100
  .themer { gap: 4px; }
785
-
786
- /* Thumb-sized controls make the form taller, which on a short phone pushed
787
- "Send report" below the fold of a panel that scrolls — so the one button
788
- the whole widget exists for was reachable only by scrolling past the
789
- attachment row. It stays on screen instead. */
790
- .foot {
791
- position: sticky;
792
- bottom: 0;
793
- margin-top: 16px;
794
- /* The panel scrolls under this, so the bar cannot be translucent. */
795
- background: var(--bc-subtle);
796
- padding-bottom: max(14px, env(safe-area-inset-bottom, 0px));
797
- }
798
1101
  }
799
1102
 
800
1103
  /* Hover is a lie on a touchscreen: it latches on tap and stays. The launcher's
801
1104
  lift in particular was left applied after the panel closed. */
802
1105
  @media (hover: none) {
803
- .launcher:hover { transform: none; filter: none; box-shadow: 0 6px 18px rgba(10,12,16,.22), 0 1px 3px rgba(10,12,16,.16); }
804
- .tool:hover, .themer button:hover { border-color: var(--bc-border); }
1106
+ .launcher:hover { transform: none; filter: none; }
1107
+ .tool:hover:not(:disabled), .themer button:hover { transform: none; }
805
1108
  }
806
- `;function Ja(t){const e=document.createElement("div");e.setAttribute("data-bugcatch","widget");let n=Ya()||Ga(t.config.theme);e.className=an(n);const a=e.attachShadow({mode:"open"}),i=document.createElement("style");i.textContent=Za(t.config.accent||"#4F46E5"),a.appendChild(i);const r=Gt[t.config.widgetPosition]?t.config.widgetPosition:"bottom-right",s=document.createElement("div");s.className=`dock ${r.includes("right")?"at-right":"at-left"}`+(r.startsWith("top")?" at-top":""),s.style.cssText=Gt[r];const l=document.createElement("div");l.className="themer",l.setAttribute("role","group"),l.setAttribute("aria-label","Report widget theme"),l.innerHTML=tn.map(y=>`<button type="button" data-theme="${y.value}" title="${y.label}" aria-label="${y.label}" aria-pressed="${y.value===n}">${y.icon}</button>`).join(""),l.addEventListener("click",y=>{const h=y.target.closest("button[data-theme]");!h||h.dataset.theme===n||(n=h.dataset.theme,e.className=an(n),Xa(n),l.querySelectorAll("button").forEach(b=>{b.setAttribute("aria-pressed",String(b.dataset.theme===n))}))});const p=document.createElement("button");p.className="launcher",p.type="button",p.innerHTML=`${Q.bug}<span>Report a bug</span>`,p.setAttribute("aria-haspopup","dialog"),p.setAttribute("aria-expanded","false");let f=null;return p.addEventListener("click",()=>{if(f){f.close();return}s.classList.add("over"),p.setAttribute("aria-expanded","true"),f=eo({root:a,host:e,dock:s,client:t,onClose:()=>{f=null,s.classList.remove("over"),p.setAttribute("aria-expanded","false")}})}),s.append(l,p),a.appendChild(s),document.body.appendChild(e),()=>{f==null||f.destroy(),e.remove()}}function Ga(t){return t==="dark"||t==="light"?t:"auto"}function an(t){return t==="dark"?"bc-dark":t==="light"?"bc-light":"bc-auto"}function eo({root:t,host:e,dock:n,client:a,onClose:i}){var In,Mn,Ln,Bn,An,Rn;const r=a.config,s=r.attachments!==!1,l=s&&na(),p=s&&ta(),f=[];let y="MEDIUM",h=null,b=!1;const g=document.createElement("div");g.className=`scrim ${n.classList.contains("at-left")?"at-left":"at-right"} ${n.classList.contains("at-top")?"at-top":"at-bottom"}`,g.style.setProperty("--bc-dock-h",`${Math.round(n.getBoundingClientRect().height)}px`),g.innerHTML=`
1109
+ `;function ka(t){const e=document.createElement("div");e.setAttribute("data-bugcatch","widget");let n=wa()||Sa(t.config.theme);e.className=xn(n);const o=e.attachShadow({mode:"open"}),i=document.createElement("style");i.textContent=xa(t.config.accent||"#4F46E5"),o.appendChild(i);const a=mn[t.config.widgetPosition]?t.config.widgetPosition:"bottom-right",s=document.createElement("div");s.className=`dock ${a.includes("right")?"at-right":"at-left"}`+(a.startsWith("top")?" at-top":""),s.style.cssText=mn[a];const l=document.createElement("div");l.className="themer",l.setAttribute("role","group"),l.setAttribute("aria-label","Report widget theme"),l.innerHTML=wn.map(b=>`<button type="button" data-theme="${b.value}" title="${b.label}" aria-label="${b.label}" aria-pressed="${b.value===n}">${b.icon}</button>`).join(""),l.addEventListener("click",b=>{const f=b.target.closest("button[data-theme]");!f||f.dataset.theme===n||(n=f.dataset.theme,e.className=xn(n),va(n),l.querySelectorAll("button").forEach(m=>{m.setAttribute("aria-pressed",String(m.dataset.theme===n))}))});const p=document.createElement("button");p.className="launcher",p.type="button",p.innerHTML=`<span class="ico" aria-hidden="true"><span class="when-closed">${M.chat}</span><span class="when-open">${M.chevronDown}</span></span><span>Report a bug</span>`,p.setAttribute("aria-haspopup","dialog"),p.setAttribute("aria-expanded","false");let h=null;return p.addEventListener("click",()=>{if(h){h.close();return}s.classList.add("over"),p.setAttribute("aria-expanded","true"),h=$a({root:o,host:e,dock:s,client:t,onClose:()=>{h=null,s.classList.remove("over"),p.setAttribute("aria-expanded","false")}})}),s.append(l,p),o.appendChild(s),document.body.appendChild(e),t.widgetControls={open:()=>{h||p.click()},close:()=>{h==null||h.close()},isOpen:()=>!!h},()=>{h==null||h.destroy(),e.remove(),t.widgetControls=null}}function Sa(t){return t==="dark"||t==="light"?t:"auto"}function xn(t){return t==="dark"?"bc-dark":t==="light"?"bc-light":"bc-auto"}function $a({root:t,host:e,dock:n,client:o,onClose:i}){var Jn,Zn,Gn,eo,to,no;const a=o.config,s=a.attachments!==!1,l=s&&To(),p=s&&Co(),h=[];let b="MEDIUM",f=null,m=!1;const g=document.createElement("div");g.className=`scrim ${n.classList.contains("at-left")?"at-left":"at-right"} ${n.classList.contains("at-top")?"at-top":"at-bottom"}`,g.style.setProperty("--bc-dock-h",`${Math.round(n.getBoundingClientRect().height)}px`),g.innerHTML=`
807
1110
  <div class="panel" role="dialog" aria-modal="true" aria-labelledby="bc-h">
808
- <div class="head">
809
- <div class="mark">${Q.bug}</div>
810
- <div class="titles">
811
- <h2 id="bc-h">Report a bug</h2>
812
- <p>We'll attach what the page was doing, so you don't have to explain it.</p>
813
- </div>
814
- <button class="icon-btn" type="button" data-act="close" aria-label="Close">${Q.close}</button>
815
- </div>
1111
+ ${Bt({id:"bc-h",title:"Tell us what went wrong",sub:"Our assistant starts looking right away. We attach the page details for you."})}
816
1112
  <div class="body">
817
- <div class="slot"></div>
1113
+ <div class="slot" role="alert"></div>
818
1114
  <div class="whoami" hidden></div>
819
1115
  <div class="known" hidden></div>
820
1116
  <div class="compose">
821
1117
  <div class="field">
822
1118
  <label for="bc-title">What went wrong?</label>
823
- <input id="bc-title" type="text" placeholder="Checkout button does nothing" autocomplete="off" />
1119
+ <input id="bc-title" type="text" placeholder="e.g. The checkout button does nothing" autocomplete="off"
1120
+ aria-describedby="bc-title-err" />
1121
+ <p class="field-err" id="bc-title-err" hidden></p>
824
1122
  </div>
825
1123
  <div class="field">
826
- <label for="bc-desc">Any detail that helps <span style="font-weight:450;color:var(--bc-faint)">(optional)</span></label>
827
- <textarea id="bc-desc" placeholder="I clicked Pay and nothing happened."></textarea>
1124
+ <label for="bc-desc">Anything else that helps <span class="opt">(optional)</span></label>
1125
+ <textarea id="bc-desc" placeholder="What you were doing, what you expected, what happened instead."></textarea>
828
1126
  </div>
829
1127
  <!-- Drawn only when this project asks for an identifier and the report
830
1128
  does not already carry one. Between the description and the
@@ -832,207 +1130,240 @@ button.primary .spinner { border-color: rgba(255,255,255,.4); border-top-color:
832
1130
  it is a question about what they just typed. -->
833
1131
  <div class="refs" hidden></div>
834
1132
  <div class="field">
835
- <label id="bc-prio-l">Severity</label>
1133
+ <label id="bc-prio-l">How much is it getting in your way?</label>
836
1134
  <div class="seg" role="group" aria-labelledby="bc-prio-l">
837
- ${en.map(o=>`
838
- <button type="button" data-prio="${o.value}" aria-pressed="${o.value===y}">${o.label}</button>
1135
+ ${yn.map(r=>`
1136
+ <button type="button" data-prio="${r.value}" aria-pressed="${r.value===b}">${r.label}</button>
839
1137
  `).join("")}
840
1138
  </div>
841
1139
  </div>
842
1140
  ${s?`
843
1141
  <div class="field">
844
- <label>Attach <span style="font-weight:450;color:var(--bc-faint)">(optional)</span></label>
845
- <div class="tools">
846
- ${l?`<button class="tool" type="button" data-act="shot">${Q.camera}Screenshot</button>`:""}
847
- ${p?`<button class="tool" type="button" data-act="rec">${Q.video}Record</button>`:""}
848
- <button class="tool" type="button" data-act="file">${Q.paperclip}File</button>
1142
+ <div class="field-head">
1143
+ <label id="bc-att-l">Show us <span class="opt">(optional)</span></label>
1144
+ <span class="count" aria-live="polite"></span>
1145
+ </div>
1146
+ <div class="tools" role="group" aria-labelledby="bc-att-l">
1147
+ ${l?`<button class="tool" type="button" data-act="shot">${M.camera}Screenshot</button>`:""}
1148
+ ${p?`<button class="tool" type="button" data-act="rec">${M.video}Record screen</button>`:""}
1149
+ <button class="tool" type="button" data-act="file">${M.paperclip}Upload file</button>
849
1150
  </div>
850
1151
  <div class="thumbs"></div>
851
- <input type="file" accept="${_e.join(",")}" multiple hidden />
1152
+ <input type="file" accept="${tt.join(",")}" multiple hidden />
852
1153
  </div>`:""}
853
1154
  </div>
854
1155
  </div>
855
1156
  <div class="foot">
856
- <a class="brand-credit" href="https://bugcatch.sphoro.com" target="_blank" rel="noopener noreferrer" aria-label="BugCatch">${Wa}</a>
857
- <span class="note"></span>
1157
+ <span class="note" aria-live="polite"></span>
1158
+ ${o.hasReports()?'<button class="quiet" type="button" data-act="history">Your reports</button>':""}
858
1159
  <span class="spacer"></span>
859
- ${a.hasReports()?'<button class="ghost" type="button" data-act="history">Your reports</button>':""}
860
- <button class="ghost" type="button" data-act="cancel">Cancel</button>
861
1160
  <!-- Hidden until the API confirms this project can take a call, which
862
1161
  most cannot. Drawn here rather than as a second launcher because it
863
1162
  is the same errand as Send report — the difference is only whether
864
1163
  the reporter would rather say it than type it. -->
865
- <button class="ghost" type="button" data-act="call" hidden>Talk to the team</button>
866
- <button class="primary" type="button" data-act="send">Send report</button>
1164
+ <button class="ghost" type="button" data-act="call" hidden>${M.phone}Talk to the team</button>
1165
+ <button class="primary" type="button" data-act="send">Send report ${M.send}</button>
867
1166
  </div>
868
- </div>`;const S=o=>g.querySelector(o),A=S("#bc-title"),ie=S(".slot"),C=S(".thumbs"),$=g.querySelector("input[type=file]"),T=S('[data-act="send"]'),L=S('[data-act="call"]'),X=S(".note"),U=S(".compose"),j=S(".whoami"),V=S(".refs"),E=S(".known"),se=S('[data-act="history"]'),ne=document.createElement("div");ne.setAttribute("role","status"),ne.className="note",U.prepend(ne);const De=da(r,(In=fe(r.projectId))==null?void 0:In.email);let xe=r.drafts===!1,at=!1,ke=Promise.resolve(),K;function ae(){if(clearTimeout(K),!xe||at||r.drafts===!1)return ke;const o=A.value||S("#bc-desc").value||f.length?{title:A.value,description:S("#bc-desc").value,priority:y,items:f.map(({blob:c,mime:u,kind:d})=>({blob:c,mime:u,kind:d}))}:null;return ke=ke.catch(()=>{}).then(()=>Xe(De,o)).then(()=>{ne.textContent=o?"Draft saved on this device":""}).catch(()=>{ne.textContent="Draft could not be saved. Keep this tab open."}),ke}function Le(){clearTimeout(K),K=setTimeout(ae,250)}U.addEventListener("input",Le),U.addEventListener("change",Le);const ot=()=>{ae()};window.addEventListener("pagehide",ot);function Ne(){f.filter(o=>o.status==="failed").forEach(Qe)}window.addEventListener("online",Ne),r.drafts!==!1&&(U.inert=!0,ua(De).then(o=>{Ae||!o||(ne.innerHTML='Unfinished report on this device. <button type="button" data-resume>Resume report</button> <button type="button" data-discard>Discard</button>',ne.querySelector("[data-resume]").onclick=()=>{A.value=o.title||"",S("#bc-desc").value=o.description||"",y=en.some(c=>c.value===o.priority)?o.priority:"MEDIUM",g.querySelectorAll("[data-prio]").forEach(c=>c.setAttribute("aria-pressed",String(c.dataset.prio===y)));for(const c of(o.items||[]).slice(0,r.maxAttachments??5))Ce(c);xe=!0,ae()},ne.querySelector("[data-discard]").onclick=()=>{xe=!0,ae()})}).catch(()=>{ne.textContent="Draft storage is unavailable. Keep this tab open."}).finally(()=>{U.inert=!1,ne.querySelector("[data-resume]")||(xe=!0)}));const me=document.activeElement,Be=document.documentElement.style,St=Be.overflow;Be.overflow="hidden";let Ae=!1,Se=null;function Ue(){var o;Ae||(ae(),Ae=!0,clearTimeout(K),window.removeEventListener("pagehide",ot),window.removeEventListener("online",Ne),h==null||h.cancel(),Se==null||Se(),f.forEach(c=>c.previewUrl&&URL.revokeObjectURL(c.previewUrl)),Be.overflow=St,document.removeEventListener("keydown",Re,!0),g.remove(),(o=t.querySelector(".recbar"))==null||o.remove(),n.hidden=!1,e.style.opacity="",i==null||i())}function ce(){var o;if(!Ae){g.classList.add("closing"),setTimeout(Ue,160);try{(o=me==null?void 0:me.focus)==null||o.call(me)}catch{}}}function Re(o){if(o.key==="Escape"){if(o.stopPropagation(),h){je({keep:!1});return}b||ce();return}if(o.key!=="Tab"||h)return;const c=[...g.querySelectorAll("button:not(:disabled), input:not([hidden]), textarea, select, [href]")].filter(w=>w.offsetParent!==null||w===document.activeElement);if(!c.length)return;const u=c[0],d=c[c.length-1],k=g.getRootNode().activeElement;o.shiftKey&&k===u?(o.preventDefault(),d.focus()):!o.shiftKey&&k===d&&(o.preventDefault(),u.focus())}document.addEventListener("keydown",Re,!0),g.addEventListener("click",o=>{o.target===g&&!b&&ce()}),S('[data-act="close"]').addEventListener("click",ce),S('[data-act="cancel"]').addEventListener("click",ce),g.querySelectorAll("[data-prio]").forEach(o=>{o.addEventListener("click",()=>{y=o.dataset.prio,Le(),g.querySelectorAll("[data-prio]").forEach(c=>{c.setAttribute("aria-pressed",String(c===o))})})});function H(o,c="err"){ie.innerHTML=o?`<div class="msg ${c}">${x(o)}</div>`:""}function de(){const o=f.some(c=>c.status==="uploading");T.disabled=b||o||f.some(c=>c.status==="failed"),X.textContent=o?"Waiting for the upload to finish…":f.some(c=>c.status==="failed")?"Retry or remove failed attachments before sending.":"",g.querySelectorAll(".tool").forEach(c=>{c.disabled=b||f.length>=(r.maxAttachments??5)})}function rt(o){var w;const c=o.el,u=o.kind==="VIDEO"?"Video":"Shot",d=o.kind==="VIDEO"?`<video src="${o.previewUrl}" muted playsinline preload="metadata"></video>`:`<img src="${o.previewUrl}" alt="" />`;let k="";o.status==="uploading"?k=`<div class="veil"><div class="spinner"></div><div class="bar"><i style="width:${Math.round(o.progress*100)}%"></i></div></div>`:o.status==="failed"&&(k=`<div class="veil err"><button type="button" data-act="retry" aria-label="Retry upload">${Q.retry}</button>Failed</div>`),c.innerHTML=`
1167
+ <div class="powered">Powered by
1168
+ <a class="brand-credit" href="https://bugcatch.sphoro.com" target="_blank" rel="noopener noreferrer" aria-label="BugCatch">${ya}</a>
1169
+ </div>
1170
+ </div>`;const T=r=>g.querySelector(r),Q=T("#bc-title"),V=T("#bc-desc"),$=T(".slot"),L=T(".thumbs"),B=g.querySelector("input[type=file]"),j=T('[data-act="send"]'),N=T('[data-act="call"]'),S=T(".note"),U=T(".compose"),q=T(".whoami"),I=T(".refs"),Z=T(".known"),Re=T('[data-act="history"]'),le=document.createElement("div");le.setAttribute("role","status"),le.className="note",U.prepend(le);const je=jo(a,(Jn=ke(a.projectId))==null?void 0:Jn.email);let ze=a.drafts===!1,ft=!1,X=Promise.resolve(),de;function me(){if(clearTimeout(de),!ze||ft||a.drafts===!1)return X;const r=Q.value||V.value||h.length?{title:Q.value,description:V.value,priority:b,items:h.map(({blob:c,mime:u,kind:d})=>({blob:c,mime:u,kind:d}))}:null;return X=X.catch(()=>{}).then(()=>rt(je,r)).then(()=>{le.textContent=r?"Draft saved on this device":""}).catch(()=>{le.textContent="Draft could not be saved. Keep this tab open."}),X}function Ke(){clearTimeout(de),de=setTimeout(me,250)}U.addEventListener("input",Ke),U.addEventListener("change",Ke);const Pe=()=>{me()};window.addEventListener("pagehide",Pe);function _e(){h.filter(r=>r.status==="failed").forEach(Xe)}window.addEventListener("online",_e),a.drafts!==!1&&(U.inert=!0,zo(je).then(r=>{Me||!r||(le.innerHTML='<span>You have an unfinished report on this device.</span> <button type="button" data-resume>Resume report</button> <button type="button" data-discard>Discard</button>',le.querySelector("[data-resume]").onclick=()=>{Q.value=r.title||"",V.value=r.description||"",b=yn.some(c=>c.value===r.priority)?r.priority:"MEDIUM",g.querySelectorAll("[data-prio]").forEach(c=>c.setAttribute("aria-pressed",String(c.dataset.prio===b)));for(const c of(r.items||[]).slice(0,a.maxAttachments??5))y(c);ze=!0,me()},le.querySelector("[data-discard]").onclick=()=>{ze=!0,me()})}).catch(()=>{le.textContent="Draft storage is unavailable. Keep this tab open."}).finally(()=>{U.inert=!1,le.querySelector("[data-resume]")||(ze=!0)}));const Ce=document.activeElement,Ve=document.documentElement.style,Nt=Ve.overflow;Ve.overflow="hidden";let Me=!1,Ae=null;function Fe(){var r;Me||(me(),Me=!0,clearTimeout(de),window.removeEventListener("pagehide",Pe),window.removeEventListener("online",_e),f==null||f.cancel(),Ae==null||Ae(),h.forEach(c=>c.previewUrl&&URL.revokeObjectURL(c.previewUrl)),Ve.overflow=Nt,document.removeEventListener("keydown",We,!0),g.remove(),(r=t.querySelector(".recbar"))==null||r.remove(),n.hidden=!1,e.style.opacity="",i==null||i())}function ue(){var r;if(!Me){g.classList.add("closing"),setTimeout(Fe,160);try{(r=Ce==null?void 0:Ce.focus)==null||r.call(Ce)}catch{}}}function We(r){if(r.key==="Escape"){if(r.stopPropagation(),f){z({keep:!1});return}m||ue();return}if(r.key!=="Tab"||f)return;const c=[...g.querySelectorAll("button:not(:disabled), input:not([hidden]), textarea, select, [href]")].filter(w=>w.offsetParent!==null||w===document.activeElement);if(!c.length)return;const u=c[0],d=c[c.length-1],x=g.getRootNode().activeElement;r.shiftKey&&x===u?(r.preventDefault(),d.focus()):!r.shiftKey&&x===d&&(r.preventDefault(),u.focus())}document.addEventListener("keydown",We,!0),g.addEventListener("click",r=>{r.target===g&&!m&&ue()}),T('[data-act="close"]').addEventListener("click",ue),g.querySelectorAll("[data-prio]").forEach(r=>{r.addEventListener("click",()=>{b=r.dataset.prio,Ke(),g.querySelectorAll("[data-prio]").forEach(c=>{c.setAttribute("aria-pressed",String(c===r))})})});function J(r,c="err"){$.innerHTML=r?`<div class="msg ${c}">${c==="err"?M.alert:""}<span>${v(r)}</span></div>`:""}const gt=T("#bc-title-err");function bt(r){gt.hidden=!r,gt.innerHTML=r?`${M.alert}<span>${v(r)}</span>`:"",Q.classList.toggle("invalid",!!r),Q.setAttribute("aria-invalid",String(!!r))}Q.addEventListener("input",()=>{Q.value.trim()&&bt("")});function pe(){const r=h.some(d=>d.status==="uploading");j.disabled=m||r||h.some(d=>d.status==="failed"),S.textContent=r?"Waiting for the upload to finish…":h.some(d=>d.status==="failed")?"Retry or remove failed attachments before sending.":"";const c=a.maxAttachments??5;g.querySelectorAll(".tool").forEach(d=>{d.disabled=m||h.length>=c});const u=T(".field-head .count");u&&(u.textContent=h.length?`${h.length} of ${c}`:"")}function Ye(r){var w;const c=r.el,u=r.kind==="VIDEO"?"Video":"Shot",d=r.kind==="VIDEO"?`<video src="${r.previewUrl}" muted playsinline preload="metadata"></video>`:`<img src="${r.previewUrl}" alt="" />`;let x="";r.status==="uploading"?x=`<div class="veil"><div class="spinner"></div><div class="bar"><i style="width:${Math.round(r.progress*100)}%"></i></div></div>`:r.status==="failed"&&(x=`<div class="veil err"><button type="button" data-act="retry" aria-label="Retry upload">${M.retry}</button>Failed</div>`),c.innerHTML=`
869
1171
  ${d}
870
- <span class="kind">${u} · ${Me(o.size)}</span>
871
- <button class="drop" type="button" data-act="drop" aria-label="Remove ${u.toLowerCase()}">${Q.close}</button>
872
- ${k}`,c.querySelector('[data-act="drop"]').addEventListener("click",()=>Ct(o)),(w=c.querySelector('[data-act="retry"]'))==null||w.addEventListener("click",()=>Qe(o))}function Ct(o){const c=f.indexOf(o);c>=0&&f.splice(c,1),o.previewUrl&&URL.revokeObjectURL(o.previewUrl),o.el.remove(),ae(),de()}async function Qe(o){o.status="uploading",o.progress=0,rt(o),de();try{const{storageKey:c,mime:u}=await a.uploadAttachment(o.blob,o.mime,d=>{o.progress=d;const k=o.el.querySelector(".bar i");k&&(k.style.width=`${Math.round(d*100)}%`)});o.storageKey=c,o.mime=u,o.status="ready"}catch(c){o.status="failed",H(c.message.replace("[BugCatch] ",""))}rt(o),de()}function Ce({blob:o,mime:c,kind:u}){const d=r.maxAttachmentBytes??26214400;if(o.size>d){H(`That file is ${Me(o.size)} — the limit is ${Me(d)}.`);return}const k=Fe(c||o.type,_e);if(!k){H("Only PNG, JPEG, WebP, WebM and MP4 files can be attached to a report.");return}const w={blob:o,kind:u,mime:k,size:o.size,previewUrl:URL.createObjectURL(o),status:"uploading",progress:0,storageKey:null,el:document.createElement("div")};w.el.className="thumb",f.push(w),C.appendChild(w.el),H(""),ae(),Qe(w)}async function $t(o){e.style.opacity="0",e.style.pointerEvents="none",await new Promise(c=>requestAnimationFrame(()=>requestAnimationFrame(c)));try{return await o()}finally{e.style.opacity="",e.style.pointerEvents=""}}(Mn=g.querySelector('[data-act="shot"]'))==null||Mn.addEventListener("click",async()=>{try{const o=await $t(aa);Ce(o)}catch(o){(o==null?void 0:o.name)!=="NotAllowedError"&&H(`Screenshot failed: ${o.message}`)}}),(Ln=g.querySelector('[data-act="file"]'))==null||Ln.addEventListener("click",()=>$.click()),$==null||$.addEventListener("change",()=>{const o=(r.maxAttachments??5)-f.length;[...$.files].slice(0,Math.max(o,0)).forEach(c=>{Ce({blob:c,mime:c.type,kind:c.type.startsWith("video/")?"VIDEO":"SCREENSHOT"})}),$.value=""}),(Bn=g.querySelector('[data-act="rec"]'))==null||Bn.addEventListener("click",async()=>{const o=r.maxRecordingMs??12e4;let c;try{h=await oa({maxMs:o,onTick:u=>{c&&(c.querySelector(".time").textContent=We(u))},onAutoStop:()=>{h&&je({keep:!0})}})}catch(u){(u==null?void 0:u.name)!=="NotAllowedError"&&H(`Recording failed: ${u.message}`);return}g.style.display="none",n.hidden=!0,c=document.createElement("div"),c.className="recbar",c.innerHTML=`
1172
+ <span class="kind">${u} · ${Be(r.size)}</span>
1173
+ <button class="drop" type="button" data-act="drop" aria-label="Remove ${u.toLowerCase()}">${M.close}</button>
1174
+ ${x}`,c.querySelector('[data-act="drop"]').addEventListener("click",()=>Ut(r)),(w=c.querySelector('[data-act="retry"]'))==null||w.addEventListener("click",()=>Xe(r))}function Ut(r){const c=h.indexOf(r);c>=0&&h.splice(c,1),r.previewUrl&&URL.revokeObjectURL(r.previewUrl),r.el.remove(),me(),pe()}async function Xe(r){r.status="uploading",r.progress=0,Ye(r),pe();try{const{storageKey:c,mime:u}=await o.uploadAttachment(r.blob,r.mime,d=>{r.progress=d;const x=r.el.querySelector(".bar i");x&&(x.style.width=`${Math.round(d*100)}%`)});r.storageKey=c,r.mime=u,r.status="ready"}catch(c){r.status="failed",J(c.message.replace("[BugCatch] ",""))}Ye(r),pe()}function y({blob:r,mime:c,kind:u}){const d=a.maxAttachmentBytes??26214400;if(r.size>d){J(`That file is ${Be(r.size)} — the limit is ${Be(d)}.`);return}const x=nt(c||r.type,tt);if(!x){J("Only PNG, JPEG, WebP, WebM and MP4 files can be attached to a report.");return}const w={blob:r,kind:u,mime:x,size:r.size,previewUrl:URL.createObjectURL(r),status:"uploading",progress:0,storageKey:null,el:document.createElement("div")};w.el.className="thumb",h.push(w),L.appendChild(w.el),J(""),me(),Xe(w)}async function k(r){e.style.opacity="0",e.style.pointerEvents="none",await new Promise(c=>requestAnimationFrame(()=>requestAnimationFrame(c)));try{return await r()}finally{e.style.opacity="",e.style.pointerEvents=""}}(Zn=g.querySelector('[data-act="shot"]'))==null||Zn.addEventListener("click",async()=>{try{const r=await k(Eo);y(r)}catch(r){(r==null?void 0:r.name)!=="NotAllowedError"&&J(`Screenshot failed: ${r.message}`)}}),(Gn=g.querySelector('[data-act="file"]'))==null||Gn.addEventListener("click",()=>B.click()),B==null||B.addEventListener("change",()=>{const r=(a.maxAttachments??5)-h.length;[...B.files].slice(0,Math.max(r,0)).forEach(c=>{y({blob:c,mime:c.type,kind:c.type.startsWith("video/")?"VIDEO":"SCREENSHOT"})}),B.value=""}),(eo=g.querySelector('[data-act="rec"]'))==null||eo.addEventListener("click",async()=>{const r=a.maxRecordingMs??12e4;let c;try{f=await Io({maxMs:r,onTick:u=>{c&&(c.querySelector(".time").textContent=ot(u))},onAutoStop:()=>{f&&z({keep:!0})}})}catch(u){(u==null?void 0:u.name)!=="NotAllowedError"&&J(`Recording failed: ${u.message}`);return}g.style.display="none",n.hidden=!0,c=document.createElement("div"),c.className="recbar",c.innerHTML=`
873
1175
  <span class="dot"></span>
874
1176
  <span class="time">0:00</span>
875
- <span class="hint">Recording — up to ${We(Math.round(o/1e3))}</span>
1177
+ <span class="hint">Recording — up to ${ot(Math.round(r/1e3))}</span>
876
1178
  <button class="stop" type="button">Stop</button>
877
- <button class="ghost" type="button">Discard</button>`,c.querySelector(".stop").addEventListener("click",()=>je({keep:!0})),c.querySelector(".ghost").addEventListener("click",()=>je({keep:!1})),t.appendChild(c),c.querySelector(".stop").focus()});async function je({keep:o}){var u;const c=h;if(c){if(h=null,(u=t.querySelector(".recbar"))==null||u.remove(),g.style.display="",n.hidden=!1,!o){c.cancel(),A.focus();return}try{const d=await c.stop();d.blob.size?Ce(d):H("That recording came back empty — nothing was captured.")}catch(d){H(`Recording failed: ${d.message}`)}A.focus()}}let m={policy:"off",fields:[]},v=null,I="",F="",W=!1,$e=!1;a.referenceFields().then(o=>{m=o}).catch(()=>{});function it(){return m.policy==="off"||!m.fields.length?[]:Pa(m.fields,[A.value,S("#bc-desc").value])}function Ee(){return!v||!I.trim()?[]:[{key:v,value:I.trim().slice(0,120)}]}function ge(){var d,k;if(!v){V.hidden=!0,V.innerHTML="";return}const o=m.fields.find(w=>w.key===v)||m.fields[0],c=m.policy!=="required";V.hidden=!1,V.innerHTML=`
878
- <p class="why">${x(c?"One more thing, so we can find your record — this helps us answer faster.":"We need one of these to look this up.")}</p>
1179
+ <button class="ghost" type="button">Discard</button>`,c.querySelector(".stop").addEventListener("click",()=>z({keep:!0})),c.querySelector(".ghost").addEventListener("click",()=>z({keep:!1})),t.appendChild(c),c.querySelector(".stop").focus()});async function z({keep:r}){var u;const c=f;if(c){if(f=null,(u=t.querySelector(".recbar"))==null||u.remove(),g.style.display="",n.hidden=!1,!r){c.cancel(),Q.focus();return}try{const d=await c.stop();d.blob.size?y(d):J("That recording came back empty — nothing was captured.")}catch(d){J(`Recording failed: ${d.message}`)}Q.focus()}}let O={policy:"off",fields:[]},D=null,ye="",he="",Le=!1,we=!1;o.referenceFields().then(r=>{O=r}).catch(()=>{});function or(){return O.policy==="off"||!O.fields.length?[]:ga(O.fields,[Q.value,V.value])}function Dn(){return!D||!ye.trim()?[]:[{key:D,value:ye.trim().slice(0,120)}]}function Je(){var x,w;if(!D){I.hidden=!0,I.innerHTML="";return}const r=O.fields.find(C=>C.key===D)||O.fields[0],c=O.policy!=="required";I.hidden=!1;const u=O.fields.length>6;I.innerHTML=`
1180
+ <div class="ask-head">
1181
+ <span class="avatar" aria-hidden="true">${M.sparkle}</span>
1182
+ <div>
1183
+ <strong>${c?"One more thing":"We need one detail"}</strong>
1184
+ <p class="why">${v(c?"So we can find your record — this helps us answer faster.":"We need one of these to look this up.")}</p>
1185
+ </div>
1186
+ </div>
1187
+ ${O.fields.length>1&&!u?`
1188
+ <div class="chips" role="group" aria-label="Which detail you are giving">
1189
+ ${O.fields.map(C=>`
1190
+ <button type="button" data-ref-kind="${v(C.key)}" aria-pressed="${C.key===r.key}">${v(C.label)}</button>
1191
+ `).join("")}
1192
+ </div>`:""}
879
1193
  <div class="row">
880
- ${m.fields.length>1?`
1194
+ ${u?`
881
1195
  <select class="ref-kind" aria-label="Which detail you are giving">
882
- ${m.fields.map(w=>`
883
- <option value="${x(w.key)}" ${w.key===o.key?"selected":""}>${x(w.label)}</option>
1196
+ ${O.fields.map(C=>`
1197
+ <option value="${v(C.key)}" ${C.key===r.key?"selected":""}>${v(C.label)}</option>
884
1198
  `).join("")}
885
1199
  </select>`:""}
886
- <input class="ref-value" type="${o.inputMode==="email"?"email":"text"}"
887
- inputmode="${x(o.inputMode==="numeric"||o.inputMode==="tel"?"numeric":"text")}"
888
- value="${x(I)}"
889
- placeholder="${x(o.placeholder||"")}"
890
- aria-label="${x(o.label)}" />
1200
+ <input class="ref-value${he?" invalid":""}" type="${r.inputMode==="email"?"email":"text"}"
1201
+ inputmode="${v(r.inputMode==="numeric"||r.inputMode==="tel"?"numeric":"text")}"
1202
+ value="${v(ye)}"
1203
+ placeholder="${v(r.placeholder||r.label)}"
1204
+ aria-label="${v(r.label)}" ${he?'aria-invalid="true"':""} />
891
1205
  </div>
892
- ${o.hint?`<p class="hint">${x(o.hint)}</p>`:""}
893
- ${F?`<p class="after err">${x(F)}</p>`:""}
894
- ${c?`<button type="button" class="link" data-act="ref-skip">I don't have this</button>`:""}`;const u=V.querySelector(".ref-value");u.addEventListener("input",()=>{I=u.value,F="",$e=!1}),u.addEventListener("keydown",w=>{w.key==="Enter"&&(w.preventDefault(),T.click())}),(d=V.querySelector(".ref-kind"))==null||d.addEventListener("change",w=>{var z;v=w.target.value,F="",ge(),(z=V.querySelector(".ref-value"))==null||z.focus()}),(k=V.querySelector('[data-act="ref-skip"]'))==null||k.addEventListener("click",()=>{W=!0,v=null,I="",F="",$e=!1,ge(),H("")}),u.focus()}function wo(){return m.policy==="off"||!m.fields.length||it().length||Ee().length?!1:!W||m.policy==="required"}T.addEventListener("click",async()=>{const o=A.value;if(!o.trim()){H("Please describe what went wrong."),A.classList.add("invalid"),A.focus(),setTimeout(()=>A.classList.remove("invalid"),500);return}if(wo()){v=v||m.fields[0].key,ge(),H("");return}if(v&&I.trim()){const u=m.fields.find(d=>d.key===v);if(!$e&&u&&!_a(u,I)){F=`That does not look like a ${u.label.toLowerCase()}. Press Send again to use it anyway.`,$e=!0,ge();return}}b=!0,H(""),de();const c=T.innerHTML;T.innerHTML='<span class="spinner"></span>Sending…';try{const u=await a.report({title:o,description:S("#bc-desc").value,priority:y,references:Ee(),attachments:f.filter(d=>d.status==="ready").map(d=>({type:d.kind,storageKey:d.storageKey,mime:d.mime}))});if(u!=null&&u.cancelled){b=!1,T.innerHTML=c,de();return}at=!0,clearTimeout(K),await ke,r.drafts!==!1&&await Xe(De,null).catch(()=>{}),kn(u)}catch(u){b=!1,T.innerHTML=c,H(u.message.replace("[BugCatch] ","")),de(),Z.mode!=="off"&&Mt().catch(()=>{})}}),(An=g.querySelector('[data-act="history"]'))==null||An.addEventListener("click",Cn);let ze=[],st="",Et=null,Ve=null;function bn(){r.knownIssues!==!1&&a.knownIssues().then(o=>{ze=o,Ke()}).catch(()=>{})}let yn=null;function vo(o){if(r.knownIssues===!1)return;clearTimeout(yn),Ve==null||Ve.abort();const c=(o||"").trim();if(c.length<3){bn();return}yn=setTimeout(()=>{Ve=new AbortController,a.matchKnownIssues(c,{signal:Ve.signal}).then(u=>{u.length&&(ze=u,Ke())}).catch(()=>{})},250)}function Ke(){if(!ze.length){E.hidden=!0,E.innerHTML="";return}E.hidden=!1,E.innerHTML=`
1206
+ ${r.hint?`<p class="hint">${v(r.hint)}</p>`:""}
1207
+ ${he?`<p class="field-err" role="alert">${M.alert}<span>${v(he)}</span></p>`:""}
1208
+ ${c?`<button type="button" class="link" data-act="ref-skip">I don't have this — send without it</button>`:""}`,I.querySelectorAll("[data-ref-kind]").forEach(C=>{C.addEventListener("click",()=>{D=C.dataset.refKind,he="",we=!1,Je()})});const d=I.querySelector(".ref-value");d.addEventListener("input",()=>{ye=d.value,he="",we=!1}),d.addEventListener("keydown",C=>{C.key==="Enter"&&(C.preventDefault(),j.click())}),(x=I.querySelector(".ref-kind"))==null||x.addEventListener("change",C=>{var R;D=C.target.value,he="",Je(),(R=I.querySelector(".ref-value"))==null||R.focus()}),(w=I.querySelector('[data-act="ref-skip"]'))==null||w.addEventListener("click",()=>{Le=!0,D=null,ye="",he="",we=!1,Je(),J("")}),d.focus()}function ar(){return O.policy==="off"||!O.fields.length||or().length||Dn().length?!1:!Le||O.policy==="required"}j.addEventListener("click",async()=>{const r=Q.value;if(!r.trim()){bt("Add a few words about what went wrong — a short sentence is plenty."),Q.focus();return}if(ar()){D=D||O.fields[0].key,Je(),J("");return}if(D&&ye.trim()){const u=O.fields.find(d=>d.key===D);if(!we&&u&&!ba(u,ye)){he=`That does not look like a ${u.label.toLowerCase()}. Press Send again to use it anyway.`,we=!0,Je();return}}m=!0,J(""),pe();const c=j.innerHTML;j.innerHTML='<span class="spinner" aria-hidden="true"></span>Sending…';try{const u=await o.report({title:r,description:V.value,priority:b,references:Dn(),attachments:h.filter(d=>d.status==="ready").map(d=>({type:d.kind,storageKey:d.storageKey,mime:d.mime}))});if(u!=null&&u.cancelled){m=!1,j.innerHTML=c,pe();return}ft=!0,clearTimeout(de),await X,a.drafts!==!1&&await rt(je,null).catch(()=>{}),Vn(u)}catch(u){m=!1,j.innerHTML=c,J(u.message.replace("[BugCatch] ","")),pe(),ne.mode!=="off"&&Vt().catch(()=>{})}}),(to=g.querySelector('[data-act="history"]'))==null||to.addEventListener("click",Wn);let Qe=[],mt="",Kt=null,Ze=null;function Nn(){a.knownIssues!==!1&&o.knownIssues().then(r=>{Qe=r,Ge()}).catch(()=>{})}let Un=null;function rr(r){if(a.knownIssues===!1)return;clearTimeout(Un),Ze==null||Ze.abort();const c=(r||"").trim();if(c.length<3){Nn();return}Un=setTimeout(()=>{Ze=new AbortController,o.matchKnownIssues(c,{signal:Ze.signal}).then(u=>{u.length&&(Qe=u,Ge())}).catch(()=>{})},250)}function Ge(){if(!Qe.length){Z.hidden=!0,Z.innerHTML="";return}Z.hidden=!1,Z.innerHTML=`
895
1209
  <p class="known-h">Already reported</p>
896
- ${ze.map(o=>`
897
- <div class="issue ${o.joined?"is-joined":""}">
1210
+ ${Qe.map(r=>`
1211
+ <div class="issue ${r.joined?"is-joined":""}">
898
1212
  <span class="who">
899
- <span class="t">${x(o.title)}</span>
900
- <span class="meta">${x(xo(o))}</span>
1213
+ <span class="t">${v(r.title)}</span>
1214
+ <span class="meta">${v(ir(r))}</span>
901
1215
  </span>
902
- <button class="join" type="button" data-join="${x(o.id)}"
903
- ${o.joined?"disabled":""}>${o.joined?"Following":"Me too"}</button>
1216
+ <button class="join" type="button" data-join="${v(r.id)}"
1217
+ ${r.joined?"disabled":""}>${r.joined?"Following":"Me too"}</button>
904
1218
  </div>
905
- ${Et===o.id?`
1219
+ ${Kt===r.id?`
906
1220
  <div class="ask">
907
1221
  <input type="email" class="join-email" placeholder="you@example.com"
908
1222
  aria-label="Your email, so we can tell you when this is fixed" />
909
- <button class="ghost" type="button" data-join-confirm="${x(o.id)}">Follow</button>
1223
+ <button class="ghost" type="button" data-join-confirm="${v(r.id)}">Follow</button>
910
1224
  </div>`:""}
911
1225
  `).join("")}
912
- ${st?`<p class="err">${x(st)}</p>`:""}`}function xo(o){const c=o.status==="IN_PROGRESS"?"Being worked on now":"Not fixed yet",u=o.affectedCount===0?"":` · ${o.affectedCount} ${o.affectedCount===1?"person has":"people have"} said this is happening to them`;return`${c} · reported ${et(o.since)}${u}`}E.addEventListener("click",async o=>{var w,z,O,q,ee;const c=o.target.closest("[data-join]"),u=o.target.closest("[data-join-confirm]");if(!c&&!u)return;const d=(u||c).getAttribute(u?"data-join-confirm":"data-join");st="";const k=((z=(w=E.querySelector(".join-email"))==null?void 0:w.value)==null?void 0:z.trim())||((O=a.signedInAs())==null?void 0:O.email)||((q=a.config.user)==null?void 0:q.email);if(!k){Et=d,Ke(),(ee=E.querySelector(".join-email"))==null||ee.focus();return}try{const pe=await a.meToo(d,{email:k});Et=null,ze=ze.map(P=>P.id===d?{...P,joined:!0,affectedCount:pe.affectedCount??P.affectedCount}:P),Ke()}catch(pe){st=pe.message.replace("[BugCatch] ",""),Ke()}}),bn(),A.addEventListener("input",()=>vo(A.value));let wn=!1;function vn(){a.callKind().then(o=>{o&&(wn=!0,L.hidden=Tt())}).catch(()=>{})}vn();let Z={mode:a.lastLoginMode||"off",signedIn:null},J="idle",Oe=((Rn=a.config.user)==null?void 0:Rn.email)||"",He="",G=!1,ue="";const Tt=()=>Z.mode==="required"&&!Z.signedIn;function ko(){const o=Tt();U.hidden=o,T.hidden=o,se&&(se.hidden=o),o?L.hidden=!0:wn&&(L.hidden=!1)}function So(){var c;if(Z.mode==="off"){j.hidden=!0,j.innerHTML="";return}j.hidden=!1,j.classList.toggle("asking",J!=="idle");const o=ue?`<div class="after err">${x(ue)}</div>`:"";if(J==="idle"){if(Z.signedIn){j.innerHTML=`<span class="who">Signed in as <strong>${x(Z.signedIn.email)}</strong></span><button type="button" class="link" data-act="signout">Sign out</button>`;return}const u=(c=a.config.user)==null?void 0:c.email;j.innerHTML=`<span class="who">${Z.mode==="required"?"Sign in to report a bug here.":u?`Reporting as <strong>${x(u)}</strong>.`:"Reporting anonymously — sign in and we can tell you what happens next."}</span><button type="button" class="link" data-act="signin">Sign in</button>`;return}if(J==="email"){j.innerHTML=`
1226
+ ${mt?`<p class="err">${v(mt)}</p>`:""}`}function ir(r){const c=r.status==="IN_PROGRESS"?"Being worked on now":"Not fixed yet",u=r.affectedCount===0?"":` · ${r.affectedCount} ${r.affectedCount===1?"person has":"people have"} said this is happening to them`;return`${c} · reported ${lt(r.since)}${u}`}Z.addEventListener("click",async r=>{var w,C,R,F,G;const c=r.target.closest("[data-join]"),u=r.target.closest("[data-join-confirm]");if(!c&&!u)return;const d=(u||c).getAttribute(u?"data-join-confirm":"data-join");mt="";const x=((C=(w=Z.querySelector(".join-email"))==null?void 0:w.value)==null?void 0:C.trim())||((R=o.signedInAs())==null?void 0:R.email)||((F=o.config.user)==null?void 0:F.email);if(!x){Kt=d,Ge(),(G=Z.querySelector(".join-email"))==null||G.focus();return}try{const re=await o.meToo(d,{email:x});Kt=null,Qe=Qe.map(P=>P.id===d?{...P,joined:!0,affectedCount:re.affectedCount??P.affectedCount}:P),Ge()}catch(re){mt=re.message.replace("[BugCatch] ",""),Ge()}}),Nn(),Q.addEventListener("input",()=>rr(Q.value));let Kn=!1;function Pn(){o.callKind().then(r=>{r&&(Kn=!0,N.hidden=Pt())}).catch(()=>{})}Pn();let ne={mode:o.lastLoginMode||"off",signedIn:null},oe="idle",Oe=((no=o.config.user)==null?void 0:no.email)||"",He="",ae=!1,ge="";const Pt=()=>ne.mode==="required"&&!ne.signedIn;function sr(){const r=Pt();U.hidden=r,j.hidden=r,Re&&(Re.hidden=r),r?N.hidden=!0:Kn&&(N.hidden=!1)}function cr(){var c;if(ne.mode==="off"){q.hidden=!0,q.innerHTML="";return}q.hidden=!1,q.classList.toggle("asking",oe!=="idle");const r=ge?`<div class="after err">${v(ge)}</div>`:"";if(oe==="idle"){if(ne.signedIn){q.innerHTML=`<span class="who">Signed in as <strong>${v(ne.signedIn.email)}</strong></span><button type="button" class="link" data-act="signout">Sign out</button>`;return}const u=(c=o.config.user)==null?void 0:c.email;q.innerHTML=`<span class="who">${ne.mode==="required"?"Sign in to report a bug here.":u?`Reporting as <strong>${v(u)}</strong>.`:"Reporting anonymously — sign in and we can tell you what happens next."}</span><button type="button" class="link" data-act="signin">Sign in</button>`;return}if(oe==="email"){q.innerHTML=`
913
1227
  <p class="why">Sign in with any email address — we'll send you a code.
914
- It's how you hear back about this report${Z.mode==="required"?", and this project asks for it":""}.</p>
1228
+ It's how you hear back about this report${ne.mode==="required"?", and this project asks for it":""}.</p>
915
1229
  <div class="row">
916
- <input type="email" data-fld="email" value="${x(Oe)}"
1230
+ <input type="email" data-fld="email" value="${v(Oe)}"
917
1231
  placeholder="you@example.com" autocomplete="email" spellcheck="false"
918
- aria-label="Your email address" ${G?"disabled":""} />
919
- <button type="button" class="tool" data-act="code" ${G?"disabled":""}>
920
- ${G?"Sending…":"Send code"}
1232
+ aria-label="Your email address" ${ae?"disabled":""} />
1233
+ <button type="button" class="primary" data-act="code" ${ae?"disabled":""}>
1234
+ ${ae?"Sending…":"Send code"}
921
1235
  </button>
922
1236
  </div>
923
- ${o}
924
- ${Z.mode==="optional"?'<div class="after"><button type="button" class="link" data-act="skip">Not now</button></div>':""}`;return}j.innerHTML=`
925
- <p class="why">We sent a code to <strong>${x(Oe)}</strong>. It expires in ten minutes.</p>
1237
+ ${r}
1238
+ ${ne.mode==="optional"?'<div class="after"><button type="button" class="link" data-act="skip">Not now</button></div>':""}`;return}q.innerHTML=`
1239
+ <p class="why">We sent a code to <strong>${v(Oe)}</strong>. It expires in ten minutes.</p>
926
1240
  <div class="row">
927
- <input type="text" class="code" data-fld="code" value="${x(He)}"
1241
+ <input type="text" class="code" data-fld="code" value="${v(He)}"
928
1242
  placeholder="123456" inputmode="numeric" autocomplete="one-time-code"
929
- maxlength="8" aria-label="The code we emailed you" ${G?"disabled":""} />
930
- <button type="button" class="tool" data-act="confirm" ${G?"disabled":""}>
931
- ${G?"Checking…":"Sign in"}
1243
+ maxlength="8" aria-label="The code we emailed you" ${ae?"disabled":""} />
1244
+ <button type="button" class="primary" data-act="confirm" ${ae?"disabled":""}>
1245
+ ${ae?"Checking…":"Sign in"}
932
1246
  </button>
933
1247
  </div>
934
- ${o}
1248
+ ${r}
935
1249
  <div class="after">
936
- <button type="button" class="link" data-act="resend" ${G?"disabled":""}>Send it again</button>
937
- <button type="button" class="link" data-act="signin-back" ${G?"disabled":""}>Use another address</button>
938
- </div>`}function le({focus:o=!1}={}){var u;if(So(),ko(),!o||G)return;const c=j.querySelector("[data-fld]");c&&(c.focus(),(u=c.setSelectionRange)==null||u.call(c,c.value.length,c.value.length))}j.addEventListener("input",o=>{const c=o.target.closest("[data-fld]");c&&(c.dataset.fld==="email"?Oe=c.value:He=c.value)}),j.addEventListener("keydown",o=>{o.key!=="Enter"||!o.target.closest("[data-fld]")||(o.preventDefault(),J==="email"?It():xn())});async function It({resent:o=!1}={}){const c=Oe.trim();if(!c){ue="Enter the address to send the code to.",le({focus:!0});return}G=!0,ue="",le();try{await a.signIn(c),Oe=c,o||(He=""),J="code"}catch(u){ue=u.message}finally{G=!1,le({focus:!0})}}async function xn(){const o=He.trim();if(!o){ue="Enter the code we emailed you.",le({focus:!0});return}G=!0,ue="",le();try{const c=await a.confirmSignIn(Oe.trim(),o);Z.signedIn=c,J="idle",He="",H(""),vn()}catch(c){ue=c.message}finally{G=!1,le({focus:J!=="idle"})}}j.addEventListener("click",async o=>{const c=o.target.closest("button[data-act]");if(!c)return;const u=c.dataset.act;if(u==="signin"){J="email",ue="",le({focus:!0});return}if(u==="skip"){J="idle",ue="",le();return}if(u==="signin-back"){J="email",ue="",He="",le({focus:!0});return}if(u==="code"){It();return}if(u==="resend"){It({resent:!0});return}if(u==="confirm"){xn();return}if(u==="signout"){G=!0,le();try{await a.signOut()}finally{Z.signedIn=null,G=!1,J=Z.mode==="required"?"email":"idle",le({focus:J!=="idle"})}}});async function Mt({announce:o=!1}={}){const c=await a.loginState();Z={mode:c.mode,signedIn:c.signedIn},a.lastLoginMode=c.mode,Tt()&&J==="idle"&&(J="email"),Z.signedIn&&(J="idle"),o&&c.signedOutReason&&H(c.signedOutReason,"info"),le()}Mt({announce:!0}).catch(()=>{}),L.addEventListener("click",async()=>{b=!0,H(""),de(),L.disabled=!0,L.innerHTML='<span class="spinner"></span>Ringing…';try{const o=await a.startCall();Co(o)}catch(o){b=!1,L.disabled=!1,L.textContent="Talk to the team",de(),o.filed?kn(o.filed,{callFailed:o.reason||"The call could not be started."}):(H(o.message.replace("[BugCatch] ","")),Z.mode!=="off"&&Mt().catch(()=>{}))}});function Co(o){const c=g.querySelector(".panel"),u=o!=null&&o.bugId?String(o.bugId).slice(0,8):null;c.innerHTML=`
1250
+ <button type="button" class="link" data-act="resend" ${ae?"disabled":""}>Send it again</button>
1251
+ <button type="button" class="link" data-act="signin-back" ${ae?"disabled":""}>Use another address</button>
1252
+ </div>`}function fe({focus:r=!1}={}){var u;if(cr(),sr(),!r||ae)return;const c=q.querySelector("[data-fld]");c&&(c.focus(),(u=c.setSelectionRange)==null||u.call(c,c.value.length,c.value.length))}q.addEventListener("input",r=>{const c=r.target.closest("[data-fld]");c&&(c.dataset.fld==="email"?Oe=c.value:He=c.value)}),q.addEventListener("keydown",r=>{r.key!=="Enter"||!r.target.closest("[data-fld]")||(r.preventDefault(),oe==="email"?_t():_n())});async function _t({resent:r=!1}={}){const c=Oe.trim();if(!c){ge="Enter the address to send the code to.",fe({focus:!0});return}ae=!0,ge="",fe();try{await o.signIn(c),Oe=c,r||(He=""),oe="code"}catch(u){ge=u.message}finally{ae=!1,fe({focus:!0})}}async function _n(){const r=He.trim();if(!r){ge="Enter the code we emailed you.",fe({focus:!0});return}ae=!0,ge="",fe();try{const c=await o.confirmSignIn(Oe.trim(),r);ne.signedIn=c,oe="idle",He="",J(""),Pn()}catch(c){ge=c.message}finally{ae=!1,fe({focus:oe!=="idle"})}}q.addEventListener("click",async r=>{const c=r.target.closest("button[data-act]");if(!c)return;const u=c.dataset.act;if(u==="signin"){oe="email",ge="",fe({focus:!0});return}if(u==="skip"){oe="idle",ge="",fe();return}if(u==="signin-back"){oe="email",ge="",He="",fe({focus:!0});return}if(u==="code"){_t();return}if(u==="resend"){_t({resent:!0});return}if(u==="confirm"){_n();return}if(u==="signout"){ae=!0,fe();try{await o.signOut()}finally{ne.signedIn=null,ae=!1,oe=ne.mode==="required"?"email":"idle",fe({focus:oe!=="idle"})}}});async function Vt({announce:r=!1}={}){const c=await o.loginState();ne={mode:c.mode,signedIn:c.signedIn},o.lastLoginMode=c.mode,Pt()&&oe==="idle"&&(oe="email"),ne.signedIn&&(oe="idle"),r&&c.signedOutReason&&J(c.signedOutReason,"info"),fe()}Vt({announce:!0}).catch(()=>{}),N.addEventListener("click",async()=>{m=!0,J(""),pe(),N.disabled=!0,N.innerHTML='<span class="spinner"></span>Ringing…';try{const r=await o.startCall();lr(r)}catch(r){m=!1,N.disabled=!1,N.innerHTML=`${M.phone}Talk to the team`,pe(),r.filed?Vn(r.filed,{callFailed:r.reason||"The call could not be started."}):(J(r.message.replace("[BugCatch] ","")),ne.mode!=="off"&&Vt().catch(()=>{}))}});function lr(r){const c=g.querySelector(".panel"),u=r!=null&&r.bugId?String(r.bugId).slice(0,8):null;c.innerHTML=`
939
1253
  <div class="call">
940
1254
  <div class="call-head">
941
1255
  <span class="call-dot" aria-hidden="true"></span>
942
1256
  <strong class="call-state">Ringing…</strong>
943
1257
  </div>
944
1258
  <p class="call-note">
945
- We're ringing the team now. Someone will pick up if they're free — your report${u?` <code>${x(u)}</code>`:""} is already filed either way, so nothing is lost if nobody answers.
1259
+ We're ringing the team now. Someone will pick up if they're free — your report${u?` <code>${v(u)}</code>`:""} is already filed either way, so nothing is lost if nobody answers.
946
1260
  </p>
947
1261
  <div class="foot">
948
1262
  <span class="spacer"></span>
949
1263
  <button class="primary" type="button" data-act="hangup">Cancel</button>
950
1264
  </div>
951
- </div>`;const d=c.querySelector(".call-state"),k=c.querySelector(".call-dot"),w={ringing:"Ringing the team…",connecting:"Someone answered — connecting…",connected:"Connected",missed:"Nobody was free",ended:"Call ended",failed:"The call dropped"},z=["ended","failed","missed"],O=a.on("call",({state:q})=>{if(d.textContent=w[q]||q,k.classList.toggle("off",z.includes(q)),z.includes(q)&&(c.querySelector('[data-act="hangup"]').textContent="Close",q==="missed")){const ee=c.querySelector(".call-note");ee&&(ee.textContent="Nobody was free to pick up just now. Your report is filed and the team will reply in the chat.")}});c.querySelector('[data-act="hangup"]').addEventListener("click",()=>{O(),a.endCall(),ce()})}function kn(o,{callFailed:c=null}={}){if(o!=null&&o.id&&!c){Lt(o.id,{fresh:!0}).then(u=>{u||Sn(o,{callFailed:c})});return}Sn(o,{callFailed:c})}function Sn(o,{callFailed:c=null}={}){var w;const u=o!=null&&o.id?String(o.id).slice(0,8):null,d=(w=o==null?void 0:o.estimate)!=null&&w.label?String(o.estimate.label):null,k=c?`<p class="eta">${x(c)} Your report is filed, and the team will reply in the chat.</p>`:"";g.querySelector(".panel").innerHTML=`
1265
+ </div>`;const d=c.querySelector(".call-state"),x=c.querySelector(".call-dot"),w={ringing:"Ringing the team…",connecting:"Someone answered — connecting…",connected:"Connected",missed:"Nobody was free",ended:"Call ended",failed:"The call dropped"},C=["ended","failed","missed"],R=o.on("call",({state:F})=>{if(d.textContent=w[F]||F,x.classList.toggle("off",C.includes(F)),C.includes(F)&&(c.querySelector('[data-act="hangup"]').textContent="Close",F==="missed")){const G=c.querySelector(".call-note");G&&(G.textContent="Nobody was free to pick up just now. Your report is filed and the team will reply in the chat.")}});c.querySelector('[data-act="hangup"]').addEventListener("click",()=>{R(),o.endCall(),ue()})}function Vn(r,{callFailed:c=null}={}){if(r!=null&&r.id&&!c){Ft(r.id,{fresh:!0}).then(u=>{u||Fn(r,{callFailed:c})});return}Fn(r,{callFailed:c})}function Fn(r,{callFailed:c=null}={}){var w;const u=r!=null&&r.id?String(r.id).slice(0,8):null,d=(w=r==null?void 0:r.estimate)!=null&&w.label?String(r.estimate.label):null,x=c?`<p class="eta">${v(c)} Your report is filed, and the team will reply in the chat.</p>`:"";g.querySelector(".panel").innerHTML=`
952
1266
  <div class="done">
953
- <div class="tick">${Q.check}</div>
1267
+ <div class="tick">${M.check}</div>
954
1268
  <h3>Thanks — that's on its way.</h3>
955
- <p>${u?`Filed as <code>${x(u)}</code>.`:"The team has what they need to reproduce it."}</p>
956
- ${k}
957
- ${d?`<p class="eta">Reports like this usually take <strong>${x(d)}</strong>. We'll let you know when it moves.</p>`:""}
958
- </div>`,setTimeout(ce,k?6e3:d?4e3:2e3)}async function Cn(){const o=g.querySelector(".panel");o.innerHTML=`
959
- <div class="head">
960
- <div class="mark">${Q.bug}</div>
961
- <div class="titles">
962
- <h2>Your reports</h2>
963
- <p>Everything you've reported, and where each one got to.</p>
964
- </div>
965
- <button class="icon-btn" type="button" data-act="close" aria-label="Close">${Q.close}</button>
966
- </div>
967
- <div class="history"><div class="empty">Loading…</div></div>`,o.querySelector('[data-act="close"]').addEventListener("click",ce);let c=[];try{({reports:c}=await a.myReports())}catch{o.querySelector(".history").innerHTML=`<div class="empty">Couldn't load your reports just now.</div>`;return}const u=o.querySelector(".history");if(u){u.innerHTML=c.length?c.map(d=>`
968
- <button class="row" type="button" data-report="${x(d.id)}">
1269
+ <p>${u?`Filed as <code>${v(u)}</code>.`:"The team has what they need to reproduce it."}</p>
1270
+ ${x}
1271
+ ${d?`<p class="eta">Reports like this usually take <strong>${v(d)}</strong>. We'll let you know when it moves.</p>`:""}
1272
+ </div>`,setTimeout(ue,x?6e3:d?4e3:2e3)}async function Wn(){const r=g.querySelector(".panel");clearTimeout(yt),$e=null,r.classList.remove("is-chat"),r.innerHTML=`
1273
+ ${Bt({title:"Your reports",sub:"Everything you've reported, and where each one got to."})}
1274
+ <div class="history" aria-busy="true">${Ia(3)}</div>`,r.querySelector('[data-act="close"]').addEventListener("click",ue);let c=[];try{({reports:c}=await o.myReports())}catch{const d=r.querySelector(".history");d&&(d.innerHTML=Rt("Couldn't load your reports just now.",M.alert));return}const u=r.querySelector(".history");if(u){u.removeAttribute("aria-busy"),u.innerHTML=c.length?c.map((d,x)=>`
1275
+ <button class="row" type="button" data-report="${v(d.id)}" style="animation-delay:${Math.min(x,8)*30}ms">
1276
+ <span class="row-ico" aria-hidden="true">${M.chat}</span>
969
1277
  <span class="who">
970
- <span class="ttl">${x(d.title)}</span>
971
- <span class="sub">${x(d.reference)} · ${x(et(d.createdAt))}</span>
1278
+ <span class="ttl">${v(d.title)}</span>
1279
+ <span class="sub">${v(d.reference)} · ${v(lt(d.createdAt))}</span>
972
1280
  </span>
973
- <span class="pill ${x(String(d.status).toLowerCase())}">${x(vt(d.status))}</span>
974
- </button>`).join(""):`<div class="empty">You haven't reported anything yet.</div>`;for(const d of u.querySelectorAll("[data-report]"))d.addEventListener("click",()=>Lt(d.dataset.report))}}async function Lt(o,{fresh:c=!1}={}){var z;const u=g.querySelector(".panel");u.innerHTML=`
975
- <div class="head">
976
- <button class="icon-btn back" type="button" data-act="back" aria-label="Back to your reports">${Q.back}</button>
977
- <div class="titles">
978
- <h2>${c?"Looking into it":"Your report"}</h2>
979
- <p>${c?"Our assistant is investigating — it may ask you a question.":"Everything that has happened, and a way to answer."}</p>
980
- </div>
981
- <button class="icon-btn" type="button" data-act="close" aria-label="Close">${Q.close}</button>
982
- </div>
983
- <div class="history"><div class="empty">Loading…</div></div>`,u.querySelector('[data-act="close"]').addEventListener("click",ce),u.querySelector('[data-act="back"]').addEventListener("click",Cn);let d=null;try{d=await a.myReport(o)}catch{d=null}const k=u.querySelector(".history");if(!k||!u.querySelector('[data-act="back"]'))return!1;if(!d)return c||(k.innerHTML=`<div class="empty">Couldn't load that report just now.</div>`),!1;be=o,a.markReportRead(o),k.classList.add("chatting"),k.innerHTML=`
1281
+ <span class="pill ${v(String(d.status).toLowerCase())}">${v(zt(d.status))}</span>
1282
+ <span class="chev" aria-hidden="true">${M.chevronRight}</span>
1283
+ </button>`).join(""):Rt("You haven't reported anything yet.",M.inbox);for(const d of u.querySelectorAll("[data-report]"))d.addEventListener("click",()=>Ft(d.dataset.report))}}async function Ft(r,{fresh:c=!1}={}){var R;const u=g.querySelector(".panel");clearTimeout(yt),u.classList.add("is-chat"),u.innerHTML=`
1284
+ ${Bt({back:!0,title:c?"Looking into it":"Your report",sub:c?"Our assistant is on it — it may ask you a question here.":"Everything that has happened, and a way to answer."})}
1285
+ <div class="history chatting" aria-busy="true"><div class="thread">${Ma()}</div></div>`,u.querySelector('[data-act="close"]').addEventListener("click",ue),u.querySelector('[data-act="back"]').addEventListener("click",Wn);let d=null;try{d=await o.myReport(r)}catch{d=null}const x=u.querySelector(".history");if(!x||!u.querySelector('[data-act="back"]'))return!1;if(!d)return c?(u.classList.remove("is-chat"),!1):(x.removeAttribute("aria-busy"),x.innerHTML=Rt("Couldn't load that report just now.",M.alert),!1);$e=r,o.markReportRead(r);const w=kn(d.timeline);x.classList.add("chatting"),x.removeAttribute("aria-busy"),x.innerHTML=`
984
1286
  <div class="report-head">
985
- <span class="ttl">${x(d.title)}</span>
986
- <span class="sub">${x(d.reference)} · ${x(d.project||"")}</span>
987
- <span class="pill ${x(String(d.status).toLowerCase())}">${x(vt(d.status))}</span>
988
- ${(z=d.estimate)!=null&&z.label?`<span class="eta-line">Usually takes ${x(String(d.estimate.label))}</span>`:""}
1287
+ <span class="ttl">${v(d.title)}</span>
1288
+ <span class="sub">${v(d.reference)} · ${v(d.project||"")}</span>
1289
+ <span class="pill ${v(String(d.status).toLowerCase())}">${v(zt(d.status))}</span>
1290
+ ${(R=d.estimate)!=null&&R.label?`<span class="eta-line">Usually takes ${v(String(d.estimate.label))}</span>`:""}
989
1291
  </div>
990
- <div class="thread">${on(d.timeline)}</div>`;const w=k.querySelector(".thread");return wt(w),Tn(k,d),d.canReply&&$o(k,w,o),En(k,d,o),!0}let $n=null;function En(o,c,u){var w,z,O;clearTimeout($n);const d=c.assistant;if((w=o.querySelector(".assistant"))==null||w.remove(),!d)return;const k=document.createElement("div");k.className=`assistant ${x(d.phase)}`,k.setAttribute("role","status"),k.setAttribute("aria-live","polite"),k.innerHTML=`
991
- <div class="as-top">
992
- <span class="as-orb" aria-hidden="true">${d.phase==="analyzing"?'<span class="as-spin"></span>':"✦"}</span>
993
- <div class="as-text">
994
- <div class="as-title">${x(d.title)}</div>
995
- <div class="as-detail">${x(d.detail)}</div>
1292
+ <div class="thread" role="log" aria-live="polite" aria-label="Conversation">${w}</div>`;const C=x.querySelector(".thread");return jt.set(C,w),Ne(C),Xn(x,d),d.canReply&&dr(x,C,r),Yn(x,d,r),Ne(C),!0}let yt=null;function Yn(r,c,u){var _,ee,xe;clearTimeout(yt);const d=c.assistant,x=r.querySelector(".thread");let w=r.querySelector(".assistant");if(!d){w==null||w.remove(),(_=x==null?void 0:x.querySelector(".typing-row"))==null||_.remove();return}const C=(w==null?void 0:w.dataset.phase)||null;w||(w=document.createElement("div"),w.setAttribute("role","status"),w.setAttribute("aria-live","polite"),(ee=r.querySelector(".report-head"))==null||ee.after(w)),w.className=`assistant ${v(d.phase)}`,w.dataset.phase=d.phase;const R=d.steps||[],F=R.filter(te=>te.state==="done").length,G=R.some(te=>te.state==="active")?.5:0,re=R.length?Math.round((F+G)/R.length*100):0,P=`
1293
+ <div class="as-body${C&&C!==d.phase?" entering":""}">
1294
+ <div class="as-top">
1295
+ <span class="as-orb" aria-hidden="true">${d.phase==="analyzing"?'<span class="as-spin"></span>':d.phase==="resolved"?M.check:M.sparkle}</span>
1296
+ <div class="as-text">
1297
+ <div class="as-title">${v(d.title)}</div>
1298
+ <div class="as-detail">${v(d.detail)}</div>
1299
+ </div>
996
1300
  </div>
997
1301
  </div>
998
- <ol class="as-steps">${(d.steps||[]).map(q=>`<li class="${x(q.state)}"><span></span>${x(q.label)}</li>`).join("")}</ol>`,(z=o.querySelector(".report-head"))==null||z.after(k),d.phase==="analyzing"?$n=setTimeout(()=>ct(u),3e3):d.phase==="needs_info"&&((O=o.querySelector(".composer textarea"))==null||O.focus())}function Tn(o,c){var d,k;if((d=o.querySelector(".fix-verification"))==null||d.remove(),!c.resolvedAt||!["RESOLVED","CLOSED"].includes(c.status))return;const u=document.createElement("div");u.className="fix-verification",c.verification?u.textContent=c.verification==="CONFIRMED"?"You confirmed that this fix works.":"Your feedback was recorded.":(u.innerHTML='<p>Does the fix work for you?</p><textarea maxlength="4000" aria-label="Fix feedback" placeholder="What happens when you try again? (optional)"></textarea><button type="button" data-result="CONFIRMED">It works now</button> <button type="button" data-result="STILL_HAPPENING">Still happening</button><p class="feedback-status" role="status"></p>',u.querySelectorAll("[data-result]").forEach(w=>{w.onclick=async()=>{u.querySelectorAll("button").forEach(z=>{z.disabled=!0});try{await a.verifyFix(c.id,{result:w.dataset.result,resolvedAt:c.resolvedAt,note:u.querySelector("textarea").value}),await Lt(c.id)}catch(z){u.querySelector(".feedback-status").textContent=z.message,u.querySelectorAll("button").forEach(O=>{O.disabled=!1})}}})),(k=o.querySelector(".report-head"))==null||k.after(u)}async function ct(o){const c=g.querySelector(".history.chatting"),u=c==null?void 0:c.querySelector(".thread");if(!u||be!==o)return;let d=null;try{d=await a.myReport(o)}catch{}if(!d||be!==o)return;Tn(c,d),En(c,d,o);const k=ao(u);u.innerHTML=on(d.timeline),k&&wt(u);const w=c.querySelector(".report-head .pill");w&&(w.className=`pill ${String(d.status).toLowerCase()}`,w.textContent=vt(d.status))}function $o(o,c,u){const d=document.createElement("div");d.className="composer",d.innerHTML=`
1302
+ ${R.length?`
1303
+ <div class="as-progress" role="progressbar" aria-label="Progress" aria-valuemin="0" aria-valuemax="100" aria-valuenow="${re}"><i style="width:${re}%"></i></div>
1304
+ <ol class="as-steps">${R.map(te=>`<li class="${v(te.state)}"${te.state==="active"?' aria-current="step"':""}><span class="dot"></span><span class="lbl">${v(te.label)}</span></li>`).join("")}</ol>`:""}`,ve=JSON.stringify([d.phase,d.title,d.detail,R]);if(w.dataset.key!==ve){const te=w.querySelector(".as-progress i"),ie=te==null?void 0:te.style.width;w.innerHTML=P,w.dataset.key=ve;const A=w.querySelector(".as-progress i");A&&ie&&(A.style.width=ie,requestAnimationFrame(()=>{A.style.width=`${re}%`}))}if(x){const te=Cn(x),ie=x.querySelector(".typing-row");d.phase!=="analyzing"?ie==null||ie.remove():(!ie||ie!==x.lastElementChild)&&(ie==null||ie.remove(),x.insertAdjacentHTML("beforeend",Ea()),te&&Ne(x))}d.phase==="analyzing"?yt=setTimeout(()=>wt(u),3e3):d.phase==="needs_info"&&C!=="needs_info"&&((xe=r.querySelector(".composer textarea"))==null||xe.focus())}function Xn(r,c){var d,x;if((d=r.querySelector(".fix-verification"))==null||d.remove(),!c.resolvedAt||!["RESOLVED","CLOSED"].includes(c.status))return;const u=document.createElement("div");u.className="fix-verification",c.verification?u.textContent=c.verification==="CONFIRMED"?"You confirmed that this fix works.":"Your feedback was recorded.":(u.innerHTML='<p>Does the fix work for you?</p><textarea maxlength="4000" aria-label="Fix feedback" placeholder="What happens when you try again? (optional)"></textarea><button type="button" data-result="CONFIRMED">It works now</button> <button type="button" data-result="STILL_HAPPENING">Still happening</button><p class="feedback-status" role="status"></p>',u.querySelectorAll("[data-result]").forEach(w=>{w.onclick=async()=>{u.querySelectorAll("button").forEach(C=>{C.disabled=!0});try{await o.verifyFix(c.id,{result:w.dataset.result,resolvedAt:c.resolvedAt,note:u.querySelector("textarea").value}),await Ft(c.id)}catch(C){u.querySelector(".feedback-status").textContent=C.message,u.querySelectorAll("button").forEach(R=>{R.disabled=!1})}}})),(x=r.querySelector(".report-head"))==null||x.after(u)}async function wt(r){const c=g.querySelector(".history.chatting"),u=c==null?void 0:c.querySelector(".thread");if(!u||$e!==r)return;let d=null;try{d=await o.myReport(r)}catch{}if(!d||$e!==r)return;Xn(c,d);const x=Cn(u),w=kn(d.timeline);jt.get(u)!==w&&(u.innerHTML=w,jt.set(u,w)),Yn(c,d,r),x&&Ne(u);const C=c.querySelector(".report-head .pill");C&&(C.className=`pill ${String(d.status).toLowerCase()}`,C.textContent=zt(d.status))}function dr(r,c,u){const d=document.createElement("div");d.className="composer",d.innerHTML=`
999
1305
  <div class="staged" hidden></div>
1000
1306
  <div class="row">
1001
1307
  <div class="tools">
1002
- <button class="tool" type="button" data-act="attach" title="Attach a file" aria-label="Attach a file">${Q.paperclip}</button>
1003
- <button class="tool" type="button" data-act="voice" title="Record a voice note" aria-label="Record a voice note">${Q.mic}</button>
1004
- <button class="tool" type="button" data-act="livecall" title="Call the team" aria-label="Call the team" hidden>${Q.phone}</button>
1308
+ <button class="tool" type="button" data-act="attach" title="Attach a file" aria-label="Attach a file">${M.paperclip}</button>
1309
+ <button class="tool" type="button" data-act="voice" title="Record a voice note" aria-label="Record a voice note">${M.mic}</button>
1310
+ <button class="tool" type="button" data-act="livecall" title="Call the team" aria-label="Call the team" hidden>${M.phone}</button>
1005
1311
  </div>
1006
1312
  <textarea rows="1" placeholder="Write a reply…" aria-label="Write a reply"></textarea>
1007
- <button class="send" type="button" data-act="send" title="Send" aria-label="Send" disabled>${Q.send}</button>
1313
+ <button class="send" type="button" data-act="send" title="Send" aria-label="Send" disabled>${M.send}</button>
1008
1314
  </div>
1009
1315
  <div class="note" hidden></div>
1010
- <input type="file" hidden multiple accept="${Nt.join(",")}">`,o.appendChild(d);const k=d.querySelector(".staged"),w=d.querySelector("textarea"),z=d.querySelector('[data-act="send"]'),O=d.querySelector('[data-act="voice"]'),q=d.querySelector('[data-act="livecall"]'),ee=d.querySelector("input[type=file]"),pe=d.querySelector(".note"),P=[];let Te=null,Y=!1;function oe(M,R=""){pe.hidden=!M,pe.className=`note ${R}`,pe.textContent=M||""}function Ie(){const M=P.filter(R=>R.storageKey);z.disabled=Y||!w.value.trim()&&!M.length,k.hidden=!P.length,k.innerHTML=P.map((R,he)=>`
1011
- <span class="chip ${R.storageKey?"":"uploading"}">
1012
- <span class="nm">${x(R.name)}</span>
1013
- <span class="sz">${R.storageKey?Me(R.size):"sending…"}</span>
1014
- <button type="button" data-drop="${he}" aria-label="Remove ${x(R.name)}">${Q.close}</button>
1015
- </span>`).join("");for(const R of k.querySelectorAll("[data-drop]"))R.addEventListener("click",()=>{P.splice(Number(R.dataset.drop),1),Ie()})}async function Qn(M,R,he){const D={name:he,size:M.size,storageKey:null};P.push(D),Ie();try{const{storageKey:At,mime:To}=await a.uploadAttachment(M,R);D.storageKey=At,D.mime=To}catch(At){P.splice(P.indexOf(D),1),oe(At.message||"That file could not be sent.","err")}Ie()}w.addEventListener("input",()=>{w.style.height="auto",w.style.height=`${Math.min(w.scrollHeight,120)}px`,Ie()}),w.addEventListener("keydown",M=>{M.key==="Enter"&&!M.shiftKey&&!M.isComposing&&(M.preventDefault(),Bt())}),d.querySelector('[data-act="attach"]').addEventListener("click",()=>ee.click()),ee.addEventListener("change",()=>{oe("");for(const M of ee.files){if(M.size>a.config.maxAttachmentBytes){oe(`${M.name} is larger than ${Me(a.config.maxAttachmentBytes)}.`,"err");continue}Qn(M,M.type,M.name)}ee.value=""}),ea()||(O.disabled=!0,O.title="This browser cannot record audio"),O.addEventListener("click",async()=>{if(Te){const M=Te;Te=null,O.classList.remove("recording"),O.innerHTML=Q.mic,oe("");const{blob:R,mime:he}=await M.stop();R.size&&Qn(R,he,"Voice note");return}try{oe(""),Te=await ra({maxMs:a.config.maxRecordingMs,onTick:M=>oe(`Recording — ${We(M)}. Tap the mic to stop.`),onAutoStop:()=>O.click()}),O.classList.add("recording"),O.innerHTML=Q.stopSquare}catch{Te=null,oe("The microphone is not available — check the browser permission.","err")}}),a.canCallTeam(u).then(M=>{M&&(q.hidden=!1)}).catch(()=>{}),q.addEventListener("click",async()=>{q.disabled=!0,oe("");try{const M=await a.startLiveCall(u);Eo(o,c,M)}catch(M){oe(M.message.replace("[BugCatch] ",""),"err")}finally{q.disabled=!1}}),z.addEventListener("click",Bt),c.addEventListener("click",M=>{var he,D;const R=(D=(he=M.target).closest)==null?void 0:D.call(he,"[data-quick]");!R||Y||(w.value=R.dataset.quick,Bt())});async function Bt(){var he;const M=w.value.trim(),R=P.filter(D=>D.storageKey);if(!(Y||!M&&!R.length)){Y=!0,Ie(),oe(""),c.insertAdjacentHTML("beforeend",rn({from:"reporter",body:M,at:new Date().toISOString(),attachments:R.map(D=>({type:"FILE",name:D.name,size:D.size}))},"pending")),wt(c);try{await Pt({apiBase:a.config.apiBase,bugId:u,body:M,attachments:R.map(D=>({storageKey:D.storageKey,mime:D.mime,name:D.name,size:D.size}))}),w.value="",w.style.height="auto",P.length=0,await ct(u)}catch(D){(he=c.querySelector(".msg-row.pending"))==null||he.classList.replace("pending","failed"),oe(D.message||"That could not be sent — try again.","err")}finally{Y=!1,Ie()}}}Ie()}function Eo(o,c,u){const d=document.createElement("div");d.className="livecall",d.innerHTML=`
1316
+ <input type="file" hidden multiple accept="${an.join(",")}">`,r.appendChild(d);const x=d.querySelector(".staged"),w=d.querySelector("textarea"),C=d.querySelector('[data-act="send"]'),R=d.querySelector('[data-act="voice"]'),F=d.querySelector('[data-act="livecall"]'),G=d.querySelector("input[type=file]"),re=d.querySelector(".note"),P=[];let ve=null,_=!1;function ee(A,K=""){re.hidden=!A,re.className=`note ${K}`,re.textContent=A||""}function xe(){const A=P.filter(K=>K.storageKey);C.disabled=_||!w.value.trim()&&!A.length,x.hidden=!P.length,x.innerHTML=P.map((K,be)=>`
1317
+ <span class="chip ${K.storageKey?"":"uploading"}">
1318
+ <span class="nm">${v(K.name)}</span>
1319
+ <span class="sz">${K.storageKey?Be(K.size):"sending…"}</span>
1320
+ <button type="button" data-drop="${be}" aria-label="Remove ${v(K.name)}">${M.close}</button>
1321
+ </span>`).join("");for(const K of x.querySelectorAll("[data-drop]"))K.addEventListener("click",()=>{P.splice(Number(K.dataset.drop),1),xe()})}async function te(A,K,be){const W={name:be,size:A.size,storageKey:null};P.push(W),xe();try{const{storageKey:Wt,mime:pr}=await o.uploadAttachment(A,K);W.storageKey=Wt,W.mime=pr}catch(Wt){P.splice(P.indexOf(W),1),ee(Wt.message||"That file could not be sent.","err")}xe()}w.addEventListener("input",()=>{w.style.height="auto",w.style.height=`${Math.min(w.scrollHeight,120)}px`,xe()}),w.addEventListener("keydown",A=>{A.key==="Enter"&&!A.shiftKey&&!A.isComposing&&(A.preventDefault(),ie())}),d.querySelector('[data-act="attach"]').addEventListener("click",()=>G.click()),G.addEventListener("change",()=>{ee("");for(const A of G.files){if(A.size>o.config.maxAttachmentBytes){ee(`${A.name} is larger than ${Be(o.config.maxAttachmentBytes)}.`,"err");continue}te(A,A.type,A.name)}G.value=""}),$o()||(R.disabled=!0,R.title="This browser cannot record audio"),R.addEventListener("click",async()=>{if(ve){const A=ve;ve=null,R.classList.remove("recording"),R.innerHTML=M.mic,ee("");const{blob:K,mime:be}=await A.stop();K.size&&te(K,be,"Voice note");return}try{ee(""),ve=await Mo({maxMs:o.config.maxRecordingMs,onTick:A=>ee(`Recording — ${ot(A)}. Tap the mic to stop.`),onAutoStop:()=>R.click()}),R.classList.add("recording"),R.innerHTML=M.stopSquare}catch{ve=null,ee("The microphone is not available — check the browser permission.","err")}}),o.canCallTeam(u).then(A=>{A&&(F.hidden=!1)}).catch(()=>{}),F.addEventListener("click",async()=>{F.disabled=!0,ee("");try{const A=await o.startLiveCall(u);ur(r,c,A)}catch(A){ee(A.message.replace("[BugCatch] ",""),"err")}finally{F.disabled=!1}}),C.addEventListener("click",ie),c.addEventListener("click",A=>{var be,W;const K=(W=(be=A.target).closest)==null?void 0:W.call(be,"[data-quick]");!K||_||(w.value=K.dataset.quick,ie())});async function ie(){var be;const A=w.value.trim(),K=P.filter(W=>W.storageKey);if(!(_||!A&&!K.length)){_=!0,xe(),ee(""),c.insertAdjacentHTML("beforeend",Sn({from:"reporter",body:A,at:new Date().toISOString(),attachments:K.map(W=>({type:"FILE",name:W.name,size:W.size}))},"pending")),Ne(c,{smooth:!0});try{await ln({apiBase:o.config.apiBase,bugId:u,body:A,attachments:K.map(W=>({storageKey:W.storageKey,mime:W.mime,name:W.name,size:W.size}))}),w.value="",w.style.height="auto",P.length=0,await wt(u)}catch(W){(be=c.querySelector(".msg-row.pending"))==null||be.classList.replace("pending","failed"),ee(W.message||"That could not be sent — try again.","err")}finally{_=!1,xe()}}}xe()}function ur(r,c,u){const d=document.createElement("div");d.className="livecall",d.innerHTML=`
1016
1322
  <span class="call-dot" aria-hidden="true"></span>
1017
1323
  <span class="who" role="status" aria-live="polite">Calling the team…</span>
1018
1324
  <span class="secs" hidden></span>
1019
1325
  <button class="act" type="button" data-act="mute" hidden>Mute</button>
1020
- <button class="act danger" type="button" data-act="hangup">Cancel</button>`,o.insertBefore(d,c);const k=d.querySelector(".who"),w=d.querySelector(".secs"),z=d.querySelector(".call-dot"),O=d.querySelector('[data-act="mute"]'),q=d.querySelector('[data-act="hangup"]');let ee=null;const pe=()=>{ee&&(clearInterval(ee),ee=null)},P=Y=>{pe(),z.classList.add("off"),d.classList.add("over"),k.textContent=Y,w.hidden=!0,O.hidden=!0,q.textContent="Dismiss",q.classList.remove("danger")},Te=a.on("call",({state:Y})=>{if(Y==="ringing"&&(k.textContent="Calling the team…"),Y==="connecting"&&(k.textContent="Someone answered — connecting…"),Y==="connected"){k.textContent="You're on a call with the team",O.hidden=!1,w.hidden=!1;const oe=Date.now();pe(),ee=setInterval(()=>{w.textContent=We(Math.floor((Date.now()-oe)/1e3))},1e3),w.textContent="0s"}Y==="missed"&&P("Nobody was free. Send a message instead and the team will pick it up."),Y==="ended"&&P("Call ended."),Y==="failed"&&P("The call dropped.")});O.addEventListener("click",()=>{const Y=u.setMuted(!u.isMuted());O.textContent=Y?"Unmute":"Mute",k.textContent=Y?"You're muted":"You're on a call with the team"}),q.addEventListener("click",()=>{Te(),pe(),a.endCall(),d.remove(),ct(be)})}let be=null;return Se=a.on("update",o=>{!be||(o==null?void 0:o.bugId)!==be||(a.markReportRead(be),ct(be))}),t.appendChild(g),de(),A.focus(),{destroy:Ue,close:ce}}function on(t){const e=t||[];return e.length?e.map(n=>{var a,i,r,s;return n.from?rn({from:n.from,author:(a=n.reply)==null?void 0:a.author,automated:(i=n.reply)==null?void 0:i.automated,body:(r=n.reply)==null?void 0:r.body,at:n.at,attachments:(s=n.reply)==null?void 0:s.attachments}):to(n)}).join(""):""}function to(t){return`
1021
- <div class="sys k-${x(t.kind)}">
1022
- <span class="dot" aria-hidden="true"></span>${x(t.summary||"")}
1023
- · ${x(et(t.at))}
1024
- </div>`}function rn(t,e=""){const n=t.from==="reporter",a=t.body||"",i=t.attachments||[],r=!n&&!!t.automated,s=a?`<span class="msg-text">${x(a)}</span>`:"",l=i.length?`<div class="att">${i.map(no).join("")}</div>`:"";let p="";r?p='<span class="msg-who auto">Automatic reply</span>':!n&&t.author&&(p=`<span class="msg-who">${x(t.author)}</span>`);const f=r&&/reply "yes" or "no"/i.test(a)?`<div class="quick" role="group" aria-label="Answer">
1025
- <button type="button" data-quick="Yes, this is the problem">Yes, that's it</button>
1326
+ <button class="act danger" type="button" data-act="hangup">Cancel</button>`,r.insertBefore(d,c);const x=d.querySelector(".who"),w=d.querySelector(".secs"),C=d.querySelector(".call-dot"),R=d.querySelector('[data-act="mute"]'),F=d.querySelector('[data-act="hangup"]');let G=null;const re=()=>{G&&(clearInterval(G),G=null)},P=_=>{re(),C.classList.add("off"),d.classList.add("over"),x.textContent=_,w.hidden=!0,R.hidden=!0,F.textContent="Dismiss",F.classList.remove("danger")},ve=o.on("call",({state:_})=>{if(_==="ringing"&&(x.textContent="Calling the team…"),_==="connecting"&&(x.textContent="Someone answered — connecting…"),_==="connected"){x.textContent="You're on a call with the team",R.hidden=!1,w.hidden=!1;const ee=Date.now();re(),G=setInterval(()=>{w.textContent=ot(Math.floor((Date.now()-ee)/1e3))},1e3),w.textContent="0s"}_==="missed"&&P("Nobody was free. Send a message instead and the team will pick it up."),_==="ended"&&P("Call ended."),_==="failed"&&P("The call dropped.")});R.addEventListener("click",()=>{const _=u.setMuted(!u.isMuted());R.textContent=_?"Unmute":"Mute",x.textContent=_?"You're muted":"You're on a call with the team"}),F.addEventListener("click",()=>{ve(),re(),o.endCall(),d.remove(),wt($e)})}let $e=null;return Ae=o.on("update",r=>{!$e||(r==null?void 0:r.bugId)!==$e||(o.markReportRead($e),wt($e))}),t.appendChild(g),pe(),Q.focus(),{destroy:Fe,close:ue}}function kn(t){const e=t||[];if(!e.length)return"";let n=null,o=null;return e.map(i=>{var b,f,m,g;const a=De(i.at),s=a&&a!==n?`<div class="day-sep" role="separator">${v(La(i.at))}</div>`:"";if(s&&(n=a,o=null),!i.from)return o=null,s+Ta(i);const l={from:i.from,author:(b=i.reply)==null?void 0:b.author,automated:(f=i.reply)==null?void 0:f.automated,body:(m=i.reply)==null?void 0:m.body,at:i.at,attachments:(g=i.reply)==null?void 0:g.attachments},p=Ca(l),h=o&&o.who===p&&Math.abs(new Date(i.at).getTime()-new Date(o.at).getTime())<5*6e4;return o={who:p,at:i.at},s+Sn(l,h?"cont":"")}).join("")}function Ca(t){return t.from==="reporter"?"me":t.automated?"assistant":`team:${t.author||""}`}function Ta(t){const e=$n(t.at);return`
1327
+ <div class="sys k-${v(t.kind)}">
1328
+ <span class="dot" aria-hidden="true"></span>${v(t.summary||"")}${e?`
1329
+ <span class="t">· ${v(e)}</span>`:""}
1330
+ </div>`}function Sn(t,e=""){const n=t.from==="reporter",o=t.body||"",i=t.attachments||[],a=!n&&!!t.automated,s=o?`<span class="msg-text">${v(o)}</span>`:"",l=i.length?`<div class="att">${i.map(Ba).join("")}</div>`:"";let p="",h="";if(a)p='<span class="msg-who auto">Assistant <span class="tag">AI</span></span>',h=`<span class="av bot" aria-hidden="true">${M.sparkle}</span>`;else if(!n){const f=t.author||"Support team";p=`<span class="msg-who">${v(f)}</span>`,h=`<span class="av" aria-hidden="true">${v(Aa(f))}</span>`}e.includes("cont")&&(p="");const b=a&&/reply "yes" or "no"/i.test(o)?`<div class="quick" role="group" aria-label="Answer">
1331
+ <button type="button" data-quick="Yes, this is the problem">${M.check}Yes, that's it</button>
1026
1332
  <button type="button" data-quick="No, that is not the problem">No, it's something else</button>
1027
1333
  </div>`:"";return`
1028
- <div class="msg-row ${n?"mine":"theirs"} ${r?"auto":""} ${e}">
1334
+ <div class="msg-row ${n?"mine":"theirs"} ${a?"auto":""} ${e}">
1335
+ ${h}
1029
1336
  ${p}
1030
- <div class="bubble ${a?"":"silent"}">${s}${l}</div>
1031
- ${f}
1032
- <span class="msg-when">${x(et(t.at))}</span>
1033
- </div>`}function no(t){const e=x(t.name||"attachment");if(!t.url)return`<span class="file"><span class="nm">${e}</span></span>`;const n=x(t.url);return t.type==="SCREENSHOT"?`<a href="${n}" target="_blank" rel="noopener noreferrer"><img src="${n}" alt="${e}" loading="lazy"></a>`:t.type==="AUDIO"?`<audio controls preload="metadata" src="${n}"></audio>`:t.type==="VIDEO"?`<video controls preload="metadata" src="${n}"></video>`:`
1337
+ <div class="bubble ${o?"":"silent"}">${s}${l}</div>
1338
+ ${b}
1339
+ <span class="msg-when">${v($n(t.at)||lt(t.at))}</span>
1340
+ </div>`}function Ea(){return`
1341
+ <div class="typing-row">
1342
+ <span class="av bot" aria-hidden="true">${M.sparkle}</span>
1343
+ <span class="msg-who auto">Assistant <span class="tag">AI</span></span>
1344
+ <div class="bubble typing" role="img" aria-label="The assistant is working on it"><i></i><i></i><i></i></div>
1345
+ </div>`}function Bt({title:t,sub:e,id:n="",back:o=!1}){return`
1346
+ <div class="head">
1347
+ ${o?`<button class="icon-btn back" type="button" data-act="back" aria-label="Back to your reports">${M.back}</button>`:""}
1348
+ <div class="mark" aria-hidden="true">${M.sparkle}</div>
1349
+ <div class="titles">
1350
+ <h2${n?` id="${n}"`:""}>${v(t)}</h2>
1351
+ <p>${v(e)}</p>
1352
+ </div>
1353
+ <button class="icon-btn" type="button" data-act="close" aria-label="Close">${M.close}</button>
1354
+ </div>`}function Rt(t,e){return`<div class="empty"><span class="empty-ico" aria-hidden="true">${e}</span>${v(t)}</div>`}function Ia(t){return Array.from({length:t},()=>`
1355
+ <div class="row" aria-hidden="true">
1356
+ <span class="row-ico"></span>
1357
+ <span class="who"><span class="skel" style="width:70%"></span><span class="skel" style="width:40%;height:9px"></span></span>
1358
+ </div>`).join("")+'<span class="sr-only">Loading…</span>'}function Ma(){return`
1359
+ <div aria-hidden="true" style="display:flex;flex-direction:column;gap:10px;padding-top:6px">
1360
+ <span class="skel" style="width:42%;height:34px;border-radius:16px;align-self:center"></span>
1361
+ <span class="skel" style="width:66%;height:52px;border-radius:18px"></span>
1362
+ <span class="skel" style="width:48%;height:38px;border-radius:18px;align-self:flex-end"></span>
1363
+ </div>
1364
+ <span class="sr-only">Loading…</span>`}const jt=new WeakMap;function Aa(t){const e=String(t).trim().split(/\s+/).filter(Boolean);return e.length?(e[0][0]+(e.length>1?e[e.length-1][0]:"")).toUpperCase():"?"}function De(t){const e=new Date(t);return Number.isFinite(e.getTime())?`${e.getFullYear()}-${e.getMonth()}-${e.getDate()}`:null}function La(t){const e=new Date(t),n=new Date,o=new Date(n.getFullYear(),n.getMonth(),n.getDate()-1);if(De(e)===De(n))return"Today";if(De(e)===De(o))return"Yesterday";try{return e.toLocaleDateString(void 0,{weekday:"short",day:"numeric",month:"short",...e.getFullYear()!==n.getFullYear()?{year:"numeric"}:{}})}catch{return lt(t)}}function $n(t){const e=new Date(t);if(!Number.isFinite(e.getTime()))return"";try{return e.toLocaleTimeString(void 0,{hour:"numeric",minute:"2-digit"})}catch{return""}}function Ba(t){const e=v(t.name||"attachment");if(!t.url)return`<span class="file"><span class="nm">${e}</span></span>`;const n=v(t.url);return t.type==="SCREENSHOT"?`<a href="${n}" target="_blank" rel="noopener noreferrer"><img src="${n}" alt="${e}" loading="lazy"></a>`:t.type==="AUDIO"?`<audio controls preload="metadata" src="${n}"></audio>`:t.type==="VIDEO"?`<video controls preload="metadata" src="${n}"></video>`:`
1034
1365
  <a class="file" href="${n}" target="_blank" rel="noopener noreferrer" download>
1035
1366
  <span class="nm">${e}</span>
1036
- ${t.size?`<span class="sz">${x(Me(t.size))}</span>`:""}
1037
- </a>`}function ao(t){return t.scrollHeight-t.scrollTop-t.clientHeight<40}function wt(t){t.scrollTop=t.scrollHeight}function vt(t){return{OPEN:"Open",IN_PROGRESS:"In progress",RESOLVED:"Fixed",CLOSED:"Closed"}[t]||String(t||"").toLowerCase()}function et(t){const e=new Date(t).getTime();if(!Number.isFinite(e))return"";const n=Math.floor((Date.now()-e)/864e5);if(n<=0)return"today";if(n===1)return"yesterday";if(n<30)return`${n} days ago`;const a=Math.floor(n/30);return a===1?"a month ago":`${a} months ago`}function x(t){return String(t).replace(/[&<>"']/g,e=>({"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#39;"})[e])}const sn=8e3;function oo(t=sn){const e=window.AudioContext||window.webkitAudioContext;try{return new e({sampleRate:t})}catch{return new e}}async function ro(t){if(t.state==="suspended")try{await t.resume()}catch{}}function io(t,e,n){const a=e/n,i=new Float32Array(Math.floor(t.length/a));for(let r=0;r<i.length;r++){const s=Math.floor(r*a),l=Math.min(Math.floor((r+1)*a),t.length);let p=0;for(let f=s;f<l;f++)p+=t[f];i[r]=l>s?p/(l-s):0}return i}const so=132,cn=32635;function co(t){const e=new Uint8Array(t.length);for(let n=0;n<t.length;n++){const a=Math.max(-1,Math.min(1,t[n]));let i=Math.round(a*32767);const r=i<0?128:0;r&&(i=-i),i>cn&&(i=cn),i+=so;let s=7;for(let p=16384;!(i&p)&&s>0;s--,p>>=1);const l=i>>s+3&15;e[n]=~(r|s<<4|l)&255}return e}const lo=512;function uo(t,e,n,a=sn){const i=t.createMediaStreamSource(e),r=t.createScriptProcessor(lo,1,1);r.onaudioprocess=l=>{const p=l.inputBuffer.getChannelData(0),f=t.sampleRate===a?p:io(p,t.sampleRate,a);n(co(f))},i.connect(r);const s=t.createGain();return s.gain.value=0,r.connect(s),s.connect(t.destination),{stop(){r.onaudioprocess=null;try{i.disconnect()}catch{}try{r.disconnect()}catch{}try{s.disconnect()}catch{}}}}const po="voiceai.realtime.v1",ho=[{urls:"stun:stun.l.google.com:19302"}];function xt(){return navigator.mediaDevices.getUserMedia({audio:{echoCancellation:!0,noiseSuppression:!0,autoGainControl:!0,channelCount:1}})}function kt(){var t;return typeof window<"u"&&typeof window.RTCPeerConnection=="function"&&!!((t=navigator.mediaDevices)!=null&&t.getUserMedia)}async function ln({realtimeUrl:t,stream:e,ringsUntil:n,onState:a,onAudioBlocked:i,onMicrophone:r}){const s=(m,v)=>{try{a==null||a(m,v)}catch{}},l=m=>{try{i==null||i(m)}catch{}},p=m=>{try{r==null||r(m)}catch{}};if(!kt()){const m=new Error("[BugCatch] this browser cannot make live calls.");throw s("failed",{reason:"unsupported"}),m}let f=e;if(!f)try{f=await xt()}catch(m){throw s("failed",{reason:"microphone",error:String((m==null?void 0:m.name)||m)}),m}let y;try{y=await fo(t)}catch(m){throw un(f),s("failed",{reason:"connect"}),m}let h=null,b=null,g=!1,S=null,A=null,ie=null,C=!1,$=null,T=null,L=!1;const X=[];let U=!1,j=!1,V=!1,E=null,se=null,ne=0;const De=2e3,xe=5e3,at=3e4,ke=4,K=(m,v)=>{if(!g){g=!0,S&&(clearTimeout(S),S=null),ce(),T==null||T(),T=null,ot(),$==null||$(),$=null;try{h==null||h.close()}catch{}un(f),b&&(b.srcObject=null,b.remove(),b=null);try{y.readyState===WebSocket.OPEN&&y.close(1e3,"call over")}catch{}s(m,v)}},ae=m=>{y.readyState===WebSocket.OPEN&&y.send(JSON.stringify(m))},Le=async()=>{if(L||ie||g||!A||!A.audio&&!A.transcript)return;L=!0;const m=A.encoding||"mulaw";if(m!=="mulaw"){dn(`this call is kept as ${m}, which this SDK cannot produce.`);return}const v=Number(A.sample_rate)||8e3;try{const I=oo(v);if(await ro(I),g){try{I.close()}catch{}return}const F=uo(I,f,W=>{y.readyState===WebSocket.OPEN&&y.send(W)},v);ie={context:I,tap:F}}catch(I){dn(`could not send the copy this call is keeping: ${String((I==null?void 0:I.message)||I)}`)}};function ot(){if(L=!1,!ie)return;const{context:m,tap:v}=ie;ie=null;try{v.stop()}catch{}try{m.close()}catch{}}function Ne(){var v;if(!b||g)return;let m;try{m=(v=b.play)==null?void 0:v.call(b)}catch{Be();return}if(!m||typeof m.then!="function"){me();return}m.then(me,Be)}function me(){$==null||$(),$=null,C&&(C=!1,l(!1))}function Be(){g||(C||(C=!0,l(!0)),St())}function St(){if($||typeof window>"u"||typeof window.addEventListener!="function")return;const m=()=>Ne(),v=["pointerdown","keydown","touchstart"];for(const I of v)window.addEventListener(I,m,{capture:!0,passive:!0});$=()=>{for(const I of v)try{window.removeEventListener(I,m,{capture:!0})}catch{}}}const Ae=m=>{h=new RTCPeerConnection({iceServers:m!=null&&m.length?m:ho});for(const v of f.getAudioTracks())h.addTrack(v,f);T=de(),h.onicecandidate=v=>{v.candidate&&ae({type:"signal",signal:{kind:"candidate",payload:v.candidate.toJSON()}})},h.ontrack=v=>{var F;const[I]=v.streams;I&&(b||(b=document.createElement("audio"),b.autoplay=!0,b.playsInline=!0,(F=b.setAttribute)==null||F.call(b,"playsinline",""),b.style.cssText="position:fixed;width:0;height:0;opacity:0;pointer-events:none",document.body.appendChild(b)),b.srcObject=I,Ne())},h.onconnectionstatechange=Se,h.oniceconnectionstatechange=Se};function Se(){if(!h||g)return;const m=h.connectionState||h.iceConnectionState;if(m==="connected"||m==="completed"){j=!0,ne=0,ce(),V=!1,s("connected");return}if(m==="disconnected"){if(!j)return;Ue(De);return}if(m==="failed"){if(!j){K("failed",{reason:"ice"});return}Ue(0)}}function Ue(m){g||(V||(V=!0,s("reconnecting"),se=setTimeout(()=>K("failed",{reason:"network"}),at)),!E&&(E=setTimeout(Re,m)))}function ce(){E&&(clearTimeout(E),E=null),se&&(clearTimeout(se),se=null)}async function Re(){if(E=null,g||!h)return;const m=h.connectionState||h.iceConnectionState;if(!(m==="connected"||m==="completed")){if(!U){ae({type:"signal",signal:{kind:"restart",payload:{}}}),E=setTimeout(Re,xe);return}ne>=ke||(ne+=1,await H(),E=setTimeout(Re,xe))}}async function H(){if(!(g||!h))try{const m=await h.createOffer({iceRestart:!0});await h.setLocalDescription(m),ae({type:"signal",signal:{kind:"offer",payload:h.localDescription.toJSON()}})}catch{}}function de(){let v=null,I=!1;const F=W=>{if(v&&(clearTimeout(v),v=null),W){if(!I)return;I=!1,p(!0);return}I||(v=setTimeout(()=>{v=null,!g&&(I=!0,p(!1))},600))};for(const W of f.getAudioTracks())W.onmute=()=>F(!1),W.onunmute=()=>F(!0),W.onended=()=>{v&&(clearTimeout(v),v=null),!I&&(I=!0,p(!1))};return()=>{v&&(clearTimeout(v),v=null);for(const W of f.getAudioTracks())W.onmute=null,W.onunmute=null,W.onended=null}}const rt=async()=>{try{const m=await h.createOffer();await h.setLocalDescription(m),ae({type:"signal",signal:{kind:"offer",payload:h.localDescription.toJSON()}})}catch{K("failed",{reason:"negotiation"})}},Ct=async m=>{try{await h.setRemoteDescription(new RTCSessionDescription(m));const v=await h.createAnswer();await h.setLocalDescription(v),ae({type:"signal",signal:{kind:"answer",payload:h.localDescription.toJSON()}}),await Qe()}catch{K("failed",{reason:"negotiation"})}},Qe=async()=>{for(;X.length;){const m=X.shift();try{await h.addIceCandidate(new RTCIceCandidate(m))}catch{}}};let Ce=Promise.resolve();y.onmessage=m=>{Ce=Ce.then(()=>$t(m)).catch(()=>{})};const $t=async m=>{var I,F,W,$e,it;if(typeof m.data!="string")return;let v;try{v=JSON.parse(m.data)}catch{return}switch(v.type){case"session.created":{if(Ae((I=v.data)==null?void 0:I.ice_servers),A=((F=v.data)==null?void 0:F.capture)||null,(W=v.data)!=null&&W.peer_present){s("connecting"),Le();break}s("ringing"),je();break}case"peer.joined":{S&&(clearTimeout(S),S=null),s("connecting"),U=!!(($e=v.data)!=null&&$e.should_offer),U&&await rt(),Le();break}case"signal":{if(!h)break;const{kind:Ee,payload:ge}=v.data||{};if(Ee==="offer")await Ct(ge);else if(Ee==="answer")try{await h.setRemoteDescription(new RTCSessionDescription(ge)),await Qe()}catch{K("failed",{reason:"negotiation"})}else if(Ee==="candidate")if(h.remoteDescription)try{await h.addIceCandidate(new RTCIceCandidate(ge))}catch{}else X.push(ge);else Ee==="restart"&&U&&await H();break}case"peer.left":K("ended",{reason:"peer_left"});break;case"error":K("failed",{reason:"server",detail:(it=v.error)==null?void 0:it.detail});break;case"session.ended":K("ended",{reason:"server"});break}};y.onclose=()=>K("ended",{reason:"disconnected"}),y.onerror=()=>K("failed",{reason:"socket"});function je(){if(!n)return;const m=new Date(n).getTime()-Date.now();Number.isFinite(m)&&(S=setTimeout(()=>K("missed"),Math.max(0,m)))}return{hangUp(){ae({type:"session.end"}),K("ended",{reason:"hung_up"})},setMuted(m){for(const v of f.getAudioTracks())v.enabled=!m;return m},isMuted(){return f.getAudioTracks().every(m=>!m.enabled)}}}function fo(t){return new Promise((e,n)=>{let a;try{a=new WebSocket(t,po)}catch(i){n(i);return}a.onopen=()=>{a.onopen=null,a.onerror=null,e(a)},a.onerror=()=>{a.onopen=null,a.onerror=null,n(new Error("[BugCatch] could not connect the call."))}})}function dn(t){try{console.warn(`[BugCatch] ${t}`)}catch{}}function un(t){var e;for(const n of((e=t==null?void 0:t.getTracks)==null?void 0:e.call(t))??[])try{n.stop()}catch{}}const tt={cycleMs:3e3,peak:.045,bursts:[{at:0,seconds:.4,hz:[440,660]},{at:.55,seconds:.4,hz:[440,660]}]};let pn=!1;if(typeof window<"u"&&window.addEventListener)for(const t of["pointerdown","keydown","touchstart"])window.addEventListener(t,()=>{pn=!0},{once:!0,capture:!0,passive:!0});function go(){var t;try{return!!((t=navigator.userActivation)!=null&&t.hasBeenActive)}catch{return!1}}function mo(){if(!pn&&!go())return()=>{};const t=typeof window<"u"&&(window.AudioContext||window.webkitAudioContext);if(!t)return()=>{};let e;try{e=new t}catch{return()=>{}}let n=!1,a=null;const i=[],r=({at:p,seconds:f,hz:y})=>{const h=e.currentTime+p,b=e.createGain();b.connect(e.destination),b.gain.setValueAtTime(0,h),b.gain.linearRampToValueAtTime(tt.peak,h+.02),b.gain.setValueAtTime(tt.peak,h+f-.06),b.gain.linearRampToValueAtTime(0,h+f);for(const g of y){const S=e.createOscillator();S.type="sine",S.frequency.value=g,S.connect(b),S.start(h),S.stop(h+f+.02),i.push(S)}},s=()=>{if(!n)try{tt.bursts.forEach(r)}catch{}},l=()=>{n||(s(),a=setInterval(s,tt.cycleMs))};return e.state==="running"?l():e.resume().then(l).catch(()=>{}),()=>{n=!0,a&&clearInterval(a);for(const p of i)try{p.stop()}catch{}try{e.close()}catch{}}}function bo(t){const e=Date.parse(t||"");return Number.isNaN(e)?0:Math.max(0,Math.round((e-Date.now())/1e3))}const hn=["flex:1","padding:9px 12px","border:0","border-radius:8px","font:600 13px/1.4 inherit","cursor:pointer"].join(";");function yo({call:t,accent:e="#5b6ef5",position:n="bottom-right",onAnswer:a,onDecline:i,onExpire:r}){if(typeof document>"u"||!document.body)return()=>{};const[s,l]=String(n).split("-"),p=document.createElement("div");p.setAttribute("role","alertdialog"),p.setAttribute("aria-live","assertive"),p.setAttribute("aria-label",`${t.from||"Support"} is calling about ${t.reference}`),p.style.cssText=["position:fixed",`${s==="top"?"top":"bottom"}:20px`,`${l==="left"?"left":"right"}:20px`,"z-index:2147483647","width:300px","max-width:calc(100vw - 40px)","padding:14px","border-radius:12px","background:#1b1e26","color:#eceef2",'font:13px/1.5 -apple-system,BlinkMacSystemFont,"Segoe UI",sans-serif',"box-shadow:0 18px 44px rgba(0,0,0,0.5)",`border:1px solid ${e}`,"opacity:0","transform:translateY(8px)","transition:opacity .2s ease,transform .2s ease"].join(";");const f=document.createElement("div");f.style.cssText="font-weight:600;font-size:14px;margin-bottom:2px",f.textContent=`${t.from||"Support"} is calling`;const y=document.createElement("div");y.style.cssText="color:#a4abba;margin-bottom:10px",y.textContent=t.project?`About your report ${t.reference} · ${t.project}`:`About your report ${t.reference}`;const h=document.createElement("div");h.style.cssText="color:#7d8598;font-size:12px;margin-bottom:10px";const b=document.createElement("button");b.type="button",b.textContent="Answer",b.style.cssText=`${hn};background:${e};color:#fff`;const g=document.createElement("button");g.type="button",g.textContent="Not now",g.style.cssText=`${hn};background:#2b2f3a;color:#c8cedb`;const S=document.createElement("div");if(S.style.cssText="display:flex;gap:8px",S.append(b,g),p.append(f,y,h),t.recorded){const L=document.createElement("div");L.style.cssText="color:#7d8598;font-size:12px;margin-bottom:10px",L.textContent="This call will be recorded.",p.append(L)}p.append(S),document.body.appendChild(p);const A=mo();let ie=!1,C=null;const $=()=>{ie||(ie=!0,C&&clearInterval(C),A(),p.style.opacity="0",p.style.transform="translateY(8px)",setTimeout(()=>p.remove(),250))},T=()=>{const L=bo(t.ringsUntil);if(h.textContent=L?`Ringing — ${L}s`:"The call has stopped ringing.",!L){$();try{r==null||r()}catch{}}};return T(),C=setInterval(T,1e3),b.addEventListener("click",()=>{$();try{a==null||a()}catch{}}),g.addEventListener("click",()=>{$();try{i==null||i()}catch{}}),requestAnimationFrame(()=>{p.style.opacity="1",p.style.transform="translateY(0)"}),$}const fn={name:"@sphoro/bugcatch-web-sdk",version:"0.14.4"},nt={apiBase:"http://localhost:3000",apiKey:null,projectId:null,consoleLimit:100,networkLimit:50,captureConsole:!0,captureNetwork:!0,captureErrors:!0,widget:!0,widgetPosition:"bottom-right",theme:"auto",accent:"#4F46E5",attachments:!0,maxAttachments:5,maxAttachmentBytes:25*1024*1024,maxRecordingMs:12e4,beforeSend:null,user:null,updates:!0,updateToast:!0,onUpdate:null,voice:!0,onCallState:null,onIncomingCall:null};class gn{constructor(){zn(this,B);this.config={...nt},this.started=!1,this.teardown=[],this.consoleBuffer=Pe(nt.consoleLimit),this.networkBuffer=Pe(nt.networkLimit),this.stopWatching=null,this.notifier=null,this.call=null,this.callStarting=!1,this.ringing=null,this.listeners=new Map}init(e={}){if(this.started)return console.warn("[BugCatch] init() called twice — ignoring the second call."),this;if(this.config={...nt,...e},!this.config.apiKey)throw new Error("[BugCatch] apiKey is required.");if(!this.config.projectId)throw new Error("[BugCatch] projectId is required.");return this.consoleBuffer=Pe(this.config.consoleLimit),this.networkBuffer=Pe(this.config.networkLimit),this.config.captureConsole&&this.teardown.push(Wn(this.consoleBuffer)),this.config.captureNetwork&&this.teardown.push(Yn(this.networkBuffer)),this.config.captureErrors&&this.teardown.push(Xn(this.consoleBuffer)),this.config.widget&&this.teardown.push(Ja(this)),this.config.updates&&re()&&(this.startWatching(),queueMicrotask(()=>_(this,B,ye).call(this))),this.started=!0,this}startWatching(){if(this.stopWatching)return this;this.stopWatching=Ba({apiBase:this.config.apiBase,onUpdate:n=>{if(n!=null&&n.incomingCall){_(this,B,qn).call(this,n);return}if(n!=null&&n.callWithdrawn){_(this,B,dt).call(this,n.callWithdrawn.callId);return}const a=va(n);typeof this.config.onUpdate=="function"&&this.config.onUpdate(a),this.emit("update",a),_(this,B,ye).call(this)}}),this.teardown.push(()=>{var n;return(n=this.stopWatching)==null?void 0:n.call(this)}),this.teardown.push(()=>_(this,B,dt).call(this));const e=n=>{(n.key===Je||n.key===null)&&_(this,B,ye).call(this)};return window.addEventListener("storage",e),this.teardown.push(()=>window.removeEventListener("storage",e)),this}on(e,n){if(typeof n!="function")return()=>{};const a=this.listeners.get(e)||new Set;return a.add(n),this.listeners.set(e,a),()=>this.off(e,n)}off(e,n){var a;return(a=this.listeners.get(e))==null||a.delete(n),this}emit(e,n){for(const a of this.listeners.get(e)||[])try{a(n)}catch(i){console.error("[BugCatch] an update listener threw:",i)}}unreadUpdates(){return qe()}markUpdateRead(e){return xa(e),_(this,B,ye).call(this),this}markReportRead(e){return ka(e),_(this,B,ye).call(this),this}markUpdatesRead(){return Kt(),_(this,B,ye).call(this),this}async verifyFix(e,{result:n,resolvedAt:a,note:i}){const r=n==="STILL_HAPPENING"?await _(this,B,lt).call(this,{}):{};return Ua({apiBase:this.config.apiBase,bugId:e,result:n,resolvedAt:a,note:i,metadata:r.metadata,logs:r.logs})}myReport(e){return $a({apiBase:this.config.apiBase,bugId:e})}replyToReport(e,{body:n,attachments:a}={}){return Pt({apiBase:this.config.apiBase,bugId:e,body:n,attachments:a})}async canCallNow(){return!!await this.callKind()}async callKind(){return(await this.callKinds()).live?"live":null}async callKinds(){var n;const e={agent:!1,live:!1};return!this.config.voice||!((n=this.config.user)!=null&&n.email)?e:this.kinds!==void 0?this.kinds:(this.kinds=await Ea({apiBase:this.config.apiBase,apiKey:this.config.apiKey,projectId:this.config.projectId}),this.kinds)}canCall(e){return this.config.voice?_t({apiBase:this.config.apiBase,bugId:e}):Promise.resolve(!1)}async startCall(e){var n;if(!this.config.voice)throw new Error("[BugCatch] calling is switched off.");if(this.call||this.callStarting)throw new Error("[BugCatch] a call is already running.");this.callStarting=!0;try{if(!await this.callKind())throw new Error((n=this.config.user)!=null&&n.email?"[BugCatch] calling is not available on this project.":"[BugCatch] a call needs to know who is calling — call identify() with an email first.");return await _(this,B,Hn).call(this,e)}finally{this.callStarting=!1}}startLiveCall(e){return this.startCall(e)}canCallTeam(e){return this.config.voice?_t({apiBase:this.config.apiBase,bugId:e}):Promise.resolve(!1)}endCall(){var e;return(e=this.call)==null||e.hangUp(),this.call=null,this}myReports(){return Ca({apiBase:this.config.apiBase})}hasReports(){return!!re()}forgetReports(){var e;return(e=this.stopWatching)==null||e.call(this),this.stopWatching=null,this.endCall(),ve(),_(this,B,ye).call(this),this}identify(e){return this.config.user=e,this}async uploadAttachment(e,n,a){if(!this.started)throw new Error("[BugCatch] call init() first.");return ia({apiBase:this.config.apiBase,apiKey:this.config.apiKey,blob:e,mime:n||(e==null?void 0:e.type),onProgress:a})}async report({title:e,description:n="",priority:a="MEDIUM",metadata:i={},attachments:r=[],references:s=[]}={}){if(!this.started)throw new Error("[BugCatch] call init() first.");if(!e||!e.trim())throw new Error("[BugCatch] a title is required.");const l=(r||[]).filter(b=>(b==null?void 0:b.storageKey)&&Fe(b.mime,_e)).map(b=>({type:b.type==="VIDEO"?"VIDEO":"SCREENSHOT",storageKey:b.storageKey,mime:Fe(b.mime,_e)}));let p=await _(this,B,lt).call(this,{title:e.trim(),description:n,priority:a,metadata:i,media:l,references:s});if(typeof this.config.beforeSend=="function"){const b=this.config.beforeSend(p);if(b===!1)return{cancelled:!0};b&&typeof b=="object"&&(p=b)}const f=fe(this.config.projectId),y=await fetch(`${this.config.apiBase}/ingest/bugs`,{method:"POST",headers:{"Content-Type":"application/json","X-BugCatch-Key":this.config.apiKey,...f!=null&&f.token?{"X-BugCatch-Session":f.token}:{}},body:JSON.stringify(p)});if(y.status===401&&f&&gt(this.config.projectId),!y.ok){let b="";try{const g=await y.json();b=Array.isArray(g.message)?g.message.join(", "):g.message||""}catch{}throw new Error(`[BugCatch] report failed (HTTP ${y.status})${b?": "+b:""}`)}const h=await y.json();return h.watchToken&&(bt(h.watchToken),this.config.updates&&this.startWatching()),h}loginState(){var e;return fa({apiBase:this.config.apiBase,apiKey:this.config.apiKey,projectId:this.config.projectId,token:(e=fe(this.config.projectId))==null?void 0:e.token})}referenceFields(){return this.refFields?this.refFields:(this.refFields=Fa({apiBase:this.config.apiBase,apiKey:this.config.apiKey,projectId:this.config.projectId}),this.refFields)}signedInAs(){const e=fe(this.config.projectId);return e?{email:e.email,name:e.name}:null}signIn(e,{name:n}={}){var a;return ga({apiBase:this.config.apiBase,apiKey:this.config.apiKey,projectId:this.config.projectId,email:e,name:n??((a=this.config.user)==null?void 0:a.name)??null})}async confirmSignIn(e,n){var i;const a=await ma({apiBase:this.config.apiBase,apiKey:this.config.apiKey,projectId:this.config.projectId,email:e,code:n});return(i=this.config.user)!=null&&i.email||(this.config.user={email:a.email,name:a.name||void 0}),this.emit("signin",{email:a.email,name:a.name}),{email:a.email,name:a.name}}async signOut(){var a;const e=fe(this.config.projectId),n=await ba({apiBase:this.config.apiBase,apiKey:this.config.apiKey,projectId:this.config.projectId,token:e==null?void 0:e.token});return e!=null&&e.email&&((a=this.config.user)==null?void 0:a.email)===e.email&&(this.config.user=null),this.emit("signout",{email:(e==null?void 0:e.email)||null}),n}knownIssues(){var e;return Ha({apiBase:this.config.apiBase,apiKey:this.config.apiKey,projectId:this.config.projectId,sessionToken:(e=fe(this.config.projectId))==null?void 0:e.token})}matchKnownIssues(e,{signal:n}={}){var a;return qa({apiBase:this.config.apiBase,apiKey:this.config.apiKey,projectId:this.config.projectId,q:e||"",sessionToken:(a=fe(this.config.projectId))==null?void 0:a.token,signal:n})}async meToo(e,{email:n,name:a}={}){var s,l;const i=fe(this.config.projectId),r=await Ht();return Da({apiBase:this.config.apiBase,apiKey:this.config.apiKey,projectId:this.config.projectId,bugId:e,reporterEmail:n||((s=this.config.user)==null?void 0:s.email),reporterName:a||((l=this.config.user)==null?void 0:l.name),metadata:{...r,user:this.config.user||void 0,sdk:fn},logs:{console:{entries:this.consoleBuffer.all()},network:{entries:this.networkBuffer.all()}},sessionToken:i==null?void 0:i.token})}snapshot(){return{console:this.consoleBuffer.all(),network:this.networkBuffer.all(),environment:qt()}}clear(){this.consoleBuffer.clear(),this.networkBuffer.clear()}destroy(){this.endCall(),this.teardown.forEach(e=>{try{e()}catch{}}),this.teardown=[],this.notifier=null,this.started=!1}}B=new WeakSet,ye=function(){const e=qe();if(this.emit("unread",{count:e.length,updates:e}),!!this.config.updateToast){if(!this.notifier){if(!e.length)return;this.notifier=Oa({accent:this.config.accent,position:this.config.widgetPosition,onRead:n=>this.markUpdateRead(n),onReadAll:()=>this.markUpdatesRead(),onCall:this.config.voice?n=>{this.markUpdateRead(n.id),this.startCall(n.bugId)}:null}),this.teardown.push(()=>{var n;return(n=this.notifier)==null?void 0:n.destroy()})}this.notifier.render(e)}},lt=async function({title:e,description:n="",priority:a="MEDIUM",metadata:i={},media:r=[],references:s=[]}){var l,p;return{projectId:this.config.projectId,...e?{title:e}:{},description:n,priority:a,url:window.location.href,reporterEmail:(l=this.config.user)==null?void 0:l.email,reporterName:(p=this.config.user)==null?void 0:p.name,metadata:{...await Ht(),release:this.config.release,environment:this.config.environment,buildId:this.config.buildId,...i,user:this.config.user||void 0,sdk:fn},logs:{console:{entries:this.consoleBuffer.all()},network:{entries:this.networkBuffer.all()}},...r.length?{attachments:r}:{},...s.length?{references:s}:{}}},On=async function(){const e=fe(this.config.projectId);let n;try{n=await Ta({apiBase:this.config.apiBase,apiKey:this.config.apiKey,token:e==null?void 0:e.token,payload:await _(this,B,lt).call(this,{})})}catch(a){throw a.status===401&&e&&gt(this.config.projectId),a}return n.watchToken&&(bt(n.watchToken),this.config.updates&&this.startWatching()),n},Hn=async function(e){if(!kt())throw new Error("[BugCatch] this browser cannot make live calls.");const n=await xt();let a,i=null;try{if(e)a=await Ia({apiBase:this.config.apiBase,bugId:e});else if(i=await _(this,B,On).call(this),e=i.id,a=i.live_call,!(a!=null&&a.realtime_url)){const s=new Error(`[BugCatch] the report was filed, but the team could not be rung${i.call_error?`: ${i.call_error}`:"."}`);throw s.filed=i,s.reason=i.call_error||null,s}}catch(s){for(const l of n.getTracks())l.stop();throw s}const r=await ln({realtimeUrl:a.realtime_url,stream:n,ringsUntil:a.rings_until,onState:(s,l)=>{(s==="ended"||s==="failed"||s==="missed")&&(this.call=null),s==="missed"&&Ma({apiBase:this.config.apiBase,bugId:e,callId:a.call_id}),typeof this.config.onCallState=="function"&&this.config.onCallState(s,{bugId:e,live:!0,...l}),this.emit("call",{bugId:e,live:!0,state:s,...l})}});return this.call=r,Object.assign(r,{bugId:e,callId:a.call_id,live:!0,filed:i})},qn=function(e){var i;const n=e.incomingCall;if(!this.config.voice||!kt()||((i=this.ringing)==null?void 0:i.callId)===n.callId||this.call||this.callStarting)return;_(this,B,dt).call(this);const a=yo({call:n,accent:this.config.accent,position:this.config.widgetPosition,onAnswer:()=>{_(this,B,Dn).call(this,e.bugId,n)},onDecline:()=>{this.ringing=null,Ft({apiBase:this.config.apiBase,bugId:e.bugId,callId:n.callId}),this.emit("incoming-call",{bugId:e.bugId,callId:n.callId,state:"declined"})},onExpire:()=>{this.ringing=null,this.emit("incoming-call",{bugId:e.bugId,callId:n.callId,state:"missed"})}});if(this.ringing={callId:n.callId,dismiss:a},typeof this.config.onIncomingCall=="function")try{this.config.onIncomingCall({bugId:e.bugId,...n})}catch{}this.emit("incoming-call",{bugId:e.bugId,callId:n.callId,state:"ringing"})},dt=function(e){if(this.ringing&&!(e&&this.ringing.callId!==e)){try{this.ringing.dismiss()}catch{}this.ringing=null}},Dn=async function(e,n){if(this.ringing=null,this.call||this.callStarting)return;this.callStarting=!0;let a;try{a=await xt()}catch(r){this.callStarting=!1,Ft({apiBase:this.config.apiBase,bugId:e,callId:n.callId}),this.emit("incoming-call",{bugId:e,callId:n.callId,state:"failed",error:r});return}let i;try{i=await La({apiBase:this.config.apiBase,bugId:e,callId:n.callId})}catch(r){for(const s of a.getTracks())s.stop();this.callStarting=!1,this.emit("incoming-call",{bugId:e,callId:n.callId,state:"missed",error:r});return}try{const r=await ln({realtimeUrl:i.realtime_url,stream:a,onState:(s,l)=>{(s==="ended"||s==="failed"||s==="missed")&&(this.call=null),typeof this.config.onCallState=="function"&&this.config.onCallState(s,{bugId:e,live:!0,incoming:!0,...l}),this.emit("call",{bugId:e,live:!0,incoming:!0,state:s,...l})}});this.call=r,this.emit("incoming-call",{bugId:e,callId:n.callId,state:"answered"})}catch(r){for(const s of a.getTracks())s.stop();this.emit("incoming-call",{bugId:e,callId:n.callId,state:"failed",error:r})}finally{this.callStarting=!1}};const mn=new gn;return mn.Client=gn,mn});
1367
+ ${t.size?`<span class="sz">${v(Be(t.size))}</span>`:""}
1368
+ </a>`}function Cn(t){return t.scrollHeight-t.scrollTop-t.clientHeight<40}function Ne(t,{smooth:e=!1}={}){const n=typeof matchMedia=="function"&&matchMedia("(prefers-reduced-motion: reduce)").matches;e&&!n&&t.scrollTo?t.scrollTo({top:t.scrollHeight,behavior:"smooth"}):t.scrollTop=t.scrollHeight}function zt(t){return{OPEN:"Open",IN_PROGRESS:"In progress",RESOLVED:"Fixed",CLOSED:"Closed"}[t]||String(t||"").toLowerCase()}function lt(t){const e=new Date(t).getTime();if(!Number.isFinite(e))return"";const n=Math.floor((Date.now()-e)/864e5);if(n<=0)return"today";if(n===1)return"yesterday";if(n<30)return`${n} days ago`;const o=Math.floor(n/30);return o===1?"a month ago":`${o} months ago`}function v(t){return String(t).replace(/[&<>"']/g,e=>({"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#39;"})[e])}const Tn=8e3;function Ra(t=Tn){const e=window.AudioContext||window.webkitAudioContext;try{return new e({sampleRate:t})}catch{return new e}}async function ja(t){if(t.state==="suspended")try{await t.resume()}catch{}}function za(t,e,n){const o=e/n,i=new Float32Array(Math.floor(t.length/o));for(let a=0;a<i.length;a++){const s=Math.floor(a*o),l=Math.min(Math.floor((a+1)*o),t.length);let p=0;for(let h=s;h<l;h++)p+=t[h];i[a]=l>s?p/(l-s):0}return i}const Qa=132,En=32635;function Oa(t){const e=new Uint8Array(t.length);for(let n=0;n<t.length;n++){const o=Math.max(-1,Math.min(1,t[n]));let i=Math.round(o*32767);const a=i<0?128:0;a&&(i=-i),i>En&&(i=En),i+=Qa;let s=7;for(let p=16384;!(i&p)&&s>0;s--,p>>=1);const l=i>>s+3&15;e[n]=~(a|s<<4|l)&255}return e}const Ha=512;function qa(t,e,n,o=Tn){const i=t.createMediaStreamSource(e),a=t.createScriptProcessor(Ha,1,1);a.onaudioprocess=l=>{const p=l.inputBuffer.getChannelData(0),h=t.sampleRate===o?p:za(p,t.sampleRate,o);n(Oa(h))},i.connect(a);const s=t.createGain();return s.gain.value=0,a.connect(s),s.connect(t.destination),{stop(){a.onaudioprocess=null;try{i.disconnect()}catch{}try{a.disconnect()}catch{}try{s.disconnect()}catch{}}}}const Da="voiceai.realtime.v1",Na=[{urls:"stun:stun.l.google.com:19302"}];function Qt(){return navigator.mediaDevices.getUserMedia({audio:{echoCancellation:!0,noiseSuppression:!0,autoGainControl:!0,channelCount:1}})}function Ot(){var t;return typeof window<"u"&&typeof window.RTCPeerConnection=="function"&&!!((t=navigator.mediaDevices)!=null&&t.getUserMedia)}async function In({realtimeUrl:t,stream:e,ringsUntil:n,onState:o,onAudioBlocked:i,onMicrophone:a}){const s=(y,k)=>{try{o==null||o(y,k)}catch{}},l=y=>{try{i==null||i(y)}catch{}},p=y=>{try{a==null||a(y)}catch{}};if(!Ot()){const y=new Error("[BugCatch] this browser cannot make live calls.");throw s("failed",{reason:"unsupported"}),y}let h=e;if(!h)try{h=await Qt()}catch(y){throw s("failed",{reason:"microphone",error:String((y==null?void 0:y.name)||y)}),y}let b;try{b=await Ua(t)}catch(y){throw An(h),s("failed",{reason:"connect"}),y}let f=null,m=null,g=!1,T=null,Q=null,V=null,$=!1,L=null,B=null,j=!1;const N=[];let S=!1,U=!1,q=!1,I=null,Z=null,Re=0;const le=2e3,je=5e3,ze=3e4,ft=4,X=(y,k)=>{if(!g){g=!0,T&&(clearTimeout(T),T=null),Fe(),B==null||B(),B=null,Ke(),L==null||L(),L=null;try{f==null||f.close()}catch{}An(h),m&&(m.srcObject=null,m.remove(),m=null);try{b.readyState===WebSocket.OPEN&&b.close(1e3,"call over")}catch{}s(y,k)}},de=y=>{b.readyState===WebSocket.OPEN&&b.send(JSON.stringify(y))},me=async()=>{if(j||V||g||!Q||!Q.audio&&!Q.transcript)return;j=!0;const y=Q.encoding||"mulaw";if(y!=="mulaw"){Mn(`this call is kept as ${y}, which this SDK cannot produce.`);return}const k=Number(Q.sample_rate)||8e3;try{const z=Ra(k);if(await ja(z),g){try{z.close()}catch{}return}const O=qa(z,h,D=>{b.readyState===WebSocket.OPEN&&b.send(D)},k);V={context:z,tap:O}}catch(z){Mn(`could not send the copy this call is keeping: ${String((z==null?void 0:z.message)||z)}`)}};function Ke(){if(j=!1,!V)return;const{context:y,tap:k}=V;V=null;try{k.stop()}catch{}try{y.close()}catch{}}function Pe(){var k;if(!m||g)return;let y;try{y=(k=m.play)==null?void 0:k.call(m)}catch{Ce();return}if(!y||typeof y.then!="function"){_e();return}y.then(_e,Ce)}function _e(){L==null||L(),L=null,$&&($=!1,l(!1))}function Ce(){g||($||($=!0,l(!0)),Ve())}function Ve(){if(L||typeof window>"u"||typeof window.addEventListener!="function")return;const y=()=>Pe(),k=["pointerdown","keydown","touchstart"];for(const z of k)window.addEventListener(z,y,{capture:!0,passive:!0});L=()=>{for(const z of k)try{window.removeEventListener(z,y,{capture:!0})}catch{}}}const Nt=y=>{f=new RTCPeerConnection({iceServers:y!=null&&y.length?y:Na});for(const k of h.getAudioTracks())f.addTrack(k,h);B=J(),f.onicecandidate=k=>{k.candidate&&de({type:"signal",signal:{kind:"candidate",payload:k.candidate.toJSON()}})},f.ontrack=k=>{var O;const[z]=k.streams;z&&(m||(m=document.createElement("audio"),m.autoplay=!0,m.playsInline=!0,(O=m.setAttribute)==null||O.call(m,"playsinline",""),m.style.cssText="position:fixed;width:0;height:0;opacity:0;pointer-events:none",document.body.appendChild(m)),m.srcObject=z,Pe())},f.onconnectionstatechange=Me,f.oniceconnectionstatechange=Me};function Me(){if(!f||g)return;const y=f.connectionState||f.iceConnectionState;if(y==="connected"||y==="completed"){U=!0,Re=0,Fe(),q=!1,s("connected");return}if(y==="disconnected"){if(!U)return;Ae(le);return}if(y==="failed"){if(!U){X("failed",{reason:"ice"});return}Ae(0)}}function Ae(y){g||(q||(q=!0,s("reconnecting"),Z=setTimeout(()=>X("failed",{reason:"network"}),ze)),!I&&(I=setTimeout(ue,y)))}function Fe(){I&&(clearTimeout(I),I=null),Z&&(clearTimeout(Z),Z=null)}async function ue(){if(I=null,g||!f)return;const y=f.connectionState||f.iceConnectionState;if(!(y==="connected"||y==="completed")){if(!S){de({type:"signal",signal:{kind:"restart",payload:{}}}),I=setTimeout(ue,je);return}Re>=ft||(Re+=1,await We(),I=setTimeout(ue,je))}}async function We(){if(!(g||!f))try{const y=await f.createOffer({iceRestart:!0});await f.setLocalDescription(y),de({type:"signal",signal:{kind:"offer",payload:f.localDescription.toJSON()}})}catch{}}function J(){let k=null,z=!1;const O=D=>{if(k&&(clearTimeout(k),k=null),D){if(!z)return;z=!1,p(!0);return}z||(k=setTimeout(()=>{k=null,!g&&(z=!0,p(!1))},600))};for(const D of h.getAudioTracks())D.onmute=()=>O(!1),D.onunmute=()=>O(!0),D.onended=()=>{k&&(clearTimeout(k),k=null),!z&&(z=!0,p(!1))};return()=>{k&&(clearTimeout(k),k=null);for(const D of h.getAudioTracks())D.onmute=null,D.onunmute=null,D.onended=null}}const gt=async()=>{try{const y=await f.createOffer();await f.setLocalDescription(y),de({type:"signal",signal:{kind:"offer",payload:f.localDescription.toJSON()}})}catch{X("failed",{reason:"negotiation"})}},bt=async y=>{try{await f.setRemoteDescription(new RTCSessionDescription(y));const k=await f.createAnswer();await f.setLocalDescription(k),de({type:"signal",signal:{kind:"answer",payload:f.localDescription.toJSON()}}),await pe()}catch{X("failed",{reason:"negotiation"})}},pe=async()=>{for(;N.length;){const y=N.shift();try{await f.addIceCandidate(new RTCIceCandidate(y))}catch{}}};let Ye=Promise.resolve();b.onmessage=y=>{Ye=Ye.then(()=>Ut(y)).catch(()=>{})};const Ut=async y=>{var z,O,D,ye,he;if(typeof y.data!="string")return;let k;try{k=JSON.parse(y.data)}catch{return}switch(k.type){case"session.created":{if(Nt((z=k.data)==null?void 0:z.ice_servers),Q=((O=k.data)==null?void 0:O.capture)||null,(D=k.data)!=null&&D.peer_present){s("connecting"),me();break}s("ringing"),Xe();break}case"peer.joined":{T&&(clearTimeout(T),T=null),s("connecting"),S=!!((ye=k.data)!=null&&ye.should_offer),S&&await gt(),me();break}case"signal":{if(!f)break;const{kind:Le,payload:we}=k.data||{};if(Le==="offer")await bt(we);else if(Le==="answer")try{await f.setRemoteDescription(new RTCSessionDescription(we)),await pe()}catch{X("failed",{reason:"negotiation"})}else if(Le==="candidate")if(f.remoteDescription)try{await f.addIceCandidate(new RTCIceCandidate(we))}catch{}else N.push(we);else Le==="restart"&&S&&await We();break}case"peer.left":X("ended",{reason:"peer_left"});break;case"error":X("failed",{reason:"server",detail:(he=k.error)==null?void 0:he.detail});break;case"session.ended":X("ended",{reason:"server"});break}};b.onclose=()=>X("ended",{reason:"disconnected"}),b.onerror=()=>X("failed",{reason:"socket"});function Xe(){if(!n)return;const y=new Date(n).getTime()-Date.now();Number.isFinite(y)&&(T=setTimeout(()=>X("missed"),Math.max(0,y)))}return{hangUp(){de({type:"session.end"}),X("ended",{reason:"hung_up"})},setMuted(y){for(const k of h.getAudioTracks())k.enabled=!y;return y},isMuted(){return h.getAudioTracks().every(y=>!y.enabled)}}}function Ua(t){return new Promise((e,n)=>{let o;try{o=new WebSocket(t,Da)}catch(i){n(i);return}o.onopen=()=>{o.onopen=null,o.onerror=null,e(o)},o.onerror=()=>{o.onopen=null,o.onerror=null,n(new Error("[BugCatch] could not connect the call."))}})}function Mn(t){try{console.warn(`[BugCatch] ${t}`)}catch{}}function An(t){var e;for(const n of((e=t==null?void 0:t.getTracks)==null?void 0:e.call(t))??[])try{n.stop()}catch{}}const dt={cycleMs:3e3,peak:.045,bursts:[{at:0,seconds:.4,hz:[440,660]},{at:.55,seconds:.4,hz:[440,660]}]};let Ln=!1;if(typeof window<"u"&&window.addEventListener)for(const t of["pointerdown","keydown","touchstart"])window.addEventListener(t,()=>{Ln=!0},{once:!0,capture:!0,passive:!0});function Ka(){var t;try{return!!((t=navigator.userActivation)!=null&&t.hasBeenActive)}catch{return!1}}function Pa(){if(!Ln&&!Ka())return()=>{};const t=typeof window<"u"&&(window.AudioContext||window.webkitAudioContext);if(!t)return()=>{};let e;try{e=new t}catch{return()=>{}}let n=!1,o=null;const i=[],a=({at:p,seconds:h,hz:b})=>{const f=e.currentTime+p,m=e.createGain();m.connect(e.destination),m.gain.setValueAtTime(0,f),m.gain.linearRampToValueAtTime(dt.peak,f+.02),m.gain.setValueAtTime(dt.peak,f+h-.06),m.gain.linearRampToValueAtTime(0,f+h);for(const g of b){const T=e.createOscillator();T.type="sine",T.frequency.value=g,T.connect(m),T.start(f),T.stop(f+h+.02),i.push(T)}},s=()=>{if(!n)try{dt.bursts.forEach(a)}catch{}},l=()=>{n||(s(),o=setInterval(s,dt.cycleMs))};return e.state==="running"?l():e.resume().then(l).catch(()=>{}),()=>{n=!0,o&&clearInterval(o);for(const p of i)try{p.stop()}catch{}try{e.close()}catch{}}}function _a(t){const e=Date.parse(t||"");return Number.isNaN(e)?0:Math.max(0,Math.round((e-Date.now())/1e3))}const Bn=["flex:1","padding:9px 12px","border:0","border-radius:8px","font:600 13px/1.4 inherit","cursor:pointer"].join(";");function Va({call:t,accent:e="#5b6ef5",position:n="bottom-right",onAnswer:o,onDecline:i,onExpire:a}){if(typeof document>"u"||!document.body)return()=>{};const[s,l]=String(n).split("-"),p=document.createElement("div");p.setAttribute("role","alertdialog"),p.setAttribute("aria-live","assertive"),p.setAttribute("aria-label",`${t.from||"Support"} is calling about ${t.reference}`),p.style.cssText=["position:fixed",`${s==="top"?"top":"bottom"}:20px`,`${l==="left"?"left":"right"}:20px`,"z-index:2147483647","width:300px","max-width:calc(100vw - 40px)","padding:14px","border-radius:12px","background:#1b1e26","color:#eceef2",'font:13px/1.5 -apple-system,BlinkMacSystemFont,"Segoe UI",sans-serif',"box-shadow:0 18px 44px rgba(0,0,0,0.5)",`border:1px solid ${e}`,"opacity:0","transform:translateY(8px)","transition:opacity .2s ease,transform .2s ease"].join(";");const h=document.createElement("div");h.style.cssText="font-weight:600;font-size:14px;margin-bottom:2px",h.textContent=`${t.from||"Support"} is calling`;const b=document.createElement("div");b.style.cssText="color:#a4abba;margin-bottom:10px",b.textContent=t.project?`About your report ${t.reference} · ${t.project}`:`About your report ${t.reference}`;const f=document.createElement("div");f.style.cssText="color:#7d8598;font-size:12px;margin-bottom:10px";const m=document.createElement("button");m.type="button",m.textContent="Answer",m.style.cssText=`${Bn};background:${e};color:#fff`;const g=document.createElement("button");g.type="button",g.textContent="Not now",g.style.cssText=`${Bn};background:#2b2f3a;color:#c8cedb`;const T=document.createElement("div");if(T.style.cssText="display:flex;gap:8px",T.append(m,g),p.append(h,b,f),t.recorded){const j=document.createElement("div");j.style.cssText="color:#7d8598;font-size:12px;margin-bottom:10px",j.textContent="This call will be recorded.",p.append(j)}p.append(T),document.body.appendChild(p);const Q=Pa();let V=!1,$=null;const L=()=>{V||(V=!0,$&&clearInterval($),Q(),p.style.opacity="0",p.style.transform="translateY(8px)",setTimeout(()=>p.remove(),250))},B=()=>{const j=_a(t.ringsUntil);if(f.textContent=j?`Ringing — ${j}s`:"The call has stopped ringing.",!j){L();try{a==null||a()}catch{}}};return B(),$=setInterval(B,1e3),m.addEventListener("click",()=>{L();try{o==null||o()}catch{}}),g.addEventListener("click",()=>{L();try{i==null||i()}catch{}}),requestAnimationFrame(()=>{p.style.opacity="1",p.style.transform="translateY(0)"}),L}const ut=120,Fa=500,pt=30,Wa=1e3,Ht={loanId:["loanId","loanNumber"],applicationId:["applicationId"],customerNumber:["customerNumber","customerId"]},Ya=/[\u0000-\u001f\u007f]/;function Xa(t){if(typeof t=="number")return Number.isFinite(t)?String(t):null;if(typeof t!="string")return null;const e=t.trim();return!e||e.length>ut||Ya.test(e)?null:e}function Se(t){return t===null?"null":Array.isArray(t)?"an array":typeof t=="object"?"an object":`a ${typeof t}`}function qt(t,e,n,o,i){for(const a of n){if(!(a in t)||t[a]===void 0||t[a]===null||t[a]==="")continue;const s=Xa(t[a]);if(s)return s;const l=t[a];i(typeof l=="string"&&l.trim().length>ut?`${o}.${a} is longer than ${ut} characters and was dropped — pass the identifier itself, not a sentence or a URL.`:`${o}.${a} should be a string or number, got ${Se(l)} — it was dropped.`)}return null}function Rn(t){if(t===null||typeof t=="boolean")return{ok:!0,value:t};if(typeof t=="number")return Number.isFinite(t)?{ok:!0,value:t}:{ok:!1};if(typeof t=="string")return{ok:!0,value:t.slice(0,Fa)};if(typeof t=="object")try{const e=JSON.stringify(t);if(e&&e.length<=Wa)return{ok:!0,value:JSON.parse(e)}}catch{}return{ok:!1}}const jn=["email","name","phone"],Ja=new Set(["id","userId",...jn,...Object.values(Ht).flat()]);function zn(t,e=()=>{}){if(t==null)return null;if(typeof t!="object"||Array.isArray(t))return e(`identify() takes an object like { id, email, name } or null, got ${Se(t)} — ignored.`),null;const n={};try{const o=qt(t,"id",["id","userId"],"identify()",e);o&&(n.id=o);for(const a of jn){const s=t[a];if(s==null||s==="")continue;if(a==="phone"&&typeof s=="number"&&Number.isFinite(s)){n.phone=String(s);continue}if(typeof s!="string"){e(`identify().${a} should be a string, got ${Se(s)} — it was dropped.`);continue}const l=s.trim().slice(0,a==="name"?200:ut);l&&(a==="email"&&!l.includes("@")&&e(`identify().email "${l}" does not look like an email address — reports cannot be threaded or followed up without one.`),n[a]=l)}for(const[a,s]of Object.entries(Ht)){const l=qt(t,a,s,"identify()",e);l&&(n[a]=l)}let i=0;for(const[a,s]of Object.entries(t)){if(Ja.has(a)||s===void 0||typeof s=="function")continue;if(i>=pt){e(`identify() was given more than ${pt} extra fields; the rest were dropped.`);break}const l=Rn(s);if(!l.ok){e(`identify().${a} could not be sent (${Se(s)} too large or not serialisable) — dropped.`);continue}n[a]=l.value,i+=1}}catch{}return!n.id&&!n.email&&e("identify() was called without an id or email — reports will not be attributed to anyone, and nothing can be looked up by user."),n}function Qn(t,e,n=()=>{}){if(e===null)return{};const o={...t||{}};if(e===void 0)return o;if(typeof e!="object"||Array.isArray(e))return n(`setContext() takes an object like { loanId, screen } or null, got ${Se(e)} — ignored.`),o;try{const i=new Map;for(const[a,s]of Object.entries(Ht))for(const l of s)i.set(l,a);for(const[a,s]of Object.entries(e)){const l=i.get(a);if(s==null){delete o[l||a];continue}if(l){const h=qt({[a]:s},l,[a],"setContext()",n);h?o[l]=h:delete o[l];continue}if(typeof s=="function")continue;if(!(a in o)&&Object.keys(o).length>=pt){n(`setContext() holds at most ${pt} keys; "${a}" was dropped.`);continue}const p=Rn(s);if(!p.ok){n(`setContext().${a} could not be sent (${Se(s)} too large or not serialisable) — dropped.`);continue}o[a]=p.value}}catch{}return o}const On=["apiBase","apiKey","projectId","consoleLimit","networkLimit","captureConsole","captureNetwork","captureErrors","widget","widgetPosition","theme","accent","attachments","maxAttachments","maxAttachmentBytes","maxRecordingMs","beforeSend","user","context","updates","updateToast","onUpdate","voice","onCallState","onIncomingCall","onReportSubmitted","onAssistantPhase","onError","debug","drafts","knownIssues","release","environment","buildId"],Za=["beforeSend","onUpdate","onCallState","onIncomingCall","onReportSubmitted","onAssistantPhase","onError"];function Ga(t){const e=t.toLowerCase().replace(/[-_]/g,"");return On.find(n=>n.toLowerCase()===e)||null}const Hn=/^(your[_-]|<|xxx|todo|changeme)/i,er=/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;function tr(t,{pageHost:e=""}={}){const n=[],o=[];if(!t||typeof t!="object")return n.push("init() takes an options object: BugCatch.init({ apiBase, apiKey, projectId })."),{errors:n,warnings:o};const{apiKey:i,projectId:a,apiBase:s}=t;i?typeof i!="string"?n.push(`apiKey must be a string, got ${Se(i)}.`):Hn.test(i)?n.push(`apiKey is still the placeholder "${i}" — paste the key you saved when you created it.`):er.test(i)?o.push("apiKey looks like a project id — did you swap apiKey and projectId?"):i.startsWith("bc_")||o.push('apiKey does not look like a BugCatch key (they start with "bc_live_") — reports will be refused with HTTP 401.'):n.push("apiKey is required — create one under Workspace Settings → API Keys."),a?typeof a!="string"?n.push(`projectId must be a string, got ${Se(a)}.`):Hn.test(a)?n.push(`projectId is still the placeholder "${a}".`):a.startsWith("bc_")?o.push("projectId looks like an API key — did you swap apiKey and projectId?"):/\s/.test(a)&&o.push("projectId contains whitespace — check it was copied cleanly."):n.push("projectId is required — copy it from Project Settings → Web SDK."),s==null?!e||/^(localhost|127\.|0\.0\.0\.0|\[::1\])/.test(e)||o.push("apiBase is not set, so reports go to http://localhost:3000 — set apiBase to your BugCatch API URL."):(typeof s!="string"||!/^https?:\/\//.test(s))&&o.push(`apiBase should be an absolute http(s) URL, got ${JSON.stringify(s)}.`);for(const l of Object.keys(t)){if(On.includes(l))continue;const p=Ga(l);o.push(p?`unknown option "${l}" — did you mean "${p}"?`:`unknown option "${l}" is ignored.`)}for(const l of Za){const p=t[l];p!=null&&typeof p!="function"&&o.push(`${l} should be a function, got ${Se(p)} — it will not be called.`)}return{errors:n,warnings:o}}function nr(t){return typeof t=="string"?t.replace(/\/+$/,""):t}const ht={name:"@sphoro/bugcatch-web-sdk",version:"0.15.0"},Ue={apiBase:"http://localhost:3000",apiKey:null,projectId:null,consoleLimit:100,networkLimit:50,captureConsole:!0,captureNetwork:!0,captureErrors:!0,widget:!0,widgetPosition:"bottom-right",theme:"auto",accent:"#4F46E5",attachments:!0,maxAttachments:5,maxAttachmentBytes:25*1024*1024,maxRecordingMs:12e4,beforeSend:null,user:null,updates:!0,updateToast:!0,onUpdate:null,voice:!0,onCallState:null,onIncomingCall:null,onReportSubmitted:null,onAssistantPhase:null,onError:null,context:null,debug:!1};class qn{constructor(){ao(this,E);this.config={...Ue},this.started=!1,this.teardown=[],this.consoleBuffer=et(Ue.consoleLimit),this.networkBuffer=et(Ue.networkLimit),this.stopWatching=null,this.notifier=null,this.call=null,this.callStarting=!1,this.ringing=null,this.listeners=new Map,this.context={},this.warned=new Set,this.phases=new Map}warn(e){this.warned.has(e)||(this.warned.add(e),console.warn(`[BugCatch] ${e}`))}debugLog(...e){this.config.debug&&console.info("[BugCatch]",...e)}init(e={}){if(this.started)return console.warn("[BugCatch] init() called twice — ignoring the second call."),this;const{errors:n,warnings:o}=tr(e,{pageHost:typeof location<"u"?location.hostname:""});if(n.length)throw new Error(`[BugCatch] ${n[0]}`);for(const a of o)this.warn(a);const i=this.config.user;return this.config={...Ue,...e,apiBase:nr(e.apiBase??Ue.apiBase)},this.config.user=e.user!==void 0?zn(e.user,a=>this.warn(a.replace("identify()","init({ user })"))):i||null,e.context&&this.setContext(e.context),this.consoleBuffer=et(this.config.consoleLimit),this.networkBuffer=et(this.config.networkLimit),this.config.captureConsole&&this.teardown.push(yo(this.consoleBuffer)),this.config.captureNetwork&&this.teardown.push(wo(this.networkBuffer)),this.config.captureErrors&&this.teardown.push(vo(this.consoleBuffer)),this.config.widget&&this.teardown.push(ka(this)),this.config.updates&&ce()&&(this.startWatching(),queueMicrotask(()=>H(this,E,Te).call(this))),this.started=!0,this.debugLog("initialised",{version:ht.version,apiBase:this.config.apiBase,projectId:this.config.projectId,user:this.config.user,context:this.context}),this}startWatching(){if(this.stopWatching)return this;this.stopWatching=ta({apiBase:this.config.apiBase,onUpdate:n=>{if(n!=null&&n.incomingCall){H(this,E,co).call(this,n);return}if(n!=null&&n.callWithdrawn){H(this,E,St).call(this,n.callWithdrawn.callId);return}const o=Po(n);typeof this.config.onUpdate=="function"&&this.config.onUpdate(o),this.emit("update",o),H(this,E,Te).call(this)}}),this.teardown.push(()=>{var n;return(n=this.stopWatching)==null?void 0:n.call(this)}),this.teardown.push(()=>H(this,E,St).call(this));const e=n=>{(n.key===st||n.key===null)&&H(this,E,Te).call(this)};return window.addEventListener("storage",e),this.teardown.push(()=>window.removeEventListener("storage",e)),this}on(e,n){if(typeof n!="function")return()=>{};const o=this.listeners.get(e)||new Set;return o.add(n),this.listeners.set(e,o),()=>this.off(e,n)}off(e,n){var o;return(o=this.listeners.get(e))==null||o.delete(n),this}emit(e,n){for(const o of this.listeners.get(e)||[])try{o(n)}catch(i){console.error(`[BugCatch] a '${e}' listener threw:`,i)}}unreadUpdates(){return qe()}markUpdateRead(e){return _o(e),H(this,E,Te).call(this),this}markReportRead(e){return Vo(e),H(this,E,Te).call(this),this}markUpdatesRead(){return cn(),H(this,E,Te).call(this),this}async verifyFix(e,{result:n,resolvedAt:o,note:i}){const a=n==="STILL_HAPPENING"?await H(this,E,kt).call(this,{}):{};return pa({apiBase:this.config.apiBase,bugId:e,result:n,resolvedAt:o,note:i,metadata:a.metadata,logs:a.logs})}async myReport(e){const n=await Yo({apiBase:this.config.apiBase,bugId:e});return H(this,E,ro).call(this,e,n==null?void 0:n.assistant),n}replyToReport(e,{body:n,attachments:o}={}){return ln({apiBase:this.config.apiBase,bugId:e,body:n,attachments:o})}async canCallNow(){return!!await this.callKind()}async callKind(){return(await this.callKinds()).live?"live":null}async callKinds(){var n;const e={agent:!1,live:!1};return!this.config.voice||!((n=this.config.user)!=null&&n.email)?e:this.kinds!==void 0?this.kinds:(this.kinds=await Xo({apiBase:this.config.apiBase,apiKey:this.config.apiKey,projectId:this.config.projectId}),this.kinds)}canCall(e){return this.config.voice?dn({apiBase:this.config.apiBase,bugId:e}):Promise.resolve(!1)}async startCall(e){var n;if(!this.config.voice)throw new Error("[BugCatch] calling is switched off.");if(this.call||this.callStarting)throw new Error("[BugCatch] a call is already running.");this.callStarting=!0;try{if(!await this.callKind())throw new Error((n=this.config.user)!=null&&n.email?"[BugCatch] calling is not available on this project.":"[BugCatch] a call needs to know who is calling — call identify() with an email first.");return await H(this,E,so).call(this,e)}finally{this.callStarting=!1}}startLiveCall(e){return this.startCall(e)}canCallTeam(e){return this.config.voice?dn({apiBase:this.config.apiBase,bugId:e}):Promise.resolve(!1)}endCall(){var e;return(e=this.call)==null||e.hangUp(),this.call=null,this}myReports(){return Wo({apiBase:this.config.apiBase})}hasReports(){return!!ce()}forgetReports(){var e;return(e=this.stopWatching)==null||e.call(this),this.stopWatching=null,this.endCall(),Ie(),H(this,E,Te).call(this),this}identify(e){const n=zn(e,o=>this.warn(o));return e!=null&&!n?this:(this.config.user=n,this.debugLog("identify",n),this)}setContext(e){return this.context=Qn(this.context,e,n=>this.warn(n)),this.debugLog("context",this.context),this}getContext(){return{...this.context}}open(){return this.started?this.widgetControls?(this.widgetControls.open(),this):(this.warn("open() needs the built-in widget; it was turned off with widget: false."),this):(this.warn("open() was called before init() — nothing to open yet."),this)}close(){var e;return(e=this.widgetControls)==null||e.close(),this}isOpen(){var e;return!!((e=this.widgetControls)!=null&&e.isOpen())}async uploadAttachment(e,n,o){if(!this.started)throw new Error("[BugCatch] call init() first.");return Ao({apiBase:this.config.apiBase,apiKey:this.config.apiKey,blob:e,mime:n||(e==null?void 0:e.type),onProgress:o})}async report({title:e,description:n="",priority:o="MEDIUM",metadata:i={},attachments:a=[],references:s=[],context:l=null}={}){var T,Q,V,$,L,B,j,N;if(!this.started)throw new Error("[BugCatch] call init() first.");if(typeof e!="string"||!e.trim())throw new Error("[BugCatch] a title is required.");["LOW","MEDIUM","HIGH","CRITICAL"].includes(String(o).toUpperCase())||(this.warn(`priority "${o}" is not one of LOW, MEDIUM, HIGH, CRITICAL — sent as MEDIUM.`),o="MEDIUM");const p=(a||[]).filter(S=>(S==null?void 0:S.storageKey)&&nt(S.mime,tt)).map(S=>({type:S.type==="VIDEO"?"VIDEO":"SCREENSHOT",storageKey:S.storageKey,mime:nt(S.mime,tt)})),h=(Array.isArray(s)?s:[]).filter(S=>S&&typeof S.key=="string"&&S.key&&(typeof S.value=="string"||typeof S.value=="number")).map(S=>({key:S.key.slice(0,64),value:String(S.value).trim().slice(0,120)})).filter(S=>S.value);Array.isArray(s)&&h.length<s.length&&this.warn("report({ references }) takes [{ key, value }] with string values; malformed entries were dropped.");let b=await H(this,E,kt).call(this,{title:e.trim(),description:typeof n=="string"?n:String(n??""),priority:String(o).toUpperCase(),metadata:i,media:p,references:h,context:l});if(typeof this.config.beforeSend=="function"){const S=this.config.beforeSend(b);if(S===!1)return{cancelled:!0};S&&typeof S=="object"&&(b=S)}this.debugLog("sending report",{title:b.title,user:(T=b.metadata)==null?void 0:T.user,context:(Q=b.metadata)==null?void 0:Q.context,references:b.references,console:(L=($=(V=b.logs)==null?void 0:V.console)==null?void 0:$.entries)==null?void 0:L.length,network:(N=(j=(B=b.logs)==null?void 0:B.network)==null?void 0:j.entries)==null?void 0:N.length});const f=ke(this.config.projectId);let m;try{m=await fetch(`${this.config.apiBase}/ingest/bugs`,{method:"POST",headers:{"Content-Type":"application/json","X-BugCatch-Key":this.config.apiKey,...f!=null&&f.token?{"X-BugCatch-Session":f.token}:{}},body:JSON.stringify(b)})}catch(S){const U=new Error(`[BugCatch] could not reach ${this.config.apiBase} — check apiBase, and that this site's origin is allowed by the API.`);throw U.cause=S,H(this,E,xt).call(this,"report",U),U}if(m.status===401&&f&&It(this.config.projectId),!m.ok){let S="";try{const q=await m.json();S=Array.isArray(q.message)?q.message.join(", "):q.message||""}catch{}m.status===401&&!f&&(S||(S="the apiKey was not accepted")),m.status===403&&(S||(S="the apiKey is not allowed to report to this projectId"));const U=new Error(`[BugCatch] report failed (HTTP ${m.status})${S?": "+S:""}`);throw U.status=m.status,H(this,E,xt).call(this,"report",U),U}const g=await m.json();return H(this,E,Yt).call(this,g,{title:b.title??e.trim(),via:"form"}),g.watchToken&&(At(g.watchToken),this.config.updates&&this.startWatching()),g}loginState(){var e;return Ho({apiBase:this.config.apiBase,apiKey:this.config.apiKey,projectId:this.config.projectId,token:(e=ke(this.config.projectId))==null?void 0:e.token})}referenceFields(){return this.refFields?this.refFields:(this.refFields=ma({apiBase:this.config.apiBase,apiKey:this.config.apiKey,projectId:this.config.projectId}),this.refFields)}signedInAs(){const e=ke(this.config.projectId);return e?{email:e.email,name:e.name}:null}signIn(e,{name:n}={}){var o;return qo({apiBase:this.config.apiBase,apiKey:this.config.apiKey,projectId:this.config.projectId,email:e,name:n??((o=this.config.user)==null?void 0:o.name)??null})}async confirmSignIn(e,n){var i;const o=await Do({apiBase:this.config.apiBase,apiKey:this.config.apiKey,projectId:this.config.projectId,email:e,code:n});return(i=this.config.user)!=null&&i.email||(this.config.user={email:o.email,name:o.name||void 0}),this.emit("signin",{email:o.email,name:o.name}),{email:o.email,name:o.name}}async signOut(){var o;const e=ke(this.config.projectId),n=await No({apiBase:this.config.apiBase,apiKey:this.config.apiKey,projectId:this.config.projectId,token:e==null?void 0:e.token});return e!=null&&e.email&&((o=this.config.user)==null?void 0:o.email)===e.email&&(this.config.user=null),this.emit("signout",{email:(e==null?void 0:e.email)||null}),n}knownIssues(){var e;return ca({apiBase:this.config.apiBase,apiKey:this.config.apiKey,projectId:this.config.projectId,sessionToken:(e=ke(this.config.projectId))==null?void 0:e.token})}matchKnownIssues(e,{signal:n}={}){var o;return la({apiBase:this.config.apiBase,apiKey:this.config.apiKey,projectId:this.config.projectId,q:e||"",sessionToken:(o=ke(this.config.projectId))==null?void 0:o.token,signal:n})}async meToo(e,{email:n,name:o}={}){var s,l;const i=ke(this.config.projectId),a=await tn();return da({apiBase:this.config.apiBase,apiKey:this.config.apiKey,projectId:this.config.projectId,bugId:e,reporterEmail:n||((s=this.config.user)==null?void 0:s.email),reporterName:o||((l=this.config.user)==null?void 0:l.name),metadata:{...a,user:this.config.user||void 0,...Object.keys(this.context).length?{context:this.context}:{},sdk:ht},logs:{console:{entries:this.consoleBuffer.all()},network:{entries:this.networkBuffer.all()}},sessionToken:i==null?void 0:i.token})}snapshot(){return{user:this.config.user||null,context:{...this.context},console:this.consoleBuffer.all(),network:this.networkBuffer.all(),environment:nn()}}clear(){this.consoleBuffer.clear(),this.networkBuffer.clear()}destroy(){this.endCall(),this.teardown.forEach(e=>{try{e()}catch{}}),this.teardown=[],this.notifier=null,this.started=!1}}E=new WeakSet,vt=function(e,n){const o=this.config[e];if(typeof o=="function")try{o(n)}catch(i){console.error(`[BugCatch] your ${e} callback threw:`,i)}},Te=function(){const e=qe();if(this.emit("unread",{count:e.length,updates:e}),!!this.config.updateToast){if(!this.notifier){if(!e.length)return;this.notifier=sa({accent:this.config.accent,position:this.config.widgetPosition,onRead:n=>this.markUpdateRead(n),onReadAll:()=>this.markUpdatesRead(),onCall:this.config.voice?n=>{this.markUpdateRead(n.id),this.startCall(n.bugId)}:null}),this.teardown.push(()=>{var n;return(n=this.notifier)==null?void 0:n.destroy()})}this.notifier.render(e)}},ro=function(e,n){const o=n==null?void 0:n.phase;if(!e||typeof o!="string"||this.phases.get(e)===o)return;this.phases.set(e,o);const i={bugId:e,phase:o,title:n.title??null,detail:n.detail??null};this.debugLog("assistant",i),H(this,E,vt).call(this,"onAssistantPhase",i),this.emit("assistant",i)},Yt=function(e,{title:n,via:o}){if(!(e!=null&&e.id))return;const i={bugId:e.id,title:n??null,via:o,result:e};this.debugLog("report accepted",i),H(this,E,vt).call(this,"onReportSubmitted",i),this.emit("report",i)},xt=function(e,n){H(this,E,vt).call(this,"onError",{action:e,error:n}),this.emit("error",{action:e,error:n})},kt=async function({title:e,description:n="",priority:o="MEDIUM",metadata:i={},media:a=[],references:s=[],context:l=null}){var h,b;const p=l?Qn(this.context,l,f=>this.warn(f.replace("setContext()","report({ context })"))):this.context;return{projectId:this.config.projectId,...e?{title:e}:{},description:n,priority:o,url:window.location.href,reporterEmail:(h=this.config.user)==null?void 0:h.email,reporterName:(b=this.config.user)==null?void 0:b.name,metadata:{...await tn(),release:this.config.release,environment:this.config.environment,buildId:this.config.buildId,...i,user:this.config.user||void 0,...Object.keys(p).length?{context:p}:{},sdk:ht},logs:{console:{entries:this.consoleBuffer.all()},network:{entries:this.networkBuffer.all()}},...a.length?{attachments:a}:{},...s.length?{references:s}:{}}},io=async function(){const e=ke(this.config.projectId);let n;try{n=await Jo({apiBase:this.config.apiBase,apiKey:this.config.apiKey,token:e==null?void 0:e.token,payload:await H(this,E,kt).call(this,{})})}catch(o){throw o.status===401&&e&&It(this.config.projectId),H(this,E,xt).call(this,"call",o),o}return H(this,E,Yt).call(this,n,{title:null,via:"call"}),n.watchToken&&(At(n.watchToken),this.config.updates&&this.startWatching()),n},so=async function(e){if(!Ot())throw new Error("[BugCatch] this browser cannot make live calls.");const n=await Qt();let o,i=null;try{if(e)o=await Zo({apiBase:this.config.apiBase,bugId:e});else if(i=await H(this,E,io).call(this),e=i.id,o=i.live_call,!(o!=null&&o.realtime_url)){const s=new Error(`[BugCatch] the report was filed, but the team could not be rung${i.call_error?`: ${i.call_error}`:"."}`);throw s.filed=i,s.reason=i.call_error||null,s}}catch(s){for(const l of n.getTracks())l.stop();throw s}const a=await In({realtimeUrl:o.realtime_url,stream:n,ringsUntil:o.rings_until,onState:(s,l)=>{(s==="ended"||s==="failed"||s==="missed")&&(this.call=null),s==="missed"&&Go({apiBase:this.config.apiBase,bugId:e,callId:o.call_id}),typeof this.config.onCallState=="function"&&this.config.onCallState(s,{bugId:e,live:!0,...l}),this.emit("call",{bugId:e,live:!0,state:s,...l})}});return this.call=a,Object.assign(a,{bugId:e,callId:o.call_id,live:!0,filed:i})},co=function(e){var i;const n=e.incomingCall;if(!this.config.voice||!Ot()||((i=this.ringing)==null?void 0:i.callId)===n.callId||this.call||this.callStarting)return;H(this,E,St).call(this);const o=Va({call:n,accent:this.config.accent,position:this.config.widgetPosition,onAnswer:()=>{H(this,E,lo).call(this,e.bugId,n)},onDecline:()=>{this.ringing=null,un({apiBase:this.config.apiBase,bugId:e.bugId,callId:n.callId}),this.emit("incoming-call",{bugId:e.bugId,callId:n.callId,state:"declined"})},onExpire:()=>{this.ringing=null,this.emit("incoming-call",{bugId:e.bugId,callId:n.callId,state:"missed"})}});if(this.ringing={callId:n.callId,dismiss:o},typeof this.config.onIncomingCall=="function")try{this.config.onIncomingCall({bugId:e.bugId,...n})}catch{}this.emit("incoming-call",{bugId:e.bugId,callId:n.callId,state:"ringing"})},St=function(e){if(this.ringing&&!(e&&this.ringing.callId!==e)){try{this.ringing.dismiss()}catch{}this.ringing=null}},lo=async function(e,n){if(this.ringing=null,this.call||this.callStarting)return;this.callStarting=!0;let o;try{o=await Qt()}catch(a){this.callStarting=!1,un({apiBase:this.config.apiBase,bugId:e,callId:n.callId}),this.emit("incoming-call",{bugId:e,callId:n.callId,state:"failed",error:a});return}let i;try{i=await ea({apiBase:this.config.apiBase,bugId:e,callId:n.callId})}catch(a){for(const s of o.getTracks())s.stop();this.callStarting=!1,this.emit("incoming-call",{bugId:e,callId:n.callId,state:"missed",error:a});return}try{const a=await In({realtimeUrl:i.realtime_url,stream:o,onState:(s,l)=>{(s==="ended"||s==="failed"||s==="missed")&&(this.call=null),typeof this.config.onCallState=="function"&&this.config.onCallState(s,{bugId:e,live:!0,incoming:!0,...l}),this.emit("call",{bugId:e,live:!0,incoming:!0,state:s,...l})}});this.call=a,this.emit("incoming-call",{bugId:e,callId:n.callId,state:"answered"})}catch(a){for(const s of o.getTracks())s.stop();this.emit("incoming-call",{bugId:e,callId:n.callId,state:"failed",error:a})}finally{this.callStarting=!1}};const Dt=new qn;return Dt.Client=qn,Dt.version=ht.version,Dt});
1038
1369
  //# sourceMappingURL=bugcatch.umd.js.map