From 37d63c09a5853b12febc39a8712c35aa2d678f5b Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Tue, 29 Sep 2026 06:58:20 +0800 Subject: [PATCH] =?UTF-8?q?=F0=9F=94=A5=20Sync=202026-09-29=2006:58:20?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- luci-app-smartsafehub/CHANGELOG.md | 11 ++ luci-app-smartsafehub/Makefile | 2 +- .../src/components/FirmwareUpdatesCard.tsx | 7 +- luci-app-smartsafehub/frontend/src/main.tsx | 2 +- .../ucode/luci/template/smartsafehub/login.ut | 6 +- .../root/www/luci-static/smartsafehub/app.js | 2 +- .../tests/test-update-ui-contract.sh | 9 +- luci-app-substore/CHANGELOG.md | 24 +++ luci-app-substore/Makefile | 2 +- luci-app-substore/README.en.md | 18 +- luci-app-substore/README.md | 18 +- luci-app-substore/docs/INSTALL.md | 6 +- .../usr/lib/lua/luci/view/substore/output.htm | 14 +- .../lua/luci/view/substore/subscriptions.htm | 15 +- .../root/usr/share/substore/output.lua | 100 +++++----- .../usr/share/substore/output_formats.lua | 17 ++ .../share/substore/output_wireguard_conf.lua | 107 +++++++++++ luci-app-substore/tests/core_link_test.lua | 10 +- .../tests/output_formats_test.lua | 7 +- .../tests/output_new_formats_test.lua | 176 ++++++++++++++++++ luci-app-tailscale/Makefile | 17 +- .../root/etc/uci-defaults/40_luci-tailscale | 10 +- 22 files changed, 459 insertions(+), 121 deletions(-) create mode 100644 luci-app-substore/root/usr/share/substore/output_wireguard_conf.lua create mode 100644 luci-app-substore/tests/output_new_formats_test.lua diff --git a/luci-app-smartsafehub/CHANGELOG.md b/luci-app-smartsafehub/CHANGELOG.md index 37ebd2432..ca2d2a85f 100644 --- a/luci-app-smartsafehub/CHANGELOG.md +++ b/luci-app-smartsafehub/CHANGELOG.md @@ -1,5 +1,16 @@ # 변경 기록 +## [0.2.24-r2] - 2026-09-29 + +### 개선 + +- `새 펌웨어가 있습니다.` 안내에서 내부 OpenWrt 기반 버전 표기를 제거하고 SmartSafeHub 펌웨어 버전, 이미지 크기와 배포 채널만 표시하도록 단순화했습니다. +- OpenWrt 기반 버전이 확인되지 않을 때 사용자에게 `OpenWrt 미확인`이 노출되지 않도록 했습니다. + +### 테스트 + +- 사용 가능한 펌웨어 요약에 OpenWrt 기반 버전이 다시 노출되지 않고 SmartSafeHub 펌웨어 버전과 이미지 크기가 유지되는지 UI contract 테스트를 추가했습니다. + ## [0.2.24-r1] - 2026-09-28 ### 수정 diff --git a/luci-app-smartsafehub/Makefile b/luci-app-smartsafehub/Makefile index b6692ac0e..389eb4fb1 100644 --- a/luci-app-smartsafehub/Makefile +++ b/luci-app-smartsafehub/Makefile @@ -7,7 +7,7 @@ include $(TOPDIR)/rules.mk PKG_NAME:=luci-app-smartsafehub PKG_VERSION:=0.2.24 -PKG_RELEASE:=3 +PKG_RELEASE:=4 PKG_MAINTAINER:=Beomjun Kang PKG_LICENSE:=GPL-3.0-or-later diff --git a/luci-app-smartsafehub/frontend/src/components/FirmwareUpdatesCard.tsx b/luci-app-smartsafehub/frontend/src/components/FirmwareUpdatesCard.tsx index a19cbc30d..b7390d1d9 100644 --- a/luci-app-smartsafehub/frontend/src/components/FirmwareUpdatesCard.tsx +++ b/luci-app-smartsafehub/frontend/src/components/FirmwareUpdatesCard.tsx @@ -372,6 +372,11 @@ export function FirmwareUpdatesCard({ ? '새 펌웨어' : '최신 버전'} + {data.release?.buildId ? ( + + 빌드 ID {data.release.buildId} + + ) : null}
Last check
@@ -388,7 +393,7 @@ export function FirmwareUpdatesCard({

Available firmware

새 펌웨어가 있습니다.

- 펌웨어 {data.release.version || '미확인'} · OpenWrt {data.release.openwrtVersion || '미확인'} · {formatBytes(data.release.sysupgrade.sizeBytes)} · {(data.release.channel || data.settings.channel) === 'beta' ? 'Beta' : 'Stable'} + 펌웨어 {data.release.version || '미확인'} · {formatBytes(data.release.sysupgrade.sizeBytes)} · {(data.release.channel || data.settings.channel) === 'beta' ? 'Beta' : 'Stable'}

diff --git a/luci-app-smartsafehub/frontend/src/main.tsx b/luci-app-smartsafehub/frontend/src/main.tsx index 98f80b575..2525dfee3 100644 --- a/luci-app-smartsafehub/frontend/src/main.tsx +++ b/luci-app-smartsafehub/frontend/src/main.tsx @@ -44,7 +44,7 @@ function installBootstrap(sessionId: string, host: HTMLElement): void { sessionId, rpcUrl: luciUrl('/admin/ubus'), assetBase: host.dataset.assetBase ?? '/luci-static/smartsafehub/', - assetVersion: host.dataset.assetVersion ?? '0.2.24-r1', + assetVersion: host.dataset.assetVersion ?? '0.2.24-r2', locale: document.documentElement.lang || 'ko', }); } diff --git a/luci-app-smartsafehub/root/usr/share/ucode/luci/template/smartsafehub/login.ut b/luci-app-smartsafehub/root/usr/share/ucode/luci/template/smartsafehub/login.ut index d82c6a4a4..702554763 100644 --- a/luci-app-smartsafehub/root/usr/share/ucode/luci/template/smartsafehub/login.ut +++ b/luci-app-smartsafehub/root/usr/share/ucode/luci/template/smartsafehub/login.ut @@ -10,16 +10,16 @@ SmartSafeHub - +
- + diff --git a/luci-app-smartsafehub/root/www/luci-static/smartsafehub/app.js b/luci-app-smartsafehub/root/www/luci-static/smartsafehub/app.js index c558a5485..827d840eb 100644 --- a/luci-app-smartsafehub/root/www/luci-static/smartsafehub/app.js +++ b/luci-app-smartsafehub/root/www/luci-static/smartsafehub/app.js @@ -1,3 +1,3 @@ var e,t,n,r,i,a,o,s,c,l,u,d,f,p,m={},h=[],g=/acit|ex(?:s|g|n|p|$)|rph|grid|ows|mnc|ntw|ine[ch]|zoo|^ord|itera/i,_=Array.isArray;function v(e,t){for(var n in t)e[n]=t[n];return e}function y(e){e&&e.parentNode&&e.parentNode.removeChild(e)}function b(t,n,r){var i,a,o,s={};for(o in n)o==`key`?i=n[o]:o==`ref`?a=n[o]:s[o]=n[o];if(arguments.length>2&&(s.children=arguments.length>3?e.call(arguments,2):r),typeof t==`function`&&t.defaultProps!=null)for(o in t.defaultProps)s[o]===void 0&&(s[o]=t.defaultProps[o]);return x(t,s,i,a,null)}function x(e,r,i,a,o){var s={type:e,props:r,key:i,ref:a,__k:null,__:null,__b:0,__e:null,__c:null,constructor:void 0,__v:o??++n,__i:-1,__u:0};return o==null&&t.vnode!=null&&t.vnode(s),s}function S(e){return e.children}function C(e,t){this.props=e,this.context=t}function w(e,t){if(t==null)return e.__?w(e.__,e.__i+1):null;for(var n;tt&&r.sort(o),e=r.shift(),t=r.length,T(e)}finally{r.length=O.__r=0}}function k(e,t,n,r,i,a,o,s,c,l,u){var d,f,p,g,_,v,y=r&&r.__k||h,b=t.length;for(c=A(n,t,y,c,b),d=0;d0?o=e.__k[a]=x(o.type,o.props,o.key,o.ref?o.ref:null,o.__v):e.__k[a]=o,c=a+f,o.__=e,o.__b=e.__b+1,s=null,(l=o.__i=te(o,n,c,d))!=-1&&(d--,(s=n[l])&&(s.__u|=2)),s==null||s.__v==null?(l==-1&&(i>u?f--:ic?f--:f++,o.__u|=4))):e.__k[a]=null;if(d)for(a=0;a+!!u){for(i=n-1,a=n+1;i>=0||a=0?i--:a++])!=null&&!(2&l.__u)&&s==l.key&&c==l.type)return o}return-1}function ne(e,t,n){t[0]==`-`?e.setProperty(t,n??``):e[t]=n==null?``:typeof n!=`number`||g.test(t)?n:n+`px`}function M(e,t,n,r,i){var a,o;n:if(t==`style`){if(typeof n==`string`)e.style.cssText=n;else{if(typeof r==`string`&&(e.style.cssText=r=``),r)for(t in r)n&&t in n||ne(e.style,t,``);if(n)for(t in n)r&&n[t]==r[t]||ne(e.style,t,n[t])}}else if(t[0]==`o`&&t[1]==`n`)a=t!=(t=t.replace(u,`$1`)),o=t.toLowerCase(),t=o in e||t==`onFocusOut`||t==`onFocusIn`?o.slice(2):t.slice(2),e.l||(e.l={}),e.l[t+a]=n,n?r?n[l]=r[l]:(n[l]=d,e.addEventListener(t,a?p:f,a)):e.removeEventListener(t,a?p:f,a);else{if(i==`http://www.w3.org/2000/svg`)t=t.replace(/xlink(H|:h)/,`h`).replace(/sName$/,`s`);else if(t!=`width`&&t!=`height`&&t!=`href`&&t!=`list`&&t!=`form`&&t!=`tabIndex`&&t!=`download`&&t!=`rowSpan`&&t!=`colSpan`&&t!=`role`&&t!=`popover`&&t in e)try{e[t]=n??``;break n}catch{}typeof n==`function`||(n==null||!1===n&&t[4]!=`-`?e.removeAttribute(t):e.setAttribute(t,t==`popover`&&n==1?``:n))}}function re(e){return function(n){if(this.l){var r=this.l[n.type+e];if(n[c]==null)n[c]=d++;else if(n[c]0?e:_(e)?e.map(se):e.constructor===void 0?v({},e):null}function ce(n,r,i,a,o,s,c,l,u){var d,f,p,h,g,v,b,x=i.props||m,S=r.props,C=r.type;if(C==`svg`?o=`http://www.w3.org/2000/svg`:C==`math`?o=`http://www.w3.org/1998/Math/MathML`:o||(o=`http://www.w3.org/1999/xhtml`),s!=null){for(d=0;d=0?e.slice(0,t+13):ve}function be(){let e=ye();return e.endsWith(`/luci`)?e.slice(0,-5):_e}function xe(e){let t=e.startsWith(`/`)?e:`/${e}`;return`${be()}${t}`}function Se(e){let t=e.startsWith(`/`)?e:`/${e}`;return`${ye()}${t}`}function Ce(e){return Se(e)}function we(e=``){return`/${e?e.startsWith(`#`)?e:`#${e}`:``}`}var Te=/^[0-9a-f]{32}$/i;function Ee(){return Se(`/smartsafehub/session`)}function De(e){return e.headers.get(`X-LuCI-Login-Required`)===`yes`}async function Oe(e){if(e.status===401||e.status===403||De(e))return null;if(!e.ok)throw Error(`LuCI session endpoint returned HTTP ${e.status}`);let t=(await e.text()).trim();if(Te.test(t))return t;if(e.redirected||/^(?:access|permission)\s+denied\.?$/i.test(t)||/^)/i.test(t))return null;throw Error(`LuCI session endpoint returned an invalid session id`)}async function ke(e={}){return Oe(await fetch(Ee(),{cache:`no-store`,credentials:`same-origin`,redirect:`follow`,...e}))}function Ae(){return ke()}async function je(){await fetch(Se(`/admin/logout`),{cache:`no-store`,credentials:`same-origin`,redirect:`manual`})}function Me(e,t){let n=new URLSearchParams;return n.set(`luci_username`,e),n.set(`luci_password`,t),ke({method:`POST`,headers:{"Content-Type":`application/x-www-form-urlencoded;charset=UTF-8`},body:n})}var Ne=`smartsafehub:session-expired`,Pe=`로그인 세션이 만료되었습니다. 계속하려면 다시 로그인해 주세요.`,Fe=null;function Ie(){Fe=null}function Le(e){Fe!==e&&(Fe=e,window.dispatchEvent(new CustomEvent(Ne)))}var Re,ze,Be,Ve,He=0,Ue=[],We=t,Ge=We.__b,Ke=We.__r,qe=We.diffed,Je=We.__c,Ye=We.unmount,Xe=We.__;function Ze(e,t){We.__h&&We.__h(ze,e,He||t),He=0;var n=ze.__H||(ze.__H={__:[],__h:[]});return e>=n.__.length&&n.__.push({}),n.__[e]}function N(e){return He=1,Qe(st,e)}function Qe(e,t,n){var r=Ze(Re++,2);if(r.t=e,!r.__c&&(r.__=[n?n(t):st(void 0,t),function(e){var t=r.__N?r.__N[0]:r.__[0],n=r.t(t,e);t!==n&&(r.__N=[n,r.__[1]],r.__c.setState({}))}],r.__c=ze,!ze.__f)){var i=function(e,t,n){if(!r.__c.__H)return!0;var i=!1,o=r.__c.props!==e;if(r.__c.__H.__.some(function(e){if(e.__N){i=!0;var t=e.__[0];e.__=e.__N,e.__N=void 0,t!==e.__[0]&&(o=!0)}}),a){var s=a.call(this,e,t,n);return i?s||o:s}return!i||o};ze.__f=!0;var a=ze.shouldComponentUpdate,o=ze.componentWillUpdate;ze.componentWillUpdate=function(e,t,n){if(this.__e){var r=a;a=void 0,i(e,t,n),a=r}o&&o.call(this,e,t,n)},ze.shouldComponentUpdate=i}return r.__N||r.__}function P(e,t){var n=Ze(Re++,3);!We.__s&&ot(n.__H,t)&&(n.__=e,n.u=t,ze.__H.__h.push(n))}function F(e){return He=5,$e(function(){return{current:e}},[])}function $e(e,t){var n=Ze(Re++,7);return ot(n.__H,t)&&(n.__=e(),n.__H=t,n.__h=e),n.__}function I(e,t){return He=8,$e(function(){return e},t)}function et(){var e=Ze(Re++,11);if(!e.__){for(var t=ze.__v;t!==null&&!t.__m&&t.__!==null;)t=t.__;var n=t.__m||(t.__m=[0,0]);e.__=`P`+n[0]+`-`+n[1]++}return e.__}function tt(){for(var e;e=Ue.shift();){var t=e.__H;if(e.__P&&t)try{t.__h.some(it),t.__h.some(at),t.__h=[]}catch(n){t.__h=[],We.__e(n,e.__v)}}}We.__b=function(e){ze=null,Ge&&Ge(e)},We.__=function(e,t){e&&t.__k&&t.__k.__m&&(e.__m=t.__k.__m),Xe&&Xe(e,t)},We.__r=function(e){Ke&&Ke(e),Re=0;var t=(ze=e.__c).__H;t&&(Be===ze?(t.__h=[],ze.__h=[],t.__.some(function(e){e.__N&&(e.__=e.__N),e.u=e.__N=void 0})):(t.__h.some(it),t.__h.some(at),t.__h=[],Re=0)),Be=ze},We.diffed=function(e){qe&&qe(e);var t=e.__c;t&&t.__H&&(t.__H.__h.length&&(Ue.push(t)!==1&&Ve===We.requestAnimationFrame||((Ve=We.requestAnimationFrame)||rt)(tt)),t.__H.__.some(function(e){e.u&&(e.__H=e.u,e.u=void 0)})),Be=ze=null},We.__c=function(e,t){t.some(function(e){try{e.__h.some(it),e.__h=e.__h.filter(function(e){return!e.__||at(e)})}catch(n){t.some(function(e){e.__h&&(e.__h=[])}),t=[],We.__e(n,e.__v)}}),Je&&Je(e,t)},We.unmount=function(e){Ye&&Ye(e);var t,n=e.__c;n&&n.__H&&(n.__H.__.some(function(e){try{it(e)}catch(e){t=e}}),n.__H=void 0,t&&We.__e(t,n.__v))};var nt=typeof requestAnimationFrame==`function`;function rt(e){var t,n=function(){clearTimeout(r),nt&&cancelAnimationFrame(t),setTimeout(e)},r=setTimeout(n,35);nt&&(t=requestAnimationFrame(n))}function it(e){var t=ze,n=e.__c;typeof n==`function`&&(e.__c=void 0,n()),ze=t}function at(e){var t=ze;e.__c=e.__(),ze=t}function ot(e,t){return!e||e.length!==t.length||t.some(function(t,n){return t!==e[n]})}function st(e,t){return typeof t==`function`?t(e):t}function ct(e){"@babel/helpers - typeof";return ct=typeof Symbol==`function`&&typeof Symbol.iterator==`symbol`?function(e){return typeof e}:function(e){return e&&typeof Symbol==`function`&&e.constructor===Symbol&&e!==Symbol.prototype?`symbol`:typeof e},ct(e)}function lt(e,t){if(ct(e)!=`object`||!e)return e;var n=e[Symbol.toPrimitive];if(n!==void 0){var r=n.call(e,t||`default`);if(ct(r)!=`object`)return r;throw TypeError(`@@toPrimitive must return a primitive value.`)}return(t===`string`?String:Number)(e)}function ut(e){var t=lt(e,`string`);return ct(t)==`symbol`?t:t+``}function L(e,t,n){return(t=ut(t))in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}var dt={1:`잘못된 명령입니다.`,2:`요청 인자가 올바르지 않습니다.`,3:`요청한 메서드를 찾을 수 없습니다.`,4:`요청한 리소스를 찾을 수 없습니다.`,5:`응답 데이터가 없습니다.`,6:`접근 권한이 없습니다.`,7:`요청 시간이 초과되었습니다.`,8:`지원하지 않는 기능입니다.`,9:`장치에서 알 수 없는 오류가 발생했습니다.`,10:`장치 연결이 끊어졌습니다.`},ft=2e4,pt=3e3,mt=1e3,ht=6e4,gt=1,R=class extends Error{constructor(e,t){super(t),L(this,`code`,void 0),this.name=`RpcError`,this.code=e}};function _t(){let e=window.__SMARTHUB_BOOTSTRAP__;if(!e?.sessionId||!e.rpcUrl)throw new R(`BOOTSTRAP_MISSING`,`LuCI 세션 정보를 찾을 수 없습니다. 페이지를 새로고침해 주세요.`);return e}function vt(e){return typeof e==`object`&&!!e&&!Array.isArray(e)}function yt(){return new R(`INVALID_RESPONSE`,`장치 API가 올바르지 않은 응답을 반환했습니다.`)}function bt(e){return typeof e!=`number`||!Number.isFinite(e)?ft:Math.min(ht,Math.max(mt,Math.trunc(e)))}function xt(e){let t=e.message.trim().toLowerCase();return e.code===`UBUS_6`||e.code===`JSON_RPC_-32002`||e.code===`HTTP_ERROR`&&/HTTP (401|403)\b/.test(e.message)||t.includes(`access denied`)||t.includes(`permission denied`)||t.includes(`접근 권한`)}function St(e){return window.__SMARTHUB_BOOTSTRAP__?.sessionId===e}async function Ct(e){let t=gt++,n=new AbortController,r=window.setTimeout(()=>n.abort(),pt);try{let r=await fetch(e.rpcUrl,{method:`POST`,credentials:`same-origin`,headers:{"Content-Type":`application/json`},body:JSON.stringify({jsonrpc:`2.0`,id:t,method:`call`,params:[e.sessionId,`smartsafehub`,`system_root_password_status`,{}]}),signal:n.signal});if(r.status===401||r.status===403)return`expired`;if(!r.ok)return`unknown`;let i=await r.json();if(!vt(i)||i.jsonrpc!==`2.0`||i.id!==t)return`unknown`;if(`error`in i){let e=i.error;return vt(e)&&typeof e.code==`number`&&e.code===-32002?`expired`:`unknown`}let a=i.result;return!Array.isArray(a)||a.length<1?`unknown`:a[0]===0?`active`:a[0]===6?`expired`:`unknown`}catch{return`unknown`}finally{window.clearTimeout(r)}}async function wt(e,t){if(!xt(e)||!St(t.sessionId))return e;let n=await Ct(t);return St(t.sessionId)?n===`active`?new R(`RPC_PERMISSION_DENIED`,`현재 로그인 세션에 이 기능 권한이 없습니다. SmartSafeHub 업데이트 직후라면 로그아웃 후 다시 로그인해 주세요.`):n===`expired`?(Le(t.sessionId),new R(`SESSION_EXPIRED`,Pe)):e:e}function Tt(e,t){if(!vt(e)||e.jsonrpc!==`2.0`||e.id!==t)throw yt();if(`error`in e){let t=e.error;throw!vt(t)||typeof t.code!=`number`?yt():new R(`JSON_RPC_${t.code}`,typeof t.message==`string`&&t.message.length>0?t.message:`JSON-RPC 요청에 실패했습니다.`)}let n=e.result;if(!Array.isArray(n)||n.length<1||n.length>2)throw yt();let r=n[0];if(typeof r!=`number`||!Number.isInteger(r))throw yt();if(r!==0)throw new R(`UBUS_${r}`,dt[r]??`ubus 오류 코드 ${r}가 반환되었습니다.`);if(n.length<2||n[1]===void 0)throw new R(`EMPTY_RESPONSE`,`장치 API 응답이 비어 있습니다.`);return n[1]}async function Et(e,t,n={},r={}){let i=_t(),a=gt++,o=new AbortController,s=window.setTimeout(()=>o.abort(),bt(r.timeoutMs));try{let r=await fetch(i.rpcUrl,{method:`POST`,credentials:`same-origin`,headers:{"Content-Type":`application/json`},body:JSON.stringify({jsonrpc:`2.0`,id:a,method:`call`,params:[i.sessionId,e,t,n]}),signal:o.signal});if(!r.ok)throw new R(`HTTP_ERROR`,`장치 API가 HTTP ${r.status} 오류를 반환했습니다.`);let s;try{s=await r.json()}catch{throw yt()}return Tt(s,a)}catch(e){throw o.signal.aborted?new R(`RPC_TIMEOUT`,`장치 응답 시간이 초과되었습니다. 잠시 후 다시 시도해 주세요.`):e instanceof R?await wt(e,i):new R(`NETWORK_ERROR`,`공유기와 통신할 수 없습니다. 네트워크 연결을 확인해 주세요.`)}finally{window.clearTimeout(s)}}async function z(e,t,n={},r={}){let i=await Et(e,t,n,r);if(!i.ok)throw new R(i.error.code,i.error.message);return i.data}function Dt(){return z(`smartsafehub`,`system_root_password_status`)}function Ot(e){return z(`smartsafehub`,`system_root_password_set`,{password:e})}var kt=0;Array.isArray;function B(e,n,r,i,a,o){n||(n={});var s,c,l=n;if(`ref`in l)for(c in l={},n)c==`ref`?s=n[c]:l[c]=n[c];var u={type:e,props:l,key:r,ref:s,__k:null,__:null,__b:0,__e:null,__c:null,constructor:void 0,__v:--kt,__i:-1,__u:0,__source:a,__self:o};if(typeof e==`function`&&(s=e.defaultProps))for(c in s)l[c]===void 0&&(l[c]=s[c]);return t.vnode&&t.vnode(u),u}function V({children:e,title:t,...n}){return B(`svg`,{"aria-hidden":!t||void 0,fill:`none`,role:t?`img`:void 0,stroke:`currentColor`,"stroke-linecap":`round`,"stroke-linejoin":`round`,"stroke-width":`1.8`,viewBox:`0 0 24 24`,...n,children:[t?B(`title`,{children:t}):null,e]})}function At(e){return B(V,{...e,children:[B(`path`,{d:`M12 3 5 6v5c0 4.6 2.8 8.1 7 10 4.2-1.9 7-5.4 7-10V6l-7-3Z`}),B(`path`,{d:`m9 12 2 2 4-4`})]})}function jt(e){return B(V,{...e,children:[B(`rect`,{height:`7`,rx:`2`,width:`18`,x:`3`,y:`13`}),B(`path`,{d:`M7 16.5h.01M11 16.5h.01M7 10a7 7 0 0 1 10 0M9.5 7.5a3.5 3.5 0 0 1 5 0`})]})}function Mt(e){return B(V,{...e,children:[B(`rect`,{height:`11`,rx:`2`,width:`16`,x:`4`,y:`3`}),B(`path`,{d:`M8 21h8M12 14v7`})]})}function Nt(e){return B(V,{...e,children:[B(`path`,{d:`m3 11 9-8 9 8`}),B(`path`,{d:`M5 10v10h14V10M9 20v-6h6v6`})]})}function Pt(e){return B(V,{...e,children:[B(`circle`,{cx:`12`,cy:`8`,r:`4`}),B(`path`,{d:`M4.5 21a7.5 7.5 0 0 1 15 0`})]})}function Ft(e){return B(V,{...e,children:[B(`path`,{d:`M12 16V4`}),B(`path`,{d:`m7 9 5-5 5 5`}),B(`path`,{d:`M5 14v5h14v-5`})]})}function It(e){return B(V,{...e,children:[B(`circle`,{cx:`12`,cy:`12`,r:`3`}),B(`path`,{d:`M19.4 15a1.7 1.7 0 0 0 .3 1.9l.1.1-2.8 2.8-.1-.1a1.7 1.7 0 0 0-1.9-.3 1.7 1.7 0 0 0-1 1.6v.2h-4V21a1.7 1.7 0 0 0-1-1.6 1.7 1.7 0 0 0-1.9.3l-.1.1L4.2 17l.1-.1a1.7 1.7 0 0 0 .3-1.9A1.7 1.7 0 0 0 3 14H2.8v-4H3a1.7 1.7 0 0 0 1.6-1 1.7 1.7 0 0 0-.3-1.9L4.2 7 7 4.2l.1.1a1.7 1.7 0 0 0 1.9.3A1.7 1.7 0 0 0 10 3V2.8h4V3a1.7 1.7 0 0 0 1 1.6 1.7 1.7 0 0 0 1.9-.3l.1-.1L19.8 7l-.1.1a1.7 1.7 0 0 0-.3 1.9 1.7 1.7 0 0 0 1.6 1h.2v4H21a1.7 1.7 0 0 0-1.6 1Z`})]})}function Lt(e){return B(V,{...e,children:[B(`path`,{d:`M5 9.5a10 10 0 0 1 14 0M8 13a6 6 0 0 1 8 0M11 16.5a2 2 0 0 1 2 0`}),B(`path`,{d:`M12 20h.01`})]})}function Rt(e){return B(V,{...e,children:[B(`path`,{d:`M7 3v4M17 3v4M5 7h14v4a7 7 0 0 1-14 0V7Z`}),B(`path`,{d:`M12 18v3`})]})}function zt(e){return B(V,{...e,children:[B(`circle`,{cx:`12`,cy:`12`,r:`9`}),B(`path`,{d:`M3 12h18M12 3a14 14 0 0 1 0 18M12 3a14 14 0 0 0 0 18`})]})}function Bt(e){return B(V,{...e,children:[B(`rect`,{height:`13`,rx:`2`,width:`18`,x:`3`,y:`6`}),B(`path`,{d:`m8 2 4 4 4-4M8 22h8`})]})}function Vt(e){return B(V,{...e,children:[B(`circle`,{cx:`12`,cy:`12`,r:`9`}),B(`path`,{d:`M12 7v5l3 2`})]})}function Ht(e){return B(V,{...e,children:[B(`rect`,{height:`14`,rx:`2`,width:`14`,x:`5`,y:`5`}),B(`path`,{d:`M9 9h6v6H9zM9 2v3M15 2v3M9 19v3M15 19v3M2 9h3M2 15h3M19 9h3M19 15h3`})]})}function H(e){return B(V,{...e,children:[B(`path`,{d:`M20 11a8 8 0 1 0-2.3 5.7`}),B(`path`,{d:`M20 4v7h-7`})]})}function Ut(e){return B(V,{...e,children:[B(`path`,{d:`M12 2v10`}),B(`path`,{d:`M18.4 6.6a8 8 0 1 1-12.8 0`})]})}function Wt(e){return B(V,{...e,children:[B(`path`,{d:`M12 3v12`}),B(`path`,{d:`m7 10 5 5 5-5`}),B(`path`,{d:`M5 21h14`})]})}function Gt(e){return B(V,{...e,children:[B(`ellipse`,{cx:`12`,cy:`5`,rx:`8`,ry:`3`}),B(`path`,{d:`M4 5v6c0 1.7 3.6 3 8 3s8-1.3 8-3V5M4 11v6c0 1.7 3.6 3 8 3s8-1.3 8-3v-6`})]})}function Kt(e){return B(V,{...e,children:[B(`circle`,{cx:`8`,cy:`15`,r:`4`}),B(`path`,{d:`m11 12 8-8M15 8l2 2M17 6l2 2`})]})}function qt(e){return B(V,{...e,children:[B(`path`,{d:`M2.5 12s3.5-6 9.5-6 9.5 6 9.5 6-3.5 6-9.5 6-9.5-6-9.5-6Z`}),B(`circle`,{cx:`12`,cy:`12`,r:`2.5`})]})}function Jt(e){return B(V,{...e,children:[B(`path`,{d:`m3 3 18 18`}),B(`path`,{d:`M10.6 6.2A8.8 8.8 0 0 1 12 6c6 0 9.5 6 9.5 6a15.5 15.5 0 0 1-2.6 3.2`}),B(`path`,{d:`M6.2 6.3C3.8 8 2.5 12 2.5 12s3.5 6 9.5 6a9.8 9.8 0 0 0 3.1-.5`}),B(`path`,{d:`M10.3 10.3a2.5 2.5 0 0 0 3.4 3.4`})]})}function Yt(e){return B(V,{...e,children:[B(`rect`,{height:`17`,rx:`2`,width:`18`,x:`3`,y:`4`}),B(`path`,{d:`M8 2v4M16 2v4M3 9h18`})]})}function Xt(e){return B(V,{...e,children:[B(`circle`,{cx:`12`,cy:`12`,r:`9`}),B(`path`,{d:`m8 12 2.5 2.5L16 9`})]})}function U(e){return B(V,{...e,children:[B(`path`,{d:`M10.3 4.2 2.7 17.5A2 2 0 0 0 4.4 20h15.2a2 2 0 0 0 1.7-2.5L13.7 4.2a2 2 0 0 0-3.4 0Z`}),B(`path`,{d:`M12 9v4M12 17h.01`})]})}function Zt(e){return B(V,{...e,children:B(`path`,{d:`M12 5v14M5 12h14`})})}function Qt(e){return B(V,{...e,children:B(`path`,{d:`M4 7h16M9 7V4h6v3M7 7l1 13h8l1-13M10 11v5M14 11v5`})})}function $t(e){return B(V,{...e,children:[B(`circle`,{cx:`11`,cy:`11`,r:`7`}),B(`path`,{d:`m20 20-4-4`})]})}function en(e){return B(V,{...e,children:[B(`path`,{d:`M8 6h12M8 12h12M8 18h12`}),B(`path`,{d:`M4 6h.01M4 12h.01M4 18h.01`})]})}function tn(e){return B(V,{...e,children:[B(`path`,{d:`M10 5H6a2 2 0 0 0-2 2v10a2 2 0 0 0 2 2h4`}),B(`path`,{d:`M14 8l4 4-4 4M8 12h10`})]})}function nn(e){return B(V,{...e,children:B(`path`,{d:`M4 7h16M4 12h16M4 17h16`})})}function rn(e){return B(V,{...e,children:B(`path`,{d:`m6 9 6 6 6-6`})})}function an(e){return B(V,{...e,children:B(`path`,{d:`m6 6 12 12M18 6 6 18`})})}function on(e){return B(V,{...e,children:B(`path`,{d:`m15 18-6-6 6-6`})})}function sn(e){return B(V,{...e,children:B(`path`,{d:`m9 18 6-6-6-6`})})}function cn(e){return B(V,{...e,children:B(`path`,{d:`M20.7 13.2A8.5 8.5 0 1 1 10.8 3.3 6.7 6.7 0 0 0 20.7 13.2Z`})})}function ln(e){return B(V,{...e,children:[B(`circle`,{cx:`12`,cy:`12`,r:`4`}),B(`path`,{d:`M12 2v2M12 20v2M4.93 4.93l1.41 1.41M17.66 17.66l1.41 1.41M2 12h2M20 12h2M4.93 19.07l1.41-1.41M17.66 6.34l1.41-1.41`})]})}var un=`smartsafehub.theme`;function dn(){if(typeof window>`u`)return`light`;try{let e=window.localStorage.getItem(un);if(e===`dark`||e===`light`)return e}catch{}return window.matchMedia(`(prefers-color-scheme: dark)`).matches?`dark`:`light`}function fn(e){try{window.localStorage.setItem(un,e)}catch{}}function pn(e){let t=document.querySelector(`meta[name="theme-color"]`);t&&(t.content=e===`dark`?`#0f172a`:`#f8fafc`),document.documentElement.style.colorScheme=e,document.body.style.backgroundColor=e===`dark`?`#020617`:`#f8fafc`}function mn(e){return{length:e.length>=8,letter:/[A-Za-z]/.test(e),number:/[0-9]/.test(e)}}function hn(e){return e.length&&e.letter&&e.number}function gn({theme:e}){return B(e===`dark`?ln:cn,{})}function _n({met:e,children:t}){return B(`li`,{class:e?`ssh-password-requirement is-met`:`ssh-password-requirement`,children:[B(Xt,{"aria-hidden":`true`}),B(`span`,{children:t})]})}function vn({onCompleted:e,recovery:t}){let n=F(null),r=F(null),[i,a]=N(``),[o,s]=N(``),[c,l]=N(!1),[u,d]=N(!1),[f,p]=N(!1),[m,h]=N(null),[g,_]=N(dn),v=mn(i),y=hn(v),b=o.length>0&&i===o,x=g===`dark`?`라이트 모드로 전환`:`다크 모드로 전환`;P(()=>{fn(g),pn(g)},[g]),P(()=>{let e=window.requestAnimationFrame(()=>n.current?.focus());return()=>window.cancelAnimationFrame(e)},[]);let S=e=>{d(e.getModifierState?.(`CapsLock`)??!1)};return B(`main`,{class:`ssh-login-page`,"data-theme":g,children:[B(`section`,{class:`ssh-login-brand`,"aria-labelledby":`ssh-password-setup-brand-title`,children:[B(`div`,{class:`ssh-login-brand-orb ssh-login-brand-orb-one`,"aria-hidden":`true`}),B(`div`,{class:`ssh-login-brand-orb ssh-login-brand-orb-two`,"aria-hidden":`true`}),B(`div`,{class:`ssh-login-brand-content`,children:[B(`span`,{class:`ssh-login-brand-mark`,"aria-hidden":`true`,children:B(At,{})}),B(`p`,{class:`ssh-login-eyebrow`,children:t?`PASSWORD RECOVERY`:`FIRST SECURITY SETUP`}),B(`h1`,{id:`ssh-password-setup-brand-title`,children:[B(`span`,{class:`ssh-password-setup-brand-title-line`,children:`SmartSafeHub`}),B(`span`,{class:`ssh-password-setup-brand-title-line`,children:t?`비밀번호 복구`:`보호 시작`})]}),B(`p`,{class:`ssh-login-brand-description`,children:t?`물리 Reset 버튼으로 관리자 비밀번호 복구가 요청되었습니다. 네트워크, Wi-Fi, SafeShield 등 기존 설정은 그대로 유지됩니다.`:`관리자 비밀번호가 없는 상태에서는 SmartSafeHub 관리 기능을 사용할 수 없습니다. 먼저 이 공유기의 root 관리자 비밀번호를 설정해 주세요.`}),B(`div`,{class:`ssh-password-setup-summary`,children:[B(At,{"aria-hidden":`true`}),B(`div`,{children:[B(`strong`,{children:t?`새 관리자 비밀번호를 설정해 주세요`:`초기 보안 설정이 필요합니다`}),B(`span`,{children:t?`새 비밀번호를 설정하기 전까지 SSH 접근은 비활성화되고 다른 관리 기능도 잠겨 있습니다.`:`설정이 완료되기 전까지 다른 SmartSafeHub 기능은 잠겨 있습니다.`})]})]})]})]}),B(`section`,{class:`ssh-login-panel`,"aria-labelledby":`ssh-password-setup-title`,children:[B(`button`,{"aria-label":x,class:`ssh-login-theme-toggle`,onClick:()=>_(e=>e===`dark`?`light`:`dark`),title:x,type:`button`,children:B(gn,{theme:g})}),B(`div`,{class:`ssh-login-panel-inner`,children:[B(`div`,{class:`ssh-login-card`,children:[B(`div`,{class:`ssh-login-card-heading`,children:[B(`span`,{class:`ssh-login-mobile-mark`,"aria-hidden":`true`,children:B(Kt,{})}),B(`div`,{children:[B(`p`,{class:`ssh-login-kicker`,children:`ADMIN PASSWORD`}),B(`h2`,{id:`ssh-password-setup-title`,children:t?`관리자 비밀번호 복구`:`관리자 비밀번호 설정`}),B(`p`,{class:`ssh-login-subtitle`,children:`비밀번호 설정 후 새 비밀번호로 다시 로그인해야 합니다.`})]})]}),m?B(`div`,{class:`ssh-login-alert`,role:`alert`,"aria-live":`polite`,children:m}):null,B(`form`,{class:`ssh-login-form`,onSubmit:async t=>{if(t.preventDefault(),h(null),!y){h(`비밀번호는 8자 이상이며 영문과 숫자를 각각 하나 이상 포함해야 합니다.`),window.requestAnimationFrame(()=>n.current?.focus());return}if(i!==o){h(`비밀번호 확인 값이 일치하지 않습니다.`),window.requestAnimationFrame(()=>r.current?.focus());return}p(!0);try{await Ot(i),a(``),s(``);try{await je()}catch{}e()}catch(e){h(e instanceof R?e.message:`관리자 비밀번호를 설정하지 못했습니다. 잠시 후 다시 시도해 주세요.`)}finally{p(!1)}},noValidate:!0,children:[B(`label`,{class:`ssh-login-field`,for:`smartsafehub-new-root-password`,children:[B(`span`,{class:`ssh-login-label`,children:`새 비밀번호`}),B(`span`,{class:`ssh-login-input-wrap`,children:[B(`span`,{class:`ssh-login-field-icon`,"aria-hidden":`true`,children:B(Kt,{})}),B(`input`,{autoComplete:`new-password`,disabled:f,id:`smartsafehub-new-root-password`,name:`new-password`,onBlur:()=>d(!1),onInput:e=>a(e.currentTarget.value),onKeyDown:S,onKeyUp:S,placeholder:`새 관리자 비밀번호`,ref:n,type:c?`text`:`password`,value:i}),B(`button`,{"aria-label":c?`비밀번호 숨기기`:`비밀번호 표시`,"aria-pressed":c,class:`ssh-login-password-toggle`,disabled:f,onClick:()=>l(e=>!e),title:c?`비밀번호 숨기기`:`비밀번호 표시`,type:`button`,children:B(c?Jt:qt,{})})]})]}),B(`ul`,{class:`ssh-password-requirements`,"aria-label":`비밀번호 요구 사항`,children:[B(_n,{met:v.length,children:`8자 이상`}),B(_n,{met:v.letter,children:`영문자 1자 이상 포함`}),B(_n,{met:v.number,children:`숫자 1자 이상 포함`})]}),B(`label`,{class:`ssh-login-field`,for:`smartsafehub-confirm-root-password`,children:[B(`span`,{class:`ssh-login-label`,children:`비밀번호 확인`}),B(`span`,{class:`ssh-login-input-wrap`,children:[B(`span`,{class:`ssh-login-field-icon`,"aria-hidden":`true`,children:B(Kt,{})}),B(`input`,{autoComplete:`new-password`,disabled:f,id:`smartsafehub-confirm-root-password`,name:`confirm-password`,onBlur:()=>d(!1),onInput:e=>s(e.currentTarget.value),onKeyDown:S,onKeyUp:S,placeholder:`새 관리자 비밀번호 다시 입력`,ref:r,type:c?`text`:`password`,value:o})]})]}),o.length>0?B(`p`,{class:b?`ssh-password-match is-met`:`ssh-password-match`,role:`status`,children:b?`비밀번호가 일치합니다.`:`비밀번호가 일치하지 않습니다.`}):null,u?B(`p`,{class:`ssh-login-caps`,role:`status`,children:`Caps Lock이 켜져 있습니다.`}):null,B(`button`,{class:`ssh-login-submit`,disabled:f,type:`submit`,children:[f?B(H,{class:`ssh-login-submit-spinner`,"aria-hidden":`true`}):null,B(`span`,{children:f?`설정 중…`:`비밀번호 설정`})]})]}),B(`div`,{class:`ssh-login-security-note`,children:[B(At,{"aria-hidden":`true`}),B(`span`,{children:`비밀번호는 현재 공유기에 직접 설정되며 외부 서버로 전송되지 않습니다.`})]})]}),B(`footer`,{class:`ssh-login-footer`,children:[B(`span`,{children:`SmartSafeHub`}),B(`span`,{"aria-hidden":`true`,children:`·`}),B(`span`,{children:window.location.host})]})]})]})]})}var yn=Object.fromEntries([{route:`home`,hash:`#home`,label:`대시보드`,title:`대시보드`,description:`네트워크, 장치와 시스템 상태를 한눈에 확인합니다.`},{route:`activity`,hash:`#activity`,label:`최근 활동`,title:`최근 활동`,description:`현재 부팅 이후 인터넷, 보호, 업데이트와 진단 상태 변화를 확인합니다.`},{route:`network`,hash:`#network`,label:`네트워크`,title:`네트워크`,description:`인터넷 연결과 내부 네트워크 주소, DHCP 및 네트워크 충돌을 한 곳에서 관리합니다.`},{route:`wifi`,hash:`#wifi`,label:`Wi-Fi`,title:`Wi-Fi`,description:`기본 무선 네트워크의 이름, 보안과 사용 상태를 관리합니다.`},{route:`iptv`,hash:`#iptv`,label:`IPTV`,title:`IPTV`,description:`SK Broadband와 LG U+ 멀티캐스트 IPTV를 설정합니다.`},{route:`devices`,hash:`#devices`,label:`연결된 기기`,title:`연결된 기기`,description:`네트워크에서 확인된 기기와 연결 방식을 살펴봅니다.`},{route:`safeshield`,hash:`#safeshield`,label:`SafeShield`,title:`SafeShield`,description:`DNS 보호 상태를 확인하고 차단 목록을 관리합니다.`},{route:`rules`,hash:`#rules`,label:`사용자 규칙`,title:`사용자 규칙`,description:`직접 허용하거나 차단할 도메인을 관리합니다.`},{route:`system`,hash:`#system`,label:`업데이트`,title:`업데이트`,description:`기기의 펌웨어와 관리 소프트웨어 업데이트를 관리합니다.`},{route:`settings`,hash:`#settings`,label:`설정`,title:`설정`,description:`시스템 상태와 시간대를 확인하고 장치 관리 및 진단 기능을 설정합니다.`}].map(e=>[e.route,e]));function bn({description:e,loading:t,onRefresh:n,onToggleTheme:r,refreshing:i,theme:a,title:o}){return B(`header`,{class:`ssh-product-hero border-b border-slate-200 bg-white px-4 py-4 sm:px-6 md:h-[4.5rem] md:py-0 lg:px-8 xl:px-10`,children:B(`div`,{class:`flex w-full items-center justify-between gap-4 md:h-full`,children:[B(`div`,{class:`min-w-0`,children:[B(`p`,{class:`m-0 text-[0.68rem] font-extrabold uppercase tracking-[0.18em] text-teal-700`,children:`SmartSafeHub`}),B(`div`,{class:`mt-1 flex min-w-0 items-baseline gap-3`,children:[B(`h1`,{class:`m-0 truncate text-xl font-black tracking-tight text-slate-950 sm:text-2xl`,children:o}),B(`p`,{class:`m-0 hidden truncate text-sm text-slate-500 lg:block`,children:e})]})]}),B(`div`,{class:`flex shrink-0 items-center gap-2`,children:[B(`button`,{"aria-label":a===`dark`?`라이트 모드로 전환`:`다크 모드로 전환`,class:`ssh-product-header-action hidden h-10 w-10 shrink-0 items-center justify-center rounded-xl border border-slate-200 bg-white text-slate-600 shadow-sm transition hover:border-teal-300 hover:text-teal-700 focus:outline-none focus-visible:ring-4 focus-visible:ring-teal-100 md:inline-flex`,onClick:r,title:a===`dark`?`라이트 모드`:`다크 모드`,type:`button`,children:B(a===`dark`?ln:cn,{class:`size-5`})}),B(`button`,{"aria-busy":i,"aria-label":i?`새로고침 중`:`현재 화면 새로고침`,class:`ssh-product-header-action hidden h-10 w-10 shrink-0 items-center justify-center rounded-xl border border-slate-200 bg-white shadow-sm transition hover:border-teal-300 hover:text-teal-700 focus:outline-none focus-visible:ring-4 focus-visible:ring-teal-100 disabled:cursor-wait disabled:opacity-60 md:inline-flex ${i?`text-teal-700`:`text-slate-600`}`,disabled:t||i,onClick:n,title:i?`새로고침 중`:`새로고침`,type:`button`,children:i?B(H,{class:`size-5 animate-spin`}):B(H,{class:`size-5`})})]})]})})}var xn=[{label:`Overview`,routes:[`home`,`activity`]},{label:`Network`,routes:[`network`,`wifi`,`iptv`,`devices`]},{label:`Security`,routes:[`safeshield`,`rules`]},{label:`System`,routes:[`system`,`settings`]}];function Sn({route:e}){switch(e){case`home`:return B(Nt,{class:`size-5`});case`activity`:return B(Vt,{class:`size-5`});case`network`:return B(zt,{class:`size-5`});case`wifi`:return B(Lt,{class:`size-5`});case`iptv`:return B(Bt,{class:`size-5`});case`devices`:return B(Mt,{class:`size-5`});case`safeshield`:return B(At,{class:`size-5`});case`rules`:return B(Pt,{class:`size-5`});case`system`:return B(Ft,{class:`size-5`});case`settings`:return B(It,{class:`size-5`})}}function Cn({theme:e}){return B(e===`dark`?ln:cn,{class:`size-5`})}function wn(e){return e===`dark`?`라이트 모드`:`다크 모드`}function Tn(e,t=!1){return`relative flex min-h-11 min-w-0 items-center rounded-xl py-2.5 text-sm font-extrabold no-underline transition ${t?`justify-center px-2`:`gap-3 px-3`} ${e?`bg-teal-50 text-teal-800 ring-1 ring-inset ring-teal-200`:`text-slate-600 hover:bg-slate-50 hover:text-slate-950`}`}function En({collapsed:e=!1,route:t,updateCount:n}){return B(`div`,{class:e?`space-y-3`:`space-y-5`,children:xn.map((r,i)=>B(`section`,{"aria-label":r.label,class:e&&i>0?`border-t border-slate-100 pt-3`:void 0,children:[e?null:B(`p`,{class:`mb-2 px-3 text-[0.65rem] font-black uppercase tracking-[0.18em] text-slate-400`,children:r.label}),B(`div`,{class:`space-y-1`,children:r.routes.map(r=>{let i=yn[r],a=t===r;return B(`a`,{"aria-current":a?`page`:void 0,"aria-label":e?i.label:void 0,class:Tn(a,e),href:i.hash,title:e?i.label:void 0,children:[B(`span`,{class:`grid size-9 shrink-0 place-items-center rounded-lg ${a?`bg-teal-700 text-white`:`bg-slate-100 text-slate-500`}`,children:B(Sn,{route:r})}),e?null:B(`span`,{class:`flex min-w-0 flex-1 items-center gap-2`,children:[B(`span`,{class:`truncate`,children:i.label}),r===`iptv`?B(`span`,{class:`rounded-full border border-amber-300 bg-amber-100 px-1.5 py-0.5 text-[9px] font-black uppercase tracking-[0.08em] text-amber-800`,children:`Beta`}):null]}),e&&r===`iptv`?B(`span`,{"aria-label":`Beta 기능`,class:`absolute right-0.5 top-0.5 inline-flex size-5 items-center justify-center rounded-full border border-amber-300 bg-amber-100 text-[13px] font-extrabold leading-none text-amber-900 shadow-sm ring-2 ring-white`,children:`β`}):null,r===`system`&&n>0?e?B(`span`,{"aria-label":`${n}개의 업데이트 유형`,class:`ssh-update-nav-badge`,"data-collapsed":`true`,children:n}):B(`span`,{class:`ssh-update-nav-badge`,"data-collapsed":`false`,children:n}):null]},r)})})]},r.label))})}function Dn({collapsed:e,loading:t,onRefresh:n,onToggleCollapsed:r,onToggleTheme:i,refreshing:a,route:o,theme:s,title:c,updateCount:l}){let[u,d]=N(!1),f=wn(s);return P(()=>{d(!1)},[o]),P(()=>{if(!u)return;let e=e=>{e.key===`Escape`&&d(!1)};return window.addEventListener(`keydown`,e),()=>window.removeEventListener(`keydown`,e)},[u]),B(S,{children:[B(`nav`,{"aria-label":`SmartSafeHub 모바일 메뉴`,class:`ssh-mobile-navigation sticky top-0 z-40 border-b border-slate-200 bg-white/95 px-4 shadow-sm shadow-slate-900/5 backdrop-blur md:hidden`,children:[B(`div`,{class:`flex min-h-16 items-center justify-between gap-3`,children:[B(`a`,{class:`flex min-w-0 items-center gap-3 no-underline`,href:`#home`,children:[B(`span`,{class:`grid size-10 shrink-0 place-items-center rounded-xl bg-slate-950 text-teal-300`,children:B(At,{class:`size-5`})}),B(`span`,{class:`min-w-0`,children:[B(`strong`,{class:`block truncate text-sm font-black text-slate-950`,children:`SmartSafeHub`}),B(`span`,{class:`block truncate text-xs font-semibold text-slate-500`,children:c})]})]}),B(`div`,{class:`flex shrink-0 items-center gap-2`,children:[B(`button`,{"aria-label":`${f}로 전환`,class:`inline-flex size-11 shrink-0 items-center justify-center rounded-xl border border-slate-200 bg-white text-slate-600 transition hover:border-slate-300 hover:bg-slate-50 hover:text-teal-700 focus:outline-none focus-visible:ring-4 focus-visible:ring-teal-100`,onClick:i,title:f,type:`button`,children:B(Cn,{theme:s})}),B(`button`,{"aria-busy":a,"aria-label":a?`새로고침 중`:`현재 화면 새로고침`,class:`inline-flex size-11 shrink-0 items-center justify-center rounded-xl border border-slate-200 bg-white transition hover:border-slate-300 hover:bg-slate-50 hover:text-teal-700 focus:outline-none focus-visible:ring-4 focus-visible:ring-teal-100 disabled:cursor-wait disabled:opacity-60 ${a?`text-teal-700`:`text-slate-600`}`,disabled:t||a,onClick:n,title:a?`새로고침 중`:`새로고침`,type:`button`,children:a?B(H,{class:`size-5 animate-spin`}):B(H,{class:`size-5`})}),B(`button`,{"aria-controls":`smartsafehub-mobile-menu`,"aria-expanded":u,"aria-label":u?`모바일 메뉴 닫기`:`모바일 메뉴 열기`,class:`inline-flex size-11 shrink-0 items-center justify-center rounded-xl border border-slate-200 bg-white text-slate-700 transition hover:bg-slate-50 focus:outline-none focus-visible:ring-4 focus-visible:ring-teal-100`,onClick:()=>d(e=>!e),type:`button`,children:B(u?an:nn,{class:`size-5`})})]})]}),u?B(`div`,{class:`ssh-mobile-menu border-t border-slate-100 py-4`,id:`smartsafehub-mobile-menu`,children:[B(En,{route:o,updateCount:l}),B(`div`,{class:`mt-5 space-y-1 border-t border-slate-100 pt-4`,children:B(`a`,{class:`${Tn(!1)} text-rose-700 hover:bg-rose-50 hover:text-rose-800`,href:Ce(`/admin/logout`),children:[B(`span`,{class:`grid size-9 shrink-0 place-items-center rounded-lg bg-rose-50 text-rose-600`,children:B(tn,{class:`size-5`})}),`로그아웃`]})})]}):null]}),B(`aside`,{class:`hidden min-h-screen border-r border-slate-200 bg-white md:flex md:flex-col`,"data-collapsed":e?`true`:`false`,children:B(`div`,{class:`sticky top-0 flex h-screen flex-col`,children:[B(`div`,{class:`flex h-[4.5rem] min-h-[4.5rem] shrink-0 items-center border-b border-slate-100 ${e?`justify-center px-2`:`gap-3 px-4`}`,children:[B(`a`,{"aria-label":`SmartSafeHub Dashboard`,class:`flex items-center no-underline ${e?`justify-center`:`min-w-0 flex-1 gap-3`}`,href:`#home`,title:e?`SmartSafeHub`:void 0,children:[B(`span`,{class:`grid size-10 shrink-0 place-items-center rounded-xl bg-slate-950 text-teal-300 shadow-sm shadow-slate-950/10`,children:B(At,{class:`size-5`})}),e?null:B(`div`,{class:`min-w-0`,children:[B(`strong`,{class:`block truncate text-sm font-black tracking-tight text-slate-950`,children:`SmartSafeHub`}),B(`span`,{class:`block text-[0.68rem] font-bold uppercase tracking-[0.14em] text-slate-400`,children:`Home Gateway`})]})]}),B(`button`,{"aria-controls":`smartsafehub-desktop-navigation`,"aria-expanded":!e,"aria-label":e?`사이드바 펼치기`:`사이드바 접기`,class:`ssh-sidebar-toggle absolute right-0 top-[4.5rem] z-20 inline-flex size-7 translate-x-1/2 -translate-y-1/2 shrink-0 items-center justify-center rounded-full transition focus:outline-none focus-visible:ring-4 focus-visible:ring-teal-100`,onClick:r,title:e?`사이드바 펼치기`:`사이드바 접기`,type:`button`,children:B(e?sn:on,{class:`size-4`})})]}),B(`nav`,{"aria-label":`SmartSafeHub 메뉴`,class:`flex-1 overflow-y-auto py-5 ${e?`px-2`:`px-3`}`,id:`smartsafehub-desktop-navigation`,children:B(En,{collapsed:e,route:o,updateCount:l})}),B(`div`,{class:`border-t border-slate-100 ${e?`p-2`:`p-3`}`,children:B(`a`,{"aria-label":`SmartSafeHub에서 로그아웃`,class:`${Tn(!1,e)} mt-1 text-rose-700 hover:bg-rose-50 hover:text-rose-800`,href:Ce(`/admin/logout`),title:e?`로그아웃`:void 0,children:[B(`span`,{class:`grid size-9 shrink-0 place-items-center rounded-lg bg-rose-50 text-rose-600`,children:B(tn,{class:`size-5`})}),e?null:`로그아웃`]})})]})})]})}var On=`smartsafehub.sidebar.collapsed`;function kn(){if(typeof window>`u`)return!1;try{return window.localStorage.getItem(On)===`1`}catch{return!1}}function An({children:e,loading:t,onRefresh:n,refreshing:r,route:i,updateCount:a}){let o=yn[i],[s,c]=N(kn),[l,u]=N(dn);return P(()=>{try{window.localStorage.setItem(On,s?`1`:`0`)}catch{}},[s]),P(()=>{fn(l),pn(l)},[l]),B(`div`,{class:`ssh-app min-h-screen bg-slate-50 text-slate-950 md:grid md:transition-[grid-template-columns] md:duration-200 md:ease-out ${s?`md:grid-cols-[5rem_minmax(0,1fr)]`:`md:grid-cols-[16rem_minmax(0,1fr)]`}`,"data-theme":l,children:[B(Dn,{collapsed:s,loading:t,onRefresh:n,onToggleCollapsed:()=>c(e=>!e),onToggleTheme:()=>u(e=>e===`dark`?`light`:`dark`),refreshing:r,route:i,theme:l,title:o.title,updateCount:a}),B(`div`,{class:`min-w-0 md:min-h-screen`,children:[B(bn,{description:o.description,loading:t,onRefresh:n,onToggleTheme:()=>u(e=>e===`dark`?`light`:`dark`),refreshing:r,theme:l,title:o.title}),B(`main`,{class:`ssh-product-main w-full max-w-[1600px] bg-slate-50 px-4 pb-8 sm:px-6 sm:pb-10 lg:px-8 lg:pb-12 xl:px-10 ${t?`pt-2 sm:pt-2 lg:pt-3`:`pt-5 sm:pt-6 lg:pt-8`}`,children:e})]})]})}var W=`smartsafehub`,jn=`smartsafehub_network`;function Mn(){return z(W,`connected_devices`)}function Nn(){return{schema:1,scope:`current_boot`,volatile:!0,maxEvents:128,cloud:{enabled:!1,phase:`preparing`,eligible:null,plan:null,retentionDays:0,pendingEvents:0,lastAttemptAt:0,lastSuccessAt:0,lastUploadedCount:0,lastErrorCode:null,nextSyncAt:0},events:[]}}async function Pn(){let e=(await z(W,`status`)).activityHistory??Nn();return{...e,cloud:{...e.cloud,enabled:e.cloud.enabled??!0}}}function Fn(e){return z(W,`activity_cloud_sync_update`,{enabled:e})}function In(){return z(W,`status`)}function Ln(){return z(W,`license_status`,{},{timeoutMs:5e3})}function Rn(e){return z(W,`license_activate`,{license_key:e})}function zn(){return z(W,`health_status`)}function Bn(){return z(W,`health_run`)}function Vn(e){return z(W,`health_reporter_update`,{enabled:e})}function Hn(){return z(W,`updates_status`)}function Un(){return z(W,`firmware_status`)}function Wn(){return z(W,`firmware_check`)}function Gn(){return z(W,`firmware_prepare`)}function Kn(e){return z(W,`firmware_validate_upload`,{filename:e})}function qn(e){return z(W,`firmware_install`,{confirm:`install`,keep_settings:e})}function Jn(){return z(W,`firmware_discard`)}function Yn(){return z(W,`updates_check`)}function Xn(){return z(W,`updates_install`,{confirm:`install`})}function Zn(e){return z(W,`updates_settings_update`,{check_enabled:e.checkEnabled,check_interval_s:e.checkIntervalSeconds,auto_install:e.autoInstall,auto_install_time:e.autoInstallTime})}function Qn(){return z(W,`system_time_settings`)}function $n(e){return z(W,`system_timezone_update`,{zonename:e})}function er(){return z(W,`system_time_sync`)}function tr(){return z(W,`system_scheduled_reboot_settings`)}function nr(e){return z(W,`system_scheduled_reboot_update`,{enabled:e.enabled,frequency:e.frequency,day_of_week:e.dayOfWeek,time:e.time})}function rr(e){return z(W,`system_backup_validate`,{filename:e})}function ir(){return z(W,`system_backup_restore`,{confirm:`restore`},{timeoutMs:35e3})}function ar(){return z(W,`system_backup_discard`)}function or(){return z(W,`system_reboot`,{confirm:`reboot`})}function sr(){return z(jn,`wan_settings`)}function cr(e){return z(jn,`wan_update`,{protocol:e.protocol,pppoe_username:e.pppoeUsername,pppoe_password:e.pppoePassword,pppoe_password_changed:e.pppoePasswordChanged,static_address:e.staticAddress,static_prefix_length:e.staticPrefixLength,static_gateway:e.staticGateway,dns_primary:e.dnsPrimary,dns_secondary:e.dnsSecondary,confirm:`apply`},{timeoutMs:1e4})}function lr(){return z(jn,`wan_reconnect`,{confirm:`reconnect`},{timeoutMs:1e4})}function ur(){return z(jn,`lan_settings`)}function dr(e){return z(jn,`lan_update`,{ip_address:e.ipAddress,prefix_length:e.prefixLength,dhcp_enabled:e.dhcpEnabled,dhcp_start:e.dhcpStart,dhcp_end:e.dhcpEnd,lease_time:e.leaseTime,confirm:`apply`},{timeoutMs:1e4})}function fr(){return z(jn,`lan_auto_subnet`,{confirm:`apply`},{timeoutMs:1e4})}function pr(){return z(jn,`iptv_settings`)}function mr(e){return z(jn,`iptv_update`,{enabled:e.enabled,provider:e.provider,confirm:`apply`},{timeoutMs:2e4})}function hr(){return z(W,`wifi_summary`)}function gr(e){return z(W,`wifi_update`,{...e},{timeoutMs:35e3})}function G(e,t){return e instanceof R||e instanceof Error?e.message:t}function _r({active:e=!0,fallbackError:t,loader:n,pollInterval:r,refreshOnFocus:i=!1}){let[a,o]=N({data:null,error:null,loading:e,refreshing:!1}),s=F(!1),c=F(!0),l=F(null),u=F(null);P(()=>(c.current=!0,()=>{c.current=!1}),[]);let d=I((e=!1)=>{if(l.current)return l.current;c.current&&o(t=>({...t,error:null,loading:t.data===null,refreshing:e}));let r;return u.current=Date.now(),r=n().then(e=>{c.current&&o({data:e,error:null,loading:!1,refreshing:!1})}).catch(e=>{c.current&&o(n=>({...n,error:G(e,t),loading:!1,refreshing:!1}))}).finally(()=>{l.current===r&&(l.current=null)}),l.current=r,r},[t,n]);P(()=>{if(!e){s.current=!1;return}s.current||(s.current=!0,d())},[e,d]);let f=typeof r==`function`?r(a.data):r;P(()=>{if(!e||f==null||f<=0)return;let t=!1,n=null,r=()=>{n!==null&&(window.clearTimeout(n),n=null)},a=()=>u.current===null?0:Math.max(0,f-(Date.now()-u.current)),o=()=>{r(),!(t||document.visibilityState===`hidden`)&&(n=window.setTimeout(()=>{if(n=null,!(t||document.visibilityState===`hidden`)){if(a()>0){o();return}d(!1).finally(o)}},a()))},s=()=>{if(r(),!(t||document.visibilityState===`hidden`)){if(a()>0){o();return}d(!1).finally(o)}},c=()=>{if(document.visibilityState===`hidden`){r();return}s()},l=()=>{s()};return document.addEventListener(`visibilitychange`,c),i&&window.addEventListener(`focus`,l),o(),()=>{t=!0,r(),document.removeEventListener(`visibilitychange`,c),i&&window.removeEventListener(`focus`,l)}},[e,f,d,i]);let p=I(()=>d(!0),[d]),m=I(e=>{c.current&&o(t=>({...t,data:e,error:null,loading:!1,refreshing:!1}))},[]);return{...a,refresh:p,replaceData:m}}var vr=6e4;function yr(e){let t=_r({active:e,fallbackError:`최근 활동을 불러오지 못했습니다.`,loader:()=>Pn(),pollInterval:vr,refreshOnFocus:!0}),[n,r]=N({savingCloudSync:!1,actionError:null,actionMessage:null}),i=I(async e=>{r({savingCloudSync:!0,actionError:null,actionMessage:null});try{let n=await Fn(e);return t.replaceData(n),r({savingCloudSync:!1,actionError:null,actionMessage:e?`Cloud 활동 기록 전송을 켰습니다. 지금부터 발생하는 활동을 Cloud에 전송합니다.`:`Cloud 활동 기록 전송을 껐습니다. 로컬 최근 활동은 계속 기록됩니다.`}),!0}catch(e){return r({savingCloudSync:!1,actionError:G(e,`Cloud 활동 기록 설정을 변경하지 못했습니다.`),actionMessage:null}),!1}},[t.replaceData]),a=I(()=>{r(e=>({...e,actionError:null,actionMessage:null}))},[]);return{...t,...n,dismissActionFeedback:a,setCloudSyncEnabled:i}}var br=`/tmp/smartsafehub/config-backup.tar.gz`,xr=`/cgi-backup`,Sr=`/cgi-upload`;function Cr(){let e=window.__SMARTHUB_BOOTSTRAP__?.sessionId;if(!e)throw new R(`BOOTSTRAP_MISSING`,`LuCI 세션 정보를 찾을 수 없습니다.`);return e}function wr(e){return(e?.match(/filename="?([^";]+)"?/i))?.[1]?.trim()||`backup-openwrt.tar.gz`}function Tr(e,t){let n=URL.createObjectURL(t),r=document.createElement(`a`);r.href=n,r.download=e,r.style.display=`none`,(document.body??document.documentElement).appendChild(r),r.click(),r.remove(),window.setTimeout(()=>URL.revokeObjectURL(n),1e3)}async function Er(){let e=xe(xr),t=await fetch(e,{method:`POST`,credentials:`same-origin`,headers:{"Content-Type":`application/x-www-form-urlencoded;charset=UTF-8`},body:new URLSearchParams({sessionid:Cr()}).toString()});if(!t.ok)throw new R(`SYSTEM_BACKUP_DOWNLOAD_FAILED`,`설정 백업 생성에 실패했습니다. (HTTP ${t.status})`);let n=await t.blob();if(n.size<=0)throw new R(`SYSTEM_BACKUP_DOWNLOAD_EMPTY`,`설정 백업 파일이 비어 있습니다.`);Tr(wr(t.headers.get(`Content-Disposition`)),n)}function Dr(e,t){let n;try{n=Cr()}catch(e){return Promise.reject(e)}return new Promise((r,i)=>{let a=new XMLHttpRequest,o=new FormData;o.append(`sessionid`,n),o.append(`filename`,br),o.append(`filedata`,e),a.open(`POST`,xe(Sr)),a.timeout=0,a.upload.addEventListener(`progress`,e=>{!e.lengthComputable||e.total<=0||t?.(Math.min(100,Math.max(0,e.loaded/e.total*100)))}),a.addEventListener(`error`,()=>{i(new R(`SYSTEM_BACKUP_UPLOAD_FAILED`,`설정 백업 파일을 공유기에 업로드하지 못했습니다.`))}),a.addEventListener(`load`,()=>{if(a.status<200||a.status>=300){i(new R(`SYSTEM_BACKUP_UPLOAD_HTTP_ERROR`,`설정 백업 업로드가 HTTP ${a.status} 오류를 반환했습니다.`));return}let n;try{n=JSON.parse(a.responseText)}catch{i(new R(`SYSTEM_BACKUP_UPLOAD_INVALID_RESPONSE`,`설정 백업 업로드 응답을 확인하지 못했습니다.`));return}if(n.failure){i(new R(n.failure,n.message||`설정 백업 파일 업로드가 거부되었습니다.`));return}t?.(100),r({...n,name:e.name})}),a.send(o)})}var Or=16777216;function kr(){let[e,t]=N(null),[n,r]=N(null),[i,a]=N(null),[o,s]=N(null),[c,l]=N(null),[u,d]=N(!1),f=I(async()=>{t(`download`),r(null),a(null);try{await Er(),a(`현재 설정 백업을 다운로드했습니다.`)}catch(e){r(G(e,`설정 백업을 다운로드하지 못했습니다.`))}finally{t(null)}},[]),p=I(async e=>{if(r(null),a(null),s(null),d(!1),e.size<=0||e.size>Or)return r(`설정 백업 파일은 16MB 이하여야 합니다.`),!1;try{t(`upload`),l(0),await Dr(e,l),t(`validate`);let n=await rr(e.name);return s(n),a(`백업 파일 검증이 완료되었습니다. 복원 내용을 확인해 주세요.`),!0}catch(e){return r(G(e,`설정 백업 파일을 검증하지 못했습니다.`)),!1}finally{t(null),l(null)}},[]),m=I(async()=>{t(`discard`),r(null),a(null);try{return await ar(),s(null),d(!1),a(`업로드한 백업 파일을 삭제했습니다.`),!0}catch(e){return r(G(e,`업로드한 백업 파일을 삭제하지 못했습니다.`)),!1}finally{t(null)}},[]),h=I(async()=>{if(!o)return r(`먼저 복원할 백업 파일을 업로드하고 검증해 주세요.`),!1;t(`restore`),r(null),a(null);try{let e=await ir();return d(e.accepted&&e.rebooting),s(null),a(e.accepted?`설정을 복원했습니다. 공유기가 재부팅되며 네트워크 설정에 따라 다시 연결해야 할 수 있습니다.`:`설정 복원 요청이 접수되지 않았습니다.`),e.accepted}catch(e){return r(G(e,`설정 백업을 복원하지 못했습니다.`)),!1}finally{t(null)}},[o]);return{action:e,discard:m,dismissFeedback:I(()=>{r(null),a(null)},[]),download:f,error:n,message:i,restore:h,restoreAccepted:u,upload:p,uploadProgress:c,validated:o}}var Ar=15e3;function jr(e,t=!0){return _r({active:e,fallbackError:`연결된 기기 목록을 불러오지 못했습니다.`,loader:Mn,...t?{pollInterval:Ar}:{}})}var Mr=`/tmp/smartsafehub/firmware.bin`,Nr=`/cgi-upload`;function Pr(e,t){let n=window.__SMARTHUB_BOOTSTRAP__;return n?.sessionId?new Promise((r,i)=>{let a=new XMLHttpRequest,o=new FormData;o.append(`sessionid`,n.sessionId),o.append(`filename`,Mr),o.append(`filedata`,e);let s=xe(Nr);a.open(`POST`,s),a.timeout=0,a.upload.addEventListener(`progress`,e=>{!e.lengthComputable||e.total<=0||t?.(Math.min(100,Math.max(0,e.loaded/e.total*100)))}),a.addEventListener(`error`,()=>{console.error(`[SmartSafeHub] firmware upload network error`,{endpoint:s,destination:Mr,fileName:e.name,fileSize:e.size,readyState:a.readyState,status:a.status}),i(new R(`FIRMWARE_UPLOAD_FAILED`,`펌웨어 파일 업로드에 실패했습니다. (${s}, 네트워크 오류)`))}),a.addEventListener(`load`,()=>{if(a.status<200||a.status>=300){console.error(`[SmartSafeHub] firmware upload HTTP error`,{endpoint:s,destination:Mr,fileName:e.name,fileSize:e.size,readyState:a.readyState,status:a.status,response:a.responseText}),i(new R(`FIRMWARE_UPLOAD_HTTP_ERROR`,`펌웨어 업로드가 HTTP ${a.status} 오류를 반환했습니다. (${s})`));return}let n;try{n=JSON.parse(a.responseText)}catch{console.error(`[SmartSafeHub] firmware upload returned invalid JSON`,{endpoint:s,destination:Mr,fileName:e.name,fileSize:e.size,readyState:a.readyState,status:a.status,response:a.responseText}),i(new R(`FIRMWARE_UPLOAD_INVALID_RESPONSE`,`펌웨어 업로드 응답을 확인하지 못했습니다. (${s})`));return}if(n.failure){i(new R(n.failure,n.message||`펌웨어 파일 업로드가 거부되었습니다.`));return}t?.(100),r({...n,name:e.name})}),a.send(o)}):Promise.reject(new R(`BOOTSTRAP_MISSING`,`LuCI 세션 정보를 찾을 수 없습니다.`))}var Fr=3e5,Ir=1e3,Lr=500,Rr=3e3,zr=3e4,Br=15e3,Vr=5e3;function Hr(e){return new Promise(t=>window.setTimeout(t,e))}function Ur(e){return e===`checking`||e===`downloading`||e===`verifying`}function Wr(e=!0){let t=_r({active:e,fallbackError:`펌웨어 업데이트 상태를 불러오지 못했습니다.`,loader:Un,pollInterval:e=>Ur(e?.phase)?Ir:Fr,refreshOnFocus:!0}),[n,r]=N(null),[i,a]=N(null),[o,s]=N(null),[c,l]=N(null),[u,d]=N(!1),f=F(null);P(()=>()=>{f.current!==null&&window.clearTimeout(f.current)},[]);let p=I(e=>{t.data&&t.replaceData({...t.data,phase:e,lastError:null})},[t]),m=I(async(e,n,i,o)=>{r(e),a(null),s(null);try{if(!(await i()).accepted)throw Error(`펌웨어 작업 요청이 접수되지 않았습니다.`);p(n),r(null),window.setTimeout(()=>void t.refresh(),400)}catch(e){r(null),a(G(e,o))}},[p,t]),h=I(()=>m(`check`,`checking`,Wn,`펌웨어 업데이트 확인을 시작하지 못했습니다.`),[m]),g=I(()=>m(`prepare`,`downloading`,Gn,`펌웨어 다운로드를 시작하지 못했습니다.`),[m]),_=I(async()=>{let e=Date.now(),n=null;for(;Date.now()-e{r(`upload`),a(null),s(null),l(0);try{if(await Pr(e,l),r(`validate-upload`),!(await Kn(e.name)).accepted)throw Error(`업로드한 펌웨어 검증 요청이 접수되지 않았습니다.`);p(`verifying`),l(null);let t=await _();if(r(null),t.phase===`error`)return!1;if(!t.prepared)throw Error(`검증된 펌웨어의 설치 준비 정보를 확인하지 못했습니다. 다시 시도해 주세요.`);return s(`펌웨어 검증이 완료되었습니다. 설치 옵션을 확인해 주세요.`),!0}catch(e){return r(null),l(null),a(G(e,`펌웨어 파일을 업로드하지 못했습니다.`)),!1}},[p,_]),y=I(()=>{d(!0);let e=async()=>{try{if((await fetch(window.location.pathname,{cache:`no-store`,credentials:`same-origin`})).ok){window.location.reload();return}}catch{}f.current=window.setTimeout(e,Vr)};f.current=window.setTimeout(e,Br)},[]),b=I(async e=>{r(`install`),a(null),s(null);try{if(!(await qn(e)).accepted)throw Error(`펌웨어 설치 요청이 접수되지 않았습니다.`);return p(`flashing`),r(null),y(),!0}catch(e){return r(null),a(G(e,`펌웨어 설치를 시작하지 못했습니다.`)),!1}},[p,y]),x=I(async()=>{r(`discard`),a(null),s(null);try{if(!(await Jn()).accepted)throw Error(`준비된 펌웨어 정리 요청이 접수되지 않았습니다.`);return r(null),s(`준비된 펌웨어 파일을 삭제했습니다.`),await t.refresh(),!0}catch(e){return r(null),a(G(e,`준비된 펌웨어를 정리하지 못했습니다.`)),!1}},[t]),S=I(()=>{a(null),s(null)},[]);return{...t,action:n,actionError:i,message:o,uploadProgress:c,reconnecting:u,check:h,prepare:g,upload:v,install:b,discard:x,dismissFeedback:S}}var Gr={"#home":`home`,"#activity":`activity`,"#network":`network`,"#wan":`network`,"#lan":`network`,"#wifi":`wifi`,"#iptv":`iptv`,"#devices":`devices`,"#safeshield":`safeshield`,"#rules":`rules`,"#system":`system`,"#settings":`settings`};function Kr(){return Gr[window.location.hash]??`home`}function qr(){let[e,t]=N(Kr);return P(()=>{let e=()=>t(Kr());return window.addEventListener(`hashchange`,e),()=>window.removeEventListener(`hashchange`,e)},[]),e}var Jr=6e4,Yr=1e3,Xr=[400,800,1200,1600],Zr=[400,800,1200,2e3,4e3];function Qr(e){return new Promise(t=>window.setTimeout(t,e))}function $r(e){let t=_r({active:e,fallbackError:`장치 진단 상태를 불러오지 못했습니다.`,loader:zn,pollInterval:e=>e?.generatedAt?Jr:Yr,refreshOnFocus:!0}),n=F(0),[r,i]=N({running:!1,savingReporter:!1,actionError:null,actionMessage:null}),a=I(async()=>{i({running:!0,savingReporter:!1,actionError:null,actionMessage:null});try{let e=t.data?.generatedAt??0;if(!(await Bn()).accepted)throw Error(`장치가 진단 요청을 접수하지 않았습니다.`);let n=t.data;for(let t of Xr)if(await Qr(t),n=await zn(),n.generatedAt>0&&n.generatedAt!==e)break;return n&&t.replaceData(n),i({running:!1,savingReporter:!1,actionError:null,actionMessage:`장치 상태를 다시 진단했습니다.`}),!0}catch(e){return i({running:!1,savingReporter:!1,actionError:G(e,`장치 상태 진단을 실행하지 못했습니다.`),actionMessage:null}),!1}},[t.data,t.replaceData]),o=I(async(e,r)=>{for(let i of Zr){if(await Qr(i),n.current!==r)return;try{let i=await zn();if(n.current!==r)return;if(t.replaceData(i),i.reporter.enabled!==e)continue;if(!e||![`disabled`,`never`,`initializing`].includes(i.reporter.lastResult))return}catch{}}},[t.replaceData]),s=I(async e=>{let r=n.current+1;n.current=r;let a=t.data;a&&t.replaceData({...a,reporter:{...a.reporter,enabled:e,lastResult:e?`initializing`:`disabled`,lastErrorCode:null,nextReportAt:e?a.reporter.nextReportAt:0}}),i({running:!1,savingReporter:!0,actionError:null,actionMessage:null});try{let a=await Vn(e);return n.current!==r||(t.replaceData(a),i({running:!1,savingReporter:!1,actionError:null,actionMessage:e?`원격 상태 보고를 켰습니다. 첫 서버 보고를 준비합니다.`:`원격 상태 보고를 껐습니다. 로컬 진단은 계속 동작합니다.`}),o(e,r),!0)}catch(e){return n.current===r&&(a&&t.replaceData(a),i({running:!1,savingReporter:!1,actionError:G(e,`원격 상태 보고 설정을 변경하지 못했습니다.`),actionMessage:null})),!1}},[o,t.data,t.replaceData]),c=I(()=>{i(e=>({...e,actionError:null,actionMessage:null}))},[]);return{...t,...r,dismissActionFeedback:c,runDiagnostic:a,setReporterEnabled:s}}function ei(e){let t=_r({active:e,fallbackError:`IPTV 설정을 불러오지 못했습니다.`,loader:pr,refreshOnFocus:!0}),[n,r]=N(!1),[i,a]=N(null),o=I(async e=>{r(!0),a(null);try{let n=await mr(e);return t.replaceData(n.settings),r(!1),a({kind:`success`,message:e.enabled?n.changed?`IPTV 설정을 적용했습니다.`:`IPTV 설정을 다시 적용했습니다.`:`IPTV 기능을 껐습니다.`}),!0}catch(e){return r(!1),a({kind:`error`,message:G(e,`IPTV 설정을 적용하지 못했습니다.`)}),!1}},[t.replaceData]),s=I(()=>a(null),[]);return{...t,saving:n,feedback:i,save:o,dismissFeedback:s}}var ti=4e3;function ni(e){let t=_r({active:e,fallbackError:`내부 네트워크 설정을 불러오지 못했습니다.`,loader:ur}),n=F(e),[r,i]=N({action:null,feedback:null});P(()=>{n.current=e},[e]);let a=I((e,r)=>{if(t.replaceData(e.settings),!e.changed){i({action:null,feedback:{kind:`success`,message:`변경된 내부 네트워크 설정이 없습니다.`}});return}if(e.addressChanged){i({action:null,feedback:{kind:`warning`,message:r?`추천 대역 ${e.settings.lan.subnet}을 저장했습니다. 네트워크가 다시 적용되면 새 공유기 주소로 다시 연결해 주세요.`:`내부 네트워크 주소를 저장했습니다. 네트워크가 다시 적용되면 새 공유기 주소로 다시 연결해 주세요.`,newAddress:e.newAddress??e.settings.lan.address}});return}i({action:null,feedback:{kind:`success`,message:r?`추천 내부 네트워크 설정을 적용했습니다.`:`내부 네트워크 설정을 저장했습니다.`}}),e.reloadScheduled&&window.setTimeout(()=>{n.current&&t.refresh()},ti)},[t.refresh,t.replaceData]),o=I(async e=>{i({action:`saving`,feedback:null});try{let t=await dr(e);return a(t,!1),!0}catch(e){return i({action:null,feedback:{kind:`error`,message:G(e,`내부 네트워크 설정을 저장하지 못했습니다.`)}}),!1}},[a]),s=I(async()=>{i({action:`auto`,feedback:null});try{let e=await fr();return a(e,!0),!0}catch(e){return i({action:null,feedback:{kind:`error`,message:G(e,`추천 내부 네트워크를 적용하지 못했습니다.`)}}),!1}},[a]),c=I(()=>{i(e=>({...e,feedback:null}))},[]);return{...t,...r,save:o,applyRecommendation:s,dismissFeedback:c}}var ri=5e3;function ii(e){let t=_r({active:e,fallbackError:`인터넷 연결 설정을 불러오지 못했습니다.`,loader:sr}),n=F(e),[r,i]=N({action:null,feedback:null});P(()=>{n.current=e},[e]);let a=I(()=>{window.setTimeout(()=>{n.current&&t.refresh()},ri)},[t.refresh]),o=I(async e=>{i({action:`saving`,feedback:null});try{let n=await cr(e);return t.replaceData(n.settings),i({action:null,feedback:{kind:n.changed?`warning`:`success`,message:n.changed?`인터넷 연결 설정을 저장했습니다. WAN을 다시 연결하는 동안 잠시 인터넷이 끊길 수 있습니다.`:`변경된 인터넷 연결 설정이 없습니다.`}}),n.reconnectScheduled&&a(),!0}catch(e){return i({action:null,feedback:{kind:`error`,message:G(e,`인터넷 연결 설정을 저장하지 못했습니다.`)}}),!1}},[t.replaceData,a]),s=I(async()=>{i({action:`reconnecting`,feedback:null});try{let e=await lr();t.replaceData(e.settings),i({action:null,feedback:{kind:`warning`,message:`WAN 재연결을 시작했습니다. 인터넷 연결이 다시 올라오면 상태를 자동으로 새로고침합니다.`}}),e.reconnectScheduled&&a()}catch(e){i({action:null,feedback:{kind:`error`,message:G(e,`WAN 재연결을 시작하지 못했습니다.`)}})}},[t.replaceData,a]),c=I(()=>{i(e=>({...e,feedback:null}))},[]);return{...t,...r,save:o,reconnect:s,dismissFeedback:c}}var ai=`safeshield`,oi=`smartsafehub`;function si(e,t){return typeof e==`string`&&e.length>0?e:t}function ci(e){return typeof e==`string`?e:``}function li(e){return typeof e==`number`&&Number.isFinite(e)?e:0}function K(e){return e===!0}function ui(e){return Array.isArray(e)?e.length:0}function di(e){return Array.isArray(e)?e.filter(e=>typeof e==`string`):[]}function fi(e){return typeof e==`object`&&e&&!Array.isArray(e)?e:{}}function pi(e){let t=fi(e.error),n=ci(t.code)||`UNKNOWN_ERROR`,r=ci(t.message)||`SafeShield API 요청을 처리하지 못했습니다.`;return new R(`SAFESHIELD_${n.toUpperCase()}`,r)}async function mi(e,t={}){let n=await Et(ai,e,t),r=fi(n);if(r.ok===!1)throw pi(r);return n}async function hi(e,t,n,r=t){try{return await z(oi,e,t)}catch(e){if(e instanceof R&&[`RPC_PERMISSION_DENIED`,`UBUS_3`,`UBUS_6`].includes(e.code))return mi(n,r);throw e}}function gi(){return{enabled:!1,collectorRunning:!1,available:!1,schemaVersion:0,volatile:!0,startedAt:0,updatedAt:0,retentionHours:0,totals:{queries:0,blocked:0},hourly:[],deviceLimit:0,devicesTruncated:!1,devices:[]}}function _i(e){let t=fi(e);if(Object.keys(t).length===0)return gi();let n=fi(t.schema),r=fi(t.totals),i=Array.isArray(t.hourly)?t.hourly.map(e=>fi(e)).map(e=>({bucketStart:li(e.bucket_start),queries:li(e.queries),blocked:li(e.blocked)})).filter(e=>e.bucketStart>0).sort((e,t)=>e.bucketStart-t.bucketStart):[],a=Array.isArray(t.devices)?t.devices.map(e=>fi(e)).map(e=>{let t=ci(e.ip),n=ci(e.mac);return{id:ci(e.id)||n||(t?`ip:${t}`:``),mac:n,ip:t,hostname:ci(e.hostname),identified:K(e.identified),queries:li(e.queries),blocked:li(e.blocked)}}).filter(e=>e.id.length>0):[];return{enabled:K(t.enabled),collectorRunning:K(t.collector_running),available:t.available!==!1,schemaVersion:li(n.version),volatile:t.volatile!==!1,startedAt:li(t.started_at),updatedAt:li(t.updated_at),retentionHours:li(t.retention_hours),totals:{queries:li(r.queries),blocked:li(r.blocked)},hourly:i,deviceLimit:li(t.device_limit),devicesTruncated:K(t.devices_truncated),devices:a}}function vi(){return{available:!1,version:null,enabled:!1,active:!1,status:`unavailable`,stage:null,summary:{label:`Unavailable`,message:`SafeShield status API is unavailable`,severity:`warning`},runtime:{refreshdRunning:!1,dnsmasqRunning:!1,dnsRuntimeOk:!1,lastResult:null,lastErrorCode:null},license:{configured:!1,keyMasked:``,plan:null,status:null},artifact:{resolved:!1,tier:null,version:null,uniqueDomains:0,rules:0},localOverrides:{enabled:!1,allowlistPath:null,blocklistPath:null},blocklist:{installed:!1,validLineCount:0,fileSizeKb:0,verificationOk:!1},health:{overall:`unavailable`},issueCounts:{warnings:0,errors:0},timestamps:{lastAttempt:0,lastSuccess:0,lastFailure:0,lastLocalApply:0,lastLocalApplyFailure:0,nextRefreshAt:0,refreshIntervalS:0}}}function yi(e){let t=fi(e);if(Object.keys(t).length===0)return vi();let n=fi(t.summary),r=fi(t.runtime),i=fi(t.license),a=fi(t.artifact),o=fi(t.local_overrides),s=fi(t.blocklist),c=fi(t.health),l=fi(t.timestamps);return{available:!0,version:si(t.version,null),enabled:K(t.enabled),active:K(t.active),status:si(t.status,`unknown`)??`unknown`,stage:si(t.stage,null),summary:{label:si(n.label,`Unknown`)??`Unknown`,message:si(n.message,`SafeShield status is unknown`)??`SafeShield status is unknown`,severity:si(n.severity,`warning`)??`warning`},runtime:{refreshdRunning:K(r.refreshd_running),dnsmasqRunning:K(r.dnsmasq_running),dnsRuntimeOk:K(r.dns_runtime_ok),lastResult:si(r.last_result,null),lastErrorCode:si(r.last_error_code,null)},license:{configured:K(i.configured),keyMasked:ci(i.key_masked),plan:si(i.plan,null),status:si(i.status,null)},artifact:{resolved:K(a.resolved),tier:si(a.tier,null),version:si(a.version,null),uniqueDomains:li(a.unique_domains),rules:li(a.rules)},localOverrides:{enabled:K(o.enabled),allowlistPath:si(o.allowlist_path,null),blocklistPath:si(o.blocklist_path,null)},blocklist:{installed:K(s.installed),validLineCount:li(s.valid_line_count),fileSizeKb:li(s.file_size_kb),verificationOk:K(s.verification_ok)},health:{overall:si(c.overall,`unknown`)??`unknown`},issueCounts:{warnings:ui(t.warnings),errors:ui(t.errors)},timestamps:{lastAttempt:li(l.last_attempt),lastSuccess:li(l.last_success),lastFailure:li(l.last_failure),lastLocalApply:li(l.last_local_apply),lastLocalApplyFailure:li(l.last_local_apply_failure),nextRefreshAt:li(l.next_refresh_at),refreshIntervalS:li(l.refresh_interval_s)}}}function bi(e){let t=fi(fi(e).values);return{enabled:K(t.enabled),applyLocalOverrides:K(t.apply_local_overrides)}}function xi(e){let t=fi(e);return{requested:K(t.requested),accepted:K(t.accepted),reason:ci(t.reason)}}async function Si(){try{return _i(await mi(`statistics`))}catch(e){if(e instanceof R&&[`UBUS_3`,`UBUS_4`,`UBUS_5`].includes(e.code))return gi();throw e}}async function Ci(e){let t=await hi(`safeshield_statistics_update`,{enabled:e},`config_update`,{values:{statistics_enabled:e}});return{changed:Array.isArray(t.changed)?t.changed.some(e=>e===`statistics_enabled`):!1,enabled:e,restarted:K(t.restarted),reconciled:K(t.reconciled)}}async function wi(){try{return yi(await mi(`status`))}catch(e){if(e instanceof R&&[`UBUS_3`,`UBUS_4`,`UBUS_5`].includes(e.code))return vi();throw e}}async function Ti(){return bi(await mi(`config`))}async function Ei(e){let t=await hi(`safeshield_set_enabled`,{enabled:e},`set_enabled`);return{changed:K(t.changed),accepted:K(t.accepted),targetEnabled:K(t.target_enabled),reconciled:K(t.reconciled)}}async function Di(){let e=await hi(`safeshield_refresh`,{},`refresh`);return{accepted:K(e.accepted),reason:ci(e.reason),status:yi(e.status)}}async function Oi(){let[e,t]=await Promise.all([mi(`rules_list`),Ti()]),n=di(e.allow),r=di(e.block);return{allow:n,block:r,counts:{allow:n.length,block:r.length,total:n.length+r.length},safeshieldEnabled:t.enabled,applyLocalOverrides:t.applyLocalOverrides}}async function ki(e,t,n,r=!0){let i=await hi(e===`rule_add`?`safeshield_rule_add`:`safeshield_rule_delete`,{action:t,domain:n,refresh:r},e),a=K(e===`rule_add`?i.added:i.deleted);return{action:t,domain:ci(i.domain)||n,changed:a,refresh:xi(i.refresh),rules:await Oi()}}function Ai(e,t,n=!0){return ki(`rule_add`,e,t,n)}function ji(e,t,n=!0){return ki(`rule_delete`,e,t,n)}async function Mi(){let e=fi((await mi(`license_get`)).license);return{configured:K(e.configured),key:ci(e.key)}}async function Ni(e){let t=await hi(`safeshield_license_update`,{license_key:e},`license_update`),n=fi(t.license);return{changed:K(t.changed),license:{configured:K(n.configured),keyMasked:ci(n.key_masked)},refresh:xi(t.refresh)}}var Pi=4500,Fi=1e3,Ii=30,Li=2;function Ri(e){switch(e){case`license_invalid`:return`유효하지 않은 라이선스 키입니다.`;case`safeshield_upgrade_required`:return`라이선스를 등록하려면 SafeShield를 먼저 업데이트해 주세요.`;case`LICENSE_DEVICE_IDENTITY_UNAVAILABLE`:case`LICENSE_DEVICE_PROFILE_UNAVAILABLE`:return`라이선스 등록에 필요한 장치 정보를 확인하지 못했습니다.`;case`LICENSE_LOCAL_UPDATE_FAILED`:return`서버 등록은 완료했지만 이 기기에 라이선스 키를 적용하지 못했습니다.`;case`LICENSE_ACTIVATE_HTTP_FAILED`:return`라이선스 서버에 연결하지 못했습니다.`;default:return`라이선스 등록을 완료하지 못했습니다.`}}function zi(e){return new Promise(t=>window.setTimeout(t,e))}function Bi(e){return e.startsWith(`license-`)?`license`:`global`}function Vi(e){return e instanceof R&&[`RPC_TIMEOUT`,`NETWORK_ERROR`,`UBUS_10`].includes(e.code)}function Hi(e,t){let[n,r]=N({action:null,error:null,feedbackTarget:null,message:null}),i=F([]),a=F([]),o=F(null),s=I(()=>{for(let e of i.current)window.clearTimeout(e);i.current=[]},[]),c=I(()=>{for(let e of a.current)window.clearTimeout(e);a.current=[]},[]),l=I(()=>{o.current!==null&&(window.clearTimeout(o.current),o.current=null)},[]),u=I(e=>{l(),r({action:e,error:null,feedbackTarget:Bi(e),message:null})},[l]),d=I((e,t=`global`)=>{l(),r({action:null,error:null,feedbackTarget:t,message:e}),o.current=window.setTimeout(()=>{o.current=null,r(e=>e.error!==null||e.action!==null?e:{...e,feedbackTarget:null,message:null})},Pi)},[l]),f=I(t=>{s(),i.current=t.map(t=>window.setTimeout(()=>{e()},t))},[s,e]),p=I(e=>{c(),a.current=e.map(e=>window.setTimeout(()=>{t()},e))},[c,t]);P(()=>()=>{s(),c(),l()},[l,c,s]);let m=I(async t=>{u(t?`enable`:`disable`);try{let n=await Ei(t);d(n.changed?t?`SafeShield 보호 활성화 요청을 적용했습니다.`:`SafeShield 보호 비활성화 요청을 적용했습니다.`:t?`SafeShield 보호가 이미 활성화 상태입니다.`:`SafeShield 보호가 이미 비활성화 상태입니다.`),await e(),f([800,2e3,5e3])}catch(e){r({action:null,error:G(e,`SafeShield 작업을 수행하지 못했습니다.`),feedbackTarget:`global`,message:null})}},[u,e,f,d]),h=I(async e=>{u(e?`statistics-enable`:`statistics-disable`);try{let n=await Ci(e);await t(),d(n.changed?n.reconciled?e?`차단 통계 수집을 활성화했습니다.`:`차단 통계 수집을 비활성화했습니다.`:`차단 통계 설정을 저장했습니다.`:e?`차단 통계 수집이 이미 활성화되어 있습니다.`:`차단 통계 수집이 이미 비활성화되어 있습니다.`),n.changed&&p([500,1500])}catch(e){r({action:null,error:G(e,`차단 통계 설정을 변경하지 못했습니다.`),feedbackTarget:`global`,message:null})}},[u,t,p,d]),g=I(async()=>{u(`refresh`);try{await Di(),r({action:null,error:null,feedbackTarget:null,message:null}),f([700,2500,6e3,12e3])}catch(e){r({action:null,error:G(e,`SafeShield 작업을 수행하지 못했습니다.`),feedbackTarget:`global`,message:null})}},[u,f]),_=I(async t=>{let n=t.trim();if(!n)return l(),r({action:null,error:`라이선스 키를 입력해 주세요.`,feedbackTarget:`license`,message:null}),!1;u(`license-update`);try{let t=await Rn(n);if(!t.accepted)throw Error(`라이선스 등록 요청을 시작하지 못했습니다.`);let r=!1,i=0;for(let e=0;e=t.startedAt){r=!0;break}if(e.phase===`error`&&e.lastAttemptAt>=t.startedAt)throw Error(Ri(e.lastErrorCode))}if(!r)throw Error(`라이선스 등록 결과 확인이 지연되고 있습니다. 잠시 후 상태를 다시 확인해 주세요.`);return d(`라이선스를 서버에 등록하고 이 기기에 적용했습니다.`,`license`),await e(),f([800,2500,6e3,12e3]),!0}catch(e){return r({action:null,error:G(e,`라이선스를 등록하지 못했습니다.`),feedbackTarget:`license`,message:null}),!1}},[u,l,e,f,d]),v=I(async()=>{u(`license-read`);try{let e=await Mi();return r({action:null,error:null,feedbackTarget:null,message:null}),e.key}catch(e){return r({action:null,error:G(e,`라이선스 키를 불러오지 못했습니다.`),feedbackTarget:`license`,message:null}),null}},[u]),y=I(async()=>{u(`license-remove`);try{let t=await Ni(``);return d(t.changed?`라이선스 키를 제거했습니다.`:`설정된 라이선스 키가 없습니다.`,`license`),await e(),t.refresh.requested&&f([800,2500,6e3,12e3]),!0}catch(e){return r({action:null,error:G(e,`라이선스 키를 제거하지 못했습니다.`),feedbackTarget:`license`,message:null}),!1}},[u,e,f,d]),b=I(()=>{l(),r(e=>({...e,error:null,feedbackTarget:null,message:null}))},[l]);return{...n,dismissFeedback:b,readLicense:v,refreshBlocklist:g,removeLicense:y,setEnabled:m,setStatisticsEnabled:h,updateLicense:_}}var Ui=500,Wi=45e3;function Gi(e){return new Promise(t=>window.setTimeout(t,e))}function Ki(e){return e===`allow`?`허용`:`차단`}function qi(e,t){if(!t.changed)return e===`add`?t.action===`allow`?`이미 허용 목록에 있는 도메인입니다.`:`이미 차단 목록에 있는 도메인입니다.`:`이미 삭제된 규칙입니다.`;let n=Ki(t.action),r=e===`add`?`저장`:`삭제`;return t.rules.safeshieldEnabled?t.rules.applyLocalOverrides?`${t.domain} ${n} 규칙을 ${r}했습니다.`:`${t.domain} ${n} 규칙을 ${r}했습니다. 로컬 규칙 적용 설정이 꺼져 있어 아직 DNS에는 반영되지 않습니다.`:`${t.domain} ${n} 규칙을 ${r}했습니다. SafeShield를 켜면 다음 갱신에서 적용됩니다.`}function Ji(e,t){let n=e===`add`?`추가`:`삭제`;return`${t.domain} ${Ki(t.action)} 규칙 ${n}를 저장했습니다. 로컬 규칙을 DNS에 적용하고 있습니다…`}function Yi(e,t){let n=e===`add`?`추가`:`삭제`;return`${t.domain} ${Ki(t.action)} 규칙 ${n}와 DNS 적용이 완료되었습니다.`}async function Xi(e){let t=Date.now()+Wi,n=null;for(;Date.now()e.timestamps.lastLocalApply)return{kind:`success`,status:n};if(n.timestamps.lastLocalApplyFailure>e.timestamps.lastLocalApplyFailure)return{kind:`failure`,status:n};await Gi(Ui)}return{kind:`timeout`,status:n}}function Zi(e){let t=_r({active:e,fallbackError:`사용자 규칙을 불러오지 못했습니다.`,loader:Oi}),[n,r]=N({action:null,error:null,feedback:null}),i=I(async(e,n,i)=>{r({action:{operation:e,action:n,domain:i},error:null,feedback:null});try{let a=await wi(),o=e===`add`?await Ai(n,i,!0):await ji(n,i,!0);if(t.replaceData(o.rules),!(o.changed&&o.rules.safeshieldEnabled&&o.rules.applyLocalOverrides))return r({action:null,error:null,feedback:qi(e,o)}),!0;if(!o.refresh.accepted)return r({action:null,error:`규칙은 저장되었지만 로컬 DNS 적용 요청을 시작하지 못했습니다${o.refresh.reason?` (${o.refresh.reason})`:``}.`,feedback:null}),!0;r({action:null,error:null,feedback:Ji(e,o)});let s=await Xi(a);return s.kind===`success`?(r({action:null,error:null,feedback:Yi(e,o)}),!0):s.kind===`disabled`?(r({action:null,error:null,feedback:`규칙은 저장되었지만 SafeShield가 꺼져 있어 DNS 적용을 대기하고 있습니다.`}),!0):s.kind===`failure`?(r({action:null,error:`규칙은 저장되었지만 로컬 DNS 적용이 실패했습니다. SafeShield 상태를 확인해 주세요.`,feedback:null}),!0):(r({action:null,error:`규칙은 저장되었지만 제한 시간 안에 로컬 DNS 적용 완료를 확인하지 못했습니다.`,feedback:null}),!0)}catch(e){return r({action:null,error:G(e,`사용자 규칙을 변경하지 못했습니다.`),feedback:null}),!1}},[t.replaceData]),a=I((e,t)=>i(`add`,e,t),[i]),o=I((e,t)=>i(`delete`,e,t),[i]),s=I(async()=>{r(e=>({...e,error:null})),await t.refresh()},[t.refresh]),c=I(()=>{r(e=>({...e,feedback:null}))},[]);return{...t,...n,error:n.error??t.error,addRule:a,deleteRule:o,dismissFeedback:c,refresh:s}}var Qi=6e4;function $i(e,t=!0){return _r({active:e,fallbackError:`SafeShield 통계를 불러오지 못했습니다.`,loader:Si,...t?{pollInterval:Qi}:{}})}var ea=[{label:`갱신 준비`,description:`차단 목록 갱신을 준비하고 있습니다.`,stages:[`starting`,`boot_delay`,`boot_refresh`,`boot_refresh_skipped`,`scheduled_refresh`,`init`]},{label:`최신 차단 목록 확인`,description:`서버에서 최신 차단 목록 정보를 확인하고 있습니다.`,stages:[`resolve_api`]},{label:`차단 목록 다운로드`,description:`최신 차단 목록을 안전하게 다운로드하고 있습니다.`,stages:[`download_artifact`]},{label:`사용자 규칙 적용`,description:`허용·차단 사용자 규칙을 새 차단 목록에 반영하고 있습니다.`,stages:[`local_overrides`,`merge`]},{label:`보호 규칙 적용`,description:`새 차단 규칙을 설치하고 DNS 보호 서비스를 갱신하고 있습니다.`,stages:[`install`,`restart_dnsmasq`]},{label:`보호 상태 확인`,description:`새 차단 목록과 DNS 보호가 정상적으로 동작하는지 확인하고 있습니다.`,stages:[`runtime_check`,`blocklist_verify`]}],ta=new Map;ea.forEach((e,t)=>{e.stages.forEach(e=>ta.set(e,t))});function na(e,t){return e===`running`||t!==null&&ta.has(t)}function ra(e){let t=e===null?0:ta.get(e)??0,n=ea[t];return{description:n.description,label:n.label,number:t+1,total:ea.length}}function ia(e){return(e??``).trim().toLowerCase()}function aa(e,t){let n=ia(e);if(n.includes(`upgrade`)||n.includes(`version`))return`현재 SafeShield 버전으로는 갱신을 계속할 수 없습니다. 시스템 업데이트에서 SafeShield를 최신 버전으로 업데이트해 주세요.`;if(n.includes(`license`)||n.includes(`unauthorized`)||n.includes(`forbidden`))return`차단 목록을 사용할 권한을 확인하지 못했습니다. SafeShield 라이선스 상태를 확인해 주세요.`;if(n.includes(`dnsmasq`)||n.includes(`restart`)||n.includes(`runtime`))return`DNS 보호 서비스를 정상적으로 갱신하지 못했습니다. 잠시 후 다시 갱신해 보고 문제가 계속되면 상태 점검 정보를 확인해 주세요.`;if(n.includes(`verify`)||n.includes(`sanity`))return`새 차단 목록을 적용한 뒤 보호 상태 확인을 완료하지 못했습니다. 다시 갱신해 주세요.`;if(n.includes(`download`)||n.includes(`fetch`)||n.includes(`timeout`)||n.includes(`network`)||n.includes(`wan`))return`차단 목록을 다운로드하지 못했습니다. 인터넷 연결을 확인한 뒤 다시 갱신해 주세요.`;if(n.includes(`resolve`)||n.includes(`manifest`)||n.includes(`artifact`)||n.includes(`api`))return`최신 차단 목록 정보를 확인하지 못했습니다. 인터넷 연결을 확인한 뒤 다시 갱신해 주세요.`;if(n.includes(`override`)||n.includes(`allowlist`)||n.includes(`merge`)||n.includes(`rule`))return`사용자 허용·차단 규칙을 새 차단 목록에 반영하지 못했습니다. 사용자 규칙을 확인한 뒤 다시 갱신해 주세요.`;if(n.includes(`install`)||n.includes(`write`)||n.includes(`space`))return`새 차단 규칙을 장치에 적용하지 못했습니다. 저장 공간과 SafeShield 상태를 확인한 뒤 다시 갱신해 주세요.`;let r=ra(t);return r.number===2?`최신 차단 목록 정보를 확인하는 중 문제가 발생했습니다. 인터넷 연결을 확인한 뒤 다시 갱신해 주세요.`:r.number===3?`차단 목록을 다운로드하는 중 문제가 발생했습니다. 인터넷 연결을 확인한 뒤 다시 갱신해 주세요.`:r.number===4?`사용자 규칙을 적용하는 중 문제가 발생했습니다. 사용자 규칙을 확인한 뒤 다시 갱신해 주세요.`:r.number===5?`새 보호 규칙을 적용하는 중 문제가 발생했습니다. 잠시 후 다시 갱신해 주세요.`:r.number===6?`새 차단 목록의 보호 상태를 확인하지 못했습니다. 다시 갱신해 주세요.`:`차단 목록 갱신을 완료하지 못했습니다. 잠시 후 다시 갱신해 주세요.`}var oa=3e3;function sa(e){return e?na(e.status,e.stage):!1}function ca(e){return _r({active:e,fallbackError:`SafeShield 상태를 불러오지 못했습니다.`,loader:wi,pollInterval:e=>sa(e)?oa:null})}var la=3e5,ua=1e3,da=3e3,fa=`luci-app-smartsafehub`;function pa(e=!0){let t=_r({active:e,fallbackError:`소프트웨어 업데이트 상태를 불러오지 못했습니다.`,loader:Hn,pollInterval:e=>e?.phase===`checking`?ua:e?.phase===`installing`?da:la,refreshOnFocus:!0}),[n,r]=N(null),[i,a]=N(null),[o,s]=N(null),c=F(!1),l=F(void 0);P(()=>{if(c.current||!t.data)return;let e=t.data.lastInstallAt??null,n=l.current;if(n===void 0){l.current=e;return}if(l.current=e,e===null||e===n||t.data.phase!==`idle`)return;let r=t.data.packages.find(e=>e.name===fa)?.installedVersion,i=window.__SMARTHUB_BOOTSTRAP__?.assetVersion;r&&i&&r!==i&&(c.current=!0,window.location.reload())},[t.data]);let u=I(e=>{t.data&&t.replaceData({...t.data,phase:e,lastError:null})},[t]),d=I(async()=>{r(`check`),a(null),s(null);try{if(!(await Yn()).accepted)throw Error(`업데이트 확인 요청이 접수되지 않았습니다.`);u(`checking`),r(null),window.setTimeout(()=>void t.refresh(),500)}catch(e){r(null),a(G(e,`업데이트 확인을 시작하지 못했습니다.`))}},[u,t]),f=I(async()=>{r(`install`),a(null),s(null);try{if(!(await Xn()).accepted)throw Error(`업데이트 설치 요청이 접수되지 않았습니다.`);u(`installing`),r(null),window.setTimeout(()=>void t.refresh(),750)}catch(e){r(null),a(G(e,`업데이트 설치를 시작하지 못했습니다.`))}},[u,t]),p=I(async e=>{r(`settings`),a(null),s(null);try{let n=await Zn(e);return t.data&&t.replaceData({...t.data,settings:n}),r(null),s(`자동 업데이트 설정을 저장했습니다.`),!0}catch(e){return r(null),a(G(e,`자동 업데이트 설정을 저장하지 못했습니다.`)),!1}},[t]),m=I(()=>{a(null),s(null)},[]);return{...t,action:n,actionError:i,message:o,check:d,dismissFeedback:m,install:f,saveSettings:p}}var ma=6e4;function ha(e){return _r({active:e,fallbackError:`장치 상태를 불러오지 못했습니다.`,loader:In,pollInterval:ma})}function ga(e){let t=_r({active:e,fallbackError:`예약 재부팅 설정을 불러오지 못했습니다.`,loader:tr,refreshOnFocus:!0}),[n,r]=N({saving:!1,saveError:null,saveMessage:null}),i=I(async e=>{r({saving:!0,saveError:null,saveMessage:null});try{let n=await nr(e);return t.replaceData(n),r({saving:!1,saveError:null,saveMessage:e.enabled?`예약 재부팅 일정을 저장했습니다.`:`예약 재부팅을 껐습니다.`}),!0}catch(e){return r({saving:!1,saveError:G(e,`예약 재부팅 설정을 저장하지 못했습니다.`),saveMessage:null}),!1}},[t.replaceData]),a=I(()=>{r(e=>({...e,saveError:null,saveMessage:null}))},[]);return{...t,...n,dismissSaveFeedback:a,saveSettings:i}}function _a(e){return e.trim().toLowerCase().replace(/[^a-z0-9._-]+/g,`-`)||`openwrt`}function va(e,t){let n=new Date(t*1e3).toISOString().replace(/[:.]/g,`-`);return`smartsafehub-diagnostics-${_a(e)}-${n}.json`}function ya(e,t){let n=new Blob([`${JSON.stringify(t,null,2)}\n`],{type:`application/json;charset=utf-8`}),r=URL.createObjectURL(n),i=document.createElement(`a`);i.href=r,i.download=e,i.style.display=`none`,(document.body??document.documentElement).appendChild(i),i.click(),i.remove(),window.setTimeout(()=>URL.revokeObjectURL(r),1e3)}function ba(e){return{enabled:e.available?e.enabled:null,status:e.status,lastResult:e.runtime.lastResult,validLineCount:e.blocklist.validLineCount,blocklistInstalled:e.blocklist.installed,dnsmasqOk:e.runtime.dnsRuntimeOk}}function xa(){return{networks:[],totalClients:0}}function Sa(){return{enabled:null,status:`unavailable`,lastResult:null,validLineCount:0,blocklistInstalled:!1,dnsmasqOk:!1}}async function Ca(e){if(!e)throw Error(`시스템 상태가 준비되지 않았습니다. 새로고침한 뒤 다시 시도해 주세요.`);let[t,n,r]=await Promise.allSettled([hr(),wi(),zn()]);return{generatedAt:Math.floor(Date.now()/1e3),health:r.status===`fulfilled`?r.value:null,system:e,wifi:t.status===`fulfilled`?t.value:xa(),safeshield:n.status===`fulfilled`?ba(n.value):Sa()}}function wa(e){let[t,n]=N({action:null,error:null,message:null,rebootAccepted:!1}),r=I(async()=>{n(e=>({...e,action:`diagnostics`,error:null,message:null}));try{let t=await Ca(e);ya(va(t.system.device.hostname,t.generatedAt),t),n(e=>({...e,action:null,message:`진단 정보 파일을 만들었습니다.`}))}catch(e){n(t=>({...t,action:null,error:G(e,`시스템 작업을 완료하지 못했습니다.`)}))}},[e]),i=I(async()=>{n(e=>({...e,action:`reboot`,error:null,message:null}));try{let e=await or();n({action:null,error:null,message:e.accepted?`재부팅을 시작했습니다. 잠시 후 공유기에 다시 연결해 주세요.`:`재부팅 요청이 접수되지 않았습니다.`,rebootAccepted:e.accepted})}catch(e){n(t=>({...t,action:null,error:G(e,`시스템 작업을 완료하지 못했습니다.`)}))}},[]),a=I(()=>{n(e=>({...e,error:null,message:null}))},[]);return{...t,dismissFeedback:a,downloadDiagnostics:r,reboot:i}}function Ta(e){let t=_r({active:e,fallbackError:`시간대 설정을 불러오지 못했습니다.`,loader:Qn,refreshOnFocus:!0}),[n,r]=N({saving:!1,syncing:!1,saveError:null,saveMessage:null}),i=I(async e=>{r({saving:!0,syncing:!1,saveError:null,saveMessage:null});try{let n=await $n(e);return t.replaceData(n),r({saving:!1,syncing:!1,saveError:null,saveMessage:`시간대를 저장하고 시스템 시간 설정에 적용했습니다.`}),!0}catch(e){return r({saving:!1,syncing:!1,saveError:G(e,`시간대 설정을 저장하지 못했습니다.`),saveMessage:null}),!1}},[t.replaceData]),a=I(async()=>{r({saving:!1,syncing:!0,saveError:null,saveMessage:null});try{await er(),await new Promise(e=>{window.setTimeout(e,1500)});let e=await Qn();return t.replaceData(e),r({saving:!1,syncing:!1,saveError:null,saveMessage:`NTP 시간 동기화를 요청하고 장치 시간을 다시 확인했습니다.`}),!0}catch(e){return r({saving:!1,syncing:!1,saveError:G(e,`시간을 동기화하지 못했습니다.`),saveMessage:null}),!1}},[t.replaceData]),o=I(()=>{r(e=>({...e,saveError:null,saveMessage:null}))},[]);return{...t,...n,dismissSaveFeedback:o,saveTimezone:i,syncTime:a}}var Ea=[2e3,3e3];function Da(e){return new Promise(t=>window.setTimeout(t,e))}function Oa(e){let t=_r({active:e,fallbackError:`Wi-Fi 설정을 처리하지 못했습니다.`,loader:hr}),n=F(!0),r=F(e),[i,a]=N({updatingSection:null,feedback:null});P(()=>(n.current=!0,()=>{n.current=!1}),[]),P(()=>{r.current=e},[e]);let o=I(async()=>{for(let e of Ea){if(await Da(e),!n.current||!r.current)return;await t.refresh()}},[t.refresh]),s=I(async e=>{a({updatingSection:e.section,feedback:null});try{let n=await gr(e);return t.replaceData(n.summary),a({updatingSection:null,feedback:{kind:`success`,message:n.changed?`Wi-Fi 설정을 저장하고 무선 네트워크를 다시 불러왔습니다.`:`변경된 Wi-Fi 설정이 없습니다.`}}),n.reloaded&&o(),!0}catch(e){let t=e instanceof R&&[`NETWORK_ERROR`,`RPC_TIMEOUT`].includes(e.code);return a({updatingSection:null,feedback:{kind:t?`warning`:`error`,message:t?`Wi-Fi가 다시 시작되면서 연결이 끊어졌을 수 있습니다. 변경한 SSID로 다시 연결한 뒤 화면을 새로고침해 주세요.`:G(e,`Wi-Fi 설정을 처리하지 못했습니다.`)}}),!1}},[o,t.replaceData]),c=I(()=>{a(e=>({...e,feedback:null}))},[]);return{...t,...i,update:s,dismissFeedback:c}}var ka=new Intl.NumberFormat(`ko-KR`),Aa=new Intl.DateTimeFormat(`ko-KR`,{dateStyle:`medium`,timeStyle:`short`});function ja(e){if(!Number.isFinite(e)||e<0)return`확인 불가`;let t=Math.floor(e/86400),n=Math.floor(e%86400/3600),r=Math.floor(e%3600/60);return t>0?`${t}일 ${n}시간`:n>0?`${n}시간 ${r}분`:`${Math.max(r,1)}분`}function Ma(e){if(!Number.isFinite(e)||e<0)return`확인 불가`;let t=[`B`,`KB`,`MB`,`GB`],n=e,r=0;for(;n>=1024&&r0?n>0?`${t}시간 ${n}분`:`${t}시간`:`${n}분`}function za(e){let t=Math.max(0,e.total),n=e.free+e.buffered+e.cached,r=Math.min(t,Math.max(0,e.available>0?e.available:n)),i=Math.max(0,t-r);return{used:i,percent:t>0?i/t*100:0}}function Ba(e,t){let n=e.metadata[t];return typeof n==`string`&&n.trim().length>0?n.trim():null}function Va(e,t){let n=e.metadata[t];return typeof n==`number`&&Number.isFinite(n)?n:null}function Ha(e,t){let n=e.metadata[t];return typeof n==`boolean`?n:null}function Ua(e,t){let n=Ba(e,`error_code`);return n?`${t} (오류 코드: ${n})`:t}function Wa(e){let t=Math.max(0,Math.floor(e));if(t<60)return`${t}초`;let n=Math.floor(t/60),r=t%60;if(n<60)return r>0?`${n}분 ${r}초`:`${n}분`;let i=Math.floor(n/60),a=n%60;return a>0?`${i}시간 ${a}분`:`${i}시간`}function Ga(e){let t=Ba(e,`from_version`),n=Ba(e,`to_version`);return t&&n?`${t} → ${n}`:n?`${n} 버전이 적용되었습니다.`:null}function Ka(e){return e?e.toUpperCase():null}function qa(e){switch(e){case`dhcp`:return`자동 IP(DHCP)`;case`pppoe`:return`PPPoE`;case`static`:return`고정 IPv4`;default:return e.toUpperCase()}}function Ja(e){switch(e.eventType){case`system.booted`:return{title:`공유기 부팅 감지`,description:`공유기가 켜지거나 재시작된 것을 확인했습니다.`};case`network.internet.disconnected`:return{title:`인터넷 연결 끊김 감지`,description:`공유기에서 인터넷 연결을 확인할 수 없었습니다.`};case`network.internet.recovered`:{let t=Va(e,`downtime_seconds`);return{title:`인터넷 연결 복구`,description:t!==null&&t>0?`약 ${Wa(t)} 동안 인터넷 연결이 확인되지 않았습니다.`:`공유기에서 인터넷 연결을 다시 확인했습니다.`}}case`safeshield.protection.enabled`:return{title:`SafeShield 보호 활성화`,description:`DNS 보호 기능이 활성화되었습니다.`};case`safeshield.protection.disabled`:return{title:`SafeShield 보호 비활성화`,description:`DNS 보호 기능이 비활성화되었습니다.`};case`safeshield.blocklist.updated`:{let t=Va(e,`domain_count`),n=Ba(e,`artifact_version`),r=[];return t!==null&&t>0&&r.push(`${q(t)}개 도메인 적용`),n&&r.push(`목록 ${n}`),{title:`SafeShield 차단 목록 업데이트 완료`,description:r.length>0?r.join(` · `):`최신 차단 목록을 적용했습니다.`}}case`safeshield.blocklist.update_failed`:return{title:`SafeShield 차단 목록 업데이트 실패`,description:Ua(e,`차단 목록을 업데이트하지 못했습니다.`)};case`safeshield.statistics.enabled`:return{title:`SafeShield 차단 통계 수집 활성화`,description:`기기별 차단 통계 수집을 활성화했습니다.`};case`safeshield.statistics.disabled`:return{title:`SafeShield 차단 통계 수집 비활성화`,description:`기기별 차단 통계 수집을 비활성화했습니다.`};case`safeshield.rule.added`:return{title:Ba(e,`rule_action`)===`allow`?`사용자 허용 규칙 추가`:`사용자 차단 규칙 추가`,description:`SafeShield 사용자 규칙이 변경되었습니다.`};case`safeshield.rule.removed`:return{title:Ba(e,`rule_action`)===`allow`?`사용자 허용 규칙 삭제`:`사용자 차단 규칙 삭제`,description:`SafeShield 사용자 규칙이 변경되었습니다.`};case`settings.scheduled_reboot.updated`:{let t=Ha(e,`enabled`);return{title:`예약 재부팅 설정 변경`,description:t===!0?`예약 재부팅 설정을 저장하고 새 일정에 적용했습니다.`:t===!1?`예약 재부팅을 비활성화했습니다.`:`예약 재부팅 설정을 변경했습니다.`}}case`settings.software_updates.updated`:return{title:`관리 소프트웨어 업데이트 설정 변경`,description:Ha(e,`auto_install`)===!0?`자동 설치를 포함한 업데이트 설정을 저장했습니다.`:`관리 소프트웨어 업데이트 설정을 저장했습니다.`};case`settings.health_reporter.enabled`:return{title:`원격 상태 보고 활성화`,description:`장치 상태를 SmartSafeHub Cloud에 보고하도록 설정했습니다.`};case`settings.health_reporter.disabled`:return{title:`원격 상태 보고 비활성화`,description:`SmartSafeHub Cloud로의 장치 상태 보고를 중지했습니다.`};case`settings.activity_cloud_sync.enabled`:return{title:`Cloud 활동 기록 전송 활성화`,description:`이후 발생하는 활동을 SmartSafeHub Cloud에 전송하도록 설정했습니다.`};case`settings.activity_cloud_sync.disabled`:return{title:`Cloud 활동 기록 전송 비활성화`,description:`Cloud 전송을 중지했습니다. 로컬 최근 활동은 계속 기록됩니다.`};case`settings.timezone.updated`:{let t=Ba(e,`zonename`);return{title:`시간대 설정 변경`,description:t?`공유기 시간대를 ${t}(으)로 변경했습니다.`:`공유기 시간대를 변경했습니다.`}}case`settings.wifi.updated`:return{title:`Wi-Fi 설정 변경`,description:`Wi-Fi 설정을 저장하고 무선 네트워크에 적용했습니다.`};case`settings.wan.updated`:{let t=Ba(e,`protocol`);return{title:`인터넷 설정 변경`,description:t?`${qa(t)} 방식으로 WAN 설정을 변경했습니다.`:`WAN 인터넷 연결 설정을 변경했습니다.`}}case`settings.lan.updated`:return{title:`LAN 설정 변경`,description:`내부 네트워크 및 DHCP 설정을 변경했습니다.`};case`settings.iptv.updated`:{let t=Ha(e,`enabled`),n=Ba(e,`provider`),r=n===`skb`?`SK Broadband`:n===`lgu`?`LG U+`:null;return{title:`IPTV 설정 변경`,description:t===!1?`IPTV 기능을 비활성화했습니다.`:r?`${r} IPTV 설정을 적용했습니다.`:`IPTV 설정을 적용했습니다.`}}case`software.update.completed`:return{title:`관리 소프트웨어 업데이트 완료`,description:Ga(e)};case`software.update.failed`:return{title:`관리 소프트웨어 업데이트 실패`,description:Ua(e,`관리 소프트웨어를 업데이트하지 못했습니다.`)};case`firmware.update.started`:return{title:`펌웨어 업데이트 시작`,description:`펌웨어 설치를 시작했습니다. 완료 과정에서 공유기가 재부팅됩니다.`};case`firmware.update.failed`:return{title:`펌웨어 업데이트 실패`,description:Ua(e,`펌웨어 설치 준비 또는 검증에 실패했습니다.`)};case`license.activated`:{let t=Ka(Ba(e,`to_plan`));return{title:`라이선스 활성화`,description:t?`${t} 라이선스가 활성화되었습니다.`:`라이선스가 활성화되었습니다.`}}case`license.changed`:{let t=Ka(Ba(e,`from_plan`)),n=Ka(Ba(e,`to_plan`));return{title:`라이선스 변경`,description:t&&n?`${t} → ${n}`:n?`${n} 라이선스로 변경되었습니다.`:`라이선스 상태가 변경되었습니다.`}}case`license.cleared`:return{title:`라이선스 연결 해제`,description:Ba(e,`reason`)===`manual`?`이 공유기에서 라이선스 연결을 해제했습니다.`:`서버의 라이선스 상태가 반영되어 이 공유기의 라이선스 연결이 해제되었습니다.`};case`health.issue.started`:{let t=Va(e,`warning_count`)??0,n=Va(e,`critical_count`)??0,r=[];return n>0&&r.push(`이상 ${q(n)}건`),t>0&&r.push(`주의 ${q(t)}건`),{title:`확인이 필요한 장치 상태 발견`,description:r.length>0?r.join(` · `):`장치 상태에서 확인이 필요한 항목이 발견되었습니다.`}}case`health.issue.changed`:{let t=Va(e,`warning_count`)??0,n=Va(e,`critical_count`)??0,r=[];return n>0&&r.push(`이상 ${q(n)}건`),t>0&&r.push(`주의 ${q(t)}건`),{title:`확인이 필요한 장치 상태 변경`,description:r.length>0?r.join(` · `):`확인이 필요한 장치 상태 항목이 변경되었습니다.`}}case`health.issue.resolved`:return{title:`장치 상태 정상으로 복구`,description:`이전에 확인이 필요했던 장치 상태가 정상으로 돌아왔습니다.`};default:return{title:`SmartSafeHub 활동`,description:`장치에서 새로운 활동이 기록되었습니다.`}}}function Ya(e){return e===`error`?{icon:B(U,{class:`size-4`}),surface:`bg-rose-50 text-rose-700 ring-rose-200`}:e===`warning`?{icon:B(U,{class:`size-4`}),surface:`bg-amber-50 text-amber-800 ring-amber-200`}:e===`success`?{icon:B(Xt,{class:`size-4`}),surface:`bg-emerald-50 text-emerald-700 ring-emerald-200`}:{icon:B(Vt,{class:`size-4`}),surface:`bg-slate-100 text-slate-600 ring-slate-200`}}function Xa(e){let t=new Date(e*1e3);return new Intl.DateTimeFormat(`ko-KR`,{hour:`2-digit`,minute:`2-digit`,hour12:!1}).format(t)}function Za(e){let t=new Date(e*1e3);return`${t.getFullYear()}-${t.getMonth()+1}-${t.getDate()}`}function Qa(e){let t=new Date(e*1e3),n=new Date,r=new Date(n.getFullYear(),n.getMonth(),n.getDate()),i=new Date(t.getFullYear(),t.getMonth(),t.getDate()),a=Math.round((r.getTime()-i.getTime())/864e5);return a===0?`오늘`:a===1?`어제`:new Intl.DateTimeFormat(`ko-KR`,{month:`long`,day:`numeric`,weekday:`short`}).format(t)}function $a({compact:e=!1,events:t}){if(t.length===0)return B(`div`,{class:`rounded-xl border border-slate-200 bg-slate-50 px-4 py-5 text-center`,children:[B(Vt,{class:`mx-auto size-5 text-slate-400`}),B(`p`,{class:`mt-2 mb-0 text-sm font-extrabold text-slate-700`,children:`아직 기록된 활동이 없습니다.`}),B(`p`,{class:`mt-1 mb-0 text-xs leading-5 text-slate-500`,children:`상태가 실제로 변경되면 이곳에 시간순으로 기록됩니다.`})]});let n=``;return B(`div`,{class:e?`space-y-2`:`space-y-1`,children:t.map(t=>{let r=Ja(t),i=Ya(t.severity),a=Za(t.occurredAt),o=!e&&a!==n;return n=a,B(`div`,{children:[o?B(`p`,{class:`mt-5 mb-2 first:mt-0 text-xs font-black text-slate-500`,children:Qa(t.occurredAt)}):null,B(`article`,{class:`relative flex min-w-0 gap-3 ${e?`border-b border-slate-100 py-3 first:pt-0 last:border-b-0 last:pb-0`:`rounded-xl px-2 py-3 hover:bg-slate-50`}`,children:[B(`div`,{class:`w-12 shrink-0 pt-1 text-xs font-bold tabular-nums text-slate-400`,children:B(`time`,{dateTime:new Date(t.occurredAt*1e3).toISOString(),title:Fa(t.occurredAt),children:Xa(t.occurredAt)})}),B(`span`,{class:`mt-0.5 grid size-8 shrink-0 place-items-center rounded-full ring-1 ring-inset ${i.surface}`,children:i.icon}),B(`div`,{class:`min-w-0 flex-1`,children:[B(`p`,{class:`m-0 text-sm font-black leading-5 text-slate-950`,children:r.title}),r.description?B(`p`,{class:`mt-1 mb-0 break-words text-xs font-medium leading-5 text-slate-500`,children:r.description}):null]})]})]},t.eventId)})})}function eo({error:e,loading:t,onRetry:n}){return t?B(`div`,{class:`rounded-xl border border-slate-200 bg-slate-50 px-4 py-5 text-center`,children:[B(H,{class:`mx-auto size-5 animate-spin text-teal-700`}),B(`p`,{class:`mt-2 mb-0 text-sm font-bold text-slate-500`,children:`최근 활동을 불러오는 중입니다.`})]}):e?B(`div`,{class:`rounded-xl border border-amber-200 bg-amber-50/70 px-4 py-4`,children:B(`div`,{class:`flex items-start gap-3`,children:[B(U,{class:`mt-0.5 size-5 shrink-0 text-amber-700`}),B(`div`,{class:`min-w-0 flex-1`,children:[B(`p`,{class:`m-0 text-sm font-black text-slate-950`,children:`최근 활동을 불러오지 못했습니다.`}),B(`p`,{class:`mt-1 mb-0 text-xs leading-5 text-slate-500`,children:e}),n?B(`button`,{class:`mt-3 inline-flex min-h-9 items-center justify-center rounded-lg border border-amber-300 bg-white px-3 text-xs font-extrabold text-amber-800 transition hover:bg-amber-50`,onClick:n,type:`button`,children:`다시 시도`}):null]})]})}):null}function to(e){return e.enabled?e.eligible===!1||e.phase===`ineligible`?{label:`Pro / Ultimate 전용`,description:`유료 멤버십이 활성화되면 이후 발생하는 활동을 Cloud에 자동으로 동기화합니다.`,tone:`bg-slate-100 text-slate-600 ring-slate-200`}:e.phase===`error`?{label:`동기화 확인 필요`,description:`최근 Cloud 전송을 완료하지 못했습니다. 로컬 활동 기록은 계속 보관됩니다.`,tone:`bg-amber-50 text-amber-800 ring-amber-200`}:e.phase===`syncing`?{label:`동기화 중`,description:`새 활동을 SmartSafeHub Cloud에 전송하고 있습니다.`,tone:`bg-teal-50 text-teal-800 ring-teal-200`}:e.eligible===!0?{label:`자동 동기화`,description:`새 활동이 생기면 SmartSafeHub Cloud에 자동으로 안전하게 전송합니다.`,tone:`bg-emerald-50 text-emerald-800 ring-emerald-200`}:{label:`확인 중`,description:`Cloud 활동 기록 사용 가능 여부를 확인하고 있습니다.`,tone:`bg-slate-100 text-slate-600 ring-slate-200`}:e.eligible===!1?{label:`Pro / Ultimate 전용`,description:`로컬 최근 활동은 계속 사용할 수 있으며, 유료 멤버십에서 Cloud 저장을 선택적으로 켤 수 있습니다.`,tone:`bg-slate-100 text-slate-600 ring-slate-200`}:{label:`Cloud 전송 꺼짐`,description:`활동 기록은 이 공유기에만 저장됩니다. Cloud에는 새로운 활동을 전송하지 않습니다.`,tone:`bg-slate-100 text-slate-700 ring-slate-200`}}function no({actionError:e,actionMessage:t,cloud:n,onDismissFeedback:r,onSetEnabled:i,saving:a}){let o=to(n),s=n.plan?.toUpperCase()??null,c=n.eligible===!0,l=n.enabled||c;return B(`section`,{class:`rounded-2xl border border-slate-200 bg-white p-5 shadow-sm shadow-slate-900/5 sm:p-6`,children:[B(`div`,{class:`flex flex-wrap items-start justify-between gap-4`,children:[B(`div`,{class:`min-w-0`,children:[B(`p`,{class:`m-0 text-xs font-extrabold uppercase tracking-[0.16em] text-teal-700`,children:`Cloud history`}),B(`h2`,{class:`mt-2 mb-0 text-base font-black text-slate-950`,children:`Cloud 활동 기록`}),B(`p`,{class:`mt-2 mb-0 max-w-3xl text-sm leading-6 text-slate-500`,children:o.description})]}),B(`div`,{class:`flex shrink-0 items-center gap-3`,children:[B(`span`,{class:`rounded-full px-3 py-1.5 text-xs font-extrabold ring-1 ring-inset ${o.tone}`,children:a?`설정 중`:o.label}),B(`button`,{"aria-checked":n.enabled,"aria-label":`Cloud 활동 기록 전송 사용`,class:`ssh-switch-control relative inline-flex shrink-0 rounded-full border transition focus:outline-none focus-visible:ring-4 focus-visible:ring-teal-100 disabled:cursor-not-allowed disabled:opacity-50 ${n.enabled?`border-teal-600 bg-teal-600`:`border-slate-300 bg-slate-200`}`,disabled:a||!l,onClick:()=>i(!n.enabled),role:`switch`,type:`button`,children:B(`span`,{"aria-hidden":`true`,class:`ssh-switch-thumb absolute top-1 shadow-sm transition-[left] ${n.enabled?`left-6`:`left-1`}`})})]})]}),(e||t)&&B(`div`,{class:`mt-4 flex min-w-0 items-start justify-between gap-3 rounded-xl border px-4 py-3 text-sm font-bold ${e?`border-rose-200 bg-rose-50 text-rose-800`:`border-emerald-200 bg-emerald-50 text-emerald-800`}`,role:e?`alert`:`status`,children:[B(`span`,{class:`min-w-0`,children:e||t}),B(`button`,{class:`shrink-0 rounded-lg px-2 py-1 text-xs font-extrabold hover:bg-black/5`,onClick:r,type:`button`,children:`닫기`})]}),B(`dl`,{class:`mt-5 grid gap-3 sm:grid-cols-4`,children:[B(`div`,{class:`rounded-xl bg-slate-50 px-4 py-3 ring-1 ring-inset ring-slate-200`,children:[B(`dt`,{class:`text-xs font-bold text-slate-500`,children:`멤버십`}),B(`dd`,{class:`mt-1 text-sm font-black text-slate-900`,children:s??(n.eligible===!1?`Free`:`확인 중`)})]}),B(`div`,{class:`rounded-xl bg-slate-50 px-4 py-3 ring-1 ring-inset ring-slate-200`,children:[B(`dt`,{class:`text-xs font-bold text-slate-500`,children:`전송 대기`}),B(`dd`,{class:`mt-1 text-sm font-black text-slate-900`,children:[q(n.pendingEvents),`건`]})]}),B(`div`,{class:`rounded-xl bg-slate-50 px-4 py-3 ring-1 ring-inset ring-slate-200`,children:[B(`dt`,{class:`text-xs font-bold text-slate-500`,children:`마지막 동기화`}),B(`dd`,{class:`mt-1 text-sm font-black text-slate-900`,children:n.lastSuccessAt>0?Ia(n.lastSuccessAt):`아직 없음`})]}),B(`div`,{class:`rounded-xl bg-slate-50 px-4 py-3 ring-1 ring-inset ring-slate-200`,children:[B(`dt`,{class:`text-xs font-bold text-slate-500`,children:`Cloud 보관`}),B(`dd`,{class:`mt-1 text-sm font-black text-slate-900`,children:n.enabled&&n.eligible===!0&&n.retentionDays>0?`${n.retentionDays}일`:`—`})]})]}),n.enabled&&n.phase===`error`&&n.lastErrorCode?B(`p`,{class:`mt-3 mb-0 text-xs font-semibold text-amber-700`,children:[`오류 코드: `,B(`code`,{children:n.lastErrorCode})]}):null,B(`p`,{class:`mt-3 mb-0 text-xs leading-5 text-slate-500`,children:`Cloud 전송은 Pro 또는 Ultimate 멤버십에서 선택적으로 사용할 수 있습니다. 끄면 전송 대기 데이터와 임시 인증 정보를 삭제하며, 다시 켠 뒤 새로 발생한 활동부터 Cloud에 전송합니다. 로컬 최근 활동은 항상 유지됩니다.`})]})}function ro({actionError:e,actionMessage:t,data:n,error:r,loading:i,onDismissActionFeedback:a,onRetry:o,onSetCloudSync:s,savingCloudSync:c}){return B(`div`,{class:`min-w-0 space-y-5`,children:[B(`section`,{"aria-labelledby":`activity-history-title`,class:`min-w-0 rounded-2xl border border-slate-200 bg-white p-5 shadow-sm shadow-slate-900/5 sm:p-6`,children:[B(`div`,{class:`flex flex-wrap items-start justify-between gap-4`,children:[B(`div`,{children:[B(`p`,{class:`m-0 text-xs font-extrabold uppercase tracking-[0.16em] text-teal-700`,children:`Local history`}),B(`h2`,{class:`mt-2 mb-0 text-xl font-black tracking-tight text-slate-950`,id:`activity-history-title`,children:`현재 부팅 이후의 최근 활동`}),B(`p`,{class:`mt-2 mb-0 max-w-3xl text-sm leading-6 text-slate-500`,children:`인터넷, SafeShield, 업데이트, 라이선스와 주요 설정에서 실제 상태가 변경된 시점만 기록합니다.`})]}),B(`span`,{class:`rounded-full bg-slate-100 px-3 py-1.5 text-xs font-extrabold text-slate-600 ring-1 ring-inset ring-slate-200`,children:[`최대 `,n?.maxEvents??128,`건`]})]}),B(`div`,{class:`mt-5`,children:i||r&&!n?B(eo,{error:r,loading:i,onRetry:o}):B($a,{events:n?.events??[]})})]}),B(no,{actionError:e,actionMessage:t,cloud:n?.cloud??{enabled:!1,phase:`preparing`,eligible:null,plan:null,retentionDays:0,pendingEvents:0,lastAttemptAt:0,lastSuccessAt:0,lastUploadedCount:0,lastErrorCode:null,nextSyncAt:0},onDismissFeedback:a,onSetEnabled:s,saving:c}),B(`aside`,{class:`rounded-2xl border border-slate-200 bg-slate-50 px-5 py-4`,children:[B(`p`,{class:`m-0 text-sm font-extrabold text-slate-800`,children:`로컬 활동 기록 안내`}),B(`p`,{class:`mt-1 mb-0 text-xs leading-5 text-slate-500`,children:`이 기록은 공유기의 메모리 영역에만 보관되어 재부팅하면 초기화됩니다. 직접 설정을 변경한 작업은 성공 시점에 즉시 기록하고, 인터넷 및 장치 진단처럼 외부 상태를 확인해야 하는 항목은 실제 상태 변화가 관찰된 경우에만 추가합니다.`})]})]})}function io(){return B(`section`,{"aria-busy":`true`,"aria-live":`polite`,class:`rounded-2xl border border-slate-200 bg-white p-5 shadow-sm shadow-slate-900/5 sm:p-6`,children:B(`div`,{class:`flex items-center gap-4`,children:[B(H,{class:`size-8 shrink-0 animate-spin text-teal-700`}),B(`div`,{class:`min-w-0 text-left`,children:[B(`h2`,{class:`m-0 text-lg font-extrabold text-slate-950`,children:`장치 상태를 확인하고 있습니다`}),B(`p`,{class:`mt-1 mb-0 text-sm leading-6 text-slate-600`,children:`OpenWrt의 rpcd API에서 정보를 불러오는 중입니다.`})]})]})})}function ao({message:e,onRetry:t}){return B(`section`,{"aria-live":`assertive`,class:`rounded-2xl border border-red-200 bg-red-50 p-5 sm:p-6`,children:[B(`p`,{class:`m-0 text-xs font-bold uppercase tracking-[0.16em] text-red-700`,children:`연결 오류`}),B(`h2`,{class:`mt-2 mb-0 text-lg font-extrabold text-red-950`,children:`장치 상태를 불러오지 못했습니다`}),B(`p`,{class:`mt-2 mb-0 text-sm leading-6 text-red-800`,children:e}),B(`button`,{class:`mt-5 inline-flex min-h-10 items-center justify-center gap-2 rounded-xl border-0 bg-red-700 px-4 py-2 text-sm font-bold text-white shadow-sm transition hover:bg-red-800 focus:outline-none focus-visible:ring-4 focus-visible:ring-red-200`,onClick:t,type:`button`,children:[B(H,{class:`size-4`}),`다시 시도`]})]})}var oo=[{value:`all`,label:`전체`},{value:`online`,label:`현재 연결`},{value:`wifi`,label:`Wi-Fi`},{value:`ethernet`,label:`유선/기타`},{value:`offline`,label:`최근 기기`}],so=new Intl.Collator(`ko`),co=new Intl.DateTimeFormat(`ko-KR`,{month:`numeric`,day:`numeric`,hour:`2-digit`,minute:`2-digit`});function lo(e){switch(e){case`wifi`:return`Wi-Fi`;case`ethernet`:return`유선/기타`;default:return`연결 방식 미확인`}}function uo(e){return e.hostname??e.ipv4Address??`이름 없는 기기`}function fo(e){return e===null?null:e>=-50?`매우 좋음`:e>=-60?`좋음`:e>=-70?`보통`:`약함`}function po(e){if(e===null||e<0)return null;let t=Math.floor(e/86400),n=Math.floor(e%86400/3600),r=Math.floor(e%3600/60);return t>0?`${t}일 ${n}시간`:n>0?`${n}시간 ${r}분`:`${Math.max(r,1)}분`}function mo(e){return e.leaseActive?e.leaseExpiresAt===null?`DHCP 임대 활성`:`DHCP ${co.format(new Date(e.leaseExpiresAt*1e3))}까지`:null}function ho(e,t){switch(t){case`online`:return e.online;case`wifi`:return e.online&&e.connection===`wifi`;case`ethernet`:return e.online&&e.connection===`ethernet`;case`offline`:return!e.online;default:return!0}}function go({device:e}){return B(`span`,{class:`inline-flex items-center gap-2 rounded-full px-3 py-1.5 text-xs font-extrabold ring-1 ring-inset ${e.online?`bg-emerald-50 text-emerald-700 ring-emerald-200`:`bg-slate-100 text-slate-600 ring-slate-200`}`,children:[B(`span`,{class:`size-2 rounded-full ${e.online?`bg-emerald-500`:`bg-slate-400`}`}),e.online?`현재 연결`:`최근 임대`]})}function _o({device:e}){let t=fo(e.signalDbm),n=po(e.connectedSeconds),r=mo(e);return B(`article`,{class:`rounded-2xl border border-slate-200 bg-white p-4 shadow-sm shadow-slate-900/5 sm:p-5`,children:[B(`div`,{class:`flex min-w-0 flex-col items-start gap-4 sm:flex-row sm:justify-between`,children:[B(`div`,{class:`flex min-w-0 items-start gap-3`,children:[B(`span`,{class:`grid size-11 shrink-0 place-items-center rounded-xl ${e.connection===`wifi`?`bg-teal-50 text-teal-700`:e.connection===`ethernet`?`bg-blue-50 text-blue-700`:`bg-slate-100 text-slate-600`}`,children:e.connection===`wifi`?B(Lt,{class:`size-6`}):e.connection===`ethernet`?B(Rt,{class:`size-6`}):B(Mt,{class:`size-6`})}),B(`div`,{class:`min-w-0`,children:[B(`h3`,{class:`m-0 break-words text-base font-extrabold text-slate-950`,children:uo(e)}),B(`p`,{class:`mt-1 mb-0 break-all font-mono text-xs leading-5 text-slate-500`,children:e.mac})]})]}),B(`span`,{class:`shrink-0 self-start`,children:B(go,{device:e})})]}),B(`dl`,{class:`mt-5 grid gap-3 text-sm sm:grid-cols-2`,children:[B(`div`,{class:`rounded-xl bg-slate-50 p-3.5`,children:[B(`dt`,{class:`text-xs font-bold text-slate-500`,children:`IP 주소`}),B(`dd`,{class:`mt-1.5 mb-0 ml-0 font-extrabold text-slate-900`,children:e.ipv4Address??`확인되지 않음`})]}),B(`div`,{class:`rounded-xl bg-slate-50 p-3.5`,children:[B(`dt`,{class:`text-xs font-bold text-slate-500`,children:`연결 방식`}),B(`dd`,{class:`mt-1.5 mb-0 ml-0 font-extrabold text-slate-900`,children:lo(e.connection)})]})]}),B(`div`,{class:`mt-4 flex flex-wrap gap-2 text-xs font-bold text-slate-600`,children:[e.ssid?B(`span`,{class:`rounded-full bg-teal-50 px-3 py-1.5 text-teal-800`,children:[e.ssid,e.bandLabel?` · ${e.bandLabel}`:``]}):null,t?B(`span`,{class:`rounded-full bg-slate-100 px-3 py-1.5`,children:[`신호 `,t,` · `,e.signalDbm,` dBm`]}):null,n?B(`span`,{class:`rounded-full bg-slate-100 px-3 py-1.5`,children:[`연결 `,n]}):null,r?B(`span`,{class:`rounded-full bg-slate-100 px-3 py-1.5`,children:r}):null,e.interface?B(`span`,{class:`rounded-full bg-slate-100 px-3 py-1.5`,children:e.interface}):null]})]})}function vo({data:e,error:t,loading:n,onRetry:r}){let[i,a]=N(``),[o,s]=N(`all`),c=$e(()=>{if(!e)return[];let t=i.trim().toLocaleLowerCase();return[...e.devices].filter(e=>ho(e,o)).filter(e=>!t||[e.hostname,e.ipv4Address,e.mac,e.ssid].filter(e=>!!e).some(e=>e.toLocaleLowerCase().includes(t))).sort((e,t)=>e.online===t.online?e.connection===t.connection?so.compare(uo(e),uo(t)):e.connection===`wifi`?-1:1:e.online?-1:1)},[e,o,i]);return n?B(io,{}):t?B(ao,{message:t,onRetry:r}):e?B(S,{children:[B(`section`,{"aria-label":`연결 기기 요약`,class:`grid gap-4 sm:grid-cols-2 xl:grid-cols-4`,children:[B(yo,{description:`${e.totals.offline}대는 최근 DHCP 임대에서 확인`,icon:B(Mt,{class:`size-6`}),label:`확인된 기기`,value:e.totals.known}),B(yo,{description:`Wi-Fi 또는 ARP에서 현재 확인됨`,icon:B(Vt,{class:`size-6`}),label:`현재 연결`,value:e.totals.online}),B(yo,{description:`무선 AP에 연결된 기기`,icon:B(Lt,{class:`size-6`}),label:`Wi-Fi`,value:e.totals.wireless}),B(yo,{description:`LAN ARP에서 확인된 비무선 기기`,icon:B(Rt,{class:`size-6`}),label:`유선/기타`,value:e.totals.ethernet})]}),B(`section`,{class:`mt-5 rounded-2xl border border-slate-200 bg-white p-4 shadow-sm shadow-slate-900/5 sm:p-5`,children:[B(`div`,{class:`flex flex-col gap-4 lg:flex-row lg:items-center lg:justify-between`,children:[B(`div`,{children:[B(`p`,{class:`m-0 text-xs font-bold uppercase tracking-[0.16em] text-slate-500`,children:`Device inventory`}),B(`h2`,{class:`mt-2 mb-0 text-xl font-extrabold text-slate-950`,children:`기기 목록`})]}),B(`label`,{class:`relative block w-full lg:max-w-sm`,children:[B(`span`,{class:`sr-only`,children:`기기 검색`}),B(`span`,{class:`pointer-events-none absolute inset-y-0 left-0 flex w-11 items-center justify-center text-slate-400`,children:B($t,{class:`size-5`})}),B(`input`,{class:`min-h-11 w-full rounded-xl border-2 border-slate-300 bg-slate-50 py-2.5 pr-4 pl-11 text-sm font-semibold text-slate-950 shadow-inner outline-none transition placeholder:text-slate-400 focus:border-teal-500 focus:bg-white focus:ring-4 focus:ring-teal-100`,onInput:e=>a(e.currentTarget.value),placeholder:`이름, IP, MAC 또는 SSID 검색`,type:`search`,value:i})]})]}),B(`div`,{class:`ssh-touch-scroll mt-4 flex gap-2 overflow-x-auto pb-1`,role:`group`,"aria-label":`기기 필터`,children:oo.map(e=>B(`button`,{"aria-pressed":o===e.value,class:`min-h-10 shrink-0 rounded-xl border px-4 py-2 text-sm font-extrabold transition ${o===e.value?`border-teal-700 bg-teal-700 text-white`:`border-slate-200 bg-white text-slate-600 hover:bg-slate-50 hover:text-slate-950`}`,onClick:()=>s(e.value),type:`button`,children:e.label},e.value))})]}),c.length?B(`section`,{"aria-live":`polite`,class:`mt-5 grid gap-4 lg:grid-cols-2`,children:c.map(e=>B(_o,{device:e},e.id))}):B(`section`,{class:`mt-5 rounded-2xl border border-dashed border-slate-300 bg-white p-5 text-center sm:p-8`,children:[B(Mt,{class:`mx-auto size-10 text-slate-400`}),B(`h2`,{class:`mt-4 mb-0 text-lg font-extrabold text-slate-950`,children:`조건에 맞는 기기가 없습니다`}),B(`p`,{class:`mt-2 mb-0 text-sm text-slate-600`,children:`검색어 또는 필터를 변경해 주세요.`})]}),B(`p`,{class:`mt-5 mb-0 rounded-xl bg-slate-100 px-4 py-3 text-xs leading-5 text-slate-600`,children:`유선/기타 상태는 ARP 테이블을 기준으로 하며, 최근 DHCP 임대는 기기가 연결 해제된 뒤에도 일정 시간 남을 수 있습니다.`})]}):null}function yo({description:e,icon:t,label:n,value:r}){return B(`article`,{class:`rounded-2xl border border-slate-200 bg-white p-4 shadow-sm shadow-slate-900/5 sm:p-5`,children:[B(`div`,{class:`flex items-start justify-between gap-4`,children:[B(`div`,{children:[B(`p`,{class:`m-0 text-xs font-bold uppercase tracking-[0.14em] text-slate-500`,children:n}),B(`p`,{class:`mt-3 mb-0 text-3xl font-black tracking-tight text-slate-950`,children:r})]}),B(`span`,{class:`grid size-11 shrink-0 place-items-center rounded-xl bg-teal-50 text-teal-700`,children:t})]}),B(`p`,{class:`mt-3 mb-0 text-xs leading-5 text-slate-500`,children:e})]})}function bo(e){return e+.5|0}var xo=(e,t,n)=>Math.max(Math.min(e,n),t);function So(e){return xo(bo(e*2.55),0,255)}function Co(e){return xo(bo(e*255),0,255)}function wo(e){return xo(bo(e/2.55)/100,0,1)}function To(e){return xo(bo(e*100),0,100)}var Eo={0:0,1:1,2:2,3:3,4:4,5:5,6:6,7:7,8:8,9:9,A:10,B:11,C:12,D:13,E:14,F:15,a:10,b:11,c:12,d:13,e:14,f:15},Do=[...`0123456789ABCDEF`],Oo=e=>Do[e&15],ko=e=>Do[(e&240)>>4]+Do[e&15],Ao=e=>(e&240)>>4==(e&15),jo=e=>Ao(e.r)&&Ao(e.g)&&Ao(e.b)&&Ao(e.a);function Mo(e){var t=e.length,n;return e[0]===`#`&&(t===4||t===5?n={r:255&Eo[e[1]]*17,g:255&Eo[e[2]]*17,b:255&Eo[e[3]]*17,a:t===5?Eo[e[4]]*17:255}:(t===7||t===9)&&(n={r:Eo[e[1]]<<4|Eo[e[2]],g:Eo[e[3]]<<4|Eo[e[4]],b:Eo[e[5]]<<4|Eo[e[6]],a:t===9?Eo[e[7]]<<4|Eo[e[8]]:255})),n}var No=(e,t)=>e<255?t(e):``;function Po(e){var t=jo(e)?Oo:ko;return e?`#`+t(e.r)+t(e.g)+t(e.b)+No(e.a,t):void 0}var Fo=/^(hsla?|hwb|hsv)\(\s*([-+.e\d]+)(?:deg)?[\s,]+([-+.e\d]+)%[\s,]+([-+.e\d]+)%(?:[\s,]+([-+.e\d]+)(%)?)?\s*\)$/;function Io(e,t,n){let r=t*Math.min(n,1-n),i=(t,i=(t+e/30)%12)=>n-r*Math.max(Math.min(i-3,9-i,1),-1);return[i(0),i(8),i(4)]}function Lo(e,t,n){let r=(r,i=(r+e/60)%6)=>n-n*t*Math.max(Math.min(i,4-i,1),0);return[r(5),r(3),r(1)]}function Ro(e,t,n){let r=Io(e,1,.5),i;for(t+n>1&&(i=1/(t+n),t*=i,n*=i),i=0;i<3;i++)r[i]*=1-t-n,r[i]+=t;return r}function zo(e,t,n,r,i){return e===i?(t-n)/r+(t.5?l/(2-i-a):l/(i+a),s=zo(t,n,r,l,i),s=s*60+.5),[s|0,c||0,o]}function Vo(e,t,n,r){return(Array.isArray(t)?e(t[0],t[1],t[2]):e(t,n,r)).map(Co)}function Ho(e,t,n){return Vo(Io,e,t,n)}function Uo(e,t,n){return Vo(Ro,e,t,n)}function Wo(e,t,n){return Vo(Lo,e,t,n)}function Go(e){return(e%360+360)%360}function Ko(e){let t=Fo.exec(e),n=255,r;if(!t)return;t[5]!==r&&(n=t[6]?So(+t[5]):Co(+t[5]));let i=Go(+t[2]),a=t[3]/100,o=t[4]/100;return r=t[1]===`hwb`?Uo(i,a,o):t[1]===`hsv`?Wo(i,a,o):Ho(i,a,o),{r:r[0],g:r[1],b:r[2],a:n}}function qo(e,t){var n=Bo(e);n[0]=Go(n[0]+t),n=Ho(n),e.r=n[0],e.g=n[1],e.b=n[2]}function Jo(e){if(!e)return;let t=Bo(e),n=t[0],r=To(t[1]),i=To(t[2]);return e.a<255?`hsla(${n}, ${r}%, ${i}%, ${wo(e.a)})`:`hsl(${n}, ${r}%, ${i}%)`}var Yo={x:`dark`,Z:`light`,Y:`re`,X:`blu`,W:`gr`,V:`medium`,U:`slate`,A:`ee`,T:`ol`,S:`or`,B:`ra`,C:`lateg`,D:`ights`,R:`in`,Q:`turquois`,E:`hi`,P:`ro`,O:`al`,N:`le`,M:`de`,L:`yello`,F:`en`,K:`ch`,G:`arks`,H:`ea`,I:`ightg`,J:`wh`},Xo={OiceXe:`f0f8ff`,antiquewEte:`faebd7`,aqua:`ffff`,aquamarRe:`7fffd4`,azuY:`f0ffff`,beige:`f5f5dc`,bisque:`ffe4c4`,black:`0`,blanKedOmond:`ffebcd`,Xe:`ff`,XeviTet:`8a2be2`,bPwn:`a52a2a`,burlywood:`deb887`,caMtXe:`5f9ea0`,KartYuse:`7fff00`,KocTate:`d2691e`,cSO:`ff7f50`,cSnflowerXe:`6495ed`,cSnsilk:`fff8dc`,crimson:`dc143c`,cyan:`ffff`,xXe:`8b`,xcyan:`8b8b`,xgTMnPd:`b8860b`,xWay:`a9a9a9`,xgYF:`6400`,xgYy:`a9a9a9`,xkhaki:`bdb76b`,xmagFta:`8b008b`,xTivegYF:`556b2f`,xSange:`ff8c00`,xScEd:`9932cc`,xYd:`8b0000`,xsOmon:`e9967a`,xsHgYF:`8fbc8f`,xUXe:`483d8b`,xUWay:`2f4f4f`,xUgYy:`2f4f4f`,xQe:`ced1`,xviTet:`9400d3`,dAppRk:`ff1493`,dApskyXe:`bfff`,dimWay:`696969`,dimgYy:`696969`,dodgerXe:`1e90ff`,fiYbrick:`b22222`,flSOwEte:`fffaf0`,foYstWAn:`228b22`,fuKsia:`ff00ff`,gaRsbSo:`dcdcdc`,ghostwEte:`f8f8ff`,gTd:`ffd700`,gTMnPd:`daa520`,Way:`808080`,gYF:`8000`,gYFLw:`adff2f`,gYy:`808080`,honeyMw:`f0fff0`,hotpRk:`ff69b4`,RdianYd:`cd5c5c`,Rdigo:`4b0082`,ivSy:`fffff0`,khaki:`f0e68c`,lavFMr:`e6e6fa`,lavFMrXsh:`fff0f5`,lawngYF:`7cfc00`,NmoncEffon:`fffacd`,ZXe:`add8e6`,ZcSO:`f08080`,Zcyan:`e0ffff`,ZgTMnPdLw:`fafad2`,ZWay:`d3d3d3`,ZgYF:`90ee90`,ZgYy:`d3d3d3`,ZpRk:`ffb6c1`,ZsOmon:`ffa07a`,ZsHgYF:`20b2aa`,ZskyXe:`87cefa`,ZUWay:`778899`,ZUgYy:`778899`,ZstAlXe:`b0c4de`,ZLw:`ffffe0`,lime:`ff00`,limegYF:`32cd32`,lRF:`faf0e6`,magFta:`ff00ff`,maPon:`800000`,VaquamarRe:`66cdaa`,VXe:`cd`,VScEd:`ba55d3`,VpurpN:`9370db`,VsHgYF:`3cb371`,VUXe:`7b68ee`,VsprRggYF:`fa9a`,VQe:`48d1cc`,VviTetYd:`c71585`,midnightXe:`191970`,mRtcYam:`f5fffa`,mistyPse:`ffe4e1`,moccasR:`ffe4b5`,navajowEte:`ffdead`,navy:`80`,Tdlace:`fdf5e6`,Tive:`808000`,TivedBb:`6b8e23`,Sange:`ffa500`,SangeYd:`ff4500`,ScEd:`da70d6`,pOegTMnPd:`eee8aa`,pOegYF:`98fb98`,pOeQe:`afeeee`,pOeviTetYd:`db7093`,papayawEp:`ffefd5`,pHKpuff:`ffdab9`,peru:`cd853f`,pRk:`ffc0cb`,plum:`dda0dd`,powMrXe:`b0e0e6`,purpN:`800080`,YbeccapurpN:`663399`,Yd:`ff0000`,Psybrown:`bc8f8f`,PyOXe:`4169e1`,saddNbPwn:`8b4513`,sOmon:`fa8072`,sandybPwn:`f4a460`,sHgYF:`2e8b57`,sHshell:`fff5ee`,siFna:`a0522d`,silver:`c0c0c0`,skyXe:`87ceeb`,UXe:`6a5acd`,UWay:`708090`,UgYy:`708090`,snow:`fffafa`,sprRggYF:`ff7f`,stAlXe:`4682b4`,tan:`d2b48c`,teO:`8080`,tEstN:`d8bfd8`,tomato:`ff6347`,Qe:`40e0d0`,viTet:`ee82ee`,JHt:`f5deb3`,wEte:`ffffff`,wEtesmoke:`f5f5f5`,Lw:`ffff00`,LwgYF:`9acd32`};function Zo(){let e={},t=Object.keys(Xo),n=Object.keys(Yo),r,i,a,o,s;for(r=0;r>16&255,a>>8&255,a&255]}return e}var Qo;function $o(e){Qo||(Qo=Zo(),Qo.transparent=[0,0,0,0]);let t=Qo[e.toLowerCase()];return t&&{r:t[0],g:t[1],b:t[2],a:t.length===4?t[3]:255}}var es=/^rgba?\(\s*([-+.\d]+)(%)?[\s,]+([-+.e\d]+)(%)?[\s,]+([-+.e\d]+)(%)?(?:[\s,/]+([-+.e\d]+)(%)?)?\s*\)$/;function ts(e){let t=es.exec(e),n=255,r,i,a;if(t){if(t[7]!==r){let e=+t[7];n=t[8]?So(e):xo(e*255,0,255)}return r=+t[1],i=+t[3],a=+t[5],r=255&(t[2]?So(r):xo(r,0,255)),i=255&(t[4]?So(i):xo(i,0,255)),a=255&(t[6]?So(a):xo(a,0,255)),{r,g:i,b:a,a:n}}}function ns(e){return e&&(e.a<255?`rgba(${e.r}, ${e.g}, ${e.b}, ${wo(e.a)})`:`rgb(${e.r}, ${e.g}, ${e.b})`)}var rs=e=>e<=.0031308?e*12.92:e**(1/2.4)*1.055-.055,is=e=>e<=.04045?e/12.92:((e+.055)/1.055)**2.4;function as(e,t,n){let r=is(wo(e.r)),i=is(wo(e.g)),a=is(wo(e.b));return{r:Co(rs(r+n*(is(wo(t.r))-r))),g:Co(rs(i+n*(is(wo(t.g))-i))),b:Co(rs(a+n*(is(wo(t.b))-a))),a:e.a+n*(t.a-e.a)}}function os(e,t,n){if(e){let r=Bo(e);r[t]=Math.max(0,Math.min(r[t]+r[t]*n,t===0?360:1)),r=Ho(r),e.r=r[0],e.g=r[1],e.b=r[2]}}function ss(e,t){return e&&Object.assign(t||{},e)}function cs(e){var t={r:0,g:0,b:0,a:255};return Array.isArray(e)?e.length>=3&&(t={r:e[0],g:e[1],b:e[2],a:255},e.length>3&&(t.a=Co(e[3]))):(t=ss(e,{r:0,g:0,b:0,a:1}),t.a=Co(t.a)),t}function ls(e){return e.charAt(0)===`r`?ts(e):Ko(e)}var us=class e{constructor(t){if(t instanceof e)return t;let n=typeof t,r;n===`object`?r=cs(t):n===`string`&&(r=Mo(t)||$o(t)||ls(t)),this._rgb=r,this._valid=!!r}get valid(){return this._valid}get rgb(){var e=ss(this._rgb);return e&&(e.a=wo(e.a)),e}set rgb(e){this._rgb=cs(e)}rgbString(){return this._valid?ns(this._rgb):void 0}hexString(){return this._valid?Po(this._rgb):void 0}hslString(){return this._valid?Jo(this._rgb):void 0}mix(e,t){if(e){let n=this.rgb,r=e.rgb,i,a=t===i?.5:t,o=2*a-1,s=n.a-r.a,c=((o*s===-1?o:(o+s)/(1+o*s))+1)/2;i=1-c,n.r=255&c*n.r+i*r.r+.5,n.g=255&c*n.g+i*r.g+.5,n.b=255&c*n.b+i*r.b+.5,n.a=a*n.a+(1-a)*r.a,this.rgb=n}return this}interpolate(e,t){return e&&(this._rgb=as(this._rgb,e._rgb,t)),this}clone(){return new e(this.rgb)}alpha(e){return this._rgb.a=Co(e),this}clearer(e){let t=this._rgb;return t.a*=1-e,this}greyscale(){let e=this._rgb;return e.r=e.g=e.b=bo(e.r*.3+e.g*.59+e.b*.11),this}opaquer(e){let t=this._rgb;return t.a*=1+e,this}negate(){let e=this._rgb;return e.r=255-e.r,e.g=255-e.g,e.b=255-e.b,this}lighten(e){return os(this._rgb,2,e),this}darken(e){return os(this._rgb,2,-e),this}saturate(e){return os(this._rgb,1,e),this}desaturate(e){return os(this._rgb,1,-e),this}rotate(e){return qo(this._rgb,e),this}};function ds(){}var fs=(()=>{let e=0;return()=>e++})();function J(e){return e==null}function ps(e){if(Array.isArray&&Array.isArray(e))return!0;let t=Object.prototype.toString.call(e);return t.slice(0,7)===`[object`&&t.slice(-6)===`Array]`}function Y(e){return e!==null&&Object.prototype.toString.call(e)===`[object Object]`}function ms(e){return(typeof e==`number`||e instanceof Number)&&isFinite(+e)}function hs(e,t){return ms(e)?e:t}function X(e,t){return e===void 0?t:e}var gs=(e,t)=>typeof e==`string`&&e.endsWith(`%`)?parseFloat(e)/100:+e/t,_s=(e,t)=>typeof e==`string`&&e.endsWith(`%`)?parseFloat(e)/100*t:+e;function vs(e,t,n){if(e&&typeof e.call==`function`)return e.apply(n,t)}function Z(e,t,n,r){let i,a,o;if(ps(e)){if(a=e.length,r)for(i=a-1;i>=0;i--)t.call(n,e[i],i);else for(i=0;ie,x:e=>e.x,y:e=>e.y};function Ds(e){let t=e.split(`.`),n=[],r=``;for(let e of t)r+=e,r.endsWith(`\\`)?r=r.slice(0,-1)+`.`:(n.push(r),r=``);return n}function Os(e){let t=Ds(e);return e=>{for(let n of t){if(n===``)break;e=e&&e[n]}return e}}function ks(e,t){return(Es[t]||(Es[t]=Os(t)))(e)}function As(e){return e.charAt(0).toUpperCase()+e.slice(1)}var js=e=>e!==void 0,Ms=e=>typeof e==`function`,Ns=(e,t)=>{if(e.size!==t.size)return!1;for(let n of e)if(!t.has(n))return!1;return!0};function Ps(e){return e.type===`mouseup`||e.type===`click`||e.type===`contextmenu`}var Q=Math.PI,$=2*Q,Fs=$+Q,Is=1/0,Ls=Q/180,Rs=Q/2,zs=Q/4,Bs=Q*2/3,Vs=Math.log10,Hs=Math.sign;function Us(e,t,n){return Math.abs(e-t)e-t).pop(),t}function Ks(e){return typeof e==`symbol`||typeof e==`object`&&!!e&&!(Symbol.toPrimitive in e||`toString`in e||`valueOf`in e)}function qs(e){return!Ks(e)&&!isNaN(parseFloat(e))&&isFinite(e)}function Js(e,t){let n=Math.round(e);return n-t<=e&&n+t>=e}function Ys(e,t,n){let r,i,a;for(r=0,i=e.length;rc&&l=Math.min(t,n)-r&&e<=Math.max(t,n)+r}function sc(e,t,n){n=n||(n=>e[n]1;)a=i+r>>1,n(a)?i=a:r=a;return{lo:i,hi:r}}var cc=(e,t,n,r)=>sc(e,n,r?r=>{let i=e[r][t];return ie[r][t]sc(e,n,r=>e[r][t]>=n);function uc(e,t,n){let r=0,i=e.length;for(;rr&&e[i-1]>n;)i--;return r>0||i{let n=`_onData`+As(t),r=e[t];Object.defineProperty(e,t,{configurable:!0,enumerable:!1,value(...t){let i=r.apply(this,t);return e._chartjs.listeners.forEach(e=>{typeof e[n]==`function`&&e[n](...t)}),i}})})}function pc(e,t){let n=e._chartjs;if(!n)return;let r=n.listeners,i=r.indexOf(t);i!==-1&&r.splice(i,1),!(r.length>0)&&(dc.forEach(t=>{delete e[t]}),delete e._chartjs)}function mc(e){let t=new Set(e);return t.size===e.length?e:Array.from(t)}var hc=function(){return typeof window>`u`?function(e){return e()}:window.requestAnimationFrame}();function gc(e,t){let n=[],r=!1;return function(...i){n=i,r||(r=!0,hc.call(window,()=>{r=!1,e.apply(t,n)}))}}function _c(e,t){let n;return function(...r){return t?(clearTimeout(n),n=setTimeout(e,t,r)):e.apply(this,r),t}}var vc=e=>e===`start`?`left`:e===`end`?`right`:`center`,yc=(e,t,n)=>e===`start`?t:e===`end`?n:(t+n)/2;function bc(e,t,n){let r=t.length,i=0,a=r;if(e._sorted){let{iScale:o,vScale:s,_parsed:c}=e,l=e.dataset&&e.dataset.options?e.dataset.options.spanGaps:null,u=o.axis,{min:d,max:f,minDefined:p,maxDefined:m}=o.getUserBounds();if(p){if(i=Math.min(cc(c,u,d).lo,n?r:cc(t,u,o.getPixelForValue(d)).lo),l){let e=c.slice(0,i+1).reverse().findIndex(e=>!J(e[s.axis]));i-=Math.max(0,e)}i=ic(i,0,r-1)}if(m){let e=Math.max(cc(c,o.axis,f,!0).hi+1,n?0:cc(t,u,o.getPixelForValue(f),!0).hi+1);if(l){let t=c.slice(e-1).findIndex(e=>!J(e[s.axis]));e+=Math.max(0,t)}a=ic(e,i,r)-i}else a=r-i}return{start:i,count:a}}function xc(e){let{xScale:t,yScale:n,_scaleRanges:r}=e,i={xmin:t.min,xmax:t.max,ymin:n.min,ymax:n.max};if(!r)return e._scaleRanges=i,!0;let a=r.xmin!==t.min||r.xmax!==t.max||r.ymin!==n.min||r.ymax!==n.max;return Object.assign(r,i),a}var Sc=e=>e===0||e===1,Cc=(e,t,n)=>-(2**(10*--e)*Math.sin((e-t)*$/n)),wc=(e,t,n)=>2**(-10*e)*Math.sin((e-t)*$/n)+1,Tc={linear:e=>e,easeInQuad:e=>e*e,easeOutQuad:e=>-e*(e-2),easeInOutQuad:e=>(e/=.5)<1?.5*e*e:-.5*(--e*(e-2)-1),easeInCubic:e=>e*e*e,easeOutCubic:e=>--e*e*e+1,easeInOutCubic:e=>(e/=.5)<1?.5*e*e*e:.5*((e-=2)*e*e+2),easeInQuart:e=>e*e*e*e,easeOutQuart:e=>-(--e*e*e*e-1),easeInOutQuart:e=>(e/=.5)<1?.5*e*e*e*e:-.5*((e-=2)*e*e*e-2),easeInQuint:e=>e*e*e*e*e,easeOutQuint:e=>--e*e*e*e*e+1,easeInOutQuint:e=>(e/=.5)<1?.5*e*e*e*e*e:.5*((e-=2)*e*e*e*e+2),easeInSine:e=>-Math.cos(e*Rs)+1,easeOutSine:e=>Math.sin(e*Rs),easeInOutSine:e=>-.5*(Math.cos(Q*e)-1),easeInExpo:e=>e===0?0:2**(10*(e-1)),easeOutExpo:e=>e===1?1:-(2**(-10*e))+1,easeInOutExpo:e=>Sc(e)?e:e<.5?.5*2**(10*(e*2-1)):.5*(-(2**(-10*(e*2-1)))+2),easeInCirc:e=>e>=1?e:-(Math.sqrt(1-e*e)-1),easeOutCirc:e=>Math.sqrt(1- --e*e),easeInOutCirc:e=>(e/=.5)<1?-.5*(Math.sqrt(1-e*e)-1):.5*(Math.sqrt(1-(e-=2)*e)+1),easeInElastic:e=>Sc(e)?e:Cc(e,.075,.3),easeOutElastic:e=>Sc(e)?e:wc(e,.075,.3),easeInOutElastic(e){let t=.1125,n=.45;return Sc(e)?e:e<.5?.5*Cc(e*2,t,n):.5+.5*wc(e*2-1,t,n)},easeInBack(e){return e*e*(2.70158*e-1.70158)},easeOutBack(e){return--e*e*(2.70158*e+1.70158)+1},easeInOutBack(e){let t=1.70158;return(e/=.5)<1?.5*(e*e*(((t*=1.525)+1)*e-t)):.5*((e-=2)*e*(((t*=1.525)+1)*e+t)+2)},easeInBounce:e=>1-Tc.easeOutBounce(1-e),easeOutBounce(e){let t=7.5625,n=2.75;return e<1/n?t*e*e:e<2/n?t*(e-=1.5/n)*e+.75:e<2.5/n?t*(e-=2.25/n)*e+.9375:t*(e-=2.625/n)*e+.984375},easeInOutBounce:e=>e<.5?Tc.easeInBounce(e*2)*.5:Tc.easeOutBounce(e*2-1)*.5+.5};function Ec(e){if(e&&typeof e==`object`){let t=e.toString();return t===`[object CanvasPattern]`||t===`[object CanvasGradient]`}return!1}function Dc(e){return Ec(e)?e:new us(e)}function Oc(e){return Ec(e)?e:new us(e).saturate(.5).darken(.1).hexString()}var kc=[`x`,`y`,`borderWidth`,`radius`,`tension`],Ac=[`color`,`borderColor`,`backgroundColor`];function jc(e){e.set(`animation`,{delay:void 0,duration:1e3,easing:`easeOutQuart`,fn:void 0,from:void 0,loop:void 0,to:void 0,type:void 0}),e.describe(`animation`,{_fallback:!1,_indexable:!1,_scriptable:e=>e!==`onProgress`&&e!==`onComplete`&&e!==`fn`}),e.set(`animations`,{colors:{type:`color`,properties:Ac},numbers:{type:`number`,properties:kc}}),e.describe(`animations`,{_fallback:`animation`}),e.set(`transitions`,{active:{animation:{duration:400}},resize:{animation:{duration:0}},show:{animations:{colors:{from:`transparent`},visible:{type:`boolean`,duration:0}}},hide:{animations:{colors:{to:`transparent`},visible:{type:`boolean`,easing:`linear`,fn:e=>e|0}}}})}function Mc(e){e.set(`layout`,{autoPadding:!0,padding:{top:0,right:0,bottom:0,left:0}})}var Nc=new Map;function Pc(e,t){t=t||{};let n=e+JSON.stringify(t),r=Nc.get(n);return r||(r=new Intl.NumberFormat(e,t),Nc.set(n,r)),r}function Fc(e,t,n){return Pc(t,n).format(e)}var Ic={values(e){return ps(e)?e:``+e},numeric(e,t,n){if(e===0)return`0`;let r=this.chart.options.locale,i,a=e;if(n.length>1){let t=Math.max(Math.abs(n[0].value),Math.abs(n[n.length-1].value));(t<1e-4||t>0x38d7ea4c68000)&&(i=`scientific`),a=Lc(e,n)}let o=Vs(Math.abs(a)),s=isNaN(o)?1:Math.max(Math.min(-1*Math.floor(o),20),0),c={notation:i,minimumFractionDigits:s,maximumFractionDigits:s};return Object.assign(c,this.options.ticks.format),Fc(e,r,c)},logarithmic(e,t,n){if(e===0)return`0`;let r=n[t].significand||e/10**Math.floor(Vs(e));return[1,2,3,5,10,15].includes(r)||t>.8*n.length?Ic.numeric.call(this,e,t,n):``}};function Lc(e,t){let n=t.length>3?t[2].value-t[1].value:t[1].value-t[0].value;return Math.abs(n)>=1&&e!==Math.floor(e)&&(n=e-Math.floor(e)),n}var Rc={formatters:Ic};function zc(e){e.set(`scale`,{display:!0,offset:!1,reverse:!1,beginAtZero:!1,bounds:`ticks`,clip:!0,grace:0,grid:{display:!0,lineWidth:1,drawOnChartArea:!0,drawTicks:!0,tickLength:8,tickWidth:(e,t)=>t.lineWidth,tickColor:(e,t)=>t.color,offset:!1},border:{display:!0,dash:[],dashOffset:0,width:1},title:{display:!1,text:``,padding:{top:4,bottom:4}},ticks:{minRotation:0,maxRotation:50,mirror:!1,textStrokeWidth:0,textStrokeColor:``,padding:3,display:!0,autoSkip:!0,autoSkipPadding:3,labelOffset:0,callback:Rc.formatters.values,minor:{},major:{},align:`center`,crossAlign:`near`,showLabelBackdrop:!1,backdropColor:`rgba(255, 255, 255, 0.75)`,backdropPadding:2}}),e.route(`scale.ticks`,`color`,``,`color`),e.route(`scale.grid`,`color`,``,`borderColor`),e.route(`scale.border`,`color`,``,`borderColor`),e.route(`scale.title`,`color`,``,`color`),e.describe(`scale`,{_fallback:!1,_scriptable:e=>!e.startsWith(`before`)&&!e.startsWith(`after`)&&e!==`callback`&&e!==`parser`,_indexable:e=>e!==`borderDash`&&e!==`tickBorderDash`&&e!==`dash`}),e.describe(`scales`,{_fallback:`scale`}),e.describe(`scale.ticks`,{_scriptable:e=>e!==`backdropPadding`&&e!==`callback`,_indexable:e=>e!==`backdropPadding`})}var Bc=Object.create(null),Vc=Object.create(null);function Hc(e,t){if(!t)return e;let n=t.split(`.`);for(let t=0,r=n.length;te.chart.platform.getDevicePixelRatio(),this.elements={},this.events=[`mousemove`,`mouseout`,`click`,`touchstart`,`touchmove`],this.font={family:`'Helvetica Neue', 'Helvetica', 'Arial', sans-serif`,size:12,style:`normal`,lineHeight:1.2,weight:null},this.hover={},this.hoverBackgroundColor=(e,t)=>Oc(t.backgroundColor),this.hoverBorderColor=(e,t)=>Oc(t.borderColor),this.hoverColor=(e,t)=>Oc(t.color),this.indexAxis=`x`,this.interaction={mode:`nearest`,intersect:!0,includeInvisible:!1},this.maintainAspectRatio=!0,this.onHover=null,this.onClick=null,this.parsing=!0,this.plugins={},this.responsive=!0,this.scale=void 0,this.scales={},this.showLine=!0,this.drawActiveElementsOnTop=!0,this.describe(e),this.apply(t)}set(e,t){return Uc(this,e,t)}get(e){return Hc(this,e)}describe(e,t){return Uc(Vc,e,t)}override(e,t){return Uc(Bc,e,t)}route(e,t,n,r){let i=Hc(this,e),a=Hc(this,n),o=`_`+t;Object.defineProperties(i,{[o]:{value:i[t],writable:!0},[t]:{enumerable:!0,get(){let e=this[o],t=a[r];return Y(e)?Object.assign({},t,e):X(e,t)},set(e){this[o]=e}}})}apply(e){e.forEach(e=>e(this))}}({_scriptable:e=>!e.startsWith(`on`),_indexable:e=>e!==`events`,hover:{_fallback:`interaction`},interaction:{_scriptable:!1,_indexable:!1}},[jc,Mc,zc]);function Gc(e){return!e||J(e.size)||J(e.family)?null:(e.style?e.style+` `:``)+(e.weight?e.weight+` `:``)+e.size+`px `+e.family}function Kc(e,t,n,r,i){let a=t[i];return a||(a=t[i]=e.measureText(i).width,n.push(i)),a>r&&(r=a),r}function qc(e,t,n,r){r=r||{};let i=r.data=r.data||{},a=r.garbageCollect=r.garbageCollect||[];r.font!==t&&(i=r.data={},a=r.garbageCollect=[],r.font=t),e.save(),e.font=t;let o=0,s=n.length,c,l,u,d,f;for(c=0;cn.length){for(c=0;c0&&e.stroke()}}function Qc(e,t,n){return n=n||.5,!t||e&&e.x>t.left-n&&e.xt.top-n&&e.y0&&a.strokeColor!==``,c,l;for(e.save(),e.font=i.string,rl(e,a),c=0;c+e||0;function fl(e,t){let n={},r=Y(t),i=r?Object.keys(t):t,a=Y(e)?r?n=>X(e[n],e[t[n]]):t=>e[t]:()=>e;for(let e of i)n[e]=dl(a(e));return n}function pl(e){return fl(e,{top:`y`,right:`x`,bottom:`y`,left:`x`})}function ml(e){return fl(e,[`topLeft`,`topRight`,`bottomLeft`,`bottomRight`])}function hl(e){let t=pl(e);return t.width=t.left+t.right,t.height=t.top+t.bottom,t}function gl(e,t){e=e||{},t=t||Wc.font;let n=X(e.size,t.size);typeof n==`string`&&(n=parseInt(n,10));let r=X(e.style,t.style);r&&!(``+r).match(ll)&&(console.warn(`Invalid font style specified: "`+r+`"`),r=void 0);let i={family:X(e.family,t.family),lineHeight:ul(X(e.lineHeight,t.lineHeight),n),size:n,style:r,weight:X(e.weight,t.weight),string:``};return i.string=Gc(i),i}function _l(e,t,n,r){let i=!0,a,o,s;for(a=0,o=e.length;an&&e===0?0:e+t;return{min:o(r,-Math.abs(a)),max:o(i,a)}}function yl(e,t){return Object.assign(Object.create(e),t)}function bl(e,t=[``],n,r,i=()=>e[0]){let a=n||e;return r===void 0&&(r=Il(`_fallback`,e)),new Proxy({[Symbol.toStringTag]:`Object`,_cacheable:!0,_scopes:e,_rootScopes:a,_fallback:r,_getTarget:i,override:n=>bl([n,...e],t,a,r)},{deleteProperty(t,n){return delete t[n],delete t._keys,delete e[0][n],!0},get(n,r){return Tl(n,r,()=>Fl(r,t,e,n))},getOwnPropertyDescriptor(e,t){return Reflect.getOwnPropertyDescriptor(e._scopes[0],t)},getPrototypeOf(){return Reflect.getPrototypeOf(e[0])},has(e,t){return Ll(e).includes(t)},ownKeys(e){return Ll(e)},set(e,t,n){let r=e._storage||(e._storage=i());return e[t]=r[t]=n,delete e._keys,!0}})}function xl(e,t,n,r){let i={_cacheable:!1,_proxy:e,_context:t,_subProxy:n,_stack:new Set,_descriptors:Sl(e,r),setContext:t=>xl(e,t,n,r),override:i=>xl(e.override(i),t,n,r)};return new Proxy(i,{deleteProperty(t,n){return delete t[n],delete e[n],!0},get(e,t,n){return Tl(e,t,()=>El(e,t,n))},getOwnPropertyDescriptor(t,n){return t._descriptors.allKeys?Reflect.has(e,n)?{enumerable:!0,configurable:!0}:void 0:Reflect.getOwnPropertyDescriptor(e,n)},getPrototypeOf(){return Reflect.getPrototypeOf(e)},has(t,n){return Reflect.has(e,n)},ownKeys(){return Reflect.ownKeys(e)},set(t,n,r){return e[n]=r,delete t[n],!0}})}function Sl(e,t={scriptable:!0,indexable:!0}){let{_scriptable:n=t.scriptable,_indexable:r=t.indexable,_allKeys:i=t.allKeys}=e;return{allKeys:i,scriptable:n,indexable:r,isScriptable:Ms(n)?n:()=>n,isIndexable:Ms(r)?r:()=>r}}var Cl=(e,t)=>e?e+As(t):t,wl=(e,t)=>Y(t)&&e!==`adapters`&&(Object.getPrototypeOf(t)===null||t.constructor===Object);function Tl(e,t,n){if(Object.prototype.hasOwnProperty.call(e,t)||t===`constructor`)return e[t];let r=n();return e[t]=r,r}function El(e,t,n){let{_proxy:r,_context:i,_subProxy:a,_descriptors:o}=e,s=r[t];return Ms(s)&&o.isScriptable(t)&&(s=Dl(t,s,e,n)),ps(s)&&s.length&&(s=Ol(t,s,e,o.isIndexable)),wl(t,s)&&(s=xl(s,i,a&&a[t],o)),s}function Dl(e,t,n,r){let{_proxy:i,_context:a,_subProxy:o,_stack:s}=n;if(s.has(e))throw Error(`Recursion detected: `+Array.from(s).join(`->`)+`->`+e);s.add(e);let c=t(a,o||r);return s.delete(e),wl(e,c)&&(c=Ml(i._scopes,i,e,c)),c}function Ol(e,t,n,r){let{_proxy:i,_context:a,_subProxy:o,_descriptors:s}=n;if(a.index!==void 0&&r(e))return t[a.index%t.length];if(Y(t[0])){let n=t,r=i._scopes.filter(e=>e!==n);t=[];for(let c of n){let n=Ml(r,i,e,c);t.push(xl(n,a,o&&o[e],s))}}return t}function kl(e,t,n){return Ms(e)?e(t,n):e}var Al=(e,t)=>e===!0?t:typeof e==`string`?ks(t,e):void 0;function jl(e,t,n,r,i){for(let a of t){let t=Al(n,a);if(t){e.add(t);let a=kl(t._fallback,n,i);if(a!==void 0&&a!==n&&a!==r)return a}else if(t===!1&&r!==void 0&&n!==r)return null}return!1}function Ml(e,t,n,r){let i=t._rootScopes,a=kl(t._fallback,n,r),o=[...e,...i],s=new Set;s.add(r);let c=Nl(s,o,n,a||n,r);return c===null||a!==void 0&&a!==n&&(c=Nl(s,o,a,c,r),c===null)?!1:bl(Array.from(s),[``],i,a,()=>Pl(t,n,r))}function Nl(e,t,n,r,i){for(;n;)n=jl(e,t,n,r,i);return n}function Pl(e,t,n){let r=e._getTarget();t in r||(r[t]={});let i=r[t];return ps(i)&&Y(n)?n:i||{}}function Fl(e,t,n,r){let i;for(let a of t)if(i=Il(Cl(a,e),n),i!==void 0)return wl(e,i)?Ml(n,r,e,i):i}function Il(e,t){for(let n of t){if(!n)continue;let t=n[e];if(t!==void 0)return t}}function Ll(e){let t=e._keys;return t||(t=e._keys=Rl(e._scopes)),t}function Rl(e){let t=new Set;for(let n of e)for(let e of Object.keys(n).filter(e=>!e.startsWith(`_`)))t.add(e);return Array.from(t)}function zl(e,t,n,r){let{iScale:i}=e,{key:a=`r`}=this._parsing,o=Array(r),s,c,l,u;for(s=0,c=r;ste===`x`?`y`:`x`;function Ul(e,t,n,r){let i=e.skip?t:e,a=t,o=n.skip?t:n,s=ec(a,i),c=ec(o,a),l=s/(s+c),u=c/(s+c);l=isNaN(l)?0:l,u=isNaN(u)?0:u;let d=r*l,f=r*u;return{previous:{x:a.x-d*(o.x-i.x),y:a.y-d*(o.y-i.y)},next:{x:a.x+f*(o.x-i.x),y:a.y+f*(o.y-i.y)}}}function Wl(e,t,n){let r=e.length,i,a,o,s,c,l=Vl(e,0);for(let u=0;u!e.skip)),t.cubicInterpolationMode===`monotone`)Kl(e,i);else{let n=r?e[e.length-1]:e[0];for(a=0,o=e.length;ae.ownerDocument.defaultView.getComputedStyle(e,null);function eu(e,t){return $l(e).getPropertyValue(t)}var tu=[`top`,`right`,`bottom`,`left`];function nu(e,t,n){let r={};n=n?`-`+n:``;for(let i=0;i<4;i++){let a=tu[i];r[a]=parseFloat(e[t+`-`+a+n])||0}return r.width=r.left+r.right,r.height=r.top+r.bottom,r}var ru=(e,t,n)=>(e>0||t>0)&&(!n||!n.shadowRoot);function iu(e,t){let n=e.touches,r=n&&n.length?n[0]:e,{offsetX:i,offsetY:a}=r,o=!1,s,c;if(ru(i,a,e.target))s=i,c=a;else{let e=t.getBoundingClientRect();s=r.clientX-e.left,c=r.clientY-e.top,o=!0}return{x:s,y:c,box:o}}function au(e,t){if(`native`in e)return e;let{canvas:n,currentDevicePixelRatio:r}=t,i=$l(n),a=i.boxSizing===`border-box`,o=nu(i,`padding`),s=nu(i,`border`,`width`),{x:c,y:l,box:u}=iu(e,n),d=o.left+(u&&s.left),f=o.top+(u&&s.top),{width:p,height:m}=t;return a&&(p-=o.width+s.width,m-=o.height+s.height),{x:Math.round((c-d)/p*n.width/r),y:Math.round((l-f)/m*n.height/r)}}function ou(e,t,n){let r,i;if(t===void 0||n===void 0){let a=e&&Zl(e);if(!a)t=e.clientWidth,n=e.clientHeight;else{let e=a.getBoundingClientRect(),o=$l(a),s=nu(o,`border`,`width`),c=nu(o,`padding`);t=e.width-c.width-s.width,n=e.height-c.height-s.height,r=Ql(o.maxWidth,a,`clientWidth`),i=Ql(o.maxHeight,a,`clientHeight`)}}return{width:t,height:n,maxWidth:r||Is,maxHeight:i||Is}}var su=e=>Math.round(e*10)/10;function cu(e,t,n,r){let i=$l(e),a=nu(i,`margin`),o=Ql(i.maxWidth,e,`clientWidth`)||Is,s=Ql(i.maxHeight,e,`clientHeight`)||Is,c=ou(e,t,n),{width:l,height:u}=c;if(i.boxSizing===`content-box`){let e=nu(i,`border`,`width`),t=nu(i,`padding`);l-=t.width+e.width,u-=t.height+e.height}return l=Math.max(0,l-a.width),u=Math.max(0,r?l/r:u-a.height),l=su(Math.min(l,o,c.maxWidth)),u=su(Math.min(u,s,c.maxHeight)),l&&!u&&(u=su(l/2)),(t!==void 0||n!==void 0)&&r&&c.height&&u>c.height&&(u=c.height,l=su(Math.floor(u*r))),{width:l,height:u}}function lu(e,t,n){let r=t||1,i=su(e.height*r),a=su(e.width*r);e.height=su(e.height),e.width=su(e.width);let o=e.canvas;return o.style&&(n||!o.style.height&&!o.style.width)&&(o.style.height=`${e.height}px`,o.style.width=`${e.width}px`),e.currentDevicePixelRatio!==r||o.height!==i||o.width!==a?(e.currentDevicePixelRatio=r,o.height=i,o.width=a,e.ctx.setTransform(r,0,0,r,0,0),!0):!1}var uu=function(){let e=!1;try{let t={get passive(){return e=!0,!1}};Xl()&&(window.addEventListener(`test`,null,t),window.removeEventListener(`test`,null,t))}catch{}return e}();function du(e,t){let n=eu(e,t),r=n&&n.match(/^(\d+)(\.\d+)?px$/);return r?+r[1]:void 0}function fu(e,t,n,r){return{x:e.x+n*(t.x-e.x),y:e.y+n*(t.y-e.y)}}function pu(e,t,n,r){return{x:e.x+n*(t.x-e.x),y:r===`middle`?n<.5?e.y:t.y:r===`after`?n<1?e.y:t.y:n>0?t.y:e.y}}function mu(e,t,n,r){let i={x:e.cp2x,y:e.cp2y},a={x:t.cp1x,y:t.cp1y},o=fu(e,i,n),s=fu(i,a,n),c=fu(a,t,n);return fu(fu(o,s,n),fu(s,c,n),n)}var hu=function(e,t){return{x(n){return e+e+t-n},setWidth(e){t=e},textAlign(e){return e===`center`?e:e===`right`?`left`:`right`},xPlus(e,t){return e-t},leftForLtr(e,t){return e-t}}},gu=function(){return{x(e){return e},setWidth(e){},textAlign(e){return e},xPlus(e,t){return e+t},leftForLtr(e,t){return e}}};function _u(e,t,n){return e?hu(t,n):gu()}function vu(e,t){let n,r;(t===`ltr`||t===`rtl`)&&(n=e.canvas.style,r=[n.getPropertyValue(`direction`),n.getPropertyPriority(`direction`)],n.setProperty(`direction`,t,`important`),e.prevTextDirection=r)}function yu(e,t){t!==void 0&&(delete e.prevTextDirection,e.canvas.style.setProperty(`direction`,t[0],t[1]))}function bu(e){return e===`angle`?{between:rc,compare:tc,normalize:nc}:{between:oc,compare:(e,t)=>e-t,normalize:e=>e}}function xu({start:e,end:t,count:n,loop:r,style:i}){return{start:e%n,end:t%n,loop:r&&(t-e+1)%n===0,style:i}}function Su(e,t,n){let{property:r,start:i,end:a}=n,{between:o,normalize:s}=bu(r),c=t.length,{start:l,end:u,loop:d}=e,f,p;if(d){for(l+=c,u+=c,f=0,p=c;fc(i,y,_)&&s(i,y)!==0,x=()=>s(a,_)===0||c(a,y,_),S=()=>h||b(),C=()=>!h||x();for(let e=u,n=u;e<=d;++e)v=t[e%o],!v.skip&&(_=l(v[r]),_!==y&&(h=c(_,i,a),g===null&&S()&&(g=s(_,i)===0?e:n),g!==null&&C()&&(m.push(xu({start:g,end:e,loop:f,count:o,style:p})),g=null),n=e,y=_));return g!==null&&m.push(xu({start:g,end:d,loop:f,count:o,style:p})),m}function wu(e,t){let n=[],r=e.segments;for(let i=0;ii&&e[a%t].skip;)a--;return a%=t,{start:i,end:a}}function Eu(e,t,n,r){let i=e.length,a=[],o=t,s=e[t],c;for(c=t+1;c<=n;++c){let n=e[c%i];n.skip||n.stop?s.skip||(r=!1,a.push({start:t%i,end:(c-1)%i,loop:r}),t=o=n.stop?c:null):(o=c,s.skip&&(t=c)),s=n}return o!==null&&a.push({start:t%i,end:o%i,loop:r}),a}function Du(e,t){let n=e.points,r=e.options.spanGaps,i=n.length;if(!i)return[];let a=!!e._loop,{start:o,end:s}=Tu(n,i,a,r);return r===!0?Ou(e,[{start:o,end:s,loop:a}],n,t):Ou(e,Eu(n,o,sr({chart:e,initial:t.initial,numSteps:a,currentStep:Math.min(n-t.start,a)}))}_refresh(){this._request||(this._running=!0,this._request=hc.call(window,()=>{this._update(),this._request=null,this._running&&this._refresh()}))}_update(e=Date.now()){let t=0;this._charts.forEach((n,r)=>{if(!n.running||!n.items.length)return;let i=n.items,a=i.length-1,o=!1,s;for(;a>=0;--a)s=i[a],s._active?(s._total>n.duration&&(n.duration=s._total),s.tick(e),o=!0):(i[a]=i[i.length-1],i.pop());o&&(r.draw(),this._notify(r,n,e,`progress`)),i.length||(n.running=!1,this._notify(r,n,e,`complete`),n.initial=!1),t+=i.length}),this._lastDate=e,t===0&&(this._running=!1)}_getAnims(e){let t=this._charts,n=t.get(e);return n||(n={running:!1,initial:!0,items:[],listeners:{complete:[],progress:[]}},t.set(e,n)),n}listen(e,t,n){this._getAnims(e).listeners[t].push(n)}add(e,t){!t||!t.length||this._getAnims(e).items.push(...t)}has(e){return this._getAnims(e).items.length>0}start(e){let t=this._charts.get(e);t&&(t.running=!0,t.start=Date.now(),t.duration=t.items.reduce((e,t)=>Math.max(e,t._duration),0),this._refresh())}running(e){if(!this._running)return!1;let t=this._charts.get(e);return!(!t||!t.running||!t.items.length)}stop(e){let t=this._charts.get(e);if(!t||!t.items.length)return;let n=t.items,r=n.length-1;for(;r>=0;--r)n[r].cancel();t.items=[],this._notify(e,t,Date.now(),`complete`)}remove(e){return this._charts.delete(e)}},Iu=`transparent`,Lu={boolean(e,t,n){return n>.5?t:e},color(e,t,n){let r=Dc(e||Iu),i=r.valid&&Dc(t||Iu);return i&&i.valid?i.mix(r,n).hexString():t},number(e,t,n){return e+(t-e)*n}},Ru=class{constructor(e,t,n,r){let i=t[n];r=_l([e.to,r,i,e.from]);let a=_l([e.from,i,r]);this._active=!0,this._fn=e.fn||Lu[e.type||typeof a],this._easing=Tc[e.easing]||Tc.linear,this._start=Math.floor(Date.now()+(e.delay||0)),this._duration=this._total=Math.floor(e.duration),this._loop=!!e.loop,this._target=t,this._prop=n,this._from=a,this._to=r,this._promises=void 0}active(){return this._active}update(e,t,n){if(this._active){this._notify(!1);let r=this._target[this._prop],i=n-this._start,a=this._duration-i;this._start=n,this._duration=Math.floor(Math.max(a,e.duration)),this._total+=i,this._loop=!!e.loop,this._to=_l([e.to,t,r,e.from]),this._from=_l([e.from,r,t])}}cancel(){this._active&&(this.tick(Date.now()),this._active=!1,this._notify(!1))}tick(e){let t=e-this._start,n=this._duration,r=this._prop,i=this._from,a=this._loop,o=this._to,s;if(this._active=i!==o&&(a||t1?2-s:s,s=this._easing(Math.min(1,Math.max(0,s))),this._target[r]=this._fn(i,o,s)}wait(){let e=this._promises||(this._promises=[]);return new Promise((t,n)=>{e.push({res:t,rej:n})})}_notify(e){let t=e?`res`:`rej`,n=this._promises||[];for(let e=0;e{let i=e[r];if(!Y(i))return;let a={};for(let e of t)a[e]=i[e];(ps(i.properties)&&i.properties||[r]).forEach(e=>{(e===r||!n.has(e))&&n.set(e,a)})})}_animateOptions(e,t){let n=t.options,r=Vu(e,n);if(!r)return[];let i=this._createAnimations(r,n);return n.$shared&&Bu(e.options.$animations,n).then(()=>{e.options=n},()=>{}),i}_createAnimations(e,t){let n=this._properties,r=[],i=e.$animations||(e.$animations={}),a=Object.keys(t),o=Date.now(),s;for(s=a.length-1;s>=0;--s){let c=a[s];if(c.charAt(0)===`$`)continue;if(c===`options`){r.push(...this._animateOptions(e,t));continue}let l=t[c],u=i[c],d=n.get(c);if(u){if(d&&u.active()){u.update(d,l,o);continue}u.cancel()}if(!d||!d.duration){e[c]=l;continue}i[c]=u=new Ru(d,e,c,l),r.push(u)}return r}update(e,t){if(this._properties.size===0){Object.assign(e,t);return}let n=this._createAnimations(e,t);if(n.length)return Fu.add(this._chart,n),!0}};function Bu(e,t){let n=[],r=Object.keys(t);for(let t=0;t0||!n&&t<0)return i.index}return null}function $u(e,t){let{chart:n,_cachedMeta:r}=e,i=n._stacks||(n._stacks={}),{iScale:a,vScale:o,index:s}=r,c=a.axis,l=o.axis,u=Yu(a,o,r),d=t.length,f;for(let e=0;en[e].axis===t).shift()}function td(e,t){return yl(e,{active:!1,dataset:void 0,datasetIndex:t,index:t,mode:`default`,type:`dataset`})}function nd(e,t,n){return yl(e,{active:!1,dataIndex:t,parsed:void 0,raw:void 0,element:n,index:t,mode:`default`,type:`data`})}function rd(e,t){let n=e.controller.index,r=e.vScale&&e.vScale.axis;if(r){t=t||e._parsed;for(let e of t){let t=e._stacks;if(!t||t[r]===void 0||t[r][n]===void 0)return;delete t[r][n],t[r]._visualValues!==void 0&&t[r]._visualValues[n]!==void 0&&delete t[r]._visualValues[n]}}}var id=e=>e===`reset`||e===`none`,ad=(e,t)=>t?e:Object.assign({},e),od=(e,t,n)=>e&&!t.hidden&&t._stacked&&{keys:Gu(n,!0),values:null},sd=class{constructor(e,t){this.chart=e,this._ctx=e.ctx,this.index=t,this._cachedDataOpts={},this._cachedMeta=this.getMeta(),this._type=this._cachedMeta.type,this.options=void 0,this._parsing=!1,this._data=void 0,this._objectData=void 0,this._sharedOptions=void 0,this._drawStart=void 0,this._drawCount=void 0,this.enableOptionSharing=!1,this.supportsDecimation=!1,this.$context=void 0,this._syncList=[],this.datasetElementType=new.target.datasetElementType,this.dataElementType=new.target.dataElementType,this.initialize()}initialize(){let e=this._cachedMeta;this.configure(),this.linkScales(),e._stacked=Ju(e.vScale,e),this.addElements(),this.options.fill&&!this.chart.isPluginEnabled(`filler`)&&console.warn(`Tried to use the 'fill' option without the 'Filler' plugin enabled. Please import and register the 'Filler' plugin and make sure it is not disabled in the options`)}updateIndex(e){this.index!==e&&rd(this._cachedMeta),this.index=e}linkScales(){let e=this.chart,t=this._cachedMeta,n=this.getDataset(),r=(e,t,n,r)=>e===`x`?t:e===`r`?r:n,i=t.xAxisID=X(n.xAxisID,ed(e,`x`)),a=t.yAxisID=X(n.yAxisID,ed(e,`y`)),o=t.rAxisID=X(n.rAxisID,ed(e,`r`)),s=t.indexAxis,c=t.iAxisID=r(s,i,a,o),l=t.vAxisID=r(s,a,i,o);t.xScale=this.getScaleForId(i),t.yScale=this.getScaleForId(a),t.rScale=this.getScaleForId(o),t.iScale=this.getScaleForId(c),t.vScale=this.getScaleForId(l)}getDataset(){return this.chart.data.datasets[this.index]}getMeta(){return this.chart.getDatasetMeta(this.index)}getScaleForId(e){return this.chart.scales[e]}_getOtherScale(e){let t=this._cachedMeta;return e===t.iScale?t.vScale:t.iScale}reset(){this._update(`reset`)}_destroy(){let e=this._cachedMeta;this._data&&pc(this._data,this),e._stacked&&rd(e)}_dataCheck(){let e=this.getDataset(),t=e.data||(e.data=[]),n=this._data;if(Y(t)){let e=this._cachedMeta;this._data=qu(t,e)}else if(n!==t){if(n){pc(n,this);let e=this._cachedMeta;rd(e),e._parsed=[]}t&&Object.isExtensible(t)&&fc(t,this),this._syncList=[],this._data=t}}addElements(){let e=this._cachedMeta;this._dataCheck(),this.datasetElementType&&(e.dataset=new this.datasetElementType)}buildOrUpdateElements(e){let t=this._cachedMeta,n=this.getDataset(),r=!1;this._dataCheck();let i=t._stacked;t._stacked=Ju(t.vScale,t),t.stack!==n.stack&&(r=!0,rd(t),t.stack=n.stack),this._resyncElements(e),(r||i!==t._stacked)&&($u(this,t._parsed),t._stacked=Ju(t.vScale,t))}configure(){let e=this.chart.config,t=e.datasetScopeKeys(this._type),n=e.getOptionScopes(this.getDataset(),t,!0);this.options=e.createResolver(n,this.getContext()),this._parsing=this.options.parsing,this._cachedDataOpts={}}parse(e,t){let{_cachedMeta:n,_data:r}=this,{iScale:i,_stacked:a}=n,o=i.axis,s=e===0&&t===r.length||n._sorted,c=e>0&&n._parsed[e-1],l,u,d;if(this._parsing===!1)n._parsed=r,n._sorted=!0,d=r;else{d=ps(r[e])?this.parseArrayData(n,r,e,t):Y(r[e])?this.parseObjectData(n,r,e,t):this.parsePrimitiveData(n,r,e,t);let i=()=>u[o]===null||c&&u[o]t||u=0;--d)if(!p()){this.updateRangeFromParsed(c,e,f,s);break}}return c}getAllParsedValues(e){let t=this._cachedMeta._parsed,n=[],r,i,a;for(r=0,i=t.length;r=0&&ethis.getContext(n,r,t),u);return p.$shared&&(p.$shared=s,i[a]=Object.freeze(ad(p,s))),p}_resolveAnimations(e,t,n){let r=this.chart,i=this._cachedDataOpts,a=`animation-${t}`,o=i[a];if(o)return o;let s;if(r.options.animation!==!1){let r=this.chart.config,i=r.datasetAnimationScopeKeys(this._type,t),a=r.getOptionScopes(this.getDataset(),i);s=r.createResolver(a,this.getContext(e,n,t))}let c=new zu(r,s&&s.animations);return s&&s._cacheable&&(i[a]=Object.freeze(c)),c}getSharedOptions(e){if(e.$shared)return this._sharedOptions||(this._sharedOptions=Object.assign({},e))}includeOptions(e,t){return!t||id(e)||this.chart._animationsDisabled}_getSharedOptions(e,t){let n=this.resolveDataElementOptions(e,t),r=this._sharedOptions,i=this.getSharedOptions(n),a=this.includeOptions(t,i)||i!==r;return this.updateSharedOptions(i,t,n),{sharedOptions:i,includeOptions:a}}updateElement(e,t,n,r){id(r)?Object.assign(e,n):this._resolveAnimations(t,r).update(e,n)}updateSharedOptions(e,t,n){e&&!id(t)&&this._resolveAnimations(void 0,t).update(e,n)}_setStyle(e,t,n,r){e.active=r;let i=this.getStyle(t,r);this._resolveAnimations(t,n,r).update(e,{options:!r&&this.getSharedOptions(i)||i})}removeHoverStyle(e,t,n){this._setStyle(e,n,`active`,!1)}setHoverStyle(e,t,n){this._setStyle(e,n,`active`,!0)}_removeDatasetHoverStyle(){let e=this._cachedMeta.dataset;e&&this._setStyle(e,void 0,`active`,!1)}_setDatasetHoverStyle(){let e=this._cachedMeta.dataset;e&&this._setStyle(e,void 0,`active`,!0)}_resyncElements(e){let t=this._data,n=this._cachedMeta.data;for(let[e,t,n]of this._syncList)this[e](t,n);this._syncList=[];let r=n.length,i=t.length,a=Math.min(i,r);a&&this.parse(0,a),i>r?this._insertElements(r,i-r,e):i{for(e.length+=t,o=e.length-1;o>=a;o--)e[o]=e[o-t]};for(s(i),o=e;oe-t))}return e._cache.$bar}function ld(e){let t=e.iScale,n=cd(t,e.type),r=t._length,i,a,o,s,c=()=>{o!==32767&&o!==-32768&&(js(s)&&(r=Math.min(r,Math.abs(o-s)||r)),s=o)};for(i=0,a=n.length;i0?i[e-1]:null,s=eMath.abs(s)&&(c=s,l=o),t[n.axis]=l,t._custom={barStart:c,barEnd:l,start:i,end:a,min:o,max:s}}function pd(e,t,n,r){return ps(e)?fd(e,t,n,r):t[n.axis]=n.parse(e,r),t}function md(e,t,n,r){let i=e.iScale,a=e.vScale,o=i.getLabels(),s=i===a,c=[],l,u,d,f;for(l=n,u=n+r;l=n?1:-1):Hs(e)}function _d(e){let t,n,r,i,a;return e.horizontal?(t=e.base>e.x,n=`left`,r=`right`):(t=e.basee.controller.options.grouped),i=n.options.stacked,a=[],o=this._cachedMeta.controller.getParsed(t),s=o&&o[n.axis],c=e=>{let t=e._parsed.find(e=>e[n.axis]===s),r=t&&t[e.vScale.axis];if(J(r)||isNaN(r))return!0};for(let n of r)if(!(t!==void 0&&c(n))&&((i===!1||a.indexOf(n.stack)===-1||i===void 0&&n.stack===void 0)&&a.push(n.stack),n.index===e))break;return a.length||a.push(void 0),a}_getStackCount(e){return this._getStacks(void 0,e).length}_getAxisCount(){return this._getAxis().length}getFirstScaleIdForIndexAxis(){let e=this.chart.scales,t=this.chart.options.indexAxis;return Object.keys(e).filter(n=>e[n].axis===t).shift()}_getAxis(){let e={},t=this.getFirstScaleIdForIndexAxis();for(let n of this.chart.data.datasets)e[X(this.chart.options.indexAxis===`x`?n.xAxisID:n.yAxisID,t)]=!0;return Object.keys(e)}_getStackIndex(e,t,n){let r=this._getStacks(e,n),i=t===void 0?-1:r.indexOf(t);return i===-1?r.length-1:i}_getRuler(){let e=this.options,t=this._cachedMeta,n=t.iScale,r=[],i,a;for(i=0,a=t.data.length;i=0;--n)t=Math.max(t,e[n].size(this.resolveDataElementOptions(n))/2);return t>0&&t}getLabelAndValue(e){let t=this._cachedMeta,n=this.chart.data.labels||[],{xScale:r,yScale:i}=t,a=this.getParsed(e),o=r.getLabelForValue(a.x),s=i.getLabelForValue(a.y),c=a._custom;return{label:n[e]||``,value:`(`+o+`, `+s+(c?`, `+c:``)+`)`}}update(e){let t=this._cachedMeta.data;this.updateElements(t,0,t.length,e)}updateElements(e,t,n,r){let i=r===`reset`,{iScale:a,vScale:o}=this._cachedMeta,{sharedOptions:s,includeOptions:c}=this._getSharedOptions(t,r),l=a.axis,u=o.axis;for(let d=t;drc(e,s,c,!0)?1:Math.max(t,t*n,r,r*n),m=(e,t,r)=>rc(e,s,c,!0)?-1:Math.min(t,t*n,r,r*n),h=p(0,l,d),g=p(Rs,u,f),_=m(Q,l,d),v=m(Q+Rs,u,f);r=(h-_)/2,i=(g-v)/2,a=-(h+_)/2,o=-(g+v)/2}return{ratioX:r,ratioY:i,offsetX:a,offsetY:o}}var Ed=class extends sd{constructor(e,t){super(e,t),this.enableOptionSharing=!0,this.innerRadius=void 0,this.outerRadius=void 0,this.offsetX=void 0,this.offsetY=void 0}linkScales(){}parse(e,t){let n=this.getDataset().data,r=this._cachedMeta;if(this._parsing===!1)r._parsed=n;else{let i=e=>+n[e];if(Y(n[e])){let{key:e=`value`}=this._parsing;i=t=>+ks(n[t],e)}let a,o;for(a=e,o=e+t;a0&&!isNaN(e)?Math.abs(e)/t*$:0}getLabelAndValue(e){let t=this._cachedMeta,n=this.chart,r=n.data.labels||[],i=Fc(t._parsed[e],n.options.locale);return{label:r[e]||``,value:i}}getMaxBorderWidth(e){let t=0,n=this.chart,r,i,a,o,s;if(!e){for(r=0,i=n.data.datasets.length;re!==`spacing`,_indexable:e=>e!==`spacing`&&!e.startsWith(`borderDash`)&&!e.startsWith(`hoverBorderDash`)}),L(Ed,`overrides`,{aspectRatio:1,plugins:{legend:{labels:{generateLabels(e){let t=e.data,{labels:{pointStyle:n,textAlign:r,color:i,useBorderRadius:a,borderRadius:o}}=e.legend.options;return t.labels.length&&t.datasets.length?t.labels.map((t,s)=>{let c=e.getDatasetMeta(0).controller.getStyle(s);return{text:t,fillStyle:c.backgroundColor,fontColor:i,hidden:!e.getDataVisibility(s),lineDash:c.borderDash,lineDashOffset:c.borderDashOffset,lineJoin:c.borderJoinStyle,lineWidth:c.borderWidth,strokeStyle:c.borderColor,textAlign:r,pointStyle:n,borderRadius:a&&(o||c.borderRadius),index:s}}):[]}},onClick(e,t,n){n.chart.toggleDataVisibility(t.index),n.chart.update()}}}});var Dd=class extends sd{initialize(){this.enableOptionSharing=!0,this.supportsDecimation=!0,super.initialize()}update(e){let t=this._cachedMeta,{dataset:n,data:r=[],_dataset:i}=t,a=this.chart._animationsDisabled,{start:o,count:s}=bc(t,r,a);this._drawStart=o,this._drawCount=s,xc(t)&&(o=0,s=r.length),n._chart=this.chart,n._datasetIndex=this.index,n._decimated=!!i._decimated,n.points=r;let c=this.resolveDatasetElementOptions(e);this.options.showLine||(c.borderWidth=0),c.segment=this.options.segment,this.updateElement(n,void 0,{animated:!a,options:c},e),this.updateElements(r,o,s,e)}updateElements(e,t,n,r){let i=r===`reset`,{iScale:a,vScale:o,_stacked:s,_dataset:c}=this._cachedMeta,{sharedOptions:l,includeOptions:u}=this._getSharedOptions(t,r),d=a.axis,f=o.axis,{spanGaps:p,segment:m}=this.options,h=qs(p)?p:1/0,g=this.chart._animationsDisabled||i||r===`none`,_=t+n,v=e.length,y=t>0&&this.getParsed(t-1);for(let n=0;n=_){v.skip=!0;continue}let b=this.getParsed(n),x=J(b[f]),S=v[d]=a.getPixelForValue(b[d],n),C=v[f]=i||x?o.getBasePixel():o.getPixelForValue(s?this.applyStack(o,b,s):b[f],n);v.skip=isNaN(S)||isNaN(C)||x,v.stop=n>0&&Math.abs(b[d]-y[d])>h,m&&(v.parsed=b,v.raw=c.data[n]),u&&(v.options=l||this.resolveDataElementOptions(n,p.active?`active`:r)),g||this.updateElement(p,n,v,r),y=b}}getMaxOverflow(){let e=this._cachedMeta,t=e.dataset,n=t.options&&t.options.borderWidth||0,r=e.data||[];if(!r.length)return n;let i=r[0].size(this.resolveDataElementOptions(0)),a=r[r.length-1].size(this.resolveDataElementOptions(r.length-1));return Math.max(n,i,a)/2}draw(){let e=this._cachedMeta;e.dataset.updateControlPoints(this.chart.chartArea,e.iScale.axis),super.draw()}};L(Dd,`id`,`line`),L(Dd,`defaults`,{datasetElementType:`line`,dataElementType:`point`,showLine:!0,spanGaps:!1}),L(Dd,`overrides`,{scales:{_index_:{type:`category`},_value_:{type:`linear`}}});var Od=class extends sd{constructor(e,t){super(e,t),this.innerRadius=void 0,this.outerRadius=void 0}getLabelAndValue(e){let t=this._cachedMeta,n=this.chart,r=n.data.labels||[],i=Fc(t._parsed[e].r,n.options.locale);return{label:r[e]||``,value:i}}parseObjectData(e,t,n,r){return zl.bind(this)(e,t,n,r)}update(e){let t=this._cachedMeta.data;this._updateRadius(),this.updateElements(t,0,t.length,e)}getMinMax(){let e=this._cachedMeta,t={min:1/0,max:-1/0};return e.data.forEach((e,n)=>{let r=this.getParsed(n).r;!isNaN(r)&&this.chart.getDataVisibility(n)&&(rt.max&&(t.max=r))}),t}_updateRadius(){let e=this.chart,t=e.chartArea,n=e.options,r=Math.min(t.right-t.left,t.bottom-t.top),i=Math.max(r/2,0),a=(i-Math.max(n.cutoutPercentage?i/100*n.cutoutPercentage:1,0))/e.getVisibleDatasetCount();this.outerRadius=i-a*this.index,this.innerRadius=this.outerRadius-a}updateElements(e,t,n,r){let i=r===`reset`,a=this.chart,o=a.options.animation,s=this._cachedMeta.rScale,c=s.xCenter,l=s.yCenter,u=s.getIndexAngle(0)-.5*Q,d=u,f,p=360/this.countVisibleElements();for(f=0;f{!isNaN(this.getParsed(n).r)&&this.chart.getDataVisibility(n)&&t++}),t}_computeAngle(e,t,n){return this.chart.getDataVisibility(e)?Xs(this.resolveDataElementOptions(e,t).angle||n):0}};L(Od,`id`,`polarArea`),L(Od,`defaults`,{dataElementType:`arc`,animation:{animateRotate:!0,animateScale:!0},animations:{numbers:{type:`number`,properties:[`x`,`y`,`startAngle`,`endAngle`,`innerRadius`,`outerRadius`]}},indexAxis:`r`,startAngle:0}),L(Od,`overrides`,{aspectRatio:1,plugins:{legend:{labels:{generateLabels(e){let t=e.data;if(t.labels.length&&t.datasets.length){let{labels:{pointStyle:n,color:r}}=e.legend.options;return t.labels.map((t,i)=>{let a=e.getDatasetMeta(0).controller.getStyle(i);return{text:t,fillStyle:a.backgroundColor,strokeStyle:a.borderColor,fontColor:r,lineWidth:a.borderWidth,pointStyle:n,hidden:!e.getDataVisibility(i),index:i}})}return[]}},onClick(e,t,n){n.chart.toggleDataVisibility(t.index),n.chart.update()}}},scales:{r:{type:`radialLinear`,angleLines:{display:!1},beginAtZero:!0,grid:{circular:!0},pointLabels:{display:!1},startAngle:0}}});var kd=class extends Ed{};L(kd,`id`,`pie`),L(kd,`defaults`,{cutout:0,rotation:0,circumference:360,radius:`100%`});var Ad=class extends sd{getLabelAndValue(e){let t=this._cachedMeta.vScale,n=this.getParsed(e);return{label:t.getLabels()[e],value:``+t.getLabelForValue(n[t.axis])}}parseObjectData(e,t,n,r){return zl.bind(this)(e,t,n,r)}update(e){let t=this._cachedMeta,n=t.dataset,r=t.data||[],i=t.iScale.getLabels();if(n.points=r,e!==`resize`){let t=this.resolveDatasetElementOptions(e);this.options.showLine||(t.borderWidth=0);let a={_loop:!0,_fullLoop:i.length===r.length,options:t};this.updateElement(n,void 0,a,e)}this.updateElements(r,0,r.length,e)}updateElements(e,t,n,r){let i=this._cachedMeta.rScale,a=r===`reset`;for(let o=t;o0&&this.getParsed(t-1);for(let l=t;l0&&Math.abs(n[f]-v[f])>g,h&&(m.parsed=n,m.raw=c.data[l]),d&&(m.options=u||this.resolveDataElementOptions(l,t.active?`active`:r)),_||this.updateElement(t,l,m,r),v=n}this.updateSharedOptions(u,r,l)}getMaxOverflow(){let e=this._cachedMeta,t=e.data||[];if(!this.options.showLine){let e=0;for(let n=t.length-1;n>=0;--n)e=Math.max(e,t[n].size(this.resolveDataElementOptions(n))/2);return e>0&&e}let n=e.dataset,r=n.options&&n.options.borderWidth||0;if(!t.length)return r;let i=t[0].size(this.resolveDataElementOptions(0)),a=t[t.length-1].size(this.resolveDataElementOptions(t.length-1));return Math.max(r,i,a)/2}};L(jd,`id`,`scatter`),L(jd,`defaults`,{datasetElementType:!1,dataElementType:`point`,showLine:!1,fill:!1}),L(jd,`overrides`,{interaction:{mode:`point`},scales:{x:{type:`linear`},y:{type:`linear`}}});function Md(){throw Error(`This method is not implemented: Check that a complete date adapter is provided.`)}var Nd={_date:class e{static override(t){Object.assign(e.prototype,t)}constructor(e){L(this,`options`,void 0),this.options=e||{}}init(){}formats(){return Md()}parse(){return Md()}format(){return Md()}add(){return Md()}diff(){return Md()}startOf(){return Md()}endOf(){return Md()}}};function Pd(e,t,n,r){let{controller:i,data:a,_sorted:o}=e,s=i._cachedMeta.iScale,c=e.dataset&&e.dataset.options?e.dataset.options.spanGaps:null;if(s&&t===s.axis&&t!==`r`&&o&&a.length){let o=s._reversePixels?lc:cc;if(!r){let r=o(a,t,n);if(c){let{vScale:t}=i._cachedMeta,{_parsed:n}=e,a=n.slice(0,r.lo+1).reverse().findIndex(e=>!J(e[t.axis]));r.lo-=Math.max(0,a);let o=n.slice(r.hi).findIndex(e=>!J(e[t.axis]));r.hi+=Math.max(0,o)}return r}if(i._sharedOptions){let e=a[0],r=typeof e.getRange==`function`&&e.getRange(t);if(r){let e=o(a,t,n-r),i=o(a,t,n+r);return{lo:e.lo,hi:i.hi}}}}return{lo:0,hi:a.length-1}}function Fd(e,t,n,r,i){let a=e.getSortedVisibleDatasetMetas(),o=n[t];for(let e=0,n=a.length;e{e[o]&&e[o](t[n],i)&&(a.push({element:e,datasetIndex:r,index:c}),s=s||e.inRange(t.x,t.y,i))}),r&&!s?[]:a}var Hd={evaluateInteractionItems:Fd,modes:{index(e,t,n,r){let i=au(t,e),a=n.axis||`x`,o=n.includeInvisible||!1,s=n.intersect?Ld(e,i,a,r,o):Bd(e,i,a,!1,r,o),c=[];return s.length?(e.getSortedVisibleDatasetMetas().forEach(e=>{let t=s[0].index,n=e.data[t];n&&!n.skip&&c.push({element:n,datasetIndex:e.index,index:t})}),c):[]},dataset(e,t,n,r){let i=au(t,e),a=n.axis||`xy`,o=n.includeInvisible||!1,s=n.intersect?Ld(e,i,a,r,o):Bd(e,i,a,!1,r,o);if(s.length>0){let t=s[0].datasetIndex,n=e.getDatasetMeta(t).data;s=[];for(let e=0;ee.pos===t)}function Gd(e,t){return e.filter(e=>Ud.indexOf(e.pos)===-1&&e.box.axis===t)}function Kd(e,t){return e.sort((e,n)=>{let r=t?n:e,i=t?e:n;return r.weight===i.weight?r.index-i.index:r.weight-i.weight})}function qd(e){let t=[],n,r,i,a,o,s;for(n=0,r=(e||[]).length;ne.box.fullSize),!0),r=Kd(Wd(t,`left`),!0),i=Kd(Wd(t,`right`)),a=Kd(Wd(t,`top`),!0),o=Kd(Wd(t,`bottom`)),s=Gd(t,`x`),c=Gd(t,`y`);return{fullSize:n,leftAndTop:r.concat(a),rightAndBottom:i.concat(c).concat(o).concat(s),chartArea:Wd(t,`chartArea`),vertical:r.concat(i).concat(c),horizontal:a.concat(o).concat(s)}}function Zd(e,t,n,r){return Math.max(e[n],t[n])+Math.max(e[r],t[r])}function Qd(e,t){e.top=Math.max(e.top,t.top),e.left=Math.max(e.left,t.left),e.bottom=Math.max(e.bottom,t.bottom),e.right=Math.max(e.right,t.right)}function $d(e,t,n,r){let{pos:i,box:a}=n,o=e.maxPadding;if(!Y(i)){n.size&&(e[i]-=n.size);let t=r[n.stack]||{size:0,count:1};t.size=Math.max(t.size,n.horizontal?a.height:a.width),n.size=t.size/t.count,e[i]+=n.size}a.getPadding&&Qd(o,a.getPadding());let s=Math.max(0,t.outerWidth-Zd(o,e,`left`,`right`)),c=Math.max(0,t.outerHeight-Zd(o,e,`top`,`bottom`)),l=s!==e.w,u=c!==e.h;return e.w=s,e.h=c,n.horizontal?{same:l,other:u}:{same:u,other:l}}function ef(e){let t=e.maxPadding;function n(n){let r=Math.max(t[n]-e[n],0);return e[n]+=r,r}e.y+=n(`top`),e.x+=n(`left`),n(`right`),n(`bottom`)}function tf(e,t){let n=t.maxPadding;function r(e){let r={left:0,top:0,right:0,bottom:0};return e.forEach(e=>{r[e]=Math.max(t[e],n[e])}),r}return r(e?[`left`,`right`]:[`top`,`bottom`])}function nf(e,t,n,r){let i=[],a,o,s,c,l,u;for(a=0,o=e.length,l=0;a{typeof e.beforeLayout==`function`&&e.beforeLayout()});let u=c.reduce((e,t)=>t.box.options&&t.box.options.display===!1?e:e+1,0)||1,d=Object.freeze({outerWidth:t,outerHeight:n,padding:i,availableWidth:a,availableHeight:o,vBoxMaxWidth:a/2/u,hBoxMaxHeight:o/2}),f=Object.assign({},i);Qd(f,hl(r));let p=Object.assign({maxPadding:f,w:a,h:o,x:i.left,y:i.top},i),m=Yd(c.concat(l),d);nf(s.fullSize,p,d,m),nf(c,p,d,m),nf(l,p,d,m)&&nf(c,p,d,m),ef(p),af(s.leftAndTop,p,d,m),p.x+=p.w,p.y+=p.h,af(s.rightAndBottom,p,d,m),e.chartArea={left:p.left,top:p.top,right:p.left+p.w,bottom:p.top+p.h,height:p.h,width:p.w},Z(s.chartArea,t=>{let n=t.box;Object.assign(n,e.chartArea),n.update(p.w,p.h,{left:0,top:0,right:0,bottom:0})})}},sf=class{acquireContext(e,t){}releaseContext(e){return!1}addEventListener(e,t,n){}removeEventListener(e,t,n){}getDevicePixelRatio(){return 1}getMaximumSize(e,t,n,r){return t=Math.max(0,t||e.width),n=n||e.height,{width:t,height:Math.max(0,r?Math.floor(t/r):n)}}isAttached(e){return!0}updateConfig(e){}},cf=class extends sf{acquireContext(e){return e&&e.getContext&&e.getContext(`2d`)||null}updateConfig(e){e.options.animation=!1}},lf=`$chartjs`,uf={touchstart:`mousedown`,touchmove:`mousemove`,touchend:`mouseup`,pointerenter:`mouseenter`,pointerdown:`mousedown`,pointermove:`mousemove`,pointerup:`mouseup`,pointerleave:`mouseout`,pointerout:`mouseout`},df=e=>e===null||e===``;function ff(e,t){let n=e.style,r=e.getAttribute(`height`),i=e.getAttribute(`width`);if(e[lf]={initial:{height:r,width:i,style:{display:n.display,height:n.height,width:n.width}}},n.display=n.display||`block`,n.boxSizing=n.boxSizing||`border-box`,df(i)){let t=du(e,`width`);t!==void 0&&(e.width=t)}if(df(r)){if(e.style.height===``)e.height=e.width/(t||2);else{let t=du(e,`height`);t!==void 0&&(e.height=t)}}return e}var pf=uu?{passive:!0}:!1;function mf(e,t,n){e&&e.addEventListener(t,n,pf)}function hf(e,t,n){e&&e.canvas&&e.canvas.removeEventListener(t,n,pf)}function gf(e,t){let n=uf[e.type]||e.type,{x:r,y:i}=au(e,t);return{type:n,chart:t,native:e,x:r===void 0?null:r,y:i===void 0?null:i}}function _f(e,t){for(let n of e)if(n===t||n.contains(t))return!0}function vf(e,t,n){let r=e.canvas,i=new MutationObserver(e=>{let t=!1;for(let n of e)t=t||_f(n.addedNodes,r),t=t&&!_f(n.removedNodes,r);t&&n()});return i.observe(document,{childList:!0,subtree:!0}),i}function yf(e,t,n){let r=e.canvas,i=new MutationObserver(e=>{let t=!1;for(let n of e)t=t||_f(n.removedNodes,r),t=t&&!_f(n.addedNodes,r);t&&n()});return i.observe(document,{childList:!0,subtree:!0}),i}var bf=new Map,xf=0;function Sf(){let e=window.devicePixelRatio;e!==xf&&(xf=e,bf.forEach((t,n)=>{n.currentDevicePixelRatio!==e&&t()}))}function Cf(e,t){bf.size||window.addEventListener(`resize`,Sf),bf.set(e,t)}function wf(e){bf.delete(e),bf.size||window.removeEventListener(`resize`,Sf)}function Tf(e,t,n){let r=e.canvas,i=r&&Zl(r);if(!i)return;let a=gc((e,t)=>{let r=i.clientWidth;n(e,t),r{let t=e[0],n=t.contentRect.width,r=t.contentRect.height;(n!==0||r!==0)&&a(n,r)});return o.observe(i),Cf(e,a),o}function Ef(e,t,n){n&&n.disconnect(),t===`resize`&&wf(e)}function Df(e,t,n){let r=e.canvas,i=gc(t=>{e.ctx!==null&&n(gf(t,e))},e);return mf(r,t,i),i}var Of=class extends sf{acquireContext(e,t){let n=e&&e.getContext&&e.getContext(`2d`);return n&&n.canvas===e?(ff(e,t),n):null}releaseContext(e){let t=e.canvas;if(!t[lf])return!1;let n=t[lf].initial;[`height`,`width`].forEach(e=>{let r=n[e];J(r)?t.removeAttribute(e):t.setAttribute(e,r)});let r=n.style||{};return Object.keys(r).forEach(e=>{t.style[e]=r[e]}),t.width=t.width,delete t[lf],!0}addEventListener(e,t,n){this.removeEventListener(e,t);let r=e.$proxies||(e.$proxies={});r[t]=({attach:vf,detach:yf,resize:Tf}[t]||Df)(e,t,n)}removeEventListener(e,t){let n=e.$proxies||(e.$proxies={}),r=n[t];r&&(({attach:Ef,detach:Ef,resize:Ef}[t]||hf)(e,t,r),n[t]=void 0)}getDevicePixelRatio(){return window.devicePixelRatio}getMaximumSize(e,t,n,r){return cu(e,t,n,r)}isAttached(e){let t=e&&Zl(e);return!!(t&&t.isConnected)}};function kf(e){return!Xl()||typeof OffscreenCanvas<`u`&&e instanceof OffscreenCanvas?cf:Of}var Af=class{constructor(){L(this,`x`,void 0),L(this,`y`,void 0),L(this,`active`,!1),L(this,`options`,void 0),L(this,`$animations`,void 0)}tooltipPosition(e){let{x:t,y:n}=this.getProps([`x`,`y`],e);return{x:t,y:n}}hasValue(){return qs(this.x)&&qs(this.y)}getProps(e,t){let n=this.$animations;if(!t||!n)return this;let r={};return e.forEach(e=>{r[e]=n[e]&&n[e].active()?n[e]._to:this[e]}),r}};L(Af,`defaults`,{}),L(Af,`defaultRoutes`,void 0);function jf(e,t){let n=e.options.ticks,r=Mf(e),i=Math.min(n.maxTicksLimit||r,r),a=n.major.enabled?Pf(t):[],o=a.length,s=a[0],c=a[o-1],l=[];if(o>i)return Ff(t,l,a,o/i),l;let u=Nf(a,t,i);if(o>0){let e,n,r=o>1?Math.round((c-s)/(o-1)):null;for(If(t,l,u,J(r)?0:s-r,s),e=0,n=o-1;ei)return t}return Math.max(i,1)}function Pf(e){let t=[],n,r;for(n=0,r=e.length;ne===`left`?`right`:e===`right`?`left`:e,zf=(e,t,n)=>t===`top`||t===`left`?e[t]+n:e[t]-n,Bf=(e,t)=>Math.min(t||e,e);function Vf(e,t){let n=[],r=e.length/t,i=e.length,a=0;for(;ao+s)))return c}function Uf(e,t){Z(e,e=>{let n=e.gc,r=n.length/2,i;if(r>t){for(i=0;in?n:t,n=r&&t>n?t:n,{min:hs(t,hs(n,t)),max:hs(n,hs(t,n))}}getPadding(){return{left:this.paddingLeft||0,top:this.paddingTop||0,right:this.paddingRight||0,bottom:this.paddingBottom||0}}getTicks(){return this.ticks}getLabels(){let e=this.chart.data;return this.options.labels||(this.isHorizontal()?e.xLabels:e.yLabels)||e.labels||[]}getLabelItems(e=this.chart.chartArea){return this._labelItems||(this._labelItems=this._computeLabelItems(e))}beforeLayout(){this._cache={},this._dataLimitsCached=!1}beforeUpdate(){vs(this.options.beforeUpdate,[this])}update(e,t,n){let{beginAtZero:r,grace:i,ticks:a}=this.options,o=a.sampleSize;this.beforeUpdate(),this.maxWidth=e,this.maxHeight=t,this._margins=n=Object.assign({left:0,right:0,top:0,bottom:0},n),this.ticks=null,this._labelSizes=null,this._gridLineItems=null,this._labelItems=null,this.beforeSetDimensions(),this.setDimensions(),this.afterSetDimensions(),this._maxLength=this.isHorizontal()?this.width+n.left+n.right:this.height+n.top+n.bottom,this._dataLimitsCached||(this.beforeDataLimits(),this.determineDataLimits(),this.afterDataLimits(),this._range=vl(this,i,r),this._dataLimitsCached=!0),this.beforeBuildTicks(),this.ticks=this.buildTicks()||[],this.afterBuildTicks();let s=o=i||n<=1||!this.isHorizontal()){this.labelRotation=r;return}let l=this._getLabelSizes(),u=l.widest.width,d=l.highest.height,f=ic(this.chart.width-u,0,this.maxWidth);o=e.offset?this.maxWidth/n:f/(n-1),u+6>o&&(o=f/(n-(e.offset?.5:1)),s=this.maxHeight-Wf(e.grid)-t.padding-Gf(e.title,this.chart.options.font),c=Math.sqrt(u*u+d*d),a=Zs(Math.min(Math.asin(ic((l.highest.height+6)/o,-1,1)),Math.asin(ic(s/c,-1,1))-Math.asin(ic(d/c,-1,1)))),a=Math.max(r,Math.min(i,a))),this.labelRotation=a}afterCalculateLabelRotation(){vs(this.options.afterCalculateLabelRotation,[this])}afterAutoSkip(){}beforeFit(){vs(this.options.beforeFit,[this])}fit(){let e={width:0,height:0},{chart:t,options:{ticks:n,title:r,grid:i}}=this,a=this._isVisible(),o=this.isHorizontal();if(a){let a=Gf(r,t.options.font);if(o?(e.width=this.maxWidth,e.height=Wf(i)+a):(e.height=this.maxHeight,e.width=Wf(i)+a),n.display&&this.ticks.length){let{first:t,last:r,widest:i,highest:a}=this._getLabelSizes(),s=n.padding*2,c=Xs(this.labelRotation),l=Math.cos(c),u=Math.sin(c);if(o){let t=n.mirror?0:u*i.width+l*a.height;e.height=Math.min(this.maxHeight,e.height+t+s)}else{let t=n.mirror?0:l*i.width+u*a.height;e.width=Math.min(this.maxWidth,e.width+t+s)}this._calculatePadding(t,r,u,l)}}this._handleMargins(),o?(this.width=this._length=t.width-this._margins.left-this._margins.right,this.height=e.height):(this.width=e.width,this.height=this._length=t.height-this._margins.top-this._margins.bottom)}_calculatePadding(e,t,n,r){let{ticks:{align:i,padding:a},position:o}=this.options,s=this.labelRotation!==0,c=o!==`top`&&this.axis===`x`;if(this.isHorizontal()){let o=this.getPixelForTick(0)-this.left,l=this.right-this.getPixelForTick(this.ticks.length-1),u=0,d=0;s?c?(u=r*e.width,d=n*t.height):(u=n*e.height,d=r*t.width):i===`start`?d=t.width:i===`end`?u=e.width:i!==`inner`&&(u=e.width/2,d=t.width/2),this.paddingLeft=Math.max((u-o+a)*this.width/(this.width-o),0),this.paddingRight=Math.max((d-l+a)*this.width/(this.width-l),0)}else{let n=t.height/2,r=e.height/2;i===`start`?(n=0,r=e.height):i===`end`&&(n=t.height,r=0),this.paddingTop=n+a,this.paddingBottom=r+a}}_handleMargins(){this._margins&&(this._margins.left=Math.max(this.paddingLeft,this._margins.left),this._margins.top=Math.max(this.paddingTop,this._margins.top),this._margins.right=Math.max(this.paddingRight,this._margins.right),this._margins.bottom=Math.max(this.paddingBottom,this._margins.bottom))}afterFit(){vs(this.options.afterFit,[this])}isHorizontal(){let{axis:e,position:t}=this.options;return t===`top`||t===`bottom`||e===`x`}isFullSize(){return this.options.fullSize}_convertTicksToLabels(e){this.beforeTickToLabelConversion(),this.generateTickLabels(e);let t,n;for(t=0,n=e.length;t({width:a[e]||0,height:o[e]||0});return{first:C(0),last:C(t-1),widest:C(x),highest:C(S),widths:a,heights:o}}getLabelForValue(e){return e}getPixelForValue(e,t){return NaN}getValueForPixel(e){}getPixelForTick(e){let t=this.ticks;return e<0||e>t.length-1?null:this.getPixelForValue(t[e].value)}getPixelForDecimal(e){this._reversePixels&&(e=1-e);let t=this._startPixel+e*this._length;return ac(this._alignToPixels?Jc(this.chart,t,0):t)}getDecimalForPixel(e){let t=(e-this._startPixel)/this._length;return this._reversePixels?1-t:t}getBasePixel(){return this.getPixelForValue(this.getBaseValue())}getBaseValue(){let{min:e,max:t}=this;return e<0&&t<0?t:e>0&&t>0?e:0}getContext(e){let t=this.ticks||[];if(e>=0&&eo*r?o/n:s/r:s*r0:!!e}_computeGridLineItems(e){let t=this.axis,n=this.chart,r=this.options,{grid:i,position:a,border:o}=r,s=i.offset,c=this.isHorizontal(),l=this.ticks.length+ +!!s,u=Wf(i),d=[],f=o.setContext(this.getContext()),p=f.display?f.width:0,m=p/2,h=function(e){return Jc(n,e,p)},g,_,v,y,b,x,S,C,w,T,E,D;if(a===`top`)g=h(this.bottom),x=this.bottom-u,C=g-m,T=h(e.top)+m,D=e.bottom;else if(a===`bottom`)g=h(this.top),T=e.top,D=h(e.bottom)-m,x=g+m,C=this.top+u;else if(a===`left`)g=h(this.right),b=this.right-u,S=g-m,w=h(e.left)+m,E=e.right;else if(a===`right`)g=h(this.left),w=e.left,E=h(e.right)-m,b=g+m,S=this.left+u;else if(t===`x`){if(a===`center`)g=h((e.top+e.bottom)/2+.5);else if(Y(a)){let e=Object.keys(a)[0],t=a[e];g=h(this.chart.scales[e].getPixelForValue(t))}T=e.top,D=e.bottom,x=g+m,C=x+u}else if(t===`y`){if(a===`center`)g=h((e.left+e.right)/2);else if(Y(a)){let e=Object.keys(a)[0],t=a[e];g=h(this.chart.scales[e].getPixelForValue(t))}b=g-m,S=b-u,w=e.left,E=e.right}let O=X(r.ticks.maxTicksLimit,l),k=Math.max(1,Math.ceil(l/O));for(_=0;_0&&(a-=r/2)}f={left:a,top:i,width:r+t.width,height:n+t.height,color:e.backdropColor}}h.push({label:y,font:w,textOffset:D,options:{rotation:m,color:n,strokeColor:s,strokeWidth:l,textAlign:d,textBaseline:O,translation:[b,x],backdrop:f}})}return h}_getXAxisLabelAlignment(){let{position:e,ticks:t}=this.options;if(-Xs(this.labelRotation))return e===`top`?`left`:`right`;let n=`center`;return t.align===`start`?n=`left`:t.align===`end`?n=`right`:t.align===`inner`&&(n=`inner`),n}_getYAxisLabelAlignment(e){let{position:t,ticks:{crossAlign:n,mirror:r,padding:i}}=this.options,a=this._getLabelSizes(),o=e+i,s=a.widest.width,c,l;return t===`left`?r?(l=this.right+i,n===`near`?c=`left`:n===`center`?(c=`center`,l+=s/2):(c=`right`,l+=s)):(l=this.right-o,n===`near`?c=`right`:n===`center`?(c=`center`,l-=s/2):(c=`left`,l=this.left)):t===`right`?r?(l=this.left+i,n===`near`?c=`right`:n===`center`?(c=`center`,l-=s/2):(c=`left`,l-=s)):(l=this.left+o,n===`near`?c=`left`:n===`center`?(c=`center`,l+=s/2):(c=`right`,l=this.right)):c=`right`,{textAlign:c,x:l}}_computeLabelArea(){if(this.options.ticks.mirror)return;let e=this.chart,t=this.options.position;if(t===`left`||t===`right`)return{top:0,left:this.left,bottom:e.height,right:this.right};if(t===`top`||t===`bottom`)return{top:this.top,left:0,bottom:this.bottom,right:e.width}}drawBackground(){let{ctx:e,options:{backgroundColor:t},left:n,top:r,width:i,height:a}=this;t&&(e.save(),e.fillStyle=t,e.fillRect(n,r,i,a),e.restore())}getLineWidthForValue(e){let t=this.options.grid;if(!this._isVisible()||!t.display)return 0;let n=this.ticks.findIndex(t=>t.value===e);return n>=0?t.setContext(this.getContext(n)).lineWidth:0}drawGrid(e){let t=this.options.grid,n=this.ctx,r=this._gridLineItems||(this._gridLineItems=this._computeGridLineItems(e)),i,a,o=(e,t,r)=>{!r.width||!r.color||(n.save(),n.lineWidth=r.width,n.strokeStyle=r.color,n.setLineDash(r.borderDash||[]),n.lineDashOffset=r.borderDashOffset,n.beginPath(),n.moveTo(e.x,e.y),n.lineTo(t.x,t.y),n.stroke(),n.restore())};if(t.display)for(i=0,a=r.length;i{this.draw(e)}}]:[{z:r,draw:e=>{this.drawBackground(),this.drawGrid(e),this.drawTitle()}},{z:i,draw:()=>{this.drawBorder()}},{z:n,draw:e=>{this.drawLabels(e)}}]}getMatchingVisibleMetas(e){let t=this.chart.getSortedVisibleDatasetMetas(),n=this.axis+`AxisID`,r=[],i,a;for(i=0,a=t.length;i{let r=n.split(`.`),i=r.pop(),a=[e].concat(r).join(`.`),o=t[n].split(`.`),s=o.pop(),c=o.join(`.`);Wc.route(a,i,c,s)})}function ep(e){return`id`in e&&`defaults`in e}var tp=new class{constructor(){this.controllers=new Zf(sd,`datasets`,!0),this.elements=new Zf(Af,`elements`),this.plugins=new Zf(Object,`plugins`),this.scales=new Zf(Xf,`scales`),this._typedRegistries=[this.controllers,this.scales,this.elements]}add(...e){this._each(`register`,e)}remove(...e){this._each(`unregister`,e)}addControllers(...e){this._each(`register`,e,this.controllers)}addElements(...e){this._each(`register`,e,this.elements)}addPlugins(...e){this._each(`register`,e,this.plugins)}addScales(...e){this._each(`register`,e,this.scales)}getController(e){return this._get(e,this.controllers,`controller`)}getElement(e){return this._get(e,this.elements,`element`)}getPlugin(e){return this._get(e,this.plugins,`plugin`)}getScale(e){return this._get(e,this.scales,`scale`)}removeControllers(...e){this._each(`unregister`,e,this.controllers)}removeElements(...e){this._each(`unregister`,e,this.elements)}removePlugins(...e){this._each(`unregister`,e,this.plugins)}removeScales(...e){this._each(`unregister`,e,this.scales)}_each(e,t,n){[...t].forEach(t=>{let r=n||this._getRegistryForType(t);n||r.isForType(t)||r===this.plugins&&t.id?this._exec(e,r,t):Z(t,t=>{let r=n||this._getRegistryForType(t);this._exec(e,r,t)})})}_exec(e,t,n){let r=As(e);vs(n[`before`+r],[],n),t[e](n),vs(n[`after`+r],[],n)}_getRegistryForType(e){for(let t=0;te.filter(e=>!t.some(t=>e.plugin.id===t.plugin.id));this._notify(r(t,n),e,`stop`),this._notify(r(n,t),e,`start`)}};function rp(e){let t={},n=[],r=Object.keys(tp.plugins.items);for(let e=0;e1&&up(e[0].toLowerCase());if(t)return t}throw Error(`Cannot determine type of '${e}' axis. Please provide 'axis' or 'position' option.`)}function pp(e,t,n){if(n[t+`AxisID`]===e)return{axis:t}}function mp(e,t){if(t.data&&t.data.datasets){let n=t.data.datasets.filter(t=>t.xAxisID===e||t.yAxisID===e);if(n.length)return pp(e,`x`,n[0])||pp(e,`y`,n[0])}return{}}function hp(e,t){let n=Bc[e.type]||{scales:{}},r=t.scales||{},i=sp(e.type,t),a=Object.create(null);return Object.keys(r).forEach(t=>{let o=r[t];if(!Y(o))return console.error(`Invalid scale configuration for scale: ${t}`);if(o._proxy)return console.warn(`Ignoring resolver passed as options for scale: ${t}`);let s=fp(t,o,mp(t,e),Wc.scales[o.type]),c=lp(s,i),l=n.scales||{};a[t]=ws(Object.create(null),[{axis:s},o,l[s],l[c]])}),e.data.datasets.forEach(n=>{let i=n.type||e.type,o=n.indexAxis||sp(i,t),s=(Bc[i]||{}).scales||{};Object.keys(s).forEach(e=>{let t=cp(e,o),i=n[t+`AxisID`]||t;a[i]=a[i]||Object.create(null),ws(a[i],[{axis:t},r[i],s[e]])})}),Object.keys(a).forEach(e=>{let t=a[e];ws(t,[Wc.scales[t.type],Wc.scale])}),a}function gp(e){let t=e.options||(e.options={});t.plugins=X(t.plugins,{}),t.scales=hp(e,t)}function _p(e){return e=e||{},e.datasets=e.datasets||[],e.labels=e.labels||[],e}function vp(e){return e=e||{},e.data=_p(e.data),gp(e),e}var yp=new Map,bp=new Set;function xp(e,t){let n=yp.get(e);return n||(n=t(),yp.set(e,n),bp.add(n)),n}var Sp=(e,t,n)=>{let r=ks(t,n);r!==void 0&&e.add(r)},Cp=class{constructor(e){this._config=vp(e),this._scopeCache=new Map,this._resolverCache=new Map}get platform(){return this._config.platform}get type(){return this._config.type}set type(e){this._config.type=e}get data(){return this._config.data}set data(e){this._config.data=_p(e)}get options(){return this._config.options}set options(e){this._config.options=e}get plugins(){return this._config.plugins}update(){let e=this._config;this.clearCache(),gp(e)}clearCache(){this._scopeCache.clear(),this._resolverCache.clear()}datasetScopeKeys(e){return xp(e,()=>[[`datasets.${e}`,``]])}datasetAnimationScopeKeys(e,t){return xp(`${e}.transition.${t}`,()=>[[`datasets.${e}.transitions.${t}`,`transitions.${t}`],[`datasets.${e}`,``]])}datasetElementScopeKeys(e,t){return xp(`${e}-${t}`,()=>[[`datasets.${e}.elements.${t}`,`datasets.${e}`,`elements.${t}`,``]])}pluginScopeKeys(e){let t=e.id,n=this.type;return xp(`${n}-plugin-${t}`,()=>[[`plugins.${t}`,...e.additionalOptionScopes||[]]])}_cachedScopes(e,t){let n=this._scopeCache,r=n.get(e);return(!r||t)&&(r=new Map,n.set(e,r)),r}getOptionScopes(e,t,n){let{options:r,type:i}=this,a=this._cachedScopes(e,n),o=a.get(t);if(o)return o;let s=new Set;t.forEach(t=>{e&&(s.add(e),t.forEach(t=>Sp(s,e,t))),t.forEach(e=>Sp(s,r,e)),t.forEach(e=>Sp(s,Bc[i]||{},e)),t.forEach(e=>Sp(s,Wc,e)),t.forEach(e=>Sp(s,Vc,e))});let c=Array.from(s);return c.length===0&&c.push(Object.create(null)),bp.has(t)&&a.set(t,c),c}chartOptionScopes(){let{options:e,type:t}=this;return[e,Bc[t]||{},Wc.datasets[t]||{},{type:t},Wc,Vc]}resolveNamedOptions(e,t,n,r=[``]){let i={$shared:!0},{resolver:a,subPrefixes:o}=wp(this._resolverCache,e,r),s=a;if(Ep(a,t)){i.$shared=!1,n=Ms(n)?n():n;let t=this.createResolver(e,n,o);s=xl(a,n,t)}for(let e of t)i[e]=s[e];return i}createResolver(e,t,n=[``],r){let{resolver:i}=wp(this._resolverCache,e,n);return Y(t)?xl(i,t,void 0,r):i}};function wp(e,t,n){let r=e.get(t);r||(r=new Map,e.set(t,r));let i=n.join(),a=r.get(i);return a||(a={resolver:bl(t,n),subPrefixes:n.filter(e=>!e.toLowerCase().includes(`hover`))},r.set(i,a)),a}var Tp=e=>Y(e)&&Object.getOwnPropertyNames(e).some(t=>Ms(e[t]));function Ep(e,t){let{isScriptable:n,isIndexable:r}=Sl(e);for(let i of t){let t=n(i),a=r(i),o=(a||t)&&e[i];if(t&&(Ms(o)||Tp(o))||a&&ps(o))return!0}return!1}var Dp=`4.5.1`,Op=[`top`,`bottom`,`left`,`right`,`chartArea`];function kp(e,t){return e===`top`||e===`bottom`||Op.indexOf(e)===-1&&t===`x`}function Ap(e,t){return function(n,r){return n[e]===r[e]?n[t]-r[t]:n[e]-r[e]}}function jp(e){let t=e.chart,n=t.options.animation;t.notifyPlugins(`afterRender`),vs(n&&n.onComplete,[e],t)}function Mp(e){let t=e.chart,n=t.options.animation;vs(n&&n.onProgress,[e],t)}function Np(e){return Xl()&&typeof e==`string`?e=document.getElementById(e):e&&e.length&&(e=e[0]),e&&e.canvas&&(e=e.canvas),e}var Pp={},Fp=e=>{let t=Np(e);return Object.values(Pp).filter(e=>e.canvas===t).pop()};function Ip(e,t,n){let r=Object.keys(e);for(let i of r){let r=+i;if(r>=t){let a=e[i];delete e[i],(n>0||r>t)&&(e[r+n]=a)}}}function Lp(e,t,n,r){return!n||e.type===`mouseout`?null:r?t:e}var Rp=class{static register(...e){tp.add(...e),zp()}static unregister(...e){tp.remove(...e),zp()}constructor(e,t){let n=this.config=new Cp(t),r=Np(e),i=Fp(r);if(i)throw Error(`Canvas is already in use. Chart with ID '`+i.id+`' must be destroyed before the canvas with ID '`+i.canvas.id+`' can be reused.`);let a=n.createResolver(n.chartOptionScopes(),this.getContext());this.platform=new(n.platform||(kf(r))),this.platform.updateConfig(n);let o=this.platform.acquireContext(r,a.aspectRatio),s=o&&o.canvas,c=s&&s.height,l=s&&s.width;if(this.id=fs(),this.ctx=o,this.canvas=s,this.width=l,this.height=c,this._options=a,this._aspectRatio=this.aspectRatio,this._layers=[],this._metasets=[],this._stacks=void 0,this.boxes=[],this.currentDevicePixelRatio=void 0,this.chartArea=void 0,this._active=[],this._lastEvent=void 0,this._listeners={},this._responsiveListeners=void 0,this._sortedMetasets=[],this.scales={},this._plugins=new np,this.$proxies={},this._hiddenIndices={},this.attached=!1,this._animationsDisabled=void 0,this.$context=void 0,this._doResize=_c(e=>this.update(e),a.resizeDelay||0),this._dataChanges=[],Pp[this.id]=this,!o||!s){console.error(`Failed to create chart: can't acquire context from the given item`);return}Fu.listen(this,`complete`,jp),Fu.listen(this,`progress`,Mp),this._initialize(),this.attached&&this.update()}get aspectRatio(){let{options:{aspectRatio:e,maintainAspectRatio:t},width:n,height:r,_aspectRatio:i}=this;return J(e)?t&&i?i:r?n/r:null:e}get data(){return this.config.data}set data(e){this.config.data=e}get options(){return this._options}set options(e){this.config.options=e}get registry(){return tp}_initialize(){return this.notifyPlugins(`beforeInit`),this.options.responsive?this.resize():lu(this,this.options.devicePixelRatio),this.bindEvents(),this.notifyPlugins(`afterInit`),this}clear(){return Yc(this.canvas,this.ctx),this}stop(){return Fu.stop(this),this}resize(e,t){Fu.running(this)?this._resizeBeforeDraw={width:e,height:t}:this._resize(e,t)}_resize(e,t){let n=this.options,r=this.canvas,i=n.maintainAspectRatio&&this.aspectRatio,a=this.platform.getMaximumSize(r,e,t,i),o=n.devicePixelRatio||this.platform.getDevicePixelRatio(),s=this.width?`resize`:`attach`;this.width=a.width,this.height=a.height,this._aspectRatio=this.aspectRatio,lu(this,o,!0)&&(this.notifyPlugins(`resize`,{size:a}),vs(n.onResize,[this,a],this),this.attached&&this._doResize(s)&&this.render())}ensureScalesHaveIDs(){Z(this.options.scales||{},(e,t)=>{e.id=t})}buildOrUpdateScales(){let e=this.options,t=e.scales,n=this.scales,r=Object.keys(n).reduce((e,t)=>(e[t]=!1,e),{}),i=[];t&&(i=i.concat(Object.keys(t).map(e=>{let n=t[e],r=fp(e,n),i=r===`r`,a=r===`x`;return{options:n,dposition:i?`chartArea`:a?`bottom`:`left`,dtype:i?`radialLinear`:a?`category`:`linear`}}))),Z(i,t=>{let i=t.options,a=i.id,o=fp(a,i),s=X(i.type,t.dtype);(i.position===void 0||kp(i.position,o)!==kp(t.dposition))&&(i.position=t.dposition),r[a]=!0;let c=null;a in n&&n[a].type===s?c=n[a]:(c=new(tp.getScale(s))({id:a,type:s,ctx:this.ctx,chart:this}),n[c.id]=c),c.init(i,e)}),Z(r,(e,t)=>{e||delete n[t]}),Z(n,e=>{of.configure(this,e,e.options),of.addBox(this,e)})}_updateMetasets(){let e=this._metasets,t=this.data.datasets.length,n=e.length;if(e.sort((e,t)=>e.index-t.index),n>t){for(let e=t;et.length&&delete this._stacks,e.forEach((e,n)=>{t.filter(t=>t===e._dataset).length===0&&this._destroyDatasetMeta(n)})}buildOrUpdateControllers(){let e=[],t=this.data.datasets,n,r;for(this._removeUnreferencedMetasets(),n=0,r=t.length;n{this.getDatasetMeta(t).controller.reset()},this)}reset(){this._resetElements(),this.notifyPlugins(`reset`)}update(e){let t=this.config;t.update();let n=this._options=t.createResolver(t.chartOptionScopes(),this.getContext()),r=this._animationsDisabled=!n.animation;if(this._updateScales(),this._checkEventBindings(),this._updateHiddenIndices(),this._plugins.invalidate(),this.notifyPlugins(`beforeUpdate`,{mode:e,cancelable:!0})===!1)return;let i=this.buildOrUpdateControllers();this.notifyPlugins(`beforeElementsUpdate`);let a=0;for(let e=0,t=this.data.datasets.length;e{e.reset()}),this._updateDatasets(e),this.notifyPlugins(`afterUpdate`,{mode:e}),this._layers.sort(Ap(`z`,`_idx`));let{_active:o,_lastEvent:s}=this;s?this._eventHandler(s,!0):o.length&&this._updateHoverStyles(o,o,!0),this.render()}_updateScales(){Z(this.scales,e=>{of.removeBox(this,e)}),this.ensureScalesHaveIDs(),this.buildOrUpdateScales()}_checkEventBindings(){let e=this.options;(!Ns(new Set(Object.keys(this._listeners)),new Set(e.events))||!!this._responsiveListeners!==e.responsive)&&(this.unbindEvents(),this.bindEvents())}_updateHiddenIndices(){let{_hiddenIndices:e}=this,t=this._getUniformDataChanges()||[];for(let{method:n,start:r,count:i}of t)Ip(e,r,n===`_removeElements`?-i:i)}_getUniformDataChanges(){let e=this._dataChanges;if(!e||!e.length)return;this._dataChanges=[];let t=this.data.datasets.length,n=t=>new Set(e.filter(e=>e[0]===t).map((e,t)=>t+`,`+e.splice(1).join(`,`))),r=n(0);for(let e=1;ee.split(`,`)).map(e=>({method:e[1],start:+e[2],count:+e[3]}))}_updateLayout(e){if(this.notifyPlugins(`beforeLayout`,{cancelable:!0})===!1)return;of.update(this,this.width,this.height,e);let t=this.chartArea,n=t.width<=0||t.height<=0;this._layers=[],Z(this.boxes,e=>{n&&e.position===`chartArea`||(e.configure&&e.configure(),this._layers.push(...e._layers()))},this),this._layers.forEach((e,t)=>{e._idx=t}),this.notifyPlugins(`afterLayout`)}_updateDatasets(e){if(this.notifyPlugins(`beforeDatasetsUpdate`,{mode:e,cancelable:!0})!==!1){for(let e=0,t=this.data.datasets.length;e=0;--t)this._drawDataset(e[t]);this.notifyPlugins(`afterDatasetsDraw`)}_drawDataset(e){let t=this.ctx,n={meta:e,index:e.index,cancelable:!0},r=Pu(this,e);this.notifyPlugins(`beforeDatasetDraw`,n)!==!1&&(r&&$c(t,r),e.controller.draw(),r&&el(t),n.cancelable=!1,this.notifyPlugins(`afterDatasetDraw`,n))}isPointInArea(e){return Qc(e,this.chartArea,this._minPadding)}getElementsAtEventForMode(e,t,n,r){let i=Hd.modes[t];return typeof i==`function`?i(this,e,n,r):[]}getDatasetMeta(e){let t=this.data.datasets[e],n=this._metasets,r=n.filter(e=>e&&e._dataset===t).pop();return r||(r={type:null,data:[],dataset:null,controller:null,hidden:null,xAxisID:null,yAxisID:null,order:t&&t.order||0,index:e,_dataset:t,_parsed:[],_sorted:!1},n.push(r)),r}getContext(){return this.$context||(this.$context=yl(null,{chart:this,type:`chart`}))}getVisibleDatasetCount(){return this.getSortedVisibleDatasetMetas().length}isDatasetVisible(e){let t=this.data.datasets[e];if(!t)return!1;let n=this.getDatasetMeta(e);return typeof n.hidden==`boolean`?!n.hidden:!t.hidden}setDatasetVisibility(e,t){let n=this.getDatasetMeta(e);n.hidden=!t}toggleDataVisibility(e){this._hiddenIndices[e]=!this._hiddenIndices[e]}getDataVisibility(e){return!this._hiddenIndices[e]}_updateVisibility(e,t,n){let r=n?`show`:`hide`,i=this.getDatasetMeta(e),a=i.controller._resolveAnimations(void 0,r);js(t)?(i.data[t].hidden=!n,this.update()):(this.setDatasetVisibility(e,n),a.update(i,{visible:n}),this.update(t=>t.datasetIndex===e?r:void 0))}hide(e,t){this._updateVisibility(e,t,!1)}show(e,t){this._updateVisibility(e,t,!0)}_destroyDatasetMeta(e){let t=this._metasets[e];t&&t.controller&&t.controller._destroy(),delete this._metasets[e]}_stop(){let e,t;for(this.stop(),Fu.remove(this),e=0,t=this.data.datasets.length;e{t.addEventListener(this,n,r),e[n]=r},r=(e,t,n)=>{e.offsetX=t,e.offsetY=n,this._eventHandler(e)};Z(this.options.events,e=>n(e,r))}bindResponsiveEvents(){this._responsiveListeners||(this._responsiveListeners={});let e=this._responsiveListeners,t=this.platform,n=(n,r)=>{t.addEventListener(this,n,r),e[n]=r},r=(n,r)=>{e[n]&&(t.removeEventListener(this,n,r),delete e[n])},i=(e,t)=>{this.canvas&&this.resize(e,t)},a,o=()=>{r(`attach`,o),this.attached=!0,this.resize(),n(`resize`,i),n(`detach`,a)};a=()=>{this.attached=!1,r(`resize`,i),this._stop(),this._resize(0,0),n(`attach`,o)},t.isAttached(this.canvas)?o():a()}unbindEvents(){Z(this._listeners,(e,t)=>{this.platform.removeEventListener(this,t,e)}),this._listeners={},Z(this._responsiveListeners,(e,t)=>{this.platform.removeEventListener(this,t,e)}),this._responsiveListeners=void 0}updateHoverStyle(e,t,n){let r=n?`set`:`remove`,i,a,o,s;for(t===`dataset`&&(i=this.getDatasetMeta(e[0].datasetIndex),i.controller[`_`+r+`DatasetHoverStyle`]()),o=0,s=e.length;o{let n=this.getDatasetMeta(e);if(!n)throw Error(`No dataset found at index `+e);return{datasetIndex:e,element:n.data[t],index:t}});ys(n,t)||(this._active=n,this._lastEvent=null,this._updateHoverStyles(n,t))}notifyPlugins(e,t,n){return this._plugins.notify(this,e,t,n)}isPluginEnabled(e){return this._plugins._cache.filter(t=>t.plugin.id===e).length===1}_updateHoverStyles(e,t,n){let r=this.options.hover,i=(e,t)=>e.filter(e=>!t.some(t=>e.datasetIndex===t.datasetIndex&&e.index===t.index)),a=i(t,e),o=n?e:i(e,t);a.length&&this.updateHoverStyle(a,r.mode,!1),o.length&&r.mode&&this.updateHoverStyle(o,r.mode,!0)}_eventHandler(e,t){let n={event:e,replay:t,cancelable:!0,inChartArea:this.isPointInArea(e)},r=t=>(t.options.events||this.options.events).includes(e.native.type);if(this.notifyPlugins(`beforeEvent`,n,r)===!1)return;let i=this._handleEvent(e,t,n.inChartArea);return n.cancelable=!1,this.notifyPlugins(`afterEvent`,n,r),(i||n.changed)&&this.render(),this}_handleEvent(e,t,n){let{_active:r=[],options:i}=this,a=t,o=this._getActiveElements(e,r,n,a),s=Ps(e),c=Lp(e,this._lastEvent,n,s);n&&(this._lastEvent=null,vs(i.onHover,[e,o,this],this),s&&vs(i.onClick,[e,o,this],this));let l=!ys(o,r);return(l||t)&&(this._active=o,this._updateHoverStyles(o,r,t)),this._lastEvent=c,l}_getActiveElements(e,t,n,r){if(e.type===`mouseout`)return[];if(!n)return t;let i=this.options.hover;return this.getElementsAtEventForMode(e,i.mode,i,r)}};L(Rp,`defaults`,Wc),L(Rp,`instances`,Pp),L(Rp,`overrides`,Bc),L(Rp,`registry`,tp),L(Rp,`version`,Dp),L(Rp,`getChart`,Fp);function zp(){return Z(Rp.instances,e=>e._plugins.invalidate())}function Bp(e,t,n){let{startAngle:r,x:i,y:a,outerRadius:o,innerRadius:s,options:c}=t,{borderWidth:l,borderJoinStyle:u}=c,d=Math.min(l/o,nc(r-n));if(e.beginPath(),e.arc(i,a,o-l/2,r+d/2,n-d/2),s>0){let t=Math.min(l/s,nc(r-n));e.arc(i,a,s+l/2,n-t/2,r+t/2,!0)}else{let t=Math.min(l/2,o*nc(r-n));if(u===`round`)e.arc(i,a,t,n-Q/2,r+Q/2,!0);else if(u===`bevel`){let o=2*t*t,s=-o*Math.cos(n+Q/2)+i,c=-o*Math.sin(n+Q/2)+a,l=o*Math.cos(r+Q/2)+i,u=o*Math.sin(r+Q/2)+a;e.lineTo(s,c),e.lineTo(l,u)}}e.closePath(),e.moveTo(0,0),e.rect(0,0,e.canvas.width,e.canvas.height),e.clip(`evenodd`)}function Vp(e,t,n){let{startAngle:r,pixelMargin:i,x:a,y:o,outerRadius:s,innerRadius:c}=t,l=i/s;e.beginPath(),e.arc(a,o,s,r-l,n+l),c>i?(l=i/c,e.arc(a,o,c,n+l,r-l,!0)):e.arc(a,o,i,n+Rs,r-Rs),e.closePath(),e.clip()}function Hp(e){return fl(e,[`outerStart`,`outerEnd`,`innerStart`,`innerEnd`])}function Up(e,t,n,r){let i=Hp(e.options.borderRadius),a=(n-t)/2,o=Math.min(a,r*t/2),s=e=>{let t=(n-Math.min(a,e))*r/2;return ic(e,0,Math.min(a,t))};return{outerStart:s(i.outerStart),outerEnd:s(i.outerEnd),innerStart:ic(i.innerStart,0,o),innerEnd:ic(i.innerEnd,0,o)}}function Wp(e,t,n,r){return{x:n+e*Math.cos(t),y:r+e*Math.sin(t)}}function Gp(e,t,n,r,i,a){let{x:o,y:s,startAngle:c,pixelMargin:l,innerRadius:u}=t,d=Math.max(t.outerRadius+r+n-l,0),f=u>0?u+r+n+l:0,p=0,m=i-c;if(r){let e=((u>0?u-r:0)+(d>0?d-r:0))/2;p=(m-(e===0?m:m*e/(e+r)))/2}let h=(m-Math.max(.001,m*d-n/Q)/d)/2,g=c+h+p,_=i-h-p,{outerStart:v,outerEnd:y,innerStart:b,innerEnd:x}=Up(t,f,d,_-g),S=d-v,C=d-y,w=g+v/S,T=_-y/C,E=f+b,D=f+x,O=g+b/E,k=_-x/D;if(e.beginPath(),a){let t=(w+T)/2;if(e.arc(o,s,d,w,t),e.arc(o,s,d,t,T),y>0){let t=Wp(C,T,o,s);e.arc(t.x,t.y,y,T,_+Rs)}let n=Wp(D,_,o,s);if(e.lineTo(n.x,n.y),x>0){let t=Wp(D,k,o,s);e.arc(t.x,t.y,x,_+Rs,k+Math.PI)}let r=(_-x/f+(g+b/f))/2;if(e.arc(o,s,f,_-x/f,r,!0),e.arc(o,s,f,r,g+b/f,!0),b>0){let t=Wp(E,O,o,s);e.arc(t.x,t.y,b,O+Math.PI,g-Rs)}let i=Wp(S,g,o,s);if(e.lineTo(i.x,i.y),v>0){let t=Wp(S,w,o,s);e.arc(t.x,t.y,v,g-Rs,w)}}else{e.moveTo(o,s);let t=Math.cos(w)*d+o,n=Math.sin(w)*d+s;e.lineTo(t,n);let r=Math.cos(T)*d+o,i=Math.sin(T)*d+s;e.lineTo(r,i)}e.closePath()}function Kp(e,t,n,r,i){let{fullCircles:a,startAngle:o,circumference:s}=t,c=t.endAngle;if(a){Gp(e,t,n,r,c,i);for(let t=0;t=Q&&p===0&&u!==`miter`&&Bp(e,t,h),a||(Gp(e,t,n,r,h,i),e.stroke())}var Jp=class extends Af{constructor(e){super(),L(this,`circumference`,void 0),L(this,`endAngle`,void 0),L(this,`fullCircles`,void 0),L(this,`innerRadius`,void 0),L(this,`outerRadius`,void 0),L(this,`pixelMargin`,void 0),L(this,`startAngle`,void 0),this.options=void 0,this.circumference=void 0,this.startAngle=void 0,this.endAngle=void 0,this.innerRadius=void 0,this.outerRadius=void 0,this.pixelMargin=0,this.fullCircles=0,e&&Object.assign(this,e)}inRange(e,t,n){let{angle:r,distance:i}=$s(this.getProps([`x`,`y`],n),{x:e,y:t}),{startAngle:a,endAngle:o,innerRadius:s,outerRadius:c,circumference:l}=this.getProps([`startAngle`,`endAngle`,`innerRadius`,`outerRadius`,`circumference`],n),u=(this.options.spacing+this.options.borderWidth)/2,d=X(l,o-a),f=rc(r,a,o)&&a!==o,p=d>=$||f,m=oc(i,s+u,c+u);return p&&m}getCenterPoint(e){let{x:t,y:n,startAngle:r,endAngle:i,innerRadius:a,outerRadius:o}=this.getProps([`x`,`y`,`startAngle`,`endAngle`,`innerRadius`,`outerRadius`],e),{offset:s,spacing:c}=this.options,l=(r+i)/2,u=(a+o+c+s)/2;return{x:t+Math.cos(l)*u,y:n+Math.sin(l)*u}}tooltipPosition(e){return this.getCenterPoint(e)}draw(e){let{options:t,circumference:n}=this,r=(t.offset||0)/4,i=(t.spacing||0)/2,a=t.circular;if(this.pixelMargin=t.borderAlign===`inner`?.33:0,this.fullCircles=n>$?Math.floor(n/$):0,n===0||this.innerRadius<0||this.outerRadius<0)return;e.save();let o=(this.startAngle+this.endAngle)/2;e.translate(Math.cos(o)*r,Math.sin(o)*r);let s=r*(1-Math.sin(Math.min(Q,n||0)));e.fillStyle=t.backgroundColor,e.strokeStyle=t.borderColor,Kp(e,this,s,i,a),qp(e,this,s,i,a),e.restore()}};L(Jp,`id`,`arc`),L(Jp,`defaults`,{borderAlign:`center`,borderColor:`#fff`,borderDash:[],borderDashOffset:0,borderJoinStyle:void 0,borderRadius:0,borderWidth:2,offset:0,spacing:0,angle:void 0,circular:!0,selfJoin:!1}),L(Jp,`defaultRoutes`,{backgroundColor:`backgroundColor`}),L(Jp,`descriptors`,{_scriptable:!0,_indexable:e=>e!==`borderDash`});function Yp(e,t,n=t){e.lineCap=X(n.borderCapStyle,t.borderCapStyle),e.setLineDash(X(n.borderDash,t.borderDash)),e.lineDashOffset=X(n.borderDashOffset,t.borderDashOffset),e.lineJoin=X(n.borderJoinStyle,t.borderJoinStyle),e.lineWidth=X(n.borderWidth,t.borderWidth),e.strokeStyle=X(n.borderColor,t.borderColor)}function Xp(e,t,n){e.lineTo(n.x,n.y)}function Zp(e){return e.stepped?tl:e.tension||e.cubicInterpolationMode===`monotone`?nl:Xp}function Qp(e,t,n={}){let r=e.length,{start:i=0,end:a=r-1}=n,{start:o,end:s}=t,c=Math.max(i,o),l=Math.min(a,s),u=is&&a>s;return{count:r,start:c,loop:t.loop,ilen:l(o+(l?s-e:e))%a,y=()=>{h!==g&&(e.lineTo(u,g),e.lineTo(u,h),e.lineTo(u,_))};for(c&&(p=i[v(0)],e.moveTo(p.x,p.y)),f=0;f<=s;++f){if(p=i[v(f)],p.skip)continue;let t=p.x,n=p.y,r=t|0;r===m?(ng&&(g=n),u=(d*u+t)/++d):(y(),e.lineTo(t,n),m=r,d=0,h=g=n),_=n}y()}function tm(e){let t=e.options,n=t.borderDash&&t.borderDash.length;return!e._decimated&&!e._loop&&!t.tension&&t.cubicInterpolationMode!==`monotone`&&!t.stepped&&!n?em:$p}function nm(e){return e.stepped?pu:e.tension||e.cubicInterpolationMode===`monotone`?mu:fu}function rm(e,t,n,r){let i=t._path;i||(i=t._path=new Path2D,t.path(i,n,r)&&i.closePath()),Yp(e,t.options),e.stroke(i)}function im(e,t,n,r){let{segments:i,options:a}=t,o=tm(t);for(let s of i)Yp(e,a,s.style),e.beginPath(),o(e,t,s,{start:n,end:n+r-1})&&e.closePath(),e.stroke()}var am=typeof Path2D==`function`;function om(e,t,n,r){am&&!t.options.segment?rm(e,t,n,r):im(e,t,n,r)}var sm=class extends Af{constructor(e){super(),this.animated=!0,this.options=void 0,this._chart=void 0,this._loop=void 0,this._fullLoop=void 0,this._path=void 0,this._points=void 0,this._segments=void 0,this._decimated=!1,this._pointsUpdated=!1,this._datasetIndex=void 0,e&&Object.assign(this,e)}updateControlPoints(e,t){let n=this.options;if((n.tension||n.cubicInterpolationMode===`monotone`)&&!n.stepped&&!this._pointsUpdated){let r=n.spanGaps?this._loop:this._fullLoop;Yl(this._points,n,e,r,t),this._pointsUpdated=!0}}set points(e){this._points=e,delete this._segments,delete this._path,this._pointsUpdated=!1}get points(){return this._points}get segments(){return this._segments||(this._segments=Du(this,this.options.segment))}first(){let e=this.segments,t=this.points;return e.length&&t[e[0].start]}last(){let e=this.segments,t=this.points,n=e.length;return n&&t[e[n-1].end]}interpolate(e,t){let n=this.options,r=e[t],i=this.points,a=wu(this,{property:t,start:r,end:r});if(!a.length)return;let o=[],s=nm(n),c,l;for(c=0,l=a.length;ce!==`borderDash`&&e!==`fill`});function cm(e,t,n,r){let i=e.options,{[n]:a}=e.getProps([n],r);return Math.abs(t-a)e+t)/r.size,y:i/a}},nearest(e,t){if(!e.length)return!1;let n=t.x,r=t.y,i=1/0,a,o,s;for(a=0,o=e.length;a-1?e.split(` -`):e}function Cm(e,t){let{element:n,datasetIndex:r,index:i}=t,a=e.getDatasetMeta(r).controller,{label:o,value:s}=a.getLabelAndValue(i);return{chart:e,label:o,parsed:a.getParsed(i),raw:e.data.datasets[r].data[i],formattedValue:s,dataset:a.getDataset(),dataIndex:i,datasetIndex:r,element:n}}function wm(e,t){let n=e.chart.ctx,{body:r,footer:i,title:a}=e,{boxWidth:o,boxHeight:s}=t,c=gl(t.bodyFont),l=gl(t.titleFont),u=gl(t.footerFont),d=a.length,f=i.length,p=r.length,m=hl(t.padding),h=m.height,g=0,_=r.reduce((e,t)=>e+t.before.length+t.lines.length+t.after.length,0);if(_+=e.beforeBody.length+e.afterBody.length,d&&(h+=d*l.lineHeight+(d-1)*t.titleSpacing+t.titleMarginBottom),_){let e=t.displayColors?Math.max(s,c.lineHeight):c.lineHeight;h+=p*e+(_-p)*c.lineHeight+(_-1)*t.bodySpacing}f&&(h+=t.footerMarginTop+f*u.lineHeight+(f-1)*t.footerSpacing);let v=0,y=function(e){g=Math.max(g,n.measureText(e).width+v)};return n.save(),n.font=l.string,Z(e.title,y),n.font=c.string,Z(e.beforeBody.concat(e.afterBody),y),v=t.displayColors?o+2+t.boxPadding:0,Z(r,e=>{Z(e.before,y),Z(e.lines,y),Z(e.after,y)}),v=0,n.font=u.string,Z(e.footer,y),n.restore(),g+=m.width,{width:g,height:h}}function Tm(e,t){let{y:n,height:r}=t;return ne.height-r/2?`bottom`:`center`}function Em(e,t,n,r){let{x:i,width:a}=r,o=n.caretSize+n.caretPadding;if(e===`left`&&i+a+o>t.width||e===`right`&&i-a-o<0)return!0}function Dm(e,t,n,r){let{x:i,width:a}=n,{width:o,chartArea:{left:s,right:c}}=e,l=`center`;return r===`center`?l=i<=(s+c)/2?`left`:`right`:i<=a/2?l=`left`:i>=o-a/2&&(l=`right`),Em(l,e,t,n)&&(l=`center`),l}function Om(e,t,n){let r=n.yAlign||t.yAlign||Tm(e,n);return{xAlign:n.xAlign||t.xAlign||Dm(e,t,n,r),yAlign:r}}function km(e,t){let{x:n,width:r}=e;return t===`right`?n-=r:t===`center`&&(n-=r/2),n}function Am(e,t,n){let{y:r,height:i}=e;return t===`top`?r+=n:r-=t===`bottom`?i+n:i/2,r}function jm(e,t,n,r){let{caretSize:i,caretPadding:a,cornerRadius:o}=e,{xAlign:s,yAlign:c}=n,l=i+a,{topLeft:u,topRight:d,bottomLeft:f,bottomRight:p}=ml(o),m=km(t,s),h=Am(t,c,l);return c===`center`?s===`left`?m+=l:s===`right`&&(m-=l):s===`left`?m-=Math.max(u,f)+i:s===`right`&&(m+=Math.max(d,p)+i),{x:ic(m,0,r.width-t.width),y:ic(h,0,r.height-t.height)}}function Mm(e,t,n){let r=hl(n.padding);return t===`center`?e.x+e.width/2:t===`right`?e.x+e.width-r.right:e.x+r.left}function Nm(e){return xm([],Sm(e))}function Pm(e,t,n){return yl(e,{tooltip:t,tooltipItems:n,type:`tooltip`})}function Fm(e,t){let n=t&&t.dataset&&t.dataset.tooltip&&t.dataset.tooltip.callbacks;return n?e.override(n):e}var Im={beforeTitle:ds,title(e){if(e.length>0){let t=e[0],n=t.chart.data.labels,r=n?n.length:0;if(this&&this.options&&this.options.mode===`dataset`)return t.dataset.label||``;if(t.label)return t.label;if(r>0&&t.dataIndex{let t={before:[],lines:[],after:[]},i=Fm(n,e);xm(t.before,Sm(Lm(i,`beforeLabel`,this,e))),xm(t.lines,Lm(i,`label`,this,e)),xm(t.after,Sm(Lm(i,`afterLabel`,this,e))),r.push(t)}),r}getAfterBody(e,t){return Nm(Lm(t.callbacks,`afterBody`,this,e))}getFooter(e,t){let{callbacks:n}=t,r=Lm(n,`beforeFooter`,this,e),i=Lm(n,`footer`,this,e),a=Lm(n,`afterFooter`,this,e),o=[];return o=xm(o,Sm(r)),o=xm(o,Sm(i)),o=xm(o,Sm(a)),o}_createItems(e){let t=this._active,n=this.chart.data,r=[],i=[],a=[],o=[],s,c;for(s=0,c=t.length;se.filter(t,r,i,n))),e.itemSort&&(o=o.sort((t,r)=>e.itemSort(t,r,n))),Z(o,t=>{let n=Fm(e.callbacks,t);r.push(Lm(n,`labelColor`,this,t)),i.push(Lm(n,`labelPointStyle`,this,t)),a.push(Lm(n,`labelTextColor`,this,t))}),this.labelColors=r,this.labelPointStyles=i,this.labelTextColors=a,this.dataPoints=o,o}update(e,t){let n=this.options.setContext(this.getContext()),r=this._active,i,a=[];if(!r.length)this.opacity!==0&&(i={opacity:0});else{let e=bm[n.position].call(this,r,this._eventPosition);a=this._createItems(n),this.title=this.getTitle(a,n),this.beforeBody=this.getBeforeBody(a,n),this.body=this.getBody(a,n),this.afterBody=this.getAfterBody(a,n),this.footer=this.getFooter(a,n);let t=this._size=wm(this,n),o=Object.assign({},e,t),s=Om(this.chart,n,o),c=jm(n,o,s,this.chart);this.xAlign=s.xAlign,this.yAlign=s.yAlign,i={opacity:1,x:c.x,y:c.y,width:t.width,height:t.height,caretX:e.x,caretY:e.y}}this._tooltipItems=a,this.$context=void 0,i&&this._resolveAnimations().update(this,i),e&&n.external&&n.external.call(this,{chart:this.chart,tooltip:this,replay:t})}drawCaret(e,t,n,r){let i=this.getCaretPosition(e,n,r);t.lineTo(i.x1,i.y1),t.lineTo(i.x2,i.y2),t.lineTo(i.x3,i.y3)}getCaretPosition(e,t,n){let{xAlign:r,yAlign:i}=this,{caretSize:a,cornerRadius:o}=n,{topLeft:s,topRight:c,bottomLeft:l,bottomRight:u}=ml(o),{x:d,y:f}=e,{width:p,height:m}=t,h,g,_,v,y,b;return i===`center`?(y=f+m/2,r===`left`?(h=d,g=h-a,v=y+a,b=y-a):(h=d+p,g=h+a,v=y-a,b=y+a),_=h):(g=r===`left`?d+Math.max(s,l)+a:r===`right`?d+p-Math.max(c,u)-a:this.caretX,i===`top`?(v=f,y=v-a,h=g-a,_=g+a):(v=f+m,y=v+a,h=g+a,_=g-a),b=v),{x1:h,x2:g,x3:_,y1:v,y2:y,y3:b}}drawTitle(e,t,n){let r=this.title,i=r.length,a,o,s;if(i){let c=_u(n.rtl,this.x,this.width);for(e.x=Mm(this,n.titleAlign,n),t.textAlign=c.textAlign(n.titleAlign),t.textBaseline=`middle`,a=gl(n.titleFont),o=n.titleSpacing,t.fillStyle=n.titleColor,t.font=a.string,s=0;se!==0)?(e.beginPath(),e.fillStyle=i.multiKeyBackground,sl(e,{x:t,y:p,w:c,h:s,radius:o}),e.fill(),e.stroke(),e.fillStyle=a.backgroundColor,e.beginPath(),sl(e,{x:n,y:p+1,w:c-2,h:s-2,radius:o}),e.fill()):(e.fillStyle=i.multiKeyBackground,e.fillRect(t,p,c,s),e.strokeRect(t,p,c,s),e.fillStyle=a.backgroundColor,e.fillRect(n,p+1,c-2,s-2))}e.fillStyle=this.labelTextColors[n]}drawBody(e,t,n){let{body:r}=this,{bodySpacing:i,bodyAlign:a,displayColors:o,boxHeight:s,boxWidth:c,boxPadding:l}=n,u=gl(n.bodyFont),d=u.lineHeight,f=0,p=_u(n.rtl,this.x,this.width),m=function(n){t.fillText(n,p.x(e.x+f),e.y+d/2),e.y+=d+i},h=p.textAlign(a),g,_,v,y,b,x,S;for(t.textAlign=a,t.textBaseline=`middle`,t.font=u.string,e.x=Mm(this,h,n),t.fillStyle=n.bodyColor,Z(this.beforeBody,m),f=o&&h!==`right`?a===`center`?c/2+l:c+2+l:0,y=0,x=r.length;y0&&t.stroke()}_updateAnimationTarget(e){let t=this.chart,n=this.$animations,r=n&&n.x,i=n&&n.y;if(r||i){let n=bm[e.position].call(this,this._active,this._eventPosition);if(!n)return;let a=this._size=wm(this,e),o=Object.assign({},n,this._size),s=Om(t,e,o),c=jm(e,o,s,t);(r._to!==c.x||i._to!==c.y)&&(this.xAlign=s.xAlign,this.yAlign=s.yAlign,this.width=a.width,this.height=a.height,this.caretX=n.x,this.caretY=n.y,this._resolveAnimations().update(this,c))}}_willRender(){return!!this.opacity}draw(e){let t=this.options.setContext(this.getContext()),n=this.opacity;if(!n)return;this._updateAnimationTarget(t);let r={width:this.width,height:this.height},i={x:this.x,y:this.y};n=Math.abs(n)<.001?0:n;let a=hl(t.padding),o=this.title.length||this.beforeBody.length||this.body.length||this.afterBody.length||this.footer.length;t.enabled&&o&&(e.save(),e.globalAlpha=n,this.drawBackground(i,e,r,t),vu(e,t.textDirection),i.y+=a.top,this.drawTitle(i,e,t),this.drawBody(i,e,t),this.drawFooter(i,e,t),yu(e,t.textDirection),e.restore())}getActiveElements(){return this._active||[]}setActiveElements(e,t){let n=this._active,r=e.map(({datasetIndex:e,index:t})=>{let n=this.chart.getDatasetMeta(e);if(!n)throw Error(`Cannot find a dataset at index `+e);return{datasetIndex:e,element:n.data[t],index:t}}),i=!ys(n,r),a=this._positionChanged(r,t);(i||a)&&(this._active=r,this._eventPosition=t,this._ignoreReplayEvents=!0,this.update(!0))}handleEvent(e,t,n=!0){if(t&&this._ignoreReplayEvents)return!1;this._ignoreReplayEvents=!1;let r=this.options,i=this._active||[],a=this._getActiveElements(e,i,t,n),o=this._positionChanged(a,e),s=t||!ys(a,i)||o;return s&&(this._active=a,(r.enabled||r.external)&&(this._eventPosition={x:e.x,y:e.y},this.update(!0,t))),s}_getActiveElements(e,t,n,r){let i=this.options;if(e.type===`mouseout`)return[];if(!r)return t.filter(e=>this.chart.data.datasets[e.datasetIndex]&&this.chart.getDatasetMeta(e.datasetIndex).controller.getParsed(e.index)!==void 0);let a=this.chart.getElementsAtEventForMode(e,i.mode,i,n);return i.reverse&&a.reverse(),a}_positionChanged(e,t){let{caretX:n,caretY:r,options:i}=this,a=bm[i.position].call(this,e,t);return a!==!1&&(n!==a.x||r!==a.y)}};L(Rm,`positioners`,bm);var zm={id:`tooltip`,_element:Rm,positioners:bm,afterInit(e,t,n){n&&(e.tooltip=new Rm({chart:e,options:n}))},beforeUpdate(e,t,n){e.tooltip&&e.tooltip.initialize(n)},reset(e,t,n){e.tooltip&&e.tooltip.initialize(n)},afterDraw(e){let t=e.tooltip;if(t&&t._willRender()){let n={tooltip:t};if(e.notifyPlugins(`beforeTooltipDraw`,{...n,cancelable:!0})===!1)return;t.draw(e.ctx),e.notifyPlugins(`afterTooltipDraw`,n)}},afterEvent(e,t){if(e.tooltip){let n=t.replay;e.tooltip.handleEvent(t.event,n,t.inChartArea)&&(t.changed=!0)}},defaults:{enabled:!0,external:null,position:`average`,backgroundColor:`rgba(0,0,0,0.8)`,titleColor:`#fff`,titleFont:{weight:`bold`},titleSpacing:2,titleMarginBottom:6,titleAlign:`left`,bodyColor:`#fff`,bodySpacing:2,bodyFont:{},bodyAlign:`left`,footerColor:`#fff`,footerSpacing:2,footerMarginTop:6,footerFont:{weight:`bold`},footerAlign:`left`,padding:6,caretPadding:2,caretSize:5,cornerRadius:6,boxHeight:(e,t)=>t.bodyFont.size,boxWidth:(e,t)=>t.bodyFont.size,multiKeyBackground:`#fff`,displayColors:!0,boxPadding:0,borderColor:`rgba(0,0,0,0)`,borderWidth:0,animation:{duration:400,easing:`easeOutQuart`},animations:{numbers:{type:`number`,properties:[`x`,`y`,`width`,`height`,`caretX`,`caretY`]},opacity:{easing:`linear`,duration:200}},callbacks:Im},defaultRoutes:{bodyFont:`font`,footerFont:`font`,titleFont:`font`},descriptors:{_scriptable:e=>e!==`filter`&&e!==`itemSort`&&e!==`external`,_indexable:!1,callbacks:{_scriptable:!1,_indexable:!1},animation:{_fallback:!1},animations:{_fallback:`animation`}},additionalOptionScopes:[`interaction`]},Bm=(e,t,n,r)=>(typeof t==`string`?(n=e.push(t)-1,r.unshift({index:n,label:t})):isNaN(t)&&(n=null),n);function Vm(e,t,n,r){let i=e.indexOf(t);return i===-1?Bm(e,t,n,r):i===e.lastIndexOf(t)?i:n}var Hm=(e,t)=>e===null?null:ic(Math.round(e),0,t);function Um(e){let t=this.getLabels();return e>=0&&et.length-1?null:this.getPixelForValue(t[e].value)}getValueForPixel(e){return Math.round(this._startValue+this.getDecimalForPixel(e)*this._valueRange)}getBasePixel(){return this.bottom}};L(Wm,`id`,`category`),L(Wm,`defaults`,{ticks:{callback:Um}});function Gm(e,t){let n=[],{bounds:r,step:i,min:a,max:o,precision:s,count:c,maxTicks:l,maxDigits:u,includeBounds:d}=e,f=i||1,p=l-1,{min:m,max:h}=t,g=!J(a),_=!J(o),v=!J(c),y=(h-m)/(u+1),b=Ws((h-m)/p/f)*f,x,S,C,w;if(b<1e-14&&!g&&!_)return[{value:m},{value:h}];w=Math.ceil(h/b)-Math.floor(m/b),w>p&&(b=Ws(w*b/p/f)*f),J(s)||(x=10**s,b=Math.ceil(b*x)/x),r===`ticks`?(S=Math.floor(m/b)*b,C=Math.ceil(h/b)*b):(S=m,C=h),g&&_&&i&&Js((o-a)/i,b/1e3)?(w=Math.round(Math.min((o-a)/b,l)),b=(o-a)/w,S=a,C=o):v?(S=g?a:S,C=_?o:C,w=c-1,b=(C-S)/w):(w=(C-S)/b,w=Us(w,Math.round(w),b/1e3)?Math.round(w):Math.ceil(w));let T=Math.max(Qs(b),Qs(S));x=10**(J(s)?T:s),S=Math.round(S*x)/x,C=Math.round(C*x)/x;let E=0;for(g&&(d&&S!==a?(n.push({value:a}),So)break;n.push({value:e})}return _&&d&&C!==o?n.length&&Us(n[n.length-1].value,o,Km(o,y,e))?n[n.length-1].value=o:n.push({value:o}):(!_||C===o)&&n.push({value:C}),n}function Km(e,t,{horizontal:n,minRotation:r}){let i=Xs(r),a=(n?Math.sin(i):Math.cos(i))||.001,o=.75*t*(``+e).length;return Math.min(t/a,o)}var qm=class extends Xf{constructor(e){super(e),this.start=void 0,this.end=void 0,this._startValue=void 0,this._endValue=void 0,this._valueRange=0}parse(e,t){return J(e)||(typeof e==`number`||e instanceof Number)&&!isFinite(+e)?null:+e}handleTickRangeOptions(){let{beginAtZero:e}=this.options,{minDefined:t,maxDefined:n}=this.getUserBounds(),{min:r,max:i}=this,a=e=>r=t?r:e,o=e=>i=n?i:e;if(e){let e=Hs(r),t=Hs(i);e<0&&t<0?o(0):e>0&&t>0&&a(0)}if(r===i){let t=i===0?1:Math.abs(i*.05);o(i+t),e||a(r-t)}this.min=r,this.max=i}getTickLimit(){let{maxTicksLimit:e,stepSize:t}=this.options.ticks,n;return t?(n=Math.ceil(this.max/t)-Math.floor(this.min/t)+1,n>1e3&&(console.warn(`scales.${this.id}.ticks.stepSize: ${t} would result generating up to ${n} ticks. Limiting to 1000.`),n=1e3)):(n=this.computeTickLimit(),e=e||11),e&&(n=Math.min(e,n)),n}computeTickLimit(){return 1/0}buildTicks(){let e=this.options,t=e.ticks,n=this.getTickLimit();n=Math.max(2,n);let r=Gm({maxTicks:n,bounds:e.bounds,min:e.min,max:e.max,precision:t.precision,step:t.stepSize,count:t.count,maxDigits:this._maxDigits(),horizontal:this.isHorizontal(),minRotation:t.minRotation||0,includeBounds:t.includeBounds!==!1},this._range||this);return e.bounds===`ticks`&&Ys(r,this,`value`),e.reverse?(r.reverse(),this.start=this.max,this.end=this.min):(this.start=this.min,this.end=this.max),r}configure(){let e=this.ticks,t=this.min,n=this.max;if(super.configure(),this.options.offset&&e.length){let r=(n-t)/Math.max(e.length-1,1)/2;t-=r,n+=r}this._startValue=t,this._endValue=n,this._valueRange=n-t}getLabelForValue(e){return Fc(e,this.chart.options.locale,this.options.ticks.format)}},Jm=class extends qm{determineDataLimits(){let{min:e,max:t}=this.getMinMax(!0);this.min=ms(e)?e:0,this.max=ms(t)?t:1,this.handleTickRangeOptions()}computeTickLimit(){let e=this.isHorizontal(),t=e?this.width:this.height,n=Xs(this.options.ticks.minRotation),r=(e?Math.sin(n):Math.cos(n))||.001,i=this._resolveTickFontOptions(0);return Math.ceil(t/Math.min(40,i.lineHeight/r))}getPixelForValue(e){return e===null?NaN:this.getPixelForDecimal((e-this._startValue)/this._valueRange)}getValueForPixel(e){return this._startValue+this.getDecimalForPixel(e)*this._valueRange}};L(Jm,`id`,`linear`),L(Jm,`defaults`,{ticks:{callback:Rc.formatters.numeric}});var Ym=e=>Math.floor(Vs(e)),Xm=(e,t)=>10**(Ym(e)+t);function Zm(e){return e/10**Ym(e)==1}function Qm(e,t,n){let r=10**n,i=Math.floor(e/r);return Math.ceil(t/r)-i}function $m(e,t){let n=Ym(t-e);for(;Qm(e,t,n)>10;)n++;for(;Qm(e,t,n)<10;)n--;return Math.min(n,Ym(e))}function eh(e,{min:t,max:n}){t=hs(e.min,t);let r=[],i=Ym(t),a=$m(t,n),o=a<0?10**Math.abs(a):1,s=10**a,c=i>a?10**i:0,l=Math.round((t-c)*o)/o,u=Math.floor((t-c)/s/10)*s*10,d=Math.floor((l-u)/10**a),f=hs(e.min,Math.round((c+u+d*10**a)*o)/o);for(;f=10?d=d<15?15:20:d++,d>=20&&(a++,d=2,o=a>=0?1:o),f=Math.round((c+u+d*10**a)*o)/o;let p=hs(e.max,f);return r.push({value:p,major:Zm(p),significand:d}),r}var th=class extends Xf{constructor(e){super(e),this.start=void 0,this.end=void 0,this._startValue=void 0,this._valueRange=0}parse(e,t){let n=qm.prototype.parse.apply(this,[e,t]);if(n===0){this._zero=!0;return}return ms(n)&&n>0?n:null}determineDataLimits(){let{min:e,max:t}=this.getMinMax(!0);this.min=ms(e)?Math.max(0,e):null,this.max=ms(t)?Math.max(0,t):null,this.options.beginAtZero&&(this._zero=!0),this._zero&&this.min!==this._suggestedMin&&!ms(this._userMin)&&(this.min=e===Xm(this.min,0)?Xm(this.min,-1):Xm(this.min,0)),this.handleTickRangeOptions()}handleTickRangeOptions(){let{minDefined:e,maxDefined:t}=this.getUserBounds(),n=this.min,r=this.max,i=t=>n=e?n:t,a=e=>r=t?r:e;n===r&&(n<=0?(i(1),a(10)):(i(Xm(n,-1)),a(Xm(r,1)))),n<=0&&i(Xm(r,-1)),r<=0&&a(Xm(n,1)),this.min=n,this.max=r}buildTicks(){let e=this.options,t=eh({min:this._userMin,max:this._userMax},this);return e.bounds===`ticks`&&Ys(t,this,`value`),e.reverse?(t.reverse(),this.start=this.max,this.end=this.min):(this.start=this.min,this.end=this.max),t}getLabelForValue(e){return e===void 0?`0`:Fc(e,this.chart.options.locale,this.options.ticks.format)}configure(){let e=this.min;super.configure(),this._startValue=Vs(e),this._valueRange=Vs(this.max)-Vs(e)}getPixelForValue(e){return(e===void 0||e===0)&&(e=this.min),e===null||isNaN(e)?NaN:this.getPixelForDecimal(e===this.min?0:(Vs(e)-this._startValue)/this._valueRange)}getValueForPixel(e){let t=this.getDecimalForPixel(e);return 10**(this._startValue+t*this._valueRange)}};L(th,`id`,`logarithmic`),L(th,`defaults`,{ticks:{callback:Rc.formatters.logarithmic,major:{enabled:!0}}});function nh(e){let t=e.ticks;if(t.display&&e.display){let e=hl(t.backdropPadding);return X(t.font&&t.font.size,Wc.font.size)+e.height}return 0}function rh(e,t,n){return n=ps(n)?n:[n],{w:qc(e,t.string,n),h:n.length*t.lineHeight}}function ih(e,t,n,r,i){return e===r||e===i?{start:t-n/2,end:t+n/2}:ei?{start:t-n,end:t}:{start:t,end:t+n}}function ah(e){let t={l:e.left+e._padding.left,r:e.right-e._padding.right,t:e.top+e._padding.top,b:e.bottom-e._padding.bottom},n=Object.assign({},t),r=[],i=[],a=e._pointLabels.length,o=e.options.pointLabels,s=o.centerPointLabels?Q/a:0;for(let c=0;ct.r&&(s=(r.end-t.r)/a,e.r=Math.max(e.r,t.r+s)),i.startt.b&&(c=(i.end-t.b)/o,e.b=Math.max(e.b,t.b+c))}function sh(e,t,n){let r=e.drawingArea,{extra:i,additionalAngle:a,padding:o,size:s}=n,c=e.getPointPosition(t,r+i+o,a),l=Math.round(Zs(nc(c.angle+Rs))),u=fh(c.y,s.h,l),d=uh(l),f=dh(c.x,s.w,d);return{visible:!0,x:c.x,y:u,textAlign:d,left:f,top:u,right:f+s.w,bottom:u+s.h}}function ch(e,t){if(!t)return!0;let{left:n,top:r,right:i,bottom:a}=e;return!(Qc({x:n,y:r},t)||Qc({x:n,y:a},t)||Qc({x:i,y:r},t)||Qc({x:i,y:a},t))}function lh(e,t,n){let r=[],i=e._pointLabels.length,a=e.options,{centerPointLabels:o,display:s}=a.pointLabels,c={extra:nh(a)/2,additionalAngle:o?Q/i:0},l;for(let a=0;a270||n<90)&&(e-=t),e}function ph(e,t,n){let{left:r,top:i,right:a,bottom:o}=n,{backdropColor:s}=t;if(!J(s)){let n=ml(t.borderRadius),c=hl(t.backdropPadding);e.fillStyle=s;let l=r-c.left,u=i-c.top,d=a-r+c.width,f=o-i+c.height;Object.values(n).some(e=>e!==0)?(e.beginPath(),sl(e,{x:l,y:u,w:d,h:f,radius:n}),e.fill()):e.fillRect(l,u,d,f)}}function mh(e,t){let{ctx:n,options:{pointLabels:r}}=e;for(let i=t-1;i>=0;i--){let t=e._pointLabelItems[i];if(!t.visible)continue;let a=r.setContext(e.getPointLabelContext(i));ph(n,a,t);let o=gl(a.font),{x:s,y:c,textAlign:l}=t;ol(n,e._pointLabels[i],s,c+o.lineHeight/2,o,{color:a.color,textAlign:l,textBaseline:`middle`})}}function hh(e,t,n,r){let{ctx:i}=e;if(n)i.arc(e.xCenter,e.yCenter,t,0,$);else{let n=e.getPointPosition(0,t);i.moveTo(n.x,n.y);for(let a=1;a{let n=vs(this.options.pointLabels.callback,[e,t],this);return n||n===0?n:``}).filter((e,t)=>this.chart.getDataVisibility(t))}fit(){let e=this.options;e.display&&e.pointLabels.display?ah(this):this.setCenterPoint(0,0,0,0)}setCenterPoint(e,t,n,r){this.xCenter+=Math.floor((e-t)/2),this.yCenter+=Math.floor((n-r)/2),this.drawingArea-=Math.min(this.drawingArea/2,Math.max(e,t,n,r))}getIndexAngle(e){let t=$/(this._pointLabels.length||1),n=this.options.startAngle||0;return nc(e*t+Xs(n))}getDistanceFromCenterForValue(e){if(J(e))return NaN;let t=this.drawingArea/(this.max-this.min);return this.options.reverse?(this.max-e)*t:(e-this.min)*t}getValueForDistanceFromCenter(e){if(J(e))return NaN;let t=e/(this.drawingArea/(this.max-this.min));return this.options.reverse?this.max-t:this.min+t}getPointLabelContext(e){let t=this._pointLabels||[];if(e>=0&&e{if(t!==0||t===0&&this.min<0){s=this.getDistanceFromCenterForValue(e.value);let n=this.getContext(t),o=r.setContext(n),c=i.setContext(n);gh(this,o,s,a,c)}}),n.display){for(e.save(),o=a-1;o>=0;o--){let r=n.setContext(this.getPointLabelContext(o)),{color:i,lineWidth:a}=r;!a||!i||(e.lineWidth=a,e.strokeStyle=i,e.setLineDash(r.borderDash),e.lineDashOffset=r.borderDashOffset,s=this.getDistanceFromCenterForValue(t.reverse?this.min:this.max),c=this.getPointPosition(o,s),e.beginPath(),e.moveTo(this.xCenter,this.yCenter),e.lineTo(c.x,c.y),e.stroke())}e.restore()}}drawBorder(){}drawLabels(){let e=this.ctx,t=this.options,n=t.ticks;if(!n.display)return;let r=this.getIndexAngle(0),i,a;e.save(),e.translate(this.xCenter,this.yCenter),e.rotate(r),e.textAlign=`center`,e.textBaseline=`middle`,this.ticks.forEach((r,o)=>{if(o===0&&this.min>=0&&!t.reverse)return;let s=n.setContext(this.getContext(o)),c=gl(s.font);if(i=this.getDistanceFromCenterForValue(this.ticks[o].value),s.showLabelBackdrop){e.font=c.string,a=e.measureText(r.label).width,e.fillStyle=s.backdropColor;let t=hl(s.backdropPadding);e.fillRect(-a/2-t.left,-i-c.size/2-t.top,a+t.width,c.size+t.height)}ol(e,r.label,0,-i,c,{color:s.color,strokeColor:s.textStrokeColor,strokeWidth:s.textStrokeWidth})}),e.restore()}drawTitle(){}};L(vh,`id`,`radialLinear`),L(vh,`defaults`,{display:!0,animate:!0,position:`chartArea`,angleLines:{display:!0,lineWidth:1,borderDash:[],borderDashOffset:0},grid:{circular:!1},startAngle:0,ticks:{showLabelBackdrop:!0,callback:Rc.formatters.numeric},pointLabels:{backdropColor:void 0,backdropPadding:2,display:!0,font:{size:10},callback(e){return e},padding:5,centerPointLabels:!1}}),L(vh,`defaultRoutes`,{"angleLines.color":`borderColor`,"pointLabels.color":`color`,"ticks.color":`color`}),L(vh,`descriptors`,{angleLines:{_fallback:`grid`}});var yh={millisecond:{common:!0,size:1,steps:1e3},second:{common:!0,size:1e3,steps:60},minute:{common:!0,size:6e4,steps:60},hour:{common:!0,size:36e5,steps:24},day:{common:!0,size:864e5,steps:30},week:{common:!1,size:6048e5,steps:4},month:{common:!0,size:2628e6,steps:12},quarter:{common:!1,size:7884e6,steps:4},year:{common:!0,size:3154e7}},bh=Object.keys(yh);function xh(e,t){return e-t}function Sh(e,t){if(J(t))return null;let n=e._adapter,{parser:r,round:i,isoWeekday:a}=e._parseOpts,o=t;return typeof r==`function`&&(o=r(o)),ms(o)||(o=typeof r==`string`?n.parse(o,r):n.parse(o)),o===null?null:(i&&(o=i===`week`&&(qs(a)||a===!0)?n.startOf(o,`isoWeek`,a):n.startOf(o,i)),+o)}function Ch(e,t,n,r){let i=bh.length;for(let a=bh.indexOf(e);a=bh.indexOf(n);a--){let n=bh[a];if(yh[n].common&&e._adapter.diff(i,r,n)>=t-1)return n}return bh[n?bh.indexOf(n):0]}function Th(e){for(let t=bh.indexOf(e)+1,n=bh.length;t=t?n[r]:n[i];e[a]=!0}}function Dh(e,t,n,r){let i=e._adapter,a=+i.startOf(t[0].value,r),o=t[t.length-1].value,s,c;for(s=a;s<=o;s=+i.add(s,1,r))c=n[s],c>=0&&(t[c].major=!0);return t}function Oh(e,t,n){let r=[],i={},a=t.length,o,s;for(o=0;o+e.value))}initOffsets(e=[]){let t=0,n=0,r,i;this.options.offset&&e.length&&(r=this.getDecimalForValue(e[0]),t=e.length===1?1-r:(this.getDecimalForValue(e[1])-r)/2,i=this.getDecimalForValue(e[e.length-1]),n=e.length===1?i:(i-this.getDecimalForValue(e[e.length-2]))/2);let a=e.length<3?.5:.25;t=ic(t,0,a),n=ic(n,0,a),this._offsets={start:t,end:n,factor:1/(t+1+n)}}_generate(){let e=this._adapter,t=this.min,n=this.max,r=this.options,i=r.time,a=i.unit||Ch(i.minUnit,t,n,this._getLabelCapacity(t)),o=X(r.ticks.stepSize,1),s=a===`week`&&i.isoWeekday,c=qs(s)||s===!0,l={},u=t,d,f;if(c&&(u=+e.startOf(u,`isoWeek`,s)),u=+e.startOf(u,c?`day`:a),e.diff(n,t,a)>1e5*o)throw Error(t+` and `+n+` are too far apart with stepSize of `+o+` `+a);let p=r.ticks.source===`data`&&this.getDataTimestamps();for(d=u,f=0;d+e)}getLabelForValue(e){let t=this._adapter,n=this.options.time;return n.tooltipFormat?t.format(e,n.tooltipFormat):t.format(e,n.displayFormats.datetime)}format(e,t){let n=this.options.time.displayFormats,r=this._unit,i=t||n[r];return this._adapter.format(e,i)}_tickFormatFunction(e,t,n,r){let i=this.options,a=i.ticks.callback;if(a)return vs(a,[e,t,n],this);let o=i.time.displayFormats,s=this._unit,c=this._majorUnit,l=s&&o[s],u=c&&o[c],d=n[t],f=c&&u&&d&&d.major;return this._adapter.format(e,r||(f?u:l))}generateTickLabels(e){let t,n,r;for(t=0,n=e.length;t0?o:1}getDataTimestamps(){let e=this._cache.data||[],t,n;if(e.length)return e;let r=this.getMatchingVisibleMetas();if(this._normalized&&r.length)return this._cache.data=r[0].controller.getAllParsedValues(this);for(t=0,n=r.length;t=e[r].pos&&t<=e[i].pos&&({lo:r,hi:i}=cc(e,`pos`,t)),{pos:a,time:s}=e[r],{pos:o,time:c}=e[i]):(t>=e[r].time&&t<=e[i].time&&({lo:r,hi:i}=cc(e,`time`,t)),{time:a,pos:s}=e[r],{time:o,pos:c}=e[i]);let l=o-a;return l?s+(c-s)*(t-a)/l:s}var jh=class extends kh{constructor(e){super(e),this._table=[],this._minPos=void 0,this._tableRange=void 0}initOffsets(){let e=this._getTimestampsForTable(),t=this._table=this.buildLookupTable(e);this._minPos=Ah(t,this.min),this._tableRange=Ah(t,this.max)-this._minPos,super.initOffsets(e)}buildLookupTable(e){let{min:t,max:n}=this,r=[],i=[],a,o,s,c,l;for(a=0,o=e.length;a=t&&c<=n&&r.push(c);if(r.length<2)return[{time:t,pos:0},{time:n,pos:1}];for(a=0,o=r.length;ae-t)}_getTimestampsForTable(){let e=this._cache.all||[];if(e.length)return e;let t=this.getDataTimestamps(),n=this.getLabelTimestamps();return e=t.length&&n.length?this.normalize(t.concat(n)):t.length?t:n,e=this._cache.all=e,e}getDecimalForValue(e){return(Ah(this._table,e)-this._minPos)/this._tableRange}getValueForPixel(e){let t=this._offsets,n=this.getDecimalForPixel(e)/t.factor-t.end;return Ah(this._table,n*this._tableRange+this._minPos,!0)}};L(jh,`id`,`timeseries`),L(jh,`defaults`,kh.defaults),Rp.register(Cd,ym,Wm,Jm,zm);var Mh=new Intl.DateTimeFormat(`ko-KR`,{hour:`2-digit`,hour12:!1}),Nh=`#94a3b8`,Ph=`rgba(148, 163, 184, 0.18)`,Fh=`#0d9488`,Ih=`#0f766e`;function Lh(e){return Mh.format(new Date(e*1e3))}function Rh(e){return e.map((t,n)=>n%3==0||n===e.length-1?Lh(t.bucketStart):``)}function zh({buckets:e}){let t=F(null),n=F(null),r=F(e);return r.current=e,P(()=>{let e=t.current;if(!e)return;let i=window.matchMedia(`(prefers-reduced-motion: reduce)`).matches,a=window.getComputedStyle(e).fontFamily,o={animation:!i&&{duration:500,easing:`easeOutQuart`},maintainAspectRatio:!1,responsive:!0,interaction:{intersect:!1,mode:`index`},plugins:{legend:{display:!1},tooltip:{displayColors:!1,callbacks:{title:e=>{let t=e[0]?.dataIndex??-1,n=r.current[t];return n?Lh(n.bucketStart):``},label:e=>`차단 ${q(Number(e.raw??0))}`,afterLabel:e=>{let t=r.current[e.dataIndex];return t?`DNS 요청 ${q(t.queries)}`:``}}}},scales:{x:{border:{display:!1},grid:{display:!1},ticks:{autoSkip:!1,color:Nh,font:{family:a,size:11,weight:700},maxRotation:0,minRotation:0}},y:{beginAtZero:!0,border:{display:!1},grid:{color:Ph},ticks:{color:Nh,font:{family:a,size:11,weight:700},maxTicksLimit:4,precision:0}}}};return n.current=new Rp(e,{type:`bar`,data:{labels:Rh(r.current),datasets:[{data:r.current.map(e=>e.blocked),backgroundColor:Fh,hoverBackgroundColor:Ih,borderRadius:4,borderSkipped:!1,barPercentage:.82,categoryPercentage:.9,maxBarThickness:24}]},options:o}),()=>{n.current?.destroy(),n.current=null}},[]),P(()=>{let t=n.current;t&&(t.data.labels=Rh(e),t.data.datasets[0].data=e.map(e=>e.blocked),t.update())},[e]),B(`div`,{class:`mt-5 h-44 sm:h-52`,children:B(`canvas`,{"aria-label":`최근 24시간 시간대별 SafeShield 차단 요청`,ref:t,role:`img`,children:`최근 24시간 시간대별 SafeShield 차단 요청 차트`})})}var Bh=3600,Vh=24;function Hh(e,t){return e<=0?`0.0%`:`${(t/e*100).toFixed(1)}%`}function Uh(e){let t=e.hourly[e.hourly.length-1];if(t?.bucketStart)return t.bucketStart;let n=e.updatedAt>0?e.updatedAt:Math.floor(Date.now()/1e3);return Math.floor(n/Bh)*Bh}function Wh(e){let t=new Map(e.hourly.map(e=>[e.bucketStart,e])),n=Uh(e)-23*Bh;return Array.from({length:Vh},(e,r)=>{let i=n+r*Bh;return t.get(i)??{bucketStart:i,queries:0,blocked:0}})}function Gh({children:e}){return B(`div`,{class:`mt-5 flex min-h-52 items-center justify-center rounded-xl border border-slate-200 bg-slate-50 px-5 text-center`,children:B(`p`,{class:`m-0 max-w-lg text-sm font-semibold leading-6 text-slate-500`,children:e})})}function Kh({data:e,error:t,loading:n,nowTimestamp:r,refreshing:i}){let a;if(n&&!e)a=B(Gh,{children:`SafeShield 보호 활동을 불러오는 중입니다.`});else if(t&&!e)a=B(Gh,{children:`SafeShield 보호 활동을 불러오지 못했습니다. SafeShield 페이지에서 상태를 확인해 주세요.`});else if(!e||!e.available)a=B(Gh,{children:`현재 SafeShield에서 차단 통계를 제공하지 않습니다. 통계 기능을 확인해 주세요.`});else if(!e.enabled)a=B(Gh,{children:`통계 수집이 꺼져 있습니다. SafeShield 페이지에서 통계를 켜면 최근 24시간 활동이 표시됩니다.`});else{let t=Wh(e),n=t.reduce((e,t)=>({queries:e.queries+t.queries,blocked:e.blocked+t.blocked}),{queries:0,blocked:0});a=B(S,{children:[B(`dl`,{class:`mt-5 grid gap-3 sm:grid-cols-3`,children:[B(`div`,{class:`rounded-xl bg-slate-50 px-4 py-3`,children:[B(`dt`,{class:`text-[0.68rem] font-black uppercase tracking-[0.12em] text-slate-400`,children:`DNS 요청`}),B(`dd`,{class:`mt-1 mb-0 ml-0 text-lg font-black text-slate-950`,children:q(n.queries)})]}),B(`div`,{class:`rounded-xl bg-slate-50 px-4 py-3`,children:[B(`dt`,{class:`text-[0.68rem] font-black uppercase tracking-[0.12em] text-slate-400`,children:`차단`}),B(`dd`,{class:`mt-1 mb-0 ml-0 text-lg font-black text-teal-700`,children:q(n.blocked)})]}),B(`div`,{class:`rounded-xl bg-slate-50 px-4 py-3`,children:[B(`dt`,{class:`text-[0.68rem] font-black uppercase tracking-[0.12em] text-slate-400`,children:`차단율`}),B(`dd`,{class:`mt-1 mb-0 ml-0 text-lg font-black text-slate-950`,children:Hh(n.queries,n.blocked)})]})]}),B(zh,{buckets:t})]})}return B(`article`,{class:`min-w-0 rounded-2xl border border-slate-200 bg-white p-5 shadow-sm shadow-slate-900/5 sm:p-6`,children:[B(`div`,{class:`min-w-0`,children:[B(`p`,{class:`m-0 text-xs font-extrabold uppercase tracking-[0.16em] text-slate-500`,children:`SafeShield activity`}),B(`div`,{class:`mt-2 flex min-w-0 items-center justify-between gap-3`,children:[B(`h3`,{class:`m-0 min-w-0 text-xl font-black text-slate-950`,children:`최근 24시간 보호 활동`}),B(`a`,{class:`shrink-0 whitespace-nowrap text-xs font-extrabold text-teal-700 no-underline hover:text-teal-800`,href:`#safeshield`,children:`상세 통계 →`})]}),e?.updatedAt?B(`p`,{class:`mt-2 mb-0 text-[0.68rem] font-semibold text-slate-400`,title:Fa(e.updatedAt),children:i?`갱신 중…`:`집계: ${Ia(e.updatedAt,r)}`}):null]}),a,t&&e?B(`p`,{class:`mt-3 mb-0 text-xs font-bold text-amber-700`,children:`최근 통계 갱신에 실패해 마지막 정상 데이터를 표시하고 있습니다.`}):null]})}var qh=7200;function Jh(e,t=Math.floor(Date.now()/1e3)){return!e||!e.settings.checkEnabled||e.phase===`checking`||!e.lastCheckAt?!1:Math.max(0,t-e.lastCheckAt)>Math.max(e.settings.checkIntervalSeconds*2,qh)}function Yh(e){return e===`healthy`?`bg-emerald-50 text-emerald-700 ring-emerald-200`:e===`warning`?`bg-amber-50 text-amber-800 ring-amber-200`:`bg-slate-100 text-slate-600 ring-slate-200`}function Xh({detail:e,eyebrow:t,href:n,icon:r,linkLabel:i=`자세히 보기 →`,meta:a,metaState:o,metaWarning:s=!1,state:c=`neutral`,value:l}){let u=B(S,{children:[B(`div`,{class:`flex items-start justify-between gap-4`,children:[B(`p`,{class:`m-0 text-[0.68rem] font-black uppercase tracking-[0.16em] text-slate-500`,children:t}),B(`span`,{class:`grid size-10 shrink-0 place-items-center rounded-xl ring-1 ring-inset ${Yh(c)}`,children:r})]}),B(`p`,{class:`mt-4 mb-0 break-words text-2xl font-black tracking-tight text-slate-950`,children:l}),B(`p`,{class:`mt-2 mb-0 min-h-10 text-sm font-medium leading-5 text-slate-500`,children:e}),a?B(`p`,{class:`mt-3 mb-0 text-xs font-bold ${o===`healthy`?`text-emerald-700`:o===`warning`||s?`text-amber-700`:`text-slate-400`}`,children:a}):null,n?B(`span`,{class:`mt-4 inline-flex text-xs font-extrabold text-teal-700`,children:i}):null]}),d=`min-w-0 rounded-2xl border border-slate-200 bg-white p-5 shadow-sm shadow-slate-900/5 transition`;return n?B(`a`,{class:`${d} no-underline hover:border-slate-300 hover:shadow-md`,href:n,children:u}):B(`article`,{class:d,children:u})}function Zh({action:e,description:t,eyebrow:n,id:r,title:i}){return B(`div`,{class:`mb-4 min-w-0`,children:[B(`p`,{class:`m-0 text-[0.68rem] font-black uppercase tracking-[0.18em] text-teal-700`,children:n}),B(`div`,{class:`mt-2 flex min-w-0 items-center justify-between gap-3`,children:[B(`h2`,{class:`m-0 min-w-0 text-xl font-black tracking-tight text-slate-950`,id:r,children:i}),e?B(`div`,{class:`shrink-0`,children:e}):null]}),B(`p`,{class:`mt-2 mb-0 text-sm leading-6 text-slate-500`,children:t})]})}var Qh=6e4;function $h(e,t){return!e||!Number.isFinite(e)||e<=0?null:Math.max(0,t-e)}function eg(e,t,n,r){return!t||t<=0?`${e}: ${r}`:B(`span`,{title:Fa(t),children:[e,`: `,Ia(t,n)]})}function tg(e){if(!e)return null;switch(e.toLowerCase()){case`dhcp`:return`DHCP`;case`static`:return`Static`;case`pppoe`:return`PPPoE`;default:return e.toUpperCase()}}function ng(e){if(!e)return!1;let t=e.split(`.`).map(e=>Number(e));if(t.length!==4||t.some(e=>!Number.isInteger(e)||e<0||e>255))return!1;let[n,r]=t;return n===void 0||r===void 0?!1:n===10||n===172&&r>=16&&r<=31||n===192&&r===168}function rg({label:e,value:t}){return B(`div`,{class:`flex min-w-0 items-start justify-between gap-4 border-b border-slate-100 py-3 last:border-b-0`,children:[B(`dt`,{class:`text-sm font-semibold text-slate-500`,children:e}),B(`dd`,{class:`m-0 min-w-0 max-w-[68%] break-words text-right text-sm font-extrabold text-slate-950`,children:t})]})}function ig(e){return e===`initializing`?{badge:`bg-teal-100 text-teal-800`,icon:`text-teal-700`,label:`준비 중`,panel:`border-teal-200 bg-teal-50`}:e===`critical`?{badge:`bg-rose-100 text-rose-800`,icon:`text-rose-700`,label:`이상`,panel:`border-rose-200 bg-rose-50/70`}:e===`warning`?{badge:`bg-amber-100 text-amber-800`,icon:`text-amber-700`,label:`주의`,panel:`border-amber-200 bg-amber-50/70`}:e===`unknown`?{badge:`bg-slate-200 text-slate-700`,icon:`text-slate-500`,label:`확인 불가`,panel:`border-slate-200 bg-slate-50`}:{badge:`bg-emerald-100 text-emerald-800`,icon:`text-emerald-700`,label:`정상`,panel:`border-emerald-200 bg-emerald-50/70`}}function ag({data:e,error:t,loading:n,nowTimestamp:r}){let i=!!(e&&e.generatedAt>0),a=ig(i&&e?e.overall:`unknown`),o=i&&e?e.checks.filter(e=>e.status!==`ok`):[],s=o.slice(0,2),c=Math.max(0,o.length-s.length);return B(`div`,{class:`mt-5 border-t border-slate-200 pt-5`,children:[B(`div`,{class:`flex flex-wrap items-center justify-between gap-3`,children:[B(`div`,{class:`flex items-center gap-2`,children:[B(`p`,{class:`m-0 text-sm font-black text-slate-950`,children:`장치 진단`}),i?B(`span`,{class:`rounded-full px-2.5 py-1 text-[11px] font-extrabold ${a.badge}`,children:a.label}):null]}),B(`a`,{class:`text-xs font-extrabold text-teal-700 no-underline hover:text-teal-900`,href:`#settings`,children:`상세 보기 →`})]}),t&&!i?B(`div`,{class:`mt-3 rounded-xl border border-amber-200 bg-amber-50/70 px-4 py-3`,children:B(`div`,{class:`flex items-start gap-2`,children:[B(U,{class:`mt-0.5 size-4 shrink-0 text-amber-700`}),B(`div`,{class:`min-w-0`,children:[B(`p`,{class:`m-0 text-sm font-extrabold text-slate-900`,children:`진단 상태를 확인하지 못했습니다.`}),B(`p`,{class:`mt-1 mb-0 text-xs leading-5 text-slate-500`,children:`설정에서 장치 진단 상태를 다시 확인해 주세요.`})]})]})}):i&&e?B(`div`,{class:`mt-3 rounded-xl border px-4 py-3 ${a.panel}`,children:[B(`div`,{class:`flex min-w-0 items-start gap-3`,children:[e.overall===`ok`?B(Xt,{class:`mt-0.5 size-5 shrink-0 ${a.icon}`}):e.overall===`initializing`?B(Vt,{class:`mt-0.5 size-5 shrink-0 ${a.icon}`}):B(U,{class:`mt-0.5 size-5 shrink-0 ${a.icon}`}),B(`div`,{class:`min-w-0 flex-1`,children:[B(`p`,{class:`m-0 text-sm font-black text-slate-950`,children:e.summary.message}),B(`p`,{class:`mt-1 mb-0 text-xs font-semibold leading-5 text-slate-500`,children:[`마지막 진단: `,Ia(e.generatedAt,r),` · 검사 항목:`,` `,e.summary.total,`개`]})]})]}),s.length>0?B(`div`,{class:`mt-3 grid gap-2 sm:grid-cols-2`,children:s.map(e=>B(`div`,{class:`min-w-0 rounded-lg border border-white/80 bg-white/70 px-3 py-2`,children:[B(`p`,{class:`m-0 text-xs font-extrabold text-slate-900`,children:e.label}),B(`p`,{class:`mt-1 mb-0 line-clamp-2 text-xs leading-5 text-slate-500`,children:e.message})]},e.id))}):null,c>0?B(`p`,{class:`mt-2 mb-0 text-xs font-extrabold text-slate-600`,children:[`외 `,c,`건의 확인 항목이 있습니다.`]}):null]}):B(`div`,{class:`mt-3 rounded-xl border border-slate-200 bg-slate-50 px-4 py-3`,children:[B(`p`,{class:`m-0 text-sm font-extrabold text-slate-900`,children:n?`진단 상태를 확인하고 있습니다.`:`아직 생성된 진단 결과가 없습니다.`}),B(`p`,{class:`mt-1 mb-0 text-xs leading-5 text-slate-500`,children:`진단 결과가 생성되면 현재 장치 상태를 이곳에 요약해서 표시합니다.`})]})]})}function og(e,t,n){if(t&&!e)return{detail:`보호 상태를 확인하고 있습니다.`,state:`neutral`,value:`확인 중`};if(n&&!e)return{detail:`SafeShield 상태를 불러오지 못했습니다.`,state:`warning`,value:`확인 필요`};if(!e||!e.available)return{detail:`SafeShield 서비스를 사용할 수 없습니다.`,state:`warning`,value:`사용 불가`};if(!e.enabled||e.status===`disabled`)return{detail:`DNS 보호가 비활성화되어 있습니다.`,state:`neutral`,value:`꺼짐`};if(e.status===`running`)return{detail:`차단 목록을 갱신하고 있습니다.`,state:`neutral`,value:`갱신 중`};if(!(e.active&&e.runtime.dnsmasqRunning&&e.runtime.dnsRuntimeOk&&e.health.overall!==`error`&&e.issueCounts.errors===0))return{detail:e.runtime.lastErrorCode?`최근 오류: ${e.runtime.lastErrorCode}`:`DNS 보호 상태를 확인해 주세요.`,state:`warning`,value:`확인 필요`};let r=e.license.plan?.trim(),i=e.blocklist.validLineCount>0?`${q(e.blocklist.validLineCount)}개 차단 규칙`:`차단 목록 적용됨`;return{detail:r?`${i} · ${r.toUpperCase()}`:i,state:`healthy`,value:`보호 중`}}function sg({activity:e,activityError:t,activityLoading:n,data:r,devices:i,devicesError:a,devicesLoading:o,error:s,firmware:c,firmwareError:l,firmwareLoading:u,health:d,healthError:f,healthLoading:p,lan:m,lanError:h,lanLoading:g,loading:_,onRetry:v,safeshield:y,safeshieldError:b,safeshieldLoading:x,statistics:S,statisticsError:C,statisticsLoading:w,statisticsRefreshing:T,updates:E,updatesError:D,updatesLoading:O}){let k=$e(()=>r?za(r.runtime.memory):null,[r]),[A,ee]=N(()=>Math.floor(Date.now()/1e3));if(P(()=>{let e=window.setInterval(()=>{ee(Math.floor(Date.now()/1e3))},Qh);return()=>window.clearInterval(e)},[]),_)return B(io,{});if(s)return B(ao,{message:s,onRetry:v});if(!r)return null;let j=k?Math.round(k.percent):0,te=og(y,x,b),ne=E?.packages.find(e=>e.name===`luci-app-smartsafehub`)??E?.packages[0]??null,M=!!(E&&E.updateCount>0),re=E?M?`${E.updateCount}개 업데이트`:E.lastCheckAt?`최신 상태`:`확인 전`:D?`확인 필요`:`확인 중`,ie=ne?M&&ne.availableVersion?`${ne.installedVersion} → ${ne.availableVersion}`:`설치 버전 ${ne.installedVersion}`:D?`업데이트 상태를 불러오지 못했습니다.`:O?`업데이트 상태를 확인하고 있습니다.`:`업데이트 상태를 확인할 수 없습니다.`,ae=i?`${q(i.totals.online)}대`:o?`확인 중`:`확인 필요`,oe=i?`Wi-Fi ${q(i.totals.wireless)}대 · 유선/기타 ${q(i.totals.ethernet)}대`:a||`연결 기기 요약을 불러오고 있습니다.`,se=tg(r.network.protocol),ce=r.network.available?r.network.ipv4Address?`WAN ${r.network.ipv4Address}${se?` · ${se}`:``}`:se?`${se} · WAN 주소를 받지 못했습니다.`:`WAN 주소를 받지 못했습니다.`:`WAN 인터페이스를 찾을 수 없습니다.`,le=!!m?.conflict.detected,ue=!r.network.up||le||h!==null&&!m?`warning`:m?`healthy`:`neutral`,de=le?`네트워크 충돌`:r.network.up?`정상 연결`:`연결 확인`,fe=r.network.up?le?`⚠ LAN 대역과 충돌합니다`:g&&!m?`네트워크 대역 확인 중`:h&&!m?`네트워크 대역을 확인하지 못했습니다.`:m?`✓ 네트워크 충돌 없음`:`네트워크 대역 확인 필요`:`WAN 연결 상태를 확인해 주세요.`,pe=!r.network.up||le||h!==null&&!m?`warning`:m?`healthy`:`neutral`,me=r.network.ipv4Address?ng(r.network.ipv4Address)?`${r.network.ipv4Address} · 사설 네트워크`:r.network.ipv4Address:`할당되지 않음`,he=$h(y?.timestamps.lastSuccess,A),ge=y?Math.max(y.timestamps.refreshIntervalS*2,86400):null,_e=!!(y?.enabled&&y.status!==`running`&&he!==null&&ge!==null&&he>ge),ve=Jh(E,A),ye=!!c?.current.metadataAvailable,be=u&&!c?`확인 중`:l&&!c?`확인 필요`:ye?c?.current.releaseVersion?`SmartSafeHub ${c.current.releaseVersion}`:`SmartSafeHub 펌웨어`:`${r.software.distribution} ${r.software.version}`,xe=u&&!c?`확인 중`:l&&!c?`확인 필요`:ye&&c?.current.buildId||r.software.revision,Se=ye?`빌드 ID`:`리비전`;return B(`div`,{class:`min-w-0 space-y-6`,children:[B(`section`,{"aria-labelledby":`dashboard-overview-title`,children:[B(Zh,{description:`인터넷, SafeShield, 연결 기기와 소프트웨어 상태를 한눈에 확인합니다.`,eyebrow:`Overview`,id:`dashboard-overview-title`,title:`시스템 개요`}),B(`div`,{class:`grid min-w-0 gap-4 sm:grid-cols-2 xl:grid-cols-4`,children:[B(Xh,{detail:ce,eyebrow:`Internet`,href:`#network`,icon:B(zt,{class:`size-5`}),linkLabel:le?`해결하기 →`:`자세히 보기 →`,meta:fe,metaState:pe,state:ue,value:de}),B(Xh,{detail:te.detail,eyebrow:`SafeShield`,href:`#safeshield`,icon:B(At,{class:`size-5`}),meta:eg(_e?`차단 목록 갱신 지연`:`차단 목록 갱신`,y?.timestamps.lastSuccess,A,x?`확인 중`:`기록 없음`),metaWarning:_e,state:te.state===`healthy`&&_e?`warning`:te.state,value:te.value}),B(Xh,{detail:oe,eyebrow:`Connected devices`,href:`#devices`,icon:B(Mt,{class:`size-5`}),meta:eg(`목록 확인`,i?.generatedAt,A,o?`확인 중`:`기록 없음`),state:i?`healthy`:a?`warning`:`neutral`,value:ae}),B(Xh,{detail:ie,eyebrow:`Software update`,href:`#system`,icon:B(Ft,{class:`size-5`}),meta:E&&!E.settings.checkEnabled?eg(`자동 확인 꺼짐 · 마지막 확인`,E.lastCheckAt,A,`확인 기록 없음`):eg(ve?`업데이트 확인 지연`:`마지막 확인`,E?.lastCheckAt,A,O?`확인 중`:`아직 없음`),metaWarning:ve,state:D||ve||M?`warning`:E?.lastCheckAt?`healthy`:`neutral`,value:re})]})]}),B(`section`,{"aria-labelledby":`dashboard-activity-title`,children:[B(Zh,{description:`최근 SafeShield 차단 활동과 현재 네트워크 연결 구성을 함께 확인합니다.`,eyebrow:`Activity`,id:`dashboard-activity-title`,title:`네트워크 보호 활동`}),B(`div`,{class:`grid min-w-0 gap-4 xl:grid-cols-[minmax(0,1.55fr)_minmax(18rem,0.65fr)]`,children:[B(Kh,{data:S,error:C,loading:w,nowTimestamp:A,refreshing:T}),B(`article`,{class:`min-w-0 rounded-2xl border border-slate-200 bg-white p-5 shadow-sm shadow-slate-900/5 sm:p-6`,children:[B(`div`,{class:`flex items-start justify-between gap-4`,children:[B(`div`,{children:[B(`p`,{class:`m-0 text-xs font-extrabold uppercase tracking-[0.16em] text-slate-500`,children:`Network`}),B(`h3`,{class:`mt-2 mb-0 text-xl font-black text-slate-950`,children:`연결 상태`})]}),B(`span`,{class:`grid size-10 shrink-0 place-items-center rounded-xl ${r.network.up&&!le?`bg-emerald-50 text-emerald-700`:`bg-amber-50 text-amber-800`}`,children:B(zt,{class:`size-5`})})]}),B(`dl`,{class:`mt-4 mb-0`,children:[B(rg,{label:`인터넷`,value:le?`네트워크 충돌`:r.network.up?`정상 연결`:`연결 확인`}),B(rg,{label:`WAN IP`,value:me}),B(rg,{label:`프로토콜`,value:se||`확인되지 않음`}),B(rg,{label:`상위 네트워크`,value:m?.wan.subnet||(g?`확인 중`:h?`확인 필요`:`확인되지 않음`)}),B(rg,{label:`LAN 네트워크`,value:m?.lan.subnet||(g?`확인 중`:h?`확인 필요`:`확인되지 않음`)}),B(rg,{label:`대역 충돌`,value:m?B(`span`,{class:m.conflict.detected?`text-amber-700`:`text-emerald-700`,children:m.conflict.detected?`충돌 감지`:`없음`}):g?`확인 중`:`확인 필요`})]}),B(`a`,{class:`mt-5 inline-flex min-h-10 w-full items-center justify-center rounded-xl border border-slate-200 bg-slate-50 px-4 py-2 text-sm font-extrabold text-slate-700 no-underline transition hover:border-teal-200 hover:bg-teal-50 hover:text-teal-800`,href:`#network`,children:`네트워크 보기`})]})]})]}),B(`section`,{"aria-labelledby":`dashboard-recent-activity-title`,children:[B(Zh,{action:B(`a`,{class:`inline-flex whitespace-nowrap text-xs font-extrabold text-teal-700 no-underline hover:text-teal-900`,href:`#activity`,children:`전체 보기 →`}),description:`인터넷, 보호, 업데이트와 진단에서 실제 상태가 바뀐 시점을 확인합니다.`,eyebrow:`History`,id:`dashboard-recent-activity-title`,title:`최근 활동`}),B(`article`,{class:`min-w-0 rounded-2xl border border-slate-200 bg-white p-5 shadow-sm shadow-slate-900/5 sm:p-6`,children:n||t&&!e?B(eo,{error:t,loading:n}):B($a,{compact:!0,events:(e?.events??[]).slice(0,3)})})]}),B(`section`,{"aria-labelledby":`dashboard-system-title`,children:[B(Zh,{description:`메모리, 시스템 부하와 장치 정보를 빠르게 점검합니다.`,eyebrow:`System`,id:`dashboard-system-title`,title:`시스템 상태`}),B(`div`,{class:`grid min-w-0 gap-4 xl:grid-cols-[minmax(0,1.45fr)_minmax(20rem,0.75fr)]`,children:[B(`article`,{class:`min-w-0 rounded-2xl border border-slate-200 bg-white p-5 shadow-sm shadow-slate-900/5 sm:p-6`,children:[B(`div`,{class:`flex flex-wrap items-start justify-between gap-4`,children:[B(`div`,{children:[B(`p`,{class:`m-0 text-xs font-extrabold uppercase tracking-[0.16em] text-slate-500`,children:`Runtime`}),B(`h3`,{class:`mt-2 mb-0 text-xl font-black text-slate-950`,children:`리소스 사용량`})]}),B(`span`,{class:`inline-flex items-center gap-2 rounded-full px-3 py-1.5 text-xs font-black ring-1 ring-inset ${j>=90?`bg-amber-50 text-amber-800 ring-amber-200`:`bg-emerald-50 text-emerald-700 ring-emerald-200`}`,children:[B(`span`,{class:`size-2 rounded-full ${j>=90?`bg-amber-500`:`bg-emerald-500`}`}),j>=90?`메모리 확인`:`정상 실행`]})]}),B(`div`,{class:`mt-5 grid gap-3 sm:grid-cols-3`,children:[B(`div`,{class:`rounded-xl border border-slate-200 bg-slate-50 p-4`,children:[B(`div`,{class:`flex items-center gap-2 text-slate-500`,children:[B(Ht,{class:`size-4`}),B(`span`,{class:`text-xs font-extrabold`,children:`메모리`})]}),B(`p`,{class:`mt-2 mb-0 text-xl font-black text-slate-950`,children:[j,`%`]}),B(`p`,{class:`mt-1 mb-0 text-xs font-semibold text-slate-500`,children:[k?Ma(k.used):`-`,` /`,` `,Ma(r.runtime.memory.total)]}),B(`div`,{"aria-label":`메모리 사용률 ${j}%`,class:`mt-3 h-1.5 overflow-hidden rounded-full bg-slate-200`,role:`progressbar`,"aria-valuemin":0,"aria-valuemax":100,"aria-valuenow":j,children:B(`div`,{class:`h-full rounded-full transition-[width] duration-300 ${j>=90?`bg-amber-500`:`bg-teal-600`}`,style:{width:`${Math.min(100,j)}%`}})})]}),B(`div`,{class:`rounded-xl border border-slate-200 bg-slate-50 p-4`,children:[B(`div`,{class:`flex items-center gap-2 text-slate-500`,children:[B(jt,{class:`size-4`}),B(`span`,{class:`text-xs font-extrabold`,children:`시스템 부하`})]}),B(`p`,{class:`mt-2 mb-0 text-xl font-black text-slate-950`,children:Na(r.runtime.load[0])}),B(`p`,{class:`mt-1 mb-0 text-xs font-semibold text-slate-500`,children:[`5분 `,Na(r.runtime.load[1]),` · 15분`,` `,Na(r.runtime.load[2])]})]}),B(`div`,{class:`rounded-xl border border-slate-200 bg-slate-50 p-4`,children:[B(`div`,{class:`flex items-center gap-2 text-slate-500`,children:[B(Vt,{class:`size-4`}),B(`span`,{class:`text-xs font-extrabold`,children:`실행 시간`})]}),B(`p`,{class:`mt-2 mb-0 text-xl font-black text-slate-950`,children:ja(r.runtime.uptime)}),B(`p`,{class:`mt-1 mb-0 text-xs font-semibold text-slate-500`,children:[`부팅 `,Pa(r.runtime.localtime,r.runtime.uptime)]})]})]}),B(ag,{data:d,error:f,loading:p,nowTimestamp:A})]}),B(`article`,{class:`min-w-0 rounded-2xl border border-slate-200 bg-white p-5 shadow-sm shadow-slate-900/5 sm:p-6`,children:[B(`div`,{class:`flex items-start justify-between gap-4`,children:[B(`div`,{children:[B(`p`,{class:`m-0 text-xs font-extrabold uppercase tracking-[0.16em] text-slate-500`,children:`Device`}),B(`h3`,{class:`mt-2 mb-0 text-xl font-black text-slate-950`,children:`장치 정보`})]}),B(`span`,{class:`grid size-10 shrink-0 place-items-center rounded-xl bg-teal-50 text-teal-700`,children:B(jt,{class:`size-5`})})]}),B(`dl`,{class:`mt-4 mb-0`,children:[B(rg,{label:`모델`,value:r.device.model}),B(rg,{label:`호스트 이름`,value:r.device.hostname}),B(rg,{label:`펌웨어`,value:B(`span`,{title:ye?c?.current.releaseVersion?`SmartSafeHub 펌웨어 ${c.current.releaseVersion}`:`SmartSafeHub 커스텀 펌웨어`:l||void 0,children:be})}),B(rg,{label:Se,value:xe}),B(rg,{label:`커널`,value:r.software.kernel}),B(rg,{label:`WAN IP`,value:r.network.ipv4Address||`할당되지 않음`})]})]})]})]})]})}function cg(e,t){for(var n in t)e[n]=t[n];return e}function lg(e,t){for(var n in e)if(n!==`__source`&&!(n in t))return!0;for(var r in t)if(r!==`__source`&&e[r]!==t[r])return!0;return!1}function ug(e,t){this.props=e,this.context=t}(ug.prototype=new C).isPureReactComponent=!0,ug.prototype.shouldComponentUpdate=function(e,t){return lg(this.props,e)||lg(this.state,t)};var dg=t.__b;t.__b=function(e){e.type&&e.type.__f&&e.ref&&(e.props.ref=e.ref,e.ref=null),dg&&dg(e)},typeof Symbol<`u`&&Symbol.for;var fg=t.__e;t.__e=function(e,t,n,r){if(e.then){for(var i,a=t;a=a.__;)if((i=a.__c)&&i.__c)return t.__e??(t.__e=n.__e,t.__k=n.__k||[]),i.__c(e,t)}fg(e,t,n,r)};var pg=t.unmount;function mg(e,t,n){return e&&(e.__c&&e.__c.__H&&(e.__c.__H.__.forEach(function(e){typeof e.__c==`function`&&e.__c()}),e.__c.__H=null),(e=cg({},e)).__c!=null&&(e.__c.__P===n&&(e.__c.__P=t),e.__c.__e=!0,e.__c=null),e.__k=e.__k&&e.__k.map(function(e){return mg(e,t,n)})),e}function hg(e,t,n){return e&&n&&(e.__v=null,e.__k=e.__k&&e.__k.map(function(e){return hg(e,t,n)}),e.__c&&e.__c.__P===t&&(e.__e&&n.appendChild(e.__e),e.__c.__e=!0,e.__c.__P=n)),e}function gg(){this.__u=0,this.o=null,this.__b=null}function _g(e){var t=e.__&&e.__.__c;return t&&t.__a&&t.__a(e)}function vg(){this.i=null,this.l=null}t.unmount=function(e){var t=e.__c;t&&(t.__z=!0),t&&t.__R&&t.__R(),t&&32&e.__u&&(e.type=null),pg&&pg(e)},(gg.prototype=new C).__c=function(e,t){var n=t.__c,r=this;r.o??(r.o=[]),r.o.push(n);var i=_g(r.__v),a=!1,o=function(){a||r.__z||(a=!0,n.__R=null,i?i(c):c())};n.__R=o;var s=n.__P;n.__P=null;var c=function(){if(!--r.__u){if(r.state.__a){var e=r.state.__a;r.__v.__k[0]=hg(e,e.__c.__P,e.__c.__O)}var t;for(r.setState({__a:r.__b=null});t=r.o.pop();)t.__P=s,t.forceUpdate()}};r.__u++||32&t.__u||r.setState({__a:r.__b=r.__v.__k[0]}),e.then(o,o)},gg.prototype.componentWillUnmount=function(){this.o=[]},gg.prototype.render=function(e,t){if(this.__b){if(this.__v.__k){var n=document.createElement(`div`),r=this.__v.__k[0].__c;this.__v.__k[0]=mg(this.__b,n,r.__O=r.__P)}this.__b=null}var i=t.__a&&b(S,null,e.fallback);return i&&(i.__u&=-33),[b(S,null,t.__a?null:e.children),i]};var yg=function(e,t,n){if(++n[1]===n[0]&&e.l.delete(t),e.props.revealOrder&&(e.props.revealOrder[0]!==`t`||!e.l.size))for(n=e.i;n;){for(;n.length>3;)n.pop()();if(n[1]>>1,1),t.h.removeChild(e)}}}fe(b(bg,{context:t.context},e.__v),t.v)}function Sg(e,t){var n=b(xg,{__v:e,h:t});return n.containerInfo=t,n}(vg.prototype=new C).__a=function(e){var t=this,n=_g(t.__v),r=t.l.get(e);return r[0]++,function(i){var a=function(){t.props.revealOrder?(r.push(i),yg(t,e,r)):i()};n?n(a):a()}},vg.prototype.render=function(e){this.i=null,this.l=new Map;var t=j(e.children);e.revealOrder&&e.revealOrder[0]===`b`&&t.reverse();for(var n=t.length;n--;)this.l.set(t[n],this.i=[1,0,this.i]);return e.children},vg.prototype.componentDidUpdate=vg.prototype.componentDidMount=function(){var e=this;this.l.forEach(function(t,n){yg(e,n,t)})};var Cg=typeof Symbol<`u`&&Symbol.for&&Symbol.for(`react.element`)||60103,wg=/^(?:accent|alignment|arabic|baseline|cap|clip(?!PathU)|color|dominant|fill|flood|font|glyph(?!R)|horiz|image(!S)|letter|lighting|marker(?!H|W|U)|overline|paint|pointer|shape|stop|strikethrough|stroke|text(?!L)|transform|underline|unicode|units|v|vector|vert|word|writing|x(?!C))[A-Z]/,Tg=/^on(Ani|Tra|Tou|BeforeInp|Compo)/,Eg=/[A-Z0-9]/g,Dg=typeof document<`u`,Og=function(e){return(typeof Symbol<`u`&&typeof Symbol()==`symbol`?/fil|che|rad/:/fil|che|ra/).test(e)};C.prototype.isReactComponent=!0,[`componentWillMount`,`componentWillReceiveProps`,`componentWillUpdate`].forEach(function(e){Object.defineProperty(C.prototype,e,{configurable:!0,get:function(){return this[`UNSAFE_`+e]},set:function(t){Object.defineProperty(this,e,{configurable:!0,writable:!0,value:t})}})});var kg=t.event;t.event=function(e){return kg&&(e=kg(e)),e.persist=function(){},e.isPropagationStopped=function(){return this.cancelBubble},e.isDefaultPrevented=function(){return this.defaultPrevented},e.nativeEvent=e};var Ag={configurable:!0,get:function(){return this.class}},jg=t.vnode;t.vnode=function(e){typeof e.type==`string`&&function(e){var t=e.props,n=e.type,r={},i=n.indexOf(`-`)==-1;for(var a in t){var o=t[a];if(!(a===`value`&&`defaultValue`in t&&o==null||Dg&&a===`children`&&n===`noscript`||a===`class`||a===`className`)){var s=a.toLowerCase();a===`defaultValue`&&`value`in t&&t.value==null?a=`value`:a===`download`&&!0===o?o=``:s===`translate`&&o===`no`?o=!1:s[0]===`o`&&s[1]===`n`?s===`ondoubleclick`?a=`ondblclick`:s!==`onchange`||n!==`input`&&n!==`textarea`||Og(t.type)?s===`onfocus`?a=`onfocusin`:s===`onblur`?a=`onfocusout`:Tg.test(a)&&(a=s):s=a=`oninput`:i&&wg.test(a)?a=a.replace(Eg,`-$&`).toLowerCase():o===null&&(o=void 0),s===`oninput`&&r[a=s]&&(a=`oninputCapture`),r[a]=o}}n==`select`&&(r.multiple&&Array.isArray(r.value)&&(r.value=j(t.children).forEach(function(e){e.props.selected=r.value.indexOf(e.props.value)!=-1})),r.defaultValue!=null&&(r.value=j(t.children).forEach(function(e){e.props.selected=r.multiple?r.defaultValue.indexOf(e.props.value)!=-1:r.defaultValue==e.props.value}))),t.class&&!t.className?(r.class=t.class,Object.defineProperty(r,"className",Ag)):t.className&&(r.class=r.className=t.className),e.props=r}(e),e.$$typeof=Cg,jg&&jg(e)};var Mg=t.__r;t.__r=function(e){Mg&&Mg(e),e.__c};var Ng=t.diffed;t.diffed=function(e){Ng&&Ng(e);var t=e.props,n=e.__e;n!=null&&e.type===`textarea`&&`value`in t&&t.value!==n.value&&(n.value=t.value==null?``:t.value)};var Pg=8,Fg=256,Ig=8;function Lg(e){return e.findIndex(e=>!e.disabled)}function Rg(e){for(let t=e.length-1;t>=0;--t)if(!e[t]?.disabled)return t;return-1}function zg(e,t,n){if(e.length===0)return-1;let r=t;for(let t=0;te.value===t&&!e.disabled);return n>=0?n:Lg(e)}function Vg({ariaLabel:e,className:t=``,disabled:n=!1,id:r,onChange:i,options:a,value:o,variant:s=`default`}){let c=et(),l=r??`ssh-custom-select-${c}`,u=`${l}-menu`,d=F(null),f=F(null),p=F(null),m=F([]),[h,g]=N(!1),[_,v]=N(()=>Bg(a,o)),[y,b]=N(`bottom`),[x,S]=N(Fg),[C,w]=N({}),[T,E]=N(null),D=$e(()=>a.find(e=>e.value===o)??a[0]??null,[a,o]),O=()=>{let e=f.current;if(!e)return;let t=e.getBoundingClientRect(),n=Math.min(Fg,Math.max(44,a.length*42+12)),r=window.innerHeight-t.bottom-Ig,i=t.top-Ig,o=rr?`top`:`bottom`,s=Math.min(t.width,Math.max(0,window.innerWidth-16)),c=Math.max(Ig,Math.min(t.left,window.innerWidth-s-Ig)),l=o===`bottom`?r:i;b(o),S(Math.max(44,Math.min(Fg,Math.floor(l)))),w({left:`${c}px`,width:`${s}px`,...o===`bottom`?{top:`${t.bottom+Pg}px`}:{bottom:`${window.innerHeight-t.top+Pg}px`}})},k=(e=!1)=>{g(!1),e&&window.requestAnimationFrame(()=>f.current?.focus())},A=e=>{e<0||(v(e),window.requestAnimationFrame(()=>m.current[e]?.focus()))},ee=e=>{let t=a[e];!t||t.disabled||(i(t.value),g(!1),window.requestAnimationFrame(()=>f.current?.focus()))},j=e=>{n||a.length===0||(O(),g(!0),A(e??Bg(a,o)))};P(()=>{let e=d.current?.closest(`.ssh-app`);if(e){E(e);return}let t=d.current?.getRootNode();t instanceof ShadowRoot?E(t):typeof document<`u`&&E(document.body)},[]),P(()=>{v(Bg(a,o)),m.current=m.current.slice(0,a.length)},[a,o]),P(()=>{if(!h)return;O();let e=e=>{let t=e.composedPath();d.current&&t.includes(d.current)||p.current&&t.includes(p.current)||k()},t=e=>{e.key===`Escape`&&(e.preventDefault(),k(!0))},n=()=>O();return document.addEventListener(`pointerdown`,e),document.addEventListener(`keydown`,t),window.addEventListener(`resize`,n),window.addEventListener(`scroll`,n,!0),()=>{document.removeEventListener(`pointerdown`,e),document.removeEventListener(`keydown`,t),window.removeEventListener(`resize`,n),window.removeEventListener(`scroll`,n,!0)}},[h,a.length]),P(()=>{n&&h&&k()},[n,h]);let te=s===`emphasized`?`min-h-11 border-2 border-slate-300 bg-slate-50 px-4 py-2.5 text-sm font-semibold text-slate-950 shadow-inner focus:border-teal-500 focus:bg-white focus:ring-4 focus:ring-teal-100`:`min-h-11 border border-slate-300 bg-slate-50 px-3 py-2.5 text-sm font-bold text-slate-900 focus:border-teal-500 focus:ring-2 focus:ring-teal-100`,ne=h?B(`div`,{"aria-label":`${e} 목록`,class:`ssh-custom-select-menu fixed z-[1000] overflow-hidden rounded-xl border border-slate-200 bg-white p-1.5 shadow-xl shadow-slate-950/10`,id:u,ref:p,role:`listbox`,style:C,children:B(`div`,{class:`overflow-y-auto overscroll-contain`,style:{maxHeight:`${x}px`},children:a.map((e,t)=>{let n=e.value===o;return B(`button`,{"aria-selected":n,class:`flex min-h-10 w-full items-center justify-between gap-3 rounded-lg px-3 py-2.5 text-left text-sm font-bold transition ${n?`bg-teal-50 text-teal-800`:`text-slate-700 hover:bg-slate-50`} ${e.disabled?`cursor-not-allowed opacity-50`:``}`,disabled:e.disabled,onClick:()=>ee(t),onFocus:()=>v(t),onKeyDown:e=>{switch(e.key){case`ArrowDown`:e.preventDefault(),A(zg(a,t,1));break;case`ArrowUp`:e.preventDefault(),A(zg(a,t,-1));break;case`Home`:e.preventDefault(),A(Lg(a));break;case`End`:e.preventDefault(),A(Rg(a));break;case`Enter`:case` `:e.preventDefault(),ee(t);break;case`Escape`:e.preventDefault(),k(!0);break;case`Tab`:g(!1)}},ref:e=>{m.current[t]=e},role:`option`,tabIndex:_===t?0:-1,type:`button`,children:[B(`span`,{class:`min-w-0 truncate`,children:e.label}),n?B(`span`,{"aria-hidden":`true`,class:`size-2 shrink-0 rounded-full bg-teal-500`}):null]},e.value)})})}):null;return B(`div`,{class:`relative ${t}`,ref:d,children:[B(`button`,{"aria-controls":u,"aria-expanded":h,"aria-haspopup":`listbox`,"aria-label":e,class:`ssh-custom-select-trigger flex w-full cursor-pointer items-center justify-between gap-3 rounded-xl text-left outline-none transition disabled:cursor-not-allowed disabled:bg-slate-100 disabled:text-slate-400 disabled:opacity-60 ${te}`,disabled:n,id:l,onClick:()=>{if(h){k();return}O(),g(!0)},onKeyDown:e=>{switch(e.key){case`ArrowDown`:e.preventDefault(),j(h?zg(a,_,1):Bg(a,o));break;case`ArrowUp`:e.preventDefault(),j(h?zg(a,_,-1):Bg(a,o));break;case`Home`:e.preventDefault(),j(Lg(a));break;case`End`:e.preventDefault(),j(Rg(a));break;case`Enter`:case` `:e.preventDefault(),h?k():j();break;case`Escape`:h&&(e.preventDefault(),k())}},ref:f,type:`button`,children:[B(`span`,{class:`min-w-0 truncate`,children:D?.label??`선택하세요`}),B(rn,{"aria-hidden":`true`,class:`size-4 shrink-0 text-slate-400 transition-transform ${h?`rotate-180`:``}`})]}),ne&&T?Sg(ne,T):null,B(`span`,{class:`sr-only`,"aria-live":`polite`,children:y===`top`?`선택 목록이 위쪽에 열렸습니다.`:``})]})}var Hg=[{value:`skb`,label:`SK Broadband`},{value:`lgu`,label:`LG U+`}];function Ug(e){return e===`lgu`?`LG U+`:`SK Broadband`}function Wg({active:e,label:t,value:n}){return B(`div`,{class:`rounded-xl border border-slate-200 bg-white p-4`,children:[B(`div`,{class:`flex items-center justify-between gap-3`,children:[B(`p`,{class:`m-0 text-xs font-extrabold text-slate-500`,children:t}),B(`span`,{class:`size-2.5 shrink-0 rounded-full ${e?`bg-emerald-500`:`bg-slate-300`}`,"aria-hidden":`true`})]}),B(`p`,{class:`mt-2 mb-0 text-sm font-black text-slate-950`,children:n})]})}function Gg({data:e,error:t,feedback:n,loading:r,onDismissFeedback:i,onRetry:a,onSave:o,saving:s}){let[c,l]=N(!1),[u,d]=N(`skb`);if(P(()=>{e&&(l(e.enabled),d(e.provider))},[e]),r&&!e)return B(io,{});if(t&&!e)return B(ao,{message:t,onRetry:a});if(!e)return B(ao,{message:`IPTV 설정을 확인할 수 없습니다.`,onRetry:a});let f=c!==e.enabled||u!==e.provider,p=!e.enabled||e.running&&e.igmpSnooping;return B(`div`,{class:`space-y-5`,children:[B(`section`,{class:`rounded-2xl border border-amber-200 bg-amber-50 p-5 sm:p-6`,children:B(`div`,{class:`flex items-start gap-4`,children:[B(`span`,{class:`grid size-11 shrink-0 place-items-center rounded-xl bg-amber-100 text-amber-800`,children:B(U,{class:`size-5`})}),B(`div`,{class:`min-w-0 flex-1`,children:[B(`div`,{class:`flex flex-wrap items-center gap-2`,children:[B(`h2`,{class:`m-0 text-base font-black text-amber-950`,children:`IPTV 실험 기능`}),B(`span`,{class:`rounded-full border border-amber-300 bg-amber-100 px-2 py-0.5 text-[10px] font-black uppercase tracking-[0.12em] text-amber-800`,children:`Beta`})]}),B(`p`,{class:`mt-2 mb-0 text-sm leading-6 text-amber-900/80`,children:`현재 SK Broadband와 LG U+를 지원하며 두 통신사에는 동일한 멀티캐스트 IPTV 프로파일을 적용합니다. KT IPTV는 별도 네트워크 방식이 필요해 아직 지원하지 않습니다.`})]})]})}),n?B(`section`,{"aria-live":`polite`,class:`rounded-2xl border p-4 ${n.kind===`success`?`border-emerald-200 bg-emerald-50 text-emerald-900`:`border-red-200 bg-red-50 text-red-900`}`,children:B(`div`,{class:`flex items-start justify-between gap-3`,children:[B(`p`,{class:`m-0 text-sm font-bold leading-6`,children:n.message}),B(`button`,{class:`shrink-0 text-xs font-extrabold underline underline-offset-2`,onClick:i,type:`button`,children:`닫기`})]})}):null,B(`section`,{class:`rounded-2xl border border-slate-200 bg-white p-5 shadow-sm shadow-slate-900/5 sm:p-6`,children:[B(`div`,{class:`flex min-w-0 items-start gap-3`,children:[B(`span`,{class:`grid size-11 shrink-0 place-items-center rounded-xl bg-teal-50 text-teal-700`,children:B(Bt,{class:`size-5`})}),B(`div`,{class:`min-w-0 flex-1`,children:[B(`div`,{class:`flex min-w-0 flex-wrap items-center justify-between gap-2`,children:[B(`h2`,{class:`m-0 text-lg font-black text-slate-950`,children:`IPTV`}),B(`div`,{class:`flex shrink-0 items-center gap-2`,children:[f?B(`span`,{"aria-live":`polite`,class:`inline-flex shrink-0 items-center gap-1.5 rounded-full border border-amber-200 bg-amber-50 px-2.5 py-1 text-xs font-extrabold text-amber-800`,role:`status`,children:[B(U,{"aria-hidden":`true`,class:`size-3.5 shrink-0`}),`저장되지 않음`]}):null,B(`button`,{"aria-checked":c,"aria-label":`IPTV 사용`,class:`ssh-switch-control relative inline-flex shrink-0 rounded-full border-0 transition focus:outline-none focus-visible:ring-4 focus-visible:ring-teal-100 ${c?`bg-teal-700`:`bg-slate-300`} disabled:cursor-not-allowed disabled:opacity-60`,disabled:s||!e.available,onClick:()=>l(e=>!e),role:`switch`,type:`button`,children:B(`span`,{"aria-hidden":`true`,class:`ssh-switch-thumb absolute top-1 shadow-sm transition-[left] ${c?`left-6`:`left-1`}`})})]})]}),B(`p`,{class:`mt-1 mb-0 text-sm leading-6 text-slate-600`,children:`WAN의 멀티캐스트 방송을 LAN 셋톱박스로 전달합니다.`})]})]}),B(`div`,{class:`mt-6 grid gap-5 lg:grid-cols-[minmax(0,1fr)_minmax(0,1fr)]`,children:[B(`div`,{class:`rounded-xl border border-slate-200 bg-slate-50 p-4`,children:[B(`div`,{class:`flex flex-wrap items-start justify-between gap-2`,children:[B(`div`,{children:[B(`label`,{class:`block text-xs font-extrabold text-slate-600`,htmlFor:`iptv-provider`,children:`통신사`}),B(`p`,{class:`mt-1 mb-0 text-xs leading-5 text-slate-500`,children:`IPTV를 제공하는 회선 사업자를 선택하세요.`})]}),B(`span`,{class:`rounded-full border border-teal-200 bg-teal-50 px-2.5 py-1 text-[10px] font-black text-teal-700`,children:`멀티캐스트 방식`})]}),B(Vg,{ariaLabel:`IPTV 통신사`,className:`mt-3`,disabled:s||!c,id:`iptv-provider`,onChange:e=>d(e),options:Hg,value:u}),B(`div`,{class:`mt-3 flex items-start gap-2 rounded-lg border border-slate-200 bg-white p-3`,children:[B(Xt,{"aria-hidden":`true`,class:`mt-0.5 size-4 shrink-0 text-teal-700`}),B(`p`,{class:`m-0 text-xs leading-5 text-slate-600`,children:[Ug(u),`에는 현재 SK Broadband/LG U+ 공통 IGMP Proxy 프로파일을 적용합니다. KT는 추후 별도 IPTV 프로파일로 지원할 예정입니다.`]})]})]}),B(`div`,{class:`rounded-xl border border-slate-200 bg-slate-50 p-4`,children:[B(`div`,{class:`flex items-center justify-between gap-3`,children:[B(`p`,{class:`m-0 text-xs font-extrabold text-slate-500`,children:`현재 지원 프로파일`}),B(`span`,{class:`text-xs font-extrabold text-slate-500`,children:`SKB · LG U+`})]}),B(`p`,{class:`mt-2 mb-0 text-sm font-black text-slate-950`,children:`WAN → IGMP Proxy → LAN`}),B(`p`,{class:`mt-1 mb-0 text-xs leading-5 text-slate-600`,children:`WAN을 upstream, LAN을 downstream으로 사용하고 LAN bridge에는 IGMP snooping을 함께 활성화해 필요하지 않은 포트와 Wi-Fi로 멀티캐스트가 불필요하게 퍼지는 것을 줄입니다.`})]})]}),e.available?null:B(`div`,{class:`mt-5 rounded-xl border border-red-200 bg-red-50 p-4 text-sm font-bold leading-6 text-red-900`,children:`IGMP Proxy 패키지를 찾지 못했습니다. 현재 펌웨어에 igmpproxy 패키지가 포함되어 있는지 확인해 주세요.`}),B(`div`,{class:`mt-6 flex flex-wrap items-center justify-between gap-3 border-t border-slate-200 pt-5`,children:[B(`p`,{class:`m-0 text-xs leading-5 text-slate-500`,children:`설정을 적용하면 네트워크 서비스가 잠시 다시 로드될 수 있습니다.`}),B(`button`,{class:`inline-flex min-h-11 items-center justify-center rounded-xl border-0 bg-teal-700 px-5 py-2.5 text-sm font-black text-white shadow-sm transition hover:bg-teal-800 focus:outline-none focus-visible:ring-4 focus-visible:ring-teal-100 disabled:cursor-not-allowed disabled:opacity-50`,disabled:s||!e.available||!f&&!c,onClick:()=>void o({enabled:c,provider:u}),type:`button`,children:s?`적용 중…`:f?`변경사항 적용`:`설정 다시 적용`})]})]}),B(`section`,{class:`rounded-2xl border border-slate-200 bg-white p-5 shadow-sm shadow-slate-900/5 sm:p-6`,children:[B(`div`,{class:`flex items-center justify-between gap-3`,children:[B(`div`,{children:[B(`p`,{class:`m-0 text-xs font-black uppercase tracking-[0.14em] text-teal-700`,children:`Runtime`}),B(`h2`,{class:`mt-1 mb-0 text-lg font-black text-slate-950`,children:`IPTV 동작 상태`})]}),B(`span`,{class:`inline-flex items-center gap-1.5 rounded-full px-3 py-1 text-xs font-black ${p?`bg-emerald-100 text-emerald-800`:`bg-amber-100 text-amber-800`}`,children:[B(Xt,{class:`size-4`}),p?e.enabled?`정상`:`꺼짐`:`확인 필요`]})]}),f?B(`div`,{class:`mt-4 flex items-start gap-2 rounded-xl border border-amber-200 bg-amber-50 p-3 text-xs font-bold leading-5 text-amber-900`,children:[B(U,{"aria-hidden":`true`,class:`mt-0.5 size-4 shrink-0`}),`아래 동작 상태는 마지막으로 적용된 설정 기준입니다. 변경사항을 적용하면 새 설정으로 갱신됩니다.`]}):null,B(`div`,{class:`mt-5 grid gap-3 sm:grid-cols-2 lg:grid-cols-4`,children:[B(Wg,{active:e.enabled&&e.running,label:`IGMP Proxy`,value:e.enabled?e.running?`동작 중`:`중지됨`:`꺼짐`}),B(Wg,{active:e.enabled&&e.igmpSnooping,label:`IGMP Snooping`,value:e.igmpSnooping?`켜짐`:`꺼짐`}),B(Wg,{active:e.enabled,label:`Upstream`,value:e.upstreamNetwork.toUpperCase()}),B(Wg,{active:e.enabled,label:`Downstream`,value:e.lanBridge??e.downstreamNetwork.toUpperCase()})]})]})]})}function Kg(e){let t=e.split(`.`);return[t[0]??``,t[1]??``,t[2]??``,t[3]??``]}function qg(e){return e.replace(/\D/g,``).slice(0,3)}function Jg(e){return e.every(e=>e===``)?``:e.join(`.`)}function Yg({disabled:e=!1,label:t,value:n,onChange:r}){let i=Kg(n),a=(e,t)=>{let n=[...i];n[e]=qg(t),r(Jg(n))};return B(`div`,{class:`ssh-ipv4-segments mt-2 min-h-11`,"aria-label":`${t} 입력`,children:i.map((n,r)=>B(`div`,{class:`ssh-ipv4-segment`,children:[B(`input`,{"aria-label":`${t} ${r+1}번째 옥텟`,autocomplete:`off`,class:`min-h-11 w-full min-w-0 max-w-full rounded-xl border-2 border-slate-300 bg-slate-50 px-1.5 py-2.5 text-center text-sm font-semibold text-slate-950 shadow-inner outline-none transition focus:border-teal-500 focus:bg-white focus:ring-4 focus:ring-teal-100 disabled:cursor-not-allowed disabled:bg-slate-100 sm:px-2`,disabled:e,inputMode:`numeric`,maxLength:3,onInput:e=>a(r,e.currentTarget.value),pattern:`[0-9]*`,spellcheck:!1,value:n}),r{if(!/^(0|[1-9][0-9]{0,2})$/.test(e))return!1;let t=Number(e);return t>=0&&t<=255})}function $g(e){let t=Kg(e);return t.slice(0,3).some(e=>e===``||Number(e)>255)?null:t.slice(0,3).join(`.`)}function e_(e){return Kg(e)[3]}function t_(e){let t=$g(e.lan.address),n=e_(e.dhcp.start??``),r=e_(e.dhcp.end??``);return{ipAddress:e.lan.address,prefixLength:e.lan.prefixLength,dhcpEnabled:e.dhcp.enabled,dhcpStart:t&&n?`${t}.${n}`:e.dhcp.start??``,dhcpEnd:t&&r?`${t}.${r}`:e.dhcp.end??``,leaseTime:e.dhcp.leaseTime}}function n_({disabled:e,label:t,lanAddress:n,value:r,onChange:i}){let a=$g(n),o=a?.split(`.`)??[``,``,``],s=e_(r),c=e=>{let t=qg(e);i(a&&t!==``?`${a}.${t}`:t)};return B(`label`,{class:`block`,children:[B(`span`,{class:`text-sm font-extrabold text-slate-800`,children:t}),B(`div`,{class:`ssh-ipv4-segments mt-2 min-h-11`,"aria-label":`${t} 입력`,children:[o.map((e,t)=>B(`div`,{class:`ssh-ipv4-segment`,children:[B(`span`,{class:`grid min-h-11 w-full min-w-0 max-w-full place-items-center rounded-xl border border-slate-200 bg-slate-100 px-1.5 py-2.5 text-center text-sm font-bold text-slate-500 sm:px-2`,children:e||`—`}),B(`span`,{"aria-hidden":`true`,class:`ssh-ipv4-separator text-sm font-black text-slate-400`,children:`.`})]},t)),B(`div`,{class:`ssh-ipv4-segment`,children:B(`input`,{"aria-label":`${t} 마지막 옥텟`,autocomplete:`off`,class:`min-h-11 w-full min-w-0 max-w-full rounded-xl border-2 border-slate-300 bg-slate-50 px-1.5 py-2.5 text-center text-sm font-semibold text-slate-950 shadow-inner outline-none transition focus:border-teal-500 focus:bg-white focus:ring-4 focus:ring-teal-100 disabled:cursor-not-allowed disabled:bg-slate-100 sm:px-2`,disabled:e||!a,inputMode:`numeric`,maxLength:3,onInput:e=>c(e.currentTarget.value),pattern:`[0-9]*`,spellcheck:!1,value:s})})]}),B(`span`,{class:`mt-2 block text-xs text-slate-500`,children:`앞 3개 주소는 공유기 IP 주소와 동일하게 유지됩니다.`})]})}function r_(e){return`${window.location.protocol}//${e}${window.location.pathname}${window.location.search}${window.location.hash}`}function i_({feedback:e,onDismiss:t}){return B(`div`,{"aria-live":`polite`,class:`mb-5 rounded-2xl border px-4 py-4 text-sm ${e.kind===`success`?`border-emerald-200 bg-emerald-50 text-emerald-900`:e.kind===`warning`?`border-amber-200 bg-amber-50 text-amber-950`:`border-red-200 bg-red-50 text-red-900`}`,children:[B(`div`,{class:`flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between`,children:[B(`p`,{class:`m-0 font-bold leading-6`,children:e.message}),B(`button`,{class:`min-h-10 shrink-0 rounded-lg border border-current bg-transparent px-3 py-1.5 text-xs font-extrabold`,onClick:t,type:`button`,children:`닫기`})]}),e.newAddress?B(`a`,{class:`mt-3 inline-flex min-h-10 items-center rounded-lg border border-current px-3 py-2 font-extrabold underline underline-offset-2`,href:r_(e.newAddress),children:[`새 공유기 주소 `,e.newAddress,`로 연결`]}):null]})}function a_({data:e}){let t=e.conflict.detected;return B(`section`,{class:`grid gap-4 lg:grid-cols-3`,"aria-label":`내부 네트워크 상태`,children:[B(`article`,{class:`rounded-2xl border border-slate-200 bg-white p-5 shadow-sm shadow-slate-900/5`,children:[B(`span`,{class:`grid size-10 place-items-center rounded-xl bg-teal-50 text-teal-700`,children:B(jt,{class:`size-5`})}),B(`p`,{class:`mt-4 mb-0 text-xs font-extrabold uppercase tracking-[0.14em] text-slate-500`,children:`SmartSafeHub LAN`}),B(`p`,{class:`mt-2 mb-0 text-xl font-black text-slate-950`,children:e.lan.subnet}),B(`p`,{class:`mt-1 mb-0 text-sm font-semibold text-slate-600`,children:[`공유기 주소 `,e.lan.address]})]}),B(`article`,{class:`rounded-2xl border border-slate-200 bg-white p-5 shadow-sm shadow-slate-900/5`,children:[B(`span`,{class:`grid size-10 place-items-center rounded-xl bg-slate-100 text-slate-700`,children:B(zt,{class:`size-5`})}),B(`p`,{class:`mt-4 mb-0 text-xs font-extrabold uppercase tracking-[0.14em] text-slate-500`,children:`상위 네트워크`}),B(`p`,{class:`mt-2 mb-0 text-xl font-black text-slate-950`,children:e.wan.subnet??`확인 전`}),B(`p`,{class:`mt-1 mb-0 text-sm font-semibold text-slate-600`,children:e.wan.connected?`WAN ${e.wan.address??`주소 확인 중`}`:`WAN 연결 후 자동으로 확인합니다.`})]}),B(`article`,{class:`rounded-2xl border p-5 shadow-sm shadow-slate-900/5 ${t?`border-red-200 bg-red-50 text-red-950`:`border-emerald-200 bg-emerald-50 text-emerald-950`}`,children:[B(`span`,{class:`grid size-10 place-items-center rounded-xl ${t?`bg-red-100 text-red-700`:`bg-emerald-100 text-emerald-700`}`,children:B(t?U:Xt,{class:`size-5`})}),B(`p`,{class:`mt-4 mb-0 text-xs font-extrabold uppercase tracking-[0.14em] opacity-70`,children:`대역 충돌`}),B(`p`,{class:`mt-2 mb-0 text-lg font-black`,children:t?`주소 대역이 겹칩니다`:`충돌이 감지되지 않았습니다`}),B(`p`,{class:`mt-1 mb-0 text-sm font-semibold leading-6 opacity-80`,children:t?`상위 네트워크 ${e.conflict.wanSubnet??``}와 다른 LAN 대역이 필요합니다.`:e.wan.connected?`현재 WAN과 LAN이 서로 다른 IPv4 대역을 사용합니다.`:`WAN이 연결되면 상위 네트워크와의 충돌 여부를 확인합니다.`})]})]})}function o_({action:e,data:t,error:n,feedback:r,loading:i,onApplyRecommendation:a,onDismissFeedback:o,onRetry:s,onSave:c}){let[l,u]=N(``),[d,f]=N(24),[p,m]=N(!0),[h,g]=N(``),[_,v]=N(``),[y,b]=N(`12h`),[x,C]=N(!1),[w,T]=N(null),E=(e={})=>{if(!t)return!1;let n=t_(t);return(e.ipAddress??l).trim()!==n.ipAddress||(e.prefixLength??d)!==n.prefixLength||(e.dhcpEnabled??p)!==n.dhcpEnabled||(e.dhcpStart??h).trim()!==n.dhcpStart||(e.dhcpEnd??_).trim()!==n.dhcpEnd||(e.leaseTime??y)!==n.leaseTime},D=e=>{let t=$g(e);if(u(e),!t){C(E({ipAddress:e}));return}let n=e_(h),r=e_(_),i=n?`${t}.${n}`:``,a=r?`${t}.${r}`:``;g(i),v(a),C(E({ipAddress:e,dhcpStart:i,dhcpEnd:a}))},O=e=>{g(e),C(E({dhcpStart:e}))},k=e=>{v(e),C(E({dhcpEnd:e}))},A=e=>{f(e),C(E({prefixLength:e}))},ee=e=>{b(e),C(E({leaseTime:e}))},j=e=>{m(e),C(E({dhcpEnabled:e}))};P(()=>{if(!t||x)return;let e=t_(t);u(e.ipAddress),f(e.prefixLength),m(e.dhcpEnabled),g(e.dhcpStart),v(e.dhcpEnd),b(e.leaseTime),T(null)},[t,x]);let te=$e(()=>{let e=[...Xg];return e.includes(d)||(e.push(d),e.sort((e,t)=>e-t)),e},[d]),ne=$e(()=>{let e=[...Zg];return e.some(([e])=>e===y)||e.push([y,`현재 설정 (${y})`]),e},[y]);if(i)return B(io,{});if(n)return B(ao,{message:n,onRetry:s});if(!t)return null;let M=e!==null,re=async e=>{if(e.preventDefault(),!Qg(l)){T(`공유기 주소를 올바른 IPv4 형식으로 입력해 주세요.`);return}if(!Qg(h)||!Qg(_)){T(`DHCP 시작/종료 주소를 올바른 IPv4 형식으로 입력해 주세요.`);return}window.confirm(`내부 네트워크 설정을 적용하면 연결된 기기가 새 DHCP 정보를 받는 동안 잠시 연결이 끊길 수 있습니다. 계속하시겠습니까?`)&&(T(null),await c({ipAddress:l.trim(),prefixLength:d,dhcpEnabled:p,dhcpStart:h.trim(),dhcpEnd:_.trim(),leaseTime:y})&&C(!1))},ie=async()=>{t.recommendation&&window.confirm(`상위 네트워크와 겹치지 않는 ${t.recommendation.subnet} 대역으로 자동 변경합니다. 현재 연결이 잠시 끊길 수 있습니다. 계속하시겠습니까?`)&&(T(null),await a()&&C(!1))};return B(S,{children:[r?B(i_,{feedback:r,onDismiss:o}):null,B(a_,{data:t}),t.conflict.detected?B(`section`,{class:`mt-5 rounded-2xl border border-amber-200 bg-amber-50 p-5 text-amber-950 sm:p-6`,children:B(`div`,{class:`flex flex-col gap-4 lg:flex-row lg:items-center lg:justify-between`,children:[B(`div`,{class:`min-w-0`,children:[B(`p`,{class:`m-0 text-xs font-extrabold uppercase tracking-[0.16em] text-amber-700`,children:`자동 충돌 해결`}),B(`h2`,{class:`mt-2 mb-0 text-lg font-black`,children:`안전한 LAN 대역으로 변경할 수 있습니다`}),B(`p`,{class:`mt-2 mb-0 text-sm font-semibold leading-6 text-amber-900/80`,children:t.recommendation?`${t.recommendation.subnet} · DHCP ${t.recommendation.dhcpStart} ~ ${t.recommendation.dhcpEnd}`:`현재 활성 네트워크와 겹치지 않는 추천 대역을 찾지 못했습니다. 아래에서 직접 설정해 주세요.`})]}),t.recommendation?B(`button`,{class:`inline-flex min-h-11 shrink-0 items-center justify-center gap-2 rounded-xl border-0 bg-amber-700 px-5 py-2.5 text-sm font-extrabold text-white transition hover:bg-amber-800 focus:outline-none focus-visible:ring-4 focus-visible:ring-amber-200 disabled:cursor-wait disabled:opacity-60`,disabled:M,onClick:()=>void ie(),type:`button`,children:[B(Xt,{class:`size-5 ${e===`auto`?`animate-pulse`:``}`}),e===`auto`?`변경 중`:`추천 대역으로 자동 변경`]}):null]})}):null,B(`form`,{class:`mt-5 rounded-2xl border border-slate-200 bg-white p-5 shadow-sm shadow-slate-900/5 sm:p-6`,onSubmit:e=>void re(e),children:[B(`div`,{class:`flex flex-col gap-4 sm:flex-row sm:items-start sm:justify-between`,children:[B(`div`,{class:`flex min-w-0 items-start gap-3`,children:[B(`span`,{class:`grid size-11 shrink-0 place-items-center rounded-xl bg-teal-50 text-teal-700`,children:B(Rt,{class:`size-6`})}),B(`div`,{class:`min-w-0`,children:[B(`p`,{class:`m-0 text-xs font-extrabold uppercase tracking-[0.16em] text-slate-500`,children:`내부 네트워크`}),B(`h2`,{class:`mt-2 mb-0 text-xl font-black text-slate-950`,children:`LAN 및 DHCP 설정`}),B(`p`,{class:`mt-2 mb-0 text-sm font-semibold leading-6 text-slate-600`,children:`상위 공유기와 다른 주소 대역을 사용해야 안정적으로 라우팅할 수 있습니다.`})]})]}),x?B(`span`,{"aria-live":`polite`,class:`inline-flex shrink-0 self-start items-center gap-1.5 rounded-full border border-amber-200 bg-amber-50 px-2.5 py-1 text-xs font-extrabold text-amber-800`,role:`status`,children:[B(U,{"aria-hidden":`true`,class:`size-3.5 shrink-0`}),`저장되지 않음`]}):null]}),B(`div`,{class:`mt-6 grid gap-5 lg:grid-cols-2`,children:[B(`div`,{class:`block`,children:[B(`span`,{class:`text-sm font-extrabold text-slate-800`,children:`공유기 IP 주소`}),B(Yg,{disabled:M,label:`공유기 IP 주소`,onChange:D,value:l})]}),B(`div`,{class:`block`,children:[B(`span`,{class:`text-sm font-extrabold text-slate-800`,children:`현재 LAN 대역`}),B(`div`,{class:`mt-2 min-h-11 rounded-xl border border-slate-200 bg-slate-50 px-4 py-3 text-sm font-bold text-slate-700`,children:t.lan.subnet}),B(`span`,{class:`mt-2 block text-xs text-slate-500`,children:`서브넷 마스크는 아래 고급 설정에서 변경할 수 있습니다.`})]}),B(n_,{disabled:M,label:`DHCP 시작 주소`,lanAddress:l,onChange:O,value:h}),B(n_,{disabled:M,label:`DHCP 종료 주소`,lanAddress:l,onChange:k,value:_})]}),B(`details`,{class:`mt-6 rounded-xl border border-slate-200 bg-slate-50 p-4`,children:[B(`summary`,{class:`cursor-pointer text-sm font-black text-slate-900`,children:`고급 DHCP 설정`}),B(`div`,{class:`mt-5 grid gap-5 lg:grid-cols-2`,children:[B(`div`,{class:`block`,children:[B(`span`,{class:`text-sm font-extrabold text-slate-800`,children:`서브넷 마스크`}),B(Vg,{ariaLabel:`서브넷 마스크`,className:`mt-2`,disabled:M,id:`lan-prefix-length`,onChange:e=>A(Number(e)),options:te.map(e=>({value:String(e),label:`/${e} · ${e===t.lan.prefixLength?t.lan.netmask:`CIDR /${e}`}`})),value:String(d),variant:`emphasized`}),B(`span`,{class:`mt-2 block text-xs text-slate-500`,children:`일반 가정용 네트워크는 /24 사용을 권장합니다.`})]}),B(`div`,{class:`block`,children:[B(`span`,{class:`text-sm font-extrabold text-slate-800`,children:`DHCP 임대 시간`}),B(Vg,{ariaLabel:`DHCP 임대 시간`,className:`mt-2`,disabled:M,id:`lan-dhcp-lease-time`,onChange:ee,options:ne.map(([e,t])=>({value:e,label:t})),value:y,variant:`emphasized`})]}),B(`label`,{class:`inline-flex min-h-11 items-center gap-3 text-sm font-extrabold text-slate-800 lg:col-span-2`,children:[B(`input`,{checked:p,class:`size-5 accent-teal-700`,disabled:M,onChange:e=>j(e.currentTarget.checked),type:`checkbox`}),`SmartSafeHub DHCP 서버 사용`]}),B(`p`,{class:`m-0 text-xs font-semibold leading-5 text-slate-500 lg:col-span-2`,children:`DHCP를 끄면 SmartSafeHub에 연결되는 장치에 IP 주소를 자동으로 할당하지 않습니다. 별도의 DHCP 서버를 사용하는 고급 구성에서만 비활성화하세요.`})]})]}),w?B(`p`,{class:`mt-5 mb-0 rounded-xl bg-red-50 px-4 py-3 text-sm font-bold text-red-800`,children:w}):null,B(`div`,{class:`mt-6 flex flex-col gap-3 border-t border-slate-200 pt-5 sm:flex-row sm:items-center sm:justify-between`,children:[B(`p`,{class:`m-0 text-xs font-semibold leading-5 text-slate-500`,children:`주소가 바뀌면 현재 관리 페이지 연결이 종료되며 새 IP를 받아 다시 접속해야 합니다.`}),B(`button`,{class:`inline-flex min-h-11 w-full shrink-0 items-center justify-center gap-2 rounded-xl border-0 bg-teal-700 px-5 py-2.5 text-sm font-extrabold text-white shadow-sm transition hover:bg-teal-800 focus:outline-none focus-visible:ring-4 focus-visible:ring-teal-200 disabled:cursor-wait disabled:opacity-60 sm:w-auto`,disabled:M||!x,type:`submit`,children:[B(Xt,{class:`size-5 ${e===`saving`?`animate-pulse`:``}`}),e===`saving`?`저장 중`:`설정 저장`]})]})]})]})}var s_=[`dhcp`,`pppoe`,`static`],c_=`1.1.1.1`,l_=Array.from({length:33},(e,t)=>t);function u_(e){return s_.includes(e)}function d_(e){switch(e){case`dhcp`:return`자동 IP (DHCP)`;case`pppoe`:return`PPPoE`;case`static`:return`고정 IPv4`;default:return e?e.toUpperCase():`확인 전`}}function f_(e){return{protocol:e.configuration.protocol,pppoeUsername:e.configuration.pppoe.username,pppoePassword:``,staticAddress:e.configuration.static.address??``,staticPrefixLength:e.configuration.static.prefixLength??24,staticGateway:e.configuration.static.gateway??``,dnsPrimary:e.configuration.static.dns[0]??``,dnsSecondary:e.configuration.static.dns[1]??``}}function p_(e){return e.trim()}function m_(e,t){let n=f_(t);return e.protocol===n.protocol?e.protocol===`dhcp`||!u_(e.protocol)?!1:e.protocol===`pppoe`?p_(e.pppoeUsername)!==n.pppoeUsername||e.pppoePassword.length>0:p_(e.staticAddress)!==n.staticAddress||e.staticPrefixLength!==n.staticPrefixLength||p_(e.staticGateway)!==n.staticGateway||p_(e.dnsPrimary)!==n.dnsPrimary||p_(e.dnsSecondary)!==n.dnsSecondary:!0}function h_(e){let t=e.trim().split(`.`);return t.length===4&&t.every(e=>{if(!/^(0|[1-9][0-9]{0,2})$/.test(e))return!1;let t=Number(e);return t>=0&&t<=255})}function g_(e){let t=e;return Array.from({length:4},()=>{if(t>=8)return t-=8,255;if(t<=0)return 0;let e=256-2**(8-t);return t=0,e}).join(`.`)}function __(e){if(!Number.isFinite(e)||e<=0)return`연결 시간 확인 전`;let t=Math.floor(e/86400),n=Math.floor(e%86400/3600),r=Math.floor(e%3600/60);return t>0?`${t}일 ${n}시간 연결됨`:n>0?`${n}시간 ${r}분 연결됨`:`${Math.max(1,r)}분 연결됨`}function v_({feedback:e,onDismiss:t}){return B(`div`,{"aria-live":`polite`,class:`mb-5 rounded-2xl border px-4 py-4 text-sm ${e.kind===`success`?`border-emerald-200 bg-emerald-50 text-emerald-900`:e.kind===`warning`?`border-amber-200 bg-amber-50 text-amber-950`:`border-red-200 bg-red-50 text-red-900`}`,children:B(`div`,{class:`flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between`,children:[B(`p`,{class:`m-0 font-bold leading-6`,children:e.message}),B(`button`,{class:`min-h-10 shrink-0 rounded-lg border border-current bg-transparent px-3 py-1.5 text-xs font-extrabold`,onClick:t,type:`button`,children:`닫기`})]})})}function y_({data:e,busy:t,onReconnect:n}){let r=e.status,i=r.connected;return B(`section`,{class:`grid gap-4 lg:grid-cols-3`,"aria-label":`인터넷 연결 상태`,children:[B(`article`,{class:`rounded-2xl border p-5 shadow-sm shadow-slate-900/5 ${i?`border-emerald-200 bg-emerald-50 text-emerald-950`:`border-amber-200 bg-amber-50 text-amber-950`}`,children:[B(`div`,{class:`flex items-start justify-between gap-3`,children:[B(`span`,{class:`grid size-10 place-items-center rounded-xl ${i?`bg-emerald-100 text-emerald-700`:`bg-amber-100 text-amber-700`}`,children:B(i?Xt:U,{class:`size-5`})}),B(`button`,{class:`inline-flex min-h-10 items-center justify-center gap-2 rounded-xl border border-current bg-transparent px-3 py-2 text-xs font-extrabold transition disabled:cursor-wait disabled:opacity-60`,disabled:t,onClick:n,type:`button`,children:[B(H,{class:`size-4 ${t?`animate-spin`:``}`}),`재연결`]})]}),B(`p`,{class:`mt-4 mb-0 text-xs font-extrabold uppercase tracking-[0.14em] opacity-70`,children:`인터넷 상태`}),B(`p`,{class:`mt-2 mb-0 text-xl font-black`,children:r.pending?`연결 중`:i?`연결됨`:`연결 안 됨`}),B(`p`,{class:`mt-1 mb-0 text-sm font-semibold leading-6 opacity-80`,children:[d_(r.protocol??e.configuration.protocol),` · `,__(r.uptimeSeconds)]})]}),B(`article`,{class:`rounded-2xl border border-slate-200 bg-white p-5 shadow-sm shadow-slate-900/5`,children:[B(`span`,{class:`grid size-10 place-items-center rounded-xl bg-teal-50 text-teal-700`,children:B(zt,{class:`size-5`})}),B(`p`,{class:`mt-4 mb-0 text-xs font-extrabold uppercase tracking-[0.14em] text-slate-500`,children:`WAN IPv4`}),B(`p`,{class:`mt-2 mb-0 break-all text-xl font-black text-slate-950`,children:r.address?`${r.address}${r.prefixLength===null?``:`/${r.prefixLength}`}`:`주소 없음`}),B(`p`,{class:`mt-1 mb-0 text-sm font-semibold text-slate-600`,children:r.device?`인터페이스 ${r.device}`:`인터페이스 확인 전`})]}),B(`article`,{class:`rounded-2xl border border-slate-200 bg-white p-5 shadow-sm shadow-slate-900/5`,children:[B(`span`,{class:`grid size-10 place-items-center rounded-xl bg-slate-100 text-slate-700`,children:B(jt,{class:`size-5`})}),B(`p`,{class:`mt-4 mb-0 text-xs font-extrabold uppercase tracking-[0.14em] text-slate-500`,children:`Gateway · DNS`}),B(`p`,{class:`mt-2 mb-0 break-all text-base font-black text-slate-950`,children:r.gateway??`Gateway 확인 전`}),B(`p`,{class:`mt-1 mb-0 break-all text-sm font-semibold leading-6 text-slate-600`,children:r.dns.length>0?r.dns.join(` · `):`DNS 확인 전`})]})]})}function b_({action:e,data:t,error:n,feedback:r,loading:i,onDismissFeedback:a,onReconnect:o,onRetry:s,onSave:c}){let[l,u]=N({protocol:`dhcp`,pppoeUsername:``,pppoePassword:``,staticAddress:``,staticPrefixLength:24,staticGateway:``,dnsPrimary:``,dnsSecondary:``}),[d,f]=N(!1),[p,m]=N(!1),[h,g]=N(null);P(()=>{!t||d||(u(f_(t)),g(null))},[t,d]);let _=$e(()=>{let e=[{value:`dhcp`,label:`자동 IP (DHCP)`},{value:`pppoe`,label:`PPPoE`},{value:`static`,label:`고정 IPv4`}];return t&&!t.configuration.supported&&e.unshift({value:t.configuration.protocol,label:`현재 설정 (${t.configuration.protocol})`}),e},[t]);if(i)return B(io,{});if(n)return B(ao,{message:n,onRetry:s});if(!t)return null;let v=e!==null,y=e=>{u(n=>{let r={...n,...e};return f(m_(r,t)),r}),g(null)},b=async e=>{if(e.preventDefault(),!u_(l.protocol)){g(`DHCP, PPPoE 또는 고정 IPv4 중 하나를 선택해 주세요.`);return}if(l.protocol===`pppoe`){if(!p_(l.pppoeUsername)){g(`PPPoE 사용자명을 입력해 주세요.`);return}if((t.configuration.protocol!==`pppoe`||!t.configuration.pppoe.passwordConfigured)&&l.pppoePassword.length===0){g(`PPPoE 연결을 시작하려면 비밀번호를 입력해 주세요.`);return}}if(l.protocol===`static`){if(!h_(l.staticAddress)){g(`고정 IPv4 주소를 올바르게 입력해 주세요.`);return}if(!h_(l.staticGateway)){g(`기본 게이트웨이를 올바르게 입력해 주세요.`);return}if(!h_(l.dnsPrimary)){g(`기본 DNS 서버를 올바르게 입력해 주세요.`);return}if(p_(l.dnsSecondary)&&!h_(l.dnsSecondary)){g(`보조 DNS 서버를 올바르게 입력해 주세요.`);return}}window.confirm(`인터넷 연결 설정을 적용하면 WAN 연결이 다시 시작되어 인터넷이 잠시 끊길 수 있습니다. 계속하시겠습니까?`)&&await c({protocol:l.protocol,pppoeUsername:p_(l.pppoeUsername),pppoePassword:l.pppoePassword,pppoePasswordChanged:l.pppoePassword.length>0,staticAddress:p_(l.staticAddress),staticPrefixLength:l.staticPrefixLength,staticGateway:p_(l.staticGateway),dnsPrimary:p_(l.dnsPrimary),dnsSecondary:p_(l.dnsSecondary)})&&(u(e=>({...e,pppoePassword:``})),f(!1))};return B(S,{children:[r?B(v_,{feedback:r,onDismiss:a}):null,B(y_,{data:t,busy:v,onReconnect:()=>{window.confirm(`WAN 연결을 다시 시작합니다. 인터넷이 잠시 끊길 수 있습니다. 계속하시겠습니까?`)&&o()}}),t.configuration.supported?null:B(`section`,{class:`mt-5 rounded-2xl border border-amber-200 bg-amber-50 p-5 text-amber-950 sm:p-6`,children:B(`div`,{class:`flex items-start gap-3`,children:[B(U,{class:`mt-0.5 size-5 shrink-0 text-amber-700`}),B(`div`,{children:[B(`h2`,{class:`m-0 text-base font-black`,children:`현재 WAN 방식은 직접 관리하지 않습니다`}),B(`p`,{class:`mt-2 mb-0 text-sm font-semibold leading-6 text-amber-900/80`,children:[`현재 설정은 `,t.configuration.protocol,`입니다. 아래에서 DHCP, PPPoE 또는 고정 IPv4를 선택해 저장하면 해당 방식으로 전환합니다.`]})]})]})}),B(`form`,{class:`mt-5 rounded-2xl border border-slate-200 bg-white p-5 shadow-sm shadow-slate-900/5 sm:p-6`,onSubmit:e=>void b(e),children:[B(`div`,{class:`flex flex-col gap-4 sm:flex-row sm:items-start sm:justify-between`,children:[B(`div`,{class:`flex min-w-0 items-start gap-3`,children:[B(`span`,{class:`grid size-11 shrink-0 place-items-center rounded-xl bg-teal-50 text-teal-700`,children:B(zt,{class:`size-6`})}),B(`div`,{class:`min-w-0`,children:[B(`p`,{class:`m-0 text-xs font-extrabold uppercase tracking-[0.16em] text-slate-500`,children:`Internet`}),B(`h2`,{class:`mt-2 mb-0 text-xl font-black text-slate-950`,children:`인터넷 연결 설정`}),B(`p`,{class:`mt-2 mb-0 text-sm font-semibold leading-6 text-slate-600`,children:`통신사 또는 상위 네트워크 환경에 맞는 WAN 연결 방식을 선택합니다.`})]})]}),d?B(`span`,{"aria-live":`polite`,class:`inline-flex shrink-0 self-start items-center gap-1.5 rounded-full border border-amber-200 bg-amber-50 px-2.5 py-1 text-xs font-extrabold text-amber-800`,role:`status`,children:[B(U,{"aria-hidden":`true`,class:`size-3.5 shrink-0`}),`저장되지 않음`]}):null]}),B(`div`,{class:`mt-6`,children:[B(`span`,{class:`text-sm font-extrabold text-slate-800`,children:`연결 방식`}),B(Vg,{ariaLabel:`WAN 연결 방식`,className:`mt-2 max-w-xl`,disabled:v,id:`wan-protocol`,onChange:e=>y(e===`static`&&!p_(l.dnsSecondary)?{protocol:e,dnsSecondary:c_}:{protocol:e}),options:_,value:l.protocol,variant:`emphasized`}),B(`span`,{class:`mt-2 block text-xs font-semibold leading-5 text-slate-500`,children:`대부분의 가정용 인터넷과 상위 공유기 연결은 자동 IP(DHCP)를 사용합니다.`})]}),l.protocol===`pppoe`?B(`div`,{class:`mt-6 grid gap-5 lg:grid-cols-2`,children:[B(`label`,{class:`block`,children:[B(`span`,{class:`text-sm font-extrabold text-slate-800`,children:`PPPoE 사용자명`}),B(`input`,{autocomplete:`username`,class:`mt-2 min-h-11 w-full rounded-xl border-2 border-slate-300 bg-slate-50 px-4 py-2.5 text-sm font-semibold text-slate-950 shadow-inner outline-none transition focus:border-teal-500 focus:bg-white focus:ring-4 focus:ring-teal-100 disabled:cursor-not-allowed disabled:bg-slate-100`,disabled:v,onInput:e=>y({pppoeUsername:e.currentTarget.value}),spellcheck:!1,value:l.pppoeUsername})]}),B(`label`,{class:`block`,children:[B(`span`,{class:`text-sm font-extrabold text-slate-800`,children:`PPPoE 비밀번호`}),B(`span`,{class:`relative mt-2 block`,children:[B(`input`,{autocomplete:`new-password`,class:`min-h-11 w-full rounded-xl border-2 border-slate-300 bg-slate-50 px-4 py-2.5 pr-12 text-sm font-semibold text-slate-950 shadow-inner outline-none transition focus:border-teal-500 focus:bg-white focus:ring-4 focus:ring-teal-100 disabled:cursor-not-allowed disabled:bg-slate-100`,disabled:v,onInput:e=>y({pppoePassword:e.currentTarget.value}),placeholder:t.configuration.protocol===`pppoe`&&t.configuration.pppoe.passwordConfigured?`변경할 때만 입력`:`PPPoE 비밀번호`,type:p?`text`:`password`,value:l.pppoePassword}),B(`button`,{"aria-label":p?`비밀번호 숨기기`:`비밀번호 표시`,class:`absolute inset-y-0 right-1 grid w-10 place-items-center rounded-lg border-0 bg-transparent text-slate-500`,disabled:v,onClick:()=>m(e=>!e),type:`button`,children:B(p?Jt:qt,{class:`size-5`})})]}),B(`span`,{class:`mt-2 block text-xs text-slate-500`,children:t.configuration.protocol===`pppoe`&&t.configuration.pppoe.passwordConfigured?`비워 두면 현재 저장된 비밀번호를 그대로 사용합니다.`:`통신사에서 제공한 PPPoE 비밀번호를 입력해 주세요.`})]})]}):null,l.protocol===`static`?B(`div`,{class:`mt-6 grid gap-5 lg:grid-cols-2`,children:[B(`label`,{class:`block`,children:[B(`span`,{class:`text-sm font-extrabold text-slate-800`,children:`IPv4 주소`}),B(Yg,{disabled:v,label:`IPv4 주소`,onChange:e=>y({staticAddress:e}),value:l.staticAddress})]}),B(`div`,{class:`block`,children:[B(`span`,{class:`text-sm font-extrabold text-slate-800`,children:`서브넷 마스크`}),B(Vg,{ariaLabel:`WAN 서브넷 마스크`,className:`mt-2`,disabled:v,id:`wan-static-prefix-length`,onChange:e=>y({staticPrefixLength:Number(e)}),options:l_.map(e=>({value:String(e),label:`/${e} · ${g_(e)}`})),value:String(l.staticPrefixLength),variant:`emphasized`})]}),B(`label`,{class:`block`,children:[B(`span`,{class:`text-sm font-extrabold text-slate-800`,children:`기본 게이트웨이`}),B(Yg,{disabled:v,label:`기본 게이트웨이`,onChange:e=>y({staticGateway:e}),value:l.staticGateway})]}),B(`label`,{class:`block`,children:[B(`span`,{class:`text-sm font-extrabold text-slate-800`,children:`기본 DNS`}),B(Yg,{disabled:v,label:`기본 DNS`,onChange:e=>y({dnsPrimary:e}),value:l.dnsPrimary})]}),B(`label`,{class:`block lg:col-start-2`,children:[B(`span`,{class:`text-sm font-extrabold text-slate-800`,children:`보조 DNS (선택)`}),B(Yg,{disabled:v,label:`보조 DNS`,onChange:e=>y({dnsSecondary:e}),value:l.dnsSecondary})]})]}):null,l.protocol===`dhcp`?B(`div`,{class:`mt-6 rounded-xl border border-slate-200 bg-slate-50 px-4 py-4 text-sm font-semibold leading-6 text-slate-600`,children:`상위 공유기 또는 통신사 장비에서 IP 주소, 기본 게이트웨이와 DNS 정보를 자동으로 받습니다. 별도의 계정이나 고정 주소가 없다면 이 방식을 사용하세요.`}):null,h?B(`p`,{class:`mt-5 mb-0 rounded-xl bg-red-50 px-4 py-3 text-sm font-bold text-red-800`,children:h}):null,B(`div`,{class:`mt-6 flex flex-col gap-3 border-t border-slate-200 pt-5 sm:flex-row sm:items-center sm:justify-between`,children:[B(`p`,{class:`m-0 text-xs font-semibold leading-5 text-slate-500`,children:`설정 저장 후 WAN만 다시 연결하며 LAN 관리 페이지와 내부 네트워크 설정은 유지됩니다.`}),B(`button`,{class:`inline-flex min-h-11 w-full shrink-0 items-center justify-center gap-2 rounded-xl border-0 bg-teal-700 px-5 py-2.5 text-sm font-extrabold text-white shadow-sm transition hover:bg-teal-800 focus:outline-none focus-visible:ring-4 focus-visible:ring-teal-200 disabled:cursor-wait disabled:opacity-60 sm:w-auto`,disabled:v||!d,type:`submit`,children:[B(Xt,{class:`size-5 ${e===`saving`?`animate-pulse`:``}`}),e===`saving`?`저장 중`:`설정 저장`]})]})]})]})}var x_=3,S_=10;function C_(e,t){return e<=0?`0.0%`:`${(t/e*100).toFixed(1)}%`}function w_(e){return e.id===`other`?`기타 기기`:e.hostname?e.hostname:e.identified?`이름 없는 기기`:`미식별 기기`}function T_(e){return[...e].sort((e,t)=>e.id===`other`?1:t.id===`other`?-1:t.blocked-e.blocked||t.queries-e.queries||w_(e).localeCompare(w_(t),`ko`))}function E_({devices:e,deviceLimit:t,truncated:n}){let r=T_(e),[i,a]=N(!1),[o,s]=N(1),c=Math.max(1,Math.ceil(r.length/S_)),l=Math.min(o,c),u=(l-1)*S_,d=Math.min(u+S_,r.length),f=i?r.slice(u,d):r.slice(0,x_),p=r.length>x_;return P(()=>{s(e=>Math.min(e,c))},[c]),B(`div`,{class:`mt-6 rounded-2xl border border-slate-100 bg-slate-50/70 p-4 sm:p-5`,children:[B(`div`,{class:`flex flex-wrap items-start justify-between gap-3`,children:[B(`div`,{children:[B(`div`,{class:`flex flex-wrap items-center gap-2`,children:[B(`p`,{class:`m-0 text-xs font-bold text-slate-500`,children:`기기별 통계`}),p&&!i?B(`span`,{class:`inline-flex items-center rounded-full bg-teal-50 px-2 py-1 text-[10px] font-extrabold tracking-wide text-teal-700 ring-1 ring-teal-100`,children:`차단 TOP 3`}):null]}),B(`h3`,{class:`mt-1 mb-0 text-base font-extrabold text-slate-950`,children:`어떤 기기에서 차단되었는지 확인`}),B(`p`,{class:`mt-2 mb-0 text-xs leading-5 text-slate-500`,children:`DHCP 정보가 있는 기기는 MAC 주소를 기준으로 식별하며, 기기별 숫자만 현재 부팅 세션 동안 메모리에 집계합니다.`})]}),B(`div`,{class:`flex flex-wrap items-center justify-end gap-2`,children:[B(`span`,{class:`inline-flex items-center gap-2 rounded-full bg-white px-3 py-1.5 text-xs font-extrabold text-slate-600 ring-1 ring-slate-200`,children:[B(Mt,{class:`size-4 text-teal-700`}),q(r.length),`개 항목`]}),p?B(`button`,{"aria-controls":`safeshield-device-statistics-list`,"aria-expanded":i,class:`rounded-full bg-white px-3 py-1.5 text-xs font-extrabold text-teal-700 ring-1 ring-slate-200 transition hover:bg-slate-50`,onClick:()=>{a(e=>!e),s(1)},type:`button`,children:i?`간단히 보기 ↑`:`전체 ${q(r.length)}개 기기 보기 ↓`}):null]})]}),r.length===0?B(`p`,{class:`mt-4 mb-0 rounded-xl bg-white p-4 text-sm leading-6 text-slate-500 ring-1 ring-slate-100`,children:`아직 기기별 DNS 통계가 없습니다. 클라이언트에서 DNS 요청이 발생하면 다음 통계 갱신 시 표시됩니다.`}):B(`div`,{class:`mt-4 grid gap-3`,id:`safeshield-device-statistics-list`,children:f.map(e=>B(`article`,{class:`grid gap-4 rounded-xl bg-white p-4 ring-1 ring-slate-100 sm:grid-cols-[minmax(0,1fr)_auto] sm:items-center`,children:[B(`div`,{class:`min-w-0`,children:B(`div`,{class:`flex min-w-0 flex-wrap items-center gap-2`,children:[B(`span`,{class:`grid size-9 shrink-0 place-items-center rounded-lg bg-teal-50 text-teal-700`,children:B(Mt,{class:`size-4`})}),B(`div`,{class:`min-w-0`,children:[B(`h4`,{class:`m-0 truncate text-sm font-extrabold text-slate-950`,children:w_(e)}),B(`p`,{class:`mt-1 mb-0 break-all text-xs text-slate-500`,children:[e.ip||`IP 미확인`,e.mac?` · ${e.mac}`:``]})]}),B(`span`,{class:`rounded-full px-2 py-1 text-[11px] font-extrabold ${e.identified?`bg-emerald-50 text-emerald-700`:`bg-slate-100 text-slate-600`}`,children:e.id===`other`?`합산`:e.identified?`DHCP 식별`:`IP 임시 식별`})]})}),B(`dl`,{class:`m-0 grid grid-cols-3 gap-2 text-right`,children:[B(`div`,{class:`min-w-20`,children:[B(`dt`,{class:`text-[11px] font-bold text-slate-400`,children:`DNS 요청`}),B(`dd`,{class:`mt-1 mb-0 ml-0 text-sm font-extrabold text-slate-900`,children:q(e.queries)})]}),B(`div`,{class:`min-w-20`,children:[B(`dt`,{class:`text-[11px] font-bold text-slate-400`,children:`차단`}),B(`dd`,{class:`mt-1 mb-0 ml-0 text-sm font-extrabold text-teal-700`,children:q(e.blocked)})]}),B(`div`,{class:`min-w-20`,children:[B(`dt`,{class:`text-[11px] font-bold text-slate-400`,children:`차단율`}),B(`dd`,{class:`mt-1 mb-0 ml-0 text-sm font-extrabold text-slate-900`,children:C_(e.queries,e.blocked)})]})]})]},e.id))}),p&&!i?B(`p`,{class:`mt-3 mb-0 text-xs font-semibold leading-5 text-slate-500`,children:[`전체 `,q(r.length),`개 기기 중 차단 수 기준 상위 `,x_,`개를 표시하고 있습니다.`]}):null,i&&r.length>S_?B(`nav`,{"aria-label":`기기별 통계 페이지`,class:`mt-4 flex flex-wrap items-center justify-between gap-3`,children:[B(`p`,{class:`m-0 text-xs font-semibold text-slate-500`,children:[q(u+1),`–`,q(d),` /`,` `,q(r.length),`개`]}),B(`div`,{class:`flex items-center gap-2`,children:[B(`button`,{class:`rounded-lg bg-white px-3 py-2 text-xs font-extrabold text-slate-700 ring-1 ring-slate-200 transition hover:bg-slate-50 disabled:cursor-not-allowed disabled:opacity-50`,disabled:l<=1,onClick:()=>s(e=>Math.max(1,e-1)),type:`button`,children:`이전`}),B(`span`,{"aria-current":`page`,class:`min-w-20 text-center text-xs font-extrabold text-slate-600`,children:[q(l),` / `,q(c)]}),B(`button`,{class:`rounded-lg bg-white px-3 py-2 text-xs font-extrabold text-slate-700 ring-1 ring-slate-200 transition hover:bg-slate-50 disabled:cursor-not-allowed disabled:opacity-50`,disabled:l>=c,onClick:()=>s(e=>Math.min(c,e+1)),type:`button`,children:`다음`})]})]}):null,n?B(`p`,{class:`mt-4 mb-0 rounded-xl border border-amber-200 bg-amber-50 p-3 text-xs font-semibold leading-5 text-amber-800`,children:[`개별 통계는 최대 `,q(t),`개 기기까지 추적합니다. 한도를 초과한 기기의 요청은 기타 기기로 합산됩니다.`]}):null]})}var D_=3600,O_=24;function k_(e,t){return e<=0?`0.0%`:`${(t/e*100).toFixed(1)}%`}function A_(e){let t=e.hourly[e.hourly.length-1];if(t?.bucketStart)return t.bucketStart;let n=e.updatedAt>0?e.updatedAt:Math.floor(Date.now()/1e3);return Math.floor(n/D_)*D_}function j_(e){let t=new Map(e.hourly.map(e=>[e.bucketStart,e])),n=A_(e)-23*D_;return Array.from({length:O_},(e,r)=>{let i=n+r*D_;return t.get(i)??{bucketStart:i,queries:0,blocked:0}})}function M_({emphasized:e=!1,label:t,value:n}){return B(`div`,{class:`rounded-xl border border-slate-100 bg-slate-50 p-4 sm:p-5`,children:[B(`dt`,{class:`text-[0.68rem] font-black uppercase tracking-[0.12em] text-slate-400`,children:t}),B(`dd`,{class:`mt-2 mb-0 ml-0 text-2xl font-black tracking-tight ${e?`text-teal-700`:`text-slate-950`}`,children:n})]})}function N_({action:e,data:t,error:n,loading:r,onRetry:i,onSetEnabled:a,refreshing:o}){if(r&&t===null)return B(`section`,{class:`mt-5 rounded-2xl border border-slate-200 bg-white p-5 shadow-sm shadow-slate-900/5 sm:p-6`,children:B(`p`,{class:`m-0 text-sm font-bold text-slate-500`,children:`차단 통계를 불러오는 중입니다…`})});if(n&&t===null)return B(`section`,{class:`mt-5 rounded-2xl border border-amber-200 bg-amber-50 p-5 sm:p-6`,children:[B(`p`,{class:`m-0 text-sm font-extrabold text-amber-950`,children:`차단 통계를 불러오지 못했습니다.`}),B(`p`,{class:`mt-2 mb-0 text-xs leading-5 text-amber-800`,children:n}),B(`button`,{class:`mt-4 inline-flex min-h-9 items-center justify-center rounded-xl border border-amber-300 bg-white px-3 py-2 text-xs font-extrabold text-amber-900 transition hover:bg-amber-100 focus:outline-none focus-visible:ring-4 focus-visible:ring-amber-100`,onClick:i,type:`button`,children:`다시 시도`})]});if(!t)return B(`section`,{class:`mt-5 rounded-2xl border border-slate-200 bg-white p-5 shadow-sm shadow-slate-900/5 sm:p-6`,children:[B(`p`,{class:`m-0 text-xs font-bold uppercase tracking-[0.16em] text-slate-500`,children:`Activity`}),B(`h2`,{class:`mt-3 mb-0 text-xl font-extrabold text-slate-950`,children:`보호 활동`}),B(`p`,{class:`mt-3 mb-0 text-sm leading-6 text-slate-600`,children:`현재 SafeShield에서 통계 데이터를 제공하지 않습니다. SafeShield 0.3.15 버전 이상이 설치되어 있고, 통계 수집이 활성화되어 있는지 확인해 주세요.`})]});let s=j_(t),c=s[s.length-1],l=s.reduce((e,t)=>({queries:e.queries+t.queries,blocked:e.blocked+t.blocked}),{queries:0,blocked:0}),u=e===`statistics-enable`||e===`statistics-disable`,d=e===`statistics-enable`||e!==`statistics-disable`&&t.enabled,f=u?d?`활성화하는 중…`:`비활성화하는 중…`:t.enabled?t.collectorRunning?`활성화 · 수집 중`:`활성화 · 시작 중`:`비활성화`;return B(`section`,{"aria-busy":u,class:`mt-5 rounded-2xl border border-slate-200 bg-white p-5 shadow-sm shadow-slate-900/5 sm:p-6 ${u?`cursor-wait`:``}`,children:[B(`div`,{class:`flex flex-wrap items-start justify-between gap-4`,children:[B(`div`,{children:[B(`p`,{class:`m-0 text-[0.68rem] font-black uppercase tracking-[0.18em] text-teal-700`,children:`Activity`}),B(`h2`,{class:`mt-2 mb-0 text-xl font-black tracking-tight text-slate-950`,children:`최근 24시간 보호 활동`}),B(`p`,{class:`mt-2 mb-0 text-sm leading-6 text-slate-500`,children:`DNS 요청 원본은 저장하지 않고 숫자만 로컬 메모리에 집계합니다.`})]}),B(`div`,{class:`flex items-center gap-3 rounded-xl border border-slate-100 bg-slate-50 px-3 py-2.5`,children:[B(`span`,{class:`grid size-9 place-items-center rounded-lg bg-slate-100 text-slate-500`,children:B(Gt,{class:`size-5`})}),B(`div`,{class:`text-right`,children:[B(`p`,{class:`m-0 text-[0.68rem] font-bold text-slate-400`,children:`통계 수집`}),B(`p`,{class:`mt-1 mb-0 text-xs font-extrabold ${u||d?`text-emerald-700`:`text-slate-500`}`,role:`status`,children:f})]}),B(`button`,{"aria-checked":d,"aria-label":d?`차단 통계 수집 끄기`:`차단 통계 수집 켜기`,class:`ssh-switch-control relative inline-flex shrink-0 items-center rounded-full border-0 p-0 transition focus:outline-none focus-visible:ring-4 focus-visible:ring-teal-100 ${u?`cursor-wait opacity-80`:`disabled:cursor-not-allowed disabled:opacity-50`} ${d?`bg-teal-600`:`bg-slate-300`}`,disabled:e!==null,onClick:()=>a(!t.enabled),role:`switch`,type:`button`,children:B(`span`,{"aria-hidden":`true`,class:`ssh-switch-thumb absolute top-1 grid place-items-center shadow-sm transition-all ${d?`left-6`:`left-1`}`,children:u?B(H,{"aria-hidden":`true`,class:`size-3 animate-spin text-teal-600`}):null})})]})]}),t.enabled?null:B(`div`,{class:`mt-5 rounded-xl border border-slate-200 bg-slate-50 px-4 py-3 text-sm leading-6 text-slate-600`,children:`통계 수집이 꺼져 있습니다. 활성화하면 DNS 요청 원본은 저장하지 않고 요청 수와 차단 수만 로컬 메모리에 집계합니다.`}),B(`dl`,{class:`mt-6 grid gap-3 sm:grid-cols-2 xl:grid-cols-4`,children:[B(M_,{label:`최근 24시간 DNS 요청`,value:q(l.queries)}),B(M_,{emphasized:!0,label:`최근 24시간 차단`,value:q(l.blocked)}),B(M_,{label:`최근 24시간 차단율`,value:k_(l.queries,l.blocked)}),B(M_,{label:`현재 시간 차단`,value:q(c?.blocked??0)})]}),B(`div`,{class:`mt-5 rounded-2xl border border-slate-100 bg-slate-50/70 p-4 sm:p-5`,children:[B(`div`,{class:`flex flex-wrap items-end justify-between gap-3`,children:[B(`div`,{children:[B(`p`,{class:`m-0 text-xs font-bold text-slate-500`,children:`최근 24시간`}),B(`h3`,{class:`mt-1 mb-0 text-base font-extrabold text-slate-950`,children:`시간대별 차단 요청`})]}),B(`span`,{class:`text-xs font-bold text-slate-500`,children:o?`갱신 중…`:`마지막 집계 ${Fa(t.updatedAt)}`})]}),B(zh,{buckets:s})]}),B(E_,{deviceLimit:t.deviceLimit,devices:t.devices,truncated:t.devicesTruncated}),B(`div`,{class:`mt-5 flex flex-wrap gap-x-5 gap-y-2 border-t border-slate-100 pt-4 text-xs leading-5 text-slate-500`,children:[B(`span`,{children:[`수집 누적 DNS 요청 `,q(t.totals.queries)]}),B(`span`,{children:[`수집 누적 차단 `,q(t.totals.blocked)]}),B(`span`,{children:[`수집 시작 `,Fa(t.startedAt)]}),B(`span`,{children:[`보존 `,q(t.retentionHours),`시간`]}),t.volatile?B(`span`,{children:`재부팅 시 초기화되는 메모리 통계`}):null]}),n?B(`p`,{class:`mt-3 mb-0 text-xs font-bold text-amber-700`,children:`최근 자동 갱신에 실패했습니다. 현재 표시된 마지막 정상 통계를 유지합니다.`}):null]})}var P_=`https://www.smartsafehub.com/pricing/`;function F_({value:e,trueLabel:t=`정상`,falseLabel:n=`확인 필요`}){return B(`span`,{class:`inline-flex items-center gap-2 text-sm font-extrabold ${e?`text-emerald-700`:`text-slate-500`}`,children:[B(`span`,{class:`size-2 rounded-full ${e?`bg-emerald-500`:`bg-slate-300`}`}),e?t:n]})}function I_(e){return!e.enabled||e.status===`disabled`?`disabled`:e.status===`running`?`refreshing`:e.status===`error`||e.health.overall===`error`||e.issueCounts.errors>0?`error`:e.status===`paused`?`paused`:e.active&&e.runtime.dnsmasqRunning&&e.runtime.dnsRuntimeOk?`protecting`:`attention`}function L_(e){return!e.enabled||e.status===`disabled`?`비활성화`:e.active&&e.runtime.dnsmasqRunning&&e.runtime.dnsRuntimeOk?`보호 중`:e.status===`paused`?`일시 중지`:`확인 필요`}function R_(e){let t=I_(e);return t===`error`&&L_(e)===`보호 중`&&e.runtime.lastErrorCode?`갱신 실패`:{disabled:`비활성화`,refreshing:`갱신 중`,protecting:`보호 중`,paused:`일시 중지`,error:`오류`,attention:`확인 필요`}[t]}function z_(e){let t=I_(e);return t===`protecting`?e.blocklist.validLineCount>0?`${q(e.blocklist.validLineCount)}개 도메인 차단 규칙으로 DNS를 보호하고 있습니다.`:e.blocklist.installed?`차단 목록이 설치되어 있으며 DNS 보호가 정상적으로 동작하고 있습니다.`:`SafeShield 서비스와 DNS 런타임이 정상적으로 동작하고 있습니다.`:t===`refreshing`?`차단 목록을 최신 상태로 갱신하고 있습니다.`:t===`disabled`?`SafeShield DNS 보호가 비활성화되어 있습니다.`:t===`paused`?`SafeShield 작업이 일시 중지되어 있습니다.`:t===`error`?L_(e)===`보호 중`?`기존 DNS 보호는 유지되고 있지만 최근 차단 목록 갱신을 완료하지 못했습니다.`:`SafeShield 보호 상태에 문제가 발생했습니다. 아래 오류 내용을 확인해 주세요.`:e.active?e.runtime.dnsmasqRunning?e.runtime.dnsRuntimeOk?e.summary.message:`SafeShield DNS 런타임 상태를 확인해야 합니다.`:`dnsmasq가 실행 중이 아니어서 DNS 보호 상태를 확인해야 합니다.`:`SafeShield가 활성화되어 있지만 서비스가 실행 중이 아닙니다.`}function B_(e){return{ok:`정상`,warning:`경고`,error:`오류`,unavailable:`사용 불가`}[e]??e}function V_({data:e}){let t=I_(e);return B(`span`,{class:`inline-flex items-center rounded-full px-3 py-1.5 text-xs font-extrabold ring-1 ring-inset ${t===`error`?`bg-red-50 text-red-700 ring-red-200`:t===`disabled`?`bg-slate-100 text-slate-700 ring-slate-200`:t===`refreshing`?`bg-blue-50 text-blue-700 ring-blue-200`:t===`paused`||t===`attention`?`bg-amber-50 text-amber-800 ring-amber-200`:`bg-emerald-50 text-emerald-700 ring-emerald-200`}`,children:R_(e)})}function H_({failed:e,step:t,total:n}){let r=2*Math.PI*17,i=r*.22,a=r-i;return B(`span`,{"aria-label":e?`갱신 실패 · ${t}/${n} 단계`:`갱신 ${t}/${n} 단계`,class:`ssh-safeshield-refresh-donut`,"data-state":e?`error`:`active`,role:`progressbar`,"aria-valuemin":0,"aria-valuemax":n,"aria-valuenow":t,children:[B(`svg`,{"aria-hidden":`true`,class:e?`ssh-safeshield-refresh-loader-svg ssh-safeshield-refresh-loader-svg-error`:`ssh-safeshield-refresh-loader-svg`,viewBox:`0 0 48 48`,children:[B(`circle`,{class:`ssh-safeshield-refresh-loader-track`,cx:`24`,cy:`24`,fill:`none`,r:17,stroke:`currentColor`,strokeWidth:3}),e?null:B(`circle`,{class:`ssh-safeshield-refresh-loader-arc`,cx:`24`,cy:`24`,fill:`none`,r:17,stroke:`currentColor`,strokeDasharray:`${i} ${a}`,strokeLinecap:`round`,strokeWidth:4})]}),B(`span`,{class:`ssh-safeshield-refresh-donut-label`,children:e?`!`:`${t}/${n}`})]})}function U_({data:e}){let t=na(e.status,e.stage),n=I_(e)===`error`;if(!t&&!n)return null;let r=ra(e.stage),i=n?aa(e.runtime.lastErrorCode,e.stage):null;return B(`div`,{"aria-live":n?`assertive`:`polite`,class:`ssh-safeshield-refresh`,"data-state":n?`error`:`active`,role:n?`alert`:`status`,children:[B(H_,{failed:n,step:r.number,total:r.total}),B(`div`,{class:`ssh-safeshield-refresh-copy`,children:[B(`p`,{class:`ssh-safeshield-refresh-kicker`,children:n?`갱신 실패 · ${r.number}/${r.total}`:`갱신 ${r.number}/${r.total}`}),B(`p`,{class:`ssh-safeshield-refresh-title`,children:n?`${r.label} 단계에서 문제가 발생했습니다.`:r.label}),B(`p`,{class:`ssh-safeshield-refresh-description`,children:i??r.description}),n&&e.runtime.lastErrorCode?B(`p`,{class:`ssh-safeshield-refresh-error-code`,children:[`오류 코드: `,B(`code`,{children:e.runtime.lastErrorCode})]}):null]})]})}function W_({label:e,value:t}){return B(`div`,{class:`bg-white px-5 py-4 sm:px-6`,children:[B(`dt`,{class:`text-[0.68rem] font-black uppercase tracking-[0.14em] text-slate-400`,children:e}),B(`dd`,{class:`mt-2 mb-0 ml-0 truncate text-sm font-extrabold text-slate-950`,title:t,children:t})]})}function G_(e){return e?.trim().toUpperCase()||`FREE`}function K_(e){return e===`FREE`?`free`:e===`PRO`?`pro`:e===`ULTIMATE`?`ultimate`:`paid`}function q_({compact:e=!1,plan:t}){let n=K_(t),r=n!==`free`;return B(`span`,{class:`ssh-safeshield-plan-badge`,"data-compact":e?`true`:`false`,"data-tier":n,title:r?`${t} 멤버십`:`무료 플랜`,children:[B(`span`,{"aria-hidden":`true`,class:`ssh-safeshield-plan-badge-mark`,children:r?`✦`:`•`}),B(`span`,{children:t})]})}function J_({plan:e}){let t=K_(e)===`free`;return B(`div`,{class:`bg-white px-5 py-4 sm:px-6`,children:[B(`dt`,{class:`text-[0.68rem] font-black uppercase tracking-[0.14em] text-slate-400`,children:`Plan`}),B(`dd`,{class:`mt-2 mb-0 ml-0 flex min-w-0 flex-wrap items-center gap-2`,children:[B(q_,{plan:e}),t?B(`span`,{class:`ssh-safeshield-plan-caption`,children:`기본 플랜`}):null]})]})}function Y_(){return B(`div`,{class:`ssh-safeshield-upgrade-card`,children:[B(`span`,{"aria-hidden":`true`,class:`ssh-safeshield-upgrade-mark`,children:`✦`}),B(`div`,{class:`ssh-safeshield-upgrade-copy`,children:[B(`div`,{class:`ssh-safeshield-upgrade-meta`,children:[B(`span`,{children:`SmartSafeHub Membership`}),B(`span`,{class:`ssh-safeshield-upgrade-soon`,children:`Coming soon`})]}),B(`strong`,{children:`더 강력한 보호 기능을 준비하고 있습니다.`}),B(`span`,{children:`프리미엄 보호와 확장된 관리 기능을 미리 확인해 보세요.`})]}),B(`a`,{class:`ssh-safeshield-upgrade-action`,href:P_,rel:`noopener noreferrer`,target:`_blank`,children:[`요금제 보기`,B(`span`,{"aria-hidden":`true`,children:`→`})]})]})}function X_({description:e,eyebrow:t,title:n}){return B(`div`,{class:`mb-4 flex flex-wrap items-end justify-between gap-3`,children:B(`div`,{children:[B(`p`,{class:`m-0 text-[0.68rem] font-black uppercase tracking-[0.18em] text-teal-700`,children:t}),B(`h2`,{class:`mt-2 mb-0 text-xl font-black tracking-tight text-slate-950`,children:n}),B(`p`,{class:`mt-2 mb-0 text-sm leading-6 text-slate-500`,children:e})]})})}function Z_({children:e,eyebrow:t,icon:n,title:r}){return B(`article`,{class:`rounded-2xl border border-slate-200 bg-white p-5 shadow-sm shadow-slate-900/5 sm:p-6`,children:[B(`div`,{class:`flex items-start justify-between gap-4`,children:[B(`div`,{children:[B(`p`,{class:`m-0 text-[0.68rem] font-black uppercase tracking-[0.16em] text-slate-400`,children:t}),B(`h3`,{class:`mt-2 mb-0 text-lg font-black tracking-tight text-slate-950`,children:r})]}),B(`span`,{class:`grid size-10 shrink-0 place-items-center rounded-xl bg-slate-100 text-slate-500`,children:n})]}),B(`dl`,{class:`mt-5 mb-0 grid gap-3`,children:e})]})}function Q_({label:e,value:t}){return B(`div`,{class:`flex min-w-0 items-center justify-between gap-4 border-b border-slate-100 pb-3 last:border-b-0 last:pb-0`,children:[B(`dt`,{class:`text-sm font-semibold text-slate-500`,children:e}),B(`dd`,{class:`m-0 min-w-0 text-right text-sm font-extrabold text-slate-950`,children:t})]})}function $_({error:e,message:t,onDismiss:n}){if(!e&&!t)return null;let r=e!==null;return B(`div`,{"aria-live":r?`assertive`:`polite`,class:`mt-4 flex flex-col items-start gap-3 rounded-2xl border px-4 py-3 text-sm sm:flex-row sm:justify-between ${r?`border-red-200 bg-red-50 text-red-900`:`border-emerald-200 bg-emerald-50 text-emerald-900`}`,role:r?`alert`:`status`,children:[B(`div`,{class:`flex min-w-0 items-start gap-3`,children:[B(r?U:Xt,{class:`mt-0.5 size-5 shrink-0`}),B(`p`,{class:`m-0 font-semibold leading-6`,children:e??t})]}),B(`button`,{"aria-label":`알림 닫기`,class:`shrink-0 rounded-lg border-0 bg-transparent px-2 py-1 font-black text-current opacity-60 transition hover:opacity-100 focus:outline-none focus-visible:ring-2 focus-visible:ring-current`,onClick:n,type:`button`,children:`×`})]})}function ev({action:e,actionError:t,actionFeedbackTarget:n,actionMessage:r,data:i,error:a,loading:o,statistics:s,statisticsError:c,statisticsLoading:l,statisticsRefreshing:u,onDismissFeedback:d,onReadLicense:f,onRefreshBlocklist:p,onRemoveLicense:m,onRetry:h,onRetryStatistics:g,onSetEnabled:_,onSetStatisticsEnabled:v,onUpdateLicense:y}){let[b,x]=N(``),[C,w]=N(!1),[T,E]=N(null);if(P(()=>{i?.available&&i.blocklist.validLineCount>0&&!na(i.status,i.stage)&&E(i.blocklist.validLineCount)},[i?.available,i?.blocklist.validLineCount,i?.stage,i?.status]),P(()=>{i?.license.configured===!1&&(x(``),w(!1))},[i?.license.configured]),o)return B(io,{});if(a)return B(ao,{message:a,onRetry:h});if(!i)return B(io,{});if(!i.available)return B(`section`,{class:`rounded-2xl border border-amber-200 bg-amber-50 p-5 sm:p-6`,children:[B(`span`,{class:`grid size-11 place-items-center rounded-xl bg-amber-100 text-amber-800`,children:B(U,{class:`size-6`})}),B(`h2`,{class:`mt-5 mb-0 text-xl font-extrabold text-amber-950`,children:`SafeShield 상태 API를 찾을 수 없습니다`}),B(`p`,{class:`mt-2 mb-0 text-sm leading-6 text-amber-900`,children:`safeshield 패키지와 rpcd ucode 플러그인이 설치되어 있는지 확인해 주세요.`})]});let D=i.enabled,O=G_(i.license.plan),k=na(i.status,i.stage),A=e!==null,ee=(k||I_(i)===`error`)&&i.blocklist.validLineCount===0&&T!==null?T:i.blocklist.validLineCount,j=D?e===`disable`?`끄는 중…`:`보호 끄기`:e===`enable`?`켜는 중…`:`보호 켜기`;async function te(){if(b.length>0)return;let e=await f();e!==null&&(x(e),w(!0))}function ne(){x(``),w(!1)}function M(){window.confirm(`라이선스 키를 제거하면 SafeShield가 라이선스 없는 상태로 다시 확인하고 차단 목록을 갱신합니다. 계속하시겠습니까?`)&&m().then(e=>{e&&ne()})}function re(){D&&!window.confirm(`SafeShield 보호를 끄면 현재 차단 목록이 제거되고 DNS 차단이 즉시 중단됩니다. 계속하시겠습니까?`)||_(!D)}return B(S,{children:[B(`section`,{class:`overflow-hidden rounded-2xl border border-slate-200 bg-white shadow-sm shadow-slate-900/5`,children:[B(`div`,{class:`flex flex-col gap-5 p-5 sm:p-6 lg:flex-row lg:items-start lg:justify-between`,children:[B(`div`,{class:`flex min-w-0 items-start gap-3 sm:gap-4`,children:[B(`span`,{class:`grid size-12 shrink-0 place-items-center rounded-2xl bg-teal-50 text-teal-700`,children:B(At,{class:`size-7`})}),B(`div`,{class:`min-w-0`,children:[B(`p`,{class:`m-0 text-[0.68rem] font-black uppercase tracking-[0.18em] text-teal-700`,children:`Protection`}),B(`div`,{class:`mt-2 flex flex-wrap items-center gap-3`,children:[B(`h2`,{class:`m-0 break-words text-xl font-black tracking-tight text-slate-950 sm:text-2xl`,children:`SafeShield 보호 상태`}),B(V_,{data:i})]}),B(`p`,{class:`mt-3 mb-0 max-w-3xl text-sm leading-6 text-slate-600`,children:z_(i)}),B(U_,{data:i})]})]}),B(`div`,{class:`flex w-full flex-col gap-2 sm:w-auto sm:flex-row`,children:[B(`button`,{class:`inline-flex min-h-11 items-center justify-center gap-2 rounded-xl border px-4 py-2.5 text-sm font-extrabold transition focus:outline-none focus-visible:ring-4 disabled:cursor-not-allowed disabled:opacity-50 ${i.enabled?`border-red-200 bg-white text-red-700 hover:border-red-300 hover:bg-red-50 focus-visible:ring-red-100`:`border-teal-700 bg-teal-700 text-white hover:border-teal-800 hover:bg-teal-800 focus-visible:ring-teal-100`}`,disabled:A||k,onClick:re,type:`button`,children:[B(Ut,{class:`size-4 ${e===`enable`||e===`disable`?`animate-pulse`:``}`}),j]}),B(`button`,{class:`inline-flex min-h-11 items-center justify-center gap-2 rounded-xl border border-slate-200 bg-white px-4 py-2.5 text-sm font-extrabold text-slate-700 transition hover:border-teal-300 hover:bg-teal-50 hover:text-teal-800 focus:outline-none focus-visible:ring-4 focus-visible:ring-teal-100 disabled:cursor-not-allowed disabled:opacity-50`,disabled:!i.enabled||A||k,onClick:p,type:`button`,children:[B(Wt,{class:`size-4 ${e===`refresh`||k?`animate-bounce`:``}`}),e===`refresh`?`시작 중…`:k?`갱신 중…`:`지금 갱신`]})]})]}),B(`div`,{class:`px-5 pb-5 sm:px-6 sm:pb-6`,children:[B(`dl`,{class:`grid overflow-hidden rounded-xl border border-slate-200 bg-slate-200 sm:grid-cols-2 xl:grid-cols-4`,children:[B(W_,{label:`SafeShield`,value:i.version??`확인되지 않음`}),B(W_,{label:`Blocklist`,value:`${q(ee)}개 도메인`}),B(W_,{label:`Last refresh`,value:Fa(i.timestamps.lastSuccess)}),B(J_,{plan:O})]}),O===`FREE`?B(Y_,{}):null]})]}),B($_,{error:n===`license`?null:t,message:n===`license`?null:r,onDismiss:d}),B(N_,{action:e,data:s,error:c,loading:l,onRetry:g,onSetEnabled:v,refreshing:u}),B(`section`,{class:`mt-7`,children:[B(X_,{description:`DNS 보호 런타임, 차단 목록, 갱신 일정과 상태 점검 결과를 한곳에서 확인합니다.`,eyebrow:`Protection details`,title:`보호 구성`}),B(`div`,{class:`grid gap-4 lg:grid-cols-2`,children:[B(Z_,{eyebrow:`Runtime`,icon:B(Xt,{class:`size-5`}),title:`DNS 보호 런타임`,children:[B(Q_,{label:`SafeShield 서비스`,value:B(F_,{falseLabel:`중지됨`,trueLabel:`동작 중`,value:i.active})}),B(Q_,{label:`dnsmasq`,value:B(F_,{falseLabel:`중지됨`,value:i.runtime.dnsmasqRunning})}),B(Q_,{label:`DNS 런타임`,value:B(F_,{value:i.runtime.dnsRuntimeOk})}),B(Q_,{label:`Refresh daemon`,value:B(F_,{falseLabel:`중지됨`,value:i.runtime.refreshdRunning})})]}),B(Z_,{eyebrow:`Blocklist`,icon:B(Gt,{class:`size-5`}),title:`차단 목록`,children:[B(Q_,{label:`적용 규칙`,value:`${q(i.blocklist.validLineCount)}개 도메인`}),B(Q_,{label:`파일 크기`,value:Ma(i.blocklist.fileSizeKb*1024)}),B(Q_,{label:`설치 상태`,value:B(F_,{falseLabel:`미설치`,trueLabel:`설치됨`,value:i.blocklist.installed})}),B(Q_,{label:`검증 상태`,value:B(F_,{falseLabel:`확인 필요`,value:i.blocklist.verificationOk})})]}),B(Z_,{eyebrow:`Refresh schedule`,icon:B(Yt,{class:`size-5`}),title:`차단 목록 갱신`,children:[B(Q_,{label:`마지막 성공`,value:Fa(i.timestamps.lastSuccess)}),B(Q_,{label:`다음 갱신`,value:Fa(i.timestamps.nextRefreshAt)}),B(Q_,{label:`갱신 주기`,value:Ra(i.timestamps.refreshIntervalS)}),B(Q_,{label:`최근 결과`,value:i.runtime.lastResult||(k?`갱신 중`:`확인되지 않음`)})]}),B(Z_,{eyebrow:`Health`,icon:B(At,{class:`size-5`}),title:`상태 점검`,children:[B(Q_,{label:`전체 상태`,value:B_(i.health.overall)}),B(Q_,{label:`경고`,value:B(`span`,{class:`text-amber-700`,children:q(i.issueCounts.warnings)})}),B(Q_,{label:`오류`,value:B(`span`,{class:`text-red-700`,children:q(i.issueCounts.errors)})}),B(Q_,{label:`최근 오류 코드`,value:i.runtime.lastErrorCode||`없음`})]})]})]}),B(`section`,{class:`mt-7`,children:[B(X_,{description:`라이선스와 현재 적용 중인 SafeShield 아티팩트 및 로컬 규칙 구성을 관리합니다.`,eyebrow:`Settings`,title:`SafeShield 설정`}),B(`div`,{class:`grid gap-4 xl:grid-cols-[minmax(0,1.35fr)_minmax(18rem,0.65fr)]`,children:[B(`article`,{class:`rounded-2xl border border-slate-200 bg-white p-5 shadow-sm shadow-slate-900/5 sm:p-6`,children:[B(`div`,{class:`flex items-start justify-between gap-4`,children:[B(`div`,{children:[B(`p`,{class:`m-0 text-[0.68rem] font-black uppercase tracking-[0.16em] text-slate-400`,children:`License`}),B(`h3`,{class:`mt-2 mb-0 text-lg font-black tracking-tight text-slate-950`,children:`라이선스`}),B(`p`,{class:`mt-2 mb-0 text-sm leading-6 text-slate-500`,children:[`현재 플랜은 `,O,`이며, 라이선스 키를 등록하거나 변경할 수 있습니다.`]})]}),B(`span`,{class:`grid size-10 shrink-0 place-items-center rounded-xl bg-slate-100 text-slate-500`,children:B(Kt,{class:`size-5`})})]}),B(`div`,{class:`ssh-safeshield-license-summary mt-5`,children:[B(`div`,{class:`ssh-safeshield-license-summary-main`,children:[B(q_,{compact:!0,plan:O}),i.license.configured?null:B(`span`,{class:`ssh-safeshield-license-summary-status`,children:`라이선스 미설정`})]}),i.license.configured&&i.license.keyMasked?B(`span`,{class:`ssh-safeshield-license-key-mask`,children:i.license.keyMasked}):null]}),B(`form`,{class:`ssh-safeshield-license-editor mt-5`,onSubmit:e=>{e.preventDefault(),y(b).then(e=>{e&&ne()})},children:[B(`div`,{class:`ssh-safeshield-license-editor-header`,children:[B(`label`,{class:`ssh-safeshield-license-editor-label`,for:`safeshield-license-key`,children:i.license.configured?`라이선스 키 확인 / 변경`:`라이선스 키 등록`}),B(`span`,{class:`ssh-safeshield-license-editor-hint`,children:i.license.configured?`현재 키를 확인하거나 새 키로 교체할 수 있습니다.`:`새 라이선스 키를 등록해 프리미엄 기능을 준비하세요.`})]}),B(`div`,{class:`ssh-safeshield-license-input-row`,children:[B(`input`,{autocomplete:`off`,autocapitalize:`none`,class:`ssh-safeshield-license-input`,"data-1p-ignore":!0,"data-bwignore":`true`,"data-lpignore":`true`,disabled:A,id:`safeshield-license-key`,onInput:e=>{x(e.currentTarget.value),w(!1)},placeholder:i.license.configured?`새 라이선스 키 입력`:`라이선스 키 입력`,spellcheck:!1,type:`text`,value:b}),B(`button`,{class:`ssh-safeshield-license-secondary-action`,disabled:A||b.length>0||!i.license.configured,onClick:()=>void te(),type:`button`,children:[B(Wt,{class:`size-4`}),e===`license-read`?`불러오는 중…`:C?`현재 키 불러옴`:`현재 키 불러오기`]})]}),B(`div`,{class:`ssh-safeshield-license-actions`,children:[B(`button`,{class:`ssh-safeshield-license-primary-action`,disabled:A||b.trim().length===0,type:`submit`,children:e===`license-update`?`저장 중…`:i.license.configured?`라이선스 변경`:`라이선스 등록`}),i.license.configured?B(`button`,{class:`ssh-safeshield-license-danger-action`,disabled:A,onClick:M,type:`button`,children:e===`license-remove`?`제거 중…`:`라이선스 제거`}):null]}),e===`license-update`?B(`div`,{"aria-live":`polite`,class:`mt-4 flex items-center gap-3 rounded-2xl border border-teal-200 bg-teal-50 px-4 py-3 text-sm font-semibold text-teal-800`,role:`status`,children:[B(`span`,{class:`size-2 shrink-0 animate-pulse rounded-full bg-teal-500`}),`라이선스를 확인하고 이 기기에 적용하고 있습니다…`]}):null,B($_,{error:n===`license`?t:null,message:n===`license`?r:null,onDismiss:d})]})]}),B(`div`,{class:`grid gap-4`,children:[B(`article`,{class:`rounded-2xl border border-slate-200 bg-white p-5 shadow-sm shadow-slate-900/5`,children:[B(`div`,{class:`flex items-start justify-between gap-4`,children:[B(`div`,{children:[B(`p`,{class:`m-0 text-[0.68rem] font-black uppercase tracking-[0.16em] text-slate-400`,children:`Artifact`}),B(`h3`,{class:`mt-2 mb-0 text-lg font-black tracking-tight text-slate-950`,children:`보호 데이터`})]}),B(`span`,{class:`grid size-10 shrink-0 place-items-center rounded-xl bg-slate-100 text-slate-500`,children:B(Gt,{class:`size-5`})})]}),B(`dl`,{class:`mt-5 mb-0 grid gap-3`,children:[B(Q_,{label:`Tier`,value:i.artifact.tier||`확인되지 않음`}),B(Q_,{label:`Version`,value:i.artifact.version||`확인되지 않음`}),B(Q_,{label:`Rules`,value:q(i.artifact.rules)}),B(Q_,{label:`Unique domains`,value:q(i.artifact.uniqueDomains)})]})]}),B(`article`,{class:`rounded-2xl border border-slate-200 bg-white p-5 shadow-sm shadow-slate-900/5`,children:[B(`p`,{class:`m-0 text-[0.68rem] font-black uppercase tracking-[0.16em] text-slate-400`,children:`Custom rules`}),B(`h3`,{class:`mt-2 mb-0 text-lg font-black tracking-tight text-slate-950`,children:`사용자 규칙`}),B(`div`,{class:`mt-4`,children:B(F_,{falseLabel:`비활성화`,trueLabel:`활성화`,value:i.localOverrides.enabled})}),B(`p`,{class:`mt-4 mb-0 text-sm font-semibold leading-6 text-slate-500`,children:`허용하거나 차단할 도메인을 직접 관리해 SafeShield 보호 정책에 반영합니다.`}),B(`a`,{class:`mt-5 inline-flex min-h-11 items-center justify-center gap-2 rounded-xl border border-teal-700 bg-teal-700 px-4 py-2 text-sm font-extrabold text-white no-underline shadow-sm transition hover:border-teal-800 hover:bg-teal-800 focus:outline-none focus-visible:ring-4 focus-visible:ring-teal-100`,href:`#rules`,children:[B(en,{class:`size-4`}),`사용자 규칙 관리`]})]})]})]})]})]})}function tv(e){return e.trim().toLowerCase().replace(/\.+$/,``)}function nv(e){return e.length===0||e.length>253||!e.includes(`.`)||!/^[a-z0-9.-]+$/.test(e)?!1:e.split(`.`).every(e=>e.length>0&&e.length<=63&&/^[a-z0-9](?:[a-z0-9-]*[a-z0-9])?$/.test(e))}function rv({action:e,kind:t,onAddRule:n,onDeleteRule:r,rules:i}){let[a,o]=N(``),[s,c]=N(``),[l,u]=N(null),d=t===`allow`,f=e!==null,p=$e(()=>{let e=s.trim().toLowerCase();return e.length>0?i.filter(t=>t.includes(e)):i},[i,s]);async function m(e){e.preventDefault();let r=tv(a);if(!nv(r)){u(`example.com 형식의 도메인을 입력해 주세요. URL, IP 주소, 와일드카드는 사용할 수 없습니다.`);return}u(null),await n(t,r)&&o(``)}let h=d?{badge:`bg-emerald-100 text-emerald-800`,button:`border-emerald-700 bg-emerald-700 text-white hover:border-emerald-800 hover:bg-emerald-800 focus-visible:ring-emerald-100`,icon:`bg-emerald-50 text-emerald-700`,label:`허용 목록`,description:`차단 목록에 포함되어도 허용할 도메인과 하위 도메인을 등록합니다.`,empty:`등록된 허용 도메인이 없습니다.`}:{badge:`bg-red-100 text-red-800`,button:`border-red-700 bg-red-700 text-white hover:border-red-800 hover:bg-red-800 focus-visible:ring-red-100`,icon:`bg-red-50 text-red-700`,label:`차단 목록`,description:`SafeShield 기본 목록에 없더라도 직접 차단할 도메인을 등록합니다.`,empty:`등록된 차단 도메인이 없습니다.`};return B(`article`,{class:`min-w-0 rounded-2xl border border-slate-200 bg-white shadow-sm shadow-slate-900/5`,children:[B(`div`,{class:`border-b border-slate-200 p-4 sm:p-6`,children:[B(`div`,{class:`flex items-start justify-between gap-4`,children:B(`div`,{class:`flex min-w-0 items-start gap-3`,children:[B(`span`,{class:`grid size-11 shrink-0 place-items-center rounded-xl ${h.icon}`,children:B(d?Xt:At,{class:`size-6`})}),B(`div`,{class:`min-w-0`,children:[B(`div`,{class:`flex flex-wrap items-center gap-2`,children:[B(`h2`,{class:`m-0 text-xl font-extrabold tracking-tight text-slate-950`,children:h.label}),B(`span`,{class:`rounded-full px-2.5 py-1 text-xs font-extrabold ${h.badge}`,children:i.length})]}),B(`p`,{class:`mt-2 mb-0 text-sm leading-6 text-slate-600`,children:h.description})]})]})}),B(`form`,{class:`mt-5`,onSubmit:m,children:[B(`label`,{class:`block text-xs font-extrabold text-slate-600`,for:`${t}-domain`,children:`새 도메인`}),B(`div`,{class:`mt-2 flex flex-col gap-2 sm:flex-row`,children:[B(`input`,{"aria-describedby":l?`${t}-domain-error`:void 0,"aria-invalid":l?!0:void 0,autocomplete:`off`,class:`min-h-11 min-w-0 flex-1 rounded-xl border-2 border-slate-300 bg-slate-50 px-4 py-2.5 text-sm font-semibold text-slate-950 shadow-inner outline-none transition placeholder:text-slate-400 focus:border-teal-500 focus:bg-white focus:ring-4 focus:ring-teal-100 disabled:cursor-not-allowed disabled:bg-slate-100`,disabled:f,id:`${t}-domain`,onInput:e=>o(e.currentTarget.value),placeholder:`example.com`,spellcheck:!1,type:`text`,value:a}),B(`button`,{class:`inline-flex min-h-11 w-full shrink-0 items-center justify-center gap-2 sm:w-auto rounded-xl border px-4 py-2.5 text-sm font-extrabold transition focus:outline-none focus-visible:ring-4 disabled:cursor-not-allowed disabled:opacity-50 ${h.button}`,disabled:f||a.trim().length===0,type:`submit`,children:[B(Zt,{class:`size-4`}),e?.operation===`add`&&e.action===t?`추가 중…`:`추가`]})]}),l?B(`p`,{class:`mt-2 mb-0 text-xs font-semibold leading-5 text-red-700`,id:`${t}-domain-error`,children:l}):null]})]}),B(`div`,{class:`p-4 sm:p-6`,children:[B(`label`,{class:`relative block`,for:`${t}-search`,children:[B(`span`,{class:`sr-only`,children:[h.label,` 검색`]}),B(`span`,{class:`pointer-events-none absolute inset-y-0 left-0 flex w-11 items-center justify-center text-slate-400`,children:B($t,{class:`size-4`})}),B(`input`,{class:`min-h-11 w-full rounded-xl border-2 border-slate-300 bg-slate-50 py-2.5 pr-4 pl-11 text-sm font-semibold text-slate-950 shadow-inner outline-none transition placeholder:text-slate-400 focus:border-teal-500 focus:bg-white focus:ring-4 focus:ring-teal-100`,id:`${t}-search`,onInput:e=>c(e.currentTarget.value),placeholder:`${h.label} 검색`,type:`search`,value:s})]}),B(`div`,{class:`mt-4 max-h-[28rem] overflow-y-auto rounded-xl border border-slate-200`,children:p.length>0?B(`ul`,{class:`m-0 list-none divide-y divide-slate-200 p-0`,children:p.map(n=>{let i=e?.operation===`delete`&&e.action===t&&e.domain===n;return B(`li`,{class:`flex min-w-0 items-center justify-between gap-3 px-3.5 py-3`,children:[B(`code`,{class:`min-w-0 break-all font-mono text-sm font-semibold text-slate-800`,children:n}),B(`button`,{"aria-label":`${n} ${h.label}에서 삭제`,class:`inline-flex size-9 shrink-0 items-center justify-center rounded-lg border border-slate-200 bg-white text-slate-500 transition hover:border-red-200 hover:bg-red-50 hover:text-red-700 focus:outline-none focus-visible:ring-4 focus-visible:ring-red-100 disabled:cursor-not-allowed disabled:opacity-50`,disabled:f,onClick:()=>void r(t,n),title:`삭제`,type:`button`,children:B(Qt,{class:`size-4 ${i?`animate-pulse`:``}`})})]},n)})}):B(`div`,{class:`px-5 py-10 text-center`,children:[B(en,{class:`mx-auto size-8 text-slate-300`}),B(`p`,{class:`mt-3 mb-0 text-sm font-bold text-slate-600`,children:s.trim().length>0?`검색 결과가 없습니다.`:h.empty})]})})]})]})}function iv({action:e,data:t,error:n,feedback:r,loading:i,onAddRule:a,onDeleteRule:o,onDismissFeedback:s,onRetry:c}){return i&&!t?B(io,{}):n&&!t?B(ao,{message:n,onRetry:c}):t?B(S,{children:[B(`section`,{class:`rounded-2xl border border-slate-200 bg-white p-4 shadow-sm shadow-slate-900/5 sm:p-6`,children:B(`div`,{class:`flex flex-col gap-4 lg:flex-row lg:items-center lg:justify-between`,children:[B(`div`,{class:`flex min-w-0 items-start gap-3 sm:gap-4`,children:[B(`span`,{class:`grid size-12 shrink-0 place-items-center rounded-2xl bg-teal-50 text-teal-700`,children:B(en,{class:`size-7`})}),B(`div`,{class:`min-w-0`,children:[B(`p`,{class:`m-0 text-xs font-extrabold uppercase tracking-[0.16em] text-teal-700`,children:`Local overrides`}),B(`h2`,{class:`mt-2 mb-0 break-words text-xl font-black tracking-tight text-slate-950 sm:text-2xl`,children:`사용자 도메인 규칙`}),B(`p`,{class:`mt-2 mb-0 max-w-3xl text-sm leading-6 text-slate-600`,children:`허용 목록은 오탐을 해제하고, 차단 목록은 원하는 도메인을 SafeShield 보호 목록에 추가합니다.`})]})]}),B(`dl`,{class:`m-0 grid grid-cols-3 gap-2 sm:min-w-80`,children:[B(`div`,{class:`rounded-xl bg-emerald-50 px-3 py-3 text-center`,children:[B(`dt`,{class:`text-[0.68rem] font-extrabold uppercase tracking-wide text-emerald-700`,children:`허용`}),B(`dd`,{class:`mt-1 mb-0 ml-0 text-lg font-black text-emerald-950`,children:t.counts.allow})]}),B(`div`,{class:`rounded-xl bg-red-50 px-3 py-3 text-center`,children:[B(`dt`,{class:`text-[0.68rem] font-extrabold uppercase tracking-wide text-red-700`,children:`차단`}),B(`dd`,{class:`mt-1 mb-0 ml-0 text-lg font-black text-red-950`,children:t.counts.block})]}),B(`div`,{class:`rounded-xl bg-slate-100 px-3 py-3 text-center`,children:[B(`dt`,{class:`text-[0.68rem] font-extrabold uppercase tracking-wide text-slate-600`,children:`전체`}),B(`dd`,{class:`mt-1 mb-0 ml-0 text-lg font-black text-slate-950`,children:t.counts.total})]})]})]})}),t.applyLocalOverrides?null:B(`section`,{class:`mt-4 flex items-start gap-3 rounded-2xl border border-amber-200 bg-amber-50 p-4`,role:`alert`,children:[B(U,{class:`mt-0.5 size-5 shrink-0 text-amber-700`}),B(`div`,{children:[B(`p`,{class:`m-0 text-sm font-extrabold text-amber-950`,children:`로컬 규칙 적용이 꺼져 있습니다`}),B(`p`,{class:`mt-1 mb-0 text-sm leading-6 text-amber-800`,children:`규칙은 저장되지만 SafeShield의 apply_local_overrides 설정을 켜기 전까지 DNS에 반영되지 않습니다.`})]})]}),t.safeshieldEnabled?null:B(`section`,{class:`mt-4 flex items-start gap-3 rounded-2xl border border-slate-200 bg-slate-100 p-4`,role:`status`,children:[B(At,{class:`mt-0.5 size-5 shrink-0 text-slate-600`}),B(`div`,{children:[B(`p`,{class:`m-0 text-sm font-extrabold text-slate-950`,children:`SafeShield가 비활성화되어 있습니다`}),B(`p`,{class:`mt-1 mb-0 text-sm leading-6 text-slate-600`,children:`규칙을 미리 저장할 수 있으며, SafeShield를 켜고 차단 목록을 갱신하면 적용됩니다.`})]})]}),r?B(`section`,{"aria-live":`polite`,class:`mt-4 flex flex-col items-start gap-3 rounded-2xl border border-teal-200 bg-teal-50 sm:flex-row sm:justify-between p-4`,children:[B(`div`,{class:`flex min-w-0 items-start gap-3`,children:[B(Xt,{class:`mt-0.5 size-5 shrink-0 text-teal-700`}),B(`p`,{class:`m-0 text-sm font-semibold leading-6 text-teal-950`,children:r})]}),B(`button`,{class:`shrink-0 rounded-lg border-0 bg-transparent px-2 py-1 text-xs font-extrabold text-teal-800 hover:bg-teal-100`,onClick:s,type:`button`,children:`닫기`})]}):null,n&&t?B(`section`,{"aria-live":`assertive`,class:`mt-4 flex items-start gap-3 rounded-2xl border border-red-200 bg-red-50 p-4`,children:[B(U,{class:`mt-0.5 size-5 shrink-0 text-red-700`}),B(`p`,{class:`m-0 text-sm font-semibold leading-6 text-red-900`,children:n})]}):null,B(`section`,{class:`mt-5 grid gap-5 xl:grid-cols-2`,children:[B(rv,{action:e,kind:`allow`,onAddRule:a,onDeleteRule:o,rules:t.allow}),B(rv,{action:e,kind:`block`,onAddRule:a,onDeleteRule:o,rules:t.block})]}),B(`p`,{class:`mt-5 mb-0 text-xs leading-5 text-slate-500`,children:`규칙 저장과 유효성 검사는 SafeShield API가 관리합니다. 도메인은 소문자로 정규화되고 중복 항목은 하나로 유지됩니다.`})]}):B(ao,{message:`사용자 규칙 응답이 비어 있습니다.`,onRetry:c})}function av(e,t){return z(`smartsafehub`,`system_root_password_change`,{current_password:e,new_password:t})}var ov=Array.from({length:24},(e,t)=>{let n=String(t).padStart(2,`0`);return{value:n,label:`${n}시`}}),sv=Array.from({length:60},(e,t)=>{let n=String(t).padStart(2,`0`);return{value:n,label:`${n}분`}});function cv(e){let t=/^([01]\d|2[0-3]):([0-5]\d)$/.exec(e);return{hour:t?.[1]??`03`,minute:t?.[2]??`00`}}function lv({ariaLabel:e,className:t=``,disabled:n=!1,id:r,onChange:i,value:a,variant:o=`default`}){let{hour:s,minute:c}=cv(a),l=(e,t)=>{i(`${e}:${t}`)};return B(`div`,{"aria-label":e,class:`ssh-time-select ${t}`.trim(),"data-time-select":r,role:`group`,children:[B(Vg,{ariaLabel:`${e} 시`,disabled:n,id:`${r}-hour`,onChange:e=>l(e,c),options:ov,value:s,variant:o}),B(Vg,{ariaLabel:`${e} 분`,disabled:n,id:`${r}-minute`,onChange:e=>l(s,e),options:sv,value:c,variant:o})]})}function uv(e){return B(`article`,{class:`min-w-0 rounded-2xl border border-slate-200 bg-white p-4 shadow-sm shadow-slate-900/5 sm:p-5`,children:[B(`p`,{class:`m-0 text-xs font-extrabold uppercase tracking-[0.16em] text-slate-500`,children:e.label}),B(`p`,{class:`mt-3 mb-0 break-words text-2xl font-black tracking-tight text-slate-950`,children:e.value}),B(`p`,{class:`mt-2 mb-0 text-sm leading-6 text-slate-500`,children:e.description})]})}function dv(e){return B(`article`,{class:`min-w-0 rounded-2xl border border-slate-200 bg-white p-5 shadow-sm shadow-slate-900/5 sm:p-6 ${e.className??``}`,children:[B(`div`,{class:`flex min-w-0 items-start gap-4`,children:[B(`div`,{class:`flex size-11 shrink-0 items-center justify-center rounded-xl bg-slate-100 text-slate-600`,children:e.icon}),B(`div`,{class:`min-w-0`,children:[B(`h2`,{class:`m-0 text-lg font-black text-slate-950`,children:e.title}),B(`p`,{class:`mt-1.5 mb-0 text-sm leading-6 text-slate-500`,children:e.description})]})]}),B(`div`,{class:`mt-5`,children:e.children})]})}function fv(){try{return Intl.DateTimeFormat().resolvedOptions().timeZone||null}catch{return null}}function pv(e){let[t,n]=N(``),[r,i]=N(e.data?.localtime??0),a=fv();P(()=>{e.data?.zonename&&n(e.data.zonename)},[e.data?.zonename]),P(()=>{let t=e.data?.localtime??0,n=Date.now();if(i(t),!Number.isFinite(t)||t<=0)return;let r=window.setInterval(()=>{i(t+Math.floor((Date.now()-n)/1e3))},1e3);return()=>window.clearInterval(r)},[e.data?.localtime]);let o=e.data?Object.keys(e.data.timezones).sort((e,t)=>e.localeCompare(t)):[],s=La(r,e.data?.zonename??`UTC`),c=a!==null&&e.data?.timezones[a]!==void 0,l=e.data!==null&&t.length>0&&t!==e.data.zonename;return B(dv,{description:`공유기의 기준 시간대를 설정합니다. 로그, 통계, 자동 설치와 예약 재부팅 시각도 이 시간대를 기준으로 동작합니다.`,icon:B(Vt,{class:`size-5`}),title:`시간 및 시간대`,children:[(e.saveError||e.saveMessage)&&B(`div`,{class:`mb-5 flex min-w-0 items-start justify-between gap-3 rounded-xl border px-4 py-3 text-sm font-bold ${e.saveError?`border-rose-200 bg-rose-50 text-rose-800`:`border-emerald-200 bg-emerald-50 text-emerald-800`}`,children:[B(`span`,{class:`min-w-0`,children:e.saveError||e.saveMessage}),B(`button`,{class:`shrink-0 rounded-lg px-2 py-1 text-xs font-extrabold hover:bg-black/5`,onClick:e.onDismissFeedback,type:`button`,children:`닫기`})]}),e.error&&!e.data?B(`div`,{class:`rounded-xl border border-rose-200 bg-rose-50 p-4`,children:[B(`p`,{class:`m-0 text-sm font-bold text-rose-800`,children:e.error}),B(`button`,{class:`mt-3 inline-flex min-h-10 items-center rounded-xl border border-rose-300 bg-white px-3 py-2 text-xs font-extrabold text-rose-700 transition hover:bg-rose-100`,onClick:e.onRetry,type:`button`,children:`다시 불러오기`})]}):B(S,{children:[B(`div`,{class:`grid min-w-0 grid-cols-1 gap-3 sm:grid-cols-2`,children:[B(`div`,{class:`rounded-xl bg-slate-50 p-4`,children:[B(`p`,{class:`m-0 text-xs font-extrabold uppercase tracking-[0.12em] text-slate-500`,children:`현재 시간`}),B(`p`,{class:`mt-2 mb-0 text-sm font-extrabold leading-6 text-slate-900`,children:s}),B(`p`,{class:`mt-1 mb-0 break-words text-xs leading-5 text-slate-500`,children:e.data?.zonename??`시간대 확인 중`})]}),B(`div`,{class:`rounded-xl bg-slate-50 p-4`,children:[B(`p`,{class:`m-0 text-xs font-extrabold uppercase tracking-[0.12em] text-slate-500`,children:`시간 동기화`}),B(`p`,{class:`mt-2 mb-0 text-sm font-extrabold ${e.data?.ntpEnabled?`text-emerald-700`:`text-amber-700`}`,children:e.data?.ntpEnabled?`자동 동기화 설정됨`:`자동 동기화 꺼짐`}),B(`p`,{class:`mt-1 mb-0 text-xs leading-5 text-slate-500`,children:`장치의 기본 NTP 설정 상태입니다.`}),B(`button`,{class:`mt-3 inline-flex min-h-9 items-center justify-center gap-2 rounded-lg border border-slate-300 bg-white px-3 py-2 text-xs font-extrabold text-slate-700 transition hover:bg-slate-100 disabled:cursor-not-allowed disabled:opacity-50`,disabled:!e.data?.ntpEnabled||e.saving||e.syncing,onClick:()=>void e.onSync(),type:`button`,children:e.syncing?`동기화 요청 중`:`지금 동기화`})]})]}),B(`div`,{class:`mt-5`,children:[B(`label`,{class:`mb-2 block text-sm font-extrabold text-slate-800`,for:`smartsafehub-timezone`,children:`시간대`}),B(Vg,{ariaLabel:`시간대`,disabled:e.loading||e.saving||e.syncing||!e.data,id:`smartsafehub-timezone`,onChange:n,options:e.data?o.map(e=>({value:e,label:e})):[{value:``,label:`시간대 불러오는 중`}],value:t}),B(`p`,{class:`mt-2 mb-0 text-xs leading-5 text-slate-500`,children:`시간대를 변경하면 시스템에 즉시 적용되며 자동 설치와 예약 재부팅 일정도 새 기준 시간으로 다시 계산합니다.`})]}),B(`div`,{class:`mt-4 flex flex-col gap-3 sm:flex-row sm:flex-wrap sm:justify-end`,children:[c&&a!==t&&B(`button`,{class:`inline-flex min-h-11 w-full items-center justify-center rounded-xl border border-slate-300 bg-white px-4 py-2.5 text-sm font-extrabold text-slate-700 transition hover:bg-slate-50 disabled:opacity-60 sm:w-auto`,disabled:e.saving||e.syncing,onClick:()=>n(a),type:`button`,children:`브라우저 시간대 사용`}),B(`button`,{class:`inline-flex min-h-11 w-full items-center justify-center rounded-xl bg-teal-700 px-4 py-2.5 text-sm font-extrabold text-white transition hover:bg-teal-800 disabled:cursor-not-allowed disabled:opacity-50 sm:w-auto`,disabled:!l||e.saving||e.syncing,onClick:()=>void e.onSave(t),type:`button`,children:e.saving?`시간대 저장 중`:`시간대 저장`})]})]}),B(Tv,{data:e.scheduledRebootData,error:e.scheduledRebootError,loading:e.scheduledRebootLoading,onDismissFeedback:e.onDismissScheduledRebootFeedback,onRetry:e.onRetry,onSave:e.onSaveScheduledReboot,saveError:e.scheduledRebootSaveError,saveMessage:e.scheduledRebootSaveMessage,saving:e.scheduledRebootSaving})]})}function mv(e){return e===`initializing`?{badge:`bg-teal-100 text-teal-800`,panel:`border-teal-200 bg-teal-50`,label:`준비 중`}:e===`critical`?{badge:`bg-rose-100 text-rose-800`,panel:`border-rose-200 bg-rose-50`,label:`이상`}:e===`warning`?{badge:`bg-amber-100 text-amber-800`,panel:`border-amber-200 bg-amber-50`,label:`주의`}:e===`unknown`?{badge:`bg-slate-200 text-slate-700`,panel:`border-slate-200 bg-slate-50`,label:`확인 불가`}:{badge:`bg-emerald-100 text-emerald-800`,panel:`border-emerald-200 bg-emerald-50`,label:`정상`}}function hv(e){if(!e.enabled)return`보고 중지됨`;switch(e.lastResult){case`reported`:return`정상 보고`;case`initializing`:return e.lastReportAt>0?`상태 갱신 중`:`첫 보고 진행 중`;case`failed`:return`최근 보고 실패`;case`idle`:return`다음 보고 대기`;case`ineligible`:return`멤버십 확인 필요`;case`disabled`:case`never`:return`첫 보고 준비 중`;default:return`보고 준비 중`}}function gv(e){return e.lastReportAt>0?Ia(e.lastReportAt):e.enabled?`첫 보고 대기 중`:`보고 기록 없음`}function _v(e){let t=e?.plan?.trim().toUpperCase(),n=e?.licenseStatus?.trim().toLowerCase();return t&&(n===`trial`||n===`trialing`)?`${t} · 체험`:t||`유료 · Trial`}function vv(e){let t=e.data,n=mv(t?.overall??`unknown`),r=t?.checks.filter(e=>e.status!==`ok`)??[],i=r.length>0?r.slice(0,4):t?.checks.filter(e=>[`system.memory`,`network.wan`,`service.dnsmasq`,`safeshield.runtime`].includes(e.id))??[],a=t?.reporter,o=a?.enabled===!0,s=a?.eligible===!0||o,c=e.savingReporter?o?`원격 상태 보고를 켜고 있습니다.`:`원격 상태 보고를 끄고 있습니다.`:o?`원격 상태 보고가 켜져 있습니다.`:`원격 상태 보고가 꺼져 있습니다.`,l=o?`장치 상태가 바뀌면 즉시 보고하고, 정상 상태에서도 주기적으로 SmartSafeHub 서버에 보고합니다.`:`로컬 진단은 계속 동작하지만 장치 상태는 SmartSafeHub 서버에 자동으로 전송되지 않습니다.`;return B(dv,{description:`SmartSafeHub가 장치 상태를 직접 점검하고 이상 항목을 알려줍니다. 로컬 진단은 멤버십과 관계없이 사용할 수 있습니다.`,icon:B(Wt,{class:`size-5`}),title:`진단 및 지원`,children:[(e.actionError||e.actionMessage)&&B(`div`,{class:`mb-4 flex items-start justify-between gap-3 rounded-xl border px-4 py-3 text-sm font-bold ${e.actionError?`border-rose-200 bg-rose-50 text-rose-800`:`border-emerald-200 bg-emerald-50 text-emerald-800`}`,children:[B(`span`,{children:e.actionError||e.actionMessage}),B(`button`,{class:`shrink-0 rounded-lg px-2 py-1 text-xs font-extrabold hover:bg-black/5`,onClick:e.onDismissFeedback,type:`button`,children:`닫기`})]}),e.error&&!t?B(`div`,{class:`rounded-xl border border-rose-200 bg-rose-50 p-4`,children:[B(`p`,{class:`m-0 text-sm font-bold text-rose-800`,children:e.error}),B(`button`,{class:`mt-3 inline-flex min-h-10 items-center rounded-xl border border-rose-300 bg-white px-3 py-2 text-xs font-extrabold text-rose-700 transition hover:bg-rose-100`,onClick:e.onRetry,type:`button`,children:`다시 불러오기`})]}):B(S,{children:[B(`div`,{class:`rounded-xl border p-4 ${n.panel}`,children:B(`div`,{class:`flex flex-wrap items-start justify-between gap-3`,children:[B(`div`,{class:`flex min-w-0 items-start gap-3`,children:[B(`span`,{class:`mt-0.5 shrink-0`,children:t?.overall===`ok`?B(Xt,{class:`size-5 text-emerald-700`}):t?.overall===`initializing`?B(Vt,{class:`size-5 text-teal-700`}):B(U,{class:`size-5 text-amber-700`})}),B(`div`,{class:`min-w-0`,children:[B(`p`,{class:`m-0 text-sm font-black text-slate-950`,children:t?.summary.message??`장치 상태를 확인하고 있습니다.`}),B(`p`,{class:`mt-1 mb-0 text-xs leading-5 text-slate-600`,children:[`마지막 진단 : `,t?Ia(t.generatedAt):`확인 중`]})]})]}),B(`span`,{class:`rounded-full px-2.5 py-1 text-xs font-extrabold ${n.badge}`,children:n.label})]})}),t&&B(`div`,{class:`mt-4 grid grid-cols-3 gap-2`,children:[B(`div`,{class:`rounded-xl bg-slate-50 p-3`,children:[B(`p`,{class:`m-0 text-[11px] font-extrabold text-slate-500`,children:`진단 항목`}),B(`p`,{class:`mt-1 mb-0 text-lg font-black text-slate-950`,children:t.summary.total})]}),B(`div`,{class:`rounded-xl bg-slate-50 p-3`,children:[B(`p`,{class:`m-0 text-[11px] font-extrabold text-slate-500`,children:`주의`}),B(`p`,{class:`mt-1 mb-0 text-lg font-black text-amber-700`,children:t.summary.warning})]}),B(`div`,{class:`rounded-xl bg-slate-50 p-3`,children:[B(`p`,{class:`m-0 text-[11px] font-extrabold text-slate-500`,children:`이상`}),B(`p`,{class:`mt-1 mb-0 text-lg font-black text-rose-700`,children:t.summary.critical})]})]}),i.length>0&&B(`div`,{class:`mt-4 space-y-2`,children:i.map(e=>{let t=mv(e.status);return B(`div`,{class:`flex min-w-0 items-start justify-between gap-3 rounded-xl border border-slate-200 px-3 py-2.5`,children:[B(`div`,{class:`min-w-0`,children:[B(`p`,{class:`m-0 text-xs font-extrabold text-slate-900`,children:e.label}),B(`p`,{class:`mt-1 mb-0 text-xs leading-5 text-slate-500`,children:e.message})]}),B(`span`,{class:`shrink-0 rounded-full px-2 py-1 text-[11px] font-extrabold ${t.badge}`,children:t.label})]},e.id)})}),B(`div`,{class:`mt-4 flex flex-col gap-2 sm:flex-row`,children:[B(`button`,{class:`inline-flex min-h-11 w-full items-center justify-center rounded-xl bg-teal-700 px-4 py-2.5 text-sm font-extrabold text-white transition hover:bg-teal-800 disabled:cursor-wait disabled:opacity-60 sm:w-auto`,disabled:e.running||e.loading,onClick:e.onRun,type:`button`,children:e.running?`진단 중`:`지금 진단`}),B(`button`,{class:`inline-flex min-h-11 w-full items-center justify-center rounded-xl border border-slate-300 bg-white px-4 py-2.5 text-sm font-extrabold text-slate-800 transition hover:bg-slate-50 disabled:cursor-wait disabled:opacity-60 sm:w-auto`,disabled:e.downloadBusy,onClick:e.onDownload,type:`button`,children:e.downloadBusy?`진단 정보 생성 중`:`진단 정보 다운로드`})]}),B(`p`,{class:`mt-3 mb-0 text-xs leading-5 text-slate-500`,children:`다운로드 파일에는 호스트명, WAN IP와 Wi-Fi SSID 같은 네트워크 식별 정보가 포함될 수 있으므로 외부 전달 전에 내용을 확인해 주세요.`}),B(`div`,{class:`mt-5 border-t border-slate-200 pt-5`,children:[B(`div`,{class:`flex min-w-0 items-start justify-between gap-4`,children:[B(`div`,{class:`min-w-0`,children:[B(`div`,{class:`flex flex-wrap items-center gap-2`,children:[B(`p`,{class:`m-0 text-sm font-black text-slate-950`,children:`원격 상태 보고`}),B(`span`,{class:`rounded-full bg-slate-100 px-2 py-1 text-[10px] font-extrabold uppercase tracking-[0.08em] text-slate-600`,children:_v(a)})]}),B(`p`,{class:`mt-1 mb-0 text-xs leading-5 text-slate-500`,children:`장치의 최소 상태 정보와 이상 코드만 SmartSafeHub 서버에 전송합니다. 기본값은 꺼짐이며 언제든지 다시 끌 수 있습니다.`})]}),B(`button`,{"aria-checked":a?.enabled===!0,"aria-label":`원격 상태 보고 사용`,class:`ssh-switch-control relative inline-flex shrink-0 rounded-full border transition focus:outline-none focus-visible:ring-4 focus-visible:ring-teal-100 disabled:cursor-not-allowed disabled:opacity-50 ${a?.enabled?`border-teal-600 bg-teal-600`:`border-slate-300 bg-slate-200`}`,disabled:!t||e.savingReporter||!s,onClick:()=>e.onSetReporter(!(a?.enabled??!1)),role:`switch`,type:`button`,children:B(`span`,{"aria-hidden":`true`,class:`ssh-switch-thumb absolute top-1 shadow-sm transition-[left] ${a?.enabled?`left-6`:`left-1`}`})})]}),a?.eligible?B(`div`,{class:`mt-4 rounded-xl bg-slate-50 p-4`,children:[B(`div`,{class:`mb-4 flex items-start gap-3 rounded-xl border p-3 ${o?`border-emerald-200 bg-emerald-50`:`border-slate-200 bg-white`}`,children:[B(`span`,{class:`mt-0.5 shrink-0`,children:o?B(Xt,{class:`size-5 text-emerald-700`}):B(Ut,{class:`size-5 text-slate-500`})}),B(`div`,{class:`min-w-0 flex-1`,children:[B(`div`,{class:`flex flex-wrap items-center gap-2`,children:[B(`p`,{class:`m-0 text-sm font-black text-slate-950`,children:c}),B(`span`,{class:`rounded-full px-2 py-0.5 text-[10px] font-extrabold ${e.savingReporter?`bg-slate-200 text-slate-700`:o?`bg-emerald-100 text-emerald-800`:`bg-slate-200 text-slate-700`}`,children:e.savingReporter?`설정 중`:o?`켜짐`:`꺼짐`})]}),B(`p`,{class:`mt-1 mb-0 text-xs leading-5 text-slate-600`,children:l})]})]}),B(`div`,{class:`grid grid-cols-1 gap-3 sm:grid-cols-2`,children:[B(`div`,{children:[B(`p`,{class:`m-0 text-[11px] font-extrabold text-slate-500`,children:`최근 전송 상태`}),B(`p`,{class:`mt-1 mb-0 text-sm font-black text-slate-900`,children:e.savingReporter?`설정 반영 중`:hv(a)})]}),B(`div`,{children:[B(`p`,{class:`m-0 text-[11px] font-extrabold text-slate-500`,children:`마지막 서버 보고`}),B(`p`,{class:`mt-1 mb-0 text-sm font-black text-slate-900`,children:gv(a)})]})]}),a.enabled&&a.lastErrorCode&&B(`p`,{class:`mt-3 mb-0 text-xs font-bold text-rose-700`,children:[`최근 보고 오류 : `,a.lastErrorCode]})]}):B(`div`,{class:`mt-4 rounded-xl border border-slate-200 bg-slate-50 p-4`,children:[B(`p`,{class:`m-0 text-sm font-extrabold text-slate-900`,children:`원격 상태 보고는 유료 멤버십 또는 체험 기간에 사용할 수 있습니다.`}),B(`a`,{class:`mt-3 inline-flex text-xs font-extrabold text-teal-700 hover:text-teal-800`,href:`https://www.smartsafehub.com/pricing/`,rel:`noopener noreferrer`,target:`_blank`,children:`멤버십 알아보기`})]}),B(`div`,{class:`mt-4 grid grid-cols-1 gap-3 text-xs leading-5 text-slate-500 sm:grid-cols-2`,children:[B(`div`,{class:`rounded-xl border border-slate-200 p-3`,children:[B(`p`,{class:`m-0 font-extrabold text-slate-700`,children:`전송되는 정보`}),B(`p`,{class:`mt-1 mb-0`,children:`메모리·부하·저장 공간 수치, 진단 상태, 이상 코드와 보고 시각`})]}),B(`div`,{class:`rounded-xl border border-slate-200 p-3`,children:[B(`p`,{class:`m-0 font-extrabold text-slate-700`,children:`전송하지 않는 정보`}),B(`p`,{class:`mt-1 mb-0`,children:`호스트명, WAN IP, Wi-Fi SSID/MAC, DNS 요청 내용, 시스템 로그 원문`})]})]})]})]})]})}function yv(e){let[t,n]=N(!1);return B(`label`,{class:`block min-w-0`,for:e.id,children:[B(`span`,{class:`mb-2 block text-sm font-extrabold text-slate-800`,children:e.label}),B(`span`,{class:`relative block min-w-0`,children:[B(`input`,{autoComplete:e.autoComplete,class:`min-h-11 w-full rounded-xl border border-slate-300 bg-white px-3 py-2.5 pr-12 text-sm font-bold text-slate-900 outline-none transition focus:border-teal-500 focus:ring-2 focus:ring-teal-100 disabled:cursor-wait disabled:opacity-60`,disabled:e.disabled,id:e.id,name:e.name,onInput:t=>e.onInput(t.currentTarget.value),placeholder:e.placeholder,type:t?`text`:`password`,value:e.value}),B(`button`,{"aria-label":t?`${e.label} 숨기기`:`${e.label} 표시`,"aria-pressed":t,class:`absolute inset-y-0 right-1 my-auto flex size-9 items-center justify-center rounded-lg text-slate-500 transition hover:bg-slate-100 hover:text-slate-800 disabled:opacity-50`,disabled:e.disabled,onClick:()=>n(e=>!e),title:t?`비밀번호 숨기기`:`비밀번호 표시`,type:`button`,children:B(t?Jt:qt,{class:`size-4`})})]})]})}function bv(e){return B(`li`,{class:`flex min-w-0 items-center gap-1.5 text-xs font-bold ${e.met?`text-emerald-700`:`text-slate-500`}`,children:[B(Xt,{class:`size-3.5 shrink-0`,"aria-hidden":`true`}),B(`span`,{children:e.label})]})}function xv(e){let[t,n]=N(``),[r,i]=N(``),[a,o]=N(``),[s,c]=N(!1),[l,u]=N(null),d=mn(r),f=hn(d),p=a.length>0&&r===a,m=t.length>0&&r.length>0&&t!==r,h=!s&&m&&f&&p,g=async()=>{if(u(null),!t){u(`현재 관리자 비밀번호를 입력해 주세요.`);return}if(!f){u(`새 비밀번호는 8자 이상이며 영문과 숫자를 각각 하나 이상 포함해야 합니다.`);return}if(t===r){u(`새 관리자 비밀번호는 현재 비밀번호와 다르게 설정해 주세요.`);return}if(r!==a){u(`새 비밀번호 확인 값이 일치하지 않습니다.`);return}c(!0);try{await av(t,r),n(``),i(``),o(``);try{await je()}catch{}c(!1),e.onChanged()}catch(e){u(G(e,`관리자 비밀번호를 변경하지 못했습니다. 잠시 후 다시 시도해 주세요.`)),c(!1)}};return B(dv,{description:`현재 비밀번호를 확인한 뒤 공유기 관리자 비밀번호를 변경합니다. 변경이 완료되면 새 비밀번호로 다시 로그인해야 합니다.`,icon:B(Kt,{class:`size-5`}),title:`관리자 비밀번호`,children:B(`form`,{class:`space-y-4`,noValidate:!0,onSubmit:e=>{e.preventDefault(),g()},children:[l&&B(`div`,{"aria-live":`polite`,class:`rounded-xl border border-rose-200 bg-rose-50 px-4 py-3 text-sm font-bold text-rose-800`,role:`alert`,children:l}),B(yv,{autoComplete:`current-password`,disabled:s,id:`smartsafehub-current-admin-password`,label:`현재 비밀번호`,name:`current-password`,onInput:n,placeholder:`현재 관리자 비밀번호`,value:t}),B(yv,{autoComplete:`new-password`,disabled:s,id:`smartsafehub-new-admin-password`,label:`새 비밀번호`,name:`new-password`,onInput:i,placeholder:`새 관리자 비밀번호`,value:r}),B(`ul`,{"aria-label":`새 비밀번호 요구 사항`,class:`m-0 grid list-none grid-cols-1 gap-2 p-0 sm:grid-cols-3`,children:[B(bv,{label:`8자 이상`,met:d.length}),B(bv,{label:`영문자 포함`,met:d.letter}),B(bv,{label:`숫자 포함`,met:d.number})]}),B(yv,{autoComplete:`new-password`,disabled:s,id:`smartsafehub-confirm-admin-password`,label:`새 비밀번호 확인`,name:`confirm-password`,onInput:o,placeholder:`새 관리자 비밀번호 다시 입력`,value:a}),a.length>0&&B(`p`,{"aria-live":`polite`,class:`m-0 text-xs font-bold ${p?`text-emerald-700`:`text-rose-700`}`,role:`status`,children:p?`새 비밀번호가 일치합니다.`:`새 비밀번호 확인 값이 일치하지 않습니다.`}),r.length>0&&t===r&&B(`p`,{class:`m-0 text-xs font-bold text-amber-700`,children:`새 비밀번호는 현재 비밀번호와 다르게 설정해 주세요.`}),B(`div`,{class:`rounded-xl border border-slate-200 bg-slate-50 p-3 text-xs leading-5 text-slate-600`,children:`비밀번호는 현재 공유기에 직접 적용되며 외부 서버로 전송되지 않습니다. 변경 후 현재 로그인 세션은 종료됩니다.`}),B(`div`,{class:`rounded-xl border border-amber-200 bg-amber-50 p-3 text-xs leading-5 text-amber-900`,children:[B(`strong`,{class:`block font-extrabold`,children:`비밀번호를 잊었을 때`}),`전원이 켜진 상태에서 Reset 버튼을 5~9초 누른 뒤 놓으면 관리자 비밀번호만 복구할 수 있습니다. 네트워크, Wi-Fi와 SafeShield 설정은 유지됩니다. 10초 이상 누르면 모든 사용자 설정을 초기화하는 기기 초기화가 실행됩니다.`]}),B(`div`,{class:`flex justify-end`,children:B(`button`,{class:`inline-flex min-h-11 w-full items-center justify-center rounded-xl bg-teal-700 px-4 py-2.5 text-sm font-extrabold text-white transition hover:bg-teal-800 disabled:cursor-not-allowed disabled:opacity-50 sm:w-auto`,disabled:!h,type:`submit`,children:s?`비밀번호 변경 중`:`비밀번호 변경`})})]})})}function Sv(e){let t=F(null),[n,r]=N(null),[i,a]=N(!1),o=e.action!==null;P(()=>{e.validated||a(!1)},[e.validated]);let s=()=>{!o&&!e.restoreAccepted&&t.current?.click()},c=async()=>{n&&await e.onUpload(n)&&(r(null),t.current&&(t.current.value=``))};return B(dv,{description:`펌웨어 업데이트나 복구 전에 현재 OpenWrt 설정을 표준 백업 파일로 저장하고, 필요할 때 검증 후 복원합니다.`,icon:B(Gt,{class:`size-5`}),title:`설정 백업 및 복원`,children:[(e.error||e.message)&&B(`div`,{class:`mb-5 flex min-w-0 items-start justify-between gap-3 rounded-xl border px-4 py-3 text-sm font-bold ${e.error?`border-rose-200 bg-rose-50 text-rose-800`:`border-emerald-200 bg-emerald-50 text-emerald-800`}`,children:[B(`span`,{class:`min-w-0`,children:e.error||e.message}),!e.restoreAccepted&&B(`button`,{class:`shrink-0 rounded-lg px-2 py-1 text-xs font-extrabold hover:bg-black/5`,onClick:e.onDismissFeedback,type:`button`,children:`닫기`})]}),B(`div`,{class:`grid min-w-0 grid-cols-1 gap-3`,children:[B(`div`,{class:`rounded-xl border border-slate-200 bg-slate-50 p-4 sm:p-5`,children:[B(`p`,{class:`m-0 text-sm font-black text-slate-900`,children:`현재 설정 백업`}),B(`p`,{class:`mt-2 mb-0 text-xs leading-5 text-slate-600`,children:`네트워크, Wi-Fi, SmartSafeHub와 SafeShield 등 OpenWrt가 관리하는 설정을 표준 백업 파일로 저장합니다.`}),B(`button`,{class:`mt-4 inline-flex min-h-11 w-full items-center justify-center gap-2 rounded-xl bg-teal-700 px-4 py-2.5 text-sm font-extrabold text-white transition hover:bg-teal-800 disabled:cursor-wait disabled:opacity-60 sm:w-auto`,disabled:o||e.restoreAccepted,onClick:e.onDownload,type:`button`,children:[B(Wt,{class:`size-4`}),e.action===`download`?`백업 생성 중`:`설정 백업 다운로드`]}),B(`p`,{class:`mt-3 mb-0 text-xs font-bold leading-5 text-amber-700`,children:`백업에는 Wi-Fi 비밀번호, 관리자 설정, VPN 키나 라이선스 정보 같은 민감한 값이 포함될 수 있으므로 안전한 위치에 보관해 주세요.`})]}),B(`div`,{class:`rounded-xl border border-slate-200 bg-white p-4 sm:p-5`,children:[B(`p`,{class:`m-0 text-sm font-black text-slate-900`,children:`설정 복원`}),B(`p`,{class:`mt-2 mb-0 text-xs leading-5 text-slate-600`,children:`SmartSafeHub 또는 OpenWrt 백업을 업로드하고 검증한 뒤 복원합니다. 최대 16MB까지 사용할 수 있습니다.`}),e.validated?B(`div`,{class:`mt-4 rounded-xl border border-emerald-200 bg-emerald-50 p-4`,children:[B(`div`,{class:`flex min-w-0 flex-col gap-1 sm:flex-row sm:items-center sm:justify-between`,children:B(`div`,{class:`min-w-0`,children:[B(`p`,{class:`m-0 break-words text-sm font-extrabold text-emerald-900`,children:e.validated.filename}),B(`p`,{class:`mt-1 mb-0 text-xs font-bold text-emerald-700`,children:[Ma(e.validated.sizeBytes),` · 검증 완료`]})]})}),i?B(`div`,{class:`mt-4 rounded-xl border border-rose-200 bg-white p-4`,children:[B(`p`,{class:`m-0 text-sm font-black text-rose-900`,children:`현재 설정을 백업 파일의 내용으로 덮어쓰시겠습니까?`}),B(`p`,{class:`mt-2 mb-0 text-xs leading-5 text-rose-700`,children:`LAN 주소, Wi-Fi, 관리자 접속 정보가 바뀌어 현재 연결이 끊길 수 있습니다. 복원 직후 공유기가 자동으로 재부팅됩니다. 같은 장치와 호환되는 백업만 사용해 주세요.`}),B(`div`,{class:`mt-4 flex flex-col gap-3 sm:flex-row sm:flex-wrap`,children:[B(`button`,{class:`inline-flex min-h-10 w-full items-center justify-center rounded-xl border border-slate-300 bg-white px-4 py-2 text-sm font-extrabold text-slate-700 transition hover:bg-slate-50 disabled:opacity-60 sm:w-auto`,disabled:o,onClick:()=>a(!1),type:`button`,children:`취소`}),B(`button`,{class:`inline-flex min-h-10 w-full items-center justify-center rounded-xl bg-rose-700 px-4 py-2 text-sm font-extrabold text-white transition hover:bg-rose-800 disabled:cursor-wait disabled:opacity-60 sm:w-auto`,disabled:o,onClick:()=>void e.onRestore(),type:`button`,children:e.action===`restore`?`설정 복원 중`:`설정 복원 및 재부팅`})]})]}):B(`div`,{class:`mt-4 flex flex-col gap-3 sm:flex-row sm:flex-wrap`,children:[B(`button`,{class:`inline-flex min-h-10 w-full items-center justify-center rounded-xl border border-slate-300 bg-white px-4 py-2 text-sm font-extrabold text-slate-700 transition hover:bg-slate-50 disabled:opacity-60 sm:w-auto`,disabled:o||e.restoreAccepted,onClick:()=>void e.onDiscard(),type:`button`,children:e.action===`discard`?`파일 삭제 중`:`파일 삭제`}),B(`button`,{class:`inline-flex min-h-10 w-full items-center justify-center rounded-xl bg-amber-600 px-4 py-2 text-sm font-extrabold text-white transition hover:bg-amber-700 disabled:opacity-60 sm:w-auto`,disabled:o||e.restoreAccepted,onClick:()=>a(!0),type:`button`,children:`복원 준비`})]})]}):B(S,{children:[B(`input`,{accept:`.tar.gz,.tgz,application/gzip,application/x-gzip`,class:`sr-only`,disabled:o||e.restoreAccepted,onChange:e=>r(e.currentTarget.files?.[0]??null),ref:t,type:`file`}),B(`button`,{class:`mt-4 flex min-h-11 w-full items-center justify-between gap-3 rounded-xl border border-dashed border-slate-300 bg-slate-50 px-4 py-3 text-left text-sm font-bold text-slate-700 transition hover:border-teal-400 hover:bg-teal-50 disabled:cursor-wait disabled:opacity-60`,disabled:o||e.restoreAccepted,onClick:s,type:`button`,children:[B(`span`,{class:`min-w-0 truncate`,children:n?.name??`복원할 백업 파일 선택`}),B(`span`,{class:`shrink-0 text-xs font-extrabold text-teal-700`,children:`찾아보기`})]}),n&&B(`div`,{class:`mt-3 flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between`,children:[B(`span`,{class:`text-xs font-bold text-slate-500`,children:Ma(n.size)}),B(`button`,{class:`inline-flex min-h-10 w-full items-center justify-center rounded-xl border border-teal-300 bg-white px-4 py-2 text-sm font-extrabold text-teal-800 transition hover:bg-teal-50 disabled:cursor-wait disabled:opacity-60 sm:w-auto`,disabled:o||e.restoreAccepted,onClick:()=>void c(),type:`button`,children:e.action===`upload`?`업로드 중 ${Math.round(e.uploadProgress??0)}%`:e.action===`validate`?`백업 검증 중`:`업로드 및 검증`})]})]})]})]})]})}function Cv(e){return B(dv,{description:`공유기 재부팅과 SmartSafeHub에서 제공하지 않는 고급 관리 도구를 한곳에서 제공합니다.`,...e.className===void 0?{}:{className:e.className},icon:B(It,{class:`size-5`}),title:`시스템 도구`,children:B(`div`,{class:`space-y-3`,children:[B(`section`,{"aria-labelledby":`router-reboot-heading`,class:`rounded-xl border border-slate-200 bg-slate-50 p-4`,children:[B(`div`,{class:`flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between`,children:[B(`div`,{class:`flex min-w-0 items-start gap-3`,children:[B(`span`,{class:`flex size-9 shrink-0 items-center justify-center rounded-lg bg-rose-50 text-rose-700`,children:B(Ut,{class:`size-4`})}),B(`div`,{class:`min-w-0`,children:[B(`p`,{class:`m-0 text-sm font-black text-rose-950`,id:`router-reboot-heading`,children:`공유기 재부팅`}),B(`p`,{class:`mt-1 mb-0 text-xs leading-5 text-slate-500`,children:`재부팅 중에는 인터넷과 Wi-Fi 연결이 잠시 중단됩니다.`})]})]}),!e.confirmingReboot&&B(`button`,{class:`inline-flex min-h-10 w-full shrink-0 items-center justify-center rounded-xl border border-rose-300 bg-white px-3 py-2 text-xs font-extrabold text-rose-700 transition hover:bg-rose-50 disabled:opacity-60 sm:w-auto`,disabled:e.action!==null||e.rebootAccepted,onClick:e.onConfirmReboot,type:`button`,children:`재부팅`})]}),e.confirmingReboot&&B(`div`,{class:`mt-3 rounded-xl border border-rose-200 bg-rose-50 p-3`,children:[B(`p`,{class:`m-0 text-xs font-extrabold leading-5 text-rose-900`,children:`지금 공유기를 재부팅하시겠습니까? 저장되지 않은 LuCI 설정이 있다면 먼저 저장해 주세요.`}),B(`div`,{class:`mt-3 flex flex-col gap-2 sm:flex-row sm:flex-wrap`,children:[B(`button`,{class:`inline-flex min-h-10 w-full items-center justify-center rounded-xl border border-slate-300 bg-white px-3 py-2 text-xs font-extrabold text-slate-700 transition hover:bg-slate-50 sm:w-auto`,disabled:e.action!==null,onClick:e.onCancelReboot,type:`button`,children:`취소`}),B(`button`,{class:`inline-flex min-h-10 w-full items-center justify-center rounded-xl bg-rose-700 px-3 py-2 text-xs font-extrabold text-white transition hover:bg-rose-800 disabled:cursor-wait disabled:opacity-60 sm:w-auto`,disabled:e.action!==null,onClick:e.onReboot,type:`button`,children:e.action===`reboot`?`재부팅 요청 중`:`지금 재부팅`})]})]})]}),B(`section`,{"aria-labelledby":`advanced-tools-heading`,class:`rounded-xl border border-slate-200 bg-slate-50 p-4`,children:[B(`div`,{class:`min-w-0`,children:[B(`p`,{class:`m-0 text-sm font-black text-slate-900`,id:`advanced-tools-heading`,children:`고급 도구`}),B(`p`,{class:`mt-1 mb-0 text-xs leading-5 text-slate-500`,children:`SmartSafeHub에서 아직 제공하지 않는 상세 시스템 설정이나 원본 로그가 필요할 때 사용합니다.`})]}),B(`div`,{class:`mt-3 flex flex-col gap-2 sm:flex-row sm:flex-wrap`,children:[B(`a`,{class:`inline-flex min-h-10 w-full items-center justify-center rounded-xl border border-slate-300 bg-white px-3 py-2 text-xs font-extrabold text-slate-800 no-underline transition hover:bg-slate-50 sm:w-auto`,href:e.advancedSystemUrl,children:`LuCI 고급 설정 열기`}),B(`a`,{class:`inline-flex min-h-10 w-full items-center justify-center rounded-xl border border-slate-300 bg-white px-3 py-2 text-xs font-extrabold text-slate-800 no-underline transition hover:bg-slate-50 sm:w-auto`,href:e.logsUrl,children:`시스템 로그 열기`})]})]})]})})}var wv=[{value:`mon`,label:`월요일`},{value:`tue`,label:`화요일`},{value:`wed`,label:`수요일`},{value:`thu`,label:`목요일`},{value:`fri`,label:`금요일`},{value:`sat`,label:`토요일`},{value:`sun`,label:`일요일`}];function Tv(e){let[t,n]=N(!1),[r,i]=N(`weekly`),[a,o]=N(`sun`),[s,c]=N(`04:00`);P(()=>{e.data&&(n(e.data.enabled),i(e.data.frequency),o(e.data.dayOfWeek),c(e.data.time))},[e.data?.dayOfWeek,e.data?.enabled,e.data?.frequency,e.data?.time]);let l=e.data!==null&&(t!==e.data.enabled||r!==e.data.frequency||a!==e.data.dayOfWeek||s!==e.data.time),u=wv.find(e=>e.value===a),d=t?r===`daily`?`매일 ${s}`:`매주 ${u?.label??`일요일`} ${s}`:`예약 재부팅 꺼짐`;return B(`section`,{"aria-labelledby":`scheduled-reboot-heading`,class:`mt-6 border-t border-slate-200 pt-6`,children:[B(`div`,{class:`flex flex-col gap-4 sm:flex-row sm:items-start sm:justify-between`,children:[B(`div`,{class:`flex min-w-0 items-start gap-3`,children:[B(`span`,{class:`flex size-10 shrink-0 items-center justify-center rounded-xl bg-slate-100 text-slate-600`,children:B(Yt,{class:`size-5`})}),B(`div`,{class:`min-w-0`,children:[B(`h3`,{class:`m-0 text-base font-black text-slate-950`,id:`scheduled-reboot-heading`,children:`예약 재부팅`}),B(`p`,{class:`mt-1.5 mb-0 text-xs leading-5 text-slate-500`,children:`공유기를 정해진 시간에 자동으로 재부팅합니다. 기본값은 꺼짐이며 필요한 장치에서만 사용하세요.`})]})]}),B(`div`,{class:`flex shrink-0 flex-wrap items-center justify-between gap-3 sm:justify-end`,children:[l&&B(`span`,{"aria-live":`polite`,class:`inline-flex items-center gap-1.5 rounded-full border border-amber-200 bg-amber-50 px-2.5 py-1 text-xs font-extrabold text-amber-800`,role:`status`,children:[B(U,{"aria-hidden":`true`,class:`size-3.5 shrink-0`}),`저장되지 않음`]}),B(`span`,{class:`text-xs font-extrabold text-slate-500`,children:t?`사용 중`:`꺼짐`}),B(`button`,{"aria-checked":t,"aria-label":`예약 재부팅 사용`,class:`ssh-switch-control relative inline-flex shrink-0 rounded-full border transition focus:outline-none focus-visible:ring-4 focus-visible:ring-teal-100 disabled:cursor-not-allowed disabled:opacity-50 ${t?`border-teal-600 bg-teal-600`:`border-slate-300 bg-slate-200`}`,disabled:e.loading||e.saving||!e.data,onClick:()=>n(e=>!e),role:`switch`,type:`button`,children:B(`span`,{"aria-hidden":`true`,class:`ssh-switch-thumb absolute top-1 shadow-sm transition-[left] ${t?`left-6`:`left-1`}`})})]})]}),(e.saveError||e.saveMessage)&&B(`div`,{class:`mt-4 flex min-w-0 items-start justify-between gap-3 rounded-xl border px-4 py-3 text-sm font-bold ${e.saveError?`border-rose-200 bg-rose-50 text-rose-800`:`border-emerald-200 bg-emerald-50 text-emerald-800`}`,children:[B(`span`,{class:`min-w-0`,children:e.saveError||e.saveMessage}),B(`button`,{class:`shrink-0 rounded-lg px-2 py-1 text-xs font-extrabold hover:bg-black/5`,onClick:e.onDismissFeedback,type:`button`,children:`닫기`})]}),e.error&&!e.data?B(`div`,{class:`mt-4 rounded-xl border border-rose-200 bg-rose-50 p-4`,children:[B(`p`,{class:`m-0 text-sm font-bold text-rose-800`,children:e.error}),B(`button`,{class:`mt-3 inline-flex min-h-10 items-center rounded-xl border border-rose-300 bg-white px-3 py-2 text-xs font-extrabold text-rose-700 transition hover:bg-rose-100`,onClick:e.onRetry,type:`button`,children:`다시 불러오기`})]}):B(S,{children:[B(`div`,{class:`mt-4 grid min-w-0 grid-cols-1 gap-4 md:grid-cols-3`,children:[B(`div`,{children:[B(`label`,{class:`mb-2 block text-sm font-extrabold text-slate-800`,for:`scheduled-reboot-frequency`,children:`주기`}),B(Vg,{ariaLabel:`예약 재부팅 주기`,disabled:!t||e.saving||!e.data,id:`scheduled-reboot-frequency`,onChange:e=>i(e),options:[{value:`weekly`,label:`매주`},{value:`daily`,label:`매일`}],value:r})]}),B(`div`,{children:[B(`label`,{class:`mb-2 block text-sm font-extrabold text-slate-800`,for:`scheduled-reboot-day`,children:`요일`}),B(Vg,{ariaLabel:`예약 재부팅 요일`,disabled:!t||r!==`weekly`||e.saving||!e.data,id:`scheduled-reboot-day`,onChange:e=>o(e),options:wv.map(e=>({value:e.value,label:e.label})),value:a})]}),B(`div`,{children:[B(`label`,{class:`mb-2 block text-sm font-extrabold text-slate-800`,for:`scheduled-reboot-time-hour`,children:`재부팅 시간`}),B(lv,{ariaLabel:`예약 재부팅 시간`,disabled:!t||e.saving||!e.data,id:`scheduled-reboot-time`,onChange:c,value:s})]})]}),B(`div`,{class:`mt-4 flex flex-col gap-3 rounded-xl bg-slate-50 p-4 sm:flex-row sm:items-end sm:justify-between`,children:[B(`div`,{class:`min-w-0`,children:[B(`p`,{class:`m-0 text-xs font-extrabold uppercase tracking-[0.12em] text-slate-500`,children:`예약 일정`}),B(`p`,{class:`mt-1.5 mb-0 text-sm font-extrabold text-slate-900`,children:d}),B(`p`,{class:`mt-1 mb-0 text-xs leading-5 text-slate-500`,children:[e.data?.timezone??`장치 시간대`,` 기준 · 업데이트 작업 중이면 15분 단위로 최대 2시간 연기합니다.`]})]}),B(`button`,{class:`inline-flex min-h-11 w-full shrink-0 items-center justify-center rounded-xl bg-teal-700 px-4 py-2.5 text-sm font-extrabold text-white transition hover:bg-teal-800 disabled:cursor-not-allowed disabled:opacity-50 sm:w-auto`,disabled:!l||e.saving||!e.data,onClick:()=>void e.onSave({enabled:t,frequency:r,dayOfWeek:a,time:s}),type:`button`,children:e.saving?`예약 저장 중`:`예약 저장`})]})]})]})}function Ev({action:e,backupAction:t,backupError:n,backupMessage:r,backupRestoreAccepted:i,backupUploadProgress:a,backupValidated:o,data:s,error:c,feedbackError:l,feedbackMessage:u,firmware:d,firmwareError:f,firmwareLoading:p,health:m,healthActionError:h,healthActionMessage:g,healthError:_,healthLoading:v,healthRunning:y,healthSavingReporter:b,loading:x,rebootAccepted:S,scheduledRebootData:C,scheduledRebootError:w,scheduledRebootLoading:T,scheduledRebootSaveError:E,scheduledRebootSaveMessage:D,scheduledRebootSaving:O,timeData:k,timeError:A,timeLoading:ee,timeSaveError:j,timeSaveMessage:te,timeSaving:ne,timeSyncing:M,onBackupDiscard:re,onBackupDownload:ie,onBackupRestore:ae,onBackupUpload:oe,onDismissBackupFeedback:se,onDismissFeedback:ce,onDismissHealthFeedback:le,onDismissTimeFeedback:ue,onDownloadDiagnostics:de,onRunHealth:fe,onSetHealthReporter:pe,onReboot:me,onRetry:he,onDismissScheduledRebootFeedback:ge,onSaveScheduledReboot:_e,onSaveTimezone:ve,onSyncTime:ye,onAdministratorPasswordChanged:be}){let[xe,Se]=N(!1);if(x&&!s)return B(`div`,{class:`rounded-2xl border border-slate-200 bg-white p-8 text-center shadow-sm shadow-slate-900/5`,children:B(`p`,{class:`m-0 text-sm font-bold text-slate-500`,children:`시스템 정보를 확인하고 있습니다.`})});if(c&&!s)return B(`div`,{class:`rounded-2xl border border-rose-200 bg-rose-50 p-6`,children:[B(`h2`,{class:`m-0 text-lg font-black text-rose-900`,children:`시스템 정보를 불러오지 못했습니다.`}),B(`p`,{class:`mt-2 mb-0 text-sm leading-6 text-rose-700`,children:c}),B(`button`,{class:`mt-4 inline-flex min-h-10 items-center rounded-xl bg-rose-700 px-4 py-2 text-sm font-extrabold text-white transition hover:bg-rose-800`,onClick:he,type:`button`,children:`다시 시도`})]});let we=s?.runtime.memory,Te=we?.total??0,Ee=we?za(we):null,De=Ee?.used??0,Oe=Math.round(Ee?.percent??0),ke=Ce(`/admin/system`),Ae=Ce(`/admin/status/logs`),je=!!d?.current.metadataAvailable,Me=s?p&&!d?`확인 중`:f&&!d?`확인 필요`:je?d?.current.releaseVersion?`SmartSafeHub ${d.current.releaseVersion}`:`SmartSafeHub 펌웨어`:`${s.software.distribution} ${s.software.version}`:`미확인`,Ne=s?p&&!d?`펌웨어 정보를 확인하고 있습니다.`:f&&!d?f:je?d?.current.buildId?`빌드 ID ${d.current.buildId}`:`빌드 ID를 확인할 수 없습니다.`:`리비전 ${s.software.revision}`:`버전 정보를 확인할 수 없습니다.`;return B(`section`,{class:`min-w-0 space-y-7`,children:[(l||u)&&B(`div`,{class:`flex min-w-0 flex-col gap-3 rounded-xl border px-4 py-3 text-sm font-bold sm:flex-row sm:items-center sm:justify-between ${l?`border-rose-200 bg-rose-50 text-rose-800`:`border-emerald-200 bg-emerald-50 text-emerald-800`}`,children:[B(`span`,{class:`min-w-0`,children:l||u}),!S&&B(`button`,{class:`shrink-0 self-start rounded-lg px-3 py-1.5 text-xs font-extrabold hover:bg-black/5 sm:self-auto`,onClick:ce,type:`button`,children:`닫기`})]}),B(`section`,{class:`min-w-0`,children:[B(`div`,{class:`mb-4`,children:[B(`p`,{class:`m-0 text-xs font-extrabold uppercase tracking-[0.16em] text-teal-700`,children:`System`}),B(`h2`,{class:`mt-2 mb-0 text-xl font-black text-slate-950`,children:`시스템 상태`}),B(`p`,{class:`mt-2 mb-0 text-sm leading-6 text-slate-500`,children:`장치의 펌웨어, 실행 시간, 메모리와 시스템 부하를 확인합니다.`})]}),B(`div`,{class:`grid min-w-0 grid-cols-1 gap-4 sm:grid-cols-2 xl:grid-cols-4`,children:[B(uv,{label:`Firmware`,value:Me,description:Ne}),B(uv,{label:`Uptime`,value:s?ja(s.runtime.uptime):`미확인`,description:s?`커널 ${s.software.kernel}`:`실행 시간을 확인할 수 없습니다.`}),B(uv,{label:`Memory`,value:`${Oe}%`,description:`${Ma(De)} / ${Ma(Te)} 사용`}),B(uv,{label:`Load`,value:s?Na(s.runtime.load[0]):`0.00`,description:s?`5분 ${Na(s.runtime.load[1])} · 15분 ${Na(s.runtime.load[2])}`:`시스템 부하를 확인할 수 없습니다.`})]})]}),B(`section`,{class:`min-w-0`,children:[B(`div`,{class:`mb-4`,children:[B(`p`,{class:`m-0 text-xs font-extrabold uppercase tracking-[0.16em] text-teal-700`,children:`Device settings`}),B(`h2`,{class:`mt-2 mb-0 text-xl font-black text-slate-950`,children:`장치 설정`}),B(`p`,{class:`mt-2 mb-0 text-sm leading-6 text-slate-500`,children:`시간 기준과 예약 재부팅, 진단 정보를 SmartSafeHub에서 직접 관리합니다.`})]}),B(`div`,{class:`grid min-w-0 grid-cols-1 gap-4 lg:grid-cols-2`,children:[B(pv,{data:k,error:A,loading:ee,onDismissFeedback:ue,onDismissScheduledRebootFeedback:ge,onRetry:he,onSave:ve,onSaveScheduledReboot:_e,onSync:ye,saveError:j,saveMessage:te,saving:ne,scheduledRebootData:C,scheduledRebootError:w,scheduledRebootLoading:T,scheduledRebootSaveError:E,scheduledRebootSaveMessage:D,scheduledRebootSaving:O,syncing:M}),B(vv,{actionError:h,actionMessage:g,data:m,downloadBusy:e===`diagnostics`,error:_,loading:v,onDismissFeedback:le,onDownload:de,onRetry:he,onRun:fe,onSetReporter:pe,running:y,savingReporter:b})]})]}),B(`section`,{class:`min-w-0`,children:[B(`div`,{class:`mb-4`,children:[B(`p`,{class:`m-0 text-xs font-extrabold uppercase tracking-[0.16em] text-teal-700`,children:`System management`}),B(`h2`,{class:`mt-2 mb-0 text-xl font-black text-slate-950`,children:`시스템 관리`}),B(`p`,{class:`mt-2 mb-0 text-sm leading-6 text-slate-500`,children:`관리자 비밀번호, 설정 백업·복원과 공유기 시스템 도구를 한곳에서 관리합니다.`})]}),B(`div`,{class:`grid min-w-0 grid-cols-1 gap-4 lg:grid-cols-2`,children:[B(xv,{onChanged:be}),B(Sv,{action:t,error:n,message:r,onDiscard:re,onDismissFeedback:se,onDownload:ie,onRestore:ae,onUpload:oe,restoreAccepted:i,uploadProgress:a,validated:o}),B(Cv,{action:e,className:`lg:col-span-2`,advancedSystemUrl:ke,confirmingReboot:xe,logsUrl:Ae,onCancelReboot:()=>Se(!1),onConfirmReboot:()=>Se(!0),onReboot:me,rebootAccepted:S})]})]})]})}function Dv(e){return!e||e<=0?`미확인`:e>=1048576?`${(e/1048576).toFixed(1)} MB`:`${(e/1024).toFixed(1)} KB`}function Ov(e){return e?new Date(e*1e3).toLocaleString(`ko-KR`,{dateStyle:`medium`,timeStyle:`short`}):`아직 없음`}function kv(e){switch(e.phase){case`checking`:return`확인 중`;case`downloading`:return`다운로드 중`;case`verifying`:return`검증 중`;case`ready`:return`설치 준비 완료`;case`flashing`:return`설치 중`;case`error`:return`확인 필요`;default:return e.updateAvailable?`업데이트 가능`:e.lastCheckAt?`최신 상태`:`확인 전`}}function Av(e){return e.phase===`error`?`bg-rose-50 text-rose-700 ring-rose-200`:e.phase===`checking`||e.phase===`downloading`||e.phase===`verifying`||e.phase===`flashing`?`bg-sky-50 text-sky-700 ring-sky-200`:e.phase===`ready`||e.updateAvailable?`bg-amber-50 text-amber-800 ring-amber-200`:e.lastCheckAt?`bg-emerald-50 text-emerald-700 ring-emerald-200`:`bg-slate-100 text-slate-600 ring-slate-200`}function jv(e){return e.phase===`checking`||e.phase===`downloading`||e.phase===`verifying`||e.phase===`flashing`?B(H,{class:`size-3.5 animate-spin`}):e.phase===`error`?B(U,{class:`size-3.5`}):e.phase===`ready`||e.updateAvailable?B(Wt,{class:`size-3.5`}):e.lastCheckAt?B(Xt,{class:`size-3.5`}):B(Vt,{class:`size-3.5`})}function Mv({checked:e,disabled:t,onChange:n}){return B(`button`,{"aria-checked":e,"aria-label":`현재 설정 유지`,class:`ssh-switch-control relative inline-flex shrink-0 rounded-full border transition focus:outline-none focus-visible:ring-4 focus-visible:ring-teal-100 disabled:cursor-not-allowed disabled:opacity-50 ${e?`border-teal-600 bg-teal-600`:`border-slate-300 bg-slate-200`}`,disabled:t,onClick:()=>n(!e),role:`switch`,type:`button`,children:B(`span`,{"aria-hidden":`true`,class:`ssh-switch-thumb absolute top-1 shadow-sm transition-[left] ${e?`left-6`:`left-1`}`})})}function Nv({action:e,actionError:t,data:n,error:r,loading:i,message:a,reconnecting:o,uploadProgress:s,onCheck:c,onDiscard:l,onDismissFeedback:u,onInstall:d,onPrepare:f,onRetry:p,onUpload:m}){let h=F(null),[g,_]=N(null),[v,y]=N(!0),[b,x]=N(!1);P(()=>{n?.prepared&&y(n.prepared.allowBackup)},[n?.prepared]);let C=e!==null||n?.phase===`checking`||n?.phase===`downloading`||n?.phase===`verifying`||n?.phase===`flashing`,w=n?.phase===`ready`?n.prepared:null,T=e===`check`||n?.phase===`checking`,E=e===`prepare`||n?.phase===`downloading`||n?.phase===`verifying`,D=e===`upload`||e===`validate-upload`,O=async()=>{g&&await m(g)&&(_(null),h.current&&(h.current.value=``))};return B(`article`,{class:`min-w-0 overflow-hidden rounded-2xl border border-slate-200 bg-white shadow-sm shadow-slate-900/5`,"data-component":`firmware-update-card`,children:[B(`div`,{class:`p-5 sm:p-6`,children:[B(`div`,{class:`flex flex-col gap-5 lg:flex-row lg:items-start lg:justify-between`,children:[B(`div`,{class:`flex min-w-0 gap-4`,children:[B(`span`,{class:`grid size-12 shrink-0 place-items-center rounded-2xl bg-sky-50 text-sky-700`,children:B(jt,{class:`size-6`})}),B(`div`,{class:`min-w-0`,children:[B(`p`,{class:`m-0 text-xs font-extrabold uppercase tracking-[0.16em] text-sky-700`,children:`Firmware update`}),B(`h2`,{class:`mt-2 mb-0 text-xl font-black text-slate-950 sm:text-2xl`,children:`펌웨어 업데이트`}),B(`p`,{class:`mt-2 mb-0 text-sm leading-6 text-slate-500 lg:whitespace-nowrap`,children:`시스템 펌웨어를 확인하고 설치합니다. 온라인·수동 설치는 안전성 검증 후 진행됩니다.`})]})]}),n?B(`div`,{class:`flex shrink-0 flex-col gap-2 sm:flex-row lg:justify-end`,children:[B(`span`,{class:`inline-flex min-h-11 items-center justify-center gap-1.5 rounded-xl px-3 py-2 text-xs font-extrabold ring-1 ring-inset ${Av(n)}`,children:[jv(n),kv(n)]}),B(`button`,{class:`inline-flex min-h-11 items-center justify-center gap-2 rounded-xl border border-slate-300 bg-white px-4 py-2.5 text-sm font-extrabold text-slate-800 transition hover:bg-slate-50 disabled:cursor-wait disabled:opacity-60`,disabled:C||w!==null,onClick:c,type:`button`,children:[B(H,{class:`size-4 ${T?`animate-spin`:``}`}),T?`확인 중...`:`펌웨어 확인`]}),n.updateAvailable&&!w?B(`button`,{class:`inline-flex min-h-11 items-center justify-center gap-2 rounded-xl bg-sky-700 px-4 py-2.5 text-sm font-extrabold text-white transition hover:bg-sky-800 disabled:cursor-wait disabled:opacity-60`,disabled:C,onClick:f,type:`button`,children:[E?B(H,{class:`size-4 animate-spin`}):B(Wt,{class:`size-4`}),E?`준비 중...`:`다운로드 및 검증`]}):null]}):null]}),t||a?B(`div`,{class:`mt-5 flex flex-col gap-3 rounded-xl border px-4 py-3 text-sm font-bold sm:flex-row sm:items-center sm:justify-between ${t?`border-rose-200 bg-rose-50 text-rose-800`:`border-emerald-200 bg-emerald-50 text-emerald-800`}`,children:[B(`span`,{children:t||a}),B(`button`,{class:`shrink-0 self-start rounded-lg px-3 py-1.5 text-xs font-extrabold hover:bg-black/5 sm:self-auto`,onClick:u,type:`button`,children:`닫기`})]}):null,o||n?.phase===`flashing`?B(`div`,{class:`mt-5 rounded-xl border border-amber-200 bg-amber-50 p-4 sm:p-5`,role:`status`,children:B(`div`,{class:`flex gap-3`,children:[B(`span`,{class:`grid size-10 shrink-0 place-items-center rounded-xl bg-white text-amber-700 ring-1 ring-inset ring-amber-200`,children:B(H,{class:`size-5 animate-spin`})}),B(`div`,{children:[B(`strong`,{class:`block text-sm font-black text-amber-950`,children:`펌웨어를 설치하고 재부팅하고 있습니다.`}),B(`p`,{class:`mt-1 mb-0 text-sm leading-6 text-amber-800`,children:`전원을 끄지 마세요. 현재 주소에서 공유기가 다시 응답하면 SmartSafeHub가 자동으로 새로고침됩니다.`})]})]})}):null,r&&!n?B(`div`,{class:`mt-5 rounded-xl border border-rose-200 bg-rose-50 p-4 text-sm text-rose-800`,children:[B(`p`,{class:`m-0 font-bold`,children:r}),B(`button`,{class:`mt-3 rounded-lg border border-rose-300 bg-white px-3 py-2 text-xs font-extrabold text-rose-700`,onClick:p,type:`button`,children:`다시 시도`})]}):i&&!n?B(`div`,{class:`mt-5 flex items-center gap-3 rounded-xl bg-slate-50 p-4 text-sm font-bold text-slate-500`,children:[B(H,{class:`size-4 animate-spin`}),`펌웨어 상태를 확인하고 있습니다.`]}):n?B(S,{children:[n.lastError?B(`div`,{class:`mt-5 rounded-xl border border-rose-200 bg-rose-50 p-4 sm:p-5`,children:B(`div`,{class:`flex gap-3`,children:[B(`span`,{class:`grid size-10 shrink-0 place-items-center rounded-xl bg-white text-rose-700 ring-1 ring-inset ring-rose-200`,children:B(U,{class:`size-5`})}),B(`div`,{class:`min-w-0 flex-1`,children:[B(`strong`,{class:`block text-sm font-black text-rose-950`,children:`펌웨어 작업을 완료하지 못했습니다.`}),B(`p`,{class:`mt-1 mb-0 text-sm leading-6 text-rose-800`,children:n.lastError.message}),B(`details`,{class:`mt-3 rounded-lg border border-rose-200 bg-white p-3`,children:[B(`summary`,{class:`cursor-pointer text-xs font-extrabold text-rose-800`,children:`상세 정보 보기`}),B(`p`,{class:`mt-2 mb-0 break-all font-mono text-[11px] text-slate-600`,children:n.lastError.code})]})]})]})}):null,n.current.metadataAvailable?null:B(`div`,{class:`mt-5 rounded-xl border border-amber-200 bg-amber-50 px-4 py-3 text-xs leading-5 text-amber-900`,children:[B(`strong`,{class:`block font-extrabold`,children:`현재 펌웨어의 버전 정보를 완전히 확인할 수 없습니다.`}),B(`span`,{class:`mt-1 block text-amber-800`,children:`새 펌웨어를 설치하면 이후부터 정확한 설치 버전을 자동으로 확인할 수 있습니다.`}),B(`details`,{class:`mt-2`,children:[B(`summary`,{class:`cursor-pointer font-extrabold text-amber-800`,children:`기술 상세 보기`}),B(`p`,{class:`mt-2 mb-0 break-all font-mono text-[11px] leading-5 text-amber-800`,children:`SmartSafeHub build ID metadata is missing. Future images should include /usr/share/smartsafehub/firmware.json.`})]})]}),B(`dl`,{class:`mt-5 grid overflow-hidden rounded-xl border border-slate-200 bg-slate-200 sm:grid-cols-2 xl:grid-cols-4`,children:[B(`div`,{class:`bg-white p-4`,children:[B(`dt`,{class:`text-[11px] font-black uppercase tracking-[0.16em] text-slate-400`,children:`Device`}),B(`dd`,{class:`mt-2 mb-0 ml-0 break-all text-sm font-black text-slate-950`,children:n.current.deviceCode||n.current.boardName||`미확인`})]}),B(`div`,{class:`bg-white p-4`,children:[B(`dt`,{class:`text-[11px] font-black uppercase tracking-[0.16em] text-slate-400`,children:`Current version`}),B(`dd`,{class:`mt-2 mb-0 ml-0 break-all text-sm font-black text-slate-950`,children:n.current.releaseVersion||`미확인`}),n.current.buildId?B(`span`,{class:`mt-1 block break-all text-[11px] leading-5 text-slate-400`,children:[`빌드 ID `,n.current.buildId]}):n.current.openwrtVersion?B(`span`,{class:`mt-1 block text-[11px] leading-5 text-slate-400`,children:[`OpenWrt `,n.current.openwrtVersion]}):null]}),B(`div`,{class:`bg-white p-4`,children:[B(`dt`,{class:`text-[11px] font-black uppercase tracking-[0.16em] text-slate-400`,children:`Available version`}),B(`dd`,{class:`mt-2 mb-0 ml-0 break-all text-sm font-black ${n.updateAvailable?`text-amber-700`:`text-slate-950`}`,children:n.lastCheckAt?n.release?.version?`${n.release.version}${n.updateAvailable?``:` · 최신`}`:n.updateAvailable?`새 펌웨어`:`최신 버전`:`미확인`})]}),B(`div`,{class:`bg-white p-4`,children:[B(`dt`,{class:`text-[11px] font-black uppercase tracking-[0.16em] text-slate-400`,children:`Last check`}),B(`dd`,{class:`mt-2 mb-0 ml-0 text-sm font-black text-slate-950`,children:Ov(n.lastCheckAt)})]})]})]}):null,n?.updateAvailable&&n.release?B(`section`,{class:`mt-5 rounded-xl border border-sky-200 bg-sky-50/60 p-4 sm:p-5`,"data-section":`available-firmware`,children:[B(`div`,{class:`flex flex-col gap-2 sm:flex-row sm:items-start sm:justify-between sm:gap-4`,children:[B(`div`,{children:[B(`p`,{class:`m-0 text-xs font-extrabold uppercase tracking-[0.16em] text-sky-700`,children:`Available firmware`}),B(`h3`,{class:`mt-2 mb-0 text-lg font-black text-slate-950`,children:`새 펌웨어가 있습니다.`}),B(`p`,{class:`mt-2 mb-0 text-sm leading-6 text-slate-600`,children:[`펌웨어 `,n.release.version||`미확인`,` · OpenWrt `,n.release.openwrtVersion||`미확인`,` · `,Dv(n.release.sysupgrade.sizeBytes),` · `,(n.release.channel||n.settings.channel)===`beta`?`Beta`:`Stable`]})]}),B(`span`,{class:`shrink-0 rounded-full bg-white px-3 py-1.5 text-xs font-extrabold text-sky-700 ring-1 ring-inset ring-sky-200`,children:n.release.version||`Latest`})]}),n.release.releaseNotes.length?B(`ul`,{class:`mt-4 mb-0 space-y-2 rounded-xl bg-white p-4 pl-9 text-sm leading-6 text-slate-700 ring-1 ring-inset ring-sky-100`,children:n.release.releaseNotes.map((e,t)=>B(`li`,{children:e},`${t}-${e}`))}):null]}):null,w?B(`section`,{class:`mt-5 rounded-xl border border-amber-200 bg-amber-50 p-4 sm:p-5`,"data-section":`prepared-firmware`,children:B(`div`,{class:`flex gap-4`,children:[B(`span`,{class:`grid size-11 shrink-0 place-items-center rounded-xl bg-white text-amber-700 ring-1 ring-inset ring-amber-200`,children:B(Xt,{class:`size-5`})}),B(`div`,{class:`min-w-0 flex-1`,children:[B(`p`,{class:`m-0 text-xs font-extrabold uppercase tracking-[0.16em] text-amber-700`,children:`Verified image`}),B(`h3`,{class:`mt-2 mb-0 text-lg font-black text-amber-950`,children:`설치할 펌웨어가 준비되었습니다.`}),B(`p`,{class:`mt-2 mb-0 break-all text-sm leading-6 text-amber-900`,children:[w.filename||`firmware.bin`,` · `,Dv(w.sizeBytes)]}),w.sha256?B(`p`,{class:`mt-2 mb-0 break-all font-mono text-[11px] leading-5 text-amber-800`,children:[`SHA-256 `,w.sha256]}):null,B(`div`,{class:`mt-5 flex items-start justify-between gap-4 rounded-xl border border-amber-200 bg-white p-4`,children:[B(`div`,{children:[B(`strong`,{class:`block text-sm font-black text-slate-950`,children:`현재 설정 유지`}),B(`span`,{class:`mt-1 block text-xs leading-5 text-slate-500`,children:`Wi-Fi, SafeShield, SmartSafeHub 설정을 유지합니다.`}),w.allowBackup?null:B(`span`,{class:`mt-2 block text-xs font-bold text-rose-700`,children:`이 이미지는 설정 유지 업그레이드를 지원하지 않습니다.`})]}),B(Mv,{checked:v,disabled:!w.allowBackup,onChange:y})]}),b?B(`div`,{class:`mt-4 rounded-xl border border-rose-200 bg-rose-50 p-4`,children:[B(`strong`,{class:`block text-sm font-black text-rose-950`,children:`펌웨어 설치를 시작할까요?`}),B(`p`,{class:`mt-1 mb-0 text-xs leading-5 text-rose-800`,children:`설치 중 전원을 끄면 장치가 복구 불가능한 상태가 될 수 있습니다. 이미지 검증은 설치 직전에 다시 수행됩니다.`}),B(`div`,{class:`mt-4 flex flex-wrap justify-end gap-2`,children:[B(`button`,{class:`min-h-10 rounded-lg border border-slate-300 bg-white px-3 py-2 text-xs font-extrabold text-slate-700`,onClick:()=>x(!1),type:`button`,children:`취소`}),B(`button`,{class:`min-h-10 rounded-lg bg-rose-700 px-3 py-2 text-xs font-extrabold text-white`,onClick:()=>{x(!1),d(v)},type:`button`,children:`설치 시작`})]})]}):B(`div`,{class:`mt-4 flex flex-wrap justify-end gap-2`,children:[B(`button`,{class:`min-h-10 rounded-lg border border-slate-300 bg-white px-3 py-2 text-xs font-extrabold text-slate-700`,disabled:e===`discard`,onClick:()=>void l(),type:`button`,children:`파일 삭제`}),B(`button`,{class:`inline-flex min-h-10 items-center gap-2 rounded-lg bg-rose-700 px-4 py-2 text-xs font-extrabold text-white`,onClick:()=>x(!0),type:`button`,children:[B(Ft,{class:`size-4`}),`펌웨어 설치`]})]})]})]})}):null]}),B(`details`,{class:`group mx-5 mb-5 rounded-xl border border-slate-200 bg-slate-50/70 sm:mx-6 sm:mb-6`,"data-layout":`firmware-card-subsection`,"data-section":`manual-firmware`,children:[B(`summary`,{class:`flex cursor-pointer list-none items-center justify-between gap-4 px-4 py-4 sm:px-5 [&::-webkit-details-marker]:hidden`,children:[B(`div`,{class:`flex min-w-0 items-center gap-3`,children:[B(`span`,{class:`grid size-10 shrink-0 place-items-center rounded-xl bg-white text-slate-600 ring-1 ring-inset ring-slate-200`,children:B(Wt,{class:`size-5 rotate-180`})}),B(`div`,{class:`min-w-0`,children:[B(`strong`,{class:`block text-sm font-black text-slate-950`,children:`수동 펌웨어 설치`}),B(`span`,{class:`mt-1 block text-xs leading-5 text-slate-500`,children:`펌웨어 파일(.bin)을 직접 업로드하여 검증한 뒤 설치합니다.`})]})]}),B(`span`,{class:`shrink-0 rounded-full bg-white px-3 py-1.5 text-[11px] font-extrabold text-slate-600 ring-1 ring-inset ring-slate-200 group-open:hidden`,children:`열기`}),B(`span`,{class:`hidden shrink-0 rounded-full bg-white px-3 py-1.5 text-[11px] font-extrabold text-slate-600 ring-1 ring-inset ring-slate-200 group-open:inline-flex`,children:`닫기`})]}),B(`div`,{class:`border-t border-slate-200 px-5 pb-5 pt-3 sm:px-6`,children:[B(`p`,{class:`mt-0 mb-4 text-xs leading-5 text-slate-500 lg:whitespace-nowrap`,children:"이 장치에 맞는 Sysupgrade 이미지(.bin)만 사용하세요. 업로드한 파일은 이미지 검증과 `sysupgrade --test`를 모두 통과해야 설치할 수 있으며 강제 설치는 제공하지 않습니다."}),B(`div`,{class:`rounded-xl border border-slate-200 bg-white p-4 sm:p-5`,"data-layout":`firmware-file-picker`,children:[B(`input`,{accept:`.bin,application/octet-stream`,"aria-label":`펌웨어 파일 선택`,class:`sr-only`,disabled:C||w!==null,onChange:e=>_(e.currentTarget.files?.[0]??null),ref:h,type:`file`}),B(`div`,{class:`flex flex-col gap-4 sm:flex-row sm:items-center sm:justify-between`,children:[B(`div`,{class:`flex min-w-0 items-center gap-3`,children:[B(`span`,{class:`grid size-10 shrink-0 place-items-center rounded-xl bg-slate-50 text-slate-500 ring-1 ring-inset ring-slate-200`,children:B(Wt,{class:`size-5 rotate-180`})}),B(`div`,{class:`min-w-0`,children:[B(`strong`,{class:`block truncate text-sm font-black text-slate-900`,children:g?g.name:`펌웨어 파일을 선택하세요`}),B(`span`,{class:`mt-1 block text-xs leading-5 text-slate-500`,children:g?`${Dv(g.size)} · Sysupgrade 이미지 (.bin)`:`이 장치에 맞는 Sysupgrade 이미지 (.bin)를 선택합니다.`})]})]}),B(`div`,{class:`flex shrink-0 flex-wrap gap-2 sm:justify-end`,children:[B(`button`,{class:`inline-flex min-h-10 items-center justify-center rounded-lg border border-slate-300 bg-white px-3.5 py-2 text-xs font-extrabold text-slate-700 transition hover:bg-slate-50 disabled:cursor-not-allowed disabled:opacity-50`,disabled:C||w!==null,onClick:()=>h.current?.click(),type:`button`,children:g?`다른 파일 선택`:`파일 선택`}),B(`button`,{class:`inline-flex min-h-10 items-center justify-center gap-2 rounded-lg bg-slate-900 px-3.5 py-2 text-xs font-extrabold text-white transition hover:bg-slate-800 disabled:cursor-not-allowed disabled:opacity-50`,disabled:!g||C||w!==null,onClick:()=>void O(),type:`button`,children:[D?B(H,{class:`size-4 animate-spin`}):B(Wt,{class:`size-4 rotate-180`}),D?`처리 중...`:`업로드 및 검증`]})]})]}),s===null?null:B(`div`,{class:`mt-4 border-t border-slate-100 pt-4`,children:[B(`div`,{class:`mb-2 flex items-center justify-between gap-3 text-xs font-bold text-slate-600`,children:[B(`span`,{children:`업로드 중`}),B(`span`,{children:[s,`%`]})]}),B(`div`,{class:`h-2 overflow-hidden rounded-full bg-slate-200`,children:B(`div`,{class:`h-full rounded-full bg-sky-600 transition-[width]`,style:{width:`${Math.max(0,Math.min(100,s))}%`}})})]})]})]})]})]})}var Pv=[{value:3600,label:`1시간마다`},{value:21600,label:`6시간마다`},{value:43200,label:`12시간마다`},{value:86400,label:`24시간마다`}],Fv=`luci-app-smartsafehub`;function Iv(e){return e?new Date(e*1e3).toLocaleString(`ko-KR`,{dateStyle:`medium`,timeStyle:`short`}):`아직 없음`}function Lv(e){return e===`stable`?`Stable`:e===`beta`?`Beta`:`미확인`}function Rv(e){return e===`stable`?`bg-emerald-50 text-emerald-700 ring-emerald-200`:e===`beta`?`bg-amber-50 text-amber-700 ring-amber-200`:`bg-slate-100 text-slate-600 ring-slate-200`}function zv(e){return e.code===`UPDATES_INDEX_REFRESH_FAILED`?{title:`패키지 저장소를 확인하지 못했습니다.`,description:`OpenWrt 패키지 저장소 동기화 또는 네트워크 상태가 일시적으로 불안정할 수 있습니다. 잠시 후 업데이트 확인을 다시 실행해 주세요.`}:e.code===`UPDATES_INSTALL_FAILED`?{title:`관리 소프트웨어 업데이트 설치에 실패했습니다.`,description:`패키지 설치가 완료되지 않았습니다. 네트워크 연결과 저장 공간을 확인한 뒤 다시 시도해 주세요.`}:{title:`최근 업데이트 작업을 완료하지 못했습니다.`,description:`잠시 후 다시 시도해 주세요. 문제가 반복되면 상세 정보를 확인해 주세요.`}}function Bv(e,t){return e.phase===`checking`?`업데이트 확인 중`:e.phase===`installing`?`업데이트 설치 중`:e.phase===`error`?`확인 필요`:e.updateCount>0?`업데이트 가능`:t?`업데이트 확인 지연`:e.lastCheckAt?`최신 상태`:`확인 전`}function Vv(e,t){return e.phase===`error`?`bg-rose-50 text-rose-700 ring-rose-200`:e.phase===`checking`||e.phase===`installing`?`bg-sky-50 text-sky-700 ring-sky-200`:e.updateCount>0||t?`bg-amber-50 text-amber-800 ring-amber-200`:e.lastCheckAt?`bg-emerald-50 text-emerald-700 ring-emerald-200`:`bg-slate-100 text-slate-600 ring-slate-200`}function Hv(e,t){return e.phase===`checking`||e.phase===`installing`?B(H,{class:`size-3.5 shrink-0 animate-spin`}):e.phase===`error`?B(U,{class:`size-3.5 shrink-0`}):e.updateCount>0?B(Wt,{class:`size-3.5 shrink-0`}):t?B(U,{class:`size-3.5 shrink-0`}):e.lastCheckAt?B(Xt,{class:`size-3.5 shrink-0`}):B(Vt,{class:`size-3.5 shrink-0`})}function Uv({checked:e,disabled:t=!1,label:n,onChange:r}){return B(`button`,{"aria-checked":e,"aria-label":n,class:`ssh-switch-control relative inline-flex shrink-0 rounded-full border transition focus:outline-none focus-visible:ring-4 focus-visible:ring-teal-100 disabled:cursor-not-allowed disabled:opacity-50 ${e?`border-teal-600 bg-teal-600`:`border-slate-300 bg-slate-200`}`,disabled:t,onClick:()=>r(!e),role:`switch`,type:`button`,children:B(`span`,{"aria-hidden":`true`,class:`ssh-switch-thumb absolute top-1 shadow-sm transition-[left] ${e?`left-6`:`left-1`}`})})}function Wv({action:e,actionError:t,data:n,error:r,loading:i,message:a,onCheck:o,onDismissFeedback:s,onInstall:c,onRetry:l,onSaveSettings:u}){let[d,f]=N(!0),[p,m]=N(21600),[h,g]=N(!1),[_,v]=N(`03:00`),[y,b]=N(!1),[x,C]=N(!1);P(()=>{!n||y||(f(n.settings.checkEnabled),m(n.settings.checkIntervalSeconds),g(n.settings.autoInstall),v(n.settings.autoInstallTime))},[n,y]);let w=e===`check`||n?.phase===`checking`,T=e===`install`||n?.phase===`installing`,E=w||T,D=Jh(n),O=n?.phase===`error`&&n.lastError?.code===`UPDATES_INDEX_REFRESH_FAILED`,k=n?.lastError?zv(n.lastError):null,A=n?.packages.find(e=>e.name===Fv)??n?.packages[0]??null,ee=(e={})=>n?(e.checkEnabled??d)!==n.settings.checkEnabled||(e.checkIntervalSeconds??p)!==n.settings.checkIntervalSeconds||(e.autoInstall??h)!==n.settings.autoInstall||(e.autoInstallTime??_)!==n.settings.autoInstallTime:!1,j=async()=>{await u({checkEnabled:d,checkIntervalSeconds:p,autoInstall:h,autoInstallTime:_})&&b(!1)};return B(`article`,{class:`min-w-0 overflow-hidden rounded-2xl border border-slate-200 bg-white shadow-sm shadow-slate-900/5 ${n?`grid xl:grid-cols-[minmax(0,0.95fr)_minmax(0,1.05fr)]`:``}`,"data-component":`management-software-update-card`,"data-layout":`management-software-sections`,children:[B(`section`,{class:`min-w-0 xl:col-start-1 xl:row-start-1`,"data-section":`software-update-status`,children:[B(`div`,{class:`p-5 sm:p-6`,children:[B(`div`,{class:`flex flex-col gap-5 lg:flex-row lg:items-start lg:justify-between`,children:[B(`div`,{class:`flex min-w-0 gap-4`,children:[B(`span`,{class:`grid size-12 shrink-0 place-items-center rounded-2xl bg-teal-50 text-teal-700`,children:B(Ft,{class:`size-6`})}),B(`div`,{class:`min-w-0`,children:[B(`div`,{class:`flex flex-wrap items-center gap-2`,children:[B(`p`,{class:`m-0 text-xs font-extrabold uppercase tracking-[0.16em] text-teal-700`,children:`Management software`}),n?B(`span`,{class:`inline-flex items-center gap-1.5 rounded-full px-2.5 py-1 text-[11px] font-extrabold ring-1 ring-inset ${Vv(n,D)}`,children:[B(`span`,{"aria-hidden":`true`,class:`flex items-center justify-center`,children:Hv(n,D)}),Bv(n,D)]}):null]}),B(`h2`,{class:`mt-2 mb-0 text-xl font-black text-slate-950 sm:text-2xl`,children:`관리 소프트웨어 업데이트`}),B(`p`,{class:`mt-2 mb-0 text-sm leading-6 text-slate-500 xl:whitespace-nowrap`,children:`새 버전을 확인하고 안전하게 설치합니다.`})]})]}),n?B(`div`,{class:`flex shrink-0 flex-col gap-2 sm:flex-row lg:justify-end`,children:[B(`button`,{class:`inline-flex min-h-11 items-center justify-center gap-2 rounded-xl border border-slate-300 bg-white px-4 py-2.5 text-sm font-extrabold text-slate-800 transition hover:bg-slate-50 disabled:cursor-wait disabled:opacity-60`,disabled:E,onClick:o,type:`button`,children:[B(H,{class:`size-4 ${w?`animate-spin`:``}`}),w?`확인 중...`:`업데이트 확인`]}),n.updateCount>0&&!x?B(`button`,{class:`inline-flex min-h-11 items-center justify-center gap-2 rounded-xl bg-teal-700 px-4 py-2.5 text-sm font-extrabold text-white transition hover:bg-teal-800 disabled:cursor-wait disabled:opacity-60`,disabled:E,onClick:()=>C(!0),type:`button`,children:[T?B(H,{class:`size-4 animate-spin`}):B(Wt,{class:`size-4`}),T?`설치 중...`:`업데이트 설치`]}):null]}):null]}),(t||a)&&B(`div`,{class:`mt-5 flex flex-col gap-3 rounded-xl border px-4 py-3 text-sm font-bold sm:flex-row sm:items-center sm:justify-between ${t?`border-rose-200 bg-rose-50 text-rose-800`:`border-emerald-200 bg-emerald-50 text-emerald-800`}`,children:[B(`span`,{children:t||a}),B(`button`,{class:`shrink-0 self-start rounded-lg px-3 py-1.5 text-xs font-extrabold hover:bg-black/5 sm:self-auto`,onClick:s,type:`button`,children:`닫기`})]}),T?B(`div`,{"aria-busy":`true`,"aria-live":`polite`,class:`mt-5 rounded-xl border border-sky-200 bg-sky-50 p-4 sm:p-5`,children:[B(`div`,{class:`flex items-start gap-3`,children:[B(`span`,{class:`grid size-10 shrink-0 place-items-center rounded-xl bg-white text-sky-700 ring-1 ring-inset ring-sky-200`,children:B(H,{"aria-hidden":`true`,class:`size-5 animate-spin`})}),B(`div`,{class:`min-w-0`,children:[B(`h3`,{class:`m-0 text-sm font-black text-sky-950`,children:`관리 소프트웨어를 업데이트하고 있습니다.`}),B(`p`,{class:`mt-1 mb-0 text-sm leading-6 text-sky-800`,children:`설치가 완료되면 이 화면이 자동으로 갱신됩니다. 작업 중에는 웹 연결이 잠시 끊길 수 있습니다.`})]})]}),B(`div`,{"aria-hidden":`true`,class:`ssh-update-progress-track mt-4`,children:B(`span`,{class:`ssh-update-progress-bar`})})]}):null,r&&!n?B(`div`,{class:`mt-5 rounded-xl border border-rose-200 bg-rose-50 p-4 text-sm text-rose-800`,children:[B(`p`,{class:`m-0 font-bold`,children:r}),B(`button`,{class:`mt-3 rounded-lg border border-rose-300 bg-white px-3 py-2 text-xs font-extrabold text-rose-700`,onClick:l,type:`button`,children:`다시 시도`})]}):i&&!n?B(`div`,{class:`mt-5 flex items-center gap-3 rounded-xl bg-slate-50 p-4 text-sm font-bold text-slate-500`,children:[B(`span`,{class:`grid size-9 shrink-0 place-items-center rounded-xl bg-white text-teal-700 ring-1 ring-inset ring-slate-200`,children:B(H,{"aria-hidden":`true`,class:`size-4 animate-spin`})}),B(`span`,{children:`관리 소프트웨어 업데이트 상태를 확인하고 있습니다.`})]}):n?B(S,{children:[n.lastError&&k?B(`div`,{class:`mt-5 rounded-xl border border-rose-200 bg-rose-50 p-4 sm:p-5`,children:B(`div`,{class:`flex items-start gap-3`,children:[B(`span`,{class:`grid size-10 shrink-0 place-items-center rounded-xl bg-white text-rose-700 ring-1 ring-inset ring-rose-200`,children:B(U,{class:`size-5`})}),B(`div`,{class:`min-w-0 flex-1`,children:[B(`p`,{class:`m-0 text-sm font-extrabold text-rose-950`,children:k.title}),B(`p`,{class:`mt-1 mb-0 text-sm leading-6 text-rose-800`,children:k.description}),n.lastError.at?B(`p`,{class:`mt-2 mb-0 text-xs font-bold text-rose-700`,children:[`발생 시각 `,Iv(n.lastError.at)]}):null,B(`details`,{class:`mt-3 rounded-lg border border-rose-200 bg-white p-3`,children:[B(`summary`,{class:`cursor-pointer text-xs font-extrabold text-rose-800`,children:`상세 정보 보기`}),B(`div`,{class:`mt-3 grid gap-2 text-xs leading-5 text-slate-600`,children:[B(`p`,{class:`m-0`,children:[`오류 코드 `,B(`strong`,{class:`font-black text-slate-900`,children:n.lastError.code})]}),B(`pre`,{class:`m-0 max-h-40 overflow-auto whitespace-pre-wrap break-words rounded-lg bg-slate-50 p-3 font-mono text-[11px] leading-5 text-slate-700`,children:n.lastError.message})]})]})]})]})}):null,x?B(`div`,{class:`mt-5 flex flex-col gap-3 rounded-xl border border-amber-200 bg-amber-50 p-4 sm:flex-row sm:items-center sm:justify-between`,children:[B(`div`,{class:`min-w-0`,children:[B(`strong`,{class:`block text-sm font-black text-amber-900`,children:`관리 소프트웨어를 지금 업데이트할까요?`}),B(`span`,{class:`mt-1 block text-xs leading-5 text-amber-800`,children:`설치 중 SmartSafeHub 웹 화면 연결이 잠시 끊길 수 있습니다.`})]}),B(`div`,{class:`flex shrink-0 gap-2`,children:[B(`button`,{class:`min-h-10 rounded-lg border border-slate-300 bg-white px-3 py-2 text-xs font-extrabold text-slate-700`,disabled:E,onClick:()=>C(!1),type:`button`,children:`취소`}),B(`button`,{class:`min-h-10 rounded-lg bg-amber-700 px-3 py-2 text-xs font-extrabold text-white disabled:opacity-60`,disabled:E,onClick:()=>{C(!1),c()},type:`button`,children:`설치 시작`})]})]}):null]}):null]}),n?B(`div`,{class:`px-5 pb-5 sm:px-6 sm:pb-6`,children:[B(`h3`,{class:`mb-3 text-sm font-black text-slate-950`,children:`현재 상태`}),B(`dl`,{class:`grid overflow-hidden rounded-xl border border-slate-200 bg-slate-200 sm:grid-cols-2`,children:[B(`div`,{class:`bg-white p-4`,children:[B(`dt`,{class:`text-[11px] font-black uppercase tracking-[0.16em] text-slate-400`,children:`Installed`}),B(`dd`,{class:`mt-2 mb-0 ml-0 break-all text-sm font-black text-slate-950`,children:A?.installedVersion||`미확인`})]}),B(`div`,{class:`bg-white p-4`,children:[B(`dt`,{class:`text-[11px] font-black uppercase tracking-[0.16em] text-slate-400`,children:`Available`}),B(`dd`,{class:`mt-2 mb-0 ml-0 break-all text-sm font-black ${A?.updateAvailable||D?`text-amber-700`:`text-slate-950`}`,children:!n.lastCheckAt||O&&!A?.updateAvailable?`미확인`:A?.updateAvailable&&A.availableVersion?A.availableVersion:D?`확인 필요`:`최신 버전`})]}),B(`div`,{class:`bg-white p-4`,children:[B(`dt`,{class:`text-[11px] font-black uppercase tracking-[0.16em] text-slate-400`,children:`Last check`}),B(`dd`,{class:`mt-2 mb-0 ml-0 text-sm font-black text-slate-950`,children:Iv(n.lastCheckAt)})]}),B(`div`,{class:`bg-white p-4`,children:[B(`dt`,{class:`text-[11px] font-black uppercase tracking-[0.16em] text-slate-400`,children:`Auto install`}),B(`dd`,{class:`mt-2 mb-0 ml-0 text-sm font-black text-slate-950`,children:n.settings.autoInstall?`켜짐 · ${n.settings.autoInstallTime}`:`꺼짐`})]})]})]}):null,n&&n.updateCount===0&&n.lastCheckAt?D?B(`section`,{class:`mx-5 mb-5 rounded-xl border border-amber-200 bg-amber-50 p-4 sm:mx-6 sm:mb-6 sm:p-5`,"data-section":`software-update-result`,children:B(`div`,{class:`flex gap-3`,children:[B(`span`,{class:`grid size-10 shrink-0 place-items-center rounded-xl bg-white text-amber-700 ring-1 ring-inset ring-amber-200`,children:B(U,{class:`size-5`})}),B(`div`,{children:[B(`h3`,{class:`m-0 text-base font-black text-amber-950`,children:`업데이트 확인이 지연되고 있습니다.`}),B(`p`,{class:`mt-1 mb-0 text-sm leading-6 text-amber-800`,children:[`마지막 확인은 `,Iv(n.lastCheckAt),`에 완료되었습니다. 자동 확인 상태를 점검하거나 업데이트 확인을 실행해 주세요.`]})]})]})}):B(`section`,{class:`mx-5 mb-5 rounded-xl border border-emerald-200 bg-emerald-50 p-4 sm:mx-6 sm:mb-6 sm:p-5`,"data-section":`software-update-result`,children:B(`div`,{class:`flex gap-3`,children:[B(`span`,{class:`grid size-10 shrink-0 place-items-center rounded-xl bg-white text-emerald-700`,children:B(Xt,{class:`size-5`})}),B(`div`,{children:[B(`h3`,{class:`m-0 text-base font-black text-emerald-950`,children:`최신 버전을 사용 중입니다.`}),B(`p`,{class:`mt-1 mb-0 text-sm leading-6 text-emerald-800`,children:[`마지막 확인은 `,Iv(n.lastCheckAt),`에 완료되었습니다.`]})]})]})}):null,n&&n.updateCount===0&&!n.lastCheckAt?B(`section`,{class:`mx-5 mb-5 rounded-xl border border-slate-200 bg-slate-50 p-4 sm:mx-6 sm:mb-6 sm:p-5`,"data-section":`software-update-result`,children:B(`div`,{class:`flex flex-col gap-4 sm:flex-row sm:items-center sm:justify-between`,children:[B(`div`,{class:`flex min-w-0 gap-3`,children:[B(`span`,{class:`grid size-10 shrink-0 place-items-center rounded-xl bg-white text-slate-500 ring-1 ring-inset ring-slate-200`,children:B(H,{class:`size-5`})}),B(`div`,{class:`min-w-0`,children:[B(`h3`,{class:`m-0 text-base font-black text-slate-900`,children:`업데이트 상태를 아직 확인하지 않았습니다.`}),B(`p`,{class:`mt-1 mb-0 text-sm leading-6 text-slate-600`,children:`업데이트 확인을 실행하면 현재 설치 버전과 사용 가능한 최신 버전을 확인합니다.`})]})]}),B(`button`,{class:`inline-flex min-h-10 shrink-0 items-center justify-center gap-2 rounded-xl border border-slate-300 bg-white px-4 py-2 text-sm font-extrabold text-slate-800 transition hover:border-teal-300 hover:text-teal-700 disabled:cursor-wait disabled:opacity-60`,disabled:E,onClick:o,type:`button`,children:[B(H,{class:`size-4`}),`지금 확인`]})]})}):null]}),n?B(S,{children:[B(`section`,{class:`min-w-0 border-t border-slate-200 p-5 sm:p-6 xl:col-start-2 xl:row-start-1 xl:row-span-2 xl:self-stretch xl:border-t-0 xl:border-l`,"data-section":`software-update-settings`,children:[B(`div`,{class:`flex flex-col gap-4 sm:flex-row sm:items-start sm:justify-between`,children:[B(`div`,{class:`flex min-w-0 gap-4`,children:[B(`span`,{class:`grid size-11 shrink-0 place-items-center rounded-xl bg-slate-100 text-slate-600`,children:B(It,{class:`size-5`})}),B(`div`,{class:`min-w-0`,children:[B(`p`,{class:`m-0 text-xs font-extrabold uppercase tracking-[0.16em] text-slate-500`,children:`Settings`}),B(`h3`,{class:`mt-2 mb-0 text-lg font-black text-slate-950`,children:`자동 업데이트`}),B(`p`,{class:`mt-2 mb-0 max-w-3xl text-sm leading-6 text-slate-500`,children:`관리 소프트웨어의 자동 확인과 자동 설치를 설정합니다.`})]})]}),y?B(`span`,{"aria-live":`polite`,class:`inline-flex shrink-0 self-start items-center gap-1.5 rounded-full border border-amber-200 bg-amber-50 px-2.5 py-1 text-xs font-extrabold text-amber-800`,role:`status`,children:[B(U,{"aria-hidden":`true`,class:`size-3.5 shrink-0`}),`저장되지 않음`]}):null]}),B(`div`,{class:`ssh-software-settings-grid mt-4`,children:[B(`div`,{class:`ssh-software-settings-channel rounded-xl border border-slate-200 p-4 sm:p-5`,children:B(`div`,{class:`flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between`,children:[B(`div`,{class:`min-w-0`,children:[B(`strong`,{class:`block text-sm font-black text-slate-950`,children:`업데이트 채널`}),B(`span`,{class:`mt-1 block text-xs leading-5 text-slate-500`,children:`현재 관리 소프트웨어 업데이트를 확인하는 배포 채널입니다.`})]}),B(`span`,{class:`inline-flex min-h-9 shrink-0 items-center justify-center rounded-full px-3 py-1.5 text-xs font-extrabold ring-1 ring-inset ${Rv(n.settings.channel)}`,title:`현재 업데이트 확인 채널`,children:Lv(n.settings.channel)})]})}),B(`div`,{class:`min-w-0 overflow-hidden rounded-xl border border-slate-200 p-4 sm:p-5`,children:[B(`div`,{class:`flex min-w-0 items-start justify-between gap-4`,children:[B(`div`,{class:`min-w-0`,children:[B(`strong`,{class:`block text-sm font-black text-slate-950`,children:`자동으로 업데이트 확인`}),B(`span`,{class:`mt-1 block text-xs leading-5 text-slate-500`,children:`선택한 주기에 새 관리 소프트웨어 버전을 확인합니다.`})]}),B(Uv,{checked:d,label:`자동 업데이트 확인`,onChange:e=>{f(e),b(ee({checkEnabled:e}))}})]}),B(`div`,{class:`mt-4 block`,children:[B(`span`,{class:`text-xs font-extrabold text-slate-700`,children:`확인 주기`}),B(Vg,{ariaLabel:`업데이트 확인 주기`,className:`mt-2`,disabled:!d,id:`software-update-check-interval`,onChange:e=>{let t=Number(e);m(t),b(ee({checkIntervalSeconds:t}))},options:Pv.map(e=>({value:String(e.value),label:e.label})),value:String(p),variant:`emphasized`})]})]}),B(`div`,{class:`min-w-0 overflow-hidden rounded-xl border border-slate-200 p-4 sm:p-5`,children:[B(`div`,{class:`flex min-w-0 items-start justify-between gap-4`,children:[B(`div`,{class:`min-w-0`,children:[B(`strong`,{class:`block text-sm font-black text-slate-950`,children:`자동으로 업데이트 설치`}),B(`span`,{class:`mt-1 block text-xs leading-5 text-slate-500`,children:`새 버전이 있으면 지정한 시각에 자동으로 설치합니다.`})]}),B(Uv,{checked:h,label:`자동 업데이트 설치`,onChange:e=>{g(e),b(ee({autoInstall:e}))}})]}),B(`div`,{class:`mt-4 min-w-0`,children:[B(`span`,{class:`text-xs font-extrabold text-slate-700`,children:`설치 시각`}),B(lv,{ariaLabel:`자동 업데이트 설치 시각`,className:`mt-2`,disabled:!h,id:`software-update-auto-install-time`,onChange:e=>{v(e),b(ee({autoInstallTime:e}))},value:_,variant:`emphasized`})]})]})]}),h?B(`p`,{class:`mt-4 mb-0 rounded-xl bg-amber-50 px-4 py-3 text-xs font-bold leading-5 text-amber-800`,children:`자동 설치 중에는 SmartSafeHub 웹 화면 연결이 잠시 끊길 수 있습니다.`}):null,B(`div`,{class:`mt-5 flex flex-col gap-3 border-t border-slate-100 pt-5 sm:flex-row sm:items-center sm:justify-between`,children:[B(`p`,{class:`m-0 text-xs leading-5 text-slate-500`,children:[`마지막 설치: `,Iv(n.lastInstallAt)]}),B(`button`,{class:`inline-flex min-h-11 items-center justify-center rounded-xl bg-slate-900 px-4 py-2.5 text-sm font-extrabold text-white transition hover:bg-slate-800 disabled:cursor-not-allowed disabled:opacity-50`,disabled:!y||e===`settings`||E,onClick:()=>void j(),type:`button`,children:e===`settings`?`저장 중`:`자동 업데이트 설정 저장`})]})]}),n.updateCount>0?B(`section`,{class:`border-t border-slate-200 p-5 sm:p-6 xl:col-start-1 xl:row-start-2`,"data-section":`software-update-release-notes`,children:[B(`div`,{class:`flex flex-col gap-2 sm:flex-row sm:items-start sm:justify-between sm:gap-4`,children:[B(`div`,{children:[B(`p`,{class:`m-0 text-xs font-extrabold uppercase tracking-[0.16em] text-teal-700`,children:`Release notes`}),B(`h3`,{class:`mt-2 mb-0 text-lg font-black text-slate-950`,children:`업데이트 내용`}),B(`p`,{class:`mt-2 mb-0 text-sm leading-6 text-slate-500`,children:`현재 설치된 버전 이후 포함되는 주요 변경 사항입니다.`})]}),n.releaseNotes.length?B(`span`,{class:`shrink-0 rounded-full bg-slate-100 px-3 py-1.5 text-xs font-extrabold text-slate-600`,children:n.releaseNotes.length===1?`1개 릴리즈`:`${n.releaseNotes.length}개 릴리즈`}):null]}),n.releaseNotes.length?B(`div`,{class:`mt-5 grid gap-3`,children:[n.releaseNotes.map(e=>B(`article`,{class:`rounded-xl border border-slate-200 bg-slate-50 p-4 sm:p-5`,children:[B(`div`,{class:`flex flex-col gap-1 sm:flex-row sm:items-center sm:justify-between sm:gap-4`,children:[B(`strong`,{class:`break-all text-sm font-black text-slate-950`,children:e.version}),e.date?B(`span`,{class:`text-xs font-bold text-slate-500`,children:e.date}):null]}),e.summary?B(`p`,{class:`mt-3 mb-0 text-sm leading-6 text-slate-700`,children:e.summary}):null,e.sections.length?B(`details`,{class:`mt-4 rounded-lg border border-slate-200 bg-white p-3`,open:n.releaseNotes.length===1,children:[B(`summary`,{class:`cursor-pointer text-xs font-extrabold text-slate-800`,children:`자세한 변경 사항`}),B(`div`,{class:`mt-3 grid gap-4`,children:e.sections.map(t=>B(`section`,{children:[B(`h4`,{class:`m-0 text-xs font-extrabold text-slate-700`,children:t.title}),B(`ul`,{class:`mt-2 mb-0 space-y-1.5 pl-5 text-xs leading-5 text-slate-600`,children:t.items.map((n,r)=>B(`li`,{children:n},`${e.version}-${t.title}-${r}`))})]},`${e.version}-${t.title}`))})]}):null]},e.version)),n.releaseNotesComplete?null:B(`p`,{class:`m-0 rounded-xl bg-amber-50 px-4 py-3 text-xs font-bold leading-5 text-amber-800`,children:`일부 릴리즈 노트를 불러오지 못했습니다. 업데이트 확인과 설치는 계속 사용할 수 있습니다.`})]}):B(`p`,{class:`mt-4 mb-0 rounded-xl bg-slate-50 px-4 py-3 text-sm text-slate-500`,children:`릴리즈 노트를 불러오지 못했습니다. 업데이트 확인과 설치는 계속 사용할 수 있습니다.`})]}):null]}):null]})}function Gv({action:e,actionError:t,data:n,error:r,firmware:i,loading:a,message:o,onCheck:s,onDismissFeedback:c,onInstall:l,onRetry:u,onSaveSettings:d}){return B(`section`,{class:`min-w-0 space-y-5`,children:[B(Nv,{action:i.action,actionError:i.actionError,data:i.data,error:i.error,loading:i.loading,message:i.message,reconnecting:i.reconnecting,uploadProgress:i.uploadProgress,onCheck:()=>void i.check(),onDiscard:i.discard,onDismissFeedback:i.dismissFeedback,onInstall:i.install,onPrepare:()=>void i.prepare(),onRetry:()=>void i.refresh(),onUpload:i.upload}),B(Wv,{action:e,actionError:t,data:n,error:r,loading:a,message:o,onCheck:s,onDismissFeedback:c,onInstall:l,onRetry:u,onSaveSettings:d})]})}var Kv=[{value:`sae-mixed`,label:`WPA2/WPA3 혼합 (권장)`},{value:`sae`,label:`WPA3-Personal`},{value:`psk2`,label:`WPA2-Personal`},{value:`none`,label:`암호화 없음`}];function qv(e){switch(e.security){case`sae-mixed`:return`WPA2/WPA3 혼합`;case`sae`:return`WPA3-Personal`;case`psk2`:return`WPA2-Personal`;case`none`:return`암호화 없음`;default:return`고급 설정 (${e.securityRaw})`}}function Jv(e){return e.length>=8&&e.length<=63||/^[0-9a-fA-F]{64}$/.test(e)}function Yv({network:e,busy:t,saving:n,onUpdate:r}){let[i,a]=N(e.ssid),[o,s]=N(e.enabled),[c,l]=N(e.security===`custom`?`keep`:e.security),[u,d]=N(``),[f,p]=N(null);P(()=>{a(e.ssid),s(e.enabled),l(e.security===`custom`?`keep`:e.security),d(``),p(null)},[e]);let m=e.security===`custom`&&c===`keep`,h=c===`psk2`||c===`sae-mixed`||c===`sae`,g=e.security===`custom`?`keep`:e.security,_=i.trim()!==e.ssid||o!==e.enabled||c!==g||u.length>0,v=[...e.security===`custom`?[{value:`keep`,label:`현재 고급 설정 유지 (${e.securityRaw})`}]:[],...Kv],y=async t=>{t.preventDefault();let n=i.trim(),a=new TextEncoder().encode(n).length;if(a<1||a>32){p(`SSID는 UTF-8 기준 1~32바이트로 입력해 주세요.`);return}if(u&&!Jv(u)){p(`비밀번호는 8~63자 또는 64자리 16진수여야 합니다.`);return}if(h&&!e.passwordConfigured&&u.length===0){p(`보안 Wi-Fi를 사용하려면 비밀번호를 입력해 주세요.`);return}window.confirm(`Wi-Fi 설정을 적용하면 현재 무선 연결이 잠시 끊어질 수 있습니다. 계속하시겠습니까?`)&&(p(null),await r({section:e.section,ssid:n,security:c,password:u,enabled:o})&&d(``))};return B(`form`,{class:`rounded-2xl border border-slate-200 bg-white p-4 shadow-sm shadow-slate-900/5 sm:p-6`,onSubmit:e=>void y(e),children:[B(`div`,{class:`flex flex-col gap-4 sm:flex-row sm:items-start sm:justify-between`,children:[B(`div`,{class:`flex min-w-0 items-start gap-3`,children:[B(`span`,{class:`grid size-11 shrink-0 place-items-center rounded-xl bg-teal-50 text-teal-700`,children:B(jt,{class:`size-6`})}),B(`div`,{class:`min-w-0`,children:[B(`p`,{class:`m-0 text-xs font-extrabold uppercase tracking-[0.16em] text-slate-500`,children:e.bandLabel}),B(`h2`,{class:`mt-2 mb-0 break-words text-xl font-extrabold tracking-tight text-slate-950`,children:e.ssid||`이름 없는 Wi-Fi`}),B(`p`,{class:`mt-2 mb-0 text-sm text-slate-600`,children:[`채널 `,e.channel??`자동`,` · 연결 기기 `,e.clientCount,`대`]})]})]}),B(`div`,{class:`flex flex-wrap items-center gap-2 sm:justify-end`,children:[_?B(`span`,{"aria-live":`polite`,class:`inline-flex shrink-0 items-center gap-1.5 rounded-full border border-amber-200 bg-amber-50 px-2.5 py-1 text-xs font-extrabold text-amber-800`,role:`status`,children:[B(U,{"aria-hidden":`true`,class:`size-3.5 shrink-0`}),`저장되지 않음`]}):null,B(`span`,{class:`inline-flex w-fit items-center gap-2 rounded-full px-3 py-1.5 text-xs font-extrabold ring-1 ring-inset ${e.runtimeUp?`bg-emerald-50 text-emerald-700 ring-emerald-200`:`bg-slate-100 text-slate-600 ring-slate-200`}`,children:[B(`span`,{class:`size-2 rounded-full ${e.runtimeUp?`bg-emerald-500`:`bg-slate-400`}`}),e.runtimeUp?`동작 중`:e.enabled?`시작 대기`:`꺼짐`]})]})]}),B(`div`,{class:`mt-6 grid gap-5 lg:grid-cols-2`,children:[B(`label`,{class:`block`,children:[B(`span`,{class:`text-sm font-extrabold text-slate-800`,children:`Wi-Fi 이름 (SSID)`}),B(`input`,{autocomplete:`off`,class:`mt-2 min-h-11 w-full rounded-xl border-2 border-slate-300 bg-slate-50 px-4 py-2.5 text-sm font-semibold text-slate-950 shadow-inner outline-none transition placeholder:text-slate-400 focus:border-teal-500 focus:bg-white focus:ring-4 focus:ring-teal-100 disabled:cursor-not-allowed disabled:bg-slate-100`,disabled:t,maxLength:32,onInput:e=>a(e.currentTarget.value),value:i})]}),B(`div`,{class:`block`,children:[B(`span`,{class:`text-sm font-extrabold text-slate-800`,children:`보안 방식`}),B(Vg,{ariaLabel:`${e.bandLabel} Wi-Fi 보안 방식`,className:`mt-2`,disabled:t,id:`wifi-security-${e.section}`,onChange:e=>{let t=e;l(t),(t===`none`||t===`keep`)&&d(``)},options:v,value:c,variant:`emphasized`}),B(`span`,{class:`mt-2 block text-xs text-slate-500`,children:[`현재: `,qv(e)]})]}),B(`label`,{class:`block lg:col-span-2`,children:[B(`span`,{class:`text-sm font-extrabold text-slate-800`,children:`새 비밀번호`}),B(`input`,{autocomplete:`new-password`,class:`mt-2 min-h-11 w-full rounded-xl border-2 border-slate-300 bg-slate-50 px-4 py-2.5 text-sm font-semibold text-slate-950 shadow-inner outline-none transition placeholder:text-slate-400 focus:border-teal-500 focus:bg-white focus:ring-4 focus:ring-teal-100 disabled:cursor-not-allowed disabled:bg-slate-100`,disabled:t||c===`none`||m,onInput:e=>d(e.currentTarget.value),placeholder:m?`고급 보안 설정은 기존 LuCI에서 변경합니다`:e.passwordConfigured?`비워 두면 기존 비밀번호를 유지합니다`:`8자 이상의 비밀번호를 입력하세요`,type:`password`,value:u}),B(`span`,{class:`mt-2 block text-xs text-slate-500`,children:`저장된 비밀번호는 화면이나 API로 다시 노출하지 않습니다.`})]})]}),B(`div`,{class:`mt-6 flex flex-col gap-4 border-t border-slate-200 pt-5 sm:flex-row sm:items-center sm:justify-between`,children:[B(`label`,{class:`inline-flex min-h-11 items-center gap-3 text-sm font-extrabold text-slate-800`,children:[B(`input`,{checked:o,class:`size-5 accent-teal-700`,disabled:t,onChange:e=>s(e.currentTarget.checked),type:`checkbox`}),`이 Wi-Fi 사용`]}),B(`button`,{class:`inline-flex min-h-11 w-full items-center justify-center gap-2 rounded-xl border-0 bg-teal-700 px-5 sm:w-auto py-2.5 text-sm font-extrabold text-white shadow-sm transition hover:bg-teal-800 focus:outline-none focus-visible:ring-4 focus-visible:ring-teal-200 disabled:cursor-wait disabled:opacity-60`,disabled:t||!_,type:`submit`,children:[B(Xt,{class:`size-5 ${n?`animate-pulse`:``}`}),n?`적용 중`:`설정 저장`]})]}),f?B(`p`,{class:`mt-4 mb-0 rounded-xl bg-red-50 px-4 py-3 text-sm font-bold text-red-800`,children:f}):null]})}function Xv({feedback:e,onDismiss:t}){return B(`div`,{"aria-live":`polite`,class:`mb-5 flex flex-col gap-3 rounded-2xl border px-4 py-3 text-sm sm:flex-row sm:items-center sm:justify-between ${e.kind===`success`?`border-emerald-200 bg-emerald-50 text-emerald-900`:e.kind===`warning`?`border-amber-200 bg-amber-50 text-amber-900`:`border-red-200 bg-red-50 text-red-900`}`,children:[B(`p`,{class:`m-0 font-bold leading-6`,children:e.message}),B(`button`,{class:`min-h-11 w-full shrink-0 rounded-lg border border-current bg-transparent sm:min-h-9 sm:w-auto px-3 py-1.5 text-xs font-extrabold`,onClick:t,type:`button`,children:`닫기`})]})}function Zv({data:e,error:t,feedback:n,loading:r,updatingSection:i,onDismissFeedback:a,onRetry:o,onUpdate:s}){return r?B(io,{}):t?B(ao,{message:t,onRetry:o}):e?B(S,{children:[n?B(Xv,{feedback:n,onDismiss:a}):null,B(`section`,{class:`mb-5 rounded-2xl border border-amber-200 bg-amber-50 p-5 text-amber-950 sm:p-6`,children:[B(`p`,{class:`m-0 text-xs font-extrabold uppercase tracking-[0.16em] text-amber-700`,children:`연결 주의`}),B(`h2`,{class:`mt-2 mb-0 text-lg font-extrabold`,children:`Wi-Fi 이름이나 비밀번호를 바꾸면 현재 연결이 끊어집니다`}),B(`p`,{class:`mt-2 mb-0 text-sm leading-6 text-amber-900/80`,children:`변경한 Wi-Fi 이름과 비밀번호로 다시 연결하면 SmartSafeHub를 계속 사용할 수 있습니다. VLAN, 게스트 네트워크와 고급 무선 옵션은 기존 LuCI에서 관리합니다.`})]}),e.networks.length?B(`section`,{"aria-label":`기본 Wi-Fi 설정`,class:`grid gap-5 xl:grid-cols-2`,children:e.networks.map(e=>B(Yv,{busy:i!==null,network:e,onUpdate:s,saving:i===e.section},e.section))}):B(`section`,{class:`rounded-2xl border border-slate-200 bg-white p-5 text-center shadow-sm shadow-slate-900/5 sm:p-8`,children:[B(jt,{class:`mx-auto size-10 text-slate-400`}),B(`h2`,{class:`mt-4 mb-0 text-lg font-extrabold text-slate-950`,children:`관리할 기본 Wi-Fi를 찾지 못했습니다`}),B(`p`,{class:`mt-2 mb-0 text-sm leading-6 text-slate-600`,children:`기존 LuCI에서 AP 모드의 무선 네트워크를 먼저 구성해 주세요.`})]})]}):null}function Qv({onAdministratorPasswordChanged:e}){let t=qr(),n=kr(),r=yr(t===`home`||t===`activity`),i=ha(t===`home`||t===`settings`),a=pa(!0),o=Wr(!0),s=ii(t===`network`),c=ni(t===`home`||t===`network`),l=ei(t===`iptv`),u=Oa(t===`wifi`),d=jr(t===`home`,!1),f=jr(t===`devices`),p=ca(t===`home`),m=$i(t===`home`,!1),h=ca(t===`safeshield`),g=$i(t===`safeshield`),_=Zi(t===`rules`),v=wa(i.data),y=$r(t===`home`||t===`settings`),b=ga(t===`settings`),x=Ta(t===`settings`),S=Hi(h.refresh,g.refresh),C=t===`activity`?r:t===`network`?s:t===`wifi`?u:t===`iptv`?l:t===`devices`?f:t===`safeshield`?h:t===`rules`?_:t===`system`?a:i,w;switch(t){case`network`:w=B(`div`,{class:`min-w-0`,children:[B(`div`,{"aria-label":`인터넷 연결 설정`,class:`min-w-0`,children:B(b_,{action:s.action,data:s.data,error:s.error,feedback:s.feedback,loading:s.loading,onDismissFeedback:s.dismissFeedback,onReconnect:()=>void s.reconnect(),onRetry:()=>void s.refresh(),onSave:s.save})}),B(`div`,{"aria-label":`내부 네트워크 설정`,class:`mt-8 min-w-0 border-t border-slate-200 pt-8`,children:B(o_,{action:c.action,data:c.data,error:c.error,feedback:c.feedback,loading:c.loading,onApplyRecommendation:c.applyRecommendation,onDismissFeedback:c.dismissFeedback,onRetry:()=>void c.refresh(),onSave:c.save})})]});break;case`activity`:w=B(ro,{actionError:r.actionError,actionMessage:r.actionMessage,data:r.data,error:r.error,loading:r.loading,onDismissActionFeedback:r.dismissActionFeedback,onRetry:()=>void r.refresh(),onSetCloudSync:e=>void r.setCloudSyncEnabled(e),savingCloudSync:r.savingCloudSync});break;case`wifi`:w=B(Zv,{data:u.data,error:u.error,feedback:u.feedback,loading:u.loading,onDismissFeedback:u.dismissFeedback,onRetry:()=>void u.refresh(),onUpdate:u.update,updatingSection:u.updatingSection});break;case`iptv`:w=B(Gg,{data:l.data,error:l.error,feedback:l.feedback,loading:l.loading,onDismissFeedback:l.dismissFeedback,onRetry:()=>void l.refresh(),onSave:l.save,saving:l.saving});break;case`devices`:w=B(vo,{data:f.data,error:f.error,loading:f.loading,onRetry:()=>void f.refresh()});break;case`system`:w=B(Gv,{action:a.action,actionError:a.actionError,data:a.data,error:a.error,firmware:o,loading:a.loading,message:a.message,onCheck:()=>void a.check(),onDismissFeedback:a.dismissFeedback,onInstall:()=>void a.install(),onRetry:()=>void a.refresh(),onSaveSettings:a.saveSettings});break;case`settings`:w=B(Ev,{action:v.action,backupAction:n.action,backupError:n.error,backupMessage:n.message,backupRestoreAccepted:n.restoreAccepted,backupUploadProgress:n.uploadProgress,backupValidated:n.validated,data:i.data,error:i.error,feedbackError:v.error,feedbackMessage:v.message,firmware:o.data,firmwareError:o.error,firmwareLoading:o.loading,health:y.data,healthActionError:y.actionError,healthActionMessage:y.actionMessage,healthError:y.error,healthLoading:y.loading,healthRunning:y.running,healthSavingReporter:y.savingReporter,loading:i.loading,onBackupDiscard:n.discard,onBackupDownload:()=>void n.download(),onBackupRestore:n.restore,onBackupUpload:n.upload,onDismissBackupFeedback:n.dismissFeedback,onDismissFeedback:v.dismissFeedback,onDismissHealthFeedback:y.dismissActionFeedback,onDismissTimeFeedback:x.dismissSaveFeedback,onDownloadDiagnostics:()=>void v.downloadDiagnostics(),onRunHealth:()=>void y.runDiagnostic(),onSetHealthReporter:e=>void y.setReporterEnabled(e),onReboot:()=>void v.reboot(),onRetry:()=>void Promise.all([i.refresh(),o.refresh(),x.refresh(),b.refresh(),y.refresh()]),onDismissScheduledRebootFeedback:b.dismissSaveFeedback,onSaveScheduledReboot:b.saveSettings,onSaveTimezone:x.saveTimezone,onSyncTime:x.syncTime,onAdministratorPasswordChanged:e,rebootAccepted:v.rebootAccepted,scheduledRebootData:b.data,scheduledRebootError:b.error,scheduledRebootLoading:b.loading,scheduledRebootSaveError:b.saveError,scheduledRebootSaveMessage:b.saveMessage,scheduledRebootSaving:b.saving,timeData:x.data,timeError:x.error,timeLoading:x.loading,timeSaveError:x.saveError,timeSaveMessage:x.saveMessage,timeSaving:x.saving,timeSyncing:x.syncing});break;case`safeshield`:w=B(ev,{action:S.action,actionError:S.error,actionFeedbackTarget:S.feedbackTarget,actionMessage:S.message,data:h.data,error:h.error,loading:h.loading,statistics:g.data,statisticsError:g.error,statisticsLoading:g.loading,statisticsRefreshing:g.refreshing,onDismissFeedback:S.dismissFeedback,onReadLicense:S.readLicense,onRefreshBlocklist:()=>void S.refreshBlocklist(),onRemoveLicense:S.removeLicense,onRetry:()=>void h.refresh(),onRetryStatistics:()=>void g.refresh(),onSetEnabled:e=>void S.setEnabled(e),onSetStatisticsEnabled:e=>void S.setStatisticsEnabled(e),onUpdateLicense:S.updateLicense});break;case`rules`:w=B(iv,{action:_.action,data:_.data,error:_.error,feedback:_.feedback,loading:_.loading,onAddRule:_.addRule,onDeleteRule:_.deleteRule,onDismissFeedback:_.dismissFeedback,onRetry:()=>void _.refresh()});break;default:w=B(sg,{activity:r.data,activityError:r.error,activityLoading:r.loading,data:i.data,devices:d.data,devicesError:d.error,devicesLoading:d.loading,error:i.error,firmware:o.data,firmwareError:o.error,firmwareLoading:o.loading,health:y.data,healthError:y.error,healthLoading:y.loading,lan:c.data,lanError:c.error,lanLoading:c.loading,loading:i.loading,onRetry:()=>void Promise.all([r.refresh(),i.refresh(),d.refresh(),p.refresh(),m.refresh(),a.refresh(),o.refresh(),y.refresh(),c.refresh()]),safeshield:p.data,safeshieldError:p.error,safeshieldLoading:p.loading,statistics:m.data,statisticsError:m.error,statisticsLoading:m.loading,statisticsRefreshing:m.refreshing,updates:a.data,updatesError:a.error,updatesLoading:a.loading})}let T=()=>{if(t===`home`){Promise.all([r.refresh(),i.refresh(),d.refresh(),p.refresh(),m.refresh(),a.refresh(),o.refresh(),y.refresh(),c.refresh()]);return}if(t===`network`){Promise.all([s.refresh(),c.refresh()]);return}if(t===`system`){Promise.all([a.refresh(),o.refresh()]);return}if(t===`settings`){Promise.all([i.refresh(),o.refresh(),x.refresh(),b.refresh(),y.refresh()]);return}if(t===`safeshield`){Promise.all([h.refresh(),g.refresh()]);return}C.refresh()},E=+((a.data?.updateCount??0)>0)+ +!!o.data?.updateAvailable;return B(An,{loading:t===`network`?s.loading||c.loading:C.loading,onRefresh:T,refreshing:C.refreshing||t===`network`&&c.refreshing||t===`home`&&(r.refreshing||d.refreshing||p.refreshing||m.refreshing||a.refreshing||o.refreshing||y.refreshing||c.refreshing)||t===`system`&&o.refreshing||t===`settings`&&(o.refreshing||x.refreshing||b.refreshing||y.refreshing)||t===`safeshield`&&g.refreshing,route:t,updateCount:E,children:w})}function $v({onAdministratorPasswordChanged:e,onPasswordConfigured:t}){let[n,r]=N(`checking`),[i,a]=N(!1),o=I(async()=>{r(`checking`);try{let e=await Dt();a(e.recovery),r(e.configured?`ready`:`required`)}catch{r(`error`)}},[]);return P(()=>{o()},[o]),n===`ready`?B(Qv,{onAdministratorPasswordChanged:e}):n===`required`?B(vn,{onCompleted:()=>t(i),recovery:i}):B(`main`,{class:`ssh-initial-setup-probe`,role:n===`error`?`alert`:`status`,children:B(`div`,{class:`ssh-initial-setup-probe-card`,children:[n===`checking`?B(H,{class:`ssh-login-probe-spinner`,"aria-hidden":`true`}):B(At,{"aria-hidden":`true`}),B(`strong`,{children:n===`checking`?`관리자 보안 상태 확인 중`:`관리자 보안 상태를 확인할 수 없습니다`}),B(`span`,{children:n===`checking`?`root 비밀번호 설정 여부를 확인하고 있습니다.`:`공유기 연결을 확인한 뒤 다시 시도해 주세요.`}),n===`error`?B(`button`,{onClick:()=>void o(),type:`button`,children:`다시 시도`}):null]})})}function ey({icon:e,title:t,description:n}){return B(`div`,{class:`ssh-login-feature`,children:[B(`span`,{class:`ssh-login-feature-icon`,"aria-hidden":`true`,children:e}),B(`span`,{class:`ssh-login-feature-copy`,children:[B(`strong`,{children:t}),B(`span`,{children:n})]})]})}function ty({theme:e}){return B(e===`dark`?ln:cn,{})}function ny({notice:e,onAuthenticated:t,probing:n=!1}){let r=$e(Ee,[]),i=F(null),a=F(null),[o,s]=N(`root`),[c,l]=N(``),[u,d]=N(`ready`),[f,p]=N(null),[m,h]=N(e??null),[g,_]=N(!1),[v,y]=N(!1),[b,x]=N(!1),[S,C]=N(dn),w=u===`submitting`,T=S===`dark`?`라이트 모드로 전환`:`다크 모드로 전환`;P(()=>{fn(S),pn(S)},[S]),P(()=>{if(n)return;let e=window.requestAnimationFrame(()=>a.current?.focus());return()=>window.cancelAnimationFrame(e)},[n]),P(()=>{if(h(e??null),!e)return;let t=window.setTimeout(()=>h(null),7e3);return()=>window.clearTimeout(t)},[e]);let E=e=>{x(e.getModifierState?.(`CapsLock`)??!1)};return B(`main`,{class:`ssh-login-page`,"data-theme":S,children:[m?B(`div`,{"aria-atomic":`true`,"aria-live":`assertive`,class:`ssh-login-toast`,role:`alert`,children:[B(At,{"aria-hidden":`true`}),B(`span`,{children:m})]}):null,B(`section`,{class:`ssh-login-brand`,"aria-labelledby":`ssh-login-brand-title`,children:[B(`div`,{class:`ssh-login-brand-orb ssh-login-brand-orb-one`,"aria-hidden":`true`}),B(`div`,{class:`ssh-login-brand-orb ssh-login-brand-orb-two`,"aria-hidden":`true`}),B(`div`,{class:`ssh-login-brand-content`,children:[B(`span`,{class:`ssh-login-brand-mark`,"aria-hidden":`true`,children:B(At,{})}),B(`p`,{class:`ssh-login-eyebrow`,children:`SMART NETWORK PROTECTION`}),B(`h1`,{id:`ssh-login-brand-title`,children:`SmartSafeHub`}),B(`p`,{class:`ssh-login-brand-description`,children:`네트워크와 보안을 하나의 허브에서 관리하세요. SafeShield 보호 상태부터 Wi-Fi와 연결 기기까지 로컬에서 빠르게 확인할 수 있습니다.`}),B(`div`,{class:`ssh-login-features`,"aria-label":`SmartSafeHub 주요 기능`,children:[B(ey,{description:`DNS 기반 광고·피싱 차단과 사용자 보호 정책을 관리합니다.`,icon:B(At,{}),title:`SafeShield 보호`}),B(ey,{description:`Wi-Fi 설정과 현재 연결된 기기의 상태를 한눈에 확인합니다.`,icon:B(Lt,{}),title:`네트워크 관리`}),B(ey,{description:`관리 기능과 인증은 현재 SmartSafeHub 장치에서 직접 처리됩니다.`,icon:B(Kt,{}),title:`로컬 우선 관리`})]})]})]}),B(`section`,{class:`ssh-login-panel`,"aria-labelledby":`ssh-login-title`,children:[B(`button`,{"aria-label":T,class:`ssh-login-theme-toggle`,onClick:()=>C(e=>e===`dark`?`light`:`dark`),title:T,type:`button`,children:B(ty,{theme:S})}),B(`div`,{class:`ssh-login-panel-inner`,children:[n?B(`div`,{class:`ssh-login-probe`,role:`status`,"aria-live":`polite`,children:[B(H,{class:`ssh-login-probe-spinner`,"aria-hidden":`true`}),B(`strong`,{children:`SmartSafeHub 연결 확인 중`}),B(`span`,{children:`로그인 세션을 확인하고 있습니다.`})]}):B(`div`,{class:`ssh-login-card`,children:[B(`div`,{class:`ssh-login-card-heading`,children:[B(`span`,{class:`ssh-login-mobile-mark`,"aria-hidden":`true`,children:B(At,{})}),B(`div`,{children:[B(`p`,{class:`ssh-login-kicker`,children:`SMARTSAFEHUB ACCESS`}),B(`h2`,{id:`ssh-login-title`,children:`SmartSafeHub에 로그인`}),B(`p`,{class:`ssh-login-subtitle`,children:`공유기 관리자 계정의 사용자 이름과 비밀번호를 입력해 주세요.`})]})]}),f?B(`div`,{class:`ssh-login-alert`,id:`ssh-login-error`,role:`alert`,"aria-live":`polite`,children:f}):null,B(`form`,{class:`ssh-login-form`,onSubmit:async e=>{e.preventDefault();let n=o.trim(),r=c;if(p(null),_(!1),!n||!r&&n!==`root`){p(n?`비밀번호를 입력해 주세요.`:`사용자 이름을 입력해 주세요.`),window.requestAnimationFrame(()=>{if(!n){i.current?.focus();return}a.current?.focus()});return}d(`submitting`);try{let e=await Me(n,r);if(e){l(``),t(e);return}l(``),_(!0),p(`로그인하지 못했습니다. 계정 정보를 확인해 주세요. 추가 인증이 설정된 장치는 기본 LuCI 로그인에서 계속할 수 있습니다.`),window.requestAnimationFrame(()=>a.current?.focus())}catch{p(`공유기와 통신할 수 없습니다. 네트워크 연결을 확인한 뒤 다시 시도해 주세요.`)}finally{d(`ready`)}},noValidate:!0,children:[B(`label`,{class:`ssh-login-field`,for:`smartsafehub-username`,children:[B(`span`,{class:`ssh-login-label`,children:`사용자 이름`}),B(`span`,{class:`ssh-login-input-wrap`,children:[B(`span`,{class:`ssh-login-field-icon`,"aria-hidden":`true`,children:B(Pt,{})}),B(`input`,{autoCapitalize:`none`,autoComplete:`username`,disabled:w,id:`smartsafehub-username`,name:`username`,onInput:e=>s(e.currentTarget.value),placeholder:`관리자 계정`,ref:i,required:!0,spellcheck:!1,type:`text`,value:o})]})]}),B(`label`,{class:`ssh-login-field`,for:`smartsafehub-password`,children:[B(`span`,{class:`ssh-login-label`,children:`비밀번호`}),B(`span`,{class:`ssh-login-input-wrap`,children:[B(`span`,{class:`ssh-login-field-icon`,"aria-hidden":`true`,children:B(Kt,{})}),B(`input`,{autoComplete:`current-password`,disabled:w,id:`smartsafehub-password`,name:`password`,onBlur:()=>x(!1),onInput:e=>l(e.currentTarget.value),onKeyDown:E,onKeyUp:E,placeholder:`관리자 비밀번호`,ref:a,type:v?`text`:`password`,value:c}),B(`button`,{"aria-label":v?`비밀번호 숨기기`:`비밀번호 표시`,"aria-pressed":v,class:`ssh-login-password-toggle`,disabled:w,onClick:()=>{y(e=>!e),window.requestAnimationFrame(()=>a.current?.focus())},title:v?`비밀번호 숨기기`:`비밀번호 표시`,type:`button`,children:B(v?Jt:qt,{})})]})]}),o.trim()===`root`&&c.length===0?B(`p`,{class:`ssh-login-password-hint`,children:`초기 설정 전 root 계정은 비밀번호가 비어 있을 수 있습니다.`}):null,b?B(`p`,{class:`ssh-login-caps`,role:`status`,children:`Caps Lock이 켜져 있습니다.`}):null,B(`button`,{class:`ssh-login-submit`,disabled:w,type:`submit`,children:[w?B(H,{class:`ssh-login-submit-spinner`,"aria-hidden":`true`}):null,B(`span`,{children:w?`로그인 중…`:`로그인`})]})]}),B(`div`,{class:`ssh-login-security-note`,children:[B(At,{"aria-hidden":`true`}),B(`span`,{children:`입력한 계정 정보는 현재 공유기의 LuCI 인증 경로로만 전송됩니다.`})]}),B(`div`,{class:`ssh-login-security-note`,children:[B(Kt,{"aria-hidden":`true`}),B(`span`,{children:`관리자 비밀번호를 잊었다면 전원이 켜진 상태에서 Reset 버튼을 5~9초 누른 뒤 놓아 비밀번호만 복구할 수 있습니다. 10초 이상 누르면 모든 사용자 설정을 초기화하는 기기 초기화가 실행됩니다.`})]}),g?B(`a`,{class:`ssh-login-fallback`,href:r,children:`기본 LuCI 로그인으로 계속`}):null]}),B(`footer`,{class:`ssh-login-footer`,children:[B(`span`,{children:`SmartSafeHub`}),B(`span`,{"aria-hidden":`true`,children:`·`}),B(`span`,{children:window.location.host})]})]})]})]})}var ry=`smartsafehub-entry-root`,iy=`data-smartsafehub-mount`,ay=`data-smartsafehub-shadow-style`;function oy(){let e=Se(`/`);new Set([e,e.replace(/\/$/,``),Se(`/smartsafehub`),Se(`/admin/smartsafehub`)]).has(window.location.pathname)&&window.history.replaceState(null,``,`${we()}${window.location.search}${window.location.hash}`)}function sy(e,t){Ie(),window.__SMARTHUB_BOOTSTRAP__=Object.freeze({sessionId:e,rpcUrl:Se(`/admin/ubus`),assetBase:t.dataset.assetBase??`/luci-static/smartsafehub/`,assetVersion:t.dataset.assetVersion??`0.2.24-r1`,locale:document.documentElement.lang||`ko`})}function cy(e,t){let n=window.__SMARTHUB_BOOTSTRAP__,r=n?.assetBase??t.dataset.assetBase??`/luci-static/smartsafehub/`,i=n?.assetVersion??t.dataset.assetVersion,a=`${r}${r.endsWith(`/`)?``:`/`}${e}`;return i?`${a}?v=${encodeURIComponent(i)}`:a}function ly(e,t){let n=e.shadowRoot??e.attachShadow({mode:`open`}),r=n.querySelector(`link[${ay}]`),i=cy(`app.css`,e);r?r.getAttribute(`href`)!==i&&(r.href=i):(r=document.createElement(`link`),r.rel=`stylesheet`,r.href=i,r.setAttribute(ay,``),n.appendChild(r));let a=n.querySelector(`[${iy}]`);return a?a.className!==t&&(a.className=t):(a=document.createElement(`div`),a.className=t,a.setAttribute(iy,``),n.appendChild(a)),a}function uy(e,t,n){sy(n,e),t.className=`smartsafehub-shadow-root`,fe(B($v,{onAdministratorPasswordChanged:()=>{dy(e,t,`관리자 비밀번호가 변경되었습니다. 새 비밀번호로 다시 로그인해 주세요.`)},onPasswordConfigured:n=>{dy(e,t,n?`관리자 비밀번호 복구가 완료되었습니다. 새 비밀번호로 다시 로그인해 주세요.`:`관리자 비밀번호가 설정되었습니다. 새 비밀번호로 다시 로그인해 주세요.`)}}),t)}function dy(e,t,n){delete window.__SMARTHUB_BOOTSTRAP__,t.className=`smartsafehub-login-shadow-root`,fe(B(ny,{notice:n,onAuthenticated:n=>{uy(e,t,n)}}),t)}async function fy(){pn(dn());let e=document.getElementById(ry);if(!e)return;oy(),e.style.display=`block`,e.style.width=`100%`,e.style.minWidth=`0`,e.style.minHeight=`100dvh`,e.style.maxWidth=`100%`,e.style.isolation=`isolate`;let t=ly(e,`smartsafehub-login-shadow-root`);window.addEventListener(Ne,()=>{dy(e,t,Pe)}),fe(B(ny,{onAuthenticated:n=>{uy(e,t,n)},probing:!0}),t);try{let n=await ge();if(n){uy(e,t,n);return}}catch{}try{let n=await Ae();if(n){uy(e,t,n);return}}catch{}dy(e,t)}fy(); \ No newline at end of file +`):e}function Cm(e,t){let{element:n,datasetIndex:r,index:i}=t,a=e.getDatasetMeta(r).controller,{label:o,value:s}=a.getLabelAndValue(i);return{chart:e,label:o,parsed:a.getParsed(i),raw:e.data.datasets[r].data[i],formattedValue:s,dataset:a.getDataset(),dataIndex:i,datasetIndex:r,element:n}}function wm(e,t){let n=e.chart.ctx,{body:r,footer:i,title:a}=e,{boxWidth:o,boxHeight:s}=t,c=gl(t.bodyFont),l=gl(t.titleFont),u=gl(t.footerFont),d=a.length,f=i.length,p=r.length,m=hl(t.padding),h=m.height,g=0,_=r.reduce((e,t)=>e+t.before.length+t.lines.length+t.after.length,0);if(_+=e.beforeBody.length+e.afterBody.length,d&&(h+=d*l.lineHeight+(d-1)*t.titleSpacing+t.titleMarginBottom),_){let e=t.displayColors?Math.max(s,c.lineHeight):c.lineHeight;h+=p*e+(_-p)*c.lineHeight+(_-1)*t.bodySpacing}f&&(h+=t.footerMarginTop+f*u.lineHeight+(f-1)*t.footerSpacing);let v=0,y=function(e){g=Math.max(g,n.measureText(e).width+v)};return n.save(),n.font=l.string,Z(e.title,y),n.font=c.string,Z(e.beforeBody.concat(e.afterBody),y),v=t.displayColors?o+2+t.boxPadding:0,Z(r,e=>{Z(e.before,y),Z(e.lines,y),Z(e.after,y)}),v=0,n.font=u.string,Z(e.footer,y),n.restore(),g+=m.width,{width:g,height:h}}function Tm(e,t){let{y:n,height:r}=t;return ne.height-r/2?`bottom`:`center`}function Em(e,t,n,r){let{x:i,width:a}=r,o=n.caretSize+n.caretPadding;if(e===`left`&&i+a+o>t.width||e===`right`&&i-a-o<0)return!0}function Dm(e,t,n,r){let{x:i,width:a}=n,{width:o,chartArea:{left:s,right:c}}=e,l=`center`;return r===`center`?l=i<=(s+c)/2?`left`:`right`:i<=a/2?l=`left`:i>=o-a/2&&(l=`right`),Em(l,e,t,n)&&(l=`center`),l}function Om(e,t,n){let r=n.yAlign||t.yAlign||Tm(e,n);return{xAlign:n.xAlign||t.xAlign||Dm(e,t,n,r),yAlign:r}}function km(e,t){let{x:n,width:r}=e;return t===`right`?n-=r:t===`center`&&(n-=r/2),n}function Am(e,t,n){let{y:r,height:i}=e;return t===`top`?r+=n:r-=t===`bottom`?i+n:i/2,r}function jm(e,t,n,r){let{caretSize:i,caretPadding:a,cornerRadius:o}=e,{xAlign:s,yAlign:c}=n,l=i+a,{topLeft:u,topRight:d,bottomLeft:f,bottomRight:p}=ml(o),m=km(t,s),h=Am(t,c,l);return c===`center`?s===`left`?m+=l:s===`right`&&(m-=l):s===`left`?m-=Math.max(u,f)+i:s===`right`&&(m+=Math.max(d,p)+i),{x:ic(m,0,r.width-t.width),y:ic(h,0,r.height-t.height)}}function Mm(e,t,n){let r=hl(n.padding);return t===`center`?e.x+e.width/2:t===`right`?e.x+e.width-r.right:e.x+r.left}function Nm(e){return xm([],Sm(e))}function Pm(e,t,n){return yl(e,{tooltip:t,tooltipItems:n,type:`tooltip`})}function Fm(e,t){let n=t&&t.dataset&&t.dataset.tooltip&&t.dataset.tooltip.callbacks;return n?e.override(n):e}var Im={beforeTitle:ds,title(e){if(e.length>0){let t=e[0],n=t.chart.data.labels,r=n?n.length:0;if(this&&this.options&&this.options.mode===`dataset`)return t.dataset.label||``;if(t.label)return t.label;if(r>0&&t.dataIndex{let t={before:[],lines:[],after:[]},i=Fm(n,e);xm(t.before,Sm(Lm(i,`beforeLabel`,this,e))),xm(t.lines,Lm(i,`label`,this,e)),xm(t.after,Sm(Lm(i,`afterLabel`,this,e))),r.push(t)}),r}getAfterBody(e,t){return Nm(Lm(t.callbacks,`afterBody`,this,e))}getFooter(e,t){let{callbacks:n}=t,r=Lm(n,`beforeFooter`,this,e),i=Lm(n,`footer`,this,e),a=Lm(n,`afterFooter`,this,e),o=[];return o=xm(o,Sm(r)),o=xm(o,Sm(i)),o=xm(o,Sm(a)),o}_createItems(e){let t=this._active,n=this.chart.data,r=[],i=[],a=[],o=[],s,c;for(s=0,c=t.length;se.filter(t,r,i,n))),e.itemSort&&(o=o.sort((t,r)=>e.itemSort(t,r,n))),Z(o,t=>{let n=Fm(e.callbacks,t);r.push(Lm(n,`labelColor`,this,t)),i.push(Lm(n,`labelPointStyle`,this,t)),a.push(Lm(n,`labelTextColor`,this,t))}),this.labelColors=r,this.labelPointStyles=i,this.labelTextColors=a,this.dataPoints=o,o}update(e,t){let n=this.options.setContext(this.getContext()),r=this._active,i,a=[];if(!r.length)this.opacity!==0&&(i={opacity:0});else{let e=bm[n.position].call(this,r,this._eventPosition);a=this._createItems(n),this.title=this.getTitle(a,n),this.beforeBody=this.getBeforeBody(a,n),this.body=this.getBody(a,n),this.afterBody=this.getAfterBody(a,n),this.footer=this.getFooter(a,n);let t=this._size=wm(this,n),o=Object.assign({},e,t),s=Om(this.chart,n,o),c=jm(n,o,s,this.chart);this.xAlign=s.xAlign,this.yAlign=s.yAlign,i={opacity:1,x:c.x,y:c.y,width:t.width,height:t.height,caretX:e.x,caretY:e.y}}this._tooltipItems=a,this.$context=void 0,i&&this._resolveAnimations().update(this,i),e&&n.external&&n.external.call(this,{chart:this.chart,tooltip:this,replay:t})}drawCaret(e,t,n,r){let i=this.getCaretPosition(e,n,r);t.lineTo(i.x1,i.y1),t.lineTo(i.x2,i.y2),t.lineTo(i.x3,i.y3)}getCaretPosition(e,t,n){let{xAlign:r,yAlign:i}=this,{caretSize:a,cornerRadius:o}=n,{topLeft:s,topRight:c,bottomLeft:l,bottomRight:u}=ml(o),{x:d,y:f}=e,{width:p,height:m}=t,h,g,_,v,y,b;return i===`center`?(y=f+m/2,r===`left`?(h=d,g=h-a,v=y+a,b=y-a):(h=d+p,g=h+a,v=y-a,b=y+a),_=h):(g=r===`left`?d+Math.max(s,l)+a:r===`right`?d+p-Math.max(c,u)-a:this.caretX,i===`top`?(v=f,y=v-a,h=g-a,_=g+a):(v=f+m,y=v+a,h=g+a,_=g-a),b=v),{x1:h,x2:g,x3:_,y1:v,y2:y,y3:b}}drawTitle(e,t,n){let r=this.title,i=r.length,a,o,s;if(i){let c=_u(n.rtl,this.x,this.width);for(e.x=Mm(this,n.titleAlign,n),t.textAlign=c.textAlign(n.titleAlign),t.textBaseline=`middle`,a=gl(n.titleFont),o=n.titleSpacing,t.fillStyle=n.titleColor,t.font=a.string,s=0;se!==0)?(e.beginPath(),e.fillStyle=i.multiKeyBackground,sl(e,{x:t,y:p,w:c,h:s,radius:o}),e.fill(),e.stroke(),e.fillStyle=a.backgroundColor,e.beginPath(),sl(e,{x:n,y:p+1,w:c-2,h:s-2,radius:o}),e.fill()):(e.fillStyle=i.multiKeyBackground,e.fillRect(t,p,c,s),e.strokeRect(t,p,c,s),e.fillStyle=a.backgroundColor,e.fillRect(n,p+1,c-2,s-2))}e.fillStyle=this.labelTextColors[n]}drawBody(e,t,n){let{body:r}=this,{bodySpacing:i,bodyAlign:a,displayColors:o,boxHeight:s,boxWidth:c,boxPadding:l}=n,u=gl(n.bodyFont),d=u.lineHeight,f=0,p=_u(n.rtl,this.x,this.width),m=function(n){t.fillText(n,p.x(e.x+f),e.y+d/2),e.y+=d+i},h=p.textAlign(a),g,_,v,y,b,x,S;for(t.textAlign=a,t.textBaseline=`middle`,t.font=u.string,e.x=Mm(this,h,n),t.fillStyle=n.bodyColor,Z(this.beforeBody,m),f=o&&h!==`right`?a===`center`?c/2+l:c+2+l:0,y=0,x=r.length;y0&&t.stroke()}_updateAnimationTarget(e){let t=this.chart,n=this.$animations,r=n&&n.x,i=n&&n.y;if(r||i){let n=bm[e.position].call(this,this._active,this._eventPosition);if(!n)return;let a=this._size=wm(this,e),o=Object.assign({},n,this._size),s=Om(t,e,o),c=jm(e,o,s,t);(r._to!==c.x||i._to!==c.y)&&(this.xAlign=s.xAlign,this.yAlign=s.yAlign,this.width=a.width,this.height=a.height,this.caretX=n.x,this.caretY=n.y,this._resolveAnimations().update(this,c))}}_willRender(){return!!this.opacity}draw(e){let t=this.options.setContext(this.getContext()),n=this.opacity;if(!n)return;this._updateAnimationTarget(t);let r={width:this.width,height:this.height},i={x:this.x,y:this.y};n=Math.abs(n)<.001?0:n;let a=hl(t.padding),o=this.title.length||this.beforeBody.length||this.body.length||this.afterBody.length||this.footer.length;t.enabled&&o&&(e.save(),e.globalAlpha=n,this.drawBackground(i,e,r,t),vu(e,t.textDirection),i.y+=a.top,this.drawTitle(i,e,t),this.drawBody(i,e,t),this.drawFooter(i,e,t),yu(e,t.textDirection),e.restore())}getActiveElements(){return this._active||[]}setActiveElements(e,t){let n=this._active,r=e.map(({datasetIndex:e,index:t})=>{let n=this.chart.getDatasetMeta(e);if(!n)throw Error(`Cannot find a dataset at index `+e);return{datasetIndex:e,element:n.data[t],index:t}}),i=!ys(n,r),a=this._positionChanged(r,t);(i||a)&&(this._active=r,this._eventPosition=t,this._ignoreReplayEvents=!0,this.update(!0))}handleEvent(e,t,n=!0){if(t&&this._ignoreReplayEvents)return!1;this._ignoreReplayEvents=!1;let r=this.options,i=this._active||[],a=this._getActiveElements(e,i,t,n),o=this._positionChanged(a,e),s=t||!ys(a,i)||o;return s&&(this._active=a,(r.enabled||r.external)&&(this._eventPosition={x:e.x,y:e.y},this.update(!0,t))),s}_getActiveElements(e,t,n,r){let i=this.options;if(e.type===`mouseout`)return[];if(!r)return t.filter(e=>this.chart.data.datasets[e.datasetIndex]&&this.chart.getDatasetMeta(e.datasetIndex).controller.getParsed(e.index)!==void 0);let a=this.chart.getElementsAtEventForMode(e,i.mode,i,n);return i.reverse&&a.reverse(),a}_positionChanged(e,t){let{caretX:n,caretY:r,options:i}=this,a=bm[i.position].call(this,e,t);return a!==!1&&(n!==a.x||r!==a.y)}};L(Rm,`positioners`,bm);var zm={id:`tooltip`,_element:Rm,positioners:bm,afterInit(e,t,n){n&&(e.tooltip=new Rm({chart:e,options:n}))},beforeUpdate(e,t,n){e.tooltip&&e.tooltip.initialize(n)},reset(e,t,n){e.tooltip&&e.tooltip.initialize(n)},afterDraw(e){let t=e.tooltip;if(t&&t._willRender()){let n={tooltip:t};if(e.notifyPlugins(`beforeTooltipDraw`,{...n,cancelable:!0})===!1)return;t.draw(e.ctx),e.notifyPlugins(`afterTooltipDraw`,n)}},afterEvent(e,t){if(e.tooltip){let n=t.replay;e.tooltip.handleEvent(t.event,n,t.inChartArea)&&(t.changed=!0)}},defaults:{enabled:!0,external:null,position:`average`,backgroundColor:`rgba(0,0,0,0.8)`,titleColor:`#fff`,titleFont:{weight:`bold`},titleSpacing:2,titleMarginBottom:6,titleAlign:`left`,bodyColor:`#fff`,bodySpacing:2,bodyFont:{},bodyAlign:`left`,footerColor:`#fff`,footerSpacing:2,footerMarginTop:6,footerFont:{weight:`bold`},footerAlign:`left`,padding:6,caretPadding:2,caretSize:5,cornerRadius:6,boxHeight:(e,t)=>t.bodyFont.size,boxWidth:(e,t)=>t.bodyFont.size,multiKeyBackground:`#fff`,displayColors:!0,boxPadding:0,borderColor:`rgba(0,0,0,0)`,borderWidth:0,animation:{duration:400,easing:`easeOutQuart`},animations:{numbers:{type:`number`,properties:[`x`,`y`,`width`,`height`,`caretX`,`caretY`]},opacity:{easing:`linear`,duration:200}},callbacks:Im},defaultRoutes:{bodyFont:`font`,footerFont:`font`,titleFont:`font`},descriptors:{_scriptable:e=>e!==`filter`&&e!==`itemSort`&&e!==`external`,_indexable:!1,callbacks:{_scriptable:!1,_indexable:!1},animation:{_fallback:!1},animations:{_fallback:`animation`}},additionalOptionScopes:[`interaction`]},Bm=(e,t,n,r)=>(typeof t==`string`?(n=e.push(t)-1,r.unshift({index:n,label:t})):isNaN(t)&&(n=null),n);function Vm(e,t,n,r){let i=e.indexOf(t);return i===-1?Bm(e,t,n,r):i===e.lastIndexOf(t)?i:n}var Hm=(e,t)=>e===null?null:ic(Math.round(e),0,t);function Um(e){let t=this.getLabels();return e>=0&&et.length-1?null:this.getPixelForValue(t[e].value)}getValueForPixel(e){return Math.round(this._startValue+this.getDecimalForPixel(e)*this._valueRange)}getBasePixel(){return this.bottom}};L(Wm,`id`,`category`),L(Wm,`defaults`,{ticks:{callback:Um}});function Gm(e,t){let n=[],{bounds:r,step:i,min:a,max:o,precision:s,count:c,maxTicks:l,maxDigits:u,includeBounds:d}=e,f=i||1,p=l-1,{min:m,max:h}=t,g=!J(a),_=!J(o),v=!J(c),y=(h-m)/(u+1),b=Ws((h-m)/p/f)*f,x,S,C,w;if(b<1e-14&&!g&&!_)return[{value:m},{value:h}];w=Math.ceil(h/b)-Math.floor(m/b),w>p&&(b=Ws(w*b/p/f)*f),J(s)||(x=10**s,b=Math.ceil(b*x)/x),r===`ticks`?(S=Math.floor(m/b)*b,C=Math.ceil(h/b)*b):(S=m,C=h),g&&_&&i&&Js((o-a)/i,b/1e3)?(w=Math.round(Math.min((o-a)/b,l)),b=(o-a)/w,S=a,C=o):v?(S=g?a:S,C=_?o:C,w=c-1,b=(C-S)/w):(w=(C-S)/b,w=Us(w,Math.round(w),b/1e3)?Math.round(w):Math.ceil(w));let T=Math.max(Qs(b),Qs(S));x=10**(J(s)?T:s),S=Math.round(S*x)/x,C=Math.round(C*x)/x;let E=0;for(g&&(d&&S!==a?(n.push({value:a}),So)break;n.push({value:e})}return _&&d&&C!==o?n.length&&Us(n[n.length-1].value,o,Km(o,y,e))?n[n.length-1].value=o:n.push({value:o}):(!_||C===o)&&n.push({value:C}),n}function Km(e,t,{horizontal:n,minRotation:r}){let i=Xs(r),a=(n?Math.sin(i):Math.cos(i))||.001,o=.75*t*(``+e).length;return Math.min(t/a,o)}var qm=class extends Xf{constructor(e){super(e),this.start=void 0,this.end=void 0,this._startValue=void 0,this._endValue=void 0,this._valueRange=0}parse(e,t){return J(e)||(typeof e==`number`||e instanceof Number)&&!isFinite(+e)?null:+e}handleTickRangeOptions(){let{beginAtZero:e}=this.options,{minDefined:t,maxDefined:n}=this.getUserBounds(),{min:r,max:i}=this,a=e=>r=t?r:e,o=e=>i=n?i:e;if(e){let e=Hs(r),t=Hs(i);e<0&&t<0?o(0):e>0&&t>0&&a(0)}if(r===i){let t=i===0?1:Math.abs(i*.05);o(i+t),e||a(r-t)}this.min=r,this.max=i}getTickLimit(){let{maxTicksLimit:e,stepSize:t}=this.options.ticks,n;return t?(n=Math.ceil(this.max/t)-Math.floor(this.min/t)+1,n>1e3&&(console.warn(`scales.${this.id}.ticks.stepSize: ${t} would result generating up to ${n} ticks. Limiting to 1000.`),n=1e3)):(n=this.computeTickLimit(),e=e||11),e&&(n=Math.min(e,n)),n}computeTickLimit(){return 1/0}buildTicks(){let e=this.options,t=e.ticks,n=this.getTickLimit();n=Math.max(2,n);let r=Gm({maxTicks:n,bounds:e.bounds,min:e.min,max:e.max,precision:t.precision,step:t.stepSize,count:t.count,maxDigits:this._maxDigits(),horizontal:this.isHorizontal(),minRotation:t.minRotation||0,includeBounds:t.includeBounds!==!1},this._range||this);return e.bounds===`ticks`&&Ys(r,this,`value`),e.reverse?(r.reverse(),this.start=this.max,this.end=this.min):(this.start=this.min,this.end=this.max),r}configure(){let e=this.ticks,t=this.min,n=this.max;if(super.configure(),this.options.offset&&e.length){let r=(n-t)/Math.max(e.length-1,1)/2;t-=r,n+=r}this._startValue=t,this._endValue=n,this._valueRange=n-t}getLabelForValue(e){return Fc(e,this.chart.options.locale,this.options.ticks.format)}},Jm=class extends qm{determineDataLimits(){let{min:e,max:t}=this.getMinMax(!0);this.min=ms(e)?e:0,this.max=ms(t)?t:1,this.handleTickRangeOptions()}computeTickLimit(){let e=this.isHorizontal(),t=e?this.width:this.height,n=Xs(this.options.ticks.minRotation),r=(e?Math.sin(n):Math.cos(n))||.001,i=this._resolveTickFontOptions(0);return Math.ceil(t/Math.min(40,i.lineHeight/r))}getPixelForValue(e){return e===null?NaN:this.getPixelForDecimal((e-this._startValue)/this._valueRange)}getValueForPixel(e){return this._startValue+this.getDecimalForPixel(e)*this._valueRange}};L(Jm,`id`,`linear`),L(Jm,`defaults`,{ticks:{callback:Rc.formatters.numeric}});var Ym=e=>Math.floor(Vs(e)),Xm=(e,t)=>10**(Ym(e)+t);function Zm(e){return e/10**Ym(e)==1}function Qm(e,t,n){let r=10**n,i=Math.floor(e/r);return Math.ceil(t/r)-i}function $m(e,t){let n=Ym(t-e);for(;Qm(e,t,n)>10;)n++;for(;Qm(e,t,n)<10;)n--;return Math.min(n,Ym(e))}function eh(e,{min:t,max:n}){t=hs(e.min,t);let r=[],i=Ym(t),a=$m(t,n),o=a<0?10**Math.abs(a):1,s=10**a,c=i>a?10**i:0,l=Math.round((t-c)*o)/o,u=Math.floor((t-c)/s/10)*s*10,d=Math.floor((l-u)/10**a),f=hs(e.min,Math.round((c+u+d*10**a)*o)/o);for(;f=10?d=d<15?15:20:d++,d>=20&&(a++,d=2,o=a>=0?1:o),f=Math.round((c+u+d*10**a)*o)/o;let p=hs(e.max,f);return r.push({value:p,major:Zm(p),significand:d}),r}var th=class extends Xf{constructor(e){super(e),this.start=void 0,this.end=void 0,this._startValue=void 0,this._valueRange=0}parse(e,t){let n=qm.prototype.parse.apply(this,[e,t]);if(n===0){this._zero=!0;return}return ms(n)&&n>0?n:null}determineDataLimits(){let{min:e,max:t}=this.getMinMax(!0);this.min=ms(e)?Math.max(0,e):null,this.max=ms(t)?Math.max(0,t):null,this.options.beginAtZero&&(this._zero=!0),this._zero&&this.min!==this._suggestedMin&&!ms(this._userMin)&&(this.min=e===Xm(this.min,0)?Xm(this.min,-1):Xm(this.min,0)),this.handleTickRangeOptions()}handleTickRangeOptions(){let{minDefined:e,maxDefined:t}=this.getUserBounds(),n=this.min,r=this.max,i=t=>n=e?n:t,a=e=>r=t?r:e;n===r&&(n<=0?(i(1),a(10)):(i(Xm(n,-1)),a(Xm(r,1)))),n<=0&&i(Xm(r,-1)),r<=0&&a(Xm(n,1)),this.min=n,this.max=r}buildTicks(){let e=this.options,t=eh({min:this._userMin,max:this._userMax},this);return e.bounds===`ticks`&&Ys(t,this,`value`),e.reverse?(t.reverse(),this.start=this.max,this.end=this.min):(this.start=this.min,this.end=this.max),t}getLabelForValue(e){return e===void 0?`0`:Fc(e,this.chart.options.locale,this.options.ticks.format)}configure(){let e=this.min;super.configure(),this._startValue=Vs(e),this._valueRange=Vs(this.max)-Vs(e)}getPixelForValue(e){return(e===void 0||e===0)&&(e=this.min),e===null||isNaN(e)?NaN:this.getPixelForDecimal(e===this.min?0:(Vs(e)-this._startValue)/this._valueRange)}getValueForPixel(e){let t=this.getDecimalForPixel(e);return 10**(this._startValue+t*this._valueRange)}};L(th,`id`,`logarithmic`),L(th,`defaults`,{ticks:{callback:Rc.formatters.logarithmic,major:{enabled:!0}}});function nh(e){let t=e.ticks;if(t.display&&e.display){let e=hl(t.backdropPadding);return X(t.font&&t.font.size,Wc.font.size)+e.height}return 0}function rh(e,t,n){return n=ps(n)?n:[n],{w:qc(e,t.string,n),h:n.length*t.lineHeight}}function ih(e,t,n,r,i){return e===r||e===i?{start:t-n/2,end:t+n/2}:ei?{start:t-n,end:t}:{start:t,end:t+n}}function ah(e){let t={l:e.left+e._padding.left,r:e.right-e._padding.right,t:e.top+e._padding.top,b:e.bottom-e._padding.bottom},n=Object.assign({},t),r=[],i=[],a=e._pointLabels.length,o=e.options.pointLabels,s=o.centerPointLabels?Q/a:0;for(let c=0;ct.r&&(s=(r.end-t.r)/a,e.r=Math.max(e.r,t.r+s)),i.startt.b&&(c=(i.end-t.b)/o,e.b=Math.max(e.b,t.b+c))}function sh(e,t,n){let r=e.drawingArea,{extra:i,additionalAngle:a,padding:o,size:s}=n,c=e.getPointPosition(t,r+i+o,a),l=Math.round(Zs(nc(c.angle+Rs))),u=fh(c.y,s.h,l),d=uh(l),f=dh(c.x,s.w,d);return{visible:!0,x:c.x,y:u,textAlign:d,left:f,top:u,right:f+s.w,bottom:u+s.h}}function ch(e,t){if(!t)return!0;let{left:n,top:r,right:i,bottom:a}=e;return!(Qc({x:n,y:r},t)||Qc({x:n,y:a},t)||Qc({x:i,y:r},t)||Qc({x:i,y:a},t))}function lh(e,t,n){let r=[],i=e._pointLabels.length,a=e.options,{centerPointLabels:o,display:s}=a.pointLabels,c={extra:nh(a)/2,additionalAngle:o?Q/i:0},l;for(let a=0;a270||n<90)&&(e-=t),e}function ph(e,t,n){let{left:r,top:i,right:a,bottom:o}=n,{backdropColor:s}=t;if(!J(s)){let n=ml(t.borderRadius),c=hl(t.backdropPadding);e.fillStyle=s;let l=r-c.left,u=i-c.top,d=a-r+c.width,f=o-i+c.height;Object.values(n).some(e=>e!==0)?(e.beginPath(),sl(e,{x:l,y:u,w:d,h:f,radius:n}),e.fill()):e.fillRect(l,u,d,f)}}function mh(e,t){let{ctx:n,options:{pointLabels:r}}=e;for(let i=t-1;i>=0;i--){let t=e._pointLabelItems[i];if(!t.visible)continue;let a=r.setContext(e.getPointLabelContext(i));ph(n,a,t);let o=gl(a.font),{x:s,y:c,textAlign:l}=t;ol(n,e._pointLabels[i],s,c+o.lineHeight/2,o,{color:a.color,textAlign:l,textBaseline:`middle`})}}function hh(e,t,n,r){let{ctx:i}=e;if(n)i.arc(e.xCenter,e.yCenter,t,0,$);else{let n=e.getPointPosition(0,t);i.moveTo(n.x,n.y);for(let a=1;a{let n=vs(this.options.pointLabels.callback,[e,t],this);return n||n===0?n:``}).filter((e,t)=>this.chart.getDataVisibility(t))}fit(){let e=this.options;e.display&&e.pointLabels.display?ah(this):this.setCenterPoint(0,0,0,0)}setCenterPoint(e,t,n,r){this.xCenter+=Math.floor((e-t)/2),this.yCenter+=Math.floor((n-r)/2),this.drawingArea-=Math.min(this.drawingArea/2,Math.max(e,t,n,r))}getIndexAngle(e){let t=$/(this._pointLabels.length||1),n=this.options.startAngle||0;return nc(e*t+Xs(n))}getDistanceFromCenterForValue(e){if(J(e))return NaN;let t=this.drawingArea/(this.max-this.min);return this.options.reverse?(this.max-e)*t:(e-this.min)*t}getValueForDistanceFromCenter(e){if(J(e))return NaN;let t=e/(this.drawingArea/(this.max-this.min));return this.options.reverse?this.max-t:this.min+t}getPointLabelContext(e){let t=this._pointLabels||[];if(e>=0&&e{if(t!==0||t===0&&this.min<0){s=this.getDistanceFromCenterForValue(e.value);let n=this.getContext(t),o=r.setContext(n),c=i.setContext(n);gh(this,o,s,a,c)}}),n.display){for(e.save(),o=a-1;o>=0;o--){let r=n.setContext(this.getPointLabelContext(o)),{color:i,lineWidth:a}=r;!a||!i||(e.lineWidth=a,e.strokeStyle=i,e.setLineDash(r.borderDash),e.lineDashOffset=r.borderDashOffset,s=this.getDistanceFromCenterForValue(t.reverse?this.min:this.max),c=this.getPointPosition(o,s),e.beginPath(),e.moveTo(this.xCenter,this.yCenter),e.lineTo(c.x,c.y),e.stroke())}e.restore()}}drawBorder(){}drawLabels(){let e=this.ctx,t=this.options,n=t.ticks;if(!n.display)return;let r=this.getIndexAngle(0),i,a;e.save(),e.translate(this.xCenter,this.yCenter),e.rotate(r),e.textAlign=`center`,e.textBaseline=`middle`,this.ticks.forEach((r,o)=>{if(o===0&&this.min>=0&&!t.reverse)return;let s=n.setContext(this.getContext(o)),c=gl(s.font);if(i=this.getDistanceFromCenterForValue(this.ticks[o].value),s.showLabelBackdrop){e.font=c.string,a=e.measureText(r.label).width,e.fillStyle=s.backdropColor;let t=hl(s.backdropPadding);e.fillRect(-a/2-t.left,-i-c.size/2-t.top,a+t.width,c.size+t.height)}ol(e,r.label,0,-i,c,{color:s.color,strokeColor:s.textStrokeColor,strokeWidth:s.textStrokeWidth})}),e.restore()}drawTitle(){}};L(vh,`id`,`radialLinear`),L(vh,`defaults`,{display:!0,animate:!0,position:`chartArea`,angleLines:{display:!0,lineWidth:1,borderDash:[],borderDashOffset:0},grid:{circular:!1},startAngle:0,ticks:{showLabelBackdrop:!0,callback:Rc.formatters.numeric},pointLabels:{backdropColor:void 0,backdropPadding:2,display:!0,font:{size:10},callback(e){return e},padding:5,centerPointLabels:!1}}),L(vh,`defaultRoutes`,{"angleLines.color":`borderColor`,"pointLabels.color":`color`,"ticks.color":`color`}),L(vh,`descriptors`,{angleLines:{_fallback:`grid`}});var yh={millisecond:{common:!0,size:1,steps:1e3},second:{common:!0,size:1e3,steps:60},minute:{common:!0,size:6e4,steps:60},hour:{common:!0,size:36e5,steps:24},day:{common:!0,size:864e5,steps:30},week:{common:!1,size:6048e5,steps:4},month:{common:!0,size:2628e6,steps:12},quarter:{common:!1,size:7884e6,steps:4},year:{common:!0,size:3154e7}},bh=Object.keys(yh);function xh(e,t){return e-t}function Sh(e,t){if(J(t))return null;let n=e._adapter,{parser:r,round:i,isoWeekday:a}=e._parseOpts,o=t;return typeof r==`function`&&(o=r(o)),ms(o)||(o=typeof r==`string`?n.parse(o,r):n.parse(o)),o===null?null:(i&&(o=i===`week`&&(qs(a)||a===!0)?n.startOf(o,`isoWeek`,a):n.startOf(o,i)),+o)}function Ch(e,t,n,r){let i=bh.length;for(let a=bh.indexOf(e);a=bh.indexOf(n);a--){let n=bh[a];if(yh[n].common&&e._adapter.diff(i,r,n)>=t-1)return n}return bh[n?bh.indexOf(n):0]}function Th(e){for(let t=bh.indexOf(e)+1,n=bh.length;t=t?n[r]:n[i];e[a]=!0}}function Dh(e,t,n,r){let i=e._adapter,a=+i.startOf(t[0].value,r),o=t[t.length-1].value,s,c;for(s=a;s<=o;s=+i.add(s,1,r))c=n[s],c>=0&&(t[c].major=!0);return t}function Oh(e,t,n){let r=[],i={},a=t.length,o,s;for(o=0;o+e.value))}initOffsets(e=[]){let t=0,n=0,r,i;this.options.offset&&e.length&&(r=this.getDecimalForValue(e[0]),t=e.length===1?1-r:(this.getDecimalForValue(e[1])-r)/2,i=this.getDecimalForValue(e[e.length-1]),n=e.length===1?i:(i-this.getDecimalForValue(e[e.length-2]))/2);let a=e.length<3?.5:.25;t=ic(t,0,a),n=ic(n,0,a),this._offsets={start:t,end:n,factor:1/(t+1+n)}}_generate(){let e=this._adapter,t=this.min,n=this.max,r=this.options,i=r.time,a=i.unit||Ch(i.minUnit,t,n,this._getLabelCapacity(t)),o=X(r.ticks.stepSize,1),s=a===`week`&&i.isoWeekday,c=qs(s)||s===!0,l={},u=t,d,f;if(c&&(u=+e.startOf(u,`isoWeek`,s)),u=+e.startOf(u,c?`day`:a),e.diff(n,t,a)>1e5*o)throw Error(t+` and `+n+` are too far apart with stepSize of `+o+` `+a);let p=r.ticks.source===`data`&&this.getDataTimestamps();for(d=u,f=0;d+e)}getLabelForValue(e){let t=this._adapter,n=this.options.time;return n.tooltipFormat?t.format(e,n.tooltipFormat):t.format(e,n.displayFormats.datetime)}format(e,t){let n=this.options.time.displayFormats,r=this._unit,i=t||n[r];return this._adapter.format(e,i)}_tickFormatFunction(e,t,n,r){let i=this.options,a=i.ticks.callback;if(a)return vs(a,[e,t,n],this);let o=i.time.displayFormats,s=this._unit,c=this._majorUnit,l=s&&o[s],u=c&&o[c],d=n[t],f=c&&u&&d&&d.major;return this._adapter.format(e,r||(f?u:l))}generateTickLabels(e){let t,n,r;for(t=0,n=e.length;t0?o:1}getDataTimestamps(){let e=this._cache.data||[],t,n;if(e.length)return e;let r=this.getMatchingVisibleMetas();if(this._normalized&&r.length)return this._cache.data=r[0].controller.getAllParsedValues(this);for(t=0,n=r.length;t=e[r].pos&&t<=e[i].pos&&({lo:r,hi:i}=cc(e,`pos`,t)),{pos:a,time:s}=e[r],{pos:o,time:c}=e[i]):(t>=e[r].time&&t<=e[i].time&&({lo:r,hi:i}=cc(e,`time`,t)),{time:a,pos:s}=e[r],{time:o,pos:c}=e[i]);let l=o-a;return l?s+(c-s)*(t-a)/l:s}var jh=class extends kh{constructor(e){super(e),this._table=[],this._minPos=void 0,this._tableRange=void 0}initOffsets(){let e=this._getTimestampsForTable(),t=this._table=this.buildLookupTable(e);this._minPos=Ah(t,this.min),this._tableRange=Ah(t,this.max)-this._minPos,super.initOffsets(e)}buildLookupTable(e){let{min:t,max:n}=this,r=[],i=[],a,o,s,c,l;for(a=0,o=e.length;a=t&&c<=n&&r.push(c);if(r.length<2)return[{time:t,pos:0},{time:n,pos:1}];for(a=0,o=r.length;ae-t)}_getTimestampsForTable(){let e=this._cache.all||[];if(e.length)return e;let t=this.getDataTimestamps(),n=this.getLabelTimestamps();return e=t.length&&n.length?this.normalize(t.concat(n)):t.length?t:n,e=this._cache.all=e,e}getDecimalForValue(e){return(Ah(this._table,e)-this._minPos)/this._tableRange}getValueForPixel(e){let t=this._offsets,n=this.getDecimalForPixel(e)/t.factor-t.end;return Ah(this._table,n*this._tableRange+this._minPos,!0)}};L(jh,`id`,`timeseries`),L(jh,`defaults`,kh.defaults),Rp.register(Cd,ym,Wm,Jm,zm);var Mh=new Intl.DateTimeFormat(`ko-KR`,{hour:`2-digit`,hour12:!1}),Nh=`#94a3b8`,Ph=`rgba(148, 163, 184, 0.18)`,Fh=`#0d9488`,Ih=`#0f766e`;function Lh(e){return Mh.format(new Date(e*1e3))}function Rh(e){return e.map((t,n)=>n%3==0||n===e.length-1?Lh(t.bucketStart):``)}function zh({buckets:e}){let t=F(null),n=F(null),r=F(e);return r.current=e,P(()=>{let e=t.current;if(!e)return;let i=window.matchMedia(`(prefers-reduced-motion: reduce)`).matches,a=window.getComputedStyle(e).fontFamily,o={animation:!i&&{duration:500,easing:`easeOutQuart`},maintainAspectRatio:!1,responsive:!0,interaction:{intersect:!1,mode:`index`},plugins:{legend:{display:!1},tooltip:{displayColors:!1,callbacks:{title:e=>{let t=e[0]?.dataIndex??-1,n=r.current[t];return n?Lh(n.bucketStart):``},label:e=>`차단 ${q(Number(e.raw??0))}`,afterLabel:e=>{let t=r.current[e.dataIndex];return t?`DNS 요청 ${q(t.queries)}`:``}}}},scales:{x:{border:{display:!1},grid:{display:!1},ticks:{autoSkip:!1,color:Nh,font:{family:a,size:11,weight:700},maxRotation:0,minRotation:0}},y:{beginAtZero:!0,border:{display:!1},grid:{color:Ph},ticks:{color:Nh,font:{family:a,size:11,weight:700},maxTicksLimit:4,precision:0}}}};return n.current=new Rp(e,{type:`bar`,data:{labels:Rh(r.current),datasets:[{data:r.current.map(e=>e.blocked),backgroundColor:Fh,hoverBackgroundColor:Ih,borderRadius:4,borderSkipped:!1,barPercentage:.82,categoryPercentage:.9,maxBarThickness:24}]},options:o}),()=>{n.current?.destroy(),n.current=null}},[]),P(()=>{let t=n.current;t&&(t.data.labels=Rh(e),t.data.datasets[0].data=e.map(e=>e.blocked),t.update())},[e]),B(`div`,{class:`mt-5 h-44 sm:h-52`,children:B(`canvas`,{"aria-label":`최근 24시간 시간대별 SafeShield 차단 요청`,ref:t,role:`img`,children:`최근 24시간 시간대별 SafeShield 차단 요청 차트`})})}var Bh=3600,Vh=24;function Hh(e,t){return e<=0?`0.0%`:`${(t/e*100).toFixed(1)}%`}function Uh(e){let t=e.hourly[e.hourly.length-1];if(t?.bucketStart)return t.bucketStart;let n=e.updatedAt>0?e.updatedAt:Math.floor(Date.now()/1e3);return Math.floor(n/Bh)*Bh}function Wh(e){let t=new Map(e.hourly.map(e=>[e.bucketStart,e])),n=Uh(e)-23*Bh;return Array.from({length:Vh},(e,r)=>{let i=n+r*Bh;return t.get(i)??{bucketStart:i,queries:0,blocked:0}})}function Gh({children:e}){return B(`div`,{class:`mt-5 flex min-h-52 items-center justify-center rounded-xl border border-slate-200 bg-slate-50 px-5 text-center`,children:B(`p`,{class:`m-0 max-w-lg text-sm font-semibold leading-6 text-slate-500`,children:e})})}function Kh({data:e,error:t,loading:n,nowTimestamp:r,refreshing:i}){let a;if(n&&!e)a=B(Gh,{children:`SafeShield 보호 활동을 불러오는 중입니다.`});else if(t&&!e)a=B(Gh,{children:`SafeShield 보호 활동을 불러오지 못했습니다. SafeShield 페이지에서 상태를 확인해 주세요.`});else if(!e||!e.available)a=B(Gh,{children:`현재 SafeShield에서 차단 통계를 제공하지 않습니다. 통계 기능을 확인해 주세요.`});else if(!e.enabled)a=B(Gh,{children:`통계 수집이 꺼져 있습니다. SafeShield 페이지에서 통계를 켜면 최근 24시간 활동이 표시됩니다.`});else{let t=Wh(e),n=t.reduce((e,t)=>({queries:e.queries+t.queries,blocked:e.blocked+t.blocked}),{queries:0,blocked:0});a=B(S,{children:[B(`dl`,{class:`mt-5 grid gap-3 sm:grid-cols-3`,children:[B(`div`,{class:`rounded-xl bg-slate-50 px-4 py-3`,children:[B(`dt`,{class:`text-[0.68rem] font-black uppercase tracking-[0.12em] text-slate-400`,children:`DNS 요청`}),B(`dd`,{class:`mt-1 mb-0 ml-0 text-lg font-black text-slate-950`,children:q(n.queries)})]}),B(`div`,{class:`rounded-xl bg-slate-50 px-4 py-3`,children:[B(`dt`,{class:`text-[0.68rem] font-black uppercase tracking-[0.12em] text-slate-400`,children:`차단`}),B(`dd`,{class:`mt-1 mb-0 ml-0 text-lg font-black text-teal-700`,children:q(n.blocked)})]}),B(`div`,{class:`rounded-xl bg-slate-50 px-4 py-3`,children:[B(`dt`,{class:`text-[0.68rem] font-black uppercase tracking-[0.12em] text-slate-400`,children:`차단율`}),B(`dd`,{class:`mt-1 mb-0 ml-0 text-lg font-black text-slate-950`,children:Hh(n.queries,n.blocked)})]})]}),B(zh,{buckets:t})]})}return B(`article`,{class:`min-w-0 rounded-2xl border border-slate-200 bg-white p-5 shadow-sm shadow-slate-900/5 sm:p-6`,children:[B(`div`,{class:`min-w-0`,children:[B(`p`,{class:`m-0 text-xs font-extrabold uppercase tracking-[0.16em] text-slate-500`,children:`SafeShield activity`}),B(`div`,{class:`mt-2 flex min-w-0 items-center justify-between gap-3`,children:[B(`h3`,{class:`m-0 min-w-0 text-xl font-black text-slate-950`,children:`최근 24시간 보호 활동`}),B(`a`,{class:`shrink-0 whitespace-nowrap text-xs font-extrabold text-teal-700 no-underline hover:text-teal-800`,href:`#safeshield`,children:`상세 통계 →`})]}),e?.updatedAt?B(`p`,{class:`mt-2 mb-0 text-[0.68rem] font-semibold text-slate-400`,title:Fa(e.updatedAt),children:i?`갱신 중…`:`집계: ${Ia(e.updatedAt,r)}`}):null]}),a,t&&e?B(`p`,{class:`mt-3 mb-0 text-xs font-bold text-amber-700`,children:`최근 통계 갱신에 실패해 마지막 정상 데이터를 표시하고 있습니다.`}):null]})}var qh=7200;function Jh(e,t=Math.floor(Date.now()/1e3)){return!e||!e.settings.checkEnabled||e.phase===`checking`||!e.lastCheckAt?!1:Math.max(0,t-e.lastCheckAt)>Math.max(e.settings.checkIntervalSeconds*2,qh)}function Yh(e){return e===`healthy`?`bg-emerald-50 text-emerald-700 ring-emerald-200`:e===`warning`?`bg-amber-50 text-amber-800 ring-amber-200`:`bg-slate-100 text-slate-600 ring-slate-200`}function Xh({detail:e,eyebrow:t,href:n,icon:r,linkLabel:i=`자세히 보기 →`,meta:a,metaState:o,metaWarning:s=!1,state:c=`neutral`,value:l}){let u=B(S,{children:[B(`div`,{class:`flex items-start justify-between gap-4`,children:[B(`p`,{class:`m-0 text-[0.68rem] font-black uppercase tracking-[0.16em] text-slate-500`,children:t}),B(`span`,{class:`grid size-10 shrink-0 place-items-center rounded-xl ring-1 ring-inset ${Yh(c)}`,children:r})]}),B(`p`,{class:`mt-4 mb-0 break-words text-2xl font-black tracking-tight text-slate-950`,children:l}),B(`p`,{class:`mt-2 mb-0 min-h-10 text-sm font-medium leading-5 text-slate-500`,children:e}),a?B(`p`,{class:`mt-3 mb-0 text-xs font-bold ${o===`healthy`?`text-emerald-700`:o===`warning`||s?`text-amber-700`:`text-slate-400`}`,children:a}):null,n?B(`span`,{class:`mt-4 inline-flex text-xs font-extrabold text-teal-700`,children:i}):null]}),d=`min-w-0 rounded-2xl border border-slate-200 bg-white p-5 shadow-sm shadow-slate-900/5 transition`;return n?B(`a`,{class:`${d} no-underline hover:border-slate-300 hover:shadow-md`,href:n,children:u}):B(`article`,{class:d,children:u})}function Zh({action:e,description:t,eyebrow:n,id:r,title:i}){return B(`div`,{class:`mb-4 min-w-0`,children:[B(`p`,{class:`m-0 text-[0.68rem] font-black uppercase tracking-[0.18em] text-teal-700`,children:n}),B(`div`,{class:`mt-2 flex min-w-0 items-center justify-between gap-3`,children:[B(`h2`,{class:`m-0 min-w-0 text-xl font-black tracking-tight text-slate-950`,id:r,children:i}),e?B(`div`,{class:`shrink-0`,children:e}):null]}),B(`p`,{class:`mt-2 mb-0 text-sm leading-6 text-slate-500`,children:t})]})}var Qh=6e4;function $h(e,t){return!e||!Number.isFinite(e)||e<=0?null:Math.max(0,t-e)}function eg(e,t,n,r){return!t||t<=0?`${e}: ${r}`:B(`span`,{title:Fa(t),children:[e,`: `,Ia(t,n)]})}function tg(e){if(!e)return null;switch(e.toLowerCase()){case`dhcp`:return`DHCP`;case`static`:return`Static`;case`pppoe`:return`PPPoE`;default:return e.toUpperCase()}}function ng(e){if(!e)return!1;let t=e.split(`.`).map(e=>Number(e));if(t.length!==4||t.some(e=>!Number.isInteger(e)||e<0||e>255))return!1;let[n,r]=t;return n===void 0||r===void 0?!1:n===10||n===172&&r>=16&&r<=31||n===192&&r===168}function rg({label:e,value:t}){return B(`div`,{class:`flex min-w-0 items-start justify-between gap-4 border-b border-slate-100 py-3 last:border-b-0`,children:[B(`dt`,{class:`text-sm font-semibold text-slate-500`,children:e}),B(`dd`,{class:`m-0 min-w-0 max-w-[68%] break-words text-right text-sm font-extrabold text-slate-950`,children:t})]})}function ig(e){return e===`initializing`?{badge:`bg-teal-100 text-teal-800`,icon:`text-teal-700`,label:`준비 중`,panel:`border-teal-200 bg-teal-50`}:e===`critical`?{badge:`bg-rose-100 text-rose-800`,icon:`text-rose-700`,label:`이상`,panel:`border-rose-200 bg-rose-50/70`}:e===`warning`?{badge:`bg-amber-100 text-amber-800`,icon:`text-amber-700`,label:`주의`,panel:`border-amber-200 bg-amber-50/70`}:e===`unknown`?{badge:`bg-slate-200 text-slate-700`,icon:`text-slate-500`,label:`확인 불가`,panel:`border-slate-200 bg-slate-50`}:{badge:`bg-emerald-100 text-emerald-800`,icon:`text-emerald-700`,label:`정상`,panel:`border-emerald-200 bg-emerald-50/70`}}function ag({data:e,error:t,loading:n,nowTimestamp:r}){let i=!!(e&&e.generatedAt>0),a=ig(i&&e?e.overall:`unknown`),o=i&&e?e.checks.filter(e=>e.status!==`ok`):[],s=o.slice(0,2),c=Math.max(0,o.length-s.length);return B(`div`,{class:`mt-5 border-t border-slate-200 pt-5`,children:[B(`div`,{class:`flex flex-wrap items-center justify-between gap-3`,children:[B(`div`,{class:`flex items-center gap-2`,children:[B(`p`,{class:`m-0 text-sm font-black text-slate-950`,children:`장치 진단`}),i?B(`span`,{class:`rounded-full px-2.5 py-1 text-[11px] font-extrabold ${a.badge}`,children:a.label}):null]}),B(`a`,{class:`text-xs font-extrabold text-teal-700 no-underline hover:text-teal-900`,href:`#settings`,children:`상세 보기 →`})]}),t&&!i?B(`div`,{class:`mt-3 rounded-xl border border-amber-200 bg-amber-50/70 px-4 py-3`,children:B(`div`,{class:`flex items-start gap-2`,children:[B(U,{class:`mt-0.5 size-4 shrink-0 text-amber-700`}),B(`div`,{class:`min-w-0`,children:[B(`p`,{class:`m-0 text-sm font-extrabold text-slate-900`,children:`진단 상태를 확인하지 못했습니다.`}),B(`p`,{class:`mt-1 mb-0 text-xs leading-5 text-slate-500`,children:`설정에서 장치 진단 상태를 다시 확인해 주세요.`})]})]})}):i&&e?B(`div`,{class:`mt-3 rounded-xl border px-4 py-3 ${a.panel}`,children:[B(`div`,{class:`flex min-w-0 items-start gap-3`,children:[e.overall===`ok`?B(Xt,{class:`mt-0.5 size-5 shrink-0 ${a.icon}`}):e.overall===`initializing`?B(Vt,{class:`mt-0.5 size-5 shrink-0 ${a.icon}`}):B(U,{class:`mt-0.5 size-5 shrink-0 ${a.icon}`}),B(`div`,{class:`min-w-0 flex-1`,children:[B(`p`,{class:`m-0 text-sm font-black text-slate-950`,children:e.summary.message}),B(`p`,{class:`mt-1 mb-0 text-xs font-semibold leading-5 text-slate-500`,children:[`마지막 진단: `,Ia(e.generatedAt,r),` · 검사 항목:`,` `,e.summary.total,`개`]})]})]}),s.length>0?B(`div`,{class:`mt-3 grid gap-2 sm:grid-cols-2`,children:s.map(e=>B(`div`,{class:`min-w-0 rounded-lg border border-white/80 bg-white/70 px-3 py-2`,children:[B(`p`,{class:`m-0 text-xs font-extrabold text-slate-900`,children:e.label}),B(`p`,{class:`mt-1 mb-0 line-clamp-2 text-xs leading-5 text-slate-500`,children:e.message})]},e.id))}):null,c>0?B(`p`,{class:`mt-2 mb-0 text-xs font-extrabold text-slate-600`,children:[`외 `,c,`건의 확인 항목이 있습니다.`]}):null]}):B(`div`,{class:`mt-3 rounded-xl border border-slate-200 bg-slate-50 px-4 py-3`,children:[B(`p`,{class:`m-0 text-sm font-extrabold text-slate-900`,children:n?`진단 상태를 확인하고 있습니다.`:`아직 생성된 진단 결과가 없습니다.`}),B(`p`,{class:`mt-1 mb-0 text-xs leading-5 text-slate-500`,children:`진단 결과가 생성되면 현재 장치 상태를 이곳에 요약해서 표시합니다.`})]})]})}function og(e,t,n){if(t&&!e)return{detail:`보호 상태를 확인하고 있습니다.`,state:`neutral`,value:`확인 중`};if(n&&!e)return{detail:`SafeShield 상태를 불러오지 못했습니다.`,state:`warning`,value:`확인 필요`};if(!e||!e.available)return{detail:`SafeShield 서비스를 사용할 수 없습니다.`,state:`warning`,value:`사용 불가`};if(!e.enabled||e.status===`disabled`)return{detail:`DNS 보호가 비활성화되어 있습니다.`,state:`neutral`,value:`꺼짐`};if(e.status===`running`)return{detail:`차단 목록을 갱신하고 있습니다.`,state:`neutral`,value:`갱신 중`};if(!(e.active&&e.runtime.dnsmasqRunning&&e.runtime.dnsRuntimeOk&&e.health.overall!==`error`&&e.issueCounts.errors===0))return{detail:e.runtime.lastErrorCode?`최근 오류: ${e.runtime.lastErrorCode}`:`DNS 보호 상태를 확인해 주세요.`,state:`warning`,value:`확인 필요`};let r=e.license.plan?.trim(),i=e.blocklist.validLineCount>0?`${q(e.blocklist.validLineCount)}개 차단 규칙`:`차단 목록 적용됨`;return{detail:r?`${i} · ${r.toUpperCase()}`:i,state:`healthy`,value:`보호 중`}}function sg({activity:e,activityError:t,activityLoading:n,data:r,devices:i,devicesError:a,devicesLoading:o,error:s,firmware:c,firmwareError:l,firmwareLoading:u,health:d,healthError:f,healthLoading:p,lan:m,lanError:h,lanLoading:g,loading:_,onRetry:v,safeshield:y,safeshieldError:b,safeshieldLoading:x,statistics:S,statisticsError:C,statisticsLoading:w,statisticsRefreshing:T,updates:E,updatesError:D,updatesLoading:O}){let k=$e(()=>r?za(r.runtime.memory):null,[r]),[A,ee]=N(()=>Math.floor(Date.now()/1e3));if(P(()=>{let e=window.setInterval(()=>{ee(Math.floor(Date.now()/1e3))},Qh);return()=>window.clearInterval(e)},[]),_)return B(io,{});if(s)return B(ao,{message:s,onRetry:v});if(!r)return null;let j=k?Math.round(k.percent):0,te=og(y,x,b),ne=E?.packages.find(e=>e.name===`luci-app-smartsafehub`)??E?.packages[0]??null,M=!!(E&&E.updateCount>0),re=E?M?`${E.updateCount}개 업데이트`:E.lastCheckAt?`최신 상태`:`확인 전`:D?`확인 필요`:`확인 중`,ie=ne?M&&ne.availableVersion?`${ne.installedVersion} → ${ne.availableVersion}`:`설치 버전 ${ne.installedVersion}`:D?`업데이트 상태를 불러오지 못했습니다.`:O?`업데이트 상태를 확인하고 있습니다.`:`업데이트 상태를 확인할 수 없습니다.`,ae=i?`${q(i.totals.online)}대`:o?`확인 중`:`확인 필요`,oe=i?`Wi-Fi ${q(i.totals.wireless)}대 · 유선/기타 ${q(i.totals.ethernet)}대`:a||`연결 기기 요약을 불러오고 있습니다.`,se=tg(r.network.protocol),ce=r.network.available?r.network.ipv4Address?`WAN ${r.network.ipv4Address}${se?` · ${se}`:``}`:se?`${se} · WAN 주소를 받지 못했습니다.`:`WAN 주소를 받지 못했습니다.`:`WAN 인터페이스를 찾을 수 없습니다.`,le=!!m?.conflict.detected,ue=!r.network.up||le||h!==null&&!m?`warning`:m?`healthy`:`neutral`,de=le?`네트워크 충돌`:r.network.up?`정상 연결`:`연결 확인`,fe=r.network.up?le?`⚠ LAN 대역과 충돌합니다`:g&&!m?`네트워크 대역 확인 중`:h&&!m?`네트워크 대역을 확인하지 못했습니다.`:m?`✓ 네트워크 충돌 없음`:`네트워크 대역 확인 필요`:`WAN 연결 상태를 확인해 주세요.`,pe=!r.network.up||le||h!==null&&!m?`warning`:m?`healthy`:`neutral`,me=r.network.ipv4Address?ng(r.network.ipv4Address)?`${r.network.ipv4Address} · 사설 네트워크`:r.network.ipv4Address:`할당되지 않음`,he=$h(y?.timestamps.lastSuccess,A),ge=y?Math.max(y.timestamps.refreshIntervalS*2,86400):null,_e=!!(y?.enabled&&y.status!==`running`&&he!==null&&ge!==null&&he>ge),ve=Jh(E,A),ye=!!c?.current.metadataAvailable,be=u&&!c?`확인 중`:l&&!c?`확인 필요`:ye?c?.current.releaseVersion?`SmartSafeHub ${c.current.releaseVersion}`:`SmartSafeHub 펌웨어`:`${r.software.distribution} ${r.software.version}`,xe=u&&!c?`확인 중`:l&&!c?`확인 필요`:ye&&c?.current.buildId||r.software.revision,Se=ye?`빌드 ID`:`리비전`;return B(`div`,{class:`min-w-0 space-y-6`,children:[B(`section`,{"aria-labelledby":`dashboard-overview-title`,children:[B(Zh,{description:`인터넷, SafeShield, 연결 기기와 소프트웨어 상태를 한눈에 확인합니다.`,eyebrow:`Overview`,id:`dashboard-overview-title`,title:`시스템 개요`}),B(`div`,{class:`grid min-w-0 gap-4 sm:grid-cols-2 xl:grid-cols-4`,children:[B(Xh,{detail:ce,eyebrow:`Internet`,href:`#network`,icon:B(zt,{class:`size-5`}),linkLabel:le?`해결하기 →`:`자세히 보기 →`,meta:fe,metaState:pe,state:ue,value:de}),B(Xh,{detail:te.detail,eyebrow:`SafeShield`,href:`#safeshield`,icon:B(At,{class:`size-5`}),meta:eg(_e?`차단 목록 갱신 지연`:`차단 목록 갱신`,y?.timestamps.lastSuccess,A,x?`확인 중`:`기록 없음`),metaWarning:_e,state:te.state===`healthy`&&_e?`warning`:te.state,value:te.value}),B(Xh,{detail:oe,eyebrow:`Connected devices`,href:`#devices`,icon:B(Mt,{class:`size-5`}),meta:eg(`목록 확인`,i?.generatedAt,A,o?`확인 중`:`기록 없음`),state:i?`healthy`:a?`warning`:`neutral`,value:ae}),B(Xh,{detail:ie,eyebrow:`Software update`,href:`#system`,icon:B(Ft,{class:`size-5`}),meta:E&&!E.settings.checkEnabled?eg(`자동 확인 꺼짐 · 마지막 확인`,E.lastCheckAt,A,`확인 기록 없음`):eg(ve?`업데이트 확인 지연`:`마지막 확인`,E?.lastCheckAt,A,O?`확인 중`:`아직 없음`),metaWarning:ve,state:D||ve||M?`warning`:E?.lastCheckAt?`healthy`:`neutral`,value:re})]})]}),B(`section`,{"aria-labelledby":`dashboard-activity-title`,children:[B(Zh,{description:`최근 SafeShield 차단 활동과 현재 네트워크 연결 구성을 함께 확인합니다.`,eyebrow:`Activity`,id:`dashboard-activity-title`,title:`네트워크 보호 활동`}),B(`div`,{class:`grid min-w-0 gap-4 xl:grid-cols-[minmax(0,1.55fr)_minmax(18rem,0.65fr)]`,children:[B(Kh,{data:S,error:C,loading:w,nowTimestamp:A,refreshing:T}),B(`article`,{class:`min-w-0 rounded-2xl border border-slate-200 bg-white p-5 shadow-sm shadow-slate-900/5 sm:p-6`,children:[B(`div`,{class:`flex items-start justify-between gap-4`,children:[B(`div`,{children:[B(`p`,{class:`m-0 text-xs font-extrabold uppercase tracking-[0.16em] text-slate-500`,children:`Network`}),B(`h3`,{class:`mt-2 mb-0 text-xl font-black text-slate-950`,children:`연결 상태`})]}),B(`span`,{class:`grid size-10 shrink-0 place-items-center rounded-xl ${r.network.up&&!le?`bg-emerald-50 text-emerald-700`:`bg-amber-50 text-amber-800`}`,children:B(zt,{class:`size-5`})})]}),B(`dl`,{class:`mt-4 mb-0`,children:[B(rg,{label:`인터넷`,value:le?`네트워크 충돌`:r.network.up?`정상 연결`:`연결 확인`}),B(rg,{label:`WAN IP`,value:me}),B(rg,{label:`프로토콜`,value:se||`확인되지 않음`}),B(rg,{label:`상위 네트워크`,value:m?.wan.subnet||(g?`확인 중`:h?`확인 필요`:`확인되지 않음`)}),B(rg,{label:`LAN 네트워크`,value:m?.lan.subnet||(g?`확인 중`:h?`확인 필요`:`확인되지 않음`)}),B(rg,{label:`대역 충돌`,value:m?B(`span`,{class:m.conflict.detected?`text-amber-700`:`text-emerald-700`,children:m.conflict.detected?`충돌 감지`:`없음`}):g?`확인 중`:`확인 필요`})]}),B(`a`,{class:`mt-5 inline-flex min-h-10 w-full items-center justify-center rounded-xl border border-slate-200 bg-slate-50 px-4 py-2 text-sm font-extrabold text-slate-700 no-underline transition hover:border-teal-200 hover:bg-teal-50 hover:text-teal-800`,href:`#network`,children:`네트워크 보기`})]})]})]}),B(`section`,{"aria-labelledby":`dashboard-recent-activity-title`,children:[B(Zh,{action:B(`a`,{class:`inline-flex whitespace-nowrap text-xs font-extrabold text-teal-700 no-underline hover:text-teal-900`,href:`#activity`,children:`전체 보기 →`}),description:`인터넷, 보호, 업데이트와 진단에서 실제 상태가 바뀐 시점을 확인합니다.`,eyebrow:`History`,id:`dashboard-recent-activity-title`,title:`최근 활동`}),B(`article`,{class:`min-w-0 rounded-2xl border border-slate-200 bg-white p-5 shadow-sm shadow-slate-900/5 sm:p-6`,children:n||t&&!e?B(eo,{error:t,loading:n}):B($a,{compact:!0,events:(e?.events??[]).slice(0,3)})})]}),B(`section`,{"aria-labelledby":`dashboard-system-title`,children:[B(Zh,{description:`메모리, 시스템 부하와 장치 정보를 빠르게 점검합니다.`,eyebrow:`System`,id:`dashboard-system-title`,title:`시스템 상태`}),B(`div`,{class:`grid min-w-0 gap-4 xl:grid-cols-[minmax(0,1.45fr)_minmax(20rem,0.75fr)]`,children:[B(`article`,{class:`min-w-0 rounded-2xl border border-slate-200 bg-white p-5 shadow-sm shadow-slate-900/5 sm:p-6`,children:[B(`div`,{class:`flex flex-wrap items-start justify-between gap-4`,children:[B(`div`,{children:[B(`p`,{class:`m-0 text-xs font-extrabold uppercase tracking-[0.16em] text-slate-500`,children:`Runtime`}),B(`h3`,{class:`mt-2 mb-0 text-xl font-black text-slate-950`,children:`리소스 사용량`})]}),B(`span`,{class:`inline-flex items-center gap-2 rounded-full px-3 py-1.5 text-xs font-black ring-1 ring-inset ${j>=90?`bg-amber-50 text-amber-800 ring-amber-200`:`bg-emerald-50 text-emerald-700 ring-emerald-200`}`,children:[B(`span`,{class:`size-2 rounded-full ${j>=90?`bg-amber-500`:`bg-emerald-500`}`}),j>=90?`메모리 확인`:`정상 실행`]})]}),B(`div`,{class:`mt-5 grid gap-3 sm:grid-cols-3`,children:[B(`div`,{class:`rounded-xl border border-slate-200 bg-slate-50 p-4`,children:[B(`div`,{class:`flex items-center gap-2 text-slate-500`,children:[B(Ht,{class:`size-4`}),B(`span`,{class:`text-xs font-extrabold`,children:`메모리`})]}),B(`p`,{class:`mt-2 mb-0 text-xl font-black text-slate-950`,children:[j,`%`]}),B(`p`,{class:`mt-1 mb-0 text-xs font-semibold text-slate-500`,children:[k?Ma(k.used):`-`,` /`,` `,Ma(r.runtime.memory.total)]}),B(`div`,{"aria-label":`메모리 사용률 ${j}%`,class:`mt-3 h-1.5 overflow-hidden rounded-full bg-slate-200`,role:`progressbar`,"aria-valuemin":0,"aria-valuemax":100,"aria-valuenow":j,children:B(`div`,{class:`h-full rounded-full transition-[width] duration-300 ${j>=90?`bg-amber-500`:`bg-teal-600`}`,style:{width:`${Math.min(100,j)}%`}})})]}),B(`div`,{class:`rounded-xl border border-slate-200 bg-slate-50 p-4`,children:[B(`div`,{class:`flex items-center gap-2 text-slate-500`,children:[B(jt,{class:`size-4`}),B(`span`,{class:`text-xs font-extrabold`,children:`시스템 부하`})]}),B(`p`,{class:`mt-2 mb-0 text-xl font-black text-slate-950`,children:Na(r.runtime.load[0])}),B(`p`,{class:`mt-1 mb-0 text-xs font-semibold text-slate-500`,children:[`5분 `,Na(r.runtime.load[1]),` · 15분`,` `,Na(r.runtime.load[2])]})]}),B(`div`,{class:`rounded-xl border border-slate-200 bg-slate-50 p-4`,children:[B(`div`,{class:`flex items-center gap-2 text-slate-500`,children:[B(Vt,{class:`size-4`}),B(`span`,{class:`text-xs font-extrabold`,children:`실행 시간`})]}),B(`p`,{class:`mt-2 mb-0 text-xl font-black text-slate-950`,children:ja(r.runtime.uptime)}),B(`p`,{class:`mt-1 mb-0 text-xs font-semibold text-slate-500`,children:[`부팅 `,Pa(r.runtime.localtime,r.runtime.uptime)]})]})]}),B(ag,{data:d,error:f,loading:p,nowTimestamp:A})]}),B(`article`,{class:`min-w-0 rounded-2xl border border-slate-200 bg-white p-5 shadow-sm shadow-slate-900/5 sm:p-6`,children:[B(`div`,{class:`flex items-start justify-between gap-4`,children:[B(`div`,{children:[B(`p`,{class:`m-0 text-xs font-extrabold uppercase tracking-[0.16em] text-slate-500`,children:`Device`}),B(`h3`,{class:`mt-2 mb-0 text-xl font-black text-slate-950`,children:`장치 정보`})]}),B(`span`,{class:`grid size-10 shrink-0 place-items-center rounded-xl bg-teal-50 text-teal-700`,children:B(jt,{class:`size-5`})})]}),B(`dl`,{class:`mt-4 mb-0`,children:[B(rg,{label:`모델`,value:r.device.model}),B(rg,{label:`호스트 이름`,value:r.device.hostname}),B(rg,{label:`펌웨어`,value:B(`span`,{title:ye?c?.current.releaseVersion?`SmartSafeHub 펌웨어 ${c.current.releaseVersion}`:`SmartSafeHub 커스텀 펌웨어`:l||void 0,children:be})}),B(rg,{label:Se,value:xe}),B(rg,{label:`커널`,value:r.software.kernel}),B(rg,{label:`WAN IP`,value:r.network.ipv4Address||`할당되지 않음`})]})]})]})]})]})}function cg(e,t){for(var n in t)e[n]=t[n];return e}function lg(e,t){for(var n in e)if(n!==`__source`&&!(n in t))return!0;for(var r in t)if(r!==`__source`&&e[r]!==t[r])return!0;return!1}function ug(e,t){this.props=e,this.context=t}(ug.prototype=new C).isPureReactComponent=!0,ug.prototype.shouldComponentUpdate=function(e,t){return lg(this.props,e)||lg(this.state,t)};var dg=t.__b;t.__b=function(e){e.type&&e.type.__f&&e.ref&&(e.props.ref=e.ref,e.ref=null),dg&&dg(e)},typeof Symbol<`u`&&Symbol.for;var fg=t.__e;t.__e=function(e,t,n,r){if(e.then){for(var i,a=t;a=a.__;)if((i=a.__c)&&i.__c)return t.__e??(t.__e=n.__e,t.__k=n.__k||[]),i.__c(e,t)}fg(e,t,n,r)};var pg=t.unmount;function mg(e,t,n){return e&&(e.__c&&e.__c.__H&&(e.__c.__H.__.forEach(function(e){typeof e.__c==`function`&&e.__c()}),e.__c.__H=null),(e=cg({},e)).__c!=null&&(e.__c.__P===n&&(e.__c.__P=t),e.__c.__e=!0,e.__c=null),e.__k=e.__k&&e.__k.map(function(e){return mg(e,t,n)})),e}function hg(e,t,n){return e&&n&&(e.__v=null,e.__k=e.__k&&e.__k.map(function(e){return hg(e,t,n)}),e.__c&&e.__c.__P===t&&(e.__e&&n.appendChild(e.__e),e.__c.__e=!0,e.__c.__P=n)),e}function gg(){this.__u=0,this.o=null,this.__b=null}function _g(e){var t=e.__&&e.__.__c;return t&&t.__a&&t.__a(e)}function vg(){this.i=null,this.l=null}t.unmount=function(e){var t=e.__c;t&&(t.__z=!0),t&&t.__R&&t.__R(),t&&32&e.__u&&(e.type=null),pg&&pg(e)},(gg.prototype=new C).__c=function(e,t){var n=t.__c,r=this;r.o??(r.o=[]),r.o.push(n);var i=_g(r.__v),a=!1,o=function(){a||r.__z||(a=!0,n.__R=null,i?i(c):c())};n.__R=o;var s=n.__P;n.__P=null;var c=function(){if(!--r.__u){if(r.state.__a){var e=r.state.__a;r.__v.__k[0]=hg(e,e.__c.__P,e.__c.__O)}var t;for(r.setState({__a:r.__b=null});t=r.o.pop();)t.__P=s,t.forceUpdate()}};r.__u++||32&t.__u||r.setState({__a:r.__b=r.__v.__k[0]}),e.then(o,o)},gg.prototype.componentWillUnmount=function(){this.o=[]},gg.prototype.render=function(e,t){if(this.__b){if(this.__v.__k){var n=document.createElement(`div`),r=this.__v.__k[0].__c;this.__v.__k[0]=mg(this.__b,n,r.__O=r.__P)}this.__b=null}var i=t.__a&&b(S,null,e.fallback);return i&&(i.__u&=-33),[b(S,null,t.__a?null:e.children),i]};var yg=function(e,t,n){if(++n[1]===n[0]&&e.l.delete(t),e.props.revealOrder&&(e.props.revealOrder[0]!==`t`||!e.l.size))for(n=e.i;n;){for(;n.length>3;)n.pop()();if(n[1]>>1,1),t.h.removeChild(e)}}}fe(b(bg,{context:t.context},e.__v),t.v)}function Sg(e,t){var n=b(xg,{__v:e,h:t});return n.containerInfo=t,n}(vg.prototype=new C).__a=function(e){var t=this,n=_g(t.__v),r=t.l.get(e);return r[0]++,function(i){var a=function(){t.props.revealOrder?(r.push(i),yg(t,e,r)):i()};n?n(a):a()}},vg.prototype.render=function(e){this.i=null,this.l=new Map;var t=j(e.children);e.revealOrder&&e.revealOrder[0]===`b`&&t.reverse();for(var n=t.length;n--;)this.l.set(t[n],this.i=[1,0,this.i]);return e.children},vg.prototype.componentDidUpdate=vg.prototype.componentDidMount=function(){var e=this;this.l.forEach(function(t,n){yg(e,n,t)})};var Cg=typeof Symbol<`u`&&Symbol.for&&Symbol.for(`react.element`)||60103,wg=/^(?:accent|alignment|arabic|baseline|cap|clip(?!PathU)|color|dominant|fill|flood|font|glyph(?!R)|horiz|image(!S)|letter|lighting|marker(?!H|W|U)|overline|paint|pointer|shape|stop|strikethrough|stroke|text(?!L)|transform|underline|unicode|units|v|vector|vert|word|writing|x(?!C))[A-Z]/,Tg=/^on(Ani|Tra|Tou|BeforeInp|Compo)/,Eg=/[A-Z0-9]/g,Dg=typeof document<`u`,Og=function(e){return(typeof Symbol<`u`&&typeof Symbol()==`symbol`?/fil|che|rad/:/fil|che|ra/).test(e)};C.prototype.isReactComponent=!0,[`componentWillMount`,`componentWillReceiveProps`,`componentWillUpdate`].forEach(function(e){Object.defineProperty(C.prototype,e,{configurable:!0,get:function(){return this[`UNSAFE_`+e]},set:function(t){Object.defineProperty(this,e,{configurable:!0,writable:!0,value:t})}})});var kg=t.event;t.event=function(e){return kg&&(e=kg(e)),e.persist=function(){},e.isPropagationStopped=function(){return this.cancelBubble},e.isDefaultPrevented=function(){return this.defaultPrevented},e.nativeEvent=e};var Ag={configurable:!0,get:function(){return this.class}},jg=t.vnode;t.vnode=function(e){typeof e.type==`string`&&function(e){var t=e.props,n=e.type,r={},i=n.indexOf(`-`)==-1;for(var a in t){var o=t[a];if(!(a===`value`&&`defaultValue`in t&&o==null||Dg&&a===`children`&&n===`noscript`||a===`class`||a===`className`)){var s=a.toLowerCase();a===`defaultValue`&&`value`in t&&t.value==null?a=`value`:a===`download`&&!0===o?o=``:s===`translate`&&o===`no`?o=!1:s[0]===`o`&&s[1]===`n`?s===`ondoubleclick`?a=`ondblclick`:s!==`onchange`||n!==`input`&&n!==`textarea`||Og(t.type)?s===`onfocus`?a=`onfocusin`:s===`onblur`?a=`onfocusout`:Tg.test(a)&&(a=s):s=a=`oninput`:i&&wg.test(a)?a=a.replace(Eg,`-$&`).toLowerCase():o===null&&(o=void 0),s===`oninput`&&r[a=s]&&(a=`oninputCapture`),r[a]=o}}n==`select`&&(r.multiple&&Array.isArray(r.value)&&(r.value=j(t.children).forEach(function(e){e.props.selected=r.value.indexOf(e.props.value)!=-1})),r.defaultValue!=null&&(r.value=j(t.children).forEach(function(e){e.props.selected=r.multiple?r.defaultValue.indexOf(e.props.value)!=-1:r.defaultValue==e.props.value}))),t.class&&!t.className?(r.class=t.class,Object.defineProperty(r,"className",Ag)):t.className&&(r.class=r.className=t.className),e.props=r}(e),e.$$typeof=Cg,jg&&jg(e)};var Mg=t.__r;t.__r=function(e){Mg&&Mg(e),e.__c};var Ng=t.diffed;t.diffed=function(e){Ng&&Ng(e);var t=e.props,n=e.__e;n!=null&&e.type===`textarea`&&`value`in t&&t.value!==n.value&&(n.value=t.value==null?``:t.value)};var Pg=8,Fg=256,Ig=8;function Lg(e){return e.findIndex(e=>!e.disabled)}function Rg(e){for(let t=e.length-1;t>=0;--t)if(!e[t]?.disabled)return t;return-1}function zg(e,t,n){if(e.length===0)return-1;let r=t;for(let t=0;te.value===t&&!e.disabled);return n>=0?n:Lg(e)}function Vg({ariaLabel:e,className:t=``,disabled:n=!1,id:r,onChange:i,options:a,value:o,variant:s=`default`}){let c=et(),l=r??`ssh-custom-select-${c}`,u=`${l}-menu`,d=F(null),f=F(null),p=F(null),m=F([]),[h,g]=N(!1),[_,v]=N(()=>Bg(a,o)),[y,b]=N(`bottom`),[x,S]=N(Fg),[C,w]=N({}),[T,E]=N(null),D=$e(()=>a.find(e=>e.value===o)??a[0]??null,[a,o]),O=()=>{let e=f.current;if(!e)return;let t=e.getBoundingClientRect(),n=Math.min(Fg,Math.max(44,a.length*42+12)),r=window.innerHeight-t.bottom-Ig,i=t.top-Ig,o=rr?`top`:`bottom`,s=Math.min(t.width,Math.max(0,window.innerWidth-16)),c=Math.max(Ig,Math.min(t.left,window.innerWidth-s-Ig)),l=o===`bottom`?r:i;b(o),S(Math.max(44,Math.min(Fg,Math.floor(l)))),w({left:`${c}px`,width:`${s}px`,...o===`bottom`?{top:`${t.bottom+Pg}px`}:{bottom:`${window.innerHeight-t.top+Pg}px`}})},k=(e=!1)=>{g(!1),e&&window.requestAnimationFrame(()=>f.current?.focus())},A=e=>{e<0||(v(e),window.requestAnimationFrame(()=>m.current[e]?.focus()))},ee=e=>{let t=a[e];!t||t.disabled||(i(t.value),g(!1),window.requestAnimationFrame(()=>f.current?.focus()))},j=e=>{n||a.length===0||(O(),g(!0),A(e??Bg(a,o)))};P(()=>{let e=d.current?.closest(`.ssh-app`);if(e){E(e);return}let t=d.current?.getRootNode();t instanceof ShadowRoot?E(t):typeof document<`u`&&E(document.body)},[]),P(()=>{v(Bg(a,o)),m.current=m.current.slice(0,a.length)},[a,o]),P(()=>{if(!h)return;O();let e=e=>{let t=e.composedPath();d.current&&t.includes(d.current)||p.current&&t.includes(p.current)||k()},t=e=>{e.key===`Escape`&&(e.preventDefault(),k(!0))},n=()=>O();return document.addEventListener(`pointerdown`,e),document.addEventListener(`keydown`,t),window.addEventListener(`resize`,n),window.addEventListener(`scroll`,n,!0),()=>{document.removeEventListener(`pointerdown`,e),document.removeEventListener(`keydown`,t),window.removeEventListener(`resize`,n),window.removeEventListener(`scroll`,n,!0)}},[h,a.length]),P(()=>{n&&h&&k()},[n,h]);let te=s===`emphasized`?`min-h-11 border-2 border-slate-300 bg-slate-50 px-4 py-2.5 text-sm font-semibold text-slate-950 shadow-inner focus:border-teal-500 focus:bg-white focus:ring-4 focus:ring-teal-100`:`min-h-11 border border-slate-300 bg-slate-50 px-3 py-2.5 text-sm font-bold text-slate-900 focus:border-teal-500 focus:ring-2 focus:ring-teal-100`,ne=h?B(`div`,{"aria-label":`${e} 목록`,class:`ssh-custom-select-menu fixed z-[1000] overflow-hidden rounded-xl border border-slate-200 bg-white p-1.5 shadow-xl shadow-slate-950/10`,id:u,ref:p,role:`listbox`,style:C,children:B(`div`,{class:`overflow-y-auto overscroll-contain`,style:{maxHeight:`${x}px`},children:a.map((e,t)=>{let n=e.value===o;return B(`button`,{"aria-selected":n,class:`flex min-h-10 w-full items-center justify-between gap-3 rounded-lg px-3 py-2.5 text-left text-sm font-bold transition ${n?`bg-teal-50 text-teal-800`:`text-slate-700 hover:bg-slate-50`} ${e.disabled?`cursor-not-allowed opacity-50`:``}`,disabled:e.disabled,onClick:()=>ee(t),onFocus:()=>v(t),onKeyDown:e=>{switch(e.key){case`ArrowDown`:e.preventDefault(),A(zg(a,t,1));break;case`ArrowUp`:e.preventDefault(),A(zg(a,t,-1));break;case`Home`:e.preventDefault(),A(Lg(a));break;case`End`:e.preventDefault(),A(Rg(a));break;case`Enter`:case` `:e.preventDefault(),ee(t);break;case`Escape`:e.preventDefault(),k(!0);break;case`Tab`:g(!1)}},ref:e=>{m.current[t]=e},role:`option`,tabIndex:_===t?0:-1,type:`button`,children:[B(`span`,{class:`min-w-0 truncate`,children:e.label}),n?B(`span`,{"aria-hidden":`true`,class:`size-2 shrink-0 rounded-full bg-teal-500`}):null]},e.value)})})}):null;return B(`div`,{class:`relative ${t}`,ref:d,children:[B(`button`,{"aria-controls":u,"aria-expanded":h,"aria-haspopup":`listbox`,"aria-label":e,class:`ssh-custom-select-trigger flex w-full cursor-pointer items-center justify-between gap-3 rounded-xl text-left outline-none transition disabled:cursor-not-allowed disabled:bg-slate-100 disabled:text-slate-400 disabled:opacity-60 ${te}`,disabled:n,id:l,onClick:()=>{if(h){k();return}O(),g(!0)},onKeyDown:e=>{switch(e.key){case`ArrowDown`:e.preventDefault(),j(h?zg(a,_,1):Bg(a,o));break;case`ArrowUp`:e.preventDefault(),j(h?zg(a,_,-1):Bg(a,o));break;case`Home`:e.preventDefault(),j(Lg(a));break;case`End`:e.preventDefault(),j(Rg(a));break;case`Enter`:case` `:e.preventDefault(),h?k():j();break;case`Escape`:h&&(e.preventDefault(),k())}},ref:f,type:`button`,children:[B(`span`,{class:`min-w-0 truncate`,children:D?.label??`선택하세요`}),B(rn,{"aria-hidden":`true`,class:`size-4 shrink-0 text-slate-400 transition-transform ${h?`rotate-180`:``}`})]}),ne&&T?Sg(ne,T):null,B(`span`,{class:`sr-only`,"aria-live":`polite`,children:y===`top`?`선택 목록이 위쪽에 열렸습니다.`:``})]})}var Hg=[{value:`skb`,label:`SK Broadband`},{value:`lgu`,label:`LG U+`}];function Ug(e){return e===`lgu`?`LG U+`:`SK Broadband`}function Wg({active:e,label:t,value:n}){return B(`div`,{class:`rounded-xl border border-slate-200 bg-white p-4`,children:[B(`div`,{class:`flex items-center justify-between gap-3`,children:[B(`p`,{class:`m-0 text-xs font-extrabold text-slate-500`,children:t}),B(`span`,{class:`size-2.5 shrink-0 rounded-full ${e?`bg-emerald-500`:`bg-slate-300`}`,"aria-hidden":`true`})]}),B(`p`,{class:`mt-2 mb-0 text-sm font-black text-slate-950`,children:n})]})}function Gg({data:e,error:t,feedback:n,loading:r,onDismissFeedback:i,onRetry:a,onSave:o,saving:s}){let[c,l]=N(!1),[u,d]=N(`skb`);if(P(()=>{e&&(l(e.enabled),d(e.provider))},[e]),r&&!e)return B(io,{});if(t&&!e)return B(ao,{message:t,onRetry:a});if(!e)return B(ao,{message:`IPTV 설정을 확인할 수 없습니다.`,onRetry:a});let f=c!==e.enabled||u!==e.provider,p=!e.enabled||e.running&&e.igmpSnooping;return B(`div`,{class:`space-y-5`,children:[B(`section`,{class:`rounded-2xl border border-amber-200 bg-amber-50 p-5 sm:p-6`,children:B(`div`,{class:`flex items-start gap-4`,children:[B(`span`,{class:`grid size-11 shrink-0 place-items-center rounded-xl bg-amber-100 text-amber-800`,children:B(U,{class:`size-5`})}),B(`div`,{class:`min-w-0 flex-1`,children:[B(`div`,{class:`flex flex-wrap items-center gap-2`,children:[B(`h2`,{class:`m-0 text-base font-black text-amber-950`,children:`IPTV 실험 기능`}),B(`span`,{class:`rounded-full border border-amber-300 bg-amber-100 px-2 py-0.5 text-[10px] font-black uppercase tracking-[0.12em] text-amber-800`,children:`Beta`})]}),B(`p`,{class:`mt-2 mb-0 text-sm leading-6 text-amber-900/80`,children:`현재 SK Broadband와 LG U+를 지원하며 두 통신사에는 동일한 멀티캐스트 IPTV 프로파일을 적용합니다. KT IPTV는 별도 네트워크 방식이 필요해 아직 지원하지 않습니다.`})]})]})}),n?B(`section`,{"aria-live":`polite`,class:`rounded-2xl border p-4 ${n.kind===`success`?`border-emerald-200 bg-emerald-50 text-emerald-900`:`border-red-200 bg-red-50 text-red-900`}`,children:B(`div`,{class:`flex items-start justify-between gap-3`,children:[B(`p`,{class:`m-0 text-sm font-bold leading-6`,children:n.message}),B(`button`,{class:`shrink-0 text-xs font-extrabold underline underline-offset-2`,onClick:i,type:`button`,children:`닫기`})]})}):null,B(`section`,{class:`rounded-2xl border border-slate-200 bg-white p-5 shadow-sm shadow-slate-900/5 sm:p-6`,children:[B(`div`,{class:`flex min-w-0 items-start gap-3`,children:[B(`span`,{class:`grid size-11 shrink-0 place-items-center rounded-xl bg-teal-50 text-teal-700`,children:B(Bt,{class:`size-5`})}),B(`div`,{class:`min-w-0 flex-1`,children:[B(`div`,{class:`flex min-w-0 flex-wrap items-center justify-between gap-2`,children:[B(`h2`,{class:`m-0 text-lg font-black text-slate-950`,children:`IPTV`}),B(`div`,{class:`flex shrink-0 items-center gap-2`,children:[f?B(`span`,{"aria-live":`polite`,class:`inline-flex shrink-0 items-center gap-1.5 rounded-full border border-amber-200 bg-amber-50 px-2.5 py-1 text-xs font-extrabold text-amber-800`,role:`status`,children:[B(U,{"aria-hidden":`true`,class:`size-3.5 shrink-0`}),`저장되지 않음`]}):null,B(`button`,{"aria-checked":c,"aria-label":`IPTV 사용`,class:`ssh-switch-control relative inline-flex shrink-0 rounded-full border-0 transition focus:outline-none focus-visible:ring-4 focus-visible:ring-teal-100 ${c?`bg-teal-700`:`bg-slate-300`} disabled:cursor-not-allowed disabled:opacity-60`,disabled:s||!e.available,onClick:()=>l(e=>!e),role:`switch`,type:`button`,children:B(`span`,{"aria-hidden":`true`,class:`ssh-switch-thumb absolute top-1 shadow-sm transition-[left] ${c?`left-6`:`left-1`}`})})]})]}),B(`p`,{class:`mt-1 mb-0 text-sm leading-6 text-slate-600`,children:`WAN의 멀티캐스트 방송을 LAN 셋톱박스로 전달합니다.`})]})]}),B(`div`,{class:`mt-6 grid gap-5 lg:grid-cols-[minmax(0,1fr)_minmax(0,1fr)]`,children:[B(`div`,{class:`rounded-xl border border-slate-200 bg-slate-50 p-4`,children:[B(`div`,{class:`flex flex-wrap items-start justify-between gap-2`,children:[B(`div`,{children:[B(`label`,{class:`block text-xs font-extrabold text-slate-600`,htmlFor:`iptv-provider`,children:`통신사`}),B(`p`,{class:`mt-1 mb-0 text-xs leading-5 text-slate-500`,children:`IPTV를 제공하는 회선 사업자를 선택하세요.`})]}),B(`span`,{class:`rounded-full border border-teal-200 bg-teal-50 px-2.5 py-1 text-[10px] font-black text-teal-700`,children:`멀티캐스트 방식`})]}),B(Vg,{ariaLabel:`IPTV 통신사`,className:`mt-3`,disabled:s||!c,id:`iptv-provider`,onChange:e=>d(e),options:Hg,value:u}),B(`div`,{class:`mt-3 flex items-start gap-2 rounded-lg border border-slate-200 bg-white p-3`,children:[B(Xt,{"aria-hidden":`true`,class:`mt-0.5 size-4 shrink-0 text-teal-700`}),B(`p`,{class:`m-0 text-xs leading-5 text-slate-600`,children:[Ug(u),`에는 현재 SK Broadband/LG U+ 공통 IGMP Proxy 프로파일을 적용합니다. KT는 추후 별도 IPTV 프로파일로 지원할 예정입니다.`]})]})]}),B(`div`,{class:`rounded-xl border border-slate-200 bg-slate-50 p-4`,children:[B(`div`,{class:`flex items-center justify-between gap-3`,children:[B(`p`,{class:`m-0 text-xs font-extrabold text-slate-500`,children:`현재 지원 프로파일`}),B(`span`,{class:`text-xs font-extrabold text-slate-500`,children:`SKB · LG U+`})]}),B(`p`,{class:`mt-2 mb-0 text-sm font-black text-slate-950`,children:`WAN → IGMP Proxy → LAN`}),B(`p`,{class:`mt-1 mb-0 text-xs leading-5 text-slate-600`,children:`WAN을 upstream, LAN을 downstream으로 사용하고 LAN bridge에는 IGMP snooping을 함께 활성화해 필요하지 않은 포트와 Wi-Fi로 멀티캐스트가 불필요하게 퍼지는 것을 줄입니다.`})]})]}),e.available?null:B(`div`,{class:`mt-5 rounded-xl border border-red-200 bg-red-50 p-4 text-sm font-bold leading-6 text-red-900`,children:`IGMP Proxy 패키지를 찾지 못했습니다. 현재 펌웨어에 igmpproxy 패키지가 포함되어 있는지 확인해 주세요.`}),B(`div`,{class:`mt-6 flex flex-wrap items-center justify-between gap-3 border-t border-slate-200 pt-5`,children:[B(`p`,{class:`m-0 text-xs leading-5 text-slate-500`,children:`설정을 적용하면 네트워크 서비스가 잠시 다시 로드될 수 있습니다.`}),B(`button`,{class:`inline-flex min-h-11 items-center justify-center rounded-xl border-0 bg-teal-700 px-5 py-2.5 text-sm font-black text-white shadow-sm transition hover:bg-teal-800 focus:outline-none focus-visible:ring-4 focus-visible:ring-teal-100 disabled:cursor-not-allowed disabled:opacity-50`,disabled:s||!e.available||!f&&!c,onClick:()=>void o({enabled:c,provider:u}),type:`button`,children:s?`적용 중…`:f?`변경사항 적용`:`설정 다시 적용`})]})]}),B(`section`,{class:`rounded-2xl border border-slate-200 bg-white p-5 shadow-sm shadow-slate-900/5 sm:p-6`,children:[B(`div`,{class:`flex items-center justify-between gap-3`,children:[B(`div`,{children:[B(`p`,{class:`m-0 text-xs font-black uppercase tracking-[0.14em] text-teal-700`,children:`Runtime`}),B(`h2`,{class:`mt-1 mb-0 text-lg font-black text-slate-950`,children:`IPTV 동작 상태`})]}),B(`span`,{class:`inline-flex items-center gap-1.5 rounded-full px-3 py-1 text-xs font-black ${p?`bg-emerald-100 text-emerald-800`:`bg-amber-100 text-amber-800`}`,children:[B(Xt,{class:`size-4`}),p?e.enabled?`정상`:`꺼짐`:`확인 필요`]})]}),f?B(`div`,{class:`mt-4 flex items-start gap-2 rounded-xl border border-amber-200 bg-amber-50 p-3 text-xs font-bold leading-5 text-amber-900`,children:[B(U,{"aria-hidden":`true`,class:`mt-0.5 size-4 shrink-0`}),`아래 동작 상태는 마지막으로 적용된 설정 기준입니다. 변경사항을 적용하면 새 설정으로 갱신됩니다.`]}):null,B(`div`,{class:`mt-5 grid gap-3 sm:grid-cols-2 lg:grid-cols-4`,children:[B(Wg,{active:e.enabled&&e.running,label:`IGMP Proxy`,value:e.enabled?e.running?`동작 중`:`중지됨`:`꺼짐`}),B(Wg,{active:e.enabled&&e.igmpSnooping,label:`IGMP Snooping`,value:e.igmpSnooping?`켜짐`:`꺼짐`}),B(Wg,{active:e.enabled,label:`Upstream`,value:e.upstreamNetwork.toUpperCase()}),B(Wg,{active:e.enabled,label:`Downstream`,value:e.lanBridge??e.downstreamNetwork.toUpperCase()})]})]})]})}function Kg(e){let t=e.split(`.`);return[t[0]??``,t[1]??``,t[2]??``,t[3]??``]}function qg(e){return e.replace(/\D/g,``).slice(0,3)}function Jg(e){return e.every(e=>e===``)?``:e.join(`.`)}function Yg({disabled:e=!1,label:t,value:n,onChange:r}){let i=Kg(n),a=(e,t)=>{let n=[...i];n[e]=qg(t),r(Jg(n))};return B(`div`,{class:`ssh-ipv4-segments mt-2 min-h-11`,"aria-label":`${t} 입력`,children:i.map((n,r)=>B(`div`,{class:`ssh-ipv4-segment`,children:[B(`input`,{"aria-label":`${t} ${r+1}번째 옥텟`,autocomplete:`off`,class:`min-h-11 w-full min-w-0 max-w-full rounded-xl border-2 border-slate-300 bg-slate-50 px-1.5 py-2.5 text-center text-sm font-semibold text-slate-950 shadow-inner outline-none transition focus:border-teal-500 focus:bg-white focus:ring-4 focus:ring-teal-100 disabled:cursor-not-allowed disabled:bg-slate-100 sm:px-2`,disabled:e,inputMode:`numeric`,maxLength:3,onInput:e=>a(r,e.currentTarget.value),pattern:`[0-9]*`,spellcheck:!1,value:n}),r{if(!/^(0|[1-9][0-9]{0,2})$/.test(e))return!1;let t=Number(e);return t>=0&&t<=255})}function $g(e){let t=Kg(e);return t.slice(0,3).some(e=>e===``||Number(e)>255)?null:t.slice(0,3).join(`.`)}function e_(e){return Kg(e)[3]}function t_(e){let t=$g(e.lan.address),n=e_(e.dhcp.start??``),r=e_(e.dhcp.end??``);return{ipAddress:e.lan.address,prefixLength:e.lan.prefixLength,dhcpEnabled:e.dhcp.enabled,dhcpStart:t&&n?`${t}.${n}`:e.dhcp.start??``,dhcpEnd:t&&r?`${t}.${r}`:e.dhcp.end??``,leaseTime:e.dhcp.leaseTime}}function n_({disabled:e,label:t,lanAddress:n,value:r,onChange:i}){let a=$g(n),o=a?.split(`.`)??[``,``,``],s=e_(r),c=e=>{let t=qg(e);i(a&&t!==``?`${a}.${t}`:t)};return B(`label`,{class:`block`,children:[B(`span`,{class:`text-sm font-extrabold text-slate-800`,children:t}),B(`div`,{class:`ssh-ipv4-segments mt-2 min-h-11`,"aria-label":`${t} 입력`,children:[o.map((e,t)=>B(`div`,{class:`ssh-ipv4-segment`,children:[B(`span`,{class:`grid min-h-11 w-full min-w-0 max-w-full place-items-center rounded-xl border border-slate-200 bg-slate-100 px-1.5 py-2.5 text-center text-sm font-bold text-slate-500 sm:px-2`,children:e||`—`}),B(`span`,{"aria-hidden":`true`,class:`ssh-ipv4-separator text-sm font-black text-slate-400`,children:`.`})]},t)),B(`div`,{class:`ssh-ipv4-segment`,children:B(`input`,{"aria-label":`${t} 마지막 옥텟`,autocomplete:`off`,class:`min-h-11 w-full min-w-0 max-w-full rounded-xl border-2 border-slate-300 bg-slate-50 px-1.5 py-2.5 text-center text-sm font-semibold text-slate-950 shadow-inner outline-none transition focus:border-teal-500 focus:bg-white focus:ring-4 focus:ring-teal-100 disabled:cursor-not-allowed disabled:bg-slate-100 sm:px-2`,disabled:e||!a,inputMode:`numeric`,maxLength:3,onInput:e=>c(e.currentTarget.value),pattern:`[0-9]*`,spellcheck:!1,value:s})})]}),B(`span`,{class:`mt-2 block text-xs text-slate-500`,children:`앞 3개 주소는 공유기 IP 주소와 동일하게 유지됩니다.`})]})}function r_(e){return`${window.location.protocol}//${e}${window.location.pathname}${window.location.search}${window.location.hash}`}function i_({feedback:e,onDismiss:t}){return B(`div`,{"aria-live":`polite`,class:`mb-5 rounded-2xl border px-4 py-4 text-sm ${e.kind===`success`?`border-emerald-200 bg-emerald-50 text-emerald-900`:e.kind===`warning`?`border-amber-200 bg-amber-50 text-amber-950`:`border-red-200 bg-red-50 text-red-900`}`,children:[B(`div`,{class:`flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between`,children:[B(`p`,{class:`m-0 font-bold leading-6`,children:e.message}),B(`button`,{class:`min-h-10 shrink-0 rounded-lg border border-current bg-transparent px-3 py-1.5 text-xs font-extrabold`,onClick:t,type:`button`,children:`닫기`})]}),e.newAddress?B(`a`,{class:`mt-3 inline-flex min-h-10 items-center rounded-lg border border-current px-3 py-2 font-extrabold underline underline-offset-2`,href:r_(e.newAddress),children:[`새 공유기 주소 `,e.newAddress,`로 연결`]}):null]})}function a_({data:e}){let t=e.conflict.detected;return B(`section`,{class:`grid gap-4 lg:grid-cols-3`,"aria-label":`내부 네트워크 상태`,children:[B(`article`,{class:`rounded-2xl border border-slate-200 bg-white p-5 shadow-sm shadow-slate-900/5`,children:[B(`span`,{class:`grid size-10 place-items-center rounded-xl bg-teal-50 text-teal-700`,children:B(jt,{class:`size-5`})}),B(`p`,{class:`mt-4 mb-0 text-xs font-extrabold uppercase tracking-[0.14em] text-slate-500`,children:`SmartSafeHub LAN`}),B(`p`,{class:`mt-2 mb-0 text-xl font-black text-slate-950`,children:e.lan.subnet}),B(`p`,{class:`mt-1 mb-0 text-sm font-semibold text-slate-600`,children:[`공유기 주소 `,e.lan.address]})]}),B(`article`,{class:`rounded-2xl border border-slate-200 bg-white p-5 shadow-sm shadow-slate-900/5`,children:[B(`span`,{class:`grid size-10 place-items-center rounded-xl bg-slate-100 text-slate-700`,children:B(zt,{class:`size-5`})}),B(`p`,{class:`mt-4 mb-0 text-xs font-extrabold uppercase tracking-[0.14em] text-slate-500`,children:`상위 네트워크`}),B(`p`,{class:`mt-2 mb-0 text-xl font-black text-slate-950`,children:e.wan.subnet??`확인 전`}),B(`p`,{class:`mt-1 mb-0 text-sm font-semibold text-slate-600`,children:e.wan.connected?`WAN ${e.wan.address??`주소 확인 중`}`:`WAN 연결 후 자동으로 확인합니다.`})]}),B(`article`,{class:`rounded-2xl border p-5 shadow-sm shadow-slate-900/5 ${t?`border-red-200 bg-red-50 text-red-950`:`border-emerald-200 bg-emerald-50 text-emerald-950`}`,children:[B(`span`,{class:`grid size-10 place-items-center rounded-xl ${t?`bg-red-100 text-red-700`:`bg-emerald-100 text-emerald-700`}`,children:B(t?U:Xt,{class:`size-5`})}),B(`p`,{class:`mt-4 mb-0 text-xs font-extrabold uppercase tracking-[0.14em] opacity-70`,children:`대역 충돌`}),B(`p`,{class:`mt-2 mb-0 text-lg font-black`,children:t?`주소 대역이 겹칩니다`:`충돌이 감지되지 않았습니다`}),B(`p`,{class:`mt-1 mb-0 text-sm font-semibold leading-6 opacity-80`,children:t?`상위 네트워크 ${e.conflict.wanSubnet??``}와 다른 LAN 대역이 필요합니다.`:e.wan.connected?`현재 WAN과 LAN이 서로 다른 IPv4 대역을 사용합니다.`:`WAN이 연결되면 상위 네트워크와의 충돌 여부를 확인합니다.`})]})]})}function o_({action:e,data:t,error:n,feedback:r,loading:i,onApplyRecommendation:a,onDismissFeedback:o,onRetry:s,onSave:c}){let[l,u]=N(``),[d,f]=N(24),[p,m]=N(!0),[h,g]=N(``),[_,v]=N(``),[y,b]=N(`12h`),[x,C]=N(!1),[w,T]=N(null),E=(e={})=>{if(!t)return!1;let n=t_(t);return(e.ipAddress??l).trim()!==n.ipAddress||(e.prefixLength??d)!==n.prefixLength||(e.dhcpEnabled??p)!==n.dhcpEnabled||(e.dhcpStart??h).trim()!==n.dhcpStart||(e.dhcpEnd??_).trim()!==n.dhcpEnd||(e.leaseTime??y)!==n.leaseTime},D=e=>{let t=$g(e);if(u(e),!t){C(E({ipAddress:e}));return}let n=e_(h),r=e_(_),i=n?`${t}.${n}`:``,a=r?`${t}.${r}`:``;g(i),v(a),C(E({ipAddress:e,dhcpStart:i,dhcpEnd:a}))},O=e=>{g(e),C(E({dhcpStart:e}))},k=e=>{v(e),C(E({dhcpEnd:e}))},A=e=>{f(e),C(E({prefixLength:e}))},ee=e=>{b(e),C(E({leaseTime:e}))},j=e=>{m(e),C(E({dhcpEnabled:e}))};P(()=>{if(!t||x)return;let e=t_(t);u(e.ipAddress),f(e.prefixLength),m(e.dhcpEnabled),g(e.dhcpStart),v(e.dhcpEnd),b(e.leaseTime),T(null)},[t,x]);let te=$e(()=>{let e=[...Xg];return e.includes(d)||(e.push(d),e.sort((e,t)=>e-t)),e},[d]),ne=$e(()=>{let e=[...Zg];return e.some(([e])=>e===y)||e.push([y,`현재 설정 (${y})`]),e},[y]);if(i)return B(io,{});if(n)return B(ao,{message:n,onRetry:s});if(!t)return null;let M=e!==null,re=async e=>{if(e.preventDefault(),!Qg(l)){T(`공유기 주소를 올바른 IPv4 형식으로 입력해 주세요.`);return}if(!Qg(h)||!Qg(_)){T(`DHCP 시작/종료 주소를 올바른 IPv4 형식으로 입력해 주세요.`);return}window.confirm(`내부 네트워크 설정을 적용하면 연결된 기기가 새 DHCP 정보를 받는 동안 잠시 연결이 끊길 수 있습니다. 계속하시겠습니까?`)&&(T(null),await c({ipAddress:l.trim(),prefixLength:d,dhcpEnabled:p,dhcpStart:h.trim(),dhcpEnd:_.trim(),leaseTime:y})&&C(!1))},ie=async()=>{t.recommendation&&window.confirm(`상위 네트워크와 겹치지 않는 ${t.recommendation.subnet} 대역으로 자동 변경합니다. 현재 연결이 잠시 끊길 수 있습니다. 계속하시겠습니까?`)&&(T(null),await a()&&C(!1))};return B(S,{children:[r?B(i_,{feedback:r,onDismiss:o}):null,B(a_,{data:t}),t.conflict.detected?B(`section`,{class:`mt-5 rounded-2xl border border-amber-200 bg-amber-50 p-5 text-amber-950 sm:p-6`,children:B(`div`,{class:`flex flex-col gap-4 lg:flex-row lg:items-center lg:justify-between`,children:[B(`div`,{class:`min-w-0`,children:[B(`p`,{class:`m-0 text-xs font-extrabold uppercase tracking-[0.16em] text-amber-700`,children:`자동 충돌 해결`}),B(`h2`,{class:`mt-2 mb-0 text-lg font-black`,children:`안전한 LAN 대역으로 변경할 수 있습니다`}),B(`p`,{class:`mt-2 mb-0 text-sm font-semibold leading-6 text-amber-900/80`,children:t.recommendation?`${t.recommendation.subnet} · DHCP ${t.recommendation.dhcpStart} ~ ${t.recommendation.dhcpEnd}`:`현재 활성 네트워크와 겹치지 않는 추천 대역을 찾지 못했습니다. 아래에서 직접 설정해 주세요.`})]}),t.recommendation?B(`button`,{class:`inline-flex min-h-11 shrink-0 items-center justify-center gap-2 rounded-xl border-0 bg-amber-700 px-5 py-2.5 text-sm font-extrabold text-white transition hover:bg-amber-800 focus:outline-none focus-visible:ring-4 focus-visible:ring-amber-200 disabled:cursor-wait disabled:opacity-60`,disabled:M,onClick:()=>void ie(),type:`button`,children:[B(Xt,{class:`size-5 ${e===`auto`?`animate-pulse`:``}`}),e===`auto`?`변경 중`:`추천 대역으로 자동 변경`]}):null]})}):null,B(`form`,{class:`mt-5 rounded-2xl border border-slate-200 bg-white p-5 shadow-sm shadow-slate-900/5 sm:p-6`,onSubmit:e=>void re(e),children:[B(`div`,{class:`flex flex-col gap-4 sm:flex-row sm:items-start sm:justify-between`,children:[B(`div`,{class:`flex min-w-0 items-start gap-3`,children:[B(`span`,{class:`grid size-11 shrink-0 place-items-center rounded-xl bg-teal-50 text-teal-700`,children:B(Rt,{class:`size-6`})}),B(`div`,{class:`min-w-0`,children:[B(`p`,{class:`m-0 text-xs font-extrabold uppercase tracking-[0.16em] text-slate-500`,children:`내부 네트워크`}),B(`h2`,{class:`mt-2 mb-0 text-xl font-black text-slate-950`,children:`LAN 및 DHCP 설정`}),B(`p`,{class:`mt-2 mb-0 text-sm font-semibold leading-6 text-slate-600`,children:`상위 공유기와 다른 주소 대역을 사용해야 안정적으로 라우팅할 수 있습니다.`})]})]}),x?B(`span`,{"aria-live":`polite`,class:`inline-flex shrink-0 self-start items-center gap-1.5 rounded-full border border-amber-200 bg-amber-50 px-2.5 py-1 text-xs font-extrabold text-amber-800`,role:`status`,children:[B(U,{"aria-hidden":`true`,class:`size-3.5 shrink-0`}),`저장되지 않음`]}):null]}),B(`div`,{class:`mt-6 grid gap-5 lg:grid-cols-2`,children:[B(`div`,{class:`block`,children:[B(`span`,{class:`text-sm font-extrabold text-slate-800`,children:`공유기 IP 주소`}),B(Yg,{disabled:M,label:`공유기 IP 주소`,onChange:D,value:l})]}),B(`div`,{class:`block`,children:[B(`span`,{class:`text-sm font-extrabold text-slate-800`,children:`현재 LAN 대역`}),B(`div`,{class:`mt-2 min-h-11 rounded-xl border border-slate-200 bg-slate-50 px-4 py-3 text-sm font-bold text-slate-700`,children:t.lan.subnet}),B(`span`,{class:`mt-2 block text-xs text-slate-500`,children:`서브넷 마스크는 아래 고급 설정에서 변경할 수 있습니다.`})]}),B(n_,{disabled:M,label:`DHCP 시작 주소`,lanAddress:l,onChange:O,value:h}),B(n_,{disabled:M,label:`DHCP 종료 주소`,lanAddress:l,onChange:k,value:_})]}),B(`details`,{class:`mt-6 rounded-xl border border-slate-200 bg-slate-50 p-4`,children:[B(`summary`,{class:`cursor-pointer text-sm font-black text-slate-900`,children:`고급 DHCP 설정`}),B(`div`,{class:`mt-5 grid gap-5 lg:grid-cols-2`,children:[B(`div`,{class:`block`,children:[B(`span`,{class:`text-sm font-extrabold text-slate-800`,children:`서브넷 마스크`}),B(Vg,{ariaLabel:`서브넷 마스크`,className:`mt-2`,disabled:M,id:`lan-prefix-length`,onChange:e=>A(Number(e)),options:te.map(e=>({value:String(e),label:`/${e} · ${e===t.lan.prefixLength?t.lan.netmask:`CIDR /${e}`}`})),value:String(d),variant:`emphasized`}),B(`span`,{class:`mt-2 block text-xs text-slate-500`,children:`일반 가정용 네트워크는 /24 사용을 권장합니다.`})]}),B(`div`,{class:`block`,children:[B(`span`,{class:`text-sm font-extrabold text-slate-800`,children:`DHCP 임대 시간`}),B(Vg,{ariaLabel:`DHCP 임대 시간`,className:`mt-2`,disabled:M,id:`lan-dhcp-lease-time`,onChange:ee,options:ne.map(([e,t])=>({value:e,label:t})),value:y,variant:`emphasized`})]}),B(`label`,{class:`inline-flex min-h-11 items-center gap-3 text-sm font-extrabold text-slate-800 lg:col-span-2`,children:[B(`input`,{checked:p,class:`size-5 accent-teal-700`,disabled:M,onChange:e=>j(e.currentTarget.checked),type:`checkbox`}),`SmartSafeHub DHCP 서버 사용`]}),B(`p`,{class:`m-0 text-xs font-semibold leading-5 text-slate-500 lg:col-span-2`,children:`DHCP를 끄면 SmartSafeHub에 연결되는 장치에 IP 주소를 자동으로 할당하지 않습니다. 별도의 DHCP 서버를 사용하는 고급 구성에서만 비활성화하세요.`})]})]}),w?B(`p`,{class:`mt-5 mb-0 rounded-xl bg-red-50 px-4 py-3 text-sm font-bold text-red-800`,children:w}):null,B(`div`,{class:`mt-6 flex flex-col gap-3 border-t border-slate-200 pt-5 sm:flex-row sm:items-center sm:justify-between`,children:[B(`p`,{class:`m-0 text-xs font-semibold leading-5 text-slate-500`,children:`주소가 바뀌면 현재 관리 페이지 연결이 종료되며 새 IP를 받아 다시 접속해야 합니다.`}),B(`button`,{class:`inline-flex min-h-11 w-full shrink-0 items-center justify-center gap-2 rounded-xl border-0 bg-teal-700 px-5 py-2.5 text-sm font-extrabold text-white shadow-sm transition hover:bg-teal-800 focus:outline-none focus-visible:ring-4 focus-visible:ring-teal-200 disabled:cursor-wait disabled:opacity-60 sm:w-auto`,disabled:M||!x,type:`submit`,children:[B(Xt,{class:`size-5 ${e===`saving`?`animate-pulse`:``}`}),e===`saving`?`저장 중`:`설정 저장`]})]})]})]})}var s_=[`dhcp`,`pppoe`,`static`],c_=`1.1.1.1`,l_=Array.from({length:33},(e,t)=>t);function u_(e){return s_.includes(e)}function d_(e){switch(e){case`dhcp`:return`자동 IP (DHCP)`;case`pppoe`:return`PPPoE`;case`static`:return`고정 IPv4`;default:return e?e.toUpperCase():`확인 전`}}function f_(e){return{protocol:e.configuration.protocol,pppoeUsername:e.configuration.pppoe.username,pppoePassword:``,staticAddress:e.configuration.static.address??``,staticPrefixLength:e.configuration.static.prefixLength??24,staticGateway:e.configuration.static.gateway??``,dnsPrimary:e.configuration.static.dns[0]??``,dnsSecondary:e.configuration.static.dns[1]??``}}function p_(e){return e.trim()}function m_(e,t){let n=f_(t);return e.protocol===n.protocol?e.protocol===`dhcp`||!u_(e.protocol)?!1:e.protocol===`pppoe`?p_(e.pppoeUsername)!==n.pppoeUsername||e.pppoePassword.length>0:p_(e.staticAddress)!==n.staticAddress||e.staticPrefixLength!==n.staticPrefixLength||p_(e.staticGateway)!==n.staticGateway||p_(e.dnsPrimary)!==n.dnsPrimary||p_(e.dnsSecondary)!==n.dnsSecondary:!0}function h_(e){let t=e.trim().split(`.`);return t.length===4&&t.every(e=>{if(!/^(0|[1-9][0-9]{0,2})$/.test(e))return!1;let t=Number(e);return t>=0&&t<=255})}function g_(e){let t=e;return Array.from({length:4},()=>{if(t>=8)return t-=8,255;if(t<=0)return 0;let e=256-2**(8-t);return t=0,e}).join(`.`)}function __(e){if(!Number.isFinite(e)||e<=0)return`연결 시간 확인 전`;let t=Math.floor(e/86400),n=Math.floor(e%86400/3600),r=Math.floor(e%3600/60);return t>0?`${t}일 ${n}시간 연결됨`:n>0?`${n}시간 ${r}분 연결됨`:`${Math.max(1,r)}분 연결됨`}function v_({feedback:e,onDismiss:t}){return B(`div`,{"aria-live":`polite`,class:`mb-5 rounded-2xl border px-4 py-4 text-sm ${e.kind===`success`?`border-emerald-200 bg-emerald-50 text-emerald-900`:e.kind===`warning`?`border-amber-200 bg-amber-50 text-amber-950`:`border-red-200 bg-red-50 text-red-900`}`,children:B(`div`,{class:`flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between`,children:[B(`p`,{class:`m-0 font-bold leading-6`,children:e.message}),B(`button`,{class:`min-h-10 shrink-0 rounded-lg border border-current bg-transparent px-3 py-1.5 text-xs font-extrabold`,onClick:t,type:`button`,children:`닫기`})]})})}function y_({data:e,busy:t,onReconnect:n}){let r=e.status,i=r.connected;return B(`section`,{class:`grid gap-4 lg:grid-cols-3`,"aria-label":`인터넷 연결 상태`,children:[B(`article`,{class:`rounded-2xl border p-5 shadow-sm shadow-slate-900/5 ${i?`border-emerald-200 bg-emerald-50 text-emerald-950`:`border-amber-200 bg-amber-50 text-amber-950`}`,children:[B(`div`,{class:`flex items-start justify-between gap-3`,children:[B(`span`,{class:`grid size-10 place-items-center rounded-xl ${i?`bg-emerald-100 text-emerald-700`:`bg-amber-100 text-amber-700`}`,children:B(i?Xt:U,{class:`size-5`})}),B(`button`,{class:`inline-flex min-h-10 items-center justify-center gap-2 rounded-xl border border-current bg-transparent px-3 py-2 text-xs font-extrabold transition disabled:cursor-wait disabled:opacity-60`,disabled:t,onClick:n,type:`button`,children:[B(H,{class:`size-4 ${t?`animate-spin`:``}`}),`재연결`]})]}),B(`p`,{class:`mt-4 mb-0 text-xs font-extrabold uppercase tracking-[0.14em] opacity-70`,children:`인터넷 상태`}),B(`p`,{class:`mt-2 mb-0 text-xl font-black`,children:r.pending?`연결 중`:i?`연결됨`:`연결 안 됨`}),B(`p`,{class:`mt-1 mb-0 text-sm font-semibold leading-6 opacity-80`,children:[d_(r.protocol??e.configuration.protocol),` · `,__(r.uptimeSeconds)]})]}),B(`article`,{class:`rounded-2xl border border-slate-200 bg-white p-5 shadow-sm shadow-slate-900/5`,children:[B(`span`,{class:`grid size-10 place-items-center rounded-xl bg-teal-50 text-teal-700`,children:B(zt,{class:`size-5`})}),B(`p`,{class:`mt-4 mb-0 text-xs font-extrabold uppercase tracking-[0.14em] text-slate-500`,children:`WAN IPv4`}),B(`p`,{class:`mt-2 mb-0 break-all text-xl font-black text-slate-950`,children:r.address?`${r.address}${r.prefixLength===null?``:`/${r.prefixLength}`}`:`주소 없음`}),B(`p`,{class:`mt-1 mb-0 text-sm font-semibold text-slate-600`,children:r.device?`인터페이스 ${r.device}`:`인터페이스 확인 전`})]}),B(`article`,{class:`rounded-2xl border border-slate-200 bg-white p-5 shadow-sm shadow-slate-900/5`,children:[B(`span`,{class:`grid size-10 place-items-center rounded-xl bg-slate-100 text-slate-700`,children:B(jt,{class:`size-5`})}),B(`p`,{class:`mt-4 mb-0 text-xs font-extrabold uppercase tracking-[0.14em] text-slate-500`,children:`Gateway · DNS`}),B(`p`,{class:`mt-2 mb-0 break-all text-base font-black text-slate-950`,children:r.gateway??`Gateway 확인 전`}),B(`p`,{class:`mt-1 mb-0 break-all text-sm font-semibold leading-6 text-slate-600`,children:r.dns.length>0?r.dns.join(` · `):`DNS 확인 전`})]})]})}function b_({action:e,data:t,error:n,feedback:r,loading:i,onDismissFeedback:a,onReconnect:o,onRetry:s,onSave:c}){let[l,u]=N({protocol:`dhcp`,pppoeUsername:``,pppoePassword:``,staticAddress:``,staticPrefixLength:24,staticGateway:``,dnsPrimary:``,dnsSecondary:``}),[d,f]=N(!1),[p,m]=N(!1),[h,g]=N(null);P(()=>{!t||d||(u(f_(t)),g(null))},[t,d]);let _=$e(()=>{let e=[{value:`dhcp`,label:`자동 IP (DHCP)`},{value:`pppoe`,label:`PPPoE`},{value:`static`,label:`고정 IPv4`}];return t&&!t.configuration.supported&&e.unshift({value:t.configuration.protocol,label:`현재 설정 (${t.configuration.protocol})`}),e},[t]);if(i)return B(io,{});if(n)return B(ao,{message:n,onRetry:s});if(!t)return null;let v=e!==null,y=e=>{u(n=>{let r={...n,...e};return f(m_(r,t)),r}),g(null)},b=async e=>{if(e.preventDefault(),!u_(l.protocol)){g(`DHCP, PPPoE 또는 고정 IPv4 중 하나를 선택해 주세요.`);return}if(l.protocol===`pppoe`){if(!p_(l.pppoeUsername)){g(`PPPoE 사용자명을 입력해 주세요.`);return}if((t.configuration.protocol!==`pppoe`||!t.configuration.pppoe.passwordConfigured)&&l.pppoePassword.length===0){g(`PPPoE 연결을 시작하려면 비밀번호를 입력해 주세요.`);return}}if(l.protocol===`static`){if(!h_(l.staticAddress)){g(`고정 IPv4 주소를 올바르게 입력해 주세요.`);return}if(!h_(l.staticGateway)){g(`기본 게이트웨이를 올바르게 입력해 주세요.`);return}if(!h_(l.dnsPrimary)){g(`기본 DNS 서버를 올바르게 입력해 주세요.`);return}if(p_(l.dnsSecondary)&&!h_(l.dnsSecondary)){g(`보조 DNS 서버를 올바르게 입력해 주세요.`);return}}window.confirm(`인터넷 연결 설정을 적용하면 WAN 연결이 다시 시작되어 인터넷이 잠시 끊길 수 있습니다. 계속하시겠습니까?`)&&await c({protocol:l.protocol,pppoeUsername:p_(l.pppoeUsername),pppoePassword:l.pppoePassword,pppoePasswordChanged:l.pppoePassword.length>0,staticAddress:p_(l.staticAddress),staticPrefixLength:l.staticPrefixLength,staticGateway:p_(l.staticGateway),dnsPrimary:p_(l.dnsPrimary),dnsSecondary:p_(l.dnsSecondary)})&&(u(e=>({...e,pppoePassword:``})),f(!1))};return B(S,{children:[r?B(v_,{feedback:r,onDismiss:a}):null,B(y_,{data:t,busy:v,onReconnect:()=>{window.confirm(`WAN 연결을 다시 시작합니다. 인터넷이 잠시 끊길 수 있습니다. 계속하시겠습니까?`)&&o()}}),t.configuration.supported?null:B(`section`,{class:`mt-5 rounded-2xl border border-amber-200 bg-amber-50 p-5 text-amber-950 sm:p-6`,children:B(`div`,{class:`flex items-start gap-3`,children:[B(U,{class:`mt-0.5 size-5 shrink-0 text-amber-700`}),B(`div`,{children:[B(`h2`,{class:`m-0 text-base font-black`,children:`현재 WAN 방식은 직접 관리하지 않습니다`}),B(`p`,{class:`mt-2 mb-0 text-sm font-semibold leading-6 text-amber-900/80`,children:[`현재 설정은 `,t.configuration.protocol,`입니다. 아래에서 DHCP, PPPoE 또는 고정 IPv4를 선택해 저장하면 해당 방식으로 전환합니다.`]})]})]})}),B(`form`,{class:`mt-5 rounded-2xl border border-slate-200 bg-white p-5 shadow-sm shadow-slate-900/5 sm:p-6`,onSubmit:e=>void b(e),children:[B(`div`,{class:`flex flex-col gap-4 sm:flex-row sm:items-start sm:justify-between`,children:[B(`div`,{class:`flex min-w-0 items-start gap-3`,children:[B(`span`,{class:`grid size-11 shrink-0 place-items-center rounded-xl bg-teal-50 text-teal-700`,children:B(zt,{class:`size-6`})}),B(`div`,{class:`min-w-0`,children:[B(`p`,{class:`m-0 text-xs font-extrabold uppercase tracking-[0.16em] text-slate-500`,children:`Internet`}),B(`h2`,{class:`mt-2 mb-0 text-xl font-black text-slate-950`,children:`인터넷 연결 설정`}),B(`p`,{class:`mt-2 mb-0 text-sm font-semibold leading-6 text-slate-600`,children:`통신사 또는 상위 네트워크 환경에 맞는 WAN 연결 방식을 선택합니다.`})]})]}),d?B(`span`,{"aria-live":`polite`,class:`inline-flex shrink-0 self-start items-center gap-1.5 rounded-full border border-amber-200 bg-amber-50 px-2.5 py-1 text-xs font-extrabold text-amber-800`,role:`status`,children:[B(U,{"aria-hidden":`true`,class:`size-3.5 shrink-0`}),`저장되지 않음`]}):null]}),B(`div`,{class:`mt-6`,children:[B(`span`,{class:`text-sm font-extrabold text-slate-800`,children:`연결 방식`}),B(Vg,{ariaLabel:`WAN 연결 방식`,className:`mt-2 max-w-xl`,disabled:v,id:`wan-protocol`,onChange:e=>y(e===`static`&&!p_(l.dnsSecondary)?{protocol:e,dnsSecondary:c_}:{protocol:e}),options:_,value:l.protocol,variant:`emphasized`}),B(`span`,{class:`mt-2 block text-xs font-semibold leading-5 text-slate-500`,children:`대부분의 가정용 인터넷과 상위 공유기 연결은 자동 IP(DHCP)를 사용합니다.`})]}),l.protocol===`pppoe`?B(`div`,{class:`mt-6 grid gap-5 lg:grid-cols-2`,children:[B(`label`,{class:`block`,children:[B(`span`,{class:`text-sm font-extrabold text-slate-800`,children:`PPPoE 사용자명`}),B(`input`,{autocomplete:`username`,class:`mt-2 min-h-11 w-full rounded-xl border-2 border-slate-300 bg-slate-50 px-4 py-2.5 text-sm font-semibold text-slate-950 shadow-inner outline-none transition focus:border-teal-500 focus:bg-white focus:ring-4 focus:ring-teal-100 disabled:cursor-not-allowed disabled:bg-slate-100`,disabled:v,onInput:e=>y({pppoeUsername:e.currentTarget.value}),spellcheck:!1,value:l.pppoeUsername})]}),B(`label`,{class:`block`,children:[B(`span`,{class:`text-sm font-extrabold text-slate-800`,children:`PPPoE 비밀번호`}),B(`span`,{class:`relative mt-2 block`,children:[B(`input`,{autocomplete:`new-password`,class:`min-h-11 w-full rounded-xl border-2 border-slate-300 bg-slate-50 px-4 py-2.5 pr-12 text-sm font-semibold text-slate-950 shadow-inner outline-none transition focus:border-teal-500 focus:bg-white focus:ring-4 focus:ring-teal-100 disabled:cursor-not-allowed disabled:bg-slate-100`,disabled:v,onInput:e=>y({pppoePassword:e.currentTarget.value}),placeholder:t.configuration.protocol===`pppoe`&&t.configuration.pppoe.passwordConfigured?`변경할 때만 입력`:`PPPoE 비밀번호`,type:p?`text`:`password`,value:l.pppoePassword}),B(`button`,{"aria-label":p?`비밀번호 숨기기`:`비밀번호 표시`,class:`absolute inset-y-0 right-1 grid w-10 place-items-center rounded-lg border-0 bg-transparent text-slate-500`,disabled:v,onClick:()=>m(e=>!e),type:`button`,children:B(p?Jt:qt,{class:`size-5`})})]}),B(`span`,{class:`mt-2 block text-xs text-slate-500`,children:t.configuration.protocol===`pppoe`&&t.configuration.pppoe.passwordConfigured?`비워 두면 현재 저장된 비밀번호를 그대로 사용합니다.`:`통신사에서 제공한 PPPoE 비밀번호를 입력해 주세요.`})]})]}):null,l.protocol===`static`?B(`div`,{class:`mt-6 grid gap-5 lg:grid-cols-2`,children:[B(`label`,{class:`block`,children:[B(`span`,{class:`text-sm font-extrabold text-slate-800`,children:`IPv4 주소`}),B(Yg,{disabled:v,label:`IPv4 주소`,onChange:e=>y({staticAddress:e}),value:l.staticAddress})]}),B(`div`,{class:`block`,children:[B(`span`,{class:`text-sm font-extrabold text-slate-800`,children:`서브넷 마스크`}),B(Vg,{ariaLabel:`WAN 서브넷 마스크`,className:`mt-2`,disabled:v,id:`wan-static-prefix-length`,onChange:e=>y({staticPrefixLength:Number(e)}),options:l_.map(e=>({value:String(e),label:`/${e} · ${g_(e)}`})),value:String(l.staticPrefixLength),variant:`emphasized`})]}),B(`label`,{class:`block`,children:[B(`span`,{class:`text-sm font-extrabold text-slate-800`,children:`기본 게이트웨이`}),B(Yg,{disabled:v,label:`기본 게이트웨이`,onChange:e=>y({staticGateway:e}),value:l.staticGateway})]}),B(`label`,{class:`block`,children:[B(`span`,{class:`text-sm font-extrabold text-slate-800`,children:`기본 DNS`}),B(Yg,{disabled:v,label:`기본 DNS`,onChange:e=>y({dnsPrimary:e}),value:l.dnsPrimary})]}),B(`label`,{class:`block lg:col-start-2`,children:[B(`span`,{class:`text-sm font-extrabold text-slate-800`,children:`보조 DNS (선택)`}),B(Yg,{disabled:v,label:`보조 DNS`,onChange:e=>y({dnsSecondary:e}),value:l.dnsSecondary})]})]}):null,l.protocol===`dhcp`?B(`div`,{class:`mt-6 rounded-xl border border-slate-200 bg-slate-50 px-4 py-4 text-sm font-semibold leading-6 text-slate-600`,children:`상위 공유기 또는 통신사 장비에서 IP 주소, 기본 게이트웨이와 DNS 정보를 자동으로 받습니다. 별도의 계정이나 고정 주소가 없다면 이 방식을 사용하세요.`}):null,h?B(`p`,{class:`mt-5 mb-0 rounded-xl bg-red-50 px-4 py-3 text-sm font-bold text-red-800`,children:h}):null,B(`div`,{class:`mt-6 flex flex-col gap-3 border-t border-slate-200 pt-5 sm:flex-row sm:items-center sm:justify-between`,children:[B(`p`,{class:`m-0 text-xs font-semibold leading-5 text-slate-500`,children:`설정 저장 후 WAN만 다시 연결하며 LAN 관리 페이지와 내부 네트워크 설정은 유지됩니다.`}),B(`button`,{class:`inline-flex min-h-11 w-full shrink-0 items-center justify-center gap-2 rounded-xl border-0 bg-teal-700 px-5 py-2.5 text-sm font-extrabold text-white shadow-sm transition hover:bg-teal-800 focus:outline-none focus-visible:ring-4 focus-visible:ring-teal-200 disabled:cursor-wait disabled:opacity-60 sm:w-auto`,disabled:v||!d,type:`submit`,children:[B(Xt,{class:`size-5 ${e===`saving`?`animate-pulse`:``}`}),e===`saving`?`저장 중`:`설정 저장`]})]})]})]})}var x_=3,S_=10;function C_(e,t){return e<=0?`0.0%`:`${(t/e*100).toFixed(1)}%`}function w_(e){return e.id===`other`?`기타 기기`:e.hostname?e.hostname:e.identified?`이름 없는 기기`:`미식별 기기`}function T_(e){return[...e].sort((e,t)=>e.id===`other`?1:t.id===`other`?-1:t.blocked-e.blocked||t.queries-e.queries||w_(e).localeCompare(w_(t),`ko`))}function E_({devices:e,deviceLimit:t,truncated:n}){let r=T_(e),[i,a]=N(!1),[o,s]=N(1),c=Math.max(1,Math.ceil(r.length/S_)),l=Math.min(o,c),u=(l-1)*S_,d=Math.min(u+S_,r.length),f=i?r.slice(u,d):r.slice(0,x_),p=r.length>x_;return P(()=>{s(e=>Math.min(e,c))},[c]),B(`div`,{class:`mt-6 rounded-2xl border border-slate-100 bg-slate-50/70 p-4 sm:p-5`,children:[B(`div`,{class:`flex flex-wrap items-start justify-between gap-3`,children:[B(`div`,{children:[B(`div`,{class:`flex flex-wrap items-center gap-2`,children:[B(`p`,{class:`m-0 text-xs font-bold text-slate-500`,children:`기기별 통계`}),p&&!i?B(`span`,{class:`inline-flex items-center rounded-full bg-teal-50 px-2 py-1 text-[10px] font-extrabold tracking-wide text-teal-700 ring-1 ring-teal-100`,children:`차단 TOP 3`}):null]}),B(`h3`,{class:`mt-1 mb-0 text-base font-extrabold text-slate-950`,children:`어떤 기기에서 차단되었는지 확인`}),B(`p`,{class:`mt-2 mb-0 text-xs leading-5 text-slate-500`,children:`DHCP 정보가 있는 기기는 MAC 주소를 기준으로 식별하며, 기기별 숫자만 현재 부팅 세션 동안 메모리에 집계합니다.`})]}),B(`div`,{class:`flex flex-wrap items-center justify-end gap-2`,children:[B(`span`,{class:`inline-flex items-center gap-2 rounded-full bg-white px-3 py-1.5 text-xs font-extrabold text-slate-600 ring-1 ring-slate-200`,children:[B(Mt,{class:`size-4 text-teal-700`}),q(r.length),`개 항목`]}),p?B(`button`,{"aria-controls":`safeshield-device-statistics-list`,"aria-expanded":i,class:`rounded-full bg-white px-3 py-1.5 text-xs font-extrabold text-teal-700 ring-1 ring-slate-200 transition hover:bg-slate-50`,onClick:()=>{a(e=>!e),s(1)},type:`button`,children:i?`간단히 보기 ↑`:`전체 ${q(r.length)}개 기기 보기 ↓`}):null]})]}),r.length===0?B(`p`,{class:`mt-4 mb-0 rounded-xl bg-white p-4 text-sm leading-6 text-slate-500 ring-1 ring-slate-100`,children:`아직 기기별 DNS 통계가 없습니다. 클라이언트에서 DNS 요청이 발생하면 다음 통계 갱신 시 표시됩니다.`}):B(`div`,{class:`mt-4 grid gap-3`,id:`safeshield-device-statistics-list`,children:f.map(e=>B(`article`,{class:`grid gap-4 rounded-xl bg-white p-4 ring-1 ring-slate-100 sm:grid-cols-[minmax(0,1fr)_auto] sm:items-center`,children:[B(`div`,{class:`min-w-0`,children:B(`div`,{class:`flex min-w-0 flex-wrap items-center gap-2`,children:[B(`span`,{class:`grid size-9 shrink-0 place-items-center rounded-lg bg-teal-50 text-teal-700`,children:B(Mt,{class:`size-4`})}),B(`div`,{class:`min-w-0`,children:[B(`h4`,{class:`m-0 truncate text-sm font-extrabold text-slate-950`,children:w_(e)}),B(`p`,{class:`mt-1 mb-0 break-all text-xs text-slate-500`,children:[e.ip||`IP 미확인`,e.mac?` · ${e.mac}`:``]})]}),B(`span`,{class:`rounded-full px-2 py-1 text-[11px] font-extrabold ${e.identified?`bg-emerald-50 text-emerald-700`:`bg-slate-100 text-slate-600`}`,children:e.id===`other`?`합산`:e.identified?`DHCP 식별`:`IP 임시 식별`})]})}),B(`dl`,{class:`m-0 grid grid-cols-3 gap-2 text-right`,children:[B(`div`,{class:`min-w-20`,children:[B(`dt`,{class:`text-[11px] font-bold text-slate-400`,children:`DNS 요청`}),B(`dd`,{class:`mt-1 mb-0 ml-0 text-sm font-extrabold text-slate-900`,children:q(e.queries)})]}),B(`div`,{class:`min-w-20`,children:[B(`dt`,{class:`text-[11px] font-bold text-slate-400`,children:`차단`}),B(`dd`,{class:`mt-1 mb-0 ml-0 text-sm font-extrabold text-teal-700`,children:q(e.blocked)})]}),B(`div`,{class:`min-w-20`,children:[B(`dt`,{class:`text-[11px] font-bold text-slate-400`,children:`차단율`}),B(`dd`,{class:`mt-1 mb-0 ml-0 text-sm font-extrabold text-slate-900`,children:C_(e.queries,e.blocked)})]})]})]},e.id))}),p&&!i?B(`p`,{class:`mt-3 mb-0 text-xs font-semibold leading-5 text-slate-500`,children:[`전체 `,q(r.length),`개 기기 중 차단 수 기준 상위 `,x_,`개를 표시하고 있습니다.`]}):null,i&&r.length>S_?B(`nav`,{"aria-label":`기기별 통계 페이지`,class:`mt-4 flex flex-wrap items-center justify-between gap-3`,children:[B(`p`,{class:`m-0 text-xs font-semibold text-slate-500`,children:[q(u+1),`–`,q(d),` /`,` `,q(r.length),`개`]}),B(`div`,{class:`flex items-center gap-2`,children:[B(`button`,{class:`rounded-lg bg-white px-3 py-2 text-xs font-extrabold text-slate-700 ring-1 ring-slate-200 transition hover:bg-slate-50 disabled:cursor-not-allowed disabled:opacity-50`,disabled:l<=1,onClick:()=>s(e=>Math.max(1,e-1)),type:`button`,children:`이전`}),B(`span`,{"aria-current":`page`,class:`min-w-20 text-center text-xs font-extrabold text-slate-600`,children:[q(l),` / `,q(c)]}),B(`button`,{class:`rounded-lg bg-white px-3 py-2 text-xs font-extrabold text-slate-700 ring-1 ring-slate-200 transition hover:bg-slate-50 disabled:cursor-not-allowed disabled:opacity-50`,disabled:l>=c,onClick:()=>s(e=>Math.min(c,e+1)),type:`button`,children:`다음`})]})]}):null,n?B(`p`,{class:`mt-4 mb-0 rounded-xl border border-amber-200 bg-amber-50 p-3 text-xs font-semibold leading-5 text-amber-800`,children:[`개별 통계는 최대 `,q(t),`개 기기까지 추적합니다. 한도를 초과한 기기의 요청은 기타 기기로 합산됩니다.`]}):null]})}var D_=3600,O_=24;function k_(e,t){return e<=0?`0.0%`:`${(t/e*100).toFixed(1)}%`}function A_(e){let t=e.hourly[e.hourly.length-1];if(t?.bucketStart)return t.bucketStart;let n=e.updatedAt>0?e.updatedAt:Math.floor(Date.now()/1e3);return Math.floor(n/D_)*D_}function j_(e){let t=new Map(e.hourly.map(e=>[e.bucketStart,e])),n=A_(e)-23*D_;return Array.from({length:O_},(e,r)=>{let i=n+r*D_;return t.get(i)??{bucketStart:i,queries:0,blocked:0}})}function M_({emphasized:e=!1,label:t,value:n}){return B(`div`,{class:`rounded-xl border border-slate-100 bg-slate-50 p-4 sm:p-5`,children:[B(`dt`,{class:`text-[0.68rem] font-black uppercase tracking-[0.12em] text-slate-400`,children:t}),B(`dd`,{class:`mt-2 mb-0 ml-0 text-2xl font-black tracking-tight ${e?`text-teal-700`:`text-slate-950`}`,children:n})]})}function N_({action:e,data:t,error:n,loading:r,onRetry:i,onSetEnabled:a,refreshing:o}){if(r&&t===null)return B(`section`,{class:`mt-5 rounded-2xl border border-slate-200 bg-white p-5 shadow-sm shadow-slate-900/5 sm:p-6`,children:B(`p`,{class:`m-0 text-sm font-bold text-slate-500`,children:`차단 통계를 불러오는 중입니다…`})});if(n&&t===null)return B(`section`,{class:`mt-5 rounded-2xl border border-amber-200 bg-amber-50 p-5 sm:p-6`,children:[B(`p`,{class:`m-0 text-sm font-extrabold text-amber-950`,children:`차단 통계를 불러오지 못했습니다.`}),B(`p`,{class:`mt-2 mb-0 text-xs leading-5 text-amber-800`,children:n}),B(`button`,{class:`mt-4 inline-flex min-h-9 items-center justify-center rounded-xl border border-amber-300 bg-white px-3 py-2 text-xs font-extrabold text-amber-900 transition hover:bg-amber-100 focus:outline-none focus-visible:ring-4 focus-visible:ring-amber-100`,onClick:i,type:`button`,children:`다시 시도`})]});if(!t)return B(`section`,{class:`mt-5 rounded-2xl border border-slate-200 bg-white p-5 shadow-sm shadow-slate-900/5 sm:p-6`,children:[B(`p`,{class:`m-0 text-xs font-bold uppercase tracking-[0.16em] text-slate-500`,children:`Activity`}),B(`h2`,{class:`mt-3 mb-0 text-xl font-extrabold text-slate-950`,children:`보호 활동`}),B(`p`,{class:`mt-3 mb-0 text-sm leading-6 text-slate-600`,children:`현재 SafeShield에서 통계 데이터를 제공하지 않습니다. SafeShield 0.3.15 버전 이상이 설치되어 있고, 통계 수집이 활성화되어 있는지 확인해 주세요.`})]});let s=j_(t),c=s[s.length-1],l=s.reduce((e,t)=>({queries:e.queries+t.queries,blocked:e.blocked+t.blocked}),{queries:0,blocked:0}),u=e===`statistics-enable`||e===`statistics-disable`,d=e===`statistics-enable`||e!==`statistics-disable`&&t.enabled,f=u?d?`활성화하는 중…`:`비활성화하는 중…`:t.enabled?t.collectorRunning?`활성화 · 수집 중`:`활성화 · 시작 중`:`비활성화`;return B(`section`,{"aria-busy":u,class:`mt-5 rounded-2xl border border-slate-200 bg-white p-5 shadow-sm shadow-slate-900/5 sm:p-6 ${u?`cursor-wait`:``}`,children:[B(`div`,{class:`flex flex-wrap items-start justify-between gap-4`,children:[B(`div`,{children:[B(`p`,{class:`m-0 text-[0.68rem] font-black uppercase tracking-[0.18em] text-teal-700`,children:`Activity`}),B(`h2`,{class:`mt-2 mb-0 text-xl font-black tracking-tight text-slate-950`,children:`최근 24시간 보호 활동`}),B(`p`,{class:`mt-2 mb-0 text-sm leading-6 text-slate-500`,children:`DNS 요청 원본은 저장하지 않고 숫자만 로컬 메모리에 집계합니다.`})]}),B(`div`,{class:`flex items-center gap-3 rounded-xl border border-slate-100 bg-slate-50 px-3 py-2.5`,children:[B(`span`,{class:`grid size-9 place-items-center rounded-lg bg-slate-100 text-slate-500`,children:B(Gt,{class:`size-5`})}),B(`div`,{class:`text-right`,children:[B(`p`,{class:`m-0 text-[0.68rem] font-bold text-slate-400`,children:`통계 수집`}),B(`p`,{class:`mt-1 mb-0 text-xs font-extrabold ${u||d?`text-emerald-700`:`text-slate-500`}`,role:`status`,children:f})]}),B(`button`,{"aria-checked":d,"aria-label":d?`차단 통계 수집 끄기`:`차단 통계 수집 켜기`,class:`ssh-switch-control relative inline-flex shrink-0 items-center rounded-full border-0 p-0 transition focus:outline-none focus-visible:ring-4 focus-visible:ring-teal-100 ${u?`cursor-wait opacity-80`:`disabled:cursor-not-allowed disabled:opacity-50`} ${d?`bg-teal-600`:`bg-slate-300`}`,disabled:e!==null,onClick:()=>a(!t.enabled),role:`switch`,type:`button`,children:B(`span`,{"aria-hidden":`true`,class:`ssh-switch-thumb absolute top-1 grid place-items-center shadow-sm transition-all ${d?`left-6`:`left-1`}`,children:u?B(H,{"aria-hidden":`true`,class:`size-3 animate-spin text-teal-600`}):null})})]})]}),t.enabled?null:B(`div`,{class:`mt-5 rounded-xl border border-slate-200 bg-slate-50 px-4 py-3 text-sm leading-6 text-slate-600`,children:`통계 수집이 꺼져 있습니다. 활성화하면 DNS 요청 원본은 저장하지 않고 요청 수와 차단 수만 로컬 메모리에 집계합니다.`}),B(`dl`,{class:`mt-6 grid gap-3 sm:grid-cols-2 xl:grid-cols-4`,children:[B(M_,{label:`최근 24시간 DNS 요청`,value:q(l.queries)}),B(M_,{emphasized:!0,label:`최근 24시간 차단`,value:q(l.blocked)}),B(M_,{label:`최근 24시간 차단율`,value:k_(l.queries,l.blocked)}),B(M_,{label:`현재 시간 차단`,value:q(c?.blocked??0)})]}),B(`div`,{class:`mt-5 rounded-2xl border border-slate-100 bg-slate-50/70 p-4 sm:p-5`,children:[B(`div`,{class:`flex flex-wrap items-end justify-between gap-3`,children:[B(`div`,{children:[B(`p`,{class:`m-0 text-xs font-bold text-slate-500`,children:`최근 24시간`}),B(`h3`,{class:`mt-1 mb-0 text-base font-extrabold text-slate-950`,children:`시간대별 차단 요청`})]}),B(`span`,{class:`text-xs font-bold text-slate-500`,children:o?`갱신 중…`:`마지막 집계 ${Fa(t.updatedAt)}`})]}),B(zh,{buckets:s})]}),B(E_,{deviceLimit:t.deviceLimit,devices:t.devices,truncated:t.devicesTruncated}),B(`div`,{class:`mt-5 flex flex-wrap gap-x-5 gap-y-2 border-t border-slate-100 pt-4 text-xs leading-5 text-slate-500`,children:[B(`span`,{children:[`수집 누적 DNS 요청 `,q(t.totals.queries)]}),B(`span`,{children:[`수집 누적 차단 `,q(t.totals.blocked)]}),B(`span`,{children:[`수집 시작 `,Fa(t.startedAt)]}),B(`span`,{children:[`보존 `,q(t.retentionHours),`시간`]}),t.volatile?B(`span`,{children:`재부팅 시 초기화되는 메모리 통계`}):null]}),n?B(`p`,{class:`mt-3 mb-0 text-xs font-bold text-amber-700`,children:`최근 자동 갱신에 실패했습니다. 현재 표시된 마지막 정상 통계를 유지합니다.`}):null]})}var P_=`https://www.smartsafehub.com/pricing/`;function F_({value:e,trueLabel:t=`정상`,falseLabel:n=`확인 필요`}){return B(`span`,{class:`inline-flex items-center gap-2 text-sm font-extrabold ${e?`text-emerald-700`:`text-slate-500`}`,children:[B(`span`,{class:`size-2 rounded-full ${e?`bg-emerald-500`:`bg-slate-300`}`}),e?t:n]})}function I_(e){return!e.enabled||e.status===`disabled`?`disabled`:e.status===`running`?`refreshing`:e.status===`error`||e.health.overall===`error`||e.issueCounts.errors>0?`error`:e.status===`paused`?`paused`:e.active&&e.runtime.dnsmasqRunning&&e.runtime.dnsRuntimeOk?`protecting`:`attention`}function L_(e){return!e.enabled||e.status===`disabled`?`비활성화`:e.active&&e.runtime.dnsmasqRunning&&e.runtime.dnsRuntimeOk?`보호 중`:e.status===`paused`?`일시 중지`:`확인 필요`}function R_(e){let t=I_(e);return t===`error`&&L_(e)===`보호 중`&&e.runtime.lastErrorCode?`갱신 실패`:{disabled:`비활성화`,refreshing:`갱신 중`,protecting:`보호 중`,paused:`일시 중지`,error:`오류`,attention:`확인 필요`}[t]}function z_(e){let t=I_(e);return t===`protecting`?e.blocklist.validLineCount>0?`${q(e.blocklist.validLineCount)}개 도메인 차단 규칙으로 DNS를 보호하고 있습니다.`:e.blocklist.installed?`차단 목록이 설치되어 있으며 DNS 보호가 정상적으로 동작하고 있습니다.`:`SafeShield 서비스와 DNS 런타임이 정상적으로 동작하고 있습니다.`:t===`refreshing`?`차단 목록을 최신 상태로 갱신하고 있습니다.`:t===`disabled`?`SafeShield DNS 보호가 비활성화되어 있습니다.`:t===`paused`?`SafeShield 작업이 일시 중지되어 있습니다.`:t===`error`?L_(e)===`보호 중`?`기존 DNS 보호는 유지되고 있지만 최근 차단 목록 갱신을 완료하지 못했습니다.`:`SafeShield 보호 상태에 문제가 발생했습니다. 아래 오류 내용을 확인해 주세요.`:e.active?e.runtime.dnsmasqRunning?e.runtime.dnsRuntimeOk?e.summary.message:`SafeShield DNS 런타임 상태를 확인해야 합니다.`:`dnsmasq가 실행 중이 아니어서 DNS 보호 상태를 확인해야 합니다.`:`SafeShield가 활성화되어 있지만 서비스가 실행 중이 아닙니다.`}function B_(e){return{ok:`정상`,warning:`경고`,error:`오류`,unavailable:`사용 불가`}[e]??e}function V_({data:e}){let t=I_(e);return B(`span`,{class:`inline-flex items-center rounded-full px-3 py-1.5 text-xs font-extrabold ring-1 ring-inset ${t===`error`?`bg-red-50 text-red-700 ring-red-200`:t===`disabled`?`bg-slate-100 text-slate-700 ring-slate-200`:t===`refreshing`?`bg-blue-50 text-blue-700 ring-blue-200`:t===`paused`||t===`attention`?`bg-amber-50 text-amber-800 ring-amber-200`:`bg-emerald-50 text-emerald-700 ring-emerald-200`}`,children:R_(e)})}function H_({failed:e,step:t,total:n}){let r=2*Math.PI*17,i=r*.22,a=r-i;return B(`span`,{"aria-label":e?`갱신 실패 · ${t}/${n} 단계`:`갱신 ${t}/${n} 단계`,class:`ssh-safeshield-refresh-donut`,"data-state":e?`error`:`active`,role:`progressbar`,"aria-valuemin":0,"aria-valuemax":n,"aria-valuenow":t,children:[B(`svg`,{"aria-hidden":`true`,class:e?`ssh-safeshield-refresh-loader-svg ssh-safeshield-refresh-loader-svg-error`:`ssh-safeshield-refresh-loader-svg`,viewBox:`0 0 48 48`,children:[B(`circle`,{class:`ssh-safeshield-refresh-loader-track`,cx:`24`,cy:`24`,fill:`none`,r:17,stroke:`currentColor`,strokeWidth:3}),e?null:B(`circle`,{class:`ssh-safeshield-refresh-loader-arc`,cx:`24`,cy:`24`,fill:`none`,r:17,stroke:`currentColor`,strokeDasharray:`${i} ${a}`,strokeLinecap:`round`,strokeWidth:4})]}),B(`span`,{class:`ssh-safeshield-refresh-donut-label`,children:e?`!`:`${t}/${n}`})]})}function U_({data:e}){let t=na(e.status,e.stage),n=I_(e)===`error`;if(!t&&!n)return null;let r=ra(e.stage),i=n?aa(e.runtime.lastErrorCode,e.stage):null;return B(`div`,{"aria-live":n?`assertive`:`polite`,class:`ssh-safeshield-refresh`,"data-state":n?`error`:`active`,role:n?`alert`:`status`,children:[B(H_,{failed:n,step:r.number,total:r.total}),B(`div`,{class:`ssh-safeshield-refresh-copy`,children:[B(`p`,{class:`ssh-safeshield-refresh-kicker`,children:n?`갱신 실패 · ${r.number}/${r.total}`:`갱신 ${r.number}/${r.total}`}),B(`p`,{class:`ssh-safeshield-refresh-title`,children:n?`${r.label} 단계에서 문제가 발생했습니다.`:r.label}),B(`p`,{class:`ssh-safeshield-refresh-description`,children:i??r.description}),n&&e.runtime.lastErrorCode?B(`p`,{class:`ssh-safeshield-refresh-error-code`,children:[`오류 코드: `,B(`code`,{children:e.runtime.lastErrorCode})]}):null]})]})}function W_({label:e,value:t}){return B(`div`,{class:`bg-white px-5 py-4 sm:px-6`,children:[B(`dt`,{class:`text-[0.68rem] font-black uppercase tracking-[0.14em] text-slate-400`,children:e}),B(`dd`,{class:`mt-2 mb-0 ml-0 truncate text-sm font-extrabold text-slate-950`,title:t,children:t})]})}function G_(e){return e?.trim().toUpperCase()||`FREE`}function K_(e){return e===`FREE`?`free`:e===`PRO`?`pro`:e===`ULTIMATE`?`ultimate`:`paid`}function q_({compact:e=!1,plan:t}){let n=K_(t),r=n!==`free`;return B(`span`,{class:`ssh-safeshield-plan-badge`,"data-compact":e?`true`:`false`,"data-tier":n,title:r?`${t} 멤버십`:`무료 플랜`,children:[B(`span`,{"aria-hidden":`true`,class:`ssh-safeshield-plan-badge-mark`,children:r?`✦`:`•`}),B(`span`,{children:t})]})}function J_({plan:e}){let t=K_(e)===`free`;return B(`div`,{class:`bg-white px-5 py-4 sm:px-6`,children:[B(`dt`,{class:`text-[0.68rem] font-black uppercase tracking-[0.14em] text-slate-400`,children:`Plan`}),B(`dd`,{class:`mt-2 mb-0 ml-0 flex min-w-0 flex-wrap items-center gap-2`,children:[B(q_,{plan:e}),t?B(`span`,{class:`ssh-safeshield-plan-caption`,children:`기본 플랜`}):null]})]})}function Y_(){return B(`div`,{class:`ssh-safeshield-upgrade-card`,children:[B(`span`,{"aria-hidden":`true`,class:`ssh-safeshield-upgrade-mark`,children:`✦`}),B(`div`,{class:`ssh-safeshield-upgrade-copy`,children:[B(`div`,{class:`ssh-safeshield-upgrade-meta`,children:[B(`span`,{children:`SmartSafeHub Membership`}),B(`span`,{class:`ssh-safeshield-upgrade-soon`,children:`Coming soon`})]}),B(`strong`,{children:`더 강력한 보호 기능을 준비하고 있습니다.`}),B(`span`,{children:`프리미엄 보호와 확장된 관리 기능을 미리 확인해 보세요.`})]}),B(`a`,{class:`ssh-safeshield-upgrade-action`,href:P_,rel:`noopener noreferrer`,target:`_blank`,children:[`요금제 보기`,B(`span`,{"aria-hidden":`true`,children:`→`})]})]})}function X_({description:e,eyebrow:t,title:n}){return B(`div`,{class:`mb-4 flex flex-wrap items-end justify-between gap-3`,children:B(`div`,{children:[B(`p`,{class:`m-0 text-[0.68rem] font-black uppercase tracking-[0.18em] text-teal-700`,children:t}),B(`h2`,{class:`mt-2 mb-0 text-xl font-black tracking-tight text-slate-950`,children:n}),B(`p`,{class:`mt-2 mb-0 text-sm leading-6 text-slate-500`,children:e})]})})}function Z_({children:e,eyebrow:t,icon:n,title:r}){return B(`article`,{class:`rounded-2xl border border-slate-200 bg-white p-5 shadow-sm shadow-slate-900/5 sm:p-6`,children:[B(`div`,{class:`flex items-start justify-between gap-4`,children:[B(`div`,{children:[B(`p`,{class:`m-0 text-[0.68rem] font-black uppercase tracking-[0.16em] text-slate-400`,children:t}),B(`h3`,{class:`mt-2 mb-0 text-lg font-black tracking-tight text-slate-950`,children:r})]}),B(`span`,{class:`grid size-10 shrink-0 place-items-center rounded-xl bg-slate-100 text-slate-500`,children:n})]}),B(`dl`,{class:`mt-5 mb-0 grid gap-3`,children:e})]})}function Q_({label:e,value:t}){return B(`div`,{class:`flex min-w-0 items-center justify-between gap-4 border-b border-slate-100 pb-3 last:border-b-0 last:pb-0`,children:[B(`dt`,{class:`text-sm font-semibold text-slate-500`,children:e}),B(`dd`,{class:`m-0 min-w-0 text-right text-sm font-extrabold text-slate-950`,children:t})]})}function $_({error:e,message:t,onDismiss:n}){if(!e&&!t)return null;let r=e!==null;return B(`div`,{"aria-live":r?`assertive`:`polite`,class:`mt-4 flex flex-col items-start gap-3 rounded-2xl border px-4 py-3 text-sm sm:flex-row sm:justify-between ${r?`border-red-200 bg-red-50 text-red-900`:`border-emerald-200 bg-emerald-50 text-emerald-900`}`,role:r?`alert`:`status`,children:[B(`div`,{class:`flex min-w-0 items-start gap-3`,children:[B(r?U:Xt,{class:`mt-0.5 size-5 shrink-0`}),B(`p`,{class:`m-0 font-semibold leading-6`,children:e??t})]}),B(`button`,{"aria-label":`알림 닫기`,class:`shrink-0 rounded-lg border-0 bg-transparent px-2 py-1 font-black text-current opacity-60 transition hover:opacity-100 focus:outline-none focus-visible:ring-2 focus-visible:ring-current`,onClick:n,type:`button`,children:`×`})]})}function ev({action:e,actionError:t,actionFeedbackTarget:n,actionMessage:r,data:i,error:a,loading:o,statistics:s,statisticsError:c,statisticsLoading:l,statisticsRefreshing:u,onDismissFeedback:d,onReadLicense:f,onRefreshBlocklist:p,onRemoveLicense:m,onRetry:h,onRetryStatistics:g,onSetEnabled:_,onSetStatisticsEnabled:v,onUpdateLicense:y}){let[b,x]=N(``),[C,w]=N(!1),[T,E]=N(null);if(P(()=>{i?.available&&i.blocklist.validLineCount>0&&!na(i.status,i.stage)&&E(i.blocklist.validLineCount)},[i?.available,i?.blocklist.validLineCount,i?.stage,i?.status]),P(()=>{i?.license.configured===!1&&(x(``),w(!1))},[i?.license.configured]),o)return B(io,{});if(a)return B(ao,{message:a,onRetry:h});if(!i)return B(io,{});if(!i.available)return B(`section`,{class:`rounded-2xl border border-amber-200 bg-amber-50 p-5 sm:p-6`,children:[B(`span`,{class:`grid size-11 place-items-center rounded-xl bg-amber-100 text-amber-800`,children:B(U,{class:`size-6`})}),B(`h2`,{class:`mt-5 mb-0 text-xl font-extrabold text-amber-950`,children:`SafeShield 상태 API를 찾을 수 없습니다`}),B(`p`,{class:`mt-2 mb-0 text-sm leading-6 text-amber-900`,children:`safeshield 패키지와 rpcd ucode 플러그인이 설치되어 있는지 확인해 주세요.`})]});let D=i.enabled,O=G_(i.license.plan),k=na(i.status,i.stage),A=e!==null,ee=(k||I_(i)===`error`)&&i.blocklist.validLineCount===0&&T!==null?T:i.blocklist.validLineCount,j=D?e===`disable`?`끄는 중…`:`보호 끄기`:e===`enable`?`켜는 중…`:`보호 켜기`;async function te(){if(b.length>0)return;let e=await f();e!==null&&(x(e),w(!0))}function ne(){x(``),w(!1)}function M(){window.confirm(`라이선스 키를 제거하면 SafeShield가 라이선스 없는 상태로 다시 확인하고 차단 목록을 갱신합니다. 계속하시겠습니까?`)&&m().then(e=>{e&&ne()})}function re(){D&&!window.confirm(`SafeShield 보호를 끄면 현재 차단 목록이 제거되고 DNS 차단이 즉시 중단됩니다. 계속하시겠습니까?`)||_(!D)}return B(S,{children:[B(`section`,{class:`overflow-hidden rounded-2xl border border-slate-200 bg-white shadow-sm shadow-slate-900/5`,children:[B(`div`,{class:`flex flex-col gap-5 p-5 sm:p-6 lg:flex-row lg:items-start lg:justify-between`,children:[B(`div`,{class:`flex min-w-0 items-start gap-3 sm:gap-4`,children:[B(`span`,{class:`grid size-12 shrink-0 place-items-center rounded-2xl bg-teal-50 text-teal-700`,children:B(At,{class:`size-7`})}),B(`div`,{class:`min-w-0`,children:[B(`p`,{class:`m-0 text-[0.68rem] font-black uppercase tracking-[0.18em] text-teal-700`,children:`Protection`}),B(`div`,{class:`mt-2 flex flex-wrap items-center gap-3`,children:[B(`h2`,{class:`m-0 break-words text-xl font-black tracking-tight text-slate-950 sm:text-2xl`,children:`SafeShield 보호 상태`}),B(V_,{data:i})]}),B(`p`,{class:`mt-3 mb-0 max-w-3xl text-sm leading-6 text-slate-600`,children:z_(i)}),B(U_,{data:i})]})]}),B(`div`,{class:`flex w-full flex-col gap-2 sm:w-auto sm:flex-row`,children:[B(`button`,{class:`inline-flex min-h-11 items-center justify-center gap-2 rounded-xl border px-4 py-2.5 text-sm font-extrabold transition focus:outline-none focus-visible:ring-4 disabled:cursor-not-allowed disabled:opacity-50 ${i.enabled?`border-red-200 bg-white text-red-700 hover:border-red-300 hover:bg-red-50 focus-visible:ring-red-100`:`border-teal-700 bg-teal-700 text-white hover:border-teal-800 hover:bg-teal-800 focus-visible:ring-teal-100`}`,disabled:A||k,onClick:re,type:`button`,children:[B(Ut,{class:`size-4 ${e===`enable`||e===`disable`?`animate-pulse`:``}`}),j]}),B(`button`,{class:`inline-flex min-h-11 items-center justify-center gap-2 rounded-xl border border-slate-200 bg-white px-4 py-2.5 text-sm font-extrabold text-slate-700 transition hover:border-teal-300 hover:bg-teal-50 hover:text-teal-800 focus:outline-none focus-visible:ring-4 focus-visible:ring-teal-100 disabled:cursor-not-allowed disabled:opacity-50`,disabled:!i.enabled||A||k,onClick:p,type:`button`,children:[B(Wt,{class:`size-4 ${e===`refresh`||k?`animate-bounce`:``}`}),e===`refresh`?`시작 중…`:k?`갱신 중…`:`지금 갱신`]})]})]}),B(`div`,{class:`px-5 pb-5 sm:px-6 sm:pb-6`,children:[B(`dl`,{class:`grid overflow-hidden rounded-xl border border-slate-200 bg-slate-200 sm:grid-cols-2 xl:grid-cols-4`,children:[B(W_,{label:`SafeShield`,value:i.version??`확인되지 않음`}),B(W_,{label:`Blocklist`,value:`${q(ee)}개 도메인`}),B(W_,{label:`Last refresh`,value:Fa(i.timestamps.lastSuccess)}),B(J_,{plan:O})]}),O===`FREE`?B(Y_,{}):null]})]}),B($_,{error:n===`license`?null:t,message:n===`license`?null:r,onDismiss:d}),B(N_,{action:e,data:s,error:c,loading:l,onRetry:g,onSetEnabled:v,refreshing:u}),B(`section`,{class:`mt-7`,children:[B(X_,{description:`DNS 보호 런타임, 차단 목록, 갱신 일정과 상태 점검 결과를 한곳에서 확인합니다.`,eyebrow:`Protection details`,title:`보호 구성`}),B(`div`,{class:`grid gap-4 lg:grid-cols-2`,children:[B(Z_,{eyebrow:`Runtime`,icon:B(Xt,{class:`size-5`}),title:`DNS 보호 런타임`,children:[B(Q_,{label:`SafeShield 서비스`,value:B(F_,{falseLabel:`중지됨`,trueLabel:`동작 중`,value:i.active})}),B(Q_,{label:`dnsmasq`,value:B(F_,{falseLabel:`중지됨`,value:i.runtime.dnsmasqRunning})}),B(Q_,{label:`DNS 런타임`,value:B(F_,{value:i.runtime.dnsRuntimeOk})}),B(Q_,{label:`Refresh daemon`,value:B(F_,{falseLabel:`중지됨`,value:i.runtime.refreshdRunning})})]}),B(Z_,{eyebrow:`Blocklist`,icon:B(Gt,{class:`size-5`}),title:`차단 목록`,children:[B(Q_,{label:`적용 규칙`,value:`${q(i.blocklist.validLineCount)}개 도메인`}),B(Q_,{label:`파일 크기`,value:Ma(i.blocklist.fileSizeKb*1024)}),B(Q_,{label:`설치 상태`,value:B(F_,{falseLabel:`미설치`,trueLabel:`설치됨`,value:i.blocklist.installed})}),B(Q_,{label:`검증 상태`,value:B(F_,{falseLabel:`확인 필요`,value:i.blocklist.verificationOk})})]}),B(Z_,{eyebrow:`Refresh schedule`,icon:B(Yt,{class:`size-5`}),title:`차단 목록 갱신`,children:[B(Q_,{label:`마지막 성공`,value:Fa(i.timestamps.lastSuccess)}),B(Q_,{label:`다음 갱신`,value:Fa(i.timestamps.nextRefreshAt)}),B(Q_,{label:`갱신 주기`,value:Ra(i.timestamps.refreshIntervalS)}),B(Q_,{label:`최근 결과`,value:i.runtime.lastResult||(k?`갱신 중`:`확인되지 않음`)})]}),B(Z_,{eyebrow:`Health`,icon:B(At,{class:`size-5`}),title:`상태 점검`,children:[B(Q_,{label:`전체 상태`,value:B_(i.health.overall)}),B(Q_,{label:`경고`,value:B(`span`,{class:`text-amber-700`,children:q(i.issueCounts.warnings)})}),B(Q_,{label:`오류`,value:B(`span`,{class:`text-red-700`,children:q(i.issueCounts.errors)})}),B(Q_,{label:`최근 오류 코드`,value:i.runtime.lastErrorCode||`없음`})]})]})]}),B(`section`,{class:`mt-7`,children:[B(X_,{description:`라이선스와 현재 적용 중인 SafeShield 아티팩트 및 로컬 규칙 구성을 관리합니다.`,eyebrow:`Settings`,title:`SafeShield 설정`}),B(`div`,{class:`grid gap-4 xl:grid-cols-[minmax(0,1.35fr)_minmax(18rem,0.65fr)]`,children:[B(`article`,{class:`rounded-2xl border border-slate-200 bg-white p-5 shadow-sm shadow-slate-900/5 sm:p-6`,children:[B(`div`,{class:`flex items-start justify-between gap-4`,children:[B(`div`,{children:[B(`p`,{class:`m-0 text-[0.68rem] font-black uppercase tracking-[0.16em] text-slate-400`,children:`License`}),B(`h3`,{class:`mt-2 mb-0 text-lg font-black tracking-tight text-slate-950`,children:`라이선스`}),B(`p`,{class:`mt-2 mb-0 text-sm leading-6 text-slate-500`,children:[`현재 플랜은 `,O,`이며, 라이선스 키를 등록하거나 변경할 수 있습니다.`]})]}),B(`span`,{class:`grid size-10 shrink-0 place-items-center rounded-xl bg-slate-100 text-slate-500`,children:B(Kt,{class:`size-5`})})]}),B(`div`,{class:`ssh-safeshield-license-summary mt-5`,children:[B(`div`,{class:`ssh-safeshield-license-summary-main`,children:[B(q_,{compact:!0,plan:O}),i.license.configured?null:B(`span`,{class:`ssh-safeshield-license-summary-status`,children:`라이선스 미설정`})]}),i.license.configured&&i.license.keyMasked?B(`span`,{class:`ssh-safeshield-license-key-mask`,children:i.license.keyMasked}):null]}),B(`form`,{class:`ssh-safeshield-license-editor mt-5`,onSubmit:e=>{e.preventDefault(),y(b).then(e=>{e&&ne()})},children:[B(`div`,{class:`ssh-safeshield-license-editor-header`,children:[B(`label`,{class:`ssh-safeshield-license-editor-label`,for:`safeshield-license-key`,children:i.license.configured?`라이선스 키 확인 / 변경`:`라이선스 키 등록`}),B(`span`,{class:`ssh-safeshield-license-editor-hint`,children:i.license.configured?`현재 키를 확인하거나 새 키로 교체할 수 있습니다.`:`새 라이선스 키를 등록해 프리미엄 기능을 준비하세요.`})]}),B(`div`,{class:`ssh-safeshield-license-input-row`,children:[B(`input`,{autocomplete:`off`,autocapitalize:`none`,class:`ssh-safeshield-license-input`,"data-1p-ignore":!0,"data-bwignore":`true`,"data-lpignore":`true`,disabled:A,id:`safeshield-license-key`,onInput:e=>{x(e.currentTarget.value),w(!1)},placeholder:i.license.configured?`새 라이선스 키 입력`:`라이선스 키 입력`,spellcheck:!1,type:`text`,value:b}),B(`button`,{class:`ssh-safeshield-license-secondary-action`,disabled:A||b.length>0||!i.license.configured,onClick:()=>void te(),type:`button`,children:[B(Wt,{class:`size-4`}),e===`license-read`?`불러오는 중…`:C?`현재 키 불러옴`:`현재 키 불러오기`]})]}),B(`div`,{class:`ssh-safeshield-license-actions`,children:[B(`button`,{class:`ssh-safeshield-license-primary-action`,disabled:A||b.trim().length===0,type:`submit`,children:e===`license-update`?`저장 중…`:i.license.configured?`라이선스 변경`:`라이선스 등록`}),i.license.configured?B(`button`,{class:`ssh-safeshield-license-danger-action`,disabled:A,onClick:M,type:`button`,children:e===`license-remove`?`제거 중…`:`라이선스 제거`}):null]}),e===`license-update`?B(`div`,{"aria-live":`polite`,class:`mt-4 flex items-center gap-3 rounded-2xl border border-teal-200 bg-teal-50 px-4 py-3 text-sm font-semibold text-teal-800`,role:`status`,children:[B(`span`,{class:`size-2 shrink-0 animate-pulse rounded-full bg-teal-500`}),`라이선스를 확인하고 이 기기에 적용하고 있습니다…`]}):null,B($_,{error:n===`license`?t:null,message:n===`license`?r:null,onDismiss:d})]})]}),B(`div`,{class:`grid gap-4`,children:[B(`article`,{class:`rounded-2xl border border-slate-200 bg-white p-5 shadow-sm shadow-slate-900/5`,children:[B(`div`,{class:`flex items-start justify-between gap-4`,children:[B(`div`,{children:[B(`p`,{class:`m-0 text-[0.68rem] font-black uppercase tracking-[0.16em] text-slate-400`,children:`Artifact`}),B(`h3`,{class:`mt-2 mb-0 text-lg font-black tracking-tight text-slate-950`,children:`보호 데이터`})]}),B(`span`,{class:`grid size-10 shrink-0 place-items-center rounded-xl bg-slate-100 text-slate-500`,children:B(Gt,{class:`size-5`})})]}),B(`dl`,{class:`mt-5 mb-0 grid gap-3`,children:[B(Q_,{label:`Tier`,value:i.artifact.tier||`확인되지 않음`}),B(Q_,{label:`Version`,value:i.artifact.version||`확인되지 않음`}),B(Q_,{label:`Rules`,value:q(i.artifact.rules)}),B(Q_,{label:`Unique domains`,value:q(i.artifact.uniqueDomains)})]})]}),B(`article`,{class:`rounded-2xl border border-slate-200 bg-white p-5 shadow-sm shadow-slate-900/5`,children:[B(`p`,{class:`m-0 text-[0.68rem] font-black uppercase tracking-[0.16em] text-slate-400`,children:`Custom rules`}),B(`h3`,{class:`mt-2 mb-0 text-lg font-black tracking-tight text-slate-950`,children:`사용자 규칙`}),B(`div`,{class:`mt-4`,children:B(F_,{falseLabel:`비활성화`,trueLabel:`활성화`,value:i.localOverrides.enabled})}),B(`p`,{class:`mt-4 mb-0 text-sm font-semibold leading-6 text-slate-500`,children:`허용하거나 차단할 도메인을 직접 관리해 SafeShield 보호 정책에 반영합니다.`}),B(`a`,{class:`mt-5 inline-flex min-h-11 items-center justify-center gap-2 rounded-xl border border-teal-700 bg-teal-700 px-4 py-2 text-sm font-extrabold text-white no-underline shadow-sm transition hover:border-teal-800 hover:bg-teal-800 focus:outline-none focus-visible:ring-4 focus-visible:ring-teal-100`,href:`#rules`,children:[B(en,{class:`size-4`}),`사용자 규칙 관리`]})]})]})]})]})]})}function tv(e){return e.trim().toLowerCase().replace(/\.+$/,``)}function nv(e){return e.length===0||e.length>253||!e.includes(`.`)||!/^[a-z0-9.-]+$/.test(e)?!1:e.split(`.`).every(e=>e.length>0&&e.length<=63&&/^[a-z0-9](?:[a-z0-9-]*[a-z0-9])?$/.test(e))}function rv({action:e,kind:t,onAddRule:n,onDeleteRule:r,rules:i}){let[a,o]=N(``),[s,c]=N(``),[l,u]=N(null),d=t===`allow`,f=e!==null,p=$e(()=>{let e=s.trim().toLowerCase();return e.length>0?i.filter(t=>t.includes(e)):i},[i,s]);async function m(e){e.preventDefault();let r=tv(a);if(!nv(r)){u(`example.com 형식의 도메인을 입력해 주세요. URL, IP 주소, 와일드카드는 사용할 수 없습니다.`);return}u(null),await n(t,r)&&o(``)}let h=d?{badge:`bg-emerald-100 text-emerald-800`,button:`border-emerald-700 bg-emerald-700 text-white hover:border-emerald-800 hover:bg-emerald-800 focus-visible:ring-emerald-100`,icon:`bg-emerald-50 text-emerald-700`,label:`허용 목록`,description:`차단 목록에 포함되어도 허용할 도메인과 하위 도메인을 등록합니다.`,empty:`등록된 허용 도메인이 없습니다.`}:{badge:`bg-red-100 text-red-800`,button:`border-red-700 bg-red-700 text-white hover:border-red-800 hover:bg-red-800 focus-visible:ring-red-100`,icon:`bg-red-50 text-red-700`,label:`차단 목록`,description:`SafeShield 기본 목록에 없더라도 직접 차단할 도메인을 등록합니다.`,empty:`등록된 차단 도메인이 없습니다.`};return B(`article`,{class:`min-w-0 rounded-2xl border border-slate-200 bg-white shadow-sm shadow-slate-900/5`,children:[B(`div`,{class:`border-b border-slate-200 p-4 sm:p-6`,children:[B(`div`,{class:`flex items-start justify-between gap-4`,children:B(`div`,{class:`flex min-w-0 items-start gap-3`,children:[B(`span`,{class:`grid size-11 shrink-0 place-items-center rounded-xl ${h.icon}`,children:B(d?Xt:At,{class:`size-6`})}),B(`div`,{class:`min-w-0`,children:[B(`div`,{class:`flex flex-wrap items-center gap-2`,children:[B(`h2`,{class:`m-0 text-xl font-extrabold tracking-tight text-slate-950`,children:h.label}),B(`span`,{class:`rounded-full px-2.5 py-1 text-xs font-extrabold ${h.badge}`,children:i.length})]}),B(`p`,{class:`mt-2 mb-0 text-sm leading-6 text-slate-600`,children:h.description})]})]})}),B(`form`,{class:`mt-5`,onSubmit:m,children:[B(`label`,{class:`block text-xs font-extrabold text-slate-600`,for:`${t}-domain`,children:`새 도메인`}),B(`div`,{class:`mt-2 flex flex-col gap-2 sm:flex-row`,children:[B(`input`,{"aria-describedby":l?`${t}-domain-error`:void 0,"aria-invalid":l?!0:void 0,autocomplete:`off`,class:`min-h-11 min-w-0 flex-1 rounded-xl border-2 border-slate-300 bg-slate-50 px-4 py-2.5 text-sm font-semibold text-slate-950 shadow-inner outline-none transition placeholder:text-slate-400 focus:border-teal-500 focus:bg-white focus:ring-4 focus:ring-teal-100 disabled:cursor-not-allowed disabled:bg-slate-100`,disabled:f,id:`${t}-domain`,onInput:e=>o(e.currentTarget.value),placeholder:`example.com`,spellcheck:!1,type:`text`,value:a}),B(`button`,{class:`inline-flex min-h-11 w-full shrink-0 items-center justify-center gap-2 sm:w-auto rounded-xl border px-4 py-2.5 text-sm font-extrabold transition focus:outline-none focus-visible:ring-4 disabled:cursor-not-allowed disabled:opacity-50 ${h.button}`,disabled:f||a.trim().length===0,type:`submit`,children:[B(Zt,{class:`size-4`}),e?.operation===`add`&&e.action===t?`추가 중…`:`추가`]})]}),l?B(`p`,{class:`mt-2 mb-0 text-xs font-semibold leading-5 text-red-700`,id:`${t}-domain-error`,children:l}):null]})]}),B(`div`,{class:`p-4 sm:p-6`,children:[B(`label`,{class:`relative block`,for:`${t}-search`,children:[B(`span`,{class:`sr-only`,children:[h.label,` 검색`]}),B(`span`,{class:`pointer-events-none absolute inset-y-0 left-0 flex w-11 items-center justify-center text-slate-400`,children:B($t,{class:`size-4`})}),B(`input`,{class:`min-h-11 w-full rounded-xl border-2 border-slate-300 bg-slate-50 py-2.5 pr-4 pl-11 text-sm font-semibold text-slate-950 shadow-inner outline-none transition placeholder:text-slate-400 focus:border-teal-500 focus:bg-white focus:ring-4 focus:ring-teal-100`,id:`${t}-search`,onInput:e=>c(e.currentTarget.value),placeholder:`${h.label} 검색`,type:`search`,value:s})]}),B(`div`,{class:`mt-4 max-h-[28rem] overflow-y-auto rounded-xl border border-slate-200`,children:p.length>0?B(`ul`,{class:`m-0 list-none divide-y divide-slate-200 p-0`,children:p.map(n=>{let i=e?.operation===`delete`&&e.action===t&&e.domain===n;return B(`li`,{class:`flex min-w-0 items-center justify-between gap-3 px-3.5 py-3`,children:[B(`code`,{class:`min-w-0 break-all font-mono text-sm font-semibold text-slate-800`,children:n}),B(`button`,{"aria-label":`${n} ${h.label}에서 삭제`,class:`inline-flex size-9 shrink-0 items-center justify-center rounded-lg border border-slate-200 bg-white text-slate-500 transition hover:border-red-200 hover:bg-red-50 hover:text-red-700 focus:outline-none focus-visible:ring-4 focus-visible:ring-red-100 disabled:cursor-not-allowed disabled:opacity-50`,disabled:f,onClick:()=>void r(t,n),title:`삭제`,type:`button`,children:B(Qt,{class:`size-4 ${i?`animate-pulse`:``}`})})]},n)})}):B(`div`,{class:`px-5 py-10 text-center`,children:[B(en,{class:`mx-auto size-8 text-slate-300`}),B(`p`,{class:`mt-3 mb-0 text-sm font-bold text-slate-600`,children:s.trim().length>0?`검색 결과가 없습니다.`:h.empty})]})})]})]})}function iv({action:e,data:t,error:n,feedback:r,loading:i,onAddRule:a,onDeleteRule:o,onDismissFeedback:s,onRetry:c}){return i&&!t?B(io,{}):n&&!t?B(ao,{message:n,onRetry:c}):t?B(S,{children:[B(`section`,{class:`rounded-2xl border border-slate-200 bg-white p-4 shadow-sm shadow-slate-900/5 sm:p-6`,children:B(`div`,{class:`flex flex-col gap-4 lg:flex-row lg:items-center lg:justify-between`,children:[B(`div`,{class:`flex min-w-0 items-start gap-3 sm:gap-4`,children:[B(`span`,{class:`grid size-12 shrink-0 place-items-center rounded-2xl bg-teal-50 text-teal-700`,children:B(en,{class:`size-7`})}),B(`div`,{class:`min-w-0`,children:[B(`p`,{class:`m-0 text-xs font-extrabold uppercase tracking-[0.16em] text-teal-700`,children:`Local overrides`}),B(`h2`,{class:`mt-2 mb-0 break-words text-xl font-black tracking-tight text-slate-950 sm:text-2xl`,children:`사용자 도메인 규칙`}),B(`p`,{class:`mt-2 mb-0 max-w-3xl text-sm leading-6 text-slate-600`,children:`허용 목록은 오탐을 해제하고, 차단 목록은 원하는 도메인을 SafeShield 보호 목록에 추가합니다.`})]})]}),B(`dl`,{class:`m-0 grid grid-cols-3 gap-2 sm:min-w-80`,children:[B(`div`,{class:`rounded-xl bg-emerald-50 px-3 py-3 text-center`,children:[B(`dt`,{class:`text-[0.68rem] font-extrabold uppercase tracking-wide text-emerald-700`,children:`허용`}),B(`dd`,{class:`mt-1 mb-0 ml-0 text-lg font-black text-emerald-950`,children:t.counts.allow})]}),B(`div`,{class:`rounded-xl bg-red-50 px-3 py-3 text-center`,children:[B(`dt`,{class:`text-[0.68rem] font-extrabold uppercase tracking-wide text-red-700`,children:`차단`}),B(`dd`,{class:`mt-1 mb-0 ml-0 text-lg font-black text-red-950`,children:t.counts.block})]}),B(`div`,{class:`rounded-xl bg-slate-100 px-3 py-3 text-center`,children:[B(`dt`,{class:`text-[0.68rem] font-extrabold uppercase tracking-wide text-slate-600`,children:`전체`}),B(`dd`,{class:`mt-1 mb-0 ml-0 text-lg font-black text-slate-950`,children:t.counts.total})]})]})]})}),t.applyLocalOverrides?null:B(`section`,{class:`mt-4 flex items-start gap-3 rounded-2xl border border-amber-200 bg-amber-50 p-4`,role:`alert`,children:[B(U,{class:`mt-0.5 size-5 shrink-0 text-amber-700`}),B(`div`,{children:[B(`p`,{class:`m-0 text-sm font-extrabold text-amber-950`,children:`로컬 규칙 적용이 꺼져 있습니다`}),B(`p`,{class:`mt-1 mb-0 text-sm leading-6 text-amber-800`,children:`규칙은 저장되지만 SafeShield의 apply_local_overrides 설정을 켜기 전까지 DNS에 반영되지 않습니다.`})]})]}),t.safeshieldEnabled?null:B(`section`,{class:`mt-4 flex items-start gap-3 rounded-2xl border border-slate-200 bg-slate-100 p-4`,role:`status`,children:[B(At,{class:`mt-0.5 size-5 shrink-0 text-slate-600`}),B(`div`,{children:[B(`p`,{class:`m-0 text-sm font-extrabold text-slate-950`,children:`SafeShield가 비활성화되어 있습니다`}),B(`p`,{class:`mt-1 mb-0 text-sm leading-6 text-slate-600`,children:`규칙을 미리 저장할 수 있으며, SafeShield를 켜고 차단 목록을 갱신하면 적용됩니다.`})]})]}),r?B(`section`,{"aria-live":`polite`,class:`mt-4 flex flex-col items-start gap-3 rounded-2xl border border-teal-200 bg-teal-50 sm:flex-row sm:justify-between p-4`,children:[B(`div`,{class:`flex min-w-0 items-start gap-3`,children:[B(Xt,{class:`mt-0.5 size-5 shrink-0 text-teal-700`}),B(`p`,{class:`m-0 text-sm font-semibold leading-6 text-teal-950`,children:r})]}),B(`button`,{class:`shrink-0 rounded-lg border-0 bg-transparent px-2 py-1 text-xs font-extrabold text-teal-800 hover:bg-teal-100`,onClick:s,type:`button`,children:`닫기`})]}):null,n&&t?B(`section`,{"aria-live":`assertive`,class:`mt-4 flex items-start gap-3 rounded-2xl border border-red-200 bg-red-50 p-4`,children:[B(U,{class:`mt-0.5 size-5 shrink-0 text-red-700`}),B(`p`,{class:`m-0 text-sm font-semibold leading-6 text-red-900`,children:n})]}):null,B(`section`,{class:`mt-5 grid gap-5 xl:grid-cols-2`,children:[B(rv,{action:e,kind:`allow`,onAddRule:a,onDeleteRule:o,rules:t.allow}),B(rv,{action:e,kind:`block`,onAddRule:a,onDeleteRule:o,rules:t.block})]}),B(`p`,{class:`mt-5 mb-0 text-xs leading-5 text-slate-500`,children:`규칙 저장과 유효성 검사는 SafeShield API가 관리합니다. 도메인은 소문자로 정규화되고 중복 항목은 하나로 유지됩니다.`})]}):B(ao,{message:`사용자 규칙 응답이 비어 있습니다.`,onRetry:c})}function av(e,t){return z(`smartsafehub`,`system_root_password_change`,{current_password:e,new_password:t})}var ov=Array.from({length:24},(e,t)=>{let n=String(t).padStart(2,`0`);return{value:n,label:`${n}시`}}),sv=Array.from({length:60},(e,t)=>{let n=String(t).padStart(2,`0`);return{value:n,label:`${n}분`}});function cv(e){let t=/^([01]\d|2[0-3]):([0-5]\d)$/.exec(e);return{hour:t?.[1]??`03`,minute:t?.[2]??`00`}}function lv({ariaLabel:e,className:t=``,disabled:n=!1,id:r,onChange:i,value:a,variant:o=`default`}){let{hour:s,minute:c}=cv(a),l=(e,t)=>{i(`${e}:${t}`)};return B(`div`,{"aria-label":e,class:`ssh-time-select ${t}`.trim(),"data-time-select":r,role:`group`,children:[B(Vg,{ariaLabel:`${e} 시`,disabled:n,id:`${r}-hour`,onChange:e=>l(e,c),options:ov,value:s,variant:o}),B(Vg,{ariaLabel:`${e} 분`,disabled:n,id:`${r}-minute`,onChange:e=>l(s,e),options:sv,value:c,variant:o})]})}function uv(e){return B(`article`,{class:`min-w-0 rounded-2xl border border-slate-200 bg-white p-4 shadow-sm shadow-slate-900/5 sm:p-5`,children:[B(`p`,{class:`m-0 text-xs font-extrabold uppercase tracking-[0.16em] text-slate-500`,children:e.label}),B(`p`,{class:`mt-3 mb-0 break-words text-2xl font-black tracking-tight text-slate-950`,children:e.value}),B(`p`,{class:`mt-2 mb-0 text-sm leading-6 text-slate-500`,children:e.description})]})}function dv(e){return B(`article`,{class:`min-w-0 rounded-2xl border border-slate-200 bg-white p-5 shadow-sm shadow-slate-900/5 sm:p-6 ${e.className??``}`,children:[B(`div`,{class:`flex min-w-0 items-start gap-4`,children:[B(`div`,{class:`flex size-11 shrink-0 items-center justify-center rounded-xl bg-slate-100 text-slate-600`,children:e.icon}),B(`div`,{class:`min-w-0`,children:[B(`h2`,{class:`m-0 text-lg font-black text-slate-950`,children:e.title}),B(`p`,{class:`mt-1.5 mb-0 text-sm leading-6 text-slate-500`,children:e.description})]})]}),B(`div`,{class:`mt-5`,children:e.children})]})}function fv(){try{return Intl.DateTimeFormat().resolvedOptions().timeZone||null}catch{return null}}function pv(e){let[t,n]=N(``),[r,i]=N(e.data?.localtime??0),a=fv();P(()=>{e.data?.zonename&&n(e.data.zonename)},[e.data?.zonename]),P(()=>{let t=e.data?.localtime??0,n=Date.now();if(i(t),!Number.isFinite(t)||t<=0)return;let r=window.setInterval(()=>{i(t+Math.floor((Date.now()-n)/1e3))},1e3);return()=>window.clearInterval(r)},[e.data?.localtime]);let o=e.data?Object.keys(e.data.timezones).sort((e,t)=>e.localeCompare(t)):[],s=La(r,e.data?.zonename??`UTC`),c=a!==null&&e.data?.timezones[a]!==void 0,l=e.data!==null&&t.length>0&&t!==e.data.zonename;return B(dv,{description:`공유기의 기준 시간대를 설정합니다. 로그, 통계, 자동 설치와 예약 재부팅 시각도 이 시간대를 기준으로 동작합니다.`,icon:B(Vt,{class:`size-5`}),title:`시간 및 시간대`,children:[(e.saveError||e.saveMessage)&&B(`div`,{class:`mb-5 flex min-w-0 items-start justify-between gap-3 rounded-xl border px-4 py-3 text-sm font-bold ${e.saveError?`border-rose-200 bg-rose-50 text-rose-800`:`border-emerald-200 bg-emerald-50 text-emerald-800`}`,children:[B(`span`,{class:`min-w-0`,children:e.saveError||e.saveMessage}),B(`button`,{class:`shrink-0 rounded-lg px-2 py-1 text-xs font-extrabold hover:bg-black/5`,onClick:e.onDismissFeedback,type:`button`,children:`닫기`})]}),e.error&&!e.data?B(`div`,{class:`rounded-xl border border-rose-200 bg-rose-50 p-4`,children:[B(`p`,{class:`m-0 text-sm font-bold text-rose-800`,children:e.error}),B(`button`,{class:`mt-3 inline-flex min-h-10 items-center rounded-xl border border-rose-300 bg-white px-3 py-2 text-xs font-extrabold text-rose-700 transition hover:bg-rose-100`,onClick:e.onRetry,type:`button`,children:`다시 불러오기`})]}):B(S,{children:[B(`div`,{class:`grid min-w-0 grid-cols-1 gap-3 sm:grid-cols-2`,children:[B(`div`,{class:`rounded-xl bg-slate-50 p-4`,children:[B(`p`,{class:`m-0 text-xs font-extrabold uppercase tracking-[0.12em] text-slate-500`,children:`현재 시간`}),B(`p`,{class:`mt-2 mb-0 text-sm font-extrabold leading-6 text-slate-900`,children:s}),B(`p`,{class:`mt-1 mb-0 break-words text-xs leading-5 text-slate-500`,children:e.data?.zonename??`시간대 확인 중`})]}),B(`div`,{class:`rounded-xl bg-slate-50 p-4`,children:[B(`p`,{class:`m-0 text-xs font-extrabold uppercase tracking-[0.12em] text-slate-500`,children:`시간 동기화`}),B(`p`,{class:`mt-2 mb-0 text-sm font-extrabold ${e.data?.ntpEnabled?`text-emerald-700`:`text-amber-700`}`,children:e.data?.ntpEnabled?`자동 동기화 설정됨`:`자동 동기화 꺼짐`}),B(`p`,{class:`mt-1 mb-0 text-xs leading-5 text-slate-500`,children:`장치의 기본 NTP 설정 상태입니다.`}),B(`button`,{class:`mt-3 inline-flex min-h-9 items-center justify-center gap-2 rounded-lg border border-slate-300 bg-white px-3 py-2 text-xs font-extrabold text-slate-700 transition hover:bg-slate-100 disabled:cursor-not-allowed disabled:opacity-50`,disabled:!e.data?.ntpEnabled||e.saving||e.syncing,onClick:()=>void e.onSync(),type:`button`,children:e.syncing?`동기화 요청 중`:`지금 동기화`})]})]}),B(`div`,{class:`mt-5`,children:[B(`label`,{class:`mb-2 block text-sm font-extrabold text-slate-800`,for:`smartsafehub-timezone`,children:`시간대`}),B(Vg,{ariaLabel:`시간대`,disabled:e.loading||e.saving||e.syncing||!e.data,id:`smartsafehub-timezone`,onChange:n,options:e.data?o.map(e=>({value:e,label:e})):[{value:``,label:`시간대 불러오는 중`}],value:t}),B(`p`,{class:`mt-2 mb-0 text-xs leading-5 text-slate-500`,children:`시간대를 변경하면 시스템에 즉시 적용되며 자동 설치와 예약 재부팅 일정도 새 기준 시간으로 다시 계산합니다.`})]}),B(`div`,{class:`mt-4 flex flex-col gap-3 sm:flex-row sm:flex-wrap sm:justify-end`,children:[c&&a!==t&&B(`button`,{class:`inline-flex min-h-11 w-full items-center justify-center rounded-xl border border-slate-300 bg-white px-4 py-2.5 text-sm font-extrabold text-slate-700 transition hover:bg-slate-50 disabled:opacity-60 sm:w-auto`,disabled:e.saving||e.syncing,onClick:()=>n(a),type:`button`,children:`브라우저 시간대 사용`}),B(`button`,{class:`inline-flex min-h-11 w-full items-center justify-center rounded-xl bg-teal-700 px-4 py-2.5 text-sm font-extrabold text-white transition hover:bg-teal-800 disabled:cursor-not-allowed disabled:opacity-50 sm:w-auto`,disabled:!l||e.saving||e.syncing,onClick:()=>void e.onSave(t),type:`button`,children:e.saving?`시간대 저장 중`:`시간대 저장`})]})]}),B(Tv,{data:e.scheduledRebootData,error:e.scheduledRebootError,loading:e.scheduledRebootLoading,onDismissFeedback:e.onDismissScheduledRebootFeedback,onRetry:e.onRetry,onSave:e.onSaveScheduledReboot,saveError:e.scheduledRebootSaveError,saveMessage:e.scheduledRebootSaveMessage,saving:e.scheduledRebootSaving})]})}function mv(e){return e===`initializing`?{badge:`bg-teal-100 text-teal-800`,panel:`border-teal-200 bg-teal-50`,label:`준비 중`}:e===`critical`?{badge:`bg-rose-100 text-rose-800`,panel:`border-rose-200 bg-rose-50`,label:`이상`}:e===`warning`?{badge:`bg-amber-100 text-amber-800`,panel:`border-amber-200 bg-amber-50`,label:`주의`}:e===`unknown`?{badge:`bg-slate-200 text-slate-700`,panel:`border-slate-200 bg-slate-50`,label:`확인 불가`}:{badge:`bg-emerald-100 text-emerald-800`,panel:`border-emerald-200 bg-emerald-50`,label:`정상`}}function hv(e){if(!e.enabled)return`보고 중지됨`;switch(e.lastResult){case`reported`:return`정상 보고`;case`initializing`:return e.lastReportAt>0?`상태 갱신 중`:`첫 보고 진행 중`;case`failed`:return`최근 보고 실패`;case`idle`:return`다음 보고 대기`;case`ineligible`:return`멤버십 확인 필요`;case`disabled`:case`never`:return`첫 보고 준비 중`;default:return`보고 준비 중`}}function gv(e){return e.lastReportAt>0?Ia(e.lastReportAt):e.enabled?`첫 보고 대기 중`:`보고 기록 없음`}function _v(e){let t=e?.plan?.trim().toUpperCase(),n=e?.licenseStatus?.trim().toLowerCase();return t&&(n===`trial`||n===`trialing`)?`${t} · 체험`:t||`유료 · Trial`}function vv(e){let t=e.data,n=mv(t?.overall??`unknown`),r=t?.checks.filter(e=>e.status!==`ok`)??[],i=r.length>0?r.slice(0,4):t?.checks.filter(e=>[`system.memory`,`network.wan`,`service.dnsmasq`,`safeshield.runtime`].includes(e.id))??[],a=t?.reporter,o=a?.enabled===!0,s=a?.eligible===!0||o,c=e.savingReporter?o?`원격 상태 보고를 켜고 있습니다.`:`원격 상태 보고를 끄고 있습니다.`:o?`원격 상태 보고가 켜져 있습니다.`:`원격 상태 보고가 꺼져 있습니다.`,l=o?`장치 상태가 바뀌면 즉시 보고하고, 정상 상태에서도 주기적으로 SmartSafeHub 서버에 보고합니다.`:`로컬 진단은 계속 동작하지만 장치 상태는 SmartSafeHub 서버에 자동으로 전송되지 않습니다.`;return B(dv,{description:`SmartSafeHub가 장치 상태를 직접 점검하고 이상 항목을 알려줍니다. 로컬 진단은 멤버십과 관계없이 사용할 수 있습니다.`,icon:B(Wt,{class:`size-5`}),title:`진단 및 지원`,children:[(e.actionError||e.actionMessage)&&B(`div`,{class:`mb-4 flex items-start justify-between gap-3 rounded-xl border px-4 py-3 text-sm font-bold ${e.actionError?`border-rose-200 bg-rose-50 text-rose-800`:`border-emerald-200 bg-emerald-50 text-emerald-800`}`,children:[B(`span`,{children:e.actionError||e.actionMessage}),B(`button`,{class:`shrink-0 rounded-lg px-2 py-1 text-xs font-extrabold hover:bg-black/5`,onClick:e.onDismissFeedback,type:`button`,children:`닫기`})]}),e.error&&!t?B(`div`,{class:`rounded-xl border border-rose-200 bg-rose-50 p-4`,children:[B(`p`,{class:`m-0 text-sm font-bold text-rose-800`,children:e.error}),B(`button`,{class:`mt-3 inline-flex min-h-10 items-center rounded-xl border border-rose-300 bg-white px-3 py-2 text-xs font-extrabold text-rose-700 transition hover:bg-rose-100`,onClick:e.onRetry,type:`button`,children:`다시 불러오기`})]}):B(S,{children:[B(`div`,{class:`rounded-xl border p-4 ${n.panel}`,children:B(`div`,{class:`flex flex-wrap items-start justify-between gap-3`,children:[B(`div`,{class:`flex min-w-0 items-start gap-3`,children:[B(`span`,{class:`mt-0.5 shrink-0`,children:t?.overall===`ok`?B(Xt,{class:`size-5 text-emerald-700`}):t?.overall===`initializing`?B(Vt,{class:`size-5 text-teal-700`}):B(U,{class:`size-5 text-amber-700`})}),B(`div`,{class:`min-w-0`,children:[B(`p`,{class:`m-0 text-sm font-black text-slate-950`,children:t?.summary.message??`장치 상태를 확인하고 있습니다.`}),B(`p`,{class:`mt-1 mb-0 text-xs leading-5 text-slate-600`,children:[`마지막 진단 : `,t?Ia(t.generatedAt):`확인 중`]})]})]}),B(`span`,{class:`rounded-full px-2.5 py-1 text-xs font-extrabold ${n.badge}`,children:n.label})]})}),t&&B(`div`,{class:`mt-4 grid grid-cols-3 gap-2`,children:[B(`div`,{class:`rounded-xl bg-slate-50 p-3`,children:[B(`p`,{class:`m-0 text-[11px] font-extrabold text-slate-500`,children:`진단 항목`}),B(`p`,{class:`mt-1 mb-0 text-lg font-black text-slate-950`,children:t.summary.total})]}),B(`div`,{class:`rounded-xl bg-slate-50 p-3`,children:[B(`p`,{class:`m-0 text-[11px] font-extrabold text-slate-500`,children:`주의`}),B(`p`,{class:`mt-1 mb-0 text-lg font-black text-amber-700`,children:t.summary.warning})]}),B(`div`,{class:`rounded-xl bg-slate-50 p-3`,children:[B(`p`,{class:`m-0 text-[11px] font-extrabold text-slate-500`,children:`이상`}),B(`p`,{class:`mt-1 mb-0 text-lg font-black text-rose-700`,children:t.summary.critical})]})]}),i.length>0&&B(`div`,{class:`mt-4 space-y-2`,children:i.map(e=>{let t=mv(e.status);return B(`div`,{class:`flex min-w-0 items-start justify-between gap-3 rounded-xl border border-slate-200 px-3 py-2.5`,children:[B(`div`,{class:`min-w-0`,children:[B(`p`,{class:`m-0 text-xs font-extrabold text-slate-900`,children:e.label}),B(`p`,{class:`mt-1 mb-0 text-xs leading-5 text-slate-500`,children:e.message})]}),B(`span`,{class:`shrink-0 rounded-full px-2 py-1 text-[11px] font-extrabold ${t.badge}`,children:t.label})]},e.id)})}),B(`div`,{class:`mt-4 flex flex-col gap-2 sm:flex-row`,children:[B(`button`,{class:`inline-flex min-h-11 w-full items-center justify-center rounded-xl bg-teal-700 px-4 py-2.5 text-sm font-extrabold text-white transition hover:bg-teal-800 disabled:cursor-wait disabled:opacity-60 sm:w-auto`,disabled:e.running||e.loading,onClick:e.onRun,type:`button`,children:e.running?`진단 중`:`지금 진단`}),B(`button`,{class:`inline-flex min-h-11 w-full items-center justify-center rounded-xl border border-slate-300 bg-white px-4 py-2.5 text-sm font-extrabold text-slate-800 transition hover:bg-slate-50 disabled:cursor-wait disabled:opacity-60 sm:w-auto`,disabled:e.downloadBusy,onClick:e.onDownload,type:`button`,children:e.downloadBusy?`진단 정보 생성 중`:`진단 정보 다운로드`})]}),B(`p`,{class:`mt-3 mb-0 text-xs leading-5 text-slate-500`,children:`다운로드 파일에는 호스트명, WAN IP와 Wi-Fi SSID 같은 네트워크 식별 정보가 포함될 수 있으므로 외부 전달 전에 내용을 확인해 주세요.`}),B(`div`,{class:`mt-5 border-t border-slate-200 pt-5`,children:[B(`div`,{class:`flex min-w-0 items-start justify-between gap-4`,children:[B(`div`,{class:`min-w-0`,children:[B(`div`,{class:`flex flex-wrap items-center gap-2`,children:[B(`p`,{class:`m-0 text-sm font-black text-slate-950`,children:`원격 상태 보고`}),B(`span`,{class:`rounded-full bg-slate-100 px-2 py-1 text-[10px] font-extrabold uppercase tracking-[0.08em] text-slate-600`,children:_v(a)})]}),B(`p`,{class:`mt-1 mb-0 text-xs leading-5 text-slate-500`,children:`장치의 최소 상태 정보와 이상 코드만 SmartSafeHub 서버에 전송합니다. 기본값은 꺼짐이며 언제든지 다시 끌 수 있습니다.`})]}),B(`button`,{"aria-checked":a?.enabled===!0,"aria-label":`원격 상태 보고 사용`,class:`ssh-switch-control relative inline-flex shrink-0 rounded-full border transition focus:outline-none focus-visible:ring-4 focus-visible:ring-teal-100 disabled:cursor-not-allowed disabled:opacity-50 ${a?.enabled?`border-teal-600 bg-teal-600`:`border-slate-300 bg-slate-200`}`,disabled:!t||e.savingReporter||!s,onClick:()=>e.onSetReporter(!(a?.enabled??!1)),role:`switch`,type:`button`,children:B(`span`,{"aria-hidden":`true`,class:`ssh-switch-thumb absolute top-1 shadow-sm transition-[left] ${a?.enabled?`left-6`:`left-1`}`})})]}),a?.eligible?B(`div`,{class:`mt-4 rounded-xl bg-slate-50 p-4`,children:[B(`div`,{class:`mb-4 flex items-start gap-3 rounded-xl border p-3 ${o?`border-emerald-200 bg-emerald-50`:`border-slate-200 bg-white`}`,children:[B(`span`,{class:`mt-0.5 shrink-0`,children:o?B(Xt,{class:`size-5 text-emerald-700`}):B(Ut,{class:`size-5 text-slate-500`})}),B(`div`,{class:`min-w-0 flex-1`,children:[B(`div`,{class:`flex flex-wrap items-center gap-2`,children:[B(`p`,{class:`m-0 text-sm font-black text-slate-950`,children:c}),B(`span`,{class:`rounded-full px-2 py-0.5 text-[10px] font-extrabold ${e.savingReporter?`bg-slate-200 text-slate-700`:o?`bg-emerald-100 text-emerald-800`:`bg-slate-200 text-slate-700`}`,children:e.savingReporter?`설정 중`:o?`켜짐`:`꺼짐`})]}),B(`p`,{class:`mt-1 mb-0 text-xs leading-5 text-slate-600`,children:l})]})]}),B(`div`,{class:`grid grid-cols-1 gap-3 sm:grid-cols-2`,children:[B(`div`,{children:[B(`p`,{class:`m-0 text-[11px] font-extrabold text-slate-500`,children:`최근 전송 상태`}),B(`p`,{class:`mt-1 mb-0 text-sm font-black text-slate-900`,children:e.savingReporter?`설정 반영 중`:hv(a)})]}),B(`div`,{children:[B(`p`,{class:`m-0 text-[11px] font-extrabold text-slate-500`,children:`마지막 서버 보고`}),B(`p`,{class:`mt-1 mb-0 text-sm font-black text-slate-900`,children:gv(a)})]})]}),a.enabled&&a.lastErrorCode&&B(`p`,{class:`mt-3 mb-0 text-xs font-bold text-rose-700`,children:[`최근 보고 오류 : `,a.lastErrorCode]})]}):B(`div`,{class:`mt-4 rounded-xl border border-slate-200 bg-slate-50 p-4`,children:[B(`p`,{class:`m-0 text-sm font-extrabold text-slate-900`,children:`원격 상태 보고는 유료 멤버십 또는 체험 기간에 사용할 수 있습니다.`}),B(`a`,{class:`mt-3 inline-flex text-xs font-extrabold text-teal-700 hover:text-teal-800`,href:`https://www.smartsafehub.com/pricing/`,rel:`noopener noreferrer`,target:`_blank`,children:`멤버십 알아보기`})]}),B(`div`,{class:`mt-4 grid grid-cols-1 gap-3 text-xs leading-5 text-slate-500 sm:grid-cols-2`,children:[B(`div`,{class:`rounded-xl border border-slate-200 p-3`,children:[B(`p`,{class:`m-0 font-extrabold text-slate-700`,children:`전송되는 정보`}),B(`p`,{class:`mt-1 mb-0`,children:`메모리·부하·저장 공간 수치, 진단 상태, 이상 코드와 보고 시각`})]}),B(`div`,{class:`rounded-xl border border-slate-200 p-3`,children:[B(`p`,{class:`m-0 font-extrabold text-slate-700`,children:`전송하지 않는 정보`}),B(`p`,{class:`mt-1 mb-0`,children:`호스트명, WAN IP, Wi-Fi SSID/MAC, DNS 요청 내용, 시스템 로그 원문`})]})]})]})]})]})}function yv(e){let[t,n]=N(!1);return B(`label`,{class:`block min-w-0`,for:e.id,children:[B(`span`,{class:`mb-2 block text-sm font-extrabold text-slate-800`,children:e.label}),B(`span`,{class:`relative block min-w-0`,children:[B(`input`,{autoComplete:e.autoComplete,class:`min-h-11 w-full rounded-xl border border-slate-300 bg-white px-3 py-2.5 pr-12 text-sm font-bold text-slate-900 outline-none transition focus:border-teal-500 focus:ring-2 focus:ring-teal-100 disabled:cursor-wait disabled:opacity-60`,disabled:e.disabled,id:e.id,name:e.name,onInput:t=>e.onInput(t.currentTarget.value),placeholder:e.placeholder,type:t?`text`:`password`,value:e.value}),B(`button`,{"aria-label":t?`${e.label} 숨기기`:`${e.label} 표시`,"aria-pressed":t,class:`absolute inset-y-0 right-1 my-auto flex size-9 items-center justify-center rounded-lg text-slate-500 transition hover:bg-slate-100 hover:text-slate-800 disabled:opacity-50`,disabled:e.disabled,onClick:()=>n(e=>!e),title:t?`비밀번호 숨기기`:`비밀번호 표시`,type:`button`,children:B(t?Jt:qt,{class:`size-4`})})]})]})}function bv(e){return B(`li`,{class:`flex min-w-0 items-center gap-1.5 text-xs font-bold ${e.met?`text-emerald-700`:`text-slate-500`}`,children:[B(Xt,{class:`size-3.5 shrink-0`,"aria-hidden":`true`}),B(`span`,{children:e.label})]})}function xv(e){let[t,n]=N(``),[r,i]=N(``),[a,o]=N(``),[s,c]=N(!1),[l,u]=N(null),d=mn(r),f=hn(d),p=a.length>0&&r===a,m=t.length>0&&r.length>0&&t!==r,h=!s&&m&&f&&p,g=async()=>{if(u(null),!t){u(`현재 관리자 비밀번호를 입력해 주세요.`);return}if(!f){u(`새 비밀번호는 8자 이상이며 영문과 숫자를 각각 하나 이상 포함해야 합니다.`);return}if(t===r){u(`새 관리자 비밀번호는 현재 비밀번호와 다르게 설정해 주세요.`);return}if(r!==a){u(`새 비밀번호 확인 값이 일치하지 않습니다.`);return}c(!0);try{await av(t,r),n(``),i(``),o(``);try{await je()}catch{}c(!1),e.onChanged()}catch(e){u(G(e,`관리자 비밀번호를 변경하지 못했습니다. 잠시 후 다시 시도해 주세요.`)),c(!1)}};return B(dv,{description:`현재 비밀번호를 확인한 뒤 공유기 관리자 비밀번호를 변경합니다. 변경이 완료되면 새 비밀번호로 다시 로그인해야 합니다.`,icon:B(Kt,{class:`size-5`}),title:`관리자 비밀번호`,children:B(`form`,{class:`space-y-4`,noValidate:!0,onSubmit:e=>{e.preventDefault(),g()},children:[l&&B(`div`,{"aria-live":`polite`,class:`rounded-xl border border-rose-200 bg-rose-50 px-4 py-3 text-sm font-bold text-rose-800`,role:`alert`,children:l}),B(yv,{autoComplete:`current-password`,disabled:s,id:`smartsafehub-current-admin-password`,label:`현재 비밀번호`,name:`current-password`,onInput:n,placeholder:`현재 관리자 비밀번호`,value:t}),B(yv,{autoComplete:`new-password`,disabled:s,id:`smartsafehub-new-admin-password`,label:`새 비밀번호`,name:`new-password`,onInput:i,placeholder:`새 관리자 비밀번호`,value:r}),B(`ul`,{"aria-label":`새 비밀번호 요구 사항`,class:`m-0 grid list-none grid-cols-1 gap-2 p-0 sm:grid-cols-3`,children:[B(bv,{label:`8자 이상`,met:d.length}),B(bv,{label:`영문자 포함`,met:d.letter}),B(bv,{label:`숫자 포함`,met:d.number})]}),B(yv,{autoComplete:`new-password`,disabled:s,id:`smartsafehub-confirm-admin-password`,label:`새 비밀번호 확인`,name:`confirm-password`,onInput:o,placeholder:`새 관리자 비밀번호 다시 입력`,value:a}),a.length>0&&B(`p`,{"aria-live":`polite`,class:`m-0 text-xs font-bold ${p?`text-emerald-700`:`text-rose-700`}`,role:`status`,children:p?`새 비밀번호가 일치합니다.`:`새 비밀번호 확인 값이 일치하지 않습니다.`}),r.length>0&&t===r&&B(`p`,{class:`m-0 text-xs font-bold text-amber-700`,children:`새 비밀번호는 현재 비밀번호와 다르게 설정해 주세요.`}),B(`div`,{class:`rounded-xl border border-slate-200 bg-slate-50 p-3 text-xs leading-5 text-slate-600`,children:`비밀번호는 현재 공유기에 직접 적용되며 외부 서버로 전송되지 않습니다. 변경 후 현재 로그인 세션은 종료됩니다.`}),B(`div`,{class:`rounded-xl border border-amber-200 bg-amber-50 p-3 text-xs leading-5 text-amber-900`,children:[B(`strong`,{class:`block font-extrabold`,children:`비밀번호를 잊었을 때`}),`전원이 켜진 상태에서 Reset 버튼을 5~9초 누른 뒤 놓으면 관리자 비밀번호만 복구할 수 있습니다. 네트워크, Wi-Fi와 SafeShield 설정은 유지됩니다. 10초 이상 누르면 모든 사용자 설정을 초기화하는 기기 초기화가 실행됩니다.`]}),B(`div`,{class:`flex justify-end`,children:B(`button`,{class:`inline-flex min-h-11 w-full items-center justify-center rounded-xl bg-teal-700 px-4 py-2.5 text-sm font-extrabold text-white transition hover:bg-teal-800 disabled:cursor-not-allowed disabled:opacity-50 sm:w-auto`,disabled:!h,type:`submit`,children:s?`비밀번호 변경 중`:`비밀번호 변경`})})]})})}function Sv(e){let t=F(null),[n,r]=N(null),[i,a]=N(!1),o=e.action!==null;P(()=>{e.validated||a(!1)},[e.validated]);let s=()=>{!o&&!e.restoreAccepted&&t.current?.click()},c=async()=>{n&&await e.onUpload(n)&&(r(null),t.current&&(t.current.value=``))};return B(dv,{description:`펌웨어 업데이트나 복구 전에 현재 OpenWrt 설정을 표준 백업 파일로 저장하고, 필요할 때 검증 후 복원합니다.`,icon:B(Gt,{class:`size-5`}),title:`설정 백업 및 복원`,children:[(e.error||e.message)&&B(`div`,{class:`mb-5 flex min-w-0 items-start justify-between gap-3 rounded-xl border px-4 py-3 text-sm font-bold ${e.error?`border-rose-200 bg-rose-50 text-rose-800`:`border-emerald-200 bg-emerald-50 text-emerald-800`}`,children:[B(`span`,{class:`min-w-0`,children:e.error||e.message}),!e.restoreAccepted&&B(`button`,{class:`shrink-0 rounded-lg px-2 py-1 text-xs font-extrabold hover:bg-black/5`,onClick:e.onDismissFeedback,type:`button`,children:`닫기`})]}),B(`div`,{class:`grid min-w-0 grid-cols-1 gap-3`,children:[B(`div`,{class:`rounded-xl border border-slate-200 bg-slate-50 p-4 sm:p-5`,children:[B(`p`,{class:`m-0 text-sm font-black text-slate-900`,children:`현재 설정 백업`}),B(`p`,{class:`mt-2 mb-0 text-xs leading-5 text-slate-600`,children:`네트워크, Wi-Fi, SmartSafeHub와 SafeShield 등 OpenWrt가 관리하는 설정을 표준 백업 파일로 저장합니다.`}),B(`button`,{class:`mt-4 inline-flex min-h-11 w-full items-center justify-center gap-2 rounded-xl bg-teal-700 px-4 py-2.5 text-sm font-extrabold text-white transition hover:bg-teal-800 disabled:cursor-wait disabled:opacity-60 sm:w-auto`,disabled:o||e.restoreAccepted,onClick:e.onDownload,type:`button`,children:[B(Wt,{class:`size-4`}),e.action===`download`?`백업 생성 중`:`설정 백업 다운로드`]}),B(`p`,{class:`mt-3 mb-0 text-xs font-bold leading-5 text-amber-700`,children:`백업에는 Wi-Fi 비밀번호, 관리자 설정, VPN 키나 라이선스 정보 같은 민감한 값이 포함될 수 있으므로 안전한 위치에 보관해 주세요.`})]}),B(`div`,{class:`rounded-xl border border-slate-200 bg-white p-4 sm:p-5`,children:[B(`p`,{class:`m-0 text-sm font-black text-slate-900`,children:`설정 복원`}),B(`p`,{class:`mt-2 mb-0 text-xs leading-5 text-slate-600`,children:`SmartSafeHub 또는 OpenWrt 백업을 업로드하고 검증한 뒤 복원합니다. 최대 16MB까지 사용할 수 있습니다.`}),e.validated?B(`div`,{class:`mt-4 rounded-xl border border-emerald-200 bg-emerald-50 p-4`,children:[B(`div`,{class:`flex min-w-0 flex-col gap-1 sm:flex-row sm:items-center sm:justify-between`,children:B(`div`,{class:`min-w-0`,children:[B(`p`,{class:`m-0 break-words text-sm font-extrabold text-emerald-900`,children:e.validated.filename}),B(`p`,{class:`mt-1 mb-0 text-xs font-bold text-emerald-700`,children:[Ma(e.validated.sizeBytes),` · 검증 완료`]})]})}),i?B(`div`,{class:`mt-4 rounded-xl border border-rose-200 bg-white p-4`,children:[B(`p`,{class:`m-0 text-sm font-black text-rose-900`,children:`현재 설정을 백업 파일의 내용으로 덮어쓰시겠습니까?`}),B(`p`,{class:`mt-2 mb-0 text-xs leading-5 text-rose-700`,children:`LAN 주소, Wi-Fi, 관리자 접속 정보가 바뀌어 현재 연결이 끊길 수 있습니다. 복원 직후 공유기가 자동으로 재부팅됩니다. 같은 장치와 호환되는 백업만 사용해 주세요.`}),B(`div`,{class:`mt-4 flex flex-col gap-3 sm:flex-row sm:flex-wrap`,children:[B(`button`,{class:`inline-flex min-h-10 w-full items-center justify-center rounded-xl border border-slate-300 bg-white px-4 py-2 text-sm font-extrabold text-slate-700 transition hover:bg-slate-50 disabled:opacity-60 sm:w-auto`,disabled:o,onClick:()=>a(!1),type:`button`,children:`취소`}),B(`button`,{class:`inline-flex min-h-10 w-full items-center justify-center rounded-xl bg-rose-700 px-4 py-2 text-sm font-extrabold text-white transition hover:bg-rose-800 disabled:cursor-wait disabled:opacity-60 sm:w-auto`,disabled:o,onClick:()=>void e.onRestore(),type:`button`,children:e.action===`restore`?`설정 복원 중`:`설정 복원 및 재부팅`})]})]}):B(`div`,{class:`mt-4 flex flex-col gap-3 sm:flex-row sm:flex-wrap`,children:[B(`button`,{class:`inline-flex min-h-10 w-full items-center justify-center rounded-xl border border-slate-300 bg-white px-4 py-2 text-sm font-extrabold text-slate-700 transition hover:bg-slate-50 disabled:opacity-60 sm:w-auto`,disabled:o||e.restoreAccepted,onClick:()=>void e.onDiscard(),type:`button`,children:e.action===`discard`?`파일 삭제 중`:`파일 삭제`}),B(`button`,{class:`inline-flex min-h-10 w-full items-center justify-center rounded-xl bg-amber-600 px-4 py-2 text-sm font-extrabold text-white transition hover:bg-amber-700 disabled:opacity-60 sm:w-auto`,disabled:o||e.restoreAccepted,onClick:()=>a(!0),type:`button`,children:`복원 준비`})]})]}):B(S,{children:[B(`input`,{accept:`.tar.gz,.tgz,application/gzip,application/x-gzip`,class:`sr-only`,disabled:o||e.restoreAccepted,onChange:e=>r(e.currentTarget.files?.[0]??null),ref:t,type:`file`}),B(`button`,{class:`mt-4 flex min-h-11 w-full items-center justify-between gap-3 rounded-xl border border-dashed border-slate-300 bg-slate-50 px-4 py-3 text-left text-sm font-bold text-slate-700 transition hover:border-teal-400 hover:bg-teal-50 disabled:cursor-wait disabled:opacity-60`,disabled:o||e.restoreAccepted,onClick:s,type:`button`,children:[B(`span`,{class:`min-w-0 truncate`,children:n?.name??`복원할 백업 파일 선택`}),B(`span`,{class:`shrink-0 text-xs font-extrabold text-teal-700`,children:`찾아보기`})]}),n&&B(`div`,{class:`mt-3 flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between`,children:[B(`span`,{class:`text-xs font-bold text-slate-500`,children:Ma(n.size)}),B(`button`,{class:`inline-flex min-h-10 w-full items-center justify-center rounded-xl border border-teal-300 bg-white px-4 py-2 text-sm font-extrabold text-teal-800 transition hover:bg-teal-50 disabled:cursor-wait disabled:opacity-60 sm:w-auto`,disabled:o||e.restoreAccepted,onClick:()=>void c(),type:`button`,children:e.action===`upload`?`업로드 중 ${Math.round(e.uploadProgress??0)}%`:e.action===`validate`?`백업 검증 중`:`업로드 및 검증`})]})]})]})]})]})}function Cv(e){return B(dv,{description:`공유기 재부팅과 SmartSafeHub에서 제공하지 않는 고급 관리 도구를 한곳에서 제공합니다.`,...e.className===void 0?{}:{className:e.className},icon:B(It,{class:`size-5`}),title:`시스템 도구`,children:B(`div`,{class:`space-y-3`,children:[B(`section`,{"aria-labelledby":`router-reboot-heading`,class:`rounded-xl border border-slate-200 bg-slate-50 p-4`,children:[B(`div`,{class:`flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between`,children:[B(`div`,{class:`flex min-w-0 items-start gap-3`,children:[B(`span`,{class:`flex size-9 shrink-0 items-center justify-center rounded-lg bg-rose-50 text-rose-700`,children:B(Ut,{class:`size-4`})}),B(`div`,{class:`min-w-0`,children:[B(`p`,{class:`m-0 text-sm font-black text-rose-950`,id:`router-reboot-heading`,children:`공유기 재부팅`}),B(`p`,{class:`mt-1 mb-0 text-xs leading-5 text-slate-500`,children:`재부팅 중에는 인터넷과 Wi-Fi 연결이 잠시 중단됩니다.`})]})]}),!e.confirmingReboot&&B(`button`,{class:`inline-flex min-h-10 w-full shrink-0 items-center justify-center rounded-xl border border-rose-300 bg-white px-3 py-2 text-xs font-extrabold text-rose-700 transition hover:bg-rose-50 disabled:opacity-60 sm:w-auto`,disabled:e.action!==null||e.rebootAccepted,onClick:e.onConfirmReboot,type:`button`,children:`재부팅`})]}),e.confirmingReboot&&B(`div`,{class:`mt-3 rounded-xl border border-rose-200 bg-rose-50 p-3`,children:[B(`p`,{class:`m-0 text-xs font-extrabold leading-5 text-rose-900`,children:`지금 공유기를 재부팅하시겠습니까? 저장되지 않은 LuCI 설정이 있다면 먼저 저장해 주세요.`}),B(`div`,{class:`mt-3 flex flex-col gap-2 sm:flex-row sm:flex-wrap`,children:[B(`button`,{class:`inline-flex min-h-10 w-full items-center justify-center rounded-xl border border-slate-300 bg-white px-3 py-2 text-xs font-extrabold text-slate-700 transition hover:bg-slate-50 sm:w-auto`,disabled:e.action!==null,onClick:e.onCancelReboot,type:`button`,children:`취소`}),B(`button`,{class:`inline-flex min-h-10 w-full items-center justify-center rounded-xl bg-rose-700 px-3 py-2 text-xs font-extrabold text-white transition hover:bg-rose-800 disabled:cursor-wait disabled:opacity-60 sm:w-auto`,disabled:e.action!==null,onClick:e.onReboot,type:`button`,children:e.action===`reboot`?`재부팅 요청 중`:`지금 재부팅`})]})]})]}),B(`section`,{"aria-labelledby":`advanced-tools-heading`,class:`rounded-xl border border-slate-200 bg-slate-50 p-4`,children:[B(`div`,{class:`min-w-0`,children:[B(`p`,{class:`m-0 text-sm font-black text-slate-900`,id:`advanced-tools-heading`,children:`고급 도구`}),B(`p`,{class:`mt-1 mb-0 text-xs leading-5 text-slate-500`,children:`SmartSafeHub에서 아직 제공하지 않는 상세 시스템 설정이나 원본 로그가 필요할 때 사용합니다.`})]}),B(`div`,{class:`mt-3 flex flex-col gap-2 sm:flex-row sm:flex-wrap`,children:[B(`a`,{class:`inline-flex min-h-10 w-full items-center justify-center rounded-xl border border-slate-300 bg-white px-3 py-2 text-xs font-extrabold text-slate-800 no-underline transition hover:bg-slate-50 sm:w-auto`,href:e.advancedSystemUrl,children:`LuCI 고급 설정 열기`}),B(`a`,{class:`inline-flex min-h-10 w-full items-center justify-center rounded-xl border border-slate-300 bg-white px-3 py-2 text-xs font-extrabold text-slate-800 no-underline transition hover:bg-slate-50 sm:w-auto`,href:e.logsUrl,children:`시스템 로그 열기`})]})]})]})})}var wv=[{value:`mon`,label:`월요일`},{value:`tue`,label:`화요일`},{value:`wed`,label:`수요일`},{value:`thu`,label:`목요일`},{value:`fri`,label:`금요일`},{value:`sat`,label:`토요일`},{value:`sun`,label:`일요일`}];function Tv(e){let[t,n]=N(!1),[r,i]=N(`weekly`),[a,o]=N(`sun`),[s,c]=N(`04:00`);P(()=>{e.data&&(n(e.data.enabled),i(e.data.frequency),o(e.data.dayOfWeek),c(e.data.time))},[e.data?.dayOfWeek,e.data?.enabled,e.data?.frequency,e.data?.time]);let l=e.data!==null&&(t!==e.data.enabled||r!==e.data.frequency||a!==e.data.dayOfWeek||s!==e.data.time),u=wv.find(e=>e.value===a),d=t?r===`daily`?`매일 ${s}`:`매주 ${u?.label??`일요일`} ${s}`:`예약 재부팅 꺼짐`;return B(`section`,{"aria-labelledby":`scheduled-reboot-heading`,class:`mt-6 border-t border-slate-200 pt-6`,children:[B(`div`,{class:`flex flex-col gap-4 sm:flex-row sm:items-start sm:justify-between`,children:[B(`div`,{class:`flex min-w-0 items-start gap-3`,children:[B(`span`,{class:`flex size-10 shrink-0 items-center justify-center rounded-xl bg-slate-100 text-slate-600`,children:B(Yt,{class:`size-5`})}),B(`div`,{class:`min-w-0`,children:[B(`h3`,{class:`m-0 text-base font-black text-slate-950`,id:`scheduled-reboot-heading`,children:`예약 재부팅`}),B(`p`,{class:`mt-1.5 mb-0 text-xs leading-5 text-slate-500`,children:`공유기를 정해진 시간에 자동으로 재부팅합니다. 기본값은 꺼짐이며 필요한 장치에서만 사용하세요.`})]})]}),B(`div`,{class:`flex shrink-0 flex-wrap items-center justify-between gap-3 sm:justify-end`,children:[l&&B(`span`,{"aria-live":`polite`,class:`inline-flex items-center gap-1.5 rounded-full border border-amber-200 bg-amber-50 px-2.5 py-1 text-xs font-extrabold text-amber-800`,role:`status`,children:[B(U,{"aria-hidden":`true`,class:`size-3.5 shrink-0`}),`저장되지 않음`]}),B(`span`,{class:`text-xs font-extrabold text-slate-500`,children:t?`사용 중`:`꺼짐`}),B(`button`,{"aria-checked":t,"aria-label":`예약 재부팅 사용`,class:`ssh-switch-control relative inline-flex shrink-0 rounded-full border transition focus:outline-none focus-visible:ring-4 focus-visible:ring-teal-100 disabled:cursor-not-allowed disabled:opacity-50 ${t?`border-teal-600 bg-teal-600`:`border-slate-300 bg-slate-200`}`,disabled:e.loading||e.saving||!e.data,onClick:()=>n(e=>!e),role:`switch`,type:`button`,children:B(`span`,{"aria-hidden":`true`,class:`ssh-switch-thumb absolute top-1 shadow-sm transition-[left] ${t?`left-6`:`left-1`}`})})]})]}),(e.saveError||e.saveMessage)&&B(`div`,{class:`mt-4 flex min-w-0 items-start justify-between gap-3 rounded-xl border px-4 py-3 text-sm font-bold ${e.saveError?`border-rose-200 bg-rose-50 text-rose-800`:`border-emerald-200 bg-emerald-50 text-emerald-800`}`,children:[B(`span`,{class:`min-w-0`,children:e.saveError||e.saveMessage}),B(`button`,{class:`shrink-0 rounded-lg px-2 py-1 text-xs font-extrabold hover:bg-black/5`,onClick:e.onDismissFeedback,type:`button`,children:`닫기`})]}),e.error&&!e.data?B(`div`,{class:`mt-4 rounded-xl border border-rose-200 bg-rose-50 p-4`,children:[B(`p`,{class:`m-0 text-sm font-bold text-rose-800`,children:e.error}),B(`button`,{class:`mt-3 inline-flex min-h-10 items-center rounded-xl border border-rose-300 bg-white px-3 py-2 text-xs font-extrabold text-rose-700 transition hover:bg-rose-100`,onClick:e.onRetry,type:`button`,children:`다시 불러오기`})]}):B(S,{children:[B(`div`,{class:`mt-4 grid min-w-0 grid-cols-1 gap-4 md:grid-cols-3`,children:[B(`div`,{children:[B(`label`,{class:`mb-2 block text-sm font-extrabold text-slate-800`,for:`scheduled-reboot-frequency`,children:`주기`}),B(Vg,{ariaLabel:`예약 재부팅 주기`,disabled:!t||e.saving||!e.data,id:`scheduled-reboot-frequency`,onChange:e=>i(e),options:[{value:`weekly`,label:`매주`},{value:`daily`,label:`매일`}],value:r})]}),B(`div`,{children:[B(`label`,{class:`mb-2 block text-sm font-extrabold text-slate-800`,for:`scheduled-reboot-day`,children:`요일`}),B(Vg,{ariaLabel:`예약 재부팅 요일`,disabled:!t||r!==`weekly`||e.saving||!e.data,id:`scheduled-reboot-day`,onChange:e=>o(e),options:wv.map(e=>({value:e.value,label:e.label})),value:a})]}),B(`div`,{children:[B(`label`,{class:`mb-2 block text-sm font-extrabold text-slate-800`,for:`scheduled-reboot-time-hour`,children:`재부팅 시간`}),B(lv,{ariaLabel:`예약 재부팅 시간`,disabled:!t||e.saving||!e.data,id:`scheduled-reboot-time`,onChange:c,value:s})]})]}),B(`div`,{class:`mt-4 flex flex-col gap-3 rounded-xl bg-slate-50 p-4 sm:flex-row sm:items-end sm:justify-between`,children:[B(`div`,{class:`min-w-0`,children:[B(`p`,{class:`m-0 text-xs font-extrabold uppercase tracking-[0.12em] text-slate-500`,children:`예약 일정`}),B(`p`,{class:`mt-1.5 mb-0 text-sm font-extrabold text-slate-900`,children:d}),B(`p`,{class:`mt-1 mb-0 text-xs leading-5 text-slate-500`,children:[e.data?.timezone??`장치 시간대`,` 기준 · 업데이트 작업 중이면 15분 단위로 최대 2시간 연기합니다.`]})]}),B(`button`,{class:`inline-flex min-h-11 w-full shrink-0 items-center justify-center rounded-xl bg-teal-700 px-4 py-2.5 text-sm font-extrabold text-white transition hover:bg-teal-800 disabled:cursor-not-allowed disabled:opacity-50 sm:w-auto`,disabled:!l||e.saving||!e.data,onClick:()=>void e.onSave({enabled:t,frequency:r,dayOfWeek:a,time:s}),type:`button`,children:e.saving?`예약 저장 중`:`예약 저장`})]})]})]})}function Ev({action:e,backupAction:t,backupError:n,backupMessage:r,backupRestoreAccepted:i,backupUploadProgress:a,backupValidated:o,data:s,error:c,feedbackError:l,feedbackMessage:u,firmware:d,firmwareError:f,firmwareLoading:p,health:m,healthActionError:h,healthActionMessage:g,healthError:_,healthLoading:v,healthRunning:y,healthSavingReporter:b,loading:x,rebootAccepted:S,scheduledRebootData:C,scheduledRebootError:w,scheduledRebootLoading:T,scheduledRebootSaveError:E,scheduledRebootSaveMessage:D,scheduledRebootSaving:O,timeData:k,timeError:A,timeLoading:ee,timeSaveError:j,timeSaveMessage:te,timeSaving:ne,timeSyncing:M,onBackupDiscard:re,onBackupDownload:ie,onBackupRestore:ae,onBackupUpload:oe,onDismissBackupFeedback:se,onDismissFeedback:ce,onDismissHealthFeedback:le,onDismissTimeFeedback:ue,onDownloadDiagnostics:de,onRunHealth:fe,onSetHealthReporter:pe,onReboot:me,onRetry:he,onDismissScheduledRebootFeedback:ge,onSaveScheduledReboot:_e,onSaveTimezone:ve,onSyncTime:ye,onAdministratorPasswordChanged:be}){let[xe,Se]=N(!1);if(x&&!s)return B(`div`,{class:`rounded-2xl border border-slate-200 bg-white p-8 text-center shadow-sm shadow-slate-900/5`,children:B(`p`,{class:`m-0 text-sm font-bold text-slate-500`,children:`시스템 정보를 확인하고 있습니다.`})});if(c&&!s)return B(`div`,{class:`rounded-2xl border border-rose-200 bg-rose-50 p-6`,children:[B(`h2`,{class:`m-0 text-lg font-black text-rose-900`,children:`시스템 정보를 불러오지 못했습니다.`}),B(`p`,{class:`mt-2 mb-0 text-sm leading-6 text-rose-700`,children:c}),B(`button`,{class:`mt-4 inline-flex min-h-10 items-center rounded-xl bg-rose-700 px-4 py-2 text-sm font-extrabold text-white transition hover:bg-rose-800`,onClick:he,type:`button`,children:`다시 시도`})]});let we=s?.runtime.memory,Te=we?.total??0,Ee=we?za(we):null,De=Ee?.used??0,Oe=Math.round(Ee?.percent??0),ke=Ce(`/admin/system`),Ae=Ce(`/admin/status/logs`),je=!!d?.current.metadataAvailable,Me=s?p&&!d?`확인 중`:f&&!d?`확인 필요`:je?d?.current.releaseVersion?`SmartSafeHub ${d.current.releaseVersion}`:`SmartSafeHub 펌웨어`:`${s.software.distribution} ${s.software.version}`:`미확인`,Ne=s?p&&!d?`펌웨어 정보를 확인하고 있습니다.`:f&&!d?f:je?d?.current.buildId?`빌드 ID ${d.current.buildId}`:`빌드 ID를 확인할 수 없습니다.`:`리비전 ${s.software.revision}`:`버전 정보를 확인할 수 없습니다.`;return B(`section`,{class:`min-w-0 space-y-7`,children:[(l||u)&&B(`div`,{class:`flex min-w-0 flex-col gap-3 rounded-xl border px-4 py-3 text-sm font-bold sm:flex-row sm:items-center sm:justify-between ${l?`border-rose-200 bg-rose-50 text-rose-800`:`border-emerald-200 bg-emerald-50 text-emerald-800`}`,children:[B(`span`,{class:`min-w-0`,children:l||u}),!S&&B(`button`,{class:`shrink-0 self-start rounded-lg px-3 py-1.5 text-xs font-extrabold hover:bg-black/5 sm:self-auto`,onClick:ce,type:`button`,children:`닫기`})]}),B(`section`,{class:`min-w-0`,children:[B(`div`,{class:`mb-4`,children:[B(`p`,{class:`m-0 text-xs font-extrabold uppercase tracking-[0.16em] text-teal-700`,children:`System`}),B(`h2`,{class:`mt-2 mb-0 text-xl font-black text-slate-950`,children:`시스템 상태`}),B(`p`,{class:`mt-2 mb-0 text-sm leading-6 text-slate-500`,children:`장치의 펌웨어, 실행 시간, 메모리와 시스템 부하를 확인합니다.`})]}),B(`div`,{class:`grid min-w-0 grid-cols-1 gap-4 sm:grid-cols-2 xl:grid-cols-4`,children:[B(uv,{label:`Firmware`,value:Me,description:Ne}),B(uv,{label:`Uptime`,value:s?ja(s.runtime.uptime):`미확인`,description:s?`커널 ${s.software.kernel}`:`실행 시간을 확인할 수 없습니다.`}),B(uv,{label:`Memory`,value:`${Oe}%`,description:`${Ma(De)} / ${Ma(Te)} 사용`}),B(uv,{label:`Load`,value:s?Na(s.runtime.load[0]):`0.00`,description:s?`5분 ${Na(s.runtime.load[1])} · 15분 ${Na(s.runtime.load[2])}`:`시스템 부하를 확인할 수 없습니다.`})]})]}),B(`section`,{class:`min-w-0`,children:[B(`div`,{class:`mb-4`,children:[B(`p`,{class:`m-0 text-xs font-extrabold uppercase tracking-[0.16em] text-teal-700`,children:`Device settings`}),B(`h2`,{class:`mt-2 mb-0 text-xl font-black text-slate-950`,children:`장치 설정`}),B(`p`,{class:`mt-2 mb-0 text-sm leading-6 text-slate-500`,children:`시간 기준과 예약 재부팅, 진단 정보를 SmartSafeHub에서 직접 관리합니다.`})]}),B(`div`,{class:`grid min-w-0 grid-cols-1 gap-4 lg:grid-cols-2`,children:[B(pv,{data:k,error:A,loading:ee,onDismissFeedback:ue,onDismissScheduledRebootFeedback:ge,onRetry:he,onSave:ve,onSaveScheduledReboot:_e,onSync:ye,saveError:j,saveMessage:te,saving:ne,scheduledRebootData:C,scheduledRebootError:w,scheduledRebootLoading:T,scheduledRebootSaveError:E,scheduledRebootSaveMessage:D,scheduledRebootSaving:O,syncing:M}),B(vv,{actionError:h,actionMessage:g,data:m,downloadBusy:e===`diagnostics`,error:_,loading:v,onDismissFeedback:le,onDownload:de,onRetry:he,onRun:fe,onSetReporter:pe,running:y,savingReporter:b})]})]}),B(`section`,{class:`min-w-0`,children:[B(`div`,{class:`mb-4`,children:[B(`p`,{class:`m-0 text-xs font-extrabold uppercase tracking-[0.16em] text-teal-700`,children:`System management`}),B(`h2`,{class:`mt-2 mb-0 text-xl font-black text-slate-950`,children:`시스템 관리`}),B(`p`,{class:`mt-2 mb-0 text-sm leading-6 text-slate-500`,children:`관리자 비밀번호, 설정 백업·복원과 공유기 시스템 도구를 한곳에서 관리합니다.`})]}),B(`div`,{class:`grid min-w-0 grid-cols-1 gap-4 lg:grid-cols-2`,children:[B(xv,{onChanged:be}),B(Sv,{action:t,error:n,message:r,onDiscard:re,onDismissFeedback:se,onDownload:ie,onRestore:ae,onUpload:oe,restoreAccepted:i,uploadProgress:a,validated:o}),B(Cv,{action:e,className:`lg:col-span-2`,advancedSystemUrl:ke,confirmingReboot:xe,logsUrl:Ae,onCancelReboot:()=>Se(!1),onConfirmReboot:()=>Se(!0),onReboot:me,rebootAccepted:S})]})]})]})}function Dv(e){return!e||e<=0?`미확인`:e>=1048576?`${(e/1048576).toFixed(1)} MB`:`${(e/1024).toFixed(1)} KB`}function Ov(e){return e?new Date(e*1e3).toLocaleString(`ko-KR`,{dateStyle:`medium`,timeStyle:`short`}):`아직 없음`}function kv(e){switch(e.phase){case`checking`:return`확인 중`;case`downloading`:return`다운로드 중`;case`verifying`:return`검증 중`;case`ready`:return`설치 준비 완료`;case`flashing`:return`설치 중`;case`error`:return`확인 필요`;default:return e.updateAvailable?`업데이트 가능`:e.lastCheckAt?`최신 상태`:`확인 전`}}function Av(e){return e.phase===`error`?`bg-rose-50 text-rose-700 ring-rose-200`:e.phase===`checking`||e.phase===`downloading`||e.phase===`verifying`||e.phase===`flashing`?`bg-sky-50 text-sky-700 ring-sky-200`:e.phase===`ready`||e.updateAvailable?`bg-amber-50 text-amber-800 ring-amber-200`:e.lastCheckAt?`bg-emerald-50 text-emerald-700 ring-emerald-200`:`bg-slate-100 text-slate-600 ring-slate-200`}function jv(e){return e.phase===`checking`||e.phase===`downloading`||e.phase===`verifying`||e.phase===`flashing`?B(H,{class:`size-3.5 animate-spin`}):e.phase===`error`?B(U,{class:`size-3.5`}):e.phase===`ready`||e.updateAvailable?B(Wt,{class:`size-3.5`}):e.lastCheckAt?B(Xt,{class:`size-3.5`}):B(Vt,{class:`size-3.5`})}function Mv({checked:e,disabled:t,onChange:n}){return B(`button`,{"aria-checked":e,"aria-label":`현재 설정 유지`,class:`ssh-switch-control relative inline-flex shrink-0 rounded-full border transition focus:outline-none focus-visible:ring-4 focus-visible:ring-teal-100 disabled:cursor-not-allowed disabled:opacity-50 ${e?`border-teal-600 bg-teal-600`:`border-slate-300 bg-slate-200`}`,disabled:t,onClick:()=>n(!e),role:`switch`,type:`button`,children:B(`span`,{"aria-hidden":`true`,class:`ssh-switch-thumb absolute top-1 shadow-sm transition-[left] ${e?`left-6`:`left-1`}`})})}function Nv({action:e,actionError:t,data:n,error:r,loading:i,message:a,reconnecting:o,uploadProgress:s,onCheck:c,onDiscard:l,onDismissFeedback:u,onInstall:d,onPrepare:f,onRetry:p,onUpload:m}){let h=F(null),[g,_]=N(null),[v,y]=N(!0),[b,x]=N(!1);P(()=>{n?.prepared&&y(n.prepared.allowBackup)},[n?.prepared]);let C=e!==null||n?.phase===`checking`||n?.phase===`downloading`||n?.phase===`verifying`||n?.phase===`flashing`,w=n?.phase===`ready`?n.prepared:null,T=e===`check`||n?.phase===`checking`,E=e===`prepare`||n?.phase===`downloading`||n?.phase===`verifying`,D=e===`upload`||e===`validate-upload`,O=async()=>{g&&await m(g)&&(_(null),h.current&&(h.current.value=``))};return B(`article`,{class:`min-w-0 overflow-hidden rounded-2xl border border-slate-200 bg-white shadow-sm shadow-slate-900/5`,"data-component":`firmware-update-card`,children:[B(`div`,{class:`p-5 sm:p-6`,children:[B(`div`,{class:`flex flex-col gap-5 lg:flex-row lg:items-start lg:justify-between`,children:[B(`div`,{class:`flex min-w-0 gap-4`,children:[B(`span`,{class:`grid size-12 shrink-0 place-items-center rounded-2xl bg-sky-50 text-sky-700`,children:B(jt,{class:`size-6`})}),B(`div`,{class:`min-w-0`,children:[B(`p`,{class:`m-0 text-xs font-extrabold uppercase tracking-[0.16em] text-sky-700`,children:`Firmware update`}),B(`h2`,{class:`mt-2 mb-0 text-xl font-black text-slate-950 sm:text-2xl`,children:`펌웨어 업데이트`}),B(`p`,{class:`mt-2 mb-0 text-sm leading-6 text-slate-500 lg:whitespace-nowrap`,children:`시스템 펌웨어를 확인하고 설치합니다. 온라인·수동 설치는 안전성 검증 후 진행됩니다.`})]})]}),n?B(`div`,{class:`flex shrink-0 flex-col gap-2 sm:flex-row lg:justify-end`,children:[B(`span`,{class:`inline-flex min-h-11 items-center justify-center gap-1.5 rounded-xl px-3 py-2 text-xs font-extrabold ring-1 ring-inset ${Av(n)}`,children:[jv(n),kv(n)]}),B(`button`,{class:`inline-flex min-h-11 items-center justify-center gap-2 rounded-xl border border-slate-300 bg-white px-4 py-2.5 text-sm font-extrabold text-slate-800 transition hover:bg-slate-50 disabled:cursor-wait disabled:opacity-60`,disabled:C||w!==null,onClick:c,type:`button`,children:[B(H,{class:`size-4 ${T?`animate-spin`:``}`}),T?`확인 중...`:`펌웨어 확인`]}),n.updateAvailable&&!w?B(`button`,{class:`inline-flex min-h-11 items-center justify-center gap-2 rounded-xl bg-sky-700 px-4 py-2.5 text-sm font-extrabold text-white transition hover:bg-sky-800 disabled:cursor-wait disabled:opacity-60`,disabled:C,onClick:f,type:`button`,children:[E?B(H,{class:`size-4 animate-spin`}):B(Wt,{class:`size-4`}),E?`준비 중...`:`다운로드 및 검증`]}):null]}):null]}),t||a?B(`div`,{class:`mt-5 flex flex-col gap-3 rounded-xl border px-4 py-3 text-sm font-bold sm:flex-row sm:items-center sm:justify-between ${t?`border-rose-200 bg-rose-50 text-rose-800`:`border-emerald-200 bg-emerald-50 text-emerald-800`}`,children:[B(`span`,{children:t||a}),B(`button`,{class:`shrink-0 self-start rounded-lg px-3 py-1.5 text-xs font-extrabold hover:bg-black/5 sm:self-auto`,onClick:u,type:`button`,children:`닫기`})]}):null,o||n?.phase===`flashing`?B(`div`,{class:`mt-5 rounded-xl border border-amber-200 bg-amber-50 p-4 sm:p-5`,role:`status`,children:B(`div`,{class:`flex gap-3`,children:[B(`span`,{class:`grid size-10 shrink-0 place-items-center rounded-xl bg-white text-amber-700 ring-1 ring-inset ring-amber-200`,children:B(H,{class:`size-5 animate-spin`})}),B(`div`,{children:[B(`strong`,{class:`block text-sm font-black text-amber-950`,children:`펌웨어를 설치하고 재부팅하고 있습니다.`}),B(`p`,{class:`mt-1 mb-0 text-sm leading-6 text-amber-800`,children:`전원을 끄지 마세요. 현재 주소에서 공유기가 다시 응답하면 SmartSafeHub가 자동으로 새로고침됩니다.`})]})]})}):null,r&&!n?B(`div`,{class:`mt-5 rounded-xl border border-rose-200 bg-rose-50 p-4 text-sm text-rose-800`,children:[B(`p`,{class:`m-0 font-bold`,children:r}),B(`button`,{class:`mt-3 rounded-lg border border-rose-300 bg-white px-3 py-2 text-xs font-extrabold text-rose-700`,onClick:p,type:`button`,children:`다시 시도`})]}):i&&!n?B(`div`,{class:`mt-5 flex items-center gap-3 rounded-xl bg-slate-50 p-4 text-sm font-bold text-slate-500`,children:[B(H,{class:`size-4 animate-spin`}),`펌웨어 상태를 확인하고 있습니다.`]}):n?B(S,{children:[n.lastError?B(`div`,{class:`mt-5 rounded-xl border border-rose-200 bg-rose-50 p-4 sm:p-5`,children:B(`div`,{class:`flex gap-3`,children:[B(`span`,{class:`grid size-10 shrink-0 place-items-center rounded-xl bg-white text-rose-700 ring-1 ring-inset ring-rose-200`,children:B(U,{class:`size-5`})}),B(`div`,{class:`min-w-0 flex-1`,children:[B(`strong`,{class:`block text-sm font-black text-rose-950`,children:`펌웨어 작업을 완료하지 못했습니다.`}),B(`p`,{class:`mt-1 mb-0 text-sm leading-6 text-rose-800`,children:n.lastError.message}),B(`details`,{class:`mt-3 rounded-lg border border-rose-200 bg-white p-3`,children:[B(`summary`,{class:`cursor-pointer text-xs font-extrabold text-rose-800`,children:`상세 정보 보기`}),B(`p`,{class:`mt-2 mb-0 break-all font-mono text-[11px] text-slate-600`,children:n.lastError.code})]})]})]})}):null,n.current.metadataAvailable?null:B(`div`,{class:`mt-5 rounded-xl border border-amber-200 bg-amber-50 px-4 py-3 text-xs leading-5 text-amber-900`,children:[B(`strong`,{class:`block font-extrabold`,children:`현재 펌웨어의 버전 정보를 완전히 확인할 수 없습니다.`}),B(`span`,{class:`mt-1 block text-amber-800`,children:`새 펌웨어를 설치하면 이후부터 정확한 설치 버전을 자동으로 확인할 수 있습니다.`}),B(`details`,{class:`mt-2`,children:[B(`summary`,{class:`cursor-pointer font-extrabold text-amber-800`,children:`기술 상세 보기`}),B(`p`,{class:`mt-2 mb-0 break-all font-mono text-[11px] leading-5 text-amber-800`,children:`SmartSafeHub build ID metadata is missing. Future images should include /usr/share/smartsafehub/firmware.json.`})]})]}),B(`dl`,{class:`mt-5 grid overflow-hidden rounded-xl border border-slate-200 bg-slate-200 sm:grid-cols-2 xl:grid-cols-4`,children:[B(`div`,{class:`bg-white p-4`,children:[B(`dt`,{class:`text-[11px] font-black uppercase tracking-[0.16em] text-slate-400`,children:`Device`}),B(`dd`,{class:`mt-2 mb-0 ml-0 break-all text-sm font-black text-slate-950`,children:n.current.deviceCode||n.current.boardName||`미확인`})]}),B(`div`,{class:`bg-white p-4`,children:[B(`dt`,{class:`text-[11px] font-black uppercase tracking-[0.16em] text-slate-400`,children:`Current version`}),B(`dd`,{class:`mt-2 mb-0 ml-0 break-all text-sm font-black text-slate-950`,children:n.current.releaseVersion||`미확인`}),n.current.buildId?B(`span`,{class:`mt-1 block break-all text-[11px] leading-5 text-slate-400`,children:[`빌드 ID `,n.current.buildId]}):n.current.openwrtVersion?B(`span`,{class:`mt-1 block text-[11px] leading-5 text-slate-400`,children:[`OpenWrt `,n.current.openwrtVersion]}):null]}),B(`div`,{class:`bg-white p-4`,children:[B(`dt`,{class:`text-[11px] font-black uppercase tracking-[0.16em] text-slate-400`,children:`Available version`}),B(`dd`,{class:`mt-2 mb-0 ml-0 break-all text-sm font-black ${n.updateAvailable?`text-amber-700`:`text-slate-950`}`,children:n.lastCheckAt?n.release?.version?`${n.release.version}${n.updateAvailable?``:` · 최신`}`:n.updateAvailable?`새 펌웨어`:`최신 버전`:`미확인`}),n.release?.buildId?B(`span`,{class:`mt-1 block break-all text-[11px] leading-5 text-slate-400`,children:[`빌드 ID `,n.release.buildId]}):null]}),B(`div`,{class:`bg-white p-4`,children:[B(`dt`,{class:`text-[11px] font-black uppercase tracking-[0.16em] text-slate-400`,children:`Last check`}),B(`dd`,{class:`mt-2 mb-0 ml-0 text-sm font-black text-slate-950`,children:Ov(n.lastCheckAt)})]})]})]}):null,n?.updateAvailable&&n.release?B(`section`,{class:`mt-5 rounded-xl border border-sky-200 bg-sky-50/60 p-4 sm:p-5`,"data-section":`available-firmware`,children:[B(`div`,{class:`flex flex-col gap-2 sm:flex-row sm:items-start sm:justify-between sm:gap-4`,children:[B(`div`,{children:[B(`p`,{class:`m-0 text-xs font-extrabold uppercase tracking-[0.16em] text-sky-700`,children:`Available firmware`}),B(`h3`,{class:`mt-2 mb-0 text-lg font-black text-slate-950`,children:`새 펌웨어가 있습니다.`}),B(`p`,{class:`mt-2 mb-0 text-sm leading-6 text-slate-600`,children:[`펌웨어 `,n.release.version||`미확인`,` · `,Dv(n.release.sysupgrade.sizeBytes),` · `,(n.release.channel||n.settings.channel)===`beta`?`Beta`:`Stable`]})]}),B(`span`,{class:`shrink-0 rounded-full bg-white px-3 py-1.5 text-xs font-extrabold text-sky-700 ring-1 ring-inset ring-sky-200`,children:n.release.version||`Latest`})]}),n.release.releaseNotes.length?B(`ul`,{class:`mt-4 mb-0 space-y-2 rounded-xl bg-white p-4 pl-9 text-sm leading-6 text-slate-700 ring-1 ring-inset ring-sky-100`,children:n.release.releaseNotes.map((e,t)=>B(`li`,{children:e},`${t}-${e}`))}):null]}):null,w?B(`section`,{class:`mt-5 rounded-xl border border-amber-200 bg-amber-50 p-4 sm:p-5`,"data-section":`prepared-firmware`,children:B(`div`,{class:`flex gap-4`,children:[B(`span`,{class:`grid size-11 shrink-0 place-items-center rounded-xl bg-white text-amber-700 ring-1 ring-inset ring-amber-200`,children:B(Xt,{class:`size-5`})}),B(`div`,{class:`min-w-0 flex-1`,children:[B(`p`,{class:`m-0 text-xs font-extrabold uppercase tracking-[0.16em] text-amber-700`,children:`Verified image`}),B(`h3`,{class:`mt-2 mb-0 text-lg font-black text-amber-950`,children:`설치할 펌웨어가 준비되었습니다.`}),B(`p`,{class:`mt-2 mb-0 break-all text-sm leading-6 text-amber-900`,children:[w.filename||`firmware.bin`,` · `,Dv(w.sizeBytes)]}),w.sha256?B(`p`,{class:`mt-2 mb-0 break-all font-mono text-[11px] leading-5 text-amber-800`,children:[`SHA-256 `,w.sha256]}):null,B(`div`,{class:`mt-5 flex items-start justify-between gap-4 rounded-xl border border-amber-200 bg-white p-4`,children:[B(`div`,{children:[B(`strong`,{class:`block text-sm font-black text-slate-950`,children:`현재 설정 유지`}),B(`span`,{class:`mt-1 block text-xs leading-5 text-slate-500`,children:`Wi-Fi, SafeShield, SmartSafeHub 설정을 유지합니다.`}),w.allowBackup?null:B(`span`,{class:`mt-2 block text-xs font-bold text-rose-700`,children:`이 이미지는 설정 유지 업그레이드를 지원하지 않습니다.`})]}),B(Mv,{checked:v,disabled:!w.allowBackup,onChange:y})]}),b?B(`div`,{class:`mt-4 rounded-xl border border-rose-200 bg-rose-50 p-4`,children:[B(`strong`,{class:`block text-sm font-black text-rose-950`,children:`펌웨어 설치를 시작할까요?`}),B(`p`,{class:`mt-1 mb-0 text-xs leading-5 text-rose-800`,children:`설치 중 전원을 끄면 장치가 복구 불가능한 상태가 될 수 있습니다. 이미지 검증은 설치 직전에 다시 수행됩니다.`}),B(`div`,{class:`mt-4 flex flex-wrap justify-end gap-2`,children:[B(`button`,{class:`min-h-10 rounded-lg border border-slate-300 bg-white px-3 py-2 text-xs font-extrabold text-slate-700`,onClick:()=>x(!1),type:`button`,children:`취소`}),B(`button`,{class:`min-h-10 rounded-lg bg-rose-700 px-3 py-2 text-xs font-extrabold text-white`,onClick:()=>{x(!1),d(v)},type:`button`,children:`설치 시작`})]})]}):B(`div`,{class:`mt-4 flex flex-wrap justify-end gap-2`,children:[B(`button`,{class:`min-h-10 rounded-lg border border-slate-300 bg-white px-3 py-2 text-xs font-extrabold text-slate-700`,disabled:e===`discard`,onClick:()=>void l(),type:`button`,children:`파일 삭제`}),B(`button`,{class:`inline-flex min-h-10 items-center gap-2 rounded-lg bg-rose-700 px-4 py-2 text-xs font-extrabold text-white`,onClick:()=>x(!0),type:`button`,children:[B(Ft,{class:`size-4`}),`펌웨어 설치`]})]})]})]})}):null]}),B(`details`,{class:`group mx-5 mb-5 rounded-xl border border-slate-200 bg-slate-50/70 sm:mx-6 sm:mb-6`,"data-layout":`firmware-card-subsection`,"data-section":`manual-firmware`,children:[B(`summary`,{class:`flex cursor-pointer list-none items-center justify-between gap-4 px-4 py-4 sm:px-5 [&::-webkit-details-marker]:hidden`,children:[B(`div`,{class:`flex min-w-0 items-center gap-3`,children:[B(`span`,{class:`grid size-10 shrink-0 place-items-center rounded-xl bg-white text-slate-600 ring-1 ring-inset ring-slate-200`,children:B(Wt,{class:`size-5 rotate-180`})}),B(`div`,{class:`min-w-0`,children:[B(`strong`,{class:`block text-sm font-black text-slate-950`,children:`수동 펌웨어 설치`}),B(`span`,{class:`mt-1 block text-xs leading-5 text-slate-500`,children:`펌웨어 파일(.bin)을 직접 업로드하여 검증한 뒤 설치합니다.`})]})]}),B(`span`,{class:`shrink-0 rounded-full bg-white px-3 py-1.5 text-[11px] font-extrabold text-slate-600 ring-1 ring-inset ring-slate-200 group-open:hidden`,children:`열기`}),B(`span`,{class:`hidden shrink-0 rounded-full bg-white px-3 py-1.5 text-[11px] font-extrabold text-slate-600 ring-1 ring-inset ring-slate-200 group-open:inline-flex`,children:`닫기`})]}),B(`div`,{class:`border-t border-slate-200 px-5 pb-5 pt-3 sm:px-6`,children:[B(`p`,{class:`mt-0 mb-4 text-xs leading-5 text-slate-500 lg:whitespace-nowrap`,children:"이 장치에 맞는 Sysupgrade 이미지(.bin)만 사용하세요. 업로드한 파일은 이미지 검증과 `sysupgrade --test`를 모두 통과해야 설치할 수 있으며 강제 설치는 제공하지 않습니다."}),B(`div`,{class:`rounded-xl border border-slate-200 bg-white p-4 sm:p-5`,"data-layout":`firmware-file-picker`,children:[B(`input`,{accept:`.bin,application/octet-stream`,"aria-label":`펌웨어 파일 선택`,class:`sr-only`,disabled:C||w!==null,onChange:e=>_(e.currentTarget.files?.[0]??null),ref:h,type:`file`}),B(`div`,{class:`flex flex-col gap-4 sm:flex-row sm:items-center sm:justify-between`,children:[B(`div`,{class:`flex min-w-0 items-center gap-3`,children:[B(`span`,{class:`grid size-10 shrink-0 place-items-center rounded-xl bg-slate-50 text-slate-500 ring-1 ring-inset ring-slate-200`,children:B(Wt,{class:`size-5 rotate-180`})}),B(`div`,{class:`min-w-0`,children:[B(`strong`,{class:`block truncate text-sm font-black text-slate-900`,children:g?g.name:`펌웨어 파일을 선택하세요`}),B(`span`,{class:`mt-1 block text-xs leading-5 text-slate-500`,children:g?`${Dv(g.size)} · Sysupgrade 이미지 (.bin)`:`이 장치에 맞는 Sysupgrade 이미지 (.bin)를 선택합니다.`})]})]}),B(`div`,{class:`flex shrink-0 flex-wrap gap-2 sm:justify-end`,children:[B(`button`,{class:`inline-flex min-h-10 items-center justify-center rounded-lg border border-slate-300 bg-white px-3.5 py-2 text-xs font-extrabold text-slate-700 transition hover:bg-slate-50 disabled:cursor-not-allowed disabled:opacity-50`,disabled:C||w!==null,onClick:()=>h.current?.click(),type:`button`,children:g?`다른 파일 선택`:`파일 선택`}),B(`button`,{class:`inline-flex min-h-10 items-center justify-center gap-2 rounded-lg bg-slate-900 px-3.5 py-2 text-xs font-extrabold text-white transition hover:bg-slate-800 disabled:cursor-not-allowed disabled:opacity-50`,disabled:!g||C||w!==null,onClick:()=>void O(),type:`button`,children:[D?B(H,{class:`size-4 animate-spin`}):B(Wt,{class:`size-4 rotate-180`}),D?`처리 중...`:`업로드 및 검증`]})]})]}),s===null?null:B(`div`,{class:`mt-4 border-t border-slate-100 pt-4`,children:[B(`div`,{class:`mb-2 flex items-center justify-between gap-3 text-xs font-bold text-slate-600`,children:[B(`span`,{children:`업로드 중`}),B(`span`,{children:[s,`%`]})]}),B(`div`,{class:`h-2 overflow-hidden rounded-full bg-slate-200`,children:B(`div`,{class:`h-full rounded-full bg-sky-600 transition-[width]`,style:{width:`${Math.max(0,Math.min(100,s))}%`}})})]})]})]})]})]})}var Pv=[{value:3600,label:`1시간마다`},{value:21600,label:`6시간마다`},{value:43200,label:`12시간마다`},{value:86400,label:`24시간마다`}],Fv=`luci-app-smartsafehub`;function Iv(e){return e?new Date(e*1e3).toLocaleString(`ko-KR`,{dateStyle:`medium`,timeStyle:`short`}):`아직 없음`}function Lv(e){return e===`stable`?`Stable`:e===`beta`?`Beta`:`미확인`}function Rv(e){return e===`stable`?`bg-emerald-50 text-emerald-700 ring-emerald-200`:e===`beta`?`bg-amber-50 text-amber-700 ring-amber-200`:`bg-slate-100 text-slate-600 ring-slate-200`}function zv(e){return e.code===`UPDATES_INDEX_REFRESH_FAILED`?{title:`패키지 저장소를 확인하지 못했습니다.`,description:`OpenWrt 패키지 저장소 동기화 또는 네트워크 상태가 일시적으로 불안정할 수 있습니다. 잠시 후 업데이트 확인을 다시 실행해 주세요.`}:e.code===`UPDATES_INSTALL_FAILED`?{title:`관리 소프트웨어 업데이트 설치에 실패했습니다.`,description:`패키지 설치가 완료되지 않았습니다. 네트워크 연결과 저장 공간을 확인한 뒤 다시 시도해 주세요.`}:{title:`최근 업데이트 작업을 완료하지 못했습니다.`,description:`잠시 후 다시 시도해 주세요. 문제가 반복되면 상세 정보를 확인해 주세요.`}}function Bv(e,t){return e.phase===`checking`?`업데이트 확인 중`:e.phase===`installing`?`업데이트 설치 중`:e.phase===`error`?`확인 필요`:e.updateCount>0?`업데이트 가능`:t?`업데이트 확인 지연`:e.lastCheckAt?`최신 상태`:`확인 전`}function Vv(e,t){return e.phase===`error`?`bg-rose-50 text-rose-700 ring-rose-200`:e.phase===`checking`||e.phase===`installing`?`bg-sky-50 text-sky-700 ring-sky-200`:e.updateCount>0||t?`bg-amber-50 text-amber-800 ring-amber-200`:e.lastCheckAt?`bg-emerald-50 text-emerald-700 ring-emerald-200`:`bg-slate-100 text-slate-600 ring-slate-200`}function Hv(e,t){return e.phase===`checking`||e.phase===`installing`?B(H,{class:`size-3.5 shrink-0 animate-spin`}):e.phase===`error`?B(U,{class:`size-3.5 shrink-0`}):e.updateCount>0?B(Wt,{class:`size-3.5 shrink-0`}):t?B(U,{class:`size-3.5 shrink-0`}):e.lastCheckAt?B(Xt,{class:`size-3.5 shrink-0`}):B(Vt,{class:`size-3.5 shrink-0`})}function Uv({checked:e,disabled:t=!1,label:n,onChange:r}){return B(`button`,{"aria-checked":e,"aria-label":n,class:`ssh-switch-control relative inline-flex shrink-0 rounded-full border transition focus:outline-none focus-visible:ring-4 focus-visible:ring-teal-100 disabled:cursor-not-allowed disabled:opacity-50 ${e?`border-teal-600 bg-teal-600`:`border-slate-300 bg-slate-200`}`,disabled:t,onClick:()=>r(!e),role:`switch`,type:`button`,children:B(`span`,{"aria-hidden":`true`,class:`ssh-switch-thumb absolute top-1 shadow-sm transition-[left] ${e?`left-6`:`left-1`}`})})}function Wv({action:e,actionError:t,data:n,error:r,loading:i,message:a,onCheck:o,onDismissFeedback:s,onInstall:c,onRetry:l,onSaveSettings:u}){let[d,f]=N(!0),[p,m]=N(21600),[h,g]=N(!1),[_,v]=N(`03:00`),[y,b]=N(!1),[x,C]=N(!1);P(()=>{!n||y||(f(n.settings.checkEnabled),m(n.settings.checkIntervalSeconds),g(n.settings.autoInstall),v(n.settings.autoInstallTime))},[n,y]);let w=e===`check`||n?.phase===`checking`,T=e===`install`||n?.phase===`installing`,E=w||T,D=Jh(n),O=n?.phase===`error`&&n.lastError?.code===`UPDATES_INDEX_REFRESH_FAILED`,k=n?.lastError?zv(n.lastError):null,A=n?.packages.find(e=>e.name===Fv)??n?.packages[0]??null,ee=(e={})=>n?(e.checkEnabled??d)!==n.settings.checkEnabled||(e.checkIntervalSeconds??p)!==n.settings.checkIntervalSeconds||(e.autoInstall??h)!==n.settings.autoInstall||(e.autoInstallTime??_)!==n.settings.autoInstallTime:!1,j=async()=>{await u({checkEnabled:d,checkIntervalSeconds:p,autoInstall:h,autoInstallTime:_})&&b(!1)};return B(`article`,{class:`min-w-0 overflow-hidden rounded-2xl border border-slate-200 bg-white shadow-sm shadow-slate-900/5 ${n?`grid xl:grid-cols-[minmax(0,0.95fr)_minmax(0,1.05fr)]`:``}`,"data-component":`management-software-update-card`,"data-layout":`management-software-sections`,children:[B(`section`,{class:`min-w-0 xl:col-start-1 xl:row-start-1`,"data-section":`software-update-status`,children:[B(`div`,{class:`p-5 sm:p-6`,children:[B(`div`,{class:`flex flex-col gap-5 lg:flex-row lg:items-start lg:justify-between`,children:[B(`div`,{class:`flex min-w-0 gap-4`,children:[B(`span`,{class:`grid size-12 shrink-0 place-items-center rounded-2xl bg-teal-50 text-teal-700`,children:B(Ft,{class:`size-6`})}),B(`div`,{class:`min-w-0`,children:[B(`div`,{class:`flex flex-wrap items-center gap-2`,children:[B(`p`,{class:`m-0 text-xs font-extrabold uppercase tracking-[0.16em] text-teal-700`,children:`Management software`}),n?B(`span`,{class:`inline-flex items-center gap-1.5 rounded-full px-2.5 py-1 text-[11px] font-extrabold ring-1 ring-inset ${Vv(n,D)}`,children:[B(`span`,{"aria-hidden":`true`,class:`flex items-center justify-center`,children:Hv(n,D)}),Bv(n,D)]}):null]}),B(`h2`,{class:`mt-2 mb-0 text-xl font-black text-slate-950 sm:text-2xl`,children:`관리 소프트웨어 업데이트`}),B(`p`,{class:`mt-2 mb-0 text-sm leading-6 text-slate-500 xl:whitespace-nowrap`,children:`새 버전을 확인하고 안전하게 설치합니다.`})]})]}),n?B(`div`,{class:`flex shrink-0 flex-col gap-2 sm:flex-row lg:justify-end`,children:[B(`button`,{class:`inline-flex min-h-11 items-center justify-center gap-2 rounded-xl border border-slate-300 bg-white px-4 py-2.5 text-sm font-extrabold text-slate-800 transition hover:bg-slate-50 disabled:cursor-wait disabled:opacity-60`,disabled:E,onClick:o,type:`button`,children:[B(H,{class:`size-4 ${w?`animate-spin`:``}`}),w?`확인 중...`:`업데이트 확인`]}),n.updateCount>0&&!x?B(`button`,{class:`inline-flex min-h-11 items-center justify-center gap-2 rounded-xl bg-teal-700 px-4 py-2.5 text-sm font-extrabold text-white transition hover:bg-teal-800 disabled:cursor-wait disabled:opacity-60`,disabled:E,onClick:()=>C(!0),type:`button`,children:[T?B(H,{class:`size-4 animate-spin`}):B(Wt,{class:`size-4`}),T?`설치 중...`:`업데이트 설치`]}):null]}):null]}),(t||a)&&B(`div`,{class:`mt-5 flex flex-col gap-3 rounded-xl border px-4 py-3 text-sm font-bold sm:flex-row sm:items-center sm:justify-between ${t?`border-rose-200 bg-rose-50 text-rose-800`:`border-emerald-200 bg-emerald-50 text-emerald-800`}`,children:[B(`span`,{children:t||a}),B(`button`,{class:`shrink-0 self-start rounded-lg px-3 py-1.5 text-xs font-extrabold hover:bg-black/5 sm:self-auto`,onClick:s,type:`button`,children:`닫기`})]}),T?B(`div`,{"aria-busy":`true`,"aria-live":`polite`,class:`mt-5 rounded-xl border border-sky-200 bg-sky-50 p-4 sm:p-5`,children:[B(`div`,{class:`flex items-start gap-3`,children:[B(`span`,{class:`grid size-10 shrink-0 place-items-center rounded-xl bg-white text-sky-700 ring-1 ring-inset ring-sky-200`,children:B(H,{"aria-hidden":`true`,class:`size-5 animate-spin`})}),B(`div`,{class:`min-w-0`,children:[B(`h3`,{class:`m-0 text-sm font-black text-sky-950`,children:`관리 소프트웨어를 업데이트하고 있습니다.`}),B(`p`,{class:`mt-1 mb-0 text-sm leading-6 text-sky-800`,children:`설치가 완료되면 이 화면이 자동으로 갱신됩니다. 작업 중에는 웹 연결이 잠시 끊길 수 있습니다.`})]})]}),B(`div`,{"aria-hidden":`true`,class:`ssh-update-progress-track mt-4`,children:B(`span`,{class:`ssh-update-progress-bar`})})]}):null,r&&!n?B(`div`,{class:`mt-5 rounded-xl border border-rose-200 bg-rose-50 p-4 text-sm text-rose-800`,children:[B(`p`,{class:`m-0 font-bold`,children:r}),B(`button`,{class:`mt-3 rounded-lg border border-rose-300 bg-white px-3 py-2 text-xs font-extrabold text-rose-700`,onClick:l,type:`button`,children:`다시 시도`})]}):i&&!n?B(`div`,{class:`mt-5 flex items-center gap-3 rounded-xl bg-slate-50 p-4 text-sm font-bold text-slate-500`,children:[B(`span`,{class:`grid size-9 shrink-0 place-items-center rounded-xl bg-white text-teal-700 ring-1 ring-inset ring-slate-200`,children:B(H,{"aria-hidden":`true`,class:`size-4 animate-spin`})}),B(`span`,{children:`관리 소프트웨어 업데이트 상태를 확인하고 있습니다.`})]}):n?B(S,{children:[n.lastError&&k?B(`div`,{class:`mt-5 rounded-xl border border-rose-200 bg-rose-50 p-4 sm:p-5`,children:B(`div`,{class:`flex items-start gap-3`,children:[B(`span`,{class:`grid size-10 shrink-0 place-items-center rounded-xl bg-white text-rose-700 ring-1 ring-inset ring-rose-200`,children:B(U,{class:`size-5`})}),B(`div`,{class:`min-w-0 flex-1`,children:[B(`p`,{class:`m-0 text-sm font-extrabold text-rose-950`,children:k.title}),B(`p`,{class:`mt-1 mb-0 text-sm leading-6 text-rose-800`,children:k.description}),n.lastError.at?B(`p`,{class:`mt-2 mb-0 text-xs font-bold text-rose-700`,children:[`발생 시각 `,Iv(n.lastError.at)]}):null,B(`details`,{class:`mt-3 rounded-lg border border-rose-200 bg-white p-3`,children:[B(`summary`,{class:`cursor-pointer text-xs font-extrabold text-rose-800`,children:`상세 정보 보기`}),B(`div`,{class:`mt-3 grid gap-2 text-xs leading-5 text-slate-600`,children:[B(`p`,{class:`m-0`,children:[`오류 코드 `,B(`strong`,{class:`font-black text-slate-900`,children:n.lastError.code})]}),B(`pre`,{class:`m-0 max-h-40 overflow-auto whitespace-pre-wrap break-words rounded-lg bg-slate-50 p-3 font-mono text-[11px] leading-5 text-slate-700`,children:n.lastError.message})]})]})]})]})}):null,x?B(`div`,{class:`mt-5 flex flex-col gap-3 rounded-xl border border-amber-200 bg-amber-50 p-4 sm:flex-row sm:items-center sm:justify-between`,children:[B(`div`,{class:`min-w-0`,children:[B(`strong`,{class:`block text-sm font-black text-amber-900`,children:`관리 소프트웨어를 지금 업데이트할까요?`}),B(`span`,{class:`mt-1 block text-xs leading-5 text-amber-800`,children:`설치 중 SmartSafeHub 웹 화면 연결이 잠시 끊길 수 있습니다.`})]}),B(`div`,{class:`flex shrink-0 gap-2`,children:[B(`button`,{class:`min-h-10 rounded-lg border border-slate-300 bg-white px-3 py-2 text-xs font-extrabold text-slate-700`,disabled:E,onClick:()=>C(!1),type:`button`,children:`취소`}),B(`button`,{class:`min-h-10 rounded-lg bg-amber-700 px-3 py-2 text-xs font-extrabold text-white disabled:opacity-60`,disabled:E,onClick:()=>{C(!1),c()},type:`button`,children:`설치 시작`})]})]}):null]}):null]}),n?B(`div`,{class:`px-5 pb-5 sm:px-6 sm:pb-6`,children:[B(`h3`,{class:`mb-3 text-sm font-black text-slate-950`,children:`현재 상태`}),B(`dl`,{class:`grid overflow-hidden rounded-xl border border-slate-200 bg-slate-200 sm:grid-cols-2`,children:[B(`div`,{class:`bg-white p-4`,children:[B(`dt`,{class:`text-[11px] font-black uppercase tracking-[0.16em] text-slate-400`,children:`Installed`}),B(`dd`,{class:`mt-2 mb-0 ml-0 break-all text-sm font-black text-slate-950`,children:A?.installedVersion||`미확인`})]}),B(`div`,{class:`bg-white p-4`,children:[B(`dt`,{class:`text-[11px] font-black uppercase tracking-[0.16em] text-slate-400`,children:`Available`}),B(`dd`,{class:`mt-2 mb-0 ml-0 break-all text-sm font-black ${A?.updateAvailable||D?`text-amber-700`:`text-slate-950`}`,children:!n.lastCheckAt||O&&!A?.updateAvailable?`미확인`:A?.updateAvailable&&A.availableVersion?A.availableVersion:D?`확인 필요`:`최신 버전`})]}),B(`div`,{class:`bg-white p-4`,children:[B(`dt`,{class:`text-[11px] font-black uppercase tracking-[0.16em] text-slate-400`,children:`Last check`}),B(`dd`,{class:`mt-2 mb-0 ml-0 text-sm font-black text-slate-950`,children:Iv(n.lastCheckAt)})]}),B(`div`,{class:`bg-white p-4`,children:[B(`dt`,{class:`text-[11px] font-black uppercase tracking-[0.16em] text-slate-400`,children:`Auto install`}),B(`dd`,{class:`mt-2 mb-0 ml-0 text-sm font-black text-slate-950`,children:n.settings.autoInstall?`켜짐 · ${n.settings.autoInstallTime}`:`꺼짐`})]})]})]}):null,n&&n.updateCount===0&&n.lastCheckAt?D?B(`section`,{class:`mx-5 mb-5 rounded-xl border border-amber-200 bg-amber-50 p-4 sm:mx-6 sm:mb-6 sm:p-5`,"data-section":`software-update-result`,children:B(`div`,{class:`flex gap-3`,children:[B(`span`,{class:`grid size-10 shrink-0 place-items-center rounded-xl bg-white text-amber-700 ring-1 ring-inset ring-amber-200`,children:B(U,{class:`size-5`})}),B(`div`,{children:[B(`h3`,{class:`m-0 text-base font-black text-amber-950`,children:`업데이트 확인이 지연되고 있습니다.`}),B(`p`,{class:`mt-1 mb-0 text-sm leading-6 text-amber-800`,children:[`마지막 확인은 `,Iv(n.lastCheckAt),`에 완료되었습니다. 자동 확인 상태를 점검하거나 업데이트 확인을 실행해 주세요.`]})]})]})}):B(`section`,{class:`mx-5 mb-5 rounded-xl border border-emerald-200 bg-emerald-50 p-4 sm:mx-6 sm:mb-6 sm:p-5`,"data-section":`software-update-result`,children:B(`div`,{class:`flex gap-3`,children:[B(`span`,{class:`grid size-10 shrink-0 place-items-center rounded-xl bg-white text-emerald-700`,children:B(Xt,{class:`size-5`})}),B(`div`,{children:[B(`h3`,{class:`m-0 text-base font-black text-emerald-950`,children:`최신 버전을 사용 중입니다.`}),B(`p`,{class:`mt-1 mb-0 text-sm leading-6 text-emerald-800`,children:[`마지막 확인은 `,Iv(n.lastCheckAt),`에 완료되었습니다.`]})]})]})}):null,n&&n.updateCount===0&&!n.lastCheckAt?B(`section`,{class:`mx-5 mb-5 rounded-xl border border-slate-200 bg-slate-50 p-4 sm:mx-6 sm:mb-6 sm:p-5`,"data-section":`software-update-result`,children:B(`div`,{class:`flex flex-col gap-4 sm:flex-row sm:items-center sm:justify-between`,children:[B(`div`,{class:`flex min-w-0 gap-3`,children:[B(`span`,{class:`grid size-10 shrink-0 place-items-center rounded-xl bg-white text-slate-500 ring-1 ring-inset ring-slate-200`,children:B(H,{class:`size-5`})}),B(`div`,{class:`min-w-0`,children:[B(`h3`,{class:`m-0 text-base font-black text-slate-900`,children:`업데이트 상태를 아직 확인하지 않았습니다.`}),B(`p`,{class:`mt-1 mb-0 text-sm leading-6 text-slate-600`,children:`업데이트 확인을 실행하면 현재 설치 버전과 사용 가능한 최신 버전을 확인합니다.`})]})]}),B(`button`,{class:`inline-flex min-h-10 shrink-0 items-center justify-center gap-2 rounded-xl border border-slate-300 bg-white px-4 py-2 text-sm font-extrabold text-slate-800 transition hover:border-teal-300 hover:text-teal-700 disabled:cursor-wait disabled:opacity-60`,disabled:E,onClick:o,type:`button`,children:[B(H,{class:`size-4`}),`지금 확인`]})]})}):null]}),n?B(S,{children:[B(`section`,{class:`min-w-0 border-t border-slate-200 p-5 sm:p-6 xl:col-start-2 xl:row-start-1 xl:row-span-2 xl:self-stretch xl:border-t-0 xl:border-l`,"data-section":`software-update-settings`,children:[B(`div`,{class:`flex flex-col gap-4 sm:flex-row sm:items-start sm:justify-between`,children:[B(`div`,{class:`flex min-w-0 gap-4`,children:[B(`span`,{class:`grid size-11 shrink-0 place-items-center rounded-xl bg-slate-100 text-slate-600`,children:B(It,{class:`size-5`})}),B(`div`,{class:`min-w-0`,children:[B(`p`,{class:`m-0 text-xs font-extrabold uppercase tracking-[0.16em] text-slate-500`,children:`Settings`}),B(`h3`,{class:`mt-2 mb-0 text-lg font-black text-slate-950`,children:`자동 업데이트`}),B(`p`,{class:`mt-2 mb-0 max-w-3xl text-sm leading-6 text-slate-500`,children:`관리 소프트웨어의 자동 확인과 자동 설치를 설정합니다.`})]})]}),y?B(`span`,{"aria-live":`polite`,class:`inline-flex shrink-0 self-start items-center gap-1.5 rounded-full border border-amber-200 bg-amber-50 px-2.5 py-1 text-xs font-extrabold text-amber-800`,role:`status`,children:[B(U,{"aria-hidden":`true`,class:`size-3.5 shrink-0`}),`저장되지 않음`]}):null]}),B(`div`,{class:`ssh-software-settings-grid mt-4`,children:[B(`div`,{class:`ssh-software-settings-channel rounded-xl border border-slate-200 p-4 sm:p-5`,children:B(`div`,{class:`flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between`,children:[B(`div`,{class:`min-w-0`,children:[B(`strong`,{class:`block text-sm font-black text-slate-950`,children:`업데이트 채널`}),B(`span`,{class:`mt-1 block text-xs leading-5 text-slate-500`,children:`현재 관리 소프트웨어 업데이트를 확인하는 배포 채널입니다.`})]}),B(`span`,{class:`inline-flex min-h-9 shrink-0 items-center justify-center rounded-full px-3 py-1.5 text-xs font-extrabold ring-1 ring-inset ${Rv(n.settings.channel)}`,title:`현재 업데이트 확인 채널`,children:Lv(n.settings.channel)})]})}),B(`div`,{class:`min-w-0 overflow-hidden rounded-xl border border-slate-200 p-4 sm:p-5`,children:[B(`div`,{class:`flex min-w-0 items-start justify-between gap-4`,children:[B(`div`,{class:`min-w-0`,children:[B(`strong`,{class:`block text-sm font-black text-slate-950`,children:`자동으로 업데이트 확인`}),B(`span`,{class:`mt-1 block text-xs leading-5 text-slate-500`,children:`선택한 주기에 새 관리 소프트웨어 버전을 확인합니다.`})]}),B(Uv,{checked:d,label:`자동 업데이트 확인`,onChange:e=>{f(e),b(ee({checkEnabled:e}))}})]}),B(`div`,{class:`mt-4 block`,children:[B(`span`,{class:`text-xs font-extrabold text-slate-700`,children:`확인 주기`}),B(Vg,{ariaLabel:`업데이트 확인 주기`,className:`mt-2`,disabled:!d,id:`software-update-check-interval`,onChange:e=>{let t=Number(e);m(t),b(ee({checkIntervalSeconds:t}))},options:Pv.map(e=>({value:String(e.value),label:e.label})),value:String(p),variant:`emphasized`})]})]}),B(`div`,{class:`min-w-0 overflow-hidden rounded-xl border border-slate-200 p-4 sm:p-5`,children:[B(`div`,{class:`flex min-w-0 items-start justify-between gap-4`,children:[B(`div`,{class:`min-w-0`,children:[B(`strong`,{class:`block text-sm font-black text-slate-950`,children:`자동으로 업데이트 설치`}),B(`span`,{class:`mt-1 block text-xs leading-5 text-slate-500`,children:`새 버전이 있으면 지정한 시각에 자동으로 설치합니다.`})]}),B(Uv,{checked:h,label:`자동 업데이트 설치`,onChange:e=>{g(e),b(ee({autoInstall:e}))}})]}),B(`div`,{class:`mt-4 min-w-0`,children:[B(`span`,{class:`text-xs font-extrabold text-slate-700`,children:`설치 시각`}),B(lv,{ariaLabel:`자동 업데이트 설치 시각`,className:`mt-2`,disabled:!h,id:`software-update-auto-install-time`,onChange:e=>{v(e),b(ee({autoInstallTime:e}))},value:_,variant:`emphasized`})]})]})]}),h?B(`p`,{class:`mt-4 mb-0 rounded-xl bg-amber-50 px-4 py-3 text-xs font-bold leading-5 text-amber-800`,children:`자동 설치 중에는 SmartSafeHub 웹 화면 연결이 잠시 끊길 수 있습니다.`}):null,B(`div`,{class:`mt-5 flex flex-col gap-3 border-t border-slate-100 pt-5 sm:flex-row sm:items-center sm:justify-between`,children:[B(`p`,{class:`m-0 text-xs leading-5 text-slate-500`,children:[`마지막 설치: `,Iv(n.lastInstallAt)]}),B(`button`,{class:`inline-flex min-h-11 items-center justify-center rounded-xl bg-slate-900 px-4 py-2.5 text-sm font-extrabold text-white transition hover:bg-slate-800 disabled:cursor-not-allowed disabled:opacity-50`,disabled:!y||e===`settings`||E,onClick:()=>void j(),type:`button`,children:e===`settings`?`저장 중`:`자동 업데이트 설정 저장`})]})]}),n.updateCount>0?B(`section`,{class:`border-t border-slate-200 p-5 sm:p-6 xl:col-start-1 xl:row-start-2`,"data-section":`software-update-release-notes`,children:[B(`div`,{class:`flex flex-col gap-2 sm:flex-row sm:items-start sm:justify-between sm:gap-4`,children:[B(`div`,{children:[B(`p`,{class:`m-0 text-xs font-extrabold uppercase tracking-[0.16em] text-teal-700`,children:`Release notes`}),B(`h3`,{class:`mt-2 mb-0 text-lg font-black text-slate-950`,children:`업데이트 내용`}),B(`p`,{class:`mt-2 mb-0 text-sm leading-6 text-slate-500`,children:`현재 설치된 버전 이후 포함되는 주요 변경 사항입니다.`})]}),n.releaseNotes.length?B(`span`,{class:`shrink-0 rounded-full bg-slate-100 px-3 py-1.5 text-xs font-extrabold text-slate-600`,children:n.releaseNotes.length===1?`1개 릴리즈`:`${n.releaseNotes.length}개 릴리즈`}):null]}),n.releaseNotes.length?B(`div`,{class:`mt-5 grid gap-3`,children:[n.releaseNotes.map(e=>B(`article`,{class:`rounded-xl border border-slate-200 bg-slate-50 p-4 sm:p-5`,children:[B(`div`,{class:`flex flex-col gap-1 sm:flex-row sm:items-center sm:justify-between sm:gap-4`,children:[B(`strong`,{class:`break-all text-sm font-black text-slate-950`,children:e.version}),e.date?B(`span`,{class:`text-xs font-bold text-slate-500`,children:e.date}):null]}),e.summary?B(`p`,{class:`mt-3 mb-0 text-sm leading-6 text-slate-700`,children:e.summary}):null,e.sections.length?B(`details`,{class:`mt-4 rounded-lg border border-slate-200 bg-white p-3`,open:n.releaseNotes.length===1,children:[B(`summary`,{class:`cursor-pointer text-xs font-extrabold text-slate-800`,children:`자세한 변경 사항`}),B(`div`,{class:`mt-3 grid gap-4`,children:e.sections.map(t=>B(`section`,{children:[B(`h4`,{class:`m-0 text-xs font-extrabold text-slate-700`,children:t.title}),B(`ul`,{class:`mt-2 mb-0 space-y-1.5 pl-5 text-xs leading-5 text-slate-600`,children:t.items.map((n,r)=>B(`li`,{children:n},`${e.version}-${t.title}-${r}`))})]},`${e.version}-${t.title}`))})]}):null]},e.version)),n.releaseNotesComplete?null:B(`p`,{class:`m-0 rounded-xl bg-amber-50 px-4 py-3 text-xs font-bold leading-5 text-amber-800`,children:`일부 릴리즈 노트를 불러오지 못했습니다. 업데이트 확인과 설치는 계속 사용할 수 있습니다.`})]}):B(`p`,{class:`mt-4 mb-0 rounded-xl bg-slate-50 px-4 py-3 text-sm text-slate-500`,children:`릴리즈 노트를 불러오지 못했습니다. 업데이트 확인과 설치는 계속 사용할 수 있습니다.`})]}):null]}):null]})}function Gv({action:e,actionError:t,data:n,error:r,firmware:i,loading:a,message:o,onCheck:s,onDismissFeedback:c,onInstall:l,onRetry:u,onSaveSettings:d}){return B(`section`,{class:`min-w-0 space-y-5`,children:[B(Nv,{action:i.action,actionError:i.actionError,data:i.data,error:i.error,loading:i.loading,message:i.message,reconnecting:i.reconnecting,uploadProgress:i.uploadProgress,onCheck:()=>void i.check(),onDiscard:i.discard,onDismissFeedback:i.dismissFeedback,onInstall:i.install,onPrepare:()=>void i.prepare(),onRetry:()=>void i.refresh(),onUpload:i.upload}),B(Wv,{action:e,actionError:t,data:n,error:r,loading:a,message:o,onCheck:s,onDismissFeedback:c,onInstall:l,onRetry:u,onSaveSettings:d})]})}var Kv=[{value:`sae-mixed`,label:`WPA2/WPA3 혼합 (권장)`},{value:`sae`,label:`WPA3-Personal`},{value:`psk2`,label:`WPA2-Personal`},{value:`none`,label:`암호화 없음`}];function qv(e){switch(e.security){case`sae-mixed`:return`WPA2/WPA3 혼합`;case`sae`:return`WPA3-Personal`;case`psk2`:return`WPA2-Personal`;case`none`:return`암호화 없음`;default:return`고급 설정 (${e.securityRaw})`}}function Jv(e){return e.length>=8&&e.length<=63||/^[0-9a-fA-F]{64}$/.test(e)}function Yv({network:e,busy:t,saving:n,onUpdate:r}){let[i,a]=N(e.ssid),[o,s]=N(e.enabled),[c,l]=N(e.security===`custom`?`keep`:e.security),[u,d]=N(``),[f,p]=N(null);P(()=>{a(e.ssid),s(e.enabled),l(e.security===`custom`?`keep`:e.security),d(``),p(null)},[e]);let m=e.security===`custom`&&c===`keep`,h=c===`psk2`||c===`sae-mixed`||c===`sae`,g=e.security===`custom`?`keep`:e.security,_=i.trim()!==e.ssid||o!==e.enabled||c!==g||u.length>0,v=[...e.security===`custom`?[{value:`keep`,label:`현재 고급 설정 유지 (${e.securityRaw})`}]:[],...Kv],y=async t=>{t.preventDefault();let n=i.trim(),a=new TextEncoder().encode(n).length;if(a<1||a>32){p(`SSID는 UTF-8 기준 1~32바이트로 입력해 주세요.`);return}if(u&&!Jv(u)){p(`비밀번호는 8~63자 또는 64자리 16진수여야 합니다.`);return}if(h&&!e.passwordConfigured&&u.length===0){p(`보안 Wi-Fi를 사용하려면 비밀번호를 입력해 주세요.`);return}window.confirm(`Wi-Fi 설정을 적용하면 현재 무선 연결이 잠시 끊어질 수 있습니다. 계속하시겠습니까?`)&&(p(null),await r({section:e.section,ssid:n,security:c,password:u,enabled:o})&&d(``))};return B(`form`,{class:`rounded-2xl border border-slate-200 bg-white p-4 shadow-sm shadow-slate-900/5 sm:p-6`,onSubmit:e=>void y(e),children:[B(`div`,{class:`flex flex-col gap-4 sm:flex-row sm:items-start sm:justify-between`,children:[B(`div`,{class:`flex min-w-0 items-start gap-3`,children:[B(`span`,{class:`grid size-11 shrink-0 place-items-center rounded-xl bg-teal-50 text-teal-700`,children:B(jt,{class:`size-6`})}),B(`div`,{class:`min-w-0`,children:[B(`p`,{class:`m-0 text-xs font-extrabold uppercase tracking-[0.16em] text-slate-500`,children:e.bandLabel}),B(`h2`,{class:`mt-2 mb-0 break-words text-xl font-extrabold tracking-tight text-slate-950`,children:e.ssid||`이름 없는 Wi-Fi`}),B(`p`,{class:`mt-2 mb-0 text-sm text-slate-600`,children:[`채널 `,e.channel??`자동`,` · 연결 기기 `,e.clientCount,`대`]})]})]}),B(`div`,{class:`flex flex-wrap items-center gap-2 sm:justify-end`,children:[_?B(`span`,{"aria-live":`polite`,class:`inline-flex shrink-0 items-center gap-1.5 rounded-full border border-amber-200 bg-amber-50 px-2.5 py-1 text-xs font-extrabold text-amber-800`,role:`status`,children:[B(U,{"aria-hidden":`true`,class:`size-3.5 shrink-0`}),`저장되지 않음`]}):null,B(`span`,{class:`inline-flex w-fit items-center gap-2 rounded-full px-3 py-1.5 text-xs font-extrabold ring-1 ring-inset ${e.runtimeUp?`bg-emerald-50 text-emerald-700 ring-emerald-200`:`bg-slate-100 text-slate-600 ring-slate-200`}`,children:[B(`span`,{class:`size-2 rounded-full ${e.runtimeUp?`bg-emerald-500`:`bg-slate-400`}`}),e.runtimeUp?`동작 중`:e.enabled?`시작 대기`:`꺼짐`]})]})]}),B(`div`,{class:`mt-6 grid gap-5 lg:grid-cols-2`,children:[B(`label`,{class:`block`,children:[B(`span`,{class:`text-sm font-extrabold text-slate-800`,children:`Wi-Fi 이름 (SSID)`}),B(`input`,{autocomplete:`off`,class:`mt-2 min-h-11 w-full rounded-xl border-2 border-slate-300 bg-slate-50 px-4 py-2.5 text-sm font-semibold text-slate-950 shadow-inner outline-none transition placeholder:text-slate-400 focus:border-teal-500 focus:bg-white focus:ring-4 focus:ring-teal-100 disabled:cursor-not-allowed disabled:bg-slate-100`,disabled:t,maxLength:32,onInput:e=>a(e.currentTarget.value),value:i})]}),B(`div`,{class:`block`,children:[B(`span`,{class:`text-sm font-extrabold text-slate-800`,children:`보안 방식`}),B(Vg,{ariaLabel:`${e.bandLabel} Wi-Fi 보안 방식`,className:`mt-2`,disabled:t,id:`wifi-security-${e.section}`,onChange:e=>{let t=e;l(t),(t===`none`||t===`keep`)&&d(``)},options:v,value:c,variant:`emphasized`}),B(`span`,{class:`mt-2 block text-xs text-slate-500`,children:[`현재: `,qv(e)]})]}),B(`label`,{class:`block lg:col-span-2`,children:[B(`span`,{class:`text-sm font-extrabold text-slate-800`,children:`새 비밀번호`}),B(`input`,{autocomplete:`new-password`,class:`mt-2 min-h-11 w-full rounded-xl border-2 border-slate-300 bg-slate-50 px-4 py-2.5 text-sm font-semibold text-slate-950 shadow-inner outline-none transition placeholder:text-slate-400 focus:border-teal-500 focus:bg-white focus:ring-4 focus:ring-teal-100 disabled:cursor-not-allowed disabled:bg-slate-100`,disabled:t||c===`none`||m,onInput:e=>d(e.currentTarget.value),placeholder:m?`고급 보안 설정은 기존 LuCI에서 변경합니다`:e.passwordConfigured?`비워 두면 기존 비밀번호를 유지합니다`:`8자 이상의 비밀번호를 입력하세요`,type:`password`,value:u}),B(`span`,{class:`mt-2 block text-xs text-slate-500`,children:`저장된 비밀번호는 화면이나 API로 다시 노출하지 않습니다.`})]})]}),B(`div`,{class:`mt-6 flex flex-col gap-4 border-t border-slate-200 pt-5 sm:flex-row sm:items-center sm:justify-between`,children:[B(`label`,{class:`inline-flex min-h-11 items-center gap-3 text-sm font-extrabold text-slate-800`,children:[B(`input`,{checked:o,class:`size-5 accent-teal-700`,disabled:t,onChange:e=>s(e.currentTarget.checked),type:`checkbox`}),`이 Wi-Fi 사용`]}),B(`button`,{class:`inline-flex min-h-11 w-full items-center justify-center gap-2 rounded-xl border-0 bg-teal-700 px-5 sm:w-auto py-2.5 text-sm font-extrabold text-white shadow-sm transition hover:bg-teal-800 focus:outline-none focus-visible:ring-4 focus-visible:ring-teal-200 disabled:cursor-wait disabled:opacity-60`,disabled:t||!_,type:`submit`,children:[B(Xt,{class:`size-5 ${n?`animate-pulse`:``}`}),n?`적용 중`:`설정 저장`]})]}),f?B(`p`,{class:`mt-4 mb-0 rounded-xl bg-red-50 px-4 py-3 text-sm font-bold text-red-800`,children:f}):null]})}function Xv({feedback:e,onDismiss:t}){return B(`div`,{"aria-live":`polite`,class:`mb-5 flex flex-col gap-3 rounded-2xl border px-4 py-3 text-sm sm:flex-row sm:items-center sm:justify-between ${e.kind===`success`?`border-emerald-200 bg-emerald-50 text-emerald-900`:e.kind===`warning`?`border-amber-200 bg-amber-50 text-amber-900`:`border-red-200 bg-red-50 text-red-900`}`,children:[B(`p`,{class:`m-0 font-bold leading-6`,children:e.message}),B(`button`,{class:`min-h-11 w-full shrink-0 rounded-lg border border-current bg-transparent sm:min-h-9 sm:w-auto px-3 py-1.5 text-xs font-extrabold`,onClick:t,type:`button`,children:`닫기`})]})}function Zv({data:e,error:t,feedback:n,loading:r,updatingSection:i,onDismissFeedback:a,onRetry:o,onUpdate:s}){return r?B(io,{}):t?B(ao,{message:t,onRetry:o}):e?B(S,{children:[n?B(Xv,{feedback:n,onDismiss:a}):null,B(`section`,{class:`mb-5 rounded-2xl border border-amber-200 bg-amber-50 p-5 text-amber-950 sm:p-6`,children:[B(`p`,{class:`m-0 text-xs font-extrabold uppercase tracking-[0.16em] text-amber-700`,children:`연결 주의`}),B(`h2`,{class:`mt-2 mb-0 text-lg font-extrabold`,children:`Wi-Fi 이름이나 비밀번호를 바꾸면 현재 연결이 끊어집니다`}),B(`p`,{class:`mt-2 mb-0 text-sm leading-6 text-amber-900/80`,children:`변경한 Wi-Fi 이름과 비밀번호로 다시 연결하면 SmartSafeHub를 계속 사용할 수 있습니다. VLAN, 게스트 네트워크와 고급 무선 옵션은 기존 LuCI에서 관리합니다.`})]}),e.networks.length?B(`section`,{"aria-label":`기본 Wi-Fi 설정`,class:`grid gap-5 xl:grid-cols-2`,children:e.networks.map(e=>B(Yv,{busy:i!==null,network:e,onUpdate:s,saving:i===e.section},e.section))}):B(`section`,{class:`rounded-2xl border border-slate-200 bg-white p-5 text-center shadow-sm shadow-slate-900/5 sm:p-8`,children:[B(jt,{class:`mx-auto size-10 text-slate-400`}),B(`h2`,{class:`mt-4 mb-0 text-lg font-extrabold text-slate-950`,children:`관리할 기본 Wi-Fi를 찾지 못했습니다`}),B(`p`,{class:`mt-2 mb-0 text-sm leading-6 text-slate-600`,children:`기존 LuCI에서 AP 모드의 무선 네트워크를 먼저 구성해 주세요.`})]})]}):null}function Qv({onAdministratorPasswordChanged:e}){let t=qr(),n=kr(),r=yr(t===`home`||t===`activity`),i=ha(t===`home`||t===`settings`),a=pa(!0),o=Wr(!0),s=ii(t===`network`),c=ni(t===`home`||t===`network`),l=ei(t===`iptv`),u=Oa(t===`wifi`),d=jr(t===`home`,!1),f=jr(t===`devices`),p=ca(t===`home`),m=$i(t===`home`,!1),h=ca(t===`safeshield`),g=$i(t===`safeshield`),_=Zi(t===`rules`),v=wa(i.data),y=$r(t===`home`||t===`settings`),b=ga(t===`settings`),x=Ta(t===`settings`),S=Hi(h.refresh,g.refresh),C=t===`activity`?r:t===`network`?s:t===`wifi`?u:t===`iptv`?l:t===`devices`?f:t===`safeshield`?h:t===`rules`?_:t===`system`?a:i,w;switch(t){case`network`:w=B(`div`,{class:`min-w-0`,children:[B(`div`,{"aria-label":`인터넷 연결 설정`,class:`min-w-0`,children:B(b_,{action:s.action,data:s.data,error:s.error,feedback:s.feedback,loading:s.loading,onDismissFeedback:s.dismissFeedback,onReconnect:()=>void s.reconnect(),onRetry:()=>void s.refresh(),onSave:s.save})}),B(`div`,{"aria-label":`내부 네트워크 설정`,class:`mt-8 min-w-0 border-t border-slate-200 pt-8`,children:B(o_,{action:c.action,data:c.data,error:c.error,feedback:c.feedback,loading:c.loading,onApplyRecommendation:c.applyRecommendation,onDismissFeedback:c.dismissFeedback,onRetry:()=>void c.refresh(),onSave:c.save})})]});break;case`activity`:w=B(ro,{actionError:r.actionError,actionMessage:r.actionMessage,data:r.data,error:r.error,loading:r.loading,onDismissActionFeedback:r.dismissActionFeedback,onRetry:()=>void r.refresh(),onSetCloudSync:e=>void r.setCloudSyncEnabled(e),savingCloudSync:r.savingCloudSync});break;case`wifi`:w=B(Zv,{data:u.data,error:u.error,feedback:u.feedback,loading:u.loading,onDismissFeedback:u.dismissFeedback,onRetry:()=>void u.refresh(),onUpdate:u.update,updatingSection:u.updatingSection});break;case`iptv`:w=B(Gg,{data:l.data,error:l.error,feedback:l.feedback,loading:l.loading,onDismissFeedback:l.dismissFeedback,onRetry:()=>void l.refresh(),onSave:l.save,saving:l.saving});break;case`devices`:w=B(vo,{data:f.data,error:f.error,loading:f.loading,onRetry:()=>void f.refresh()});break;case`system`:w=B(Gv,{action:a.action,actionError:a.actionError,data:a.data,error:a.error,firmware:o,loading:a.loading,message:a.message,onCheck:()=>void a.check(),onDismissFeedback:a.dismissFeedback,onInstall:()=>void a.install(),onRetry:()=>void a.refresh(),onSaveSettings:a.saveSettings});break;case`settings`:w=B(Ev,{action:v.action,backupAction:n.action,backupError:n.error,backupMessage:n.message,backupRestoreAccepted:n.restoreAccepted,backupUploadProgress:n.uploadProgress,backupValidated:n.validated,data:i.data,error:i.error,feedbackError:v.error,feedbackMessage:v.message,firmware:o.data,firmwareError:o.error,firmwareLoading:o.loading,health:y.data,healthActionError:y.actionError,healthActionMessage:y.actionMessage,healthError:y.error,healthLoading:y.loading,healthRunning:y.running,healthSavingReporter:y.savingReporter,loading:i.loading,onBackupDiscard:n.discard,onBackupDownload:()=>void n.download(),onBackupRestore:n.restore,onBackupUpload:n.upload,onDismissBackupFeedback:n.dismissFeedback,onDismissFeedback:v.dismissFeedback,onDismissHealthFeedback:y.dismissActionFeedback,onDismissTimeFeedback:x.dismissSaveFeedback,onDownloadDiagnostics:()=>void v.downloadDiagnostics(),onRunHealth:()=>void y.runDiagnostic(),onSetHealthReporter:e=>void y.setReporterEnabled(e),onReboot:()=>void v.reboot(),onRetry:()=>void Promise.all([i.refresh(),o.refresh(),x.refresh(),b.refresh(),y.refresh()]),onDismissScheduledRebootFeedback:b.dismissSaveFeedback,onSaveScheduledReboot:b.saveSettings,onSaveTimezone:x.saveTimezone,onSyncTime:x.syncTime,onAdministratorPasswordChanged:e,rebootAccepted:v.rebootAccepted,scheduledRebootData:b.data,scheduledRebootError:b.error,scheduledRebootLoading:b.loading,scheduledRebootSaveError:b.saveError,scheduledRebootSaveMessage:b.saveMessage,scheduledRebootSaving:b.saving,timeData:x.data,timeError:x.error,timeLoading:x.loading,timeSaveError:x.saveError,timeSaveMessage:x.saveMessage,timeSaving:x.saving,timeSyncing:x.syncing});break;case`safeshield`:w=B(ev,{action:S.action,actionError:S.error,actionFeedbackTarget:S.feedbackTarget,actionMessage:S.message,data:h.data,error:h.error,loading:h.loading,statistics:g.data,statisticsError:g.error,statisticsLoading:g.loading,statisticsRefreshing:g.refreshing,onDismissFeedback:S.dismissFeedback,onReadLicense:S.readLicense,onRefreshBlocklist:()=>void S.refreshBlocklist(),onRemoveLicense:S.removeLicense,onRetry:()=>void h.refresh(),onRetryStatistics:()=>void g.refresh(),onSetEnabled:e=>void S.setEnabled(e),onSetStatisticsEnabled:e=>void S.setStatisticsEnabled(e),onUpdateLicense:S.updateLicense});break;case`rules`:w=B(iv,{action:_.action,data:_.data,error:_.error,feedback:_.feedback,loading:_.loading,onAddRule:_.addRule,onDeleteRule:_.deleteRule,onDismissFeedback:_.dismissFeedback,onRetry:()=>void _.refresh()});break;default:w=B(sg,{activity:r.data,activityError:r.error,activityLoading:r.loading,data:i.data,devices:d.data,devicesError:d.error,devicesLoading:d.loading,error:i.error,firmware:o.data,firmwareError:o.error,firmwareLoading:o.loading,health:y.data,healthError:y.error,healthLoading:y.loading,lan:c.data,lanError:c.error,lanLoading:c.loading,loading:i.loading,onRetry:()=>void Promise.all([r.refresh(),i.refresh(),d.refresh(),p.refresh(),m.refresh(),a.refresh(),o.refresh(),y.refresh(),c.refresh()]),safeshield:p.data,safeshieldError:p.error,safeshieldLoading:p.loading,statistics:m.data,statisticsError:m.error,statisticsLoading:m.loading,statisticsRefreshing:m.refreshing,updates:a.data,updatesError:a.error,updatesLoading:a.loading})}let T=()=>{if(t===`home`){Promise.all([r.refresh(),i.refresh(),d.refresh(),p.refresh(),m.refresh(),a.refresh(),o.refresh(),y.refresh(),c.refresh()]);return}if(t===`network`){Promise.all([s.refresh(),c.refresh()]);return}if(t===`system`){Promise.all([a.refresh(),o.refresh()]);return}if(t===`settings`){Promise.all([i.refresh(),o.refresh(),x.refresh(),b.refresh(),y.refresh()]);return}if(t===`safeshield`){Promise.all([h.refresh(),g.refresh()]);return}C.refresh()},E=+((a.data?.updateCount??0)>0)+ +!!o.data?.updateAvailable;return B(An,{loading:t===`network`?s.loading||c.loading:C.loading,onRefresh:T,refreshing:C.refreshing||t===`network`&&c.refreshing||t===`home`&&(r.refreshing||d.refreshing||p.refreshing||m.refreshing||a.refreshing||o.refreshing||y.refreshing||c.refreshing)||t===`system`&&o.refreshing||t===`settings`&&(o.refreshing||x.refreshing||b.refreshing||y.refreshing)||t===`safeshield`&&g.refreshing,route:t,updateCount:E,children:w})}function $v({onAdministratorPasswordChanged:e,onPasswordConfigured:t}){let[n,r]=N(`checking`),[i,a]=N(!1),o=I(async()=>{r(`checking`);try{let e=await Dt();a(e.recovery),r(e.configured?`ready`:`required`)}catch{r(`error`)}},[]);return P(()=>{o()},[o]),n===`ready`?B(Qv,{onAdministratorPasswordChanged:e}):n===`required`?B(vn,{onCompleted:()=>t(i),recovery:i}):B(`main`,{class:`ssh-initial-setup-probe`,role:n===`error`?`alert`:`status`,children:B(`div`,{class:`ssh-initial-setup-probe-card`,children:[n===`checking`?B(H,{class:`ssh-login-probe-spinner`,"aria-hidden":`true`}):B(At,{"aria-hidden":`true`}),B(`strong`,{children:n===`checking`?`관리자 보안 상태 확인 중`:`관리자 보안 상태를 확인할 수 없습니다`}),B(`span`,{children:n===`checking`?`root 비밀번호 설정 여부를 확인하고 있습니다.`:`공유기 연결을 확인한 뒤 다시 시도해 주세요.`}),n===`error`?B(`button`,{onClick:()=>void o(),type:`button`,children:`다시 시도`}):null]})})}function ey({icon:e,title:t,description:n}){return B(`div`,{class:`ssh-login-feature`,children:[B(`span`,{class:`ssh-login-feature-icon`,"aria-hidden":`true`,children:e}),B(`span`,{class:`ssh-login-feature-copy`,children:[B(`strong`,{children:t}),B(`span`,{children:n})]})]})}function ty({theme:e}){return B(e===`dark`?ln:cn,{})}function ny({notice:e,onAuthenticated:t,probing:n=!1}){let r=$e(Ee,[]),i=F(null),a=F(null),[o,s]=N(`root`),[c,l]=N(``),[u,d]=N(`ready`),[f,p]=N(null),[m,h]=N(e??null),[g,_]=N(!1),[v,y]=N(!1),[b,x]=N(!1),[S,C]=N(dn),w=u===`submitting`,T=S===`dark`?`라이트 모드로 전환`:`다크 모드로 전환`;P(()=>{fn(S),pn(S)},[S]),P(()=>{if(n)return;let e=window.requestAnimationFrame(()=>a.current?.focus());return()=>window.cancelAnimationFrame(e)},[n]),P(()=>{if(h(e??null),!e)return;let t=window.setTimeout(()=>h(null),7e3);return()=>window.clearTimeout(t)},[e]);let E=e=>{x(e.getModifierState?.(`CapsLock`)??!1)};return B(`main`,{class:`ssh-login-page`,"data-theme":S,children:[m?B(`div`,{"aria-atomic":`true`,"aria-live":`assertive`,class:`ssh-login-toast`,role:`alert`,children:[B(At,{"aria-hidden":`true`}),B(`span`,{children:m})]}):null,B(`section`,{class:`ssh-login-brand`,"aria-labelledby":`ssh-login-brand-title`,children:[B(`div`,{class:`ssh-login-brand-orb ssh-login-brand-orb-one`,"aria-hidden":`true`}),B(`div`,{class:`ssh-login-brand-orb ssh-login-brand-orb-two`,"aria-hidden":`true`}),B(`div`,{class:`ssh-login-brand-content`,children:[B(`span`,{class:`ssh-login-brand-mark`,"aria-hidden":`true`,children:B(At,{})}),B(`p`,{class:`ssh-login-eyebrow`,children:`SMART NETWORK PROTECTION`}),B(`h1`,{id:`ssh-login-brand-title`,children:`SmartSafeHub`}),B(`p`,{class:`ssh-login-brand-description`,children:`네트워크와 보안을 하나의 허브에서 관리하세요. SafeShield 보호 상태부터 Wi-Fi와 연결 기기까지 로컬에서 빠르게 확인할 수 있습니다.`}),B(`div`,{class:`ssh-login-features`,"aria-label":`SmartSafeHub 주요 기능`,children:[B(ey,{description:`DNS 기반 광고·피싱 차단과 사용자 보호 정책을 관리합니다.`,icon:B(At,{}),title:`SafeShield 보호`}),B(ey,{description:`Wi-Fi 설정과 현재 연결된 기기의 상태를 한눈에 확인합니다.`,icon:B(Lt,{}),title:`네트워크 관리`}),B(ey,{description:`관리 기능과 인증은 현재 SmartSafeHub 장치에서 직접 처리됩니다.`,icon:B(Kt,{}),title:`로컬 우선 관리`})]})]})]}),B(`section`,{class:`ssh-login-panel`,"aria-labelledby":`ssh-login-title`,children:[B(`button`,{"aria-label":T,class:`ssh-login-theme-toggle`,onClick:()=>C(e=>e===`dark`?`light`:`dark`),title:T,type:`button`,children:B(ty,{theme:S})}),B(`div`,{class:`ssh-login-panel-inner`,children:[n?B(`div`,{class:`ssh-login-probe`,role:`status`,"aria-live":`polite`,children:[B(H,{class:`ssh-login-probe-spinner`,"aria-hidden":`true`}),B(`strong`,{children:`SmartSafeHub 연결 확인 중`}),B(`span`,{children:`로그인 세션을 확인하고 있습니다.`})]}):B(`div`,{class:`ssh-login-card`,children:[B(`div`,{class:`ssh-login-card-heading`,children:[B(`span`,{class:`ssh-login-mobile-mark`,"aria-hidden":`true`,children:B(At,{})}),B(`div`,{children:[B(`p`,{class:`ssh-login-kicker`,children:`SMARTSAFEHUB ACCESS`}),B(`h2`,{id:`ssh-login-title`,children:`SmartSafeHub에 로그인`}),B(`p`,{class:`ssh-login-subtitle`,children:`공유기 관리자 계정의 사용자 이름과 비밀번호를 입력해 주세요.`})]})]}),f?B(`div`,{class:`ssh-login-alert`,id:`ssh-login-error`,role:`alert`,"aria-live":`polite`,children:f}):null,B(`form`,{class:`ssh-login-form`,onSubmit:async e=>{e.preventDefault();let n=o.trim(),r=c;if(p(null),_(!1),!n||!r&&n!==`root`){p(n?`비밀번호를 입력해 주세요.`:`사용자 이름을 입력해 주세요.`),window.requestAnimationFrame(()=>{if(!n){i.current?.focus();return}a.current?.focus()});return}d(`submitting`);try{let e=await Me(n,r);if(e){l(``),t(e);return}l(``),_(!0),p(`로그인하지 못했습니다. 계정 정보를 확인해 주세요. 추가 인증이 설정된 장치는 기본 LuCI 로그인에서 계속할 수 있습니다.`),window.requestAnimationFrame(()=>a.current?.focus())}catch{p(`공유기와 통신할 수 없습니다. 네트워크 연결을 확인한 뒤 다시 시도해 주세요.`)}finally{d(`ready`)}},noValidate:!0,children:[B(`label`,{class:`ssh-login-field`,for:`smartsafehub-username`,children:[B(`span`,{class:`ssh-login-label`,children:`사용자 이름`}),B(`span`,{class:`ssh-login-input-wrap`,children:[B(`span`,{class:`ssh-login-field-icon`,"aria-hidden":`true`,children:B(Pt,{})}),B(`input`,{autoCapitalize:`none`,autoComplete:`username`,disabled:w,id:`smartsafehub-username`,name:`username`,onInput:e=>s(e.currentTarget.value),placeholder:`관리자 계정`,ref:i,required:!0,spellcheck:!1,type:`text`,value:o})]})]}),B(`label`,{class:`ssh-login-field`,for:`smartsafehub-password`,children:[B(`span`,{class:`ssh-login-label`,children:`비밀번호`}),B(`span`,{class:`ssh-login-input-wrap`,children:[B(`span`,{class:`ssh-login-field-icon`,"aria-hidden":`true`,children:B(Kt,{})}),B(`input`,{autoComplete:`current-password`,disabled:w,id:`smartsafehub-password`,name:`password`,onBlur:()=>x(!1),onInput:e=>l(e.currentTarget.value),onKeyDown:E,onKeyUp:E,placeholder:`관리자 비밀번호`,ref:a,type:v?`text`:`password`,value:c}),B(`button`,{"aria-label":v?`비밀번호 숨기기`:`비밀번호 표시`,"aria-pressed":v,class:`ssh-login-password-toggle`,disabled:w,onClick:()=>{y(e=>!e),window.requestAnimationFrame(()=>a.current?.focus())},title:v?`비밀번호 숨기기`:`비밀번호 표시`,type:`button`,children:B(v?Jt:qt,{})})]})]}),o.trim()===`root`&&c.length===0?B(`p`,{class:`ssh-login-password-hint`,children:`초기 설정 전 root 계정은 비밀번호가 비어 있을 수 있습니다.`}):null,b?B(`p`,{class:`ssh-login-caps`,role:`status`,children:`Caps Lock이 켜져 있습니다.`}):null,B(`button`,{class:`ssh-login-submit`,disabled:w,type:`submit`,children:[w?B(H,{class:`ssh-login-submit-spinner`,"aria-hidden":`true`}):null,B(`span`,{children:w?`로그인 중…`:`로그인`})]})]}),B(`div`,{class:`ssh-login-security-note`,children:[B(At,{"aria-hidden":`true`}),B(`span`,{children:`입력한 계정 정보는 현재 공유기의 LuCI 인증 경로로만 전송됩니다.`})]}),B(`div`,{class:`ssh-login-security-note`,children:[B(Kt,{"aria-hidden":`true`}),B(`span`,{children:`관리자 비밀번호를 잊었다면 전원이 켜진 상태에서 Reset 버튼을 5~9초 누른 뒤 놓아 비밀번호만 복구할 수 있습니다. 10초 이상 누르면 모든 사용자 설정을 초기화하는 기기 초기화가 실행됩니다.`})]}),g?B(`a`,{class:`ssh-login-fallback`,href:r,children:`기본 LuCI 로그인으로 계속`}):null]}),B(`footer`,{class:`ssh-login-footer`,children:[B(`span`,{children:`SmartSafeHub`}),B(`span`,{"aria-hidden":`true`,children:`·`}),B(`span`,{children:window.location.host})]})]})]})]})}var ry=`smartsafehub-entry-root`,iy=`data-smartsafehub-mount`,ay=`data-smartsafehub-shadow-style`;function oy(){let e=Se(`/`);new Set([e,e.replace(/\/$/,``),Se(`/smartsafehub`),Se(`/admin/smartsafehub`)]).has(window.location.pathname)&&window.history.replaceState(null,``,`${we()}${window.location.search}${window.location.hash}`)}function sy(e,t){Ie(),window.__SMARTHUB_BOOTSTRAP__=Object.freeze({sessionId:e,rpcUrl:Se(`/admin/ubus`),assetBase:t.dataset.assetBase??`/luci-static/smartsafehub/`,assetVersion:t.dataset.assetVersion??`0.2.24-r2`,locale:document.documentElement.lang||`ko`})}function cy(e,t){let n=window.__SMARTHUB_BOOTSTRAP__,r=n?.assetBase??t.dataset.assetBase??`/luci-static/smartsafehub/`,i=n?.assetVersion??t.dataset.assetVersion,a=`${r}${r.endsWith(`/`)?``:`/`}${e}`;return i?`${a}?v=${encodeURIComponent(i)}`:a}function ly(e,t){let n=e.shadowRoot??e.attachShadow({mode:`open`}),r=n.querySelector(`link[${ay}]`),i=cy(`app.css`,e);r?r.getAttribute(`href`)!==i&&(r.href=i):(r=document.createElement(`link`),r.rel=`stylesheet`,r.href=i,r.setAttribute(ay,``),n.appendChild(r));let a=n.querySelector(`[${iy}]`);return a?a.className!==t&&(a.className=t):(a=document.createElement(`div`),a.className=t,a.setAttribute(iy,``),n.appendChild(a)),a}function uy(e,t,n){sy(n,e),t.className=`smartsafehub-shadow-root`,fe(B($v,{onAdministratorPasswordChanged:()=>{dy(e,t,`관리자 비밀번호가 변경되었습니다. 새 비밀번호로 다시 로그인해 주세요.`)},onPasswordConfigured:n=>{dy(e,t,n?`관리자 비밀번호 복구가 완료되었습니다. 새 비밀번호로 다시 로그인해 주세요.`:`관리자 비밀번호가 설정되었습니다. 새 비밀번호로 다시 로그인해 주세요.`)}}),t)}function dy(e,t,n){delete window.__SMARTHUB_BOOTSTRAP__,t.className=`smartsafehub-login-shadow-root`,fe(B(ny,{notice:n,onAuthenticated:n=>{uy(e,t,n)}}),t)}async function fy(){pn(dn());let e=document.getElementById(ry);if(!e)return;oy(),e.style.display=`block`,e.style.width=`100%`,e.style.minWidth=`0`,e.style.minHeight=`100dvh`,e.style.maxWidth=`100%`,e.style.isolation=`isolate`;let t=ly(e,`smartsafehub-login-shadow-root`);window.addEventListener(Ne,()=>{dy(e,t,Pe)}),fe(B(ny,{onAuthenticated:n=>{uy(e,t,n)},probing:!0}),t);try{let n=await ge();if(n){uy(e,t,n);return}}catch{}try{let n=await Ae();if(n){uy(e,t,n);return}}catch{}dy(e,t)}fy(); \ No newline at end of file diff --git a/luci-app-smartsafehub/tests/test-update-ui-contract.sh b/luci-app-smartsafehub/tests/test-update-ui-contract.sh index 67b5cde1e..5d53d0a1d 100755 --- a/luci-app-smartsafehub/tests/test-update-ui-contract.sh +++ b/luci-app-smartsafehub/tests/test-update-ui-contract.sh @@ -408,8 +408,13 @@ grep -Fq '빌드 ID {data.current.buildId}' "$FIRMWARE_CARD" || \ fail 'firmware UI must keep build_id as secondary diagnostic identity' grep -Fq 'data.release?.version' "$FIRMWARE_CARD" || \ fail 'firmware UI must use the Hub release version for the available firmware version' -grep -Fq "펌웨어 {data.release.version || '미확인'} · OpenWrt" "$FIRMWARE_CARD" || \ - fail 'available firmware details must distinguish product firmware version from the OpenWrt base version' +grep -Fq '빌드 ID {data.release.buildId}' "$FIRMWARE_CARD" || \ + fail 'available firmware version must keep build_id as secondary diagnostic identity' +grep -Fq "펌웨어 {data.release.version || '미확인'} · {formatBytes(data.release.sysupgrade.sizeBytes)}" "$FIRMWARE_CARD" || \ + fail 'available firmware details must show product firmware version and image size without OpenWrt base metadata' +if grep -Fq "펌웨어 {data.release.version || '미확인'} · OpenWrt" "$FIRMWARE_CARD"; then + fail 'available firmware summary must not expose the OpenWrt base version' +fi grep -Fq "(data.release.channel || data.settings.channel) === 'beta' ? 'Beta' : 'Stable'" "$FIRMWARE_CARD" || fail 'available firmware details must prefer the release firmware channel over package update settings' grep -Fq "[class~='bg-sky-50']" "$APP_CSS" || fail 'dark mode must define a sky surface override for the firmware update panel' grep -Fq "[class~='text-sky-700']" "$APP_CSS" || fail 'dark mode must define a sky text override for the firmware update panel' diff --git a/luci-app-substore/CHANGELOG.md b/luci-app-substore/CHANGELOG.md index 482f2f916..da97075e4 100644 --- a/luci-app-substore/CHANGELOG.md +++ b/luci-app-substore/CHANGELOG.md @@ -2,6 +2,30 @@ All notable changes to this project will be documented in this file. +## [2.3.0-r2] - 新增 Clash 原版与 WireGuard .conf 输出,输出层清理 + +- 新增输出格式 **WireGuard / AmneziaWG `.conf`**(`target=wgconf`,别名 `wg` / `wireguard` / `amneziawg` / `amnezia` / `conf`) + - 与 `parser.parse_wireguard_conf` 互为逆操作:输出 `[Interface]` / `[Peer]` 标准 wg-quick 配置 + - `[Interface]`:PrivateKey / Address(IPv4 + IPv6 合并)/ ListenPort / MTU / DNS / AmneziaWG 参数(键名首字母大写,按键名排序保证可 diff) + - `[Peer]`:PublicKey / PresharedKey / AllowedIPs / Endpoint / PersistentKeepalive + - IPv6 Endpoint 自动加方括号(`[2001:db8::1]:51821`) + - 仅输出 wireguard 节点;无 wireguard 节点时明确报错(而非下载到空文件) + - 已知有损项:`Reserved` 不是 wg-quick 标准键,导出时不写出(`reserved` 仍保留在 clash.meta / sing-box / URI 输出中) + - 新增模块 `root/usr/share/substore/output_wireguard_conf.lua` +- 新增输出格式 **Clash 原版**(`target=clash`),面向 Dreamacro Clash / ClashX / Clash for Windows + - 过滤原版不支持的协议(vless / hysteria2 / hysteria / tuic / wireguard),其余复用 Clash.Meta 的 YAML 生成 + - 采用排除法而非白名单,避免误丢原版其实支持的协议 +- ⚠️ **行为变更**:`target=clash` 语义由「Clash.Meta」改为「Clash 原版」。原先使用 `?target=clash` 拉取 Clash.Meta 配置的用户请改用 `target=clashmeta`(或 `yaml` / `mihomo`) +- ⚠️ **行为变更(无感)**:未指定 `target` 时的默认格式显式固定为 `clashmeta`,与历史默认行为一致 +- 输出层清理(`output.lua`) + - 删除死代码 `to_clash_yaml` / `to_json` / `to_base64`(无任何调用点;且 `to_clash_yaml` 会把 `type:` 写成原始协议名,产出非法 YAML) + - 删除随之失效的 `util` / `node` require + - 新增 `M.FORMAT_OPTIONS` 作为格式清单的唯一数据源,`subscriptions.htm` 与 `output.htm` 两处硬编码 `