Back to Napplet Explorer
SOURCE / PINNED RELEASE

Made of little things.

Napplet Explorer

Release
4069af3dde6b…
Author-recorded commit
Not provided
License
Check the original source

The hash-verified playable HTML, which may contain bundled or minified code. This view does not execute it.

index.html
<!doctype html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Napplet Explorer</title>
    <script type="module" crossorigin>(function(){const t=document.createElement("link").relList;if(t&&t.supports&&t.supports("modulepreload"))return;for(const o of document.querySelectorAll('link[rel="modulepreload"]'))r(o);new MutationObserver(o=>{for(const i of o)if(i.type==="childList")for(const s of i.addedNodes)s.tagName==="LINK"&&s.rel==="modulepreload"&&r(s)}).observe(document,{childList:!0,subtree:!0});function n(o){const i={};return o.integrity&&(i.integrity=o.integrity),o.referrerPolicy&&(i.referrerPolicy=o.referrerPolicy),o.crossOrigin==="use-credentials"?i.credentials="include":o.crossOrigin==="anonymous"?i.credentials="omit":i.credentials="same-origin",i}function r(o){if(o.ep)return;o.ep=!0;const i=n(o);fetch(o.href,i)}})();var Q=new Map,T=new Map,J=new Map,Le=!1,F=null,Qt=new Set(["Tab","Shift+Tab","Escape"]);function $e(e,t){return e.type===t}function Jt(e){var r;if(!(e instanceof Element))return!1;const t=e.tagName;if(t==="TEXTAREA"||t==="SELECT")return!0;if(t==="INPUT"){const o=((r=e.type)==null?void 0:r.toLowerCase())??"text";return new Set(["text","search","email","url","password","number","tel","date","datetime-local","month","time","week"]).has(o)||o===""}if(e.isContentEditable)return!0;const n=e.contentEditable;return n==="true"||n==="plaintext-only"}function Yt(e){return e==="Control"||e==="Alt"||e==="Shift"||e==="Meta"}function Gt(e){const t=[];return e.altKey&&t.push("Alt"),e.ctrlKey&&t.push("Ctrl"),e.metaKey&&t.push("Meta"),e.shiftKey&&t.push("Shift"),t.push(e.key),t.join("+")}function Wt(e){Q.clear();for(const t of e.bindings)Q.set(t.key,t.actionId)}function Vt(e){const t=J.get(e.id);if(t){if(J.delete(e.id),e.error){t.reject(new Error(e.error));return}t.resolve({actionId:e.actionId,binding:e.binding})}}function Zt(e){const t=T.get(e.actionId);if(t)for(const n of t)n()}function dt(e){if(Jt(e.target)||Yt(e.key)||e.isComposing)return;const t=Gt(e);if(!Qt.has(t)&&Q.has(t)){e.preventDefault();const r=Q.get(t),o=T.get(r);if(o)for(const i of o)i();return}const n={type:"keys.forward",key:e.key,code:e.code,ctrl:e.ctrlKey,alt:e.altKey,shift:e.shiftKey,meta:e.metaKey};window.parent.postMessage(n,"*")}function Xt(e){$e(e,"keys.bindings")?Wt(e):$e(e,"keys.registerAction.result")?Vt(e):$e(e,"keys.action")&&Zt(e)}function en(e){const t=crypto.randomUUID();return new Promise((n,r)=>{J.set(t,{resolve:n,reject:r});const o={type:"keys.registerAction",id:t,action:e};window.parent.postMessage(o,"*"),setTimeout(()=>{J.delete(t)&&r(new Error("keys.registerAction timed out"))},3e4)})}function tn(e){const t={type:"keys.unregisterAction",actionId:e};window.parent.postMessage(t,"*")}function nn(e,t){return T.has(e)||T.set(e,new Set),T.get(e).add(t),{close(){const n=T.get(e);n&&(n.delete(t),n.size===0&&T.delete(e))}}}function rn(){return Le&&F||(document.addEventListener("keydown",dt,!0),Le=!0,F=()=>{document.removeEventListener("keydown",dt,!0),Q.clear(),T.clear(),J.clear(),Le=!1,F=null}),F}var de=new Map,C=new Map,R=new Map,P=new Map,N=new Map;function H(e,t){return e.type===t}function on(e){const t=de.get(e.id);if(!t)return;de.delete(e.id),clearTimeout(t.timeout);const n={};e.sessionId!==void 0&&(n.sessionId=e.sessionId),e.owner!==void 0&&(n.owner=e.owner),e.error!==void 0&&(n.error=e.error),t.resolve(n)}function sn(e){const t=C.get(e.sessionId);if(t)for(const n of t)n(e.action,e.value)}function an(e){const t=R.get(e.sessionId);if(t)for(const n of t)n(e.controls)}function cn(e){const t=P.get(e.sessionId);if(!t)return;const n={status:e.status,position:e.position,duration:e.duration,volume:e.volume};for(const r of t)r(n)}function ln(e){const t=N.get(e.sessionId);if(t)for(const n of t)n(e.actions)}function dn(e){H(e,"media.session.create.result")?on(e):H(e,"media.command")?sn(e):H(e,"media.controls")?an(e):H(e,"media.state")?cn(e):H(e,"media.capabilities")&&ln(e)}function un(e){const t=crypto.randomUUID();return new Promise((n,r)=>{const o=setTimeout(()=>{de.delete(t)&&r(new Error("media.session.create timed out"))},3e4);de.set(t,{resolve:n,reject:r,timeout:o});const i={type:"media.session.create",id:t,...e};window.parent.postMessage(i,"*")})}function fn(e,t){const n={type:"media.session.update",sessionId:e,metadata:t};window.parent.postMessage(n,"*")}function pn(e){const t={type:"media.session.destroy",sessionId:e};window.parent.postMessage(t,"*"),C.delete(e),R.delete(e),P.delete(e),N.delete(e)}function yn(e,t){const n={type:"media.state",sessionId:e,...t};window.parent.postMessage(n,"*")}function mn(e,t){const n={type:"media.capabilities",sessionId:e,actions:t};window.parent.postMessage(n,"*")}function gn(e,t,n){const r={type:"media.command",sessionId:e,action:t,...n===void 0?{}:{value:n}};window.parent.postMessage(r,"*")}function hn(e,t){return C.has(e)||C.set(e,new Set),C.get(e).add(t),{close(){const n=C.get(e);n&&(n.delete(t),n.size===0&&C.delete(e))}}}function wn(e,t){return P.has(e)||P.set(e,new Set),P.get(e).add(t),{close(){const n=P.get(e);n&&(n.delete(t),n.size===0&&P.delete(e))}}}function vn(e,t){return N.has(e)||N.set(e,new Set),N.get(e).add(t),{close(){const n=N.get(e);n&&(n.delete(t),n.size===0&&N.delete(e))}}}function bn(e,t){return R.has(e)||R.set(e,new Set),R.get(e).add(t),{close(){const n=R.get(e);n&&(n.delete(t),n.size===0&&R.delete(e))}}}var Mt=3e4,ue=new Map,fe=new Map,He=new Set,ze=new Set,Ke=new Set,je=new Set;function k(e,t){return e.type===t}function En(e){const t=ue.get(e.id);if(t){if(ue.delete(e.id),e.error){t.reject(new Error(e.error));return}e.notificationId?t.resolve({notificationId:e.notificationId}):t.reject(new Error("notify.send.result missing notificationId"))}}function Mn(e){const t=fe.get(e.id);t&&(fe.delete(e.id),t.resolve({granted:e.granted}))}function Sn(e){for(const t of He)t(e.notificationId,e.actionId)}function Tn(e){for(const t of ze)t(e.notificationId)}function xn(e){for(const t of Ke)t(e.notificationId,e.reason)}function Un(e){for(const t of je)t(e.controls)}function In(e){k(e,"notify.send.result")?En(e):k(e,"notify.permission.result")?Mn(e):k(e,"notify.action")?Sn(e):k(e,"notify.clicked")?Tn(e):k(e,"notify.dismissed")?xn(e):k(e,"notify.controls")&&Un(e)}function Cn(e){const t=crypto.randomUUID();return new Promise((n,r)=>{ue.set(t,{resolve:n,reject:r});const o={type:"notify.send",id:t,...e};window.parent.postMessage(o,"*"),setTimeout(()=>{ue.delete(t)&&r(new Error("notify.send timed out"))},Mt)})}function Rn(e){const t={type:"notify.dismiss",notificationId:e};window.parent.postMessage(t,"*")}function Pn(e){const t={type:"notify.badge",count:e};window.parent.postMessage(t,"*")}function Nn(e){const t={type:"notify.channel.register",...e};window.parent.postMessage(t,"*")}function An(e){const t=crypto.randomUUID();return new Promise((n,r)=>{fe.set(t,{resolve:n,reject:r});const o={type:"notify.permission.request",id:t,channel:e};window.parent.postMessage(o,"*"),setTimeout(()=>{fe.delete(t)&&r(new Error("notify.permission.request timed out"))},Mt)})}function kn(e){return He.add(e),{close(){He.delete(e)}}}function Dn(e){return ze.add(e),{close(){ze.delete(e)}}}function Ln(e){return Ke.add(e),{close(){Ke.delete(e)}}}function $n(e){return je.add(e),{close(){je.delete(e)}}}var Y=new Map,On=5e3;function ut(e){if(e.source!==window.parent)return;const t=e.data;if(typeof t!="object"||t===null||typeof t.type!="string"||!t.type.startsWith("storage.")||!t.type.endsWith(".result"))return;const n=t.id;if(!n)return;const r=Y.get(n);if(r){if(Y.delete(n),t.error){r.reject(new Error(t.error));return}r.resolve(t)}}function ee(e){return new Promise((t,n)=>{Y.set(e.id,{resolve:t,reject:n}),window.parent.postMessage(e,"*"),setTimeout(()=>{Y.delete(e.id)&&n(new Error("State request timed out"))},On)})}var M={async getItem(e){const t={type:"storage.get",id:crypto.randomUUID(),key:e};return(await ee(t)).value},async setItem(e,t){const n={type:"storage.set",id:crypto.randomUUID(),key:e,value:t};await ee(n)},async removeItem(e){const t={type:"storage.remove",id:crypto.randomUUID(),key:e};await ee(t)},async keys(){const e={type:"storage.keys",id:crypto.randomUUID()};return(await ee(e)).keys}};function qn(){return window.addEventListener("message",ut),()=>{window.removeEventListener("message",ut),Y.clear()}}var _n=3e4,oe=new Map,$=new Map;function ft(e,t){return e.type===t}function Bn(e){if(ft(e,"resource.bytes.result")){const t=e,n=$.get(t.id);if(!n)return;$.delete(t.id),n.resolve(t.blob)}else if(ft(e,"resource.bytes.error")){const t=e,n=$.get(t.id);if(!n)return;$.delete(t.id),n.reject(new Error(t.message?`${t.error}: ${t.message}`:t.error))}}function Fn(e,t){return new Promise((n,r)=>{$.set(t,{resolve:n,reject:r,url:e});const o={type:"resource.bytes",id:t,url:e};window.parent.postMessage(o,"*"),setTimeout(()=>{$.delete(t)&&r(new Error(`resource.bytes timed out for ${e}`))},_n)})}function pt(e){const t={type:"resource.cancel",id:e};window.parent.postMessage(t,"*")}function Hn(e){return fetch(e).then(t=>t.blob())}function yt(e,t,n=null){return t?t.aborted?(n&&pt(n),Promise.reject(new DOMException("Aborted","AbortError"))):new Promise((r,o)=>{const i=()=>{n&&pt(n),o(new DOMException("Aborted","AbortError"))};t.addEventListener("abort",i,{once:!0}),e.then(s=>{t.removeEventListener("abort",i),r(s)},s=>{t.removeEventListener("abort",i),o(s)})}):e}function St(e,t){var i;if((i=t==null?void 0:t.signal)!=null&&i.aborted)return Promise.reject(new DOMException("Aborted","AbortError"));const n=oe.get(e);if(n)return yt(n,t==null?void 0:t.signal);let r,o=null;try{new URL(e).protocol==="data:"?r=Hn(e):(o=crypto.randomUUID(),r=Fn(e,o))}catch{return Promise.reject(new Error(`invalid URL: ${e}`))}return r=r.finally(()=>{oe.delete(e)}),oe.set(e,r),yt(r,t==null?void 0:t.signal,o)}function zn(e){const t={url:"",revoke:()=>{}};let n=null,r=!1;const o=St(e).then(i=>{if(!r)return n=URL.createObjectURL(i),t.url=n,n});return t.revoke=()=>{r||(r=!0,n&&(URL.revokeObjectURL(n),n=null))},Object.defineProperty(t,"ready",{value:o,enumerable:!1,writable:!1}),t}function Kn(e){if(!(!e||e.length===0))for(const t of e)oe.set(t.url,Promise.resolve(t.blob))}function jn(e,t,n,r){const o=Array.isArray(e)?e:[e],i=crypto.randomUUID();function s(c){if(c.source!==window.parent)return;const d=c.data;if(typeof d!="object"||d===null||typeof d.type!="string"||!d.type.startsWith("relay."))return;const f=d;if(!(!("subId"in f)||f.subId!==i))if(d.type==="relay.event"){const w=d;Kn(w.resources),t(w.event)}else d.type==="relay.eose"?n():d.type==="relay.closed"&&window.removeEventListener("message",s)}window.addEventListener("message",s);const a={type:"relay.subscribe",id:crypto.randomUUID(),subId:i,filters:o,...r!=null&&r.relay?{relay:r.relay}:{}};return window.parent.postMessage(a,"*"),{close(){const c={type:"relay.close",id:crypto.randomUUID(),subId:i};window.parent.postMessage(c,"*"),window.removeEventListener("message",s)}}}function Qn(e,t){const n=crypto.randomUUID();return new Promise((r,o)=>{function i(a){if(a.source!==window.parent)return;const c=a.data;if(typeof c!="object"||c===null||typeof c.type!="string"||c.type!=="relay.publish.result"&&c.type!=="relay.publish.error")return;const d=c;d.id===n&&(window.removeEventListener("message",i),d.error||c.type==="relay.publish.error"?o(new Error(d.error||"relay:write denied")):d.event?r(d.event):o(new Error("relay.publish.result missing event")))}window.addEventListener("message",i);const s={type:"relay.publish",id:n,event:e};window.parent.postMessage(s,"*")})}function Jn(e,t,n="nip44"){const r=crypto.randomUUID();return new Promise((o,i)=>{function s(c){if(c.source!==window.parent)return;const d=c.data;if(typeof d!="object"||d===null||typeof d.type!="string"||d.type!=="relay.publishEncrypted.result")return;const f=d;f.id===r&&(window.removeEventListener("message",s),f.error?i(new Error(f.error)):f.event?o(f.event):i(new Error("relay.publishEncrypted.result missing event")))}window.addEventListener("message",s);const a={type:"relay.publishEncrypted",id:r,event:e,recipient:t,encryption:n};window.parent.postMessage(a,"*")})}function Yn(e){const t=Array.isArray(e)?e:[e],n=crypto.randomUUID();return new Promise((r,o)=>{function i(a){if(a.source!==window.parent)return;const c=a.data;if(typeof c!="object"||c===null||typeof c.type!="string"||c.type!=="relay.query.result")return;const d=c;d.id===n&&(window.removeEventListener("message",i),d.error?o(new Error(d.error)):r(d.events))}window.addEventListener("message",i);const s={type:"relay.query",id:n,filters:t};window.parent.postMessage(s,"*")})}var Gn=3e4,O=new Map,Qe=new Set,Wn=new Set(["identity.getPublicKey.result","identity.getRelays.result","identity.getProfile.result","identity.getFollows.result","identity.getList.result","identity.getZaps.result","identity.getMutes.result","identity.getBlocked.result","identity.getBadges.result","identity.changed","identity.getPublicKey","identity.getRelays","identity.getProfile","identity.getFollows","identity.getList","identity.getZaps","identity.getMutes","identity.getBlocked","identity.getBadges"]);function Vn(e){return Wn.has(e.type)}function Zn(e){if(Vn(e))switch(e.type){case"identity.getPublicKey.result":Xn(e.id,e.pubkey);return;case"identity.changed":er(e.pubkey);return;case"identity.getRelays.result":S(e.id,e.relays,e.error);return;case"identity.getProfile.result":S(e.id,e.profile,e.error);return;case"identity.getFollows.result":S(e.id,e.pubkeys,e.error);return;case"identity.getList.result":S(e.id,e.entries,e.error);return;case"identity.getZaps.result":S(e.id,e.zaps,e.error);return;case"identity.getMutes.result":S(e.id,e.pubkeys,e.error);return;case"identity.getBlocked.result":S(e.id,e.pubkeys,e.error);return;case"identity.getBadges.result":S(e.id,e.badges,e.error);return;case"identity.getPublicKey":case"identity.getRelays":case"identity.getProfile":case"identity.getFollows":case"identity.getList":case"identity.getZaps":case"identity.getMutes":case"identity.getBlocked":case"identity.getBadges":return;default:return}}function Xn(e,t){const n=O.get(e);n&&(O.delete(e),clearTimeout(n.timeout),n.resolve(t))}function S(e,t,n){const r=O.get(e);r&&(O.delete(e),clearTimeout(r.timeout),n?r.reject(new Error(n)):r.resolve(t))}function er(e){if(typeof e=="string")for(const t of Qe)t(e)}function b(e){return new Promise((t,n)=>{const r=setTimeout(()=>{O.delete(e.id)&&n(new Error(`${e.type} timed out`))},Gn);O.set(e.id,{resolve:t,reject:n,timeout:r}),window.parent.postMessage(e,"*")})}function tr(){const e={type:"identity.getPublicKey",id:crypto.randomUUID()};return b(e)}function nr(e){Qe.add(e);let t=!1;return{close(){t||(t=!0,Qe.delete(e))}}}function rr(){const e={type:"identity.getRelays",id:crypto.randomUUID()};return b(e)}function or(){const e={type:"identity.getProfile",id:crypto.randomUUID()};return b(e)}function ir(){const e={type:"identity.getFollows",id:crypto.randomUUID()};return b(e)}function sr(e){const t={type:"identity.getList",id:crypto.randomUUID(),listType:e};return b(t)}function ar(){const e={type:"identity.getZaps",id:crypto.randomUUID()};return b(e)}function cr(){const e={type:"identity.getMutes",id:crypto.randomUUID()};return b(e)}function lr(){const e={type:"identity.getBlocked",id:crypto.randomUUID()};return b(e)}function dr(){const e={type:"identity.getBadges",id:crypto.randomUUID()};return b(e)}var ur=3e4,pe=new Map,Je=new Set,fr=new Set(["theme.get.result","theme.changed","theme.get"]);function pr(e){return fr.has(e.type)}function yr(e){if(pr(e))switch(e.type){case"theme.get.result":mr(e.id,e.theme,e.error);return;case"theme.changed":gr(e.theme);return;case"theme.get":return;default:return}}function mr(e,t,n){const r=pe.get(e);r&&(pe.delete(e),clearTimeout(r.timeout),n?r.reject(new Error(n)):r.resolve(t))}function gr(e){for(const t of Je)t(e)}function hr(e){return new Promise((t,n)=>{const r=setTimeout(()=>{pe.delete(e.id)&&n(new Error(`${e.type} timed out`))},ur);pe.set(e.id,{resolve:t,reject:n,timeout:r}),window.parent.postMessage(e,"*")})}function wr(){const e={type:"theme.get",id:crypto.randomUUID()};return hr(e)}function vr(e){Je.add(e);let t=!1;return{close(){t||(t=!0,Je.delete(e))}}}var L=new Map;function br(e,t=[],n=""){let r;try{r=n?JSON.parse(n):void 0}catch{r=n||void 0}const o={type:"inc.emit",topic:e,...r!==void 0?{payload:r}:{}};window.parent.postMessage(o,"*")}function Er(e,t){const n=(o,i)=>{const s={id:"",pubkey:i,created_at:Math.floor(Date.now()/1e3),kind:0,tags:[["t",e]],content:typeof o=="string"?o:JSON.stringify(o??{}),sig:""};t(o,s)};L.has(e)||L.set(e,[]),L.get(e).push(n);const r={type:"inc.subscribe",id:crypto.randomUUID(),topic:e};return window.parent.postMessage(r,"*"),{close(){const o=L.get(e);if(o){const s=o.indexOf(n);s>=0&&o.splice(s,1),o.length===0&&L.delete(e)}const i={type:"inc.unsubscribe",topic:e};window.parent.postMessage(i,"*")}}}function Mr(e){const t=L.get(e.topic);if(t){const n=e.payload??{},r=e.sender??"";for(const o of t)o(n,r)}}function Oe(e,t){return e.type===t}var Tt=3e4,Sr="napplet-config-schema",ie=null,ye=null,A=new Set,me=new Set,G=new Map,W=new Map,qe=!1;function Tr(e){Oe(e,"config.registerSchema.result")?xr(e):Oe(e,"config.values")?Ur(e):Oe(e,"config.schemaError")&&Ir(e)}function xr(e){const t=W.get(e.id);if(t)if(W.delete(e.id),e.ok)ie=t.schema,t.resolve();else{const n=e.code??"invalid-schema",r=e.error??"schema rejected";t.reject(new Error(`${n}: ${r}`))}}function Ur(e){if(ye=e.values,typeof e.id=="string"){const t=G.get(e.id);if(!t)return;G.delete(e.id),t.resolve(e.values);return}for(const t of A)try{t(e.values)}catch{}}function Ir(e){const t={code:e.code,error:e.error};for(const n of me)try{n(t)}catch{}}function Cr(){if(typeof document>"u")return null;const e=document.querySelector(`meta[name="${Sr}"]`);if(!e)return null;const t=e.getAttribute("content");if(!t)return null;try{return JSON.parse(t)}catch{return null}}function xt(e,t){const n=crypto.randomUUID();return new Promise((r,o)=>{W.set(n,{resolve:r,reject:o,schema:e});const i=t===void 0?{type:"config.registerSchema",id:n,schema:e}:{type:"config.registerSchema",id:n,schema:e,version:t};window.parent.postMessage(i,"*"),setTimeout(()=>{W.delete(n)&&o(new Error("config.registerSchema timed out"))},Tt)})}function Ut(){const e=crypto.randomUUID();return new Promise((t,n)=>{G.set(e,{resolve:t,reject:n});const r={type:"config.get",id:e};window.parent.postMessage(r,"*"),setTimeout(()=>{G.delete(e)&&n(new Error("config.get timed out"))},Tt)})}function It(e){const t=A.size===0;if(A.add(e),t){const n={type:"config.subscribe"};window.parent.postMessage(n,"*")}else if(ye!==null){const n=ye;queueMicrotask(()=>{if(A.has(e)&&n!==null)try{e(n)}catch{}})}return{close(){if(A.delete(e)&&A.size===0){const r={type:"config.unsubscribe"};window.parent.postMessage(r,"*")}}}}function Ct(e){const t=e==null?void 0:e.section,n=t===void 0?{type:"config.openSettings"}:{type:"config.openSettings",section:t};window.parent.postMessage(n,"*")}function Rt(e){return me.add(e),()=>{me.delete(e)}}function Rr(){if(qe)return()=>{};ie=Cr();const e=window,t=e.napplet??(e.napplet={}),n={registerSchema:xt,get:Ut,subscribe:It,openSettings:Ct,onSchemaError:Rt};return Object.defineProperty(n,"schema",{get:()=>ie,enumerable:!0,configurable:!1}),t.config=n,qe=!0,()=>{A.clear(),me.clear(),G.clear(),W.clear(),ye=null,ie=null,t.config===n&&delete t.config,qe=!1}}var et=3e4,ge=new Map,he=new Map,we=new Map,Ye=new Set;function te(e,t){return e.type===t}function Pr(e){const t=ge.get(e.id);if(t){if(ge.delete(e.id),clearTimeout(t.timeout),e.error!==void 0){t.reject(new Error(e.error));return}t.resolve(Array.isArray(e.servers)?e.servers:[])}}function Nr(e){const t=he.get(e.id);if(t){if(he.delete(e.id),clearTimeout(t.timeout),e.error!==void 0){t.reject(new Error(e.error));return}if(e.message===void 0){t.reject(new Error("cvm.request.result missing message"));return}t.resolve(e.message)}}function Ar(e){const t=we.get(e.id);if(t){if(we.delete(e.id),clearTimeout(t.timeout),e.error!==void 0){t.reject(new Error(e.error));return}t.resolve()}}function kr(e){if(!(!e.server||!e.message))for(const t of Ye)t(e.server,e.message)}function Dr(e){te(e,"cvm.discover.result")?Pr(e):te(e,"cvm.request.result")?Nr(e):te(e,"cvm.close.result")?Ar(e):te(e,"cvm.event")&&kr(e)}function Lr(e){const t=crypto.randomUUID();return new Promise((n,r)=>{const o=setTimeout(()=>{ge.delete(t)&&r(new Error("cvm.discover timed out"))},et);ge.set(t,{resolve:n,reject:r,timeout:o});const i={type:"cvm.discover",id:t,...e===void 0?{}:{query:e}};window.parent.postMessage(i,"*")})}function Pt(e,t,n){const r=crypto.randomUUID(),o=(n==null?void 0:n.timeoutMs)??et;return new Promise((i,s)=>{const a=setTimeout(()=>{he.delete(r)&&s(new Error("cvm.request timed out"))},o);he.set(r,{resolve:i,reject:s,timeout:a});const c={type:"cvm.request",id:r,server:e,message:t,...n===void 0?{}:{options:n}};window.parent.postMessage(c,"*")})}async function Pe(e,t,n,r){const o=await Pt(e,{jsonrpc:"2.0",id:crypto.randomUUID(),method:t,...n===void 0?{}:{params:n}},r);if(o.error!==void 0){const i=o.error;throw new Error(i!=null&&i.message?`${t}: ${i.message}`:`${t} failed`)}return o.result}async function $r(e,t){const n=await Pe(e,"tools/list",void 0,t);return(n==null?void 0:n.tools)??[]}function Or(e,t,n,r){return Pe(e,"tools/call",{name:t,...n===void 0?{}:{arguments:n}},r)}async function qr(e,t){const n=await Pe(e,"resources/list",void 0,t);return(n==null?void 0:n.resources)??[]}async function _r(e,t,n){var i;const r=await Pe(e,"resources/read",{uri:t},n),o=(i=r==null?void 0:r.contents)==null?void 0:i[0];if(!o)throw new Error(`resources/read returned no contents for ${t}`);return o}function Br(e){const t=crypto.randomUUID();return new Promise((n,r)=>{const o=setTimeout(()=>{we.delete(t)&&r(new Error("cvm.close timed out"))},et);we.set(t,{resolve:n,reject:r,timeout:o});const i={type:"cvm.close",id:t,server:e};window.parent.postMessage(i,"*")})}function Fr(e){return Ye.add(e),{close(){Ye.delete(e)}}}var tt=3e4,ve=new Map,be=new Map,Ee=new Map,q=new Map;function D(e,t){return e.type===t}function Hr(e){const t=ve.get(e.id);if(!t)return;ve.delete(e.id),clearTimeout(t.timeout);const n={events:Array.isArray(e.events)?e.events:[],relays:e.relays??{}};e.incomplete!==void 0&&(n.incomplete=e.incomplete),e.error!==void 0&&(n.error=e.error),t.resolve(n)}function zr(e){const t=be.get(e.id);if(!t)return;be.delete(e.id),clearTimeout(t.timeout);const n={ok:e.ok};e.event!==void 0&&(n.event=e.event),e.eventId!==void 0&&(n.eventId=e.eventId),e.relays!==void 0&&(n.relays=e.relays),e.error!==void 0&&(n.error=e.error),t.resolve(n)}function Kr(e){const t=Ee.get(e.id);if(t){if(Ee.delete(e.id),clearTimeout(t.timeout),e.error!==void 0){t.reject(new Error(e.error));return}if(!e.plan){t.reject(new Error("outbox.resolveRelays.result missing plan"));return}t.resolve(e.plan)}}function jr(e){const t=q.get(e.subId);if(t)for(const n of t.event)n(e.event,e.relay)}function Qr(e){const t=q.get(e.subId);if(t)for(const n of t.eose)n()}function Jr(e){const t=q.get(e.subId);if(t){for(const n of t.closed)n(e.reason);q.delete(e.subId)}}function Yr(e){D(e,"outbox.query.result")?Hr(e):D(e,"outbox.publish.result")?zr(e):D(e,"outbox.resolveRelays.result")?Kr(e):D(e,"outbox.event")?jr(e):D(e,"outbox.eose")?Qr(e):D(e,"outbox.closed")&&Jr(e)}function Gr(e,t){const n=crypto.randomUUID(),r=(t==null?void 0:t.timeoutMs)??tt;return new Promise((o,i)=>{const s=setTimeout(()=>{ve.delete(n)&&i(new Error("outbox.query timed out"))},r);ve.set(n,{resolve:o,reject:i,timeout:s});const a={type:"outbox.query",id:n,filters:e,...t===void 0?{}:{options:t}};window.parent.postMessage(a,"*")})}function Wr(e,t){const n=crypto.randomUUID(),r=crypto.randomUUID(),o={event:new Set,eose:new Set,closed:new Set};q.set(r,o);const i={type:"outbox.subscribe",id:n,subId:r,filters:e,...t===void 0?{}:{options:t}};window.parent.postMessage(i,"*");function s(a,c){a==="event"?o.event.add(c):a==="eose"?o.eose.add(c):a==="closed"&&o.closed.add(c)}return{on:s,close(){if(!q.delete(r))return;const a={type:"outbox.close",id:crypto.randomUUID(),subId:r};window.parent.postMessage(a,"*")}}}function Vr(e,t){const n=crypto.randomUUID();return new Promise((r,o)=>{const i=setTimeout(()=>{be.delete(n)&&o(new Error("outbox.publish timed out"))},tt);be.set(n,{resolve:r,reject:o,timeout:i});const s={type:"outbox.publish",id:n,event:e,...t===void 0?{}:{options:t}};window.parent.postMessage(s,"*")})}function Zr(e){const t=crypto.randomUUID();return new Promise((n,r)=>{const o=setTimeout(()=>{Ee.delete(t)&&r(new Error("outbox.resolveRelays timed out"))},tt);Ee.set(t,{resolve:n,reject:r,timeout:o});const i={type:"outbox.resolveRelays",id:t,target:e};window.parent.postMessage(i,"*")})}var Nt=3e4,Me=new Map,Se=new Map,Ge=new Set;function _e(e,t){return e.type===t}function Xr(e){const t=Me.get(e.id);if(t){if(Me.delete(e.id),clearTimeout(t.timeout),e.result!==void 0){t.resolve(e.result);return}t.reject(new Error(e.error??"upload failed"))}}function eo(e){const t=Se.get(e.id);if(t){if(Se.delete(e.id),clearTimeout(t.timeout),e.status!==void 0){t.resolve(e.status);return}t.reject(new Error(e.error??"upload status unavailable"))}}function to(e){if(e.status)for(const t of Ge)t(e.status)}function no(e){_e(e,"upload.upload.result")?Xr(e):_e(e,"upload.status.result")?eo(e):_e(e,"upload.status.changed")&&to(e)}function ro(e){const t=crypto.randomUUID();return new Promise((n,r)=>{const o=setTimeout(()=>{Me.delete(t)&&r(new Error("upload.upload timed out"))},Nt);Me.set(t,{resolve:n,reject:r,timeout:o});const i={type:"upload.upload",id:t,request:e};window.parent.postMessage(i,"*")})}function oo(e){const t=crypto.randomUUID();return new Promise((n,r)=>{const o=setTimeout(()=>{Se.delete(t)&&r(new Error("upload.status timed out"))},Nt);Se.set(t,{resolve:n,reject:r,timeout:o});const i={type:"upload.status",id:t,uploadId:e};window.parent.postMessage(i,"*")})}function io(e){return Ge.add(e),{close(){Ge.delete(e)}}}var nt=3e4,Te=new Map,xe=new Map,Ue=new Map,We=new Set;function ne(e,t){return e.type===t}function so(e){const t=Te.get(e.id);if(t){if(Te.delete(e.id),clearTimeout(t.timeout),e.result!==void 0){t.resolve(e.result);return}t.reject(new Error(e.error??"invoke failed"))}}function ao(e){const t=xe.get(e.id);if(t){if(xe.delete(e.id),clearTimeout(t.timeout),e.availability!==void 0){t.resolve(e.availability);return}t.reject(new Error(e.error??"intent availability unavailable"))}}function co(e){const t=Ue.get(e.id);if(t){if(Ue.delete(e.id),clearTimeout(t.timeout),e.handlers!==void 0){t.resolve(e.handlers);return}t.reject(new Error(e.error??"intent handlers unavailable"))}}function lo(e){if(e.availability)for(const t of We)t(e.availability)}function uo(e){ne(e,"intent.invoke.result")?so(e):ne(e,"intent.available.result")?ao(e):ne(e,"intent.handlers.result")?co(e):ne(e,"intent.changed")&&lo(e)}function At(e){const t=crypto.randomUUID();return new Promise((n,r)=>{const o=setTimeout(()=>{Te.delete(t)&&r(new Error("intent.invoke timed out"))},nt);Te.set(t,{resolve:n,reject:r,timeout:o});const i={type:"intent.invoke",id:t,request:e};window.parent.postMessage(i,"*")})}function fo(e,t,n){return At({archetype:e,action:"open",payload:t,...n})}function po(e){const t=crypto.randomUUID();return new Promise((n,r)=>{const o=setTimeout(()=>{xe.delete(t)&&r(new Error("intent.available timed out"))},nt);xe.set(t,{resolve:n,reject:r,timeout:o});const i={type:"intent.available",id:t,archetype:e};window.parent.postMessage(i,"*")})}function yo(){const e=crypto.randomUUID();return new Promise((t,n)=>{const r=setTimeout(()=>{Ue.delete(e)&&n(new Error("intent.handlers timed out"))},nt);Ue.set(e,{resolve:t,reject:n,timeout:r});const o={type:"intent.handlers",id:e};window.parent.postMessage(o,"*")})}function mo(e){return We.add(e),{close(){We.delete(e)}}}function rt(e){return Array.isArray(e)?e.filter(t=>typeof t=="string"):[]}function go(e){if(typeof e!="object"||e===null||Array.isArray(e))return{};const t={};for(const[n,r]of Object.entries(e))t[n]=rt(r);return t}function ho(e){if(typeof e!="object"||e===null)return{domains:[],protocols:{}};const t=e;return{domains:rt(t.domains),protocols:go(t.protocols)}}function wo(e){const t=e,n=t.class;return{capabilities:ho(t.capabilities),services:rt(t.services),class:typeof n=="number"?n:null}}function vo(e){const t=new Set(e.capabilities.domains);return(n,r)=>{if(typeof n!="string")return!1;if(r!==void 0){const o=e.capabilities.protocols[n];return Array.isArray(o)&&o.includes(r)}return t.has(n)}}function bo(e,t){return!1}var V=new Map,se=new Map,mt=new Map;function Ve(e,t,n){const r=crypto.randomUUID(),o={type:"nostrdb.request",id:r,method:e,content:t,...n?{subId:n}:{}};return window.parent.postMessage(o,"*"),r}function z(e,t,n){return new Promise((r,o)=>{const i=Ve(e,t,n);V.set(i,{resolve:r,reject:o}),setTimeout(()=>{V.delete(i)&&o(new Error(`NIPDB request '${e}' timed out`))},1e4)})}function Eo(e){const t=V.get(e.id);if(t){V.delete(e.id);try{const n=e.content?JSON.parse(e.content):void 0;t.resolve(n)}catch{t.resolve(void 0)}}}function Mo(e){const t=se.get(e.subId);if(t)try{const n=JSON.parse(e.content);t(n)}catch{}}var So=["query","add","event","replaceable","count","subscribe"];function gt(e){const t=e.data;typeof t!="object"||t===null||typeof t.type!="string"||t.type.startsWith("nostrdb.")&&(t.type==="nostrdb.result"?Eo(t):t.type==="nostrdb.event-push"&&Mo(t))}function To(){return window.addEventListener("message",gt),window.nostrdb={async query(e){const t=Array.isArray(e)?e:[e];return await z("query",JSON.stringify(t))??[]},async add(e){return await z("add",JSON.stringify(e))===!0},async event(e){const t=await z("event",JSON.stringify({id:e}));return t??void 0},async replaceable(e,t,n){const r={kind:e,author:t};n!==void 0&&(r.identifier=n);const o=await z("replaceable",JSON.stringify(r));return o??void 0},async count(e){const t=Array.isArray(e)?e:[e],n=await z("count",JSON.stringify(t));return typeof n=="number"?n:0},async supports(){return[...So]},async*subscribe(e){const t=crypto.randomUUID(),n=Array.isArray(e)?e:[e];Ve("subscribe",JSON.stringify(n),t);const r=[];let o=null;function i(){if(o){const s=o;o=null,s()}}se.set(t,s=>{r.push(s),i()}),mt.set(t,i);try{for(;;)r.length>0?yield r.shift():await new Promise(s=>{o=s})}finally{se.delete(t),mt.delete(t),Ve("unsubscribe",JSON.stringify({subId:t}),t)}}},()=>{window.removeEventListener("message",gt),delete window.nostrdb,V.clear(),se.clear()}}var xo="https://github.com/nostr-protocol/nips/pull/2303/files",kt="https://napplet.run",Uo="https://github.com/kehto/web",Io=3e3,Dt=!1,ht=!1,j;function Co(){Dt=!0,j!==void 0&&(clearTimeout(j),j=void 0)}function Ro(){if(!No()){if(Po()){wt();return}j=setTimeout(()=>{j=void 0,Dt||wt()},Io)}}function Po(){try{return window.self===window.top}catch{return!1}}function No(){try{if(window.__NAPPLET_ALLOW_STANDALONE__===!0||typeof document<"u"&&document.querySelector('meta[name="napplet-allow-standalone"]'))return!0}catch{}return!1}function wt(){console.error(`[napplet] No napplet runtime detected. This app is a sandboxed napplet and must run inside a napplet runtime (shell) that proxies Nostr access over postMessage per NIP-5D. Open it in a runtime — see ${kt}`),Ao(ko)}function Ao(e){typeof document>"u"||(document.readyState==="loading"?document.addEventListener("DOMContentLoaded",e,{once:!0}):e())}function ko(){if(ht||typeof document>"u"||!document.body)return;ht=!0;const e=document.createElement("div");e.setAttribute("data-napplet-runtime-error",""),e.style.cssText="position:fixed;inset:0;z-index:2147483647;";const t=e.attachShadow?e.attachShadow({mode:"open"}):e,n=document.createElement("style");n.textContent=Lo,t.appendChild(n),t.appendChild(Do()),document.body.appendChild(e)}function m(e,t={}){const n=document.createElement(e);if(t.className&&(n.className=t.className),t.text!==void 0&&(n.textContent=t.text),t.attrs)for(const[r,o]of Object.entries(t.attrs))n.setAttribute(r,o);return t.children&&n.append(...t.children),n}function Be(e,t,n){const r=m("span",{text:t,children:[m("small",{text:n})]}),o=m("span",{className:"arrow",text:"→",attrs:{"aria-hidden":"true"}});return m("a",{attrs:{href:e,target:"_blank",rel:"noopener noreferrer"},children:[r,o]})}function Do(){const e=m("span",{className:"badge",text:"Napplet · no runtime"}),t=m("h1",{text:"This napplet can’t run here",attrs:{id:"napplet-rg-title"}}),n=m("p");n.append("Napplets are sandboxed apps that run ",m("strong",{text:"inside a napplet runtime"}),". The runtime proxies all Nostr access — relays, signing, storage — over ",m("code",{text:"postMessage"}),", the wire format defined by NIP-5D. Opened on its own (for example directly from a NIP-5A nsite gateway), there’s no runtime to talk to, so nothing loads.");const r=m("p",{text:"To use this napplet, open it inside a napplet runtime:"}),o=m("div",{className:"links",children:[Be(kt,"napplet.run","Find a runtime to open napplets in"),Be(Uo,"kehto/web","The reference web runtime — open source"),Be(xo,"NIP-5D specification","How napplets and runtimes talk")]}),i=m("div",{className:"card",children:[e,t,n,r,o]});return m("div",{className:"overlay",attrs:{role:"dialog","aria-modal":"true","aria-labelledby":"napplet-rg-title"},children:[i]})}var Lo=`
  :host { all: initial; }
  * { box-sizing: border-box; }
  .overlay {
    position: fixed; inset: 0;
    display: flex; align-items: center; justify-content: center;
    padding: 24px;
    background: rgba(9, 9, 14, 0.82);
    -webkit-backdrop-filter: blur(6px);
    backdrop-filter: blur(6px);
    font-family: ui-sans-serif, system-ui, -apple-system, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;
  }
  .card {
    width: 100%; max-width: 480px;
    background: #14141b; color: #e9e9f1;
    border: 1px solid rgba(255, 255, 255, 0.08);
    border-radius: 16px;
    padding: 32px;
    box-shadow: 0 24px 60px rgba(0, 0, 0, 0.5);
    line-height: 1.55;
  }
  .badge {
    display: inline-block;
    font-size: 11px; letter-spacing: 0.14em; text-transform: uppercase;
    color: #8b8ba7; margin-bottom: 14px;
  }
  h1 { margin: 0 0 12px; font-size: 20px; font-weight: 650; letter-spacing: -0.01em; }
  p { margin: 0 0 14px; font-size: 14px; color: #c5c5d6; }
  code {
    font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
    font-size: 12px; padding: 1px 5px; border-radius: 5px;
    background: rgba(255, 255, 255, 0.07); color: #d8d8e6;
  }
  .links { display: flex; flex-direction: column; gap: 8px; margin-top: 20px; }
  a {
    display: flex; align-items: center; justify-content: space-between; gap: 12px;
    padding: 12px 14px; border-radius: 10px; text-decoration: none;
    background: rgba(255, 255, 255, 0.04);
    border: 1px solid rgba(255, 255, 255, 0.07);
    color: #e9e9f1; font-size: 13px; font-weight: 550;
    transition: background 0.15s ease, border-color 0.15s ease;
  }
  a:hover { background: rgba(124, 108, 255, 0.14); border-color: rgba(124, 108, 255, 0.45); }
  a small { display: block; margin-top: 2px; font-size: 11px; font-weight: 400; color: #8b8ba7; }
  a .arrow { color: #8b8ba7; flex: none; }
`,_=null,Lt=[],Ie=new Set;function $o(e){if(_)return;const t=wo(e);_=t;const n=window.napplet;if(n){const r=n.shell;r.supports=vo(t),r.services=t.services,r.class=t.class}for(const r of Lt.splice(0))r(t);for(const r of Ie)r(t);Ie.clear()}function Oo(){return _?Promise.resolve(_):new Promise(e=>{Lt.push(e)})}function qo(e){if(_)return e(_),{close(){}};Ie.add(e);let t=!1;return{close(){t||(t=!0,Ie.delete(e))}}}var _o=[["keys.",Xt],["media.",dn],["notify.",In],["resource.",Bn],["cvm.",Dr],["outbox.",Yr],["upload.",no],["intent.",uo],["identity.",Zn],["theme.",yr],["config.",Tr]];function Bo(e){if(e.source!==window.parent)return;const t=e.data;if(typeof t!="object"||t===null||typeof t.type!="string")return;Co();const n=t.type;if(n==="shell.init"){$o(t);return}if(n==="inc.event"){Mr(t);return}const r=t;for(const[o,i]of _o)if(n.startsWith(o)){i(r);return}}window.napplet={relay:{subscribe:jn,publish:Qn,publishEncrypted:Jn,query:Yn},inc:{emit:br,on:Er},storage:{getItem:M.getItem.bind(M),setItem:M.setItem.bind(M),removeItem:M.removeItem.bind(M),keys:M.keys.bind(M)},keys:{registerAction:en,unregisterAction:tn,onAction:nn},media:{createSession:un,updateSession:fn,destroySession:pn,reportState:yn,reportCapabilities:mn,sendCommand:gn,onCommand:hn,onState:wn,onCapabilities:vn,onControls:bn},notify:{send:Cn,dismiss:Rn,badge:Pn,registerChannel:Nn,requestPermission:An,onAction:kn,onClicked:Dn,onDismissed:Ln,onControls:$n},identity:{getPublicKey:tr,onChanged:nr,getRelays:rr,getProfile:or,getFollows:ir,getList:sr,getZaps:ar,getMutes:cr,getBlocked:lr,getBadges:dr},theme:{get:wr,onChanged:vr},config:{registerSchema:xt,get:Ut,subscribe:It,openSettings:Ct,onSchemaError:Rt,schema:null},resource:{bytes:St,bytesAsObjectURL:zn},cvm:{discover:Lr,request:Pt,listTools:$r,callTool:Or,listResources:qr,readResource:_r,close:Br,onEvent:Fr},outbox:{query:Gr,subscribe:Wr,publish:Vr,resolveRelays:Zr},upload:{upload:ro,status:oo,onStatus:io},intent:{invoke:At,open:fo,available:po,handlers:yo,onChanged:mo},shell:{supports:bo,services:[],class:null,ready:Oo,onReady:qo}};window.addEventListener("message",Bo);window.parent.postMessage({type:"shell.ready"},"*");Ro();To();rn();qn();Rr();function Fo(){const e=new Map;function t(o,i){if(e.has(o))throw new Error(`NAP domain "${o}" is already registered`);e.set(o,i)}function n(o){const i=o.type.indexOf(".");if(i<=0)return!1;const s=o.type.slice(0,i),a=e.get(s);return a?(a(o),!0):!1}function r(){return Array.from(e.keys())}return{registerNap:t,dispatch:n,getRegisteredDomains:r}}var Ho=Fo(),ot=Ho.registerNap,it="relay";ot(it,e=>{});var X="storage";ot(X,e=>{});var zo="theme";function $t(){var t;const e=window;if(!((t=e.napplet)!=null&&t.theme))throw new Error("window.napplet.theme not installed -- import @napplet/shim first");return e.napplet.theme}function Ko(){return $t().get()}function jo(e){return $t().onChanged(e)}ot(zo,e=>{});var Ot="config";function y(){const e=window;if(!e.napplet)throw new Error("window.napplet not installed -- import @napplet/shim first");return e.napplet}var Qo={subscribe(e,t,n,r){return y().relay.subscribe(e,t,n,r)},publish(e,t){return y().relay.publish(e,t)},publishEncrypted(e,t,n="nip44"){return y().relay.publishEncrypted(e,t,n)},query(e){return y().relay.query(e)}},Ne={getItem(e){return y().storage.getItem(e)},setItem(e,t){return y().storage.setItem(e,t)},removeItem(e){return y().storage.removeItem(e)},keys(){return y().storage.keys()}},Ze={get(){return y().config.get()},subscribe(e){return y().config.subscribe(e)},openSettings(e){y().config.openSettings(e)},registerSchema(e,t){return y().config.registerSchema(e,t)},onSchemaError(e){return y().config.onSchemaError(e)},get schema(){return y().config.schema}};const Jo=35129,Yo="0.2.0",qt="favorite-napplets",_t="last-search",l={statusPill:u("#statusPill"),statusText:u("#statusText"),versionTag:u("#versionTag"),searchInput:u("#searchInput"),resultCount:u("#resultCount"),refreshButton:u("#refreshButton"),settingsButton:u("#settingsButton"),statTotal:u("#statTotal"),statFavorites:u("#statFavorites"),summary:u("#summary"),grid:u("#grid"),emptyState:u("#emptyState"),emptyTitle:u("#emptyTitle"),emptyBody:u("#emptyBody"),output:u("#output"),detail:u("#detail"),detailTitle:u("#detailTitle"),detailName:u("#detailName"),detailMonogram:u("#detailMonogram"),detailBody:u("#detailBody"),detailClose:u("#detailClose"),favoriteButton:u("#favoriteButton"),copyIdButton:u("#copyIdButton")},g=new Map,st=[];let v=new Set,Ce="",x={resultLimit:200,liveUpdates:!0,showFileTree:!1},ae=0,ce=null,le=null,U=null;function u(e){const t=document.querySelector(e);if(!t)throw new Error(`Missing required element: ${e}`);return t}function E(e){var t;return!!((t=window.napplet)!=null&&t[e])}function h(e,t){l.statusPill.className=`pill pill-${e}`,l.statusText.textContent=t}function I(e){l.output.textContent=typeof e=="string"?e:JSON.stringify(e,null,2)}function at(e){return e?e.length<=16?e:`${e.slice(0,10)}…${e.slice(-6)}`:"unknown"}function re(e,t){for(const n of e.tags)if(n[0]===t&&n.length>1)return n[1]??null;return null}function Go(e,t){const n=[];for(const r of e.tags)r[0]===t&&r.length>1&&n.push(r[1]??"");return n}function Wo(e){const t=[];let n=null;for(const r of e.tags)r[0]==="path"&&r.length>=3?t.push({path:r[1]??"",sha256:r[2]??""}):r[0]==="x"&&r.length>1&&(n=r[1]??null);return{event:e,name:re(e,"d")??"(unnamed)",title:re(e,"title"),description:re(e,"description")??re(e,"summary"),paths:t,aggregateHash:n,requires:Go(e,"requires"),hasConfig:e.tags.some(r=>r[0]==="config")}}function Bt(e){let t=2166136261;for(let i=0;i<e.length;i++)t^=e.charCodeAt(i),t=Math.imul(t,16777619)>>>0;const n=t%360,r=`hsl(${n} 72% 62%)`,o=`linear-gradient(135deg, hsl(${n} 72% 58%), hsl(${(n+48)%360} 72% 52%))`;return{hue:n,color:r,gradient:o}}function Ft(e){return(e.replace(/[^a-z0-9]/gi,"")[0]??"◇").toUpperCase()}function Vo(e,t){return t?[e.name,e.title??"",e.description??"",e.event.pubkey,at(e.event.pubkey),...e.requires].join(" ").toLowerCase().includes(t.toLowerCase()):!0}function Zo(){l.statTotal.textContent=String(g.size),l.statFavorites.textContent=String(v.size)}function Ae(){const e=Ce.trim(),t=[];for(const n of st){const r=g.get(n);r&&Vo(r,e)&&t.push(r)}l.resultCount.textContent=String(t.length),l.emptyState.hidden=t.length>0,l.grid.replaceChildren(...t.map(Xo)),l.summary.textContent=t.length===g.size?`${g.size} napplet${g.size===1?"":"s"} discovered`:`${t.length} of ${g.size} shown`,Zo()}function Xo(e){const{color:t,gradient:n}=Bt(e.event.id),r=document.createElement("article");r.className="card",r.tabIndex=0,r.dataset.id=e.event.id,r.style.setProperty("--card-accent",t),r.style.setProperty("--card-gradient",n);const o=document.createElement("div");o.className="card-top";const i=document.createElement("div");i.className="monogram",i.textContent=Ft(e.name);const s=document.createElement("div");s.className="card-head";const a=document.createElement("h3");a.className="card-title",a.textContent=e.title??e.name;const c=document.createElement("p");c.className="card-name mono",c.textContent=e.name,s.append(a,c),o.append(i,s);const d=document.createElement("p");d.className="card-meta",d.textContent=`${at(e.event.pubkey)} · ${e.paths.length} file${e.paths.length===1?"":"s"}`;const f=document.createElement("div");if(f.className="pills",e.requires.length>0){for(const p of e.requires.slice(0,4)){const De=document.createElement("span");De.className="tag tag-accent",De.textContent=p,f.appendChild(De)}if(e.requires.length>4){const p=document.createElement("span");p.className="tag",p.textContent=`+${e.requires.length-4}`,f.appendChild(p)}}else{const p=document.createElement("span");p.className="tag",p.textContent="no requirements",f.appendChild(p)}const w=document.createElement("div");w.className="card-foot";const ke=document.createElement("time");ke.dateTime=new Date(e.event.created_at*1e3).toISOString(),ke.textContent=new Date(e.event.created_at*1e3).toLocaleDateString();const B=document.createElement("span");return B.className="star",B.textContent=v.has(e.event.id)?"★":"☆",B.dataset.fav=v.has(e.event.id)?"on":"off",B.title="Favorite",w.append(ke,B),r.append(o,d,f,w),r.addEventListener("click",p=>{p.target.classList.contains("star")?zt(e.event.id):vt(e.event.id)}),r.addEventListener("keydown",p=>{(p.key==="Enter"||p.key===" ")&&(p.preventDefault(),vt(e.event.id))}),r}function vt(e){const t=g.get(e);if(!t)return;U=e;const{color:n,gradient:r}=Bt(e);l.detailTitle.textContent=t.title??t.name,l.detailName.textContent=t.name,l.detailMonogram.style.setProperty("--card-accent",n),l.detailMonogram.style.setProperty("--card-gradient",r),l.detailMonogram.textContent=Ft(t.name),l.detailBody.replaceChildren();const o=[["Author",at(t.event.pubkey)],["Event id",t.event.id],["Kind",String(t.event.kind)],["Published",new Date(t.event.created_at*1e3).toISOString()],["Aggregate hash",t.aggregateHash??"—"],["Requires",t.requires.length?t.requires.join(", "):"none"],["Config schema",t.hasConfig?"present":"none"],["Files",String(t.paths.length)]];for(const[i,s]of o){const a=document.createElement("dt");a.textContent=i;const c=document.createElement("dd");c.textContent=s,l.detailBody.append(a,c)}if(x.showFileTree&&t.paths.length>0){const i=document.createElement("dt");i.textContent="File tree";const s=document.createElement("dd"),a=document.createElement("ul");a.className="file-tree";for(const c of t.paths){const d=document.createElement("li"),f=document.createElement("span");f.className="mono",f.textContent=c.path;const w=document.createElement("span");w.className="hash mono",w.textContent=c.sha256.slice(0,12),d.append(f,w),a.appendChild(d)}s.appendChild(a),l.detailBody.append(i,s)}Ht(),typeof l.detail.showModal=="function"?l.detail.open||l.detail.showModal():l.detail.open=!0}function Ht(){if(!U)return;const e=v.has(U);l.favoriteButton.textContent=e?"★ Favorited":"☆ Favorite",l.favoriteButton.setAttribute("aria-pressed",String(e))}function zt(e){v.has(e)?v.delete(e):v.add(e),Ae(),U===e&&Ht(),ti()}async function ei(){U&&zt(U)}async function ti(){if(E(X))try{await Ne.setItem(qt,JSON.stringify([...v]))}catch(e){I({warning:"favorite persist failed",error:e instanceof Error?e.message:e})}}async function ni(){if(E(X))try{const e=await Ne.getItem(qt);if(e){const t=JSON.parse(e);Array.isArray(t)&&(v=new Set(t.filter(n=>typeof n=="string")))}}catch{}}async function ri(){if(E(X))try{const e=await Ne.getItem(_t);typeof e=="string"&&(l.searchInput.value=e,Ce=e)}catch{}}async function oi(e){if(E(X))try{await Ne.setItem(_t,e)}catch{}}function ii(e){const n=e.event??e;return!n||typeof n!="object"||!Array.isArray(n.tags)?null:n}function si(e){g.has(e.id)||(g.set(e.id,Wo(e)),st.unshift(e.id))}async function Kt(){const e=x.resultLimit,t=[{kinds:[Jo],limit:e}];h("loading","Querying Nostr"),l.emptyState.hidden=!0,l.summary.textContent="Querying Nostr for napplet manifests…";try{const n=await Qo.query(t);let r=0;for(const i of n){const s=ii(i);s?si(s):r++}Ae();const o=g.size;o===0?(h("warn","None found"),Re("No napplets found","No kind 35129 manifests were returned by this shell. Hit Refresh to try again.")):h("ok",`${o} napplet${o===1?"":"s"}`),I(`Discovered ${o} napplet manifest${o===1?"":"s"}.${r?` (${r} non-event result${r===1?"":"s"} skipped.)`:""}`)}catch(n){h("error","Query failed"),Re("Query failed",n instanceof Error?n.message:String(n)),I(n instanceof Error?n.message:n)}}function Re(e,t){l.grid.replaceChildren(),l.emptyTitle.textContent=e,l.emptyBody.textContent=t,l.emptyState.hidden=!1}function jt(){window.clearInterval(ae),ae=0,x.liveUpdates&&(ae=window.setInterval(()=>{Kt()},6e4))}function ct(){if(!E(it)){h("error","Relay unavailable"),Re("NAP-RELAY required","This napplet needs NAP-RELAY to browse Nostr, but this shell does not expose it."),I("NAP-RELAY is required to browse napplet manifests, but this shell does not expose it.");return}g.clear(),st.length=0,Ae(),Kt().then(()=>jt())}function bt(e){const t=e.resultLimit,n=typeof t=="number"&&Number.isFinite(t)?t:200;x={resultLimit:Math.min(1e3,Math.max(10,n)),liveUpdates:typeof e.liveUpdates=="boolean"?e.liveUpdates:!0,showFileTree:typeof e.showFileTree=="boolean"?e.showFileTree:!1}}async function ai(){if(E(Ot))try{bt(await Ze.get()),ce=Ze.subscribe(e=>{const t=x.resultLimit,n=x.liveUpdates;bt(e),t!==x.resultLimit?ct():n!==x.liveUpdates&&jt()})}catch(e){I({warning:"config unavailable",error:e instanceof Error?e.message:e})}}const Fe={colors:{background:"#07070d",text:"#e8ecf6",primary:"#7c5cff"}};function Xe(e){const t=/^#?([0-9a-f]{6})$/i.exec(e.trim());if(!t)return null;const n=parseInt(t[1],16);return{r:n>>16&255,g:n>>8&255,b:n&255}}function lt(e){const t=Xe(e);return t?.2126*t.r+.7152*t.g+.0722*t.b>140:!1}function Z(e,t,n){const r=Xe(e),o=Xe(t);if(!r||!o)return e;const i=(a,c)=>Math.round(a+(c-a)*n),s=a=>a.toString(16).padStart(2,"0");return`#${s(i(r.r,o.r))}${s(i(r.g,o.g))}${s(i(r.b,o.b))}`}function ci(e){return lt(e)?Z(e,"#000000",.04):Z(e,"#ffffff",.06)}function li(e){return lt(e)?Z(e,"#000000",.12):Z(e,"#ffffff",.12)}function di(e,t){return Z(e,t,.42)}function K(e){const{background:t,text:n,primary:r}=e.colors,o=ci(t),i=li(t),s=di(n,t),a=document.documentElement,c=document.body,d=document.getElementById("app");a.style.setProperty("--nap-bg",t),a.style.setProperty("--nap-fg",n),a.style.setProperty("--nap-primary",r),a.style.setProperty("--nap-surface",o),a.style.setProperty("--nap-border",i),a.style.setProperty("--nap-muted",s),a.style.backgroundColor=t,c.style.backgroundColor=t,c.style.color=n,d&&(d.style.backgroundColor=t,d.style.color=n),a.dataset.theme=lt(t)?"light":"dark"}function ui(){if(E("theme")){Ko().then(K).catch(()=>K(Fe));try{le=jo(K)}catch{K(Fe)}}else K(Fe)}l.refreshButton.addEventListener("click",()=>ct());l.settingsButton.addEventListener("click",()=>{if(E(Ot))try{Ze.openSettings({section:"browse"}),h("ok","Settings opened")}catch(e){h("error","Settings failed"),I(e instanceof Error?e.message:e)}else h("warn","Settings unavailable"),I("NAP-CONFIG is not exposed by this shell.")});let Et=0;l.searchInput.addEventListener("input",()=>{Ce=l.searchInput.value,Ae(),window.clearTimeout(Et),Et=window.setTimeout(()=>void oi(Ce),400)});l.detailClose.addEventListener("click",()=>l.detail.close());l.detail.addEventListener("click",e=>{e.target===l.detail&&l.detail.close()});l.favoriteButton.addEventListener("click",()=>void ei());l.copyIdButton.addEventListener("click",()=>{const e=U?g.get(U):null;if(e)try{navigator.clipboard.writeText(e.event.id),h("ok","Copied event id")}catch{h("warn","Copy unavailable")}});window.addEventListener("beforeunload",()=>{window.clearInterval(ae),ce==null||ce.close(),le==null||le.close()});async function fi(){if(ui(),l.versionTag.textContent="v"+Yo,await Promise.all([ni(),ri(),ai()]),!E(it)){h("error","Relay unavailable"),Re("NAP-RELAY required","This napplet needs NAP-RELAY to browse Nostr, but this shell does not expose it."),I("NAP-RELAY is required to browse napplet manifests, but this shell does not expose it.");return}ct()}fi();</script>
    <style rel="stylesheet" crossorigin>:root{color-scheme:dark;font-family:Inter,ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,Segoe UI,sans-serif;--nap-bg: #07070d;--nap-fg: #e8ecf6;--nap-primary: #7c5cff;--nap-surface: rgba(255, 255, 255, .045);--nap-surface-2: rgba(255, 255, 255, .07);--nap-border: rgba(255, 255, 255, .1);--nap-border-strong: rgba(255, 255, 255, .18);--nap-muted: #9aa3b8;--radius: 16px;--radius-sm: 11px;--shadow: 0 18px 50px -20px rgba(0, 0, 0, .7);--napplet-text-selection: none}:root[data-theme=light]{--nap-bg: #f4f5fb;--nap-fg: #161a26;--nap-primary: #6244ea;--nap-surface: rgba(20, 22, 34, .04);--nap-surface-2: rgba(20, 22, 34, .07);--nap-border: rgba(20, 22, 34, .12);--nap-border-strong: rgba(20, 22, 34, .2);--nap-muted: #5b6478;--shadow: 0 18px 50px -24px rgba(40, 30, 90, .25)}*{box-sizing:border-box}:where(html,body,body *){-webkit-user-select:var(--napplet-text-selection, none);user-select:var(--napplet-text-selection, none)}:where(input,textarea,select,[contenteditable],[data-napplet-select=text]){-webkit-user-select:text;user-select:text}:where([data-napplet-select=all]){-webkit-user-select:all;user-select:all}body{margin:0;min-height:100vh;min-width:300px;background:var(--nap-bg);color:var(--nap-fg);-webkit-font-smoothing:antialiased;text-rendering:optimizeLegibility}#app{background:var(--nap-bg);color:var(--nap-fg)}h1,h2,h3,p{margin-top:0}.mono{font-family:SFMono-Regular,JetBrains Mono,Consolas,monospace}.muted{color:var(--nap-muted)}.aurora{position:fixed;top:0;right:0;bottom:0;left:0;overflow:hidden;pointer-events:none;z-index:0}.blob{position:absolute;border-radius:50%;filter:blur(90px);opacity:.55;animation:drift 22s ease-in-out infinite alternate}.blob-a{width:46vw;height:46vw;max-width:620px;max-height:620px;top:-12%;left:-8%;background:radial-gradient(circle at 30% 30%,color-mix(in srgb,var(--nap-primary) 75%,transparent),transparent 70%)}.blob-b{width:40vw;height:40vw;max-width:540px;max-height:540px;bottom:-14%;right:-10%;background:radial-gradient(circle at 60% 40%,color-mix(in srgb,#22d3ee 60%,transparent),transparent 70%);animation-delay:-7s}.blob-c{width:34vw;height:34vw;max-width:460px;max-height:460px;top:35%;left:55%;background:radial-gradient(circle at 50% 50%,color-mix(in srgb,#f472b6 45%,transparent),transparent 70%);animation-delay:-12s}:root[data-theme=light] .blob{opacity:.3}@keyframes drift{0%{transform:translate(0) scale(1)}to{transform:translate(4%,6%) scale(1.12)}}.shell{position:relative;z-index:1;width:min(1200px,100%);margin:0 auto;padding:clamp(.9rem,2.5vw,2rem);display:grid;gap:clamp(.8rem,2vw,1.4rem)}.topbar{display:flex;justify-content:space-between;align-items:center;gap:1rem;flex-wrap:wrap}.brand{display:flex;align-items:center;gap:.85rem}.brand-mark{display:grid;place-items:center;width:44px;height:44px;border-radius:13px;color:var(--nap-primary);background:color-mix(in srgb,var(--nap-primary) 16%,transparent);border:1px solid var(--nap-border-strong);box-shadow:0 0 26px -6px color-mix(in srgb,var(--nap-primary) 60%,transparent)}.brand-eyebrow{margin:0 0 .1rem;font-size:.68rem;font-weight:700;letter-spacing:.14em;text-transform:uppercase;color:var(--nap-primary)}.brand-title{margin:0;font-size:clamp(1.35rem,3.4vw,1.85rem);font-weight:700;letter-spacing:-.02em}.topbar-actions{display:flex;align-items:center;gap:.6rem}.version-tag{font-size:.7rem;font-weight:700;letter-spacing:.04em;color:var(--nap-muted);padding:.3rem .6rem;border-radius:999px;border:1px solid var(--nap-border);background:var(--nap-surface);-webkit-backdrop-filter:blur(8px);backdrop-filter:blur(8px);font-variant-numeric:tabular-nums}.pill{display:inline-flex;align-items:center;gap:.5rem;padding:.4rem .8rem;border-radius:999px;font-size:.78rem;font-weight:600;border:1px solid var(--nap-border);background:var(--nap-surface);-webkit-backdrop-filter:blur(8px);backdrop-filter:blur(8px)}.pill-dot{width:8px;height:8px;border-radius:50%;background:var(--nap-muted);box-shadow:0 0 0 0 currentColor}.pill-idle .pill-dot{background:var(--nap-muted)}.pill-ok{color:#4ade80}.pill-ok .pill-dot{background:#4ade80;box-shadow:0 0 10px #4ade80;animation:pulse 1.8s infinite}.pill-warn{color:#fbbf24}.pill-warn .pill-dot{background:#fbbf24}.pill-error{color:#f87171}.pill-error .pill-dot{background:#f87171;animation:pulse 1s infinite}.pill-loading .pill-dot{background:var(--nap-primary);animation:pulse 1s infinite}@keyframes pulse{0%{box-shadow:0 0 color-mix(in srgb,currentColor 70%,transparent)}70%{box-shadow:0 0 0 7px transparent}to{box-shadow:0 0 0 0 transparent}}.btn{display:inline-flex;align-items:center;gap:.5rem;min-height:2.6rem;padding:.5rem .95rem;border-radius:11px;border:1px solid var(--nap-border);background:var(--nap-surface);color:var(--nap-fg);font-weight:600;font-size:.86rem;cursor:pointer;transition:transform .12s ease,border-color .12s ease,background .12s ease}.btn:hover{border-color:var(--nap-border-strong);background:var(--nap-surface-2);transform:translateY(-1px)}.btn:active{transform:translateY(0)}.btn:focus-visible{outline:3px solid color-mix(in srgb,var(--nap-primary) 45%,transparent);outline-offset:2px}.btn-primary{background:linear-gradient(135deg,var(--nap-primary),color-mix(in srgb,var(--nap-primary) 55%,#22d3ee));border-color:transparent;color:#fff;box-shadow:0 10px 26px -12px color-mix(in srgb,var(--nap-primary) 70%,transparent)}.btn-primary:hover{background:linear-gradient(135deg,color-mix(in srgb,var(--nap-primary) 85%,#fff 15%),color-mix(in srgb,var(--nap-primary) 45%,#22d3ee))}.btn-ghost{background:var(--nap-surface)}.icon-btn{min-height:2.2rem;padding:.4rem .6rem}.controls{display:flex;gap:.7rem;flex-wrap:wrap;align-items:center}.search{position:relative;display:flex;align-items:center;flex:1 1 260px;min-width:0;border:1px solid var(--nap-border);background:var(--nap-surface);border-radius:13px;padding:0 .85rem;transition:border-color .15s ease,box-shadow .15s ease}.search:focus-within{border-color:color-mix(in srgb,var(--nap-primary) 60%,transparent);box-shadow:0 0 0 4px color-mix(in srgb,var(--nap-primary) 18%,transparent)}.search-icon{color:var(--nap-muted);flex-shrink:0}.search input{flex:1;min-width:0;border:none;background:transparent;color:var(--nap-fg);padding:.85rem .6rem;font-size:.92rem;outline:none}.search input::placeholder{color:var(--nap-muted)}.search-kbd{font-family:monospace;font-size:.72rem;color:var(--nap-muted);background:var(--nap-surface-2);border:1px solid var(--nap-border);border-radius:7px;padding:.15rem .45rem;flex-shrink:0}.stats{display:flex;align-items:center;gap:1.4rem;flex-wrap:wrap;padding:0 .2rem}.stat{display:flex;flex-direction:column;line-height:1.1}.stat-num{font-size:1.5rem;font-weight:700;letter-spacing:-.02em}.stat-label{font-size:.68rem;text-transform:uppercase;letter-spacing:.12em;color:var(--nap-muted)}.stat-summary{margin:0 0 0 auto;color:var(--nap-muted);font-size:.85rem}.grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(min(100%,256px),1fr));gap:.9rem}.card{position:relative;display:grid;gap:.75rem;padding:1rem;border-radius:var(--radius);border:1px solid var(--nap-border);background:var(--nap-surface);-webkit-backdrop-filter:blur(10px);backdrop-filter:blur(10px);cursor:pointer;overflow:hidden;transition:transform .16s ease,border-color .16s ease,background .16s ease}.card:before{content:"";position:absolute;top:0;right:0;bottom:0;left:0;border-radius:inherit;padding:1px;background:linear-gradient(140deg,color-mix(in srgb,var(--card-accent) 55%,transparent),transparent 55%);-webkit-mask:linear-gradient(#000 0 0) content-box,linear-gradient(#000 0 0);-webkit-mask-composite:xor;mask-composite:exclude;opacity:0;transition:opacity .18s ease;pointer-events:none}.card:hover,.card:focus-visible{transform:translateY(-3px);background:var(--nap-surface-2);border-color:transparent;outline:none}.card:hover:before,.card:focus-visible:before{opacity:1}.card-top{display:flex;align-items:flex-start;gap:.75rem}.monogram{flex-shrink:0;width:42px;height:42px;border-radius:11px;display:grid;place-items:center;color:#fff;font-weight:700;font-size:1.05rem;background:var(--card-gradient);box-shadow:0 6px 18px -8px var(--card-accent)}.card-head{min-width:0;flex:1}.card-title{margin:0;font-size:1rem;font-weight:650;letter-spacing:-.01em;overflow-wrap:anywhere}.card-name{margin:.15rem 0 0;font-size:.78rem;color:var(--card-accent)}.card-meta{margin:.45rem 0 0;font-size:.74rem;color:var(--nap-muted);display:flex;gap:.4rem;flex-wrap:wrap}.pills{display:flex;gap:.35rem;flex-wrap:wrap}.tag{font-size:.66rem;font-weight:600;letter-spacing:.02em;padding:.18rem .5rem;border-radius:999px;background:var(--nap-surface-2);border:1px solid var(--nap-border);color:var(--nap-muted)}.tag.tag-accent{color:var(--card-accent);border-color:color-mix(in srgb,var(--card-accent) 35%,transparent)}.card-foot{display:flex;justify-content:space-between;align-items:center;margin-top:.1rem}.card-foot time{font-size:.72rem;color:var(--nap-muted)}.star{font-size:1.05rem;color:#fbbf24;cursor:pointer;line-height:1}.star[data-fav=off]{color:var(--nap-muted);opacity:.5}.empty{display:grid;place-items:center;text-align:center;gap:.6rem;padding:clamp(2rem,6vw,3.5rem) 1rem;border-radius:var(--radius);border:1px dashed var(--nap-border);background:var(--nap-surface)}.empty-art{color:var(--nap-muted)}.empty h3{margin:0;font-size:1.05rem}.empty p{margin:0;color:var(--nap-muted);max-width:42ch;font-size:.88rem}.log{border-radius:var(--radius-sm);border:1px solid var(--nap-border);background:var(--nap-surface);padding:.7rem .9rem}.log summary{cursor:pointer;font-size:.78rem;font-weight:600;color:var(--nap-muted);letter-spacing:.04em}.log-output{margin:.6rem 0 0;max-height:14rem;overflow:auto;font-size:.78rem;line-height:1.5;white-space:pre-wrap;color:var(--nap-muted)}.modal{width:min(640px,94vw);max-height:88vh;overflow:auto;border:1px solid var(--nap-border-strong);border-radius:var(--radius);background:color-mix(in srgb,var(--nap-bg) 86%,var(--nap-primary) 6%);color:var(--nap-fg);box-shadow:var(--shadow);padding:0;-webkit-backdrop-filter:blur(20px);backdrop-filter:blur(20px)}.modal::backdrop{background:color-mix(in srgb,#000 55%,transparent);-webkit-backdrop-filter:blur(4px);backdrop-filter:blur(4px)}.modal-card{display:grid;gap:1rem;padding:clamp(1rem,2.5vw,1.5rem)}.modal-head{display:flex;align-items:flex-start;gap:.85rem}.modal-monogram{width:52px;height:52px;border-radius:14px;flex-shrink:0;display:grid;place-items:center;color:#fff;font-weight:700;font-size:1.3rem;background:var(--card-gradient);box-shadow:0 8px 22px -8px var(--card-accent)}.modal-titles{flex:1;min-width:0}.modal-title{margin:0;font-size:1.3rem;font-weight:700;letter-spacing:-.02em;overflow-wrap:anywhere}.modal-subname{margin:.2rem 0 0;font-size:.84rem;color:var(--nap-primary)}.modal-body{display:grid;grid-template-columns:max-content 1fr;gap:.5rem 1.1rem;margin:0}.modal-body dt{color:var(--nap-muted);font-size:.74rem;align-self:start;padding-top:.15rem;white-space:nowrap}.modal-body dd{margin:0;font-size:.86rem;overflow-wrap:anywhere}.file-tree{list-style:none;margin:.5rem 0 0;padding:0;display:grid;gap:.2rem;grid-column:1 / -1;max-height:12rem;overflow:auto}.file-tree li{display:flex;justify-content:space-between;gap:.6rem;font-size:.78rem;padding:.25rem 0;border-bottom:1px solid var(--nap-border)}.file-tree .hash{font-size:.72rem;color:var(--nap-muted);flex-shrink:0}.modal-foot{display:flex;gap:.6rem;flex-wrap:wrap}@media(max-width:560px){.stats{gap:1rem}.stat-summary{margin:0;width:100%}.modal-body{grid-template-columns:1fr}.modal-body dt{margin-top:.4rem}}</style>
    <meta name="napplet-type" content="napplify">
    <meta name="napplet-requires" content="relay">
    <meta name="napplet-config-schema" content="{&quot;type&quot;:&quot;object&quot;,&quot;properties&quot;:{&quot;resultLimit&quot;:{&quot;type&quot;:&quot;integer&quot;,&quot;minimum&quot;:10,&quot;maximum&quot;:1000,&quot;default&quot;:200,&quot;description&quot;:&quot;Maximum napplet manifests to fetch per refresh.&quot;,&quot;x-napplet-section&quot;:&quot;browse&quot;,&quot;x-napplet-order&quot;:1},&quot;liveUpdates&quot;:{&quot;type&quot;:&quot;boolean&quot;,&quot;default&quot;:true,&quot;description&quot;:&quot;Re-query periodically for newly published napplets.&quot;,&quot;x-napplet-section&quot;:&quot;browse&quot;,&quot;x-napplet-order&quot;:2},&quot;showFileTree&quot;:{&quot;type&quot;:&quot;boolean&quot;,&quot;default&quot;:false,&quot;description&quot;:&quot;Show the manifest path/file tree in the detail view.&quot;,&quot;x-napplet-section&quot;:&quot;browse&quot;,&quot;x-napplet-order&quot;:3}},&quot;required&quot;:[&quot;resultLimit&quot;]}">
  </head>
  <body>
    <div id="app" class="app">
      <div class="aurora" aria-hidden="true">
        <span class="blob blob-a"></span>
        <span class="blob blob-b"></span>
        <span class="blob blob-c"></span>
      </div>

      <main class="shell">
        <header class="topbar">
          <div class="brand">
            <span class="brand-mark" aria-hidden="true">
              <svg viewBox="0 0 32 32" width="26" height="26" fill="none">
                <rect x="3" y="3" width="26" height="26" rx="8" stroke="currentColor" stroke-width="2" opacity="0.35"/>
                <circle cx="16" cy="16" r="5" fill="currentColor"/>
                <circle cx="16" cy="16" r="9" stroke="currentColor" stroke-width="1.5" opacity="0.55"/>
              </svg>
            </span>
            <div class="brand-text">
              <p class="brand-eyebrow">Browse Napplets on Nostr</p>
              <h1 class="brand-title">Napplet Explorer</h1>
            </div>
          </div>
          <div class="topbar-actions">
            <span id="versionTag" class="version-tag" title="Napplet version">v0.2.0</span>
            <span id="statusPill" class="pill pill-idle" title="Query status">
              <span class="pill-dot"></span><span id="statusText" class="pill-text">Ready</span>
            </span>
            <button id="settingsButton" type="button" class="btn btn-ghost" title="Settings">
              <svg viewBox="0 0 24 24" width="18" height="18" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="3"/><path d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 1 1-2.83 2.83l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-4 0v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 1 1-2.83-2.83l.06-.06a1.65 1.65 0 0 0 .33-1.82 1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1 0-4h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 1 1 2.83-2.83l.06.06a1.65 1.65 0 0 0 1.82.33H9a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 4 0v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 1 1 2.83 2.83l-.06.06a1.65 1.65 0 0 0-.33 1.82V9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 0 4h-.09a1.65 1.65 0 0 0-1.51 1z"/></svg>
            </button>
          </div>
        </header>

        <section class="controls">
          <label class="search">
            <svg class="search-icon" viewBox="0 0 24 24" width="18" height="18" fill="none" stroke="currentColor" stroke-width="2"><circle cx="11" cy="11" r="7"/><path d="m21 21-4.3-4.3"/></svg>
            <input
              id="searchInput"
              type="search"
              placeholder="Search napplets by name, author, or capability…"
              autocomplete="off"
              data-napplet-select="text"
            />
            <kbd class="search-kbd" id="resultCount">0</kbd>
          </label>
          <button id="refreshButton" type="button" class="btn btn-primary">
            <svg viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor" stroke-width="2"><path d="M21 12a9 9 0 1 1-2.64-6.36"/><path d="M21 3v6h-6"/></svg>
            <span>Refresh</span>
          </button>
        </section>

        <section class="stats" aria-live="polite">
          <div class="stat">
            <span class="stat-num" id="statTotal">0</span>
            <span class="stat-label">discovered</span>
          </div>
          <div class="stat">
            <span class="stat-num" id="statFavorites">0</span>
            <span class="stat-label">favorites</span>
          </div>
          <p id="summary" class="stat-summary">Loading napplet manifests…</p>
        </section>

        <section id="grid" class="grid" aria-label="Napplet manifests"></section>

        <div id="emptyState" class="empty" hidden>
          <div class="empty-art" aria-hidden="true">
            <svg viewBox="0 0 48 48" width="44" height="44" fill="none" stroke="currentColor" stroke-width="1.5" opacity="0.6"><rect x="6" y="10" width="36" height="28" rx="4"/><path d="M6 18h36M14 26h12M14 32h8"/></svg>
          </div>
          <h3 id="emptyTitle">No napplets yet</h3>
          <p id="emptyBody">No napplet manifests were returned by this shell. Hit Refresh to try again.</p>
        </div>

        <details class="log" id="logWrap">
          <summary>Log</summary>
          <pre id="output" class="log-output" data-napplet-select="text">Napplet ready.</pre>
        </details>
      </main>

      <dialog id="detail" class="modal" aria-labelledby="detailTitle">
        <article class="modal-card">
          <header class="modal-head">
            <div class="modal-monogram" id="detailMonogram" aria-hidden="true"></div>
            <div class="modal-titles">
              <h2 id="detailTitle" class="modal-title">Napplet</h2>
              <p id="detailName" class="modal-subname mono"></p>
            </div>
            <button id="detailClose" type="button" class="btn btn-ghost icon-btn" aria-label="Close">✕</button>
          </header>
          <dl id="detailBody" class="modal-body" data-napplet-select="text"></dl>
          <footer class="modal-foot">
            <button id="favoriteButton" type="button" class="btn btn-ghost">☆ Favorite</button>
            <button id="copyIdButton" type="button" class="btn btn-ghost">Copy event id</button>
          </footer>
        </article>
      </dialog>
    </div>
  </body>
</html>