$P@D$3RV£R commited on
Commit
e123f50
·
1 Parent(s): 8660b24

Release v1.1.31: add anonymous NHS feedback

Browse files
README.md CHANGED
@@ -24,9 +24,9 @@ Support workers talk (or type) to get safety reminders, guided documentation que
24
 
25
  ## Live demo
26
 
27
- **Version:** 1.1.30 — *Backfill Mary Nsaidoo-Storph + William FormSubmit notes*
28
 
29
- There are **two** Hugging Face Spaces (same static build). The first attempt (`careTalk`) briefly used a HF build step that needs paid credits and stuck on **CONFIG_ERROR**; `careTalk-demo` is the clean prebuilt Space. From **v1.1.9** both host the identical release (current: **v1.1.30**).
30
 
31
  | Space | Role | Links |
32
  |---|---|---|
@@ -35,7 +35,7 @@ There are **two** Hugging Face Spaces (same static build). The first attempt (`c
35
 
36
  Use **Chrome** or **Edge** for microphone / speech recognition. Allow mic when prompted. Prefer the **direct app URL** if the Space iframe blocks the mic. Data stays **on the device** (browser `localStorage`) unless you configure agency email/webhook forwarding.
37
 
38
- ### Shared feedback ticker (v1.1.30)
39
 
40
  FormSubmit still emails every submission to the careTalk inbox. New submissions are also published to a **shared public feed**, so the landing ticker shows the same notes for every visitor (name initials, workplace, message) — not only the browser that submitted. Older emails can be backfilled into `public/feedback-feed.json`.
41
 
 
24
 
25
  ## Live demo
26
 
27
+ **Version:** 1.1.31 — *Backfill Mary Nsaidoo-Storph + William FormSubmit notes*
28
 
29
+ There are **two** Hugging Face Spaces (same static build). The first attempt (`careTalk`) briefly used a HF build step that needs paid credits and stuck on **CONFIG_ERROR**; `careTalk-demo` is the clean prebuilt Space. From **v1.1.9** both host the identical release (current: **v1.1.31**).
30
 
31
  | Space | Role | Links |
32
  |---|---|---|
 
35
 
36
  Use **Chrome** or **Edge** for microphone / speech recognition. Allow mic when prompted. Prefer the **direct app URL** if the Space iframe blocks the mic. Data stays **on the device** (browser `localStorage`) unless you configure agency email/webhook forwarding.
37
 
38
+ ### Shared feedback ticker (v1.1.31)
39
 
40
  FormSubmit still emails every submission to the careTalk inbox. New submissions are also published to a **shared public feed**, so the landing ticker shows the same notes for every visitor (name initials, workplace, message) — not only the browser that submitted. Older emails can be backfilled into `public/feedback-feed.json`.
41
 
admin.html CHANGED
@@ -25,9 +25,9 @@
25
  href="https://fonts.googleapis.com/css2?family=Fraunces:opsz,wght@9..144,550;9..144,700&family=Source+Sans+3:wght@400;600;700&display=swap"
26
  rel="stylesheet"
27
  />
28
- <script type="module" crossorigin src="./assets/admin-obUvnyby.js"></script>
29
  <link rel="modulepreload" crossorigin href="./assets/theme-CuaEyjDL.js">
30
- <link rel="modulepreload" crossorigin href="./assets/subscribers-DkYmS9Go.js">
31
  <link rel="stylesheet" crossorigin href="./assets/subscribers-BHyrZ7wW.css">
32
  <link rel="manifest" href="./manifest.webmanifest"><script id="vite-plugin-pwa:register-sw" src="./registerSW.js"></script></head>
33
  <body class="admin-page">
@@ -58,7 +58,7 @@
58
 
59
  <main class="section band">
60
  <div class="section-inner admin-wrap">
61
- <p class="version-pill">Version <span data-app-version>1.1.30</span></p>
62
 
63
  <section id="adminLogin" class="admin-card" aria-labelledby="admin-login-title">
64
  <h1 id="admin-login-title">Updates access</h1>
@@ -86,7 +86,7 @@
86
  <h1 id="admin-panel-title">Subscribers</h1>
87
  <p class="lede">
88
  <strong id="subscriberCount">0</strong> email(s) on this browser
89
- · careTalk <span data-app-version>1.1.30</span>
90
  </p>
91
  </div>
92
  <div class="admin-actions">
@@ -123,7 +123,7 @@
123
 
124
  <footer class="site-footer">
125
  <div class="section-inner">
126
- <p>careTalk ops · v<span data-app-version>1.1.30</span></p>
127
  </div>
128
  </footer>
129
 
 
25
  href="https://fonts.googleapis.com/css2?family=Fraunces:opsz,wght@9..144,550;9..144,700&family=Source+Sans+3:wght@400;600;700&display=swap"
26
  rel="stylesheet"
27
  />
28
+ <script type="module" crossorigin src="./assets/admin-COcnhFD_.js"></script>
29
  <link rel="modulepreload" crossorigin href="./assets/theme-CuaEyjDL.js">
30
+ <link rel="modulepreload" crossorigin href="./assets/subscribers-CLCOf4GQ.js">
31
  <link rel="stylesheet" crossorigin href="./assets/subscribers-BHyrZ7wW.css">
32
  <link rel="manifest" href="./manifest.webmanifest"><script id="vite-plugin-pwa:register-sw" src="./registerSW.js"></script></head>
33
  <body class="admin-page">
 
58
 
59
  <main class="section band">
60
  <div class="section-inner admin-wrap">
61
+ <p class="version-pill">Version <span data-app-version>1.1.31</span></p>
62
 
63
  <section id="adminLogin" class="admin-card" aria-labelledby="admin-login-title">
64
  <h1 id="admin-login-title">Updates access</h1>
 
86
  <h1 id="admin-panel-title">Subscribers</h1>
87
  <p class="lede">
88
  <strong id="subscriberCount">0</strong> email(s) on this browser
89
+ · careTalk <span data-app-version>1.1.31</span>
90
  </p>
91
  </div>
92
  <div class="admin-actions">
 
123
 
124
  <footer class="site-footer">
125
  <div class="section-inner">
126
+ <p>careTalk ops · v<span data-app-version>1.1.31</span></p>
127
  </div>
128
  </footer>
129
 
app.html CHANGED
@@ -34,7 +34,7 @@
34
  if (!isDemo) return;
35
  sessionStorage.removeItem("don.session.userId");
36
  sessionStorage.removeItem("don.train.authed");
37
- var appVer = "1.1.30";
38
  var flag = "don.demo.appVer";
39
  if (localStorage.getItem(flag) === appVer) return;
40
  localStorage.setItem(flag, appVer);
@@ -57,7 +57,7 @@
57
  } catch (e) {}
58
  })();
59
  </script>
60
- <script type="module" crossorigin src="./assets/app-ipj-_NCA.js"></script>
61
  <link rel="modulepreload" crossorigin href="./assets/theme-CuaEyjDL.js">
62
  <link rel="stylesheet" crossorigin href="./assets/app-DT9iTHEE.css">
63
  <link rel="manifest" href="./manifest.webmanifest"><script id="vite-plugin-pwa:register-sw" src="./registerSW.js"></script></head>
 
34
  if (!isDemo) return;
35
  sessionStorage.removeItem("don.session.userId");
36
  sessionStorage.removeItem("don.train.authed");
37
+ var appVer = "1.1.31";
38
  var flag = "don.demo.appVer";
39
  if (localStorage.getItem(flag) === appVer) return;
40
  localStorage.setItem(flag, appVer);
 
57
  } catch (e) {}
58
  })();
59
  </script>
60
+ <script type="module" crossorigin src="./assets/app-Cr21RCtM.js"></script>
61
  <link rel="modulepreload" crossorigin href="./assets/theme-CuaEyjDL.js">
62
  <link rel="stylesheet" crossorigin href="./assets/app-DT9iTHEE.css">
63
  <link rel="manifest" href="./manifest.webmanifest"><script id="vite-plugin-pwa:register-sw" src="./registerSW.js"></script></head>
assets/{admin-obUvnyby.js → admin-COcnhFD_.js} RENAMED
@@ -1,4 +1,4 @@
1
- import{i as f}from"./theme-CuaEyjDL.js";import{A as g,i as v,s as p,a as y,c as E,r as h,b as L,d as B}from"./subscribers-DkYmS9Go.js";function i(e){return String(e||"").replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;")}function I(e){if(!e)return"—";try{return new Date(e).toLocaleString("en-GB",{day:"numeric",month:"short",year:"numeric",hour:"2-digit",minute:"2-digit"})}catch{return e}}function a(e){const r=document.getElementById("adminLogin"),n=document.getElementById("adminPanel");r&&(r.hidden=e),n&&(n.hidden=!e)}function o(){const e=L(),r=document.getElementById("subscriberRows"),n=document.getElementById("subscriberEmpty"),t=document.getElementById("subscriberCount");t&&(t.textContent=String(e.length)),r&&(r.innerHTML=e.map(s=>`<tr data-id="${i(s.id)}">
2
  <td>${i(s.email)}</td>
3
  <td>${i(s.name||"—")}</td>
4
  <td>${i(I(s.at))}</td>
 
1
+ import{i as f}from"./theme-CuaEyjDL.js";import{A as g,i as v,s as p,a as y,c as E,r as h,b as L,d as B}from"./subscribers-CLCOf4GQ.js";function i(e){return String(e||"").replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;")}function I(e){if(!e)return"—";try{return new Date(e).toLocaleString("en-GB",{day:"numeric",month:"short",year:"numeric",hour:"2-digit",minute:"2-digit"})}catch{return e}}function a(e){const r=document.getElementById("adminLogin"),n=document.getElementById("adminPanel");r&&(r.hidden=e),n&&(n.hidden=!e)}function o(){const e=L(),r=document.getElementById("subscriberRows"),n=document.getElementById("subscriberEmpty"),t=document.getElementById("subscriberCount");t&&(t.textContent=String(e.length)),r&&(r.innerHTML=e.map(s=>`<tr data-id="${i(s.id)}">
2
  <td>${i(s.email)}</td>
3
  <td>${i(s.name||"—")}</td>
4
  <td>${i(I(s.at))}</td>
assets/{app-ipj-_NCA.js → app-Cr21RCtM.js} RENAMED
@@ -1,5 +1,5 @@
1
- const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["./web-BVF1lTpL.js","./theme-CuaEyjDL.js","./web-o2G7w9Em.js","./web-BhapuqNa.js"])))=>i.map(i=>d[i]);
2
- import{i as zr}from"./theme-CuaEyjDL.js";/*! Capacitor: https://capacitorjs.com/ - MIT License */var Pe;(function(e){e.Unimplemented="UNIMPLEMENTED",e.Unavailable="UNAVAILABLE"})(Pe||(Pe={}));class $t extends Error{constructor(t,n,i){super(t),this.message=t,this.code=n,this.data=i}}const Kr=e=>{var t,n;return e!=null&&e.androidBridge?"android":!((n=(t=e==null?void 0:e.webkit)===null||t===void 0?void 0:t.messageHandlers)===null||n===void 0)&&n.bridge?"ios":"web"},Yr=e=>{const t=e.CapacitorCustomPlatform||null,n=e.Capacitor||{},i=n.Plugins=n.Plugins||{},r=()=>t!==null?t.name:Kr(e),o=()=>r()!=="web",a=f=>{const g=d.get(f);return!!(g!=null&&g.platforms.has(r())||s(f))},s=f=>{var g;return(g=n.PluginHeaders)===null||g===void 0?void 0:g.find(w=>w.name===f)},l=f=>e.console.error(f),d=new Map,u=(f,g={})=>{const w=d.get(f);if(w)return console.warn(`Capacitor plugin "${f}" already registered. Cannot register plugins twice.`),w.proxy;const y=r(),k=s(f);let v;const $=async()=>(!v&&y in g?v=typeof g[y]=="function"?v=await g[y]():v=g[y]:t!==null&&!v&&"web"in g&&(v=typeof g.web=="function"?v=await g.web():v=g.web),v),E=(R,_)=>{var K,Y;if(k){const J=k==null?void 0:k.methods.find(Z=>_===Z.name);if(J)return J.rtype==="promise"?Z=>n.nativePromise(f,_.toString(),Z):(Z,Ce)=>n.nativeCallback(f,_.toString(),Z,Ce);if(R)return(K=R[_])===null||K===void 0?void 0:K.bind(R)}else{if(R)return(Y=R[_])===null||Y===void 0?void 0:Y.bind(R);throw new $t(`"${f}" plugin is not implemented on ${y}`,Pe.Unimplemented)}},D=R=>{let _;const K=(...Y)=>{const J=$().then(Z=>{const Ce=E(Z,R);if(Ce){const fe=Ce(...Y);return _=fe==null?void 0:fe.remove,fe}else throw new $t(`"${f}.${R}()" is not implemented on ${y}`,Pe.Unimplemented)});return R==="addListener"&&(J.remove=async()=>_()),J};return K.toString=()=>`${R.toString()}() { [capacitor code] }`,Object.defineProperty(K,"name",{value:R,writable:!1,configurable:!1}),K},ie=D("addListener"),U=D("removeListener"),x=(R,_)=>{const K=ie({eventName:R},_),Y=async()=>{const Z=await K;U({eventName:R,callbackId:Z},_)},J=new Promise(Z=>K.then(()=>Z({remove:Y})));return J.remove=async()=>{console.warn("Using addListener() without 'await' is deprecated."),await Y()},J},z=new Proxy({},{get(R,_){switch(_){case"$$typeof":return;case"toJSON":return()=>({});case"addListener":return k?x:ie;case"removeListener":return U;default:return D(_)}}});return i[f]=z,d.set(f,{name:f,proxy:z,platforms:new Set([...Object.keys(g),...k?[y]:[]])}),z};return n.convertFileSrc||(n.convertFileSrc=f=>f),n.getPlatform=r,n.handleError=l,n.isNativePlatform=o,n.isPluginAvailable=a,n.registerPlugin=u,n.Exception=$t,n.DEBUG=!!n.DEBUG,n.isLoggingEnabled=!!n.isLoggingEnabled,n},Jr=e=>e.Capacitor=Yr(e),Oe=Jr(typeof globalThis<"u"?globalThis:typeof self<"u"?self:typeof window<"u"?window:typeof global<"u"?global:{}),Se=Oe.registerPlugin;class tr{constructor(){this.listeners={},this.retainedEventArguments={},this.windowListeners={}}addListener(t,n){let i=!1;this.listeners[t]||(this.listeners[t]=[],i=!0),this.listeners[t].push(n);const o=this.windowListeners[t];o&&!o.registered&&this.addWindowListener(o),i&&this.sendRetainedArgumentsForEvent(t);const a=async()=>this.removeListener(t,n);return Promise.resolve({remove:a})}async removeAllListeners(){this.listeners={};for(const t in this.windowListeners)this.removeWindowListener(this.windowListeners[t]);this.windowListeners={}}notifyListeners(t,n,i){const r=this.listeners[t];if(!r){if(i){let o=this.retainedEventArguments[t];o||(o=[]),o.push(n),this.retainedEventArguments[t]=o}return}r.forEach(o=>o(n))}hasListeners(t){var n;return!!(!((n=this.listeners[t])===null||n===void 0)&&n.length)}registerWindowListener(t,n){this.windowListeners[n]={registered:!1,windowEventName:t,pluginEventName:n,handler:i=>{this.notifyListeners(n,i)}}}unimplemented(t="not implemented"){return new Oe.Exception(t,Pe.Unimplemented)}unavailable(t="not available"){return new Oe.Exception(t,Pe.Unavailable)}async removeListener(t,n){const i=this.listeners[t];if(!i)return;const r=i.indexOf(n);this.listeners[t].splice(r,1),this.listeners[t].length||this.removeWindowListener(this.windowListeners[t])}addWindowListener(t){window.addEventListener(t.windowEventName,t.handler),t.registered=!0}removeWindowListener(t){t&&(window.removeEventListener(t.windowEventName,t.handler),t.registered=!1)}sendRetainedArgumentsForEvent(t){const n=this.retainedEventArguments[t];n&&(delete this.retainedEventArguments[t],n.forEach(i=>{this.notifyListeners(t,i)}))}}const en=e=>encodeURIComponent(e).replace(/%(2[346B]|5E|60|7C)/g,decodeURIComponent).replace(/[()]/g,escape),tn=e=>e.replace(/(%[\dA-F]{2})+/gi,decodeURIComponent);class Zr extends tr{async getCookies(){const t=document.cookie,n={};return t.split(";").forEach(i=>{if(i.length<=0)return;let[r,o]=i.replace(/=/,"CAP_COOKIE").split("CAP_COOKIE");r=tn(r).trim(),o=tn(o).trim(),n[r]=o}),n}async setCookie(t){try{const n=en(t.key),i=en(t.value),r=t.expires?`; expires=${t.expires.replace("expires=","")}`:"",o=(t.path||"/").replace("path=",""),a=t.url!=null&&t.url.length>0?`domain=${t.url}`:"";document.cookie=`${n}=${i||""}${r}; path=${o}; ${a};`}catch(n){return Promise.reject(n)}}async deleteCookie(t){try{document.cookie=`${t.key}=; Max-Age=0`}catch(n){return Promise.reject(n)}}async clearCookies(){try{const t=document.cookie.split(";")||[];for(const n of t)document.cookie=n.replace(/^ +/,"").replace(/=.*/,`=;expires=${new Date().toUTCString()};path=/`)}catch(t){return Promise.reject(t)}}async clearAllCookies(){try{await this.clearCookies()}catch(t){return Promise.reject(t)}}}Se("CapacitorCookies",{web:()=>new Zr});const Qr=async e=>new Promise((t,n)=>{const i=new FileReader;i.onload=()=>{const r=i.result;t(r.indexOf(",")>=0?r.split(",")[1]:r)},i.onerror=r=>n(r),i.readAsDataURL(e)}),Xr=(e={})=>{const t=Object.keys(e);return Object.keys(e).map(r=>r.toLocaleLowerCase()).reduce((r,o,a)=>(r[o]=e[t[a]],r),{})},ei=(e,t=!0)=>e?Object.entries(e).reduce((i,r)=>{const[o,a]=r;let s,l;return Array.isArray(a)?(l="",a.forEach(d=>{s=t?encodeURIComponent(d):d,l+=`${o}=${s}&`}),l.slice(0,-1)):(s=t?encodeURIComponent(a):a,l=`${o}=${s}`),`${i}&${l}`},"").substr(1):null,ti=(e,t={})=>{const n=Object.assign({method:e.method||"GET",headers:e.headers},t),r=Xr(e.headers)["content-type"]||"";if(typeof e.data=="string")n.body=e.data;else if(r.includes("application/x-www-form-urlencoded")){const o=new URLSearchParams;for(const[a,s]of Object.entries(e.data||{}))o.set(a,s);n.body=o.toString()}else if(r.includes("multipart/form-data")||e.data instanceof FormData){const o=new FormData;if(e.data instanceof FormData)e.data.forEach((s,l)=>{o.append(l,s)});else for(const s of Object.keys(e.data))o.append(s,e.data[s]);n.body=o;const a=new Headers(n.headers);a.delete("content-type"),n.headers=a}else(r.includes("application/json")||typeof e.data=="object")&&(n.body=JSON.stringify(e.data));return n};class ni extends tr{async request(t){const n=ti(t,t.webFetchExtra),i=ei(t.params,t.shouldEncodeUrlParams),r=i?`${t.url}?${i}`:t.url,o=await fetch(r,n),a=o.headers.get("content-type")||"";let{responseType:s="text"}=o.ok?t:{};a.includes("application/json")&&(s="json");let l,d;switch(s){case"arraybuffer":case"blob":d=await o.blob(),l=await Qr(d);break;case"json":l=await o.json();break;case"document":case"text":default:l=await o.text()}const u={};return o.headers.forEach((f,g)=>{u[g]=f}),{data:l,headers:u,status:o.status,url:o.url}}async get(t){return this.request(Object.assign(Object.assign({},t),{method:"GET"}))}async post(t){return this.request(Object.assign(Object.assign({},t),{method:"POST"}))}async put(t){return this.request(Object.assign(Object.assign({},t),{method:"PUT"}))}async patch(t){return this.request(Object.assign(Object.assign({},t),{method:"PATCH"}))}async delete(t){return this.request(Object.assign(Object.assign({},t),{method:"DELETE"}))}}Se("CapacitorHttp",{web:()=>new ni});const ri="modulepreload",ii=function(e,t){return new URL(e,t).href},nn={},Ut=function(t,n,i){let r=Promise.resolve();if(n&&n.length>0){let a=function(u){return Promise.all(u.map(f=>Promise.resolve(f).then(g=>({status:"fulfilled",value:g}),g=>({status:"rejected",reason:g}))))};const s=document.getElementsByTagName("link"),l=document.querySelector("meta[property=csp-nonce]"),d=(l==null?void 0:l.nonce)||(l==null?void 0:l.getAttribute("nonce"));r=a(n.map(u=>{if(u=ii(u,i),u in nn)return;nn[u]=!0;const f=u.endsWith(".css"),g=f?'[rel="stylesheet"]':"";if(!!i)for(let k=s.length-1;k>=0;k--){const v=s[k];if(v.href===u&&(!f||v.rel==="stylesheet"))return}else if(document.querySelector(`link[href="${u}"]${g}`))return;const y=document.createElement("link");if(y.rel=f?"stylesheet":ri,f||(y.as="script"),y.crossOrigin="",y.href=u,d&&y.setAttribute("nonce",d),document.head.appendChild(y),f)return new Promise((k,v)=>{y.addEventListener("load",k),y.addEventListener("error",()=>v(new Error(`Unable to preload CSS for ${u}`)))})}))}function o(a){const s=new Event("vite:preloadError",{cancelable:!0});if(s.payload=a,window.dispatchEvent(s),!s.defaultPrevented)throw a}return r.then(a=>{for(const s of a||[])s.status==="rejected"&&o(s.reason);return t().catch(o)})},ge=Se("SpeechRecognition",{web:()=>Ut(()=>import("./web-BVF1lTpL.js"),__vite__mapDeps([0,1]),import.meta.url).then(e=>new e.SpeechRecognitionWeb)});function Ze(){return Oe.isNativePlatform()}function oi({onFinal:e,onPartial:t,onStart:n,onEnd:i,onError:r,lang:o="en-GB"}){let a=!1,s=null,l=null,d=null,u=!1,f="",g=0,w="",y=null,k=null,v=o,$=!1,E=!1,D=!1,ie=0,U="";function x(I){const b=String(I||"").trim();if(!b)return!0;try{if(b===window.location.href||b===window.location.origin||b===window.location.host||b===`${window.location.protocol}//${window.location.host}`)return!0}catch{}return!!(/^https?:\/\//i.test(b)||/\blocalhost(:\d+)?\b/i.test(b)||/\b127\.0\.0\.1\b/.test(b)||/mic (issue|blocked|busy)|speech needs internet|no microphone|asking for microphone/i.test(b)||!/[a-zA-Z]{2,}/.test(b))}function z(I){const b=String(I||"").trim();if(!b||x(b)||D||E)return;const T=Date.now();b.toLowerCase()===w.toLowerCase()&&T-g<1200||(w=b,g=T,f="",clearTimeout(y),e==null||e(b))}function R(I){const b=String(I||"").trim();if(!b||x(b))return;f=b,t==null||t(b),clearTimeout(y);const T=b.split(/\s+/).filter(Boolean).length,M=T<=3?1100:T<=8?1500:1900;y=setTimeout(()=>{f===b&&!D&&!E&&z(b)},M)}function _(I){var T;let b="";for(let M=0;M<I.length;M+=1){const C=(((T=I[M])==null?void 0:T.transcript)||"").trim();if(C&&(b||(b=C),/\b(don|dawn|done|dom|dun|donn|donald)\b/i.test(C))){b=C;break}}return b}async function K(){var T,M;if(!window.isSecureContext)throw new Error("Mic blocked on insecure URL — open http://localhost:5173 in Chrome");if(!((T=navigator.mediaDevices)!=null&&T.getUserMedia))throw new Error("This window can’t use the mic — open the app in Chrome or Edge");let I;try{I=await navigator.mediaDevices.getUserMedia({audio:{echoCancellation:!0,noiseSuppression:!0,autoGainControl:!0}})}catch(C){const ne=(C==null?void 0:C.name)||"";throw ne==="NotFoundError"||ne==="DevicesNotFoundError"?new Error("No microphone detected — plug one in (System Settings → Sound → Input)"):ne==="NotAllowedError"||ne==="PermissionDeniedError"?new Error("Microphone permission denied — click the lock icon → Microphone → Allow"):ne==="NotReadableError"||ne==="TrackStartError"?new Error("Microphone is busy — quit Zoom/Teams/FaceTime/OBS, then tap the mic again"):new Error((C==null?void 0:C.message)||"Could not open microphone")}const b=I.getAudioTracks()[0];if(U=(b==null?void 0:b.label)||"Microphone",b&&b.readyState!=="live")throw I.getTracks().forEach(C=>C.stop()),new Error("Microphone track inactive — check Mac Sound input device");I.getTracks().forEach(C=>C.stop()),await new Promise(C=>setTimeout(C,180));try{if(!(await navigator.mediaDevices.enumerateDevices()).filter(Vr=>Vr.kind==="audioinput").length)throw new Error("No audio input devices listed — check System Settings → Sound → Input")}catch(C){if((M=C==null?void 0:C.message)!=null&&M.startsWith("No audio"))throw C}return U}function Y(){if(!(!u||!s||$||E)){$=!0;try{s.lang=v,s.start()}catch(I){const b=String((I==null?void 0:I.message)||I||"");/already started|InvalidStateError/i.test(b)||r==null||r(b||"Could not start mic")}finally{setTimeout(()=>{$=!1},300)}}}function J(I=300){!u||E||(clearTimeout(k),k=setTimeout(()=>{!u||E||Y()},I))}function Z(){if(s)return s;const I=window.SpeechRecognition||window.webkitSpeechRecognition;if(!I)throw new Error("Speech not supported here — use Chrome or Edge (not Safari), or type to careTalk");return s=new I,s.continuous=!0,s.interimResults=!0,s.maxAlternatives=5,s.lang=v,s.onstart=()=>{a=!0,$=!1,ie=0,n==null||n()},s.onend=()=>{a=!1,i==null||i(),!E&&(clearTimeout(y),f="",J(320))},s.onerror=b=>{const T=b.error;if(T!=="aborted"&&T!=="no-speech"){if(T==="audio-capture"){if(ie+=1,ie<=2&&u){r==null||r("Mic busy — retrying… close other apps using the mic"),clearTimeout(k),k=setTimeout(async()=>{if(u)try{await K(),Y()}catch(M){u=!1,r==null||r((M==null?void 0:M.message)||"no microphone available")}},600);return}u=!1,r==null||r(U?`Can’t capture “${U}” — quit Zoom/Teams/FaceTime, allow mic for this site, tap again`:"Can’t open microphone — allow mic in the address bar, quit apps using the mic, use Chrome on localhost");return}if(T==="not-allowed"||T==="service-not-allowed"){u=!1,r==null||r("Mic blocked — lock icon in address bar → Microphone → Allow, then tap mic");return}if(T==="network"){r==null||r("Speech needs internet (Chrome voice service)"),J(1200);return}if(T==="language-not-supported"&&v!=="en-US"){v="en-US",s.lang=v,J(300);return}r==null||r(T),J(500)}},s.onresult=b=>{let T="";for(let M=b.resultIndex;M<b.results.length;M+=1){const C=b.results[M],ne=_(C);!ne||x(ne)||(C.isFinal?!D&&!E&&z(ne):T+=`${ne} `)}T.trim()&&!D&&(t==null||t(T.trim()),f=T.trim(),R(T.trim()))},s}async function Ce(){const I=await ge.available();if(!(I!=null&&I.available))throw new Error("Speech recognition unavailable on this device");if((await ge.checkPermissions()).speechRecognition!=="granted"&&(await ge.requestPermissions()).speechRecognition!=="granted")throw new Error("Microphone / speech permission denied")}async function fe(){await Ce(),f="",l=await ge.addListener("partialResults",I=>{const b=((I==null?void 0:I.matches)||[]).filter(Boolean).join(" ").trim();b&&R(b)}),d=await ge.addListener("listeningState",I=>{I.status==="started"&&(a=!0,n==null||n()),I.status==="stopped"&&(a=!1,i==null||i(),u&&!E&&(clearTimeout(k),k=setTimeout(()=>{u&&fe().catch(b=>r==null?void 0:r((b==null?void 0:b.message)||"mic restart failed"))},400)))}),await ge.start({language:v,maxResults:5,partialResults:!0,popup:!1}),a=!0,n==null||n()}async function Gr(){clearTimeout(y),clearTimeout(k);try{await ge.stop()}catch{}f&&!x(f)&&z(f);try{await(l==null?void 0:l.remove()),await(d==null?void 0:d.remove())}catch{}l=null,d=null,a=!1,i==null||i()}return{get listening(){return a},get micLabel(){return U},setInputBlocked(I){D=!!I,D&&(clearTimeout(y),f="")},async start(){if(u=!0,E=!1,f="",ie=0,Ze()){await fe();return}await K(),Z(),Y()},async pause(){if(E=!0,D=!0,clearTimeout(k),clearTimeout(y),Ze()){try{await ge.stop()}catch{}a=!1,i==null||i();return}try{s==null||s.stop()}catch{}a=!1,i==null||i()},async resume(){if(E=!1,D=!1,u=!0,Ze()){await fe();return}Y()},async stop(){if(u=!1,E=!1,clearTimeout(k),clearTimeout(y),$=!1,Ze()){await Gr();return}const I=f;f="";try{s==null||s.stop()}catch{}I&&!x(I)&&z(I),a=!1,i==null||i()}}}var At;(function(e){e.Dark="DARK",e.Light="LIGHT",e.Default="DEFAULT"})(At||(At={}));var rn;(function(e){e.None="NONE",e.Slide="SLIDE",e.Fade="FADE"})(rn||(rn={}));const on=Se("StatusBar"),ai=Se("SplashScreen",{web:()=>Ut(()=>import("./web-o2G7w9Em.js"),__vite__mapDeps([2,1]),import.meta.url).then(e=>new e.SplashScreenWeb)});var an;(function(e){e.Dark="DARK",e.Light="LIGHT",e.Default="DEFAULT"})(an||(an={}));var Lt;(function(e){e.Body="body",e.Ionic="ionic",e.Native="native",e.None="none"})(Lt||(Lt={}));const si=Se("Keyboard"),sn=Se("App",{web:()=>Ut(()=>import("./web-BhapuqNa.js"),__vite__mapDeps([3,1]),import.meta.url).then(e=>new e.AppWeb)});async function li(){if(Oe.isNativePlatform()){document.documentElement.classList.add("native"),document.documentElement.dataset.platform=Oe.getPlatform();try{await on.setStyle({style:At.Dark}),await on.setBackgroundColor({color:"#061114"})}catch{}try{await si.setResizeMode({mode:Lt.Body})}catch{}try{await ai.hide()}catch{}sn.addListener("backButton",({canGoBack:e})=>{e?window.history.back():sn.exitApp()})}}const O={pinHash:"don.train.pinHash",pinSet:"don.train.pinSet",sessionAuth:"don.train.authed",knowledge:"don.train.knowledge",agency:"don.agency",outbox:"don.agency.outbox",incidents:"don.train.incidents",customTopics:"don.train.customTopics"},_t="2473";function Xe(e){const t=`don|${String(e||"").trim()}`;let n=2166136261;for(let i=0;i<t.length;i+=1)n^=t.charCodeAt(i),n=Math.imul(n,16777619);return(n>>>0).toString(16)}function ze(e,t){try{const n=localStorage.getItem(e);return n?JSON.parse(n):t}catch{return t}}function Ke(e,t){localStorage.setItem(e,JSON.stringify(t))}function ci(){return localStorage.getItem(O.pinSet)==="1"}function Mt(){ci()||(localStorage.setItem(O.pinHash,Xe(_t)),localStorage.setItem(O.pinSet,"1"))}function di(e){Mt();const t=localStorage.getItem(O.pinHash)||Xe(_t);return Xe(e)===t}function ui(e){const t=String(e||"").trim();if(t.length<4)throw new Error("PIN must be at least 4 digits");localStorage.setItem(O.pinHash,Xe(t)),localStorage.setItem(O.pinSet,"1")}function he(e){e?sessionStorage.setItem(O.sessionAuth,"1"):sessionStorage.removeItem(O.sessionAuth)}function nr(){return sessionStorage.getItem(O.sessionAuth)==="1"}function ue(){return ze(O.knowledge,[])}function rr(e){Ke(O.knowledge,e)}function ir(e){const t=ue(),n=r=>Array.isArray(r)?r.map(o=>String(o).trim()).filter(Boolean):String(r||"").split(`
3
  `).map(o=>o.trim()).filter(Boolean),i={id:`k_${Date.now()}`,title:String(e.title||"").trim(),body:String(e.body||"").trim(),doList:n(e.doList),dontList:n(e.dontList),keywords:String(e.keywords||"").split(",").map(r=>r.trim().toLowerCase()).filter(Boolean),sourceUrl:String(e.sourceUrl||"").trim(),images:Array.isArray(e.images)?e.images.map(r=>String(r).trim()).filter(Boolean):String(e.images||"").split(`
4
  `).map(r=>r.trim()).filter(Boolean),addedBy:e.addedBy||"Head nurse",addedAt:new Date().toISOString()};if(!i.title||!i.body)throw new Error("Title and guidance text are required");return t.unshift(i),rr(t),i}function pi(e){rr(ue().filter(t=>t.id!==e))}function ot(){return ze(O.agency,{name:"Care agency",email:"",webhookUrl:"",autoForward:!0})}function fi(e){Ke(O.agency,{name:String(e.name||"Care agency").trim()||"Care agency",email:String(e.email||"").trim(),webhookUrl:String(e.webhookUrl||"").trim(),autoForward:e.autoForward!==!1})}function or(){return ze(O.outbox,[])}function ar(e){const t=or();t.unshift(e),Ke(O.outbox,t.slice(0,50))}function sr(){return ze(O.incidents,[])}function gi(e){Ke(O.incidents,Array.isArray(e)?e:[])}function ke(){return ze(O.customTopics,[])}function jt(e){Ke(O.customTopics,Array.isArray(e)?e:[])}function lr({title:e,keywords:t="",notes:n=""}){const i=String(e||"").trim();if(!i)throw new Error("Topic title is required");const r=ke(),o={id:`topic_${Date.now()}`,title:i,keywords:String(t||"").split(",").map(a=>a.trim().toLowerCase()).filter(Boolean),notes:String(n||"").trim(),addedAt:new Date().toISOString(),lastTrainedAt:null};return r.unshift(o),jt(r),o}function mi(e){jt(ke().filter(t=>t.id!==e))}function hi(e){const t=ke(),n=t.findIndex(i=>i.id===e);n<0||(t[n].lastTrainedAt=new Date().toISOString(),jt(t))}const St={fall:[{id:"fall-assess",title:"Assess first",caption:"Stay with them, check responsiveness and injury before any move.",src:"/guides/fall-assess.svg",alt:"Carer kneeling beside a person on the floor after a fall, asking if they are hurt"},{id:"fall-no-lift",title:"Don’t haul them up",caption:"If injury may be present, keep them comfortable and get clinical advice.",src:"/guides/fall-no-lift.svg",alt:"Warning not to lift a fallen person without assessment"}],dysphagia:[{id:"dysphagia-upright",title:"Sit upright",caption:"Upright posture for eating and drinking; follow texture plan.",src:"/guides/dysphagia-upright.svg",alt:"Person sitting upright in a chair for safe eating and drinking"},{id:"dysphagia-stop",title:"Stop if choking signs",caption:"Coughing, wet voice or colour change — stop intake and call for help.",src:"/guides/dysphagia-stop.svg",alt:"Stop cup or food when choking warning signs appear"}],distress:[{id:"distress-space",title:"Give space",caption:"Reduce stimulation, keep a calm distance, use care-plan strategies.",src:"/guides/distress-space.svg",alt:"Carer giving a person space during distress"}],skin:[{id:"skin-check",title:"Note site & look",caption:"Record exact site, appearance and pain; escalate for grading/dressings.",src:"/guides/skin-check.svg",alt:"Diagram highlighting checking pressure areas on the body"}]};function yi(e,t=[]){const n=St[e]||[],i=[];for(const o of t)(Array.isArray(o.images)?o.images:[]).forEach((s,l)=>{const d=String(s||"").trim();d&&i.push({id:`trained_${o.id||l}_${l}`,title:o.title||"Home training image",caption:"From your home’s trained knowledge",src:d,alt:`${o.title||"Training"} illustration ${l+1}`})});const r=new Set;return[...n,...i].filter(o=>r.has(o.src)?!1:(r.add(o.src),!0))}function wi(e,t){return e!=null&&e.length?`
5
  <div class="guide-strip">
@@ -15,7 +15,7 @@ import{i as zr}from"./theme-CuaEyjDL.js";/*! Capacitor: https://capacitorjs.com/
15
  </figcaption>
16
  </figure>`).join("")}</div>
17
  </div>
18
- `:""}const cr={version:"1.1.30",disclaimer:"careTalk is a demonstration prototype. Notes are drafts for staff review — not an approved care record. Follow your home’s policy, escalate to the nurse in charge, and call 999 in an emergency."},Ft=[{id:"pmva_mapa",title:"PMVA / MAPA (BILD-accredited)",notes:"Physical intervention and de-escalation for mental health settings is a specialised, assessed course (typically multi-day, BILD-accredited). Prefer prevention, communication, and least-restrictive options. Only use techniques you are currently trained and authorised to use."},{id:"oliver_mcgowan",title:"Oliver McGowan Mandatory Training (Tier 2 + online)",notes:"Learning disability and autism awareness: assume competence, adapt communication, reduce sensory load, involve familiar supporters, avoid diagnostic overshadowing, and escalate concerns about distress or unmet need."},{id:"ligature",title:"Ligature awareness",notes:"Remove or reduce ligature risks where safe and authorised; do not leave someone in danger to ‘finish paperwork’. Observe, report environmental risks, stay with the person if unsafe to leave, and escalate immediately per policy."},{id:"dysphagia",title:"Dysphagia awareness",notes:"Follow IDDSI / care-plan texture and fluid guidance. Never rush feeding, never mix consistencies against the plan, sit upright, watch for coughing/wet voice/colour change, and stop and escalate if aspiration is suspected."},{id:"seniors",title:"Caring for older adults",notes:"Person-centred, dignity-first care: explain what you are doing, offer choice, watch for delirium, falls, skin, hydration, and loneliness. Document facts, not judgements."},{id:"moving_assisting",title:"Moving and assisting people",notes:"Use agreed handling plans, equipment you are trained on, and enough staff. Do not lift manually against policy. After a fall, do not haul someone up if injury is possible — assess, reassure, follow fallen-person procedure."},{id:"hswa",title:"Health and Safety at Work etc. Act",notes:"Take reasonable care of yourself and others, follow training, report hazards, and do not carry out tasks you are not competent or authorised to do."}];function bi(e,t){const n=`${e} ${t||""}`.toLowerCase(),i=ue().filter(r=>{var o;return(o=r.keywords)!=null&&o.length?r.keywords.some(a=>n.includes(a)||e.includes(a)):e==="general"||e==="medication"});if(e==="medication"){const r=i.filter(o=>/\b(medicine|medication|meds|refus|tablet|mar)\b/i.test(`${o.title} ${o.body} ${(o.keywords||[]).join(" ")}`));return r.length?r:i}return i}function ki(e,t=""){var u,f;const n=["Stay calm and reassure the person.","Check for immediate danger to them and you.","Follow your service’s escalation pathway (nurse in charge / on-call / 999).","Document facts: what you saw, what you did, time, who was informed."],i=["Don’t leave an unsafe situation to ‘write the note first’.","Don’t use restrictive holds unless you are currently trained, authorised, and it is a last resort under policy.","Don’t blame the person in the record — stick to observable facts."],r={fall:{pillars:["moving_assisting","seniors","hswa"],do:[...n,"If injury may be present, do not pull them up — keep them comfortable, check responsiveness, and get clinical advice.","Look for head injury signs, pain, limb deformity, bleeding, and sudden confusion.","After safe recovery, review footwear, mobility aid, lighting, and observation level."],dont:[...i,"Don’t use a fireman’s lift or unplanned manual lift.","Don’t dismiss an unwitnessed fall — treat it seriously until assessed.","Don’t delay informing the nurse in charge / family when policy requires it."]},skin:{pillars:["seniors","hswa"],do:[...n,"Note exact site, size/appearance if trained to, pain, and whether skin is broken.","Reposition as care plan allows; keep pressure off the area.","Inform nurse in charge for grading / dressing decisions if required."],dont:[...i,"Don’t apply creams or dressings outside your role/competence.","Don’t ignore unbroken redness over a bony area."]},dysphagia:{pillars:["dysphagia","oliver_mcgowan","seniors"],do:[...n,"Stop oral intake if coughing, choking, wet voice, or colour change.","Keep upright; follow prescribed texture/fluid level only.","Call for help early — choking is time-critical."],dont:[...i,"Don’t give food/drink against the dysphagia plan.","Don’t leave someone alone while eating if supervision is required.","Don’t do blind finger sweeps if choking."]},distress:{pillars:["pmva_mapa","oliver_mcgowan","ligature","hswa"],do:[...n,"Reduce stimulation, give space, use calm simple language, and offer known soothing strategies from the care plan.","Scan for environmental risk (ligature points, weapons, exits) without escalating conflict.","Call for trained support early; protect yourself and others."],dont:[...i,"Don’t crowd, shout, or threaten.","Don’t use physical intervention unless trained, authorised, proportionate, and necessary as a last resort.","Don’t ignore ligature risk to ‘talk it out’ from a distance if the person is in immediate danger — get help now."]},wellbeing:{pillars:["seniors","oliver_mcgowan"],do:[...n,"Ask about pain, mood, appetite, and what matters to them today.","Note changes from their usual baseline."],dont:[...i,"Don’t skip hydration/nutrition checks when someone seems ‘fine’ but quieter than usual."]},medication:{pillars:["hswa","seniors"],do:["Stay calm and do not force medicine.","Follow your home’s medication / MAR policy and the person’s care plan.","Inform the nurse in charge / on-call promptly.","Document facts: what was offered, what was refused, time, and who was informed."],dont:["Don’t hide medicine in food/drink unless the care plan and policy explicitly allow covert administration by authorised staff.","Don’t force, threaten, or restrain someone to take medicine.","Don’t leave a refused critical dose unreported."]},general:{pillars:["hswa","seniors"],do:n,dont:i}},o={...r[e]||r.general},a=bi(e,t);for(const g of a)(u=g.doList)!=null&&u.length&&(o.do=[...o.do,...g.doList]),(f=g.dontList)!=null&&f.length&&(o.dont=[...o.dont,...g.dontList]);const s=Ft.filter(g=>o.pillars.includes(g.id)).map(g=>`${g.title}: ${g.notes}`),l=a.map(g=>`${g.title}: ${g.body}`),d=yi(e,a);return{...o,pillarText:s,trainedText:l,custom:a,images:d}}async function vi(e,t={}){const n=ot(),i={id:`fwd_${Date.now()}`,at:new Date().toISOString(),agencyName:n.name,agencyEmail:n.email,carer:t.carer||"",person:t.person||"",scenario:t.scenario||"",report:e,status:"queued",channels:[]};if(i.channels.push("outbox"),n.webhookUrl)try{const r=await fetch(n.webhookUrl,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({type:"don.support_worker_report",...i})});if(!r.ok)throw new Error(`HTTP ${r.status}`);i.channels.push("webhook")}catch(r){i.webhookError=(r==null?void 0:r.message)||"webhook failed"}if(n.email){const r=encodeURIComponent(`careTalk support worker report — ${t.person||"resident"} — ${t.scenario||"care"}`),o=encodeURIComponent(e.slice(0,1800)),a=`mailto:${encodeURIComponent(n.email)}?subject=${r}&body=${o}`;i.mailto=a,i.channels.push("email");try{const s=document.createElement("a");s.href=a,s.rel="noopener",document.body.appendChild(s),s.click(),s.remove()}catch{}}return i.status=i.channels.includes("webhook")||i.channels.includes("email")?"sent":"saved_local",ar(i),{packet:i,agency:n}}function ln(e){return String(e||"").trim().toLowerCase().replace(/[^a-z'-]/g,"")}function $i(e,t){const n=ln(e),i=ln(t);if(!n||!i)return!1;if(n===i)return!0;const r=n.split(/\s+/)[0],o=i.split(/\s+/)[0];return r.length>1&&r===o}function at(e){const t=String(e||"").trim();return t?t.split(/\s+/)[0]:""}function st(e,t){return $i(e,t)}function Ii(e,t){const n=String(e||"").trim().toLowerCase().replace(/[^\w\s'-]/g,""),i=String(t||"").trim().toLowerCase().replace(/[^\w\s'-]/g,"");return!n||!i?!1:!!(n===i||n.length>8&&i.includes(n)||i.length>12&&n.includes(i.slice(0,Math.min(24,i.length))))}function Ai(e,t){return t!=="waiting_answer"?!1:/^(yes|yeah|yep|yup|no|nope|nah|ok|okay|correct|right|wrong)$/i.test(String(e||"").trim())}const Ie=[{id:"fall",label:"Fall",match:/\b(fall|fell|fallen|slipped|trip(?:ped)?)\b/i,questions:[{id:"when",ask:"When did it happen — just now, or roughly what time?"},{id:"where",ask:"Where did it happen? Bedroom, bathroom, corridor…?"},{id:"witnessed",ask:"Did anyone see it, or was it unwitnessed?"},{id:"how",ask:"What were they doing right before — standing up, walking, reaching…?"},{id:"injury",ask:"Any pain, bleeding, bumps, or odd limb position — or none that you can see?"},{id:"response",ask:"What have you done so far?"},{id:"obs",ask:"How are they now — alert, dizzy, confused, calm?"},{id:"informed",ask:"Who have you told, and who still needs telling — nurse in charge, GP, family, 999?"},{id:"prevent",ask:"Anything you want in place now for safety — mat, closer checks, footwear…?"}]},{id:"dysphagia",label:"Eating / choking / swallow",match:/\b(chok(?:e|ing)?|swallow|dysphagia|coughing (?:on|while) (?:eat|drink)|aspirat)/i,questions:[{id:"what",ask:"What happened with eating or drinking?"},{id:"texture",ask:"Were they on a special texture or fluid level?"},{id:"signs",ask:"Any coughing, colour change, wet voice, or distress?"},{id:"stopped",ask:"Did you stop food and drink?"},{id:"now",ask:"How are they now?"},{id:"informed",ask:"Who have you informed?"}]},{id:"distress",label:"Distress / behaviour support",match:/\b(distress|agitated|aggression|hitting|ligature|self[- ]harm|restrain|mapa|pmva|difficult|challenging|behaviour|behavior)\b/i,questions:[{id:"what",ask:"What’s happening for them right now, in plain words?"},{id:"trigger",ask:"Anything that seemed to trigger it?"},{id:"risk",ask:"Is anyone in immediate danger — including ligature or weapons risk?"},{id:"done",ask:"What have you tried — space, calm talk, care-plan strategies?"},{id:"help",ask:"Who is supporting you on the floor right now?"},{id:"now",ask:"How is the person now?"}]},{id:"medication",label:"Medication / refusal",match:/\b((refuse[ds]?|refusing|won'?t take|will not take|not taking|declined?).{0,40}\b(medicine|medication|meds|tablet|tablets|pill|pills|dose)\b|\b(medicine|medication|meds|tablet|tablets|pill|pills).{0,40}\b(refuse[ds]?|refusing|won'?t|not taking|declined?)\b|\b(medication|medicine|meds|mar)\b)/i,questions:[{id:"what",ask:"Which medicine was refused or not taken — if you know the name or time slot?"},{id:"when",ask:"When was this — which round / roughly what time?"},{id:"how",ask:"What exactly happened — refused, spat out, asleep, not present…?"},{id:"reason",ask:"Did they say why, or seem unwell / distressed?"},{id:"done",ask:"What have you tried so far (offer again, nurse, wait)?"},{id:"now",ask:"How are they now?"},{id:"informed",ask:"Who have you told — nurse in charge / on-call?"},{id:"next",ask:"What needs to happen next according to the home’s policy?"}]},{id:"skin",label:"Skin / pressure concern",match:/\b(skin|pressure|sore|redness|bruise|wound|mark)\b/i,questions:[{id:"where",ask:"Where on the body is the mark or sore?"},{id:"looks",ask:"What does it look like?"},{id:"pain",ask:"Are they sore there?"},{id:"found",ask:"When did you notice it?"},{id:"done",ask:"What have you done so far?"},{id:"next",ask:"What do you think needs to happen next?"}]},{id:"wellbeing",label:"Wellbeing check",match:/\b(wellbeing|well-being|mood|check(?:ed)? on|how .+ (?:is|are))\b/i,questions:[{id:"mood",ask:"How is their mood and engagement?"},{id:"eat",ask:"Eating and drinking okay?"},{id:"mobility",ask:"Any mobility notes?"},{id:"care",ask:"Any personal care done or needed?"},{id:"concerns",ask:"Anything worrying you?"},{id:"plan",ask:"What should the next shift know?"}]},{id:"general",label:"Care situation",match:/./,questions:[{id:"what",ask:"In one line, what happened?"},{id:"when",ask:"When was this?"},{id:"where",ask:"Where?"},{id:"response",ask:"What did you do?"},{id:"now",ask:"How is the person now?"},{id:"informed",ask:"Who knows / who still needs to know?"},{id:"next",ask:"What needs to happen next?"}]}],Li=/^(?:(?:hi|hii|hey|hello|yo|ok|okay|hiya|oi|excuse me)\s+)+(?:care\s*talk|caretalk|don|dawn|done|dom|dun|donn)\b[, ]*/i,Si=/^(?:care\s*talk|caretalk|don|dawn|done|dom|dun|donn)\b[, ]*/i;function lt(e){return String(e||"").toLowerCase().replace(/["""']/g,"").replace(/[^\w\s']/g," ").replace(/\bcare\s*talk\b/g,"caretalk").replace(/\b(dawn|done|dom|dun|donn|donnie|donald)\b/g,"don").replace(/\s+/g," ").trim()}function Be(e){const t=lt(e);return/^(?:(?:(?:hi|hii|hey|hello|yo|ok|okay|hiya|oi)\s+)?(?:caretalk|don)\s*)+$/.test(t)}function H(e){let t=String(e||"").trim();t=t.replace(Li,"").replace(Si,"").trim();const n=lt(t);return n.startsWith("caretalk ")&&(t=t.replace(/^(?:care\s*talk|caretalk)\s+/i,"").trim()),n.startsWith("don ")&&(t=t.replace(/^(?:don|dawn|done)\s+/i,"").trim()),t}function Ht(e){const t=String(e||"");if(/\bcare\s*talk\b/i.test(t)||/\bcaretalk\b/i.test(t)||/\bdon\b/i.test(t)||/\b(?:hi|hey|hello|yo|ok|okay|hiya|oi|excuse me)\s+(?:dawn|done|dom|dun|donn|donnie|donald|dan|donn?e)\b/i.test(t)||/^(?:dawn|done|dom|dun|donn|donald)\b/i.test(t.trim())||/,\s*(?:dawn|done|dom|dun|donn|donald)\b/i.test(t))return!0;const n=lt(t);return!!/^(?:(?:hi|hii|hey|hello|yo|ok|okay|hiya|oi)\s+)?(?:caretalk|don)(?:\s+(?:caretalk|don))*$/.test(n)}function Tt(e){const t=H(e).trim();return t?Ne(t).id!=="general"||/\b(help|need|advice|record|document|fell|fall|hurt|pain|chok|bleed|resident|patient|check|incident|report)\b/i.test(t)?!0:t.split(/\s+/).filter(Boolean).length>=4:!1}function dr(e){return!Ht(e)||Be(e)?!1:!Tt(e)}const Ti=new Set(["i","we","you","he","she","it","they","them","him","her","his","my","our","your","the","a","an","this","that","these","those","someone","somebody","anyone","anybody","everyone","everybody","resident","client","service","user","carer","nurse","staff","today","just","please","okay","ok","alright","don","caretalk","hey","hi","hello","yes","yeah","yep","yup","no","nope","nah","not","nothing","something","else","fall","distress","swallow","skin","mood","wellbeing","medication","meds","urgent","safe","unsafe","danger","right","got","still","here","there","when","where","what","why","how","who","which","because","about","with","for","from","after","before","during","maybe","kind","sort","really","actually","saying","said","tell","told","need","help","advice","report","record","document"].map(e=>e.toLowerCase()));function Fe(e){const t=String(e||"").trim();return!(!t||t.length<2||t.length>24||/\d/.test(t)||Ti.has(t.toLowerCase())||!/^[A-Za-z][A-Za-z'-]*$/.test(t))}function Ye(e,{carerName:t=""}={}){const n=H(e);if(!n)return"";function i(s){return!s||!Fe(s)||t&&st(s,t)?"":s}const r=[/(?:with|for|about|attending(?: to)?|resident|service user|client|called)\s+([A-Z][a-z]+(?:\s+[A-Z][a-z]+)?)/,/\b([A-Z][a-z]+)\s+(?:just |has |had |fell|was |is |seems |refused |won'?t )/];for(const s of r){const l=n.match(s);if(l){const d=i(l[1].split(/\s+/)[0]);if(d)return d}}const o=n.match(/\b([a-z]{2,})\s+(?:just |has |had |fell|seems|refused|won'?t)/i);if(o){const s=i(Fe(o[1])?o[1].charAt(0).toUpperCase()+o[1].slice(1).toLowerCase():"");if(s)return s}const a=n.match(/^([A-Za-z][A-Za-z'-]{1,23})(?:\s+(?:please|thanks))?[.!?]?$/);if(a){const s=i(a[1].charAt(0).toUpperCase()+a[1].slice(1).toLowerCase());if(s)return s}return""}function Ne(e){const t=H(e);for(const n of Ie)if(n.id!=="general"&&n.match.test(t))return n;return Ie.find(n=>n.id==="general")}function Ei(e,t){return t&&/^Where did it happen/i.test(e)?`Where was ${t}? Bedroom, bathroom, corridor…?`:e}function Ci({opening:e,carer:t,carerProfileName:n=""}){const i=e.trim(),r=Ne(i);let a=Ye(i,{carerName:n||t});const s=H(i)||i,l=ki(r.id,s),d=r.questions.map(u=>({...u,ask:Ei(u.ask,a)}));return{id:`sess_${Date.now()}`,opening:s,carer:t||"Staff",person:a,scenarioId:r.id,scenarioLabel:r.label,advice:l,questions:d,answers:{},voiceNotes:[{at:new Date().toISOString(),text:s}],step:0,phase:"advice",adviceAwaitingOk:!1,docTurn:"waiting_answer",pendingAnswer:"",pendingDocumented:"",correctionNote:"",recordedAt:new Date().toLocaleString("en-GB")}}function Ri(){const e=["I’m here. Do you need any help?","Hi — it’s careTalk. What do you need?","Listening. Are you okay — want help documenting something, or advice on what to do next?"];return e[Math.floor(Math.random()*e.length)]}function ct(e){return e.questions[e.step]||null}function Di(e,t,{person:n=""}={}){const i=String(t||"").trim().replace(/\s+/g," ");if(!i)return"—";const r=String((e==null?void 0:e.ask)||"Note").replace(/\?$/,"").trim();return`${n?`Service user ${n}: `:""}${r} — ${i}`}function cn(e){const t=String(e||"").trim().toLowerCase();return!t||/\b(no|nope|not right|wrong|incorrect|change)\b/.test(t)&&!/^yes\b/.test(t)?!1:/^(yes|yeah|yep|yup|correct|right|spot on|that'?s right|that is right|good|fine|ok|okay|absolutely|affirmative)\b/.test(t)}function dn(e){const t=String(e||"").trim().toLowerCase();return/^(no|nope|nah|not quite|wrong|incorrect)\b/.test(t)||/\b(not right|that'?s wrong|change that|needs changing)\b/.test(t)}function un(e){let t=String(e||"").trim();return t=t.replace(/^(no(,)?\s*)(actually|i mean|it'?s|it is)?\s*/i,"").trim(),t||String(e||"").trim()}function xi(e){return String(e||"").trim().length<2}function Pi(e,{raw:t,documented:n}){const i=ct(e);if(!i)return{session:e,done:!0};const r=String(n||t||"").trim();return e.answers[i.id]=r,e.voiceNotes||(e.voiceNotes=[]),e.voiceNotes.push({at:new Date().toISOString(),text:t?`${i.id} (voice): ${t}`:`${i.id}: ${r}`}),n&&t&&n!==t&&e.voiceNotes.push({at:new Date().toISOString(),text:`${i.id} (record): ${r}`}),e.step+=1,e.pendingAnswer="",e.pendingDocumented="",e.docTurn="waiting_answer",{session:e,done:e.step>=e.questions.length}}function Oi(e,t){if(!e)return;const n=String(t||"").trim();n&&(e.voiceNotes||(e.voiceNotes=[]),e.voiceNotes.push({at:new Date().toISOString(),text:n}))}function ur(e,t){const n=e.questions.map(r=>{const o=e.answers[r.id];return o?`<li><span class="muted-line">${t(r.ask)}</span><br /><strong>${t(o)}</strong></li>`:""}).filter(Boolean).join(""),i=e.correctionNote?`<li><span class="muted-line">Correction noted</span><br /><strong>${t(e.correctionNote)}</strong></li>`:"";return n||i?`<ul class="record-review">${n}${i}</ul>`:"<p>Nothing captured yet.</p>"}function Bi(e){return Ni(e)}function Ni(e){var r;const t=e.answers,n=e.person||"the resident",i=["SUPPORT WORKER REPORT — GENERATED BY careTalk","========================================",`Service user: ${e.person||"—"}`,`Support worker / carer: ${e.carer}`,`Incident / topic: ${e.scenarioLabel}`,`Date & time recorded: ${e.recordedAt}`,`Session id: ${e.id}`,"","1. OPENING STATEMENT (VOICE)",e.opening||"—","","2. WHAT HAPPENED (STRUCTURED)"];if(e.scenarioId==="fall")i.push(`${n} had a fall${t.when?` (${t.when})`:""}${t.where?` — location: ${t.where}`:""}.`,t.how?`Beforehand: ${t.how}.`:"",t.witnessed?`Witnessed / presence: ${t.witnessed}.`:"","","3. INJURY / PRESENTATION",t.injury||"—","","4. IMMEDIATE RESPONSE",t.response||"—","","5. CURRENT CONDITION",t.obs||"—","","6. NOTIFICATIONS",t.informed||"—","","7. SAFETY / FOLLOW-UP",t.prevent||"—");else for(const o of e.questions)i.push(`${o.ask}`,t[o.id]||"—","");return i.push("","8. VOICE NOTES (VERBATIM CAPTURE)",...(e.voiceNotes||[]).map((o,a)=>`${a+1}. [${new Date(o.at).toLocaleTimeString("en-GB")}] ${o.text}`),"","9. NARRATIVE SUMMARY FOR AGENCY"),e.scenarioId==="fall"?i.push([`${n} had a fall${t.when?` ${t.when}`:""}${t.where?` at ${t.where}`:""}.`,t.how?`Prior activity: ${t.how}.`:null,t.witnessed?`Presence: ${t.witnessed}.`:null,t.injury?`Injury/marks: ${t.injury}.`:null,t.response?`Actions: ${t.response}.`:null,t.obs?`Now: ${t.obs}.`:null,t.informed?`Informed: ${t.informed}.`:null,t.prevent?`Safety: ${t.prevent}.`:null].filter(Boolean).join(" ")):i.push(e.questions.map(o=>`${o.ask.replace(/\?$/,"")}: ${t[o.id]||"not stated"}`).join(". ")+"."),i.push("","10. SAFE PRACTICE REMINDERS APPLIED (careTalk)",`Do: ${(e.advice.do||[]).slice(0,4).join(" | ")}`,`Don’t: ${(e.advice.dont||[]).slice(0,4).join(" | ")}`),(r=e.advice.trainedText)!=null&&r.length&&i.push("","11. HOME-TRAINED KNOWLEDGE USED",...e.advice.trainedText),e.correctionNote&&i.push("","CORRECTION / AMENDMENT (VOICE)",e.correctionNote),i.push("",Ui),i.filter((o,a,s)=>!(o===""&&s[a-1]==="")).join(`
19
  `)}const Ui="Note: careTalk supports documentation and safe-practice reminders from adult care / support-worker training themes (including moving & assisting, dysphagia, ligature awareness, Oliver McGowan, PMVA/MAPA principles, HSWA). Follow local policy and clinical advice. This report is for the care agency / nurse in charge.",qt=[{id:"medication_refusal",label:"Medication refusal",match:/\b((refuse[ds]?|refusing|won'?t take|will not take|not taking|declined?|spit(?:ting)? out).{0,40}\b(medicine|medication|meds|tablet|tablets|pill|pills|dose|mar)\b|\b(medicine|medication|meds|tablet|tablets|pill|pills).{0,40}\b(refuse[ds]?|refusing|won'?t|will not|not taking|declined?)\b)/i,keywords:["medicine","medication","meds","refuse","refusal","refused","tablet","tablets","pill","mar"]}];function et(e){const t=String(e||"");for(const n of qt)if(n.match.test(t))return n;return null}function pr(e,t=""){if(!e)return[];`${t} ${e.label}`.toLowerCase();const n=ue(),i=[];for(const r of n){let o=0;const a=`${r.title} ${r.body} ${(r.keywords||[]).join(" ")} ${(r.doList||[]).join(" ")}`.toLowerCase();for(const s of e.keywords)a.includes(s)&&(o+=2),(r.keywords||[]).includes(s)&&(o+=2);/\b(refus|not taking|declin|won'?t take)\b/i.test(a)&&(o+=3),/\b(medicine|medication|meds|tablet|mar)\b/i.test(a)&&(o+=2),(r.doList||[]).length>=1&&(o+=2),r.body&&r.body.length>60&&(o+=1),o>=5&&i.push({entry:r,score:o})}return i.sort((r,o)=>o.score-r.score).map(r=>r.entry)}function Et(e,t=""){return pr(e,t).some(i=>(i.doList||[]).length>=1||(i.body||"").length>=80)}function fr(e,t=""){const i=String(e||t||"this subject").trim().replace(/\s+/g," ").slice(0,80)||"this subject";return{id:`unsure_${i.toLowerCase().replace(/[^a-z0-9]+/g,"_").replace(/^_|_$/g,"").slice(0,40)||"subject"}`,label:i,keywords:i.toLowerCase().split(/\W+/).filter(o=>o.length>3).slice(0,8),question:`careTalk was not sure about this subject: ${i}. What should carers do?`}}function _i(e=""){const t=String(e||"").toLowerCase();if(!t||t.split(/\s+/).length<3)return!1;const n=t.split(/\W+/).filter(i=>i.length>3);return n.length?ue().some(i=>{const r=`${i.title} ${i.body} ${(i.keywords||[]).join(" ")}`.toLowerCase();return n.filter(a=>r.includes(a)).length>=2&&((i.doList||[]).length>=1||(i.body||"").length>=60)}):!1}function dt(){return sr()}function Wt(e){gi(e)}function gr(){return dt().filter(e=>e.status==="unresolved")}function mr({topic:e,utterance:t,person:n="",carer:i=""}){const r=dt(),o=Date.now()-1440*60*1e3,a=r.find(l=>l.status==="unresolved"&&l.topicId===e.id&&(l.person||"").toLowerCase()===(n||"").toLowerCase()&&new Date(l.createdAt).getTime()>o);if(a)return{incident:a,created:!1};const s={id:`inc_${Date.now()}`,status:"unresolved",topicId:e.id,topicLabel:e.label,question:e.question||(e.id==="medication_refusal"?`What should carers do when ${n||"a client"} refuses / does not take their medicine?`:`careTalk was unsure about: ${e.label}. What should carers do?`),person:n||"",carer:i||"",utterance:String(t||"").trim(),createdAt:new Date().toISOString(),resolvedAt:null,resolvedBy:null,knowledgeId:null,agencyNotified:!1};return r.unshift(s),Wt(r),{incident:s,created:!0}}function Mi(e,{knowledgeId:t=null,note:n=""}={}){const i=dt(),r=i.findIndex(o=>o.id===e);if(r<0)throw new Error("Incident not found");return i[r]={...i[r],status:"resolved",resolvedAt:new Date().toISOString(),resolvedBy:"Head nurse",knowledgeId:t,resolveNote:n},Wt(i),i[r]}async function hr(e){const t=ot(),n=["careTalk — TRAINING REQUEST (UNRESOLVED)","===================================",`Incident id: ${e.id}`,`Topic: ${e.topicLabel}`,"Question careTalk could not answer from training:",e.question,"",`Person / client: ${e.person||"—"}`,`Reported by carer: ${e.carer||"—"}`,`Carer said: ${e.utterance||"—"}`,`Logged: ${new Date(e.createdAt).toLocaleString("en-GB")}`,"","careTalk told the carer he will ask for training on this.","Please open Give careTalk more knowledge in careTalk, resolve this incident, and add clear do/don’t guidance.","",`Agency: ${t.name}`].join(`
20
  `),i={id:`gap_${Date.now()}`,type:"don.training_gap",at:new Date().toISOString(),incidentId:e.id,agencyName:t.name,agencyEmail:t.email,report:n,channels:["outbox"]};if(t.webhookUrl)try{(await fetch(t.webhookUrl,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(i)})).ok&&i.channels.push("webhook")}catch(a){i.webhookError=(a==null?void 0:a.message)||"webhook failed"}if(t.email){const a=encodeURIComponent(`careTalk needs training — ${e.topicLabel}${e.person?` — ${e.person}`:""}`),s=encodeURIComponent(n.slice(0,1800)),l=`mailto:${encodeURIComponent(t.email)}?subject=${a}&body=${s}`;i.mailto=l,i.channels.push("email");try{const d=document.createElement("a");d.href=l,d.rel="noopener",document.body.appendChild(d),d.click(),d.remove()}catch{}}ar(i);const r=dt(),o=r.findIndex(a=>a.id===e.id);return o>=0&&(r[o].agencyNotified=!0,Wt(r)),{packet:i,agency:t,report:n}}const ji=[{id:"mood",label:"Mood & engagement",voice:["mood","engagement","wellbeing"],prompt:"How is their mood and engagement right now?"},{id:"mobility",label:"Mobilisation",voice:["mobility","mobilisation","transfer","zimmer","hoist"],prompt:"How did they mobilise / transfer?"},{id:"nutrition",label:"Nutrition & fluids",voice:["nutrition","hydration","ate","drank","meal"],prompt:"What did they eat and drink?"},{id:"personal",label:"Personal care",voice:["personal care","washed","dressed","continence","pad"],prompt:"What personal care was completed?"},{id:"skin",label:"Skin integrity",voice:["skin","pressure","sore","redness"],prompt:"Any skin changes or pressure areas?"},{id:"clinical",label:"Clinical / PRN",voice:["medication","prn","obs","pain","gp"],prompt:"Any medication, pain, or clinical observations?"},{id:"risk",label:"Risks & safety",voice:["risk","fall","wander","safeguarding","incident"],prompt:"Any safety or safeguarding concerns?"},{id:"plan",label:"Plan / escalate",voice:["plan","action","escalate","handover"],prompt:"What should happen next?"}],Fi=[{key:"resident",re:/(?:resident|service user|client|with)\s+([A-Z][a-z]+(?:\s+[A-Z][a-z]+)?)/i},{key:"when",re:/(?:at|around|about)\s+(\d{1,2}(?::\d{2})?\s*(?:am|pm)?|\d{1,2}\s*(?:am|pm)|this morning|this afternoon|this evening|overnight|during night shift)/i}],Hi=[["fall","Falls risk"],["slipped","Falls risk"],["wander","Exit-seeking / wandering"],["exit-seeking","Exit-seeking / wandering"],["exit seeking","Exit-seeking / wandering"],["distress","Emotional distress"],["agitated","Emotional distress"],["aggressive","Behavioural escalation"],["chok","Choking / swallow risk"],["pressure","Skin integrity watch"],["sore","Skin integrity watch"],["refus","Care preference / declined support"],["declined","Care preference / declined support"],["low mood","Mood concern"],["confused","Cognitive change"],["delirium","Cognitive change"],["safeguard","Safeguarding pathway"],["bruise","Injury / mark observed"],["unwitnessed","Unwitnessed event — verify"]],qi=[[/refused care/gi,"declined care; support and choices were offered"],[/refused/gi,"declined"],[/non[- ]compliant/gi,"needed extra encouragement and adapted support"],[/aggressive resident/gi,"showed distressed behaviour"],[/wandering/gi,"walking with purpose / exit-seeking"],[/fed/gi,"supported with meals"],[/toileted/gi,"supported with continence care"],[/put to bed/gi,"supported to settle for bed"],[/challenging behaviour/gi,"distressed behaviour"]];function Ct(e){const t=e.trim().replace(/\s+/g," ");return t?t.charAt(0).toUpperCase()+t.slice(1):""}function ve(e,t,n=[]){const i=e.toLowerCase();for(const r of t){const o=i.indexOf(r);if(o===-1)continue;let a=e.slice(o+r.length).replace(/^[\s:,-]+/,""),s=a.length;for(const d of n){const u=a.toLowerCase().indexOf(d);u!==-1&&(s=Math.min(s,u))}const l=a.slice(0,s).trim().replace(/[.;]+$/,"");if(l)return Ct(l)}return""}function Wi(e){let t=e||"";for(const[n,i]of qi)t=t.replace(n,i);return t}function pn(e){const t=(e||"").toLowerCase();return ji.map(n=>({...n,covered:n.voice.some(i=>t.includes(i))}))}function Gi(e,t){const n=t.filter(o=>!o.covered).map(o=>o.label),i=e.flags.filter(o=>!/No acute/i.test(o)),r=[];return e.resident?r.push(`${e.resident}: ${e.mood||e.narrative.slice(0,90)||"see full note"}`):e.narrative&&r.push(e.narrative.slice(0,110)),i.length&&r.push(`Watch: ${i.slice(0,3).join("; ")}`),e.actions?r.push(`Next: ${e.actions}`):n.length&&r.push(`Still to capture: ${n.slice(0,3).join(", ")}`),e.clinical&&r.push(`Clinical: ${e.clinical}`),r.slice(0,4)}function Vi(e){const t=e.flags.filter(n=>/safeguard|fall|chok|injury|behavioural|skin integrity|cognitive/i.test(n));return t.length?{title:"Nurse-in-charge brief",lines:[`Person: ${e.resident||"Resident (name not yet captured)"}`,`Flags: ${t.join("; ")}`,`Facts noted: ${e.risks||e.narrative||"See body of note"}`,`Already done: ${e.actions||"Document response and who was informed"}`,"Ask: Do we need GP / 111 / safeguarding referral / family call now?"]}:null}function ut(e,t="wellbeing"){const n=Wi(e||""),i=n.replace(/\s+/g," ").trim(),r={resident:"",when:"",mood:"",mobility:"",nutrition:"",care:"",clinical:"",risks:"",actions:"",flags:[],narrative:"",confidence:0,coverage:pn(""),handover:[],escalation:null,dignityApplied:n!==(e||""),noteType:t};if(!i)return r;let o="",a="";for(const{key:x,re:z}of Fi){const R=i.match(z);R&&(x==="resident"&&(o=R[1]),x==="when"&&(a=Ct(R[1])))}if(!o){const x=i.match(/\b([A-Z][a-z]+)\s+(?:was|is|appeared|seemed|had|ate|declined|refused)\b/);x&&(o=x[1])}const s=ve(i,["mood","appeared","seemed","engagement","engaged","wellbeing"],["mobility","transfer","ate","drink","medication","action","plan","risk"]),l=ve(i,["mobility","mobilis","transfer","zimmer","frame","hoist","walked"],["ate","drink","nutrition","hydration","personal care","medication","action"]),d=ve(i,["nutrition","hydration","ate","eaten","drank","fluid","meal","lunch","breakfast","dinner","supper"],["personal care","washed","continence","medication","action","plan"]),u=ve(i,["personal care","washed","shower","continence","pad","skin","dressed"],["medication","clinical","obs","action","plan","risk"]),f=ve(i,["medication","prn","clinical","obs","blood pressure","temperature","gp","nurse","pain"],["action","plan","next","risk","incident"]),g=ve(i,["risk","incident","concern","safeguarding","near miss"],["action","plan","we ","staff "]),w=ve(i,["action","plan","we ","staff ","escalated","informed","documented","handover"],[]),y=[],k=i.toLowerCase();for(const[x,z]of Hi)k.includes(x)&&!y.includes(z)&&y.push(z);!y.length&&/settled|comfortable|no concerns|stable/i.test(i)&&y.push("No acute escalation flagged");const v=a||"this shift",$=[];t==="family"?$.push(o?`${o} has been supported ${v}.`:`Your relative has been supported ${v}.`):t==="handover"?$.push(o?`Handover — ${o} (${v}).`:`Handover note (${v}).`):$.push(o?`${o} was reviewed ${v}.`:`Resident reviewed ${v}.`);const E=[s,l,d,u,f].filter(Boolean).map(x=>x.endsWith(".")?x:`${x}.`);$.push(...E),g&&$.push(`Risks/incidents: ${g}${g.endsWith(".")?"":"."}`),w&&$.push(`Actions/plan: ${w}${w.endsWith(".")?"":"."}`),!E.length&&!g&&!w&&$.push(Ct(i)+(i.endsWith(".")?"":"."));const D=[o,a,s,l,d,u,f,g,w].filter(Boolean).length,ie=Math.min(98,35+D*8+Math.min(20,Math.floor(i.length/40))),U={resident:o,when:a,mood:s,mobility:l,nutrition:d,care:u,clinical:f,risks:g,actions:w,flags:y,narrative:$.join(" ").replace(/\s+/g," ").trim(),confidence:ie,noteType:t,dignityApplied:n!==(e||"").replace(/\s+/g," ").trim()};return U.coverage=pn(i),U.handover=Gi(U,U.coverage),U.escalation=Vi(U),U}const He={users:"don.users",sessionUser:"don.session.userId"},zi=1800*1e3;function ye(e){const t=`don.user|${String(e||"").trim()}`;let n=2166136261;for(let i=0;i<t.length;i+=1)n^=t.charCodeAt(i),n=Math.imul(n,16777619);return(n>>>0).toString(16)}function Ki(e,t){try{const n=localStorage.getItem(e);return n?JSON.parse(n):t}catch{return t}}function Yi(e,t){localStorage.setItem(e,JSON.stringify(t))}function Ji(e){const t={...e};return t.emailVerified===void 0&&(t.emailVerified=t.status==="approved"),t.requestedRole||(t.requestedRole=t.role==="admin"?"admin":"carer"),t}function P(){return Ki(He.users,[]).map(Ji)}function ae(e){Yi(He.users,Array.isArray(e)?e:[])}function B(e){if(!e)return null;const{passwordHash:t,verificationCodeHash:n,verificationExpiresAt:i,...r}=e;return r}function Gt(){return sessionStorage.getItem(He.sessionUser)||""}function S(){const e=Gt();if(!e)return null;const t=B(P().find(n=>n.id===e)||null);return t&&t.status!=="approved"?(re(""),null):t}function re(e){e?sessionStorage.setItem(He.sessionUser,e):sessionStorage.removeItem(He.sessionUser)}function yr(){re("")}function pt(e=S()){return!!(e&&e.status==="approved")}function Te(e=S()){return pt(e)&&e.role==="admin"}function wr(e=S()){return pt(e)}function qe(e,t=S()){return pt(t)?e==="learn"?!0:e==="train"||e==="reports"?Te(t):!1:!1}function Zi(){return String(Math.floor(1e5+Math.random()*9e5))}function Qi(e,t){const n=e[t];n.requestedRole!=="admin"&&n.role!=="admin"?e[t]={...n,status:"approved",role:"carer",emailVerified:!0,approvedAt:new Date().toISOString(),approvedBy:"email_verified",verificationCodeHash:null,verificationExpiresAt:null}:e[t]={...n,emailVerified:!0,verificationCodeHash:null,verificationExpiresAt:null}}function br(e){const t=String(e||"").trim().toLowerCase(),n=P(),i=n.findIndex(l=>l.email===t);if(i<0)throw new Error("No registration found for that email");const r=Zi();n[i].verificationCodeHash=ye(r),n[i].verificationExpiresAt=new Date(Date.now()+zi).toISOString(),ae(n);const o=encodeURIComponent("careTalk — verify your email"),a=encodeURIComponent(`Your careTalk verification code is: ${r}
21
 
 
1
+ const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["./web-DrRVGgij.js","./theme-CuaEyjDL.js","./web-BoLQRCPk.js","./web-CbBz5VEx.js"])))=>i.map(i=>d[i]);
2
+ import{i as zr}from"./theme-CuaEyjDL.js";/*! Capacitor: https://capacitorjs.com/ - MIT License */var Pe;(function(e){e.Unimplemented="UNIMPLEMENTED",e.Unavailable="UNAVAILABLE"})(Pe||(Pe={}));class $t extends Error{constructor(t,n,i){super(t),this.message=t,this.code=n,this.data=i}}const Kr=e=>{var t,n;return e!=null&&e.androidBridge?"android":!((n=(t=e==null?void 0:e.webkit)===null||t===void 0?void 0:t.messageHandlers)===null||n===void 0)&&n.bridge?"ios":"web"},Yr=e=>{const t=e.CapacitorCustomPlatform||null,n=e.Capacitor||{},i=n.Plugins=n.Plugins||{},r=()=>t!==null?t.name:Kr(e),o=()=>r()!=="web",a=f=>{const g=d.get(f);return!!(g!=null&&g.platforms.has(r())||s(f))},s=f=>{var g;return(g=n.PluginHeaders)===null||g===void 0?void 0:g.find(w=>w.name===f)},l=f=>e.console.error(f),d=new Map,u=(f,g={})=>{const w=d.get(f);if(w)return console.warn(`Capacitor plugin "${f}" already registered. Cannot register plugins twice.`),w.proxy;const y=r(),k=s(f);let v;const $=async()=>(!v&&y in g?v=typeof g[y]=="function"?v=await g[y]():v=g[y]:t!==null&&!v&&"web"in g&&(v=typeof g.web=="function"?v=await g.web():v=g.web),v),E=(R,_)=>{var K,Y;if(k){const J=k==null?void 0:k.methods.find(Z=>_===Z.name);if(J)return J.rtype==="promise"?Z=>n.nativePromise(f,_.toString(),Z):(Z,Ce)=>n.nativeCallback(f,_.toString(),Z,Ce);if(R)return(K=R[_])===null||K===void 0?void 0:K.bind(R)}else{if(R)return(Y=R[_])===null||Y===void 0?void 0:Y.bind(R);throw new $t(`"${f}" plugin is not implemented on ${y}`,Pe.Unimplemented)}},D=R=>{let _;const K=(...Y)=>{const J=$().then(Z=>{const Ce=E(Z,R);if(Ce){const fe=Ce(...Y);return _=fe==null?void 0:fe.remove,fe}else throw new $t(`"${f}.${R}()" is not implemented on ${y}`,Pe.Unimplemented)});return R==="addListener"&&(J.remove=async()=>_()),J};return K.toString=()=>`${R.toString()}() { [capacitor code] }`,Object.defineProperty(K,"name",{value:R,writable:!1,configurable:!1}),K},ie=D("addListener"),U=D("removeListener"),x=(R,_)=>{const K=ie({eventName:R},_),Y=async()=>{const Z=await K;U({eventName:R,callbackId:Z},_)},J=new Promise(Z=>K.then(()=>Z({remove:Y})));return J.remove=async()=>{console.warn("Using addListener() without 'await' is deprecated."),await Y()},J},z=new Proxy({},{get(R,_){switch(_){case"$$typeof":return;case"toJSON":return()=>({});case"addListener":return k?x:ie;case"removeListener":return U;default:return D(_)}}});return i[f]=z,d.set(f,{name:f,proxy:z,platforms:new Set([...Object.keys(g),...k?[y]:[]])}),z};return n.convertFileSrc||(n.convertFileSrc=f=>f),n.getPlatform=r,n.handleError=l,n.isNativePlatform=o,n.isPluginAvailable=a,n.registerPlugin=u,n.Exception=$t,n.DEBUG=!!n.DEBUG,n.isLoggingEnabled=!!n.isLoggingEnabled,n},Jr=e=>e.Capacitor=Yr(e),Oe=Jr(typeof globalThis<"u"?globalThis:typeof self<"u"?self:typeof window<"u"?window:typeof global<"u"?global:{}),Se=Oe.registerPlugin;class tr{constructor(){this.listeners={},this.retainedEventArguments={},this.windowListeners={}}addListener(t,n){let i=!1;this.listeners[t]||(this.listeners[t]=[],i=!0),this.listeners[t].push(n);const o=this.windowListeners[t];o&&!o.registered&&this.addWindowListener(o),i&&this.sendRetainedArgumentsForEvent(t);const a=async()=>this.removeListener(t,n);return Promise.resolve({remove:a})}async removeAllListeners(){this.listeners={};for(const t in this.windowListeners)this.removeWindowListener(this.windowListeners[t]);this.windowListeners={}}notifyListeners(t,n,i){const r=this.listeners[t];if(!r){if(i){let o=this.retainedEventArguments[t];o||(o=[]),o.push(n),this.retainedEventArguments[t]=o}return}r.forEach(o=>o(n))}hasListeners(t){var n;return!!(!((n=this.listeners[t])===null||n===void 0)&&n.length)}registerWindowListener(t,n){this.windowListeners[n]={registered:!1,windowEventName:t,pluginEventName:n,handler:i=>{this.notifyListeners(n,i)}}}unimplemented(t="not implemented"){return new Oe.Exception(t,Pe.Unimplemented)}unavailable(t="not available"){return new Oe.Exception(t,Pe.Unavailable)}async removeListener(t,n){const i=this.listeners[t];if(!i)return;const r=i.indexOf(n);this.listeners[t].splice(r,1),this.listeners[t].length||this.removeWindowListener(this.windowListeners[t])}addWindowListener(t){window.addEventListener(t.windowEventName,t.handler),t.registered=!0}removeWindowListener(t){t&&(window.removeEventListener(t.windowEventName,t.handler),t.registered=!1)}sendRetainedArgumentsForEvent(t){const n=this.retainedEventArguments[t];n&&(delete this.retainedEventArguments[t],n.forEach(i=>{this.notifyListeners(t,i)}))}}const en=e=>encodeURIComponent(e).replace(/%(2[346B]|5E|60|7C)/g,decodeURIComponent).replace(/[()]/g,escape),tn=e=>e.replace(/(%[\dA-F]{2})+/gi,decodeURIComponent);class Zr extends tr{async getCookies(){const t=document.cookie,n={};return t.split(";").forEach(i=>{if(i.length<=0)return;let[r,o]=i.replace(/=/,"CAP_COOKIE").split("CAP_COOKIE");r=tn(r).trim(),o=tn(o).trim(),n[r]=o}),n}async setCookie(t){try{const n=en(t.key),i=en(t.value),r=t.expires?`; expires=${t.expires.replace("expires=","")}`:"",o=(t.path||"/").replace("path=",""),a=t.url!=null&&t.url.length>0?`domain=${t.url}`:"";document.cookie=`${n}=${i||""}${r}; path=${o}; ${a};`}catch(n){return Promise.reject(n)}}async deleteCookie(t){try{document.cookie=`${t.key}=; Max-Age=0`}catch(n){return Promise.reject(n)}}async clearCookies(){try{const t=document.cookie.split(";")||[];for(const n of t)document.cookie=n.replace(/^ +/,"").replace(/=.*/,`=;expires=${new Date().toUTCString()};path=/`)}catch(t){return Promise.reject(t)}}async clearAllCookies(){try{await this.clearCookies()}catch(t){return Promise.reject(t)}}}Se("CapacitorCookies",{web:()=>new Zr});const Qr=async e=>new Promise((t,n)=>{const i=new FileReader;i.onload=()=>{const r=i.result;t(r.indexOf(",")>=0?r.split(",")[1]:r)},i.onerror=r=>n(r),i.readAsDataURL(e)}),Xr=(e={})=>{const t=Object.keys(e);return Object.keys(e).map(r=>r.toLocaleLowerCase()).reduce((r,o,a)=>(r[o]=e[t[a]],r),{})},ei=(e,t=!0)=>e?Object.entries(e).reduce((i,r)=>{const[o,a]=r;let s,l;return Array.isArray(a)?(l="",a.forEach(d=>{s=t?encodeURIComponent(d):d,l+=`${o}=${s}&`}),l.slice(0,-1)):(s=t?encodeURIComponent(a):a,l=`${o}=${s}`),`${i}&${l}`},"").substr(1):null,ti=(e,t={})=>{const n=Object.assign({method:e.method||"GET",headers:e.headers},t),r=Xr(e.headers)["content-type"]||"";if(typeof e.data=="string")n.body=e.data;else if(r.includes("application/x-www-form-urlencoded")){const o=new URLSearchParams;for(const[a,s]of Object.entries(e.data||{}))o.set(a,s);n.body=o.toString()}else if(r.includes("multipart/form-data")||e.data instanceof FormData){const o=new FormData;if(e.data instanceof FormData)e.data.forEach((s,l)=>{o.append(l,s)});else for(const s of Object.keys(e.data))o.append(s,e.data[s]);n.body=o;const a=new Headers(n.headers);a.delete("content-type"),n.headers=a}else(r.includes("application/json")||typeof e.data=="object")&&(n.body=JSON.stringify(e.data));return n};class ni extends tr{async request(t){const n=ti(t,t.webFetchExtra),i=ei(t.params,t.shouldEncodeUrlParams),r=i?`${t.url}?${i}`:t.url,o=await fetch(r,n),a=o.headers.get("content-type")||"";let{responseType:s="text"}=o.ok?t:{};a.includes("application/json")&&(s="json");let l,d;switch(s){case"arraybuffer":case"blob":d=await o.blob(),l=await Qr(d);break;case"json":l=await o.json();break;case"document":case"text":default:l=await o.text()}const u={};return o.headers.forEach((f,g)=>{u[g]=f}),{data:l,headers:u,status:o.status,url:o.url}}async get(t){return this.request(Object.assign(Object.assign({},t),{method:"GET"}))}async post(t){return this.request(Object.assign(Object.assign({},t),{method:"POST"}))}async put(t){return this.request(Object.assign(Object.assign({},t),{method:"PUT"}))}async patch(t){return this.request(Object.assign(Object.assign({},t),{method:"PATCH"}))}async delete(t){return this.request(Object.assign(Object.assign({},t),{method:"DELETE"}))}}Se("CapacitorHttp",{web:()=>new ni});const ri="modulepreload",ii=function(e,t){return new URL(e,t).href},nn={},Ut=function(t,n,i){let r=Promise.resolve();if(n&&n.length>0){let a=function(u){return Promise.all(u.map(f=>Promise.resolve(f).then(g=>({status:"fulfilled",value:g}),g=>({status:"rejected",reason:g}))))};const s=document.getElementsByTagName("link"),l=document.querySelector("meta[property=csp-nonce]"),d=(l==null?void 0:l.nonce)||(l==null?void 0:l.getAttribute("nonce"));r=a(n.map(u=>{if(u=ii(u,i),u in nn)return;nn[u]=!0;const f=u.endsWith(".css"),g=f?'[rel="stylesheet"]':"";if(!!i)for(let k=s.length-1;k>=0;k--){const v=s[k];if(v.href===u&&(!f||v.rel==="stylesheet"))return}else if(document.querySelector(`link[href="${u}"]${g}`))return;const y=document.createElement("link");if(y.rel=f?"stylesheet":ri,f||(y.as="script"),y.crossOrigin="",y.href=u,d&&y.setAttribute("nonce",d),document.head.appendChild(y),f)return new Promise((k,v)=>{y.addEventListener("load",k),y.addEventListener("error",()=>v(new Error(`Unable to preload CSS for ${u}`)))})}))}function o(a){const s=new Event("vite:preloadError",{cancelable:!0});if(s.payload=a,window.dispatchEvent(s),!s.defaultPrevented)throw a}return r.then(a=>{for(const s of a||[])s.status==="rejected"&&o(s.reason);return t().catch(o)})},ge=Se("SpeechRecognition",{web:()=>Ut(()=>import("./web-DrRVGgij.js"),__vite__mapDeps([0,1]),import.meta.url).then(e=>new e.SpeechRecognitionWeb)});function Ze(){return Oe.isNativePlatform()}function oi({onFinal:e,onPartial:t,onStart:n,onEnd:i,onError:r,lang:o="en-GB"}){let a=!1,s=null,l=null,d=null,u=!1,f="",g=0,w="",y=null,k=null,v=o,$=!1,E=!1,D=!1,ie=0,U="";function x(I){const b=String(I||"").trim();if(!b)return!0;try{if(b===window.location.href||b===window.location.origin||b===window.location.host||b===`${window.location.protocol}//${window.location.host}`)return!0}catch{}return!!(/^https?:\/\//i.test(b)||/\blocalhost(:\d+)?\b/i.test(b)||/\b127\.0\.0\.1\b/.test(b)||/mic (issue|blocked|busy)|speech needs internet|no microphone|asking for microphone/i.test(b)||!/[a-zA-Z]{2,}/.test(b))}function z(I){const b=String(I||"").trim();if(!b||x(b)||D||E)return;const T=Date.now();b.toLowerCase()===w.toLowerCase()&&T-g<1200||(w=b,g=T,f="",clearTimeout(y),e==null||e(b))}function R(I){const b=String(I||"").trim();if(!b||x(b))return;f=b,t==null||t(b),clearTimeout(y);const T=b.split(/\s+/).filter(Boolean).length,M=T<=3?1100:T<=8?1500:1900;y=setTimeout(()=>{f===b&&!D&&!E&&z(b)},M)}function _(I){var T;let b="";for(let M=0;M<I.length;M+=1){const C=(((T=I[M])==null?void 0:T.transcript)||"").trim();if(C&&(b||(b=C),/\b(don|dawn|done|dom|dun|donn|donald)\b/i.test(C))){b=C;break}}return b}async function K(){var T,M;if(!window.isSecureContext)throw new Error("Mic blocked on insecure URL — open http://localhost:5173 in Chrome");if(!((T=navigator.mediaDevices)!=null&&T.getUserMedia))throw new Error("This window can’t use the mic — open the app in Chrome or Edge");let I;try{I=await navigator.mediaDevices.getUserMedia({audio:{echoCancellation:!0,noiseSuppression:!0,autoGainControl:!0}})}catch(C){const ne=(C==null?void 0:C.name)||"";throw ne==="NotFoundError"||ne==="DevicesNotFoundError"?new Error("No microphone detected — plug one in (System Settings → Sound → Input)"):ne==="NotAllowedError"||ne==="PermissionDeniedError"?new Error("Microphone permission denied — click the lock icon → Microphone → Allow"):ne==="NotReadableError"||ne==="TrackStartError"?new Error("Microphone is busy — quit Zoom/Teams/FaceTime/OBS, then tap the mic again"):new Error((C==null?void 0:C.message)||"Could not open microphone")}const b=I.getAudioTracks()[0];if(U=(b==null?void 0:b.label)||"Microphone",b&&b.readyState!=="live")throw I.getTracks().forEach(C=>C.stop()),new Error("Microphone track inactive — check Mac Sound input device");I.getTracks().forEach(C=>C.stop()),await new Promise(C=>setTimeout(C,180));try{if(!(await navigator.mediaDevices.enumerateDevices()).filter(Vr=>Vr.kind==="audioinput").length)throw new Error("No audio input devices listed — check System Settings → Sound → Input")}catch(C){if((M=C==null?void 0:C.message)!=null&&M.startsWith("No audio"))throw C}return U}function Y(){if(!(!u||!s||$||E)){$=!0;try{s.lang=v,s.start()}catch(I){const b=String((I==null?void 0:I.message)||I||"");/already started|InvalidStateError/i.test(b)||r==null||r(b||"Could not start mic")}finally{setTimeout(()=>{$=!1},300)}}}function J(I=300){!u||E||(clearTimeout(k),k=setTimeout(()=>{!u||E||Y()},I))}function Z(){if(s)return s;const I=window.SpeechRecognition||window.webkitSpeechRecognition;if(!I)throw new Error("Speech not supported here — use Chrome or Edge (not Safari), or type to careTalk");return s=new I,s.continuous=!0,s.interimResults=!0,s.maxAlternatives=5,s.lang=v,s.onstart=()=>{a=!0,$=!1,ie=0,n==null||n()},s.onend=()=>{a=!1,i==null||i(),!E&&(clearTimeout(y),f="",J(320))},s.onerror=b=>{const T=b.error;if(T!=="aborted"&&T!=="no-speech"){if(T==="audio-capture"){if(ie+=1,ie<=2&&u){r==null||r("Mic busy — retrying… close other apps using the mic"),clearTimeout(k),k=setTimeout(async()=>{if(u)try{await K(),Y()}catch(M){u=!1,r==null||r((M==null?void 0:M.message)||"no microphone available")}},600);return}u=!1,r==null||r(U?`Can’t capture “${U}” — quit Zoom/Teams/FaceTime, allow mic for this site, tap again`:"Can’t open microphone — allow mic in the address bar, quit apps using the mic, use Chrome on localhost");return}if(T==="not-allowed"||T==="service-not-allowed"){u=!1,r==null||r("Mic blocked — lock icon in address bar → Microphone → Allow, then tap mic");return}if(T==="network"){r==null||r("Speech needs internet (Chrome voice service)"),J(1200);return}if(T==="language-not-supported"&&v!=="en-US"){v="en-US",s.lang=v,J(300);return}r==null||r(T),J(500)}},s.onresult=b=>{let T="";for(let M=b.resultIndex;M<b.results.length;M+=1){const C=b.results[M],ne=_(C);!ne||x(ne)||(C.isFinal?!D&&!E&&z(ne):T+=`${ne} `)}T.trim()&&!D&&(t==null||t(T.trim()),f=T.trim(),R(T.trim()))},s}async function Ce(){const I=await ge.available();if(!(I!=null&&I.available))throw new Error("Speech recognition unavailable on this device");if((await ge.checkPermissions()).speechRecognition!=="granted"&&(await ge.requestPermissions()).speechRecognition!=="granted")throw new Error("Microphone / speech permission denied")}async function fe(){await Ce(),f="",l=await ge.addListener("partialResults",I=>{const b=((I==null?void 0:I.matches)||[]).filter(Boolean).join(" ").trim();b&&R(b)}),d=await ge.addListener("listeningState",I=>{I.status==="started"&&(a=!0,n==null||n()),I.status==="stopped"&&(a=!1,i==null||i(),u&&!E&&(clearTimeout(k),k=setTimeout(()=>{u&&fe().catch(b=>r==null?void 0:r((b==null?void 0:b.message)||"mic restart failed"))},400)))}),await ge.start({language:v,maxResults:5,partialResults:!0,popup:!1}),a=!0,n==null||n()}async function Gr(){clearTimeout(y),clearTimeout(k);try{await ge.stop()}catch{}f&&!x(f)&&z(f);try{await(l==null?void 0:l.remove()),await(d==null?void 0:d.remove())}catch{}l=null,d=null,a=!1,i==null||i()}return{get listening(){return a},get micLabel(){return U},setInputBlocked(I){D=!!I,D&&(clearTimeout(y),f="")},async start(){if(u=!0,E=!1,f="",ie=0,Ze()){await fe();return}await K(),Z(),Y()},async pause(){if(E=!0,D=!0,clearTimeout(k),clearTimeout(y),Ze()){try{await ge.stop()}catch{}a=!1,i==null||i();return}try{s==null||s.stop()}catch{}a=!1,i==null||i()},async resume(){if(E=!1,D=!1,u=!0,Ze()){await fe();return}Y()},async stop(){if(u=!1,E=!1,clearTimeout(k),clearTimeout(y),$=!1,Ze()){await Gr();return}const I=f;f="";try{s==null||s.stop()}catch{}I&&!x(I)&&z(I),a=!1,i==null||i()}}}var At;(function(e){e.Dark="DARK",e.Light="LIGHT",e.Default="DEFAULT"})(At||(At={}));var rn;(function(e){e.None="NONE",e.Slide="SLIDE",e.Fade="FADE"})(rn||(rn={}));const on=Se("StatusBar"),ai=Se("SplashScreen",{web:()=>Ut(()=>import("./web-BoLQRCPk.js"),__vite__mapDeps([2,1]),import.meta.url).then(e=>new e.SplashScreenWeb)});var an;(function(e){e.Dark="DARK",e.Light="LIGHT",e.Default="DEFAULT"})(an||(an={}));var Lt;(function(e){e.Body="body",e.Ionic="ionic",e.Native="native",e.None="none"})(Lt||(Lt={}));const si=Se("Keyboard"),sn=Se("App",{web:()=>Ut(()=>import("./web-CbBz5VEx.js"),__vite__mapDeps([3,1]),import.meta.url).then(e=>new e.AppWeb)});async function li(){if(Oe.isNativePlatform()){document.documentElement.classList.add("native"),document.documentElement.dataset.platform=Oe.getPlatform();try{await on.setStyle({style:At.Dark}),await on.setBackgroundColor({color:"#061114"})}catch{}try{await si.setResizeMode({mode:Lt.Body})}catch{}try{await ai.hide()}catch{}sn.addListener("backButton",({canGoBack:e})=>{e?window.history.back():sn.exitApp()})}}const O={pinHash:"don.train.pinHash",pinSet:"don.train.pinSet",sessionAuth:"don.train.authed",knowledge:"don.train.knowledge",agency:"don.agency",outbox:"don.agency.outbox",incidents:"don.train.incidents",customTopics:"don.train.customTopics"},_t="2473";function Xe(e){const t=`don|${String(e||"").trim()}`;let n=2166136261;for(let i=0;i<t.length;i+=1)n^=t.charCodeAt(i),n=Math.imul(n,16777619);return(n>>>0).toString(16)}function ze(e,t){try{const n=localStorage.getItem(e);return n?JSON.parse(n):t}catch{return t}}function Ke(e,t){localStorage.setItem(e,JSON.stringify(t))}function ci(){return localStorage.getItem(O.pinSet)==="1"}function Mt(){ci()||(localStorage.setItem(O.pinHash,Xe(_t)),localStorage.setItem(O.pinSet,"1"))}function di(e){Mt();const t=localStorage.getItem(O.pinHash)||Xe(_t);return Xe(e)===t}function ui(e){const t=String(e||"").trim();if(t.length<4)throw new Error("PIN must be at least 4 digits");localStorage.setItem(O.pinHash,Xe(t)),localStorage.setItem(O.pinSet,"1")}function he(e){e?sessionStorage.setItem(O.sessionAuth,"1"):sessionStorage.removeItem(O.sessionAuth)}function nr(){return sessionStorage.getItem(O.sessionAuth)==="1"}function ue(){return ze(O.knowledge,[])}function rr(e){Ke(O.knowledge,e)}function ir(e){const t=ue(),n=r=>Array.isArray(r)?r.map(o=>String(o).trim()).filter(Boolean):String(r||"").split(`
3
  `).map(o=>o.trim()).filter(Boolean),i={id:`k_${Date.now()}`,title:String(e.title||"").trim(),body:String(e.body||"").trim(),doList:n(e.doList),dontList:n(e.dontList),keywords:String(e.keywords||"").split(",").map(r=>r.trim().toLowerCase()).filter(Boolean),sourceUrl:String(e.sourceUrl||"").trim(),images:Array.isArray(e.images)?e.images.map(r=>String(r).trim()).filter(Boolean):String(e.images||"").split(`
4
  `).map(r=>r.trim()).filter(Boolean),addedBy:e.addedBy||"Head nurse",addedAt:new Date().toISOString()};if(!i.title||!i.body)throw new Error("Title and guidance text are required");return t.unshift(i),rr(t),i}function pi(e){rr(ue().filter(t=>t.id!==e))}function ot(){return ze(O.agency,{name:"Care agency",email:"",webhookUrl:"",autoForward:!0})}function fi(e){Ke(O.agency,{name:String(e.name||"Care agency").trim()||"Care agency",email:String(e.email||"").trim(),webhookUrl:String(e.webhookUrl||"").trim(),autoForward:e.autoForward!==!1})}function or(){return ze(O.outbox,[])}function ar(e){const t=or();t.unshift(e),Ke(O.outbox,t.slice(0,50))}function sr(){return ze(O.incidents,[])}function gi(e){Ke(O.incidents,Array.isArray(e)?e:[])}function ke(){return ze(O.customTopics,[])}function jt(e){Ke(O.customTopics,Array.isArray(e)?e:[])}function lr({title:e,keywords:t="",notes:n=""}){const i=String(e||"").trim();if(!i)throw new Error("Topic title is required");const r=ke(),o={id:`topic_${Date.now()}`,title:i,keywords:String(t||"").split(",").map(a=>a.trim().toLowerCase()).filter(Boolean),notes:String(n||"").trim(),addedAt:new Date().toISOString(),lastTrainedAt:null};return r.unshift(o),jt(r),o}function mi(e){jt(ke().filter(t=>t.id!==e))}function hi(e){const t=ke(),n=t.findIndex(i=>i.id===e);n<0||(t[n].lastTrainedAt=new Date().toISOString(),jt(t))}const St={fall:[{id:"fall-assess",title:"Assess first",caption:"Stay with them, check responsiveness and injury before any move.",src:"/guides/fall-assess.svg",alt:"Carer kneeling beside a person on the floor after a fall, asking if they are hurt"},{id:"fall-no-lift",title:"Don’t haul them up",caption:"If injury may be present, keep them comfortable and get clinical advice.",src:"/guides/fall-no-lift.svg",alt:"Warning not to lift a fallen person without assessment"}],dysphagia:[{id:"dysphagia-upright",title:"Sit upright",caption:"Upright posture for eating and drinking; follow texture plan.",src:"/guides/dysphagia-upright.svg",alt:"Person sitting upright in a chair for safe eating and drinking"},{id:"dysphagia-stop",title:"Stop if choking signs",caption:"Coughing, wet voice or colour change — stop intake and call for help.",src:"/guides/dysphagia-stop.svg",alt:"Stop cup or food when choking warning signs appear"}],distress:[{id:"distress-space",title:"Give space",caption:"Reduce stimulation, keep a calm distance, use care-plan strategies.",src:"/guides/distress-space.svg",alt:"Carer giving a person space during distress"}],skin:[{id:"skin-check",title:"Note site & look",caption:"Record exact site, appearance and pain; escalate for grading/dressings.",src:"/guides/skin-check.svg",alt:"Diagram highlighting checking pressure areas on the body"}]};function yi(e,t=[]){const n=St[e]||[],i=[];for(const o of t)(Array.isArray(o.images)?o.images:[]).forEach((s,l)=>{const d=String(s||"").trim();d&&i.push({id:`trained_${o.id||l}_${l}`,title:o.title||"Home training image",caption:"From your home’s trained knowledge",src:d,alt:`${o.title||"Training"} illustration ${l+1}`})});const r=new Set;return[...n,...i].filter(o=>r.has(o.src)?!1:(r.add(o.src),!0))}function wi(e,t){return e!=null&&e.length?`
5
  <div class="guide-strip">
 
15
  </figcaption>
16
  </figure>`).join("")}</div>
17
  </div>
18
+ `:""}const cr={version:"1.1.31",disclaimer:"careTalk is a demonstration prototype. Notes are drafts for staff review — not an approved care record. Follow your home’s policy, escalate to the nurse in charge, and call 999 in an emergency."},Ft=[{id:"pmva_mapa",title:"PMVA / MAPA (BILD-accredited)",notes:"Physical intervention and de-escalation for mental health settings is a specialised, assessed course (typically multi-day, BILD-accredited). Prefer prevention, communication, and least-restrictive options. Only use techniques you are currently trained and authorised to use."},{id:"oliver_mcgowan",title:"Oliver McGowan Mandatory Training (Tier 2 + online)",notes:"Learning disability and autism awareness: assume competence, adapt communication, reduce sensory load, involve familiar supporters, avoid diagnostic overshadowing, and escalate concerns about distress or unmet need."},{id:"ligature",title:"Ligature awareness",notes:"Remove or reduce ligature risks where safe and authorised; do not leave someone in danger to ‘finish paperwork’. Observe, report environmental risks, stay with the person if unsafe to leave, and escalate immediately per policy."},{id:"dysphagia",title:"Dysphagia awareness",notes:"Follow IDDSI / care-plan texture and fluid guidance. Never rush feeding, never mix consistencies against the plan, sit upright, watch for coughing/wet voice/colour change, and stop and escalate if aspiration is suspected."},{id:"seniors",title:"Caring for older adults",notes:"Person-centred, dignity-first care: explain what you are doing, offer choice, watch for delirium, falls, skin, hydration, and loneliness. Document facts, not judgements."},{id:"moving_assisting",title:"Moving and assisting people",notes:"Use agreed handling plans, equipment you are trained on, and enough staff. Do not lift manually against policy. After a fall, do not haul someone up if injury is possible — assess, reassure, follow fallen-person procedure."},{id:"hswa",title:"Health and Safety at Work etc. Act",notes:"Take reasonable care of yourself and others, follow training, report hazards, and do not carry out tasks you are not competent or authorised to do."}];function bi(e,t){const n=`${e} ${t||""}`.toLowerCase(),i=ue().filter(r=>{var o;return(o=r.keywords)!=null&&o.length?r.keywords.some(a=>n.includes(a)||e.includes(a)):e==="general"||e==="medication"});if(e==="medication"){const r=i.filter(o=>/\b(medicine|medication|meds|refus|tablet|mar)\b/i.test(`${o.title} ${o.body} ${(o.keywords||[]).join(" ")}`));return r.length?r:i}return i}function ki(e,t=""){var u,f;const n=["Stay calm and reassure the person.","Check for immediate danger to them and you.","Follow your service’s escalation pathway (nurse in charge / on-call / 999).","Document facts: what you saw, what you did, time, who was informed."],i=["Don’t leave an unsafe situation to ‘write the note first’.","Don’t use restrictive holds unless you are currently trained, authorised, and it is a last resort under policy.","Don’t blame the person in the record — stick to observable facts."],r={fall:{pillars:["moving_assisting","seniors","hswa"],do:[...n,"If injury may be present, do not pull them up — keep them comfortable, check responsiveness, and get clinical advice.","Look for head injury signs, pain, limb deformity, bleeding, and sudden confusion.","After safe recovery, review footwear, mobility aid, lighting, and observation level."],dont:[...i,"Don’t use a fireman’s lift or unplanned manual lift.","Don’t dismiss an unwitnessed fall — treat it seriously until assessed.","Don’t delay informing the nurse in charge / family when policy requires it."]},skin:{pillars:["seniors","hswa"],do:[...n,"Note exact site, size/appearance if trained to, pain, and whether skin is broken.","Reposition as care plan allows; keep pressure off the area.","Inform nurse in charge for grading / dressing decisions if required."],dont:[...i,"Don’t apply creams or dressings outside your role/competence.","Don’t ignore unbroken redness over a bony area."]},dysphagia:{pillars:["dysphagia","oliver_mcgowan","seniors"],do:[...n,"Stop oral intake if coughing, choking, wet voice, or colour change.","Keep upright; follow prescribed texture/fluid level only.","Call for help early — choking is time-critical."],dont:[...i,"Don’t give food/drink against the dysphagia plan.","Don’t leave someone alone while eating if supervision is required.","Don’t do blind finger sweeps if choking."]},distress:{pillars:["pmva_mapa","oliver_mcgowan","ligature","hswa"],do:[...n,"Reduce stimulation, give space, use calm simple language, and offer known soothing strategies from the care plan.","Scan for environmental risk (ligature points, weapons, exits) without escalating conflict.","Call for trained support early; protect yourself and others."],dont:[...i,"Don’t crowd, shout, or threaten.","Don’t use physical intervention unless trained, authorised, proportionate, and necessary as a last resort.","Don’t ignore ligature risk to ‘talk it out’ from a distance if the person is in immediate danger — get help now."]},wellbeing:{pillars:["seniors","oliver_mcgowan"],do:[...n,"Ask about pain, mood, appetite, and what matters to them today.","Note changes from their usual baseline."],dont:[...i,"Don’t skip hydration/nutrition checks when someone seems ‘fine’ but quieter than usual."]},medication:{pillars:["hswa","seniors"],do:["Stay calm and do not force medicine.","Follow your home’s medication / MAR policy and the person’s care plan.","Inform the nurse in charge / on-call promptly.","Document facts: what was offered, what was refused, time, and who was informed."],dont:["Don’t hide medicine in food/drink unless the care plan and policy explicitly allow covert administration by authorised staff.","Don’t force, threaten, or restrain someone to take medicine.","Don’t leave a refused critical dose unreported."]},general:{pillars:["hswa","seniors"],do:n,dont:i}},o={...r[e]||r.general},a=bi(e,t);for(const g of a)(u=g.doList)!=null&&u.length&&(o.do=[...o.do,...g.doList]),(f=g.dontList)!=null&&f.length&&(o.dont=[...o.dont,...g.dontList]);const s=Ft.filter(g=>o.pillars.includes(g.id)).map(g=>`${g.title}: ${g.notes}`),l=a.map(g=>`${g.title}: ${g.body}`),d=yi(e,a);return{...o,pillarText:s,trainedText:l,custom:a,images:d}}async function vi(e,t={}){const n=ot(),i={id:`fwd_${Date.now()}`,at:new Date().toISOString(),agencyName:n.name,agencyEmail:n.email,carer:t.carer||"",person:t.person||"",scenario:t.scenario||"",report:e,status:"queued",channels:[]};if(i.channels.push("outbox"),n.webhookUrl)try{const r=await fetch(n.webhookUrl,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({type:"don.support_worker_report",...i})});if(!r.ok)throw new Error(`HTTP ${r.status}`);i.channels.push("webhook")}catch(r){i.webhookError=(r==null?void 0:r.message)||"webhook failed"}if(n.email){const r=encodeURIComponent(`careTalk support worker report — ${t.person||"resident"} — ${t.scenario||"care"}`),o=encodeURIComponent(e.slice(0,1800)),a=`mailto:${encodeURIComponent(n.email)}?subject=${r}&body=${o}`;i.mailto=a,i.channels.push("email");try{const s=document.createElement("a");s.href=a,s.rel="noopener",document.body.appendChild(s),s.click(),s.remove()}catch{}}return i.status=i.channels.includes("webhook")||i.channels.includes("email")?"sent":"saved_local",ar(i),{packet:i,agency:n}}function ln(e){return String(e||"").trim().toLowerCase().replace(/[^a-z'-]/g,"")}function $i(e,t){const n=ln(e),i=ln(t);if(!n||!i)return!1;if(n===i)return!0;const r=n.split(/\s+/)[0],o=i.split(/\s+/)[0];return r.length>1&&r===o}function at(e){const t=String(e||"").trim();return t?t.split(/\s+/)[0]:""}function st(e,t){return $i(e,t)}function Ii(e,t){const n=String(e||"").trim().toLowerCase().replace(/[^\w\s'-]/g,""),i=String(t||"").trim().toLowerCase().replace(/[^\w\s'-]/g,"");return!n||!i?!1:!!(n===i||n.length>8&&i.includes(n)||i.length>12&&n.includes(i.slice(0,Math.min(24,i.length))))}function Ai(e,t){return t!=="waiting_answer"?!1:/^(yes|yeah|yep|yup|no|nope|nah|ok|okay|correct|right|wrong)$/i.test(String(e||"").trim())}const Ie=[{id:"fall",label:"Fall",match:/\b(fall|fell|fallen|slipped|trip(?:ped)?)\b/i,questions:[{id:"when",ask:"When did it happen — just now, or roughly what time?"},{id:"where",ask:"Where did it happen? Bedroom, bathroom, corridor…?"},{id:"witnessed",ask:"Did anyone see it, or was it unwitnessed?"},{id:"how",ask:"What were they doing right before — standing up, walking, reaching…?"},{id:"injury",ask:"Any pain, bleeding, bumps, or odd limb position — or none that you can see?"},{id:"response",ask:"What have you done so far?"},{id:"obs",ask:"How are they now — alert, dizzy, confused, calm?"},{id:"informed",ask:"Who have you told, and who still needs telling — nurse in charge, GP, family, 999?"},{id:"prevent",ask:"Anything you want in place now for safety — mat, closer checks, footwear…?"}]},{id:"dysphagia",label:"Eating / choking / swallow",match:/\b(chok(?:e|ing)?|swallow|dysphagia|coughing (?:on|while) (?:eat|drink)|aspirat)/i,questions:[{id:"what",ask:"What happened with eating or drinking?"},{id:"texture",ask:"Were they on a special texture or fluid level?"},{id:"signs",ask:"Any coughing, colour change, wet voice, or distress?"},{id:"stopped",ask:"Did you stop food and drink?"},{id:"now",ask:"How are they now?"},{id:"informed",ask:"Who have you informed?"}]},{id:"distress",label:"Distress / behaviour support",match:/\b(distress|agitated|aggression|hitting|ligature|self[- ]harm|restrain|mapa|pmva|difficult|challenging|behaviour|behavior)\b/i,questions:[{id:"what",ask:"What’s happening for them right now, in plain words?"},{id:"trigger",ask:"Anything that seemed to trigger it?"},{id:"risk",ask:"Is anyone in immediate danger — including ligature or weapons risk?"},{id:"done",ask:"What have you tried — space, calm talk, care-plan strategies?"},{id:"help",ask:"Who is supporting you on the floor right now?"},{id:"now",ask:"How is the person now?"}]},{id:"medication",label:"Medication / refusal",match:/\b((refuse[ds]?|refusing|won'?t take|will not take|not taking|declined?).{0,40}\b(medicine|medication|meds|tablet|tablets|pill|pills|dose)\b|\b(medicine|medication|meds|tablet|tablets|pill|pills).{0,40}\b(refuse[ds]?|refusing|won'?t|not taking|declined?)\b|\b(medication|medicine|meds|mar)\b)/i,questions:[{id:"what",ask:"Which medicine was refused or not taken — if you know the name or time slot?"},{id:"when",ask:"When was this — which round / roughly what time?"},{id:"how",ask:"What exactly happened — refused, spat out, asleep, not present…?"},{id:"reason",ask:"Did they say why, or seem unwell / distressed?"},{id:"done",ask:"What have you tried so far (offer again, nurse, wait)?"},{id:"now",ask:"How are they now?"},{id:"informed",ask:"Who have you told — nurse in charge / on-call?"},{id:"next",ask:"What needs to happen next according to the home’s policy?"}]},{id:"skin",label:"Skin / pressure concern",match:/\b(skin|pressure|sore|redness|bruise|wound|mark)\b/i,questions:[{id:"where",ask:"Where on the body is the mark or sore?"},{id:"looks",ask:"What does it look like?"},{id:"pain",ask:"Are they sore there?"},{id:"found",ask:"When did you notice it?"},{id:"done",ask:"What have you done so far?"},{id:"next",ask:"What do you think needs to happen next?"}]},{id:"wellbeing",label:"Wellbeing check",match:/\b(wellbeing|well-being|mood|check(?:ed)? on|how .+ (?:is|are))\b/i,questions:[{id:"mood",ask:"How is their mood and engagement?"},{id:"eat",ask:"Eating and drinking okay?"},{id:"mobility",ask:"Any mobility notes?"},{id:"care",ask:"Any personal care done or needed?"},{id:"concerns",ask:"Anything worrying you?"},{id:"plan",ask:"What should the next shift know?"}]},{id:"general",label:"Care situation",match:/./,questions:[{id:"what",ask:"In one line, what happened?"},{id:"when",ask:"When was this?"},{id:"where",ask:"Where?"},{id:"response",ask:"What did you do?"},{id:"now",ask:"How is the person now?"},{id:"informed",ask:"Who knows / who still needs to know?"},{id:"next",ask:"What needs to happen next?"}]}],Li=/^(?:(?:hi|hii|hey|hello|yo|ok|okay|hiya|oi|excuse me)\s+)+(?:care\s*talk|caretalk|don|dawn|done|dom|dun|donn)\b[, ]*/i,Si=/^(?:care\s*talk|caretalk|don|dawn|done|dom|dun|donn)\b[, ]*/i;function lt(e){return String(e||"").toLowerCase().replace(/["""']/g,"").replace(/[^\w\s']/g," ").replace(/\bcare\s*talk\b/g,"caretalk").replace(/\b(dawn|done|dom|dun|donn|donnie|donald)\b/g,"don").replace(/\s+/g," ").trim()}function Be(e){const t=lt(e);return/^(?:(?:(?:hi|hii|hey|hello|yo|ok|okay|hiya|oi)\s+)?(?:caretalk|don)\s*)+$/.test(t)}function H(e){let t=String(e||"").trim();t=t.replace(Li,"").replace(Si,"").trim();const n=lt(t);return n.startsWith("caretalk ")&&(t=t.replace(/^(?:care\s*talk|caretalk)\s+/i,"").trim()),n.startsWith("don ")&&(t=t.replace(/^(?:don|dawn|done)\s+/i,"").trim()),t}function Ht(e){const t=String(e||"");if(/\bcare\s*talk\b/i.test(t)||/\bcaretalk\b/i.test(t)||/\bdon\b/i.test(t)||/\b(?:hi|hey|hello|yo|ok|okay|hiya|oi|excuse me)\s+(?:dawn|done|dom|dun|donn|donnie|donald|dan|donn?e)\b/i.test(t)||/^(?:dawn|done|dom|dun|donn|donald)\b/i.test(t.trim())||/,\s*(?:dawn|done|dom|dun|donn|donald)\b/i.test(t))return!0;const n=lt(t);return!!/^(?:(?:hi|hii|hey|hello|yo|ok|okay|hiya|oi)\s+)?(?:caretalk|don)(?:\s+(?:caretalk|don))*$/.test(n)}function Tt(e){const t=H(e).trim();return t?Ne(t).id!=="general"||/\b(help|need|advice|record|document|fell|fall|hurt|pain|chok|bleed|resident|patient|check|incident|report)\b/i.test(t)?!0:t.split(/\s+/).filter(Boolean).length>=4:!1}function dr(e){return!Ht(e)||Be(e)?!1:!Tt(e)}const Ti=new Set(["i","we","you","he","she","it","they","them","him","her","his","my","our","your","the","a","an","this","that","these","those","someone","somebody","anyone","anybody","everyone","everybody","resident","client","service","user","carer","nurse","staff","today","just","please","okay","ok","alright","don","caretalk","hey","hi","hello","yes","yeah","yep","yup","no","nope","nah","not","nothing","something","else","fall","distress","swallow","skin","mood","wellbeing","medication","meds","urgent","safe","unsafe","danger","right","got","still","here","there","when","where","what","why","how","who","which","because","about","with","for","from","after","before","during","maybe","kind","sort","really","actually","saying","said","tell","told","need","help","advice","report","record","document"].map(e=>e.toLowerCase()));function Fe(e){const t=String(e||"").trim();return!(!t||t.length<2||t.length>24||/\d/.test(t)||Ti.has(t.toLowerCase())||!/^[A-Za-z][A-Za-z'-]*$/.test(t))}function Ye(e,{carerName:t=""}={}){const n=H(e);if(!n)return"";function i(s){return!s||!Fe(s)||t&&st(s,t)?"":s}const r=[/(?:with|for|about|attending(?: to)?|resident|service user|client|called)\s+([A-Z][a-z]+(?:\s+[A-Z][a-z]+)?)/,/\b([A-Z][a-z]+)\s+(?:just |has |had |fell|was |is |seems |refused |won'?t )/];for(const s of r){const l=n.match(s);if(l){const d=i(l[1].split(/\s+/)[0]);if(d)return d}}const o=n.match(/\b([a-z]{2,})\s+(?:just |has |had |fell|seems|refused|won'?t)/i);if(o){const s=i(Fe(o[1])?o[1].charAt(0).toUpperCase()+o[1].slice(1).toLowerCase():"");if(s)return s}const a=n.match(/^([A-Za-z][A-Za-z'-]{1,23})(?:\s+(?:please|thanks))?[.!?]?$/);if(a){const s=i(a[1].charAt(0).toUpperCase()+a[1].slice(1).toLowerCase());if(s)return s}return""}function Ne(e){const t=H(e);for(const n of Ie)if(n.id!=="general"&&n.match.test(t))return n;return Ie.find(n=>n.id==="general")}function Ei(e,t){return t&&/^Where did it happen/i.test(e)?`Where was ${t}? Bedroom, bathroom, corridor…?`:e}function Ci({opening:e,carer:t,carerProfileName:n=""}){const i=e.trim(),r=Ne(i);let a=Ye(i,{carerName:n||t});const s=H(i)||i,l=ki(r.id,s),d=r.questions.map(u=>({...u,ask:Ei(u.ask,a)}));return{id:`sess_${Date.now()}`,opening:s,carer:t||"Staff",person:a,scenarioId:r.id,scenarioLabel:r.label,advice:l,questions:d,answers:{},voiceNotes:[{at:new Date().toISOString(),text:s}],step:0,phase:"advice",adviceAwaitingOk:!1,docTurn:"waiting_answer",pendingAnswer:"",pendingDocumented:"",correctionNote:"",recordedAt:new Date().toLocaleString("en-GB")}}function Ri(){const e=["I’m here. Do you need any help?","Hi — it’s careTalk. What do you need?","Listening. Are you okay — want help documenting something, or advice on what to do next?"];return e[Math.floor(Math.random()*e.length)]}function ct(e){return e.questions[e.step]||null}function Di(e,t,{person:n=""}={}){const i=String(t||"").trim().replace(/\s+/g," ");if(!i)return"—";const r=String((e==null?void 0:e.ask)||"Note").replace(/\?$/,"").trim();return`${n?`Service user ${n}: `:""}${r} — ${i}`}function cn(e){const t=String(e||"").trim().toLowerCase();return!t||/\b(no|nope|not right|wrong|incorrect|change)\b/.test(t)&&!/^yes\b/.test(t)?!1:/^(yes|yeah|yep|yup|correct|right|spot on|that'?s right|that is right|good|fine|ok|okay|absolutely|affirmative)\b/.test(t)}function dn(e){const t=String(e||"").trim().toLowerCase();return/^(no|nope|nah|not quite|wrong|incorrect)\b/.test(t)||/\b(not right|that'?s wrong|change that|needs changing)\b/.test(t)}function un(e){let t=String(e||"").trim();return t=t.replace(/^(no(,)?\s*)(actually|i mean|it'?s|it is)?\s*/i,"").trim(),t||String(e||"").trim()}function xi(e){return String(e||"").trim().length<2}function Pi(e,{raw:t,documented:n}){const i=ct(e);if(!i)return{session:e,done:!0};const r=String(n||t||"").trim();return e.answers[i.id]=r,e.voiceNotes||(e.voiceNotes=[]),e.voiceNotes.push({at:new Date().toISOString(),text:t?`${i.id} (voice): ${t}`:`${i.id}: ${r}`}),n&&t&&n!==t&&e.voiceNotes.push({at:new Date().toISOString(),text:`${i.id} (record): ${r}`}),e.step+=1,e.pendingAnswer="",e.pendingDocumented="",e.docTurn="waiting_answer",{session:e,done:e.step>=e.questions.length}}function Oi(e,t){if(!e)return;const n=String(t||"").trim();n&&(e.voiceNotes||(e.voiceNotes=[]),e.voiceNotes.push({at:new Date().toISOString(),text:n}))}function ur(e,t){const n=e.questions.map(r=>{const o=e.answers[r.id];return o?`<li><span class="muted-line">${t(r.ask)}</span><br /><strong>${t(o)}</strong></li>`:""}).filter(Boolean).join(""),i=e.correctionNote?`<li><span class="muted-line">Correction noted</span><br /><strong>${t(e.correctionNote)}</strong></li>`:"";return n||i?`<ul class="record-review">${n}${i}</ul>`:"<p>Nothing captured yet.</p>"}function Bi(e){return Ni(e)}function Ni(e){var r;const t=e.answers,n=e.person||"the resident",i=["SUPPORT WORKER REPORT — GENERATED BY careTalk","========================================",`Service user: ${e.person||"—"}`,`Support worker / carer: ${e.carer}`,`Incident / topic: ${e.scenarioLabel}`,`Date & time recorded: ${e.recordedAt}`,`Session id: ${e.id}`,"","1. OPENING STATEMENT (VOICE)",e.opening||"—","","2. WHAT HAPPENED (STRUCTURED)"];if(e.scenarioId==="fall")i.push(`${n} had a fall${t.when?` (${t.when})`:""}${t.where?` — location: ${t.where}`:""}.`,t.how?`Beforehand: ${t.how}.`:"",t.witnessed?`Witnessed / presence: ${t.witnessed}.`:"","","3. INJURY / PRESENTATION",t.injury||"—","","4. IMMEDIATE RESPONSE",t.response||"—","","5. CURRENT CONDITION",t.obs||"—","","6. NOTIFICATIONS",t.informed||"—","","7. SAFETY / FOLLOW-UP",t.prevent||"—");else for(const o of e.questions)i.push(`${o.ask}`,t[o.id]||"—","");return i.push("","8. VOICE NOTES (VERBATIM CAPTURE)",...(e.voiceNotes||[]).map((o,a)=>`${a+1}. [${new Date(o.at).toLocaleTimeString("en-GB")}] ${o.text}`),"","9. NARRATIVE SUMMARY FOR AGENCY"),e.scenarioId==="fall"?i.push([`${n} had a fall${t.when?` ${t.when}`:""}${t.where?` at ${t.where}`:""}.`,t.how?`Prior activity: ${t.how}.`:null,t.witnessed?`Presence: ${t.witnessed}.`:null,t.injury?`Injury/marks: ${t.injury}.`:null,t.response?`Actions: ${t.response}.`:null,t.obs?`Now: ${t.obs}.`:null,t.informed?`Informed: ${t.informed}.`:null,t.prevent?`Safety: ${t.prevent}.`:null].filter(Boolean).join(" ")):i.push(e.questions.map(o=>`${o.ask.replace(/\?$/,"")}: ${t[o.id]||"not stated"}`).join(". ")+"."),i.push("","10. SAFE PRACTICE REMINDERS APPLIED (careTalk)",`Do: ${(e.advice.do||[]).slice(0,4).join(" | ")}`,`Don’t: ${(e.advice.dont||[]).slice(0,4).join(" | ")}`),(r=e.advice.trainedText)!=null&&r.length&&i.push("","11. HOME-TRAINED KNOWLEDGE USED",...e.advice.trainedText),e.correctionNote&&i.push("","CORRECTION / AMENDMENT (VOICE)",e.correctionNote),i.push("",Ui),i.filter((o,a,s)=>!(o===""&&s[a-1]==="")).join(`
19
  `)}const Ui="Note: careTalk supports documentation and safe-practice reminders from adult care / support-worker training themes (including moving & assisting, dysphagia, ligature awareness, Oliver McGowan, PMVA/MAPA principles, HSWA). Follow local policy and clinical advice. This report is for the care agency / nurse in charge.",qt=[{id:"medication_refusal",label:"Medication refusal",match:/\b((refuse[ds]?|refusing|won'?t take|will not take|not taking|declined?|spit(?:ting)? out).{0,40}\b(medicine|medication|meds|tablet|tablets|pill|pills|dose|mar)\b|\b(medicine|medication|meds|tablet|tablets|pill|pills).{0,40}\b(refuse[ds]?|refusing|won'?t|will not|not taking|declined?)\b)/i,keywords:["medicine","medication","meds","refuse","refusal","refused","tablet","tablets","pill","mar"]}];function et(e){const t=String(e||"");for(const n of qt)if(n.match.test(t))return n;return null}function pr(e,t=""){if(!e)return[];`${t} ${e.label}`.toLowerCase();const n=ue(),i=[];for(const r of n){let o=0;const a=`${r.title} ${r.body} ${(r.keywords||[]).join(" ")} ${(r.doList||[]).join(" ")}`.toLowerCase();for(const s of e.keywords)a.includes(s)&&(o+=2),(r.keywords||[]).includes(s)&&(o+=2);/\b(refus|not taking|declin|won'?t take)\b/i.test(a)&&(o+=3),/\b(medicine|medication|meds|tablet|mar)\b/i.test(a)&&(o+=2),(r.doList||[]).length>=1&&(o+=2),r.body&&r.body.length>60&&(o+=1),o>=5&&i.push({entry:r,score:o})}return i.sort((r,o)=>o.score-r.score).map(r=>r.entry)}function Et(e,t=""){return pr(e,t).some(i=>(i.doList||[]).length>=1||(i.body||"").length>=80)}function fr(e,t=""){const i=String(e||t||"this subject").trim().replace(/\s+/g," ").slice(0,80)||"this subject";return{id:`unsure_${i.toLowerCase().replace(/[^a-z0-9]+/g,"_").replace(/^_|_$/g,"").slice(0,40)||"subject"}`,label:i,keywords:i.toLowerCase().split(/\W+/).filter(o=>o.length>3).slice(0,8),question:`careTalk was not sure about this subject: ${i}. What should carers do?`}}function _i(e=""){const t=String(e||"").toLowerCase();if(!t||t.split(/\s+/).length<3)return!1;const n=t.split(/\W+/).filter(i=>i.length>3);return n.length?ue().some(i=>{const r=`${i.title} ${i.body} ${(i.keywords||[]).join(" ")}`.toLowerCase();return n.filter(a=>r.includes(a)).length>=2&&((i.doList||[]).length>=1||(i.body||"").length>=60)}):!1}function dt(){return sr()}function Wt(e){gi(e)}function gr(){return dt().filter(e=>e.status==="unresolved")}function mr({topic:e,utterance:t,person:n="",carer:i=""}){const r=dt(),o=Date.now()-1440*60*1e3,a=r.find(l=>l.status==="unresolved"&&l.topicId===e.id&&(l.person||"").toLowerCase()===(n||"").toLowerCase()&&new Date(l.createdAt).getTime()>o);if(a)return{incident:a,created:!1};const s={id:`inc_${Date.now()}`,status:"unresolved",topicId:e.id,topicLabel:e.label,question:e.question||(e.id==="medication_refusal"?`What should carers do when ${n||"a client"} refuses / does not take their medicine?`:`careTalk was unsure about: ${e.label}. What should carers do?`),person:n||"",carer:i||"",utterance:String(t||"").trim(),createdAt:new Date().toISOString(),resolvedAt:null,resolvedBy:null,knowledgeId:null,agencyNotified:!1};return r.unshift(s),Wt(r),{incident:s,created:!0}}function Mi(e,{knowledgeId:t=null,note:n=""}={}){const i=dt(),r=i.findIndex(o=>o.id===e);if(r<0)throw new Error("Incident not found");return i[r]={...i[r],status:"resolved",resolvedAt:new Date().toISOString(),resolvedBy:"Head nurse",knowledgeId:t,resolveNote:n},Wt(i),i[r]}async function hr(e){const t=ot(),n=["careTalk — TRAINING REQUEST (UNRESOLVED)","===================================",`Incident id: ${e.id}`,`Topic: ${e.topicLabel}`,"Question careTalk could not answer from training:",e.question,"",`Person / client: ${e.person||"—"}`,`Reported by carer: ${e.carer||"—"}`,`Carer said: ${e.utterance||"—"}`,`Logged: ${new Date(e.createdAt).toLocaleString("en-GB")}`,"","careTalk told the carer he will ask for training on this.","Please open Give careTalk more knowledge in careTalk, resolve this incident, and add clear do/don’t guidance.","",`Agency: ${t.name}`].join(`
20
  `),i={id:`gap_${Date.now()}`,type:"don.training_gap",at:new Date().toISOString(),incidentId:e.id,agencyName:t.name,agencyEmail:t.email,report:n,channels:["outbox"]};if(t.webhookUrl)try{(await fetch(t.webhookUrl,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(i)})).ok&&i.channels.push("webhook")}catch(a){i.webhookError=(a==null?void 0:a.message)||"webhook failed"}if(t.email){const a=encodeURIComponent(`careTalk needs training — ${e.topicLabel}${e.person?` — ${e.person}`:""}`),s=encodeURIComponent(n.slice(0,1800)),l=`mailto:${encodeURIComponent(t.email)}?subject=${a}&body=${s}`;i.mailto=l,i.channels.push("email");try{const d=document.createElement("a");d.href=l,d.rel="noopener",document.body.appendChild(d),d.click(),d.remove()}catch{}}ar(i);const r=dt(),o=r.findIndex(a=>a.id===e.id);return o>=0&&(r[o].agencyNotified=!0,Wt(r)),{packet:i,agency:t,report:n}}const ji=[{id:"mood",label:"Mood & engagement",voice:["mood","engagement","wellbeing"],prompt:"How is their mood and engagement right now?"},{id:"mobility",label:"Mobilisation",voice:["mobility","mobilisation","transfer","zimmer","hoist"],prompt:"How did they mobilise / transfer?"},{id:"nutrition",label:"Nutrition & fluids",voice:["nutrition","hydration","ate","drank","meal"],prompt:"What did they eat and drink?"},{id:"personal",label:"Personal care",voice:["personal care","washed","dressed","continence","pad"],prompt:"What personal care was completed?"},{id:"skin",label:"Skin integrity",voice:["skin","pressure","sore","redness"],prompt:"Any skin changes or pressure areas?"},{id:"clinical",label:"Clinical / PRN",voice:["medication","prn","obs","pain","gp"],prompt:"Any medication, pain, or clinical observations?"},{id:"risk",label:"Risks & safety",voice:["risk","fall","wander","safeguarding","incident"],prompt:"Any safety or safeguarding concerns?"},{id:"plan",label:"Plan / escalate",voice:["plan","action","escalate","handover"],prompt:"What should happen next?"}],Fi=[{key:"resident",re:/(?:resident|service user|client|with)\s+([A-Z][a-z]+(?:\s+[A-Z][a-z]+)?)/i},{key:"when",re:/(?:at|around|about)\s+(\d{1,2}(?::\d{2})?\s*(?:am|pm)?|\d{1,2}\s*(?:am|pm)|this morning|this afternoon|this evening|overnight|during night shift)/i}],Hi=[["fall","Falls risk"],["slipped","Falls risk"],["wander","Exit-seeking / wandering"],["exit-seeking","Exit-seeking / wandering"],["exit seeking","Exit-seeking / wandering"],["distress","Emotional distress"],["agitated","Emotional distress"],["aggressive","Behavioural escalation"],["chok","Choking / swallow risk"],["pressure","Skin integrity watch"],["sore","Skin integrity watch"],["refus","Care preference / declined support"],["declined","Care preference / declined support"],["low mood","Mood concern"],["confused","Cognitive change"],["delirium","Cognitive change"],["safeguard","Safeguarding pathway"],["bruise","Injury / mark observed"],["unwitnessed","Unwitnessed event — verify"]],qi=[[/refused care/gi,"declined care; support and choices were offered"],[/refused/gi,"declined"],[/non[- ]compliant/gi,"needed extra encouragement and adapted support"],[/aggressive resident/gi,"showed distressed behaviour"],[/wandering/gi,"walking with purpose / exit-seeking"],[/fed/gi,"supported with meals"],[/toileted/gi,"supported with continence care"],[/put to bed/gi,"supported to settle for bed"],[/challenging behaviour/gi,"distressed behaviour"]];function Ct(e){const t=e.trim().replace(/\s+/g," ");return t?t.charAt(0).toUpperCase()+t.slice(1):""}function ve(e,t,n=[]){const i=e.toLowerCase();for(const r of t){const o=i.indexOf(r);if(o===-1)continue;let a=e.slice(o+r.length).replace(/^[\s:,-]+/,""),s=a.length;for(const d of n){const u=a.toLowerCase().indexOf(d);u!==-1&&(s=Math.min(s,u))}const l=a.slice(0,s).trim().replace(/[.;]+$/,"");if(l)return Ct(l)}return""}function Wi(e){let t=e||"";for(const[n,i]of qi)t=t.replace(n,i);return t}function pn(e){const t=(e||"").toLowerCase();return ji.map(n=>({...n,covered:n.voice.some(i=>t.includes(i))}))}function Gi(e,t){const n=t.filter(o=>!o.covered).map(o=>o.label),i=e.flags.filter(o=>!/No acute/i.test(o)),r=[];return e.resident?r.push(`${e.resident}: ${e.mood||e.narrative.slice(0,90)||"see full note"}`):e.narrative&&r.push(e.narrative.slice(0,110)),i.length&&r.push(`Watch: ${i.slice(0,3).join("; ")}`),e.actions?r.push(`Next: ${e.actions}`):n.length&&r.push(`Still to capture: ${n.slice(0,3).join(", ")}`),e.clinical&&r.push(`Clinical: ${e.clinical}`),r.slice(0,4)}function Vi(e){const t=e.flags.filter(n=>/safeguard|fall|chok|injury|behavioural|skin integrity|cognitive/i.test(n));return t.length?{title:"Nurse-in-charge brief",lines:[`Person: ${e.resident||"Resident (name not yet captured)"}`,`Flags: ${t.join("; ")}`,`Facts noted: ${e.risks||e.narrative||"See body of note"}`,`Already done: ${e.actions||"Document response and who was informed"}`,"Ask: Do we need GP / 111 / safeguarding referral / family call now?"]}:null}function ut(e,t="wellbeing"){const n=Wi(e||""),i=n.replace(/\s+/g," ").trim(),r={resident:"",when:"",mood:"",mobility:"",nutrition:"",care:"",clinical:"",risks:"",actions:"",flags:[],narrative:"",confidence:0,coverage:pn(""),handover:[],escalation:null,dignityApplied:n!==(e||""),noteType:t};if(!i)return r;let o="",a="";for(const{key:x,re:z}of Fi){const R=i.match(z);R&&(x==="resident"&&(o=R[1]),x==="when"&&(a=Ct(R[1])))}if(!o){const x=i.match(/\b([A-Z][a-z]+)\s+(?:was|is|appeared|seemed|had|ate|declined|refused)\b/);x&&(o=x[1])}const s=ve(i,["mood","appeared","seemed","engagement","engaged","wellbeing"],["mobility","transfer","ate","drink","medication","action","plan","risk"]),l=ve(i,["mobility","mobilis","transfer","zimmer","frame","hoist","walked"],["ate","drink","nutrition","hydration","personal care","medication","action"]),d=ve(i,["nutrition","hydration","ate","eaten","drank","fluid","meal","lunch","breakfast","dinner","supper"],["personal care","washed","continence","medication","action","plan"]),u=ve(i,["personal care","washed","shower","continence","pad","skin","dressed"],["medication","clinical","obs","action","plan","risk"]),f=ve(i,["medication","prn","clinical","obs","blood pressure","temperature","gp","nurse","pain"],["action","plan","next","risk","incident"]),g=ve(i,["risk","incident","concern","safeguarding","near miss"],["action","plan","we ","staff "]),w=ve(i,["action","plan","we ","staff ","escalated","informed","documented","handover"],[]),y=[],k=i.toLowerCase();for(const[x,z]of Hi)k.includes(x)&&!y.includes(z)&&y.push(z);!y.length&&/settled|comfortable|no concerns|stable/i.test(i)&&y.push("No acute escalation flagged");const v=a||"this shift",$=[];t==="family"?$.push(o?`${o} has been supported ${v}.`:`Your relative has been supported ${v}.`):t==="handover"?$.push(o?`Handover — ${o} (${v}).`:`Handover note (${v}).`):$.push(o?`${o} was reviewed ${v}.`:`Resident reviewed ${v}.`);const E=[s,l,d,u,f].filter(Boolean).map(x=>x.endsWith(".")?x:`${x}.`);$.push(...E),g&&$.push(`Risks/incidents: ${g}${g.endsWith(".")?"":"."}`),w&&$.push(`Actions/plan: ${w}${w.endsWith(".")?"":"."}`),!E.length&&!g&&!w&&$.push(Ct(i)+(i.endsWith(".")?"":"."));const D=[o,a,s,l,d,u,f,g,w].filter(Boolean).length,ie=Math.min(98,35+D*8+Math.min(20,Math.floor(i.length/40))),U={resident:o,when:a,mood:s,mobility:l,nutrition:d,care:u,clinical:f,risks:g,actions:w,flags:y,narrative:$.join(" ").replace(/\s+/g," ").trim(),confidence:ie,noteType:t,dignityApplied:n!==(e||"").replace(/\s+/g," ").trim()};return U.coverage=pn(i),U.handover=Gi(U,U.coverage),U.escalation=Vi(U),U}const He={users:"don.users",sessionUser:"don.session.userId"},zi=1800*1e3;function ye(e){const t=`don.user|${String(e||"").trim()}`;let n=2166136261;for(let i=0;i<t.length;i+=1)n^=t.charCodeAt(i),n=Math.imul(n,16777619);return(n>>>0).toString(16)}function Ki(e,t){try{const n=localStorage.getItem(e);return n?JSON.parse(n):t}catch{return t}}function Yi(e,t){localStorage.setItem(e,JSON.stringify(t))}function Ji(e){const t={...e};return t.emailVerified===void 0&&(t.emailVerified=t.status==="approved"),t.requestedRole||(t.requestedRole=t.role==="admin"?"admin":"carer"),t}function P(){return Ki(He.users,[]).map(Ji)}function ae(e){Yi(He.users,Array.isArray(e)?e:[])}function B(e){if(!e)return null;const{passwordHash:t,verificationCodeHash:n,verificationExpiresAt:i,...r}=e;return r}function Gt(){return sessionStorage.getItem(He.sessionUser)||""}function S(){const e=Gt();if(!e)return null;const t=B(P().find(n=>n.id===e)||null);return t&&t.status!=="approved"?(re(""),null):t}function re(e){e?sessionStorage.setItem(He.sessionUser,e):sessionStorage.removeItem(He.sessionUser)}function yr(){re("")}function pt(e=S()){return!!(e&&e.status==="approved")}function Te(e=S()){return pt(e)&&e.role==="admin"}function wr(e=S()){return pt(e)}function qe(e,t=S()){return pt(t)?e==="learn"?!0:e==="train"||e==="reports"?Te(t):!1:!1}function Zi(){return String(Math.floor(1e5+Math.random()*9e5))}function Qi(e,t){const n=e[t];n.requestedRole!=="admin"&&n.role!=="admin"?e[t]={...n,status:"approved",role:"carer",emailVerified:!0,approvedAt:new Date().toISOString(),approvedBy:"email_verified",verificationCodeHash:null,verificationExpiresAt:null}:e[t]={...n,emailVerified:!0,verificationCodeHash:null,verificationExpiresAt:null}}function br(e){const t=String(e||"").trim().toLowerCase(),n=P(),i=n.findIndex(l=>l.email===t);if(i<0)throw new Error("No registration found for that email");const r=Zi();n[i].verificationCodeHash=ye(r),n[i].verificationExpiresAt=new Date(Date.now()+zi).toISOString(),ae(n);const o=encodeURIComponent("careTalk — verify your email"),a=encodeURIComponent(`Your careTalk verification code is: ${r}
21
 
assets/{main-Dsvc5F92.js → main-fYjBO_9U.js} RENAMED
@@ -1,4 +1,4 @@
1
- import{i as E}from"./theme-CuaEyjDL.js";import{e as $,A as y}from"./subscribers-DkYmS9Go.js";const M="pd3rvr@icloud.com",j=`https://formsubmit.co/ajax/${encodeURIComponent(M)}`;async function L({subject:e,fields:t}){const r={...t,_subject:e,_template:"table",_captcha:"false",_honey:""};try{const n=await fetch(j,{method:"POST",headers:{"Content-Type":"application/json",Accept:"application/json"},body:JSON.stringify(r)});let a=null;try{a=await n.json()}catch{a=null}if(!n.ok){const o=a&&(a.message||a.error)||`Mail forward failed (${n.status})`;return{ok:!1,error:String(o)}}return a&&a.error?{ok:!1,error:String(a.error)}:{ok:!0}}catch(n){return{ok:!1,error:n&&n.message||"Network error while sending feedback"}}}const S="https://jsonblob.com/api/jsonBlob/019fbe73-98af-789a-9ebc-7b6a719c712e";function w(e){return Array.isArray(e)?e:e&&Array.isArray(e.entries)?e.entries:[]}function m(e){if(!e||typeof e!="object")return null;const t=String(e.message||"").trim();return t?{id:String(e.id||`fb_${Date.now()}`),at:e.at||new Date().toISOString(),role:e.role==="supervisor"||e.role==="assistant"||e.role==="other"?e.role:"other",name:String(e.name||"").trim(),org:String(e.org||"").trim(),message:t.slice(0,2e3)}:null}async function T(){try{const e=await fetch("./feedback-feed.json",{headers:{Accept:"application/json"},cache:"no-store"});return e.ok?w(await e.json()).map(m).filter(Boolean):[]}catch{return[]}}async function F(){try{const e=await fetch(S,{headers:{Accept:"application/json"},cache:"no-store"});return e.ok?w(await e.json()).map(m).filter(Boolean):[]}catch{return[]}}function I(...e){const t=[],r=new Set;for(const n of e)for(const a of n||[]){const o=m(a);if(!o)continue;const s=o.id||`${o.message}|${o.org}|${o.name}`;r.has(s)||(r.add(s),t.push(o))}return t.sort((n,a)=>String(a.at||"").localeCompare(String(n.at||""))),t.slice(0,60)}async function B(e){const t=m(e);if(!t)return{ok:!1,error:"empty feedback"};for(let r=0;r<3;r+=1)try{const n=await F();if(n.some(s=>s.id===t.id))return{ok:!0,already:!0};if(n.some(s=>s.message===t.message&&s.name===t.name&&s.org===t.org))return{ok:!0,already:!0};const a=[t,...n].slice(0,60);if((await fetch(S,{method:"PUT",headers:{"Content-Type":"application/json",Accept:"application/json"},body:JSON.stringify(a)})).ok)return{ok:!0}}catch(n){if(r===2)return{ok:!1,error:(n==null?void 0:n.message)||"publish failed"}}return{ok:!1,error:"publish failed"}}const A="caretalk.landing.feedback";function v(){try{const e=localStorage.getItem(A),t=e?JSON.parse(e):[];return Array.isArray(t)?t:[]}catch{return[]}}function D(e){localStorage.setItem(A,JSON.stringify(e.slice(0,40)))}function g(e){return e==="assistant"?"Care assistant / support worker":e==="supervisor"?"Supervisor / manager / nurse":"Other / interested visitor"}function c(e){return String(e||"").replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;")}function _(e,t){const r=String(e||"").trim().split(/\s+/).filter(Boolean);return r.length>=2?`${r[0][0]||""}${r[r.length-1][0]||""}`.toUpperCase():r.length===1&&r[0].length>=2?r[0].slice(0,2).toUpperCase():r.length===1?r[0].slice(0,1).toUpperCase()||"?":t==="assistant"?"CA":t==="supervisor"?"SM":"CT"}function x(e){return String(e||"").trim()||"Workplace not shared"}function O(e,t=140){const r=String(e||"").replace(/\s+/g," ").trim();return r.length<=t?r:`${r.slice(0,t-1).trimEnd()}…`}async function N(){const[e,t]=await Promise.all([F(),T()]);return I(e,t,v()).slice(0,24)}function P(e){const t=_(e.name,e.role),r=x(e.org),n=g(e.role),a=O(e.message);return`<article class="feedback-card" aria-label="Feedback from ${c(t)} at ${c(r)}">
2
  <div class="feedback-card-initials" aria-hidden="true">${c(t)}</div>
3
  <div class="feedback-card-meta">
4
  <p class="feedback-card-workplace">${c(r)}</p>
 
1
+ import{i as E}from"./theme-CuaEyjDL.js";import{e as $,A as y}from"./subscribers-CLCOf4GQ.js";const M="pd3rvr@icloud.com",j=`https://formsubmit.co/ajax/${encodeURIComponent(M)}`;async function L({subject:e,fields:t}){const r={...t,_subject:e,_template:"table",_captcha:"false",_honey:""};try{const n=await fetch(j,{method:"POST",headers:{"Content-Type":"application/json",Accept:"application/json"},body:JSON.stringify(r)});let a=null;try{a=await n.json()}catch{a=null}if(!n.ok){const o=a&&(a.message||a.error)||`Mail forward failed (${n.status})`;return{ok:!1,error:String(o)}}return a&&a.error?{ok:!1,error:String(a.error)}:{ok:!0}}catch(n){return{ok:!1,error:n&&n.message||"Network error while sending feedback"}}}const S="https://jsonblob.com/api/jsonBlob/019fbe73-98af-789a-9ebc-7b6a719c712e";function w(e){return Array.isArray(e)?e:e&&Array.isArray(e.entries)?e.entries:[]}function m(e){if(!e||typeof e!="object")return null;const t=String(e.message||"").trim();return t?{id:String(e.id||`fb_${Date.now()}`),at:e.at||new Date().toISOString(),role:e.role==="supervisor"||e.role==="assistant"||e.role==="other"?e.role:"other",name:String(e.name||"").trim(),org:String(e.org||"").trim(),message:t.slice(0,2e3)}:null}async function T(){try{const e=await fetch("./feedback-feed.json",{headers:{Accept:"application/json"},cache:"no-store"});return e.ok?w(await e.json()).map(m).filter(Boolean):[]}catch{return[]}}async function F(){try{const e=await fetch(S,{headers:{Accept:"application/json"},cache:"no-store"});return e.ok?w(await e.json()).map(m).filter(Boolean):[]}catch{return[]}}function I(...e){const t=[],r=new Set;for(const n of e)for(const a of n||[]){const o=m(a);if(!o)continue;const s=o.id||`${o.message}|${o.org}|${o.name}`;r.has(s)||(r.add(s),t.push(o))}return t.sort((n,a)=>String(a.at||"").localeCompare(String(n.at||""))),t.slice(0,60)}async function B(e){const t=m(e);if(!t)return{ok:!1,error:"empty feedback"};for(let r=0;r<3;r+=1)try{const n=await F();if(n.some(s=>s.id===t.id))return{ok:!0,already:!0};if(n.some(s=>s.message===t.message&&s.name===t.name&&s.org===t.org))return{ok:!0,already:!0};const a=[t,...n].slice(0,60);if((await fetch(S,{method:"PUT",headers:{"Content-Type":"application/json",Accept:"application/json"},body:JSON.stringify(a)})).ok)return{ok:!0}}catch(n){if(r===2)return{ok:!1,error:(n==null?void 0:n.message)||"publish failed"}}return{ok:!1,error:"publish failed"}}const A="caretalk.landing.feedback";function v(){try{const e=localStorage.getItem(A),t=e?JSON.parse(e):[];return Array.isArray(t)?t:[]}catch{return[]}}function D(e){localStorage.setItem(A,JSON.stringify(e.slice(0,40)))}function g(e){return e==="assistant"?"Care assistant / support worker":e==="supervisor"?"Supervisor / manager / nurse":"Other / interested visitor"}function c(e){return String(e||"").replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;")}function _(e,t){const r=String(e||"").trim().split(/\s+/).filter(Boolean);return r.length>=2?`${r[0][0]||""}${r[r.length-1][0]||""}`.toUpperCase():r.length===1&&r[0].length>=2?r[0].slice(0,2).toUpperCase():r.length===1?r[0].slice(0,1).toUpperCase()||"?":t==="assistant"?"CA":t==="supervisor"?"SM":"CT"}function x(e){return String(e||"").trim()||"Workplace not shared"}function O(e,t=140){const r=String(e||"").replace(/\s+/g," ").trim();return r.length<=t?r:`${r.slice(0,t-1).trimEnd()}…`}async function N(){const[e,t]=await Promise.all([F(),T()]);return I(e,t,v()).slice(0,24)}function P(e){const t=_(e.name,e.role),r=x(e.org),n=g(e.role),a=O(e.message);return`<article class="feedback-card" aria-label="Feedback from ${c(t)} at ${c(r)}">
2
  <div class="feedback-card-initials" aria-hidden="true">${c(t)}</div>
3
  <div class="feedback-card-meta">
4
  <p class="feedback-card-workplace">${c(r)}</p>
assets/{subscribers-DkYmS9Go.js → subscribers-CLCOf4GQ.js} RENAMED
@@ -1,2 +1,2 @@
1
- const m="1.1.30",l="caretalk.landing.subscribers",a="caretalk.updates.authed",g="caretalk.ops",f="b5879926";function b(e){const t=`caretalk.updates|${String(e||"").trim()}`;let s=2166136261;for(let r=0;r<t.length;r+=1)s^=t.charCodeAt(r),s=Math.imul(s,16777619);return(s>>>0).toString(16)}function i(){try{const e=localStorage.getItem(l),t=e?JSON.parse(e):[];return Array.isArray(t)?t:[]}catch{return[]}}function o(e){localStorage.setItem(l,JSON.stringify(e.slice(0,500)))}function S(e){return String(e||"").trim().toLowerCase()}function A(e){const t=S(e);return/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(t)&&t.length<=160}function I({email:e,name:t="",source:s="landing"}={}){const r=S(e);if(!A(r))return{ok:!1,error:"Please enter a valid email address."};const n=i(),c=n.find(d=>d.email===r);if(c)return{ok:!0,entry:c,created:!1};const u={id:`sub_${Date.now()}_${Math.random().toString(36).slice(2,8)}`,email:r,name:String(t||"").trim().slice(0,80),at:new Date().toISOString(),version:m,source:s};return o([u,...n]),{ok:!0,entry:u,created:!0}}function p(e){const t=i().filter(s=>s.id!==e);return o(t),t}function h(){o([])}function _(){return sessionStorage.getItem(a)==="1"}function k(e,t){const s=String(e||"").trim().toLowerCase(),r=String(t||"");return s!==g.toLowerCase()?{ok:!1,error:"Incorrect username or password."}:b(r)!==f?{ok:!1,error:"Incorrect username or password."}:(sessionStorage.setItem(a,"1"),{ok:!0})}function E(){sessionStorage.removeItem(a)}function v(e=i()){const t="email,name,subscribed_at,version,source",s=e.map(r=>[r.email,r.name||"",r.at||"",r.version||"",r.source||""].map(n=>`"${String(n).replace(/"/g,'""')}"`).join(","));return[t,...s].join(`
2
  `)}export{m as A,E as a,i as b,h as c,v as d,I as e,_ as i,p as r,k as s};
 
1
+ const m="1.1.31",l="caretalk.landing.subscribers",a="caretalk.updates.authed",g="caretalk.ops",f="b5879926";function b(e){const t=`caretalk.updates|${String(e||"").trim()}`;let s=2166136261;for(let r=0;r<t.length;r+=1)s^=t.charCodeAt(r),s=Math.imul(s,16777619);return(s>>>0).toString(16)}function i(){try{const e=localStorage.getItem(l),t=e?JSON.parse(e):[];return Array.isArray(t)?t:[]}catch{return[]}}function o(e){localStorage.setItem(l,JSON.stringify(e.slice(0,500)))}function S(e){return String(e||"").trim().toLowerCase()}function A(e){const t=S(e);return/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(t)&&t.length<=160}function I({email:e,name:t="",source:s="landing"}={}){const r=S(e);if(!A(r))return{ok:!1,error:"Please enter a valid email address."};const n=i(),c=n.find(d=>d.email===r);if(c)return{ok:!0,entry:c,created:!1};const u={id:`sub_${Date.now()}_${Math.random().toString(36).slice(2,8)}`,email:r,name:String(t||"").trim().slice(0,80),at:new Date().toISOString(),version:m,source:s};return o([u,...n]),{ok:!0,entry:u,created:!0}}function p(e){const t=i().filter(s=>s.id!==e);return o(t),t}function h(){o([])}function _(){return sessionStorage.getItem(a)==="1"}function k(e,t){const s=String(e||"").trim().toLowerCase(),r=String(t||"");return s!==g.toLowerCase()?{ok:!1,error:"Incorrect username or password."}:b(r)!==f?{ok:!1,error:"Incorrect username or password."}:(sessionStorage.setItem(a,"1"),{ok:!0})}function E(){sessionStorage.removeItem(a)}function v(e=i()){const t="email,name,subscribed_at,version,source",s=e.map(r=>[r.email,r.name||"",r.at||"",r.version||"",r.source||""].map(n=>`"${String(n).replace(/"/g,'""')}"`).join(","));return[t,...s].join(`
2
  `)}export{m as A,E as a,i as b,h as c,v as d,I as e,_ as i,p as r,k as s};
assets/{web-o2G7w9Em.js → web-BoLQRCPk.js} RENAMED
@@ -1 +1 @@
1
- import{W as n}from"./app-ipj-_NCA.js";import"./theme-CuaEyjDL.js";class i extends n{async show(e){}async hide(e){}}export{i as SplashScreenWeb};
 
1
+ import{W as n}from"./app-Cr21RCtM.js";import"./theme-CuaEyjDL.js";class i extends n{async show(e){}async hide(e){}}export{i as SplashScreenWeb};
assets/{web-BhapuqNa.js → web-CbBz5VEx.js} RENAMED
@@ -1 +1 @@
1
- import{W as t}from"./app-ipj-_NCA.js";import"./theme-CuaEyjDL.js";class o extends t{constructor(){super(),this.handleVisibilityChange=()=>{const e={isActive:document.hidden!==!0};this.notifyListeners("appStateChange",e),document.hidden?this.notifyListeners("pause",null):this.notifyListeners("resume",null)},document.addEventListener("visibilitychange",this.handleVisibilityChange,!1)}exitApp(){throw this.unimplemented("Not implemented on web.")}async getInfo(){throw this.unimplemented("Not implemented on web.")}async getLaunchUrl(){return{url:""}}async getState(){return{isActive:document.hidden!==!0}}async minimizeApp(){throw this.unimplemented("Not implemented on web.")}async toggleBackButtonHandler(){throw this.unimplemented("Not implemented on web.")}}export{o as AppWeb};
 
1
+ import{W as t}from"./app-Cr21RCtM.js";import"./theme-CuaEyjDL.js";class o extends t{constructor(){super(),this.handleVisibilityChange=()=>{const e={isActive:document.hidden!==!0};this.notifyListeners("appStateChange",e),document.hidden?this.notifyListeners("pause",null):this.notifyListeners("resume",null)},document.addEventListener("visibilitychange",this.handleVisibilityChange,!1)}exitApp(){throw this.unimplemented("Not implemented on web.")}async getInfo(){throw this.unimplemented("Not implemented on web.")}async getLaunchUrl(){return{url:""}}async getState(){return{isActive:document.hidden!==!0}}async minimizeApp(){throw this.unimplemented("Not implemented on web.")}async toggleBackButtonHandler(){throw this.unimplemented("Not implemented on web.")}}export{o as AppWeb};
assets/{web-BVF1lTpL.js → web-DrRVGgij.js} RENAMED
@@ -1 +1 @@
1
- import{W as e}from"./app-ipj-_NCA.js";import"./theme-CuaEyjDL.js";class t extends e{available(){throw this.unimplemented("Method not implemented on web.")}start(o){throw this.unimplemented("Method not implemented on web.")}stop(){throw this.unimplemented("Method not implemented on web.")}getSupportedLanguages(){throw this.unimplemented("Method not implemented on web.")}hasPermission(){throw this.unimplemented("Method not implemented on web.")}isListening(){throw this.unimplemented("Method not implemented on web.")}requestPermission(){throw this.unimplemented("Method not implemented on web.")}checkPermissions(){throw this.unimplemented("Method not implemented on web.")}requestPermissions(){throw this.unimplemented("Method not implemented on web.")}}const s=new t;export{s as SpeechRecognition,t as SpeechRecognitionWeb};
 
1
+ import{W as e}from"./app-Cr21RCtM.js";import"./theme-CuaEyjDL.js";class t extends e{available(){throw this.unimplemented("Method not implemented on web.")}start(o){throw this.unimplemented("Method not implemented on web.")}stop(){throw this.unimplemented("Method not implemented on web.")}getSupportedLanguages(){throw this.unimplemented("Method not implemented on web.")}hasPermission(){throw this.unimplemented("Method not implemented on web.")}isListening(){throw this.unimplemented("Method not implemented on web.")}requestPermission(){throw this.unimplemented("Method not implemented on web.")}checkPermissions(){throw this.unimplemented("Method not implemented on web.")}requestPermissions(){throw this.unimplemented("Method not implemented on web.")}}const s=new t;export{s as SpeechRecognition,t as SpeechRecognitionWeb};
feedback-feed.json CHANGED
@@ -70,5 +70,13 @@
70
  "name": "Tobi",
71
  "org": "NHS",
72
  "message": "CareTalk has helped me stay calm and confident in a situations like a patient having a fall or a change in patients condition, or when i am unsure what to do next. \n\nIt helps me record what happened, prepare clear handover notes for the next shift, remind me of important care procedures, and reduce paperwork giving me more time to focus on providing safe, compassionate care to the people we support."
 
 
 
 
 
 
 
 
73
  }
74
  ]
 
70
  "name": "Tobi",
71
  "org": "NHS",
72
  "message": "CareTalk has helped me stay calm and confident in a situations like a patient having a fall or a change in patients condition, or when i am unsure what to do next. \n\nIt helps me record what happened, prepare clear handover notes for the next shift, remind me of important care procedures, and reduce paperwork giving me more time to focus on providing safe, compassionate care to the people we support."
73
+ },
74
+ {
75
+ "id": "fb_formsubmit_2026-07-23_anon_nhs",
76
+ "at": "2026-07-23T00:14:52.934Z",
77
+ "role": "assistant",
78
+ "name": "",
79
+ "org": "NHS",
80
+ "message": "CareTalk gives carers calm, practical support exactly when they need it most. Whether responding to a fall, handling an unexpected situation, or supporting a difficult conversation, it provides clear guidance, quick answers to care questions, and prompts that help carers make confident, consistent decisions. It also reinforces training for new staff, supports lone workers, and helps ensure best practice is followed across every shift.\nBy reducing paperwork and simplifying documentation, careTalk automatically creates clear handover notes, drafts care records and incident reports, and reminds carers about important routines and observations. This saves valuable time, improves communication between teams, and allows carers to focus less on administration and more on delivering safe, compassionate, person-cepintred care."
81
  }
82
  ]
index.html CHANGED
@@ -33,9 +33,9 @@
33
  href="https://fonts.googleapis.com/css2?family=Fraunces:opsz,wght@9..144,550;9..144,700&family=Source+Sans+3:wght@400;600;700&display=swap"
34
  rel="stylesheet"
35
  />
36
- <script type="module" crossorigin src="./assets/main-Dsvc5F92.js"></script>
37
  <link rel="modulepreload" crossorigin href="./assets/theme-CuaEyjDL.js">
38
- <link rel="modulepreload" crossorigin href="./assets/subscribers-DkYmS9Go.js">
39
  <link rel="stylesheet" crossorigin href="./assets/subscribers-BHyrZ7wW.css">
40
  <link rel="manifest" href="./manifest.webmanifest"><script id="vite-plugin-pwa:register-sw" src="./registerSW.js"></script></head>
41
  <body>
@@ -114,7 +114,7 @@
114
  <a class="btn btn-primary" href="./app.html">Try the live demo</a>
115
  <a class="btn btn-ghost" href="./app.html#demo">One-tap demo roles</a>
116
  </div>
117
- <p class="version-pill">Version 1.1.30</p>
118
  </div>
119
  </section>
120
 
@@ -385,7 +385,7 @@
385
  <footer class="site-footer">
386
  <div class="section-inner footer-row">
387
  <div>
388
- <p>careTalk v1.1.30 · MIT</p>
389
  <p>
390
  <a href="./app.html">App</a>
391
  ·
 
33
  href="https://fonts.googleapis.com/css2?family=Fraunces:opsz,wght@9..144,550;9..144,700&family=Source+Sans+3:wght@400;600;700&display=swap"
34
  rel="stylesheet"
35
  />
36
+ <script type="module" crossorigin src="./assets/main-fYjBO_9U.js"></script>
37
  <link rel="modulepreload" crossorigin href="./assets/theme-CuaEyjDL.js">
38
+ <link rel="modulepreload" crossorigin href="./assets/subscribers-CLCOf4GQ.js">
39
  <link rel="stylesheet" crossorigin href="./assets/subscribers-BHyrZ7wW.css">
40
  <link rel="manifest" href="./manifest.webmanifest"><script id="vite-plugin-pwa:register-sw" src="./registerSW.js"></script></head>
41
  <body>
 
114
  <a class="btn btn-primary" href="./app.html">Try the live demo</a>
115
  <a class="btn btn-ghost" href="./app.html#demo">One-tap demo roles</a>
116
  </div>
117
+ <p class="version-pill">Version 1.1.31</p>
118
  </div>
119
  </section>
120
 
 
385
  <footer class="site-footer">
386
  <div class="section-inner footer-row">
387
  <div>
388
+ <p>careTalk v1.1.31 · MIT</p>
389
  <p>
390
  <a href="./app.html">App</a>
391
  ·
sw.js CHANGED
@@ -1 +1 @@
1
- if(!self.define){let e,i={};const s=(s,n)=>(s=new URL(s+".js",n).href,i[s]||new Promise(i=>{if("document"in self){const e=document.createElement("script");e.src=s,e.onload=i,document.head.appendChild(e)}else e=s,importScripts(s),i()}).then(()=>{let e=i[s];if(!e)throw new Error(`Module ${s} didn’t register its module`);return e}));self.define=(n,r)=>{const c=e||("document"in self?document.currentScript.src:"")||location.href;if(i[c])return;let o={};const d=e=>s(e,c),a={module:{uri:c},exports:o,require:d};i[c]=Promise.all(n.map(e=>a[e]||d(e))).then(e=>(r(...e),o))}}define(["./workbox-7e792205"],function(e){"use strict";e.setCacheNameDetails({prefix:"caretalk-v1.1.30"}),self.skipWaiting(),e.clientsClaim(),e.precacheAndRoute([{url:"registerSW.js",revision:"402b66900e731ca748771b6fc5e7a068"},{url:"hero-care.svg",revision:"a9d97d192cde2661e3e4d52723d03ae7"},{url:"images/hero-voice-nurse.jpg",revision:"a0776f91455f5e559b11e586e9597d3f"},{url:"images/carer-with-resident.jpg",revision:"374120deec9fc1f1c162417925eccabe"},{url:"images/care-team-handover.jpg",revision:"6dedd4c73e49815755fd5fd8fe784792"},{url:"icons/maskable-512.png",revision:"41eb5c903fd29f4a552b55122c39d7a6"},{url:"icons/icon-96.png",revision:"c7063d694b7210675979642d3cc4bd9b"},{url:"icons/icon-72.png",revision:"40325cc62c852106f90fcc870cbc1943"},{url:"icons/icon-512.png",revision:"9e9241bfc9b4635ef53377151d7d80aa"},{url:"icons/icon-48.png",revision:"e285578e036bdb9ce72e90c74d81e32f"},{url:"icons/icon-384.png",revision:"c68ce1a6dc0d17e06addd8b808b106ca"},{url:"icons/icon-256.png",revision:"36af64867752330984fa76459c7b6f91"},{url:"icons/icon-192.png",revision:"0d97f74e5177647fbde6ac7c70e3e9bb"},{url:"icons/icon-180.png",revision:"dd4bbc3f77afe698d21e73da037d28e3"},{url:"icons/icon-152.png",revision:"afa4984306b9851dbc21a20991a4e508"},{url:"icons/icon-144.png",revision:"e6613e2654691995cd27d7315464c900"},{url:"icons/icon-128.png",revision:"ca020be4893dc4d974b52c419c55aba6"},{url:"icons/favicon.png",revision:"4526b965ff5b8d72db16968924f1b3db"},{url:"guides/skin-check.svg",revision:"2adbc18094378f18eb51061381933bbd"},{url:"guides/fall-no-lift.svg",revision:"9d172716c76094b62f5ffa2f247c7586"},{url:"guides/fall-assess.svg",revision:"ed1f8942caf390c5260ec7ecb3279a1e"},{url:"guides/dysphagia-upright.svg",revision:"c523adca44635664604f3e3d2980228d"},{url:"guides/dysphagia-stop.svg",revision:"5dfa1acc35a55f07be46ed2b0a53523c"},{url:"guides/distress-space.svg",revision:"532c2ad0b3b802a72dc10990869c4994"},{url:"assets/web-o2G7w9Em.js",revision:null},{url:"assets/web-BhapuqNa.js",revision:null},{url:"assets/web-BVF1lTpL.js",revision:null},{url:"assets/theme-CuaEyjDL.js",revision:null},{url:"assets/subscribers-DkYmS9Go.js",revision:null},{url:"assets/subscribers-BHyrZ7wW.css",revision:null},{url:"assets/main-Dsvc5F92.js",revision:null},{url:"assets/app-ipj-_NCA.js",revision:null},{url:"assets/app-DT9iTHEE.css",revision:null},{url:"assets/admin-obUvnyby.js",revision:null},{url:"hero-care.svg",revision:"a9d97d192cde2661e3e4d52723d03ae7"},{url:"icons/favicon.png",revision:"4526b965ff5b8d72db16968924f1b3db"},{url:"icons/icon-192.png",revision:"0d97f74e5177647fbde6ac7c70e3e9bb"},{url:"icons/icon-512.png",revision:"9e9241bfc9b4635ef53377151d7d80aa"},{url:"icons/maskable-512.png",revision:"41eb5c903fd29f4a552b55122c39d7a6"},{url:"images/care-team-handover.jpg",revision:"6dedd4c73e49815755fd5fd8fe784792"},{url:"images/carer-with-resident.jpg",revision:"374120deec9fc1f1c162417925eccabe"},{url:"images/hero-voice-nurse.jpg",revision:"a0776f91455f5e559b11e586e9597d3f"},{url:"manifest.webmanifest",revision:"7e7f6001ed44fd4390e69de1a5d67214"}],{}),e.cleanupOutdatedCaches()});
 
1
+ if(!self.define){let e,i={};const s=(s,r)=>(s=new URL(s+".js",r).href,i[s]||new Promise(i=>{if("document"in self){const e=document.createElement("script");e.src=s,e.onload=i,document.head.appendChild(e)}else e=s,importScripts(s),i()}).then(()=>{let e=i[s];if(!e)throw new Error(`Module ${s} didn’t register its module`);return e}));self.define=(r,n)=>{const c=e||("document"in self?document.currentScript.src:"")||location.href;if(i[c])return;let o={};const d=e=>s(e,c),a={module:{uri:c},exports:o,require:d};i[c]=Promise.all(r.map(e=>a[e]||d(e))).then(e=>(n(...e),o))}}define(["./workbox-7e792205"],function(e){"use strict";e.setCacheNameDetails({prefix:"caretalk-v1.1.31"}),self.skipWaiting(),e.clientsClaim(),e.precacheAndRoute([{url:"registerSW.js",revision:"402b66900e731ca748771b6fc5e7a068"},{url:"hero-care.svg",revision:"a9d97d192cde2661e3e4d52723d03ae7"},{url:"images/hero-voice-nurse.jpg",revision:"a0776f91455f5e559b11e586e9597d3f"},{url:"images/carer-with-resident.jpg",revision:"374120deec9fc1f1c162417925eccabe"},{url:"images/care-team-handover.jpg",revision:"6dedd4c73e49815755fd5fd8fe784792"},{url:"icons/maskable-512.png",revision:"41eb5c903fd29f4a552b55122c39d7a6"},{url:"icons/icon-96.png",revision:"c7063d694b7210675979642d3cc4bd9b"},{url:"icons/icon-72.png",revision:"40325cc62c852106f90fcc870cbc1943"},{url:"icons/icon-512.png",revision:"9e9241bfc9b4635ef53377151d7d80aa"},{url:"icons/icon-48.png",revision:"e285578e036bdb9ce72e90c74d81e32f"},{url:"icons/icon-384.png",revision:"c68ce1a6dc0d17e06addd8b808b106ca"},{url:"icons/icon-256.png",revision:"36af64867752330984fa76459c7b6f91"},{url:"icons/icon-192.png",revision:"0d97f74e5177647fbde6ac7c70e3e9bb"},{url:"icons/icon-180.png",revision:"dd4bbc3f77afe698d21e73da037d28e3"},{url:"icons/icon-152.png",revision:"afa4984306b9851dbc21a20991a4e508"},{url:"icons/icon-144.png",revision:"e6613e2654691995cd27d7315464c900"},{url:"icons/icon-128.png",revision:"ca020be4893dc4d974b52c419c55aba6"},{url:"icons/favicon.png",revision:"4526b965ff5b8d72db16968924f1b3db"},{url:"guides/skin-check.svg",revision:"2adbc18094378f18eb51061381933bbd"},{url:"guides/fall-no-lift.svg",revision:"9d172716c76094b62f5ffa2f247c7586"},{url:"guides/fall-assess.svg",revision:"ed1f8942caf390c5260ec7ecb3279a1e"},{url:"guides/dysphagia-upright.svg",revision:"c523adca44635664604f3e3d2980228d"},{url:"guides/dysphagia-stop.svg",revision:"5dfa1acc35a55f07be46ed2b0a53523c"},{url:"guides/distress-space.svg",revision:"532c2ad0b3b802a72dc10990869c4994"},{url:"assets/web-DrRVGgij.js",revision:null},{url:"assets/web-CbBz5VEx.js",revision:null},{url:"assets/web-BoLQRCPk.js",revision:null},{url:"assets/theme-CuaEyjDL.js",revision:null},{url:"assets/subscribers-CLCOf4GQ.js",revision:null},{url:"assets/subscribers-BHyrZ7wW.css",revision:null},{url:"assets/main-fYjBO_9U.js",revision:null},{url:"assets/app-DT9iTHEE.css",revision:null},{url:"assets/app-Cr21RCtM.js",revision:null},{url:"assets/admin-COcnhFD_.js",revision:null},{url:"hero-care.svg",revision:"a9d97d192cde2661e3e4d52723d03ae7"},{url:"icons/favicon.png",revision:"4526b965ff5b8d72db16968924f1b3db"},{url:"icons/icon-192.png",revision:"0d97f74e5177647fbde6ac7c70e3e9bb"},{url:"icons/icon-512.png",revision:"9e9241bfc9b4635ef53377151d7d80aa"},{url:"icons/maskable-512.png",revision:"41eb5c903fd29f4a552b55122c39d7a6"},{url:"images/care-team-handover.jpg",revision:"6dedd4c73e49815755fd5fd8fe784792"},{url:"images/carer-with-resident.jpg",revision:"374120deec9fc1f1c162417925eccabe"},{url:"images/hero-voice-nurse.jpg",revision:"a0776f91455f5e559b11e586e9597d3f"},{url:"manifest.webmanifest",revision:"7e7f6001ed44fd4390e69de1a5d67214"}],{}),e.cleanupOutdatedCaches()});