From 48a30d97db8db8d4df3a679cbe285eff55048a7e Mon Sep 17 00:00:00 2001 From: Suriyakumarvijayanayagam Date: Wed, 30 Sep 2026 16:48:43 +0530 Subject: [PATCH] Live camera view in the app, and the green light that was lying about it Two changes, and the second was found by verifying the first. ## Watching a camera from the app, in another building Snapshots answer "is that camera working". They do not answer "what is happening in my shop right now", which is what somebody who opens the app away from the counter is asking. Head office's browser already had that answer - LiveHub plus cameras.Live, where the shop PC asks outbound whether anybody is watching and pushes JPEG frames for as long as somebody is - and the app could not reach it. cloud.CameraLive opens that feed and the app's own loopback relay re-emits it as multipart MJPEG. That is the trick: frames arrive base64 over SSE, an cannot render that, and an renders MJPEG natively - so a tile is an ordinary pointed at loopback whether the camera is in this room or another city. - Reconnecting happens in the relay, not the page. The server caps one push at five minutes, so doing it here means the never sees the stream end. - The headers are flushed before the first frame. Go writes them on the first body write, so without that the whole response waits for the shop PC to start pushing. Measured against production: 30 seconds and not even a Content-Type, which surfaces as the request timing out. - One camera at a time. Watching makes a shop PC upload, so a grid that went live at once would put an estate's worth of cameras on the wire because somebody opened a page. - live.mjpeg is behind the same per-run token as the engine routes, and a wrong token is a 404 that never reaches head office at all. - CameraLive uses its own HTTP client: the shared one's 30s timeout covers the whole response and would sever a working view every thirty seconds - the trap that made the server set WriteTimeout to zero for its own SSE endpoint. ## A camera read "Connected" for 34 minutes after the shop PC went blind Which is why the verification above looked like a failure: head office registered the viewer and no frame ever came. reportWith returns early when the engine is unreachable - correctly, it has nothing to say - so the last state it sent stays in the database looking current. Measured live: cam2 and entrance both reading Connected, in green, with last_seen_at 34 minutes old, while the heartbeat from the same PC said cameras_up 0 of 0. Two surfaces reading two stored fields and disagreeing. false could not be the answer. It means "this camera is not connecting", which sends an installer to check cabling on a camera that was working perfectly the last time anybody could ask it. So there are four states and one function: connected reported recently, and working not_connecting reported recently, and the stream will not open waiting no shop PC has ever reported this camera stale reported once, and not lately - Connected is CLEARED when stale or waiting. A stale true left in place stays available to every client reading the field directly, and leaves two fields on one object disagreeing - how the shops screen once came out labelled Working, in green, above "2 of 3 cameras not connecting". - Computed in scanCamera, so every camera anybody reads passes through it. A state computed per handler is one a handler forgets, and this had already reached three screens. - CameraStaleAfter is 5 minutes: five missed reports, not one. Same reasoning as three missed heartbeats - an indicator that cries wolf gets ignored. - An unparseable last_seen_at is stale. It should be impossible, which is why it must not fall through to the state that says everything is fine. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01KGcjxF1cNLcuwc3DAPcnfj --- CLAUDE.md | 77 +++++++ desktop/app.go | 26 +++ .../frontend/dist/assets/index-6LYbNlbD.js | 40 ++++ ...{index-xWw5ie4A.css => index-DOJ2bRrM.css} | 2 +- .../frontend/dist/assets/index-vAtlvw9l.js | 40 ---- desktop/frontend/dist/index.html | 4 +- desktop/frontend/src/bridge.js | 3 + desktop/frontend/src/styles.css | 15 ++ desktop/frontend/src/views/Cameras.jsx | 55 ++++- desktop/internal/cloud/client.go | 76 +++++++ desktop/stream_proxy.go | 66 +++++- desktop/stream_remote.go | 149 +++++++++++++ desktop/stream_remote_live_test.go | 103 +++++++++ desktop/stream_remote_test.go | 209 ++++++++++++++++++ server/internal/api/camera_state_test.go | 96 ++++++++ server/internal/api/types.go | 72 ++++++ server/internal/store/api_cameras.go | 5 + .../{index-Ckr5hGZd.js => index-BuVkBNdU.js} | 16 +- server/internal/web/dist/index.html | 2 +- web/src/views/Cameras.jsx | 22 +- 20 files changed, 999 insertions(+), 79 deletions(-) create mode 100644 desktop/frontend/dist/assets/index-6LYbNlbD.js rename desktop/frontend/dist/assets/{index-xWw5ie4A.css => index-DOJ2bRrM.css} (99%) delete mode 100644 desktop/frontend/dist/assets/index-vAtlvw9l.js create mode 100644 desktop/stream_remote.go create mode 100644 desktop/stream_remote_live_test.go create mode 100644 desktop/stream_remote_test.go create mode 100644 server/internal/api/camera_state_test.go rename server/internal/web/dist/assets/{index-Ckr5hGZd.js => index-BuVkBNdU.js} (84%) diff --git a/CLAUDE.md b/CLAUDE.md index 0abd90a..79539ca 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -3359,3 +3359,80 @@ live one. - **With no engine AND nobody signed in, the engine error is still the answer.** There is nothing else to show and the person is most likely setting this PC up; naming head office there points them at a step they have not reached. + +## Watching a camera from the app, in another building + +Snapshots answer *"is that camera working"*. They do not answer *"what is +happening in my shop right now"*, which is what somebody who opens the app +away from the counter is asking. Head office's browser already had the answer +— `LiveHub` plus `cameras.Live`, where the shop PC asks outbound whether +anybody is watching and pushes JPEG frames up for exactly as long as somebody +is — and the app could not reach it. + +`cloud.CameraLive` opens that feed and the app's own loopback relay re-emits +it as **multipart MJPEG**, which is the whole trick: frames arrive base64 over +SSE, an `` cannot render that, and an `` renders MJPEG natively. So a +tile is an ordinary `` pointed at loopback whether the camera is in this +room or another city, and no screen has to know which. + +- **Reconnecting happens in the relay, not the page.** The server caps one push + at five minutes so a tab left open for a week cannot leave a shop uploading + for a week. Doing it here means the `` never sees the stream end. +- **The headers are flushed before the first frame.** Go writes them on the + first body write, so without that the whole response — status line included — + waits for the shop PC to start pushing. Measured against production: thirty + seconds and not even a `Content-Type`, which surfaces as the *request* timing + out rather than a stream that has not painted yet. +- **One camera at a time.** Watching makes a shop PC upload, so a grid that + went live at once would put an estate's worth of cameras on the wire because + somebody opened a page. `Watch live` is per tile and toggles the previous one + off. +- **`live.mjpeg` is behind the same per-run token as the engine routes**, and a + wrong token is a 404 that never reaches head office at all. It is a live view + of a shop floor; the relay being on loopback is not on its own a control. +- **`CameraLive` uses its own HTTP client.** The shared one has a 30-second + timeout that covers the whole response and would therefore sever a working + live view every thirty seconds — the same trap that made the server set + `WriteTimeout` to zero for its own SSE endpoint. + +## A camera read "Connected" for 34 minutes after the shop PC went blind + +Found while verifying the live view against production, and it is the reason +that verification looked like a failure: head office registered the viewer and +no frame ever came. + +`reportWith` returns early when the engine is unreachable — correctly, because +it has nothing to say — so the last state it sent **stays in the database +looking current**. Measured on the live estate: `cam2` and `entrance` both +reading **Connected**, in green, with `last_seen_at` thirty-four minutes old, +while the heartbeat from the same PC said `cameras_up: 0, cameras_total: 0`. +Two surfaces reading two stored fields and disagreeing about one fact. + +`false` could not be the answer. It means *"this camera is not connecting"*, +which sends an installer to check cabling on a camera that was working +perfectly the last time anybody could ask it. So there are four states, not +three, and `api.CameraState` is the one function that decides them: + +| state | meaning | what to do | +|---|---|---| +| `connected` | reported within `CameraStaleAfter`, and working | — | +| `not_connecting` | reported recently, and the stream will not open | check the address, password, cabling | +| `waiting` | no shop PC has ever reported this camera | it has not reached the PC yet | +| `stale` | reported once, and not lately | check the PC is on and Behavision is running | + +- **`Connected` is CLEARED when the state is `stale` or `waiting`.** Leaving a + stale `true` in place keeps the lie available to every client that reads the + field directly — a mobile app, a script, an older desktop build — and leaves + two fields on one object disagreeing, which is exactly how the shops screen + once came out labelled **Working**, in green, above *"2 of 3 cameras not + connecting"*. +- **It is computed in `scanCamera`**, so every camera anybody reads passes + through it. A state computed per handler is a state one handler forgets, and + this one had already reached three screens. +- **`CameraStaleAfter` is 5 minutes — five missed reports, not one.** The agent + reports on a 60-second tick, so one miss is a dropped packet. Same reasoning + as a site being offline after three missed heartbeats: an indicator that + cries wolf is one people learn to ignore. +- **An unparseable `last_seen_at` is stale**, not connected. It should be + impossible, which is precisely why it must not fall through to the state that + says everything is fine. diff --git a/desktop/app.go b/desktop/app.go index 9238d3d..8c1f746 100644 --- a/desktop/app.go +++ b/desktop/app.go @@ -82,6 +82,14 @@ func (a *App) startup(ctx context.Context) { if err := a.proxy.start(a.local.Base, a.local.User, a.local.Password); err != nil { log.Printf("camera relay unavailable, tiles will not load: %v", err) } + // And the other direction: watching a camera in another building, through + // head office's relay. Enabled unconditionally rather than only when a + // session already exists, because signing in is a thing that happens + // while the app is open - and CameraLive refuses without a session + // anyway, so there is nothing to gate. + if err := a.proxy.watchRemote(a.cloud.CameraLive); err != nil { + log.Printf("remote camera view unavailable: %v", err) + } // A saved session means a shop PC that rebooted overnight comes back // working instead of waiting for someone to log in. @@ -646,6 +654,7 @@ func (a *App) Cameras() ([]map[string]any, error) { "id": c.ID, "camera_id": c.CameraID, "label": c.Label, "site": c.Site, "enabled": c.Enabled, "connected": c.Connected, "last_seen_at": c.LastSeenAt, + "state": c.State, "state_note": c.StateNote, "snapshot": c.Snapshot, "snapshot_at": c.SnapshotAt, // What the screen keys off to hide Edit, Test and Check: this // camera is on a network this PC cannot reach. @@ -719,6 +728,23 @@ func (a *App) StreamURL(cameraID string) string { return fmt.Sprintf("http://%s/api/cameras/%s/stream.mjpeg", base, cameraID) } +// RemoteStreamURL is the live view of a camera in another building. +// +// The picture comes from head office's relay - the shop PC pushes frames +// outbound because nothing can reach in - and this app re-emits them as MJPEG +// on its own loopback, so a tile is an ordinary either way. A screen +// therefore never has to know which building it is looking at. +// +// Empty when the relay is not running, and the caller shows the last snapshot +// instead. There is no useful fallback URL: the head-office endpoint needs +// this session's bearer, which an cannot send. +func (a *App) RemoteStreamURL(cameraID string) string { + if !a.cloud.LoggedIn() { + return "" + } + return a.proxy.urlFor(cameraID, "live.mjpeg") +} + // ------------------------------------------------------------------- live -- type LiveSnapshot struct { diff --git a/desktop/frontend/dist/assets/index-6LYbNlbD.js b/desktop/frontend/dist/assets/index-6LYbNlbD.js new file mode 100644 index 0000000..23449f9 --- /dev/null +++ b/desktop/frontend/dist/assets/index-6LYbNlbD.js @@ -0,0 +1,40 @@ +(function(){const t=document.createElement("link").relList;if(t&&t.supports&&t.supports("modulepreload"))return;for(const l of document.querySelectorAll('link[rel="modulepreload"]'))r(l);new MutationObserver(l=>{for(const s of l)if(s.type==="childList")for(const o of s.addedNodes)o.tagName==="LINK"&&o.rel==="modulepreload"&&r(o)}).observe(document,{childList:!0,subtree:!0});function n(l){const s={};return l.integrity&&(s.integrity=l.integrity),l.referrerPolicy&&(s.referrerPolicy=l.referrerPolicy),l.crossOrigin==="use-credentials"?s.credentials="include":l.crossOrigin==="anonymous"?s.credentials="omit":s.credentials="same-origin",s}function r(l){if(l.ep)return;l.ep=!0;const s=n(l);fetch(l.href,s)}})();function Lc(e){return e&&e.__esModule&&Object.prototype.hasOwnProperty.call(e,"default")?e.default:e}var ca={exports:{}},dl={},da={exports:{}},D={};/** + * @license React + * react.production.min.js + * + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */var nr=Symbol.for("react.element"),Tc=Symbol.for("react.portal"),Mc=Symbol.for("react.fragment"),Rc=Symbol.for("react.strict_mode"),Dc=Symbol.for("react.profiler"),Oc=Symbol.for("react.provider"),Fc=Symbol.for("react.context"),Ic=Symbol.for("react.forward_ref"),$c=Symbol.for("react.suspense"),Uc=Symbol.for("react.memo"),Ac=Symbol.for("react.lazy"),Xi=Symbol.iterator;function Bc(e){return e===null||typeof e!="object"?null:(e=Xi&&e[Xi]||e["@@iterator"],typeof e=="function"?e:null)}var fa={isMounted:function(){return!1},enqueueForceUpdate:function(){},enqueueReplaceState:function(){},enqueueSetState:function(){}},pa=Object.assign,ha={};function pn(e,t,n){this.props=e,this.context=t,this.refs=ha,this.updater=n||fa}pn.prototype.isReactComponent={};pn.prototype.setState=function(e,t){if(typeof e!="object"&&typeof e!="function"&&e!=null)throw Error("setState(...): takes an object of state variables to update or a function which returns an object of state variables.");this.updater.enqueueSetState(this,e,t,"setState")};pn.prototype.forceUpdate=function(e){this.updater.enqueueForceUpdate(this,e,"forceUpdate")};function ma(){}ma.prototype=pn.prototype;function qs(e,t,n){this.props=e,this.context=t,this.refs=ha,this.updater=n||fa}var bs=qs.prototype=new ma;bs.constructor=qs;pa(bs,pn.prototype);bs.isPureReactComponent=!0;var Zi=Array.isArray,va=Object.prototype.hasOwnProperty,ei={current:null},ga={key:!0,ref:!0,__self:!0,__source:!0};function ya(e,t,n){var r,l={},s=null,o=null;if(t!=null)for(r in t.ref!==void 0&&(o=t.ref),t.key!==void 0&&(s=""+t.key),t)va.call(t,r)&&!ga.hasOwnProperty(r)&&(l[r]=t[r]);var a=arguments.length-2;if(a===1)l.children=n;else if(1>>1,ee=P[G];if(0>>1;Gl(zl,R))Ntl(ar,zl)?(P[G]=ar,P[Nt]=R,G=Nt):(P[G]=zl,P[St]=R,G=St);else if(Ntl(ar,R))P[G]=ar,P[Nt]=R,G=Nt;else break e}}return M}function l(P,M){var R=P.sortIndex-M.sortIndex;return R!==0?R:P.id-M.id}if(typeof performance=="object"&&typeof performance.now=="function"){var s=performance;e.unstable_now=function(){return s.now()}}else{var o=Date,a=o.now();e.unstable_now=function(){return o.now()-a}}var u=[],c=[],p=1,v=null,h=3,g=!1,w=!1,y=!1,T=typeof setTimeout=="function"?setTimeout:null,f=typeof clearTimeout=="function"?clearTimeout:null,d=typeof setImmediate<"u"?setImmediate:null;typeof navigator<"u"&&navigator.scheduling!==void 0&&navigator.scheduling.isInputPending!==void 0&&navigator.scheduling.isInputPending.bind(navigator.scheduling);function m(P){for(var M=n(c);M!==null;){if(M.callback===null)r(c);else if(M.startTime<=P)r(c),M.sortIndex=M.expirationTime,t(u,M);else break;M=n(c)}}function x(P){if(y=!1,m(P),!w)if(n(u)!==null)w=!0,_l(S);else{var M=n(c);M!==null&&Pl(x,M.startTime-P)}}function S(P,M){w=!1,y&&(y=!1,f(_),_=-1),g=!0;var R=h;try{for(m(M),v=n(u);v!==null&&(!(v.expirationTime>M)||P&&!V());){var G=v.callback;if(typeof G=="function"){v.callback=null,h=v.priorityLevel;var ee=G(v.expirationTime<=M);M=e.unstable_now(),typeof ee=="function"?v.callback=ee:v===n(u)&&r(u),m(M)}else r(u);v=n(u)}if(v!==null)var or=!0;else{var St=n(c);St!==null&&Pl(x,St.startTime-M),or=!1}return or}finally{v=null,h=R,g=!1}}var E=!1,k=null,_=-1,z=5,L=-1;function V(){return!(e.unstable_now()-LP||125G?(P.sortIndex=R,t(c,P),n(u)===null&&P===n(c)&&(y?(f(_),_=-1):y=!0,Pl(x,R-G))):(P.sortIndex=ee,t(u,P),w||g||(w=!0,_l(S))),P},e.unstable_shouldYield=V,e.unstable_wrapCallback=function(P){var M=h;return function(){var R=h;h=M;try{return P.apply(this,arguments)}finally{h=R}}}})(Sa);ka.exports=Sa;var bc=ka.exports;/** + * @license React + * react-dom.production.min.js + * + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */var ed=C,Ne=bc;function j(e){for(var t="https://reactjs.org/docs/error-decoder.html?invariant="+e,n=1;n"u"||typeof window.document>"u"||typeof window.document.createElement>"u"),rs=Object.prototype.hasOwnProperty,td=/^[:A-Z_a-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD][:A-Z_a-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD\-.0-9\u00B7\u0300-\u036F\u203F-\u2040]*$/,qi={},bi={};function nd(e){return rs.call(bi,e)?!0:rs.call(qi,e)?!1:td.test(e)?bi[e]=!0:(qi[e]=!0,!1)}function rd(e,t,n,r){if(n!==null&&n.type===0)return!1;switch(typeof t){case"function":case"symbol":return!0;case"boolean":return r?!1:n!==null?!n.acceptsBooleans:(e=e.toLowerCase().slice(0,5),e!=="data-"&&e!=="aria-");default:return!1}}function ld(e,t,n,r){if(t===null||typeof t>"u"||rd(e,t,n,r))return!0;if(r)return!1;if(n!==null)switch(n.type){case 3:return!t;case 4:return t===!1;case 5:return isNaN(t);case 6:return isNaN(t)||1>t}return!1}function he(e,t,n,r,l,s,o){this.acceptsBooleans=t===2||t===3||t===4,this.attributeName=r,this.attributeNamespace=l,this.mustUseProperty=n,this.propertyName=e,this.type=t,this.sanitizeURL=s,this.removeEmptyString=o}var se={};"children dangerouslySetInnerHTML defaultValue defaultChecked innerHTML suppressContentEditableWarning suppressHydrationWarning style".split(" ").forEach(function(e){se[e]=new he(e,0,!1,e,null,!1,!1)});[["acceptCharset","accept-charset"],["className","class"],["htmlFor","for"],["httpEquiv","http-equiv"]].forEach(function(e){var t=e[0];se[t]=new he(t,1,!1,e[1],null,!1,!1)});["contentEditable","draggable","spellCheck","value"].forEach(function(e){se[e]=new he(e,2,!1,e.toLowerCase(),null,!1,!1)});["autoReverse","externalResourcesRequired","focusable","preserveAlpha"].forEach(function(e){se[e]=new he(e,2,!1,e,null,!1,!1)});"allowFullScreen async autoFocus autoPlay controls default defer disabled disablePictureInPicture disableRemotePlayback formNoValidate hidden loop noModule noValidate open playsInline readOnly required reversed scoped seamless itemScope".split(" ").forEach(function(e){se[e]=new he(e,3,!1,e.toLowerCase(),null,!1,!1)});["checked","multiple","muted","selected"].forEach(function(e){se[e]=new he(e,3,!0,e,null,!1,!1)});["capture","download"].forEach(function(e){se[e]=new he(e,4,!1,e,null,!1,!1)});["cols","rows","size","span"].forEach(function(e){se[e]=new he(e,6,!1,e,null,!1,!1)});["rowSpan","start"].forEach(function(e){se[e]=new he(e,5,!1,e.toLowerCase(),null,!1,!1)});var ni=/[\-:]([a-z])/g;function ri(e){return e[1].toUpperCase()}"accent-height alignment-baseline arabic-form baseline-shift cap-height clip-path clip-rule color-interpolation color-interpolation-filters color-profile color-rendering dominant-baseline enable-background fill-opacity fill-rule flood-color flood-opacity font-family font-size font-size-adjust font-stretch font-style font-variant font-weight glyph-name glyph-orientation-horizontal glyph-orientation-vertical horiz-adv-x horiz-origin-x image-rendering letter-spacing lighting-color marker-end marker-mid marker-start overline-position overline-thickness paint-order panose-1 pointer-events rendering-intent shape-rendering stop-color stop-opacity strikethrough-position strikethrough-thickness stroke-dasharray stroke-dashoffset stroke-linecap stroke-linejoin stroke-miterlimit stroke-opacity stroke-width text-anchor text-decoration text-rendering underline-position underline-thickness unicode-bidi unicode-range units-per-em v-alphabetic v-hanging v-ideographic v-mathematical vector-effect vert-adv-y vert-origin-x vert-origin-y word-spacing writing-mode xmlns:xlink x-height".split(" ").forEach(function(e){var t=e.replace(ni,ri);se[t]=new he(t,1,!1,e,null,!1,!1)});"xlink:actuate xlink:arcrole xlink:role xlink:show xlink:title xlink:type".split(" ").forEach(function(e){var t=e.replace(ni,ri);se[t]=new he(t,1,!1,e,"http://www.w3.org/1999/xlink",!1,!1)});["xml:base","xml:lang","xml:space"].forEach(function(e){var t=e.replace(ni,ri);se[t]=new he(t,1,!1,e,"http://www.w3.org/XML/1998/namespace",!1,!1)});["tabIndex","crossOrigin"].forEach(function(e){se[e]=new he(e,1,!1,e.toLowerCase(),null,!1,!1)});se.xlinkHref=new he("xlinkHref",1,!1,"xlink:href","http://www.w3.org/1999/xlink",!0,!1);["src","href","action","formAction"].forEach(function(e){se[e]=new he(e,1,!1,e.toLowerCase(),null,!0,!0)});function li(e,t,n,r){var l=se.hasOwnProperty(t)?se[t]:null;(l!==null?l.type!==0:r||!(2a||l[o]!==s[a]){var u=` +`+l[o].replace(" at new "," at ");return e.displayName&&u.includes("")&&(u=u.replace("",e.displayName)),u}while(1<=o&&0<=a);break}}}finally{Ml=!1,Error.prepareStackTrace=n}return(e=e?e.displayName||e.name:"")?En(e):""}function sd(e){switch(e.tag){case 5:return En(e.type);case 16:return En("Lazy");case 13:return En("Suspense");case 19:return En("SuspenseList");case 0:case 2:case 15:return e=Rl(e.type,!1),e;case 11:return e=Rl(e.type.render,!1),e;case 1:return e=Rl(e.type,!0),e;default:return""}}function os(e){if(e==null)return null;if(typeof e=="function")return e.displayName||e.name||null;if(typeof e=="string")return e;switch(e){case Bt:return"Fragment";case At:return"Portal";case ls:return"Profiler";case si:return"StrictMode";case ss:return"Suspense";case is:return"SuspenseList"}if(typeof e=="object")switch(e.$$typeof){case Ea:return(e.displayName||"Context")+".Consumer";case Ca:return(e._context.displayName||"Context")+".Provider";case ii:var t=e.render;return e=e.displayName,e||(e=t.displayName||t.name||"",e=e!==""?"ForwardRef("+e+")":"ForwardRef"),e;case oi:return t=e.displayName||null,t!==null?t:os(e.type)||"Memo";case rt:t=e._payload,e=e._init;try{return os(e(t))}catch{}}return null}function id(e){var t=e.type;switch(e.tag){case 24:return"Cache";case 9:return(t.displayName||"Context")+".Consumer";case 10:return(t._context.displayName||"Context")+".Provider";case 18:return"DehydratedFragment";case 11:return e=t.render,e=e.displayName||e.name||"",t.displayName||(e!==""?"ForwardRef("+e+")":"ForwardRef");case 7:return"Fragment";case 5:return t;case 4:return"Portal";case 3:return"Root";case 6:return"Text";case 16:return os(t);case 8:return t===si?"StrictMode":"Mode";case 22:return"Offscreen";case 12:return"Profiler";case 21:return"Scope";case 13:return"Suspense";case 19:return"SuspenseList";case 25:return"TracingMarker";case 1:case 0:case 17:case 2:case 14:case 15:if(typeof t=="function")return t.displayName||t.name||null;if(typeof t=="string")return t}return null}function yt(e){switch(typeof e){case"boolean":case"number":case"string":case"undefined":return e;case"object":return e;default:return""}}function Pa(e){var t=e.type;return(e=e.nodeName)&&e.toLowerCase()==="input"&&(t==="checkbox"||t==="radio")}function od(e){var t=Pa(e)?"checked":"value",n=Object.getOwnPropertyDescriptor(e.constructor.prototype,t),r=""+e[t];if(!e.hasOwnProperty(t)&&typeof n<"u"&&typeof n.get=="function"&&typeof n.set=="function"){var l=n.get,s=n.set;return Object.defineProperty(e,t,{configurable:!0,get:function(){return l.call(this)},set:function(o){r=""+o,s.call(this,o)}}),Object.defineProperty(e,t,{enumerable:n.enumerable}),{getValue:function(){return r},setValue:function(o){r=""+o},stopTracking:function(){e._valueTracker=null,delete e[t]}}}}function dr(e){e._valueTracker||(e._valueTracker=od(e))}function za(e){if(!e)return!1;var t=e._valueTracker;if(!t)return!0;var n=t.getValue(),r="";return e&&(r=Pa(e)?e.checked?"true":"false":e.value),e=r,e!==n?(t.setValue(e),!0):!1}function Br(e){if(e=e||(typeof document<"u"?document:void 0),typeof e>"u")return null;try{return e.activeElement||e.body}catch{return e.body}}function as(e,t){var n=t.checked;return K({},t,{defaultChecked:void 0,defaultValue:void 0,value:void 0,checked:n??e._wrapperState.initialChecked})}function to(e,t){var n=t.defaultValue==null?"":t.defaultValue,r=t.checked!=null?t.checked:t.defaultChecked;n=yt(t.value!=null?t.value:n),e._wrapperState={initialChecked:r,initialValue:n,controlled:t.type==="checkbox"||t.type==="radio"?t.checked!=null:t.value!=null}}function La(e,t){t=t.checked,t!=null&&li(e,"checked",t,!1)}function us(e,t){La(e,t);var n=yt(t.value),r=t.type;if(n!=null)r==="number"?(n===0&&e.value===""||e.value!=n)&&(e.value=""+n):e.value!==""+n&&(e.value=""+n);else if(r==="submit"||r==="reset"){e.removeAttribute("value");return}t.hasOwnProperty("value")?cs(e,t.type,n):t.hasOwnProperty("defaultValue")&&cs(e,t.type,yt(t.defaultValue)),t.checked==null&&t.defaultChecked!=null&&(e.defaultChecked=!!t.defaultChecked)}function no(e,t,n){if(t.hasOwnProperty("value")||t.hasOwnProperty("defaultValue")){var r=t.type;if(!(r!=="submit"&&r!=="reset"||t.value!==void 0&&t.value!==null))return;t=""+e._wrapperState.initialValue,n||t===e.value||(e.value=t),e.defaultValue=t}n=e.name,n!==""&&(e.name=""),e.defaultChecked=!!e._wrapperState.initialChecked,n!==""&&(e.name=n)}function cs(e,t,n){(t!=="number"||Br(e.ownerDocument)!==e)&&(n==null?e.defaultValue=""+e._wrapperState.initialValue:e.defaultValue!==""+n&&(e.defaultValue=""+n))}var _n=Array.isArray;function qt(e,t,n,r){if(e=e.options,t){t={};for(var l=0;l"+t.valueOf().toString()+"",t=fr.firstChild;e.firstChild;)e.removeChild(e.firstChild);for(;t.firstChild;)e.appendChild(t.firstChild)}});function An(e,t){if(t){var n=e.firstChild;if(n&&n===e.lastChild&&n.nodeType===3){n.nodeValue=t;return}}e.textContent=t}var Ln={animationIterationCount:!0,aspectRatio:!0,borderImageOutset:!0,borderImageSlice:!0,borderImageWidth:!0,boxFlex:!0,boxFlexGroup:!0,boxOrdinalGroup:!0,columnCount:!0,columns:!0,flex:!0,flexGrow:!0,flexPositive:!0,flexShrink:!0,flexNegative:!0,flexOrder:!0,gridArea:!0,gridRow:!0,gridRowEnd:!0,gridRowSpan:!0,gridRowStart:!0,gridColumn:!0,gridColumnEnd:!0,gridColumnSpan:!0,gridColumnStart:!0,fontWeight:!0,lineClamp:!0,lineHeight:!0,opacity:!0,order:!0,orphans:!0,tabSize:!0,widows:!0,zIndex:!0,zoom:!0,fillOpacity:!0,floodOpacity:!0,stopOpacity:!0,strokeDasharray:!0,strokeDashoffset:!0,strokeMiterlimit:!0,strokeOpacity:!0,strokeWidth:!0},ad=["Webkit","ms","Moz","O"];Object.keys(Ln).forEach(function(e){ad.forEach(function(t){t=t+e.charAt(0).toUpperCase()+e.substring(1),Ln[t]=Ln[e]})});function Da(e,t,n){return t==null||typeof t=="boolean"||t===""?"":n||typeof t!="number"||t===0||Ln.hasOwnProperty(e)&&Ln[e]?(""+t).trim():t+"px"}function Oa(e,t){e=e.style;for(var n in t)if(t.hasOwnProperty(n)){var r=n.indexOf("--")===0,l=Da(n,t[n],r);n==="float"&&(n="cssFloat"),r?e.setProperty(n,l):e[n]=l}}var ud=K({menuitem:!0},{area:!0,base:!0,br:!0,col:!0,embed:!0,hr:!0,img:!0,input:!0,keygen:!0,link:!0,meta:!0,param:!0,source:!0,track:!0,wbr:!0});function ps(e,t){if(t){if(ud[e]&&(t.children!=null||t.dangerouslySetInnerHTML!=null))throw Error(j(137,e));if(t.dangerouslySetInnerHTML!=null){if(t.children!=null)throw Error(j(60));if(typeof t.dangerouslySetInnerHTML!="object"||!("__html"in t.dangerouslySetInnerHTML))throw Error(j(61))}if(t.style!=null&&typeof t.style!="object")throw Error(j(62))}}function hs(e,t){if(e.indexOf("-")===-1)return typeof t.is=="string";switch(e){case"annotation-xml":case"color-profile":case"font-face":case"font-face-src":case"font-face-uri":case"font-face-format":case"font-face-name":case"missing-glyph":return!1;default:return!0}}var ms=null;function ai(e){return e=e.target||e.srcElement||window,e.correspondingUseElement&&(e=e.correspondingUseElement),e.nodeType===3?e.parentNode:e}var vs=null,bt=null,en=null;function so(e){if(e=sr(e)){if(typeof vs!="function")throw Error(j(280));var t=e.stateNode;t&&(t=vl(t),vs(e.stateNode,e.type,t))}}function Fa(e){bt?en?en.push(e):en=[e]:bt=e}function Ia(){if(bt){var e=bt,t=en;if(en=bt=null,so(e),t)for(e=0;e>>=0,e===0?32:31-(wd(e)/jd|0)|0}var pr=64,hr=4194304;function Pn(e){switch(e&-e){case 1:return 1;case 2:return 2;case 4:return 4;case 8:return 8;case 16:return 16;case 32:return 32;case 64:case 128:case 256:case 512:case 1024:case 2048:case 4096:case 8192:case 16384:case 32768:case 65536:case 131072:case 262144:case 524288:case 1048576:case 2097152:return e&4194240;case 4194304:case 8388608:case 16777216:case 33554432:case 67108864:return e&130023424;case 134217728:return 134217728;case 268435456:return 268435456;case 536870912:return 536870912;case 1073741824:return 1073741824;default:return e}}function Qr(e,t){var n=e.pendingLanes;if(n===0)return 0;var r=0,l=e.suspendedLanes,s=e.pingedLanes,o=n&268435455;if(o!==0){var a=o&~l;a!==0?r=Pn(a):(s&=o,s!==0&&(r=Pn(s)))}else o=n&~l,o!==0?r=Pn(o):s!==0&&(r=Pn(s));if(r===0)return 0;if(t!==0&&t!==r&&!(t&l)&&(l=r&-r,s=t&-t,l>=s||l===16&&(s&4194240)!==0))return t;if(r&4&&(r|=n&16),t=e.entangledLanes,t!==0)for(e=e.entanglements,t&=r;0n;n++)t.push(e);return t}function rr(e,t,n){e.pendingLanes|=t,t!==536870912&&(e.suspendedLanes=0,e.pingedLanes=0),e=e.eventTimes,t=31-Ie(t),e[t]=n}function Cd(e,t){var n=e.pendingLanes&~t;e.pendingLanes=t,e.suspendedLanes=0,e.pingedLanes=0,e.expiredLanes&=t,e.mutableReadLanes&=t,e.entangledLanes&=t,t=e.entanglements;var r=e.eventTimes;for(e=e.expirationTimes;0=Mn),mo=" ",vo=!1;function ru(e,t){switch(e){case"keyup":return bd.indexOf(t.keyCode)!==-1;case"keydown":return t.keyCode!==229;case"keypress":case"mousedown":case"focusout":return!0;default:return!1}}function lu(e){return e=e.detail,typeof e=="object"&&"data"in e?e.data:null}var Vt=!1;function tf(e,t){switch(e){case"compositionend":return lu(t);case"keypress":return t.which!==32?null:(vo=!0,mo);case"textInput":return e=t.data,e===mo&&vo?null:e;default:return null}}function nf(e,t){if(Vt)return e==="compositionend"||!vi&&ru(e,t)?(e=tu(),Mr=pi=ot=null,Vt=!1,e):null;switch(e){case"paste":return null;case"keypress":if(!(t.ctrlKey||t.altKey||t.metaKey)||t.ctrlKey&&t.altKey){if(t.char&&1=t)return{node:n,offset:t-e};e=r}e:{for(;n;){if(n.nextSibling){n=n.nextSibling;break e}n=n.parentNode}n=void 0}n=wo(n)}}function au(e,t){return e&&t?e===t?!0:e&&e.nodeType===3?!1:t&&t.nodeType===3?au(e,t.parentNode):"contains"in e?e.contains(t):e.compareDocumentPosition?!!(e.compareDocumentPosition(t)&16):!1:!1}function uu(){for(var e=window,t=Br();t instanceof e.HTMLIFrameElement;){try{var n=typeof t.contentWindow.location.href=="string"}catch{n=!1}if(n)e=t.contentWindow;else break;t=Br(e.document)}return t}function gi(e){var t=e&&e.nodeName&&e.nodeName.toLowerCase();return t&&(t==="input"&&(e.type==="text"||e.type==="search"||e.type==="tel"||e.type==="url"||e.type==="password")||t==="textarea"||e.contentEditable==="true")}function ff(e){var t=uu(),n=e.focusedElem,r=e.selectionRange;if(t!==n&&n&&n.ownerDocument&&au(n.ownerDocument.documentElement,n)){if(r!==null&&gi(n)){if(t=r.start,e=r.end,e===void 0&&(e=t),"selectionStart"in n)n.selectionStart=t,n.selectionEnd=Math.min(e,n.value.length);else if(e=(t=n.ownerDocument||document)&&t.defaultView||window,e.getSelection){e=e.getSelection();var l=n.textContent.length,s=Math.min(r.start,l);r=r.end===void 0?s:Math.min(r.end,l),!e.extend&&s>r&&(l=r,r=s,s=l),l=jo(n,s);var o=jo(n,r);l&&o&&(e.rangeCount!==1||e.anchorNode!==l.node||e.anchorOffset!==l.offset||e.focusNode!==o.node||e.focusOffset!==o.offset)&&(t=t.createRange(),t.setStart(l.node,l.offset),e.removeAllRanges(),s>r?(e.addRange(t),e.extend(o.node,o.offset)):(t.setEnd(o.node,o.offset),e.addRange(t)))}}for(t=[],e=n;e=e.parentNode;)e.nodeType===1&&t.push({element:e,left:e.scrollLeft,top:e.scrollTop});for(typeof n.focus=="function"&&n.focus(),n=0;n=document.documentMode,Wt=null,ks=null,Dn=null,Ss=!1;function ko(e,t,n){var r=n.window===n?n.document:n.nodeType===9?n:n.ownerDocument;Ss||Wt==null||Wt!==Br(r)||(r=Wt,"selectionStart"in r&&gi(r)?r={start:r.selectionStart,end:r.selectionEnd}:(r=(r.ownerDocument&&r.ownerDocument.defaultView||window).getSelection(),r={anchorNode:r.anchorNode,anchorOffset:r.anchorOffset,focusNode:r.focusNode,focusOffset:r.focusOffset}),Dn&&Kn(Dn,r)||(Dn=r,r=Gr(ks,"onSelect"),0Kt||(e.current=zs[Kt],zs[Kt]=null,Kt--)}function U(e,t){Kt++,zs[Kt]=e.current,e.current=t}var xt={},ue=jt(xt),ge=jt(!1),Mt=xt;function on(e,t){var n=e.type.contextTypes;if(!n)return xt;var r=e.stateNode;if(r&&r.__reactInternalMemoizedUnmaskedChildContext===t)return r.__reactInternalMemoizedMaskedChildContext;var l={},s;for(s in n)l[s]=t[s];return r&&(e=e.stateNode,e.__reactInternalMemoizedUnmaskedChildContext=t,e.__reactInternalMemoizedMaskedChildContext=l),l}function ye(e){return e=e.childContextTypes,e!=null}function Zr(){B(ge),B(ue)}function zo(e,t,n){if(ue.current!==xt)throw Error(j(168));U(ue,t),U(ge,n)}function yu(e,t,n){var r=e.stateNode;if(t=t.childContextTypes,typeof r.getChildContext!="function")return n;r=r.getChildContext();for(var l in r)if(!(l in t))throw Error(j(108,id(e)||"Unknown",l));return K({},n,r)}function Jr(e){return e=(e=e.stateNode)&&e.__reactInternalMemoizedMergedChildContext||xt,Mt=ue.current,U(ue,e),U(ge,ge.current),!0}function Lo(e,t,n){var r=e.stateNode;if(!r)throw Error(j(169));n?(e=yu(e,t,Mt),r.__reactInternalMemoizedMergedChildContext=e,B(ge),B(ue),U(ue,e)):B(ge),U(ge,n)}var Ke=null,gl=!1,Yl=!1;function xu(e){Ke===null?Ke=[e]:Ke.push(e)}function Nf(e){gl=!0,xu(e)}function kt(){if(!Yl&&Ke!==null){Yl=!0;var e=0,t=$;try{var n=Ke;for($=1;e>=o,l-=o,Ye=1<<32-Ie(t)+l|n<_?(z=k,k=null):z=k.sibling;var L=h(f,k,m[_],x);if(L===null){k===null&&(k=z);break}e&&k&&L.alternate===null&&t(f,k),d=s(L,d,_),E===null?S=L:E.sibling=L,E=L,k=z}if(_===m.length)return n(f,k),W&&Ct(f,_),S;if(k===null){for(;__?(z=k,k=null):z=k.sibling;var V=h(f,k,L.value,x);if(V===null){k===null&&(k=z);break}e&&k&&V.alternate===null&&t(f,k),d=s(V,d,_),E===null?S=V:E.sibling=V,E=V,k=z}if(L.done)return n(f,k),W&&Ct(f,_),S;if(k===null){for(;!L.done;_++,L=m.next())L=v(f,L.value,x),L!==null&&(d=s(L,d,_),E===null?S=L:E.sibling=L,E=L);return W&&Ct(f,_),S}for(k=r(f,k);!L.done;_++,L=m.next())L=g(k,f,_,L.value,x),L!==null&&(e&&L.alternate!==null&&k.delete(L.key===null?_:L.key),d=s(L,d,_),E===null?S=L:E.sibling=L,E=L);return e&&k.forEach(function(vn){return t(f,vn)}),W&&Ct(f,_),S}function T(f,d,m,x){if(typeof m=="object"&&m!==null&&m.type===Bt&&m.key===null&&(m=m.props.children),typeof m=="object"&&m!==null){switch(m.$$typeof){case cr:e:{for(var S=m.key,E=d;E!==null;){if(E.key===S){if(S=m.type,S===Bt){if(E.tag===7){n(f,E.sibling),d=l(E,m.props.children),d.return=f,f=d;break e}}else if(E.elementType===S||typeof S=="object"&&S!==null&&S.$$typeof===rt&&Ro(S)===E.type){n(f,E.sibling),d=l(E,m.props),d.ref=Sn(f,E,m),d.return=f,f=d;break e}n(f,E);break}else t(f,E);E=E.sibling}m.type===Bt?(d=Tt(m.props.children,f.mode,x,m.key),d.return=f,f=d):(x=Ar(m.type,m.key,m.props,null,f.mode,x),x.ref=Sn(f,d,m),x.return=f,f=x)}return o(f);case At:e:{for(E=m.key;d!==null;){if(d.key===E)if(d.tag===4&&d.stateNode.containerInfo===m.containerInfo&&d.stateNode.implementation===m.implementation){n(f,d.sibling),d=l(d,m.children||[]),d.return=f,f=d;break e}else{n(f,d);break}else t(f,d);d=d.sibling}d=ts(m,f.mode,x),d.return=f,f=d}return o(f);case rt:return E=m._init,T(f,d,E(m._payload),x)}if(_n(m))return w(f,d,m,x);if(yn(m))return y(f,d,m,x);jr(f,m)}return typeof m=="string"&&m!==""||typeof m=="number"?(m=""+m,d!==null&&d.tag===6?(n(f,d.sibling),d=l(d,m),d.return=f,f=d):(n(f,d),d=es(m,f.mode,x),d.return=f,f=d),o(f)):n(f,d)}return T}var un=Su(!0),Nu=Su(!1),el=jt(null),tl=null,Xt=null,ji=null;function ki(){ji=Xt=tl=null}function Si(e){var t=el.current;B(el),e._currentValue=t}function Ms(e,t,n){for(;e!==null;){var r=e.alternate;if((e.childLanes&t)!==t?(e.childLanes|=t,r!==null&&(r.childLanes|=t)):r!==null&&(r.childLanes&t)!==t&&(r.childLanes|=t),e===n)break;e=e.return}}function nn(e,t){tl=e,ji=Xt=null,e=e.dependencies,e!==null&&e.firstContext!==null&&(e.lanes&t&&(ve=!0),e.firstContext=null)}function Te(e){var t=e._currentValue;if(ji!==e)if(e={context:e,memoizedValue:t,next:null},Xt===null){if(tl===null)throw Error(j(308));Xt=e,tl.dependencies={lanes:0,firstContext:e}}else Xt=Xt.next=e;return t}var Pt=null;function Ni(e){Pt===null?Pt=[e]:Pt.push(e)}function Cu(e,t,n,r){var l=t.interleaved;return l===null?(n.next=n,Ni(t)):(n.next=l.next,l.next=n),t.interleaved=n,qe(e,r)}function qe(e,t){e.lanes|=t;var n=e.alternate;for(n!==null&&(n.lanes|=t),n=e,e=e.return;e!==null;)e.childLanes|=t,n=e.alternate,n!==null&&(n.childLanes|=t),n=e,e=e.return;return n.tag===3?n.stateNode:null}var lt=!1;function Ci(e){e.updateQueue={baseState:e.memoizedState,firstBaseUpdate:null,lastBaseUpdate:null,shared:{pending:null,interleaved:null,lanes:0},effects:null}}function Eu(e,t){e=e.updateQueue,t.updateQueue===e&&(t.updateQueue={baseState:e.baseState,firstBaseUpdate:e.firstBaseUpdate,lastBaseUpdate:e.lastBaseUpdate,shared:e.shared,effects:e.effects})}function Xe(e,t){return{eventTime:e,lane:t,tag:0,payload:null,callback:null,next:null}}function pt(e,t,n){var r=e.updateQueue;if(r===null)return null;if(r=r.shared,O&2){var l=r.pending;return l===null?t.next=t:(t.next=l.next,l.next=t),r.pending=t,qe(e,n)}return l=r.interleaved,l===null?(t.next=t,Ni(r)):(t.next=l.next,l.next=t),r.interleaved=t,qe(e,n)}function Dr(e,t,n){if(t=t.updateQueue,t!==null&&(t=t.shared,(n&4194240)!==0)){var r=t.lanes;r&=e.pendingLanes,n|=r,t.lanes=n,ci(e,n)}}function Do(e,t){var n=e.updateQueue,r=e.alternate;if(r!==null&&(r=r.updateQueue,n===r)){var l=null,s=null;if(n=n.firstBaseUpdate,n!==null){do{var o={eventTime:n.eventTime,lane:n.lane,tag:n.tag,payload:n.payload,callback:n.callback,next:null};s===null?l=s=o:s=s.next=o,n=n.next}while(n!==null);s===null?l=s=t:s=s.next=t}else l=s=t;n={baseState:r.baseState,firstBaseUpdate:l,lastBaseUpdate:s,shared:r.shared,effects:r.effects},e.updateQueue=n;return}e=n.lastBaseUpdate,e===null?n.firstBaseUpdate=t:e.next=t,n.lastBaseUpdate=t}function nl(e,t,n,r){var l=e.updateQueue;lt=!1;var s=l.firstBaseUpdate,o=l.lastBaseUpdate,a=l.shared.pending;if(a!==null){l.shared.pending=null;var u=a,c=u.next;u.next=null,o===null?s=c:o.next=c,o=u;var p=e.alternate;p!==null&&(p=p.updateQueue,a=p.lastBaseUpdate,a!==o&&(a===null?p.firstBaseUpdate=c:a.next=c,p.lastBaseUpdate=u))}if(s!==null){var v=l.baseState;o=0,p=c=u=null,a=s;do{var h=a.lane,g=a.eventTime;if((r&h)===h){p!==null&&(p=p.next={eventTime:g,lane:0,tag:a.tag,payload:a.payload,callback:a.callback,next:null});e:{var w=e,y=a;switch(h=t,g=n,y.tag){case 1:if(w=y.payload,typeof w=="function"){v=w.call(g,v,h);break e}v=w;break e;case 3:w.flags=w.flags&-65537|128;case 0:if(w=y.payload,h=typeof w=="function"?w.call(g,v,h):w,h==null)break e;v=K({},v,h);break e;case 2:lt=!0}}a.callback!==null&&a.lane!==0&&(e.flags|=64,h=l.effects,h===null?l.effects=[a]:h.push(a))}else g={eventTime:g,lane:h,tag:a.tag,payload:a.payload,callback:a.callback,next:null},p===null?(c=p=g,u=v):p=p.next=g,o|=h;if(a=a.next,a===null){if(a=l.shared.pending,a===null)break;h=a,a=h.next,h.next=null,l.lastBaseUpdate=h,l.shared.pending=null}}while(!0);if(p===null&&(u=v),l.baseState=u,l.firstBaseUpdate=c,l.lastBaseUpdate=p,t=l.shared.interleaved,t!==null){l=t;do o|=l.lane,l=l.next;while(l!==t)}else s===null&&(l.shared.lanes=0);Ot|=o,e.lanes=o,e.memoizedState=v}}function Oo(e,t,n){if(e=t.effects,t.effects=null,e!==null)for(t=0;tn?n:4,e(!0);var r=Xl.transition;Xl.transition={};try{e(!1),t()}finally{$=n,Xl.transition=r}}function Wu(){return Me().memoizedState}function Pf(e,t,n){var r=mt(e);if(n={lane:r,action:n,hasEagerState:!1,eagerState:null,next:null},Hu(e))Qu(t,n);else if(n=Cu(e,t,n,r),n!==null){var l=de();$e(n,e,r,l),Ku(n,t,r)}}function zf(e,t,n){var r=mt(e),l={lane:r,action:n,hasEagerState:!1,eagerState:null,next:null};if(Hu(e))Qu(t,l);else{var s=e.alternate;if(e.lanes===0&&(s===null||s.lanes===0)&&(s=t.lastRenderedReducer,s!==null))try{var o=t.lastRenderedState,a=s(o,n);if(l.hasEagerState=!0,l.eagerState=a,Ue(a,o)){var u=t.interleaved;u===null?(l.next=l,Ni(t)):(l.next=u.next,u.next=l),t.interleaved=l;return}}catch{}finally{}n=Cu(e,t,l,r),n!==null&&(l=de(),$e(n,e,r,l),Ku(n,t,r))}}function Hu(e){var t=e.alternate;return e===Q||t!==null&&t===Q}function Qu(e,t){On=ll=!0;var n=e.pending;n===null?t.next=t:(t.next=n.next,n.next=t),e.pending=t}function Ku(e,t,n){if(n&4194240){var r=t.lanes;r&=e.pendingLanes,n|=r,t.lanes=n,ci(e,n)}}var sl={readContext:Te,useCallback:ie,useContext:ie,useEffect:ie,useImperativeHandle:ie,useInsertionEffect:ie,useLayoutEffect:ie,useMemo:ie,useReducer:ie,useRef:ie,useState:ie,useDebugValue:ie,useDeferredValue:ie,useTransition:ie,useMutableSource:ie,useSyncExternalStore:ie,useId:ie,unstable_isNewReconciler:!1},Lf={readContext:Te,useCallback:function(e,t){return Be().memoizedState=[e,t===void 0?null:t],e},useContext:Te,useEffect:Io,useImperativeHandle:function(e,t,n){return n=n!=null?n.concat([e]):null,Fr(4194308,4,$u.bind(null,t,e),n)},useLayoutEffect:function(e,t){return Fr(4194308,4,e,t)},useInsertionEffect:function(e,t){return Fr(4,2,e,t)},useMemo:function(e,t){var n=Be();return t=t===void 0?null:t,e=e(),n.memoizedState=[e,t],e},useReducer:function(e,t,n){var r=Be();return t=n!==void 0?n(t):t,r.memoizedState=r.baseState=t,e={pending:null,interleaved:null,lanes:0,dispatch:null,lastRenderedReducer:e,lastRenderedState:t},r.queue=e,e=e.dispatch=Pf.bind(null,Q,e),[r.memoizedState,e]},useRef:function(e){var t=Be();return e={current:e},t.memoizedState=e},useState:Fo,useDebugValue:Ri,useDeferredValue:function(e){return Be().memoizedState=e},useTransition:function(){var e=Fo(!1),t=e[0];return e=_f.bind(null,e[1]),Be().memoizedState=e,[t,e]},useMutableSource:function(){},useSyncExternalStore:function(e,t,n){var r=Q,l=Be();if(W){if(n===void 0)throw Error(j(407));n=n()}else{if(n=t(),ne===null)throw Error(j(349));Dt&30||Lu(r,t,n)}l.memoizedState=n;var s={value:n,getSnapshot:t};return l.queue=s,Io(Mu.bind(null,r,s,e),[e]),r.flags|=2048,er(9,Tu.bind(null,r,s,n,t),void 0,null),n},useId:function(){var e=Be(),t=ne.identifierPrefix;if(W){var n=Ge,r=Ye;n=(r&~(1<<32-Ie(r)-1)).toString(32)+n,t=":"+t+"R"+n,n=qn++,0<\/script>",e=e.removeChild(e.firstChild)):typeof r.is=="string"?e=o.createElement(n,{is:r.is}):(e=o.createElement(n),n==="select"&&(o=e,r.multiple?o.multiple=!0:r.size&&(o.size=r.size))):e=o.createElementNS(e,n),e[Ve]=t,e[Xn]=r,nc(e,t,!1,!1),t.stateNode=e;e:{switch(o=hs(n,r),n){case"dialog":A("cancel",e),A("close",e),l=r;break;case"iframe":case"object":case"embed":A("load",e),l=r;break;case"video":case"audio":for(l=0;lfn&&(t.flags|=128,r=!0,Nn(s,!1),t.lanes=4194304)}else{if(!r)if(e=rl(o),e!==null){if(t.flags|=128,r=!0,n=e.updateQueue,n!==null&&(t.updateQueue=n,t.flags|=4),Nn(s,!0),s.tail===null&&s.tailMode==="hidden"&&!o.alternate&&!W)return oe(t),null}else 2*X()-s.renderingStartTime>fn&&n!==1073741824&&(t.flags|=128,r=!0,Nn(s,!1),t.lanes=4194304);s.isBackwards?(o.sibling=t.child,t.child=o):(n=s.last,n!==null?n.sibling=o:t.child=o,s.last=o)}return s.tail!==null?(t=s.tail,s.rendering=t,s.tail=t.sibling,s.renderingStartTime=X(),t.sibling=null,n=H.current,U(H,r?n&1|2:n&1),t):(oe(t),null);case 22:case 23:return Ui(),r=t.memoizedState!==null,e!==null&&e.memoizedState!==null!==r&&(t.flags|=8192),r&&t.mode&1?we&1073741824&&(oe(t),t.subtreeFlags&6&&(t.flags|=8192)):oe(t),null;case 24:return null;case 25:return null}throw Error(j(156,t.tag))}function $f(e,t){switch(xi(t),t.tag){case 1:return ye(t.type)&&Zr(),e=t.flags,e&65536?(t.flags=e&-65537|128,t):null;case 3:return cn(),B(ge),B(ue),Pi(),e=t.flags,e&65536&&!(e&128)?(t.flags=e&-65537|128,t):null;case 5:return _i(t),null;case 13:if(B(H),e=t.memoizedState,e!==null&&e.dehydrated!==null){if(t.alternate===null)throw Error(j(340));an()}return e=t.flags,e&65536?(t.flags=e&-65537|128,t):null;case 19:return B(H),null;case 4:return cn(),null;case 10:return Si(t.type._context),null;case 22:case 23:return Ui(),null;case 24:return null;default:return null}}var Sr=!1,ae=!1,Uf=typeof WeakSet=="function"?WeakSet:Set,N=null;function Zt(e,t){var n=e.ref;if(n!==null)if(typeof n=="function")try{n(null)}catch(r){Y(e,t,r)}else n.current=null}function Bs(e,t,n){try{n()}catch(r){Y(e,t,r)}}var Go=!1;function Af(e,t){if(Ns=Kr,e=uu(),gi(e)){if("selectionStart"in e)var n={start:e.selectionStart,end:e.selectionEnd};else e:{n=(n=e.ownerDocument)&&n.defaultView||window;var r=n.getSelection&&n.getSelection();if(r&&r.rangeCount!==0){n=r.anchorNode;var l=r.anchorOffset,s=r.focusNode;r=r.focusOffset;try{n.nodeType,s.nodeType}catch{n=null;break e}var o=0,a=-1,u=-1,c=0,p=0,v=e,h=null;t:for(;;){for(var g;v!==n||l!==0&&v.nodeType!==3||(a=o+l),v!==s||r!==0&&v.nodeType!==3||(u=o+r),v.nodeType===3&&(o+=v.nodeValue.length),(g=v.firstChild)!==null;)h=v,v=g;for(;;){if(v===e)break t;if(h===n&&++c===l&&(a=o),h===s&&++p===r&&(u=o),(g=v.nextSibling)!==null)break;v=h,h=v.parentNode}v=g}n=a===-1||u===-1?null:{start:a,end:u}}else n=null}n=n||{start:0,end:0}}else n=null;for(Cs={focusedElem:e,selectionRange:n},Kr=!1,N=t;N!==null;)if(t=N,e=t.child,(t.subtreeFlags&1028)!==0&&e!==null)e.return=t,N=e;else for(;N!==null;){t=N;try{var w=t.alternate;if(t.flags&1024)switch(t.tag){case 0:case 11:case 15:break;case 1:if(w!==null){var y=w.memoizedProps,T=w.memoizedState,f=t.stateNode,d=f.getSnapshotBeforeUpdate(t.elementType===t.type?y:De(t.type,y),T);f.__reactInternalSnapshotBeforeUpdate=d}break;case 3:var m=t.stateNode.containerInfo;m.nodeType===1?m.textContent="":m.nodeType===9&&m.documentElement&&m.removeChild(m.documentElement);break;case 5:case 6:case 4:case 17:break;default:throw Error(j(163))}}catch(x){Y(t,t.return,x)}if(e=t.sibling,e!==null){e.return=t.return,N=e;break}N=t.return}return w=Go,Go=!1,w}function Fn(e,t,n){var r=t.updateQueue;if(r=r!==null?r.lastEffect:null,r!==null){var l=r=r.next;do{if((l.tag&e)===e){var s=l.destroy;l.destroy=void 0,s!==void 0&&Bs(t,n,s)}l=l.next}while(l!==r)}}function wl(e,t){if(t=t.updateQueue,t=t!==null?t.lastEffect:null,t!==null){var n=t=t.next;do{if((n.tag&e)===e){var r=n.create;n.destroy=r()}n=n.next}while(n!==t)}}function Vs(e){var t=e.ref;if(t!==null){var n=e.stateNode;switch(e.tag){case 5:e=n;break;default:e=n}typeof t=="function"?t(e):t.current=e}}function sc(e){var t=e.alternate;t!==null&&(e.alternate=null,sc(t)),e.child=null,e.deletions=null,e.sibling=null,e.tag===5&&(t=e.stateNode,t!==null&&(delete t[Ve],delete t[Xn],delete t[Ps],delete t[kf],delete t[Sf])),e.stateNode=null,e.return=null,e.dependencies=null,e.memoizedProps=null,e.memoizedState=null,e.pendingProps=null,e.stateNode=null,e.updateQueue=null}function ic(e){return e.tag===5||e.tag===3||e.tag===4}function Xo(e){e:for(;;){for(;e.sibling===null;){if(e.return===null||ic(e.return))return null;e=e.return}for(e.sibling.return=e.return,e=e.sibling;e.tag!==5&&e.tag!==6&&e.tag!==18;){if(e.flags&2||e.child===null||e.tag===4)continue e;e.child.return=e,e=e.child}if(!(e.flags&2))return e.stateNode}}function Ws(e,t,n){var r=e.tag;if(r===5||r===6)e=e.stateNode,t?n.nodeType===8?n.parentNode.insertBefore(e,t):n.insertBefore(e,t):(n.nodeType===8?(t=n.parentNode,t.insertBefore(e,n)):(t=n,t.appendChild(e)),n=n._reactRootContainer,n!=null||t.onclick!==null||(t.onclick=Xr));else if(r!==4&&(e=e.child,e!==null))for(Ws(e,t,n),e=e.sibling;e!==null;)Ws(e,t,n),e=e.sibling}function Hs(e,t,n){var r=e.tag;if(r===5||r===6)e=e.stateNode,t?n.insertBefore(e,t):n.appendChild(e);else if(r!==4&&(e=e.child,e!==null))for(Hs(e,t,n),e=e.sibling;e!==null;)Hs(e,t,n),e=e.sibling}var re=null,Oe=!1;function nt(e,t,n){for(n=n.child;n!==null;)oc(e,t,n),n=n.sibling}function oc(e,t,n){if(We&&typeof We.onCommitFiberUnmount=="function")try{We.onCommitFiberUnmount(fl,n)}catch{}switch(n.tag){case 5:ae||Zt(n,t);case 6:var r=re,l=Oe;re=null,nt(e,t,n),re=r,Oe=l,re!==null&&(Oe?(e=re,n=n.stateNode,e.nodeType===8?e.parentNode.removeChild(n):e.removeChild(n)):re.removeChild(n.stateNode));break;case 18:re!==null&&(Oe?(e=re,n=n.stateNode,e.nodeType===8?Kl(e.parentNode,n):e.nodeType===1&&Kl(e,n),Hn(e)):Kl(re,n.stateNode));break;case 4:r=re,l=Oe,re=n.stateNode.containerInfo,Oe=!0,nt(e,t,n),re=r,Oe=l;break;case 0:case 11:case 14:case 15:if(!ae&&(r=n.updateQueue,r!==null&&(r=r.lastEffect,r!==null))){l=r=r.next;do{var s=l,o=s.destroy;s=s.tag,o!==void 0&&(s&2||s&4)&&Bs(n,t,o),l=l.next}while(l!==r)}nt(e,t,n);break;case 1:if(!ae&&(Zt(n,t),r=n.stateNode,typeof r.componentWillUnmount=="function"))try{r.props=n.memoizedProps,r.state=n.memoizedState,r.componentWillUnmount()}catch(a){Y(n,t,a)}nt(e,t,n);break;case 21:nt(e,t,n);break;case 22:n.mode&1?(ae=(r=ae)||n.memoizedState!==null,nt(e,t,n),ae=r):nt(e,t,n);break;default:nt(e,t,n)}}function Zo(e){var t=e.updateQueue;if(t!==null){e.updateQueue=null;var n=e.stateNode;n===null&&(n=e.stateNode=new Uf),t.forEach(function(r){var l=Xf.bind(null,e,r);n.has(r)||(n.add(r),r.then(l,l))})}}function Re(e,t){var n=t.deletions;if(n!==null)for(var r=0;rl&&(l=o),r&=~s}if(r=l,r=X()-r,r=(120>r?120:480>r?480:1080>r?1080:1920>r?1920:3e3>r?3e3:4320>r?4320:1960*Vf(r/1960))-r,10e?16:e,at===null)var r=!1;else{if(e=at,at=null,al=0,O&6)throw Error(j(331));var l=O;for(O|=4,N=e.current;N!==null;){var s=N,o=s.child;if(N.flags&16){var a=s.deletions;if(a!==null){for(var u=0;uX()-Ii?Lt(e,0):Fi|=n),xe(e,t)}function mc(e,t){t===0&&(e.mode&1?(t=hr,hr<<=1,!(hr&130023424)&&(hr=4194304)):t=1);var n=de();e=qe(e,t),e!==null&&(rr(e,t,n),xe(e,n))}function Gf(e){var t=e.memoizedState,n=0;t!==null&&(n=t.retryLane),mc(e,n)}function Xf(e,t){var n=0;switch(e.tag){case 13:var r=e.stateNode,l=e.memoizedState;l!==null&&(n=l.retryLane);break;case 19:r=e.stateNode;break;default:throw Error(j(314))}r!==null&&r.delete(t),mc(e,n)}var vc;vc=function(e,t,n){if(e!==null)if(e.memoizedProps!==t.pendingProps||ge.current)ve=!0;else{if(!(e.lanes&n)&&!(t.flags&128))return ve=!1,Ff(e,t,n);ve=!!(e.flags&131072)}else ve=!1,W&&t.flags&1048576&&wu(t,br,t.index);switch(t.lanes=0,t.tag){case 2:var r=t.type;Ir(e,t),e=t.pendingProps;var l=on(t,ue.current);nn(t,n),l=Li(null,t,r,e,l,n);var s=Ti();return t.flags|=1,typeof l=="object"&&l!==null&&typeof l.render=="function"&&l.$$typeof===void 0?(t.tag=1,t.memoizedState=null,t.updateQueue=null,ye(r)?(s=!0,Jr(t)):s=!1,t.memoizedState=l.state!==null&&l.state!==void 0?l.state:null,Ci(t),l.updater=xl,t.stateNode=l,l._reactInternals=t,Ds(t,r,e,n),t=Is(null,t,r,!0,s,n)):(t.tag=0,W&&s&&yi(t),ce(null,t,l,n),t=t.child),t;case 16:r=t.elementType;e:{switch(Ir(e,t),e=t.pendingProps,l=r._init,r=l(r._payload),t.type=r,l=t.tag=Jf(r),e=De(r,e),l){case 0:t=Fs(null,t,r,e,n);break e;case 1:t=Qo(null,t,r,e,n);break e;case 11:t=Wo(null,t,r,e,n);break e;case 14:t=Ho(null,t,r,De(r.type,e),n);break e}throw Error(j(306,r,""))}return t;case 0:return r=t.type,l=t.pendingProps,l=t.elementType===r?l:De(r,l),Fs(e,t,r,l,n);case 1:return r=t.type,l=t.pendingProps,l=t.elementType===r?l:De(r,l),Qo(e,t,r,l,n);case 3:e:{if(bu(t),e===null)throw Error(j(387));r=t.pendingProps,s=t.memoizedState,l=s.element,Eu(e,t),nl(t,r,null,n);var o=t.memoizedState;if(r=o.element,s.isDehydrated)if(s={element:r,isDehydrated:!1,cache:o.cache,pendingSuspenseBoundaries:o.pendingSuspenseBoundaries,transitions:o.transitions},t.updateQueue.baseState=s,t.memoizedState=s,t.flags&256){l=dn(Error(j(423)),t),t=Ko(e,t,r,n,l);break e}else if(r!==l){l=dn(Error(j(424)),t),t=Ko(e,t,r,n,l);break e}else for(je=ft(t.stateNode.containerInfo.firstChild),ke=t,W=!0,Fe=null,n=Nu(t,null,r,n),t.child=n;n;)n.flags=n.flags&-3|4096,n=n.sibling;else{if(an(),r===l){t=be(e,t,n);break e}ce(e,t,r,n)}t=t.child}return t;case 5:return _u(t),e===null&&Ts(t),r=t.type,l=t.pendingProps,s=e!==null?e.memoizedProps:null,o=l.children,Es(r,l)?o=null:s!==null&&Es(r,s)&&(t.flags|=32),qu(e,t),ce(e,t,o,n),t.child;case 6:return e===null&&Ts(t),null;case 13:return ec(e,t,n);case 4:return Ei(t,t.stateNode.containerInfo),r=t.pendingProps,e===null?t.child=un(t,null,r,n):ce(e,t,r,n),t.child;case 11:return r=t.type,l=t.pendingProps,l=t.elementType===r?l:De(r,l),Wo(e,t,r,l,n);case 7:return ce(e,t,t.pendingProps,n),t.child;case 8:return ce(e,t,t.pendingProps.children,n),t.child;case 12:return ce(e,t,t.pendingProps.children,n),t.child;case 10:e:{if(r=t.type._context,l=t.pendingProps,s=t.memoizedProps,o=l.value,U(el,r._currentValue),r._currentValue=o,s!==null)if(Ue(s.value,o)){if(s.children===l.children&&!ge.current){t=be(e,t,n);break e}}else for(s=t.child,s!==null&&(s.return=t);s!==null;){var a=s.dependencies;if(a!==null){o=s.child;for(var u=a.firstContext;u!==null;){if(u.context===r){if(s.tag===1){u=Xe(-1,n&-n),u.tag=2;var c=s.updateQueue;if(c!==null){c=c.shared;var p=c.pending;p===null?u.next=u:(u.next=p.next,p.next=u),c.pending=u}}s.lanes|=n,u=s.alternate,u!==null&&(u.lanes|=n),Ms(s.return,n,t),a.lanes|=n;break}u=u.next}}else if(s.tag===10)o=s.type===t.type?null:s.child;else if(s.tag===18){if(o=s.return,o===null)throw Error(j(341));o.lanes|=n,a=o.alternate,a!==null&&(a.lanes|=n),Ms(o,n,t),o=s.sibling}else o=s.child;if(o!==null)o.return=s;else for(o=s;o!==null;){if(o===t){o=null;break}if(s=o.sibling,s!==null){s.return=o.return,o=s;break}o=o.return}s=o}ce(e,t,l.children,n),t=t.child}return t;case 9:return l=t.type,r=t.pendingProps.children,nn(t,n),l=Te(l),r=r(l),t.flags|=1,ce(e,t,r,n),t.child;case 14:return r=t.type,l=De(r,t.pendingProps),l=De(r.type,l),Ho(e,t,r,l,n);case 15:return Zu(e,t,t.type,t.pendingProps,n);case 17:return r=t.type,l=t.pendingProps,l=t.elementType===r?l:De(r,l),Ir(e,t),t.tag=1,ye(r)?(e=!0,Jr(t)):e=!1,nn(t,n),Yu(t,r,l),Ds(t,r,l,n),Is(null,t,r,!0,e,n);case 19:return tc(e,t,n);case 22:return Ju(e,t,n)}throw Error(j(156,t.tag))};function gc(e,t){return Ha(e,t)}function Zf(e,t,n,r){this.tag=e,this.key=n,this.sibling=this.child=this.return=this.stateNode=this.type=this.elementType=null,this.index=0,this.ref=null,this.pendingProps=t,this.dependencies=this.memoizedState=this.updateQueue=this.memoizedProps=null,this.mode=r,this.subtreeFlags=this.flags=0,this.deletions=null,this.childLanes=this.lanes=0,this.alternate=null}function ze(e,t,n,r){return new Zf(e,t,n,r)}function Bi(e){return e=e.prototype,!(!e||!e.isReactComponent)}function Jf(e){if(typeof e=="function")return Bi(e)?1:0;if(e!=null){if(e=e.$$typeof,e===ii)return 11;if(e===oi)return 14}return 2}function vt(e,t){var n=e.alternate;return n===null?(n=ze(e.tag,t,e.key,e.mode),n.elementType=e.elementType,n.type=e.type,n.stateNode=e.stateNode,n.alternate=e,e.alternate=n):(n.pendingProps=t,n.type=e.type,n.flags=0,n.subtreeFlags=0,n.deletions=null),n.flags=e.flags&14680064,n.childLanes=e.childLanes,n.lanes=e.lanes,n.child=e.child,n.memoizedProps=e.memoizedProps,n.memoizedState=e.memoizedState,n.updateQueue=e.updateQueue,t=e.dependencies,n.dependencies=t===null?null:{lanes:t.lanes,firstContext:t.firstContext},n.sibling=e.sibling,n.index=e.index,n.ref=e.ref,n}function Ar(e,t,n,r,l,s){var o=2;if(r=e,typeof e=="function")Bi(e)&&(o=1);else if(typeof e=="string")o=5;else e:switch(e){case Bt:return Tt(n.children,l,s,t);case si:o=8,l|=8;break;case ls:return e=ze(12,n,t,l|2),e.elementType=ls,e.lanes=s,e;case ss:return e=ze(13,n,t,l),e.elementType=ss,e.lanes=s,e;case is:return e=ze(19,n,t,l),e.elementType=is,e.lanes=s,e;case _a:return kl(n,l,s,t);default:if(typeof e=="object"&&e!==null)switch(e.$$typeof){case Ca:o=10;break e;case Ea:o=9;break e;case ii:o=11;break e;case oi:o=14;break e;case rt:o=16,r=null;break e}throw Error(j(130,e==null?e:typeof e,""))}return t=ze(o,n,t,l),t.elementType=e,t.type=r,t.lanes=s,t}function Tt(e,t,n,r){return e=ze(7,e,r,t),e.lanes=n,e}function kl(e,t,n,r){return e=ze(22,e,r,t),e.elementType=_a,e.lanes=n,e.stateNode={isHidden:!1},e}function es(e,t,n){return e=ze(6,e,null,t),e.lanes=n,e}function ts(e,t,n){return t=ze(4,e.children!==null?e.children:[],e.key,t),t.lanes=n,t.stateNode={containerInfo:e.containerInfo,pendingChildren:null,implementation:e.implementation},t}function qf(e,t,n,r,l){this.tag=t,this.containerInfo=e,this.finishedWork=this.pingCache=this.current=this.pendingChildren=null,this.timeoutHandle=-1,this.callbackNode=this.pendingContext=this.context=null,this.callbackPriority=0,this.eventTimes=Ol(0),this.expirationTimes=Ol(-1),this.entangledLanes=this.finishedLanes=this.mutableReadLanes=this.expiredLanes=this.pingedLanes=this.suspendedLanes=this.pendingLanes=0,this.entanglements=Ol(0),this.identifierPrefix=r,this.onRecoverableError=l,this.mutableSourceEagerHydrationData=null}function Vi(e,t,n,r,l,s,o,a,u){return e=new qf(e,t,n,a,u),t===1?(t=1,s===!0&&(t|=8)):t=0,s=ze(3,null,null,t),e.current=s,s.stateNode=e,s.memoizedState={element:r,isDehydrated:n,cache:null,transitions:null,pendingSuspenseBoundaries:null},Ci(s),e}function bf(e,t,n){var r=3"u"||typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE!="function"))try{__REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE(jc)}catch(e){console.error(e)}}jc(),ja.exports=Ce;var lp=ja.exports,kc,la=lp;kc=la.createRoot,la.hydrateRoot;const Sc=()=>{var e,t;return(t=(e=window==null?void 0:window.go)==null?void 0:e.main)==null?void 0:t.App},sp=()=>!!Sc();async function F(e,...t){const n=Sc();if(!n||typeof n[e]!="function")throw new Error(`${e} is unavailable — run this inside the Behavision app`);return n[e](...t)}const I={session:()=>F("Session"),login:(e,t)=>F("Login",e,t),logout:()=>F("Logout"),claim:e=>F("Claim",e),runStandalone:()=>F("RunStandalone"),engineStatus:()=>F("EngineStatus"),startEngine:()=>F("StartEngine"),stopEngine:()=>F("StopEngine"),cameras:()=>F("Cameras"),testCamera:e=>F("TestCamera",e),discoverCameras:()=>F("DiscoverCameras"),saveCamera:(e,t)=>F("SaveCamera",e,t),deleteCamera:e=>F("DeleteCamera",e),startPlacement:(e,t)=>F("StartPlacementCheck",e,t),placementResult:e=>F("PlacementResult",e),streamURL:e=>F("StreamURL",e),remoteStreamURL:e=>F("RemoteStreamURL",e),live:()=>F("Live"),pipelineStatus:()=>F("PipelineStatus"),localIdentities:e=>F("LocalIdentities",e),localSightings:e=>F("LocalSightings",e),footfall:(e,t,n)=>F("Footfall",e,t,n),sites:()=>F("Sites"),visitorHistory:(e,t)=>F("VisitorHistory",e,t),visitorPhoto:e=>F("VisitorPhoto",e),forgetCustomer:e=>F("ForgetCustomer",e),sales:(e,t)=>F("Sales",e,t),customers:(e,t)=>F("Customers",e,t),saveProfile:e=>F("SaveProfile",e),ask:e=>F("Ask",e),recordPurchase:(e,t,n,r)=>F("RecordPurchase",e,t,n,r)};function fe(e){return e?typeof e=="string"?e:e.message||String(e):"Something went wrong."}function et(e,t,n=[]){const[r,l]=C.useState(null),[s,o]=C.useState(null),[a,u]=C.useState(!0),c=C.useRef(!0),p=C.useRef(!1),v=C.useCallback(async()=>{if(!p.current){p.current=!0;try{const h=await e();if(!c.current)return;l(h),o(null)}catch(h){c.current&&o(fe(h))}finally{p.current=!1,c.current&&u(!1)}}},n);return C.useEffect(()=>{if(c.current=!0,v(),!t)return()=>{c.current=!1};const h=setInterval(v,t);return()=>{c.current=!1,clearInterval(h)}},[v,t]),{data:r,error:s,loading:a,reload:v}}function ip(e){if(!e)return"—";const t=typeof e=="number"?new Date(e*1e3):new Date(e);return isNaN(t)?"—":t.toLocaleTimeString([],{hour:"2-digit",minute:"2-digit"})}function sa(e){if(!e)return"—";const t=typeof e=="number"?new Date(e*1e3):new Date(e);return isNaN(t)?"—":t.toLocaleDateString([],{day:"numeric",month:"short"})}const ns={width:18,height:18,viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:1.6,strokeLinecap:"round",strokeLinejoin:"round","aria-hidden":"true",focusable:"false"};function J({size:e,children:t,...n}){return i.jsx("svg",{...ns,...n,width:e??ns.width,height:e??ns.height,children:t})}const op=e=>i.jsxs(J,{...e,children:[i.jsx("circle",{cx:"12",cy:"12",r:"3.2"}),i.jsx("path",{d:"M5.6 5.6a9 9 0 0 0 0 12.8M18.4 18.4a9 9 0 0 0 0-12.8"})]}),ap=e=>i.jsxs(J,{...e,children:[i.jsx("circle",{cx:"9",cy:"8.5",r:"3.2"}),i.jsx("path",{d:"M2.8 19.5a6.4 6.4 0 0 1 12.4 0"}),i.jsx("path",{d:"M16.5 6.2a3.2 3.2 0 0 1 0 6.1M18 19.5a6 6 0 0 0-1.6-4"})]}),up=e=>i.jsxs(J,{...e,children:[i.jsx("path",{d:"M3 8.5h3.4L8 6h8l1.6 2.5H21v10.2H3z"}),i.jsx("circle",{cx:"12",cy:"13.2",r:"3.1"})]}),Nc=e=>i.jsxs(J,{...e,children:[i.jsx("circle",{cx:"11",cy:"11",r:"6.4"}),i.jsx("path",{d:"M15.8 15.8 20.5 20.5"})]}),ia=e=>i.jsx(J,{...e,children:i.jsx("path",{d:"M12 5.5v13M5.5 12h13"})}),Ki=e=>i.jsx(J,{...e,children:i.jsx("path",{d:"M6.5 6.5l11 11M17.5 6.5l-11 11"})}),Xs=e=>i.jsx(J,{...e,children:i.jsx("path",{d:"M5 12.8l4.4 4.2L19 7"})}),Zs=e=>i.jsx(J,{...e,children:i.jsx("path",{d:"M8 5.6v12.8L18.5 12z"})}),cp=e=>i.jsx(J,{...e,children:i.jsx("rect",{x:"7",y:"7",width:"10",height:"10",rx:"1.6"})}),Se=e=>i.jsxs(J,{...e,children:[i.jsx("path",{d:"M12 4.6 21 19.4H3z"}),i.jsx("path",{d:"M12 10v4.1"}),i.jsx("path",{d:"M12 17.1v.01"})]}),oa=e=>i.jsx(J,{...e,children:i.jsx("path",{d:"M5 19.4v-4.2M10.3 19.4v-7.6M15.7 19.4v-11M21 19.4V4.6"})}),Yi=e=>i.jsx(J,{...e,children:i.jsx("path",{d:"M7.2 18.4a4.2 4.2 0 0 1-.6-8.35A6.2 6.2 0 0 1 18.4 9a4.2 4.2 0 0 1 .3 9.4z"})}),Cc=e=>i.jsxs(J,{...e,children:[i.jsx("path",{d:"M7.2 18.4a4.2 4.2 0 0 1-.6-8.35 6.2 6.2 0 0 1 2-3.2M10.6 5.2A6.2 6.2 0 0 1 18.4 9a4.2 4.2 0 0 1 1.9 7.6"}),i.jsx("path",{d:"M3.6 3.6l16.8 16.8"})]}),dp=e=>i.jsx(J,{...e,children:i.jsx("path",{d:"M12 3.8 19.4 6.6v5.2c0 4.2-3 7.4-7.4 8.4-4.4-1-7.4-4.2-7.4-8.4V6.6z"})}),fp=e=>i.jsxs(J,{...e,children:[i.jsx("path",{d:"M10.2 13.8a3.6 3.6 0 0 0 5.2 0l2.8-2.8a3.7 3.7 0 0 0-5.2-5.2l-1.3 1.3"}),i.jsx("path",{d:"M13.8 10.2a3.6 3.6 0 0 0-5.2 0l-2.8 2.8a3.7 3.7 0 0 0 5.2 5.2l1.3-1.3"})]}),pp=e=>i.jsxs(J,{...e,children:[i.jsx("path",{d:"M14.4 7.6V5.4H4.6v13.2h9.8v-2.2"}),i.jsx("path",{d:"M10 12h9.4M16.4 8.8 19.8 12l-3.4 3.2"})]}),aa=e=>i.jsx(J,{...e,children:i.jsx("path",{d:"M14.6 5.6 8 12l6.6 6.4"})}),hp=e=>i.jsx(J,{...e,children:i.jsx("path",{d:"M9.4 5.6 16 12l-6.6 6.4"})}),Ec=e=>i.jsxs(J,{...e,strokeWidth:"1.2",children:[i.jsx("path",{d:"M3 8.5h3.4L8 6h8l1.6 2.5H21v10.2H3z"}),i.jsx("circle",{cx:"12",cy:"13.2",r:"3.1"}),i.jsx("path",{d:"M3.6 3.6l16.8 16.8"})]}),_c=e=>i.jsxs(J,{...e,strokeWidth:"1.2",children:[i.jsx("circle",{cx:"12",cy:"9",r:"3.4"}),i.jsx("path",{d:"M5.4 20a6.8 6.8 0 0 1 13.2 0"})]}),gt=""+new URL("loyaly-mark-Ch-P3VSF.png",import.meta.url).href;function mp({onDone:e}){const[t,n]=C.useState(""),[r,l]=C.useState(""),[s,o]=C.useState(!1),[a,u]=C.useState(null);async function c(p){p.preventDefault(),o(!0),u(null);try{e(await I.login(t.trim(),r))}catch(v){u(fe(v))}finally{o(!1)}}return i.jsx("div",{className:"login",children:i.jsxs("div",{className:"box",children:[i.jsx("span",{className:"mark",children:i.jsx("img",{src:gt,alt:""})}),i.jsx("h1",{children:"Behavision"}),i.jsx("p",{className:"lead",children:"Sign in to connect this PC to your store."}),i.jsxs("form",{onSubmit:c,children:[a&&i.jsxs("div",{className:"err",children:[i.jsx(Se,{size:15}),a]}),i.jsxs("label",{className:"field",children:[i.jsx("span",{children:"Email"}),i.jsx("input",{type:"email",value:t,autoComplete:"username",required:!0,autoFocus:!0,onChange:p=>n(p.target.value)})]}),i.jsxs("label",{className:"field",children:[i.jsx("span",{children:"Password"}),i.jsx("input",{type:"password",value:r,autoComplete:"current-password",required:!0,onChange:p=>l(p.target.value)})]}),i.jsx("button",{className:"btn primary",disabled:s||!t||!r,children:s?"Signing in…":"Sign in"})]}),i.jsx("p",{className:"foot",children:"Signing in downloads this store's recognition models and connects it to your account. Nothing is sent until a camera is set up."})]})})}function ua({onDone:e,onCancel:t}){const[n,r]=C.useState(""),[l,s]=C.useState(null),[o,a]=C.useState(null);async function u(h){h.preventDefault(),s("claim"),a(null);try{e(await I.claim(n))}catch(g){a(fe(g))}finally{s(null)}}async function c(){s("alone"),a(null);try{e(await I.runStandalone())}catch(h){a(fe(h))}finally{s(null)}}const[p,v]=C.useState(t?"code":null);return p===null?i.jsx("div",{className:"login",children:i.jsxs("div",{className:"box wide",children:[i.jsx("span",{className:"mark",children:i.jsx("img",{src:gt,alt:""})}),i.jsx("h1",{children:"Welcome to Behavision"}),i.jsx("p",{className:"lead",children:"This PC will watch your shop’s cameras and recognise returning customers. First, one question: is this shop managed from a head office?"}),i.jsxs("div",{className:"choices",children:[i.jsxs("button",{type:"button",className:"choice",onClick:()=>v("code"),children:[i.jsx(Yi,{size:22}),i.jsx("b",{children:"Yes — I have an installation code"}),i.jsxs("span",{children:["Head office gave you a code like ",i.jsx("em",{children:"ABCDEF-123456-…"}),". This PC joins that shop and gets its cameras from there."]})]}),i.jsxs("button",{type:"button",className:"choice",onClick:()=>v("alone"),children:[i.jsx(dp,{size:22}),i.jsx("b",{children:"No — set up on this PC only"}),i.jsx("span",{children:"Cameras, customers and recognition stay on this PC. Nothing is sent anywhere. You can link to a head office later."})]})]})]})}):p==="alone"?i.jsx("div",{className:"login",children:i.jsxs("div",{className:"box",children:[i.jsx("span",{className:"mark",children:i.jsx("img",{src:gt,alt:""})}),i.jsx("h1",{children:"On this PC only"}),i.jsx("p",{className:"lead",children:"Behavision will run entirely here. Next you’ll add your camera — it can find it on the network for you — and walk past it once so it can prove it works."}),o&&i.jsxs("div",{className:"err",children:[i.jsx(Se,{size:15}),o]}),i.jsx("button",{type:"button",className:"btn primary",disabled:!!l,onClick:c,children:l==="alone"?"Setting up…":"Continue"}),i.jsx("div",{className:"alt",children:i.jsxs("button",{type:"button",className:"linkbtn",onClick:()=>v(null),children:[i.jsx(aa,{size:14})," Back"]})})]})}):i.jsx("div",{className:"login",children:i.jsxs("div",{className:"box",children:[i.jsx("span",{className:"mark",children:i.jsx("img",{src:gt,alt:""})}),i.jsx("h1",{children:t?"Link to head office":"Join your shop"}),i.jsx("p",{className:"lead",children:"Type the installation code head office gave you. It works once, and this PC becomes that shop."}),i.jsxs("form",{onSubmit:u,children:[o&&i.jsxs("div",{className:"err",children:[i.jsx(Se,{size:15}),o]}),i.jsxs("label",{className:"field",children:[i.jsx("span",{children:"Installation code"}),i.jsx("input",{value:n,autoFocus:!0,required:!0,placeholder:"ABCDEF-123456-GHIJKL-789012",autoComplete:"off",spellCheck:"false",style:{textTransform:"uppercase",letterSpacing:".06em"},onChange:h=>r(h.target.value)})]}),i.jsx("button",{className:"btn primary",disabled:!!l||n.trim().length<6,children:l==="claim"?"Linking…":"Link this PC"})]}),i.jsxs("p",{className:"foot",children:["Don’t have one? Whoever runs head office creates it under the shop: ",i.jsx("em",{children:"Shops → the shop → Set up a shop PC"}),"."]}),i.jsx("div",{className:"alt",children:t?i.jsx("button",{type:"button",className:"linkbtn",onClick:t,children:"Not now — go back"}):i.jsxs("button",{type:"button",className:"linkbtn",onClick:()=>v(null),children:[i.jsx(aa,{size:14})," Back"]})})]})})}function Pc({onNavigate:e}){var h,g,w,y;const{data:t,error:n}=et(()=>I.live(),3e3),{data:r}=et(()=>I.pipelineStatus(),5e3),l=((h=t==null?void 0:t.stats)==null?void 0:h.cameras)??[],s=((g=t==null?void 0:t.stats)==null?void 0:g.gallery)??{},o=(t==null?void 0:t.events)??[],a=(t==null?void 0:t.viewing)===!0,u=a?((w=t==null?void 0:t.stats)==null?void 0:w.fraction_below_gate)??0:l.reduce((T,f)=>{var m,x;const d=(x=(m=f==null?void 0:f.pipeline)==null?void 0:m.best_quality)==null?void 0:x.fraction_below_gate;return typeof d=="number"&&d>T?d:T},0),c=a?((y=t==null?void 0:t.stats)==null?void 0:y.cameras_up)??0:l.filter(T=>T.connected).length,p=o.filter(T=>T.type==="person.new"||T.type==="person.seen"),v=wp(p[0]);return i.jsxs("div",{className:"page",children:[i.jsxs("header",{children:[i.jsx("h2",{children:"Live"}),i.jsx("p",{children:a?"Your shops, as head office sees them.":"Who is in the shop, and whether it is reaching head office."})]}),n&&i.jsxs("div",{className:"err",children:[i.jsx(Se,{size:15}),n]}),a&&i.jsxs("div",{className:"viewing",children:[i.jsx(Yi,{size:15}),i.jsxs("span",{children:[i.jsx("b",{children:"Viewing your shops from here."})," This computer is not watching any cameras itself — everything below is what your shop PCs reported. To recognise people on this machine, it has to be on the same network as a camera."]})]}),i.jsx(xp,{pipe:r,cameras:l,up:c}),!a&&i.jsx(vp,{cameras:l,arrivals:p,onNavigate:e}),i.jsxs("div",{className:"panel arrivals-panel",children:[i.jsxs("div",{className:"panelhead",children:[i.jsx("h3",{children:"Who just walked in"}),p.length>0&&i.jsxs("span",{className:"note",children:[p.length," today"]})]}),i.jsx("div",{className:"panelbody flush",children:p.length===0?i.jsxs("div",{className:"empty",children:[i.jsx(_c,{size:34}),i.jsx("b",{children:"Nobody yet"}),i.jsx("p",{children:"Customers appear here the moment a camera recognises a face."})]}):i.jsx("div",{className:"arrivals",children:p.slice(0,30).map((T,f)=>i.jsx(gp,{e:T,fresh:f===0&&v},`${T.ts}-${f}`))})})]}),i.jsxs("div",{className:"metrics",style:{marginTop:"var(--sp-4)"},children:[i.jsx(Er,{k:"People known",v:s.identities??"—"}),i.jsx(Er,{k:"Sightings",v:s.sightings??"—"}),i.jsx(Er,{k:"Cameras live",v:l.length?`${c}/${l.length}`:"—",tone:l.length?c===0?"bad":c.5?"bad":u>.2?"warn":"ok",s:u>.5?"Most visitors are being missed — move the camera":"Share of faces below the enrolment gate"})]})]})}function vp({cameras:e,arrivals:t,onNavigate:n}){const{data:r}=et(()=>I.engineStatus(),4e3),[l,s]=C.useState(()=>{try{return localStorage.getItem("bv.gettingStarted")==="done"}catch{return!1}}),o=e.length>0,a=e.some(w=>w.connected),{data:u}=et(async()=>{const w={};for(const y of e)try{w[y.camera_id]=await I.placementResult(y.camera_id)}catch{}return w},1e4,[e.map(w=>w.camera_id).join("|")]),c=Object.values(u??{}).some(w=>w&&!w.running&&w.verdict==="good"),p=t.length>0;if(l||p)return null;const v=!!(r!=null&&r.reachable&&(r!=null&&r.recognition_model)),h=r==null?void 0:r.progress,g=[{done:v,now:!v,title:v?`Recognition ready (${r.recognition_model})`:h?`Downloading ${h.what}… ${h.percent}%`:"Starting recognition…",text:v?null:"First start downloads about 275 MB of recognition models. A few minutes on a normal connection; nothing to do meanwhile."},{done:o&&a,now:v&&!(o&&a),title:o?a?"Camera connected":"Camera added — not connecting yet":"Add your camera",text:o?a?null:"Check its password and stream path under Cameras → Edit.":"Behavision can find it on the network; you type only its password.",action:o?null:{label:"Add camera",go:"cameras"}},{done:c,now:o&&a&&!c,title:c?"Camera proven — it can recognise faces":"Walk past the camera",text:c?null:"Run Check placement and walk past like a customer for 25 seconds. Only a “good” verdict means it will recognise people.",action:o&&a&&!c?{label:"Check placement",go:"cameras"}:null}];return i.jsxs("section",{className:"panel starter",children:[i.jsxs("div",{className:"panelhead",children:[i.jsx("h3",{children:"Getting started"}),i.jsx("button",{className:"btn sm ghost",onClick:()=>{try{localStorage.setItem("bv.gettingStarted","done")}catch{}s(!0)},children:"Hide"})]}),i.jsx("ol",{className:"steps compact",children:g.map((w,y)=>i.jsxs("li",{className:w.done?"done":w.now?"now":"",children:[i.jsx("b",{children:w.title}),w.text&&i.jsx("span",{children:w.text}),w.action&&i.jsx("button",{className:"btn sm primary",onClick:()=>n==null?void 0:n(w.action.go),children:w.action.label})]},y))}),i.jsx("p",{className:"note",children:"The moment a customer is recognised, this list goes away."})]})}function gp({e,fresh:t}){var o,a,u,c,p,v;const n=e.type==="person.new",r=((o=e.data)==null?void 0:o.label)||"Unrecognised",l=[(a=e.data)==null?void 0:a.gender,((u=e.data)==null?void 0:u.age)??((c=e.data)==null?void 0:c.age_range),(p=e.data)==null?void 0:p.emotion].filter(Boolean),s=typeof((v=e.data)==null?void 0:v.similarity)=="number"?e.data.similarity:null;return i.jsxs("article",{className:`arrival ${n?"is-new":"is-seen"} ${t?"fresh":""}`,children:[i.jsx("div",{className:"avatar",children:yp(r)}),i.jsxs("div",{className:"who",children:[i.jsx("div",{className:"name",children:r}),i.jsxs("div",{className:"meta",children:[e.camera_id,l.length>0&&i.jsxs(i.Fragment,{children:[" · ",l.join(", ")]}),s!==null&&!n&&i.jsxs(i.Fragment,{children:[" · match ",s.toFixed(2)]})]})]}),i.jsxs("div",{className:"right",children:[i.jsx("span",{className:`tag ${n?"new":"seen"}`,children:n?"new":"returning"}),i.jsx("span",{className:"when",children:ip(e.ts)})]})]})}function yp(e){var r;const t=/^Visitor (\d+)$/.exec(String(e).trim());if(t)return t[1];const n=String(e).trim().split(/\s+/).filter(Boolean);return n.length?(n[0][0]+(((r=n[1])==null?void 0:r[0])??"")).toUpperCase():"?"}function xp({pipe:e,cameras:t,up:n}){if(!e)return null;if(e.standalone)return i.jsxs("div",{className:"statusbar",children:[i.jsxs("span",{className:"item",children:[i.jsx("i",{className:"dot ok"}),i.jsx("b",{children:"Running on this PC only"})]}),i.jsx("span",{className:"sep"}),i.jsx("span",{className:"item note",children:"Recognition and customers stay here."}),i.jsx("span",{className:"grow"}),i.jsxs("span",{className:"item note",children:[i.jsx(oa,{size:14}),n," of ",t.length," cameras"]})]});const r=e.claimed&&!e.broker_up,l=e.claimed?e.broker_up?"ok":"bad":"idle",s=e.claimed?e.broker_up?"Sending to head office":"Offline — saving locally":"Not linked to head office";return i.jsxs("div",{className:"statusbar",children:[i.jsxs("span",{className:"item",children:[e.broker_up?i.jsx(Yi,{size:15}):i.jsx(Cc,{size:15}),i.jsx("i",{className:`dot ${l}`}),i.jsx("b",{children:s})]}),i.jsx("span",{className:"sep"}),i.jsxs("span",{className:"item note",children:[e.accepted," recorded today"]}),e.queued>0&&i.jsxs("span",{className:`item note ${r?"warn":""}`,children:[e.queued," waiting to send"]}),e.dropped>0&&i.jsxs("span",{className:"item note bad",children:[i.jsx(Se,{size:14}),e.dropped," lost — this PC was offline too long"]}),i.jsx("span",{className:"grow"}),i.jsxs("span",{className:"item note",children:[i.jsx(oa,{size:14}),n," of ",t.length," cameras"]})]})}function Er({k:e,v:t,s:n,tone:r}){return i.jsxs("div",{className:`metric ${r??""}`,children:[i.jsx("div",{className:"metric-k",children:e}),i.jsx("div",{className:"metric-v",children:t}),n&&i.jsx("div",{className:"metric-s",children:n})]})}function wp(e){const[t,n]=C.useState(!1),r=C.useRef(null);return C.useEffect(()=>{if(!e||e.ts===r.current)return;const l=r.current===null;if(r.current=e.ts,l)return;n(!0);const s=setTimeout(()=>n(!1),1200);return()=>clearTimeout(s)},[e==null?void 0:e.ts]),t}function jp(e){const[t,n]=C.useState(null);return C.useEffect(()=>{let r=!0;return n(null),I.visitorPhoto(e).then(l=>{r&&n(l)}).catch(()=>{r&&n({available:!1,reason:""})}),()=>{r=!1}},[e]),t}function kp({photo:e,name:t,customerRef:n,onBroken:r}){return e!=null&&e.available?i.jsx("img",{className:"avatar",src:e.url,alt:`Photo of ${t}`,onError:r}):i.jsx("div",{className:"avatar none",role:"img","aria-label":`No photo of ${t}`,children:i.jsx("span",{children:Sp(t,n)})})}function Sp(e,t){const n=/^Visitor (\d+)$/.exec(String(e||"").trim());if(n)return n[1];const r=/^V-(\d+)$/.exec(String(t||""));return r?r[1]:String(e||"").split(/\s+/).filter(Boolean).slice(0,2).map(l=>l[0].toUpperCase()).join("")||"?"}function Np({customer:e}){const{data:t,error:n,loading:r}=et(()=>I.visitorHistory(e.id,50),0,[e.id]);if(r)return i.jsx("p",{className:"note",children:"Loading visits…"});if(n)return i.jsxs("p",{className:"note",children:["Could not load visits: ",n]});const l=t??[];return l.length===0?i.jsx("p",{className:"note",children:"No recorded visits yet."}):i.jsx("ul",{className:"timeline",children:l.map(s=>i.jsxs("li",{children:[i.jsx("span",{className:"when",children:Cp(s.occurred_at)}),i.jsxs("span",{className:"where",children:[s.site||"this store",s.camera_id?i.jsxs("span",{className:"note",children:[" · ",s.camera_id]}):null]}),s.is_new_visitor&&i.jsx("span",{className:"tag new",children:"first visit"})]},s.id))})}function Cp(e){const t=new Date(e);return isNaN(t)?"—":t.toLocaleString([],{day:"numeric",month:"short",hour:"2-digit",minute:"2-digit"})}function Ep({customer:e,onCancel:t,onDone:n}){const r=e.full_name||e.label,[l,s]=C.useState(""),[o,a]=C.useState(!1),[u,c]=C.useState(null),p=l.trim().toLowerCase()===r.trim().toLowerCase();async function v(){a(!0),c(null);try{await I.forgetCustomer(e.id),n()}catch(h){c(fe(h)),a(!1)}}return i.jsxs("div",{className:"confirm",children:[i.jsxs("h4",{children:["Erase ",r,"?"]}),i.jsxs("div",{className:"cols",children:[i.jsxs("div",{children:[i.jsx("p",{className:"lbl bad",children:"Deleted for good"}),i.jsxs("ul",{children:[i.jsx("li",{children:"Their face data — they will not be recognised again"}),i.jsx("li",{children:"Their photo"}),i.jsx("li",{children:"Their name, phone, email and notes"})]})]}),i.jsxs("div",{children:[i.jsx("p",{className:"lbl",children:"Kept"}),i.jsxs("ul",{children:[i.jsx("li",{children:"Past visits, with their name removed — your footfall figures do not change"}),i.jsx("li",{children:"The consent record, marked withdrawn, as proof of what was agreed"})]})]})]}),i.jsx("p",{className:"note",children:"This cannot be undone. If they come back they will be recorded as a new customer."}),u&&i.jsx("div",{className:"err",children:u}),i.jsxs("label",{className:"field",children:[i.jsxs("span",{children:["Type ",i.jsx("b",{children:r})," to confirm"]}),i.jsx("input",{value:l,onChange:h=>s(h.target.value),autoFocus:!0,autoComplete:"off",spellCheck:"false","aria-label":`Type ${r} to confirm erasure`})]}),i.jsxs("div",{className:"row",children:[i.jsx("button",{type:"button",className:"btn danger",disabled:!p||o,onClick:v,children:o?"Erasing…":"Erase permanently"}),i.jsx("button",{type:"button",className:"btn",onClick:t,disabled:o,children:"Cancel"})]})]})}function _p({customer:e,session:t,onClose:n,onSaved:r}){var E;const[l,s]=C.useState({full_name:e.full_name??"",phone:e.phone??"",email:e.email??"",gender:"",date_of_birth:"",notes:"",consent:e.has_consent??!1}),[o,a]=C.useState({amount:"",items:"",notes:""}),[u,c]=C.useState(!1),[p,v]=C.useState(null),[h,g]=C.useState(!1),[w,y]=C.useState(null),T=jp(e.id),f=w??T,d=(E=t==null?void 0:t.user)==null?void 0:E.role,m=["admin","owner","manager"].includes(d),x=k=>_=>s({...l,[k]:_.target.value});async function S(k){k.preventDefault(),c(!0),v(null);try{await I.saveProfile({visitor_id:e.id,...l});const _=parseFloat(o.amount);if(!isNaN(_)&&_>0){const z=o.items.split(",").map(L=>L.trim()).filter(Boolean);await I.recordPurchase(e.id,_,z,o.notes)}r()}catch(_){v(fe(_))}finally{c(!1)}}return i.jsx("div",{className:"drawer",onMouseDown:k=>k.target===k.currentTarget&&n(),children:i.jsxs("div",{className:"sheet",children:[i.jsxs("div",{className:"sheethead who",children:[i.jsx(kp,{photo:f,name:e.full_name||e.label,customerRef:e.ref,onBroken:()=>y({available:!1,reason:"The photo could not be loaded."})}),i.jsxs("div",{className:"grow",children:[i.jsx("h2",{children:e.full_name||e.label}),i.jsxs("p",{className:"note",children:[e.visit_count," visit",e.visit_count===1?"":"s",e.last_seen_at&&` · last seen ${new Date(e.last_seen_at).toLocaleDateString()}`,f&&!f.available&&f.reason&&` · ${f.reason}`]})]}),i.jsx("button",{type:"button",className:"close",onClick:n,"aria-label":"Close",children:"✕"})]}),i.jsxs("form",{className:"sheetbody",onSubmit:S,children:[p&&i.jsx("div",{className:"err",children:p}),i.jsxs("section",{className:"formsection",children:[i.jsx("h4",{children:"Customer details"}),i.jsxs("label",{className:"field",children:[i.jsx("span",{children:"Full name"}),i.jsx("input",{value:l.full_name,onChange:x("full_name"),autoFocus:!0})]}),i.jsxs("div",{className:"fieldrow",children:[i.jsxs("label",{className:"field",children:[i.jsx("span",{children:"Phone"}),i.jsx("input",{value:l.phone,onChange:x("phone"),inputMode:"tel"})]}),i.jsxs("label",{className:"field",children:[i.jsx("span",{children:"Email"}),i.jsx("input",{value:l.email,onChange:x("email"),type:"email"})]})]}),i.jsxs("div",{className:"fieldrow",children:[i.jsxs("label",{className:"field",children:[i.jsx("span",{children:"Gender"}),i.jsxs("select",{value:l.gender,onChange:x("gender"),children:[i.jsx("option",{value:"",children:"Not recorded"}),i.jsx("option",{children:"Female"}),i.jsx("option",{children:"Male"}),i.jsx("option",{children:"Other"})]})]}),i.jsxs("label",{className:"field",children:[i.jsx("span",{children:"Date of birth"}),i.jsx("input",{type:"date",value:l.date_of_birth,onChange:x("date_of_birth")})]})]}),i.jsxs("label",{className:"field",children:[i.jsx("span",{children:"Notes"}),i.jsx("textarea",{value:l.notes,onChange:x("notes"),placeholder:"Preferences, sizes, anything worth remembering"})]})]}),i.jsxs("section",{className:"formsection",children:[i.jsx("h4",{children:"Purchase (optional)"}),i.jsxs("div",{className:"fieldrow",children:[i.jsxs("label",{className:"field",children:[i.jsx("span",{children:"Amount"}),i.jsx("input",{value:o.amount,inputMode:"decimal",placeholder:"0.00",onChange:k=>a({...o,amount:k.target.value})})]}),i.jsxs("label",{className:"field",children:[i.jsx("span",{children:"Items"}),i.jsx("input",{value:o.items,placeholder:"shirt, belt",onChange:k=>a({...o,items:k.target.value})})]})]}),i.jsx("p",{className:"note",children:"Leave the amount blank if they did not buy anything — a visit without a sale is still worth recording."})]}),i.jsxs("section",{className:"formsection",children:[i.jsx("h4",{children:"Consent"}),i.jsxs("label",{style:{display:"flex",gap:10,alignItems:"flex-start",fontSize:13,cursor:"pointer"},children:[i.jsx("input",{type:"checkbox",checked:l.consent,style:{marginTop:3},onChange:k=>s({...l,consent:k.target.checked})}),i.jsx("span",{children:"This customer agreed to us keeping their details and recognising them on future visits."})]}),i.jsx("p",{className:"note",style:{marginTop:10},children:"Recorded with the date and who collected it. They can withdraw it at any time, which erases their face data."})]}),i.jsxs("section",{className:"formsection",children:[i.jsx("h4",{children:"Visits"}),i.jsx(Np,{customer:e})]}),i.jsxs("div",{className:"sheetactions",children:[i.jsx("button",{type:"button",className:"btn",onClick:n,children:"Cancel"}),i.jsx("button",{className:"btn primary",disabled:u,children:u?"Saving…":"Save"})]}),m&&i.jsxs("section",{className:"formsection dangerzone",children:[i.jsx("h4",{children:"At the customer's request"}),h?i.jsx(Ep,{customer:e,onCancel:()=>g(!1),onDone:r}):i.jsxs(i.Fragment,{children:[i.jsx("p",{className:"note",children:"Erase this person's face data, photo and details. Their past visits stay in your footfall figures, without their name."}),i.jsx("button",{type:"button",className:"btn danger",onClick:()=>g(!0),children:"Erase this customer…"})]})]})]})]})})}function Pp({session:e}){const[t,n]=C.useState(""),[r,l]=C.useState(null),{data:s,error:o,reload:a}=et(()=>I.customers(t,200),3e4,[t]),u=s??[],c=u.filter(p=>p.has_profile).length;return i.jsxs("div",{className:"page",children:[i.jsxs("header",{className:"pagehead",children:[i.jsxs("div",{children:[i.jsx("h2",{children:"Customers"}),i.jsx("p",{children:"Everyone this business has recognised. Fill in details once and they are known at every store."})]}),i.jsxs("label",{className:"search",children:[i.jsx(Nc,{size:15}),i.jsx("input",{placeholder:"Search by name or phone",value:t,onChange:p=>n(p.target.value)})]})]}),o&&i.jsxs("div",{className:"err",children:[i.jsx(Se,{size:15}),o]}),i.jsxs("div",{className:"metrics",style:{marginBottom:"var(--sp-4)"},children:[i.jsx(_r,{k:"Known people",v:u.length||"—"}),i.jsx(_r,{k:"With details",v:c||"—",s:u.length?`${Math.round(100*c/u.length)}% captured`:null}),i.jsx(_r,{k:"Returning",v:u.filter(p=>p.visit_count>1).length||"—"}),i.jsx(_r,{k:"With consent",v:u.filter(p=>p.has_consent).length||"—"})]}),i.jsx("div",{className:"panel",children:u.length===0?i.jsxs("div",{className:"empty tall",children:[i.jsx(_c,{size:34}),i.jsx("b",{children:"No customers yet"}),i.jsx("p",{children:"They appear here the first time a camera recognises them. Click one to add a name and phone number."})]}):i.jsx("div",{className:"tablewrap",children:i.jsxs("table",{children:[i.jsx("thead",{children:i.jsxs("tr",{children:[i.jsx("th",{children:"Customer"}),i.jsx("th",{children:"Phone"}),i.jsx("th",{className:"num",children:"Visits"}),i.jsx("th",{children:"First seen"}),i.jsx("th",{children:"Last seen"}),i.jsx("th",{children:"Details"})]})}),i.jsx("tbody",{children:u.map(p=>i.jsxs("tr",{className:"click",onClick:()=>l(p),children:[i.jsxs("td",{children:[p.full_name||i.jsx("span",{className:"note",children:p.label}),p.full_name&&p.ref&&i.jsxs("span",{className:"note",children:[" · ",p.ref]})]}),i.jsx("td",{className:"mono",children:p.phone||"—"}),i.jsx("td",{className:"num",children:p.visit_count}),i.jsx("td",{children:sa(p.first_seen_at)}),i.jsx("td",{children:sa(p.last_seen_at)}),i.jsx("td",{children:p.has_profile?i.jsxs("span",{className:"pill ok",children:[i.jsx("i",{className:"dot ok"}),"captured"]}):i.jsxs("span",{className:"pill warn",children:[i.jsx("i",{className:"dot warn"}),"needed"]})})]},p.id))})]})})}),r&&i.jsx(_p,{customer:r,session:e,onClose:()=>l(null),onSaved:()=>{l(null),a()}})]})}function _r({k:e,v:t,s:n}){return i.jsxs("div",{className:"metric",children:[i.jsx("div",{className:"metric-k",children:e}),i.jsx("div",{className:"metric-v",children:t}),n&&i.jsx("div",{className:"metric-s",children:n})]})}const ln=[{id:"hikvision",label:"Hikvision",path:"/Streaming/Channels/101",note:"Channel 1, main stream. Use /Streaming/Channels/102 for the lower-quality sub stream."},{id:"dahua",label:"Dahua",path:"/cam/realmonitor?channel=1&subtype=0",note:"Channel 1, main stream. subtype=1 is the sub stream."},{id:"cpplus",label:"CP Plus",path:"/cam/realmonitor?channel=1&subtype=0",note:"CP Plus cameras use the Dahua stream path."},{id:"uniview",label:"Uniview",path:"/media/video1",note:"Some older Uniview models use /video1 instead."},{id:"tplink",label:"TP-Link / Tapo",path:"/stream1",note:"Tapo cameras need a separate camera account created in the Tapo app — your Tapo login will not work."},{id:"reolink",label:"Reolink",path:"/h264Preview_01_main",note:"Use /h264Preview_01_sub for the lower-quality stream."},{id:"amcrest",label:"Amcrest",path:"/cam/realmonitor?channel=1&subtype=0",note:"Amcrest cameras use the Dahua stream path."},{id:"axis",label:"Axis",path:"/axis-media/media.amp",note:""},{id:"onvif",label:"Other (ONVIF)",path:"/onvif1",note:"Many generic cameras answer here. If it does not work, look for “RTSP” in the camera’s own app."},{id:"manual",label:"I know the path",path:"",note:""}],Pr=e=>ln.find(t=>t.id===e)||ln[ln.length-1],Js={id:"",host:"",port:554,path:"",username:"",password:"",max_width:1280};function zp(){const{data:e,error:t,reload:n}=et(()=>I.cameras(),8e3),[r,l]=C.useState(null),[s,o]=C.useState(null),a=e??[],u=a.some(y=>y.remote),c=Tp(u?[]:a),[p,v]=C.useState(null),[h,g]=C.useState("");C.useEffect(()=>{let y=!0;if(!p){g("");return}return I.remoteStreamURL(p).then(T=>{y&&g(T||"")}).catch(()=>{y&&g("")}),()=>{y=!1}},[p]);async function w(y){if(confirm(`Remove ${y.id}? Recognition from it stops immediately.`))try{await I.deleteCamera(y.id),n()}catch(T){alert(fe(T))}}return i.jsxs("div",{className:"page",children:[i.jsxs("header",{className:"pagehead",children:[i.jsxs("div",{children:[i.jsx("h2",{children:"Cameras"}),i.jsx("p",{children:u?"The cameras across your shops, as the shop computers last reported them.":"Add a camera, then prove it can see faces with a walk-past. Only then is it working."})]}),!u&&i.jsxs("button",{className:"btn primary",onClick:()=>l({...Js}),children:[i.jsx(ia,{size:15}),"Add camera"]})]}),u&&i.jsxs("div",{className:"viewing",children:[i.jsx("b",{children:"Viewing your shops from here."})," These cameras are wired to the shop computers, so they are set up and checked there. Each tile shows that camera's most recent frame; ",i.jsx("b",{children:"Watch live"})," asks the shop computer to send video for as long as you are looking."]}),t&&i.jsxs("div",{className:"err",children:[i.jsx(Se,{size:15}),t]}),a.length===0?i.jsx("div",{className:"panel",children:i.jsxs("div",{className:"empty tall",children:[i.jsx(Ec,{size:40}),i.jsx("b",{children:"No cameras yet"}),i.jsx("p",{children:"Add the camera by its address. Most cameras print it on a label underneath, or show it in their own app."}),i.jsxs("button",{className:"btn primary",onClick:()=>l({...Js}),children:[i.jsx(ia,{size:15}),"Add your first camera"]})]})}):i.jsx("div",{className:"camgrid",children:a.map(y=>i.jsx(Lp,{cam:y,stream:p===y.id?h:c[y.id],watching:p===y.id,onWatch:()=>v(p===y.id?null:y.id),onEdit:()=>l(y),onCheck:()=>o(y.id),onRemove:()=>w(y)},y.id))}),r&&i.jsx(Mp,{cam:r,onClose:()=>l(null),onSaved:()=>{l(null),n()}}),s&&i.jsx(Rp,{id:s,onClose:()=>o(null)})]})}function Lp({cam:e,stream:t,watching:n,onWatch:r,onEdit:l,onCheck:s,onRemove:o}){var v,h,g;const a=e.remote?{connected:{tone:"ok",label:"Connected"},not_connecting:{tone:"bad",label:"Not connecting"},stale:{tone:"warn",label:"Not reporting"}}[e.state]||{tone:"idle",label:"Waiting for the shop computer"}:e.connected===void 0||e.connected===null?{tone:"idle",label:"Engine stopped"}:e.connected?{tone:"ok",label:"Connected"}:{tone:"bad",label:"Not connecting"},{data:u}=et(()=>e.remote?Promise.resolve(null):I.placementResult(e.id),15e3,[e.id]),c=!u||u.running||!u.verdict||u.verdict==="starting"?{tone:"miss",label:"Not yet proven",text:"Walk past it once and Behavision will tell you if the placement works."}:u.verdict==="good"?{tone:"seen",label:"Proven",text:u.headline||"Faces recognised on a walk-past."}:{tone:"miss",label:"Not proven",text:u.headline||"Move the camera and check again."},p=(v=e.snapshot)!=null&&v.available?e.snapshot.url:"";return i.jsxs("article",{className:"camcard",children:[i.jsxs("div",{className:"camview",children:[t||p?i.jsx("img",{src:t||p,alt:e.id}):i.jsx("div",{className:"placeholder",children:i.jsx(Ec,{size:34})}),i.jsxs("span",{className:`pill ${a.tone==="idle"?"":a.tone} over`,children:[i.jsx("i",{className:`dot ${a.tone}`}),a.label]}),e.remote&&i.jsxs("button",{className:`btn sm watch ${n?"on":""}`,onClick:r,children:[i.jsx(Zs,{size:13}),n?"Stop watching":"Watch live"]})]}),i.jsxs("div",{className:"cambody",children:[i.jsxs("div",{className:"camtitle",children:[i.jsxs("div",{children:[i.jsx("h3",{children:e.label||e.camera_id||e.id}),i.jsx("span",{className:"mono note",children:e.remote?e.site||e.site_slug||"":`${e.host||e.url}${e.path?` · ${e.path}`:""}`})]}),!e.remote&&i.jsxs("div",{className:"camactions",children:[i.jsx("button",{className:"btn sm",onClick:l,children:"Edit"}),i.jsx("button",{className:"btn sm danger",onClick:o,children:"Remove"})]})]}),e.remote?i.jsx("div",{className:"camproof",children:i.jsx("span",{className:"note",children:e.state_note?e.state_note:n?"Live from the shop computer. It uploads only while you watch.":(h=e.snapshot)!=null&&h.available?"Last picture from the shop computer. Watch live to see it now.":((g=e.snapshot)==null?void 0:g.reason)||"No picture yet from the shop computer."})}):i.jsxs("div",{className:"camproof",children:[i.jsx("span",{className:`tag ${c.tone}`,children:c.label}),i.jsx("span",{className:"note",children:c.text}),i.jsxs("button",{className:`btn sm ${c.tone==="seen"?"":"primary"}`,onClick:s,children:[i.jsx(Zs,{size:13}),c.tone==="seen"?"Check again":"Check placement"]})]})]})]})}function Tp(e){const[t,n]=C.useState({});return C.useEffect(()=>{let r=!0;const l=e.filter(s=>!(s.id in t));if(l.length)return(async()=>{const s={};for(const o of l)try{s[o.id]=await I.streamURL(o.id)}catch{s[o.id]=""}r&&n(o=>({...o,...s}))})(),()=>{r=!1}},[e.map(r=>r.id).join("|")]),t}function Mp({cam:e,onClose:t,onSaved:n}){var _;const r=!e.id,[l,s]=C.useState({...Js,...e,password:"",path:e.path||(r?ln[0].path:"")}),[o,a]=C.useState(r?ln[0].id:"manual"),[u,c]=C.useState(null),[p,v]=C.useState(null),[h,g]=C.useState(null),w=z=>L=>s({...l,[z]:L.target.value});function y(z){const L=Pr(z.target.value);a(L.id),s(V=>({...V,path:L.path||V.path}))}function T(){const z={};for(const[L,V]of Object.entries(l))V===""||V===null||V===void 0||(z[L]=L==="port"||L==="max_width"?Number(V):V);return z}async function f(){v("test"),g(null),c(null);try{c(await I.testCamera(T()))}catch(z){g(fe(z))}finally{v(null)}}async function d(z){z.preventDefault(),v("save"),g(null);try{await I.saveCamera(r?"":e.id,T()),n()}catch(L){g(fe(L))}finally{v(null)}}const m=Pr(o),[x,S]=C.useState(null);async function E(){S("busy");try{S(await I.discoverCameras())}catch(z){S({error:fe(z)})}}function k(z){const L=z.make?Pr(z.make):null;s(V=>({...V,host:z.host,path:(L==null?void 0:L.path)||V.path,id:V.id||""})),L&&a(L.id),c(null)}return i.jsx("div",{className:"drawer",onMouseDown:z=>z.target===z.currentTarget&&t(),children:i.jsxs("div",{className:"sheet",children:[i.jsxs("div",{className:"sheethead",children:[i.jsx("h2",{children:r?"Add a camera":`Edit ${e.id}`}),i.jsx("button",{className:"close",onClick:t,"aria-label":"Close",children:i.jsx(Ki,{size:16})})]}),i.jsxs("form",{className:"sheetbody",onSubmit:d,autoComplete:"off",children:[i.jsx("p",{className:"lead",children:"Three things from the camera: its address, its make, and its password. Test before you save — a wrong address is the most common mistake."}),h&&i.jsxs("div",{className:"err",children:[i.jsx(Se,{size:15}),h]}),r&&i.jsxs("section",{className:"formsection",children:[i.jsx("h4",{children:"Find it"}),x===null&&i.jsxs("div",{className:"finder",children:[i.jsx("p",{children:"Behavision can look for cameras on this shop’s network."}),i.jsxs("button",{type:"button",className:"btn primary",onClick:E,children:[i.jsx(Nc,{size:14}),"Find cameras on this network"]})]}),x==="busy"&&i.jsxs("div",{className:"finder busy",children:[i.jsx("span",{className:"spinner"}),"Looking on the network… a few seconds."]}),(x==null?void 0:x.error)&&i.jsxs("div",{className:"err",children:[i.jsx(Se,{size:15}),x.error]}),(x==null?void 0:x.cameras)&&(x.cameras.length===0?i.jsxs("div",{className:"finder",children:[i.jsxs("p",{children:["Nothing answered on ",((_=x.networks)==null?void 0:_.join(", "))||"this network",". The camera may be on a different network, switched off, or not yet connected — check its cable and power, then try again. You can still type its address below."]}),i.jsx("button",{type:"button",className:"btn",onClick:E,children:"Try again"})]}):i.jsxs("ul",{className:"foundlist",children:[x.cameras.map(z=>i.jsx("li",{className:l.host===z.host?"picked":"",children:i.jsxs("button",{type:"button",onClick:()=>k(z),children:[i.jsx("span",{className:"mono",children:z.host}),i.jsx("span",{className:"what",children:z.name||(z.rtsp?"Streams video (RTSP)":"Answers ONVIF")}),z.make&&i.jsx("span",{className:"tag seen",children:Pr(z.make).label}),l.host===z.host&&i.jsx(Xs,{size:16})]})},z.host)),i.jsx("li",{className:"rescan",children:i.jsx("button",{type:"button",className:"btn sm",onClick:E,children:"Scan again"})})]}))]}),i.jsxs("section",{className:"formsection",children:[i.jsx("h4",{children:"The camera"}),r&&i.jsxs("label",{className:"field",children:[i.jsx("span",{children:"Name"}),i.jsx("input",{value:l.id,onChange:w("id"),placeholder:"entrance",required:!0,autoFocus:!0}),i.jsx("em",{className:"hint",children:"Short, no spaces. It names this camera everywhere and cannot be changed later."})]}),i.jsxs("div",{className:"fieldrow",children:[i.jsxs("label",{className:"field",children:[i.jsx("span",{children:"Address"}),i.jsx("input",{value:l.host,onChange:w("host"),placeholder:"192.168.1.20",inputMode:"decimal"}),i.jsx("em",{className:"hint",children:"On a label on the camera, or in its own app under “network”."})]}),i.jsxs("label",{className:"field narrow",children:[i.jsx("span",{children:"Port"}),i.jsx("input",{value:l.port,onChange:w("port"),inputMode:"numeric"})]})]})]}),i.jsxs("section",{className:"formsection",children:[i.jsx("h4",{children:"The stream"}),i.jsxs("label",{className:"field",children:[i.jsx("span",{children:"Make of camera"}),i.jsx("select",{value:o,onChange:y,children:ln.map(z=>i.jsx("option",{value:z.id,children:z.label},z.id))}),m.note&&i.jsx("em",{className:"hint",children:m.note})]}),i.jsxs("label",{className:"field",children:[i.jsx("span",{children:"Stream path"}),i.jsx("input",{className:"mono",value:l.path,onChange:w("path"),placeholder:"/Streaming/Channels/101"}),i.jsx("em",{className:"hint",children:"Filled in from the make. Change it only if the camera’s own app says something else."})]})]}),i.jsxs("section",{className:"formsection",children:[i.jsx("h4",{children:"Sign-in to the camera"}),i.jsxs("div",{className:"fieldrow",children:[i.jsxs("label",{className:"field",children:[i.jsx("span",{children:"Username"}),i.jsx("input",{name:"rtsp-account",autoComplete:"off",value:l.username,onChange:w("username"),placeholder:"admin"})]}),i.jsxs("label",{className:"field",children:[i.jsx("span",{children:"Password"}),i.jsx("input",{type:"password",name:"rtsp-secret",autoComplete:"new-password",value:l.password,onChange:w("password"),placeholder:e.has_password?"(unchanged)":""})]})]})]}),u&&(u.ok?i.jsxs("div",{className:"testresult ok",children:[i.jsx(Xs,{size:16}),i.jsxs("div",{children:[i.jsxs("b",{children:["Connected — ",u.width,"×",u.height,u.codec?` · ${String(u.codec).toUpperCase()}`:""]}),u.snapshot&&i.jsx("img",{alt:"Camera preview",src:`data:image/jpeg;base64,${u.snapshot}`})]})]}):i.jsxs("div",{className:"testresult bad",children:[i.jsx(Se,{size:16}),i.jsxs("div",{children:[i.jsx("b",{children:"Could not connect"}),i.jsx("span",{children:u.error})]})]})),i.jsxs("div",{className:"sheetactions",children:[i.jsx("button",{type:"button",className:"btn",onClick:f,disabled:!!p||!l.host,children:p==="test"?"Connecting…":"Test connection"}),i.jsx("button",{className:"btn primary",disabled:!!p||!l.id||!l.host,children:p==="save"?"Saving…":r?"Add camera":"Save changes"})]})]})]})})}function Rp({id:e,onClose:t}){var p,v;const[n,r]=C.useState({verdict:"starting",advice:[]}),[l,s]=C.useState(null),o=C.useRef(null);C.useEffect(()=>{let h=!0;return(async()=>{try{r(await I.startPlacement(e,25)),o.current=setInterval(async()=>{try{const g=await I.placementResult(e);if(!h)return;r(g),g.running||clearInterval(o.current)}catch(g){h&&s(fe(g))}},1e3)}catch(g){h&&s(fe(g))}})(),()=>{h=!1,clearInterval(o.current)}},[e]);const a={good:"ok",marginal:"warn",poor:"bad",artifact:"bad",no_faces:"warn",inconclusive:"warn",no_completed_passes:"warn"}[n.verdict],u=n.seconds?Math.min(100,n.elapsed/n.seconds*100):0,c=n.running||n.verdict==="starting";return i.jsx("div",{className:"drawer",onMouseDown:h=>h.target===h.currentTarget&&t(),children:i.jsxs("div",{className:"sheet",children:[i.jsxs("div",{className:"sheethead",children:[i.jsxs("h2",{children:["Check placement · ",e]}),i.jsx("button",{className:"close",onClick:t,"aria-label":"Close",children:i.jsx(Ki,{size:16})})]}),i.jsxs("div",{className:"sheetbody",children:[l&&i.jsxs("div",{className:"err",children:[i.jsx(Se,{size:15}),l]}),i.jsxs("ol",{className:"steps",children:[i.jsxs("li",{className:c?"now":"done",children:[i.jsx("b",{children:"Walk past the camera"}),i.jsx("span",{children:"The way a customer would — in through the door, not looking at the lens. Two or three times, for about 25 seconds."}),c&&i.jsx("div",{className:"progress",children:i.jsx("div",{style:{width:`${u}%`}})})]}),i.jsxs("li",{className:c?"":"now",children:[i.jsx("b",{children:"Behavision judges what it saw"}),i.jsx("span",{children:"Not “were the frames sharp”, but “did a person walking past produce a face worth recognising”."})]})]}),i.jsxs("div",{className:`verdict ${a??""}`,children:[i.jsxs("div",{className:"verdict-head",children:[c?i.jsx("span",{className:"spinner"}):a==="ok"?i.jsx(Xs,{size:18}):i.jsx(Se,{size:18}),i.jsx("b",{children:n.headline||"Watching…"})]}),((p=n.advice)==null?void 0:p.length)>0&&i.jsx("ul",{children:n.advice.map((h,g)=>i.jsx("li",{children:h},g))}),((v=n.quality)==null?void 0:v.n)>0&&i.jsxs("p",{className:"note",children:[n.quality.n," face",n.quality.n===1?"":"s"," seen · median quality ",n.quality.p50," ·"," ",Math.round((n.quality.fraction_below_gate??0)*100),"% too poor to use"]})]}),!c&&i.jsxs("div",{className:"sheetactions",children:[i.jsx("button",{className:"btn",onClick:t,children:"Close"}),i.jsx("button",{className:"btn primary",onClick:()=>{r({verdict:"starting",advice:[]}),I.startPlacement(e,25).then(r).catch(h=>s(fe(h)))},children:"Run again"})]})]})]})})}const Dp=["Is my shop working right now?","How do I add my camera?","Why has nobody been recognised today?","Who came in this morning?"];function Op({session:e,onClose:t}){const[n,r]=C.useState([]),[l,s]=C.useState(""),[o,a]=C.useState(!1),[u,c]=C.useState(null),p=C.useRef(null),v=e==null?void 0:e.standalone;C.useEffect(()=>{var g;(g=p.current)==null||g.scrollTo({top:1e9,behavior:"smooth"})},[n,o]);async function h(g){const w=(g??l).trim();if(!w||o)return;const y=[...n,{role:"user",text:w}];r(y),s(""),a(!0),c(null);try{const T=await I.ask(y.map(f=>({role:f.role,text:f.text})));r([...y,{role:"assistant",text:T.text,used:T.used??[]}])}catch(T){const f=fe(T);c(/session expired|unauthori[sz]ed/i.test(f)?"You’re signed out of head office, so I can’t look anything up. Sign in again and ask me once more.":f),r(n),s(w)}finally{a(!1)}}return i.jsxs("aside",{className:"helper",role:"dialog","aria-label":"Loya",children:[i.jsxs("header",{className:"helperhead",children:[i.jsx("img",{src:gt,alt:""}),i.jsxs("div",{children:[i.jsx("b",{children:"Loya"}),i.jsx("span",{children:"Your Behavision buddy — knows your cameras, your customers and your numbers."})]}),i.jsx("button",{className:"close",onClick:t,"aria-label":"Close",children:i.jsx(Ki,{size:16})})]}),i.jsxs("div",{className:"helperbody",ref:p,children:[v&&i.jsxs("div",{className:"helpernote",children:[i.jsx(Cc,{size:16}),i.jsxs("div",{children:[i.jsx("b",{children:"This PC runs on its own"}),i.jsx("span",{children:"Loya lives at head office. Link this PC to a shop to talk to her; the basics are below."})]})]}),n.length===0&&i.jsxs("div",{className:"helperintro",children:[i.jsx("div",{className:"turn assistant",children:i.jsxs("div",{className:"bubble",children:[Fp(e)," Ask me anything about ",(e==null?void 0:e.site_name)||"this shop"," — what’s happening now, or how to set something up."]})}),i.jsx("div",{className:"chips",children:Dp.map(g=>i.jsx("button",{className:"chip",onClick:()=>h(g),disabled:o||v,children:g},g))}),v&&i.jsx(Ip,{})]}),n.map((g,w)=>{var y;return i.jsxs("div",{className:`turn ${g.role}`,children:[i.jsx("div",{className:"bubble",children:g.text}),((y=g.used)==null?void 0:y.length)>0&&i.jsxs("span",{className:"used",children:["Looked at: ",g.used.join(", ")]})]},w)}),o&&i.jsx("div",{className:"turn assistant",children:i.jsxs("div",{className:"bubble thinking",children:[i.jsx("span",{}),i.jsx("span",{}),i.jsx("span",{})]})}),u&&i.jsxs("div",{className:"err",children:[i.jsx(Se,{size:15}),u]})]}),i.jsxs("form",{className:"helperask",onSubmit:g=>{g.preventDefault(),h()},children:[i.jsx("input",{value:l,onChange:g=>s(g.target.value),disabled:o||v,placeholder:v?"Link this PC to head office to talk to Loya":"Ask Loya…"}),i.jsx("button",{className:"btn primary",disabled:o||v||!l.trim(),"aria-label":"Ask",children:i.jsx(hp,{size:16})})]})]})}function Fp(e){var l,s;const t=new Date().getHours(),n=t<12?"Morning":t<17?"Afternoon":"Evening",r=(s=(l=e==null?void 0:e.user)==null?void 0:l.full_name)==null?void 0:s.split(" ")[0];return r?`${n}, ${r}.`:`${n}.`}function Ip(){return i.jsxs("dl",{className:"quickhelp",children:[i.jsx("dt",{children:"Adding a camera"}),i.jsx("dd",{children:"Cameras → Add camera. The address is on a label on the camera; pick the make and the stream path fills itself in. Test, then save."}),i.jsx("dt",{children:"Proving it works"}),i.jsx("dd",{children:"Press Check placement and walk past the camera like a customer for 25 seconds. Only “good” means it can recognise faces — otherwise move it to head height, facing the way people approach."}),i.jsx("dt",{children:"Nothing showing on Live"}),i.jsx("dd",{children:"Check the camera is Connected and Proven. A camera aimed from above or the side streams fine and recognises nobody."}),i.jsx("dt",{children:"Linking to head office later"}),i.jsx("dd",{children:"Use the link button at the bottom of the sidebar and type an installation code from head office. Nothing recorded here is lost."})]})}const $p=[{id:"live",label:"Live",Glyph:op,View:Pc},{id:"customers",label:"Customers",Glyph:ap,View:Pp,cloud:!0},{id:"cameras",label:"Cameras",Glyph:up,View:zp}];function Up(){var h,g,w;const[e,t]=C.useState(null),[n,r]=C.useState("live"),[l,s]=C.useState(!0),[o,a]=C.useState(!1),[u,c]=C.useState(!1);if(C.useEffect(()=>{let y=!0;const T=async()=>{try{const d=await I.session();y&&t(m=>JSON.stringify(m)===JSON.stringify(d)?m:d)}catch{y&&t(null)}y&&s(!1)};T();const f=setInterval(T,8e3);return()=>{y=!1,clearInterval(f)}},[]),!sp())return i.jsx("div",{className:"login",children:i.jsxs("div",{className:"box",children:[i.jsx("span",{className:"mark",children:i.jsx("img",{src:gt,alt:""})}),i.jsx("h1",{children:"Behavision"}),i.jsx("p",{className:"lead",children:"This is the Behavision window running outside the app, so it has no connection to the recognition engine. Launch the Behavision application instead."})]})});if(l)return i.jsx("div",{className:"login",children:i.jsx("p",{className:"note",children:"Starting…"})});if(!(e!=null&&e.claimed)&&!(e!=null&&e.standalone))return i.jsx(ua,{onDone:t});if(!(e!=null&&e.standalone)&&!(e!=null&&e.logged_in))return i.jsx(mp,{onDone:t});const p=$p.filter(y=>!y.cloud||!e.standalone),v=((h=p.find(y=>y.id===n))==null?void 0:h.View)??Pc;return o?i.jsx(ua,{onDone:y=>{a(!1),t(y)},onCancel:()=>a(!1)}):i.jsxs("div",{className:"shell",children:[i.jsxs("aside",{className:"side",children:[i.jsxs("div",{className:"brand",children:[i.jsx("span",{className:"mark",children:i.jsx("img",{src:gt,alt:""})}),i.jsxs("div",{className:"id",children:[i.jsx("h1",{children:"Behavision"}),i.jsx("p",{children:e.site_name||((g=e.user)==null?void 0:g.client_name)||"This shop"})]})]}),i.jsx("nav",{className:"nav",children:p.map(({id:y,label:T,Glyph:f})=>i.jsxs("button",{onClick:()=>r(y),"aria-current":y===n?"page":void 0,children:[i.jsx(f,{size:17}),T]},y))}),i.jsx(Ap,{}),i.jsx("div",{className:"who",children:e.standalone?i.jsxs(i.Fragment,{children:[i.jsxs("div",{className:"id",children:[i.jsx("b",{children:"On its own"}),i.jsx("span",{children:"No head office"})]}),i.jsx("button",{className:"btn sm icon",title:"Link to head office",onClick:()=>a(!0),children:i.jsx(fp,{size:15})})]}):i.jsxs(i.Fragment,{children:[i.jsxs("div",{className:"id",children:[i.jsx("b",{children:"Signed in"}),i.jsx("span",{children:(w=e.user)==null?void 0:w.email})]}),i.jsx("button",{className:"btn sm icon",title:"Sign out",onClick:async()=>t(await I.logout()),children:i.jsx(pp,{size:15})})]})})]}),i.jsxs("main",{className:"main",children:[i.jsx(v,{session:e,onNavigate:r}),!u&&i.jsxs("button",{className:"loya-fab",onClick:()=>c(!0),"aria-label":"Ask Loya",title:"Ask Loya",children:[i.jsx("img",{src:gt,alt:""}),i.jsx("span",{children:"Loya"})]})]}),u&&i.jsx(Op,{session:e,onClose:()=>c(!1)})]})}function Ap(){const{data:e,reload:t}=et(()=>I.engineStatus(),5e3),[n,r]=C.useState(!1),l=e??{state:"stopped"},s=C.useCallback(async v=>{r(!0);try{await v()}catch(h){alert(fe(h))}finally{r(!1),t()}},[t]),o=l.state==="running",a=Object.values(l.cameras??{}),u=a.filter(Boolean).length;let c="idle",p="Stopped";return!o&&l.reachable?(c="warn",p="Running outside the app"):l.state==="failed"||l.state==="backoff"?(c="bad",p="Not running"):o&&!l.reachable&&l.progress?(c="warn",p=`Downloading ${l.progress.what}… ${l.progress.percent}%`):o&&!l.reachable?(c="warn",p="Starting…"):o&&a.length===0?(c="warn",p="No cameras"):o&&u===0?(c="bad",p="No camera connected"):o&&us(I.startEngine),children:[i.jsx(Zs,{size:13}),"Start"]}),i.jsxs("button",{className:"btn sm",disabled:n||!o,onClick:()=>s(I.stopEngine),children:[i.jsx(cp,{size:13}),"Stop"]})]})]})}kc(document.getElementById("root")).render(i.jsx(Kc.StrictMode,{children:i.jsx(Up,{})})); diff --git a/desktop/frontend/dist/assets/index-xWw5ie4A.css b/desktop/frontend/dist/assets/index-DOJ2bRrM.css similarity index 99% rename from desktop/frontend/dist/assets/index-xWw5ie4A.css rename to desktop/frontend/dist/assets/index-DOJ2bRrM.css index 4da2cc8..ed258ea 100644 --- a/desktop/frontend/dist/assets/index-xWw5ie4A.css +++ b/desktop/frontend/dist/assets/index-DOJ2bRrM.css @@ -1 +1 @@ -:root{--bg: #0A0F13;--s1: #111A20;--s2: #17232B;--s3: #1E2D37;--line: #223038;--line-2: #1A252C;--ink: #ECF3F7;--ink-2: #A3B6C2;--ink-3: #6C808D;--accent: #40C4DC;--accent-2: #0F3B47;--accent-3: #0B2A33;--ok: #48C78E;--ok-2: #102E22;--warn: #EAAA3D;--warn-2: #31260F;--bad: #EC6A5C;--bad-2: #331815;--r-sm: 6px;--r: 10px;--r-lg: 14px;--sp-1: 4px;--sp-2: 8px;--sp-3: 12px;--sp-4: 16px;--sp-5: 20px;--sp-6: 24px;--sp-7: 32px;--sp-8: 40px;--shadow: 0 1px 2px rgb(0 0 0 / .4), 0 8px 24px -12px rgb(0 0 0 / .6);--shadow-lg: 0 2px 4px rgb(0 0 0 / .4), 0 24px 48px -16px rgb(0 0 0 / .7);--font: "Segoe UI Variable Text", "Segoe UI", Inter, -apple-system, BlinkMacSystemFont, system-ui, "Helvetica Neue", Arial, sans-serif;--font-display: "Segoe UI Variable Display", var(--font);--mono: "Cascadia Mono", "SFMono-Regular", ui-monospace, Menlo, Consolas, monospace;--ground: var(--bg);--surface: var(--s1);--surface-2: var(--s2);--line-soft: var(--line-2);--muted: var(--ink-3);--radius: var(--r);--accent-dim: var(--accent-3)}*{box-sizing:border-box;margin:0}html,body,#root{height:100%}body{background:var(--bg);color:var(--ink);font-family:var(--font);font-size:14px;line-height:1.5;-webkit-font-smoothing:antialiased;text-rendering:optimizeLegibility;overflow:hidden;-webkit-user-select:none;user-select:none}button,input,select,textarea{font:inherit;color:inherit}input,textarea{-webkit-user-select:text;user-select:text}:focus-visible{outline:2px solid var(--accent);outline-offset:2px;border-radius:3px}::selection{background:var(--accent-2);color:var(--ink)}.num,.value,.metric-v,.when,.mono,.code,td{font-variant-numeric:tabular-nums}.mono,.code{font-family:var(--mono)}*{scrollbar-width:thin;scrollbar-color:var(--s3) transparent}*::-webkit-scrollbar{width:10px;height:10px}*::-webkit-scrollbar-track{background:transparent}*::-webkit-scrollbar-thumb{background:var(--s3);border-radius:99px;border:3px solid var(--bg)}*::-webkit-scrollbar-thumb:hover{background:#2a3d49}.shell{display:grid;grid-template-columns:232px 1fr auto;height:100%}.side{background:var(--s1);border-right:1px solid var(--line);display:flex;flex-direction:column;min-height:0}.side .brand{display:flex;align-items:center;gap:var(--sp-3);padding:var(--sp-5) var(--sp-5) var(--sp-4)}.side .brand .mark{width:30px;height:30px;flex:none;display:grid;place-items:center}.side .brand .mark img,.login .mark img{width:100%;height:100%;object-fit:contain;display:block}.side .brand .id{min-width:0}.side .brand h1{font-family:var(--font-display);font-size:15px;font-weight:600;letter-spacing:-.012em;line-height:1.2}.side .brand p{font-size:11.5px;color:var(--ink-3);margin-top:1px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.nav{padding:var(--sp-2) var(--sp-3);display:flex;flex-direction:column;gap:2px;flex:1}.nav button{position:relative;display:flex;align-items:center;gap:var(--sp-3);width:100%;background:none;border:0;border-radius:var(--r-sm);padding:9px var(--sp-3);color:var(--ink-2);cursor:pointer;text-align:left;font-size:13.5px;font-weight:450;transition:background .12s ease,color .12s ease}.nav button svg{flex:none;opacity:.9}.nav button:hover{background:var(--s2);color:var(--ink)}.nav button[aria-current=page]{background:var(--accent-3);color:var(--accent);font-weight:550}.nav button[aria-current=page]:before{content:"";position:absolute;left:-12px;top:7px;bottom:7px;width:2.5px;border-radius:0 2px 2px 0;background:var(--accent)}.enginebox{margin:var(--sp-3);padding:var(--sp-3) var(--sp-4) var(--sp-4);border:1px solid var(--line);border-radius:var(--r);background:var(--s2)}.enginebox .row{display:flex;align-items:center;gap:var(--sp-2)}.enginebox .state{font-size:12.5px;font-weight:600;letter-spacing:-.005em}.enginebox .label{display:block;color:var(--ink-3);font-size:11px;line-height:1.45;margin-top:3px;font-variant-numeric:tabular-nums}.enginebox .actions,.enginebox .controls{display:flex;gap:var(--sp-2);margin-top:var(--sp-3)}.enginebox .actions .btn,.enginebox .controls .btn{flex:1;justify-content:center;padding:6px 8px;font-size:12px}.side .who{padding:var(--sp-3) var(--sp-5) var(--sp-5);border-top:1px solid var(--line-2);display:flex;align-items:center;gap:var(--sp-3)}.side .who .id{min-width:0;flex:1}.side .who .id b{display:block;font-size:12.5px;font-weight:550}.side .who .id span{display:block;font-size:11px;color:var(--ink-3);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.main{min-width:0;min-height:0;overflow:auto;position:relative}.page{padding:var(--sp-6) var(--sp-7) var(--sp-8);max-width:1500px}.page>header{margin-bottom:var(--sp-5)}.page>header h2,.page h2{font-family:var(--font-display);font-size:22px;font-weight:600;letter-spacing:-.02em;line-height:1.2}.page>header p,.page header p{color:var(--ink-3);font-size:13px;margin-top:3px}.pagehead{display:flex;align-items:flex-start;justify-content:space-between;gap:var(--sp-4);margin-bottom:var(--sp-5);flex-wrap:wrap}h3{font-size:11px;font-weight:600;letter-spacing:.085em;text-transform:uppercase;color:var(--ink-3)}.card{background:var(--s1);border:1px solid var(--line);border-radius:var(--r);padding:var(--sp-4)}.card>h3{margin-bottom:var(--sp-3)}.card.flush{padding:0;overflow:hidden}.panel{background:var(--s1);border:1px solid var(--line);border-radius:var(--r-lg);overflow:hidden;display:flex;flex-direction:column;min-height:0}.panel>.panelhead{display:flex;align-items:center;justify-content:space-between;gap:var(--sp-3);padding:var(--sp-3) var(--sp-4);border-bottom:1px solid var(--line-2);background:linear-gradient(var(--s2),var(--s1));flex:none}.panel>.panelhead h3{margin:0}.panel>.panelbody{padding:var(--sp-4);min-height:0;overflow:auto}.panel>.panelbody.flush{padding:0}.grid{display:grid;gap:var(--sp-4)}.cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.cols-4{grid-template-columns:repeat(4,minmax(0,1fr))}@media (max-width: 1180px){.cols-4{grid-template-columns:repeat(2,minmax(0,1fr))}}@media (max-width: 980px){.cols-2,.cols-3{grid-template-columns:minmax(0,1fr)}}.metrics{display:grid;grid-template-columns:repeat(auto-fit,minmax(152px,1fr));gap:1px;background:var(--line);border:1px solid var(--line);border-radius:var(--r);overflow:hidden}.metric{background:var(--s1);padding:var(--sp-3) var(--sp-4) var(--sp-4)}.metric .metric-k{font-size:10.5px;font-weight:600;letter-spacing:.085em;text-transform:uppercase;color:var(--ink-3)}.metric .metric-v{font-family:var(--font-display);font-size:26px;font-weight:600;letter-spacing:-.025em;line-height:1.1;margin-top:5px}.metric .metric-s{font-size:11.5px;color:var(--ink-3);margin-top:3px;line-height:1.4}.metric.ok .metric-v{color:var(--ok)}.metric.warn .metric-v{color:var(--warn)}.metric.bad .metric-v{color:var(--bad)}.stat h3{margin-bottom:var(--sp-2)}.stat .value{font-family:var(--font-display);font-size:26px;font-weight:600;letter-spacing:-.025em;line-height:1.1}.stat .unit{font-size:15px;color:var(--ink-3);margin-left:3px}.stat .sub{font-size:11.5px;color:var(--ink-3);margin-top:4px;line-height:1.4}.dot{width:7px;height:7px;border-radius:99px;flex:none;background:var(--ink-3)}.dot.ok{background:var(--ok);box-shadow:0 0 0 3px color-mix(in srgb,var(--ok) 18%,transparent)}.dot.warn{background:var(--warn);box-shadow:0 0 0 3px color-mix(in srgb,var(--warn) 18%,transparent)}.dot.bad{background:var(--bad);box-shadow:0 0 0 3px color-mix(in srgb,var(--bad) 18%,transparent)}.dot.idle{background:var(--ink-3)}.dot.live{background:var(--ok);animation:pulse 2.4s ease-in-out infinite}@keyframes pulse{0%,to{box-shadow:0 0 color-mix(in srgb,var(--ok) 55%,transparent)}70%{box-shadow:0 0 0 6px color-mix(in srgb,var(--ok) 0%,transparent)}}.pill{display:inline-flex;align-items:center;gap:6px;padding:3px 9px 3px 7px;border-radius:99px;font-size:11px;font-weight:600;letter-spacing:.02em;background:var(--s3);color:var(--ink-2);border:1px solid var(--line);white-space:nowrap}.pill.ok{background:var(--ok-2);color:var(--ok);border-color:color-mix(in srgb,var(--ok) 28%,transparent)}.pill.warn{background:var(--warn-2);color:var(--warn);border-color:color-mix(in srgb,var(--warn) 28%,transparent)}.pill.bad{background:var(--bad-2);color:var(--bad);border-color:color-mix(in srgb,var(--bad) 28%,transparent)}.pill.accent{background:var(--accent-3);color:var(--accent);border-color:color-mix(in srgb,var(--accent) 30%,transparent)}.tag{display:inline-flex;align-items:center;padding:2px 7px;border-radius:var(--r-sm);font-size:10.5px;font-weight:600;letter-spacing:.04em;text-transform:uppercase;background:var(--s3);color:var(--ink-2)}.tag.new{background:var(--accent-3);color:var(--accent)}.tag.seen{background:var(--ok-2);color:var(--ok)}.tag.miss{background:var(--warn-2);color:var(--warn)}.statusbar{display:flex;align-items:center;gap:var(--sp-5);flex-wrap:wrap;padding:var(--sp-3) var(--sp-4);background:var(--s1);border:1px solid var(--line);border-radius:var(--r);margin-bottom:var(--sp-4)}.statusbar .item{display:flex;align-items:center;gap:var(--sp-2);font-size:12.5px}.statusbar .item b{font-weight:600;letter-spacing:-.005em}.statusbar .item svg{color:var(--ink-3)}.statusbar .sep{width:1px;align-self:stretch;background:var(--line)}.statusbar .grow{flex:1}.arrivals{display:flex;flex-direction:column;gap:var(--sp-2);padding:var(--sp-3)}.arrival{display:grid;grid-template-columns:46px 1fr auto;gap:var(--sp-3);align-items:center;padding:var(--sp-3);border-radius:var(--r);background:var(--s2);border:1px solid var(--line-2);position:relative;overflow:hidden}.arrival:before{content:"";position:absolute;left:0;top:0;bottom:0;width:2.5px;background:var(--ink-3)}.arrival.is-new:before{background:var(--accent)}.arrival.is-seen:before{background:var(--ok)}.arrival.is-miss:before{background:var(--warn)}.arrival.fresh{animation:slidein .28s cubic-bezier(.2,.8,.3,1)}@keyframes slidein{0%{opacity:0;transform:translateY(-6px)}to{opacity:1;transform:none}}.arrival .avatar{width:46px;height:46px;border-radius:var(--r-sm);display:grid;place-items:center;overflow:hidden;background:var(--s3);border:1px solid var(--line);font-family:var(--font-display);font-size:15px;font-weight:600;color:var(--ink-2);letter-spacing:-.01em;font-variant-numeric:tabular-nums}.arrival .avatar img{width:100%;height:100%;object-fit:cover}.arrival.is-new .avatar{background:var(--accent-3);color:var(--accent);border-color:color-mix(in srgb,var(--accent) 25%,transparent)}.arrival .who{min-width:0}.arrival .who .name{font-size:14.5px;font-weight:600;letter-spacing:-.01em;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.arrival .who .meta{font-size:11.5px;color:var(--ink-3);margin-top:2px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.arrival .right{text-align:right;display:flex;flex-direction:column;align-items:flex-end;gap:5px}.arrival .right .when{font-size:11.5px;color:var(--ink-3)}.feeds{display:grid;gap:var(--sp-3);grid-template-columns:repeat(auto-fit,minmax(300px,1fr));padding:var(--sp-3)}.feed{position:relative;border-radius:var(--r);overflow:hidden;background:#05090c;border:1px solid var(--line);aspect-ratio:16 / 9}.feed img{width:100%;height:100%;object-fit:cover;display:block}.feed .placeholder{width:100%;height:100%;display:grid;place-items:center;color:var(--ink-3)}.feed .cap{position:absolute;left:0;right:0;bottom:0;display:flex;align-items:center;justify-content:space-between;gap:var(--sp-2);padding:var(--sp-5) var(--sp-3) var(--sp-3);background:linear-gradient(transparent,#000c);font-size:12.5px;font-weight:600;letter-spacing:-.005em}.events,.timeline{list-style:none;padding:0;display:flex;flex-direction:column}.events li{display:flex;align-items:center;gap:var(--sp-3);padding:9px var(--sp-4);border-bottom:1px solid var(--line-2);font-size:13px}.timeline li{display:flex;align-items:center;gap:var(--sp-3);padding:9px 0;border-bottom:1px solid var(--line-2);font-size:13px}.events li:last-child,.timeline li:last-child{border-bottom:0}.events .when,.timeline .when{font-size:11.5px;color:var(--ink-3);width:46px;flex:none}.empty{display:flex;flex-direction:column;align-items:center;justify-content:center;gap:var(--sp-3);padding:var(--sp-8) var(--sp-5);color:var(--ink-3);text-align:center;font-size:12.5px}.empty svg{opacity:.35}.empty b{display:block;color:var(--ink-2);font-size:13.5px;font-weight:550}.empty p{max-width:34ch;line-height:1.5}.tablewrap{overflow:auto}table{border-collapse:collapse;width:100%;font-size:13px}th{text-align:left;padding:9px var(--sp-4);font-size:10.5px;font-weight:600;letter-spacing:.085em;text-transform:uppercase;color:var(--ink-3);background:var(--s2);border-bottom:1px solid var(--line);position:sticky;top:0;z-index:1}td{padding:10px var(--sp-4);border-bottom:1px solid var(--line-2)}tbody tr:last-child td{border-bottom:0}tbody tr[role=button],tbody tr.clickable{cursor:pointer}tbody tr[role=button]:hover,tbody tr.clickable:hover{background:var(--s2)}.btn{display:inline-flex;align-items:center;gap:7px;padding:8px 14px;border-radius:var(--r-sm);background:var(--s3);color:var(--ink);border:1px solid var(--line);cursor:pointer;font-size:13px;font-weight:550;letter-spacing:-.005em;white-space:nowrap;transition:background .12s ease,border-color .12s ease,transform .06s ease}.btn:hover:not(:disabled){background:#253643;border-color:#2e414e}.btn:active:not(:disabled){transform:translateY(.5px)}.btn:disabled{opacity:.45;cursor:not-allowed}.btn svg{flex:none}.btn.primary{background:var(--accent);color:#04171c;border-color:transparent;font-weight:600}.btn.primary:hover:not(:disabled){background:#55d0e6}.btn.danger{background:var(--bad-2);color:var(--bad);border-color:color-mix(in srgb,var(--bad) 32%,transparent)}.btn.danger:hover:not(:disabled){background:#43201c}.btn.ghost{background:transparent}.btn.ghost:hover:not(:disabled){background:var(--s2)}.btn.sm{padding:5px 10px;font-size:12px}.btn.icon{padding:7px}.linkbtn{background:none;border:0;color:var(--accent);cursor:pointer;font-size:12.5px;padding:2px 0;text-align:left}.linkbtn:hover{text-decoration:underline}.seg{display:inline-flex;background:var(--s2);border:1px solid var(--line);border-radius:var(--r-sm);padding:2px;gap:2px}.seg button{background:none;border:0;border-radius:4px;padding:5px 11px;color:var(--ink-3);cursor:pointer;font-size:12.5px;font-weight:500}.seg button[aria-pressed=true]{background:var(--s3);color:var(--ink)}.field{display:block;margin-bottom:var(--sp-4)}.field>span{display:block;font-size:11.5px;font-weight:550;color:var(--ink-2);margin-bottom:6px}.field input,.field select,.field textarea{width:100%;padding:9px 11px;background:var(--s2);color:var(--ink);border:1px solid var(--line);border-radius:var(--r-sm);transition:border-color .12s ease,background .12s ease,box-shadow .12s ease}.field input::placeholder{color:var(--ink-3)}.field input:hover,.field select:hover,.field textarea:hover{border-color:#2c3d49}.field input:focus,.field select:focus,.field textarea:focus{outline:none;border-color:var(--accent);background:var(--s1);box-shadow:0 0 0 3px var(--accent-3)}.field .hint{display:block;font-size:11.5px;color:var(--ink-3);margin-top:5px;line-height:1.45}.fieldrow{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:var(--sp-3)}.fieldrow.three{grid-template-columns:repeat(3,minmax(0,1fr))}.err{display:flex;align-items:flex-start;gap:var(--sp-2);background:var(--bad-2);color:var(--bad);border:1px solid color-mix(in srgb,var(--bad) 30%,transparent);border-radius:var(--r-sm);padding:9px 11px;font-size:12.5px;line-height:1.45;margin-bottom:var(--sp-4)}.err svg{flex:none;margin-top:1px}.note{color:var(--ink-3);font-size:12px;line-height:1.5}.note.warn{color:var(--warn)}.note.bad{color:var(--bad)}.lead{color:var(--ink-2);font-size:13.5px;line-height:1.55}.sm{font-size:12px}.lbl,.key{color:var(--ink-3);font-size:11.5px}.grow{flex:1}.row{display:flex;align-items:center;gap:var(--sp-3)}.login{height:100%;display:grid;place-items:center;padding:var(--sp-6);overflow:auto;background:radial-gradient(900px 480px at 50% -10%,#10303A 0%,transparent 62%),var(--bg)}.login .box{width:100%;max-width:396px;background:var(--s1);border:1px solid var(--line);border-radius:var(--r-lg);padding:var(--sp-7);box-shadow:var(--shadow-lg)}.login .mark{width:44px;height:44px;margin-bottom:var(--sp-4);display:grid;place-items:center}.login h1{font-family:var(--font-display);font-size:21px;font-weight:600;letter-spacing:-.022em}.login .lead{margin:6px 0 var(--sp-5)}.login .btn{width:100%;justify-content:center;margin-top:var(--sp-1)}.login .foot{font-size:11.5px;color:var(--ink-3);line-height:1.55;margin-top:var(--sp-5);padding-top:var(--sp-4);border-top:1px solid var(--line-2)}.login .alt{margin-top:var(--sp-4);display:flex;flex-direction:column;gap:var(--sp-3)}.login .alt .btn{margin-top:0}.login .note{margin:0}.drawer{position:fixed;top:0;right:0;bottom:0;left:0;z-index:40;background:#04080b99;display:flex;justify-content:flex-end;animation:fade .16s ease}@keyframes fade{0%{opacity:0}to{opacity:1}}.drawer .sheet{width:min(540px,100%);height:100%;overflow:auto;background:var(--s1);border-left:1px solid var(--line);box-shadow:var(--shadow-lg);animation:slidein-r .2s cubic-bezier(.2,.8,.3,1)}@keyframes slidein-r{0%{transform:translate(16px);opacity:.6}to{transform:none;opacity:1}}.drawer .sheethead{position:sticky;top:0;z-index:1;display:flex;align-items:center;justify-content:space-between;gap:var(--sp-3);padding:var(--sp-4) var(--sp-5);background:var(--s1);border-bottom:1px solid var(--line)}.drawer .sheethead h2{font-family:var(--font-display);font-size:17px;font-weight:600;letter-spacing:-.015em}.drawer .sheetbody{padding:var(--sp-5)}.drawer .close{background:none;border:0;color:var(--ink-3);cursor:pointer;padding:6px;border-radius:var(--r-sm);display:grid;place-items:center}.drawer .close:hover{background:var(--s2);color:var(--ink)}.avatar{width:44px;height:44px;border-radius:var(--r-sm);flex:none;display:grid;place-items:center;overflow:hidden;background:var(--s3);border:1px solid var(--line);font-weight:600;color:var(--ink-2);font-variant-numeric:tabular-nums}.avatar img{width:100%;height:100%;object-fit:cover}@media (prefers-reduced-motion: reduce){*,*:before,*:after{animation:none!important;transition:none!important}}.live-split{display:grid;gap:var(--sp-4);grid-template-columns:minmax(0,1.35fr) minmax(0,1fr);align-items:stretch;min-height:420px}.live-split>.panel{max-height:62vh}@media (max-width: 1100px){.live-split{grid-template-columns:minmax(0,1fr)}.live-split>.panel{max-height:none}}.arrivals-panel{max-height:64vh;margin-bottom:var(--sp-4)}.arrivals-panel .arrivals{display:grid;grid-template-columns:repeat(auto-fill,minmax(340px,1fr));gap:var(--sp-2)}.pagehead{display:flex;justify-content:space-between;align-items:flex-end;gap:var(--sp-4)}.page>header.pagehead{margin-bottom:var(--sp-5)}.camgrid{display:grid;gap:var(--sp-4);grid-template-columns:repeat(auto-fill,minmax(440px,1fr))}.camcard{background:var(--s1);border:1px solid var(--line);border-radius:var(--r-lg);overflow:hidden;display:flex;flex-direction:column}.camview{position:relative;aspect-ratio:16 / 9;background:#05090c}.camview img{width:100%;height:100%;object-fit:cover;display:block}.camview .placeholder{width:100%;height:100%;display:grid;place-items:center;color:var(--ink-3)}.camview .pill.over{position:absolute;top:10px;right:10px;-webkit-backdrop-filter:blur(6px);backdrop-filter:blur(6px)}.cambody{padding:var(--sp-4);display:flex;flex-direction:column;gap:var(--sp-3)}.camtitle{display:flex;justify-content:space-between;align-items:flex-start;gap:var(--sp-3)}.camtitle h3{font-family:var(--font-display);font-size:16px;font-weight:600;letter-spacing:-.012em;text-transform:none;color:var(--ink);margin:0 0 2px}.camtitle .note{font-size:12px}.camactions{display:flex;gap:6px;flex:none}.camproof{display:grid;grid-template-columns:auto 1fr auto;align-items:center;gap:var(--sp-3);padding:var(--sp-3);border-radius:var(--r);background:var(--s2);border:1px solid var(--line-2)}.camproof .note{font-size:12px;line-height:1.45}@media (max-width: 640px){.camproof{grid-template-columns:1fr}}.empty.tall{padding:var(--sp-8) var(--sp-6)}.empty.tall .btn{margin-top:var(--sp-3)}.drawer .sheet{width:min(600px,100%)}.sheetbody .lead{color:var(--ink-2);font-size:13.5px;line-height:1.55;margin-bottom:var(--sp-5)}.formsection{margin-bottom:var(--sp-5)}.formsection h4{font-size:11px;font-weight:600;letter-spacing:.09em;text-transform:uppercase;color:var(--ink-3);margin:0 0 var(--sp-3);padding-bottom:6px;border-bottom:1px solid var(--line-2)}.field .hint{font-style:normal}.fieldrow{grid-template-columns:minmax(0,1fr) minmax(0,1fr)}.fieldrow .field.narrow{max-width:140px}.fieldrow:has(.field.narrow){grid-template-columns:minmax(0,1fr) 140px}.field input.mono{font-family:var(--font-mono);font-size:12.5px}.sheetactions{display:flex;gap:var(--sp-2);justify-content:flex-end;padding-top:var(--sp-4);border-top:1px solid var(--line-2);margin-top:var(--sp-2)}.testresult{display:flex;gap:var(--sp-3);align-items:flex-start;padding:var(--sp-3) var(--sp-4);border-radius:var(--r);margin-bottom:var(--sp-4);border:1px solid;font-size:13px}.testresult.ok{background:var(--ok-2);border-color:color-mix(in srgb,var(--ok) 30%,transparent);color:var(--ok)}.testresult.bad{background:var(--bad-2);border-color:color-mix(in srgb,var(--bad) 30%,transparent);color:var(--bad)}.testresult b{display:block}.testresult span{display:block;color:var(--ink-2);margin-top:2px}.testresult img{width:100%;margin-top:var(--sp-3);border-radius:var(--r-sm);border:1px solid var(--line);display:block}.steps{list-style:none;counter-reset:step;margin:0 0 var(--sp-5);padding:0;display:grid;gap:var(--sp-3)}.steps li{counter-increment:step;position:relative;padding:var(--sp-3) var(--sp-4) var(--sp-3) 52px;border-radius:var(--r);border:1px solid var(--line-2);background:var(--s2);opacity:.55}.steps li.now,.steps li.done{opacity:1}.steps li:before{content:counter(step);position:absolute;left:16px;top:14px;width:24px;height:24px;border-radius:50%;display:grid;place-items:center;font-size:12px;font-weight:600;background:var(--s3);color:var(--ink-2);border:1px solid var(--line)}.steps li.now:before{background:var(--accent);color:#041014;border-color:transparent}.steps li.done:before{content:"✓";background:var(--ok-2);color:var(--ok)}.steps b{display:block;font-size:14px}.steps span{display:block;font-size:12.5px;color:var(--ink-2);line-height:1.5;margin-top:2px}.progress{height:4px;background:var(--s3);border-radius:2px;overflow:hidden;margin-top:var(--sp-3)}.progress>div{height:100%;background:var(--accent);transition:width .4s linear}.verdict{padding:var(--sp-4);border-radius:var(--r);border:1px solid var(--line);background:var(--s2)}.verdict.ok{border-color:color-mix(in srgb,var(--ok) 35%,transparent);background:var(--ok-2)}.verdict.warn{border-color:color-mix(in srgb,var(--warn) 35%,transparent);background:var(--warn-2)}.verdict.bad{border-color:color-mix(in srgb,var(--bad) 35%,transparent);background:var(--bad-2)}.verdict-head{display:flex;align-items:center;gap:var(--sp-2);font-size:15px}.verdict.ok .verdict-head{color:var(--ok)}.verdict.warn .verdict-head{color:var(--warn)}.verdict.bad .verdict-head{color:var(--bad)}.verdict ul{margin:var(--sp-3) 0 0 18px;font-size:13px;color:var(--ink);line-height:1.5}.verdict ul li{margin-bottom:5px}.verdict .note{margin-top:var(--sp-3)}.spinner{width:16px;height:16px;border-radius:50%;border:2px solid var(--line);border-top-color:var(--accent);animation:spin .8s linear infinite;display:inline-block}@keyframes spin{to{transform:rotate(360deg)}}.helpbtn{display:flex;align-items:center;gap:9px;margin:0 var(--sp-3) var(--sp-3);padding:9px 10px;border-radius:var(--r);border:1px solid var(--line);background:var(--s2);color:var(--ink);cursor:pointer;font-size:12.5px;font-weight:550;text-align:left}.helpbtn img{width:18px;height:18px;object-fit:contain}.helpbtn span{flex:1}.helpbtn:hover,.helpbtn[aria-pressed=true]{border-color:color-mix(in srgb,var(--accent) 45%,transparent);background:var(--accent-3)}.helper{width:380px;height:100%;display:flex;flex-direction:column;min-height:0;background:var(--s1);border-left:1px solid var(--line);animation:slidein-r .2s cubic-bezier(.2,.8,.3,1)}.helperhead{display:flex;align-items:center;gap:var(--sp-3);padding:var(--sp-4);border-bottom:1px solid var(--line)}.helperhead img{width:26px;height:26px;object-fit:contain}.helperhead div{flex:1;min-width:0}.helperhead b{display:block;font-family:var(--font-display);font-size:14.5px}.helperhead span{display:block;font-size:11.5px;color:var(--ink-3);margin-top:1px}.helperhead .close{background:none;border:0;color:var(--ink-3);cursor:pointer;padding:6px;border-radius:var(--r-sm);display:grid;place-items:center}.helperhead .close:hover{background:var(--s2);color:var(--ink)}.helperbody{flex:1;overflow:auto;padding:var(--sp-4);display:flex;flex-direction:column;gap:var(--sp-3)}.helperintro p{color:var(--ink-2);font-size:13px;line-height:1.55;margin-bottom:var(--sp-3)}.chips{display:flex;flex-wrap:wrap;gap:6px}.chip{border:1px solid var(--line);background:var(--s2);color:var(--ink);border-radius:99px;padding:6px 11px;font-size:12px;cursor:pointer;text-align:left}.chip:hover{border-color:var(--accent);color:var(--accent)}.chip:disabled{opacity:.5;cursor:default}.helpernote{display:flex;gap:var(--sp-3);padding:var(--sp-3);border-radius:var(--r);background:var(--warn-2);border:1px solid color-mix(in srgb,var(--warn) 30%,transparent);color:var(--warn);font-size:12.5px}.helpernote b{display:block}.helpernote span{display:block;color:var(--ink-2);margin-top:2px;line-height:1.45}.turn{display:flex;flex-direction:column;gap:4px}.turn.user{align-items:flex-end}.bubble{max-width:92%;padding:10px 13px;border-radius:14px;font-size:13.5px;line-height:1.5;white-space:pre-wrap}.turn.user .bubble{background:var(--accent);color:#041014;border-bottom-right-radius:4px}.turn.assistant .bubble{background:var(--s2);border:1px solid var(--line);border-bottom-left-radius:4px}.turn .used{font-size:11px;color:var(--ink-3);padding:0 4px}.bubble.thinking{display:flex;gap:4px;padding:12px 14px}.bubble.thinking span{width:6px;height:6px;border-radius:50%;background:var(--ink-3);animation:blink 1.2s infinite ease-in-out}.bubble.thinking span:nth-child(2){animation-delay:.2s}.bubble.thinking span:nth-child(3){animation-delay:.4s}@keyframes blink{0%,80%,to{opacity:.25}40%{opacity:1}}.helperask{display:flex;gap:var(--sp-2);padding:var(--sp-3) var(--sp-4);border-top:1px solid var(--line)}.helperask input{flex:1;min-width:0;background:var(--s2);border:1px solid var(--line);border-radius:var(--r);padding:10px 12px;font-size:13.5px;color:var(--ink)}.helperask input:focus{outline:none;border-color:var(--accent)}.helperask .btn{padding:0 12px}.quickhelp{margin-top:var(--sp-5);border-top:1px solid var(--line-2);padding-top:var(--sp-4)}.quickhelp dt{font-size:12.5px;font-weight:600;margin-top:var(--sp-3)}.quickhelp dd{font-size:12.5px;color:var(--ink-2);line-height:1.5;margin:3px 0 0}@media (max-width: 1100px){.helper{position:fixed;right:0;top:0;bottom:0;z-index:30;box-shadow:var(--shadow-lg)}}.search{display:flex;align-items:center;gap:8px;background:var(--s1);border:1px solid var(--line);border-radius:var(--r);padding:0 12px;height:36px;width:min(340px,100%);color:var(--ink-3)}.search input{flex:1;min-width:0;background:none;border:0;outline:none;color:var(--ink);font-size:13.5px}.search:focus-within{border-color:var(--accent)}.sheethead.who{align-items:center;gap:var(--sp-3)}.sheethead.who .grow{flex:1;min-width:0}.sheethead.who .note{margin-top:2px;font-size:12px}.sheethead .close{font-size:14px;line-height:1}.formsection .field:last-child{margin-bottom:0}.formsection.dangerzone{margin-top:var(--sp-6);padding:var(--sp-4);border:1px solid color-mix(in srgb,var(--bad) 30%,transparent);border-radius:var(--r);background:var(--bad-2)}.formsection.dangerzone h4{color:var(--bad);border-color:color-mix(in srgb,var(--bad) 30%,transparent)}tr.click{cursor:pointer}tr.click:hover td{background:var(--s2)}.loya-fab{position:fixed;top:var(--sp-4);right:var(--sp-5);z-index:20;display:flex;align-items:center;gap:8px;padding:8px 14px 8px 10px;border-radius:99px;border:1px solid color-mix(in srgb,var(--accent) 40%,transparent);background:var(--s1);color:var(--ink);box-shadow:var(--shadow-lg);cursor:pointer;font-size:13px;font-weight:600}.loya-fab img{width:20px;height:20px;object-fit:contain}.loya-fab:hover{background:var(--accent-3);border-color:var(--accent)}.finder{display:flex;flex-direction:column;gap:var(--sp-3);align-items:flex-start;padding:var(--sp-3) var(--sp-4);border:1px dashed var(--line);border-radius:var(--r);background:var(--s2)}.finder p{font-size:13px;color:var(--ink-2);line-height:1.5;margin:0}.finder.busy{flex-direction:row;align-items:center;color:var(--ink-2);font-size:13px;border-style:solid}.foundlist{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:6px}.foundlist li button{width:100%;display:flex;align-items:center;gap:var(--sp-3);padding:10px 12px;border-radius:var(--r);border:1px solid var(--line);background:var(--s2);color:var(--ink);cursor:pointer;text-align:left;font-size:13px}.foundlist li button:hover{border-color:var(--accent)}.foundlist li.picked button{border-color:var(--accent);background:var(--accent-3)}.foundlist .mono{font-family:var(--font-mono);font-size:12.5px;min-width:120px}.foundlist .what{flex:1;color:var(--ink-2)}.foundlist li.rescan button{width:auto;border:0;background:none;padding:4px 0;color:var(--ink-3)}.login .box.wide{max-width:640px}.choices{display:grid;grid-template-columns:1fr 1fr;gap:var(--sp-3);margin-top:var(--sp-2)}@media (max-width: 720px){.choices{grid-template-columns:1fr}}.choice{display:flex;flex-direction:column;align-items:flex-start;gap:8px;text-align:left;padding:var(--sp-4);border-radius:var(--r-lg);border:1px solid var(--line);background:var(--s2);color:var(--ink);cursor:pointer}.choice:hover{border-color:var(--accent);background:var(--accent-3)}.choice b{font-size:14px}.choice span{font-size:12.5px;color:var(--ink-2);line-height:1.5}.choice em{font-family:var(--font-mono);font-style:normal;font-size:11.5px}.choice svg{color:var(--accent)}.login .foot em{font-style:normal;color:var(--ink-2)}.linkbtn{display:inline-flex;align-items:center;gap:6px}.starter{margin-bottom:var(--sp-4)}.starter .panelhead{padding:var(--sp-3) var(--sp-4)}.starter .steps{margin:0;padding:var(--sp-3) var(--sp-4) 0}.starter .steps.compact li{padding:var(--sp-3) var(--sp-4) var(--sp-3) 52px}.starter .steps li .btn{margin-top:var(--sp-2)}.starter .note{padding:var(--sp-3) var(--sp-4);font-size:12px}.btn.ghost{background:none;border-color:transparent;color:var(--ink-3)}.btn.ghost:hover{color:var(--ink)}.viewing{display:flex;gap:10px;align-items:flex-start;padding:12px 14px;margin-bottom:14px;border:1px solid var(--line);border-radius:10px;background:color-mix(in srgb,var(--accent) 7%,transparent);color:var(--ink-2);font-size:13px;line-height:1.5}.viewing b{color:var(--ink);font-weight:600}.viewing svg{flex:none;margin-top:2px;color:var(--accent)} +:root{--bg: #0A0F13;--s1: #111A20;--s2: #17232B;--s3: #1E2D37;--line: #223038;--line-2: #1A252C;--ink: #ECF3F7;--ink-2: #A3B6C2;--ink-3: #6C808D;--accent: #40C4DC;--accent-2: #0F3B47;--accent-3: #0B2A33;--ok: #48C78E;--ok-2: #102E22;--warn: #EAAA3D;--warn-2: #31260F;--bad: #EC6A5C;--bad-2: #331815;--r-sm: 6px;--r: 10px;--r-lg: 14px;--sp-1: 4px;--sp-2: 8px;--sp-3: 12px;--sp-4: 16px;--sp-5: 20px;--sp-6: 24px;--sp-7: 32px;--sp-8: 40px;--shadow: 0 1px 2px rgb(0 0 0 / .4), 0 8px 24px -12px rgb(0 0 0 / .6);--shadow-lg: 0 2px 4px rgb(0 0 0 / .4), 0 24px 48px -16px rgb(0 0 0 / .7);--font: "Segoe UI Variable Text", "Segoe UI", Inter, -apple-system, BlinkMacSystemFont, system-ui, "Helvetica Neue", Arial, sans-serif;--font-display: "Segoe UI Variable Display", var(--font);--mono: "Cascadia Mono", "SFMono-Regular", ui-monospace, Menlo, Consolas, monospace;--ground: var(--bg);--surface: var(--s1);--surface-2: var(--s2);--line-soft: var(--line-2);--muted: var(--ink-3);--radius: var(--r);--accent-dim: var(--accent-3)}*{box-sizing:border-box;margin:0}html,body,#root{height:100%}body{background:var(--bg);color:var(--ink);font-family:var(--font);font-size:14px;line-height:1.5;-webkit-font-smoothing:antialiased;text-rendering:optimizeLegibility;overflow:hidden;-webkit-user-select:none;user-select:none}button,input,select,textarea{font:inherit;color:inherit}input,textarea{-webkit-user-select:text;user-select:text}:focus-visible{outline:2px solid var(--accent);outline-offset:2px;border-radius:3px}::selection{background:var(--accent-2);color:var(--ink)}.num,.value,.metric-v,.when,.mono,.code,td{font-variant-numeric:tabular-nums}.mono,.code{font-family:var(--mono)}*{scrollbar-width:thin;scrollbar-color:var(--s3) transparent}*::-webkit-scrollbar{width:10px;height:10px}*::-webkit-scrollbar-track{background:transparent}*::-webkit-scrollbar-thumb{background:var(--s3);border-radius:99px;border:3px solid var(--bg)}*::-webkit-scrollbar-thumb:hover{background:#2a3d49}.shell{display:grid;grid-template-columns:232px 1fr auto;height:100%}.side{background:var(--s1);border-right:1px solid var(--line);display:flex;flex-direction:column;min-height:0}.side .brand{display:flex;align-items:center;gap:var(--sp-3);padding:var(--sp-5) var(--sp-5) var(--sp-4)}.side .brand .mark{width:30px;height:30px;flex:none;display:grid;place-items:center}.side .brand .mark img,.login .mark img{width:100%;height:100%;object-fit:contain;display:block}.side .brand .id{min-width:0}.side .brand h1{font-family:var(--font-display);font-size:15px;font-weight:600;letter-spacing:-.012em;line-height:1.2}.side .brand p{font-size:11.5px;color:var(--ink-3);margin-top:1px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.nav{padding:var(--sp-2) var(--sp-3);display:flex;flex-direction:column;gap:2px;flex:1}.nav button{position:relative;display:flex;align-items:center;gap:var(--sp-3);width:100%;background:none;border:0;border-radius:var(--r-sm);padding:9px var(--sp-3);color:var(--ink-2);cursor:pointer;text-align:left;font-size:13.5px;font-weight:450;transition:background .12s ease,color .12s ease}.nav button svg{flex:none;opacity:.9}.nav button:hover{background:var(--s2);color:var(--ink)}.nav button[aria-current=page]{background:var(--accent-3);color:var(--accent);font-weight:550}.nav button[aria-current=page]:before{content:"";position:absolute;left:-12px;top:7px;bottom:7px;width:2.5px;border-radius:0 2px 2px 0;background:var(--accent)}.enginebox{margin:var(--sp-3);padding:var(--sp-3) var(--sp-4) var(--sp-4);border:1px solid var(--line);border-radius:var(--r);background:var(--s2)}.enginebox .row{display:flex;align-items:center;gap:var(--sp-2)}.enginebox .state{font-size:12.5px;font-weight:600;letter-spacing:-.005em}.enginebox .label{display:block;color:var(--ink-3);font-size:11px;line-height:1.45;margin-top:3px;font-variant-numeric:tabular-nums}.enginebox .actions,.enginebox .controls{display:flex;gap:var(--sp-2);margin-top:var(--sp-3)}.enginebox .actions .btn,.enginebox .controls .btn{flex:1;justify-content:center;padding:6px 8px;font-size:12px}.side .who{padding:var(--sp-3) var(--sp-5) var(--sp-5);border-top:1px solid var(--line-2);display:flex;align-items:center;gap:var(--sp-3)}.side .who .id{min-width:0;flex:1}.side .who .id b{display:block;font-size:12.5px;font-weight:550}.side .who .id span{display:block;font-size:11px;color:var(--ink-3);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.main{min-width:0;min-height:0;overflow:auto;position:relative}.page{padding:var(--sp-6) var(--sp-7) var(--sp-8);max-width:1500px}.page>header{margin-bottom:var(--sp-5)}.page>header h2,.page h2{font-family:var(--font-display);font-size:22px;font-weight:600;letter-spacing:-.02em;line-height:1.2}.page>header p,.page header p{color:var(--ink-3);font-size:13px;margin-top:3px}.pagehead{display:flex;align-items:flex-start;justify-content:space-between;gap:var(--sp-4);margin-bottom:var(--sp-5);flex-wrap:wrap}h3{font-size:11px;font-weight:600;letter-spacing:.085em;text-transform:uppercase;color:var(--ink-3)}.card{background:var(--s1);border:1px solid var(--line);border-radius:var(--r);padding:var(--sp-4)}.card>h3{margin-bottom:var(--sp-3)}.card.flush{padding:0;overflow:hidden}.panel{background:var(--s1);border:1px solid var(--line);border-radius:var(--r-lg);overflow:hidden;display:flex;flex-direction:column;min-height:0}.panel>.panelhead{display:flex;align-items:center;justify-content:space-between;gap:var(--sp-3);padding:var(--sp-3) var(--sp-4);border-bottom:1px solid var(--line-2);background:linear-gradient(var(--s2),var(--s1));flex:none}.panel>.panelhead h3{margin:0}.panel>.panelbody{padding:var(--sp-4);min-height:0;overflow:auto}.panel>.panelbody.flush{padding:0}.grid{display:grid;gap:var(--sp-4)}.cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.cols-4{grid-template-columns:repeat(4,minmax(0,1fr))}@media (max-width: 1180px){.cols-4{grid-template-columns:repeat(2,minmax(0,1fr))}}@media (max-width: 980px){.cols-2,.cols-3{grid-template-columns:minmax(0,1fr)}}.metrics{display:grid;grid-template-columns:repeat(auto-fit,minmax(152px,1fr));gap:1px;background:var(--line);border:1px solid var(--line);border-radius:var(--r);overflow:hidden}.metric{background:var(--s1);padding:var(--sp-3) var(--sp-4) var(--sp-4)}.metric .metric-k{font-size:10.5px;font-weight:600;letter-spacing:.085em;text-transform:uppercase;color:var(--ink-3)}.metric .metric-v{font-family:var(--font-display);font-size:26px;font-weight:600;letter-spacing:-.025em;line-height:1.1;margin-top:5px}.metric .metric-s{font-size:11.5px;color:var(--ink-3);margin-top:3px;line-height:1.4}.metric.ok .metric-v{color:var(--ok)}.metric.warn .metric-v{color:var(--warn)}.metric.bad .metric-v{color:var(--bad)}.stat h3{margin-bottom:var(--sp-2)}.stat .value{font-family:var(--font-display);font-size:26px;font-weight:600;letter-spacing:-.025em;line-height:1.1}.stat .unit{font-size:15px;color:var(--ink-3);margin-left:3px}.stat .sub{font-size:11.5px;color:var(--ink-3);margin-top:4px;line-height:1.4}.dot{width:7px;height:7px;border-radius:99px;flex:none;background:var(--ink-3)}.dot.ok{background:var(--ok);box-shadow:0 0 0 3px color-mix(in srgb,var(--ok) 18%,transparent)}.dot.warn{background:var(--warn);box-shadow:0 0 0 3px color-mix(in srgb,var(--warn) 18%,transparent)}.dot.bad{background:var(--bad);box-shadow:0 0 0 3px color-mix(in srgb,var(--bad) 18%,transparent)}.dot.idle{background:var(--ink-3)}.dot.live{background:var(--ok);animation:pulse 2.4s ease-in-out infinite}@keyframes pulse{0%,to{box-shadow:0 0 color-mix(in srgb,var(--ok) 55%,transparent)}70%{box-shadow:0 0 0 6px color-mix(in srgb,var(--ok) 0%,transparent)}}.pill{display:inline-flex;align-items:center;gap:6px;padding:3px 9px 3px 7px;border-radius:99px;font-size:11px;font-weight:600;letter-spacing:.02em;background:var(--s3);color:var(--ink-2);border:1px solid var(--line);white-space:nowrap}.pill.ok{background:var(--ok-2);color:var(--ok);border-color:color-mix(in srgb,var(--ok) 28%,transparent)}.pill.warn{background:var(--warn-2);color:var(--warn);border-color:color-mix(in srgb,var(--warn) 28%,transparent)}.pill.bad{background:var(--bad-2);color:var(--bad);border-color:color-mix(in srgb,var(--bad) 28%,transparent)}.pill.accent{background:var(--accent-3);color:var(--accent);border-color:color-mix(in srgb,var(--accent) 30%,transparent)}.tag{display:inline-flex;align-items:center;padding:2px 7px;border-radius:var(--r-sm);font-size:10.5px;font-weight:600;letter-spacing:.04em;text-transform:uppercase;background:var(--s3);color:var(--ink-2)}.tag.new{background:var(--accent-3);color:var(--accent)}.tag.seen{background:var(--ok-2);color:var(--ok)}.tag.miss{background:var(--warn-2);color:var(--warn)}.statusbar{display:flex;align-items:center;gap:var(--sp-5);flex-wrap:wrap;padding:var(--sp-3) var(--sp-4);background:var(--s1);border:1px solid var(--line);border-radius:var(--r);margin-bottom:var(--sp-4)}.statusbar .item{display:flex;align-items:center;gap:var(--sp-2);font-size:12.5px}.statusbar .item b{font-weight:600;letter-spacing:-.005em}.statusbar .item svg{color:var(--ink-3)}.statusbar .sep{width:1px;align-self:stretch;background:var(--line)}.statusbar .grow{flex:1}.arrivals{display:flex;flex-direction:column;gap:var(--sp-2);padding:var(--sp-3)}.arrival{display:grid;grid-template-columns:46px 1fr auto;gap:var(--sp-3);align-items:center;padding:var(--sp-3);border-radius:var(--r);background:var(--s2);border:1px solid var(--line-2);position:relative;overflow:hidden}.arrival:before{content:"";position:absolute;left:0;top:0;bottom:0;width:2.5px;background:var(--ink-3)}.arrival.is-new:before{background:var(--accent)}.arrival.is-seen:before{background:var(--ok)}.arrival.is-miss:before{background:var(--warn)}.arrival.fresh{animation:slidein .28s cubic-bezier(.2,.8,.3,1)}@keyframes slidein{0%{opacity:0;transform:translateY(-6px)}to{opacity:1;transform:none}}.arrival .avatar{width:46px;height:46px;border-radius:var(--r-sm);display:grid;place-items:center;overflow:hidden;background:var(--s3);border:1px solid var(--line);font-family:var(--font-display);font-size:15px;font-weight:600;color:var(--ink-2);letter-spacing:-.01em;font-variant-numeric:tabular-nums}.arrival .avatar img{width:100%;height:100%;object-fit:cover}.arrival.is-new .avatar{background:var(--accent-3);color:var(--accent);border-color:color-mix(in srgb,var(--accent) 25%,transparent)}.arrival .who{min-width:0}.arrival .who .name{font-size:14.5px;font-weight:600;letter-spacing:-.01em;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.arrival .who .meta{font-size:11.5px;color:var(--ink-3);margin-top:2px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.arrival .right{text-align:right;display:flex;flex-direction:column;align-items:flex-end;gap:5px}.arrival .right .when{font-size:11.5px;color:var(--ink-3)}.feeds{display:grid;gap:var(--sp-3);grid-template-columns:repeat(auto-fit,minmax(300px,1fr));padding:var(--sp-3)}.feed{position:relative;border-radius:var(--r);overflow:hidden;background:#05090c;border:1px solid var(--line);aspect-ratio:16 / 9}.feed img{width:100%;height:100%;object-fit:cover;display:block}.feed .placeholder{width:100%;height:100%;display:grid;place-items:center;color:var(--ink-3)}.feed .cap{position:absolute;left:0;right:0;bottom:0;display:flex;align-items:center;justify-content:space-between;gap:var(--sp-2);padding:var(--sp-5) var(--sp-3) var(--sp-3);background:linear-gradient(transparent,#000c);font-size:12.5px;font-weight:600;letter-spacing:-.005em}.events,.timeline{list-style:none;padding:0;display:flex;flex-direction:column}.events li{display:flex;align-items:center;gap:var(--sp-3);padding:9px var(--sp-4);border-bottom:1px solid var(--line-2);font-size:13px}.timeline li{display:flex;align-items:center;gap:var(--sp-3);padding:9px 0;border-bottom:1px solid var(--line-2);font-size:13px}.events li:last-child,.timeline li:last-child{border-bottom:0}.events .when,.timeline .when{font-size:11.5px;color:var(--ink-3);width:46px;flex:none}.empty{display:flex;flex-direction:column;align-items:center;justify-content:center;gap:var(--sp-3);padding:var(--sp-8) var(--sp-5);color:var(--ink-3);text-align:center;font-size:12.5px}.empty svg{opacity:.35}.empty b{display:block;color:var(--ink-2);font-size:13.5px;font-weight:550}.empty p{max-width:34ch;line-height:1.5}.tablewrap{overflow:auto}table{border-collapse:collapse;width:100%;font-size:13px}th{text-align:left;padding:9px var(--sp-4);font-size:10.5px;font-weight:600;letter-spacing:.085em;text-transform:uppercase;color:var(--ink-3);background:var(--s2);border-bottom:1px solid var(--line);position:sticky;top:0;z-index:1}td{padding:10px var(--sp-4);border-bottom:1px solid var(--line-2)}tbody tr:last-child td{border-bottom:0}tbody tr[role=button],tbody tr.clickable{cursor:pointer}tbody tr[role=button]:hover,tbody tr.clickable:hover{background:var(--s2)}.btn{display:inline-flex;align-items:center;gap:7px;padding:8px 14px;border-radius:var(--r-sm);background:var(--s3);color:var(--ink);border:1px solid var(--line);cursor:pointer;font-size:13px;font-weight:550;letter-spacing:-.005em;white-space:nowrap;transition:background .12s ease,border-color .12s ease,transform .06s ease}.btn:hover:not(:disabled){background:#253643;border-color:#2e414e}.btn:active:not(:disabled){transform:translateY(.5px)}.btn:disabled{opacity:.45;cursor:not-allowed}.btn svg{flex:none}.btn.primary{background:var(--accent);color:#04171c;border-color:transparent;font-weight:600}.btn.primary:hover:not(:disabled){background:#55d0e6}.btn.danger{background:var(--bad-2);color:var(--bad);border-color:color-mix(in srgb,var(--bad) 32%,transparent)}.btn.danger:hover:not(:disabled){background:#43201c}.btn.ghost{background:transparent}.btn.ghost:hover:not(:disabled){background:var(--s2)}.btn.sm{padding:5px 10px;font-size:12px}.btn.icon{padding:7px}.linkbtn{background:none;border:0;color:var(--accent);cursor:pointer;font-size:12.5px;padding:2px 0;text-align:left}.linkbtn:hover{text-decoration:underline}.seg{display:inline-flex;background:var(--s2);border:1px solid var(--line);border-radius:var(--r-sm);padding:2px;gap:2px}.seg button{background:none;border:0;border-radius:4px;padding:5px 11px;color:var(--ink-3);cursor:pointer;font-size:12.5px;font-weight:500}.seg button[aria-pressed=true]{background:var(--s3);color:var(--ink)}.field{display:block;margin-bottom:var(--sp-4)}.field>span{display:block;font-size:11.5px;font-weight:550;color:var(--ink-2);margin-bottom:6px}.field input,.field select,.field textarea{width:100%;padding:9px 11px;background:var(--s2);color:var(--ink);border:1px solid var(--line);border-radius:var(--r-sm);transition:border-color .12s ease,background .12s ease,box-shadow .12s ease}.field input::placeholder{color:var(--ink-3)}.field input:hover,.field select:hover,.field textarea:hover{border-color:#2c3d49}.field input:focus,.field select:focus,.field textarea:focus{outline:none;border-color:var(--accent);background:var(--s1);box-shadow:0 0 0 3px var(--accent-3)}.field .hint{display:block;font-size:11.5px;color:var(--ink-3);margin-top:5px;line-height:1.45}.fieldrow{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:var(--sp-3)}.fieldrow.three{grid-template-columns:repeat(3,minmax(0,1fr))}.err{display:flex;align-items:flex-start;gap:var(--sp-2);background:var(--bad-2);color:var(--bad);border:1px solid color-mix(in srgb,var(--bad) 30%,transparent);border-radius:var(--r-sm);padding:9px 11px;font-size:12.5px;line-height:1.45;margin-bottom:var(--sp-4)}.err svg{flex:none;margin-top:1px}.note{color:var(--ink-3);font-size:12px;line-height:1.5}.note.warn{color:var(--warn)}.note.bad{color:var(--bad)}.lead{color:var(--ink-2);font-size:13.5px;line-height:1.55}.sm{font-size:12px}.lbl,.key{color:var(--ink-3);font-size:11.5px}.grow{flex:1}.row{display:flex;align-items:center;gap:var(--sp-3)}.login{height:100%;display:grid;place-items:center;padding:var(--sp-6);overflow:auto;background:radial-gradient(900px 480px at 50% -10%,#10303A 0%,transparent 62%),var(--bg)}.login .box{width:100%;max-width:396px;background:var(--s1);border:1px solid var(--line);border-radius:var(--r-lg);padding:var(--sp-7);box-shadow:var(--shadow-lg)}.login .mark{width:44px;height:44px;margin-bottom:var(--sp-4);display:grid;place-items:center}.login h1{font-family:var(--font-display);font-size:21px;font-weight:600;letter-spacing:-.022em}.login .lead{margin:6px 0 var(--sp-5)}.login .btn{width:100%;justify-content:center;margin-top:var(--sp-1)}.login .foot{font-size:11.5px;color:var(--ink-3);line-height:1.55;margin-top:var(--sp-5);padding-top:var(--sp-4);border-top:1px solid var(--line-2)}.login .alt{margin-top:var(--sp-4);display:flex;flex-direction:column;gap:var(--sp-3)}.login .alt .btn{margin-top:0}.login .note{margin:0}.drawer{position:fixed;top:0;right:0;bottom:0;left:0;z-index:40;background:#04080b99;display:flex;justify-content:flex-end;animation:fade .16s ease}@keyframes fade{0%{opacity:0}to{opacity:1}}.drawer .sheet{width:min(540px,100%);height:100%;overflow:auto;background:var(--s1);border-left:1px solid var(--line);box-shadow:var(--shadow-lg);animation:slidein-r .2s cubic-bezier(.2,.8,.3,1)}@keyframes slidein-r{0%{transform:translate(16px);opacity:.6}to{transform:none;opacity:1}}.drawer .sheethead{position:sticky;top:0;z-index:1;display:flex;align-items:center;justify-content:space-between;gap:var(--sp-3);padding:var(--sp-4) var(--sp-5);background:var(--s1);border-bottom:1px solid var(--line)}.drawer .sheethead h2{font-family:var(--font-display);font-size:17px;font-weight:600;letter-spacing:-.015em}.drawer .sheetbody{padding:var(--sp-5)}.drawer .close{background:none;border:0;color:var(--ink-3);cursor:pointer;padding:6px;border-radius:var(--r-sm);display:grid;place-items:center}.drawer .close:hover{background:var(--s2);color:var(--ink)}.avatar{width:44px;height:44px;border-radius:var(--r-sm);flex:none;display:grid;place-items:center;overflow:hidden;background:var(--s3);border:1px solid var(--line);font-weight:600;color:var(--ink-2);font-variant-numeric:tabular-nums}.avatar img{width:100%;height:100%;object-fit:cover}@media (prefers-reduced-motion: reduce){*,*:before,*:after{animation:none!important;transition:none!important}}.live-split{display:grid;gap:var(--sp-4);grid-template-columns:minmax(0,1.35fr) minmax(0,1fr);align-items:stretch;min-height:420px}.live-split>.panel{max-height:62vh}@media (max-width: 1100px){.live-split{grid-template-columns:minmax(0,1fr)}.live-split>.panel{max-height:none}}.arrivals-panel{max-height:64vh;margin-bottom:var(--sp-4)}.arrivals-panel .arrivals{display:grid;grid-template-columns:repeat(auto-fill,minmax(340px,1fr));gap:var(--sp-2)}.pagehead{display:flex;justify-content:space-between;align-items:flex-end;gap:var(--sp-4)}.page>header.pagehead{margin-bottom:var(--sp-5)}.camgrid{display:grid;gap:var(--sp-4);grid-template-columns:repeat(auto-fill,minmax(440px,1fr))}.camcard{background:var(--s1);border:1px solid var(--line);border-radius:var(--r-lg);overflow:hidden;display:flex;flex-direction:column}.camview{position:relative;aspect-ratio:16 / 9;background:#05090c}.camview img{width:100%;height:100%;object-fit:cover;display:block}.camview .placeholder{width:100%;height:100%;display:grid;place-items:center;color:var(--ink-3)}.camview .pill.over{position:absolute;top:10px;right:10px;-webkit-backdrop-filter:blur(6px);backdrop-filter:blur(6px)}.cambody{padding:var(--sp-4);display:flex;flex-direction:column;gap:var(--sp-3)}.camtitle{display:flex;justify-content:space-between;align-items:flex-start;gap:var(--sp-3)}.camtitle h3{font-family:var(--font-display);font-size:16px;font-weight:600;letter-spacing:-.012em;text-transform:none;color:var(--ink);margin:0 0 2px}.camtitle .note{font-size:12px}.camactions{display:flex;gap:6px;flex:none}.camproof{display:grid;grid-template-columns:auto 1fr auto;align-items:center;gap:var(--sp-3);padding:var(--sp-3);border-radius:var(--r);background:var(--s2);border:1px solid var(--line-2)}.camproof .note{font-size:12px;line-height:1.45}@media (max-width: 640px){.camproof{grid-template-columns:1fr}}.empty.tall{padding:var(--sp-8) var(--sp-6)}.empty.tall .btn{margin-top:var(--sp-3)}.drawer .sheet{width:min(600px,100%)}.sheetbody .lead{color:var(--ink-2);font-size:13.5px;line-height:1.55;margin-bottom:var(--sp-5)}.formsection{margin-bottom:var(--sp-5)}.formsection h4{font-size:11px;font-weight:600;letter-spacing:.09em;text-transform:uppercase;color:var(--ink-3);margin:0 0 var(--sp-3);padding-bottom:6px;border-bottom:1px solid var(--line-2)}.field .hint{font-style:normal}.fieldrow{grid-template-columns:minmax(0,1fr) minmax(0,1fr)}.fieldrow .field.narrow{max-width:140px}.fieldrow:has(.field.narrow){grid-template-columns:minmax(0,1fr) 140px}.field input.mono{font-family:var(--font-mono);font-size:12.5px}.sheetactions{display:flex;gap:var(--sp-2);justify-content:flex-end;padding-top:var(--sp-4);border-top:1px solid var(--line-2);margin-top:var(--sp-2)}.testresult{display:flex;gap:var(--sp-3);align-items:flex-start;padding:var(--sp-3) var(--sp-4);border-radius:var(--r);margin-bottom:var(--sp-4);border:1px solid;font-size:13px}.testresult.ok{background:var(--ok-2);border-color:color-mix(in srgb,var(--ok) 30%,transparent);color:var(--ok)}.testresult.bad{background:var(--bad-2);border-color:color-mix(in srgb,var(--bad) 30%,transparent);color:var(--bad)}.testresult b{display:block}.testresult span{display:block;color:var(--ink-2);margin-top:2px}.testresult img{width:100%;margin-top:var(--sp-3);border-radius:var(--r-sm);border:1px solid var(--line);display:block}.steps{list-style:none;counter-reset:step;margin:0 0 var(--sp-5);padding:0;display:grid;gap:var(--sp-3)}.steps li{counter-increment:step;position:relative;padding:var(--sp-3) var(--sp-4) var(--sp-3) 52px;border-radius:var(--r);border:1px solid var(--line-2);background:var(--s2);opacity:.55}.steps li.now,.steps li.done{opacity:1}.steps li:before{content:counter(step);position:absolute;left:16px;top:14px;width:24px;height:24px;border-radius:50%;display:grid;place-items:center;font-size:12px;font-weight:600;background:var(--s3);color:var(--ink-2);border:1px solid var(--line)}.steps li.now:before{background:var(--accent);color:#041014;border-color:transparent}.steps li.done:before{content:"✓";background:var(--ok-2);color:var(--ok)}.steps b{display:block;font-size:14px}.steps span{display:block;font-size:12.5px;color:var(--ink-2);line-height:1.5;margin-top:2px}.progress{height:4px;background:var(--s3);border-radius:2px;overflow:hidden;margin-top:var(--sp-3)}.progress>div{height:100%;background:var(--accent);transition:width .4s linear}.verdict{padding:var(--sp-4);border-radius:var(--r);border:1px solid var(--line);background:var(--s2)}.verdict.ok{border-color:color-mix(in srgb,var(--ok) 35%,transparent);background:var(--ok-2)}.verdict.warn{border-color:color-mix(in srgb,var(--warn) 35%,transparent);background:var(--warn-2)}.verdict.bad{border-color:color-mix(in srgb,var(--bad) 35%,transparent);background:var(--bad-2)}.verdict-head{display:flex;align-items:center;gap:var(--sp-2);font-size:15px}.verdict.ok .verdict-head{color:var(--ok)}.verdict.warn .verdict-head{color:var(--warn)}.verdict.bad .verdict-head{color:var(--bad)}.verdict ul{margin:var(--sp-3) 0 0 18px;font-size:13px;color:var(--ink);line-height:1.5}.verdict ul li{margin-bottom:5px}.verdict .note{margin-top:var(--sp-3)}.spinner{width:16px;height:16px;border-radius:50%;border:2px solid var(--line);border-top-color:var(--accent);animation:spin .8s linear infinite;display:inline-block}@keyframes spin{to{transform:rotate(360deg)}}.helpbtn{display:flex;align-items:center;gap:9px;margin:0 var(--sp-3) var(--sp-3);padding:9px 10px;border-radius:var(--r);border:1px solid var(--line);background:var(--s2);color:var(--ink);cursor:pointer;font-size:12.5px;font-weight:550;text-align:left}.helpbtn img{width:18px;height:18px;object-fit:contain}.helpbtn span{flex:1}.helpbtn:hover,.helpbtn[aria-pressed=true]{border-color:color-mix(in srgb,var(--accent) 45%,transparent);background:var(--accent-3)}.helper{width:380px;height:100%;display:flex;flex-direction:column;min-height:0;background:var(--s1);border-left:1px solid var(--line);animation:slidein-r .2s cubic-bezier(.2,.8,.3,1)}.helperhead{display:flex;align-items:center;gap:var(--sp-3);padding:var(--sp-4);border-bottom:1px solid var(--line)}.helperhead img{width:26px;height:26px;object-fit:contain}.helperhead div{flex:1;min-width:0}.helperhead b{display:block;font-family:var(--font-display);font-size:14.5px}.helperhead span{display:block;font-size:11.5px;color:var(--ink-3);margin-top:1px}.helperhead .close{background:none;border:0;color:var(--ink-3);cursor:pointer;padding:6px;border-radius:var(--r-sm);display:grid;place-items:center}.helperhead .close:hover{background:var(--s2);color:var(--ink)}.helperbody{flex:1;overflow:auto;padding:var(--sp-4);display:flex;flex-direction:column;gap:var(--sp-3)}.helperintro p{color:var(--ink-2);font-size:13px;line-height:1.55;margin-bottom:var(--sp-3)}.chips{display:flex;flex-wrap:wrap;gap:6px}.chip{border:1px solid var(--line);background:var(--s2);color:var(--ink);border-radius:99px;padding:6px 11px;font-size:12px;cursor:pointer;text-align:left}.chip:hover{border-color:var(--accent);color:var(--accent)}.chip:disabled{opacity:.5;cursor:default}.helpernote{display:flex;gap:var(--sp-3);padding:var(--sp-3);border-radius:var(--r);background:var(--warn-2);border:1px solid color-mix(in srgb,var(--warn) 30%,transparent);color:var(--warn);font-size:12.5px}.helpernote b{display:block}.helpernote span{display:block;color:var(--ink-2);margin-top:2px;line-height:1.45}.turn{display:flex;flex-direction:column;gap:4px}.turn.user{align-items:flex-end}.bubble{max-width:92%;padding:10px 13px;border-radius:14px;font-size:13.5px;line-height:1.5;white-space:pre-wrap}.turn.user .bubble{background:var(--accent);color:#041014;border-bottom-right-radius:4px}.turn.assistant .bubble{background:var(--s2);border:1px solid var(--line);border-bottom-left-radius:4px}.turn .used{font-size:11px;color:var(--ink-3);padding:0 4px}.bubble.thinking{display:flex;gap:4px;padding:12px 14px}.bubble.thinking span{width:6px;height:6px;border-radius:50%;background:var(--ink-3);animation:blink 1.2s infinite ease-in-out}.bubble.thinking span:nth-child(2){animation-delay:.2s}.bubble.thinking span:nth-child(3){animation-delay:.4s}@keyframes blink{0%,80%,to{opacity:.25}40%{opacity:1}}.helperask{display:flex;gap:var(--sp-2);padding:var(--sp-3) var(--sp-4);border-top:1px solid var(--line)}.helperask input{flex:1;min-width:0;background:var(--s2);border:1px solid var(--line);border-radius:var(--r);padding:10px 12px;font-size:13.5px;color:var(--ink)}.helperask input:focus{outline:none;border-color:var(--accent)}.helperask .btn{padding:0 12px}.quickhelp{margin-top:var(--sp-5);border-top:1px solid var(--line-2);padding-top:var(--sp-4)}.quickhelp dt{font-size:12.5px;font-weight:600;margin-top:var(--sp-3)}.quickhelp dd{font-size:12.5px;color:var(--ink-2);line-height:1.5;margin:3px 0 0}@media (max-width: 1100px){.helper{position:fixed;right:0;top:0;bottom:0;z-index:30;box-shadow:var(--shadow-lg)}}.search{display:flex;align-items:center;gap:8px;background:var(--s1);border:1px solid var(--line);border-radius:var(--r);padding:0 12px;height:36px;width:min(340px,100%);color:var(--ink-3)}.search input{flex:1;min-width:0;background:none;border:0;outline:none;color:var(--ink);font-size:13.5px}.search:focus-within{border-color:var(--accent)}.sheethead.who{align-items:center;gap:var(--sp-3)}.sheethead.who .grow{flex:1;min-width:0}.sheethead.who .note{margin-top:2px;font-size:12px}.sheethead .close{font-size:14px;line-height:1}.formsection .field:last-child{margin-bottom:0}.formsection.dangerzone{margin-top:var(--sp-6);padding:var(--sp-4);border:1px solid color-mix(in srgb,var(--bad) 30%,transparent);border-radius:var(--r);background:var(--bad-2)}.formsection.dangerzone h4{color:var(--bad);border-color:color-mix(in srgb,var(--bad) 30%,transparent)}tr.click{cursor:pointer}tr.click:hover td{background:var(--s2)}.loya-fab{position:fixed;top:var(--sp-4);right:var(--sp-5);z-index:20;display:flex;align-items:center;gap:8px;padding:8px 14px 8px 10px;border-radius:99px;border:1px solid color-mix(in srgb,var(--accent) 40%,transparent);background:var(--s1);color:var(--ink);box-shadow:var(--shadow-lg);cursor:pointer;font-size:13px;font-weight:600}.loya-fab img{width:20px;height:20px;object-fit:contain}.loya-fab:hover{background:var(--accent-3);border-color:var(--accent)}.finder{display:flex;flex-direction:column;gap:var(--sp-3);align-items:flex-start;padding:var(--sp-3) var(--sp-4);border:1px dashed var(--line);border-radius:var(--r);background:var(--s2)}.finder p{font-size:13px;color:var(--ink-2);line-height:1.5;margin:0}.finder.busy{flex-direction:row;align-items:center;color:var(--ink-2);font-size:13px;border-style:solid}.foundlist{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:6px}.foundlist li button{width:100%;display:flex;align-items:center;gap:var(--sp-3);padding:10px 12px;border-radius:var(--r);border:1px solid var(--line);background:var(--s2);color:var(--ink);cursor:pointer;text-align:left;font-size:13px}.foundlist li button:hover{border-color:var(--accent)}.foundlist li.picked button{border-color:var(--accent);background:var(--accent-3)}.foundlist .mono{font-family:var(--font-mono);font-size:12.5px;min-width:120px}.foundlist .what{flex:1;color:var(--ink-2)}.foundlist li.rescan button{width:auto;border:0;background:none;padding:4px 0;color:var(--ink-3)}.login .box.wide{max-width:640px}.choices{display:grid;grid-template-columns:1fr 1fr;gap:var(--sp-3);margin-top:var(--sp-2)}@media (max-width: 720px){.choices{grid-template-columns:1fr}}.choice{display:flex;flex-direction:column;align-items:flex-start;gap:8px;text-align:left;padding:var(--sp-4);border-radius:var(--r-lg);border:1px solid var(--line);background:var(--s2);color:var(--ink);cursor:pointer}.choice:hover{border-color:var(--accent);background:var(--accent-3)}.choice b{font-size:14px}.choice span{font-size:12.5px;color:var(--ink-2);line-height:1.5}.choice em{font-family:var(--font-mono);font-style:normal;font-size:11.5px}.choice svg{color:var(--accent)}.login .foot em{font-style:normal;color:var(--ink-2)}.linkbtn{display:inline-flex;align-items:center;gap:6px}.starter{margin-bottom:var(--sp-4)}.starter .panelhead{padding:var(--sp-3) var(--sp-4)}.starter .steps{margin:0;padding:var(--sp-3) var(--sp-4) 0}.starter .steps.compact li{padding:var(--sp-3) var(--sp-4) var(--sp-3) 52px}.starter .steps li .btn{margin-top:var(--sp-2)}.starter .note{padding:var(--sp-3) var(--sp-4);font-size:12px}.btn.ghost{background:none;border-color:transparent;color:var(--ink-3)}.btn.ghost:hover{color:var(--ink)}.viewing{display:flex;gap:10px;align-items:flex-start;padding:12px 14px;margin-bottom:14px;border:1px solid var(--line);border-radius:10px;background:color-mix(in srgb,var(--accent) 7%,transparent);color:var(--ink-2);font-size:13px;line-height:1.5}.viewing b{color:var(--ink);font-weight:600}.viewing svg{flex:none;margin-top:2px;color:var(--accent)}.camview .btn.watch{position:absolute;right:10px;bottom:10px;background:#0000008c;border-color:#ffffff40;color:#fff;-webkit-backdrop-filter:blur(6px);backdrop-filter:blur(6px)}.camview .btn.watch:hover{background:#000000b8}.camview .btn.watch.on{background:var(--accent);border-color:var(--accent);color:#fff} diff --git a/desktop/frontend/dist/assets/index-vAtlvw9l.js b/desktop/frontend/dist/assets/index-vAtlvw9l.js deleted file mode 100644 index 13aafed..0000000 --- a/desktop/frontend/dist/assets/index-vAtlvw9l.js +++ /dev/null @@ -1,40 +0,0 @@ -(function(){const t=document.createElement("link").relList;if(t&&t.supports&&t.supports("modulepreload"))return;for(const l of document.querySelectorAll('link[rel="modulepreload"]'))r(l);new MutationObserver(l=>{for(const s of l)if(s.type==="childList")for(const o of s.addedNodes)o.tagName==="LINK"&&o.rel==="modulepreload"&&r(o)}).observe(document,{childList:!0,subtree:!0});function n(l){const s={};return l.integrity&&(s.integrity=l.integrity),l.referrerPolicy&&(s.referrerPolicy=l.referrerPolicy),l.crossOrigin==="use-credentials"?s.credentials="include":l.crossOrigin==="anonymous"?s.credentials="omit":s.credentials="same-origin",s}function r(l){if(l.ep)return;l.ep=!0;const s=n(l);fetch(l.href,s)}})();function Tc(e){return e&&e.__esModule&&Object.prototype.hasOwnProperty.call(e,"default")?e.default:e}var ua={exports:{}},dl={},ca={exports:{}},D={};/** - * @license React - * react.production.min.js - * - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */var nr=Symbol.for("react.element"),Lc=Symbol.for("react.portal"),Mc=Symbol.for("react.fragment"),Rc=Symbol.for("react.strict_mode"),Dc=Symbol.for("react.profiler"),Oc=Symbol.for("react.provider"),Fc=Symbol.for("react.context"),Ic=Symbol.for("react.forward_ref"),$c=Symbol.for("react.suspense"),Uc=Symbol.for("react.memo"),Ac=Symbol.for("react.lazy"),Gi=Symbol.iterator;function Bc(e){return e===null||typeof e!="object"?null:(e=Gi&&e[Gi]||e["@@iterator"],typeof e=="function"?e:null)}var da={isMounted:function(){return!1},enqueueForceUpdate:function(){},enqueueReplaceState:function(){},enqueueSetState:function(){}},fa=Object.assign,pa={};function pn(e,t,n){this.props=e,this.context=t,this.refs=pa,this.updater=n||da}pn.prototype.isReactComponent={};pn.prototype.setState=function(e,t){if(typeof e!="object"&&typeof e!="function"&&e!=null)throw Error("setState(...): takes an object of state variables to update or a function which returns an object of state variables.");this.updater.enqueueSetState(this,e,t,"setState")};pn.prototype.forceUpdate=function(e){this.updater.enqueueForceUpdate(this,e,"forceUpdate")};function ha(){}ha.prototype=pn.prototype;function Js(e,t,n){this.props=e,this.context=t,this.refs=pa,this.updater=n||da}var qs=Js.prototype=new ha;qs.constructor=Js;fa(qs,pn.prototype);qs.isPureReactComponent=!0;var Xi=Array.isArray,ma=Object.prototype.hasOwnProperty,bs={current:null},va={key:!0,ref:!0,__self:!0,__source:!0};function ga(e,t,n){var r,l={},s=null,o=null;if(t!=null)for(r in t.ref!==void 0&&(o=t.ref),t.key!==void 0&&(s=""+t.key),t)ma.call(t,r)&&!va.hasOwnProperty(r)&&(l[r]=t[r]);var a=arguments.length-2;if(a===1)l.children=n;else if(1>>1,ee=_[G];if(0>>1;Gl(zl,R))Ntl(ar,zl)?(_[G]=ar,_[Nt]=R,G=Nt):(_[G]=zl,_[St]=R,G=St);else if(Ntl(ar,R))_[G]=ar,_[Nt]=R,G=Nt;else break e}}return M}function l(_,M){var R=_.sortIndex-M.sortIndex;return R!==0?R:_.id-M.id}if(typeof performance=="object"&&typeof performance.now=="function"){var s=performance;e.unstable_now=function(){return s.now()}}else{var o=Date,a=o.now();e.unstable_now=function(){return o.now()-a}}var u=[],c=[],p=1,h=null,v=3,g=!1,x=!1,w=!1,L=typeof setTimeout=="function"?setTimeout:null,f=typeof clearTimeout=="function"?clearTimeout:null,d=typeof setImmediate<"u"?setImmediate:null;typeof navigator<"u"&&navigator.scheduling!==void 0&&navigator.scheduling.isInputPending!==void 0&&navigator.scheduling.isInputPending.bind(navigator.scheduling);function m(_){for(var M=n(c);M!==null;){if(M.callback===null)r(c);else if(M.startTime<=_)r(c),M.sortIndex=M.expirationTime,t(u,M);else break;M=n(c)}}function y(_){if(w=!1,m(_),!x)if(n(u)!==null)x=!0,_l(S);else{var M=n(c);M!==null&&Pl(y,M.startTime-_)}}function S(_,M){x=!1,w&&(w=!1,f(E),E=-1),g=!0;var R=v;try{for(m(M),h=n(u);h!==null&&(!(h.expirationTime>M)||_&&!V());){var G=h.callback;if(typeof G=="function"){h.callback=null,v=h.priorityLevel;var ee=G(h.expirationTime<=M);M=e.unstable_now(),typeof ee=="function"?h.callback=ee:h===n(u)&&r(u),m(M)}else r(u);h=n(u)}if(h!==null)var or=!0;else{var St=n(c);St!==null&&Pl(y,St.startTime-M),or=!1}return or}finally{h=null,v=R,g=!1}}var C=!1,k=null,E=-1,z=5,T=-1;function V(){return!(e.unstable_now()-T_||125<_?console.error("forceFrameRate takes a positive int between 0 and 125, forcing frame rates higher than 125 fps is not supported"):z=0<_?Math.floor(1e3/_):5},e.unstable_getCurrentPriorityLevel=function(){return v},e.unstable_getFirstCallbackNode=function(){return n(u)},e.unstable_next=function(_){switch(v){case 1:case 2:case 3:var M=3;break;default:M=v}var R=v;v=M;try{return _()}finally{v=R}},e.unstable_pauseExecution=function(){},e.unstable_requestPaint=function(){},e.unstable_runWithPriority=function(_,M){switch(_){case 1:case 2:case 3:case 4:case 5:break;default:_=3}var R=v;v=_;try{return M()}finally{v=R}},e.unstable_scheduleCallback=function(_,M,R){var G=e.unstable_now();switch(typeof R=="object"&&R!==null?(R=R.delay,R=typeof R=="number"&&0G?(_.sortIndex=R,t(c,_),n(u)===null&&_===n(c)&&(w?(f(E),E=-1):w=!0,Pl(y,R-G))):(_.sortIndex=ee,t(u,_),x||g||(x=!0,_l(S))),_},e.unstable_shouldYield=V,e.unstable_wrapCallback=function(_){var M=v;return function(){var R=v;v=M;try{return _.apply(this,arguments)}finally{v=R}}}})(ka);ja.exports=ka;var bc=ja.exports;/** - * @license React - * react-dom.production.min.js - * - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */var ed=P,Ne=bc;function j(e){for(var t="https://reactjs.org/docs/error-decoder.html?invariant="+e,n=1;n"u"||typeof window.document>"u"||typeof window.document.createElement>"u"),rs=Object.prototype.hasOwnProperty,td=/^[:A-Z_a-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD][:A-Z_a-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD\-.0-9\u00B7\u0300-\u036F\u203F-\u2040]*$/,Ji={},qi={};function nd(e){return rs.call(qi,e)?!0:rs.call(Ji,e)?!1:td.test(e)?qi[e]=!0:(Ji[e]=!0,!1)}function rd(e,t,n,r){if(n!==null&&n.type===0)return!1;switch(typeof t){case"function":case"symbol":return!0;case"boolean":return r?!1:n!==null?!n.acceptsBooleans:(e=e.toLowerCase().slice(0,5),e!=="data-"&&e!=="aria-");default:return!1}}function ld(e,t,n,r){if(t===null||typeof t>"u"||rd(e,t,n,r))return!0;if(r)return!1;if(n!==null)switch(n.type){case 3:return!t;case 4:return t===!1;case 5:return isNaN(t);case 6:return isNaN(t)||1>t}return!1}function he(e,t,n,r,l,s,o){this.acceptsBooleans=t===2||t===3||t===4,this.attributeName=r,this.attributeNamespace=l,this.mustUseProperty=n,this.propertyName=e,this.type=t,this.sanitizeURL=s,this.removeEmptyString=o}var se={};"children dangerouslySetInnerHTML defaultValue defaultChecked innerHTML suppressContentEditableWarning suppressHydrationWarning style".split(" ").forEach(function(e){se[e]=new he(e,0,!1,e,null,!1,!1)});[["acceptCharset","accept-charset"],["className","class"],["htmlFor","for"],["httpEquiv","http-equiv"]].forEach(function(e){var t=e[0];se[t]=new he(t,1,!1,e[1],null,!1,!1)});["contentEditable","draggable","spellCheck","value"].forEach(function(e){se[e]=new he(e,2,!1,e.toLowerCase(),null,!1,!1)});["autoReverse","externalResourcesRequired","focusable","preserveAlpha"].forEach(function(e){se[e]=new he(e,2,!1,e,null,!1,!1)});"allowFullScreen async autoFocus autoPlay controls default defer disabled disablePictureInPicture disableRemotePlayback formNoValidate hidden loop noModule noValidate open playsInline readOnly required reversed scoped seamless itemScope".split(" ").forEach(function(e){se[e]=new he(e,3,!1,e.toLowerCase(),null,!1,!1)});["checked","multiple","muted","selected"].forEach(function(e){se[e]=new he(e,3,!0,e,null,!1,!1)});["capture","download"].forEach(function(e){se[e]=new he(e,4,!1,e,null,!1,!1)});["cols","rows","size","span"].forEach(function(e){se[e]=new he(e,6,!1,e,null,!1,!1)});["rowSpan","start"].forEach(function(e){se[e]=new he(e,5,!1,e.toLowerCase(),null,!1,!1)});var ti=/[\-:]([a-z])/g;function ni(e){return e[1].toUpperCase()}"accent-height alignment-baseline arabic-form baseline-shift cap-height clip-path clip-rule color-interpolation color-interpolation-filters color-profile color-rendering dominant-baseline enable-background fill-opacity fill-rule flood-color flood-opacity font-family font-size font-size-adjust font-stretch font-style font-variant font-weight glyph-name glyph-orientation-horizontal glyph-orientation-vertical horiz-adv-x horiz-origin-x image-rendering letter-spacing lighting-color marker-end marker-mid marker-start overline-position overline-thickness paint-order panose-1 pointer-events rendering-intent shape-rendering stop-color stop-opacity strikethrough-position strikethrough-thickness stroke-dasharray stroke-dashoffset stroke-linecap stroke-linejoin stroke-miterlimit stroke-opacity stroke-width text-anchor text-decoration text-rendering underline-position underline-thickness unicode-bidi unicode-range units-per-em v-alphabetic v-hanging v-ideographic v-mathematical vector-effect vert-adv-y vert-origin-x vert-origin-y word-spacing writing-mode xmlns:xlink x-height".split(" ").forEach(function(e){var t=e.replace(ti,ni);se[t]=new he(t,1,!1,e,null,!1,!1)});"xlink:actuate xlink:arcrole xlink:role xlink:show xlink:title xlink:type".split(" ").forEach(function(e){var t=e.replace(ti,ni);se[t]=new he(t,1,!1,e,"http://www.w3.org/1999/xlink",!1,!1)});["xml:base","xml:lang","xml:space"].forEach(function(e){var t=e.replace(ti,ni);se[t]=new he(t,1,!1,e,"http://www.w3.org/XML/1998/namespace",!1,!1)});["tabIndex","crossOrigin"].forEach(function(e){se[e]=new he(e,1,!1,e.toLowerCase(),null,!1,!1)});se.xlinkHref=new he("xlinkHref",1,!1,"xlink:href","http://www.w3.org/1999/xlink",!0,!1);["src","href","action","formAction"].forEach(function(e){se[e]=new he(e,1,!1,e.toLowerCase(),null,!0,!0)});function ri(e,t,n,r){var l=se.hasOwnProperty(t)?se[t]:null;(l!==null?l.type!==0:r||!(2a||l[o]!==s[a]){var u=` -`+l[o].replace(" at new "," at ");return e.displayName&&u.includes("")&&(u=u.replace("",e.displayName)),u}while(1<=o&&0<=a);break}}}finally{Ml=!1,Error.prepareStackTrace=n}return(e=e?e.displayName||e.name:"")?En(e):""}function sd(e){switch(e.tag){case 5:return En(e.type);case 16:return En("Lazy");case 13:return En("Suspense");case 19:return En("SuspenseList");case 0:case 2:case 15:return e=Rl(e.type,!1),e;case 11:return e=Rl(e.type.render,!1),e;case 1:return e=Rl(e.type,!0),e;default:return""}}function os(e){if(e==null)return null;if(typeof e=="function")return e.displayName||e.name||null;if(typeof e=="string")return e;switch(e){case Bt:return"Fragment";case At:return"Portal";case ls:return"Profiler";case li:return"StrictMode";case ss:return"Suspense";case is:return"SuspenseList"}if(typeof e=="object")switch(e.$$typeof){case Ca:return(e.displayName||"Context")+".Consumer";case Na:return(e._context.displayName||"Context")+".Provider";case si:var t=e.render;return e=e.displayName,e||(e=t.displayName||t.name||"",e=e!==""?"ForwardRef("+e+")":"ForwardRef"),e;case ii:return t=e.displayName||null,t!==null?t:os(e.type)||"Memo";case rt:t=e._payload,e=e._init;try{return os(e(t))}catch{}}return null}function id(e){var t=e.type;switch(e.tag){case 24:return"Cache";case 9:return(t.displayName||"Context")+".Consumer";case 10:return(t._context.displayName||"Context")+".Provider";case 18:return"DehydratedFragment";case 11:return e=t.render,e=e.displayName||e.name||"",t.displayName||(e!==""?"ForwardRef("+e+")":"ForwardRef");case 7:return"Fragment";case 5:return t;case 4:return"Portal";case 3:return"Root";case 6:return"Text";case 16:return os(t);case 8:return t===li?"StrictMode":"Mode";case 22:return"Offscreen";case 12:return"Profiler";case 21:return"Scope";case 13:return"Suspense";case 19:return"SuspenseList";case 25:return"TracingMarker";case 1:case 0:case 17:case 2:case 14:case 15:if(typeof t=="function")return t.displayName||t.name||null;if(typeof t=="string")return t}return null}function yt(e){switch(typeof e){case"boolean":case"number":case"string":case"undefined":return e;case"object":return e;default:return""}}function _a(e){var t=e.type;return(e=e.nodeName)&&e.toLowerCase()==="input"&&(t==="checkbox"||t==="radio")}function od(e){var t=_a(e)?"checked":"value",n=Object.getOwnPropertyDescriptor(e.constructor.prototype,t),r=""+e[t];if(!e.hasOwnProperty(t)&&typeof n<"u"&&typeof n.get=="function"&&typeof n.set=="function"){var l=n.get,s=n.set;return Object.defineProperty(e,t,{configurable:!0,get:function(){return l.call(this)},set:function(o){r=""+o,s.call(this,o)}}),Object.defineProperty(e,t,{enumerable:n.enumerable}),{getValue:function(){return r},setValue:function(o){r=""+o},stopTracking:function(){e._valueTracker=null,delete e[t]}}}}function dr(e){e._valueTracker||(e._valueTracker=od(e))}function Pa(e){if(!e)return!1;var t=e._valueTracker;if(!t)return!0;var n=t.getValue(),r="";return e&&(r=_a(e)?e.checked?"true":"false":e.value),e=r,e!==n?(t.setValue(e),!0):!1}function Br(e){if(e=e||(typeof document<"u"?document:void 0),typeof e>"u")return null;try{return e.activeElement||e.body}catch{return e.body}}function as(e,t){var n=t.checked;return K({},t,{defaultChecked:void 0,defaultValue:void 0,value:void 0,checked:n??e._wrapperState.initialChecked})}function eo(e,t){var n=t.defaultValue==null?"":t.defaultValue,r=t.checked!=null?t.checked:t.defaultChecked;n=yt(t.value!=null?t.value:n),e._wrapperState={initialChecked:r,initialValue:n,controlled:t.type==="checkbox"||t.type==="radio"?t.checked!=null:t.value!=null}}function za(e,t){t=t.checked,t!=null&&ri(e,"checked",t,!1)}function us(e,t){za(e,t);var n=yt(t.value),r=t.type;if(n!=null)r==="number"?(n===0&&e.value===""||e.value!=n)&&(e.value=""+n):e.value!==""+n&&(e.value=""+n);else if(r==="submit"||r==="reset"){e.removeAttribute("value");return}t.hasOwnProperty("value")?cs(e,t.type,n):t.hasOwnProperty("defaultValue")&&cs(e,t.type,yt(t.defaultValue)),t.checked==null&&t.defaultChecked!=null&&(e.defaultChecked=!!t.defaultChecked)}function to(e,t,n){if(t.hasOwnProperty("value")||t.hasOwnProperty("defaultValue")){var r=t.type;if(!(r!=="submit"&&r!=="reset"||t.value!==void 0&&t.value!==null))return;t=""+e._wrapperState.initialValue,n||t===e.value||(e.value=t),e.defaultValue=t}n=e.name,n!==""&&(e.name=""),e.defaultChecked=!!e._wrapperState.initialChecked,n!==""&&(e.name=n)}function cs(e,t,n){(t!=="number"||Br(e.ownerDocument)!==e)&&(n==null?e.defaultValue=""+e._wrapperState.initialValue:e.defaultValue!==""+n&&(e.defaultValue=""+n))}var _n=Array.isArray;function qt(e,t,n,r){if(e=e.options,t){t={};for(var l=0;l"+t.valueOf().toString()+"",t=fr.firstChild;e.firstChild;)e.removeChild(e.firstChild);for(;t.firstChild;)e.appendChild(t.firstChild)}});function An(e,t){if(t){var n=e.firstChild;if(n&&n===e.lastChild&&n.nodeType===3){n.nodeValue=t;return}}e.textContent=t}var Tn={animationIterationCount:!0,aspectRatio:!0,borderImageOutset:!0,borderImageSlice:!0,borderImageWidth:!0,boxFlex:!0,boxFlexGroup:!0,boxOrdinalGroup:!0,columnCount:!0,columns:!0,flex:!0,flexGrow:!0,flexPositive:!0,flexShrink:!0,flexNegative:!0,flexOrder:!0,gridArea:!0,gridRow:!0,gridRowEnd:!0,gridRowSpan:!0,gridRowStart:!0,gridColumn:!0,gridColumnEnd:!0,gridColumnSpan:!0,gridColumnStart:!0,fontWeight:!0,lineClamp:!0,lineHeight:!0,opacity:!0,order:!0,orphans:!0,tabSize:!0,widows:!0,zIndex:!0,zoom:!0,fillOpacity:!0,floodOpacity:!0,stopOpacity:!0,strokeDasharray:!0,strokeDashoffset:!0,strokeMiterlimit:!0,strokeOpacity:!0,strokeWidth:!0},ad=["Webkit","ms","Moz","O"];Object.keys(Tn).forEach(function(e){ad.forEach(function(t){t=t+e.charAt(0).toUpperCase()+e.substring(1),Tn[t]=Tn[e]})});function Ra(e,t,n){return t==null||typeof t=="boolean"||t===""?"":n||typeof t!="number"||t===0||Tn.hasOwnProperty(e)&&Tn[e]?(""+t).trim():t+"px"}function Da(e,t){e=e.style;for(var n in t)if(t.hasOwnProperty(n)){var r=n.indexOf("--")===0,l=Ra(n,t[n],r);n==="float"&&(n="cssFloat"),r?e.setProperty(n,l):e[n]=l}}var ud=K({menuitem:!0},{area:!0,base:!0,br:!0,col:!0,embed:!0,hr:!0,img:!0,input:!0,keygen:!0,link:!0,meta:!0,param:!0,source:!0,track:!0,wbr:!0});function ps(e,t){if(t){if(ud[e]&&(t.children!=null||t.dangerouslySetInnerHTML!=null))throw Error(j(137,e));if(t.dangerouslySetInnerHTML!=null){if(t.children!=null)throw Error(j(60));if(typeof t.dangerouslySetInnerHTML!="object"||!("__html"in t.dangerouslySetInnerHTML))throw Error(j(61))}if(t.style!=null&&typeof t.style!="object")throw Error(j(62))}}function hs(e,t){if(e.indexOf("-")===-1)return typeof t.is=="string";switch(e){case"annotation-xml":case"color-profile":case"font-face":case"font-face-src":case"font-face-uri":case"font-face-format":case"font-face-name":case"missing-glyph":return!1;default:return!0}}var ms=null;function oi(e){return e=e.target||e.srcElement||window,e.correspondingUseElement&&(e=e.correspondingUseElement),e.nodeType===3?e.parentNode:e}var vs=null,bt=null,en=null;function lo(e){if(e=sr(e)){if(typeof vs!="function")throw Error(j(280));var t=e.stateNode;t&&(t=vl(t),vs(e.stateNode,e.type,t))}}function Oa(e){bt?en?en.push(e):en=[e]:bt=e}function Fa(){if(bt){var e=bt,t=en;if(en=bt=null,lo(e),t)for(e=0;e>>=0,e===0?32:31-(wd(e)/jd|0)|0}var pr=64,hr=4194304;function Pn(e){switch(e&-e){case 1:return 1;case 2:return 2;case 4:return 4;case 8:return 8;case 16:return 16;case 32:return 32;case 64:case 128:case 256:case 512:case 1024:case 2048:case 4096:case 8192:case 16384:case 32768:case 65536:case 131072:case 262144:case 524288:case 1048576:case 2097152:return e&4194240;case 4194304:case 8388608:case 16777216:case 33554432:case 67108864:return e&130023424;case 134217728:return 134217728;case 268435456:return 268435456;case 536870912:return 536870912;case 1073741824:return 1073741824;default:return e}}function Qr(e,t){var n=e.pendingLanes;if(n===0)return 0;var r=0,l=e.suspendedLanes,s=e.pingedLanes,o=n&268435455;if(o!==0){var a=o&~l;a!==0?r=Pn(a):(s&=o,s!==0&&(r=Pn(s)))}else o=n&~l,o!==0?r=Pn(o):s!==0&&(r=Pn(s));if(r===0)return 0;if(t!==0&&t!==r&&!(t&l)&&(l=r&-r,s=t&-t,l>=s||l===16&&(s&4194240)!==0))return t;if(r&4&&(r|=n&16),t=e.entangledLanes,t!==0)for(e=e.entanglements,t&=r;0n;n++)t.push(e);return t}function rr(e,t,n){e.pendingLanes|=t,t!==536870912&&(e.suspendedLanes=0,e.pingedLanes=0),e=e.eventTimes,t=31-Ie(t),e[t]=n}function Cd(e,t){var n=e.pendingLanes&~t;e.pendingLanes=t,e.suspendedLanes=0,e.pingedLanes=0,e.expiredLanes&=t,e.mutableReadLanes&=t,e.entangledLanes&=t,t=e.entanglements;var r=e.eventTimes;for(e=e.expirationTimes;0=Mn),ho=" ",mo=!1;function nu(e,t){switch(e){case"keyup":return bd.indexOf(t.keyCode)!==-1;case"keydown":return t.keyCode!==229;case"keypress":case"mousedown":case"focusout":return!0;default:return!1}}function ru(e){return e=e.detail,typeof e=="object"&&"data"in e?e.data:null}var Vt=!1;function tf(e,t){switch(e){case"compositionend":return ru(t);case"keypress":return t.which!==32?null:(mo=!0,ho);case"textInput":return e=t.data,e===ho&&mo?null:e;default:return null}}function nf(e,t){if(Vt)return e==="compositionend"||!mi&&nu(e,t)?(e=eu(),Mr=fi=ot=null,Vt=!1,e):null;switch(e){case"paste":return null;case"keypress":if(!(t.ctrlKey||t.altKey||t.metaKey)||t.ctrlKey&&t.altKey){if(t.char&&1=t)return{node:n,offset:t-e};e=r}e:{for(;n;){if(n.nextSibling){n=n.nextSibling;break e}n=n.parentNode}n=void 0}n=xo(n)}}function ou(e,t){return e&&t?e===t?!0:e&&e.nodeType===3?!1:t&&t.nodeType===3?ou(e,t.parentNode):"contains"in e?e.contains(t):e.compareDocumentPosition?!!(e.compareDocumentPosition(t)&16):!1:!1}function au(){for(var e=window,t=Br();t instanceof e.HTMLIFrameElement;){try{var n=typeof t.contentWindow.location.href=="string"}catch{n=!1}if(n)e=t.contentWindow;else break;t=Br(e.document)}return t}function vi(e){var t=e&&e.nodeName&&e.nodeName.toLowerCase();return t&&(t==="input"&&(e.type==="text"||e.type==="search"||e.type==="tel"||e.type==="url"||e.type==="password")||t==="textarea"||e.contentEditable==="true")}function ff(e){var t=au(),n=e.focusedElem,r=e.selectionRange;if(t!==n&&n&&n.ownerDocument&&ou(n.ownerDocument.documentElement,n)){if(r!==null&&vi(n)){if(t=r.start,e=r.end,e===void 0&&(e=t),"selectionStart"in n)n.selectionStart=t,n.selectionEnd=Math.min(e,n.value.length);else if(e=(t=n.ownerDocument||document)&&t.defaultView||window,e.getSelection){e=e.getSelection();var l=n.textContent.length,s=Math.min(r.start,l);r=r.end===void 0?s:Math.min(r.end,l),!e.extend&&s>r&&(l=r,r=s,s=l),l=wo(n,s);var o=wo(n,r);l&&o&&(e.rangeCount!==1||e.anchorNode!==l.node||e.anchorOffset!==l.offset||e.focusNode!==o.node||e.focusOffset!==o.offset)&&(t=t.createRange(),t.setStart(l.node,l.offset),e.removeAllRanges(),s>r?(e.addRange(t),e.extend(o.node,o.offset)):(t.setEnd(o.node,o.offset),e.addRange(t)))}}for(t=[],e=n;e=e.parentNode;)e.nodeType===1&&t.push({element:e,left:e.scrollLeft,top:e.scrollTop});for(typeof n.focus=="function"&&n.focus(),n=0;n=document.documentMode,Ht=null,ks=null,Dn=null,Ss=!1;function jo(e,t,n){var r=n.window===n?n.document:n.nodeType===9?n:n.ownerDocument;Ss||Ht==null||Ht!==Br(r)||(r=Ht,"selectionStart"in r&&vi(r)?r={start:r.selectionStart,end:r.selectionEnd}:(r=(r.ownerDocument&&r.ownerDocument.defaultView||window).getSelection(),r={anchorNode:r.anchorNode,anchorOffset:r.anchorOffset,focusNode:r.focusNode,focusOffset:r.focusOffset}),Dn&&Kn(Dn,r)||(Dn=r,r=Gr(ks,"onSelect"),0Kt||(e.current=zs[Kt],zs[Kt]=null,Kt--)}function U(e,t){Kt++,zs[Kt]=e.current,e.current=t}var xt={},ue=jt(xt),ge=jt(!1),Mt=xt;function on(e,t){var n=e.type.contextTypes;if(!n)return xt;var r=e.stateNode;if(r&&r.__reactInternalMemoizedUnmaskedChildContext===t)return r.__reactInternalMemoizedMaskedChildContext;var l={},s;for(s in n)l[s]=t[s];return r&&(e=e.stateNode,e.__reactInternalMemoizedUnmaskedChildContext=t,e.__reactInternalMemoizedMaskedChildContext=l),l}function ye(e){return e=e.childContextTypes,e!=null}function Zr(){B(ge),B(ue)}function Po(e,t,n){if(ue.current!==xt)throw Error(j(168));U(ue,t),U(ge,n)}function gu(e,t,n){var r=e.stateNode;if(t=t.childContextTypes,typeof r.getChildContext!="function")return n;r=r.getChildContext();for(var l in r)if(!(l in t))throw Error(j(108,id(e)||"Unknown",l));return K({},n,r)}function Jr(e){return e=(e=e.stateNode)&&e.__reactInternalMemoizedMergedChildContext||xt,Mt=ue.current,U(ue,e),U(ge,ge.current),!0}function zo(e,t,n){var r=e.stateNode;if(!r)throw Error(j(169));n?(e=gu(e,t,Mt),r.__reactInternalMemoizedMergedChildContext=e,B(ge),B(ue),U(ue,e)):B(ge),U(ge,n)}var Ke=null,gl=!1,Yl=!1;function yu(e){Ke===null?Ke=[e]:Ke.push(e)}function Nf(e){gl=!0,yu(e)}function kt(){if(!Yl&&Ke!==null){Yl=!0;var e=0,t=I;try{var n=Ke;for(I=1;e>=o,l-=o,Ye=1<<32-Ie(t)+l|n<E?(z=k,k=null):z=k.sibling;var T=v(f,k,m[E],y);if(T===null){k===null&&(k=z);break}e&&k&&T.alternate===null&&t(f,k),d=s(T,d,E),C===null?S=T:C.sibling=T,C=T,k=z}if(E===m.length)return n(f,k),H&&Ct(f,E),S;if(k===null){for(;EE?(z=k,k=null):z=k.sibling;var V=v(f,k,T.value,y);if(V===null){k===null&&(k=z);break}e&&k&&V.alternate===null&&t(f,k),d=s(V,d,E),C===null?S=V:C.sibling=V,C=V,k=z}if(T.done)return n(f,k),H&&Ct(f,E),S;if(k===null){for(;!T.done;E++,T=m.next())T=h(f,T.value,y),T!==null&&(d=s(T,d,E),C===null?S=T:C.sibling=T,C=T);return H&&Ct(f,E),S}for(k=r(f,k);!T.done;E++,T=m.next())T=g(k,f,E,T.value,y),T!==null&&(e&&T.alternate!==null&&k.delete(T.key===null?E:T.key),d=s(T,d,E),C===null?S=T:C.sibling=T,C=T);return e&&k.forEach(function(vn){return t(f,vn)}),H&&Ct(f,E),S}function L(f,d,m,y){if(typeof m=="object"&&m!==null&&m.type===Bt&&m.key===null&&(m=m.props.children),typeof m=="object"&&m!==null){switch(m.$$typeof){case cr:e:{for(var S=m.key,C=d;C!==null;){if(C.key===S){if(S=m.type,S===Bt){if(C.tag===7){n(f,C.sibling),d=l(C,m.props.children),d.return=f,f=d;break e}}else if(C.elementType===S||typeof S=="object"&&S!==null&&S.$$typeof===rt&&Mo(S)===C.type){n(f,C.sibling),d=l(C,m.props),d.ref=Sn(f,C,m),d.return=f,f=d;break e}n(f,C);break}else t(f,C);C=C.sibling}m.type===Bt?(d=Lt(m.props.children,f.mode,y,m.key),d.return=f,f=d):(y=Ar(m.type,m.key,m.props,null,f.mode,y),y.ref=Sn(f,d,m),y.return=f,f=y)}return o(f);case At:e:{for(C=m.key;d!==null;){if(d.key===C)if(d.tag===4&&d.stateNode.containerInfo===m.containerInfo&&d.stateNode.implementation===m.implementation){n(f,d.sibling),d=l(d,m.children||[]),d.return=f,f=d;break e}else{n(f,d);break}else t(f,d);d=d.sibling}d=ts(m,f.mode,y),d.return=f,f=d}return o(f);case rt:return C=m._init,L(f,d,C(m._payload),y)}if(_n(m))return x(f,d,m,y);if(yn(m))return w(f,d,m,y);jr(f,m)}return typeof m=="string"&&m!==""||typeof m=="number"?(m=""+m,d!==null&&d.tag===6?(n(f,d.sibling),d=l(d,m),d.return=f,f=d):(n(f,d),d=es(m,f.mode,y),d.return=f,f=d),o(f)):n(f,d)}return L}var un=ku(!0),Su=ku(!1),el=jt(null),tl=null,Xt=null,wi=null;function ji(){wi=Xt=tl=null}function ki(e){var t=el.current;B(el),e._currentValue=t}function Ms(e,t,n){for(;e!==null;){var r=e.alternate;if((e.childLanes&t)!==t?(e.childLanes|=t,r!==null&&(r.childLanes|=t)):r!==null&&(r.childLanes&t)!==t&&(r.childLanes|=t),e===n)break;e=e.return}}function nn(e,t){tl=e,wi=Xt=null,e=e.dependencies,e!==null&&e.firstContext!==null&&(e.lanes&t&&(ve=!0),e.firstContext=null)}function Le(e){var t=e._currentValue;if(wi!==e)if(e={context:e,memoizedValue:t,next:null},Xt===null){if(tl===null)throw Error(j(308));Xt=e,tl.dependencies={lanes:0,firstContext:e}}else Xt=Xt.next=e;return t}var Pt=null;function Si(e){Pt===null?Pt=[e]:Pt.push(e)}function Nu(e,t,n,r){var l=t.interleaved;return l===null?(n.next=n,Si(t)):(n.next=l.next,l.next=n),t.interleaved=n,qe(e,r)}function qe(e,t){e.lanes|=t;var n=e.alternate;for(n!==null&&(n.lanes|=t),n=e,e=e.return;e!==null;)e.childLanes|=t,n=e.alternate,n!==null&&(n.childLanes|=t),n=e,e=e.return;return n.tag===3?n.stateNode:null}var lt=!1;function Ni(e){e.updateQueue={baseState:e.memoizedState,firstBaseUpdate:null,lastBaseUpdate:null,shared:{pending:null,interleaved:null,lanes:0},effects:null}}function Cu(e,t){e=e.updateQueue,t.updateQueue===e&&(t.updateQueue={baseState:e.baseState,firstBaseUpdate:e.firstBaseUpdate,lastBaseUpdate:e.lastBaseUpdate,shared:e.shared,effects:e.effects})}function Xe(e,t){return{eventTime:e,lane:t,tag:0,payload:null,callback:null,next:null}}function pt(e,t,n){var r=e.updateQueue;if(r===null)return null;if(r=r.shared,O&2){var l=r.pending;return l===null?t.next=t:(t.next=l.next,l.next=t),r.pending=t,qe(e,n)}return l=r.interleaved,l===null?(t.next=t,Si(r)):(t.next=l.next,l.next=t),r.interleaved=t,qe(e,n)}function Dr(e,t,n){if(t=t.updateQueue,t!==null&&(t=t.shared,(n&4194240)!==0)){var r=t.lanes;r&=e.pendingLanes,n|=r,t.lanes=n,ui(e,n)}}function Ro(e,t){var n=e.updateQueue,r=e.alternate;if(r!==null&&(r=r.updateQueue,n===r)){var l=null,s=null;if(n=n.firstBaseUpdate,n!==null){do{var o={eventTime:n.eventTime,lane:n.lane,tag:n.tag,payload:n.payload,callback:n.callback,next:null};s===null?l=s=o:s=s.next=o,n=n.next}while(n!==null);s===null?l=s=t:s=s.next=t}else l=s=t;n={baseState:r.baseState,firstBaseUpdate:l,lastBaseUpdate:s,shared:r.shared,effects:r.effects},e.updateQueue=n;return}e=n.lastBaseUpdate,e===null?n.firstBaseUpdate=t:e.next=t,n.lastBaseUpdate=t}function nl(e,t,n,r){var l=e.updateQueue;lt=!1;var s=l.firstBaseUpdate,o=l.lastBaseUpdate,a=l.shared.pending;if(a!==null){l.shared.pending=null;var u=a,c=u.next;u.next=null,o===null?s=c:o.next=c,o=u;var p=e.alternate;p!==null&&(p=p.updateQueue,a=p.lastBaseUpdate,a!==o&&(a===null?p.firstBaseUpdate=c:a.next=c,p.lastBaseUpdate=u))}if(s!==null){var h=l.baseState;o=0,p=c=u=null,a=s;do{var v=a.lane,g=a.eventTime;if((r&v)===v){p!==null&&(p=p.next={eventTime:g,lane:0,tag:a.tag,payload:a.payload,callback:a.callback,next:null});e:{var x=e,w=a;switch(v=t,g=n,w.tag){case 1:if(x=w.payload,typeof x=="function"){h=x.call(g,h,v);break e}h=x;break e;case 3:x.flags=x.flags&-65537|128;case 0:if(x=w.payload,v=typeof x=="function"?x.call(g,h,v):x,v==null)break e;h=K({},h,v);break e;case 2:lt=!0}}a.callback!==null&&a.lane!==0&&(e.flags|=64,v=l.effects,v===null?l.effects=[a]:v.push(a))}else g={eventTime:g,lane:v,tag:a.tag,payload:a.payload,callback:a.callback,next:null},p===null?(c=p=g,u=h):p=p.next=g,o|=v;if(a=a.next,a===null){if(a=l.shared.pending,a===null)break;v=a,a=v.next,v.next=null,l.lastBaseUpdate=v,l.shared.pending=null}}while(!0);if(p===null&&(u=h),l.baseState=u,l.firstBaseUpdate=c,l.lastBaseUpdate=p,t=l.shared.interleaved,t!==null){l=t;do o|=l.lane,l=l.next;while(l!==t)}else s===null&&(l.shared.lanes=0);Ot|=o,e.lanes=o,e.memoizedState=h}}function Do(e,t,n){if(e=t.effects,t.effects=null,e!==null)for(t=0;tn?n:4,e(!0);var r=Xl.transition;Xl.transition={};try{e(!1),t()}finally{I=n,Xl.transition=r}}function Vu(){return Me().memoizedState}function Pf(e,t,n){var r=mt(e);if(n={lane:r,action:n,hasEagerState:!1,eagerState:null,next:null},Hu(e))Wu(t,n);else if(n=Nu(e,t,n,r),n!==null){var l=de();$e(n,e,r,l),Qu(n,t,r)}}function zf(e,t,n){var r=mt(e),l={lane:r,action:n,hasEagerState:!1,eagerState:null,next:null};if(Hu(e))Wu(t,l);else{var s=e.alternate;if(e.lanes===0&&(s===null||s.lanes===0)&&(s=t.lastRenderedReducer,s!==null))try{var o=t.lastRenderedState,a=s(o,n);if(l.hasEagerState=!0,l.eagerState=a,Ue(a,o)){var u=t.interleaved;u===null?(l.next=l,Si(t)):(l.next=u.next,u.next=l),t.interleaved=l;return}}catch{}finally{}n=Nu(e,t,l,r),n!==null&&(l=de(),$e(n,e,r,l),Qu(n,t,r))}}function Hu(e){var t=e.alternate;return e===Q||t!==null&&t===Q}function Wu(e,t){On=ll=!0;var n=e.pending;n===null?t.next=t:(t.next=n.next,n.next=t),e.pending=t}function Qu(e,t,n){if(n&4194240){var r=t.lanes;r&=e.pendingLanes,n|=r,t.lanes=n,ui(e,n)}}var sl={readContext:Le,useCallback:ie,useContext:ie,useEffect:ie,useImperativeHandle:ie,useInsertionEffect:ie,useLayoutEffect:ie,useMemo:ie,useReducer:ie,useRef:ie,useState:ie,useDebugValue:ie,useDeferredValue:ie,useTransition:ie,useMutableSource:ie,useSyncExternalStore:ie,useId:ie,unstable_isNewReconciler:!1},Tf={readContext:Le,useCallback:function(e,t){return Be().memoizedState=[e,t===void 0?null:t],e},useContext:Le,useEffect:Fo,useImperativeHandle:function(e,t,n){return n=n!=null?n.concat([e]):null,Fr(4194308,4,Iu.bind(null,t,e),n)},useLayoutEffect:function(e,t){return Fr(4194308,4,e,t)},useInsertionEffect:function(e,t){return Fr(4,2,e,t)},useMemo:function(e,t){var n=Be();return t=t===void 0?null:t,e=e(),n.memoizedState=[e,t],e},useReducer:function(e,t,n){var r=Be();return t=n!==void 0?n(t):t,r.memoizedState=r.baseState=t,e={pending:null,interleaved:null,lanes:0,dispatch:null,lastRenderedReducer:e,lastRenderedState:t},r.queue=e,e=e.dispatch=Pf.bind(null,Q,e),[r.memoizedState,e]},useRef:function(e){var t=Be();return e={current:e},t.memoizedState=e},useState:Oo,useDebugValue:Mi,useDeferredValue:function(e){return Be().memoizedState=e},useTransition:function(){var e=Oo(!1),t=e[0];return e=_f.bind(null,e[1]),Be().memoizedState=e,[t,e]},useMutableSource:function(){},useSyncExternalStore:function(e,t,n){var r=Q,l=Be();if(H){if(n===void 0)throw Error(j(407));n=n()}else{if(n=t(),ne===null)throw Error(j(349));Dt&30||zu(r,t,n)}l.memoizedState=n;var s={value:n,getSnapshot:t};return l.queue=s,Fo(Lu.bind(null,r,s,e),[e]),r.flags|=2048,er(9,Tu.bind(null,r,s,n,t),void 0,null),n},useId:function(){var e=Be(),t=ne.identifierPrefix;if(H){var n=Ge,r=Ye;n=(r&~(1<<32-Ie(r)-1)).toString(32)+n,t=":"+t+"R"+n,n=qn++,0<\/script>",e=e.removeChild(e.firstChild)):typeof r.is=="string"?e=o.createElement(n,{is:r.is}):(e=o.createElement(n),n==="select"&&(o=e,r.multiple?o.multiple=!0:r.size&&(o.size=r.size))):e=o.createElementNS(e,n),e[Ve]=t,e[Xn]=r,tc(e,t,!1,!1),t.stateNode=e;e:{switch(o=hs(n,r),n){case"dialog":A("cancel",e),A("close",e),l=r;break;case"iframe":case"object":case"embed":A("load",e),l=r;break;case"video":case"audio":for(l=0;lfn&&(t.flags|=128,r=!0,Nn(s,!1),t.lanes=4194304)}else{if(!r)if(e=rl(o),e!==null){if(t.flags|=128,r=!0,n=e.updateQueue,n!==null&&(t.updateQueue=n,t.flags|=4),Nn(s,!0),s.tail===null&&s.tailMode==="hidden"&&!o.alternate&&!H)return oe(t),null}else 2*X()-s.renderingStartTime>fn&&n!==1073741824&&(t.flags|=128,r=!0,Nn(s,!1),t.lanes=4194304);s.isBackwards?(o.sibling=t.child,t.child=o):(n=s.last,n!==null?n.sibling=o:t.child=o,s.last=o)}return s.tail!==null?(t=s.tail,s.rendering=t,s.tail=t.sibling,s.renderingStartTime=X(),t.sibling=null,n=W.current,U(W,r?n&1|2:n&1),t):(oe(t),null);case 22:case 23:return $i(),r=t.memoizedState!==null,e!==null&&e.memoizedState!==null!==r&&(t.flags|=8192),r&&t.mode&1?we&1073741824&&(oe(t),t.subtreeFlags&6&&(t.flags|=8192)):oe(t),null;case 24:return null;case 25:return null}throw Error(j(156,t.tag))}function $f(e,t){switch(yi(t),t.tag){case 1:return ye(t.type)&&Zr(),e=t.flags,e&65536?(t.flags=e&-65537|128,t):null;case 3:return cn(),B(ge),B(ue),_i(),e=t.flags,e&65536&&!(e&128)?(t.flags=e&-65537|128,t):null;case 5:return Ei(t),null;case 13:if(B(W),e=t.memoizedState,e!==null&&e.dehydrated!==null){if(t.alternate===null)throw Error(j(340));an()}return e=t.flags,e&65536?(t.flags=e&-65537|128,t):null;case 19:return B(W),null;case 4:return cn(),null;case 10:return ki(t.type._context),null;case 22:case 23:return $i(),null;case 24:return null;default:return null}}var Sr=!1,ae=!1,Uf=typeof WeakSet=="function"?WeakSet:Set,N=null;function Zt(e,t){var n=e.ref;if(n!==null)if(typeof n=="function")try{n(null)}catch(r){Y(e,t,r)}else n.current=null}function Bs(e,t,n){try{n()}catch(r){Y(e,t,r)}}var Yo=!1;function Af(e,t){if(Ns=Kr,e=au(),vi(e)){if("selectionStart"in e)var n={start:e.selectionStart,end:e.selectionEnd};else e:{n=(n=e.ownerDocument)&&n.defaultView||window;var r=n.getSelection&&n.getSelection();if(r&&r.rangeCount!==0){n=r.anchorNode;var l=r.anchorOffset,s=r.focusNode;r=r.focusOffset;try{n.nodeType,s.nodeType}catch{n=null;break e}var o=0,a=-1,u=-1,c=0,p=0,h=e,v=null;t:for(;;){for(var g;h!==n||l!==0&&h.nodeType!==3||(a=o+l),h!==s||r!==0&&h.nodeType!==3||(u=o+r),h.nodeType===3&&(o+=h.nodeValue.length),(g=h.firstChild)!==null;)v=h,h=g;for(;;){if(h===e)break t;if(v===n&&++c===l&&(a=o),v===s&&++p===r&&(u=o),(g=h.nextSibling)!==null)break;h=v,v=h.parentNode}h=g}n=a===-1||u===-1?null:{start:a,end:u}}else n=null}n=n||{start:0,end:0}}else n=null;for(Cs={focusedElem:e,selectionRange:n},Kr=!1,N=t;N!==null;)if(t=N,e=t.child,(t.subtreeFlags&1028)!==0&&e!==null)e.return=t,N=e;else for(;N!==null;){t=N;try{var x=t.alternate;if(t.flags&1024)switch(t.tag){case 0:case 11:case 15:break;case 1:if(x!==null){var w=x.memoizedProps,L=x.memoizedState,f=t.stateNode,d=f.getSnapshotBeforeUpdate(t.elementType===t.type?w:De(t.type,w),L);f.__reactInternalSnapshotBeforeUpdate=d}break;case 3:var m=t.stateNode.containerInfo;m.nodeType===1?m.textContent="":m.nodeType===9&&m.documentElement&&m.removeChild(m.documentElement);break;case 5:case 6:case 4:case 17:break;default:throw Error(j(163))}}catch(y){Y(t,t.return,y)}if(e=t.sibling,e!==null){e.return=t.return,N=e;break}N=t.return}return x=Yo,Yo=!1,x}function Fn(e,t,n){var r=t.updateQueue;if(r=r!==null?r.lastEffect:null,r!==null){var l=r=r.next;do{if((l.tag&e)===e){var s=l.destroy;l.destroy=void 0,s!==void 0&&Bs(t,n,s)}l=l.next}while(l!==r)}}function wl(e,t){if(t=t.updateQueue,t=t!==null?t.lastEffect:null,t!==null){var n=t=t.next;do{if((n.tag&e)===e){var r=n.create;n.destroy=r()}n=n.next}while(n!==t)}}function Vs(e){var t=e.ref;if(t!==null){var n=e.stateNode;switch(e.tag){case 5:e=n;break;default:e=n}typeof t=="function"?t(e):t.current=e}}function lc(e){var t=e.alternate;t!==null&&(e.alternate=null,lc(t)),e.child=null,e.deletions=null,e.sibling=null,e.tag===5&&(t=e.stateNode,t!==null&&(delete t[Ve],delete t[Xn],delete t[Ps],delete t[kf],delete t[Sf])),e.stateNode=null,e.return=null,e.dependencies=null,e.memoizedProps=null,e.memoizedState=null,e.pendingProps=null,e.stateNode=null,e.updateQueue=null}function sc(e){return e.tag===5||e.tag===3||e.tag===4}function Go(e){e:for(;;){for(;e.sibling===null;){if(e.return===null||sc(e.return))return null;e=e.return}for(e.sibling.return=e.return,e=e.sibling;e.tag!==5&&e.tag!==6&&e.tag!==18;){if(e.flags&2||e.child===null||e.tag===4)continue e;e.child.return=e,e=e.child}if(!(e.flags&2))return e.stateNode}}function Hs(e,t,n){var r=e.tag;if(r===5||r===6)e=e.stateNode,t?n.nodeType===8?n.parentNode.insertBefore(e,t):n.insertBefore(e,t):(n.nodeType===8?(t=n.parentNode,t.insertBefore(e,n)):(t=n,t.appendChild(e)),n=n._reactRootContainer,n!=null||t.onclick!==null||(t.onclick=Xr));else if(r!==4&&(e=e.child,e!==null))for(Hs(e,t,n),e=e.sibling;e!==null;)Hs(e,t,n),e=e.sibling}function Ws(e,t,n){var r=e.tag;if(r===5||r===6)e=e.stateNode,t?n.insertBefore(e,t):n.appendChild(e);else if(r!==4&&(e=e.child,e!==null))for(Ws(e,t,n),e=e.sibling;e!==null;)Ws(e,t,n),e=e.sibling}var re=null,Oe=!1;function nt(e,t,n){for(n=n.child;n!==null;)ic(e,t,n),n=n.sibling}function ic(e,t,n){if(He&&typeof He.onCommitFiberUnmount=="function")try{He.onCommitFiberUnmount(fl,n)}catch{}switch(n.tag){case 5:ae||Zt(n,t);case 6:var r=re,l=Oe;re=null,nt(e,t,n),re=r,Oe=l,re!==null&&(Oe?(e=re,n=n.stateNode,e.nodeType===8?e.parentNode.removeChild(n):e.removeChild(n)):re.removeChild(n.stateNode));break;case 18:re!==null&&(Oe?(e=re,n=n.stateNode,e.nodeType===8?Kl(e.parentNode,n):e.nodeType===1&&Kl(e,n),Wn(e)):Kl(re,n.stateNode));break;case 4:r=re,l=Oe,re=n.stateNode.containerInfo,Oe=!0,nt(e,t,n),re=r,Oe=l;break;case 0:case 11:case 14:case 15:if(!ae&&(r=n.updateQueue,r!==null&&(r=r.lastEffect,r!==null))){l=r=r.next;do{var s=l,o=s.destroy;s=s.tag,o!==void 0&&(s&2||s&4)&&Bs(n,t,o),l=l.next}while(l!==r)}nt(e,t,n);break;case 1:if(!ae&&(Zt(n,t),r=n.stateNode,typeof r.componentWillUnmount=="function"))try{r.props=n.memoizedProps,r.state=n.memoizedState,r.componentWillUnmount()}catch(a){Y(n,t,a)}nt(e,t,n);break;case 21:nt(e,t,n);break;case 22:n.mode&1?(ae=(r=ae)||n.memoizedState!==null,nt(e,t,n),ae=r):nt(e,t,n);break;default:nt(e,t,n)}}function Xo(e){var t=e.updateQueue;if(t!==null){e.updateQueue=null;var n=e.stateNode;n===null&&(n=e.stateNode=new Uf),t.forEach(function(r){var l=Xf.bind(null,e,r);n.has(r)||(n.add(r),r.then(l,l))})}}function Re(e,t){var n=t.deletions;if(n!==null)for(var r=0;rl&&(l=o),r&=~s}if(r=l,r=X()-r,r=(120>r?120:480>r?480:1080>r?1080:1920>r?1920:3e3>r?3e3:4320>r?4320:1960*Vf(r/1960))-r,10e?16:e,at===null)var r=!1;else{if(e=at,at=null,al=0,O&6)throw Error(j(331));var l=O;for(O|=4,N=e.current;N!==null;){var s=N,o=s.child;if(N.flags&16){var a=s.deletions;if(a!==null){for(var u=0;uX()-Fi?Tt(e,0):Oi|=n),xe(e,t)}function hc(e,t){t===0&&(e.mode&1?(t=hr,hr<<=1,!(hr&130023424)&&(hr=4194304)):t=1);var n=de();e=qe(e,t),e!==null&&(rr(e,t,n),xe(e,n))}function Gf(e){var t=e.memoizedState,n=0;t!==null&&(n=t.retryLane),hc(e,n)}function Xf(e,t){var n=0;switch(e.tag){case 13:var r=e.stateNode,l=e.memoizedState;l!==null&&(n=l.retryLane);break;case 19:r=e.stateNode;break;default:throw Error(j(314))}r!==null&&r.delete(t),hc(e,n)}var mc;mc=function(e,t,n){if(e!==null)if(e.memoizedProps!==t.pendingProps||ge.current)ve=!0;else{if(!(e.lanes&n)&&!(t.flags&128))return ve=!1,Ff(e,t,n);ve=!!(e.flags&131072)}else ve=!1,H&&t.flags&1048576&&xu(t,br,t.index);switch(t.lanes=0,t.tag){case 2:var r=t.type;Ir(e,t),e=t.pendingProps;var l=on(t,ue.current);nn(t,n),l=zi(null,t,r,e,l,n);var s=Ti();return t.flags|=1,typeof l=="object"&&l!==null&&typeof l.render=="function"&&l.$$typeof===void 0?(t.tag=1,t.memoizedState=null,t.updateQueue=null,ye(r)?(s=!0,Jr(t)):s=!1,t.memoizedState=l.state!==null&&l.state!==void 0?l.state:null,Ni(t),l.updater=xl,t.stateNode=l,l._reactInternals=t,Ds(t,r,e,n),t=Is(null,t,r,!0,s,n)):(t.tag=0,H&&s&&gi(t),ce(null,t,l,n),t=t.child),t;case 16:r=t.elementType;e:{switch(Ir(e,t),e=t.pendingProps,l=r._init,r=l(r._payload),t.type=r,l=t.tag=Jf(r),e=De(r,e),l){case 0:t=Fs(null,t,r,e,n);break e;case 1:t=Wo(null,t,r,e,n);break e;case 11:t=Vo(null,t,r,e,n);break e;case 14:t=Ho(null,t,r,De(r.type,e),n);break e}throw Error(j(306,r,""))}return t;case 0:return r=t.type,l=t.pendingProps,l=t.elementType===r?l:De(r,l),Fs(e,t,r,l,n);case 1:return r=t.type,l=t.pendingProps,l=t.elementType===r?l:De(r,l),Wo(e,t,r,l,n);case 3:e:{if(qu(t),e===null)throw Error(j(387));r=t.pendingProps,s=t.memoizedState,l=s.element,Cu(e,t),nl(t,r,null,n);var o=t.memoizedState;if(r=o.element,s.isDehydrated)if(s={element:r,isDehydrated:!1,cache:o.cache,pendingSuspenseBoundaries:o.pendingSuspenseBoundaries,transitions:o.transitions},t.updateQueue.baseState=s,t.memoizedState=s,t.flags&256){l=dn(Error(j(423)),t),t=Qo(e,t,r,n,l);break e}else if(r!==l){l=dn(Error(j(424)),t),t=Qo(e,t,r,n,l);break e}else for(je=ft(t.stateNode.containerInfo.firstChild),ke=t,H=!0,Fe=null,n=Su(t,null,r,n),t.child=n;n;)n.flags=n.flags&-3|4096,n=n.sibling;else{if(an(),r===l){t=be(e,t,n);break e}ce(e,t,r,n)}t=t.child}return t;case 5:return Eu(t),e===null&&Ls(t),r=t.type,l=t.pendingProps,s=e!==null?e.memoizedProps:null,o=l.children,Es(r,l)?o=null:s!==null&&Es(r,s)&&(t.flags|=32),Ju(e,t),ce(e,t,o,n),t.child;case 6:return e===null&&Ls(t),null;case 13:return bu(e,t,n);case 4:return Ci(t,t.stateNode.containerInfo),r=t.pendingProps,e===null?t.child=un(t,null,r,n):ce(e,t,r,n),t.child;case 11:return r=t.type,l=t.pendingProps,l=t.elementType===r?l:De(r,l),Vo(e,t,r,l,n);case 7:return ce(e,t,t.pendingProps,n),t.child;case 8:return ce(e,t,t.pendingProps.children,n),t.child;case 12:return ce(e,t,t.pendingProps.children,n),t.child;case 10:e:{if(r=t.type._context,l=t.pendingProps,s=t.memoizedProps,o=l.value,U(el,r._currentValue),r._currentValue=o,s!==null)if(Ue(s.value,o)){if(s.children===l.children&&!ge.current){t=be(e,t,n);break e}}else for(s=t.child,s!==null&&(s.return=t);s!==null;){var a=s.dependencies;if(a!==null){o=s.child;for(var u=a.firstContext;u!==null;){if(u.context===r){if(s.tag===1){u=Xe(-1,n&-n),u.tag=2;var c=s.updateQueue;if(c!==null){c=c.shared;var p=c.pending;p===null?u.next=u:(u.next=p.next,p.next=u),c.pending=u}}s.lanes|=n,u=s.alternate,u!==null&&(u.lanes|=n),Ms(s.return,n,t),a.lanes|=n;break}u=u.next}}else if(s.tag===10)o=s.type===t.type?null:s.child;else if(s.tag===18){if(o=s.return,o===null)throw Error(j(341));o.lanes|=n,a=o.alternate,a!==null&&(a.lanes|=n),Ms(o,n,t),o=s.sibling}else o=s.child;if(o!==null)o.return=s;else for(o=s;o!==null;){if(o===t){o=null;break}if(s=o.sibling,s!==null){s.return=o.return,o=s;break}o=o.return}s=o}ce(e,t,l.children,n),t=t.child}return t;case 9:return l=t.type,r=t.pendingProps.children,nn(t,n),l=Le(l),r=r(l),t.flags|=1,ce(e,t,r,n),t.child;case 14:return r=t.type,l=De(r,t.pendingProps),l=De(r.type,l),Ho(e,t,r,l,n);case 15:return Xu(e,t,t.type,t.pendingProps,n);case 17:return r=t.type,l=t.pendingProps,l=t.elementType===r?l:De(r,l),Ir(e,t),t.tag=1,ye(r)?(e=!0,Jr(t)):e=!1,nn(t,n),Ku(t,r,l),Ds(t,r,l,n),Is(null,t,r,!0,e,n);case 19:return ec(e,t,n);case 22:return Zu(e,t,n)}throw Error(j(156,t.tag))};function vc(e,t){return Ha(e,t)}function Zf(e,t,n,r){this.tag=e,this.key=n,this.sibling=this.child=this.return=this.stateNode=this.type=this.elementType=null,this.index=0,this.ref=null,this.pendingProps=t,this.dependencies=this.memoizedState=this.updateQueue=this.memoizedProps=null,this.mode=r,this.subtreeFlags=this.flags=0,this.deletions=null,this.childLanes=this.lanes=0,this.alternate=null}function ze(e,t,n,r){return new Zf(e,t,n,r)}function Ai(e){return e=e.prototype,!(!e||!e.isReactComponent)}function Jf(e){if(typeof e=="function")return Ai(e)?1:0;if(e!=null){if(e=e.$$typeof,e===si)return 11;if(e===ii)return 14}return 2}function vt(e,t){var n=e.alternate;return n===null?(n=ze(e.tag,t,e.key,e.mode),n.elementType=e.elementType,n.type=e.type,n.stateNode=e.stateNode,n.alternate=e,e.alternate=n):(n.pendingProps=t,n.type=e.type,n.flags=0,n.subtreeFlags=0,n.deletions=null),n.flags=e.flags&14680064,n.childLanes=e.childLanes,n.lanes=e.lanes,n.child=e.child,n.memoizedProps=e.memoizedProps,n.memoizedState=e.memoizedState,n.updateQueue=e.updateQueue,t=e.dependencies,n.dependencies=t===null?null:{lanes:t.lanes,firstContext:t.firstContext},n.sibling=e.sibling,n.index=e.index,n.ref=e.ref,n}function Ar(e,t,n,r,l,s){var o=2;if(r=e,typeof e=="function")Ai(e)&&(o=1);else if(typeof e=="string")o=5;else e:switch(e){case Bt:return Lt(n.children,l,s,t);case li:o=8,l|=8;break;case ls:return e=ze(12,n,t,l|2),e.elementType=ls,e.lanes=s,e;case ss:return e=ze(13,n,t,l),e.elementType=ss,e.lanes=s,e;case is:return e=ze(19,n,t,l),e.elementType=is,e.lanes=s,e;case Ea:return kl(n,l,s,t);default:if(typeof e=="object"&&e!==null)switch(e.$$typeof){case Na:o=10;break e;case Ca:o=9;break e;case si:o=11;break e;case ii:o=14;break e;case rt:o=16,r=null;break e}throw Error(j(130,e==null?e:typeof e,""))}return t=ze(o,n,t,l),t.elementType=e,t.type=r,t.lanes=s,t}function Lt(e,t,n,r){return e=ze(7,e,r,t),e.lanes=n,e}function kl(e,t,n,r){return e=ze(22,e,r,t),e.elementType=Ea,e.lanes=n,e.stateNode={isHidden:!1},e}function es(e,t,n){return e=ze(6,e,null,t),e.lanes=n,e}function ts(e,t,n){return t=ze(4,e.children!==null?e.children:[],e.key,t),t.lanes=n,t.stateNode={containerInfo:e.containerInfo,pendingChildren:null,implementation:e.implementation},t}function qf(e,t,n,r,l){this.tag=t,this.containerInfo=e,this.finishedWork=this.pingCache=this.current=this.pendingChildren=null,this.timeoutHandle=-1,this.callbackNode=this.pendingContext=this.context=null,this.callbackPriority=0,this.eventTimes=Ol(0),this.expirationTimes=Ol(-1),this.entangledLanes=this.finishedLanes=this.mutableReadLanes=this.expiredLanes=this.pingedLanes=this.suspendedLanes=this.pendingLanes=0,this.entanglements=Ol(0),this.identifierPrefix=r,this.onRecoverableError=l,this.mutableSourceEagerHydrationData=null}function Bi(e,t,n,r,l,s,o,a,u){return e=new qf(e,t,n,a,u),t===1?(t=1,s===!0&&(t|=8)):t=0,s=ze(3,null,null,t),e.current=s,s.stateNode=e,s.memoizedState={element:r,isDehydrated:n,cache:null,transitions:null,pendingSuspenseBoundaries:null},Ni(s),e}function bf(e,t,n){var r=3"u"||typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE!="function"))try{__REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE(wc)}catch(e){console.error(e)}}wc(),wa.exports=Ce;var lp=wa.exports,jc,ra=lp;jc=ra.createRoot,ra.hydrateRoot;const kc=()=>{var e,t;return(t=(e=window==null?void 0:window.go)==null?void 0:e.main)==null?void 0:t.App},sp=()=>!!kc();async function F(e,...t){const n=kc();if(!n||typeof n[e]!="function")throw new Error(`${e} is unavailable — run this inside the Behavision app`);return n[e](...t)}const $={session:()=>F("Session"),login:(e,t)=>F("Login",e,t),logout:()=>F("Logout"),claim:e=>F("Claim",e),runStandalone:()=>F("RunStandalone"),engineStatus:()=>F("EngineStatus"),startEngine:()=>F("StartEngine"),stopEngine:()=>F("StopEngine"),cameras:()=>F("Cameras"),testCamera:e=>F("TestCamera",e),discoverCameras:()=>F("DiscoverCameras"),saveCamera:(e,t)=>F("SaveCamera",e,t),deleteCamera:e=>F("DeleteCamera",e),startPlacement:(e,t)=>F("StartPlacementCheck",e,t),placementResult:e=>F("PlacementResult",e),streamURL:e=>F("StreamURL",e),live:()=>F("Live"),pipelineStatus:()=>F("PipelineStatus"),localIdentities:e=>F("LocalIdentities",e),localSightings:e=>F("LocalSightings",e),footfall:(e,t,n)=>F("Footfall",e,t,n),sites:()=>F("Sites"),visitorHistory:(e,t)=>F("VisitorHistory",e,t),visitorPhoto:e=>F("VisitorPhoto",e),forgetCustomer:e=>F("ForgetCustomer",e),sales:(e,t)=>F("Sales",e,t),customers:(e,t)=>F("Customers",e,t),saveProfile:e=>F("SaveProfile",e),ask:e=>F("Ask",e),recordPurchase:(e,t,n,r)=>F("RecordPurchase",e,t,n,r)};function fe(e){return e?typeof e=="string"?e:e.message||String(e):"Something went wrong."}function et(e,t,n=[]){const[r,l]=P.useState(null),[s,o]=P.useState(null),[a,u]=P.useState(!0),c=P.useRef(!0),p=P.useRef(!1),h=P.useCallback(async()=>{if(!p.current){p.current=!0;try{const v=await e();if(!c.current)return;l(v),o(null)}catch(v){c.current&&o(fe(v))}finally{p.current=!1,c.current&&u(!1)}}},n);return P.useEffect(()=>{if(c.current=!0,h(),!t)return()=>{c.current=!1};const v=setInterval(h,t);return()=>{c.current=!1,clearInterval(v)}},[h,t]),{data:r,error:s,loading:a,reload:h}}function ip(e){if(!e)return"—";const t=typeof e=="number"?new Date(e*1e3):new Date(e);return isNaN(t)?"—":t.toLocaleTimeString([],{hour:"2-digit",minute:"2-digit"})}function la(e){if(!e)return"—";const t=typeof e=="number"?new Date(e*1e3):new Date(e);return isNaN(t)?"—":t.toLocaleDateString([],{day:"numeric",month:"short"})}const ns={width:18,height:18,viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:1.6,strokeLinecap:"round",strokeLinejoin:"round","aria-hidden":"true",focusable:"false"};function J({size:e,children:t,...n}){return i.jsx("svg",{...ns,...n,width:e??ns.width,height:e??ns.height,children:t})}const op=e=>i.jsxs(J,{...e,children:[i.jsx("circle",{cx:"12",cy:"12",r:"3.2"}),i.jsx("path",{d:"M5.6 5.6a9 9 0 0 0 0 12.8M18.4 18.4a9 9 0 0 0 0-12.8"})]}),ap=e=>i.jsxs(J,{...e,children:[i.jsx("circle",{cx:"9",cy:"8.5",r:"3.2"}),i.jsx("path",{d:"M2.8 19.5a6.4 6.4 0 0 1 12.4 0"}),i.jsx("path",{d:"M16.5 6.2a3.2 3.2 0 0 1 0 6.1M18 19.5a6 6 0 0 0-1.6-4"})]}),up=e=>i.jsxs(J,{...e,children:[i.jsx("path",{d:"M3 8.5h3.4L8 6h8l1.6 2.5H21v10.2H3z"}),i.jsx("circle",{cx:"12",cy:"13.2",r:"3.1"})]}),Sc=e=>i.jsxs(J,{...e,children:[i.jsx("circle",{cx:"11",cy:"11",r:"6.4"}),i.jsx("path",{d:"M15.8 15.8 20.5 20.5"})]}),sa=e=>i.jsx(J,{...e,children:i.jsx("path",{d:"M12 5.5v13M5.5 12h13"})}),Qi=e=>i.jsx(J,{...e,children:i.jsx("path",{d:"M6.5 6.5l11 11M17.5 6.5l-11 11"})}),Xs=e=>i.jsx(J,{...e,children:i.jsx("path",{d:"M5 12.8l4.4 4.2L19 7"})}),Nc=e=>i.jsx(J,{...e,children:i.jsx("path",{d:"M8 5.6v12.8L18.5 12z"})}),cp=e=>i.jsx(J,{...e,children:i.jsx("rect",{x:"7",y:"7",width:"10",height:"10",rx:"1.6"})}),Se=e=>i.jsxs(J,{...e,children:[i.jsx("path",{d:"M12 4.6 21 19.4H3z"}),i.jsx("path",{d:"M12 10v4.1"}),i.jsx("path",{d:"M12 17.1v.01"})]}),ia=e=>i.jsx(J,{...e,children:i.jsx("path",{d:"M5 19.4v-4.2M10.3 19.4v-7.6M15.7 19.4v-11M21 19.4V4.6"})}),Ki=e=>i.jsx(J,{...e,children:i.jsx("path",{d:"M7.2 18.4a4.2 4.2 0 0 1-.6-8.35A6.2 6.2 0 0 1 18.4 9a4.2 4.2 0 0 1 .3 9.4z"})}),Cc=e=>i.jsxs(J,{...e,children:[i.jsx("path",{d:"M7.2 18.4a4.2 4.2 0 0 1-.6-8.35 6.2 6.2 0 0 1 2-3.2M10.6 5.2A6.2 6.2 0 0 1 18.4 9a4.2 4.2 0 0 1 1.9 7.6"}),i.jsx("path",{d:"M3.6 3.6l16.8 16.8"})]}),dp=e=>i.jsx(J,{...e,children:i.jsx("path",{d:"M12 3.8 19.4 6.6v5.2c0 4.2-3 7.4-7.4 8.4-4.4-1-7.4-4.2-7.4-8.4V6.6z"})}),fp=e=>i.jsxs(J,{...e,children:[i.jsx("path",{d:"M10.2 13.8a3.6 3.6 0 0 0 5.2 0l2.8-2.8a3.7 3.7 0 0 0-5.2-5.2l-1.3 1.3"}),i.jsx("path",{d:"M13.8 10.2a3.6 3.6 0 0 0-5.2 0l-2.8 2.8a3.7 3.7 0 0 0 5.2 5.2l1.3-1.3"})]}),pp=e=>i.jsxs(J,{...e,children:[i.jsx("path",{d:"M14.4 7.6V5.4H4.6v13.2h9.8v-2.2"}),i.jsx("path",{d:"M10 12h9.4M16.4 8.8 19.8 12l-3.4 3.2"})]}),oa=e=>i.jsx(J,{...e,children:i.jsx("path",{d:"M14.6 5.6 8 12l6.6 6.4"})}),hp=e=>i.jsx(J,{...e,children:i.jsx("path",{d:"M9.4 5.6 16 12l-6.6 6.4"})}),Ec=e=>i.jsxs(J,{...e,strokeWidth:"1.2",children:[i.jsx("path",{d:"M3 8.5h3.4L8 6h8l1.6 2.5H21v10.2H3z"}),i.jsx("circle",{cx:"12",cy:"13.2",r:"3.1"}),i.jsx("path",{d:"M3.6 3.6l16.8 16.8"})]}),_c=e=>i.jsxs(J,{...e,strokeWidth:"1.2",children:[i.jsx("circle",{cx:"12",cy:"9",r:"3.4"}),i.jsx("path",{d:"M5.4 20a6.8 6.8 0 0 1 13.2 0"})]}),gt=""+new URL("loyaly-mark-Ch-P3VSF.png",import.meta.url).href;function mp({onDone:e}){const[t,n]=P.useState(""),[r,l]=P.useState(""),[s,o]=P.useState(!1),[a,u]=P.useState(null);async function c(p){p.preventDefault(),o(!0),u(null);try{e(await $.login(t.trim(),r))}catch(h){u(fe(h))}finally{o(!1)}}return i.jsx("div",{className:"login",children:i.jsxs("div",{className:"box",children:[i.jsx("span",{className:"mark",children:i.jsx("img",{src:gt,alt:""})}),i.jsx("h1",{children:"Behavision"}),i.jsx("p",{className:"lead",children:"Sign in to connect this PC to your store."}),i.jsxs("form",{onSubmit:c,children:[a&&i.jsxs("div",{className:"err",children:[i.jsx(Se,{size:15}),a]}),i.jsxs("label",{className:"field",children:[i.jsx("span",{children:"Email"}),i.jsx("input",{type:"email",value:t,autoComplete:"username",required:!0,autoFocus:!0,onChange:p=>n(p.target.value)})]}),i.jsxs("label",{className:"field",children:[i.jsx("span",{children:"Password"}),i.jsx("input",{type:"password",value:r,autoComplete:"current-password",required:!0,onChange:p=>l(p.target.value)})]}),i.jsx("button",{className:"btn primary",disabled:s||!t||!r,children:s?"Signing in…":"Sign in"})]}),i.jsx("p",{className:"foot",children:"Signing in downloads this store's recognition models and connects it to your account. Nothing is sent until a camera is set up."})]})})}function aa({onDone:e,onCancel:t}){const[n,r]=P.useState(""),[l,s]=P.useState(null),[o,a]=P.useState(null);async function u(v){v.preventDefault(),s("claim"),a(null);try{e(await $.claim(n))}catch(g){a(fe(g))}finally{s(null)}}async function c(){s("alone"),a(null);try{e(await $.runStandalone())}catch(v){a(fe(v))}finally{s(null)}}const[p,h]=P.useState(t?"code":null);return p===null?i.jsx("div",{className:"login",children:i.jsxs("div",{className:"box wide",children:[i.jsx("span",{className:"mark",children:i.jsx("img",{src:gt,alt:""})}),i.jsx("h1",{children:"Welcome to Behavision"}),i.jsx("p",{className:"lead",children:"This PC will watch your shop’s cameras and recognise returning customers. First, one question: is this shop managed from a head office?"}),i.jsxs("div",{className:"choices",children:[i.jsxs("button",{type:"button",className:"choice",onClick:()=>h("code"),children:[i.jsx(Ki,{size:22}),i.jsx("b",{children:"Yes — I have an installation code"}),i.jsxs("span",{children:["Head office gave you a code like ",i.jsx("em",{children:"ABCDEF-123456-…"}),". This PC joins that shop and gets its cameras from there."]})]}),i.jsxs("button",{type:"button",className:"choice",onClick:()=>h("alone"),children:[i.jsx(dp,{size:22}),i.jsx("b",{children:"No — set up on this PC only"}),i.jsx("span",{children:"Cameras, customers and recognition stay on this PC. Nothing is sent anywhere. You can link to a head office later."})]})]})]})}):p==="alone"?i.jsx("div",{className:"login",children:i.jsxs("div",{className:"box",children:[i.jsx("span",{className:"mark",children:i.jsx("img",{src:gt,alt:""})}),i.jsx("h1",{children:"On this PC only"}),i.jsx("p",{className:"lead",children:"Behavision will run entirely here. Next you’ll add your camera — it can find it on the network for you — and walk past it once so it can prove it works."}),o&&i.jsxs("div",{className:"err",children:[i.jsx(Se,{size:15}),o]}),i.jsx("button",{type:"button",className:"btn primary",disabled:!!l,onClick:c,children:l==="alone"?"Setting up…":"Continue"}),i.jsx("div",{className:"alt",children:i.jsxs("button",{type:"button",className:"linkbtn",onClick:()=>h(null),children:[i.jsx(oa,{size:14})," Back"]})})]})}):i.jsx("div",{className:"login",children:i.jsxs("div",{className:"box",children:[i.jsx("span",{className:"mark",children:i.jsx("img",{src:gt,alt:""})}),i.jsx("h1",{children:t?"Link to head office":"Join your shop"}),i.jsx("p",{className:"lead",children:"Type the installation code head office gave you. It works once, and this PC becomes that shop."}),i.jsxs("form",{onSubmit:u,children:[o&&i.jsxs("div",{className:"err",children:[i.jsx(Se,{size:15}),o]}),i.jsxs("label",{className:"field",children:[i.jsx("span",{children:"Installation code"}),i.jsx("input",{value:n,autoFocus:!0,required:!0,placeholder:"ABCDEF-123456-GHIJKL-789012",autoComplete:"off",spellCheck:"false",style:{textTransform:"uppercase",letterSpacing:".06em"},onChange:v=>r(v.target.value)})]}),i.jsx("button",{className:"btn primary",disabled:!!l||n.trim().length<6,children:l==="claim"?"Linking…":"Link this PC"})]}),i.jsxs("p",{className:"foot",children:["Don’t have one? Whoever runs head office creates it under the shop: ",i.jsx("em",{children:"Shops → the shop → Set up a shop PC"}),"."]}),i.jsx("div",{className:"alt",children:t?i.jsx("button",{type:"button",className:"linkbtn",onClick:t,children:"Not now — go back"}):i.jsxs("button",{type:"button",className:"linkbtn",onClick:()=>h(null),children:[i.jsx(oa,{size:14})," Back"]})})]})})}function Pc({onNavigate:e}){var v,g,x,w;const{data:t,error:n}=et(()=>$.live(),3e3),{data:r}=et(()=>$.pipelineStatus(),5e3),l=((v=t==null?void 0:t.stats)==null?void 0:v.cameras)??[],s=((g=t==null?void 0:t.stats)==null?void 0:g.gallery)??{},o=(t==null?void 0:t.events)??[],a=(t==null?void 0:t.viewing)===!0,u=a?((x=t==null?void 0:t.stats)==null?void 0:x.fraction_below_gate)??0:l.reduce((L,f)=>{var m,y;const d=(y=(m=f==null?void 0:f.pipeline)==null?void 0:m.best_quality)==null?void 0:y.fraction_below_gate;return typeof d=="number"&&d>L?d:L},0),c=a?((w=t==null?void 0:t.stats)==null?void 0:w.cameras_up)??0:l.filter(L=>L.connected).length,p=o.filter(L=>L.type==="person.new"||L.type==="person.seen"),h=wp(p[0]);return i.jsxs("div",{className:"page",children:[i.jsxs("header",{children:[i.jsx("h2",{children:"Live"}),i.jsx("p",{children:a?"Your shops, as head office sees them.":"Who is in the shop, and whether it is reaching head office."})]}),n&&i.jsxs("div",{className:"err",children:[i.jsx(Se,{size:15}),n]}),a&&i.jsxs("div",{className:"viewing",children:[i.jsx(Ki,{size:15}),i.jsxs("span",{children:[i.jsx("b",{children:"Viewing your shops from here."})," This computer is not watching any cameras itself — everything below is what your shop PCs reported. To recognise people on this machine, it has to be on the same network as a camera."]})]}),i.jsx(xp,{pipe:r,cameras:l,up:c}),!a&&i.jsx(vp,{cameras:l,arrivals:p,onNavigate:e}),i.jsxs("div",{className:"panel arrivals-panel",children:[i.jsxs("div",{className:"panelhead",children:[i.jsx("h3",{children:"Who just walked in"}),p.length>0&&i.jsxs("span",{className:"note",children:[p.length," today"]})]}),i.jsx("div",{className:"panelbody flush",children:p.length===0?i.jsxs("div",{className:"empty",children:[i.jsx(_c,{size:34}),i.jsx("b",{children:"Nobody yet"}),i.jsx("p",{children:"Customers appear here the moment a camera recognises a face."})]}):i.jsx("div",{className:"arrivals",children:p.slice(0,30).map((L,f)=>i.jsx(gp,{e:L,fresh:f===0&&h},`${L.ts}-${f}`))})})]}),i.jsxs("div",{className:"metrics",style:{marginTop:"var(--sp-4)"},children:[i.jsx(Er,{k:"People known",v:s.identities??"—"}),i.jsx(Er,{k:"Sightings",v:s.sightings??"—"}),i.jsx(Er,{k:"Cameras live",v:l.length?`${c}/${l.length}`:"—",tone:l.length?c===0?"bad":c.5?"bad":u>.2?"warn":"ok",s:u>.5?"Most visitors are being missed — move the camera":"Share of faces below the enrolment gate"})]})]})}function vp({cameras:e,arrivals:t,onNavigate:n}){const{data:r}=et(()=>$.engineStatus(),4e3),[l,s]=P.useState(()=>{try{return localStorage.getItem("bv.gettingStarted")==="done"}catch{return!1}}),o=e.length>0,a=e.some(x=>x.connected),{data:u}=et(async()=>{const x={};for(const w of e)try{x[w.camera_id]=await $.placementResult(w.camera_id)}catch{}return x},1e4,[e.map(x=>x.camera_id).join("|")]),c=Object.values(u??{}).some(x=>x&&!x.running&&x.verdict==="good"),p=t.length>0;if(l||p)return null;const h=!!(r!=null&&r.reachable&&(r!=null&&r.recognition_model)),v=r==null?void 0:r.progress,g=[{done:h,now:!h,title:h?`Recognition ready (${r.recognition_model})`:v?`Downloading ${v.what}… ${v.percent}%`:"Starting recognition…",text:h?null:"First start downloads about 275 MB of recognition models. A few minutes on a normal connection; nothing to do meanwhile."},{done:o&&a,now:h&&!(o&&a),title:o?a?"Camera connected":"Camera added — not connecting yet":"Add your camera",text:o?a?null:"Check its password and stream path under Cameras → Edit.":"Behavision can find it on the network; you type only its password.",action:o?null:{label:"Add camera",go:"cameras"}},{done:c,now:o&&a&&!c,title:c?"Camera proven — it can recognise faces":"Walk past the camera",text:c?null:"Run Check placement and walk past like a customer for 25 seconds. Only a “good” verdict means it will recognise people.",action:o&&a&&!c?{label:"Check placement",go:"cameras"}:null}];return i.jsxs("section",{className:"panel starter",children:[i.jsxs("div",{className:"panelhead",children:[i.jsx("h3",{children:"Getting started"}),i.jsx("button",{className:"btn sm ghost",onClick:()=>{try{localStorage.setItem("bv.gettingStarted","done")}catch{}s(!0)},children:"Hide"})]}),i.jsx("ol",{className:"steps compact",children:g.map((x,w)=>i.jsxs("li",{className:x.done?"done":x.now?"now":"",children:[i.jsx("b",{children:x.title}),x.text&&i.jsx("span",{children:x.text}),x.action&&i.jsx("button",{className:"btn sm primary",onClick:()=>n==null?void 0:n(x.action.go),children:x.action.label})]},w))}),i.jsx("p",{className:"note",children:"The moment a customer is recognised, this list goes away."})]})}function gp({e,fresh:t}){var o,a,u,c,p,h;const n=e.type==="person.new",r=((o=e.data)==null?void 0:o.label)||"Unrecognised",l=[(a=e.data)==null?void 0:a.gender,((u=e.data)==null?void 0:u.age)??((c=e.data)==null?void 0:c.age_range),(p=e.data)==null?void 0:p.emotion].filter(Boolean),s=typeof((h=e.data)==null?void 0:h.similarity)=="number"?e.data.similarity:null;return i.jsxs("article",{className:`arrival ${n?"is-new":"is-seen"} ${t?"fresh":""}`,children:[i.jsx("div",{className:"avatar",children:yp(r)}),i.jsxs("div",{className:"who",children:[i.jsx("div",{className:"name",children:r}),i.jsxs("div",{className:"meta",children:[e.camera_id,l.length>0&&i.jsxs(i.Fragment,{children:[" · ",l.join(", ")]}),s!==null&&!n&&i.jsxs(i.Fragment,{children:[" · match ",s.toFixed(2)]})]})]}),i.jsxs("div",{className:"right",children:[i.jsx("span",{className:`tag ${n?"new":"seen"}`,children:n?"new":"returning"}),i.jsx("span",{className:"when",children:ip(e.ts)})]})]})}function yp(e){var r;const t=/^Visitor (\d+)$/.exec(String(e).trim());if(t)return t[1];const n=String(e).trim().split(/\s+/).filter(Boolean);return n.length?(n[0][0]+(((r=n[1])==null?void 0:r[0])??"")).toUpperCase():"?"}function xp({pipe:e,cameras:t,up:n}){if(!e)return null;if(e.standalone)return i.jsxs("div",{className:"statusbar",children:[i.jsxs("span",{className:"item",children:[i.jsx("i",{className:"dot ok"}),i.jsx("b",{children:"Running on this PC only"})]}),i.jsx("span",{className:"sep"}),i.jsx("span",{className:"item note",children:"Recognition and customers stay here."}),i.jsx("span",{className:"grow"}),i.jsxs("span",{className:"item note",children:[i.jsx(ia,{size:14}),n," of ",t.length," cameras"]})]});const r=e.claimed&&!e.broker_up,l=e.claimed?e.broker_up?"ok":"bad":"idle",s=e.claimed?e.broker_up?"Sending to head office":"Offline — saving locally":"Not linked to head office";return i.jsxs("div",{className:"statusbar",children:[i.jsxs("span",{className:"item",children:[e.broker_up?i.jsx(Ki,{size:15}):i.jsx(Cc,{size:15}),i.jsx("i",{className:`dot ${l}`}),i.jsx("b",{children:s})]}),i.jsx("span",{className:"sep"}),i.jsxs("span",{className:"item note",children:[e.accepted," recorded today"]}),e.queued>0&&i.jsxs("span",{className:`item note ${r?"warn":""}`,children:[e.queued," waiting to send"]}),e.dropped>0&&i.jsxs("span",{className:"item note bad",children:[i.jsx(Se,{size:14}),e.dropped," lost — this PC was offline too long"]}),i.jsx("span",{className:"grow"}),i.jsxs("span",{className:"item note",children:[i.jsx(ia,{size:14}),n," of ",t.length," cameras"]})]})}function Er({k:e,v:t,s:n,tone:r}){return i.jsxs("div",{className:`metric ${r??""}`,children:[i.jsx("div",{className:"metric-k",children:e}),i.jsx("div",{className:"metric-v",children:t}),n&&i.jsx("div",{className:"metric-s",children:n})]})}function wp(e){const[t,n]=P.useState(!1),r=P.useRef(null);return P.useEffect(()=>{if(!e||e.ts===r.current)return;const l=r.current===null;if(r.current=e.ts,l)return;n(!0);const s=setTimeout(()=>n(!1),1200);return()=>clearTimeout(s)},[e==null?void 0:e.ts]),t}function jp(e){const[t,n]=P.useState(null);return P.useEffect(()=>{let r=!0;return n(null),$.visitorPhoto(e).then(l=>{r&&n(l)}).catch(()=>{r&&n({available:!1,reason:""})}),()=>{r=!1}},[e]),t}function kp({photo:e,name:t,customerRef:n,onBroken:r}){return e!=null&&e.available?i.jsx("img",{className:"avatar",src:e.url,alt:`Photo of ${t}`,onError:r}):i.jsx("div",{className:"avatar none",role:"img","aria-label":`No photo of ${t}`,children:i.jsx("span",{children:Sp(t,n)})})}function Sp(e,t){const n=/^Visitor (\d+)$/.exec(String(e||"").trim());if(n)return n[1];const r=/^V-(\d+)$/.exec(String(t||""));return r?r[1]:String(e||"").split(/\s+/).filter(Boolean).slice(0,2).map(l=>l[0].toUpperCase()).join("")||"?"}function Np({customer:e}){const{data:t,error:n,loading:r}=et(()=>$.visitorHistory(e.id,50),0,[e.id]);if(r)return i.jsx("p",{className:"note",children:"Loading visits…"});if(n)return i.jsxs("p",{className:"note",children:["Could not load visits: ",n]});const l=t??[];return l.length===0?i.jsx("p",{className:"note",children:"No recorded visits yet."}):i.jsx("ul",{className:"timeline",children:l.map(s=>i.jsxs("li",{children:[i.jsx("span",{className:"when",children:Cp(s.occurred_at)}),i.jsxs("span",{className:"where",children:[s.site||"this store",s.camera_id?i.jsxs("span",{className:"note",children:[" · ",s.camera_id]}):null]}),s.is_new_visitor&&i.jsx("span",{className:"tag new",children:"first visit"})]},s.id))})}function Cp(e){const t=new Date(e);return isNaN(t)?"—":t.toLocaleString([],{day:"numeric",month:"short",hour:"2-digit",minute:"2-digit"})}function Ep({customer:e,onCancel:t,onDone:n}){const r=e.full_name||e.label,[l,s]=P.useState(""),[o,a]=P.useState(!1),[u,c]=P.useState(null),p=l.trim().toLowerCase()===r.trim().toLowerCase();async function h(){a(!0),c(null);try{await $.forgetCustomer(e.id),n()}catch(v){c(fe(v)),a(!1)}}return i.jsxs("div",{className:"confirm",children:[i.jsxs("h4",{children:["Erase ",r,"?"]}),i.jsxs("div",{className:"cols",children:[i.jsxs("div",{children:[i.jsx("p",{className:"lbl bad",children:"Deleted for good"}),i.jsxs("ul",{children:[i.jsx("li",{children:"Their face data — they will not be recognised again"}),i.jsx("li",{children:"Their photo"}),i.jsx("li",{children:"Their name, phone, email and notes"})]})]}),i.jsxs("div",{children:[i.jsx("p",{className:"lbl",children:"Kept"}),i.jsxs("ul",{children:[i.jsx("li",{children:"Past visits, with their name removed — your footfall figures do not change"}),i.jsx("li",{children:"The consent record, marked withdrawn, as proof of what was agreed"})]})]})]}),i.jsx("p",{className:"note",children:"This cannot be undone. If they come back they will be recorded as a new customer."}),u&&i.jsx("div",{className:"err",children:u}),i.jsxs("label",{className:"field",children:[i.jsxs("span",{children:["Type ",i.jsx("b",{children:r})," to confirm"]}),i.jsx("input",{value:l,onChange:v=>s(v.target.value),autoFocus:!0,autoComplete:"off",spellCheck:"false","aria-label":`Type ${r} to confirm erasure`})]}),i.jsxs("div",{className:"row",children:[i.jsx("button",{type:"button",className:"btn danger",disabled:!p||o,onClick:h,children:o?"Erasing…":"Erase permanently"}),i.jsx("button",{type:"button",className:"btn",onClick:t,disabled:o,children:"Cancel"})]})]})}function _p({customer:e,session:t,onClose:n,onSaved:r}){var C;const[l,s]=P.useState({full_name:e.full_name??"",phone:e.phone??"",email:e.email??"",gender:"",date_of_birth:"",notes:"",consent:e.has_consent??!1}),[o,a]=P.useState({amount:"",items:"",notes:""}),[u,c]=P.useState(!1),[p,h]=P.useState(null),[v,g]=P.useState(!1),[x,w]=P.useState(null),L=jp(e.id),f=x??L,d=(C=t==null?void 0:t.user)==null?void 0:C.role,m=["admin","owner","manager"].includes(d),y=k=>E=>s({...l,[k]:E.target.value});async function S(k){k.preventDefault(),c(!0),h(null);try{await $.saveProfile({visitor_id:e.id,...l});const E=parseFloat(o.amount);if(!isNaN(E)&&E>0){const z=o.items.split(",").map(T=>T.trim()).filter(Boolean);await $.recordPurchase(e.id,E,z,o.notes)}r()}catch(E){h(fe(E))}finally{c(!1)}}return i.jsx("div",{className:"drawer",onMouseDown:k=>k.target===k.currentTarget&&n(),children:i.jsxs("div",{className:"sheet",children:[i.jsxs("div",{className:"sheethead who",children:[i.jsx(kp,{photo:f,name:e.full_name||e.label,customerRef:e.ref,onBroken:()=>w({available:!1,reason:"The photo could not be loaded."})}),i.jsxs("div",{className:"grow",children:[i.jsx("h2",{children:e.full_name||e.label}),i.jsxs("p",{className:"note",children:[e.visit_count," visit",e.visit_count===1?"":"s",e.last_seen_at&&` · last seen ${new Date(e.last_seen_at).toLocaleDateString()}`,f&&!f.available&&f.reason&&` · ${f.reason}`]})]}),i.jsx("button",{type:"button",className:"close",onClick:n,"aria-label":"Close",children:"✕"})]}),i.jsxs("form",{className:"sheetbody",onSubmit:S,children:[p&&i.jsx("div",{className:"err",children:p}),i.jsxs("section",{className:"formsection",children:[i.jsx("h4",{children:"Customer details"}),i.jsxs("label",{className:"field",children:[i.jsx("span",{children:"Full name"}),i.jsx("input",{value:l.full_name,onChange:y("full_name"),autoFocus:!0})]}),i.jsxs("div",{className:"fieldrow",children:[i.jsxs("label",{className:"field",children:[i.jsx("span",{children:"Phone"}),i.jsx("input",{value:l.phone,onChange:y("phone"),inputMode:"tel"})]}),i.jsxs("label",{className:"field",children:[i.jsx("span",{children:"Email"}),i.jsx("input",{value:l.email,onChange:y("email"),type:"email"})]})]}),i.jsxs("div",{className:"fieldrow",children:[i.jsxs("label",{className:"field",children:[i.jsx("span",{children:"Gender"}),i.jsxs("select",{value:l.gender,onChange:y("gender"),children:[i.jsx("option",{value:"",children:"Not recorded"}),i.jsx("option",{children:"Female"}),i.jsx("option",{children:"Male"}),i.jsx("option",{children:"Other"})]})]}),i.jsxs("label",{className:"field",children:[i.jsx("span",{children:"Date of birth"}),i.jsx("input",{type:"date",value:l.date_of_birth,onChange:y("date_of_birth")})]})]}),i.jsxs("label",{className:"field",children:[i.jsx("span",{children:"Notes"}),i.jsx("textarea",{value:l.notes,onChange:y("notes"),placeholder:"Preferences, sizes, anything worth remembering"})]})]}),i.jsxs("section",{className:"formsection",children:[i.jsx("h4",{children:"Purchase (optional)"}),i.jsxs("div",{className:"fieldrow",children:[i.jsxs("label",{className:"field",children:[i.jsx("span",{children:"Amount"}),i.jsx("input",{value:o.amount,inputMode:"decimal",placeholder:"0.00",onChange:k=>a({...o,amount:k.target.value})})]}),i.jsxs("label",{className:"field",children:[i.jsx("span",{children:"Items"}),i.jsx("input",{value:o.items,placeholder:"shirt, belt",onChange:k=>a({...o,items:k.target.value})})]})]}),i.jsx("p",{className:"note",children:"Leave the amount blank if they did not buy anything — a visit without a sale is still worth recording."})]}),i.jsxs("section",{className:"formsection",children:[i.jsx("h4",{children:"Consent"}),i.jsxs("label",{style:{display:"flex",gap:10,alignItems:"flex-start",fontSize:13,cursor:"pointer"},children:[i.jsx("input",{type:"checkbox",checked:l.consent,style:{marginTop:3},onChange:k=>s({...l,consent:k.target.checked})}),i.jsx("span",{children:"This customer agreed to us keeping their details and recognising them on future visits."})]}),i.jsx("p",{className:"note",style:{marginTop:10},children:"Recorded with the date and who collected it. They can withdraw it at any time, which erases their face data."})]}),i.jsxs("section",{className:"formsection",children:[i.jsx("h4",{children:"Visits"}),i.jsx(Np,{customer:e})]}),i.jsxs("div",{className:"sheetactions",children:[i.jsx("button",{type:"button",className:"btn",onClick:n,children:"Cancel"}),i.jsx("button",{className:"btn primary",disabled:u,children:u?"Saving…":"Save"})]}),m&&i.jsxs("section",{className:"formsection dangerzone",children:[i.jsx("h4",{children:"At the customer's request"}),v?i.jsx(Ep,{customer:e,onCancel:()=>g(!1),onDone:r}):i.jsxs(i.Fragment,{children:[i.jsx("p",{className:"note",children:"Erase this person's face data, photo and details. Their past visits stay in your footfall figures, without their name."}),i.jsx("button",{type:"button",className:"btn danger",onClick:()=>g(!0),children:"Erase this customer…"})]})]})]})]})})}function Pp({session:e}){const[t,n]=P.useState(""),[r,l]=P.useState(null),{data:s,error:o,reload:a}=et(()=>$.customers(t,200),3e4,[t]),u=s??[],c=u.filter(p=>p.has_profile).length;return i.jsxs("div",{className:"page",children:[i.jsxs("header",{className:"pagehead",children:[i.jsxs("div",{children:[i.jsx("h2",{children:"Customers"}),i.jsx("p",{children:"Everyone this business has recognised. Fill in details once and they are known at every store."})]}),i.jsxs("label",{className:"search",children:[i.jsx(Sc,{size:15}),i.jsx("input",{placeholder:"Search by name or phone",value:t,onChange:p=>n(p.target.value)})]})]}),o&&i.jsxs("div",{className:"err",children:[i.jsx(Se,{size:15}),o]}),i.jsxs("div",{className:"metrics",style:{marginBottom:"var(--sp-4)"},children:[i.jsx(_r,{k:"Known people",v:u.length||"—"}),i.jsx(_r,{k:"With details",v:c||"—",s:u.length?`${Math.round(100*c/u.length)}% captured`:null}),i.jsx(_r,{k:"Returning",v:u.filter(p=>p.visit_count>1).length||"—"}),i.jsx(_r,{k:"With consent",v:u.filter(p=>p.has_consent).length||"—"})]}),i.jsx("div",{className:"panel",children:u.length===0?i.jsxs("div",{className:"empty tall",children:[i.jsx(_c,{size:34}),i.jsx("b",{children:"No customers yet"}),i.jsx("p",{children:"They appear here the first time a camera recognises them. Click one to add a name and phone number."})]}):i.jsx("div",{className:"tablewrap",children:i.jsxs("table",{children:[i.jsx("thead",{children:i.jsxs("tr",{children:[i.jsx("th",{children:"Customer"}),i.jsx("th",{children:"Phone"}),i.jsx("th",{className:"num",children:"Visits"}),i.jsx("th",{children:"First seen"}),i.jsx("th",{children:"Last seen"}),i.jsx("th",{children:"Details"})]})}),i.jsx("tbody",{children:u.map(p=>i.jsxs("tr",{className:"click",onClick:()=>l(p),children:[i.jsxs("td",{children:[p.full_name||i.jsx("span",{className:"note",children:p.label}),p.full_name&&p.ref&&i.jsxs("span",{className:"note",children:[" · ",p.ref]})]}),i.jsx("td",{className:"mono",children:p.phone||"—"}),i.jsx("td",{className:"num",children:p.visit_count}),i.jsx("td",{children:la(p.first_seen_at)}),i.jsx("td",{children:la(p.last_seen_at)}),i.jsx("td",{children:p.has_profile?i.jsxs("span",{className:"pill ok",children:[i.jsx("i",{className:"dot ok"}),"captured"]}):i.jsxs("span",{className:"pill warn",children:[i.jsx("i",{className:"dot warn"}),"needed"]})})]},p.id))})]})})}),r&&i.jsx(_p,{customer:r,session:e,onClose:()=>l(null),onSaved:()=>{l(null),a()}})]})}function _r({k:e,v:t,s:n}){return i.jsxs("div",{className:"metric",children:[i.jsx("div",{className:"metric-k",children:e}),i.jsx("div",{className:"metric-v",children:t}),n&&i.jsx("div",{className:"metric-s",children:n})]})}const ln=[{id:"hikvision",label:"Hikvision",path:"/Streaming/Channels/101",note:"Channel 1, main stream. Use /Streaming/Channels/102 for the lower-quality sub stream."},{id:"dahua",label:"Dahua",path:"/cam/realmonitor?channel=1&subtype=0",note:"Channel 1, main stream. subtype=1 is the sub stream."},{id:"cpplus",label:"CP Plus",path:"/cam/realmonitor?channel=1&subtype=0",note:"CP Plus cameras use the Dahua stream path."},{id:"uniview",label:"Uniview",path:"/media/video1",note:"Some older Uniview models use /video1 instead."},{id:"tplink",label:"TP-Link / Tapo",path:"/stream1",note:"Tapo cameras need a separate camera account created in the Tapo app — your Tapo login will not work."},{id:"reolink",label:"Reolink",path:"/h264Preview_01_main",note:"Use /h264Preview_01_sub for the lower-quality stream."},{id:"amcrest",label:"Amcrest",path:"/cam/realmonitor?channel=1&subtype=0",note:"Amcrest cameras use the Dahua stream path."},{id:"axis",label:"Axis",path:"/axis-media/media.amp",note:""},{id:"onvif",label:"Other (ONVIF)",path:"/onvif1",note:"Many generic cameras answer here. If it does not work, look for “RTSP” in the camera’s own app."},{id:"manual",label:"I know the path",path:"",note:""}],Pr=e=>ln.find(t=>t.id===e)||ln[ln.length-1],Zs={id:"",host:"",port:554,path:"",username:"",password:"",max_width:1280};function zp(){const{data:e,error:t,reload:n}=et(()=>$.cameras(),8e3),[r,l]=P.useState(null),[s,o]=P.useState(null),a=e??[],u=a.some(h=>h.remote),c=Lp(u?[]:a);async function p(h){if(confirm(`Remove ${h.id}? Recognition from it stops immediately.`))try{await $.deleteCamera(h.id),n()}catch(v){alert(fe(v))}}return i.jsxs("div",{className:"page",children:[i.jsxs("header",{className:"pagehead",children:[i.jsxs("div",{children:[i.jsx("h2",{children:"Cameras"}),i.jsx("p",{children:u?"The cameras across your shops, as the shop computers last reported them.":"Add a camera, then prove it can see faces with a walk-past. Only then is it working."})]}),!u&&i.jsxs("button",{className:"btn primary",onClick:()=>l({...Zs}),children:[i.jsx(sa,{size:15}),"Add camera"]})]}),u&&i.jsxs("div",{className:"viewing",children:[i.jsx("b",{children:"Viewing your shops from here."})," These cameras are wired to the shop computers, so they are set up and checked there. The picture is each camera's most recent frame, not live video."]}),t&&i.jsxs("div",{className:"err",children:[i.jsx(Se,{size:15}),t]}),a.length===0?i.jsx("div",{className:"panel",children:i.jsxs("div",{className:"empty tall",children:[i.jsx(Ec,{size:40}),i.jsx("b",{children:"No cameras yet"}),i.jsx("p",{children:"Add the camera by its address. Most cameras print it on a label underneath, or show it in their own app."}),i.jsxs("button",{className:"btn primary",onClick:()=>l({...Zs}),children:[i.jsx(sa,{size:15}),"Add your first camera"]})]})}):i.jsx("div",{className:"camgrid",children:a.map(h=>i.jsx(Tp,{cam:h,stream:c[h.id],onEdit:()=>l(h),onCheck:()=>o(h.id),onRemove:()=>p(h)},h.id))}),r&&i.jsx(Mp,{cam:r,onClose:()=>l(null),onSaved:()=>{l(null),n()}}),s&&i.jsx(Rp,{id:s,onClose:()=>o(null)})]})}function Tp({cam:e,stream:t,onEdit:n,onCheck:r,onRemove:l}){var c,p,h;const s=e.connected===void 0||e.connected===null?e.remote?{tone:"idle",label:"Waiting for the shop computer"}:{tone:"idle",label:"Engine stopped"}:e.connected?{tone:"ok",label:"Connected"}:{tone:"bad",label:"Not connecting"},{data:o}=et(()=>e.remote?Promise.resolve(null):$.placementResult(e.id),15e3,[e.id]),a=!o||o.running||!o.verdict||o.verdict==="starting"?{tone:"miss",label:"Not yet proven",text:"Walk past it once and Behavision will tell you if the placement works."}:o.verdict==="good"?{tone:"seen",label:"Proven",text:o.headline||"Faces recognised on a walk-past."}:{tone:"miss",label:"Not proven",text:o.headline||"Move the camera and check again."},u=(c=e.snapshot)!=null&&c.available?e.snapshot.url:"";return i.jsxs("article",{className:"camcard",children:[i.jsxs("div",{className:"camview",children:[t||u?i.jsx("img",{src:t||u,alt:e.id}):i.jsx("div",{className:"placeholder",children:i.jsx(Ec,{size:34})}),i.jsxs("span",{className:`pill ${s.tone==="idle"?"":s.tone} over`,children:[i.jsx("i",{className:`dot ${s.tone}`}),s.label]})]}),i.jsxs("div",{className:"cambody",children:[i.jsxs("div",{className:"camtitle",children:[i.jsxs("div",{children:[i.jsx("h3",{children:e.label||e.camera_id||e.id}),i.jsx("span",{className:"mono note",children:e.remote?e.site||e.site_slug||"":`${e.host||e.url}${e.path?` · ${e.path}`:""}`})]}),!e.remote&&i.jsxs("div",{className:"camactions",children:[i.jsx("button",{className:"btn sm",onClick:n,children:"Edit"}),i.jsx("button",{className:"btn sm danger",onClick:l,children:"Remove"})]})]}),e.remote?i.jsx("div",{className:"camproof",children:i.jsx("span",{className:"note",children:(p=e.snapshot)!=null&&p.available?"Last picture from the shop computer.":((h=e.snapshot)==null?void 0:h.reason)||"No picture yet from the shop computer."})}):i.jsxs("div",{className:"camproof",children:[i.jsx("span",{className:`tag ${a.tone}`,children:a.label}),i.jsx("span",{className:"note",children:a.text}),i.jsxs("button",{className:`btn sm ${a.tone==="seen"?"":"primary"}`,onClick:r,children:[i.jsx(Nc,{size:13}),a.tone==="seen"?"Check again":"Check placement"]})]})]})]})}function Lp(e){const[t,n]=P.useState({});return P.useEffect(()=>{let r=!0;const l=e.filter(s=>!(s.id in t));if(l.length)return(async()=>{const s={};for(const o of l)try{s[o.id]=await $.streamURL(o.id)}catch{s[o.id]=""}r&&n(o=>({...o,...s}))})(),()=>{r=!1}},[e.map(r=>r.id).join("|")]),t}function Mp({cam:e,onClose:t,onSaved:n}){var E;const r=!e.id,[l,s]=P.useState({...Zs,...e,password:"",path:e.path||(r?ln[0].path:"")}),[o,a]=P.useState(r?ln[0].id:"manual"),[u,c]=P.useState(null),[p,h]=P.useState(null),[v,g]=P.useState(null),x=z=>T=>s({...l,[z]:T.target.value});function w(z){const T=Pr(z.target.value);a(T.id),s(V=>({...V,path:T.path||V.path}))}function L(){const z={};for(const[T,V]of Object.entries(l))V===""||V===null||V===void 0||(z[T]=T==="port"||T==="max_width"?Number(V):V);return z}async function f(){h("test"),g(null),c(null);try{c(await $.testCamera(L()))}catch(z){g(fe(z))}finally{h(null)}}async function d(z){z.preventDefault(),h("save"),g(null);try{await $.saveCamera(r?"":e.id,L()),n()}catch(T){g(fe(T))}finally{h(null)}}const m=Pr(o),[y,S]=P.useState(null);async function C(){S("busy");try{S(await $.discoverCameras())}catch(z){S({error:fe(z)})}}function k(z){const T=z.make?Pr(z.make):null;s(V=>({...V,host:z.host,path:(T==null?void 0:T.path)||V.path,id:V.id||""})),T&&a(T.id),c(null)}return i.jsx("div",{className:"drawer",onMouseDown:z=>z.target===z.currentTarget&&t(),children:i.jsxs("div",{className:"sheet",children:[i.jsxs("div",{className:"sheethead",children:[i.jsx("h2",{children:r?"Add a camera":`Edit ${e.id}`}),i.jsx("button",{className:"close",onClick:t,"aria-label":"Close",children:i.jsx(Qi,{size:16})})]}),i.jsxs("form",{className:"sheetbody",onSubmit:d,autoComplete:"off",children:[i.jsx("p",{className:"lead",children:"Three things from the camera: its address, its make, and its password. Test before you save — a wrong address is the most common mistake."}),v&&i.jsxs("div",{className:"err",children:[i.jsx(Se,{size:15}),v]}),r&&i.jsxs("section",{className:"formsection",children:[i.jsx("h4",{children:"Find it"}),y===null&&i.jsxs("div",{className:"finder",children:[i.jsx("p",{children:"Behavision can look for cameras on this shop’s network."}),i.jsxs("button",{type:"button",className:"btn primary",onClick:C,children:[i.jsx(Sc,{size:14}),"Find cameras on this network"]})]}),y==="busy"&&i.jsxs("div",{className:"finder busy",children:[i.jsx("span",{className:"spinner"}),"Looking on the network… a few seconds."]}),(y==null?void 0:y.error)&&i.jsxs("div",{className:"err",children:[i.jsx(Se,{size:15}),y.error]}),(y==null?void 0:y.cameras)&&(y.cameras.length===0?i.jsxs("div",{className:"finder",children:[i.jsxs("p",{children:["Nothing answered on ",((E=y.networks)==null?void 0:E.join(", "))||"this network",". The camera may be on a different network, switched off, or not yet connected — check its cable and power, then try again. You can still type its address below."]}),i.jsx("button",{type:"button",className:"btn",onClick:C,children:"Try again"})]}):i.jsxs("ul",{className:"foundlist",children:[y.cameras.map(z=>i.jsx("li",{className:l.host===z.host?"picked":"",children:i.jsxs("button",{type:"button",onClick:()=>k(z),children:[i.jsx("span",{className:"mono",children:z.host}),i.jsx("span",{className:"what",children:z.name||(z.rtsp?"Streams video (RTSP)":"Answers ONVIF")}),z.make&&i.jsx("span",{className:"tag seen",children:Pr(z.make).label}),l.host===z.host&&i.jsx(Xs,{size:16})]})},z.host)),i.jsx("li",{className:"rescan",children:i.jsx("button",{type:"button",className:"btn sm",onClick:C,children:"Scan again"})})]}))]}),i.jsxs("section",{className:"formsection",children:[i.jsx("h4",{children:"The camera"}),r&&i.jsxs("label",{className:"field",children:[i.jsx("span",{children:"Name"}),i.jsx("input",{value:l.id,onChange:x("id"),placeholder:"entrance",required:!0,autoFocus:!0}),i.jsx("em",{className:"hint",children:"Short, no spaces. It names this camera everywhere and cannot be changed later."})]}),i.jsxs("div",{className:"fieldrow",children:[i.jsxs("label",{className:"field",children:[i.jsx("span",{children:"Address"}),i.jsx("input",{value:l.host,onChange:x("host"),placeholder:"192.168.1.20",inputMode:"decimal"}),i.jsx("em",{className:"hint",children:"On a label on the camera, or in its own app under “network”."})]}),i.jsxs("label",{className:"field narrow",children:[i.jsx("span",{children:"Port"}),i.jsx("input",{value:l.port,onChange:x("port"),inputMode:"numeric"})]})]})]}),i.jsxs("section",{className:"formsection",children:[i.jsx("h4",{children:"The stream"}),i.jsxs("label",{className:"field",children:[i.jsx("span",{children:"Make of camera"}),i.jsx("select",{value:o,onChange:w,children:ln.map(z=>i.jsx("option",{value:z.id,children:z.label},z.id))}),m.note&&i.jsx("em",{className:"hint",children:m.note})]}),i.jsxs("label",{className:"field",children:[i.jsx("span",{children:"Stream path"}),i.jsx("input",{className:"mono",value:l.path,onChange:x("path"),placeholder:"/Streaming/Channels/101"}),i.jsx("em",{className:"hint",children:"Filled in from the make. Change it only if the camera’s own app says something else."})]})]}),i.jsxs("section",{className:"formsection",children:[i.jsx("h4",{children:"Sign-in to the camera"}),i.jsxs("div",{className:"fieldrow",children:[i.jsxs("label",{className:"field",children:[i.jsx("span",{children:"Username"}),i.jsx("input",{name:"rtsp-account",autoComplete:"off",value:l.username,onChange:x("username"),placeholder:"admin"})]}),i.jsxs("label",{className:"field",children:[i.jsx("span",{children:"Password"}),i.jsx("input",{type:"password",name:"rtsp-secret",autoComplete:"new-password",value:l.password,onChange:x("password"),placeholder:e.has_password?"(unchanged)":""})]})]})]}),u&&(u.ok?i.jsxs("div",{className:"testresult ok",children:[i.jsx(Xs,{size:16}),i.jsxs("div",{children:[i.jsxs("b",{children:["Connected — ",u.width,"×",u.height,u.codec?` · ${String(u.codec).toUpperCase()}`:""]}),u.snapshot&&i.jsx("img",{alt:"Camera preview",src:`data:image/jpeg;base64,${u.snapshot}`})]})]}):i.jsxs("div",{className:"testresult bad",children:[i.jsx(Se,{size:16}),i.jsxs("div",{children:[i.jsx("b",{children:"Could not connect"}),i.jsx("span",{children:u.error})]})]})),i.jsxs("div",{className:"sheetactions",children:[i.jsx("button",{type:"button",className:"btn",onClick:f,disabled:!!p||!l.host,children:p==="test"?"Connecting…":"Test connection"}),i.jsx("button",{className:"btn primary",disabled:!!p||!l.id||!l.host,children:p==="save"?"Saving…":r?"Add camera":"Save changes"})]})]})]})})}function Rp({id:e,onClose:t}){var p,h;const[n,r]=P.useState({verdict:"starting",advice:[]}),[l,s]=P.useState(null),o=P.useRef(null);P.useEffect(()=>{let v=!0;return(async()=>{try{r(await $.startPlacement(e,25)),o.current=setInterval(async()=>{try{const g=await $.placementResult(e);if(!v)return;r(g),g.running||clearInterval(o.current)}catch(g){v&&s(fe(g))}},1e3)}catch(g){v&&s(fe(g))}})(),()=>{v=!1,clearInterval(o.current)}},[e]);const a={good:"ok",marginal:"warn",poor:"bad",artifact:"bad",no_faces:"warn",inconclusive:"warn",no_completed_passes:"warn"}[n.verdict],u=n.seconds?Math.min(100,n.elapsed/n.seconds*100):0,c=n.running||n.verdict==="starting";return i.jsx("div",{className:"drawer",onMouseDown:v=>v.target===v.currentTarget&&t(),children:i.jsxs("div",{className:"sheet",children:[i.jsxs("div",{className:"sheethead",children:[i.jsxs("h2",{children:["Check placement · ",e]}),i.jsx("button",{className:"close",onClick:t,"aria-label":"Close",children:i.jsx(Qi,{size:16})})]}),i.jsxs("div",{className:"sheetbody",children:[l&&i.jsxs("div",{className:"err",children:[i.jsx(Se,{size:15}),l]}),i.jsxs("ol",{className:"steps",children:[i.jsxs("li",{className:c?"now":"done",children:[i.jsx("b",{children:"Walk past the camera"}),i.jsx("span",{children:"The way a customer would — in through the door, not looking at the lens. Two or three times, for about 25 seconds."}),c&&i.jsx("div",{className:"progress",children:i.jsx("div",{style:{width:`${u}%`}})})]}),i.jsxs("li",{className:c?"":"now",children:[i.jsx("b",{children:"Behavision judges what it saw"}),i.jsx("span",{children:"Not “were the frames sharp”, but “did a person walking past produce a face worth recognising”."})]})]}),i.jsxs("div",{className:`verdict ${a??""}`,children:[i.jsxs("div",{className:"verdict-head",children:[c?i.jsx("span",{className:"spinner"}):a==="ok"?i.jsx(Xs,{size:18}):i.jsx(Se,{size:18}),i.jsx("b",{children:n.headline||"Watching…"})]}),((p=n.advice)==null?void 0:p.length)>0&&i.jsx("ul",{children:n.advice.map((v,g)=>i.jsx("li",{children:v},g))}),((h=n.quality)==null?void 0:h.n)>0&&i.jsxs("p",{className:"note",children:[n.quality.n," face",n.quality.n===1?"":"s"," seen · median quality ",n.quality.p50," ·"," ",Math.round((n.quality.fraction_below_gate??0)*100),"% too poor to use"]})]}),!c&&i.jsxs("div",{className:"sheetactions",children:[i.jsx("button",{className:"btn",onClick:t,children:"Close"}),i.jsx("button",{className:"btn primary",onClick:()=>{r({verdict:"starting",advice:[]}),$.startPlacement(e,25).then(r).catch(v=>s(fe(v)))},children:"Run again"})]})]})]})})}const Dp=["Is my shop working right now?","How do I add my camera?","Why has nobody been recognised today?","Who came in this morning?"];function Op({session:e,onClose:t}){const[n,r]=P.useState([]),[l,s]=P.useState(""),[o,a]=P.useState(!1),[u,c]=P.useState(null),p=P.useRef(null),h=e==null?void 0:e.standalone;P.useEffect(()=>{var g;(g=p.current)==null||g.scrollTo({top:1e9,behavior:"smooth"})},[n,o]);async function v(g){const x=(g??l).trim();if(!x||o)return;const w=[...n,{role:"user",text:x}];r(w),s(""),a(!0),c(null);try{const L=await $.ask(w.map(f=>({role:f.role,text:f.text})));r([...w,{role:"assistant",text:L.text,used:L.used??[]}])}catch(L){const f=fe(L);c(/session expired|unauthori[sz]ed/i.test(f)?"You’re signed out of head office, so I can’t look anything up. Sign in again and ask me once more.":f),r(n),s(x)}finally{a(!1)}}return i.jsxs("aside",{className:"helper",role:"dialog","aria-label":"Loya",children:[i.jsxs("header",{className:"helperhead",children:[i.jsx("img",{src:gt,alt:""}),i.jsxs("div",{children:[i.jsx("b",{children:"Loya"}),i.jsx("span",{children:"Your Behavision buddy — knows your cameras, your customers and your numbers."})]}),i.jsx("button",{className:"close",onClick:t,"aria-label":"Close",children:i.jsx(Qi,{size:16})})]}),i.jsxs("div",{className:"helperbody",ref:p,children:[h&&i.jsxs("div",{className:"helpernote",children:[i.jsx(Cc,{size:16}),i.jsxs("div",{children:[i.jsx("b",{children:"This PC runs on its own"}),i.jsx("span",{children:"Loya lives at head office. Link this PC to a shop to talk to her; the basics are below."})]})]}),n.length===0&&i.jsxs("div",{className:"helperintro",children:[i.jsx("div",{className:"turn assistant",children:i.jsxs("div",{className:"bubble",children:[Fp(e)," Ask me anything about ",(e==null?void 0:e.site_name)||"this shop"," — what’s happening now, or how to set something up."]})}),i.jsx("div",{className:"chips",children:Dp.map(g=>i.jsx("button",{className:"chip",onClick:()=>v(g),disabled:o||h,children:g},g))}),h&&i.jsx(Ip,{})]}),n.map((g,x)=>{var w;return i.jsxs("div",{className:`turn ${g.role}`,children:[i.jsx("div",{className:"bubble",children:g.text}),((w=g.used)==null?void 0:w.length)>0&&i.jsxs("span",{className:"used",children:["Looked at: ",g.used.join(", ")]})]},x)}),o&&i.jsx("div",{className:"turn assistant",children:i.jsxs("div",{className:"bubble thinking",children:[i.jsx("span",{}),i.jsx("span",{}),i.jsx("span",{})]})}),u&&i.jsxs("div",{className:"err",children:[i.jsx(Se,{size:15}),u]})]}),i.jsxs("form",{className:"helperask",onSubmit:g=>{g.preventDefault(),v()},children:[i.jsx("input",{value:l,onChange:g=>s(g.target.value),disabled:o||h,placeholder:h?"Link this PC to head office to talk to Loya":"Ask Loya…"}),i.jsx("button",{className:"btn primary",disabled:o||h||!l.trim(),"aria-label":"Ask",children:i.jsx(hp,{size:16})})]})]})}function Fp(e){var l,s;const t=new Date().getHours(),n=t<12?"Morning":t<17?"Afternoon":"Evening",r=(s=(l=e==null?void 0:e.user)==null?void 0:l.full_name)==null?void 0:s.split(" ")[0];return r?`${n}, ${r}.`:`${n}.`}function Ip(){return i.jsxs("dl",{className:"quickhelp",children:[i.jsx("dt",{children:"Adding a camera"}),i.jsx("dd",{children:"Cameras → Add camera. The address is on a label on the camera; pick the make and the stream path fills itself in. Test, then save."}),i.jsx("dt",{children:"Proving it works"}),i.jsx("dd",{children:"Press Check placement and walk past the camera like a customer for 25 seconds. Only “good” means it can recognise faces — otherwise move it to head height, facing the way people approach."}),i.jsx("dt",{children:"Nothing showing on Live"}),i.jsx("dd",{children:"Check the camera is Connected and Proven. A camera aimed from above or the side streams fine and recognises nobody."}),i.jsx("dt",{children:"Linking to head office later"}),i.jsx("dd",{children:"Use the link button at the bottom of the sidebar and type an installation code from head office. Nothing recorded here is lost."})]})}const $p=[{id:"live",label:"Live",Glyph:op,View:Pc},{id:"customers",label:"Customers",Glyph:ap,View:Pp,cloud:!0},{id:"cameras",label:"Cameras",Glyph:up,View:zp}];function Up(){var v,g,x;const[e,t]=P.useState(null),[n,r]=P.useState("live"),[l,s]=P.useState(!0),[o,a]=P.useState(!1),[u,c]=P.useState(!1);if(P.useEffect(()=>{let w=!0;const L=async()=>{try{const d=await $.session();w&&t(m=>JSON.stringify(m)===JSON.stringify(d)?m:d)}catch{w&&t(null)}w&&s(!1)};L();const f=setInterval(L,8e3);return()=>{w=!1,clearInterval(f)}},[]),!sp())return i.jsx("div",{className:"login",children:i.jsxs("div",{className:"box",children:[i.jsx("span",{className:"mark",children:i.jsx("img",{src:gt,alt:""})}),i.jsx("h1",{children:"Behavision"}),i.jsx("p",{className:"lead",children:"This is the Behavision window running outside the app, so it has no connection to the recognition engine. Launch the Behavision application instead."})]})});if(l)return i.jsx("div",{className:"login",children:i.jsx("p",{className:"note",children:"Starting…"})});if(!(e!=null&&e.claimed)&&!(e!=null&&e.standalone))return i.jsx(aa,{onDone:t});if(!(e!=null&&e.standalone)&&!(e!=null&&e.logged_in))return i.jsx(mp,{onDone:t});const p=$p.filter(w=>!w.cloud||!e.standalone),h=((v=p.find(w=>w.id===n))==null?void 0:v.View)??Pc;return o?i.jsx(aa,{onDone:w=>{a(!1),t(w)},onCancel:()=>a(!1)}):i.jsxs("div",{className:"shell",children:[i.jsxs("aside",{className:"side",children:[i.jsxs("div",{className:"brand",children:[i.jsx("span",{className:"mark",children:i.jsx("img",{src:gt,alt:""})}),i.jsxs("div",{className:"id",children:[i.jsx("h1",{children:"Behavision"}),i.jsx("p",{children:e.site_name||((g=e.user)==null?void 0:g.client_name)||"This shop"})]})]}),i.jsx("nav",{className:"nav",children:p.map(({id:w,label:L,Glyph:f})=>i.jsxs("button",{onClick:()=>r(w),"aria-current":w===n?"page":void 0,children:[i.jsx(f,{size:17}),L]},w))}),i.jsx(Ap,{}),i.jsx("div",{className:"who",children:e.standalone?i.jsxs(i.Fragment,{children:[i.jsxs("div",{className:"id",children:[i.jsx("b",{children:"On its own"}),i.jsx("span",{children:"No head office"})]}),i.jsx("button",{className:"btn sm icon",title:"Link to head office",onClick:()=>a(!0),children:i.jsx(fp,{size:15})})]}):i.jsxs(i.Fragment,{children:[i.jsxs("div",{className:"id",children:[i.jsx("b",{children:"Signed in"}),i.jsx("span",{children:(x=e.user)==null?void 0:x.email})]}),i.jsx("button",{className:"btn sm icon",title:"Sign out",onClick:async()=>t(await $.logout()),children:i.jsx(pp,{size:15})})]})})]}),i.jsxs("main",{className:"main",children:[i.jsx(h,{session:e,onNavigate:r}),!u&&i.jsxs("button",{className:"loya-fab",onClick:()=>c(!0),"aria-label":"Ask Loya",title:"Ask Loya",children:[i.jsx("img",{src:gt,alt:""}),i.jsx("span",{children:"Loya"})]})]}),u&&i.jsx(Op,{session:e,onClose:()=>c(!1)})]})}function Ap(){const{data:e,reload:t}=et(()=>$.engineStatus(),5e3),[n,r]=P.useState(!1),l=e??{state:"stopped"},s=P.useCallback(async h=>{r(!0);try{await h()}catch(v){alert(fe(v))}finally{r(!1),t()}},[t]),o=l.state==="running",a=Object.values(l.cameras??{}),u=a.filter(Boolean).length;let c="idle",p="Stopped";return!o&&l.reachable?(c="warn",p="Running outside the app"):l.state==="failed"||l.state==="backoff"?(c="bad",p="Not running"):o&&!l.reachable&&l.progress?(c="warn",p=`Downloading ${l.progress.what}… ${l.progress.percent}%`):o&&!l.reachable?(c="warn",p="Starting…"):o&&a.length===0?(c="warn",p="No cameras"):o&&u===0?(c="bad",p="No camera connected"):o&&us($.startEngine),children:[i.jsx(Nc,{size:13}),"Start"]}),i.jsxs("button",{className:"btn sm",disabled:n||!o,onClick:()=>s($.stopEngine),children:[i.jsx(cp,{size:13}),"Stop"]})]})]})}jc(document.getElementById("root")).render(i.jsx(Kc.StrictMode,{children:i.jsx(Up,{})})); diff --git a/desktop/frontend/dist/index.html b/desktop/frontend/dist/index.html index da0ce8a..d9313f2 100644 --- a/desktop/frontend/dist/index.html +++ b/desktop/frontend/dist/index.html @@ -4,8 +4,8 @@ Behavision - - + +
diff --git a/desktop/frontend/src/bridge.js b/desktop/frontend/src/bridge.js index 03645aa..f351256 100644 --- a/desktop/frontend/src/bridge.js +++ b/desktop/frontend/src/bridge.js @@ -38,6 +38,9 @@ export const api = { startPlacement: (id, seconds) => call('StartPlacementCheck', id, seconds), placementResult: (id) => call('PlacementResult', id), streamURL: (id) => call('StreamURL', id), + // The live view of a camera in another building, relayed through head + // office. Empty when nobody is signed in. + remoteStreamURL: (id) => call('RemoteStreamURL', id), live: () => call('Live'), pipelineStatus: () => call('PipelineStatus'), diff --git a/desktop/frontend/src/styles.css b/desktop/frontend/src/styles.css index 37a9e08..87d09cb 100644 --- a/desktop/frontend/src/styles.css +++ b/desktop/frontend/src/styles.css @@ -648,3 +648,18 @@ tr.click { cursor: pointer; } tr.click:hover td { background: var(--s2); } } .viewing b { color: var(--ink); font-weight: 600; } .viewing svg { flex: none; margin-top: 2px; color: var(--accent); } + +/* Watch live sits over the picture, opposite the connection pill. It is on + the tile rather than in the button row because it is about the picture, and + because the row it would otherwise join is hidden on a remote camera. */ +.camview .btn.watch { + position: absolute; + right: 10px; + bottom: 10px; + background: rgba(0, 0, 0, .55); + border-color: rgba(255, 255, 255, .25); + color: #fff; + backdrop-filter: blur(6px); +} +.camview .btn.watch:hover { background: rgba(0, 0, 0, .72); } +.camview .btn.watch.on { background: var(--accent); border-color: var(--accent); color: #fff; } diff --git a/desktop/frontend/src/views/Cameras.jsx b/desktop/frontend/src/views/Cameras.jsx index 71beb7e..f74482f 100644 --- a/desktop/frontend/src/views/Cameras.jsx +++ b/desktop/frontend/src/views/Cameras.jsx @@ -27,6 +27,19 @@ export default function Cameras() { // than one that is absent. const remote = cams.some(c => c.remote) const streams = useStreamURLs(remote ? [] : cams) + // ONE camera at a time, and that is a cost decision rather than a layout + // one. A remote view makes the shop computer upload frames for as long as + // somebody is watching, so a grid that all went live at once would put an + // estate's worth of cameras on the wire because somebody opened a page. + const [watching, setWatching] = useState(null) + const [watchURL, setWatchURL] = useState('') + useEffect(() => { + let alive = true + if (!watching) { setWatchURL(''); return } + api.remoteStreamURL(watching).then(u => { if (alive) setWatchURL(u || '') }) + .catch(() => { if (alive) setWatchURL('') }) + return () => { alive = false } + }, [watching]) async function remove(cam) { if (!confirm(`Remove ${cam.id}? Recognition from it stops immediately.`)) return @@ -49,8 +62,9 @@ export default function Cameras() { {remote &&
Viewing your shops from here. These cameras are wired to the shop - computers, so they are set up and checked there. The picture is each - camera's most recent frame, not live video. + computers, so they are set up and checked there. Each tile shows that + camera's most recent frame; Watch live asks the shop computer to + send video for as long as you are looking.
} {error &&
{error}
} @@ -66,7 +80,10 @@ export default function Cameras() { :
{cams.map(c => ( - setWatching(watching === c.id ? null : c.id)} onEdit={() => setEditing(c)} onCheck={() => setCheck(c.id)} onRemove={() => remove(c)} /> ))}
} @@ -78,14 +95,23 @@ export default function Cameras() { ) } -function CameraCard({ cam, stream, onEdit, onCheck, onRemove }) { +function CameraCard({ cam, stream, watching, onWatch, onEdit, onCheck, onRemove }) { // Three states, not two, and the third is why `connected` is a pointer on // the wire: null means no shop computer has reported on this camera yet, // which reads as waiting rather than as a fault to go and investigate. - const conn = cam.connected === undefined || cam.connected === null - ? (cam.remote ? { tone: 'idle', label: 'Waiting for the shop computer' } - : { tone: 'idle', label: 'Engine stopped' }) - : cam.connected ? { tone: 'ok', label: 'Connected' } : { tone: 'bad', label: 'Not connecting' } + const conn = cam.remote + // Four states, decided once by the server. `stale` is the one that was + // missing: the shop computer reports nothing when it cannot reach its own + // engine, so its last report used to sit there reading Connected - + // measured at 34 minutes on the live estate. + ? ({ connected: { tone: 'ok', label: 'Connected' }, + not_connecting: { tone: 'bad', label: 'Not connecting' }, + stale: { tone: 'warn', label: 'Not reporting' } }[cam.state] + || { tone: 'idle', label: 'Waiting for the shop computer' }) + : cam.connected === undefined || cam.connected === null + ? { tone: 'idle', label: 'Engine stopped' } + : cam.connected ? { tone: 'ok', label: 'Connected' } + : { tone: 'bad', label: 'Not connecting' } // The last placement verdict, so "proven" survives closing the sheet. Only // `good` is a pass: marginal means half the visitors are silently discarded. // Never asked for a remote camera: that answer lives on the shop computer, @@ -105,6 +131,9 @@ function CameraCard({ cam, stream, onEdit, onCheck, onRemove }) { ? {cam.id} :
} {conn.label} + {cam.remote && }
@@ -121,9 +150,13 @@ function CameraCard({ cam, stream, onEdit, onCheck, onRemove }) {
{cam.remote ?
- {cam.snapshot?.available - ? 'Last picture from the shop computer.' - : cam.snapshot?.reason || 'No picture yet from the shop computer.'} + {cam.state_note + ? cam.state_note + : watching + ? 'Live from the shop computer. It uploads only while you watch.' + : cam.snapshot?.available + ? 'Last picture from the shop computer. Watch live to see it now.' + : cam.snapshot?.reason || 'No picture yet from the shop computer.'}
:
{proof.label} diff --git a/desktop/internal/cloud/client.go b/desktop/internal/cloud/client.go index 268641c..91bd08d 100644 --- a/desktop/internal/cloud/client.go +++ b/desktop/internal/cloud/client.go @@ -14,6 +14,7 @@ import ( "errors" "fmt" "io" + "net" "net/http" "net/url" "strings" @@ -682,6 +683,12 @@ type RemoteCamera struct { Enabled bool `json:"enabled"` Connected *bool `json:"connected"` LastSeenAt string `json:"last_seen_at"` + // State is the server's single answer - connected / not_connecting / + // waiting / stale - and the screen renders that rather than deciding + // again from Connected. Two places deciding one fact is how a shop came + // out labelled Working, in green, above "2 of 3 cameras not connecting". + State string `json:"state"` + StateNote string `json:"state_note"` Snapshot Photo `json:"snapshot"` SnapshotAt string `json:"snapshot_at"` } @@ -746,3 +753,72 @@ func (c *Client) resolveShot(ctx context.Context, camID, at string, p Photo) Pho p.URL, p.Auth = uri, false return p } + +// CameraLive opens head office's live relay for one camera and returns the +// live SSE response for the caller to read and close. +// +// A response rather than frames, because the consumer is the app's own +// loopback relay: it re-emits these frames as MJPEG so an can show them, +// and buffering the stream through a channel here would only add a place for +// frames to queue. A stale frame is worthless - the only one worth having is +// the newest - which is the whole reason LiveHub drops rather than queues. +// +// There is no client timeout on this request. A live view is endless by +// design and any deadline would cut the picture off mid-shift; the context is +// what ends it, when the viewer navigates away. +func (c *Client) CameraLive(ctx context.Context, cameraID string) (*http.Response, error) { + resp, err := c.liveOnce(ctx, cameraID) + if errors.Is(err, errTokenExpired) { + if rerr := c.Refresh(ctx); rerr != nil { + return nil, rerr + } + resp, err = c.liveOnce(ctx, cameraID) + } + return resp, err +} + +func (c *Client) liveOnce(ctx context.Context, cameraID string) (*http.Response, error) { + req, err := http.NewRequestWithContext(ctx, http.MethodGet, + c.Base+"/api/cameras/"+url.PathEscape(cameraID)+"/live", nil) + if err != nil { + return nil, err + } + req.Header.Set("Accept", "text/event-stream") + c.mu.RLock() + tok := c.token + c.mu.RUnlock() + if tok == "" { + return nil, ErrUnauthorized + } + req.Header.Set("Authorization", "Bearer "+tok) + + // c.http has a 30 s timeout, which covers the whole response and would + // therefore sever a working live view every thirty seconds - the same + // trap that made the server set WriteTimeout to zero for its own SSE + // endpoint. A dedicated client, with the dial bounded instead. + hc := &http.Client{Transport: &http.Transport{ + DialContext: (&net.Dialer{Timeout: 10 * time.Second}).DialContext, + TLSHandshakeTimeout: 10 * time.Second, + }} + resp, err := hc.Do(req) + if err != nil { + return nil, fmt.Errorf("cannot reach %s: %w", c.Base, err) + } + if resp.StatusCode == http.StatusUnauthorized { + var e struct { + Error string `json:"error"` + } + body, _ := io.ReadAll(io.LimitReader(resp.Body, 8192)) + resp.Body.Close() + _ = json.Unmarshal(body, &e) + if e.Error == "token_expired" { + return nil, errTokenExpired + } + return nil, ErrUnauthorized + } + if resp.StatusCode >= 400 { + resp.Body.Close() + return nil, fmt.Errorf("live view: %s", resp.Status) + } + return resp, nil +} diff --git a/desktop/stream_proxy.go b/desktop/stream_proxy.go index 6d57c84..3f1c3ec 100644 --- a/desktop/stream_proxy.go +++ b/desktop/stream_proxy.go @@ -21,6 +21,7 @@ package main // session and the bytes are fetched and handed over as an object URL. import ( + "context" "crypto/rand" "crypto/subtle" "encoding/hex" @@ -64,6 +65,12 @@ type streamProxy struct { target string // engine origin, e.g. http://127.0.0.1:8010 user string pass string + + // Opens head office's live relay for one camera. Set on a computer that + // is signed in, whether or not an engine runs here - which is the whole + // point: watching a camera in another building is precisely the case + // where there is no engine on this machine to ask. + live func(ctx context.Context, cameraID string) (*http.Response, error) } func newStreamProxy() *streamProxy { return &streamProxy{} } @@ -71,18 +78,49 @@ func newStreamProxy() *streamProxy { return &streamProxy{} } // start binds a loopback listener and begins relaying. Calling it again while // running is a no-op, so a restarted engine cannot leave two listeners behind. func (p *streamProxy) start(base, user, pass string) error { - p.mu.Lock() - defer p.mu.Unlock() - if p.srv != nil { - return nil - } - if !strings.HasPrefix(base, "http://") && !strings.HasPrefix(base, "https://") { base = "http://" + base } if _, err := url.Parse(base); err != nil { return fmt.Errorf("engine base %q: %w", base, err) } + if err := p.bind(); err != nil { + return err + } + p.mu.Lock() + defer p.mu.Unlock() + p.target = strings.TrimRight(base, "/") + p.user, p.pass = user, pass + return nil +} + +// watchRemote makes the relay able to serve head office's live view, and +// binds it if nothing else has. +// +// Separate from start() because the two are independent: a shop PC has both +// an engine and a session, an owner's laptop has only a session, and a PC +// still being set up has only an engine. Folding them together would mean a +// computer with no engine could not watch a camera at all - which is the one +// computer most likely to be trying to. +func (p *streamProxy) watchRemote(fn func(context.Context, string) (*http.Response, error)) error { + if err := p.bind(); err != nil { + return err + } + p.mu.Lock() + defer p.mu.Unlock() + p.live = fn + return nil +} + +// bind starts the loopback listener once. Calling it again while running is a +// no-op, so neither a restarted engine nor a second sign-in can leave two +// listeners behind. +func (p *streamProxy) bind() error { + p.mu.Lock() + defer p.mu.Unlock() + if p.srv != nil { + return nil + } // The engine's own credential exists precisely so that the live face feed // is never served open - CLAUDE.md is explicit that an unauthenticated @@ -105,8 +143,6 @@ func (p *streamProxy) start(base, user, pass string) error { p.ln = ln p.token = hex.EncodeToString(raw) - p.target = strings.TrimRight(base, "/") - p.user, p.pass = user, pass // No client timeout: an MJPEG stream is endless by design and any deadline // would cut the picture off mid-shift. The request context ends it when // the webview navigates away or the tile is replaced. @@ -130,7 +166,7 @@ func (p *streamProxy) start(base, user, pass string) error { func (p *streamProxy) stop() { p.mu.Lock() srv, ln := p.srv, p.ln - p.srv, p.ln, p.token = nil, nil, "" + p.srv, p.ln, p.token, p.live = nil, nil, "", nil p.mu.Unlock() if srv != nil { _ = srv.Close() @@ -155,6 +191,7 @@ func (p *streamProxy) urlFor(cameraID, file string) string { func (p *streamProxy) handle(w http.ResponseWriter, r *http.Request) { p.mu.RLock() token, target, user, pass, client := p.token, p.target, p.user, p.pass, p.client + liveFn := p.live p.mu.RUnlock() if token == "" || client == nil { http.NotFound(w, r) @@ -190,6 +227,17 @@ func (p *streamProxy) handle(w http.ResponseWriter, r *http.Request) { // calls; it is here so that adding a still later is a change to a screen // rather than a change to the one file where a mistake is a credentialed // proxy onto the biometric API. + // Head office's relay, not the engine. The two are different machines and + // different credentials, so this returns rather than falling through. + if parts[3] == "live.mjpeg" { + if liveFn == nil { + http.Error(w, "not signed in to head office", http.StatusBadGateway) + return + } + p.relayRemote(w, r, cameraID, liveFn) + return + } + var enginePath string switch parts[3] { case "stream.mjpeg": diff --git a/desktop/stream_remote.go b/desktop/stream_remote.go new file mode 100644 index 0000000..4066cc6 --- /dev/null +++ b/desktop/stream_remote.go @@ -0,0 +1,149 @@ +package main + +// Watching a camera in another building, from the app. +// +// The shop PC sits behind a router with no inbound route, so nothing here can +// pull its MJPEG stream - that stream is served on the shop PC's own loopback +// and always will be. Head office's LiveHub is the way round it: the agent +// asks outbound whether anyone is watching and pushes JPEG frames up for +// exactly as long as somebody is. The head-office web app already consumes +// that; this is the same feed, for the app. +// +// It arrives as base64 frames over SSE, which an cannot render, so this +// re-emits them as multipart MJPEG - which an renders natively, through +// the relay that already exists for the local engine. That is what keeps ONE +// code path in the screens: a tile points at a loopback URL and does not know +// or care which building the picture came from. + +import ( + "bufio" + "context" + "encoding/base64" + "fmt" + "net/http" + "strings" + "time" +) + +// The boundary is ours to choose; it only has to be a string the JPEG bytes +// cannot contain, and a marker line never appears inside JPEG data. +const mjpegBoundary = "behavisionframe" + +// A frame is base64, so ~1.33 bytes on the wire per byte of picture. The +// engine re-encodes to 640 px for the relay and those measure ~20 KB, so this +// is roughly a hundredfold headroom - large enough never to clip a real frame +// and small enough that a broken or hostile stream cannot grow this process's +// memory without bound. +const maxFrameLine = 8 << 20 + +func (p *streamProxy) relayRemote(w http.ResponseWriter, r *http.Request, + cameraID string, open func(context.Context, string) (*http.Response, error)) { + + w.Header().Set("Content-Type", "multipart/x-mixed-replace; boundary="+mjpegBoundary) + w.Header().Set("Cache-Control", "no-store") + flusher, _ := w.(http.Flusher) + + // Send the headers NOW, before any frame exists. Go writes them on the + // first body write, so without this the whole response - status line + // included - waits for the shop computer to start pushing, and a viewer + // whose camera is slow to answer sees the REQUEST time out rather than a + // stream that has not painted yet. Measured against production: 30 + // seconds and not even a Content-Type. + if flusher != nil { + flusher.Flush() + } + + // Reconnecting is normal, not an error. The server caps one push at five + // minutes so that a tab left open for a week cannot leave a shop + // uploading for a week - so a viewer who IS still there simply asks + // again. Doing it here rather than in the page is what lets the + // survive the cap: it never sees the stream end. + sent := 0 + for { + if r.Context().Err() != nil { + return + } + n, err := p.pumpRemote(w, flusher, r.Context(), cameraID, open) + sent += n + if r.Context().Err() != nil { + return + } + // Nothing was written and the attempt failed. Writing an error body + // now would be writing it into a multipart stream the is + // already parsing, so the picture simply stays on whatever it last + // showed and the screen's own "not connecting" state is the report. + if err != nil && sent == 0 { + return + } + select { + case <-r.Context().Done(): + return + case <-time.After(1500 * time.Millisecond): + } + } +} + +// pumpRemote runs one SSE connection to exhaustion and returns how many +// frames it forwarded. +func (p *streamProxy) pumpRemote(w http.ResponseWriter, flusher http.Flusher, + ctx context.Context, cameraID string, + open func(context.Context, string) (*http.Response, error)) (int, error) { + + resp, err := open(ctx, cameraID) + if err != nil { + return 0, err + } + defer resp.Body.Close() + + sc := bufio.NewScanner(resp.Body) + sc.Buffer(make([]byte, 0, 64*1024), maxFrameLine) + + var event, data string + frames := 0 + for sc.Scan() { + line := sc.Text() + switch { + case strings.HasPrefix(line, "event: "): + event = strings.TrimSpace(line[7:]) + case strings.HasPrefix(line, "data: "): + data = line[6:] + case line == "": + // End of one SSE event. `waiting` means head office has us + // registered and the shop PC has not started pushing yet - a real + // second or two while the agent is asked, and nothing to draw. + if event == "frame" && data != "" { + if err := writeMJPEGFrame(w, flusher, data); err != nil { + return frames, err // the webview went away + } + frames++ + } + event, data = "", "" + } + } + return frames, sc.Err() +} + +func writeMJPEGFrame(w http.ResponseWriter, flusher http.Flusher, b64 string) error { + jpg, err := base64.StdEncoding.DecodeString(b64) + if err != nil || len(jpg) == 0 { + // One malformed frame is not a reason to tear down a working view. + return nil + } + if _, err := fmt.Fprintf(w, + "--%s\r\nContent-Type: image/jpeg\r\nContent-Length: %d\r\n\r\n", + mjpegBoundary, len(jpg)); err != nil { + return err + } + if _, err := w.Write(jpg); err != nil { + return err + } + if _, err := w.Write([]byte("\r\n")); err != nil { + return err + } + // Flushed per frame. Anything held waiting for a full buffer is a tile + // that stays blank, which is indistinguishable from the view not working. + if flusher != nil { + flusher.Flush() + } + return nil +} diff --git a/desktop/stream_remote_live_test.go b/desktop/stream_remote_live_test.go new file mode 100644 index 0000000..76a0106 --- /dev/null +++ b/desktop/stream_remote_live_test.go @@ -0,0 +1,103 @@ +package main + +import ( + "bytes" + "context" + "net/http" + "os" + "testing" + "time" + + "github.com/loyaly/behavision-desktop/internal/cloud" +) + +// The whole chain against the real head office and a real shop computer: +// +// TEST_CLOUD_EMAIL=... TEST_CLOUD_PASSWORD=... \ +// go test ./desktop/ -run RemoteLive -v +// +// Everything in stream_remote_test.go proves the relay against a fake that +// agrees with me. Only this proves the part that cannot be faked: that a shop +// computer behind a router with no inbound route actually pushes frames when +// asked, that they survive base64 and SSE, and that what comes out of the +// loopback relay is a multipart stream an will paint. +// +// It also costs something to run, which is why it is opt-in: watching makes +// the shop computer upload for as long as the test reads. +func TestRemoteLiveFromProduction(t *testing.T) { + email, pass := os.Getenv("TEST_CLOUD_EMAIL"), os.Getenv("TEST_CLOUD_PASSWORD") + if email == "" || pass == "" { + t.Skip("set TEST_CLOUD_EMAIL and TEST_CLOUD_PASSWORD to run against production") + } + base := os.Getenv("TEST_CLOUD_URL") + if base == "" { + base = "https://mcp.loyaly.ai" + } + + ctx, cancel := context.WithTimeout(context.Background(), 90*time.Second) + defer cancel() + c := cloud.New(base) + if _, err := c.Login(ctx, email, pass); err != nil { + t.Fatalf("login: %v", err) + } + + cams, err := c.RemoteCameras(ctx) + if err != nil { + t.Fatalf("cameras: %v", err) + } + t.Logf("%d cameras", len(cams)) + target := os.Getenv("TEST_CLOUD_CAMERA") + for _, cam := range cams { + conn := "waiting" + if cam.Connected != nil { + conn = map[bool]string{true: "connected", false: "not connecting"}[*cam.Connected] + } + t.Logf(" %-10s %-16s %-15s snapshot=%v", cam.CameraID, cam.Site, conn, cam.Snapshot.Available) + if target == "" && cam.Connected != nil && *cam.Connected { + target = cam.CameraID + } + } + if target == "" { + t.Skip("no connected camera to watch") + } + + p := newStreamProxy() + if err := p.watchRemote(c.CameraLive); err != nil { + t.Fatalf("watchRemote: %v", err) + } + defer p.stop() + + rctx, rcancel := context.WithTimeout(ctx, 30*time.Second) + defer rcancel() + req, _ := http.NewRequestWithContext(rctx, http.MethodGet, p.urlFor(target, "live.mjpeg"), nil) + resp, err := http.DefaultClient.Do(req) + if err != nil { + t.Fatalf("GET relay: %v", err) + } + defer resp.Body.Close() + + start := time.Now() + acc, buf, frames := make([]byte, 0, 1<<20), make([]byte, 32*1024), 0 + for frames < 10 { + n, rerr := resp.Body.Read(buf) + acc = append(acc, buf[:n]...) + frames = bytes.Count(acc, []byte("--"+mjpegBoundary)) + if rerr != nil { + break + } + } + el := time.Since(start) + t.Logf("watching %q: %d frames, %d bytes, %.1fs (%.1f fps, %.0f KB/s)", + target, frames, len(acc), el.Seconds(), + float64(frames)/el.Seconds(), float64(len(acc))/el.Seconds()/1024) + + if frames < 3 { + t.Fatalf("got %d frames from a connected camera - the shop computer is "+ + "not answering head office's request to push", frames) + } + // Bytes that are actually a picture, not a framing header that happens to + // be well formed. A JPEG begins FFD8. + if !bytes.Contains(acc, []byte{0xFF, 0xD8, 0xFF}) { + t.Error("no JPEG start marker anywhere in the stream") + } +} diff --git a/desktop/stream_remote_test.go b/desktop/stream_remote_test.go new file mode 100644 index 0000000..1f5304b --- /dev/null +++ b/desktop/stream_remote_test.go @@ -0,0 +1,209 @@ +package main + +import ( + "bytes" + "context" + "encoding/base64" + "fmt" + "io" + "net/http" + "net/http/httptest" + "strings" + "sync/atomic" + "testing" + "time" +) + +// jpg is a byte sequence that is not valid JPEG and does not need to be: what +// is under test is that the bytes arrive intact and framed, not that a decoder +// likes them. +var jpg = []byte{0xFF, 0xD8, 'h', 'e', 'l', 'l', 'o', 0xFF, 0xD9} + +// sseServer answers head office's live endpoint with `pushes` frames and then +// ends the response, which is what the server's five-minute cap does. +func sseServer(t *testing.T, frames int, hits *int32) *httptest.Server { + t.Helper() + return httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + atomic.AddInt32(hits, 1) + w.Header().Set("Content-Type", "text/event-stream") + fl, _ := w.(http.Flusher) + // Registered, nothing being pushed yet. Nothing may be drawn for it. + fmt.Fprint(w, "event: waiting\ndata: \n\n") + if fl != nil { + fl.Flush() + } + for i := 0; i < frames; i++ { + fmt.Fprintf(w, "event: frame\ndata: %s\n\n", + base64.StdEncoding.EncodeToString(jpg)) + if fl != nil { + fl.Flush() + } + } + })) +} + +func openerFor(srv *httptest.Server) func(context.Context, string) (*http.Response, error) { + return func(ctx context.Context, cam string) (*http.Response, error) { + req, _ := http.NewRequestWithContext(ctx, http.MethodGet, srv.URL+"/live/"+cam, nil) + return http.DefaultClient.Do(req) + } +} + +// The whole point: base64 frames over SSE are not something an can show, +// and a multipart MJPEG stream is. Without this the app could only ever show a +// still, on exactly the computers that cannot reach the camera any other way. +func TestRemoteFramesReachTheWebviewAsMJPEG(t *testing.T) { + var hits int32 + srv := sseServer(t, 3, &hits) + defer srv.Close() + + p := newStreamProxy() + if err := p.watchRemote(openerFor(srv)); err != nil { + t.Fatalf("watchRemote: %v", err) + } + defer p.stop() + + u := p.urlFor("cam2", "live.mjpeg") + if u == "" { + t.Fatal("no relay url; the proxy did not bind") + } + + // The relay reconnects for as long as the viewer is there, so the read is + // bounded by us rather than by the stream ending - exactly as an + // would behave. + ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second) + defer cancel() + req, _ := http.NewRequestWithContext(ctx, http.MethodGet, u, nil) + resp, err := http.DefaultClient.Do(req) + if err != nil { + t.Fatalf("GET relay: %v", err) + } + defer resp.Body.Close() + + if ct := resp.Header.Get("Content-Type"); !strings.HasPrefix(ct, "multipart/x-mixed-replace") { + t.Fatalf("Content-Type = %q, an will not treat that as a stream", ct) + } + + // Read the first three frames' worth and stop; the relay would otherwise + // go on reconnecting forever, which is the behaviour being relied on. + want := append([]byte(fmt.Sprintf("--%s\r\nContent-Type: image/jpeg\r\nContent-Length: %d\r\n\r\n", + mjpegBoundary, len(jpg))), jpg...) + got := make([]byte, 0, 4096) + buf := make([]byte, 512) + for len(got) < 3*len(want) { + n, rerr := resp.Body.Read(buf) + got = append(got, buf[:n]...) + if rerr != nil { + break + } + } + if n := bytes.Count(got, []byte("--"+mjpegBoundary)); n < 3 { + t.Fatalf("got %d frames in %d bytes, want at least 3", n, len(got)) + } + if !bytes.Contains(got, want) { + t.Errorf("a frame was not framed as expected:\n%q", got[:min(len(got), 300)]) + } + // `waiting` is a real state - head office has us registered and the shop + // computer has not started pushing - and there is nothing to draw for it. + // Emitting an empty part would blank a tile that already had a picture. + if bytes.Contains(got, []byte("Content-Length: 0")) { + t.Error("an empty frame was written for a waiting event") + } +} + +// The server caps one push at five minutes so a tab left open for a week +// cannot leave a shop uploading for a week. Reconnecting is therefore a normal +// event, and doing it here rather than in the page is what lets the +// survive the cap - it never sees the stream end. +func TestTheRelayReconnectsWhenHeadOfficeEndsAPush(t *testing.T) { + var hits int32 + srv := sseServer(t, 1, &hits) + defer srv.Close() + + p := newStreamProxy() + if err := p.watchRemote(openerFor(srv)); err != nil { + t.Fatalf("watchRemote: %v", err) + } + defer p.stop() + + ctx, cancel := context.WithTimeout(context.Background(), 4*time.Second) + defer cancel() + req, _ := http.NewRequestWithContext(ctx, http.MethodGet, p.urlFor("cam2", "live.mjpeg"), nil) + resp, err := http.DefaultClient.Do(req) + if err != nil { + t.Fatalf("GET relay: %v", err) + } + defer resp.Body.Close() + + // Two frames means two pushes, because each push carries exactly one. + seen, buf := 0, make([]byte, 256) + acc := make([]byte, 0, 2048) + for seen < 2 { + n, rerr := resp.Body.Read(buf) + acc = append(acc, buf[:n]...) + seen = bytes.Count(acc, []byte("--"+mjpegBoundary)) + if rerr != nil { + break + } + } + if seen < 2 { + t.Fatalf("got %d frames across reconnects, want 2", seen) + } + if got := atomic.LoadInt32(&hits); got < 2 { + t.Errorf("head office was asked %d times, want at least 2", got) + } +} + +// Signed out, the relay must not pretend. There is no fallback URL to offer +// either: the head-office endpoint needs this session's bearer, which an +// cannot send - so a tile that silently failed would be the only alternative. +func TestTheRelayRefusesWhenNobodyIsSignedIn(t *testing.T) { + p := newStreamProxy() + if err := p.watchRemote(nil); err != nil { + t.Fatalf("watchRemote: %v", err) + } + defer p.stop() + + resp, err := http.Get(p.urlFor("cam2", "live.mjpeg")) + if err != nil { + t.Fatalf("GET relay: %v", err) + } + defer resp.Body.Close() + io.Copy(io.Discard, resp.Body) + if resp.StatusCode != http.StatusBadGateway { + t.Errorf("status = %d, want 502", resp.StatusCode) + } +} + +// The relay is credentialed - it is a path to a live view of a shop floor - +// and the token is the only thing standing between another local process and +// it. live.mjpeg must be behind exactly the same door as the engine routes. +func TestTheRemoteRouteIsBehindTheSameToken(t *testing.T) { + var hits int32 + srv := sseServer(t, 1, &hits) + defer srv.Close() + + p := newStreamProxy() + if err := p.watchRemote(openerFor(srv)); err != nil { + t.Fatalf("watchRemote: %v", err) + } + defer p.stop() + + // The right shape, the wrong value. + parts := strings.Split(p.urlFor("cam2", "live.mjpeg"), "/") + parts[4] = strings.Repeat("0", len(parts[4])) + bad := strings.Join(parts, "/") + + resp, err := http.Get(bad) + if err != nil { + t.Fatalf("GET relay: %v", err) + } + defer resp.Body.Close() + io.Copy(io.Discard, resp.Body) + if resp.StatusCode != http.StatusNotFound { + t.Errorf("status = %d, want 404 - and 404 rather than 403, because there is nothing here to tell an unwelcome caller they found the right door", resp.StatusCode) + } + if atomic.LoadInt32(&hits) != 0 { + t.Error("a request with the wrong token still made the shop computer upload") + } +} diff --git a/server/internal/api/camera_state_test.go b/server/internal/api/camera_state_test.go new file mode 100644 index 0000000..d235cbb --- /dev/null +++ b/server/internal/api/camera_state_test.go @@ -0,0 +1,96 @@ +package api + +import ( + "testing" + "time" +) + +func ptr(b bool) *bool { return &b } + +// The state this was written for. Two cameras read "Connected", in green, on +// the live estate thirty-four minutes after the shop computer had stopped +// being able to see either of them - because the agent correctly reports +// nothing when it cannot reach the engine, and the last value it sent stays +// in the database looking current. +func TestAStaleReportIsNotAConnectedCamera(t *testing.T) { + now := time.Date(2026, 9, 30, 11, 13, 0, 0, time.UTC) + c := Camera{Connected: ptr(true), + LastSeenAt: now.Add(-34 * time.Minute).Format(time.RFC3339)} + c.CameraState(now) + + if c.State != CameraStale { + t.Errorf("state = %q, want %q", c.State, CameraStale) + } + // Cleared, not merely overruled. A stale true left in place stays + // available to every client that reads the field directly, and leaves two + // fields on one object disagreeing. + if c.Connected != nil { + t.Errorf("connected = %v, want null - nobody currently knows", *c.Connected) + } + if c.StateNote == "" { + t.Error("a stale camera said nothing about what to do") + } +} + +// One missed report is a dropped packet. Warning on it would put an alarm on a +// healthy estate every few minutes, and an indicator that cries wolf is one +// people learn to ignore. +func TestOneMissedReportIsStillConnected(t *testing.T) { + now := time.Now() + c := Camera{Connected: ptr(true), + LastSeenAt: now.Add(-90 * time.Second).Format(time.RFC3339)} + c.CameraState(now) + if c.State != CameraConnected { + t.Errorf("state = %q after 90s, want %q", c.State, CameraConnected) + } + if c.Connected == nil || !*c.Connected { + t.Error("a fresh report lost its connected flag") + } +} + +// "Nobody has ever told us" and "nobody has told us lately" need different +// sentences: the first is a camera head office added a minute ago and the +// shop computer has not picked up, the second is a shop computer that has +// stopped. Sending an installer to the wrong one wastes a journey. +func TestNeverReportedIsNotTheSameAsStopped(t *testing.T) { + now := time.Now() + var never Camera + never.CameraState(now) + if never.State != CameraWaiting { + t.Errorf("state = %q, want %q", never.State, CameraWaiting) + } + + stopped := Camera{LastSeenAt: now.Add(-time.Hour).Format(time.RFC3339)} + stopped.CameraState(now) + if stopped.State == never.State { + t.Fatal("a camera nobody has reported and one that stopped read the same") + } + if stopped.StateNote == never.StateNote { + t.Error("two states that need different actions gave the same advice") + } +} + +// A camera the shop computer CAN see and cannot open is the one case where +// "check the cabling" is the right advice, and it must stay distinguishable +// from the three where it is not. +func TestAFreshFailureSaysCheckTheCamera(t *testing.T) { + now := time.Now() + c := Camera{Connected: ptr(false), LastSeenAt: now.Format(time.RFC3339)} + c.CameraState(now) + if c.State != CameraNotConnect { + t.Errorf("state = %q, want %q", c.State, CameraNotConnect) + } + if c.Connected == nil || *c.Connected { + t.Error("a reported failure must stay false, not become unknown") + } +} + +// An unparseable timestamp is not a working camera. It should not be possible, +// which is exactly why it must not fall through to "connected". +func TestAnUnreadableTimestampIsStale(t *testing.T) { + c := Camera{Connected: ptr(true), LastSeenAt: "not a time"} + c.CameraState(time.Now()) + if c.State != CameraStale || c.Connected != nil { + t.Errorf("state = %q connected = %v, want stale and unknown", c.State, c.Connected) + } +} diff --git a/server/internal/api/types.go b/server/internal/api/types.go index 235ccf6..ca1b3b6 100644 --- a/server/internal/api/types.go +++ b/server/internal/api/types.go @@ -655,6 +655,11 @@ type Camera struct { Snapshot Image `json:"snapshot"` SnapshotAt string `json:"snapshot_at,omitempty"` + // State is the ONE answer a screen should render, because there are four + // of them and only three were ever expressed. See CameraState. + State string `json:"state"` + StateNote string `json:"state_note,omitempty"` + // Check is the last attempt to prove this camera works. Always present so // a client can tell "never checked" from "checked and failed" without // guessing from an absent field. @@ -962,3 +967,70 @@ type DeviceSession struct { // hand. Current bool `json:"current"` } + +// Camera states, and why a fourth one had to exist. +// +// A shop computer reports each camera's state about once a minute. When it +// cannot reach the recognition engine it reports NOTHING - correctly, because +// it has nothing to say - and the last value it sent stays in the database +// unchanged. Measured on the live estate: two cameras reading **Connected**, +// in green, thirty-four minutes after the shop computer had stopped being +// able to see either of them, while the heartbeat from the same PC said +// 0 of 0 cameras. Both surfaces were reading stored fields and disagreeing. +// +// `false` could not be the answer. It means "this camera is not connecting", +// which sends an installer to check cabling on a camera that was working +// perfectly the last time anybody could ask it. The honest statement is that +// nobody currently knows - and that is a different sentence from "nobody has +// ever told us", which is what an unreported camera needs. Two states that +// need different actions must never share a word; the same rule that keeps +// `artifact` apart from `no_faces` in the commissioning verdicts. +const ( + CameraConnected = "connected" // reported recently, and working + CameraNotConnect = "not_connecting" // reported recently, and not + CameraWaiting = "waiting" // no shop computer has ever reported + CameraStale = "stale" // reported once, and not lately +) + +// CameraStaleAfter is five missed reports, not one. +// +// The agent reports on a 60 s tick, so one miss is a dropped packet or a slow +// upload. Calling that stale would put a warning on a healthy estate every few +// minutes, and an indicator that cries wolf is one people learn to ignore - +// which is the same reasoning that makes a site offline after three missed +// heartbeats rather than one. +const CameraStaleAfter = 5 * time.Minute + +// CameraState decides the four states, and nulls Connected when it is not +// entitled to an opinion. +// +// Connected is CLEARED rather than left alone on purpose. Leaving a stale true +// in place would keep the lie available to every client that reads the field +// directly - a mobile app, a script, an older build of our own desktop app - +// and would leave two fields on one object disagreeing, which is precisely how +// the shops screen once came out labelled Working in green above "2 of 3 +// cameras not connecting". +func (c *Camera) CameraState(now time.Time) { + switch { + case c.LastSeenAt == "": + c.State = CameraWaiting + c.StateNote = "No shop computer has reported on this camera yet." + c.Connected = nil + return + } + seen, err := time.Parse(time.RFC3339, c.LastSeenAt) + if err != nil || now.Sub(seen) > CameraStaleAfter { + c.State = CameraStale + c.StateNote = "The shop computer has stopped reporting this camera. " + + "Check that the computer is on and Behavision is running on it." + c.Connected = nil + return + } + if c.Connected != nil && *c.Connected { + c.State = CameraConnected + return + } + c.State = CameraNotConnect + c.StateNote = "The shop computer cannot open this camera's stream. " + + "Check the address, the password and the cabling." +} diff --git a/server/internal/store/api_cameras.go b/server/internal/store/api_cameras.go index 14caeef..633fd8d 100644 --- a/server/internal/store/api_cameras.go +++ b/server/internal/store/api_cameras.go @@ -59,6 +59,11 @@ func scanCamera(row pgx.Row) (api.Camera, error) { // The KEY travels in ImageKey, which is json:"-", and the handler swaps it // for a signed link. Same rule as an arrival's face. c.Snapshot.Key = snapKey + // Here rather than in a handler, because every camera anybody reads comes + // through this function and a state computed per caller is a state one + // caller forgets - which is how a stale `connected` reached three screens + // at once. + c.CameraState(time.Now()) return c, nil } diff --git a/server/internal/web/dist/assets/index-Ckr5hGZd.js b/server/internal/web/dist/assets/index-BuVkBNdU.js similarity index 84% rename from server/internal/web/dist/assets/index-Ckr5hGZd.js rename to server/internal/web/dist/assets/index-BuVkBNdU.js index ed098e4..d6df532 100644 --- a/server/internal/web/dist/assets/index-Ckr5hGZd.js +++ b/server/internal/web/dist/assets/index-BuVkBNdU.js @@ -22,7 +22,7 @@ * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. - */(function(e){function t(C,z){var L=C.length;C.push(z);e:for(;0>>1,q=C[G];if(0>>1;Gl(Rl,L))wtl(dr,Rl)?(C[G]=dr,C[wt]=L,G=wt):(C[G]=Rl,C[gt]=L,G=gt);else if(wtl(dr,L))C[G]=dr,C[wt]=L,G=wt;else break e}}return z}function l(C,z){var L=C.sortIndex-z.sortIndex;return L!==0?L:C.id-z.id}if(typeof performance=="object"&&typeof performance.now=="function"){var s=performance;e.unstable_now=function(){return s.now()}}else{var o=Date,a=o.now();e.unstable_now=function(){return o.now()-a}}var u=[],c=[],m=1,h=null,v=3,y=!1,x=!1,g=!1,P=typeof setTimeout=="function"?setTimeout:null,p=typeof clearTimeout=="function"?clearTimeout:null,d=typeof setImmediate<"u"?setImmediate:null;typeof navigator<"u"&&navigator.scheduling!==void 0&&navigator.scheduling.isInputPending!==void 0&&navigator.scheduling.isInputPending.bind(navigator.scheduling);function f(C){for(var z=n(c);z!==null;){if(z.callback===null)r(c);else if(z.startTime<=C)r(c),z.sortIndex=z.expirationTime,t(u,z);else break;z=n(c)}}function w(C){if(g=!1,f(C),!x)if(n(u)!==null)x=!0,zl(S);else{var z=n(c);z!==null&&Ll(w,z.startTime-C)}}function S(C,z){x=!1,g&&(g=!1,p(T),T=-1),y=!0;var L=v;try{for(f(z),h=n(u);h!==null&&(!(h.expirationTime>z)||C&&!Te());){var G=h.callback;if(typeof G=="function"){h.callback=null,v=h.priorityLevel;var q=G(h.expirationTime<=z);z=e.unstable_now(),typeof q=="function"?h.callback=q:h===n(u)&&r(u),f(z)}else r(u);h=n(u)}if(h!==null)var cr=!0;else{var gt=n(c);gt!==null&&Ll(w,gt.startTime-z),cr=!1}return cr}finally{h=null,v=L,y=!1}}var E=!1,_=null,T=-1,K=5,O=-1;function Te(){return!(e.unstable_now()-OC||125G?(C.sortIndex=L,t(c,C),n(u)===null&&C===n(c)&&(g?(p(T),T=-1):g=!0,Ll(w,L-G))):(C.sortIndex=q,t(u,C),x||y||(x=!0,zl(S))),C},e.unstable_shouldYield=Te,e.unstable_wrapCallback=function(C){var z=v;return function(){var L=v;v=z;try{return C.apply(this,arguments)}finally{v=L}}}})(Na);Sa.exports=Na;var Yc=Sa.exports;/** + */(function(e){function t(E,z){var L=E.length;E.push(z);e:for(;0>>1,q=E[G];if(0>>1;Gl(Rl,L))wtl(dr,Rl)?(E[G]=dr,E[wt]=L,G=wt):(E[G]=Rl,E[gt]=L,G=gt);else if(wtl(dr,L))E[G]=dr,E[wt]=L,G=wt;else break e}}return z}function l(E,z){var L=E.sortIndex-z.sortIndex;return L!==0?L:E.id-z.id}if(typeof performance=="object"&&typeof performance.now=="function"){var s=performance;e.unstable_now=function(){return s.now()}}else{var o=Date,a=o.now();e.unstable_now=function(){return o.now()-a}}var u=[],c=[],m=1,h=null,v=3,y=!1,x=!1,g=!1,N=typeof setTimeout=="function"?setTimeout:null,f=typeof clearTimeout=="function"?clearTimeout:null,d=typeof setImmediate<"u"?setImmediate:null;typeof navigator<"u"&&navigator.scheduling!==void 0&&navigator.scheduling.isInputPending!==void 0&&navigator.scheduling.isInputPending.bind(navigator.scheduling);function p(E){for(var z=n(c);z!==null;){if(z.callback===null)r(c);else if(z.startTime<=E)r(c),z.sortIndex=z.expirationTime,t(u,z);else break;z=n(c)}}function w(E){if(g=!1,p(E),!x)if(n(u)!==null)x=!0,zl(S);else{var z=n(c);z!==null&&Ll(w,z.startTime-E)}}function S(E,z){x=!1,g&&(g=!1,f(T),T=-1),y=!0;var L=v;try{for(p(z),h=n(u);h!==null&&(!(h.expirationTime>z)||E&&!Te());){var G=h.callback;if(typeof G=="function"){h.callback=null,v=h.priorityLevel;var q=G(h.expirationTime<=z);z=e.unstable_now(),typeof q=="function"?h.callback=q:h===n(u)&&r(u),p(z)}else r(u);h=n(u)}if(h!==null)var cr=!0;else{var gt=n(c);gt!==null&&Ll(w,gt.startTime-z),cr=!1}return cr}finally{h=null,v=L,y=!1}}var _=!1,P=null,T=-1,K=5,O=-1;function Te(){return!(e.unstable_now()-OE||125G?(E.sortIndex=L,t(c,E),n(u)===null&&E===n(c)&&(g?(f(T),T=-1):g=!0,Ll(w,L-G))):(E.sortIndex=q,t(u,E),x||y||(x=!0,zl(S))),E},e.unstable_shouldYield=Te,e.unstable_wrapCallback=function(E){var z=v;return function(){var L=v;v=z;try{return E.apply(this,arguments)}finally{v=L}}}})(Na);Sa.exports=Na;var Yc=Sa.exports;/** * @license React * react-dom.production.min.js * @@ -34,13 +34,13 @@ `+Il+e}var Fl=!1;function Dl(e,t){if(!e||Fl)return"";Fl=!0;var n=Error.prepareStackTrace;Error.prepareStackTrace=void 0;try{if(t)if(t=function(){throw Error()},Object.defineProperty(t.prototype,"props",{set:function(){throw Error()}}),typeof Reflect=="object"&&Reflect.construct){try{Reflect.construct(t,[])}catch(c){var r=c}Reflect.construct(e,[],t)}else{try{t.call()}catch(c){r=c}e.call(t.prototype)}else{try{throw Error()}catch(c){r=c}e()}}catch(c){if(c&&r&&typeof c.stack=="string"){for(var l=c.stack.split(` `),s=r.stack.split(` `),o=l.length-1,a=s.length-1;1<=o&&0<=a&&l[o]!==s[a];)a--;for(;1<=o&&0<=a;o--,a--)if(l[o]!==s[a]){if(o!==1||a!==1)do if(o--,a--,0>a||l[o]!==s[a]){var u=` -`+l[o].replace(" at new "," at ");return e.displayName&&u.includes("")&&(u=u.replace("",e.displayName)),u}while(1<=o&&0<=a);break}}}finally{Fl=!1,Error.prepareStackTrace=n}return(e=e?e.displayName||e.name:"")?Cn(e):""}function ed(e){switch(e.tag){case 5:return Cn(e.type);case 16:return Cn("Lazy");case 13:return Cn("Suspense");case 19:return Cn("SuspenseList");case 0:case 2:case 15:return e=Dl(e.type,!1),e;case 11:return e=Dl(e.type.render,!1),e;case 1:return e=Dl(e.type,!0),e;default:return""}}function cs(e){if(e==null)return null;if(typeof e=="function")return e.displayName||e.name||null;if(typeof e=="string")return e;switch(e){case At:return"Fragment";case Ut:return"Portal";case os:return"Profiler";case oi:return"StrictMode";case as:return"Suspense";case us:return"SuspenseList"}if(typeof e=="object")switch(e.$$typeof){case _a:return(e.displayName||"Context")+".Consumer";case Ea:return(e._context.displayName||"Context")+".Provider";case ai:var t=e.render;return e=e.displayName,e||(e=t.displayName||t.name||"",e=e!==""?"ForwardRef("+e+")":"ForwardRef"),e;case ui:return t=e.displayName||null,t!==null?t:cs(e.type)||"Memo";case be:t=e._payload,e=e._init;try{return cs(e(t))}catch{}}return null}function td(e){var t=e.type;switch(e.tag){case 24:return"Cache";case 9:return(t.displayName||"Context")+".Consumer";case 10:return(t._context.displayName||"Context")+".Provider";case 18:return"DehydratedFragment";case 11:return e=t.render,e=e.displayName||e.name||"",t.displayName||(e!==""?"ForwardRef("+e+")":"ForwardRef");case 7:return"Fragment";case 5:return t;case 4:return"Portal";case 3:return"Root";case 6:return"Text";case 16:return cs(t);case 8:return t===oi?"StrictMode":"Mode";case 22:return"Offscreen";case 12:return"Profiler";case 21:return"Scope";case 13:return"Suspense";case 19:return"SuspenseList";case 25:return"TracingMarker";case 1:case 0:case 17:case 2:case 14:case 15:if(typeof t=="function")return t.displayName||t.name||null;if(typeof t=="string")return t}return null}function pt(e){switch(typeof e){case"boolean":case"number":case"string":case"undefined":return e;case"object":return e;default:return""}}function Ta(e){var t=e.type;return(e=e.nodeName)&&e.toLowerCase()==="input"&&(t==="checkbox"||t==="radio")}function nd(e){var t=Ta(e)?"checked":"value",n=Object.getOwnPropertyDescriptor(e.constructor.prototype,t),r=""+e[t];if(!e.hasOwnProperty(t)&&typeof n<"u"&&typeof n.get=="function"&&typeof n.set=="function"){var l=n.get,s=n.set;return Object.defineProperty(e,t,{configurable:!0,get:function(){return l.call(this)},set:function(o){r=""+o,s.call(this,o)}}),Object.defineProperty(e,t,{enumerable:n.enumerable}),{getValue:function(){return r},setValue:function(o){r=""+o},stopTracking:function(){e._valueTracker=null,delete e[t]}}}}function hr(e){e._valueTracker||(e._valueTracker=nd(e))}function za(e){if(!e)return!1;var t=e._valueTracker;if(!t)return!0;var n=t.getValue(),r="";return e&&(r=Ta(e)?e.checked?"true":"false":e.value),e=r,e!==n?(t.setValue(e),!0):!1}function Vr(e){if(e=e||(typeof document<"u"?document:void 0),typeof e>"u")return null;try{return e.activeElement||e.body}catch{return e.body}}function ds(e,t){var n=t.checked;return H({},t,{defaultChecked:void 0,defaultValue:void 0,value:void 0,checked:n??e._wrapperState.initialChecked})}function ro(e,t){var n=t.defaultValue==null?"":t.defaultValue,r=t.checked!=null?t.checked:t.defaultChecked;n=pt(t.value!=null?t.value:n),e._wrapperState={initialChecked:r,initialValue:n,controlled:t.type==="checkbox"||t.type==="radio"?t.checked!=null:t.value!=null}}function La(e,t){t=t.checked,t!=null&&ii(e,"checked",t,!1)}function fs(e,t){La(e,t);var n=pt(t.value),r=t.type;if(n!=null)r==="number"?(n===0&&e.value===""||e.value!=n)&&(e.value=""+n):e.value!==""+n&&(e.value=""+n);else if(r==="submit"||r==="reset"){e.removeAttribute("value");return}t.hasOwnProperty("value")?ps(e,t.type,n):t.hasOwnProperty("defaultValue")&&ps(e,t.type,pt(t.defaultValue)),t.checked==null&&t.defaultChecked!=null&&(e.defaultChecked=!!t.defaultChecked)}function lo(e,t,n){if(t.hasOwnProperty("value")||t.hasOwnProperty("defaultValue")){var r=t.type;if(!(r!=="submit"&&r!=="reset"||t.value!==void 0&&t.value!==null))return;t=""+e._wrapperState.initialValue,n||t===e.value||(e.value=t),e.defaultValue=t}n=e.name,n!==""&&(e.name=""),e.defaultChecked=!!e._wrapperState.initialChecked,n!==""&&(e.name=n)}function ps(e,t,n){(t!=="number"||Vr(e.ownerDocument)!==e)&&(n==null?e.defaultValue=""+e._wrapperState.initialValue:e.defaultValue!==""+n&&(e.defaultValue=""+n))}var En=Array.isArray;function Zt(e,t,n,r){if(e=e.options,t){t={};for(var l=0;l"+t.valueOf().toString()+"",t=mr.firstChild;e.firstChild;)e.removeChild(e.firstChild);for(;t.firstChild;)e.appendChild(t.firstChild)}});function Un(e,t){if(t){var n=e.firstChild;if(n&&n===e.lastChild&&n.nodeType===3){n.nodeValue=t;return}}e.textContent=t}var Tn={animationIterationCount:!0,aspectRatio:!0,borderImageOutset:!0,borderImageSlice:!0,borderImageWidth:!0,boxFlex:!0,boxFlexGroup:!0,boxOrdinalGroup:!0,columnCount:!0,columns:!0,flex:!0,flexGrow:!0,flexPositive:!0,flexShrink:!0,flexNegative:!0,flexOrder:!0,gridArea:!0,gridRow:!0,gridRowEnd:!0,gridRowSpan:!0,gridRowStart:!0,gridColumn:!0,gridColumnEnd:!0,gridColumnSpan:!0,gridColumnStart:!0,fontWeight:!0,lineClamp:!0,lineHeight:!0,opacity:!0,order:!0,orphans:!0,tabSize:!0,widows:!0,zIndex:!0,zoom:!0,fillOpacity:!0,floodOpacity:!0,stopOpacity:!0,strokeDasharray:!0,strokeDashoffset:!0,strokeMiterlimit:!0,strokeOpacity:!0,strokeWidth:!0},rd=["Webkit","ms","Moz","O"];Object.keys(Tn).forEach(function(e){rd.forEach(function(t){t=t+e.charAt(0).toUpperCase()+e.substring(1),Tn[t]=Tn[e]})});function Fa(e,t,n){return t==null||typeof t=="boolean"||t===""?"":n||typeof t!="number"||t===0||Tn.hasOwnProperty(e)&&Tn[e]?(""+t).trim():t+"px"}function Da(e,t){e=e.style;for(var n in t)if(t.hasOwnProperty(n)){var r=n.indexOf("--")===0,l=Fa(n,t[n],r);n==="float"&&(n="cssFloat"),r?e.setProperty(n,l):e[n]=l}}var ld=H({menuitem:!0},{area:!0,base:!0,br:!0,col:!0,embed:!0,hr:!0,img:!0,input:!0,keygen:!0,link:!0,meta:!0,param:!0,source:!0,track:!0,wbr:!0});function vs(e,t){if(t){if(ld[e]&&(t.children!=null||t.dangerouslySetInnerHTML!=null))throw Error(k(137,e));if(t.dangerouslySetInnerHTML!=null){if(t.children!=null)throw Error(k(60));if(typeof t.dangerouslySetInnerHTML!="object"||!("__html"in t.dangerouslySetInnerHTML))throw Error(k(61))}if(t.style!=null&&typeof t.style!="object")throw Error(k(62))}}function ys(e,t){if(e.indexOf("-")===-1)return typeof t.is=="string";switch(e){case"annotation-xml":case"color-profile":case"font-face":case"font-face-src":case"font-face-uri":case"font-face-format":case"font-face-name":case"missing-glyph":return!1;default:return!0}}var gs=null;function ci(e){return e=e.target||e.srcElement||window,e.correspondingUseElement&&(e=e.correspondingUseElement),e.nodeType===3?e.parentNode:e}var ws=null,qt=null,bt=null;function oo(e){if(e=lr(e)){if(typeof ws!="function")throw Error(k(280));var t=e.stateNode;t&&(t=gl(t),ws(e.stateNode,e.type,t))}}function Ma(e){qt?bt?bt.push(e):bt=[e]:qt=e}function $a(){if(qt){var e=qt,t=bt;if(bt=qt=null,oo(e),t)for(e=0;e>>=0,e===0?32:31-(md(e)/vd|0)|0}var vr=64,yr=4194304;function _n(e){switch(e&-e){case 1:return 1;case 2:return 2;case 4:return 4;case 8:return 8;case 16:return 16;case 32:return 32;case 64:case 128:case 256:case 512:case 1024:case 2048:case 4096:case 8192:case 16384:case 32768:case 65536:case 131072:case 262144:case 524288:case 1048576:case 2097152:return e&4194240;case 4194304:case 8388608:case 16777216:case 33554432:case 67108864:return e&130023424;case 134217728:return 134217728;case 268435456:return 268435456;case 536870912:return 536870912;case 1073741824:return 1073741824;default:return e}}function Kr(e,t){var n=e.pendingLanes;if(n===0)return 0;var r=0,l=e.suspendedLanes,s=e.pingedLanes,o=n&268435455;if(o!==0){var a=o&~l;a!==0?r=_n(a):(s&=o,s!==0&&(r=_n(s)))}else o=n&~l,o!==0?r=_n(o):s!==0&&(r=_n(s));if(r===0)return 0;if(t!==0&&t!==r&&!(t&l)&&(l=r&-r,s=t&-t,l>=s||l===16&&(s&4194240)!==0))return t;if(r&4&&(r|=n&16),t=e.entangledLanes,t!==0)for(e=e.entanglements,t&=r;0n;n++)t.push(e);return t}function nr(e,t,n){e.pendingLanes|=t,t!==536870912&&(e.suspendedLanes=0,e.pingedLanes=0),e=e.eventTimes,t=31-Ie(t),e[t]=n}function xd(e,t){var n=e.pendingLanes&~t;e.pendingLanes=t,e.suspendedLanes=0,e.pingedLanes=0,e.expiredLanes&=t,e.mutableReadLanes&=t,e.entangledLanes&=t,t=e.entanglements;var r=e.eventTimes;for(e=e.expirationTimes;0=Ln),yo=" ",go=!1;function lu(e,t){switch(e){case"keyup":return Yd.indexOf(t.keyCode)!==-1;case"keydown":return t.keyCode!==229;case"keypress":case"mousedown":case"focusout":return!0;default:return!1}}function su(e){return e=e.detail,typeof e=="object"&&"data"in e?e.data:null}var Bt=!1;function Jd(e,t){switch(e){case"compositionend":return su(t);case"keypress":return t.which!==32?null:(go=!0,yo);case"textInput":return e=t.data,e===yo&&go?null:e;default:return null}}function Zd(e,t){if(Bt)return e==="compositionend"||!gi&&lu(e,t)?(e=nu(),Rr=mi=rt=null,Bt=!1,e):null;switch(e){case"paste":return null;case"keypress":if(!(t.ctrlKey||t.altKey||t.metaKey)||t.ctrlKey&&t.altKey){if(t.char&&1=t)return{node:n,offset:t-e};e=r}e:{for(;n;){if(n.nextSibling){n=n.nextSibling;break e}n=n.parentNode}n=void 0}n=jo(n)}}function uu(e,t){return e&&t?e===t?!0:e&&e.nodeType===3?!1:t&&t.nodeType===3?uu(e,t.parentNode):"contains"in e?e.contains(t):e.compareDocumentPosition?!!(e.compareDocumentPosition(t)&16):!1:!1}function cu(){for(var e=window,t=Vr();t instanceof e.HTMLIFrameElement;){try{var n=typeof t.contentWindow.location.href=="string"}catch{n=!1}if(n)e=t.contentWindow;else break;t=Vr(e.document)}return t}function wi(e){var t=e&&e.nodeName&&e.nodeName.toLowerCase();return t&&(t==="input"&&(e.type==="text"||e.type==="search"||e.type==="tel"||e.type==="url"||e.type==="password")||t==="textarea"||e.contentEditable==="true")}function of(e){var t=cu(),n=e.focusedElem,r=e.selectionRange;if(t!==n&&n&&n.ownerDocument&&uu(n.ownerDocument.documentElement,n)){if(r!==null&&wi(n)){if(t=r.start,e=r.end,e===void 0&&(e=t),"selectionStart"in n)n.selectionStart=t,n.selectionEnd=Math.min(e,n.value.length);else if(e=(t=n.ownerDocument||document)&&t.defaultView||window,e.getSelection){e=e.getSelection();var l=n.textContent.length,s=Math.min(r.start,l);r=r.end===void 0?s:Math.min(r.end,l),!e.extend&&s>r&&(l=r,r=s,s=l),l=So(n,s);var o=So(n,r);l&&o&&(e.rangeCount!==1||e.anchorNode!==l.node||e.anchorOffset!==l.offset||e.focusNode!==o.node||e.focusOffset!==o.offset)&&(t=t.createRange(),t.setStart(l.node,l.offset),e.removeAllRanges(),s>r?(e.addRange(t),e.extend(o.node,o.offset)):(t.setEnd(o.node,o.offset),e.addRange(t)))}}for(t=[],e=n;e=e.parentNode;)e.nodeType===1&&t.push({element:e,left:e.scrollLeft,top:e.scrollTop});for(typeof n.focus=="function"&&n.focus(),n=0;n=document.documentMode,Vt=null,Cs=null,On=null,Es=!1;function No(e,t,n){var r=n.window===n?n.document:n.nodeType===9?n:n.ownerDocument;Es||Vt==null||Vt!==Vr(r)||(r=Vt,"selectionStart"in r&&wi(r)?r={start:r.selectionStart,end:r.selectionEnd}:(r=(r.ownerDocument&&r.ownerDocument.defaultView||window).getSelection(),r={anchorNode:r.anchorNode,anchorOffset:r.anchorOffset,focusNode:r.focusNode,focusOffset:r.focusOffset}),On&&Qn(On,r)||(On=r,r=Xr(Cs,"onSelect"),0Qt||(e.current=Rs[Qt],Rs[Qt]=null,Qt--)}function $(e,t){Qt++,Rs[Qt]=e.current,e.current=t}var ht={},oe=vt(ht),he=vt(!1),Tt=ht;function ln(e,t){var n=e.type.contextTypes;if(!n)return ht;var r=e.stateNode;if(r&&r.__reactInternalMemoizedUnmaskedChildContext===t)return r.__reactInternalMemoizedMaskedChildContext;var l={},s;for(s in n)l[s]=t[s];return r&&(e=e.stateNode,e.__reactInternalMemoizedUnmaskedChildContext=t,e.__reactInternalMemoizedMaskedChildContext=l),l}function me(e){return e=e.childContextTypes,e!=null}function Zr(){A(he),A(oe)}function Lo(e,t,n){if(oe.current!==ht)throw Error(k(168));$(oe,t),$(he,n)}function wu(e,t,n){var r=e.stateNode;if(t=t.childContextTypes,typeof r.getChildContext!="function")return n;r=r.getChildContext();for(var l in r)if(!(l in t))throw Error(k(108,td(e)||"Unknown",l));return H({},n,r)}function qr(e){return e=(e=e.stateNode)&&e.__reactInternalMemoizedMergedChildContext||ht,Tt=oe.current,$(oe,e),$(he,he.current),!0}function Ro(e,t,n){var r=e.stateNode;if(!r)throw Error(k(169));n?(e=wu(e,t,Tt),r.__reactInternalMemoizedMergedChildContext=e,A(he),A(oe),$(oe,e)):A(he),$(he,n)}var We=null,wl=!1,Jl=!1;function xu(e){We===null?We=[e]:We.push(e)}function wf(e){wl=!0,xu(e)}function yt(){if(!Jl&&We!==null){Jl=!0;var e=0,t=M;try{var n=We;for(M=1;e>=o,l-=o,He=1<<32-Ie(t)+l|n<T?(K=_,_=null):K=_.sibling;var O=v(p,_,f[T],w);if(O===null){_===null&&(_=K);break}e&&_&&O.alternate===null&&t(p,_),d=s(O,d,T),E===null?S=O:E.sibling=O,E=O,_=K}if(T===f.length)return n(p,_),B&&xt(p,T),S;if(_===null){for(;TT?(K=_,_=null):K=_.sibling;var Te=v(p,_,O.value,w);if(Te===null){_===null&&(_=K);break}e&&_&&Te.alternate===null&&t(p,_),d=s(Te,d,T),E===null?S=Te:E.sibling=Te,E=Te,_=K}if(O.done)return n(p,_),B&&xt(p,T),S;if(_===null){for(;!O.done;T++,O=f.next())O=h(p,O.value,w),O!==null&&(d=s(O,d,T),E===null?S=O:E.sibling=O,E=O);return B&&xt(p,T),S}for(_=r(p,_);!O.done;T++,O=f.next())O=y(_,p,T,O.value,w),O!==null&&(e&&O.alternate!==null&&_.delete(O.key===null?T:O.key),d=s(O,d,T),E===null?S=O:E.sibling=O,E=O);return e&&_.forEach(function(hn){return t(p,hn)}),B&&xt(p,T),S}function P(p,d,f,w){if(typeof f=="object"&&f!==null&&f.type===At&&f.key===null&&(f=f.props.children),typeof f=="object"&&f!==null){switch(f.$$typeof){case pr:e:{for(var S=f.key,E=d;E!==null;){if(E.key===S){if(S=f.type,S===At){if(E.tag===7){n(p,E.sibling),d=l(E,f.props.children),d.return=p,p=d;break e}}else if(E.elementType===S||typeof S=="object"&&S!==null&&S.$$typeof===be&&Fo(S)===E.type){n(p,E.sibling),d=l(E,f.props),d.ref=kn(p,E,f),d.return=p,p=d;break e}n(p,E);break}else t(p,E);E=E.sibling}f.type===At?(d=_t(f.props.children,p.mode,w,f.key),d.return=p,p=d):(w=Ar(f.type,f.key,f.props,null,p.mode,w),w.ref=kn(p,d,f),w.return=p,p=w)}return o(p);case Ut:e:{for(E=f.key;d!==null;){if(d.key===E)if(d.tag===4&&d.stateNode.containerInfo===f.containerInfo&&d.stateNode.implementation===f.implementation){n(p,d.sibling),d=l(d,f.children||[]),d.return=p,p=d;break e}else{n(p,d);break}else t(p,d);d=d.sibling}d=ls(f,p.mode,w),d.return=p,p=d}return o(p);case be:return E=f._init,P(p,d,E(f._payload),w)}if(En(f))return x(p,d,f,w);if(vn(f))return g(p,d,f,w);Nr(p,f)}return typeof f=="string"&&f!==""||typeof f=="number"?(f=""+f,d!==null&&d.tag===6?(n(p,d.sibling),d=l(d,f),d.return=p,p=d):(n(p,d),d=rs(f,p.mode,w),d.return=p,p=d),o(p)):n(p,d)}return P}var on=Nu(!0),Cu=Nu(!1),tl=vt(null),nl=null,Yt=null,Si=null;function Ni(){Si=Yt=nl=null}function Ci(e){var t=tl.current;A(tl),e._currentValue=t}function Fs(e,t,n){for(;e!==null;){var r=e.alternate;if((e.childLanes&t)!==t?(e.childLanes|=t,r!==null&&(r.childLanes|=t)):r!==null&&(r.childLanes&t)!==t&&(r.childLanes|=t),e===n)break;e=e.return}}function tn(e,t){nl=e,Si=Yt=null,e=e.dependencies,e!==null&&e.firstContext!==null&&(e.lanes&t&&(pe=!0),e.firstContext=null)}function _e(e){var t=e._currentValue;if(Si!==e)if(e={context:e,memoizedValue:t,next:null},Yt===null){if(nl===null)throw Error(k(308));Yt=e,nl.dependencies={lanes:0,firstContext:e}}else Yt=Yt.next=e;return t}var Nt=null;function Ei(e){Nt===null?Nt=[e]:Nt.push(e)}function Eu(e,t,n,r){var l=t.interleaved;return l===null?(n.next=n,Ei(t)):(n.next=l.next,l.next=n),t.interleaved=n,Xe(e,r)}function Xe(e,t){e.lanes|=t;var n=e.alternate;for(n!==null&&(n.lanes|=t),n=e,e=e.return;e!==null;)e.childLanes|=t,n=e.alternate,n!==null&&(n.childLanes|=t),n=e,e=e.return;return n.tag===3?n.stateNode:null}var et=!1;function _i(e){e.updateQueue={baseState:e.memoizedState,firstBaseUpdate:null,lastBaseUpdate:null,shared:{pending:null,interleaved:null,lanes:0},effects:null}}function _u(e,t){e=e.updateQueue,t.updateQueue===e&&(t.updateQueue={baseState:e.baseState,firstBaseUpdate:e.firstBaseUpdate,lastBaseUpdate:e.lastBaseUpdate,shared:e.shared,effects:e.effects})}function Ke(e,t){return{eventTime:e,lane:t,tag:0,payload:null,callback:null,next:null}}function ut(e,t,n){var r=e.updateQueue;if(r===null)return null;if(r=r.shared,I&2){var l=r.pending;return l===null?t.next=t:(t.next=l.next,l.next=t),r.pending=t,Xe(e,n)}return l=r.interleaved,l===null?(t.next=t,Ei(r)):(t.next=l.next,l.next=t),r.interleaved=t,Xe(e,n)}function Ir(e,t,n){if(t=t.updateQueue,t!==null&&(t=t.shared,(n&4194240)!==0)){var r=t.lanes;r&=e.pendingLanes,n|=r,t.lanes=n,fi(e,n)}}function Do(e,t){var n=e.updateQueue,r=e.alternate;if(r!==null&&(r=r.updateQueue,n===r)){var l=null,s=null;if(n=n.firstBaseUpdate,n!==null){do{var o={eventTime:n.eventTime,lane:n.lane,tag:n.tag,payload:n.payload,callback:n.callback,next:null};s===null?l=s=o:s=s.next=o,n=n.next}while(n!==null);s===null?l=s=t:s=s.next=t}else l=s=t;n={baseState:r.baseState,firstBaseUpdate:l,lastBaseUpdate:s,shared:r.shared,effects:r.effects},e.updateQueue=n;return}e=n.lastBaseUpdate,e===null?n.firstBaseUpdate=t:e.next=t,n.lastBaseUpdate=t}function rl(e,t,n,r){var l=e.updateQueue;et=!1;var s=l.firstBaseUpdate,o=l.lastBaseUpdate,a=l.shared.pending;if(a!==null){l.shared.pending=null;var u=a,c=u.next;u.next=null,o===null?s=c:o.next=c,o=u;var m=e.alternate;m!==null&&(m=m.updateQueue,a=m.lastBaseUpdate,a!==o&&(a===null?m.firstBaseUpdate=c:a.next=c,m.lastBaseUpdate=u))}if(s!==null){var h=l.baseState;o=0,m=c=u=null,a=s;do{var v=a.lane,y=a.eventTime;if((r&v)===v){m!==null&&(m=m.next={eventTime:y,lane:0,tag:a.tag,payload:a.payload,callback:a.callback,next:null});e:{var x=e,g=a;switch(v=t,y=n,g.tag){case 1:if(x=g.payload,typeof x=="function"){h=x.call(y,h,v);break e}h=x;break e;case 3:x.flags=x.flags&-65537|128;case 0:if(x=g.payload,v=typeof x=="function"?x.call(y,h,v):x,v==null)break e;h=H({},h,v);break e;case 2:et=!0}}a.callback!==null&&a.lane!==0&&(e.flags|=64,v=l.effects,v===null?l.effects=[a]:v.push(a))}else y={eventTime:y,lane:v,tag:a.tag,payload:a.payload,callback:a.callback,next:null},m===null?(c=m=y,u=h):m=m.next=y,o|=v;if(a=a.next,a===null){if(a=l.shared.pending,a===null)break;v=a,a=v.next,v.next=null,l.lastBaseUpdate=v,l.shared.pending=null}}while(!0);if(m===null&&(u=h),l.baseState=u,l.firstBaseUpdate=c,l.lastBaseUpdate=m,t=l.shared.interleaved,t!==null){l=t;do o|=l.lane,l=l.next;while(l!==t)}else s===null&&(l.shared.lanes=0);Rt|=o,e.lanes=o,e.memoizedState=h}}function Mo(e,t,n){if(e=t.effects,t.effects=null,e!==null)for(t=0;tn?n:4,e(!0);var r=ql.transition;ql.transition={};try{e(!1),t()}finally{M=n,ql.transition=r}}function Hu(){return Pe().memoizedState}function Sf(e,t,n){var r=dt(e);if(n={lane:r,action:n,hasEagerState:!1,eagerState:null,next:null},Qu(e))Ku(t,n);else if(n=Eu(e,t,n,r),n!==null){var l=ue();Fe(n,e,r,l),Gu(n,t,r)}}function Nf(e,t,n){var r=dt(e),l={lane:r,action:n,hasEagerState:!1,eagerState:null,next:null};if(Qu(e))Ku(t,l);else{var s=e.alternate;if(e.lanes===0&&(s===null||s.lanes===0)&&(s=t.lastRenderedReducer,s!==null))try{var o=t.lastRenderedState,a=s(o,n);if(l.hasEagerState=!0,l.eagerState=a,De(a,o)){var u=t.interleaved;u===null?(l.next=l,Ei(t)):(l.next=u.next,u.next=l),t.interleaved=l;return}}catch{}finally{}n=Eu(e,t,l,r),n!==null&&(l=ue(),Fe(n,e,r,l),Gu(n,t,r))}}function Qu(e){var t=e.alternate;return e===W||t!==null&&t===W}function Ku(e,t){In=sl=!0;var n=e.pending;n===null?t.next=t:(t.next=n.next,n.next=t),e.pending=t}function Gu(e,t,n){if(n&4194240){var r=t.lanes;r&=e.pendingLanes,n|=r,t.lanes=n,fi(e,n)}}var il={readContext:_e,useCallback:le,useContext:le,useEffect:le,useImperativeHandle:le,useInsertionEffect:le,useLayoutEffect:le,useMemo:le,useReducer:le,useRef:le,useState:le,useDebugValue:le,useDeferredValue:le,useTransition:le,useMutableSource:le,useSyncExternalStore:le,useId:le,unstable_isNewReconciler:!1},Cf={readContext:_e,useCallback:function(e,t){return $e().memoizedState=[e,t===void 0?null:t],e},useContext:_e,useEffect:Uo,useImperativeHandle:function(e,t,n){return n=n!=null?n.concat([e]):null,Dr(4194308,4,Uu.bind(null,t,e),n)},useLayoutEffect:function(e,t){return Dr(4194308,4,e,t)},useInsertionEffect:function(e,t){return Dr(4,2,e,t)},useMemo:function(e,t){var n=$e();return t=t===void 0?null:t,e=e(),n.memoizedState=[e,t],e},useReducer:function(e,t,n){var r=$e();return t=n!==void 0?n(t):t,r.memoizedState=r.baseState=t,e={pending:null,interleaved:null,lanes:0,dispatch:null,lastRenderedReducer:e,lastRenderedState:t},r.queue=e,e=e.dispatch=Sf.bind(null,W,e),[r.memoizedState,e]},useRef:function(e){var t=$e();return e={current:e},t.memoizedState=e},useState:$o,useDebugValue:Fi,useDeferredValue:function(e){return $e().memoizedState=e},useTransition:function(){var e=$o(!1),t=e[0];return e=jf.bind(null,e[1]),$e().memoizedState=e,[t,e]},useMutableSource:function(){},useSyncExternalStore:function(e,t,n){var r=W,l=$e();if(B){if(n===void 0)throw Error(k(407));n=n()}else{if(n=t(),ee===null)throw Error(k(349));Lt&30||Lu(r,t,n)}l.memoizedState=n;var s={value:n,getSnapshot:t};return l.queue=s,Uo(Ou.bind(null,r,s,e),[e]),r.flags|=2048,bn(9,Ru.bind(null,r,s,n,t),void 0,null),n},useId:function(){var e=$e(),t=ee.identifierPrefix;if(B){var n=Qe,r=He;n=(r&~(1<<32-Ie(r)-1)).toString(32)+n,t=":"+t+"R"+n,n=Zn++,0")&&(u=u.replace("",e.displayName)),u}while(1<=o&&0<=a);break}}}finally{Fl=!1,Error.prepareStackTrace=n}return(e=e?e.displayName||e.name:"")?Cn(e):""}function ed(e){switch(e.tag){case 5:return Cn(e.type);case 16:return Cn("Lazy");case 13:return Cn("Suspense");case 19:return Cn("SuspenseList");case 0:case 2:case 15:return e=Dl(e.type,!1),e;case 11:return e=Dl(e.type.render,!1),e;case 1:return e=Dl(e.type,!0),e;default:return""}}function cs(e){if(e==null)return null;if(typeof e=="function")return e.displayName||e.name||null;if(typeof e=="string")return e;switch(e){case At:return"Fragment";case Ut:return"Portal";case os:return"Profiler";case oi:return"StrictMode";case as:return"Suspense";case us:return"SuspenseList"}if(typeof e=="object")switch(e.$$typeof){case _a:return(e.displayName||"Context")+".Consumer";case Ea:return(e._context.displayName||"Context")+".Provider";case ai:var t=e.render;return e=e.displayName,e||(e=t.displayName||t.name||"",e=e!==""?"ForwardRef("+e+")":"ForwardRef"),e;case ui:return t=e.displayName||null,t!==null?t:cs(e.type)||"Memo";case be:t=e._payload,e=e._init;try{return cs(e(t))}catch{}}return null}function td(e){var t=e.type;switch(e.tag){case 24:return"Cache";case 9:return(t.displayName||"Context")+".Consumer";case 10:return(t._context.displayName||"Context")+".Provider";case 18:return"DehydratedFragment";case 11:return e=t.render,e=e.displayName||e.name||"",t.displayName||(e!==""?"ForwardRef("+e+")":"ForwardRef");case 7:return"Fragment";case 5:return t;case 4:return"Portal";case 3:return"Root";case 6:return"Text";case 16:return cs(t);case 8:return t===oi?"StrictMode":"Mode";case 22:return"Offscreen";case 12:return"Profiler";case 21:return"Scope";case 13:return"Suspense";case 19:return"SuspenseList";case 25:return"TracingMarker";case 1:case 0:case 17:case 2:case 14:case 15:if(typeof t=="function")return t.displayName||t.name||null;if(typeof t=="string")return t}return null}function pt(e){switch(typeof e){case"boolean":case"number":case"string":case"undefined":return e;case"object":return e;default:return""}}function Ta(e){var t=e.type;return(e=e.nodeName)&&e.toLowerCase()==="input"&&(t==="checkbox"||t==="radio")}function nd(e){var t=Ta(e)?"checked":"value",n=Object.getOwnPropertyDescriptor(e.constructor.prototype,t),r=""+e[t];if(!e.hasOwnProperty(t)&&typeof n<"u"&&typeof n.get=="function"&&typeof n.set=="function"){var l=n.get,s=n.set;return Object.defineProperty(e,t,{configurable:!0,get:function(){return l.call(this)},set:function(o){r=""+o,s.call(this,o)}}),Object.defineProperty(e,t,{enumerable:n.enumerable}),{getValue:function(){return r},setValue:function(o){r=""+o},stopTracking:function(){e._valueTracker=null,delete e[t]}}}}function hr(e){e._valueTracker||(e._valueTracker=nd(e))}function za(e){if(!e)return!1;var t=e._valueTracker;if(!t)return!0;var n=t.getValue(),r="";return e&&(r=Ta(e)?e.checked?"true":"false":e.value),e=r,e!==n?(t.setValue(e),!0):!1}function Vr(e){if(e=e||(typeof document<"u"?document:void 0),typeof e>"u")return null;try{return e.activeElement||e.body}catch{return e.body}}function ds(e,t){var n=t.checked;return H({},t,{defaultChecked:void 0,defaultValue:void 0,value:void 0,checked:n??e._wrapperState.initialChecked})}function ro(e,t){var n=t.defaultValue==null?"":t.defaultValue,r=t.checked!=null?t.checked:t.defaultChecked;n=pt(t.value!=null?t.value:n),e._wrapperState={initialChecked:r,initialValue:n,controlled:t.type==="checkbox"||t.type==="radio"?t.checked!=null:t.value!=null}}function La(e,t){t=t.checked,t!=null&&ii(e,"checked",t,!1)}function fs(e,t){La(e,t);var n=pt(t.value),r=t.type;if(n!=null)r==="number"?(n===0&&e.value===""||e.value!=n)&&(e.value=""+n):e.value!==""+n&&(e.value=""+n);else if(r==="submit"||r==="reset"){e.removeAttribute("value");return}t.hasOwnProperty("value")?ps(e,t.type,n):t.hasOwnProperty("defaultValue")&&ps(e,t.type,pt(t.defaultValue)),t.checked==null&&t.defaultChecked!=null&&(e.defaultChecked=!!t.defaultChecked)}function lo(e,t,n){if(t.hasOwnProperty("value")||t.hasOwnProperty("defaultValue")){var r=t.type;if(!(r!=="submit"&&r!=="reset"||t.value!==void 0&&t.value!==null))return;t=""+e._wrapperState.initialValue,n||t===e.value||(e.value=t),e.defaultValue=t}n=e.name,n!==""&&(e.name=""),e.defaultChecked=!!e._wrapperState.initialChecked,n!==""&&(e.name=n)}function ps(e,t,n){(t!=="number"||Vr(e.ownerDocument)!==e)&&(n==null?e.defaultValue=""+e._wrapperState.initialValue:e.defaultValue!==""+n&&(e.defaultValue=""+n))}var En=Array.isArray;function Zt(e,t,n,r){if(e=e.options,t){t={};for(var l=0;l"+t.valueOf().toString()+"",t=mr.firstChild;e.firstChild;)e.removeChild(e.firstChild);for(;t.firstChild;)e.appendChild(t.firstChild)}});function Un(e,t){if(t){var n=e.firstChild;if(n&&n===e.lastChild&&n.nodeType===3){n.nodeValue=t;return}}e.textContent=t}var Tn={animationIterationCount:!0,aspectRatio:!0,borderImageOutset:!0,borderImageSlice:!0,borderImageWidth:!0,boxFlex:!0,boxFlexGroup:!0,boxOrdinalGroup:!0,columnCount:!0,columns:!0,flex:!0,flexGrow:!0,flexPositive:!0,flexShrink:!0,flexNegative:!0,flexOrder:!0,gridArea:!0,gridRow:!0,gridRowEnd:!0,gridRowSpan:!0,gridRowStart:!0,gridColumn:!0,gridColumnEnd:!0,gridColumnSpan:!0,gridColumnStart:!0,fontWeight:!0,lineClamp:!0,lineHeight:!0,opacity:!0,order:!0,orphans:!0,tabSize:!0,widows:!0,zIndex:!0,zoom:!0,fillOpacity:!0,floodOpacity:!0,stopOpacity:!0,strokeDasharray:!0,strokeDashoffset:!0,strokeMiterlimit:!0,strokeOpacity:!0,strokeWidth:!0},rd=["Webkit","ms","Moz","O"];Object.keys(Tn).forEach(function(e){rd.forEach(function(t){t=t+e.charAt(0).toUpperCase()+e.substring(1),Tn[t]=Tn[e]})});function Fa(e,t,n){return t==null||typeof t=="boolean"||t===""?"":n||typeof t!="number"||t===0||Tn.hasOwnProperty(e)&&Tn[e]?(""+t).trim():t+"px"}function Da(e,t){e=e.style;for(var n in t)if(t.hasOwnProperty(n)){var r=n.indexOf("--")===0,l=Fa(n,t[n],r);n==="float"&&(n="cssFloat"),r?e.setProperty(n,l):e[n]=l}}var ld=H({menuitem:!0},{area:!0,base:!0,br:!0,col:!0,embed:!0,hr:!0,img:!0,input:!0,keygen:!0,link:!0,meta:!0,param:!0,source:!0,track:!0,wbr:!0});function vs(e,t){if(t){if(ld[e]&&(t.children!=null||t.dangerouslySetInnerHTML!=null))throw Error(k(137,e));if(t.dangerouslySetInnerHTML!=null){if(t.children!=null)throw Error(k(60));if(typeof t.dangerouslySetInnerHTML!="object"||!("__html"in t.dangerouslySetInnerHTML))throw Error(k(61))}if(t.style!=null&&typeof t.style!="object")throw Error(k(62))}}function ys(e,t){if(e.indexOf("-")===-1)return typeof t.is=="string";switch(e){case"annotation-xml":case"color-profile":case"font-face":case"font-face-src":case"font-face-uri":case"font-face-format":case"font-face-name":case"missing-glyph":return!1;default:return!0}}var gs=null;function ci(e){return e=e.target||e.srcElement||window,e.correspondingUseElement&&(e=e.correspondingUseElement),e.nodeType===3?e.parentNode:e}var ws=null,qt=null,bt=null;function oo(e){if(e=lr(e)){if(typeof ws!="function")throw Error(k(280));var t=e.stateNode;t&&(t=gl(t),ws(e.stateNode,e.type,t))}}function Ma(e){qt?bt?bt.push(e):bt=[e]:qt=e}function $a(){if(qt){var e=qt,t=bt;if(bt=qt=null,oo(e),t)for(e=0;e>>=0,e===0?32:31-(md(e)/vd|0)|0}var vr=64,yr=4194304;function _n(e){switch(e&-e){case 1:return 1;case 2:return 2;case 4:return 4;case 8:return 8;case 16:return 16;case 32:return 32;case 64:case 128:case 256:case 512:case 1024:case 2048:case 4096:case 8192:case 16384:case 32768:case 65536:case 131072:case 262144:case 524288:case 1048576:case 2097152:return e&4194240;case 4194304:case 8388608:case 16777216:case 33554432:case 67108864:return e&130023424;case 134217728:return 134217728;case 268435456:return 268435456;case 536870912:return 536870912;case 1073741824:return 1073741824;default:return e}}function Kr(e,t){var n=e.pendingLanes;if(n===0)return 0;var r=0,l=e.suspendedLanes,s=e.pingedLanes,o=n&268435455;if(o!==0){var a=o&~l;a!==0?r=_n(a):(s&=o,s!==0&&(r=_n(s)))}else o=n&~l,o!==0?r=_n(o):s!==0&&(r=_n(s));if(r===0)return 0;if(t!==0&&t!==r&&!(t&l)&&(l=r&-r,s=t&-t,l>=s||l===16&&(s&4194240)!==0))return t;if(r&4&&(r|=n&16),t=e.entangledLanes,t!==0)for(e=e.entanglements,t&=r;0n;n++)t.push(e);return t}function nr(e,t,n){e.pendingLanes|=t,t!==536870912&&(e.suspendedLanes=0,e.pingedLanes=0),e=e.eventTimes,t=31-Ie(t),e[t]=n}function xd(e,t){var n=e.pendingLanes&~t;e.pendingLanes=t,e.suspendedLanes=0,e.pingedLanes=0,e.expiredLanes&=t,e.mutableReadLanes&=t,e.entangledLanes&=t,t=e.entanglements;var r=e.eventTimes;for(e=e.expirationTimes;0=Ln),yo=" ",go=!1;function lu(e,t){switch(e){case"keyup":return Yd.indexOf(t.keyCode)!==-1;case"keydown":return t.keyCode!==229;case"keypress":case"mousedown":case"focusout":return!0;default:return!1}}function su(e){return e=e.detail,typeof e=="object"&&"data"in e?e.data:null}var Bt=!1;function Jd(e,t){switch(e){case"compositionend":return su(t);case"keypress":return t.which!==32?null:(go=!0,yo);case"textInput":return e=t.data,e===yo&&go?null:e;default:return null}}function Zd(e,t){if(Bt)return e==="compositionend"||!gi&&lu(e,t)?(e=nu(),Rr=mi=rt=null,Bt=!1,e):null;switch(e){case"paste":return null;case"keypress":if(!(t.ctrlKey||t.altKey||t.metaKey)||t.ctrlKey&&t.altKey){if(t.char&&1=t)return{node:n,offset:t-e};e=r}e:{for(;n;){if(n.nextSibling){n=n.nextSibling;break e}n=n.parentNode}n=void 0}n=jo(n)}}function uu(e,t){return e&&t?e===t?!0:e&&e.nodeType===3?!1:t&&t.nodeType===3?uu(e,t.parentNode):"contains"in e?e.contains(t):e.compareDocumentPosition?!!(e.compareDocumentPosition(t)&16):!1:!1}function cu(){for(var e=window,t=Vr();t instanceof e.HTMLIFrameElement;){try{var n=typeof t.contentWindow.location.href=="string"}catch{n=!1}if(n)e=t.contentWindow;else break;t=Vr(e.document)}return t}function wi(e){var t=e&&e.nodeName&&e.nodeName.toLowerCase();return t&&(t==="input"&&(e.type==="text"||e.type==="search"||e.type==="tel"||e.type==="url"||e.type==="password")||t==="textarea"||e.contentEditable==="true")}function of(e){var t=cu(),n=e.focusedElem,r=e.selectionRange;if(t!==n&&n&&n.ownerDocument&&uu(n.ownerDocument.documentElement,n)){if(r!==null&&wi(n)){if(t=r.start,e=r.end,e===void 0&&(e=t),"selectionStart"in n)n.selectionStart=t,n.selectionEnd=Math.min(e,n.value.length);else if(e=(t=n.ownerDocument||document)&&t.defaultView||window,e.getSelection){e=e.getSelection();var l=n.textContent.length,s=Math.min(r.start,l);r=r.end===void 0?s:Math.min(r.end,l),!e.extend&&s>r&&(l=r,r=s,s=l),l=So(n,s);var o=So(n,r);l&&o&&(e.rangeCount!==1||e.anchorNode!==l.node||e.anchorOffset!==l.offset||e.focusNode!==o.node||e.focusOffset!==o.offset)&&(t=t.createRange(),t.setStart(l.node,l.offset),e.removeAllRanges(),s>r?(e.addRange(t),e.extend(o.node,o.offset)):(t.setEnd(o.node,o.offset),e.addRange(t)))}}for(t=[],e=n;e=e.parentNode;)e.nodeType===1&&t.push({element:e,left:e.scrollLeft,top:e.scrollTop});for(typeof n.focus=="function"&&n.focus(),n=0;n=document.documentMode,Vt=null,Cs=null,On=null,Es=!1;function No(e,t,n){var r=n.window===n?n.document:n.nodeType===9?n:n.ownerDocument;Es||Vt==null||Vt!==Vr(r)||(r=Vt,"selectionStart"in r&&wi(r)?r={start:r.selectionStart,end:r.selectionEnd}:(r=(r.ownerDocument&&r.ownerDocument.defaultView||window).getSelection(),r={anchorNode:r.anchorNode,anchorOffset:r.anchorOffset,focusNode:r.focusNode,focusOffset:r.focusOffset}),On&&Qn(On,r)||(On=r,r=Xr(Cs,"onSelect"),0Qt||(e.current=Rs[Qt],Rs[Qt]=null,Qt--)}function $(e,t){Qt++,Rs[Qt]=e.current,e.current=t}var ht={},oe=vt(ht),he=vt(!1),Tt=ht;function ln(e,t){var n=e.type.contextTypes;if(!n)return ht;var r=e.stateNode;if(r&&r.__reactInternalMemoizedUnmaskedChildContext===t)return r.__reactInternalMemoizedMaskedChildContext;var l={},s;for(s in n)l[s]=t[s];return r&&(e=e.stateNode,e.__reactInternalMemoizedUnmaskedChildContext=t,e.__reactInternalMemoizedMaskedChildContext=l),l}function me(e){return e=e.childContextTypes,e!=null}function Zr(){A(he),A(oe)}function Lo(e,t,n){if(oe.current!==ht)throw Error(k(168));$(oe,t),$(he,n)}function wu(e,t,n){var r=e.stateNode;if(t=t.childContextTypes,typeof r.getChildContext!="function")return n;r=r.getChildContext();for(var l in r)if(!(l in t))throw Error(k(108,td(e)||"Unknown",l));return H({},n,r)}function qr(e){return e=(e=e.stateNode)&&e.__reactInternalMemoizedMergedChildContext||ht,Tt=oe.current,$(oe,e),$(he,he.current),!0}function Ro(e,t,n){var r=e.stateNode;if(!r)throw Error(k(169));n?(e=wu(e,t,Tt),r.__reactInternalMemoizedMergedChildContext=e,A(he),A(oe),$(oe,e)):A(he),$(he,n)}var We=null,wl=!1,Jl=!1;function xu(e){We===null?We=[e]:We.push(e)}function wf(e){wl=!0,xu(e)}function yt(){if(!Jl&&We!==null){Jl=!0;var e=0,t=M;try{var n=We;for(M=1;e>=o,l-=o,He=1<<32-Ie(t)+l|n<T?(K=P,P=null):K=P.sibling;var O=v(f,P,p[T],w);if(O===null){P===null&&(P=K);break}e&&P&&O.alternate===null&&t(f,P),d=s(O,d,T),_===null?S=O:_.sibling=O,_=O,P=K}if(T===p.length)return n(f,P),B&&xt(f,T),S;if(P===null){for(;TT?(K=P,P=null):K=P.sibling;var Te=v(f,P,O.value,w);if(Te===null){P===null&&(P=K);break}e&&P&&Te.alternate===null&&t(f,P),d=s(Te,d,T),_===null?S=Te:_.sibling=Te,_=Te,P=K}if(O.done)return n(f,P),B&&xt(f,T),S;if(P===null){for(;!O.done;T++,O=p.next())O=h(f,O.value,w),O!==null&&(d=s(O,d,T),_===null?S=O:_.sibling=O,_=O);return B&&xt(f,T),S}for(P=r(f,P);!O.done;T++,O=p.next())O=y(P,f,T,O.value,w),O!==null&&(e&&O.alternate!==null&&P.delete(O.key===null?T:O.key),d=s(O,d,T),_===null?S=O:_.sibling=O,_=O);return e&&P.forEach(function(hn){return t(f,hn)}),B&&xt(f,T),S}function N(f,d,p,w){if(typeof p=="object"&&p!==null&&p.type===At&&p.key===null&&(p=p.props.children),typeof p=="object"&&p!==null){switch(p.$$typeof){case pr:e:{for(var S=p.key,_=d;_!==null;){if(_.key===S){if(S=p.type,S===At){if(_.tag===7){n(f,_.sibling),d=l(_,p.props.children),d.return=f,f=d;break e}}else if(_.elementType===S||typeof S=="object"&&S!==null&&S.$$typeof===be&&Fo(S)===_.type){n(f,_.sibling),d=l(_,p.props),d.ref=kn(f,_,p),d.return=f,f=d;break e}n(f,_);break}else t(f,_);_=_.sibling}p.type===At?(d=_t(p.props.children,f.mode,w,p.key),d.return=f,f=d):(w=Ar(p.type,p.key,p.props,null,f.mode,w),w.ref=kn(f,d,p),w.return=f,f=w)}return o(f);case Ut:e:{for(_=p.key;d!==null;){if(d.key===_)if(d.tag===4&&d.stateNode.containerInfo===p.containerInfo&&d.stateNode.implementation===p.implementation){n(f,d.sibling),d=l(d,p.children||[]),d.return=f,f=d;break e}else{n(f,d);break}else t(f,d);d=d.sibling}d=ls(p,f.mode,w),d.return=f,f=d}return o(f);case be:return _=p._init,N(f,d,_(p._payload),w)}if(En(p))return x(f,d,p,w);if(vn(p))return g(f,d,p,w);Nr(f,p)}return typeof p=="string"&&p!==""||typeof p=="number"?(p=""+p,d!==null&&d.tag===6?(n(f,d.sibling),d=l(d,p),d.return=f,f=d):(n(f,d),d=rs(p,f.mode,w),d.return=f,f=d),o(f)):n(f,d)}return N}var on=Nu(!0),Cu=Nu(!1),tl=vt(null),nl=null,Yt=null,Si=null;function Ni(){Si=Yt=nl=null}function Ci(e){var t=tl.current;A(tl),e._currentValue=t}function Fs(e,t,n){for(;e!==null;){var r=e.alternate;if((e.childLanes&t)!==t?(e.childLanes|=t,r!==null&&(r.childLanes|=t)):r!==null&&(r.childLanes&t)!==t&&(r.childLanes|=t),e===n)break;e=e.return}}function tn(e,t){nl=e,Si=Yt=null,e=e.dependencies,e!==null&&e.firstContext!==null&&(e.lanes&t&&(pe=!0),e.firstContext=null)}function _e(e){var t=e._currentValue;if(Si!==e)if(e={context:e,memoizedValue:t,next:null},Yt===null){if(nl===null)throw Error(k(308));Yt=e,nl.dependencies={lanes:0,firstContext:e}}else Yt=Yt.next=e;return t}var Nt=null;function Ei(e){Nt===null?Nt=[e]:Nt.push(e)}function Eu(e,t,n,r){var l=t.interleaved;return l===null?(n.next=n,Ei(t)):(n.next=l.next,l.next=n),t.interleaved=n,Xe(e,r)}function Xe(e,t){e.lanes|=t;var n=e.alternate;for(n!==null&&(n.lanes|=t),n=e,e=e.return;e!==null;)e.childLanes|=t,n=e.alternate,n!==null&&(n.childLanes|=t),n=e,e=e.return;return n.tag===3?n.stateNode:null}var et=!1;function _i(e){e.updateQueue={baseState:e.memoizedState,firstBaseUpdate:null,lastBaseUpdate:null,shared:{pending:null,interleaved:null,lanes:0},effects:null}}function _u(e,t){e=e.updateQueue,t.updateQueue===e&&(t.updateQueue={baseState:e.baseState,firstBaseUpdate:e.firstBaseUpdate,lastBaseUpdate:e.lastBaseUpdate,shared:e.shared,effects:e.effects})}function Ke(e,t){return{eventTime:e,lane:t,tag:0,payload:null,callback:null,next:null}}function ut(e,t,n){var r=e.updateQueue;if(r===null)return null;if(r=r.shared,I&2){var l=r.pending;return l===null?t.next=t:(t.next=l.next,l.next=t),r.pending=t,Xe(e,n)}return l=r.interleaved,l===null?(t.next=t,Ei(r)):(t.next=l.next,l.next=t),r.interleaved=t,Xe(e,n)}function Ir(e,t,n){if(t=t.updateQueue,t!==null&&(t=t.shared,(n&4194240)!==0)){var r=t.lanes;r&=e.pendingLanes,n|=r,t.lanes=n,fi(e,n)}}function Do(e,t){var n=e.updateQueue,r=e.alternate;if(r!==null&&(r=r.updateQueue,n===r)){var l=null,s=null;if(n=n.firstBaseUpdate,n!==null){do{var o={eventTime:n.eventTime,lane:n.lane,tag:n.tag,payload:n.payload,callback:n.callback,next:null};s===null?l=s=o:s=s.next=o,n=n.next}while(n!==null);s===null?l=s=t:s=s.next=t}else l=s=t;n={baseState:r.baseState,firstBaseUpdate:l,lastBaseUpdate:s,shared:r.shared,effects:r.effects},e.updateQueue=n;return}e=n.lastBaseUpdate,e===null?n.firstBaseUpdate=t:e.next=t,n.lastBaseUpdate=t}function rl(e,t,n,r){var l=e.updateQueue;et=!1;var s=l.firstBaseUpdate,o=l.lastBaseUpdate,a=l.shared.pending;if(a!==null){l.shared.pending=null;var u=a,c=u.next;u.next=null,o===null?s=c:o.next=c,o=u;var m=e.alternate;m!==null&&(m=m.updateQueue,a=m.lastBaseUpdate,a!==o&&(a===null?m.firstBaseUpdate=c:a.next=c,m.lastBaseUpdate=u))}if(s!==null){var h=l.baseState;o=0,m=c=u=null,a=s;do{var v=a.lane,y=a.eventTime;if((r&v)===v){m!==null&&(m=m.next={eventTime:y,lane:0,tag:a.tag,payload:a.payload,callback:a.callback,next:null});e:{var x=e,g=a;switch(v=t,y=n,g.tag){case 1:if(x=g.payload,typeof x=="function"){h=x.call(y,h,v);break e}h=x;break e;case 3:x.flags=x.flags&-65537|128;case 0:if(x=g.payload,v=typeof x=="function"?x.call(y,h,v):x,v==null)break e;h=H({},h,v);break e;case 2:et=!0}}a.callback!==null&&a.lane!==0&&(e.flags|=64,v=l.effects,v===null?l.effects=[a]:v.push(a))}else y={eventTime:y,lane:v,tag:a.tag,payload:a.payload,callback:a.callback,next:null},m===null?(c=m=y,u=h):m=m.next=y,o|=v;if(a=a.next,a===null){if(a=l.shared.pending,a===null)break;v=a,a=v.next,v.next=null,l.lastBaseUpdate=v,l.shared.pending=null}}while(!0);if(m===null&&(u=h),l.baseState=u,l.firstBaseUpdate=c,l.lastBaseUpdate=m,t=l.shared.interleaved,t!==null){l=t;do o|=l.lane,l=l.next;while(l!==t)}else s===null&&(l.shared.lanes=0);Rt|=o,e.lanes=o,e.memoizedState=h}}function Mo(e,t,n){if(e=t.effects,t.effects=null,e!==null)for(t=0;tn?n:4,e(!0);var r=ql.transition;ql.transition={};try{e(!1),t()}finally{M=n,ql.transition=r}}function Hu(){return Pe().memoizedState}function Sf(e,t,n){var r=dt(e);if(n={lane:r,action:n,hasEagerState:!1,eagerState:null,next:null},Qu(e))Ku(t,n);else if(n=Eu(e,t,n,r),n!==null){var l=ue();Fe(n,e,r,l),Gu(n,t,r)}}function Nf(e,t,n){var r=dt(e),l={lane:r,action:n,hasEagerState:!1,eagerState:null,next:null};if(Qu(e))Ku(t,l);else{var s=e.alternate;if(e.lanes===0&&(s===null||s.lanes===0)&&(s=t.lastRenderedReducer,s!==null))try{var o=t.lastRenderedState,a=s(o,n);if(l.hasEagerState=!0,l.eagerState=a,De(a,o)){var u=t.interleaved;u===null?(l.next=l,Ei(t)):(l.next=u.next,u.next=l),t.interleaved=l;return}}catch{}finally{}n=Eu(e,t,l,r),n!==null&&(l=ue(),Fe(n,e,r,l),Gu(n,t,r))}}function Qu(e){var t=e.alternate;return e===W||t!==null&&t===W}function Ku(e,t){In=sl=!0;var n=e.pending;n===null?t.next=t:(t.next=n.next,n.next=t),e.pending=t}function Gu(e,t,n){if(n&4194240){var r=t.lanes;r&=e.pendingLanes,n|=r,t.lanes=n,fi(e,n)}}var il={readContext:_e,useCallback:le,useContext:le,useEffect:le,useImperativeHandle:le,useInsertionEffect:le,useLayoutEffect:le,useMemo:le,useReducer:le,useRef:le,useState:le,useDebugValue:le,useDeferredValue:le,useTransition:le,useMutableSource:le,useSyncExternalStore:le,useId:le,unstable_isNewReconciler:!1},Cf={readContext:_e,useCallback:function(e,t){return $e().memoizedState=[e,t===void 0?null:t],e},useContext:_e,useEffect:Uo,useImperativeHandle:function(e,t,n){return n=n!=null?n.concat([e]):null,Dr(4194308,4,Uu.bind(null,t,e),n)},useLayoutEffect:function(e,t){return Dr(4194308,4,e,t)},useInsertionEffect:function(e,t){return Dr(4,2,e,t)},useMemo:function(e,t){var n=$e();return t=t===void 0?null:t,e=e(),n.memoizedState=[e,t],e},useReducer:function(e,t,n){var r=$e();return t=n!==void 0?n(t):t,r.memoizedState=r.baseState=t,e={pending:null,interleaved:null,lanes:0,dispatch:null,lastRenderedReducer:e,lastRenderedState:t},r.queue=e,e=e.dispatch=Sf.bind(null,W,e),[r.memoizedState,e]},useRef:function(e){var t=$e();return e={current:e},t.memoizedState=e},useState:$o,useDebugValue:Fi,useDeferredValue:function(e){return $e().memoizedState=e},useTransition:function(){var e=$o(!1),t=e[0];return e=jf.bind(null,e[1]),$e().memoizedState=e,[t,e]},useMutableSource:function(){},useSyncExternalStore:function(e,t,n){var r=W,l=$e();if(B){if(n===void 0)throw Error(k(407));n=n()}else{if(n=t(),ee===null)throw Error(k(349));Lt&30||Lu(r,t,n)}l.memoizedState=n;var s={value:n,getSnapshot:t};return l.queue=s,Uo(Ou.bind(null,r,s,e),[e]),r.flags|=2048,bn(9,Ru.bind(null,r,s,n,t),void 0,null),n},useId:function(){var e=$e(),t=ee.identifierPrefix;if(B){var n=Qe,r=He;n=(r&~(1<<32-Ie(r)-1)).toString(32)+n,t=":"+t+"R"+n,n=Zn++,0<\/script>",e=e.removeChild(e.firstChild)):typeof r.is=="string"?e=o.createElement(n,{is:r.is}):(e=o.createElement(n),n==="select"&&(o=e,r.multiple?o.multiple=!0:r.size&&(o.size=r.size))):e=o.createElementNS(e,n),e[Ue]=t,e[Yn]=r,rc(e,t,!1,!1),t.stateNode=e;e:{switch(o=ys(n,r),n){case"dialog":U("cancel",e),U("close",e),l=r;break;case"iframe":case"object":case"embed":U("load",e),l=r;break;case"video":case"audio":for(l=0;lcn&&(t.flags|=128,r=!0,jn(s,!1),t.lanes=4194304)}else{if(!r)if(e=ll(o),e!==null){if(t.flags|=128,r=!0,n=e.updateQueue,n!==null&&(t.updateQueue=n,t.flags|=4),jn(s,!0),s.tail===null&&s.tailMode==="hidden"&&!o.alternate&&!B)return se(t),null}else 2*Y()-s.renderingStartTime>cn&&n!==1073741824&&(t.flags|=128,r=!0,jn(s,!1),t.lanes=4194304);s.isBackwards?(o.sibling=t.child,t.child=o):(n=s.last,n!==null?n.sibling=o:t.child=o,s.last=o)}return s.tail!==null?(t=s.tail,s.rendering=t,s.tail=t.sibling,s.renderingStartTime=Y(),t.sibling=null,n=V.current,$(V,r?n&1|2:n&1),t):(se(t),null);case 22:case 23:return Bi(),r=t.memoizedState!==null,e!==null&&e.memoizedState!==null!==r&&(t.flags|=8192),r&&t.mode&1?ye&1073741824&&(se(t),t.subtreeFlags&6&&(t.flags|=8192)):se(t),null;case 24:return null;case 25:return null}throw Error(k(156,t.tag))}function Of(e,t){switch(ki(t),t.tag){case 1:return me(t.type)&&Zr(),e=t.flags,e&65536?(t.flags=e&-65537|128,t):null;case 3:return an(),A(he),A(oe),zi(),e=t.flags,e&65536&&!(e&128)?(t.flags=e&-65537|128,t):null;case 5:return Ti(t),null;case 13:if(A(V),e=t.memoizedState,e!==null&&e.dehydrated!==null){if(t.alternate===null)throw Error(k(340));sn()}return e=t.flags,e&65536?(t.flags=e&-65537|128,t):null;case 19:return A(V),null;case 4:return an(),null;case 10:return Ci(t.type._context),null;case 22:case 23:return Bi(),null;case 24:return null;default:return null}}var Er=!1,ie=!1,If=typeof WeakSet=="function"?WeakSet:Set,N=null;function Xt(e,t){var n=e.ref;if(n!==null)if(typeof n=="function")try{n(null)}catch(r){Q(e,t,r)}else n.current=null}function Hs(e,t,n){try{n()}catch(r){Q(e,t,r)}}var Jo=!1;function Ff(e,t){if(_s=Gr,e=cu(),wi(e)){if("selectionStart"in e)var n={start:e.selectionStart,end:e.selectionEnd};else e:{n=(n=e.ownerDocument)&&n.defaultView||window;var r=n.getSelection&&n.getSelection();if(r&&r.rangeCount!==0){n=r.anchorNode;var l=r.anchorOffset,s=r.focusNode;r=r.focusOffset;try{n.nodeType,s.nodeType}catch{n=null;break e}var o=0,a=-1,u=-1,c=0,m=0,h=e,v=null;t:for(;;){for(var y;h!==n||l!==0&&h.nodeType!==3||(a=o+l),h!==s||r!==0&&h.nodeType!==3||(u=o+r),h.nodeType===3&&(o+=h.nodeValue.length),(y=h.firstChild)!==null;)v=h,h=y;for(;;){if(h===e)break t;if(v===n&&++c===l&&(a=o),v===s&&++m===r&&(u=o),(y=h.nextSibling)!==null)break;h=v,v=h.parentNode}h=y}n=a===-1||u===-1?null:{start:a,end:u}}else n=null}n=n||{start:0,end:0}}else n=null;for(Ps={focusedElem:e,selectionRange:n},Gr=!1,N=t;N!==null;)if(t=N,e=t.child,(t.subtreeFlags&1028)!==0&&e!==null)e.return=t,N=e;else for(;N!==null;){t=N;try{var x=t.alternate;if(t.flags&1024)switch(t.tag){case 0:case 11:case 15:break;case 1:if(x!==null){var g=x.memoizedProps,P=x.memoizedState,p=t.stateNode,d=p.getSnapshotBeforeUpdate(t.elementType===t.type?g:Le(t.type,g),P);p.__reactInternalSnapshotBeforeUpdate=d}break;case 3:var f=t.stateNode.containerInfo;f.nodeType===1?f.textContent="":f.nodeType===9&&f.documentElement&&f.removeChild(f.documentElement);break;case 5:case 6:case 4:case 17:break;default:throw Error(k(163))}}catch(w){Q(t,t.return,w)}if(e=t.sibling,e!==null){e.return=t.return,N=e;break}N=t.return}return x=Jo,Jo=!1,x}function Fn(e,t,n){var r=t.updateQueue;if(r=r!==null?r.lastEffect:null,r!==null){var l=r=r.next;do{if((l.tag&e)===e){var s=l.destroy;l.destroy=void 0,s!==void 0&&Hs(t,n,s)}l=l.next}while(l!==r)}}function jl(e,t){if(t=t.updateQueue,t=t!==null?t.lastEffect:null,t!==null){var n=t=t.next;do{if((n.tag&e)===e){var r=n.create;n.destroy=r()}n=n.next}while(n!==t)}}function Qs(e){var t=e.ref;if(t!==null){var n=e.stateNode;switch(e.tag){case 5:e=n;break;default:e=n}typeof t=="function"?t(e):t.current=e}}function ic(e){var t=e.alternate;t!==null&&(e.alternate=null,ic(t)),e.child=null,e.deletions=null,e.sibling=null,e.tag===5&&(t=e.stateNode,t!==null&&(delete t[Ue],delete t[Yn],delete t[Ls],delete t[yf],delete t[gf])),e.stateNode=null,e.return=null,e.dependencies=null,e.memoizedProps=null,e.memoizedState=null,e.pendingProps=null,e.stateNode=null,e.updateQueue=null}function oc(e){return e.tag===5||e.tag===3||e.tag===4}function Zo(e){e:for(;;){for(;e.sibling===null;){if(e.return===null||oc(e.return))return null;e=e.return}for(e.sibling.return=e.return,e=e.sibling;e.tag!==5&&e.tag!==6&&e.tag!==18;){if(e.flags&2||e.child===null||e.tag===4)continue e;e.child.return=e,e=e.child}if(!(e.flags&2))return e.stateNode}}function Ks(e,t,n){var r=e.tag;if(r===5||r===6)e=e.stateNode,t?n.nodeType===8?n.parentNode.insertBefore(e,t):n.insertBefore(e,t):(n.nodeType===8?(t=n.parentNode,t.insertBefore(e,n)):(t=n,t.appendChild(e)),n=n._reactRootContainer,n!=null||t.onclick!==null||(t.onclick=Jr));else if(r!==4&&(e=e.child,e!==null))for(Ks(e,t,n),e=e.sibling;e!==null;)Ks(e,t,n),e=e.sibling}function Gs(e,t,n){var r=e.tag;if(r===5||r===6)e=e.stateNode,t?n.insertBefore(e,t):n.appendChild(e);else if(r!==4&&(e=e.child,e!==null))for(Gs(e,t,n),e=e.sibling;e!==null;)Gs(e,t,n),e=e.sibling}var te=null,Re=!1;function qe(e,t,n){for(n=n.child;n!==null;)ac(e,t,n),n=n.sibling}function ac(e,t,n){if(Ae&&typeof Ae.onCommitFiberUnmount=="function")try{Ae.onCommitFiberUnmount(hl,n)}catch{}switch(n.tag){case 5:ie||Xt(n,t);case 6:var r=te,l=Re;te=null,qe(e,t,n),te=r,Re=l,te!==null&&(Re?(e=te,n=n.stateNode,e.nodeType===8?e.parentNode.removeChild(n):e.removeChild(n)):te.removeChild(n.stateNode));break;case 18:te!==null&&(Re?(e=te,n=n.stateNode,e.nodeType===8?Xl(e.parentNode,n):e.nodeType===1&&Xl(e,n),Wn(e)):Xl(te,n.stateNode));break;case 4:r=te,l=Re,te=n.stateNode.containerInfo,Re=!0,qe(e,t,n),te=r,Re=l;break;case 0:case 11:case 14:case 15:if(!ie&&(r=n.updateQueue,r!==null&&(r=r.lastEffect,r!==null))){l=r=r.next;do{var s=l,o=s.destroy;s=s.tag,o!==void 0&&(s&2||s&4)&&Hs(n,t,o),l=l.next}while(l!==r)}qe(e,t,n);break;case 1:if(!ie&&(Xt(n,t),r=n.stateNode,typeof r.componentWillUnmount=="function"))try{r.props=n.memoizedProps,r.state=n.memoizedState,r.componentWillUnmount()}catch(a){Q(n,t,a)}qe(e,t,n);break;case 21:qe(e,t,n);break;case 22:n.mode&1?(ie=(r=ie)||n.memoizedState!==null,qe(e,t,n),ie=r):qe(e,t,n);break;default:qe(e,t,n)}}function qo(e){var t=e.updateQueue;if(t!==null){e.updateQueue=null;var n=e.stateNode;n===null&&(n=e.stateNode=new If),t.forEach(function(r){var l=Hf.bind(null,e,r);n.has(r)||(n.add(r),r.then(l,l))})}}function ze(e,t){var n=t.deletions;if(n!==null)for(var r=0;rl&&(l=o),r&=~s}if(r=l,r=Y()-r,r=(120>r?120:480>r?480:1080>r?1080:1920>r?1920:3e3>r?3e3:4320>r?4320:1960*Mf(r/1960))-r,10e?16:e,lt===null)var r=!1;else{if(e=lt,lt=null,ul=0,I&6)throw Error(k(331));var l=I;for(I|=4,N=e.current;N!==null;){var s=N,o=s.child;if(N.flags&16){var a=s.deletions;if(a!==null){for(var u=0;uY()-Ui?Et(e,0):$i|=n),ve(e,t)}function vc(e,t){t===0&&(e.mode&1?(t=yr,yr<<=1,!(yr&130023424)&&(yr=4194304)):t=1);var n=ue();e=Xe(e,t),e!==null&&(nr(e,t,n),ve(e,n))}function Wf(e){var t=e.memoizedState,n=0;t!==null&&(n=t.retryLane),vc(e,n)}function Hf(e,t){var n=0;switch(e.tag){case 13:var r=e.stateNode,l=e.memoizedState;l!==null&&(n=l.retryLane);break;case 19:r=e.stateNode;break;default:throw Error(k(314))}r!==null&&r.delete(t),vc(e,n)}var yc;yc=function(e,t,n){if(e!==null)if(e.memoizedProps!==t.pendingProps||he.current)pe=!0;else{if(!(e.lanes&n)&&!(t.flags&128))return pe=!1,Lf(e,t,n);pe=!!(e.flags&131072)}else pe=!1,B&&t.flags&1048576&&ku(t,el,t.index);switch(t.lanes=0,t.tag){case 2:var r=t.type;Mr(e,t),e=t.pendingProps;var l=ln(t,oe.current);tn(t,n),l=Ri(null,t,r,e,l,n);var s=Oi();return t.flags|=1,typeof l=="object"&&l!==null&&typeof l.render=="function"&&l.$$typeof===void 0?(t.tag=1,t.memoizedState=null,t.updateQueue=null,me(r)?(s=!0,qr(t)):s=!1,t.memoizedState=l.state!==null&&l.state!==void 0?l.state:null,_i(t),l.updater=kl,t.stateNode=l,l._reactInternals=t,Ms(t,r,e,n),t=As(null,t,r,!0,s,n)):(t.tag=0,B&&s&&xi(t),ae(null,t,l,n),t=t.child),t;case 16:r=t.elementType;e:{switch(Mr(e,t),e=t.pendingProps,l=r._init,r=l(r._payload),t.type=r,l=t.tag=Kf(r),e=Le(r,e),l){case 0:t=Us(null,t,r,e,n);break e;case 1:t=Go(null,t,r,e,n);break e;case 11:t=Qo(null,t,r,e,n);break e;case 14:t=Ko(null,t,r,Le(r.type,e),n);break e}throw Error(k(306,r,""))}return t;case 0:return r=t.type,l=t.pendingProps,l=t.elementType===r?l:Le(r,l),Us(e,t,r,l,n);case 1:return r=t.type,l=t.pendingProps,l=t.elementType===r?l:Le(r,l),Go(e,t,r,l,n);case 3:e:{if(ec(t),e===null)throw Error(k(387));r=t.pendingProps,s=t.memoizedState,l=s.element,_u(e,t),rl(t,r,null,n);var o=t.memoizedState;if(r=o.element,s.isDehydrated)if(s={element:r,isDehydrated:!1,cache:o.cache,pendingSuspenseBoundaries:o.pendingSuspenseBoundaries,transitions:o.transitions},t.updateQueue.baseState=s,t.memoizedState=s,t.flags&256){l=un(Error(k(423)),t),t=Yo(e,t,r,n,l);break e}else if(r!==l){l=un(Error(k(424)),t),t=Yo(e,t,r,n,l);break e}else for(ge=at(t.stateNode.containerInfo.firstChild),we=t,B=!0,Oe=null,n=Cu(t,null,r,n),t.child=n;n;)n.flags=n.flags&-3|4096,n=n.sibling;else{if(sn(),r===l){t=Je(e,t,n);break e}ae(e,t,r,n)}t=t.child}return t;case 5:return Pu(t),e===null&&Is(t),r=t.type,l=t.pendingProps,s=e!==null?e.memoizedProps:null,o=l.children,Ts(r,l)?o=null:s!==null&&Ts(r,s)&&(t.flags|=32),bu(e,t),ae(e,t,o,n),t.child;case 6:return e===null&&Is(t),null;case 13:return tc(e,t,n);case 4:return Pi(t,t.stateNode.containerInfo),r=t.pendingProps,e===null?t.child=on(t,null,r,n):ae(e,t,r,n),t.child;case 11:return r=t.type,l=t.pendingProps,l=t.elementType===r?l:Le(r,l),Qo(e,t,r,l,n);case 7:return ae(e,t,t.pendingProps,n),t.child;case 8:return ae(e,t,t.pendingProps.children,n),t.child;case 12:return ae(e,t,t.pendingProps.children,n),t.child;case 10:e:{if(r=t.type._context,l=t.pendingProps,s=t.memoizedProps,o=l.value,$(tl,r._currentValue),r._currentValue=o,s!==null)if(De(s.value,o)){if(s.children===l.children&&!he.current){t=Je(e,t,n);break e}}else for(s=t.child,s!==null&&(s.return=t);s!==null;){var a=s.dependencies;if(a!==null){o=s.child;for(var u=a.firstContext;u!==null;){if(u.context===r){if(s.tag===1){u=Ke(-1,n&-n),u.tag=2;var c=s.updateQueue;if(c!==null){c=c.shared;var m=c.pending;m===null?u.next=u:(u.next=m.next,m.next=u),c.pending=u}}s.lanes|=n,u=s.alternate,u!==null&&(u.lanes|=n),Fs(s.return,n,t),a.lanes|=n;break}u=u.next}}else if(s.tag===10)o=s.type===t.type?null:s.child;else if(s.tag===18){if(o=s.return,o===null)throw Error(k(341));o.lanes|=n,a=o.alternate,a!==null&&(a.lanes|=n),Fs(o,n,t),o=s.sibling}else o=s.child;if(o!==null)o.return=s;else for(o=s;o!==null;){if(o===t){o=null;break}if(s=o.sibling,s!==null){s.return=o.return,o=s;break}o=o.return}s=o}ae(e,t,l.children,n),t=t.child}return t;case 9:return l=t.type,r=t.pendingProps.children,tn(t,n),l=_e(l),r=r(l),t.flags|=1,ae(e,t,r,n),t.child;case 14:return r=t.type,l=Le(r,t.pendingProps),l=Le(r.type,l),Ko(e,t,r,l,n);case 15:return Zu(e,t,t.type,t.pendingProps,n);case 17:return r=t.type,l=t.pendingProps,l=t.elementType===r?l:Le(r,l),Mr(e,t),t.tag=1,me(r)?(e=!0,qr(t)):e=!1,tn(t,n),Yu(t,r,l),Ms(t,r,l,n),As(null,t,r,!0,e,n);case 19:return nc(e,t,n);case 22:return qu(e,t,n)}throw Error(k(156,t.tag))};function gc(e,t){return Qa(e,t)}function Qf(e,t,n,r){this.tag=e,this.key=n,this.sibling=this.child=this.return=this.stateNode=this.type=this.elementType=null,this.index=0,this.ref=null,this.pendingProps=t,this.dependencies=this.memoizedState=this.updateQueue=this.memoizedProps=null,this.mode=r,this.subtreeFlags=this.flags=0,this.deletions=null,this.childLanes=this.lanes=0,this.alternate=null}function Ce(e,t,n,r){return new Qf(e,t,n,r)}function Wi(e){return e=e.prototype,!(!e||!e.isReactComponent)}function Kf(e){if(typeof e=="function")return Wi(e)?1:0;if(e!=null){if(e=e.$$typeof,e===ai)return 11;if(e===ui)return 14}return 2}function ft(e,t){var n=e.alternate;return n===null?(n=Ce(e.tag,t,e.key,e.mode),n.elementType=e.elementType,n.type=e.type,n.stateNode=e.stateNode,n.alternate=e,e.alternate=n):(n.pendingProps=t,n.type=e.type,n.flags=0,n.subtreeFlags=0,n.deletions=null),n.flags=e.flags&14680064,n.childLanes=e.childLanes,n.lanes=e.lanes,n.child=e.child,n.memoizedProps=e.memoizedProps,n.memoizedState=e.memoizedState,n.updateQueue=e.updateQueue,t=e.dependencies,n.dependencies=t===null?null:{lanes:t.lanes,firstContext:t.firstContext},n.sibling=e.sibling,n.index=e.index,n.ref=e.ref,n}function Ar(e,t,n,r,l,s){var o=2;if(r=e,typeof e=="function")Wi(e)&&(o=1);else if(typeof e=="string")o=5;else e:switch(e){case At:return _t(n.children,l,s,t);case oi:o=8,l|=8;break;case os:return e=Ce(12,n,t,l|2),e.elementType=os,e.lanes=s,e;case as:return e=Ce(13,n,t,l),e.elementType=as,e.lanes=s,e;case us:return e=Ce(19,n,t,l),e.elementType=us,e.lanes=s,e;case Pa:return Nl(n,l,s,t);default:if(typeof e=="object"&&e!==null)switch(e.$$typeof){case Ea:o=10;break e;case _a:o=9;break e;case ai:o=11;break e;case ui:o=14;break e;case be:o=16,r=null;break e}throw Error(k(130,e==null?e:typeof e,""))}return t=Ce(o,n,t,l),t.elementType=e,t.type=r,t.lanes=s,t}function _t(e,t,n,r){return e=Ce(7,e,r,t),e.lanes=n,e}function Nl(e,t,n,r){return e=Ce(22,e,r,t),e.elementType=Pa,e.lanes=n,e.stateNode={isHidden:!1},e}function rs(e,t,n){return e=Ce(6,e,null,t),e.lanes=n,e}function ls(e,t,n){return t=Ce(4,e.children!==null?e.children:[],e.key,t),t.lanes=n,t.stateNode={containerInfo:e.containerInfo,pendingChildren:null,implementation:e.implementation},t}function Gf(e,t,n,r,l){this.tag=t,this.containerInfo=e,this.finishedWork=this.pingCache=this.current=this.pendingChildren=null,this.timeoutHandle=-1,this.callbackNode=this.pendingContext=this.context=null,this.callbackPriority=0,this.eventTimes=$l(0),this.expirationTimes=$l(-1),this.entangledLanes=this.finishedLanes=this.mutableReadLanes=this.expiredLanes=this.pingedLanes=this.suspendedLanes=this.pendingLanes=0,this.entanglements=$l(0),this.identifierPrefix=r,this.onRecoverableError=l,this.mutableSourceEagerHydrationData=null}function Hi(e,t,n,r,l,s,o,a,u){return e=new Gf(e,t,n,a,u),t===1?(t=1,s===!0&&(t|=8)):t=0,s=Ce(3,null,null,t),e.current=s,s.stateNode=e,s.memoizedState={element:r,isDehydrated:n,cache:null,transitions:null,pendingSuspenseBoundaries:null},_i(s),e}function Yf(e,t,n){var r=3"u"||typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE!="function"))try{__REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE(jc)}catch(e){console.error(e)}}jc(),ja.exports=ke;var bf=ja.exports,Sc,ia=bf;Sc=ia.createRoot,ia.hydrateRoot;const Nc="bv.access",Yi="bv.refresh";function qs(e){try{return localStorage.getItem(e)||""}catch{return""}}function oa(e,t){try{t?localStorage.setItem(e,t):localStorage.removeItem(e)}catch{}}function ir(){return{access:qs(Nc),refresh:qs(Yi)}}function fl(e,t){oa(Nc,e),oa(Yi,t)}function or(){fl("","")}function ep(){return!!qs(Yi)}class Pt extends Error{constructor(t,n,r){super(r),this.status=t,this.code=n}}let Nn=null;async function Tl(){return Nn||(Nn=(async()=>{const{refresh:e}=ir();if(!e)throw new Pt(401,"unauthorized","Signed out.");const t=await fetch("/api/auth/refresh",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({refresh_token:e})});if(!t.ok)throw or(),new Pt(t.status,"unauthorized","Your session has ended. Sign in again.");const n=await t.json();return fl(n.access_token,n.refresh_token),n})().finally(()=>{Nn=null}),Nn)}async function F(e,t,n,r=!0){const{access:l}=ir(),s={};l&&(s.Authorization="Bearer "+l),n!==void 0&&(s["Content-Type"]="application/json");const o=await fetch(t,{method:e,headers:s,body:n===void 0?void 0:JSON.stringify(n)});if(o.status===204)return null;const a=await o.text();let u=null;try{u=a?JSON.parse(a):null}catch{}if(o.ok)return u;const c=(u==null?void 0:u.error)||"";if(c==="token_expired"&&r)return await Tl(),F(e,t,n,!1);throw o.status===401&&or(),new Pt(o.status,c,(u==null?void 0:u.message)||`Something went wrong (${o.status}).`)}async function Cc(e,t=!0){const{access:n}=ir(),r=await fetch(e,{headers:n?{Authorization:"Bearer "+n}:{}});if(r.ok)return URL.createObjectURL(await r.blob());let l=null;try{l=await r.json()}catch{}const s=(l==null?void 0:l.error)||"";if(s==="token_expired"&&t)return await Tl(),Cc(e,!1);throw r.status===401&&or(),new Pt(r.status,s,(l==null?void 0:l.message)||`That picture could not be loaded (${r.status}).`)}function aa(){const e=navigator.userAgent||"",t=/Windows/.test(e)?"Windows":/Mac OS X|Macintosh/.test(e)?"Mac":/Android/.test(e)?"Android":/iPhone|iPad/.test(e)?"iOS":"Unknown";return`${/Edg\//.test(e)?"Edge":/Chrome\//.test(e)?"Chrome":/Safari\//.test(e)?"Safari":/Firefox\//.test(e)?"Firefox":"browser"} on ${t}`}const jt=e=>{const t=new URLSearchParams;for(const[r,l]of Object.entries(e||{}))l!=null&&l!==""&&t.set(r,l);const n=t.toString();return n?"?"+n:""},D={async login(e,t){const n=await fetch("/api/auth/login",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({email:e,password:t,device:aa()})}),r=await n.json().catch(()=>null);if(!n.ok)throw new Pt(n.status,(r==null?void 0:r.error)||"",(r==null?void 0:r.message)||"Could not sign in.");return fl(r.access_token,r.refresh_token),r.user},async previewInvitation(e){const t=await fetch("/api/auth/invitation"+jt({code:e})),n=await t.json().catch(()=>null);if(!t.ok)throw new Pt(t.status,(n==null?void 0:n.error)||"",(n==null?void 0:n.message)||"That invitation code is not valid.");return n},async register({code:e,full_name:t,password:n}){const r=await fetch("/api/auth/register",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({code:e,full_name:t,password:n,device:aa()})}),l=await r.json().catch(()=>null);if(!r.ok)throw new Pt(r.status,(l==null?void 0:l.error)||"",(l==null?void 0:l.message)||"Could not create the account.");return fl(l.access_token,l.refresh_token),l.user},async logout(){try{await F("POST","/api/auth/logout")}catch{}or()},me:()=>F("GET","/api/auth/me"),sites:()=>F("GET","/api/sites"),createSite:e=>F("POST","/api/sites",e),updateSite:(e,t)=>F("PATCH",`/api/sites/${encodeURIComponent(e)}`,t),deleteSite:e=>F("DELETE",`/api/sites/${encodeURIComponent(e)}`),arrivals:e=>F("GET","/api/visits"+jt(e)),visitors:(e,t=50)=>F("GET","/api/visitors"+jt({q:e,limit:t})),visitorHistory:(e,t=50)=>F("GET",`/api/visitors/${encodeURIComponent(e)}/history`+jt({limit:t})),saveProfile:(e,t)=>F("PUT",`/api/visitors/${encodeURIComponent(e)}/profile`,t),footfall:e=>F("GET","/api/reports/footfall"+jt(e)),conversion:e=>F("GET","/api/reports/conversion"+jt(e)),cameras:()=>F("GET","/api/cameras"),cameraSnapshot:e=>Cc(e),createCamera:(e,t)=>F("POST",`/api/sites/${encodeURIComponent(e)}/cameras`,t),updateCamera:(e,t)=>F("PATCH",`/api/cameras/${encodeURIComponent(e)}`,t),deleteCamera:e=>F("DELETE",`/api/cameras/${encodeURIComponent(e)}`),checkCamera:(e,t,n)=>F("POST",`/api/cameras/${encodeURIComponent(e)}/check`,{kind:t,...n?{seconds:n}:{}}),siteCheck:e=>F("GET",`/api/sites/${encodeURIComponent(e)}/check`),enrolmentCode:(e,t)=>F("POST",`/api/sites/${encodeURIComponent(e)}/enrolment-code`,t||{}),ask:e=>F("POST","/api/assistant",{history:e}),clients:()=>F("GET","/api/admin/clients"),createClient:e=>F("POST","/api/admin/clients",e),team:()=>F("GET","/api/team"),updateMember:(e,t)=>F("PATCH",`/api/team/${encodeURIComponent(e)}`,t),invitations:()=>F("GET","/api/team/invitations"),invite:e=>F("POST","/api/team/invitations",e),revokeInvitation:e=>F("DELETE",`/api/team/invitations/${encodeURIComponent(e)}`),sessions:()=>F("GET","/api/auth/sessions"),revokeSession:e=>F("DELETE",`/api/auth/sessions/${encodeURIComponent(e)}`),signOutOthers:()=>F("POST","/api/auth/sessions/revoke-others")};function tp({cursor:e,siteId:t,onPage:n,onError:r,signal:l}){let s=!1,o=e||"";return(async()=>{for(;!s;){try{const{access:u}=ir(),c=await fetch("/api/visits/stream"+jt({cursor:o,site_id:t}),{headers:{Authorization:"Bearer "+u,Accept:"text/event-stream"},signal:l});if(c.status===401){await Tl();continue}if(!c.ok||!c.body)throw new Error("stream unavailable");const m=c.body.getReader(),h=new TextDecoder;let v="";for(;!s;){const{value:y,done:x}=await m.read();if(x)break;v+=h.decode(y,{stream:!0});let g;for(;(g=v.indexOf(` +`+s.stack}return{value:e,source:t,stack:l,digest:null}}function ts(e,t,n){return{value:e,source:null,stack:n??null,digest:t??null}}function $s(e,t){try{console.error(t.value)}catch(n){setTimeout(function(){throw n})}}var Pf=typeof WeakMap=="function"?WeakMap:Map;function Xu(e,t,n){n=Ke(-1,n),n.tag=3,n.payload={element:null};var r=t.value;return n.callback=function(){al||(al=!0,Ys=r),$s(e,t)},n}function Ju(e,t,n){n=Ke(-1,n),n.tag=3;var r=e.type.getDerivedStateFromError;if(typeof r=="function"){var l=t.value;n.payload=function(){return r(l)},n.callback=function(){$s(e,t)}}var s=e.stateNode;return s!==null&&typeof s.componentDidCatch=="function"&&(n.callback=function(){$s(e,t),typeof r!="function"&&(ct===null?ct=new Set([this]):ct.add(this));var o=t.stack;this.componentDidCatch(t.value,{componentStack:o!==null?o:""})}),n}function Vo(e,t,n){var r=e.pingCache;if(r===null){r=e.pingCache=new Pf;var l=new Set;r.set(t,l)}else l=r.get(t),l===void 0&&(l=new Set,r.set(t,l));l.has(n)||(l.add(n),e=Vf.bind(null,e,t,n),t.then(e,e))}function Wo(e){do{var t;if((t=e.tag===13)&&(t=e.memoizedState,t=t!==null?t.dehydrated!==null:!0),t)return e;e=e.return}while(e!==null);return null}function Ho(e,t,n,r,l){return e.mode&1?(e.flags|=65536,e.lanes=l,e):(e===t?e.flags|=65536:(e.flags|=128,n.flags|=131072,n.flags&=-52805,n.tag===1&&(n.alternate===null?n.tag=17:(t=Ke(-1,1),t.tag=2,ut(n,t,1))),n.lanes|=1),e)}var Tf=Ze.ReactCurrentOwner,pe=!1;function ae(e,t,n,r){t.child=e===null?Cu(t,null,n,r):on(t,e.child,n,r)}function Qo(e,t,n,r,l){n=n.render;var s=t.ref;return tn(t,l),r=Ri(e,t,n,r,s,l),n=Oi(),e!==null&&!pe?(t.updateQueue=e.updateQueue,t.flags&=-2053,e.lanes&=~l,Je(e,t,l)):(B&&n&&xi(t),t.flags|=1,ae(e,t,r,l),t.child)}function Ko(e,t,n,r,l){if(e===null){var s=n.type;return typeof s=="function"&&!Wi(s)&&s.defaultProps===void 0&&n.compare===null&&n.defaultProps===void 0?(t.tag=15,t.type=s,Zu(e,t,s,r,l)):(e=Ar(n.type,null,r,t,t.mode,l),e.ref=t.ref,e.return=t,t.child=e)}if(s=e.child,!(e.lanes&l)){var o=s.memoizedProps;if(n=n.compare,n=n!==null?n:Qn,n(o,r)&&e.ref===t.ref)return Je(e,t,l)}return t.flags|=1,e=ft(s,r),e.ref=t.ref,e.return=t,t.child=e}function Zu(e,t,n,r,l){if(e!==null){var s=e.memoizedProps;if(Qn(s,r)&&e.ref===t.ref)if(pe=!1,t.pendingProps=r=s,(e.lanes&l)!==0)e.flags&131072&&(pe=!0);else return t.lanes=e.lanes,Je(e,t,l)}return Us(e,t,n,r,l)}function qu(e,t,n){var r=t.pendingProps,l=r.children,s=e!==null?e.memoizedState:null;if(r.mode==="hidden")if(!(t.mode&1))t.memoizedState={baseLanes:0,cachePool:null,transitions:null},$(Jt,ye),ye|=n;else{if(!(n&1073741824))return e=s!==null?s.baseLanes|n:n,t.lanes=t.childLanes=1073741824,t.memoizedState={baseLanes:e,cachePool:null,transitions:null},t.updateQueue=null,$(Jt,ye),ye|=e,null;t.memoizedState={baseLanes:0,cachePool:null,transitions:null},r=s!==null?s.baseLanes:n,$(Jt,ye),ye|=r}else s!==null?(r=s.baseLanes|n,t.memoizedState=null):r=n,$(Jt,ye),ye|=r;return ae(e,t,l,n),t.child}function bu(e,t){var n=t.ref;(e===null&&n!==null||e!==null&&e.ref!==n)&&(t.flags|=512,t.flags|=2097152)}function Us(e,t,n,r,l){var s=me(n)?Tt:oe.current;return s=ln(t,s),tn(t,l),n=Ri(e,t,n,r,s,l),r=Oi(),e!==null&&!pe?(t.updateQueue=e.updateQueue,t.flags&=-2053,e.lanes&=~l,Je(e,t,l)):(B&&r&&xi(t),t.flags|=1,ae(e,t,n,l),t.child)}function Go(e,t,n,r,l){if(me(n)){var s=!0;qr(t)}else s=!1;if(tn(t,l),t.stateNode===null)Mr(e,t),Yu(t,n,r),Ms(t,n,r,l),r=!0;else if(e===null){var o=t.stateNode,a=t.memoizedProps;o.props=a;var u=o.context,c=n.contextType;typeof c=="object"&&c!==null?c=_e(c):(c=me(n)?Tt:oe.current,c=ln(t,c));var m=n.getDerivedStateFromProps,h=typeof m=="function"||typeof o.getSnapshotBeforeUpdate=="function";h||typeof o.UNSAFE_componentWillReceiveProps!="function"&&typeof o.componentWillReceiveProps!="function"||(a!==r||u!==c)&&Bo(t,o,r,c),et=!1;var v=t.memoizedState;o.state=v,rl(t,r,o,l),u=t.memoizedState,a!==r||v!==u||he.current||et?(typeof m=="function"&&(Ds(t,n,m,r),u=t.memoizedState),(a=et||Ao(t,n,a,r,v,u,c))?(h||typeof o.UNSAFE_componentWillMount!="function"&&typeof o.componentWillMount!="function"||(typeof o.componentWillMount=="function"&&o.componentWillMount(),typeof o.UNSAFE_componentWillMount=="function"&&o.UNSAFE_componentWillMount()),typeof o.componentDidMount=="function"&&(t.flags|=4194308)):(typeof o.componentDidMount=="function"&&(t.flags|=4194308),t.memoizedProps=r,t.memoizedState=u),o.props=r,o.state=u,o.context=c,r=a):(typeof o.componentDidMount=="function"&&(t.flags|=4194308),r=!1)}else{o=t.stateNode,_u(e,t),a=t.memoizedProps,c=t.type===t.elementType?a:Le(t.type,a),o.props=c,h=t.pendingProps,v=o.context,u=n.contextType,typeof u=="object"&&u!==null?u=_e(u):(u=me(n)?Tt:oe.current,u=ln(t,u));var y=n.getDerivedStateFromProps;(m=typeof y=="function"||typeof o.getSnapshotBeforeUpdate=="function")||typeof o.UNSAFE_componentWillReceiveProps!="function"&&typeof o.componentWillReceiveProps!="function"||(a!==h||v!==u)&&Bo(t,o,r,u),et=!1,v=t.memoizedState,o.state=v,rl(t,r,o,l);var x=t.memoizedState;a!==h||v!==x||he.current||et?(typeof y=="function"&&(Ds(t,n,y,r),x=t.memoizedState),(c=et||Ao(t,n,c,r,v,x,u)||!1)?(m||typeof o.UNSAFE_componentWillUpdate!="function"&&typeof o.componentWillUpdate!="function"||(typeof o.componentWillUpdate=="function"&&o.componentWillUpdate(r,x,u),typeof o.UNSAFE_componentWillUpdate=="function"&&o.UNSAFE_componentWillUpdate(r,x,u)),typeof o.componentDidUpdate=="function"&&(t.flags|=4),typeof o.getSnapshotBeforeUpdate=="function"&&(t.flags|=1024)):(typeof o.componentDidUpdate!="function"||a===e.memoizedProps&&v===e.memoizedState||(t.flags|=4),typeof o.getSnapshotBeforeUpdate!="function"||a===e.memoizedProps&&v===e.memoizedState||(t.flags|=1024),t.memoizedProps=r,t.memoizedState=x),o.props=r,o.state=x,o.context=u,r=c):(typeof o.componentDidUpdate!="function"||a===e.memoizedProps&&v===e.memoizedState||(t.flags|=4),typeof o.getSnapshotBeforeUpdate!="function"||a===e.memoizedProps&&v===e.memoizedState||(t.flags|=1024),r=!1)}return As(e,t,n,r,s,l)}function As(e,t,n,r,l,s){bu(e,t);var o=(t.flags&128)!==0;if(!r&&!o)return l&&Ro(t,n,!1),Je(e,t,s);r=t.stateNode,Tf.current=t;var a=o&&typeof n.getDerivedStateFromError!="function"?null:r.render();return t.flags|=1,e!==null&&o?(t.child=on(t,e.child,null,s),t.child=on(t,null,a,s)):ae(e,t,a,s),t.memoizedState=r.state,l&&Ro(t,n,!0),t.child}function ec(e){var t=e.stateNode;t.pendingContext?Lo(e,t.pendingContext,t.pendingContext!==t.context):t.context&&Lo(e,t.context,!1),Pi(e,t.containerInfo)}function Yo(e,t,n,r,l){return sn(),ji(l),t.flags|=256,ae(e,t,n,r),t.child}var Bs={dehydrated:null,treeContext:null,retryLane:0};function Vs(e){return{baseLanes:e,cachePool:null,transitions:null}}function tc(e,t,n){var r=t.pendingProps,l=V.current,s=!1,o=(t.flags&128)!==0,a;if((a=o)||(a=e!==null&&e.memoizedState===null?!1:(l&2)!==0),a?(s=!0,t.flags&=-129):(e===null||e.memoizedState!==null)&&(l|=1),$(V,l&1),e===null)return Is(t),e=t.memoizedState,e!==null&&(e=e.dehydrated,e!==null)?(t.mode&1?e.data==="$!"?t.lanes=8:t.lanes=1073741824:t.lanes=1,null):(o=r.children,e=r.fallback,s?(r=t.mode,s=t.child,o={mode:"hidden",children:o},!(r&1)&&s!==null?(s.childLanes=0,s.pendingProps=o):s=Nl(o,r,0,null),e=_t(e,r,n,null),s.return=t,e.return=t,s.sibling=e,t.child=s,t.child.memoizedState=Vs(n),t.memoizedState=Bs,e):Di(t,o));if(l=e.memoizedState,l!==null&&(a=l.dehydrated,a!==null))return zf(e,t,o,r,a,l,n);if(s){s=r.fallback,o=t.mode,l=e.child,a=l.sibling;var u={mode:"hidden",children:r.children};return!(o&1)&&t.child!==l?(r=t.child,r.childLanes=0,r.pendingProps=u,t.deletions=null):(r=ft(l,u),r.subtreeFlags=l.subtreeFlags&14680064),a!==null?s=ft(a,s):(s=_t(s,o,n,null),s.flags|=2),s.return=t,r.return=t,r.sibling=s,t.child=r,r=s,s=t.child,o=e.child.memoizedState,o=o===null?Vs(n):{baseLanes:o.baseLanes|n,cachePool:null,transitions:o.transitions},s.memoizedState=o,s.childLanes=e.childLanes&~n,t.memoizedState=Bs,r}return s=e.child,e=s.sibling,r=ft(s,{mode:"visible",children:r.children}),!(t.mode&1)&&(r.lanes=n),r.return=t,r.sibling=null,e!==null&&(n=t.deletions,n===null?(t.deletions=[e],t.flags|=16):n.push(e)),t.child=r,t.memoizedState=null,r}function Di(e,t){return t=Nl({mode:"visible",children:t},e.mode,0,null),t.return=e,e.child=t}function Cr(e,t,n,r){return r!==null&&ji(r),on(t,e.child,null,n),e=Di(t,t.pendingProps.children),e.flags|=2,t.memoizedState=null,e}function zf(e,t,n,r,l,s,o){if(n)return t.flags&256?(t.flags&=-257,r=ts(Error(k(422))),Cr(e,t,o,r)):t.memoizedState!==null?(t.child=e.child,t.flags|=128,null):(s=r.fallback,l=t.mode,r=Nl({mode:"visible",children:r.children},l,0,null),s=_t(s,l,o,null),s.flags|=2,r.return=t,s.return=t,r.sibling=s,t.child=r,t.mode&1&&on(t,e.child,null,o),t.child.memoizedState=Vs(o),t.memoizedState=Bs,s);if(!(t.mode&1))return Cr(e,t,o,null);if(l.data==="$!"){if(r=l.nextSibling&&l.nextSibling.dataset,r)var a=r.dgst;return r=a,s=Error(k(419)),r=ts(s,r,void 0),Cr(e,t,o,r)}if(a=(o&e.childLanes)!==0,pe||a){if(r=ee,r!==null){switch(o&-o){case 4:l=2;break;case 16:l=8;break;case 64:case 128:case 256:case 512:case 1024:case 2048:case 4096:case 8192:case 16384:case 32768:case 65536:case 131072:case 262144:case 524288:case 1048576:case 2097152:case 4194304:case 8388608:case 16777216:case 33554432:case 67108864:l=32;break;case 536870912:l=268435456;break;default:l=0}l=l&(r.suspendedLanes|o)?0:l,l!==0&&l!==s.retryLane&&(s.retryLane=l,Xe(e,l),Fe(r,e,l,-1))}return Vi(),r=ts(Error(k(421))),Cr(e,t,o,r)}return l.data==="$?"?(t.flags|=128,t.child=e.child,t=Wf.bind(null,e),l._reactRetry=t,null):(e=s.treeContext,ge=at(l.nextSibling),we=t,B=!0,Oe=null,e!==null&&(Se[Ne++]=He,Se[Ne++]=Qe,Se[Ne++]=zt,He=e.id,Qe=e.overflow,zt=t),t=Di(t,r.children),t.flags|=4096,t)}function Xo(e,t,n){e.lanes|=t;var r=e.alternate;r!==null&&(r.lanes|=t),Fs(e.return,t,n)}function ns(e,t,n,r,l){var s=e.memoizedState;s===null?e.memoizedState={isBackwards:t,rendering:null,renderingStartTime:0,last:r,tail:n,tailMode:l}:(s.isBackwards=t,s.rendering=null,s.renderingStartTime=0,s.last=r,s.tail=n,s.tailMode=l)}function nc(e,t,n){var r=t.pendingProps,l=r.revealOrder,s=r.tail;if(ae(e,t,r.children,n),r=V.current,r&2)r=r&1|2,t.flags|=128;else{if(e!==null&&e.flags&128)e:for(e=t.child;e!==null;){if(e.tag===13)e.memoizedState!==null&&Xo(e,n,t);else if(e.tag===19)Xo(e,n,t);else if(e.child!==null){e.child.return=e,e=e.child;continue}if(e===t)break e;for(;e.sibling===null;){if(e.return===null||e.return===t)break e;e=e.return}e.sibling.return=e.return,e=e.sibling}r&=1}if($(V,r),!(t.mode&1))t.memoizedState=null;else switch(l){case"forwards":for(n=t.child,l=null;n!==null;)e=n.alternate,e!==null&&ll(e)===null&&(l=n),n=n.sibling;n=l,n===null?(l=t.child,t.child=null):(l=n.sibling,n.sibling=null),ns(t,!1,l,n,s);break;case"backwards":for(n=null,l=t.child,t.child=null;l!==null;){if(e=l.alternate,e!==null&&ll(e)===null){t.child=l;break}e=l.sibling,l.sibling=n,n=l,l=e}ns(t,!0,n,null,s);break;case"together":ns(t,!1,null,null,void 0);break;default:t.memoizedState=null}return t.child}function Mr(e,t){!(t.mode&1)&&e!==null&&(e.alternate=null,t.alternate=null,t.flags|=2)}function Je(e,t,n){if(e!==null&&(t.dependencies=e.dependencies),Rt|=t.lanes,!(n&t.childLanes))return null;if(e!==null&&t.child!==e.child)throw Error(k(153));if(t.child!==null){for(e=t.child,n=ft(e,e.pendingProps),t.child=n,n.return=t;e.sibling!==null;)e=e.sibling,n=n.sibling=ft(e,e.pendingProps),n.return=t;n.sibling=null}return t.child}function Lf(e,t,n){switch(t.tag){case 3:ec(t),sn();break;case 5:Pu(t);break;case 1:me(t.type)&&qr(t);break;case 4:Pi(t,t.stateNode.containerInfo);break;case 10:var r=t.type._context,l=t.memoizedProps.value;$(tl,r._currentValue),r._currentValue=l;break;case 13:if(r=t.memoizedState,r!==null)return r.dehydrated!==null?($(V,V.current&1),t.flags|=128,null):n&t.child.childLanes?tc(e,t,n):($(V,V.current&1),e=Je(e,t,n),e!==null?e.sibling:null);$(V,V.current&1);break;case 19:if(r=(n&t.childLanes)!==0,e.flags&128){if(r)return nc(e,t,n);t.flags|=128}if(l=t.memoizedState,l!==null&&(l.rendering=null,l.tail=null,l.lastEffect=null),$(V,V.current),r)break;return null;case 22:case 23:return t.lanes=0,qu(e,t,n)}return Je(e,t,n)}var rc,Ws,lc,sc;rc=function(e,t){for(var n=t.child;n!==null;){if(n.tag===5||n.tag===6)e.appendChild(n.stateNode);else if(n.tag!==4&&n.child!==null){n.child.return=n,n=n.child;continue}if(n===t)break;for(;n.sibling===null;){if(n.return===null||n.return===t)return;n=n.return}n.sibling.return=n.return,n=n.sibling}};Ws=function(){};lc=function(e,t,n,r){var l=e.memoizedProps;if(l!==r){e=t.stateNode,Ct(Be.current);var s=null;switch(n){case"input":l=ds(e,l),r=ds(e,r),s=[];break;case"select":l=H({},l,{value:void 0}),r=H({},r,{value:void 0}),s=[];break;case"textarea":l=hs(e,l),r=hs(e,r),s=[];break;default:typeof l.onClick!="function"&&typeof r.onClick=="function"&&(e.onclick=Jr)}vs(n,r);var o;n=null;for(c in l)if(!r.hasOwnProperty(c)&&l.hasOwnProperty(c)&&l[c]!=null)if(c==="style"){var a=l[c];for(o in a)a.hasOwnProperty(o)&&(n||(n={}),n[o]="")}else c!=="dangerouslySetInnerHTML"&&c!=="children"&&c!=="suppressContentEditableWarning"&&c!=="suppressHydrationWarning"&&c!=="autoFocus"&&($n.hasOwnProperty(c)?s||(s=[]):(s=s||[]).push(c,null));for(c in r){var u=r[c];if(a=l!=null?l[c]:void 0,r.hasOwnProperty(c)&&u!==a&&(u!=null||a!=null))if(c==="style")if(a){for(o in a)!a.hasOwnProperty(o)||u&&u.hasOwnProperty(o)||(n||(n={}),n[o]="");for(o in u)u.hasOwnProperty(o)&&a[o]!==u[o]&&(n||(n={}),n[o]=u[o])}else n||(s||(s=[]),s.push(c,n)),n=u;else c==="dangerouslySetInnerHTML"?(u=u?u.__html:void 0,a=a?a.__html:void 0,u!=null&&a!==u&&(s=s||[]).push(c,u)):c==="children"?typeof u!="string"&&typeof u!="number"||(s=s||[]).push(c,""+u):c!=="suppressContentEditableWarning"&&c!=="suppressHydrationWarning"&&($n.hasOwnProperty(c)?(u!=null&&c==="onScroll"&&U("scroll",e),s||a===u||(s=[])):(s=s||[]).push(c,u))}n&&(s=s||[]).push("style",n);var c=s;(t.updateQueue=c)&&(t.flags|=4)}};sc=function(e,t,n,r){n!==r&&(t.flags|=4)};function jn(e,t){if(!B)switch(e.tailMode){case"hidden":t=e.tail;for(var n=null;t!==null;)t.alternate!==null&&(n=t),t=t.sibling;n===null?e.tail=null:n.sibling=null;break;case"collapsed":n=e.tail;for(var r=null;n!==null;)n.alternate!==null&&(r=n),n=n.sibling;r===null?t||e.tail===null?e.tail=null:e.tail.sibling=null:r.sibling=null}}function se(e){var t=e.alternate!==null&&e.alternate.child===e.child,n=0,r=0;if(t)for(var l=e.child;l!==null;)n|=l.lanes|l.childLanes,r|=l.subtreeFlags&14680064,r|=l.flags&14680064,l.return=e,l=l.sibling;else for(l=e.child;l!==null;)n|=l.lanes|l.childLanes,r|=l.subtreeFlags,r|=l.flags,l.return=e,l=l.sibling;return e.subtreeFlags|=r,e.childLanes=n,t}function Rf(e,t,n){var r=t.pendingProps;switch(ki(t),t.tag){case 2:case 16:case 15:case 0:case 11:case 7:case 8:case 12:case 9:case 14:return se(t),null;case 1:return me(t.type)&&Zr(),se(t),null;case 3:return r=t.stateNode,an(),A(he),A(oe),zi(),r.pendingContext&&(r.context=r.pendingContext,r.pendingContext=null),(e===null||e.child===null)&&(Sr(t)?t.flags|=4:e===null||e.memoizedState.isDehydrated&&!(t.flags&256)||(t.flags|=1024,Oe!==null&&(Zs(Oe),Oe=null))),Ws(e,t),se(t),null;case 5:Ti(t);var l=Ct(Jn.current);if(n=t.type,e!==null&&t.stateNode!=null)lc(e,t,n,r,l),e.ref!==t.ref&&(t.flags|=512,t.flags|=2097152);else{if(!r){if(t.stateNode===null)throw Error(k(166));return se(t),null}if(e=Ct(Be.current),Sr(t)){r=t.stateNode,n=t.type;var s=t.memoizedProps;switch(r[Ue]=t,r[Yn]=s,e=(t.mode&1)!==0,n){case"dialog":U("cancel",r),U("close",r);break;case"iframe":case"object":case"embed":U("load",r);break;case"video":case"audio":for(l=0;l<\/script>",e=e.removeChild(e.firstChild)):typeof r.is=="string"?e=o.createElement(n,{is:r.is}):(e=o.createElement(n),n==="select"&&(o=e,r.multiple?o.multiple=!0:r.size&&(o.size=r.size))):e=o.createElementNS(e,n),e[Ue]=t,e[Yn]=r,rc(e,t,!1,!1),t.stateNode=e;e:{switch(o=ys(n,r),n){case"dialog":U("cancel",e),U("close",e),l=r;break;case"iframe":case"object":case"embed":U("load",e),l=r;break;case"video":case"audio":for(l=0;lcn&&(t.flags|=128,r=!0,jn(s,!1),t.lanes=4194304)}else{if(!r)if(e=ll(o),e!==null){if(t.flags|=128,r=!0,n=e.updateQueue,n!==null&&(t.updateQueue=n,t.flags|=4),jn(s,!0),s.tail===null&&s.tailMode==="hidden"&&!o.alternate&&!B)return se(t),null}else 2*Y()-s.renderingStartTime>cn&&n!==1073741824&&(t.flags|=128,r=!0,jn(s,!1),t.lanes=4194304);s.isBackwards?(o.sibling=t.child,t.child=o):(n=s.last,n!==null?n.sibling=o:t.child=o,s.last=o)}return s.tail!==null?(t=s.tail,s.rendering=t,s.tail=t.sibling,s.renderingStartTime=Y(),t.sibling=null,n=V.current,$(V,r?n&1|2:n&1),t):(se(t),null);case 22:case 23:return Bi(),r=t.memoizedState!==null,e!==null&&e.memoizedState!==null!==r&&(t.flags|=8192),r&&t.mode&1?ye&1073741824&&(se(t),t.subtreeFlags&6&&(t.flags|=8192)):se(t),null;case 24:return null;case 25:return null}throw Error(k(156,t.tag))}function Of(e,t){switch(ki(t),t.tag){case 1:return me(t.type)&&Zr(),e=t.flags,e&65536?(t.flags=e&-65537|128,t):null;case 3:return an(),A(he),A(oe),zi(),e=t.flags,e&65536&&!(e&128)?(t.flags=e&-65537|128,t):null;case 5:return Ti(t),null;case 13:if(A(V),e=t.memoizedState,e!==null&&e.dehydrated!==null){if(t.alternate===null)throw Error(k(340));sn()}return e=t.flags,e&65536?(t.flags=e&-65537|128,t):null;case 19:return A(V),null;case 4:return an(),null;case 10:return Ci(t.type._context),null;case 22:case 23:return Bi(),null;case 24:return null;default:return null}}var Er=!1,ie=!1,If=typeof WeakSet=="function"?WeakSet:Set,C=null;function Xt(e,t){var n=e.ref;if(n!==null)if(typeof n=="function")try{n(null)}catch(r){Q(e,t,r)}else n.current=null}function Hs(e,t,n){try{n()}catch(r){Q(e,t,r)}}var Jo=!1;function Ff(e,t){if(_s=Gr,e=cu(),wi(e)){if("selectionStart"in e)var n={start:e.selectionStart,end:e.selectionEnd};else e:{n=(n=e.ownerDocument)&&n.defaultView||window;var r=n.getSelection&&n.getSelection();if(r&&r.rangeCount!==0){n=r.anchorNode;var l=r.anchorOffset,s=r.focusNode;r=r.focusOffset;try{n.nodeType,s.nodeType}catch{n=null;break e}var o=0,a=-1,u=-1,c=0,m=0,h=e,v=null;t:for(;;){for(var y;h!==n||l!==0&&h.nodeType!==3||(a=o+l),h!==s||r!==0&&h.nodeType!==3||(u=o+r),h.nodeType===3&&(o+=h.nodeValue.length),(y=h.firstChild)!==null;)v=h,h=y;for(;;){if(h===e)break t;if(v===n&&++c===l&&(a=o),v===s&&++m===r&&(u=o),(y=h.nextSibling)!==null)break;h=v,v=h.parentNode}h=y}n=a===-1||u===-1?null:{start:a,end:u}}else n=null}n=n||{start:0,end:0}}else n=null;for(Ps={focusedElem:e,selectionRange:n},Gr=!1,C=t;C!==null;)if(t=C,e=t.child,(t.subtreeFlags&1028)!==0&&e!==null)e.return=t,C=e;else for(;C!==null;){t=C;try{var x=t.alternate;if(t.flags&1024)switch(t.tag){case 0:case 11:case 15:break;case 1:if(x!==null){var g=x.memoizedProps,N=x.memoizedState,f=t.stateNode,d=f.getSnapshotBeforeUpdate(t.elementType===t.type?g:Le(t.type,g),N);f.__reactInternalSnapshotBeforeUpdate=d}break;case 3:var p=t.stateNode.containerInfo;p.nodeType===1?p.textContent="":p.nodeType===9&&p.documentElement&&p.removeChild(p.documentElement);break;case 5:case 6:case 4:case 17:break;default:throw Error(k(163))}}catch(w){Q(t,t.return,w)}if(e=t.sibling,e!==null){e.return=t.return,C=e;break}C=t.return}return x=Jo,Jo=!1,x}function Fn(e,t,n){var r=t.updateQueue;if(r=r!==null?r.lastEffect:null,r!==null){var l=r=r.next;do{if((l.tag&e)===e){var s=l.destroy;l.destroy=void 0,s!==void 0&&Hs(t,n,s)}l=l.next}while(l!==r)}}function jl(e,t){if(t=t.updateQueue,t=t!==null?t.lastEffect:null,t!==null){var n=t=t.next;do{if((n.tag&e)===e){var r=n.create;n.destroy=r()}n=n.next}while(n!==t)}}function Qs(e){var t=e.ref;if(t!==null){var n=e.stateNode;switch(e.tag){case 5:e=n;break;default:e=n}typeof t=="function"?t(e):t.current=e}}function ic(e){var t=e.alternate;t!==null&&(e.alternate=null,ic(t)),e.child=null,e.deletions=null,e.sibling=null,e.tag===5&&(t=e.stateNode,t!==null&&(delete t[Ue],delete t[Yn],delete t[Ls],delete t[yf],delete t[gf])),e.stateNode=null,e.return=null,e.dependencies=null,e.memoizedProps=null,e.memoizedState=null,e.pendingProps=null,e.stateNode=null,e.updateQueue=null}function oc(e){return e.tag===5||e.tag===3||e.tag===4}function Zo(e){e:for(;;){for(;e.sibling===null;){if(e.return===null||oc(e.return))return null;e=e.return}for(e.sibling.return=e.return,e=e.sibling;e.tag!==5&&e.tag!==6&&e.tag!==18;){if(e.flags&2||e.child===null||e.tag===4)continue e;e.child.return=e,e=e.child}if(!(e.flags&2))return e.stateNode}}function Ks(e,t,n){var r=e.tag;if(r===5||r===6)e=e.stateNode,t?n.nodeType===8?n.parentNode.insertBefore(e,t):n.insertBefore(e,t):(n.nodeType===8?(t=n.parentNode,t.insertBefore(e,n)):(t=n,t.appendChild(e)),n=n._reactRootContainer,n!=null||t.onclick!==null||(t.onclick=Jr));else if(r!==4&&(e=e.child,e!==null))for(Ks(e,t,n),e=e.sibling;e!==null;)Ks(e,t,n),e=e.sibling}function Gs(e,t,n){var r=e.tag;if(r===5||r===6)e=e.stateNode,t?n.insertBefore(e,t):n.appendChild(e);else if(r!==4&&(e=e.child,e!==null))for(Gs(e,t,n),e=e.sibling;e!==null;)Gs(e,t,n),e=e.sibling}var te=null,Re=!1;function qe(e,t,n){for(n=n.child;n!==null;)ac(e,t,n),n=n.sibling}function ac(e,t,n){if(Ae&&typeof Ae.onCommitFiberUnmount=="function")try{Ae.onCommitFiberUnmount(hl,n)}catch{}switch(n.tag){case 5:ie||Xt(n,t);case 6:var r=te,l=Re;te=null,qe(e,t,n),te=r,Re=l,te!==null&&(Re?(e=te,n=n.stateNode,e.nodeType===8?e.parentNode.removeChild(n):e.removeChild(n)):te.removeChild(n.stateNode));break;case 18:te!==null&&(Re?(e=te,n=n.stateNode,e.nodeType===8?Xl(e.parentNode,n):e.nodeType===1&&Xl(e,n),Wn(e)):Xl(te,n.stateNode));break;case 4:r=te,l=Re,te=n.stateNode.containerInfo,Re=!0,qe(e,t,n),te=r,Re=l;break;case 0:case 11:case 14:case 15:if(!ie&&(r=n.updateQueue,r!==null&&(r=r.lastEffect,r!==null))){l=r=r.next;do{var s=l,o=s.destroy;s=s.tag,o!==void 0&&(s&2||s&4)&&Hs(n,t,o),l=l.next}while(l!==r)}qe(e,t,n);break;case 1:if(!ie&&(Xt(n,t),r=n.stateNode,typeof r.componentWillUnmount=="function"))try{r.props=n.memoizedProps,r.state=n.memoizedState,r.componentWillUnmount()}catch(a){Q(n,t,a)}qe(e,t,n);break;case 21:qe(e,t,n);break;case 22:n.mode&1?(ie=(r=ie)||n.memoizedState!==null,qe(e,t,n),ie=r):qe(e,t,n);break;default:qe(e,t,n)}}function qo(e){var t=e.updateQueue;if(t!==null){e.updateQueue=null;var n=e.stateNode;n===null&&(n=e.stateNode=new If),t.forEach(function(r){var l=Hf.bind(null,e,r);n.has(r)||(n.add(r),r.then(l,l))})}}function ze(e,t){var n=t.deletions;if(n!==null)for(var r=0;rl&&(l=o),r&=~s}if(r=l,r=Y()-r,r=(120>r?120:480>r?480:1080>r?1080:1920>r?1920:3e3>r?3e3:4320>r?4320:1960*Mf(r/1960))-r,10e?16:e,lt===null)var r=!1;else{if(e=lt,lt=null,ul=0,I&6)throw Error(k(331));var l=I;for(I|=4,C=e.current;C!==null;){var s=C,o=s.child;if(C.flags&16){var a=s.deletions;if(a!==null){for(var u=0;uY()-Ui?Et(e,0):$i|=n),ve(e,t)}function vc(e,t){t===0&&(e.mode&1?(t=yr,yr<<=1,!(yr&130023424)&&(yr=4194304)):t=1);var n=ue();e=Xe(e,t),e!==null&&(nr(e,t,n),ve(e,n))}function Wf(e){var t=e.memoizedState,n=0;t!==null&&(n=t.retryLane),vc(e,n)}function Hf(e,t){var n=0;switch(e.tag){case 13:var r=e.stateNode,l=e.memoizedState;l!==null&&(n=l.retryLane);break;case 19:r=e.stateNode;break;default:throw Error(k(314))}r!==null&&r.delete(t),vc(e,n)}var yc;yc=function(e,t,n){if(e!==null)if(e.memoizedProps!==t.pendingProps||he.current)pe=!0;else{if(!(e.lanes&n)&&!(t.flags&128))return pe=!1,Lf(e,t,n);pe=!!(e.flags&131072)}else pe=!1,B&&t.flags&1048576&&ku(t,el,t.index);switch(t.lanes=0,t.tag){case 2:var r=t.type;Mr(e,t),e=t.pendingProps;var l=ln(t,oe.current);tn(t,n),l=Ri(null,t,r,e,l,n);var s=Oi();return t.flags|=1,typeof l=="object"&&l!==null&&typeof l.render=="function"&&l.$$typeof===void 0?(t.tag=1,t.memoizedState=null,t.updateQueue=null,me(r)?(s=!0,qr(t)):s=!1,t.memoizedState=l.state!==null&&l.state!==void 0?l.state:null,_i(t),l.updater=kl,t.stateNode=l,l._reactInternals=t,Ms(t,r,e,n),t=As(null,t,r,!0,s,n)):(t.tag=0,B&&s&&xi(t),ae(null,t,l,n),t=t.child),t;case 16:r=t.elementType;e:{switch(Mr(e,t),e=t.pendingProps,l=r._init,r=l(r._payload),t.type=r,l=t.tag=Kf(r),e=Le(r,e),l){case 0:t=Us(null,t,r,e,n);break e;case 1:t=Go(null,t,r,e,n);break e;case 11:t=Qo(null,t,r,e,n);break e;case 14:t=Ko(null,t,r,Le(r.type,e),n);break e}throw Error(k(306,r,""))}return t;case 0:return r=t.type,l=t.pendingProps,l=t.elementType===r?l:Le(r,l),Us(e,t,r,l,n);case 1:return r=t.type,l=t.pendingProps,l=t.elementType===r?l:Le(r,l),Go(e,t,r,l,n);case 3:e:{if(ec(t),e===null)throw Error(k(387));r=t.pendingProps,s=t.memoizedState,l=s.element,_u(e,t),rl(t,r,null,n);var o=t.memoizedState;if(r=o.element,s.isDehydrated)if(s={element:r,isDehydrated:!1,cache:o.cache,pendingSuspenseBoundaries:o.pendingSuspenseBoundaries,transitions:o.transitions},t.updateQueue.baseState=s,t.memoizedState=s,t.flags&256){l=un(Error(k(423)),t),t=Yo(e,t,r,n,l);break e}else if(r!==l){l=un(Error(k(424)),t),t=Yo(e,t,r,n,l);break e}else for(ge=at(t.stateNode.containerInfo.firstChild),we=t,B=!0,Oe=null,n=Cu(t,null,r,n),t.child=n;n;)n.flags=n.flags&-3|4096,n=n.sibling;else{if(sn(),r===l){t=Je(e,t,n);break e}ae(e,t,r,n)}t=t.child}return t;case 5:return Pu(t),e===null&&Is(t),r=t.type,l=t.pendingProps,s=e!==null?e.memoizedProps:null,o=l.children,Ts(r,l)?o=null:s!==null&&Ts(r,s)&&(t.flags|=32),bu(e,t),ae(e,t,o,n),t.child;case 6:return e===null&&Is(t),null;case 13:return tc(e,t,n);case 4:return Pi(t,t.stateNode.containerInfo),r=t.pendingProps,e===null?t.child=on(t,null,r,n):ae(e,t,r,n),t.child;case 11:return r=t.type,l=t.pendingProps,l=t.elementType===r?l:Le(r,l),Qo(e,t,r,l,n);case 7:return ae(e,t,t.pendingProps,n),t.child;case 8:return ae(e,t,t.pendingProps.children,n),t.child;case 12:return ae(e,t,t.pendingProps.children,n),t.child;case 10:e:{if(r=t.type._context,l=t.pendingProps,s=t.memoizedProps,o=l.value,$(tl,r._currentValue),r._currentValue=o,s!==null)if(De(s.value,o)){if(s.children===l.children&&!he.current){t=Je(e,t,n);break e}}else for(s=t.child,s!==null&&(s.return=t);s!==null;){var a=s.dependencies;if(a!==null){o=s.child;for(var u=a.firstContext;u!==null;){if(u.context===r){if(s.tag===1){u=Ke(-1,n&-n),u.tag=2;var c=s.updateQueue;if(c!==null){c=c.shared;var m=c.pending;m===null?u.next=u:(u.next=m.next,m.next=u),c.pending=u}}s.lanes|=n,u=s.alternate,u!==null&&(u.lanes|=n),Fs(s.return,n,t),a.lanes|=n;break}u=u.next}}else if(s.tag===10)o=s.type===t.type?null:s.child;else if(s.tag===18){if(o=s.return,o===null)throw Error(k(341));o.lanes|=n,a=o.alternate,a!==null&&(a.lanes|=n),Fs(o,n,t),o=s.sibling}else o=s.child;if(o!==null)o.return=s;else for(o=s;o!==null;){if(o===t){o=null;break}if(s=o.sibling,s!==null){s.return=o.return,o=s;break}o=o.return}s=o}ae(e,t,l.children,n),t=t.child}return t;case 9:return l=t.type,r=t.pendingProps.children,tn(t,n),l=_e(l),r=r(l),t.flags|=1,ae(e,t,r,n),t.child;case 14:return r=t.type,l=Le(r,t.pendingProps),l=Le(r.type,l),Ko(e,t,r,l,n);case 15:return Zu(e,t,t.type,t.pendingProps,n);case 17:return r=t.type,l=t.pendingProps,l=t.elementType===r?l:Le(r,l),Mr(e,t),t.tag=1,me(r)?(e=!0,qr(t)):e=!1,tn(t,n),Yu(t,r,l),Ms(t,r,l,n),As(null,t,r,!0,e,n);case 19:return nc(e,t,n);case 22:return qu(e,t,n)}throw Error(k(156,t.tag))};function gc(e,t){return Qa(e,t)}function Qf(e,t,n,r){this.tag=e,this.key=n,this.sibling=this.child=this.return=this.stateNode=this.type=this.elementType=null,this.index=0,this.ref=null,this.pendingProps=t,this.dependencies=this.memoizedState=this.updateQueue=this.memoizedProps=null,this.mode=r,this.subtreeFlags=this.flags=0,this.deletions=null,this.childLanes=this.lanes=0,this.alternate=null}function Ce(e,t,n,r){return new Qf(e,t,n,r)}function Wi(e){return e=e.prototype,!(!e||!e.isReactComponent)}function Kf(e){if(typeof e=="function")return Wi(e)?1:0;if(e!=null){if(e=e.$$typeof,e===ai)return 11;if(e===ui)return 14}return 2}function ft(e,t){var n=e.alternate;return n===null?(n=Ce(e.tag,t,e.key,e.mode),n.elementType=e.elementType,n.type=e.type,n.stateNode=e.stateNode,n.alternate=e,e.alternate=n):(n.pendingProps=t,n.type=e.type,n.flags=0,n.subtreeFlags=0,n.deletions=null),n.flags=e.flags&14680064,n.childLanes=e.childLanes,n.lanes=e.lanes,n.child=e.child,n.memoizedProps=e.memoizedProps,n.memoizedState=e.memoizedState,n.updateQueue=e.updateQueue,t=e.dependencies,n.dependencies=t===null?null:{lanes:t.lanes,firstContext:t.firstContext},n.sibling=e.sibling,n.index=e.index,n.ref=e.ref,n}function Ar(e,t,n,r,l,s){var o=2;if(r=e,typeof e=="function")Wi(e)&&(o=1);else if(typeof e=="string")o=5;else e:switch(e){case At:return _t(n.children,l,s,t);case oi:o=8,l|=8;break;case os:return e=Ce(12,n,t,l|2),e.elementType=os,e.lanes=s,e;case as:return e=Ce(13,n,t,l),e.elementType=as,e.lanes=s,e;case us:return e=Ce(19,n,t,l),e.elementType=us,e.lanes=s,e;case Pa:return Nl(n,l,s,t);default:if(typeof e=="object"&&e!==null)switch(e.$$typeof){case Ea:o=10;break e;case _a:o=9;break e;case ai:o=11;break e;case ui:o=14;break e;case be:o=16,r=null;break e}throw Error(k(130,e==null?e:typeof e,""))}return t=Ce(o,n,t,l),t.elementType=e,t.type=r,t.lanes=s,t}function _t(e,t,n,r){return e=Ce(7,e,r,t),e.lanes=n,e}function Nl(e,t,n,r){return e=Ce(22,e,r,t),e.elementType=Pa,e.lanes=n,e.stateNode={isHidden:!1},e}function rs(e,t,n){return e=Ce(6,e,null,t),e.lanes=n,e}function ls(e,t,n){return t=Ce(4,e.children!==null?e.children:[],e.key,t),t.lanes=n,t.stateNode={containerInfo:e.containerInfo,pendingChildren:null,implementation:e.implementation},t}function Gf(e,t,n,r,l){this.tag=t,this.containerInfo=e,this.finishedWork=this.pingCache=this.current=this.pendingChildren=null,this.timeoutHandle=-1,this.callbackNode=this.pendingContext=this.context=null,this.callbackPriority=0,this.eventTimes=$l(0),this.expirationTimes=$l(-1),this.entangledLanes=this.finishedLanes=this.mutableReadLanes=this.expiredLanes=this.pingedLanes=this.suspendedLanes=this.pendingLanes=0,this.entanglements=$l(0),this.identifierPrefix=r,this.onRecoverableError=l,this.mutableSourceEagerHydrationData=null}function Hi(e,t,n,r,l,s,o,a,u){return e=new Gf(e,t,n,a,u),t===1?(t=1,s===!0&&(t|=8)):t=0,s=Ce(3,null,null,t),e.current=s,s.stateNode=e,s.memoizedState={element:r,isDehydrated:n,cache:null,transitions:null,pendingSuspenseBoundaries:null},_i(s),e}function Yf(e,t,n){var r=3"u"||typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE!="function"))try{__REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE(jc)}catch(e){console.error(e)}}jc(),ja.exports=ke;var bf=ja.exports,Sc,ia=bf;Sc=ia.createRoot,ia.hydrateRoot;const Nc="bv.access",Yi="bv.refresh";function qs(e){try{return localStorage.getItem(e)||""}catch{return""}}function oa(e,t){try{t?localStorage.setItem(e,t):localStorage.removeItem(e)}catch{}}function ir(){return{access:qs(Nc),refresh:qs(Yi)}}function fl(e,t){oa(Nc,e),oa(Yi,t)}function or(){fl("","")}function ep(){return!!qs(Yi)}class Pt extends Error{constructor(t,n,r){super(r),this.status=t,this.code=n}}let Nn=null;async function Tl(){return Nn||(Nn=(async()=>{const{refresh:e}=ir();if(!e)throw new Pt(401,"unauthorized","Signed out.");const t=await fetch("/api/auth/refresh",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({refresh_token:e})});if(!t.ok)throw or(),new Pt(t.status,"unauthorized","Your session has ended. Sign in again.");const n=await t.json();return fl(n.access_token,n.refresh_token),n})().finally(()=>{Nn=null}),Nn)}async function F(e,t,n,r=!0){const{access:l}=ir(),s={};l&&(s.Authorization="Bearer "+l),n!==void 0&&(s["Content-Type"]="application/json");const o=await fetch(t,{method:e,headers:s,body:n===void 0?void 0:JSON.stringify(n)});if(o.status===204)return null;const a=await o.text();let u=null;try{u=a?JSON.parse(a):null}catch{}if(o.ok)return u;const c=(u==null?void 0:u.error)||"";if(c==="token_expired"&&r)return await Tl(),F(e,t,n,!1);throw o.status===401&&or(),new Pt(o.status,c,(u==null?void 0:u.message)||`Something went wrong (${o.status}).`)}async function Cc(e,t=!0){const{access:n}=ir(),r=await fetch(e,{headers:n?{Authorization:"Bearer "+n}:{}});if(r.ok)return URL.createObjectURL(await r.blob());let l=null;try{l=await r.json()}catch{}const s=(l==null?void 0:l.error)||"";if(s==="token_expired"&&t)return await Tl(),Cc(e,!1);throw r.status===401&&or(),new Pt(r.status,s,(l==null?void 0:l.message)||`That picture could not be loaded (${r.status}).`)}function aa(){const e=navigator.userAgent||"",t=/Windows/.test(e)?"Windows":/Mac OS X|Macintosh/.test(e)?"Mac":/Android/.test(e)?"Android":/iPhone|iPad/.test(e)?"iOS":"Unknown";return`${/Edg\//.test(e)?"Edge":/Chrome\//.test(e)?"Chrome":/Safari\//.test(e)?"Safari":/Firefox\//.test(e)?"Firefox":"browser"} on ${t}`}const jt=e=>{const t=new URLSearchParams;for(const[r,l]of Object.entries(e||{}))l!=null&&l!==""&&t.set(r,l);const n=t.toString();return n?"?"+n:""},D={async login(e,t){const n=await fetch("/api/auth/login",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({email:e,password:t,device:aa()})}),r=await n.json().catch(()=>null);if(!n.ok)throw new Pt(n.status,(r==null?void 0:r.error)||"",(r==null?void 0:r.message)||"Could not sign in.");return fl(r.access_token,r.refresh_token),r.user},async previewInvitation(e){const t=await fetch("/api/auth/invitation"+jt({code:e})),n=await t.json().catch(()=>null);if(!t.ok)throw new Pt(t.status,(n==null?void 0:n.error)||"",(n==null?void 0:n.message)||"That invitation code is not valid.");return n},async register({code:e,full_name:t,password:n}){const r=await fetch("/api/auth/register",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({code:e,full_name:t,password:n,device:aa()})}),l=await r.json().catch(()=>null);if(!r.ok)throw new Pt(r.status,(l==null?void 0:l.error)||"",(l==null?void 0:l.message)||"Could not create the account.");return fl(l.access_token,l.refresh_token),l.user},async logout(){try{await F("POST","/api/auth/logout")}catch{}or()},me:()=>F("GET","/api/auth/me"),sites:()=>F("GET","/api/sites"),createSite:e=>F("POST","/api/sites",e),updateSite:(e,t)=>F("PATCH",`/api/sites/${encodeURIComponent(e)}`,t),deleteSite:e=>F("DELETE",`/api/sites/${encodeURIComponent(e)}`),arrivals:e=>F("GET","/api/visits"+jt(e)),visitors:(e,t=50)=>F("GET","/api/visitors"+jt({q:e,limit:t})),visitorHistory:(e,t=50)=>F("GET",`/api/visitors/${encodeURIComponent(e)}/history`+jt({limit:t})),saveProfile:(e,t)=>F("PUT",`/api/visitors/${encodeURIComponent(e)}/profile`,t),footfall:e=>F("GET","/api/reports/footfall"+jt(e)),conversion:e=>F("GET","/api/reports/conversion"+jt(e)),cameras:()=>F("GET","/api/cameras"),cameraSnapshot:e=>Cc(e),createCamera:(e,t)=>F("POST",`/api/sites/${encodeURIComponent(e)}/cameras`,t),updateCamera:(e,t)=>F("PATCH",`/api/cameras/${encodeURIComponent(e)}`,t),deleteCamera:e=>F("DELETE",`/api/cameras/${encodeURIComponent(e)}`),checkCamera:(e,t,n)=>F("POST",`/api/cameras/${encodeURIComponent(e)}/check`,{kind:t,...n?{seconds:n}:{}}),siteCheck:e=>F("GET",`/api/sites/${encodeURIComponent(e)}/check`),enrolmentCode:(e,t)=>F("POST",`/api/sites/${encodeURIComponent(e)}/enrolment-code`,t||{}),ask:e=>F("POST","/api/assistant",{history:e}),clients:()=>F("GET","/api/admin/clients"),createClient:e=>F("POST","/api/admin/clients",e),team:()=>F("GET","/api/team"),updateMember:(e,t)=>F("PATCH",`/api/team/${encodeURIComponent(e)}`,t),invitations:()=>F("GET","/api/team/invitations"),invite:e=>F("POST","/api/team/invitations",e),revokeInvitation:e=>F("DELETE",`/api/team/invitations/${encodeURIComponent(e)}`),sessions:()=>F("GET","/api/auth/sessions"),revokeSession:e=>F("DELETE",`/api/auth/sessions/${encodeURIComponent(e)}`),signOutOthers:()=>F("POST","/api/auth/sessions/revoke-others")};function tp({cursor:e,siteId:t,onPage:n,onError:r,signal:l}){let s=!1,o=e||"";return(async()=>{for(;!s;){try{const{access:u}=ir(),c=await fetch("/api/visits/stream"+jt({cursor:o,site_id:t}),{headers:{Authorization:"Bearer "+u,Accept:"text/event-stream"},signal:l});if(c.status===401){await Tl();continue}if(!c.ok||!c.body)throw new Error("stream unavailable");const m=c.body.getReader(),h=new TextDecoder;let v="";for(;!s;){const{value:y,done:x}=await m.read();if(x)break;v+=h.decode(y,{stream:!0});let g;for(;(g=v.indexOf(` -`))!==-1;){const P=v.slice(0,g);v=v.slice(g+2);for(const p of P.split(` -`))if(p.startsWith("id: "))o=p.slice(4).trim();else if(p.startsWith("data: "))try{n(JSON.parse(p.slice(6)))}catch{}}}}catch(u){if(s||l!=null&&l.aborted)return;r==null||r(u)}if(s)return;await new Promise(u=>setTimeout(u,3e3))}})(),()=>{s=!0}}function np({cameraId:e,img:t,onState:n,signal:r}){let l=!1;return(async()=>{for(;!l;){try{const{access:o}=ir(),a=await fetch(`/api/cameras/${e}/live`,{headers:{Authorization:"Bearer "+o,Accept:"text/event-stream"},signal:r});if(a.status===401){await Tl();continue}if(!a.ok||!a.body)throw new Error("live view unavailable");const u=a.body.getReader(),c=new TextDecoder;let m="";for(;!l;){const{value:h,done:v}=await u.read();if(v)break;m+=c.decode(h,{stream:!0});let y;for(;(y=m.indexOf(` +`))!==-1;){const N=v.slice(0,g);v=v.slice(g+2);for(const f of N.split(` +`))if(f.startsWith("id: "))o=f.slice(4).trim();else if(f.startsWith("data: "))try{n(JSON.parse(f.slice(6)))}catch{}}}}catch(u){if(s||l!=null&&l.aborted)return;r==null||r(u)}if(s)return;await new Promise(u=>setTimeout(u,3e3))}})(),()=>{s=!0}}function np({cameraId:e,img:t,onState:n,signal:r}){let l=!1;return(async()=>{for(;!l;){try{const{access:o}=ir(),a=await fetch(`/api/cameras/${e}/live`,{headers:{Authorization:"Bearer "+o,Accept:"text/event-stream"},signal:r});if(a.status===401){await Tl();continue}if(!a.ok||!a.body)throw new Error("live view unavailable");const u=a.body.getReader(),c=new TextDecoder;let m="";for(;!l;){const{value:h,done:v}=await u.read();if(v)break;m+=c.decode(h,{stream:!0});let y;for(;(y=m.indexOf(` -`))!==-1;){const x=m.slice(0,y);m=m.slice(y+2);let g="message",P="";for(const p of x.split(` -`))p.startsWith("event: ")?g=p.slice(7).trim():p.startsWith("data: ")&&(P=p.slice(6));g==="frame"&&P?(t.current&&(t.current.src="data:image/jpeg;base64,"+P),n==null||n("live")):g==="waiting"&&(n==null||n("waiting"))}}}catch{if(l||r!=null&&r.aborted)return;n==null||n("reconnecting")}if(l)return;await new Promise(o=>setTimeout(o,1500))}})(),()=>{l=!0}}function rp({onSignedIn:e}){const[t,n]=j.useState(!1);return t?i.jsx(sp,{onSignedIn:e,onCancel:()=>n(!1)}):i.jsx(lp,{onSignedIn:e,onJoin:()=>n(!0)})}function lp({onSignedIn:e,onJoin:t}){const[n,r]=j.useState(""),[l,s]=j.useState(""),[o,a]=j.useState(""),[u,c]=j.useState(!1),m=async h=>{h.preventDefault(),c(!0),a("");try{await D.login(n.trim(),l),e(await D.me())}catch(v){a(v.message),c(!1)}};return i.jsx("div",{className:"signin",children:i.jsxs("form",{className:"card",onSubmit:m,children:[i.jsx("span",{className:"mark big","aria-hidden":"true"}),i.jsx("h1",{children:"Behavision"}),i.jsx("p",{className:"sub",children:"Sign in to your company account."}),i.jsxs("label",{children:["Email",i.jsx("input",{type:"email",value:n,autoComplete:"username",autoFocus:!0,required:!0,onChange:h=>r(h.target.value),placeholder:"you@company.com"})]}),i.jsxs("label",{children:["Password",i.jsx("input",{type:"password",value:l,autoComplete:"current-password",required:!0,onChange:h=>s(h.target.value)})]}),o&&i.jsx("p",{className:"error",role:"alert",children:o}),i.jsx("button",{className:"primary",disabled:u||!n||!l,children:u?"Signing in…":"Sign in"}),i.jsxs("p",{className:"foot",children:["Been invited? ",i.jsx("button",{type:"button",className:"linkish",onClick:t,children:"Use your invitation code"})]})]})})}function sp({onSignedIn:e,onCancel:t}){const[n,r]=j.useState(""),[l,s]=j.useState(null),[o,a]=j.useState(""),[u,c]=j.useState(""),[m,h]=j.useState(""),[v,y]=j.useState(""),[x,g]=j.useState(!1),P=async d=>{d.preventDefault(),g(!0),y("");try{const f=await D.previewInvitation(n.trim());s(f),a(f.full_name||"")}catch(f){y(f.message)}finally{g(!1)}},p=async d=>{if(d.preventDefault(),u!==m){y("Those two passwords are not the same.");return}g(!0),y("");try{const f=await D.register({code:n.trim(),full_name:o,password:u});e(f)}catch(f){y(f.message),g(!1)}};return i.jsx("div",{className:"signin",children:i.jsxs("form",{className:"card",onSubmit:l?p:P,children:[i.jsx("span",{className:"mark big","aria-hidden":"true"}),i.jsx("h1",{children:l?`Join ${l.client_name}`:"Behavision"}),l?i.jsxs(i.Fragment,{children:[i.jsxs("p",{className:"sub",children:["You are joining as ",i.jsx("b",{children:l.role}),", signing in with"," ",i.jsx("code",{children:l.email}),". Choose a password only you know."]}),i.jsxs("label",{children:["Your name",i.jsx("input",{value:o,onChange:d=>a(d.target.value),autoFocus:!0,autoComplete:"name"})]}),i.jsxs("label",{children:["Password",i.jsx("input",{type:"password",value:u,required:!0,minLength:8,autoComplete:"new-password",onChange:d=>c(d.target.value)}),i.jsx("span",{className:"hint",children:"At least 8 characters. Longer is the only thing that helps."})]}),i.jsxs("label",{children:["Password again",i.jsx("input",{type:"password",value:m,required:!0,autoComplete:"new-password",onChange:d=>h(d.target.value)})]}),v&&i.jsx("p",{className:"error",role:"alert",children:v}),i.jsx("button",{className:"primary",disabled:x||!u||!m,children:x?"Creating your account…":"Create account and sign in"})]}):i.jsxs(i.Fragment,{children:[i.jsx("p",{className:"sub",children:"Enter the invitation code you were given."}),i.jsxs("label",{children:["Invitation code",i.jsx("input",{value:n,onChange:d=>r(d.target.value),autoFocus:!0,required:!0,autoComplete:"off",spellCheck:"false",placeholder:"ABCDEF-123456-GHIJKL-789012",className:"codefield"}),i.jsx("span",{className:"hint",children:"Dashes and capitals do not matter."})]}),v&&i.jsx("p",{className:"error",role:"alert",children:v}),i.jsx("button",{className:"primary",disabled:x||!n.trim(),children:x?"Checking…":"Continue"})]}),i.jsx("p",{className:"foot",children:i.jsx("button",{type:"button",className:"linkish",onClick:t,children:"Back to sign in"})})]})})}function It(e,t,n=[]){const[r,l]=j.useState(null),[s,o]=j.useState(null),[a,u]=j.useState(!0),c=j.useRef(!1),m=j.useRef(!0),h=j.useCallback(async()=>{if(!c.current){c.current=!0;try{const v=await e();if(!m.current)return;l(v),o(null)}catch(v){if(!m.current)return;o(v)}finally{c.current=!1,m.current&&u(!1)}}},n);return j.useEffect(()=>{if(m.current=!0,h(),!t)return()=>{m.current=!1};const v=setInterval(h,t);return()=>{m.current=!1,clearInterval(v)}},[h,t]),{data:r,error:s,loading:a,reload:h}}function ip(e){const[t,n]=j.useState(null);return j.useEffect(()=>{if(!e){n(null);return}let r=!0,l=null;return D.cameraSnapshot(e).then(s=>{if(!r){URL.revokeObjectURL(s);return}l=s,n(s)}).catch(()=>{r&&n(null)}),()=>{r=!1,l&&URL.revokeObjectURL(l)}},[e]),t}function Xi({image:e,url:t,alt:n}){const r=e?e.url:t,l=e&&!!e.auth||typeof r=="string"&&r.startsWith("/"),s=ip(l?r:null),o=l?s:r;return o?i.jsx("img",{src:o,alt:n,loading:"lazy"}):null}function op({site:e,user:t,onClose:n,onChanged:r}){const[l,s]=j.useState(null),[o,a]=j.useState(!1),[u,c]=j.useState(""),m=async()=>{a(!0),c(""),s(null);try{s(await D.siteCheck(e.site_id))}catch(h){c(h.message)}finally{a(!1)}};return i.jsx("div",{className:"overlay",onClick:n,children:i.jsxs("aside",{className:"drawer",onClick:h=>h.stopPropagation(),children:[i.jsxs("header",{className:"drawer-head",children:[i.jsxs("div",{children:[i.jsxs("h2",{children:["Is ",e.name," working?"]}),i.jsx("p",{className:"sub",children:"Checks the whole chain, from the shop’s PC to head office."})]}),i.jsx("button",{className:"ghost",onClick:n,children:"Close"})]}),i.jsxs("div",{className:"drawer-body",children:[!l&&!o&&i.jsxs(i.Fragment,{children:[i.jsx("p",{className:"sub",children:"Nothing is changed and no one is disturbed — this reads what the shop has already reported."}),i.jsx("button",{className:"primary",onClick:m,children:"Run the check"})]}),o&&i.jsxs("div",{className:"waiting",children:[i.jsx("span",{className:"spinner","aria-hidden":"true"}),i.jsx("b",{children:"Checking…"})]}),u&&i.jsx("p",{className:"error",role:"alert",children:u}),l&&i.jsxs(i.Fragment,{children:[i.jsx("div",{className:"banner "+(l.ok?"ok":"warn"),children:i.jsxs("div",{children:[i.jsx("b",{children:l.ok?"This shop is working.":"This shop needs attention."}),!l.ok&&i.jsx(i.Fragment,{children:" Work down the list — the first failure usually explains the rest."})]})}),i.jsx("ol",{className:"checklist",children:l.steps.map(h=>i.jsxs("li",{className:h.status,children:[i.jsx("span",{className:"mark","aria-hidden":"true",children:h.status==="pass"?"✓":h.status==="fail"?"✕":h.status==="warn"?"!":"–"}),i.jsxs("div",{children:[i.jsx("b",{children:h.name}),i.jsx("span",{className:"sub",children:h.detail}),h.advice&&i.jsx("span",{className:"advice-line",children:h.advice})]})]},h.name))}),i.jsx("button",{className:"ghost",onClick:m,children:"Check again"})]}),i.jsx(ap,{site:e}),i.jsx(dp,{site:e,user:t,onChanged:r,onClose:n})]})]})})}function ap({site:e}){const[t,n]=j.useState(null),[r,l]=j.useState(!1),[s,o]=j.useState(""),[a,u]=j.useState(""),c=async()=>{l(!0),o("");try{n(await D.enrolmentCode(e.site_id,{label:a.trim()}))}catch(m){o(m.message)}finally{l(!1)}};return i.jsxs("section",{className:"claim",children:[i.jsx("h3",{children:"Set up a shop PC"}),t?i.jsxs(i.Fragment,{children:[i.jsx("p",{className:"code","aria-live":"polite",children:t.code}),i.jsxs("p",{className:"sub",children:["Copy this now — it cannot be shown again. It works once, and stops working ",cp(t.expires_at),"."]}),i.jsxs("div",{className:"row",children:[i.jsx("button",{className:"ghost",onClick:()=>up(t.code),children:"Copy"}),i.jsx("button",{className:"ghost",onClick:()=>n(null),children:"Done"})]})]}):i.jsxs(i.Fragment,{children:[i.jsx("p",{className:"sub",children:"Creates a one-time code to type into Behavision on the shop’s computer. Use one for a new shop, a replacement PC, or a reinstall."}),i.jsxs("label",{className:"field",children:[i.jsx("span",{children:"What is this PC? (optional)"}),i.jsx("input",{value:a,placeholder:"counter PC",onChange:m=>u(m.target.value)})]}),s&&i.jsx("p",{className:"error",role:"alert",children:s}),i.jsx("button",{className:"ghost",onClick:c,disabled:r,children:r?"Creating…":"Create an installation code"})]})]})}function up(e){var t;try{(t=navigator.clipboard)==null||t.writeText(e)}catch{}}function cp(e){const t=new Date(e).getTime();if(Number.isNaN(t))return"shortly";const n=Math.round((t-Date.now())/864e5);return n<=0?"today":n===1?"tomorrow":`in ${n} days`}function dp({site:e,user:t,onChanged:n,onClose:r}){const[l,s]=j.useState(e.name),[o,a]=j.useState(e.timezone||"Asia/Kolkata"),[u,c]=j.useState(!1),[m,h]=j.useState(""),[v,y]=j.useState(!1),x=(t==null?void 0:t.role)==="owner"||(t==null?void 0:t.role)==="manager",g=(t==null?void 0:t.role)==="owner";if(!x)return null;const P=l.trim()!==e.name||o.trim()!==(e.timezone||"Asia/Kolkata"),p=async f=>{f.preventDefault(),c(!0),h("");try{await D.updateSite(e.slug||e.site_id,{name:l.trim(),timezone:o.trim()}),n==null||n()}catch(w){h(w.message)}finally{c(!1)}},d=async()=>{c(!0),h("");try{await D.deleteSite(e.slug||e.site_id),n==null||n(),r==null||r()}catch(f){h(f.message),y(!1)}finally{c(!1)}};return i.jsxs("section",{className:"claim",children:[i.jsx("h3",{children:"Shop details"}),i.jsxs("form",{onSubmit:p,children:[i.jsxs("label",{className:"field",children:[i.jsx("span",{children:"Name"}),i.jsx("input",{value:l,onChange:f=>s(f.target.value),required:!0})]}),i.jsxs("label",{className:"field",children:[i.jsx("span",{children:"Short name"}),i.jsx("input",{value:e.slug,readOnly:!0}),i.jsx("span",{className:"hint",children:"Fixed: the shop PC and the broker are keyed on it."})]}),i.jsxs("label",{className:"field",children:[i.jsx("span",{children:"Timezone"}),i.jsx("input",{value:o,onChange:f=>a(f.target.value)})]}),m&&i.jsx("p",{className:"error",role:"alert",children:m}),i.jsxs("div",{className:"row",children:[i.jsx("button",{className:"primary",disabled:u||!P,children:u?"Saving…":"Save"}),g&&!v&&i.jsx("button",{type:"button",className:"ghost danger",onClick:()=>y(!0),children:"Remove this shop…"})]})]}),v&&i.jsxs("div",{className:"banner warn",style:{marginTop:12},children:[i.jsxs("b",{children:["Remove ",e.name,"?"]}),i.jsx("p",{className:"sub",children:"Only possible while it has no cameras and no visits. A shop with history is kept."}),i.jsxs("div",{className:"row",children:[i.jsx("button",{className:"primary",disabled:u,onClick:d,children:u?"Removing…":"Yes, remove it"}),i.jsx("button",{className:"ghost",onClick:()=>y(!1),children:"Keep it"})]})]})]})}function fp({user:e}){const{data:t,error:n,loading:r,reload:l}=It(()=>D.sites(),2e4,[]),{data:s}=It(()=>D.cameras(),6e4,[]),[o,a]=j.useState(null),[u,c]=j.useState(!1),m=t||[],h=(e==null?void 0:e.role)==="owner";if(r&&!t)return i.jsx(ar,{});if(n)return i.jsx(ur,{error:n});if(!m.length&&!u)return i.jsx(xp,{canOpen:h,onOpen:()=>c(!0)});const v=m.map(p=>{const d=(s||[]).filter(f=>f.site_id===p.site_id);return{site:p,cams:d,verdict:hp(p,d)}}),y=p=>v.filter(d=>d.verdict.tone===p).length,x=y("bad"),g=y("warn"),P=y("idle");return i.jsxs(i.Fragment,{children:[i.jsxs("header",{className:"head",children:[i.jsx("h1",{children:"Shops"}),i.jsxs("p",{className:"sub",children:[m.length," ",m.length===1?"shop":"shops",x>0&&i.jsxs(i.Fragment,{children:[" · ",i.jsxs("b",{className:"bad",children:[x," not working"]})]}),g>0&&i.jsxs(i.Fragment,{children:[" · ",i.jsxs("b",{className:"warn",children:[g," needing attention"]})]}),P>0&&i.jsxs(i.Fragment,{children:[" · ",P," not set up yet"]}),!x&&!g&&!P&&i.jsxs(i.Fragment,{children:[" · ",i.jsx("b",{className:"ok",children:"all working"})]})]}),h&&i.jsx("button",{className:"primary",onClick:()=>c(!0),children:"Open a new shop"})]}),i.jsx("div",{className:"grid sites",children:v.map(p=>i.jsx(vp,{site:p.site,cams:p.cams,verdict:p.verdict,onCheck:()=>a(p.site)},p.site.site_id))}),o&&i.jsx(op,{site:o,user:e,onClose:()=>a(null),onChanged:l}),u&&i.jsx(pp,{onClose:()=>c(!1),onCreated:()=>{c(!1),l()}})]})}function pp({onClose:e,onCreated:t}){const[n,r]=j.useState({name:"",slug:"",timezone:"Asia/Kolkata"}),[l,s]=j.useState(!1),[o,a]=j.useState(""),u=m=>h=>r({...n,[m]:h.target.value}),c=async m=>{m.preventDefault(),s(!0),a("");try{t(await D.createSite({name:n.name,slug:n.slug||void 0,timezone:n.timezone}))}catch(h){a(h.message),s(!1)}};return i.jsx("div",{className:"overlay",onClick:e,children:i.jsxs("aside",{className:"drawer narrow",onClick:m=>m.stopPropagation(),children:[i.jsxs("header",{className:"drawer-head",children:[i.jsx("h2",{children:"Open a new shop"}),i.jsx("button",{className:"ghost",onClick:e,children:"Close"})]}),i.jsxs("form",{className:"drawer-body",onSubmit:c,children:[i.jsxs("label",{children:["Shop name",i.jsx("input",{value:n.name,onChange:u("name"),required:!0,autoFocus:!0,placeholder:"TeNext Bengaluru"})]}),i.jsxs("label",{children:["Short name",i.jsx("input",{value:n.slug,onChange:u("slug"),placeholder:"made from the name if left empty"}),i.jsx("span",{className:"hint",children:"Lower-case letters, digits and dashes. It becomes the shop PC’s identity and cannot be changed afterwards."})]}),i.jsxs("label",{children:["Timezone",i.jsx("input",{value:n.timezone,onChange:u("timezone"),required:!0}),i.jsx("span",{className:"hint",children:"Footfall is bucketed by the shop’s own clock, e.g. Asia/Kolkata."})]}),o&&i.jsx("p",{className:"error",role:"alert",children:o}),i.jsx("button",{className:"primary",disabled:l||!n.name.trim(),children:l?"Opening…":"Open shop"})]})]})})}function hp(e,t){const n=e.fraction_below_gate,r=e.cameras_total||t.length;return e.online?e.dropped>0?{tone:"bad",mark:"✕",words:`${e.dropped} visits lost and unrecoverable`}:r===0?{tone:"idle",mark:"+",headline:"Not set up",words:"No cameras set up yet"}:e.cameras_up===0?{tone:"bad",mark:"✕",words:"No cameras connected"}:e.cameras_up.5?{tone:"bad",mark:"✕",words:`${bs(n)} of faces too poor to recognise`}:n>.2?{tone:"warn",mark:"!",words:`${bs(n)} of faces too poor to recognise`}:e.queued>0?{tone:"warn",mark:"!",words:`${e.queued} visits waiting to upload`}:{tone:"ok",mark:"✓",words:`Working — ${r} ${r===1?"camera":"cameras"} connected`}:{tone:"bad",mark:"✕",headline:"Offline",words:`Offline — last heard from ${Ft(e.last_heartbeat_at)}`}}const mp={ok:"Working",warn:"Needs attention",bad:"Not working",idle:"Not set up"};function vp({site:e,cams:t,verdict:n,onCheck:r}){const l=e.fraction_below_gate,s=n.tone,o=n.headline||mp[s],a=yp(t),u=e.cameras_total||t.length;return i.jsxs("article",{className:"card site state-"+s,onClick:r,role:"button",tabIndex:0,onKeyDown:c=>c.key==="Enter"&&r(),children:[i.jsxs("div",{className:"shot",children:[a.url?i.jsx(Xi,{image:a,alt:`View inside ${e.name}`}):i.jsxs("div",{className:"noshot",children:[i.jsx(gp,{}),a.reason&&i.jsx("span",{children:a.reason})]}),i.jsxs("div",{className:"shot-over",children:[i.jsxs("div",{className:"shot-name",children:[i.jsx("b",{children:e.name}),i.jsx("span",{children:u>0?`${u} ${u===1?"camera":"cameras"}`:"No cameras yet"})]}),i.jsxs("span",{className:"status "+s,children:[i.jsx("i",{"aria-hidden":"true"}),o]})]}),a.at&&i.jsx("span",{className:"shot-age",children:Ft(a.at)})]}),i.jsxs("div",{className:"metrics",children:[i.jsx(ss,{label:"Cameras",value:u?`${e.cameras_up}/${u}`:"—",tone:u?e.cameras_up0?bs(1-l):"—",tone:l?l>.5?"bad":l>.2?"warn":"ok":"idle"}),i.jsx(ss,{label:"Last seen",value:Ft(e.last_heartbeat_at),tone:e.online?"ok":"bad"})]}),i.jsxs("div",{className:"verdict "+n.tone,children:[i.jsx("span",{className:"mark","aria-hidden":"true",children:n.mark}),i.jsx("span",{className:"words",children:n.words}),i.jsx("span",{className:"go","aria-hidden":"true",children:"→"})]})]})}function ss({label:e,value:t,tone:n}){return i.jsxs("div",{className:"metric",children:[i.jsx("b",{className:n,children:t}),i.jsx("span",{children:e})]})}function yp(e){var r;if(!e.length)return{};let t=null;for(const l of e)!((r=l.snapshot)!=null&&r.available)||!l.snapshot.url||(!t||(l.snapshot_at||"")>(t.snapshot_at||""))&&(t=l);return t?{...t.snapshot,at:t.snapshot_at}:{reason:e.map(l=>{var s;return(s=l.snapshot)==null?void 0:s.reason}).find(Boolean)||"No picture from this shop yet."}}function gp(){return i.jsxs("svg",{className:"shopmark",viewBox:"0 0 40 32","aria-hidden":"true",children:[i.jsx("path",{d:"M4 12h32v18H4z"}),i.jsx("path",{d:"M2 12l4-8h28l4 8"}),i.jsx("path",{d:"M15 30v-9h10v9"})]})}function bs(e){return`${Math.round(e*100)}%`}function Ft(e){if(!e)return"never";const t=new Date(e).getTime();if(Number.isNaN(t))return"—";const n=Math.max(0,(Date.now()-t)/1e3);if(n<90)return"just now";const r=Math.round(n/60);if(r<60)return`${r} min ago`;const l=Math.round(r/60);return l<48?`${l} h ago`:`${Math.round(l/24)} days ago`}function wp(e){if(!e)return"never";const t=new Date(e).getTime();if(Number.isNaN(t))return"—";const n=(t-Date.now())/1e3;if(n<=0)return"expired";const r=Math.round(n/60);if(r<60)return`in ${r} min`;const l=Math.round(r/60);return l<48?`in ${l} h`:`in ${Math.round(l/24)} days`}function ar(){return i.jsxs("div",{className:"state",children:[i.jsx("span",{className:"spinner","aria-hidden":"true"}),"Loading…"]})}function ur({error:e}){return i.jsx("div",{className:"state",children:i.jsx("p",{className:"error",role:"alert",children:e.message})})}function xp({canOpen:e,onOpen:t}){return i.jsxs("div",{className:"state",children:[i.jsx("h2",{children:"No shops yet"}),i.jsx("p",{className:"sub",children:e?"Open your first shop, then set up its PC and cameras from its card.":"The owner opens shops; they appear here once created."}),e&&i.jsx("button",{className:"primary",onClick:t,children:"Open a new shop"})]})}const ua=60;function kp(){const[e,t]=j.useState([]),[n,r]=j.useState("connecting"),[l,s]=j.useState(null),o=j.useRef(new Set);return j.useEffect(()=>{const a=new AbortController;let u=()=>{};return(async()=>{try{const c=await D.arrivals({limit:30}),m=c.arrivals||[];m.forEach(h=>o.current.add(h.visit_id)),t(m.slice().reverse()),r("live"),u=tp({cursor:c.cursor,signal:a.signal,onPage:h=>{const v=(h.arrivals||[]).filter(y=>!o.current.has(y.visit_id));v.length&&(v.forEach(y=>o.current.add(y.visit_id)),r("live"),t(y=>[...v.reverse(),...y].slice(0,ua)))},onError:()=>r("reconnecting")})}catch(c){s(c)}})(),()=>{a.abort(),u()}},[]),l?i.jsx(ur,{error:l}):n==="connecting"&&!e.length?i.jsx(ar,{}):i.jsxs(i.Fragment,{children:[i.jsxs("header",{className:"head",children:[i.jsx("h1",{children:"Live"}),i.jsxs("p",{className:"sub",children:[i.jsx("span",{className:"dot "+(n==="live"?"ok":"warn"),"aria-hidden":"true"}),n==="live"?"Connected":"Reconnecting…"," · ","last ",ua," arrivals"]})]}),e.length===0?i.jsxs("div",{className:"state",children:[i.jsx("h2",{children:"Nobody yet"}),i.jsx("p",{className:"sub",children:"Arrivals appear here the moment a camera recognises someone."})]}):i.jsx("ul",{className:"arrivals",children:e.map(a=>i.jsx(jp,{a},a.visit_id))})]})}function jp({a:e}){const t=e.name||e.label||"Unidentified";return i.jsxs("li",{className:"card arrival",children:[i.jsx(Sp,{image:e.image,name:t,customerRef:e.visitor_ref}),i.jsxs("div",{className:"who-col",children:[i.jsx("strong",{children:t}),i.jsxs("span",{className:"sub",children:[e.name&&e.visitor_ref?`${e.visitor_ref} · `:"",e.site,e.camera_id?` · ${e.camera_id}`:""," · ",Ft(e.occurred_at)]}),e.attributes&&i.jsx(Ep,{attrs:e.attributes})]}),e.is_new_visitor?i.jsx("span",{className:"pill new",children:"New"}):i.jsx("span",{className:"pill",children:"Returning"})]})}function Sp({image:e,name:t,customerRef:n}){return e!=null&&e.available?i.jsx("span",{className:"face",children:i.jsx(Xi,{image:e,alt:""})}):i.jsx("span",{className:"face initials",title:(e==null?void 0:e.reason)||"","aria-hidden":"true",children:Np(t,n)})}function Np(e,t){const n=/^Visitor (\d+)$/.exec(String(e).trim());if(n)return n[1];if(t){const r=/^V-(\d+)$/.exec(t);if(r)return r[1]}return Cp(e)}function Cp(e){const t=String(e).trim().split(/\s+/).filter(Boolean);return t.length?t.length===1?t[0].slice(0,2).toUpperCase():(t[0][0]+t[t.length-1][0]).toUpperCase():"?"}function Ep({attrs:e}){const t=[];return e.gender&&t.push(e.gender),e.age&&t.push(`~${Math.round(e.age)}`),e.emotion&&t.push(e.emotion),t.length?i.jsx("span",{className:"attrs",children:t.join(" · ")}):null}function _p({camera:e,onClose:t}){const n=j.useRef(null),[r,l]=j.useState("waiting"),[s,o]=j.useState(!1);j.useEffect(()=>{const c=new AbortController,m=np({cameraId:e.id,img:n,onState:v=>{l(v),v==="live"&&o(!1)},signal:c.signal}),h=setTimeout(()=>o(!0),12e3);return()=>{m(),c.abort(),clearTimeout(h)}},[e.id]);const a=e.connected===!1?"This camera was not connecting when the shop PC last reported. Check it is powered on and reachable on the shop’s network.":e.connected==null?"The shop PC has not reported on this camera yet. It may still be starting up.":"The shop PC is not sending frames. It may be offline, or its Behavision app may not be running.",u=s&&r!=="live"?a:{waiting:"Asking the shop PC…",live:"Live",reconnecting:"Reconnecting…"}[r];return i.jsx("div",{className:"overlay",onClick:t,children:i.jsxs("aside",{className:"drawer live",onClick:c=>c.stopPropagation(),children:[i.jsxs("header",{className:"drawer-head",children:[i.jsxs("div",{children:[i.jsx("h2",{children:e.label}),i.jsx("p",{className:"sub",children:e.site})]}),i.jsx("button",{className:"ghost",onClick:t,children:"Close"})]}),i.jsxs("div",{className:"drawer-body",children:[i.jsxs("div",{className:"liveshot",children:[i.jsx("img",{ref:n,alt:`Live view from ${e.label}`}),r!=="live"&&i.jsx("div",{className:"livewait",children:i.jsx("span",{children:s?"No picture yet":u})})]}),i.jsx("p",{className:"hint",style:{marginTop:10},children:r==="live"?"Live. The shop only uploads while this view is open.":u})]})]})})}const Br=[{id:"hikvision",label:"Hikvision",path:"/Streaming/Channels/101",note:"Channel 1, main stream. Use /Streaming/Channels/102 for the lower-quality sub stream."},{id:"dahua",label:"Dahua",path:"/cam/realmonitor?channel=1&subtype=0",note:"Channel 1, main stream. subtype=1 is the sub stream."},{id:"cpplus",label:"CP Plus",path:"/cam/realmonitor?channel=1&subtype=0",note:"CP Plus cameras use the Dahua stream path."},{id:"uniview",label:"Uniview",path:"/media/video1",note:"Some older Uniview models use /video1 instead."},{id:"tplink",label:"TP-Link / Tapo",path:"/stream1",note:"Tapo cameras need a separate camera account created in the Tapo app — your Tapo login will not work."},{id:"reolink",label:"Reolink",path:"/h264Preview_01_main",note:"Use /h264Preview_01_sub for the lower-quality stream."},{id:"amcrest",label:"Amcrest",path:"/cam/realmonitor?channel=1&subtype=0",note:"Amcrest cameras use the Dahua stream path."},{id:"axis",label:"Axis",path:"/axis-media/media.amp",note:""},{id:"onvif",label:"Other (ONVIF)",path:"/onvif1",note:"Many generic cameras answer here. If it does not work, look for “RTSP” in the camera’s own app."},{id:"manual",label:"I know the path",path:"",note:""}],ca=e=>Br.find(t=>t.id===e)||Br[Br.length-1],Pp=["Camera","Connection","Test","Walk past"];function Tp({sites:e,existing:t,onClose:n,onSaved:r}){var d;const l=!(t!=null&&t.id),[s,o]=j.useState(l?0:2),[a,u]=j.useState(t!=null&&t.id?t:null),[c,m]=j.useState({site_id:(t==null?void 0:t.site_id)||((d=e[0])==null?void 0:d.site_id)||"",make:"hikvision",label:(t==null?void 0:t.label)||"",host:(t==null?void 0:t.host)||"",port:(t==null?void 0:t.port)||554,path:(t==null?void 0:t.path)||"/Streaming/Channels/101",username:(t==null?void 0:t.username)||"",password:""}),[h,v]=j.useState(!1),[y,x]=j.useState(""),g=f=>w=>m(S=>({...S,[f]:w.target.value})),P=f=>{const w=ca(f.target.value);m(S=>({...S,make:w.id,path:w.path||S.path}))},p=async()=>{v(!0),x("");const f={};for(const[w,S]of Object.entries(c))w==="site_id"||w==="make"||S===""||S==null||(f[w]=w==="port"?Number(S):S);try{const w=a!=null&&a.id?await D.updateCamera(a.id,f):await D.createCamera(c.site_id,f);u(w),o(2),r==null||r(w,{keepOpen:!0})}catch(w){x(w.message)}finally{v(!1)}};return i.jsx("div",{className:"overlay",onClick:n,children:i.jsxs("aside",{className:"drawer wizard",onClick:f=>f.stopPropagation(),children:[i.jsxs("header",{className:"drawer-head",children:[i.jsxs("div",{children:[i.jsx("h2",{children:l?"Set up a camera":(a==null?void 0:a.label)||(t==null?void 0:t.label)}),i.jsx("p",{className:"sub",children:s<2?"The shop’s PC connects to the camera — nothing needs opening to the internet.":"Prove it works before you rely on it."})]}),i.jsx("button",{className:"ghost",onClick:n,children:"Close"})]}),i.jsx("ol",{className:"steps",children:Pp.map((f,w)=>i.jsxs("li",{className:w===s?"now":wi.jsx("option",{value:f.site_id,children:f.name},f.site_id))})]}),i.jsxs("label",{children:["What should staff call it?",i.jsx("input",{value:c.label,onChange:g("label"),placeholder:"Entrance",autoFocus:!0}),i.jsx("span",{className:"hint",children:"Visits are recorded against this name, so it cannot be changed later."})]}),i.jsxs("label",{children:["Make of camera",i.jsx("select",{value:c.make,onChange:P,children:Br.map(f=>i.jsx("option",{value:f.id,children:f.label},f.id))}),i.jsx("span",{className:"hint",children:ca(c.make).note||"This only fills in the stream path for you. You can change it on the next step."})]}),i.jsx("button",{className:"primary",disabled:!c.label.trim(),onClick:()=>o(1),children:"Next"})]}),s===1&&i.jsxs("div",{className:"drawer-body",children:[i.jsxs("label",{children:["Camera’s address on the shop’s network",i.jsx("input",{value:c.host,onChange:g("host"),placeholder:"192.168.0.138",autoFocus:!0}),i.jsx("span",{className:"hint",children:"Not a website address. It usually starts 192.168. — look in the camera’s own app, on its label, or in your router’s device list."})]}),i.jsxs("div",{className:"pair",children:[i.jsxs("label",{children:["Port",i.jsx("input",{type:"number",value:c.port,onChange:g("port")})]}),i.jsxs("label",{children:["Stream path",i.jsx("input",{value:c.path,onChange:g("path")})]})]}),i.jsxs("label",{children:["Camera username",i.jsx("input",{value:c.username,onChange:g("username"),placeholder:"admin",name:"camera-account",autoComplete:"off",autoCorrect:"off",autoCapitalize:"none",spellCheck:"false"}),i.jsx("span",{className:"hint",children:"The camera’s own login, not your Behavision one."})]}),i.jsxs("label",{children:["Camera password",i.jsx("input",{type:"password",value:c.password,onChange:g("password"),name:"camera-secret",autoComplete:"new-password",placeholder:a!=null&&a.has_password?"(unchanged)":""})]}),y&&i.jsx("p",{className:"error",role:"alert",children:y}),i.jsxs("div",{className:"pair",children:[i.jsx("button",{className:"ghost",onClick:()=>o(0),children:"Back"}),i.jsx("button",{className:"primary",disabled:h||!c.host.trim(),onClick:p,children:h?"Saving…":"Save and test"})]})]}),s>=2&&a&&i.jsx(zp,{camera:a,step:s,onStep:o,onUpdated:f=>{u(f),r==null||r(f,{keepOpen:!0})},onEdit:()=>o(1),onDone:n})]})})}function zp({camera:e,step:t,onStep:n,onUpdated:r,onEdit:l,onDone:s}){const[o,a]=j.useState(e),[u,c]=j.useState(!1),[m,h]=j.useState(""),v=j.useRef(null);j.useEffect(()=>a(e),[e]);const y=o.check||{},x=y.state==="requested"||y.state==="running";j.useEffect(()=>{if(!x)return;let p=!0;const d=async()=>{try{const w=(await D.cameras()).find(S=>S.id===o.id);p&&w&&(a(w),r==null||r(w))}catch{}};return v.current=setInterval(d,4e3),()=>{p=!1,clearInterval(v.current)}},[x,o.id]);const g=async(p,d)=>{c(!0),h("");try{const f=await D.checkCamera(o.id,p,d);a(f),r==null||r(f),n(p==="placement"?3:2)}catch(f){h(f.message)}finally{c(!1)}},P=y.kind==="connection"&&y.state==="done"&&y.ok;return i.jsx(i.Fragment,{children:i.jsxs("div",{className:"drawer-body",children:[t===2?i.jsxs(i.Fragment,{children:[i.jsx("h3",{children:"Can the shop’s PC reach this camera?"}),i.jsx("p",{className:"sub",children:"The PC opens the stream once and takes a single picture. Nothing is recorded."})]}):i.jsxs(i.Fragment,{children:[i.jsx("h3",{children:"Can it actually recognise a face?"}),i.jsxs("p",{className:"sub",children:["Someone needs to ",i.jsx("b",{children:"walk through the camera’s view and out of it"}),", the way a customer would. Standing still measures nothing — the check scores the best view of each person as they leave the frame, which is what recognition really uses."]})]}),x&&i.jsxs("div",{className:"waiting",children:[i.jsx("span",{className:"spinner","aria-hidden":"true"}),i.jsxs("div",{children:[i.jsx("b",{children:y.state==="running"?"Running on the shop’s PC…":"Waiting for the shop’s PC…"}),i.jsx("span",{className:"sub",children:y.state==="running"?"This takes about "+(y.seconds||25)+" seconds.":"It picks up the request within a couple of minutes."})]})]}),y.state==="done"&&i.jsx(Lp,{check:y}),m&&i.jsx("p",{className:"error",role:"alert",children:m}),i.jsx("div",{className:"pair",children:t===2?i.jsxs(i.Fragment,{children:[i.jsx("button",{className:"ghost",onClick:l,children:"Change details"}),i.jsx("button",{className:"primary",disabled:u||x,onClick:()=>g("connection"),children:y.state==="done"?"Test again":"Test connection"})]}):i.jsxs(i.Fragment,{children:[i.jsx("button",{className:"ghost",onClick:()=>n(2),children:"Back"}),i.jsx("button",{className:"primary",disabled:u||x,onClick:()=>g("placement",25),children:y.state==="done"?"Check again":"Start walk-past check"})]})}),t===2&&P&&!x&&i.jsx("button",{className:"primary",onClick:()=>n(3),children:"Next: prove it can recognise faces"}),t===3&&y.state==="done"&&!x&&i.jsx("button",{className:"ghost",onClick:s,children:"Finish"})]})})}function Lp({check:e}){var n,r,l;const t=e.ok?"ok":e.verdict==="marginal"?"warn":"bad";return i.jsxs("div",{className:"outcome "+t,children:[i.jsxs("div",{className:"outcome-head",children:[i.jsx("span",{className:"pill "+t,children:e.ok?"Working":"Not ready"}),i.jsx("b",{children:e.headline||(e.ok?"Working":"Could not be verified")})]}),((n=e.image)==null?void 0:n.available)&&i.jsx("img",{className:"proof",src:e.image.url,alt:"The view from this camera",loading:"lazy"}),((r=e.advice)==null?void 0:r.length)>0&&i.jsx("ul",{className:"advice",children:e.advice.map((s,o)=>i.jsx("li",{children:s},o))}),((l=e.detail)==null?void 0:l.faces)!=null&&i.jsxs("p",{className:"sub",children:[e.detail.faces," ",e.detail.faces===1?"person":"people"," walked past during the check."]})]})}function Rp(e){const t=e.check||{};return t.state==="requested"||t.state==="running"?{tone:"idle",mark:"…",words:"Checking now"}:t.state!=="done"?{tone:"idle",mark:"?",words:"Not checked yet"}:t.kind==="placement"?t.ok?{tone:"ok",mark:"✓",words:"Recognises faces here"}:{tone:"bad",mark:"✕",words:t.headline||"Cannot recognise faces here"}:t.ok?{tone:"warn",mark:"!",words:"Stream works — faces not checked yet"}:{tone:"bad",mark:"✕",words:t.headline||"Could not reach the camera"}}function Op({user:e}){const{data:t,error:n,loading:r,reload:l}=It(()=>D.cameras(),2e4,[]),{data:s}=It(()=>D.sites(),0,[]),[o,a]=j.useState(null),[u,c]=j.useState(null),m=["admin","owner","manager"].includes(e.role),h=t||[],v=h.filter(g=>g.connected).length,y=h.filter(g=>g.connected===!1).length,x=h.filter(g=>g.connected==null).length;return i.jsxs(i.Fragment,{children:[i.jsxs("header",{className:"head",children:[i.jsx("h1",{children:"Cameras"}),i.jsxs("p",{className:"sub",children:[h.length," ",h.length===1?"camera":"cameras",v>0&&i.jsxs(i.Fragment,{children:[" · ",i.jsxs("b",{className:"ok",children:[v," connected"]})]}),y>0&&i.jsxs(i.Fragment,{children:[" · ",i.jsxs("b",{className:"bad",children:[y," down"]})]}),x>0&&i.jsxs(i.Fragment,{children:[" · ",x," waiting for the shop PC"]})]}),m&&i.jsx("button",{className:"primary",onClick:()=>a({}),children:"Set up a camera"})]}),r&&!t?i.jsx(ar,{}):n?i.jsx(ur,{error:n}):h.length===0?i.jsxs("div",{className:"state",children:[i.jsx("h2",{children:"No cameras yet"}),i.jsx("p",{className:"sub",children:"Add one here and the shop’s PC will pick it up within a couple of minutes. Cameras already set up on a shop PC appear here on their own."})]}):i.jsx("div",{className:"grid cams",children:h.map(g=>i.jsx(Ip,{cam:g,canEdit:m,onEdit:()=>a(g),onWatch:()=>c(g)},g.id))}),o&&i.jsx(Tp,{existing:o.id?o:null,sites:s||[],onClose:()=>{a(null),l()},onSaved:(g,P)=>{P!=null&&P.keepOpen||a(null),l()}}),u&&i.jsx(_p,{camera:u,onClose:()=>c(null)})]})}function Ip({cam:e,canEdit:t,onEdit:n,onWatch:r}){var a,u;const l=e.connected==null?"idle":e.connected?"ok":"bad",s=e.connected==null?"Waiting for the shop PC":e.connected?"Connected":"Not connecting",o=Rp(e);return i.jsxs("article",{className:"card cam state-"+l,onClick:t?n:void 0,role:t?"button":void 0,tabIndex:t?0:void 0,onKeyDown:c=>t&&c.key==="Enter"&&n(),children:[i.jsxs("div",{className:"shot",children:[(a=e.snapshot)!=null&&a.available?i.jsx(Xi,{image:e.snapshot,alt:`View from ${e.label}`}):i.jsxs("div",{className:"noshot",children:[i.jsx("span",{className:"lens","aria-hidden":"true"}),((u=e.snapshot)==null?void 0:u.reason)||"No picture yet."]}),i.jsxs("div",{className:"shot-over",children:[i.jsxs("div",{className:"shot-name",children:[i.jsx("b",{children:e.label||e.camera_id}),i.jsx("span",{children:e.site})]}),i.jsxs("span",{className:"status "+l,children:[i.jsx("i",{"aria-hidden":"true"}),s]})]}),e.snapshot_at&&i.jsx("span",{className:"shot-age",children:Ft(e.snapshot_at)}),i.jsxs("button",{className:"watch",title:"Watch this camera now",onClick:c=>{c.stopPropagation(),r()},children:[i.jsx("i",{"aria-hidden":"true"}),"Live"]})]}),i.jsxs("div",{className:"verdict "+o.tone,children:[i.jsx("span",{className:"mark","aria-hidden":"true",children:o.mark}),i.jsx("span",{className:"words",children:o.words}),t&&i.jsx("span",{className:"go","aria-hidden":"true",children:"→"})]})]})}const Fp=["Is everything working today?","Why is footfall low at Chennai?","How many people came in last week?","Which cameras still need checking?"];function Dp({open:e,onClose:t}){const[n,r]=j.useState([]),[l,s]=j.useState(""),[o,a]=j.useState(!1),[u,c]=j.useState(!1),m=j.useRef(null),h=j.useRef(null);j.useEffect(()=>{var y;e&&((y=h.current)==null||y.focus())},[e]),j.useEffect(()=>{var y;(y=m.current)==null||y.scrollIntoView({behavior:"smooth",block:"end"})},[n,o]);const v=async y=>{const x=(y??l).trim();if(!x||o)return;const g=[...n,{role:"user",text:x}];r(g),s(""),a(!0);try{const P=await D.ask(g);r(p=>[...p,{role:"assistant",text:P.text,used:P.used}])}catch(P){P.code==="assistant_off"?c(!0):r(p=>[...p,{role:"assistant",text:P.message,failed:!0}])}finally{a(!1)}};return e?i.jsxs("aside",{className:"assistant",role:"complementary","aria-label":"Assistant",children:[i.jsxs("header",{className:"assistant-head",children:[i.jsxs("div",{children:[i.jsx("b",{children:"Loya"}),i.jsx("span",{className:"sub",children:"Your Behavision buddy — knows your shops, cameras and numbers."})]}),i.jsx("button",{className:"ghost",onClick:t,"aria-label":"Close assistant",children:"✕"})]}),i.jsxs("div",{className:"assistant-body",children:[u?i.jsx("p",{className:"sub pad",children:"Loya is not switched on for this server."}):n.length===0?i.jsxs("div",{className:"suggest",children:[i.jsx("p",{className:"sub",children:"Try asking:"}),Fp.map(y=>i.jsx("button",{className:"chip",onClick:()=>v(y),children:y},y))]}):n.map((y,x)=>{var g;return i.jsxs("div",{className:"bubble "+y.role+(y.failed?" failed":""),children:[y.text,((g=y.used)==null?void 0:g.length)>0&&i.jsxs("span",{className:"used",children:["looked at: ",y.used.map(Mp).join(", ")]})]},x)}),o&&i.jsxs("div",{className:"bubble assistant-thinking",children:[i.jsx("span",{className:"spinner","aria-hidden":"true"})," Looking…"]}),i.jsx("div",{ref:m})]}),!u&&i.jsxs("form",{className:"assistant-ask",onSubmit:y=>{y.preventDefault(),v()},children:[i.jsx("input",{ref:h,value:l,onChange:y=>s(y.target.value),placeholder:"Ask Loya…",disabled:o}),i.jsx("button",{className:"primary",disabled:o||!l.trim(),children:"Ask"})]})]}):null}function Mp(e){return{list_shops:"your shops",check_shop:"a shop check",list_cameras:"your cameras",check_camera:"a camera check",footfall:"footfall",sales:"sales",find_customer:"customer records"}[e]||e}function $p(){const{data:e,error:t,loading:n,reload:r}=It(()=>D.clients(),0,[]),[l,s]=j.useState(!1),[o,a]=j.useState(null),u=e||[];return i.jsxs(i.Fragment,{children:[i.jsxs("header",{className:"head",children:[i.jsx("h1",{children:"Companies"}),i.jsx("button",{className:"primary",onClick:()=>{a(null),s(!0)},children:"New company"})]}),o&&i.jsx(Ap,{result:o,onDismiss:()=>a(null)}),n&&!e?i.jsx(ar,{}):t?i.jsx(ur,{error:t}):u.length===0?i.jsxs("div",{className:"state",children:[i.jsx("h2",{children:"No companies yet"}),i.jsx("p",{className:"sub",children:"Create one, and its owner can sign in straight away."})]}):i.jsx("div",{className:"tablewrap",children:i.jsxs("table",{className:"rows",children:[i.jsx("thead",{children:i.jsxs("tr",{children:[i.jsx("th",{children:"Company"}),i.jsx("th",{children:"Short name"}),i.jsx("th",{children:"Sites"}),i.jsx("th",{children:"People"}),i.jsx("th",{children:"Created"})]})}),i.jsx("tbody",{children:u.map(c=>i.jsxs("tr",{children:[i.jsx("td",{children:i.jsx("strong",{children:c.name})}),i.jsx("td",{children:i.jsx("code",{children:c.slug})}),i.jsx("td",{className:"num",children:c.sites}),i.jsx("td",{className:"num",children:c.users}),i.jsx("td",{className:"sub",children:Ft(c.created_at)})]},c.id))})]})}),l&&i.jsx(Up,{onClose:()=>s(!1),onCreated:c=>{s(!1),a(c),r()}})]})}function Up({onClose:e,onCreated:t}){const[n,r]=j.useState({company_name:"",owner_name:"",owner_email:"",password:""}),[l,s]=j.useState(!1),[o,a]=j.useState(""),u=m=>h=>r({...n,[m]:h.target.value}),c=async m=>{m.preventDefault(),s(!0),a("");try{t(await D.createClient(n))}catch(h){a(h.message),s(!1)}};return i.jsx("div",{className:"overlay",onClick:e,children:i.jsxs("aside",{className:"drawer narrow",onClick:m=>m.stopPropagation(),children:[i.jsxs("header",{className:"drawer-head",children:[i.jsx("h2",{children:"New company"}),i.jsx("button",{className:"ghost",onClick:e,children:"Close"})]}),i.jsxs("form",{className:"drawer-body",onSubmit:c,children:[i.jsxs("label",{children:["Company name",i.jsx("input",{value:n.company_name,onChange:u("company_name"),required:!0,autoFocus:!0})]}),i.jsxs("label",{children:["Owner’s name",i.jsx("input",{value:n.owner_name,onChange:u("owner_name")})]}),i.jsxs("label",{children:["Owner’s email",i.jsx("input",{type:"email",value:n.owner_email,onChange:u("owner_email"),required:!0})]}),i.jsxs("label",{children:["Password",i.jsx("input",{type:"text",value:n.password,onChange:u("password"),placeholder:"Leave empty to generate one"}),i.jsx("span",{className:"hint",children:"Generated is better — a password you invent for someone else ends up weak and sent over chat."})]}),o&&i.jsx("p",{className:"error",role:"alert",children:o}),i.jsx("button",{className:"primary",disabled:l,children:l?"Creating…":"Create company"})]})]})})}function Ap({result:e,onDismiss:t}){return i.jsxs("div",{className:"banner ok credentials",children:[i.jsxs("div",{children:[i.jsxs("b",{children:[e.slug," created."]})," These sign-in details are shown once and cannot be recovered. Send them to the owner now.",i.jsxs("dl",{className:"creds",children:[i.jsxs("div",{children:[i.jsx("dt",{children:"Email"}),i.jsx("dd",{children:i.jsx("code",{children:e.owner_email})})]}),i.jsxs("div",{children:[i.jsx("dt",{children:"Password"}),i.jsx("dd",{children:i.jsx("code",{children:e.password})})]})]})]}),i.jsx("button",{className:"ghost",onClick:t,children:"Done"})]})}function Bp({user:e}){const t=It(()=>D.team(),0,[]),n=It(()=>D.invitations(),0,[]),[r,l]=j.useState(!1),[s,o]=j.useState(null),[a,u]=j.useState(""),[c,m]=j.useState(""),h=e.role==="owner"||e.role==="manager",v=t.data||[],y=n.data||[],x=async(g,P)=>{u(g),m("");try{await D.updateMember(g,P),t.reload()}catch(p){m(p.message)}finally{u("")}};return i.jsxs(i.Fragment,{children:[i.jsxs("header",{className:"head",children:[i.jsx("h1",{children:"Team"}),h&&i.jsx("button",{className:"primary",onClick:()=>{o(null),l(!0)},children:"Invite someone"})]}),s&&i.jsx(Wp,{invite:s,onDismiss:()=>o(null)}),c&&i.jsx("p",{className:"error",role:"alert",children:c}),t.loading&&!t.data?i.jsx(ar,{}):t.error?i.jsx(ur,{error:t.error}):i.jsx("div",{className:"tablewrap",children:i.jsxs("table",{className:"rows",children:[i.jsx("thead",{children:i.jsxs("tr",{children:[i.jsx("th",{children:"Name"}),i.jsx("th",{children:"Email"}),i.jsx("th",{children:"Role"}),i.jsx("th",{children:"Last signed in"}),h&&i.jsx("th",{})]})}),i.jsx("tbody",{children:v.map(g=>i.jsxs("tr",{className:g.active?"":"inactive",children:[i.jsxs("td",{children:[i.jsx("strong",{children:g.full_name||"—"}),!g.active&&i.jsx("span",{className:"pill muted",children:"No access"})]}),i.jsx("td",{children:i.jsx("code",{children:g.email})}),i.jsx("td",{children:h&&g.id!==e.id?i.jsxs("select",{value:g.role,disabled:a===g.id,onChange:P=>x(g.id,{role:P.target.value}),children:[i.jsx("option",{value:"staff",children:"Staff"}),i.jsx("option",{value:"manager",children:"Manager"}),e.role==="owner"&&i.jsx("option",{value:"owner",children:"Owner"})]}):i.jsx("span",{className:"role",children:g.role})}),i.jsx("td",{className:"sub",children:g.last_login_at?Ft(g.last_login_at):"Never"}),h&&i.jsx("td",{className:"right",children:g.id===e.id?null:g.active?i.jsx("button",{className:"ghost danger",disabled:a===g.id,onClick:()=>x(g.id,{active:!1}),children:"Remove access"}):i.jsx("button",{className:"ghost",disabled:a===g.id,onClick:()=>x(g.id,{active:!0}),children:"Restore"})})]},g.id))})]})}),h&&y.length>0&&i.jsxs("section",{className:"pending",children:[i.jsx("h2",{children:"Waiting to join"}),i.jsx("ul",{className:"invites",children:y.map(g=>i.jsxs("li",{className:"card invite",children:[i.jsxs("div",{children:[i.jsx("strong",{children:g.email}),i.jsxs("span",{className:"sub",children:["invited as ",g.role,g.invited_by?` by ${g.invited_by}`:""," · expires ",wp(g.expires_at)]})]}),i.jsx("button",{className:"ghost danger",onClick:async()=>{await D.revokeInvitation(g.id),n.reload()},children:"Withdraw"})]},g.id))})]}),r&&i.jsx(Vp,{canMintOwner:e.role==="owner",onClose:()=>l(!1),onDone:g=>{l(!1),o(g),n.reload()}})]})}function Vp({canMintOwner:e,onClose:t,onDone:n}){const[r,l]=j.useState({email:"",full_name:"",role:"staff"}),[s,o]=j.useState(!1),[a,u]=j.useState(""),c=h=>v=>l({...r,[h]:v.target.value}),m=async h=>{h.preventDefault(),o(!0),u("");try{n(await D.invite(r))}catch(v){u(v.message),o(!1)}};return i.jsx("div",{className:"overlay",onClick:t,children:i.jsxs("aside",{className:"drawer narrow",onClick:h=>h.stopPropagation(),children:[i.jsxs("header",{className:"drawer-head",children:[i.jsx("h2",{children:"Invite someone"}),i.jsx("button",{className:"ghost",onClick:t,children:"Close"})]}),i.jsxs("form",{className:"drawer-body",onSubmit:m,children:[i.jsxs("label",{children:["Their email",i.jsx("input",{type:"email",value:r.email,onChange:c("email"),required:!0,autoFocus:!0,autoComplete:"off",name:"invitee"}),i.jsx("span",{className:"hint",children:"This is the address they will sign in with, and it is fixed by the invitation — passing the code on cannot make it somebody else’s account."})]}),i.jsxs("label",{children:["Their name",i.jsx("input",{value:r.full_name,onChange:c("full_name"),autoComplete:"off",name:"invitee-name"})]}),i.jsxs("label",{children:["Role",i.jsxs("select",{value:r.role,onChange:c("role"),children:[i.jsx("option",{value:"staff",children:"Staff — see customers and shops"}),i.jsx("option",{value:"manager",children:"Manager — also set up cameras and invite people"}),e&&i.jsx("option",{value:"owner",children:"Owner — full control"})]})]}),a&&i.jsx("p",{className:"error",role:"alert",children:a}),i.jsx("button",{className:"primary",disabled:s,children:s?"Creating…":"Create invitation"})]})]})})}function Wp({invite:e,onDismiss:t}){return i.jsxs("div",{className:"banner ok credentials",children:[i.jsxs("div",{children:[i.jsxs("b",{children:["Invitation for ",e.email,"."]})," Give them this code. It is shown once, works once, and cannot be recovered.",i.jsxs("dl",{className:"creds",children:[i.jsxs("div",{children:[i.jsx("dt",{children:"Code"}),i.jsx("dd",{children:i.jsx("code",{className:"big",children:e.code})})]}),i.jsxs("div",{children:[i.jsx("dt",{children:"Role"}),i.jsx("dd",{children:e.role})]})]}),i.jsx("p",{className:"sub",children:"They open the app, choose “I have an invitation code”, and pick their own password. Nobody else ever sees it."})]}),i.jsx("button",{className:"ghost",onClick:t,children:"Done"})]})}const Hp=[{id:"sites",label:"Shops",View:fp},{id:"live",label:"Live",View:kp},{id:"cameras",label:"Cameras",View:Op},{id:"team",label:"Team",View:Bp}],Qp=[{id:"clients",label:"Companies",View:$p}];function Kp(){const[e,t]=j.useState(null),[n,r]=j.useState(!0),[l,s]=j.useState("sites"),[o,a]=j.useState(!1);if(j.useEffect(()=>{(async()=>{if(ep())try{t(await D.me())}catch{or()}r(!1)})()},[]),n)return i.jsxs("div",{className:"boot",children:[i.jsx("span",{className:"spinner","aria-hidden":"true"}),"Loading…"]});if(!e)return i.jsx(rp,{onSignedIn:t});const u=e.role==="admin"&&!e.client_id,c=u?Qp:Hp,m=c.find(y=>y.id===l)||c[0],h=m.View,v=async()=>{await D.logout(),t(null)};return i.jsxs("div",{className:"app",children:[i.jsxs("header",{className:"topbar",children:[i.jsxs("div",{className:"brand",children:[i.jsx("span",{className:"mark","aria-hidden":"true"}),i.jsxs("div",{children:[i.jsx("strong",{children:"Behavision"}),i.jsx("span",{className:"org",children:e.client_name||"Loyaly platform"})]})]}),i.jsx("nav",{className:"tabs",children:c.map(y=>i.jsx("button",{onClick:()=>s(y.id),"aria-current":m.id===y.id?"page":void 0,children:y.label},y.id))}),i.jsxs("div",{className:"who",children:[i.jsxs("button",{className:"ask-btn"+(o?" on":""),onClick:()=>a(y=>!y),title:"Ask Loya",children:[i.jsx("span",{className:"mark","aria-hidden":"true"})," Loya"]}),i.jsx("span",{className:"name",children:e.full_name||e.email}),i.jsx("span",{className:"role",children:u?"platform admin":e.role}),i.jsx("button",{className:"ghost",onClick:v,children:"Sign out"})]})]}),i.jsxs("div",{className:"with-assistant"+(o?" open":""),children:[i.jsx("main",{className:"page",children:i.jsx(h,{user:e})}),i.jsx(Dp,{open:o,onClose:()=>a(!1)})]})]})}Sc(document.getElementById("root")).render(i.jsx(Kp,{})); +`))!==-1;){const x=m.slice(0,y);m=m.slice(y+2);let g="message",N="";for(const f of x.split(` +`))f.startsWith("event: ")?g=f.slice(7).trim():f.startsWith("data: ")&&(N=f.slice(6));g==="frame"&&N?(t.current&&(t.current.src="data:image/jpeg;base64,"+N),n==null||n("live")):g==="waiting"&&(n==null||n("waiting"))}}}catch{if(l||r!=null&&r.aborted)return;n==null||n("reconnecting")}if(l)return;await new Promise(o=>setTimeout(o,1500))}})(),()=>{l=!0}}function rp({onSignedIn:e}){const[t,n]=j.useState(!1);return t?i.jsx(sp,{onSignedIn:e,onCancel:()=>n(!1)}):i.jsx(lp,{onSignedIn:e,onJoin:()=>n(!0)})}function lp({onSignedIn:e,onJoin:t}){const[n,r]=j.useState(""),[l,s]=j.useState(""),[o,a]=j.useState(""),[u,c]=j.useState(!1),m=async h=>{h.preventDefault(),c(!0),a("");try{await D.login(n.trim(),l),e(await D.me())}catch(v){a(v.message),c(!1)}};return i.jsx("div",{className:"signin",children:i.jsxs("form",{className:"card",onSubmit:m,children:[i.jsx("span",{className:"mark big","aria-hidden":"true"}),i.jsx("h1",{children:"Behavision"}),i.jsx("p",{className:"sub",children:"Sign in to your company account."}),i.jsxs("label",{children:["Email",i.jsx("input",{type:"email",value:n,autoComplete:"username",autoFocus:!0,required:!0,onChange:h=>r(h.target.value),placeholder:"you@company.com"})]}),i.jsxs("label",{children:["Password",i.jsx("input",{type:"password",value:l,autoComplete:"current-password",required:!0,onChange:h=>s(h.target.value)})]}),o&&i.jsx("p",{className:"error",role:"alert",children:o}),i.jsx("button",{className:"primary",disabled:u||!n||!l,children:u?"Signing in…":"Sign in"}),i.jsxs("p",{className:"foot",children:["Been invited? ",i.jsx("button",{type:"button",className:"linkish",onClick:t,children:"Use your invitation code"})]})]})})}function sp({onSignedIn:e,onCancel:t}){const[n,r]=j.useState(""),[l,s]=j.useState(null),[o,a]=j.useState(""),[u,c]=j.useState(""),[m,h]=j.useState(""),[v,y]=j.useState(""),[x,g]=j.useState(!1),N=async d=>{d.preventDefault(),g(!0),y("");try{const p=await D.previewInvitation(n.trim());s(p),a(p.full_name||"")}catch(p){y(p.message)}finally{g(!1)}},f=async d=>{if(d.preventDefault(),u!==m){y("Those two passwords are not the same.");return}g(!0),y("");try{const p=await D.register({code:n.trim(),full_name:o,password:u});e(p)}catch(p){y(p.message),g(!1)}};return i.jsx("div",{className:"signin",children:i.jsxs("form",{className:"card",onSubmit:l?f:N,children:[i.jsx("span",{className:"mark big","aria-hidden":"true"}),i.jsx("h1",{children:l?`Join ${l.client_name}`:"Behavision"}),l?i.jsxs(i.Fragment,{children:[i.jsxs("p",{className:"sub",children:["You are joining as ",i.jsx("b",{children:l.role}),", signing in with"," ",i.jsx("code",{children:l.email}),". Choose a password only you know."]}),i.jsxs("label",{children:["Your name",i.jsx("input",{value:o,onChange:d=>a(d.target.value),autoFocus:!0,autoComplete:"name"})]}),i.jsxs("label",{children:["Password",i.jsx("input",{type:"password",value:u,required:!0,minLength:8,autoComplete:"new-password",onChange:d=>c(d.target.value)}),i.jsx("span",{className:"hint",children:"At least 8 characters. Longer is the only thing that helps."})]}),i.jsxs("label",{children:["Password again",i.jsx("input",{type:"password",value:m,required:!0,autoComplete:"new-password",onChange:d=>h(d.target.value)})]}),v&&i.jsx("p",{className:"error",role:"alert",children:v}),i.jsx("button",{className:"primary",disabled:x||!u||!m,children:x?"Creating your account…":"Create account and sign in"})]}):i.jsxs(i.Fragment,{children:[i.jsx("p",{className:"sub",children:"Enter the invitation code you were given."}),i.jsxs("label",{children:["Invitation code",i.jsx("input",{value:n,onChange:d=>r(d.target.value),autoFocus:!0,required:!0,autoComplete:"off",spellCheck:"false",placeholder:"ABCDEF-123456-GHIJKL-789012",className:"codefield"}),i.jsx("span",{className:"hint",children:"Dashes and capitals do not matter."})]}),v&&i.jsx("p",{className:"error",role:"alert",children:v}),i.jsx("button",{className:"primary",disabled:x||!n.trim(),children:x?"Checking…":"Continue"})]}),i.jsx("p",{className:"foot",children:i.jsx("button",{type:"button",className:"linkish",onClick:t,children:"Back to sign in"})})]})})}function It(e,t,n=[]){const[r,l]=j.useState(null),[s,o]=j.useState(null),[a,u]=j.useState(!0),c=j.useRef(!1),m=j.useRef(!0),h=j.useCallback(async()=>{if(!c.current){c.current=!0;try{const v=await e();if(!m.current)return;l(v),o(null)}catch(v){if(!m.current)return;o(v)}finally{c.current=!1,m.current&&u(!1)}}},n);return j.useEffect(()=>{if(m.current=!0,h(),!t)return()=>{m.current=!1};const v=setInterval(h,t);return()=>{m.current=!1,clearInterval(v)}},[h,t]),{data:r,error:s,loading:a,reload:h}}function ip(e){const[t,n]=j.useState(null);return j.useEffect(()=>{if(!e){n(null);return}let r=!0,l=null;return D.cameraSnapshot(e).then(s=>{if(!r){URL.revokeObjectURL(s);return}l=s,n(s)}).catch(()=>{r&&n(null)}),()=>{r=!1,l&&URL.revokeObjectURL(l)}},[e]),t}function Xi({image:e,url:t,alt:n}){const r=e?e.url:t,l=e&&!!e.auth||typeof r=="string"&&r.startsWith("/"),s=ip(l?r:null),o=l?s:r;return o?i.jsx("img",{src:o,alt:n,loading:"lazy"}):null}function op({site:e,user:t,onClose:n,onChanged:r}){const[l,s]=j.useState(null),[o,a]=j.useState(!1),[u,c]=j.useState(""),m=async()=>{a(!0),c(""),s(null);try{s(await D.siteCheck(e.site_id))}catch(h){c(h.message)}finally{a(!1)}};return i.jsx("div",{className:"overlay",onClick:n,children:i.jsxs("aside",{className:"drawer",onClick:h=>h.stopPropagation(),children:[i.jsxs("header",{className:"drawer-head",children:[i.jsxs("div",{children:[i.jsxs("h2",{children:["Is ",e.name," working?"]}),i.jsx("p",{className:"sub",children:"Checks the whole chain, from the shop’s PC to head office."})]}),i.jsx("button",{className:"ghost",onClick:n,children:"Close"})]}),i.jsxs("div",{className:"drawer-body",children:[!l&&!o&&i.jsxs(i.Fragment,{children:[i.jsx("p",{className:"sub",children:"Nothing is changed and no one is disturbed — this reads what the shop has already reported."}),i.jsx("button",{className:"primary",onClick:m,children:"Run the check"})]}),o&&i.jsxs("div",{className:"waiting",children:[i.jsx("span",{className:"spinner","aria-hidden":"true"}),i.jsx("b",{children:"Checking…"})]}),u&&i.jsx("p",{className:"error",role:"alert",children:u}),l&&i.jsxs(i.Fragment,{children:[i.jsx("div",{className:"banner "+(l.ok?"ok":"warn"),children:i.jsxs("div",{children:[i.jsx("b",{children:l.ok?"This shop is working.":"This shop needs attention."}),!l.ok&&i.jsx(i.Fragment,{children:" Work down the list — the first failure usually explains the rest."})]})}),i.jsx("ol",{className:"checklist",children:l.steps.map(h=>i.jsxs("li",{className:h.status,children:[i.jsx("span",{className:"mark","aria-hidden":"true",children:h.status==="pass"?"✓":h.status==="fail"?"✕":h.status==="warn"?"!":"–"}),i.jsxs("div",{children:[i.jsx("b",{children:h.name}),i.jsx("span",{className:"sub",children:h.detail}),h.advice&&i.jsx("span",{className:"advice-line",children:h.advice})]})]},h.name))}),i.jsx("button",{className:"ghost",onClick:m,children:"Check again"})]}),i.jsx(ap,{site:e}),i.jsx(dp,{site:e,user:t,onChanged:r,onClose:n})]})]})})}function ap({site:e}){const[t,n]=j.useState(null),[r,l]=j.useState(!1),[s,o]=j.useState(""),[a,u]=j.useState(""),c=async()=>{l(!0),o("");try{n(await D.enrolmentCode(e.site_id,{label:a.trim()}))}catch(m){o(m.message)}finally{l(!1)}};return i.jsxs("section",{className:"claim",children:[i.jsx("h3",{children:"Set up a shop PC"}),t?i.jsxs(i.Fragment,{children:[i.jsx("p",{className:"code","aria-live":"polite",children:t.code}),i.jsxs("p",{className:"sub",children:["Copy this now — it cannot be shown again. It works once, and stops working ",cp(t.expires_at),"."]}),i.jsxs("div",{className:"row",children:[i.jsx("button",{className:"ghost",onClick:()=>up(t.code),children:"Copy"}),i.jsx("button",{className:"ghost",onClick:()=>n(null),children:"Done"})]})]}):i.jsxs(i.Fragment,{children:[i.jsx("p",{className:"sub",children:"Creates a one-time code to type into Behavision on the shop’s computer. Use one for a new shop, a replacement PC, or a reinstall."}),i.jsxs("label",{className:"field",children:[i.jsx("span",{children:"What is this PC? (optional)"}),i.jsx("input",{value:a,placeholder:"counter PC",onChange:m=>u(m.target.value)})]}),s&&i.jsx("p",{className:"error",role:"alert",children:s}),i.jsx("button",{className:"ghost",onClick:c,disabled:r,children:r?"Creating…":"Create an installation code"})]})]})}function up(e){var t;try{(t=navigator.clipboard)==null||t.writeText(e)}catch{}}function cp(e){const t=new Date(e).getTime();if(Number.isNaN(t))return"shortly";const n=Math.round((t-Date.now())/864e5);return n<=0?"today":n===1?"tomorrow":`in ${n} days`}function dp({site:e,user:t,onChanged:n,onClose:r}){const[l,s]=j.useState(e.name),[o,a]=j.useState(e.timezone||"Asia/Kolkata"),[u,c]=j.useState(!1),[m,h]=j.useState(""),[v,y]=j.useState(!1),x=(t==null?void 0:t.role)==="owner"||(t==null?void 0:t.role)==="manager",g=(t==null?void 0:t.role)==="owner";if(!x)return null;const N=l.trim()!==e.name||o.trim()!==(e.timezone||"Asia/Kolkata"),f=async p=>{p.preventDefault(),c(!0),h("");try{await D.updateSite(e.slug||e.site_id,{name:l.trim(),timezone:o.trim()}),n==null||n()}catch(w){h(w.message)}finally{c(!1)}},d=async()=>{c(!0),h("");try{await D.deleteSite(e.slug||e.site_id),n==null||n(),r==null||r()}catch(p){h(p.message),y(!1)}finally{c(!1)}};return i.jsxs("section",{className:"claim",children:[i.jsx("h3",{children:"Shop details"}),i.jsxs("form",{onSubmit:f,children:[i.jsxs("label",{className:"field",children:[i.jsx("span",{children:"Name"}),i.jsx("input",{value:l,onChange:p=>s(p.target.value),required:!0})]}),i.jsxs("label",{className:"field",children:[i.jsx("span",{children:"Short name"}),i.jsx("input",{value:e.slug,readOnly:!0}),i.jsx("span",{className:"hint",children:"Fixed: the shop PC and the broker are keyed on it."})]}),i.jsxs("label",{className:"field",children:[i.jsx("span",{children:"Timezone"}),i.jsx("input",{value:o,onChange:p=>a(p.target.value)})]}),m&&i.jsx("p",{className:"error",role:"alert",children:m}),i.jsxs("div",{className:"row",children:[i.jsx("button",{className:"primary",disabled:u||!N,children:u?"Saving…":"Save"}),g&&!v&&i.jsx("button",{type:"button",className:"ghost danger",onClick:()=>y(!0),children:"Remove this shop…"})]})]}),v&&i.jsxs("div",{className:"banner warn",style:{marginTop:12},children:[i.jsxs("b",{children:["Remove ",e.name,"?"]}),i.jsx("p",{className:"sub",children:"Only possible while it has no cameras and no visits. A shop with history is kept."}),i.jsxs("div",{className:"row",children:[i.jsx("button",{className:"primary",disabled:u,onClick:d,children:u?"Removing…":"Yes, remove it"}),i.jsx("button",{className:"ghost",onClick:()=>y(!1),children:"Keep it"})]})]})]})}function fp({user:e}){const{data:t,error:n,loading:r,reload:l}=It(()=>D.sites(),2e4,[]),{data:s}=It(()=>D.cameras(),6e4,[]),[o,a]=j.useState(null),[u,c]=j.useState(!1),m=t||[],h=(e==null?void 0:e.role)==="owner";if(r&&!t)return i.jsx(ar,{});if(n)return i.jsx(ur,{error:n});if(!m.length&&!u)return i.jsx(xp,{canOpen:h,onOpen:()=>c(!0)});const v=m.map(f=>{const d=(s||[]).filter(p=>p.site_id===f.site_id);return{site:f,cams:d,verdict:hp(f,d)}}),y=f=>v.filter(d=>d.verdict.tone===f).length,x=y("bad"),g=y("warn"),N=y("idle");return i.jsxs(i.Fragment,{children:[i.jsxs("header",{className:"head",children:[i.jsx("h1",{children:"Shops"}),i.jsxs("p",{className:"sub",children:[m.length," ",m.length===1?"shop":"shops",x>0&&i.jsxs(i.Fragment,{children:[" · ",i.jsxs("b",{className:"bad",children:[x," not working"]})]}),g>0&&i.jsxs(i.Fragment,{children:[" · ",i.jsxs("b",{className:"warn",children:[g," needing attention"]})]}),N>0&&i.jsxs(i.Fragment,{children:[" · ",N," not set up yet"]}),!x&&!g&&!N&&i.jsxs(i.Fragment,{children:[" · ",i.jsx("b",{className:"ok",children:"all working"})]})]}),h&&i.jsx("button",{className:"primary",onClick:()=>c(!0),children:"Open a new shop"})]}),i.jsx("div",{className:"grid sites",children:v.map(f=>i.jsx(vp,{site:f.site,cams:f.cams,verdict:f.verdict,onCheck:()=>a(f.site)},f.site.site_id))}),o&&i.jsx(op,{site:o,user:e,onClose:()=>a(null),onChanged:l}),u&&i.jsx(pp,{onClose:()=>c(!1),onCreated:()=>{c(!1),l()}})]})}function pp({onClose:e,onCreated:t}){const[n,r]=j.useState({name:"",slug:"",timezone:"Asia/Kolkata"}),[l,s]=j.useState(!1),[o,a]=j.useState(""),u=m=>h=>r({...n,[m]:h.target.value}),c=async m=>{m.preventDefault(),s(!0),a("");try{t(await D.createSite({name:n.name,slug:n.slug||void 0,timezone:n.timezone}))}catch(h){a(h.message),s(!1)}};return i.jsx("div",{className:"overlay",onClick:e,children:i.jsxs("aside",{className:"drawer narrow",onClick:m=>m.stopPropagation(),children:[i.jsxs("header",{className:"drawer-head",children:[i.jsx("h2",{children:"Open a new shop"}),i.jsx("button",{className:"ghost",onClick:e,children:"Close"})]}),i.jsxs("form",{className:"drawer-body",onSubmit:c,children:[i.jsxs("label",{children:["Shop name",i.jsx("input",{value:n.name,onChange:u("name"),required:!0,autoFocus:!0,placeholder:"TeNext Bengaluru"})]}),i.jsxs("label",{children:["Short name",i.jsx("input",{value:n.slug,onChange:u("slug"),placeholder:"made from the name if left empty"}),i.jsx("span",{className:"hint",children:"Lower-case letters, digits and dashes. It becomes the shop PC’s identity and cannot be changed afterwards."})]}),i.jsxs("label",{children:["Timezone",i.jsx("input",{value:n.timezone,onChange:u("timezone"),required:!0}),i.jsx("span",{className:"hint",children:"Footfall is bucketed by the shop’s own clock, e.g. Asia/Kolkata."})]}),o&&i.jsx("p",{className:"error",role:"alert",children:o}),i.jsx("button",{className:"primary",disabled:l||!n.name.trim(),children:l?"Opening…":"Open shop"})]})]})})}function hp(e,t){const n=e.fraction_below_gate,r=e.cameras_total||t.length;return e.online?e.dropped>0?{tone:"bad",mark:"✕",words:`${e.dropped} visits lost and unrecoverable`}:r===0?{tone:"idle",mark:"+",headline:"Not set up",words:"No cameras set up yet"}:e.cameras_up===0?{tone:"bad",mark:"✕",words:"No cameras connected"}:e.cameras_up.5?{tone:"bad",mark:"✕",words:`${bs(n)} of faces too poor to recognise`}:n>.2?{tone:"warn",mark:"!",words:`${bs(n)} of faces too poor to recognise`}:e.queued>0?{tone:"warn",mark:"!",words:`${e.queued} visits waiting to upload`}:{tone:"ok",mark:"✓",words:`Working — ${r} ${r===1?"camera":"cameras"} connected`}:{tone:"bad",mark:"✕",headline:"Offline",words:`Offline — last heard from ${Ft(e.last_heartbeat_at)}`}}const mp={ok:"Working",warn:"Needs attention",bad:"Not working",idle:"Not set up"};function vp({site:e,cams:t,verdict:n,onCheck:r}){const l=e.fraction_below_gate,s=n.tone,o=n.headline||mp[s],a=yp(t),u=e.cameras_total||t.length;return i.jsxs("article",{className:"card site state-"+s,onClick:r,role:"button",tabIndex:0,onKeyDown:c=>c.key==="Enter"&&r(),children:[i.jsxs("div",{className:"shot",children:[a.url?i.jsx(Xi,{image:a,alt:`View inside ${e.name}`}):i.jsxs("div",{className:"noshot",children:[i.jsx(gp,{}),a.reason&&i.jsx("span",{children:a.reason})]}),i.jsxs("div",{className:"shot-over",children:[i.jsxs("div",{className:"shot-name",children:[i.jsx("b",{children:e.name}),i.jsx("span",{children:u>0?`${u} ${u===1?"camera":"cameras"}`:"No cameras yet"})]}),i.jsxs("span",{className:"status "+s,children:[i.jsx("i",{"aria-hidden":"true"}),o]})]}),a.at&&i.jsx("span",{className:"shot-age",children:Ft(a.at)})]}),i.jsxs("div",{className:"metrics",children:[i.jsx(ss,{label:"Cameras",value:u?`${e.cameras_up}/${u}`:"—",tone:u?e.cameras_up0?bs(1-l):"—",tone:l?l>.5?"bad":l>.2?"warn":"ok":"idle"}),i.jsx(ss,{label:"Last seen",value:Ft(e.last_heartbeat_at),tone:e.online?"ok":"bad"})]}),i.jsxs("div",{className:"verdict "+n.tone,children:[i.jsx("span",{className:"mark","aria-hidden":"true",children:n.mark}),i.jsx("span",{className:"words",children:n.words}),i.jsx("span",{className:"go","aria-hidden":"true",children:"→"})]})]})}function ss({label:e,value:t,tone:n}){return i.jsxs("div",{className:"metric",children:[i.jsx("b",{className:n,children:t}),i.jsx("span",{children:e})]})}function yp(e){var r;if(!e.length)return{};let t=null;for(const l of e)!((r=l.snapshot)!=null&&r.available)||!l.snapshot.url||(!t||(l.snapshot_at||"")>(t.snapshot_at||""))&&(t=l);return t?{...t.snapshot,at:t.snapshot_at}:{reason:e.map(l=>{var s;return(s=l.snapshot)==null?void 0:s.reason}).find(Boolean)||"No picture from this shop yet."}}function gp(){return i.jsxs("svg",{className:"shopmark",viewBox:"0 0 40 32","aria-hidden":"true",children:[i.jsx("path",{d:"M4 12h32v18H4z"}),i.jsx("path",{d:"M2 12l4-8h28l4 8"}),i.jsx("path",{d:"M15 30v-9h10v9"})]})}function bs(e){return`${Math.round(e*100)}%`}function Ft(e){if(!e)return"never";const t=new Date(e).getTime();if(Number.isNaN(t))return"—";const n=Math.max(0,(Date.now()-t)/1e3);if(n<90)return"just now";const r=Math.round(n/60);if(r<60)return`${r} min ago`;const l=Math.round(r/60);return l<48?`${l} h ago`:`${Math.round(l/24)} days ago`}function wp(e){if(!e)return"never";const t=new Date(e).getTime();if(Number.isNaN(t))return"—";const n=(t-Date.now())/1e3;if(n<=0)return"expired";const r=Math.round(n/60);if(r<60)return`in ${r} min`;const l=Math.round(r/60);return l<48?`in ${l} h`:`in ${Math.round(l/24)} days`}function ar(){return i.jsxs("div",{className:"state",children:[i.jsx("span",{className:"spinner","aria-hidden":"true"}),"Loading…"]})}function ur({error:e}){return i.jsx("div",{className:"state",children:i.jsx("p",{className:"error",role:"alert",children:e.message})})}function xp({canOpen:e,onOpen:t}){return i.jsxs("div",{className:"state",children:[i.jsx("h2",{children:"No shops yet"}),i.jsx("p",{className:"sub",children:e?"Open your first shop, then set up its PC and cameras from its card.":"The owner opens shops; they appear here once created."}),e&&i.jsx("button",{className:"primary",onClick:t,children:"Open a new shop"})]})}const ua=60;function kp(){const[e,t]=j.useState([]),[n,r]=j.useState("connecting"),[l,s]=j.useState(null),o=j.useRef(new Set);return j.useEffect(()=>{const a=new AbortController;let u=()=>{};return(async()=>{try{const c=await D.arrivals({limit:30}),m=c.arrivals||[];m.forEach(h=>o.current.add(h.visit_id)),t(m.slice().reverse()),r("live"),u=tp({cursor:c.cursor,signal:a.signal,onPage:h=>{const v=(h.arrivals||[]).filter(y=>!o.current.has(y.visit_id));v.length&&(v.forEach(y=>o.current.add(y.visit_id)),r("live"),t(y=>[...v.reverse(),...y].slice(0,ua)))},onError:()=>r("reconnecting")})}catch(c){s(c)}})(),()=>{a.abort(),u()}},[]),l?i.jsx(ur,{error:l}):n==="connecting"&&!e.length?i.jsx(ar,{}):i.jsxs(i.Fragment,{children:[i.jsxs("header",{className:"head",children:[i.jsx("h1",{children:"Live"}),i.jsxs("p",{className:"sub",children:[i.jsx("span",{className:"dot "+(n==="live"?"ok":"warn"),"aria-hidden":"true"}),n==="live"?"Connected":"Reconnecting…"," · ","last ",ua," arrivals"]})]}),e.length===0?i.jsxs("div",{className:"state",children:[i.jsx("h2",{children:"Nobody yet"}),i.jsx("p",{className:"sub",children:"Arrivals appear here the moment a camera recognises someone."})]}):i.jsx("ul",{className:"arrivals",children:e.map(a=>i.jsx(jp,{a},a.visit_id))})]})}function jp({a:e}){const t=e.name||e.label||"Unidentified";return i.jsxs("li",{className:"card arrival",children:[i.jsx(Sp,{image:e.image,name:t,customerRef:e.visitor_ref}),i.jsxs("div",{className:"who-col",children:[i.jsx("strong",{children:t}),i.jsxs("span",{className:"sub",children:[e.name&&e.visitor_ref?`${e.visitor_ref} · `:"",e.site,e.camera_id?` · ${e.camera_id}`:""," · ",Ft(e.occurred_at)]}),e.attributes&&i.jsx(Ep,{attrs:e.attributes})]}),e.is_new_visitor?i.jsx("span",{className:"pill new",children:"New"}):i.jsx("span",{className:"pill",children:"Returning"})]})}function Sp({image:e,name:t,customerRef:n}){return e!=null&&e.available?i.jsx("span",{className:"face",children:i.jsx(Xi,{image:e,alt:""})}):i.jsx("span",{className:"face initials",title:(e==null?void 0:e.reason)||"","aria-hidden":"true",children:Np(t,n)})}function Np(e,t){const n=/^Visitor (\d+)$/.exec(String(e).trim());if(n)return n[1];if(t){const r=/^V-(\d+)$/.exec(t);if(r)return r[1]}return Cp(e)}function Cp(e){const t=String(e).trim().split(/\s+/).filter(Boolean);return t.length?t.length===1?t[0].slice(0,2).toUpperCase():(t[0][0]+t[t.length-1][0]).toUpperCase():"?"}function Ep({attrs:e}){const t=[];return e.gender&&t.push(e.gender),e.age&&t.push(`~${Math.round(e.age)}`),e.emotion&&t.push(e.emotion),t.length?i.jsx("span",{className:"attrs",children:t.join(" · ")}):null}function _p({camera:e,onClose:t}){const n=j.useRef(null),[r,l]=j.useState("waiting"),[s,o]=j.useState(!1);j.useEffect(()=>{const c=new AbortController,m=np({cameraId:e.id,img:n,onState:v=>{l(v),v==="live"&&o(!1)},signal:c.signal}),h=setTimeout(()=>o(!0),12e3);return()=>{m(),c.abort(),clearTimeout(h)}},[e.id]);const a=e.connected===!1?"This camera was not connecting when the shop PC last reported. Check it is powered on and reachable on the shop’s network.":e.connected==null?"The shop PC has not reported on this camera yet. It may still be starting up.":"The shop PC is not sending frames. It may be offline, or its Behavision app may not be running.",u=s&&r!=="live"?a:{waiting:"Asking the shop PC…",live:"Live",reconnecting:"Reconnecting…"}[r];return i.jsx("div",{className:"overlay",onClick:t,children:i.jsxs("aside",{className:"drawer live",onClick:c=>c.stopPropagation(),children:[i.jsxs("header",{className:"drawer-head",children:[i.jsxs("div",{children:[i.jsx("h2",{children:e.label}),i.jsx("p",{className:"sub",children:e.site})]}),i.jsx("button",{className:"ghost",onClick:t,children:"Close"})]}),i.jsxs("div",{className:"drawer-body",children:[i.jsxs("div",{className:"liveshot",children:[i.jsx("img",{ref:n,alt:`Live view from ${e.label}`}),r!=="live"&&i.jsx("div",{className:"livewait",children:i.jsx("span",{children:s?"No picture yet":u})})]}),i.jsx("p",{className:"hint",style:{marginTop:10},children:r==="live"?"Live. The shop only uploads while this view is open.":u})]})]})})}const Br=[{id:"hikvision",label:"Hikvision",path:"/Streaming/Channels/101",note:"Channel 1, main stream. Use /Streaming/Channels/102 for the lower-quality sub stream."},{id:"dahua",label:"Dahua",path:"/cam/realmonitor?channel=1&subtype=0",note:"Channel 1, main stream. subtype=1 is the sub stream."},{id:"cpplus",label:"CP Plus",path:"/cam/realmonitor?channel=1&subtype=0",note:"CP Plus cameras use the Dahua stream path."},{id:"uniview",label:"Uniview",path:"/media/video1",note:"Some older Uniview models use /video1 instead."},{id:"tplink",label:"TP-Link / Tapo",path:"/stream1",note:"Tapo cameras need a separate camera account created in the Tapo app — your Tapo login will not work."},{id:"reolink",label:"Reolink",path:"/h264Preview_01_main",note:"Use /h264Preview_01_sub for the lower-quality stream."},{id:"amcrest",label:"Amcrest",path:"/cam/realmonitor?channel=1&subtype=0",note:"Amcrest cameras use the Dahua stream path."},{id:"axis",label:"Axis",path:"/axis-media/media.amp",note:""},{id:"onvif",label:"Other (ONVIF)",path:"/onvif1",note:"Many generic cameras answer here. If it does not work, look for “RTSP” in the camera’s own app."},{id:"manual",label:"I know the path",path:"",note:""}],ca=e=>Br.find(t=>t.id===e)||Br[Br.length-1],Pp=["Camera","Connection","Test","Walk past"];function Tp({sites:e,existing:t,onClose:n,onSaved:r}){var d;const l=!(t!=null&&t.id),[s,o]=j.useState(l?0:2),[a,u]=j.useState(t!=null&&t.id?t:null),[c,m]=j.useState({site_id:(t==null?void 0:t.site_id)||((d=e[0])==null?void 0:d.site_id)||"",make:"hikvision",label:(t==null?void 0:t.label)||"",host:(t==null?void 0:t.host)||"",port:(t==null?void 0:t.port)||554,path:(t==null?void 0:t.path)||"/Streaming/Channels/101",username:(t==null?void 0:t.username)||"",password:""}),[h,v]=j.useState(!1),[y,x]=j.useState(""),g=p=>w=>m(S=>({...S,[p]:w.target.value})),N=p=>{const w=ca(p.target.value);m(S=>({...S,make:w.id,path:w.path||S.path}))},f=async()=>{v(!0),x("");const p={};for(const[w,S]of Object.entries(c))w==="site_id"||w==="make"||S===""||S==null||(p[w]=w==="port"?Number(S):S);try{const w=a!=null&&a.id?await D.updateCamera(a.id,p):await D.createCamera(c.site_id,p);u(w),o(2),r==null||r(w,{keepOpen:!0})}catch(w){x(w.message)}finally{v(!1)}};return i.jsx("div",{className:"overlay",onClick:n,children:i.jsxs("aside",{className:"drawer wizard",onClick:p=>p.stopPropagation(),children:[i.jsxs("header",{className:"drawer-head",children:[i.jsxs("div",{children:[i.jsx("h2",{children:l?"Set up a camera":(a==null?void 0:a.label)||(t==null?void 0:t.label)}),i.jsx("p",{className:"sub",children:s<2?"The shop’s PC connects to the camera — nothing needs opening to the internet.":"Prove it works before you rely on it."})]}),i.jsx("button",{className:"ghost",onClick:n,children:"Close"})]}),i.jsx("ol",{className:"steps",children:Pp.map((p,w)=>i.jsxs("li",{className:w===s?"now":wi.jsx("option",{value:p.site_id,children:p.name},p.site_id))})]}),i.jsxs("label",{children:["What should staff call it?",i.jsx("input",{value:c.label,onChange:g("label"),placeholder:"Entrance",autoFocus:!0}),i.jsx("span",{className:"hint",children:"Visits are recorded against this name, so it cannot be changed later."})]}),i.jsxs("label",{children:["Make of camera",i.jsx("select",{value:c.make,onChange:N,children:Br.map(p=>i.jsx("option",{value:p.id,children:p.label},p.id))}),i.jsx("span",{className:"hint",children:ca(c.make).note||"This only fills in the stream path for you. You can change it on the next step."})]}),i.jsx("button",{className:"primary",disabled:!c.label.trim(),onClick:()=>o(1),children:"Next"})]}),s===1&&i.jsxs("div",{className:"drawer-body",children:[i.jsxs("label",{children:["Camera’s address on the shop’s network",i.jsx("input",{value:c.host,onChange:g("host"),placeholder:"192.168.0.138",autoFocus:!0}),i.jsx("span",{className:"hint",children:"Not a website address. It usually starts 192.168. — look in the camera’s own app, on its label, or in your router’s device list."})]}),i.jsxs("div",{className:"pair",children:[i.jsxs("label",{children:["Port",i.jsx("input",{type:"number",value:c.port,onChange:g("port")})]}),i.jsxs("label",{children:["Stream path",i.jsx("input",{value:c.path,onChange:g("path")})]})]}),i.jsxs("label",{children:["Camera username",i.jsx("input",{value:c.username,onChange:g("username"),placeholder:"admin",name:"camera-account",autoComplete:"off",autoCorrect:"off",autoCapitalize:"none",spellCheck:"false"}),i.jsx("span",{className:"hint",children:"The camera’s own login, not your Behavision one."})]}),i.jsxs("label",{children:["Camera password",i.jsx("input",{type:"password",value:c.password,onChange:g("password"),name:"camera-secret",autoComplete:"new-password",placeholder:a!=null&&a.has_password?"(unchanged)":""})]}),y&&i.jsx("p",{className:"error",role:"alert",children:y}),i.jsxs("div",{className:"pair",children:[i.jsx("button",{className:"ghost",onClick:()=>o(0),children:"Back"}),i.jsx("button",{className:"primary",disabled:h||!c.host.trim(),onClick:f,children:h?"Saving…":"Save and test"})]})]}),s>=2&&a&&i.jsx(zp,{camera:a,step:s,onStep:o,onUpdated:p=>{u(p),r==null||r(p,{keepOpen:!0})},onEdit:()=>o(1),onDone:n})]})})}function zp({camera:e,step:t,onStep:n,onUpdated:r,onEdit:l,onDone:s}){const[o,a]=j.useState(e),[u,c]=j.useState(!1),[m,h]=j.useState(""),v=j.useRef(null);j.useEffect(()=>a(e),[e]);const y=o.check||{},x=y.state==="requested"||y.state==="running";j.useEffect(()=>{if(!x)return;let f=!0;const d=async()=>{try{const w=(await D.cameras()).find(S=>S.id===o.id);f&&w&&(a(w),r==null||r(w))}catch{}};return v.current=setInterval(d,4e3),()=>{f=!1,clearInterval(v.current)}},[x,o.id]);const g=async(f,d)=>{c(!0),h("");try{const p=await D.checkCamera(o.id,f,d);a(p),r==null||r(p),n(f==="placement"?3:2)}catch(p){h(p.message)}finally{c(!1)}},N=y.kind==="connection"&&y.state==="done"&&y.ok;return i.jsx(i.Fragment,{children:i.jsxs("div",{className:"drawer-body",children:[t===2?i.jsxs(i.Fragment,{children:[i.jsx("h3",{children:"Can the shop’s PC reach this camera?"}),i.jsx("p",{className:"sub",children:"The PC opens the stream once and takes a single picture. Nothing is recorded."})]}):i.jsxs(i.Fragment,{children:[i.jsx("h3",{children:"Can it actually recognise a face?"}),i.jsxs("p",{className:"sub",children:["Someone needs to ",i.jsx("b",{children:"walk through the camera’s view and out of it"}),", the way a customer would. Standing still measures nothing — the check scores the best view of each person as they leave the frame, which is what recognition really uses."]})]}),x&&i.jsxs("div",{className:"waiting",children:[i.jsx("span",{className:"spinner","aria-hidden":"true"}),i.jsxs("div",{children:[i.jsx("b",{children:y.state==="running"?"Running on the shop’s PC…":"Waiting for the shop’s PC…"}),i.jsx("span",{className:"sub",children:y.state==="running"?"This takes about "+(y.seconds||25)+" seconds.":"It picks up the request within a couple of minutes."})]})]}),y.state==="done"&&i.jsx(Lp,{check:y}),m&&i.jsx("p",{className:"error",role:"alert",children:m}),i.jsx("div",{className:"pair",children:t===2?i.jsxs(i.Fragment,{children:[i.jsx("button",{className:"ghost",onClick:l,children:"Change details"}),i.jsx("button",{className:"primary",disabled:u||x,onClick:()=>g("connection"),children:y.state==="done"?"Test again":"Test connection"})]}):i.jsxs(i.Fragment,{children:[i.jsx("button",{className:"ghost",onClick:()=>n(2),children:"Back"}),i.jsx("button",{className:"primary",disabled:u||x,onClick:()=>g("placement",25),children:y.state==="done"?"Check again":"Start walk-past check"})]})}),t===2&&N&&!x&&i.jsx("button",{className:"primary",onClick:()=>n(3),children:"Next: prove it can recognise faces"}),t===3&&y.state==="done"&&!x&&i.jsx("button",{className:"ghost",onClick:s,children:"Finish"})]})})}function Lp({check:e}){var n,r,l;const t=e.ok?"ok":e.verdict==="marginal"?"warn":"bad";return i.jsxs("div",{className:"outcome "+t,children:[i.jsxs("div",{className:"outcome-head",children:[i.jsx("span",{className:"pill "+t,children:e.ok?"Working":"Not ready"}),i.jsx("b",{children:e.headline||(e.ok?"Working":"Could not be verified")})]}),((n=e.image)==null?void 0:n.available)&&i.jsx("img",{className:"proof",src:e.image.url,alt:"The view from this camera",loading:"lazy"}),((r=e.advice)==null?void 0:r.length)>0&&i.jsx("ul",{className:"advice",children:e.advice.map((s,o)=>i.jsx("li",{children:s},o))}),((l=e.detail)==null?void 0:l.faces)!=null&&i.jsxs("p",{className:"sub",children:[e.detail.faces," ",e.detail.faces===1?"person":"people"," walked past during the check."]})]})}function Rp(e){const t=e.check||{};return t.state==="requested"||t.state==="running"?{tone:"idle",mark:"…",words:"Checking now"}:t.state!=="done"?{tone:"idle",mark:"?",words:"Not checked yet"}:t.kind==="placement"?t.ok?{tone:"ok",mark:"✓",words:"Recognises faces here"}:{tone:"bad",mark:"✕",words:t.headline||"Cannot recognise faces here"}:t.ok?{tone:"warn",mark:"!",words:"Stream works — faces not checked yet"}:{tone:"bad",mark:"✕",words:t.headline||"Could not reach the camera"}}function Op({user:e}){const{data:t,error:n,loading:r,reload:l}=It(()=>D.cameras(),2e4,[]),{data:s}=It(()=>D.sites(),0,[]),[o,a]=j.useState(null),[u,c]=j.useState(null),m=["admin","owner","manager"].includes(e.role),h=t||[],v=h.filter(N=>N.state==="connected").length,y=h.filter(N=>N.state==="not_connecting").length,x=h.filter(N=>N.state==="waiting").length,g=h.filter(N=>N.state==="stale").length;return i.jsxs(i.Fragment,{children:[i.jsxs("header",{className:"head",children:[i.jsx("h1",{children:"Cameras"}),i.jsxs("p",{className:"sub",children:[h.length," ",h.length===1?"camera":"cameras",v>0&&i.jsxs(i.Fragment,{children:[" · ",i.jsxs("b",{className:"ok",children:[v," connected"]})]}),g>0&&i.jsxs(i.Fragment,{children:[" · ",i.jsxs("b",{className:"warn",children:[g," not reporting"]})]}),y>0&&i.jsxs(i.Fragment,{children:[" · ",i.jsxs("b",{className:"bad",children:[y," down"]})]}),x>0&&i.jsxs(i.Fragment,{children:[" · ",x," waiting for the shop PC"]})]}),m&&i.jsx("button",{className:"primary",onClick:()=>a({}),children:"Set up a camera"})]}),r&&!t?i.jsx(ar,{}):n?i.jsx(ur,{error:n}):h.length===0?i.jsxs("div",{className:"state",children:[i.jsx("h2",{children:"No cameras yet"}),i.jsx("p",{className:"sub",children:"Add one here and the shop’s PC will pick it up within a couple of minutes. Cameras already set up on a shop PC appear here on their own."})]}):i.jsx("div",{className:"grid cams",children:h.map(N=>i.jsx(Ip,{cam:N,canEdit:m,onEdit:()=>a(N),onWatch:()=>c(N)},N.id))}),o&&i.jsx(Tp,{existing:o.id?o:null,sites:s||[],onClose:()=>{a(null),l()},onSaved:(N,f)=>{f!=null&&f.keepOpen||a(null),l()}}),u&&i.jsx(_p,{camera:u,onClose:()=>c(null)})]})}function Ip({cam:e,canEdit:t,onEdit:n,onWatch:r}){var a,u;const l={connected:"ok",not_connecting:"bad",stale:"warn"}[e.state]||"idle",s={connected:"Connected",not_connecting:"Not connecting",stale:"Not reporting"}[e.state]||"Waiting for the shop PC",o=Rp(e);return i.jsxs("article",{className:"card cam state-"+l,onClick:t?n:void 0,role:t?"button":void 0,tabIndex:t?0:void 0,onKeyDown:c=>t&&c.key==="Enter"&&n(),children:[i.jsxs("div",{className:"shot",children:[(a=e.snapshot)!=null&&a.available?i.jsx(Xi,{image:e.snapshot,alt:`View from ${e.label}`}):i.jsxs("div",{className:"noshot",children:[i.jsx("span",{className:"lens","aria-hidden":"true"}),((u=e.snapshot)==null?void 0:u.reason)||"No picture yet."]}),i.jsxs("div",{className:"shot-over",children:[i.jsxs("div",{className:"shot-name",children:[i.jsx("b",{children:e.label||e.camera_id}),i.jsx("span",{children:e.site})]}),i.jsxs("span",{className:"status "+l,children:[i.jsx("i",{"aria-hidden":"true"}),s]})]}),e.snapshot_at&&i.jsx("span",{className:"shot-age",children:Ft(e.snapshot_at)}),i.jsxs("button",{className:"watch",title:"Watch this camera now",onClick:c=>{c.stopPropagation(),r()},children:[i.jsx("i",{"aria-hidden":"true"}),"Live"]})]}),i.jsxs("div",{className:"verdict "+o.tone,children:[i.jsx("span",{className:"mark","aria-hidden":"true",children:o.mark}),i.jsx("span",{className:"words",children:o.words}),t&&i.jsx("span",{className:"go","aria-hidden":"true",children:"→"})]})]})}const Fp=["Is everything working today?","Why is footfall low at Chennai?","How many people came in last week?","Which cameras still need checking?"];function Dp({open:e,onClose:t}){const[n,r]=j.useState([]),[l,s]=j.useState(""),[o,a]=j.useState(!1),[u,c]=j.useState(!1),m=j.useRef(null),h=j.useRef(null);j.useEffect(()=>{var y;e&&((y=h.current)==null||y.focus())},[e]),j.useEffect(()=>{var y;(y=m.current)==null||y.scrollIntoView({behavior:"smooth",block:"end"})},[n,o]);const v=async y=>{const x=(y??l).trim();if(!x||o)return;const g=[...n,{role:"user",text:x}];r(g),s(""),a(!0);try{const N=await D.ask(g);r(f=>[...f,{role:"assistant",text:N.text,used:N.used}])}catch(N){N.code==="assistant_off"?c(!0):r(f=>[...f,{role:"assistant",text:N.message,failed:!0}])}finally{a(!1)}};return e?i.jsxs("aside",{className:"assistant",role:"complementary","aria-label":"Assistant",children:[i.jsxs("header",{className:"assistant-head",children:[i.jsxs("div",{children:[i.jsx("b",{children:"Loya"}),i.jsx("span",{className:"sub",children:"Your Behavision buddy — knows your shops, cameras and numbers."})]}),i.jsx("button",{className:"ghost",onClick:t,"aria-label":"Close assistant",children:"✕"})]}),i.jsxs("div",{className:"assistant-body",children:[u?i.jsx("p",{className:"sub pad",children:"Loya is not switched on for this server."}):n.length===0?i.jsxs("div",{className:"suggest",children:[i.jsx("p",{className:"sub",children:"Try asking:"}),Fp.map(y=>i.jsx("button",{className:"chip",onClick:()=>v(y),children:y},y))]}):n.map((y,x)=>{var g;return i.jsxs("div",{className:"bubble "+y.role+(y.failed?" failed":""),children:[y.text,((g=y.used)==null?void 0:g.length)>0&&i.jsxs("span",{className:"used",children:["looked at: ",y.used.map(Mp).join(", ")]})]},x)}),o&&i.jsxs("div",{className:"bubble assistant-thinking",children:[i.jsx("span",{className:"spinner","aria-hidden":"true"})," Looking…"]}),i.jsx("div",{ref:m})]}),!u&&i.jsxs("form",{className:"assistant-ask",onSubmit:y=>{y.preventDefault(),v()},children:[i.jsx("input",{ref:h,value:l,onChange:y=>s(y.target.value),placeholder:"Ask Loya…",disabled:o}),i.jsx("button",{className:"primary",disabled:o||!l.trim(),children:"Ask"})]})]}):null}function Mp(e){return{list_shops:"your shops",check_shop:"a shop check",list_cameras:"your cameras",check_camera:"a camera check",footfall:"footfall",sales:"sales",find_customer:"customer records"}[e]||e}function $p(){const{data:e,error:t,loading:n,reload:r}=It(()=>D.clients(),0,[]),[l,s]=j.useState(!1),[o,a]=j.useState(null),u=e||[];return i.jsxs(i.Fragment,{children:[i.jsxs("header",{className:"head",children:[i.jsx("h1",{children:"Companies"}),i.jsx("button",{className:"primary",onClick:()=>{a(null),s(!0)},children:"New company"})]}),o&&i.jsx(Ap,{result:o,onDismiss:()=>a(null)}),n&&!e?i.jsx(ar,{}):t?i.jsx(ur,{error:t}):u.length===0?i.jsxs("div",{className:"state",children:[i.jsx("h2",{children:"No companies yet"}),i.jsx("p",{className:"sub",children:"Create one, and its owner can sign in straight away."})]}):i.jsx("div",{className:"tablewrap",children:i.jsxs("table",{className:"rows",children:[i.jsx("thead",{children:i.jsxs("tr",{children:[i.jsx("th",{children:"Company"}),i.jsx("th",{children:"Short name"}),i.jsx("th",{children:"Sites"}),i.jsx("th",{children:"People"}),i.jsx("th",{children:"Created"})]})}),i.jsx("tbody",{children:u.map(c=>i.jsxs("tr",{children:[i.jsx("td",{children:i.jsx("strong",{children:c.name})}),i.jsx("td",{children:i.jsx("code",{children:c.slug})}),i.jsx("td",{className:"num",children:c.sites}),i.jsx("td",{className:"num",children:c.users}),i.jsx("td",{className:"sub",children:Ft(c.created_at)})]},c.id))})]})}),l&&i.jsx(Up,{onClose:()=>s(!1),onCreated:c=>{s(!1),a(c),r()}})]})}function Up({onClose:e,onCreated:t}){const[n,r]=j.useState({company_name:"",owner_name:"",owner_email:"",password:""}),[l,s]=j.useState(!1),[o,a]=j.useState(""),u=m=>h=>r({...n,[m]:h.target.value}),c=async m=>{m.preventDefault(),s(!0),a("");try{t(await D.createClient(n))}catch(h){a(h.message),s(!1)}};return i.jsx("div",{className:"overlay",onClick:e,children:i.jsxs("aside",{className:"drawer narrow",onClick:m=>m.stopPropagation(),children:[i.jsxs("header",{className:"drawer-head",children:[i.jsx("h2",{children:"New company"}),i.jsx("button",{className:"ghost",onClick:e,children:"Close"})]}),i.jsxs("form",{className:"drawer-body",onSubmit:c,children:[i.jsxs("label",{children:["Company name",i.jsx("input",{value:n.company_name,onChange:u("company_name"),required:!0,autoFocus:!0})]}),i.jsxs("label",{children:["Owner’s name",i.jsx("input",{value:n.owner_name,onChange:u("owner_name")})]}),i.jsxs("label",{children:["Owner’s email",i.jsx("input",{type:"email",value:n.owner_email,onChange:u("owner_email"),required:!0})]}),i.jsxs("label",{children:["Password",i.jsx("input",{type:"text",value:n.password,onChange:u("password"),placeholder:"Leave empty to generate one"}),i.jsx("span",{className:"hint",children:"Generated is better — a password you invent for someone else ends up weak and sent over chat."})]}),o&&i.jsx("p",{className:"error",role:"alert",children:o}),i.jsx("button",{className:"primary",disabled:l,children:l?"Creating…":"Create company"})]})]})})}function Ap({result:e,onDismiss:t}){return i.jsxs("div",{className:"banner ok credentials",children:[i.jsxs("div",{children:[i.jsxs("b",{children:[e.slug," created."]})," These sign-in details are shown once and cannot be recovered. Send them to the owner now.",i.jsxs("dl",{className:"creds",children:[i.jsxs("div",{children:[i.jsx("dt",{children:"Email"}),i.jsx("dd",{children:i.jsx("code",{children:e.owner_email})})]}),i.jsxs("div",{children:[i.jsx("dt",{children:"Password"}),i.jsx("dd",{children:i.jsx("code",{children:e.password})})]})]})]}),i.jsx("button",{className:"ghost",onClick:t,children:"Done"})]})}function Bp({user:e}){const t=It(()=>D.team(),0,[]),n=It(()=>D.invitations(),0,[]),[r,l]=j.useState(!1),[s,o]=j.useState(null),[a,u]=j.useState(""),[c,m]=j.useState(""),h=e.role==="owner"||e.role==="manager",v=t.data||[],y=n.data||[],x=async(g,N)=>{u(g),m("");try{await D.updateMember(g,N),t.reload()}catch(f){m(f.message)}finally{u("")}};return i.jsxs(i.Fragment,{children:[i.jsxs("header",{className:"head",children:[i.jsx("h1",{children:"Team"}),h&&i.jsx("button",{className:"primary",onClick:()=>{o(null),l(!0)},children:"Invite someone"})]}),s&&i.jsx(Wp,{invite:s,onDismiss:()=>o(null)}),c&&i.jsx("p",{className:"error",role:"alert",children:c}),t.loading&&!t.data?i.jsx(ar,{}):t.error?i.jsx(ur,{error:t.error}):i.jsx("div",{className:"tablewrap",children:i.jsxs("table",{className:"rows",children:[i.jsx("thead",{children:i.jsxs("tr",{children:[i.jsx("th",{children:"Name"}),i.jsx("th",{children:"Email"}),i.jsx("th",{children:"Role"}),i.jsx("th",{children:"Last signed in"}),h&&i.jsx("th",{})]})}),i.jsx("tbody",{children:v.map(g=>i.jsxs("tr",{className:g.active?"":"inactive",children:[i.jsxs("td",{children:[i.jsx("strong",{children:g.full_name||"—"}),!g.active&&i.jsx("span",{className:"pill muted",children:"No access"})]}),i.jsx("td",{children:i.jsx("code",{children:g.email})}),i.jsx("td",{children:h&&g.id!==e.id?i.jsxs("select",{value:g.role,disabled:a===g.id,onChange:N=>x(g.id,{role:N.target.value}),children:[i.jsx("option",{value:"staff",children:"Staff"}),i.jsx("option",{value:"manager",children:"Manager"}),e.role==="owner"&&i.jsx("option",{value:"owner",children:"Owner"})]}):i.jsx("span",{className:"role",children:g.role})}),i.jsx("td",{className:"sub",children:g.last_login_at?Ft(g.last_login_at):"Never"}),h&&i.jsx("td",{className:"right",children:g.id===e.id?null:g.active?i.jsx("button",{className:"ghost danger",disabled:a===g.id,onClick:()=>x(g.id,{active:!1}),children:"Remove access"}):i.jsx("button",{className:"ghost",disabled:a===g.id,onClick:()=>x(g.id,{active:!0}),children:"Restore"})})]},g.id))})]})}),h&&y.length>0&&i.jsxs("section",{className:"pending",children:[i.jsx("h2",{children:"Waiting to join"}),i.jsx("ul",{className:"invites",children:y.map(g=>i.jsxs("li",{className:"card invite",children:[i.jsxs("div",{children:[i.jsx("strong",{children:g.email}),i.jsxs("span",{className:"sub",children:["invited as ",g.role,g.invited_by?` by ${g.invited_by}`:""," · expires ",wp(g.expires_at)]})]}),i.jsx("button",{className:"ghost danger",onClick:async()=>{await D.revokeInvitation(g.id),n.reload()},children:"Withdraw"})]},g.id))})]}),r&&i.jsx(Vp,{canMintOwner:e.role==="owner",onClose:()=>l(!1),onDone:g=>{l(!1),o(g),n.reload()}})]})}function Vp({canMintOwner:e,onClose:t,onDone:n}){const[r,l]=j.useState({email:"",full_name:"",role:"staff"}),[s,o]=j.useState(!1),[a,u]=j.useState(""),c=h=>v=>l({...r,[h]:v.target.value}),m=async h=>{h.preventDefault(),o(!0),u("");try{n(await D.invite(r))}catch(v){u(v.message),o(!1)}};return i.jsx("div",{className:"overlay",onClick:t,children:i.jsxs("aside",{className:"drawer narrow",onClick:h=>h.stopPropagation(),children:[i.jsxs("header",{className:"drawer-head",children:[i.jsx("h2",{children:"Invite someone"}),i.jsx("button",{className:"ghost",onClick:t,children:"Close"})]}),i.jsxs("form",{className:"drawer-body",onSubmit:m,children:[i.jsxs("label",{children:["Their email",i.jsx("input",{type:"email",value:r.email,onChange:c("email"),required:!0,autoFocus:!0,autoComplete:"off",name:"invitee"}),i.jsx("span",{className:"hint",children:"This is the address they will sign in with, and it is fixed by the invitation — passing the code on cannot make it somebody else’s account."})]}),i.jsxs("label",{children:["Their name",i.jsx("input",{value:r.full_name,onChange:c("full_name"),autoComplete:"off",name:"invitee-name"})]}),i.jsxs("label",{children:["Role",i.jsxs("select",{value:r.role,onChange:c("role"),children:[i.jsx("option",{value:"staff",children:"Staff — see customers and shops"}),i.jsx("option",{value:"manager",children:"Manager — also set up cameras and invite people"}),e&&i.jsx("option",{value:"owner",children:"Owner — full control"})]})]}),a&&i.jsx("p",{className:"error",role:"alert",children:a}),i.jsx("button",{className:"primary",disabled:s,children:s?"Creating…":"Create invitation"})]})]})})}function Wp({invite:e,onDismiss:t}){return i.jsxs("div",{className:"banner ok credentials",children:[i.jsxs("div",{children:[i.jsxs("b",{children:["Invitation for ",e.email,"."]})," Give them this code. It is shown once, works once, and cannot be recovered.",i.jsxs("dl",{className:"creds",children:[i.jsxs("div",{children:[i.jsx("dt",{children:"Code"}),i.jsx("dd",{children:i.jsx("code",{className:"big",children:e.code})})]}),i.jsxs("div",{children:[i.jsx("dt",{children:"Role"}),i.jsx("dd",{children:e.role})]})]}),i.jsx("p",{className:"sub",children:"They open the app, choose “I have an invitation code”, and pick their own password. Nobody else ever sees it."})]}),i.jsx("button",{className:"ghost",onClick:t,children:"Done"})]})}const Hp=[{id:"sites",label:"Shops",View:fp},{id:"live",label:"Live",View:kp},{id:"cameras",label:"Cameras",View:Op},{id:"team",label:"Team",View:Bp}],Qp=[{id:"clients",label:"Companies",View:$p}];function Kp(){const[e,t]=j.useState(null),[n,r]=j.useState(!0),[l,s]=j.useState("sites"),[o,a]=j.useState(!1);if(j.useEffect(()=>{(async()=>{if(ep())try{t(await D.me())}catch{or()}r(!1)})()},[]),n)return i.jsxs("div",{className:"boot",children:[i.jsx("span",{className:"spinner","aria-hidden":"true"}),"Loading…"]});if(!e)return i.jsx(rp,{onSignedIn:t});const u=e.role==="admin"&&!e.client_id,c=u?Qp:Hp,m=c.find(y=>y.id===l)||c[0],h=m.View,v=async()=>{await D.logout(),t(null)};return i.jsxs("div",{className:"app",children:[i.jsxs("header",{className:"topbar",children:[i.jsxs("div",{className:"brand",children:[i.jsx("span",{className:"mark","aria-hidden":"true"}),i.jsxs("div",{children:[i.jsx("strong",{children:"Behavision"}),i.jsx("span",{className:"org",children:e.client_name||"Loyaly platform"})]})]}),i.jsx("nav",{className:"tabs",children:c.map(y=>i.jsx("button",{onClick:()=>s(y.id),"aria-current":m.id===y.id?"page":void 0,children:y.label},y.id))}),i.jsxs("div",{className:"who",children:[i.jsxs("button",{className:"ask-btn"+(o?" on":""),onClick:()=>a(y=>!y),title:"Ask Loya",children:[i.jsx("span",{className:"mark","aria-hidden":"true"})," Loya"]}),i.jsx("span",{className:"name",children:e.full_name||e.email}),i.jsx("span",{className:"role",children:u?"platform admin":e.role}),i.jsx("button",{className:"ghost",onClick:v,children:"Sign out"})]})]}),i.jsxs("div",{className:"with-assistant"+(o?" open":""),children:[i.jsx("main",{className:"page",children:i.jsx(h,{user:e})}),i.jsx(Dp,{open:o,onClose:()=>a(!1)})]})]})}Sc(document.getElementById("root")).render(i.jsx(Kp,{})); diff --git a/server/internal/web/dist/index.html b/server/internal/web/dist/index.html index 4fb1896..c6d6669 100644 --- a/server/internal/web/dist/index.html +++ b/server/internal/web/dist/index.html @@ -6,7 +6,7 @@ Behavision - + diff --git a/web/src/views/Cameras.jsx b/web/src/views/Cameras.jsx index 5508065..76f8fc7 100644 --- a/web/src/views/Cameras.jsx +++ b/web/src/views/Cameras.jsx @@ -47,9 +47,13 @@ export default function Cameras({ user }) { const canEdit = ['admin', 'owner', 'manager'].includes(user.role) const list = cams || [] - const up = list.filter(c => c.connected).length - const down = list.filter(c => c.connected === false).length - const waiting = list.filter(c => c.connected == null).length + // Counted off `state`, the one field the server computes, never off + // `connected`. Two places deciding the same fact is how a shop came out + // labelled Working, in green, above "2 of 3 cameras not connecting". + const up = list.filter(c => c.state === 'connected').length + const down = list.filter(c => c.state === 'not_connecting').length + const waiting = list.filter(c => c.state === 'waiting').length + const stale = list.filter(c => c.state === 'stale').length return ( <> @@ -58,6 +62,7 @@ export default function Cameras({ user }) {

{list.length} {list.length === 1 ? 'camera' : 'cameras'} {up > 0 && <> · {up} connected} + {stale > 0 && <> · {stale} not reporting} {down > 0 && <> · {down} down} {waiting > 0 && <> · {waiting} waiting for the shop PC}

@@ -108,10 +113,13 @@ function CameraCard({ cam, canEdit, onEdit, onWatch }) { // Three states, not two. A camera nobody has tried yet is not a camera that // is down, and telling an operator to check the cabling on a camera the shop // PC has not even seen sends them to the wrong building. - const state = cam.connected == null ? 'idle' - : cam.connected ? 'ok' : 'bad' - const words = cam.connected == null ? 'Waiting for the shop PC' - : cam.connected ? 'Connected' : 'Not connecting' + // Four states, and the fourth is the one that was missing: a camera whose + // shop PC has stopped reporting it. The agent correctly says nothing when it + // cannot reach the engine, so the last value it sent used to sit in the + // database reading Connected - measured at 34 minutes on the live estate. + const state = { connected: 'ok', not_connecting: 'bad', stale: 'warn' }[cam.state] || 'idle' + const words = { connected: 'Connected', not_connecting: 'Not connecting', + stale: 'Not reporting' }[cam.state] || 'Waiting for the shop PC' const verified = verification(cam) return (