diff --git a/package-lock.json b/package-lock.json
index e524dda..5aeef10 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -10,21 +10,21 @@
"dependencies": {
"htmx-ext-json-enc": "^2.0.3",
"htmx.org": "^2.0.8",
- "lucide": "^0.577.0"
+ "lucide": "^1.8.0"
},
"devDependencies": {
- "@tailwindcss/cli": "^4.2.1",
+ "@tailwindcss/cli": "^4.2.2",
"@tailwindcss/typography": "^0.5.19",
"daisyui": "^5.5.19",
- "esbuild": "^0.27.4",
+ "esbuild": "^0.28.0",
"glob": "^13.0.6",
- "tailwindcss": "^4.2"
+ "tailwindcss": "^4.2.2"
}
},
"node_modules/@esbuild/aix-ppc64": {
- "version": "0.27.4",
- "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.4.tgz",
- "integrity": "sha512-cQPwL2mp2nSmHHJlCyoXgHGhbEPMrEEU5xhkcy3Hs/O7nGZqEpZ2sUtLaL9MORLtDfRvVl2/3PAuEkYZH0Ty8Q==",
+ "version": "0.28.0",
+ "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.28.0.tgz",
+ "integrity": "sha512-lhRUCeuOyJQURhTxl4WkpFTjIsbDayJHih5kZC1giwE+MhIzAb7mEsQMqMf18rHLsrb5qI1tafG20mLxEWcWlA==",
"cpu": [
"ppc64"
],
@@ -39,9 +39,9 @@
}
},
"node_modules/@esbuild/android-arm": {
- "version": "0.27.4",
- "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.27.4.tgz",
- "integrity": "sha512-X9bUgvxiC8CHAGKYufLIHGXPJWnr0OCdR0anD2e21vdvgCI8lIfqFbnoeOz7lBjdrAGUhqLZLcQo6MLhTO2DKQ==",
+ "version": "0.28.0",
+ "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.28.0.tgz",
+ "integrity": "sha512-wqh0ByljabXLKHeWXYLqoJ5jKC4XBaw6Hk08OfMrCRd2nP2ZQ5eleDZC41XHyCNgktBGYMbqnrJKq/K/lzPMSQ==",
"cpu": [
"arm"
],
@@ -56,9 +56,9 @@
}
},
"node_modules/@esbuild/android-arm64": {
- "version": "0.27.4",
- "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.27.4.tgz",
- "integrity": "sha512-gdLscB7v75wRfu7QSm/zg6Rx29VLdy9eTr2t44sfTW7CxwAtQghZ4ZnqHk3/ogz7xao0QAgrkradbBzcqFPasw==",
+ "version": "0.28.0",
+ "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.28.0.tgz",
+ "integrity": "sha512-+WzIXQOSaGs33tLEgYPYe/yQHf0WTU0X42Jca3y8NWMbUVhp7rUnw+vAsRC/QiDrdD31IszMrZy+qwPOPjd+rw==",
"cpu": [
"arm64"
],
@@ -73,9 +73,9 @@
}
},
"node_modules/@esbuild/android-x64": {
- "version": "0.27.4",
- "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.27.4.tgz",
- "integrity": "sha512-PzPFnBNVF292sfpfhiyiXCGSn9HZg5BcAz+ivBuSsl6Rk4ga1oEXAamhOXRFyMcjwr2DVtm40G65N3GLeH1Lvw==",
+ "version": "0.28.0",
+ "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.28.0.tgz",
+ "integrity": "sha512-+VJggoaKhk2VNNqVL7f6S189UzShHC/mR9EE8rDdSkdpN0KflSwWY/gWjDrNxxisg8Fp1ZCD9jLMo4m0OUfeUA==",
"cpu": [
"x64"
],
@@ -90,9 +90,9 @@
}
},
"node_modules/@esbuild/darwin-arm64": {
- "version": "0.27.4",
- "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.27.4.tgz",
- "integrity": "sha512-b7xaGIwdJlht8ZFCvMkpDN6uiSmnxxK56N2GDTMYPr2/gzvfdQN8rTfBsvVKmIVY/X7EM+/hJKEIbbHs9oA4tQ==",
+ "version": "0.28.0",
+ "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.28.0.tgz",
+ "integrity": "sha512-0T+A9WZm+bZ84nZBtk1ckYsOvyA3x7e2Acj1KdVfV4/2tdG4fzUp91YHx+GArWLtwqp77pBXVCPn2We7Letr0Q==",
"cpu": [
"arm64"
],
@@ -107,9 +107,9 @@
}
},
"node_modules/@esbuild/darwin-x64": {
- "version": "0.27.4",
- "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.27.4.tgz",
- "integrity": "sha512-sR+OiKLwd15nmCdqpXMnuJ9W2kpy0KigzqScqHI3Hqwr7IXxBp3Yva+yJwoqh7rE8V77tdoheRYataNKL4QrPw==",
+ "version": "0.28.0",
+ "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.28.0.tgz",
+ "integrity": "sha512-fyzLm/DLDl/84OCfp2f/XQ4flmORsjU7VKt8HLjvIXChJoFFOIL6pLJPH4Yhd1n1gGFF9mPwtlN5Wf82DZs+LQ==",
"cpu": [
"x64"
],
@@ -124,9 +124,9 @@
}
},
"node_modules/@esbuild/freebsd-arm64": {
- "version": "0.27.4",
- "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.4.tgz",
- "integrity": "sha512-jnfpKe+p79tCnm4GVav68A7tUFeKQwQyLgESwEAUzyxk/TJr4QdGog9sqWNcUbr/bZt/O/HXouspuQDd9JxFSw==",
+ "version": "0.28.0",
+ "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.28.0.tgz",
+ "integrity": "sha512-l9GeW5UZBT9k9brBYI+0WDffcRxgHQD8ShN2Ur4xWq/NFzUKm3k5lsH4PdaRgb2w7mI9u61nr2gI2mLI27Nh3Q==",
"cpu": [
"arm64"
],
@@ -141,9 +141,9 @@
}
},
"node_modules/@esbuild/freebsd-x64": {
- "version": "0.27.4",
- "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.27.4.tgz",
- "integrity": "sha512-2kb4ceA/CpfUrIcTUl1wrP/9ad9Atrp5J94Lq69w7UwOMolPIGrfLSvAKJp0RTvkPPyn6CIWrNy13kyLikZRZQ==",
+ "version": "0.28.0",
+ "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.28.0.tgz",
+ "integrity": "sha512-BXoQai/A0wPO6Es3yFJ7APCiKGc1tdAEOgeTNy3SsB491S3aHn4S4r3e976eUnPdU+NbdtmBuLncYir2tMU9Nw==",
"cpu": [
"x64"
],
@@ -158,9 +158,9 @@
}
},
"node_modules/@esbuild/linux-arm": {
- "version": "0.27.4",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.27.4.tgz",
- "integrity": "sha512-aBYgcIxX/wd5n2ys0yESGeYMGF+pv6g0DhZr3G1ZG4jMfruU9Tl1i2Z+Wnj9/KjGz1lTLCcorqE2viePZqj4Eg==",
+ "version": "0.28.0",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.28.0.tgz",
+ "integrity": "sha512-CjaaREJagqJp7iTaNQjjidaNbCKYcd4IDkzbwwxtSvjI7NZm79qiHc8HqciMddQ6CKvJT6aBd8lO9kN/ZudLlw==",
"cpu": [
"arm"
],
@@ -175,9 +175,9 @@
}
},
"node_modules/@esbuild/linux-arm64": {
- "version": "0.27.4",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.27.4.tgz",
- "integrity": "sha512-7nQOttdzVGth1iz57kxg9uCz57dxQLHWxopL6mYuYthohPKEK0vU0C3O21CcBK6KDlkYVcnDXY099HcCDXd9dA==",
+ "version": "0.28.0",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.28.0.tgz",
+ "integrity": "sha512-RVyzfb3FWsGA55n6WY0MEIEPURL1FcbhFE6BffZEMEekfCzCIMtB5yyDcFnVbTnwk+CLAgTujmV/Lgvih56W+A==",
"cpu": [
"arm64"
],
@@ -192,9 +192,9 @@
}
},
"node_modules/@esbuild/linux-ia32": {
- "version": "0.27.4",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.27.4.tgz",
- "integrity": "sha512-oPtixtAIzgvzYcKBQM/qZ3R+9TEUd1aNJQu0HhGyqtx6oS7qTpvjheIWBbes4+qu1bNlo2V4cbkISr8q6gRBFA==",
+ "version": "0.28.0",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.28.0.tgz",
+ "integrity": "sha512-KBnSTt1kxl9x70q+ydterVdl+Cn0H18ngRMRCEQfrbqdUuntQQ0LoMZv47uB97NljZFzY6HcfqEZ2SAyIUTQBQ==",
"cpu": [
"ia32"
],
@@ -209,9 +209,9 @@
}
},
"node_modules/@esbuild/linux-loong64": {
- "version": "0.27.4",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.27.4.tgz",
- "integrity": "sha512-8mL/vh8qeCoRcFH2nM8wm5uJP+ZcVYGGayMavi8GmRJjuI3g1v6Z7Ni0JJKAJW+m0EtUuARb6Lmp4hMjzCBWzA==",
+ "version": "0.28.0",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.28.0.tgz",
+ "integrity": "sha512-zpSlUce1mnxzgBADvxKXX5sl8aYQHo2ezvMNI8I0lbblJtp8V4odlm3Yzlj7gPyt3T8ReksE6bK+pT3WD+aJRg==",
"cpu": [
"loong64"
],
@@ -226,9 +226,9 @@
}
},
"node_modules/@esbuild/linux-mips64el": {
- "version": "0.27.4",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.27.4.tgz",
- "integrity": "sha512-1RdrWFFiiLIW7LQq9Q2NES+HiD4NyT8Itj9AUeCl0IVCA459WnPhREKgwrpaIfTOe+/2rdntisegiPWn/r/aAw==",
+ "version": "0.28.0",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.28.0.tgz",
+ "integrity": "sha512-2jIfP6mmjkdmeTlsX/9vmdmhBmKADrWqN7zcdtHIeNSCH1SqIoNI63cYsjQR8J+wGa4Y5izRcSHSm8K3QWmk3w==",
"cpu": [
"mips64el"
],
@@ -243,9 +243,9 @@
}
},
"node_modules/@esbuild/linux-ppc64": {
- "version": "0.27.4",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.27.4.tgz",
- "integrity": "sha512-tLCwNG47l3sd9lpfyx9LAGEGItCUeRCWeAx6x2Jmbav65nAwoPXfewtAdtbtit/pJFLUWOhpv0FpS6GQAmPrHA==",
+ "version": "0.28.0",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.28.0.tgz",
+ "integrity": "sha512-bc0FE9wWeC0WBm49IQMPSPILRocGTQt3j5KPCA8os6VprfuJ7KD+5PzESSrJ6GmPIPJK965ZJHTUlSA6GNYEhg==",
"cpu": [
"ppc64"
],
@@ -260,9 +260,9 @@
}
},
"node_modules/@esbuild/linux-riscv64": {
- "version": "0.27.4",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.27.4.tgz",
- "integrity": "sha512-BnASypppbUWyqjd1KIpU4AUBiIhVr6YlHx/cnPgqEkNoVOhHg+YiSVxM1RLfiy4t9cAulbRGTNCKOcqHrEQLIw==",
+ "version": "0.28.0",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.28.0.tgz",
+ "integrity": "sha512-SQPZOwoTTT/HXFXQJG/vBX8sOFagGqvZyXcgLA3NhIqcBv1BJU1d46c0rGcrij2B56Z2rNiSLaZOYW5cUk7yLQ==",
"cpu": [
"riscv64"
],
@@ -277,9 +277,9 @@
}
},
"node_modules/@esbuild/linux-s390x": {
- "version": "0.27.4",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.27.4.tgz",
- "integrity": "sha512-+eUqgb/Z7vxVLezG8bVB9SfBie89gMueS+I0xYh2tJdw3vqA/0ImZJ2ROeWwVJN59ihBeZ7Tu92dF/5dy5FttA==",
+ "version": "0.28.0",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.28.0.tgz",
+ "integrity": "sha512-SCfR0HN8CEEjnYnySJTd2cw0k9OHB/YFzt5zgJEwa+wL/T/raGWYMBqwDNAC6dqFKmJYZoQBRfHjgwLHGSrn3Q==",
"cpu": [
"s390x"
],
@@ -294,9 +294,9 @@
}
},
"node_modules/@esbuild/linux-x64": {
- "version": "0.27.4",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.27.4.tgz",
- "integrity": "sha512-S5qOXrKV8BQEzJPVxAwnryi2+Iq5pB40gTEIT69BQONqR7JH1EPIcQ/Uiv9mCnn05jff9umq/5nqzxlqTOg9NA==",
+ "version": "0.28.0",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.28.0.tgz",
+ "integrity": "sha512-us0dSb9iFxIi8srnpl931Nvs65it/Jd2a2K3qs7fz2WfGPHqzfzZTfec7oxZJRNPXPnNYZtanmRc4AL/JwVzHQ==",
"cpu": [
"x64"
],
@@ -311,9 +311,9 @@
}
},
"node_modules/@esbuild/netbsd-arm64": {
- "version": "0.27.4",
- "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.4.tgz",
- "integrity": "sha512-xHT8X4sb0GS8qTqiwzHqpY00C95DPAq7nAwX35Ie/s+LO9830hrMd3oX0ZMKLvy7vsonee73x0lmcdOVXFzd6Q==",
+ "version": "0.28.0",
+ "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.28.0.tgz",
+ "integrity": "sha512-CR/RYotgtCKwtftMwJlUU7xCVNg3lMYZ0RzTmAHSfLCXw3NtZtNpswLEj/Kkf6kEL3Gw+BpOekRX0BYCtklhUw==",
"cpu": [
"arm64"
],
@@ -328,9 +328,9 @@
}
},
"node_modules/@esbuild/netbsd-x64": {
- "version": "0.27.4",
- "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.27.4.tgz",
- "integrity": "sha512-RugOvOdXfdyi5Tyv40kgQnI0byv66BFgAqjdgtAKqHoZTbTF2QqfQrFwa7cHEORJf6X2ht+l9ABLMP0dnKYsgg==",
+ "version": "0.28.0",
+ "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.28.0.tgz",
+ "integrity": "sha512-nU1yhmYutL+fQ71Kxnhg8uEOdC0pwEW9entHykTgEbna2pw2dkbFSMeqjjyHZoCmt8SBkOSvV+yNmm94aUrrqw==",
"cpu": [
"x64"
],
@@ -345,9 +345,9 @@
}
},
"node_modules/@esbuild/openbsd-arm64": {
- "version": "0.27.4",
- "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.4.tgz",
- "integrity": "sha512-2MyL3IAaTX+1/qP0O1SwskwcwCoOI4kV2IBX1xYnDDqthmq5ArrW94qSIKCAuRraMgPOmG0RDTA74mzYNQA9ow==",
+ "version": "0.28.0",
+ "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.28.0.tgz",
+ "integrity": "sha512-cXb5vApOsRsxsEl4mcZ1XY3D4DzcoMxR/nnc4IyqYs0rTI8ZKmW6kyyg+11Z8yvgMfAEldKzP7AdP64HnSC/6g==",
"cpu": [
"arm64"
],
@@ -362,9 +362,9 @@
}
},
"node_modules/@esbuild/openbsd-x64": {
- "version": "0.27.4",
- "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.27.4.tgz",
- "integrity": "sha512-u8fg/jQ5aQDfsnIV6+KwLOf1CmJnfu1ShpwqdwC0uA7ZPwFws55Ngc12vBdeUdnuWoQYx/SOQLGDcdlfXhYmXQ==",
+ "version": "0.28.0",
+ "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.28.0.tgz",
+ "integrity": "sha512-8wZM2qqtv9UP3mzy7HiGYNH/zjTA355mpeuA+859TyR+e+Tc08IHYpLJuMsfpDJwoLo1ikIJI8jC3GFjnRClzA==",
"cpu": [
"x64"
],
@@ -379,9 +379,9 @@
}
},
"node_modules/@esbuild/openharmony-arm64": {
- "version": "0.27.4",
- "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.4.tgz",
- "integrity": "sha512-JkTZrl6VbyO8lDQO3yv26nNr2RM2yZzNrNHEsj9bm6dOwwu9OYN28CjzZkH57bh4w0I2F7IodpQvUAEd1mbWXg==",
+ "version": "0.28.0",
+ "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.28.0.tgz",
+ "integrity": "sha512-FLGfyizszcef5C3YtoyQDACyg95+dndv79i2EekILBofh5wpCa1KuBqOWKrEHZg3zrL3t5ouE5jgr94vA+Wb2w==",
"cpu": [
"arm64"
],
@@ -396,9 +396,9 @@
}
},
"node_modules/@esbuild/sunos-x64": {
- "version": "0.27.4",
- "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.27.4.tgz",
- "integrity": "sha512-/gOzgaewZJfeJTlsWhvUEmUG4tWEY2Spp5M20INYRg2ZKl9QPO3QEEgPeRtLjEWSW8FilRNacPOg8R1uaYkA6g==",
+ "version": "0.28.0",
+ "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.28.0.tgz",
+ "integrity": "sha512-1ZgjUoEdHZZl/YlV76TSCz9Hqj9h9YmMGAgAPYd+q4SicWNX3G5GCyx9uhQWSLcbvPW8Ni7lj4gDa1T40akdlw==",
"cpu": [
"x64"
],
@@ -413,9 +413,9 @@
}
},
"node_modules/@esbuild/win32-arm64": {
- "version": "0.27.4",
- "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.27.4.tgz",
- "integrity": "sha512-Z9SExBg2y32smoDQdf1HRwHRt6vAHLXcxD2uGgO/v2jK7Y718Ix4ndsbNMU/+1Qiem9OiOdaqitioZwxivhXYg==",
+ "version": "0.28.0",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.28.0.tgz",
+ "integrity": "sha512-Q9StnDmQ/enxnpxCCLSg0oo4+34B9TdXpuyPeTedN/6+iXBJ4J+zwfQI28u/Jl40nOYAxGoNi7mFP40RUtkmUA==",
"cpu": [
"arm64"
],
@@ -430,9 +430,9 @@
}
},
"node_modules/@esbuild/win32-ia32": {
- "version": "0.27.4",
- "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.27.4.tgz",
- "integrity": "sha512-DAyGLS0Jz5G5iixEbMHi5KdiApqHBWMGzTtMiJ72ZOLhbu/bzxgAe8Ue8CTS3n3HbIUHQz/L51yMdGMeoxXNJw==",
+ "version": "0.28.0",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.28.0.tgz",
+ "integrity": "sha512-zF3ag/gfiCe6U2iczcRzSYJKH1DCI+ByzSENHlM2FcDbEeo5Zd2C86Aq0tKUYAJJ1obRP84ymxIAksZUcdztHA==",
"cpu": [
"ia32"
],
@@ -447,9 +447,9 @@
}
},
"node_modules/@esbuild/win32-x64": {
- "version": "0.27.4",
- "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.27.4.tgz",
- "integrity": "sha512-+knoa0BDoeXgkNvvV1vvbZX4+hizelrkwmGJBdT17t8FNPwG2lKemmuMZlmaNQ3ws3DKKCxpb4zRZEIp3UxFCg==",
+ "version": "0.28.0",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.28.0.tgz",
+ "integrity": "sha512-pEl1bO9mfAmIC+tW5btTmrKaujg3zGtUmWNdCw/xs70FBjwAL3o9OEKNHvNmnyylD6ubxUERiEhdsL0xBQ9efw==",
"cpu": [
"x64"
],
@@ -823,68 +823,68 @@
}
},
"node_modules/@tailwindcss/cli": {
- "version": "4.2.1",
- "resolved": "https://registry.npmjs.org/@tailwindcss/cli/-/cli-4.2.1.tgz",
- "integrity": "sha512-b7MGn51IA80oSG+7fuAgzfQ+7pZBgjzbqwmiv6NO7/+a1sev32cGqnwhscT7h0EcAvMa9r7gjRylqOH8Xhc4DA==",
+ "version": "4.2.2",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/cli/-/cli-4.2.2.tgz",
+ "integrity": "sha512-iJS+8kAFZ8HPqnh0O5DHCLjo4L6dD97DBQEkrhfSO4V96xeefUus2jqsBs1dUMt3OU9Ks4qIkiY0mpL5UW+4LQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"@parcel/watcher": "^2.5.1",
- "@tailwindcss/node": "4.2.1",
- "@tailwindcss/oxide": "4.2.1",
+ "@tailwindcss/node": "4.2.2",
+ "@tailwindcss/oxide": "4.2.2",
"enhanced-resolve": "^5.19.0",
"mri": "^1.2.0",
"picocolors": "^1.1.1",
- "tailwindcss": "4.2.1"
+ "tailwindcss": "4.2.2"
},
"bin": {
"tailwindcss": "dist/index.mjs"
}
},
"node_modules/@tailwindcss/node": {
- "version": "4.2.1",
- "resolved": "https://registry.npmjs.org/@tailwindcss/node/-/node-4.2.1.tgz",
- "integrity": "sha512-jlx6sLk4EOwO6hHe1oCGm1Q4AN/s0rSrTTPBGPM0/RQ6Uylwq17FuU8IeJJKEjtc6K6O07zsvP+gDO6MMWo7pg==",
+ "version": "4.2.2",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/node/-/node-4.2.2.tgz",
+ "integrity": "sha512-pXS+wJ2gZpVXqFaUEjojq7jzMpTGf8rU6ipJz5ovJV6PUGmlJ+jvIwGrzdHdQ80Sg+wmQxUFuoW1UAAwHNEdFA==",
"dev": true,
"license": "MIT",
"dependencies": {
"@jridgewell/remapping": "^2.3.5",
"enhanced-resolve": "^5.19.0",
"jiti": "^2.6.1",
- "lightningcss": "1.31.1",
+ "lightningcss": "1.32.0",
"magic-string": "^0.30.21",
"source-map-js": "^1.2.1",
- "tailwindcss": "4.2.1"
+ "tailwindcss": "4.2.2"
}
},
"node_modules/@tailwindcss/oxide": {
- "version": "4.2.1",
- "resolved": "https://registry.npmjs.org/@tailwindcss/oxide/-/oxide-4.2.1.tgz",
- "integrity": "sha512-yv9jeEFWnjKCI6/T3Oq50yQEOqmpmpfzG1hcZsAOaXFQPfzWprWrlHSdGPEF3WQTi8zu8ohC9Mh9J470nT5pUw==",
+ "version": "4.2.2",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide/-/oxide-4.2.2.tgz",
+ "integrity": "sha512-qEUA07+E5kehxYp9BVMpq9E8vnJuBHfJEC0vPC5e7iL/hw7HR61aDKoVoKzrG+QKp56vhNZe4qwkRmMC0zDLvg==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">= 20"
},
"optionalDependencies": {
- "@tailwindcss/oxide-android-arm64": "4.2.1",
- "@tailwindcss/oxide-darwin-arm64": "4.2.1",
- "@tailwindcss/oxide-darwin-x64": "4.2.1",
- "@tailwindcss/oxide-freebsd-x64": "4.2.1",
- "@tailwindcss/oxide-linux-arm-gnueabihf": "4.2.1",
- "@tailwindcss/oxide-linux-arm64-gnu": "4.2.1",
- "@tailwindcss/oxide-linux-arm64-musl": "4.2.1",
- "@tailwindcss/oxide-linux-x64-gnu": "4.2.1",
- "@tailwindcss/oxide-linux-x64-musl": "4.2.1",
- "@tailwindcss/oxide-wasm32-wasi": "4.2.1",
- "@tailwindcss/oxide-win32-arm64-msvc": "4.2.1",
- "@tailwindcss/oxide-win32-x64-msvc": "4.2.1"
+ "@tailwindcss/oxide-android-arm64": "4.2.2",
+ "@tailwindcss/oxide-darwin-arm64": "4.2.2",
+ "@tailwindcss/oxide-darwin-x64": "4.2.2",
+ "@tailwindcss/oxide-freebsd-x64": "4.2.2",
+ "@tailwindcss/oxide-linux-arm-gnueabihf": "4.2.2",
+ "@tailwindcss/oxide-linux-arm64-gnu": "4.2.2",
+ "@tailwindcss/oxide-linux-arm64-musl": "4.2.2",
+ "@tailwindcss/oxide-linux-x64-gnu": "4.2.2",
+ "@tailwindcss/oxide-linux-x64-musl": "4.2.2",
+ "@tailwindcss/oxide-wasm32-wasi": "4.2.2",
+ "@tailwindcss/oxide-win32-arm64-msvc": "4.2.2",
+ "@tailwindcss/oxide-win32-x64-msvc": "4.2.2"
}
},
"node_modules/@tailwindcss/oxide-android-arm64": {
- "version": "4.2.1",
- "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-android-arm64/-/oxide-android-arm64-4.2.1.tgz",
- "integrity": "sha512-eZ7G1Zm5EC8OOKaesIKuw77jw++QJ2lL9N+dDpdQiAB/c/B2wDh0QPFHbkBVrXnwNugvrbJFk1gK2SsVjwWReg==",
+ "version": "4.2.2",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-android-arm64/-/oxide-android-arm64-4.2.2.tgz",
+ "integrity": "sha512-dXGR1n+P3B6748jZO/SvHZq7qBOqqzQ+yFrXpoOWWALWndF9MoSKAT3Q0fYgAzYzGhxNYOoysRvYlpixRBBoDg==",
"cpu": [
"arm64"
],
@@ -899,9 +899,9 @@
}
},
"node_modules/@tailwindcss/oxide-darwin-arm64": {
- "version": "4.2.1",
- "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-arm64/-/oxide-darwin-arm64-4.2.1.tgz",
- "integrity": "sha512-q/LHkOstoJ7pI1J0q6djesLzRvQSIfEto148ppAd+BVQK0JYjQIFSK3JgYZJa+Yzi0DDa52ZsQx2rqytBnf8Hw==",
+ "version": "4.2.2",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-arm64/-/oxide-darwin-arm64-4.2.2.tgz",
+ "integrity": "sha512-iq9Qjr6knfMpZHj55/37ouZeykwbDqF21gPFtfnhCCKGDcPI/21FKC9XdMO/XyBM7qKORx6UIhGgg6jLl7BZlg==",
"cpu": [
"arm64"
],
@@ -916,9 +916,9 @@
}
},
"node_modules/@tailwindcss/oxide-darwin-x64": {
- "version": "4.2.1",
- "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-x64/-/oxide-darwin-x64-4.2.1.tgz",
- "integrity": "sha512-/f/ozlaXGY6QLbpvd/kFTro2l18f7dHKpB+ieXz+Cijl4Mt9AI2rTrpq7V+t04nK+j9XBQHnSMdeQRhbGyt6fw==",
+ "version": "4.2.2",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-x64/-/oxide-darwin-x64-4.2.2.tgz",
+ "integrity": "sha512-BlR+2c3nzc8f2G639LpL89YY4bdcIdUmiOOkv2GQv4/4M0vJlpXEa0JXNHhCHU7VWOKWT/CjqHdTP8aUuDJkuw==",
"cpu": [
"x64"
],
@@ -933,9 +933,9 @@
}
},
"node_modules/@tailwindcss/oxide-freebsd-x64": {
- "version": "4.2.1",
- "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-freebsd-x64/-/oxide-freebsd-x64-4.2.1.tgz",
- "integrity": "sha512-5e/AkgYJT/cpbkys/OU2Ei2jdETCLlifwm7ogMC7/hksI2fC3iiq6OcXwjibcIjPung0kRtR3TxEITkqgn0TcA==",
+ "version": "4.2.2",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-freebsd-x64/-/oxide-freebsd-x64-4.2.2.tgz",
+ "integrity": "sha512-YUqUgrGMSu2CDO82hzlQ5qSb5xmx3RUrke/QgnoEx7KvmRJHQuZHZmZTLSuuHwFf0DJPybFMXMYf+WJdxHy/nQ==",
"cpu": [
"x64"
],
@@ -950,9 +950,9 @@
}
},
"node_modules/@tailwindcss/oxide-linux-arm-gnueabihf": {
- "version": "4.2.1",
- "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm-gnueabihf/-/oxide-linux-arm-gnueabihf-4.2.1.tgz",
- "integrity": "sha512-Uny1EcVTTmerCKt/1ZuKTkb0x8ZaiuYucg2/kImO5A5Y/kBz41/+j0gxUZl+hTF3xkWpDmHX+TaWhOtba2Fyuw==",
+ "version": "4.2.2",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm-gnueabihf/-/oxide-linux-arm-gnueabihf-4.2.2.tgz",
+ "integrity": "sha512-FPdhvsW6g06T9BWT0qTwiVZYE2WIFo2dY5aCSpjG/S/u1tby+wXoslXS0kl3/KXnULlLr1E3NPRRw0g7t2kgaQ==",
"cpu": [
"arm"
],
@@ -967,9 +967,9 @@
}
},
"node_modules/@tailwindcss/oxide-linux-arm64-gnu": {
- "version": "4.2.1",
- "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-gnu/-/oxide-linux-arm64-gnu-4.2.1.tgz",
- "integrity": "sha512-CTrwomI+c7n6aSSQlsPL0roRiNMDQ/YzMD9EjcR+H4f0I1SQ8QqIuPnsVp7QgMkC1Qi8rtkekLkOFjo7OlEFRQ==",
+ "version": "4.2.2",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-gnu/-/oxide-linux-arm64-gnu-4.2.2.tgz",
+ "integrity": "sha512-4og1V+ftEPXGttOO7eCmW7VICmzzJWgMx+QXAJRAhjrSjumCwWqMfkDrNu1LXEQzNAwz28NCUpucgQPrR4S2yw==",
"cpu": [
"arm64"
],
@@ -984,9 +984,9 @@
}
},
"node_modules/@tailwindcss/oxide-linux-arm64-musl": {
- "version": "4.2.1",
- "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-musl/-/oxide-linux-arm64-musl-4.2.1.tgz",
- "integrity": "sha512-WZA0CHRL/SP1TRbA5mp9htsppSEkWuQ4KsSUumYQnyl8ZdT39ntwqmz4IUHGN6p4XdSlYfJwM4rRzZLShHsGAQ==",
+ "version": "4.2.2",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-musl/-/oxide-linux-arm64-musl-4.2.2.tgz",
+ "integrity": "sha512-oCfG/mS+/+XRlwNjnsNLVwnMWYH7tn/kYPsNPh+JSOMlnt93mYNCKHYzylRhI51X+TbR+ufNhhKKzm6QkqX8ag==",
"cpu": [
"arm64"
],
@@ -1001,9 +1001,9 @@
}
},
"node_modules/@tailwindcss/oxide-linux-x64-gnu": {
- "version": "4.2.1",
- "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-gnu/-/oxide-linux-x64-gnu-4.2.1.tgz",
- "integrity": "sha512-qMFzxI2YlBOLW5PhblzuSWlWfwLHaneBE0xHzLrBgNtqN6mWfs+qYbhryGSXQjFYB1Dzf5w+LN5qbUTPhW7Y5g==",
+ "version": "4.2.2",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-gnu/-/oxide-linux-x64-gnu-4.2.2.tgz",
+ "integrity": "sha512-rTAGAkDgqbXHNp/xW0iugLVmX62wOp2PoE39BTCGKjv3Iocf6AFbRP/wZT/kuCxC9QBh9Pu8XPkv/zCZB2mcMg==",
"cpu": [
"x64"
],
@@ -1018,9 +1018,9 @@
}
},
"node_modules/@tailwindcss/oxide-linux-x64-musl": {
- "version": "4.2.1",
- "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-musl/-/oxide-linux-x64-musl-4.2.1.tgz",
- "integrity": "sha512-5r1X2FKnCMUPlXTWRYpHdPYUY6a1Ar/t7P24OuiEdEOmms5lyqjDRvVY1yy9Rmioh+AunQ0rWiOTPE8F9A3v5g==",
+ "version": "4.2.2",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-musl/-/oxide-linux-x64-musl-4.2.2.tgz",
+ "integrity": "sha512-XW3t3qwbIwiSyRCggeO2zxe3KWaEbM0/kW9e8+0XpBgyKU4ATYzcVSMKteZJ1iukJ3HgHBjbg9P5YPRCVUxlnQ==",
"cpu": [
"x64"
],
@@ -1035,9 +1035,9 @@
}
},
"node_modules/@tailwindcss/oxide-wasm32-wasi": {
- "version": "4.2.1",
- "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-wasm32-wasi/-/oxide-wasm32-wasi-4.2.1.tgz",
- "integrity": "sha512-MGFB5cVPvshR85MTJkEvqDUnuNoysrsRxd6vnk1Lf2tbiqNlXpHYZqkqOQalydienEWOHHFyyuTSYRsLfxFJ2Q==",
+ "version": "4.2.2",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-wasm32-wasi/-/oxide-wasm32-wasi-4.2.2.tgz",
+ "integrity": "sha512-eKSztKsmEsn1O5lJ4ZAfyn41NfG7vzCg496YiGtMDV86jz1q/irhms5O0VrY6ZwTUkFy/EKG3RfWgxSI3VbZ8Q==",
"bundleDependencies": [
"@napi-rs/wasm-runtime",
"@emnapi/core",
@@ -1065,9 +1065,9 @@
}
},
"node_modules/@tailwindcss/oxide-win32-arm64-msvc": {
- "version": "4.2.1",
- "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-arm64-msvc/-/oxide-win32-arm64-msvc-4.2.1.tgz",
- "integrity": "sha512-YlUEHRHBGnCMh4Nj4GnqQyBtsshUPdiNroZj8VPkvTZSoHsilRCwXcVKnG9kyi0ZFAS/3u+qKHBdDc81SADTRA==",
+ "version": "4.2.2",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-arm64-msvc/-/oxide-win32-arm64-msvc-4.2.2.tgz",
+ "integrity": "sha512-qPmaQM4iKu5mxpsrWZMOZRgZv1tOZpUm+zdhhQP0VhJfyGGO3aUKdbh3gDZc/dPLQwW4eSqWGrrcWNBZWUWaXQ==",
"cpu": [
"arm64"
],
@@ -1082,9 +1082,9 @@
}
},
"node_modules/@tailwindcss/oxide-win32-x64-msvc": {
- "version": "4.2.1",
- "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-x64-msvc/-/oxide-win32-x64-msvc-4.2.1.tgz",
- "integrity": "sha512-rbO34G5sMWWyrN/idLeVxAZgAKWrn5LiR3/I90Q9MkA67s6T1oB0xtTe+0heoBvHSpbU9Mk7i6uwJnpo4u21XQ==",
+ "version": "4.2.2",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-x64-msvc/-/oxide-win32-x64-msvc-4.2.2.tgz",
+ "integrity": "sha512-1T/37VvI7WyH66b+vqHj/cLwnCxt7Qt3WFu5Q8hk65aOvlwAhs7rAp1VkulBJw/N4tMirXjVnylTR72uI0HGcA==",
"cpu": [
"x64"
],
@@ -1168,9 +1168,9 @@
}
},
"node_modules/enhanced-resolve": {
- "version": "5.20.0",
- "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.20.0.tgz",
- "integrity": "sha512-/ce7+jQ1PQ6rVXwe+jKEg5hW5ciicHwIQUagZkp6IufBoY3YDgdTTY1azVs0qoRgVmvsNB+rbjLJxDAeHHtwsQ==",
+ "version": "5.20.1",
+ "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.20.1.tgz",
+ "integrity": "sha512-Qohcme7V1inbAfvjItgw0EaxVX5q2rdVEZHRBrEQdRZTssLDGsL8Lwrznl8oQ/6kuTJONLaDcGjkNP247XEhcA==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -1182,9 +1182,9 @@
}
},
"node_modules/esbuild": {
- "version": "0.27.4",
- "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.4.tgz",
- "integrity": "sha512-Rq4vbHnYkK5fws5NF7MYTU68FPRE1ajX7heQ/8QXXWqNgqqJ/GkmmyxIzUnf2Sr/bakf8l54716CcMGHYhMrrQ==",
+ "version": "0.28.0",
+ "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.28.0.tgz",
+ "integrity": "sha512-sNR9MHpXSUV/XB4zmsFKN+QgVG82Cc7+/aaxJ8Adi8hyOac+EXptIp45QBPaVyX3N70664wRbTcLTOemCAnyqw==",
"dev": true,
"hasInstallScript": true,
"license": "MIT",
@@ -1195,32 +1195,32 @@
"node": ">=18"
},
"optionalDependencies": {
- "@esbuild/aix-ppc64": "0.27.4",
- "@esbuild/android-arm": "0.27.4",
- "@esbuild/android-arm64": "0.27.4",
- "@esbuild/android-x64": "0.27.4",
- "@esbuild/darwin-arm64": "0.27.4",
- "@esbuild/darwin-x64": "0.27.4",
- "@esbuild/freebsd-arm64": "0.27.4",
- "@esbuild/freebsd-x64": "0.27.4",
- "@esbuild/linux-arm": "0.27.4",
- "@esbuild/linux-arm64": "0.27.4",
- "@esbuild/linux-ia32": "0.27.4",
- "@esbuild/linux-loong64": "0.27.4",
- "@esbuild/linux-mips64el": "0.27.4",
- "@esbuild/linux-ppc64": "0.27.4",
- "@esbuild/linux-riscv64": "0.27.4",
- "@esbuild/linux-s390x": "0.27.4",
- "@esbuild/linux-x64": "0.27.4",
- "@esbuild/netbsd-arm64": "0.27.4",
- "@esbuild/netbsd-x64": "0.27.4",
- "@esbuild/openbsd-arm64": "0.27.4",
- "@esbuild/openbsd-x64": "0.27.4",
- "@esbuild/openharmony-arm64": "0.27.4",
- "@esbuild/sunos-x64": "0.27.4",
- "@esbuild/win32-arm64": "0.27.4",
- "@esbuild/win32-ia32": "0.27.4",
- "@esbuild/win32-x64": "0.27.4"
+ "@esbuild/aix-ppc64": "0.28.0",
+ "@esbuild/android-arm": "0.28.0",
+ "@esbuild/android-arm64": "0.28.0",
+ "@esbuild/android-x64": "0.28.0",
+ "@esbuild/darwin-arm64": "0.28.0",
+ "@esbuild/darwin-x64": "0.28.0",
+ "@esbuild/freebsd-arm64": "0.28.0",
+ "@esbuild/freebsd-x64": "0.28.0",
+ "@esbuild/linux-arm": "0.28.0",
+ "@esbuild/linux-arm64": "0.28.0",
+ "@esbuild/linux-ia32": "0.28.0",
+ "@esbuild/linux-loong64": "0.28.0",
+ "@esbuild/linux-mips64el": "0.28.0",
+ "@esbuild/linux-ppc64": "0.28.0",
+ "@esbuild/linux-riscv64": "0.28.0",
+ "@esbuild/linux-s390x": "0.28.0",
+ "@esbuild/linux-x64": "0.28.0",
+ "@esbuild/netbsd-arm64": "0.28.0",
+ "@esbuild/netbsd-x64": "0.28.0",
+ "@esbuild/openbsd-arm64": "0.28.0",
+ "@esbuild/openbsd-x64": "0.28.0",
+ "@esbuild/openharmony-arm64": "0.28.0",
+ "@esbuild/sunos-x64": "0.28.0",
+ "@esbuild/win32-arm64": "0.28.0",
+ "@esbuild/win32-ia32": "0.28.0",
+ "@esbuild/win32-x64": "0.28.0"
}
},
"node_modules/glob": {
@@ -1296,9 +1296,9 @@
}
},
"node_modules/lightningcss": {
- "version": "1.31.1",
- "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.31.1.tgz",
- "integrity": "sha512-l51N2r93WmGUye3WuFoN5k10zyvrVs0qfKBhyC5ogUQ6Ew6JUSswh78mbSO+IU3nTWsyOArqPCcShdQSadghBQ==",
+ "version": "1.32.0",
+ "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.32.0.tgz",
+ "integrity": "sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ==",
"dev": true,
"license": "MPL-2.0",
"dependencies": {
@@ -1312,23 +1312,23 @@
"url": "https://opencollective.com/parcel"
},
"optionalDependencies": {
- "lightningcss-android-arm64": "1.31.1",
- "lightningcss-darwin-arm64": "1.31.1",
- "lightningcss-darwin-x64": "1.31.1",
- "lightningcss-freebsd-x64": "1.31.1",
- "lightningcss-linux-arm-gnueabihf": "1.31.1",
- "lightningcss-linux-arm64-gnu": "1.31.1",
- "lightningcss-linux-arm64-musl": "1.31.1",
- "lightningcss-linux-x64-gnu": "1.31.1",
- "lightningcss-linux-x64-musl": "1.31.1",
- "lightningcss-win32-arm64-msvc": "1.31.1",
- "lightningcss-win32-x64-msvc": "1.31.1"
+ "lightningcss-android-arm64": "1.32.0",
+ "lightningcss-darwin-arm64": "1.32.0",
+ "lightningcss-darwin-x64": "1.32.0",
+ "lightningcss-freebsd-x64": "1.32.0",
+ "lightningcss-linux-arm-gnueabihf": "1.32.0",
+ "lightningcss-linux-arm64-gnu": "1.32.0",
+ "lightningcss-linux-arm64-musl": "1.32.0",
+ "lightningcss-linux-x64-gnu": "1.32.0",
+ "lightningcss-linux-x64-musl": "1.32.0",
+ "lightningcss-win32-arm64-msvc": "1.32.0",
+ "lightningcss-win32-x64-msvc": "1.32.0"
}
},
"node_modules/lightningcss-android-arm64": {
- "version": "1.31.1",
- "resolved": "https://registry.npmjs.org/lightningcss-android-arm64/-/lightningcss-android-arm64-1.31.1.tgz",
- "integrity": "sha512-HXJF3x8w9nQ4jbXRiNppBCqeZPIAfUo8zE/kOEGbW5NZvGc/K7nMxbhIr+YlFlHW5mpbg/YFPdbnCh1wAXCKFg==",
+ "version": "1.32.0",
+ "resolved": "https://registry.npmjs.org/lightningcss-android-arm64/-/lightningcss-android-arm64-1.32.0.tgz",
+ "integrity": "sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg==",
"cpu": [
"arm64"
],
@@ -1347,9 +1347,9 @@
}
},
"node_modules/lightningcss-darwin-arm64": {
- "version": "1.31.1",
- "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.31.1.tgz",
- "integrity": "sha512-02uTEqf3vIfNMq3h/z2cJfcOXnQ0GRwQrkmPafhueLb2h7mqEidiCzkE4gBMEH65abHRiQvhdcQ+aP0D0g67sg==",
+ "version": "1.32.0",
+ "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.32.0.tgz",
+ "integrity": "sha512-RzeG9Ju5bag2Bv1/lwlVJvBE3q6TtXskdZLLCyfg5pt+HLz9BqlICO7LZM7VHNTTn/5PRhHFBSjk5lc4cmscPQ==",
"cpu": [
"arm64"
],
@@ -1368,9 +1368,9 @@
}
},
"node_modules/lightningcss-darwin-x64": {
- "version": "1.31.1",
- "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.31.1.tgz",
- "integrity": "sha512-1ObhyoCY+tGxtsz1lSx5NXCj3nirk0Y0kB/g8B8DT+sSx4G9djitg9ejFnjb3gJNWo7qXH4DIy2SUHvpoFwfTA==",
+ "version": "1.32.0",
+ "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.32.0.tgz",
+ "integrity": "sha512-U+QsBp2m/s2wqpUYT/6wnlagdZbtZdndSmut/NJqlCcMLTWp5muCrID+K5UJ6jqD2BFshejCYXniPDbNh73V8w==",
"cpu": [
"x64"
],
@@ -1389,9 +1389,9 @@
}
},
"node_modules/lightningcss-freebsd-x64": {
- "version": "1.31.1",
- "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.31.1.tgz",
- "integrity": "sha512-1RINmQKAItO6ISxYgPwszQE1BrsVU5aB45ho6O42mu96UiZBxEXsuQ7cJW4zs4CEodPUioj/QrXW1r9pLUM74A==",
+ "version": "1.32.0",
+ "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.32.0.tgz",
+ "integrity": "sha512-JCTigedEksZk3tHTTthnMdVfGf61Fky8Ji2E4YjUTEQX14xiy/lTzXnu1vwiZe3bYe0q+SpsSH/CTeDXK6WHig==",
"cpu": [
"x64"
],
@@ -1410,9 +1410,9 @@
}
},
"node_modules/lightningcss-linux-arm-gnueabihf": {
- "version": "1.31.1",
- "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.31.1.tgz",
- "integrity": "sha512-OOCm2//MZJ87CdDK62rZIu+aw9gBv4azMJuA8/KB74wmfS3lnC4yoPHm0uXZ/dvNNHmnZnB8XLAZzObeG0nS1g==",
+ "version": "1.32.0",
+ "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.32.0.tgz",
+ "integrity": "sha512-x6rnnpRa2GL0zQOkt6rts3YDPzduLpWvwAF6EMhXFVZXD4tPrBkEFqzGowzCsIWsPjqSK+tyNEODUBXeeVHSkw==",
"cpu": [
"arm"
],
@@ -1431,9 +1431,9 @@
}
},
"node_modules/lightningcss-linux-arm64-gnu": {
- "version": "1.31.1",
- "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.31.1.tgz",
- "integrity": "sha512-WKyLWztD71rTnou4xAD5kQT+982wvca7E6QoLpoawZ1gP9JM0GJj4Tp5jMUh9B3AitHbRZ2/H3W5xQmdEOUlLg==",
+ "version": "1.32.0",
+ "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.32.0.tgz",
+ "integrity": "sha512-0nnMyoyOLRJXfbMOilaSRcLH3Jw5z9HDNGfT/gwCPgaDjnx0i8w7vBzFLFR1f6CMLKF8gVbebmkUN3fa/kQJpQ==",
"cpu": [
"arm64"
],
@@ -1452,9 +1452,9 @@
}
},
"node_modules/lightningcss-linux-arm64-musl": {
- "version": "1.31.1",
- "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.31.1.tgz",
- "integrity": "sha512-mVZ7Pg2zIbe3XlNbZJdjs86YViQFoJSpc41CbVmKBPiGmC4YrfeOyz65ms2qpAobVd7WQsbW4PdsSJEMymyIMg==",
+ "version": "1.32.0",
+ "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.32.0.tgz",
+ "integrity": "sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg==",
"cpu": [
"arm64"
],
@@ -1473,9 +1473,9 @@
}
},
"node_modules/lightningcss-linux-x64-gnu": {
- "version": "1.31.1",
- "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.31.1.tgz",
- "integrity": "sha512-xGlFWRMl+0KvUhgySdIaReQdB4FNudfUTARn7q0hh/V67PVGCs3ADFjw+6++kG1RNd0zdGRlEKa+T13/tQjPMA==",
+ "version": "1.32.0",
+ "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.32.0.tgz",
+ "integrity": "sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA==",
"cpu": [
"x64"
],
@@ -1494,9 +1494,9 @@
}
},
"node_modules/lightningcss-linux-x64-musl": {
- "version": "1.31.1",
- "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.31.1.tgz",
- "integrity": "sha512-eowF8PrKHw9LpoZii5tdZwnBcYDxRw2rRCyvAXLi34iyeYfqCQNA9rmUM0ce62NlPhCvof1+9ivRaTY6pSKDaA==",
+ "version": "1.32.0",
+ "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.32.0.tgz",
+ "integrity": "sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg==",
"cpu": [
"x64"
],
@@ -1515,9 +1515,9 @@
}
},
"node_modules/lightningcss-win32-arm64-msvc": {
- "version": "1.31.1",
- "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.31.1.tgz",
- "integrity": "sha512-aJReEbSEQzx1uBlQizAOBSjcmr9dCdL3XuC/6HLXAxmtErsj2ICo5yYggg1qOODQMtnjNQv2UHb9NpOuFtYe4w==",
+ "version": "1.32.0",
+ "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.32.0.tgz",
+ "integrity": "sha512-8SbC8BR40pS6baCM8sbtYDSwEVQd4JlFTOlaD3gWGHfThTcABnNDBda6eTZeqbofalIJhFx0qKzgHJmcPTnGdw==",
"cpu": [
"arm64"
],
@@ -1536,9 +1536,9 @@
}
},
"node_modules/lightningcss-win32-x64-msvc": {
- "version": "1.31.1",
- "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.31.1.tgz",
- "integrity": "sha512-I9aiFrbd7oYHwlnQDqr1Roz+fTz61oDDJX7n9tYF9FJymH1cIN1DtKw3iYt6b8WZgEjoNwVSncwF4wx/ZedMhw==",
+ "version": "1.32.0",
+ "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.32.0.tgz",
+ "integrity": "sha512-Amq9B/SoZYdDi1kFrojnoqPLxYhQ4Wo5XiL8EVJrVsB8ARoC1PWW6VGtT0WKCemjy8aC+louJnjS7U18x3b06Q==",
"cpu": [
"x64"
],
@@ -1567,9 +1567,9 @@
}
},
"node_modules/lucide": {
- "version": "0.577.0",
- "resolved": "https://registry.npmjs.org/lucide/-/lucide-0.577.0.tgz",
- "integrity": "sha512-PpC/m5eOItp/WU/GlQPFBXDOhq6HibL73KzYP37OX3LM7VmzWQF8voEj8QRWUFvy9FIKfeDQkWYoyS1D/MdWFA==",
+ "version": "1.8.0",
+ "resolved": "https://registry.npmjs.org/lucide/-/lucide-1.8.0.tgz",
+ "integrity": "sha512-JjV/QnadgFLj1Pyu9IKl0lknrolFEzo04B64QcYLLeRzZl/iEHpdbSrRRKbyXcv45SZNv+WGjIUCT33e7xHO6Q==",
"license": "ISC"
},
"node_modules/magic-string": {
@@ -1687,16 +1687,16 @@
}
},
"node_modules/tailwindcss": {
- "version": "4.2.1",
- "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.2.1.tgz",
- "integrity": "sha512-/tBrSQ36vCleJkAOsy9kbNTgaxvGbyOamC30PRePTQe/o1MFwEKHQk4Cn7BNGaPtjp+PuUrByJehM1hgxfq4sw==",
+ "version": "4.2.2",
+ "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.2.2.tgz",
+ "integrity": "sha512-KWBIxs1Xb6NoLdMVqhbhgwZf2PGBpPEiwOqgI4pFIYbNTfBXiKYyWoTsXgBQ9WFg/OlhnvHaY+AEpW7wSmFo2Q==",
"dev": true,
"license": "MIT"
},
"node_modules/tapable": {
- "version": "2.3.0",
- "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.3.0.tgz",
- "integrity": "sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg==",
+ "version": "2.3.2",
+ "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.3.2.tgz",
+ "integrity": "sha512-1MOpMXuhGzGL5TTCZFItxCc0AARf1EZFQkGqMm7ERKj8+Hgr5oLvJOVFcC+lRmR8hCe2S3jC4T5D7Vg/d7/fhA==",
"dev": true,
"license": "MIT",
"engines": {
diff --git a/package.json b/package.json
index 37f63cd..626d381 100644
--- a/package.json
+++ b/package.json
@@ -4,9 +4,9 @@
"private": true,
"scripts": {
"icons:build": "node scripts/generate-icons.js",
- "css:build": "BROWSERSLIST_IGNORE_OLD_DATA=1 npx tailwindcss -i ./pkg/appview/src/css/main.css -o ./pkg/appview/public/css/style.css --minify",
- "css:build:hold": "BROWSERSLIST_IGNORE_OLD_DATA=1 npx tailwindcss -i ./pkg/hold/admin/src/css/main.css -o ./pkg/hold/admin/public/css/style.css --minify",
- "css:watch": "BROWSERSLIST_IGNORE_OLD_DATA=1 npx tailwindcss -i ./pkg/appview/src/css/main.css -o ./pkg/appview/public/css/style.css --watch",
+ "css:build": "npx tailwindcss -i ./pkg/appview/src/css/main.css -o ./pkg/appview/public/css/style.css --minify",
+ "css:build:hold": "npx tailwindcss -i ./pkg/hold/admin/src/css/main.css -o ./pkg/hold/admin/public/css/style.css --minify",
+ "css:watch": "npx tailwindcss -i ./pkg/appview/src/css/main.css -o ./pkg/appview/public/css/style.css --watch",
"js:build": "esbuild pkg/appview/src/js/main.js --bundle --minify --format=esm --outfile=pkg/appview/public/js/bundle.min.js",
"js:build:hold": "esbuild pkg/hold/admin/src/js/main.js --bundle --minify --format=esm --outfile=pkg/hold/admin/public/js/bundle.min.js",
"js:watch": "esbuild pkg/appview/src/js/main.js --bundle --watch --format=esm --outfile=pkg/appview/public/js/bundle.min.js",
@@ -16,16 +16,16 @@
"watch": "npm run css:watch & npm run js:watch"
},
"devDependencies": {
- "@tailwindcss/cli": "^4.2.1",
+ "@tailwindcss/cli": "^4.2.2",
"@tailwindcss/typography": "^0.5.19",
"daisyui": "^5.5.19",
- "esbuild": "^0.27.4",
+ "esbuild": "^0.28.0",
"glob": "^13.0.6",
- "tailwindcss": "^4.2"
+ "lucide": "^1.8.0",
+ "tailwindcss": "^4.2.2"
},
"dependencies": {
"htmx-ext-json-enc": "^2.0.3",
- "htmx.org": "^2.0.8",
- "lucide": "^0.577.0"
+ "htmx.org": "^2.0.8"
}
}
diff --git a/pkg/appview/handlers/scan_result_test.go b/pkg/appview/handlers/scan_result_test.go
index f3434de..11b8e0a 100644
--- a/pkg/appview/handlers/scan_result_test.go
+++ b/pkg/appview/handlers/scan_result_test.go
@@ -95,19 +95,19 @@ func TestScanResult_WithVulnerabilities(t *testing.T) {
if !strings.Contains(body, "vuln-box-critical") {
t.Error("Expected body to contain vuln-box-critical for critical vulnerabilities")
}
- if !strings.Contains(body, `data-tip="Critical">2<`) {
+ if !strings.Contains(body, `aria-label="2 critical">2<`) {
t.Error("Expected critical count of 2")
}
if !strings.Contains(body, "vuln-box-high") {
t.Error("Expected body to contain vuln-box-high for high vulnerabilities")
}
- if !strings.Contains(body, `data-tip="High">5<`) {
+ if !strings.Contains(body, `aria-label="5 high">5<`) {
t.Error("Expected high count of 5")
}
- if !strings.Contains(body, `data-tip="Medium">10<`) {
+ if !strings.Contains(body, `aria-label="10 medium">10<`) {
t.Error("Expected medium count of 10")
}
- if !strings.Contains(body, `data-tip="Low">3<`) {
+ if !strings.Contains(body, `aria-label="3 low">3<`) {
t.Error("Expected low count of 3")
}
// Should show vulnerability strip with tooltip
@@ -274,7 +274,7 @@ func TestScanResult_OnlyCriticalShown(t *testing.T) {
body := rr.Body.String()
- if !strings.Contains(body, `data-tip="Critical">3<`) {
+ if !strings.Contains(body, `aria-label="3 critical">3<`) {
t.Error("Expected critical count of 3")
}
// Zero-count badges should NOT appear
@@ -353,7 +353,7 @@ func TestBatchScanResult_MultipleDigests(t *testing.T) {
}
// abc123 should have vulnerability badges
- if !strings.Contains(body, `data-tip="Critical">2<`) {
+ if !strings.Contains(body, `aria-label="2 critical">2<`) {
t.Error("Expected critical count of 2 for abc123")
}
// def456 should have clean badge
@@ -496,7 +496,7 @@ func TestBatchScanResult_SingleDigest(t *testing.T) {
if !strings.Contains(body, `id="scan-badge-abc123"`) {
t.Error("Expected OOB span for abc123")
}
- if !strings.Contains(body, `data-tip="Critical">1<`) {
+ if !strings.Contains(body, `aria-label="1 critical">1<`) {
t.Error("Expected critical count of 1")
}
}
diff --git a/pkg/appview/handlers/vuln_details_test.go b/pkg/appview/handlers/vuln_details_test.go
index bc7a7f7..a3eed09 100644
--- a/pkg/appview/handlers/vuln_details_test.go
+++ b/pkg/appview/handlers/vuln_details_test.go
@@ -223,8 +223,8 @@ func TestVulnDetails_FullReport(t *testing.T) {
}
// Should contain "-" placeholder for unfixed vuln
- if !strings.Contains(body, `opacity-40`) {
- t.Error("Expected body to contain opacity-40 placeholder for unfixed vulnerability")
+ if !strings.Contains(body, `text-base-content/40`) {
+ t.Error("Expected body to contain dimmed placeholder for unfixed vulnerability")
}
// Should contain a table
@@ -256,7 +256,7 @@ func TestVulnDetails_NoVulnReportBlob(t *testing.T) {
if !strings.Contains(body, "vuln-box-critical") {
t.Error("Expected body to contain vuln-box-critical in summary")
}
- if !strings.Contains(body, `data-tip="Critical">2<`) {
+ if !strings.Contains(body, `aria-label="2 critical">2<`) {
t.Error("Expected critical count of 2 in summary")
}
diff --git a/pkg/appview/public/icons.svg b/pkg/appview/public/icons.svg
index ea32d1a..eb4d6b7 100644
--- a/pkg/appview/public/icons.svg
+++ b/pkg/appview/public/icons.svg
@@ -30,7 +30,6 @@
-
diff --git a/pkg/appview/public/js/bundle.min.js b/pkg/appview/public/js/bundle.min.js
index 0e31478..4ecd3aa 100644
--- a/pkg/appview/public/js/bundle.min.js
+++ b/pkg/appview/public/js/bundle.min.js
@@ -1,2 +1,76 @@
-var ce=(function(){"use strict";let htmx={onLoad:null,process:null,on:null,off:null,trigger:null,ajax:null,find:null,findAll:null,closest:null,values:function(e,t){return getInputValues(e,t||"post").values},remove:null,addClass:null,removeClass:null,toggleClass:null,takeClass:null,swap:null,defineExtension:null,removeExtension:null,logAll:null,logNone:null,logger:null,config:{historyEnabled:!0,historyCacheSize:10,refreshOnHistoryMiss:!1,defaultSwapStyle:"innerHTML",defaultSwapDelay:0,defaultSettleDelay:20,includeIndicatorStyles:!0,indicatorClass:"htmx-indicator",requestClass:"htmx-request",addedClass:"htmx-added",settlingClass:"htmx-settling",swappingClass:"htmx-swapping",allowEval:!0,allowScriptTags:!0,inlineScriptNonce:"",inlineStyleNonce:"",attributesToSettle:["class","style","width","height"],withCredentials:!1,timeout:0,wsReconnectDelay:"full-jitter",wsBinaryType:"blob",disableSelector:"[hx-disable], [data-hx-disable]",scrollBehavior:"instant",defaultFocusScroll:!1,getCacheBusterParam:!1,globalViewTransitions:!1,methodsThatUseUrlParams:["get","delete"],selfRequestsOnly:!0,ignoreTitle:!1,scrollIntoViewOnBoost:!0,triggerSpecsCache:null,disableInheritance:!1,responseHandling:[{code:"204",swap:!1},{code:"[23]..",swap:!0},{code:"[45]..",swap:!1,error:!0}],allowNestedOobSwaps:!0,historyRestoreAsHxRequest:!0,reportValidityOfForms:!1},parseInterval:null,location,_:null,version:"2.0.8"};htmx.onLoad=onLoadHelper,htmx.process=processNode,htmx.on=addEventListenerImpl,htmx.off=removeEventListenerImpl,htmx.trigger=triggerEvent,htmx.ajax=ajaxHelper,htmx.find=find,htmx.findAll=findAll,htmx.closest=closest,htmx.remove=removeElement,htmx.addClass=addClassToElement,htmx.removeClass=removeClassFromElement,htmx.toggleClass=toggleClassOnElement,htmx.takeClass=takeClassForElement,htmx.swap=swap,htmx.defineExtension=defineExtension,htmx.removeExtension=removeExtension,htmx.logAll=logAll,htmx.logNone=logNone,htmx.parseInterval=parseInterval,htmx._=internalEval;let internalAPI={addTriggerHandler,bodyContains,canAccessLocalStorage,findThisElement,filterValues,swap,hasAttribute,getAttributeValue,getClosestAttributeValue,getClosestMatch,getExpressionVars,getHeaders,getInputValues,getInternalData,getSwapSpecification,getTriggerSpecs,getTarget,makeFragment,mergeObjects,makeSettleInfo,oobSwap,querySelectorExt,settleImmediately,shouldCancel,triggerEvent,triggerErrorEvent,withExtensions},VERBS=["get","post","put","delete","patch"],VERB_SELECTOR=VERBS.map(function(e){return"[hx-"+e+"], [data-hx-"+e+"]"}).join(", ");function parseInterval(e){if(e==null)return;let t=NaN;return e.slice(-2)=="ms"?t=parseFloat(e.slice(0,-2)):e.slice(-1)=="s"?t=parseFloat(e.slice(0,-1))*1e3:e.slice(-1)=="m"?t=parseFloat(e.slice(0,-1))*1e3*60:t=parseFloat(e),isNaN(t)?void 0:t}function getRawAttribute(e,t){return e instanceof Element&&e.getAttribute(t)}function hasAttribute(e,t){return!!e.hasAttribute&&(e.hasAttribute(t)||e.hasAttribute("data-"+t))}function getAttributeValue(e,t){return getRawAttribute(e,t)||getRawAttribute(e,"data-"+t)}function parentElt(e){let t=e.parentElement;return!t&&e.parentNode instanceof ShadowRoot?e.parentNode:t}function getDocument(){return document}function getRootNode(e,t){return e.getRootNode?e.getRootNode({composed:t}):getDocument()}function getClosestMatch(e,t){for(;e&&!t(e);)e=parentElt(e);return e||null}function getAttributeValueWithDisinheritance(e,t,n){let r=getAttributeValue(t,n),o=getAttributeValue(t,"hx-disinherit");var s=getAttributeValue(t,"hx-inherit");if(e!==t){if(htmx.config.disableInheritance)return s&&(s==="*"||s.split(" ").indexOf(n)>=0)?r:null;if(o&&(o==="*"||o.split(" ").indexOf(n)>=0))return"unset"}return r}function getClosestAttributeValue(e,t){let n=null;if(getClosestMatch(e,function(r){return!!(n=getAttributeValueWithDisinheritance(e,asElement(r),t))}),n!=="unset")return n}function matches(e,t){return e instanceof Element&&e.matches(t)}function getStartTag(e){let n=/<([a-z][^\/\0>\x20\t\r\n\f]*)/i.exec(e);return n?n[1].toLowerCase():""}function parseHTML(e){return"parseHTMLUnsafe"in Document?Document.parseHTMLUnsafe(e):new DOMParser().parseFromString(e,"text/html")}function takeChildrenFor(e,t){for(;t.childNodes.length>0;)e.append(t.childNodes[0])}function duplicateScript(e){let t=getDocument().createElement("script");return forEach(e.attributes,function(n){t.setAttribute(n.name,n.value)}),t.textContent=e.textContent,t.async=!1,htmx.config.inlineScriptNonce&&(t.nonce=htmx.config.inlineScriptNonce),t}function isJavaScriptScriptNode(e){return e.matches("script")&&(e.type==="text/javascript"||e.type==="module"||e.type==="")}function normalizeScriptTags(e){Array.from(e.querySelectorAll("script")).forEach(t=>{if(isJavaScriptScriptNode(t)){let n=duplicateScript(t),r=t.parentNode;try{r.insertBefore(n,t)}catch(o){logError(o)}finally{t.remove()}}})}function makeFragment(e){let t=e.replace(/
]*)?>[\s\S]*?<\/head>/i,""),n=getStartTag(t),r;if(n==="html"){r=new DocumentFragment;let s=parseHTML(e);takeChildrenFor(r,s.body),r.title=s.title}else if(n==="body"){r=new DocumentFragment;let s=parseHTML(t);takeChildrenFor(r,s.body),r.title=s.title}else{let s=parseHTML(''+t+" ");r=s.querySelector("template").content,r.title=s.title;var o=r.querySelector("title");o&&o.parentNode===r&&(o.remove(),r.title=o.innerText)}return r&&(htmx.config.allowScriptTags?normalizeScriptTags(r):r.querySelectorAll("script").forEach(s=>s.remove())),r}function maybeCall(e){e&&e()}function isType(e,t){return Object.prototype.toString.call(e)==="[object "+t+"]"}function isFunction(e){return typeof e=="function"}function isRawObject(e){return isType(e,"Object")}function getInternalData(e){let t="htmx-internal-data",n=e[t];return n||(n=e[t]={}),n}function toArray(e){let t=[];if(e)for(let n=0;n=0}function bodyContains(e){return e.getRootNode({composed:!0})===document}function splitOnWhitespace(e){return e.trim().split(/\s+/)}function mergeObjects(e,t){for(let n in t)t.hasOwnProperty(n)&&(e[n]=t[n]);return e}function parseJSON(e){try{return JSON.parse(e)}catch(t){return logError(t),null}}function canAccessLocalStorage(){let e="htmx:sessionStorageTest";try{return sessionStorage.setItem(e,e),sessionStorage.removeItem(e),!0}catch{return!1}}function normalizePath(e){let t=new URL(e,"http://x");return t&&(e=t.pathname+t.search),e!="/"&&(e=e.replace(/\/+$/,"")),e}function internalEval(str){return maybeEval(getDocument().body,function(){return eval(str)})}function onLoadHelper(e){return htmx.on("htmx:load",function(n){e(n.detail.elt)})}function logAll(){htmx.logger=function(e,t,n){console&&console.log(t,e,n)}}function logNone(){htmx.logger=null}function find(e,t){return typeof e!="string"?e.querySelector(t):find(getDocument(),e)}function findAll(e,t){return typeof e!="string"?e.querySelectorAll(t):findAll(getDocument(),e)}function getWindow(){return window}function removeElement(e,t){e=resolveTarget(e),t?getWindow().setTimeout(function(){removeElement(e),e=null},t):parentElt(e).removeChild(e)}function asElement(e){return e instanceof Element?e:null}function asHtmlElement(e){return e instanceof HTMLElement?e:null}function asString(e){return typeof e=="string"?e:null}function asParentNode(e){return e instanceof Element||e instanceof Document||e instanceof DocumentFragment?e:null}function addClassToElement(e,t,n){e=asElement(resolveTarget(e)),e&&(n?getWindow().setTimeout(function(){addClassToElement(e,t),e=null},n):e.classList&&e.classList.add(t))}function removeClassFromElement(e,t,n){let r=asElement(resolveTarget(e));r&&(n?getWindow().setTimeout(function(){removeClassFromElement(r,t),r=null},n):r.classList&&(r.classList.remove(t),r.classList.length===0&&r.removeAttribute("class")))}function toggleClassOnElement(e,t){e=resolveTarget(e),e.classList.toggle(t)}function takeClassForElement(e,t){e=resolveTarget(e),forEach(e.parentElement.children,function(n){removeClassFromElement(n,t)}),addClassToElement(asElement(e),t)}function closest(e,t){return e=asElement(resolveTarget(e)),e?e.closest(t):null}function startsWith(e,t){return e.substring(0,t.length)===t}function endsWith(e,t){return e.substring(e.length-t.length)===t}function normalizeSelector(e){let t=e.trim();return startsWith(t,"<")&&endsWith(t,"/>")?t.substring(1,t.length-2):t}function querySelectorAllExt(e,t,n){if(t.indexOf("global ")===0)return querySelectorAllExt(e,t.slice(7),!0);e=resolveTarget(e);let r=[];{let i=0,a=0;for(let l=0;l"&&i--}a0;){let i=normalizeSelector(r.shift()),a;i.indexOf("closest ")===0?a=closest(asElement(e),normalizeSelector(i.slice(8))):i.indexOf("find ")===0?a=find(asParentNode(e),normalizeSelector(i.slice(5))):i==="next"||i==="nextElementSibling"?a=asElement(e).nextElementSibling:i.indexOf("next ")===0?a=scanForwardQuery(e,normalizeSelector(i.slice(5)),!!n):i==="previous"||i==="previousElementSibling"?a=asElement(e).previousElementSibling:i.indexOf("previous ")===0?a=scanBackwardsQuery(e,normalizeSelector(i.slice(9)),!!n):i==="document"?a=document:i==="window"?a=window:i==="body"?a=document.body:i==="root"?a=getRootNode(e,!!n):i==="host"?a=e.getRootNode().host:s.push(i),a&&o.push(a)}if(s.length>0){let i=s.join(","),a=asParentNode(getRootNode(e,!!n));o.push(...toArray(a.querySelectorAll(i)))}return o}var scanForwardQuery=function(e,t,n){let r=asParentNode(getRootNode(e,n)).querySelectorAll(t);for(let o=0;o=0;o--){let s=r[o];if(s.compareDocumentPosition(e)===Node.DOCUMENT_POSITION_FOLLOWING)return s}};function querySelectorExt(e,t){return typeof e!="string"?querySelectorAllExt(e,t)[0]:querySelectorAllExt(getDocument().body,e)[0]}function resolveTarget(e,t){return typeof e=="string"?find(asParentNode(t)||document,e):e}function processEventArgs(e,t,n,r){return isFunction(t)?{target:getDocument().body,event:asString(e),listener:t,options:n}:{target:resolveTarget(e),event:asString(t),listener:n,options:r}}function addEventListenerImpl(e,t,n,r){return ready(function(){let s=processEventArgs(e,t,n,r);s.target.addEventListener(s.event,s.listener,s.options)}),isFunction(t)?t:n}function removeEventListenerImpl(e,t,n){return ready(function(){let r=processEventArgs(e,t,n);r.target.removeEventListener(r.event,r.listener)}),isFunction(t)?t:n}let DUMMY_ELT=getDocument().createElement("output");function findAttributeTargets(e,t){let n=getClosestAttributeValue(e,t);if(n){if(n==="this")return[findThisElement(e,t)];{let r=querySelectorAllExt(e,n);if(/(^|,)(\s*)inherit(\s*)($|,)/.test(n)){let s=asElement(getClosestMatch(e,function(i){return i!==e&&hasAttribute(asElement(i),t)}));s&&r.push(...findAttributeTargets(s,t))}return r.length===0?(logError('The selector "'+n+'" on '+t+" returned no matches!"),[DUMMY_ELT]):r}}}function findThisElement(e,t){return asElement(getClosestMatch(e,function(n){return getAttributeValue(asElement(n),t)!=null}))}function getTarget(e){let t=getClosestAttributeValue(e,"hx-target");return t?t==="this"?findThisElement(e,"hx-target"):querySelectorExt(e,t):getInternalData(e).boosted?getDocument().body:e}function shouldSettleAttribute(e){return htmx.config.attributesToSettle.includes(e)}function cloneAttributes(e,t){forEach(Array.from(e.attributes),function(n){!t.hasAttribute(n.name)&&shouldSettleAttribute(n.name)&&e.removeAttribute(n.name)}),forEach(t.attributes,function(n){shouldSettleAttribute(n.name)&&e.setAttribute(n.name,n.value)})}function isInlineSwap(e,t){let n=getExtensions(t);for(let r=0;r0?(s=e.substring(0,e.indexOf(":")),o=e.substring(e.indexOf(":")+1)):s=e),t.removeAttribute("hx-swap-oob"),t.removeAttribute("data-hx-swap-oob");let i=querySelectorAllExt(r,o,!1);return i.length?(forEach(i,function(a){let l,c=t.cloneNode(!0);l=getDocument().createDocumentFragment(),l.appendChild(c),isInlineSwap(s,a)||(l=asParentNode(c));let d={shouldSwap:!0,target:a,fragment:l};triggerEvent(a,"htmx:oobBeforeSwap",d)&&(a=d.target,d.shouldSwap&&(handlePreservedElements(l),swapWithStyle(s,a,a,l,n),restorePreservedElements()),forEach(n.elts,function(u){triggerEvent(u,"htmx:oobAfterSwap",d)}))}),t.parentNode.removeChild(t)):(t.parentNode.removeChild(t),triggerErrorEvent(getDocument().body,"htmx:oobErrorNoTarget",{content:t})),e}function restorePreservedElements(){let e=find("#--htmx-preserve-pantry--");if(e){for(let t of[...e.children]){let n=find("#"+t.id);n.parentNode.moveBefore(t,n),n.remove()}e.remove()}}function handlePreservedElements(e){forEach(findAll(e,"[hx-preserve], [data-hx-preserve]"),function(t){let n=getAttributeValue(t,"id"),r=getDocument().getElementById(n);if(r!=null)if(t.moveBefore){let o=find("#--htmx-preserve-pantry--");o==null&&(getDocument().body.insertAdjacentHTML("afterend","
"),o=find("#--htmx-preserve-pantry--")),o.moveBefore(r,null)}else t.parentNode.replaceChild(r,t)})}function handleAttributes(e,t,n){forEach(t.querySelectorAll("[id]"),function(r){let o=getRawAttribute(r,"id");if(o&&o.length>0){let s=o.replace("'","\\'"),i=r.tagName.replace(":","\\:"),a=asParentNode(e),l=a&&a.querySelector(i+"[id='"+s+"']");if(l&&l!==a){let c=r.cloneNode();cloneAttributes(r,l),n.tasks.push(function(){cloneAttributes(r,c)})}}})}function makeAjaxLoadTask(e){return function(){removeClassFromElement(e,htmx.config.addedClass),processNode(asElement(e)),processFocus(asParentNode(e)),triggerEvent(e,"htmx:load")}}function processFocus(e){let t="[autofocus]",n=asHtmlElement(matches(e,t)?e:e.querySelector(t));n?.focus()}function insertNodesBefore(e,t,n,r){for(handleAttributes(e,n,r);n.childNodes.length>0;){let o=n.firstChild;addClassToElement(asElement(o),htmx.config.addedClass),e.insertBefore(o,t),o.nodeType!==Node.TEXT_NODE&&o.nodeType!==Node.COMMENT_NODE&&r.tasks.push(makeAjaxLoadTask(o))}}function stringHash(e,t){let n=0;for(;n0}function swap(e,t,n,r){r||(r={});let o=null,s=null,i=function(){maybeCall(r.beforeSwapCallback),e=resolveTarget(e);let c=r.contextElement?getRootNode(r.contextElement,!1):getDocument(),d=document.activeElement,u={};u={elt:d,start:d?d.selectionStart:null,end:d?d.selectionEnd:null};let f=makeSettleInfo(e);if(n.swapStyle==="textContent")e.textContent=t;else{let h=makeFragment(t);if(f.title=r.title||h.title,r.historyRequest&&(h=h.querySelector("[hx-history-elt],[data-hx-history-elt]")||h),r.selectOOB){let p=r.selectOOB.split(",");for(let g=0;g0?getWindow().setTimeout(y,n.settleDelay):y()},a=htmx.config.globalViewTransitions;n.hasOwnProperty("transition")&&(a=n.transition);let l=r.contextElement||getDocument();if(a&&triggerEvent(l,"htmx:beforeTransition",r.eventInfo)&&typeof Promise<"u"&&document.startViewTransition){let c=new Promise(function(u,f){o=u,s=f}),d=i;i=function(){document.startViewTransition(function(){return d(),c})}}try{n?.swapDelay&&n.swapDelay>0?getWindow().setTimeout(i,n.swapDelay):i()}catch(c){throw triggerErrorEvent(l,"htmx:swapError",r.eventInfo),maybeCall(s),c}}function handleTriggerHeader(e,t,n){let r=e.getResponseHeader(t);if(r.indexOf("{")===0){let o=parseJSON(r);for(let s in o)if(o.hasOwnProperty(s)){let i=o[s];isRawObject(i)?n=i.target!==void 0?i.target:n:i={value:i},triggerEvent(n,s,i)}}else{let o=r.split(",");for(let s=0;s0;){let i=t[0];if(i==="]"){if(r--,r===0){s===null&&(o=o+"true"),t.shift(),o+=")})";try{let a=maybeEval(e,function(){return Function(o)()},function(){return!0});return a.source=o,a}catch(a){return triggerErrorEvent(getDocument().body,"htmx:syntax:error",{error:a,source:o}),null}}}else i==="["&&r++;isPossibleRelativeReference(i,s,n)?o+="(("+n+"."+i+") ? ("+n+"."+i+") : (window."+i+"))":o=o+i,s=t.shift()}}}function consumeUntil(e,t){let n="";for(;e.length>0&&!t.test(e[0]);)n+=e.shift();return n}function consumeCSSSelector(e){let t;return e.length>0&&COMBINED_SELECTOR_START.test(e[0])?(e.shift(),t=consumeUntil(e,COMBINED_SELECTOR_END).trim(),e.shift()):t=consumeUntil(e,WHITESPACE_OR_COMMA),t}let INPUT_SELECTOR="input, textarea, select";function parseAndCacheTrigger(e,t,n){let r=[],o=tokenizeString(t);do{consumeUntil(o,NOT_WHITESPACE);let a=o.length,l=consumeUntil(o,/[,\[\s]/);if(l!=="")if(l==="every"){let c={trigger:"every"};consumeUntil(o,NOT_WHITESPACE),c.pollInterval=parseInterval(consumeUntil(o,/[,\[\s]/)),consumeUntil(o,NOT_WHITESPACE);var s=maybeGenerateConditional(e,o,"event");s&&(c.eventFilter=s),r.push(c)}else{let c={trigger:l};var s=maybeGenerateConditional(e,o,"event");for(s&&(c.eventFilter=s),consumeUntil(o,NOT_WHITESPACE);o.length>0&&o[0]!==",";){let u=o.shift();if(u==="changed")c.changed=!0;else if(u==="once")c.once=!0;else if(u==="consume")c.consume=!0;else if(u==="delay"&&o[0]===":")o.shift(),c.delay=parseInterval(consumeUntil(o,WHITESPACE_OR_COMMA));else if(u==="from"&&o[0]===":"){if(o.shift(),COMBINED_SELECTOR_START.test(o[0]))var i=consumeCSSSelector(o);else{var i=consumeUntil(o,WHITESPACE_OR_COMMA);if(i==="closest"||i==="find"||i==="next"||i==="previous"){o.shift();let y=consumeCSSSelector(o);y.length>0&&(i+=" "+y)}}c.from=i}else u==="target"&&o[0]===":"?(o.shift(),c.target=consumeCSSSelector(o)):u==="throttle"&&o[0]===":"?(o.shift(),c.throttle=parseInterval(consumeUntil(o,WHITESPACE_OR_COMMA))):u==="queue"&&o[0]===":"?(o.shift(),c.queue=consumeUntil(o,WHITESPACE_OR_COMMA)):u==="root"&&o[0]===":"?(o.shift(),c[u]=consumeCSSSelector(o)):u==="threshold"&&o[0]===":"?(o.shift(),c[u]=consumeUntil(o,WHITESPACE_OR_COMMA)):triggerErrorEvent(e,"htmx:syntax:error",{token:o.shift()});consumeUntil(o,NOT_WHITESPACE)}r.push(c)}o.length===a&&triggerErrorEvent(e,"htmx:syntax:error",{token:o.shift()}),consumeUntil(o,NOT_WHITESPACE)}while(o[0]===","&&o.shift());return n&&(n[t]=r),r}function getTriggerSpecs(e){let t=getAttributeValue(e,"hx-trigger"),n=[];if(t){let r=htmx.config.triggerSpecsCache;n=r&&r[t]||parseAndCacheTrigger(e,t,r)}return n.length>0?n:matches(e,"form")?[{trigger:"submit"}]:matches(e,'input[type="button"], input[type="submit"]')?[{trigger:"click"}]:matches(e,INPUT_SELECTOR)?[{trigger:"change"}]:[{trigger:"click"}]}function cancelPolling(e){getInternalData(e).cancelled=!0}function processPolling(e,t,n){let r=getInternalData(e);r.timeout=getWindow().setTimeout(function(){bodyContains(e)&&r.cancelled!==!0&&(maybeFilterEvent(n,e,makeEvent("hx:poll:trigger",{triggerSpec:n,target:e}))||t(e),processPolling(e,t,n))},n.pollInterval)}function isLocalLink(e){return location.hostname===e.hostname&&getRawAttribute(e,"href")&&getRawAttribute(e,"href").indexOf("#")!==0}function eltIsDisabled(e){return closest(e,htmx.config.disableSelector)}function boostElement(e,t,n){if(e instanceof HTMLAnchorElement&&isLocalLink(e)&&(e.target===""||e.target==="_self")||e.tagName==="FORM"&&String(getRawAttribute(e,"method")).toLowerCase()!=="dialog"){t.boosted=!0;let r,o;if(e.tagName==="A")r="get",o=getRawAttribute(e,"href");else{let s=getRawAttribute(e,"method");r=s?s.toLowerCase():"get",o=getRawAttribute(e,"action"),(o==null||o==="")&&(o=location.href),r==="get"&&o.includes("?")&&(o=o.replace(/\?[^#]+/,""))}n.forEach(function(s){addEventListener(e,function(i,a){let l=asElement(i);if(eltIsDisabled(l)){cleanUpElement(l);return}issueAjaxRequest(r,o,l,a)},t,s,!0)})}}function shouldCancel(e,t){if(e.type==="submit"&&t.tagName==="FORM")return!0;if(e.type==="click"){let n=t.closest('input[type="submit"], button');if(n&&n.form&&n.type==="submit")return!0;let r=t.closest("a"),o=/^#.+/;if(r&&r.href&&!o.test(r.getAttribute("href")))return!0}return!1}function ignoreBoostedAnchorCtrlClick(e,t){return getInternalData(e).boosted&&e instanceof HTMLAnchorElement&&t.type==="click"&&(t.ctrlKey||t.metaKey)}function maybeFilterEvent(e,t,n){let r=e.eventFilter;if(r)try{return r.call(t,n)!==!0}catch(o){let s=r.source;return triggerErrorEvent(getDocument().body,"htmx:eventFilter:error",{error:o,source:s}),!0}return!1}function addEventListener(e,t,n,r,o){let s=getInternalData(e),i;r.from?i=querySelectorAllExt(e,r.from):i=[e],r.changed&&("lastValue"in s||(s.lastValue=new WeakMap),i.forEach(function(a){s.lastValue.has(r)||s.lastValue.set(r,new WeakMap),s.lastValue.get(r).set(a,a.value)})),forEach(i,function(a){let l=function(c){if(!bodyContains(e)){a.removeEventListener(r.trigger,l);return}if(ignoreBoostedAnchorCtrlClick(e,c)||((o||shouldCancel(c,a))&&c.preventDefault(),maybeFilterEvent(r,e,c)))return;let d=getInternalData(c);if(d.triggerSpec=r,d.handledFor==null&&(d.handledFor=[]),d.handledFor.indexOf(e)<0){if(d.handledFor.push(e),r.consume&&c.stopPropagation(),r.target&&c.target&&!matches(asElement(c.target),r.target))return;if(r.once){if(s.triggeredOnce)return;s.triggeredOnce=!0}if(r.changed){let u=c.target,f=u.value,y=s.lastValue.get(r);if(y.has(u)&&y.get(u)===f)return;y.set(u,f)}if(s.delayed&&clearTimeout(s.delayed),s.throttle)return;r.throttle>0?s.throttle||(triggerEvent(e,"htmx:trigger"),t(e,c),s.throttle=getWindow().setTimeout(function(){s.throttle=null},r.throttle)):r.delay>0?s.delayed=getWindow().setTimeout(function(){triggerEvent(e,"htmx:trigger"),t(e,c)},r.delay):(triggerEvent(e,"htmx:trigger"),t(e,c))}};n.listenerInfos==null&&(n.listenerInfos=[]),n.listenerInfos.push({trigger:r.trigger,listener:l,on:a}),a.addEventListener(r.trigger,l)})}let windowIsScrolling=!1,scrollHandler=null;function initScrollHandler(){scrollHandler||(scrollHandler=function(){windowIsScrolling=!0},window.addEventListener("scroll",scrollHandler),window.addEventListener("resize",scrollHandler),setInterval(function(){windowIsScrolling&&(windowIsScrolling=!1,forEach(getDocument().querySelectorAll("[hx-trigger*='revealed'],[data-hx-trigger*='revealed']"),function(e){maybeReveal(e)}))},200))}function maybeReveal(e){!hasAttribute(e,"data-hx-revealed")&&isScrolledIntoView(e)&&(e.setAttribute("data-hx-revealed","true"),getInternalData(e).initHash?triggerEvent(e,"revealed"):e.addEventListener("htmx:afterProcessNode",function(){triggerEvent(e,"revealed")},{once:!0}))}function loadImmediately(e,t,n,r){let o=function(){n.loaded||(n.loaded=!0,triggerEvent(e,"htmx:trigger"),t(e))};r>0?getWindow().setTimeout(o,r):o()}function processVerbs(e,t,n){let r=!1;return forEach(VERBS,function(o){if(hasAttribute(e,"hx-"+o)){let s=getAttributeValue(e,"hx-"+o);r=!0,t.path=s,t.verb=o,n.forEach(function(i){addTriggerHandler(e,i,t,function(a,l){let c=asElement(a);if(eltIsDisabled(c)){cleanUpElement(c);return}issueAjaxRequest(o,s,c,l)})})}}),r}function addTriggerHandler(e,t,n,r){if(t.trigger==="revealed")initScrollHandler(),addEventListener(e,r,n,t),maybeReveal(asElement(e));else if(t.trigger==="intersect"){let o={};t.root&&(o.root=querySelectorExt(e,t.root)),t.threshold&&(o.threshold=parseFloat(t.threshold)),new IntersectionObserver(function(i){for(let a=0;a0?(n.polling=!0,processPolling(asElement(e),r,t)):addEventListener(e,r,n,t)}function shouldProcessHxOn(e){let t=asElement(e);if(!t)return!1;let n=t.attributes;for(let r=0;r", "+s).join(""))}else return[]}function maybeSetLastButtonClicked(e){let t=getTargetButton(e.target),n=getRelatedFormData(e);n&&(n.lastButtonClicked=t)}function maybeUnsetLastButtonClicked(e){let t=getRelatedFormData(e);t&&(t.lastButtonClicked=null)}function getTargetButton(e){return closest(asElement(e),"button, input[type='submit']")}function getRelatedForm(e){return e.form||closest(e,"form")}function getRelatedFormData(e){let t=getTargetButton(e.target);if(!t)return;let n=getRelatedForm(t);if(n)return getInternalData(n)}function initButtonTracking(e){e.addEventListener("click",maybeSetLastButtonClicked),e.addEventListener("focusin",maybeSetLastButtonClicked),e.addEventListener("focusout",maybeUnsetLastButtonClicked)}function addHxOnEventHandler(e,t,n){let r=getInternalData(e);Array.isArray(r.onHandlers)||(r.onHandlers=[]);let o,s=function(i){maybeEval(e,function(){eltIsDisabled(e)||(o||(o=new Function("event",n)),o.call(e,i))})};e.addEventListener(t,s),r.onHandlers.push({event:t,listener:s})}function processHxOnWildcard(e){deInitOnHandlers(e);for(let t=0;thtmx.config.historyCacheSize;)s.shift();for(;s.length>0;)try{sessionStorage.setItem("htmx-history-cache",JSON.stringify(s));break}catch(a){triggerErrorEvent(getDocument().body,"htmx:historyCacheError",{cause:a,cache:s}),s.shift()}}function getCachedHistory(e){if(!canAccessLocalStorage())return null;e=normalizePath(e);let t=parseJSON(sessionStorage.getItem("htmx-history-cache"))||[];for(let n=0;n=200&&this.status<400?(r.response=this.response,triggerEvent(getDocument().body,"htmx:historyCacheMissLoad",r),swap(r.historyElt,r.response,n,{contextElement:r.historyElt,historyRequest:!0}),setCurrentPathForHistory(r.path),triggerEvent(getDocument().body,"htmx:historyRestore",{path:e,cacheMiss:!0,serverResponse:r.response})):triggerErrorEvent(getDocument().body,"htmx:historyCacheMissLoadError",r)},triggerEvent(getDocument().body,"htmx:historyCacheMiss",r)&&t.send()}function restoreHistory(e){saveCurrentPageToHistory(),e=e||location.pathname+location.search;let t=getCachedHistory(e);if(t){let n={swapStyle:"innerHTML",swapDelay:0,settleDelay:0,scroll:t.scroll},r={path:e,item:t,historyElt:getHistoryElement(),swapSpec:n};triggerEvent(getDocument().body,"htmx:historyCacheHit",r)&&(swap(r.historyElt,t.content,n,{contextElement:r.historyElt,title:t.title}),setCurrentPathForHistory(r.path),triggerEvent(getDocument().body,"htmx:historyRestore",r))}else htmx.config.refreshOnHistoryMiss?htmx.location.reload(!0):loadHistoryFromServer(e)}function addRequestIndicatorClasses(e){let t=findAttributeTargets(e,"hx-indicator");return t==null&&(t=[e]),forEach(t,function(n){let r=getInternalData(n);r.requestCount=(r.requestCount||0)+1,n.classList.add.call(n.classList,htmx.config.requestClass)}),t}function disableElements(e){let t=findAttributeTargets(e,"hx-disabled-elt");return t==null&&(t=[]),forEach(t,function(n){let r=getInternalData(n);r.requestCount=(r.requestCount||0)+1,n.setAttribute("disabled",""),n.setAttribute("data-disabled-by-htmx","")}),t}function removeRequestIndicators(e,t){forEach(e.concat(t),function(n){let r=getInternalData(n);r.requestCount=(r.requestCount||1)-1}),forEach(e,function(n){getInternalData(n).requestCount===0&&n.classList.remove.call(n.classList,htmx.config.requestClass)}),forEach(t,function(n){getInternalData(n).requestCount===0&&(n.removeAttribute("disabled"),n.removeAttribute("data-disabled-by-htmx"))})}function haveSeenNode(e,t){for(let n=0;nt.indexOf(o)<0):r=r.filter(o=>o!==t),n.delete(e),forEach(r,o=>n.append(e,o))}}function getValueFromInput(e){return e instanceof HTMLSelectElement&&e.multiple?toArray(e.querySelectorAll("option:checked")).map(function(t){return t.value}):e instanceof HTMLInputElement&&e.files?toArray(e.files):e.value}function processInputValue(e,t,n,r,o){if(!(r==null||haveSeenNode(e,r))){if(e.push(r),shouldInclude(r)){let s=getRawAttribute(r,"name");addValueToFormData(s,getValueFromInput(r),t),o&&validateElement(r,n)}r instanceof HTMLFormElement&&(forEach(r.elements,function(s){e.indexOf(s)>=0?removeValueFromFormData(s.name,getValueFromInput(s),t):e.push(s),o&&validateElement(s,n)}),new FormData(r).forEach(function(s,i){s instanceof File&&s.name===""||addValueToFormData(i,s,t)}))}}function validateElement(e,t){let n=e;n.willValidate&&(triggerEvent(n,"htmx:validation:validate"),n.checkValidity()||(triggerEvent(n,"htmx:validation:failed",{message:n.validationMessage,validity:n.validity})&&!t.length&&htmx.config.reportValidityOfForms&&n.reportValidity(),t.push({elt:n,message:n.validationMessage,validity:n.validity})))}function overrideFormData(e,t){for(let n of t.keys())e.delete(n);return t.forEach(function(n,r){e.append(r,n)}),e}function getInputValues(e,t){let n=[],r=new FormData,o=new FormData,s=[],i=getInternalData(e);i.lastButtonClicked&&!bodyContains(i.lastButtonClicked)&&(i.lastButtonClicked=null);let a=e instanceof HTMLFormElement&&e.noValidate!==!0||getAttributeValue(e,"hx-validate")==="true";if(i.lastButtonClicked&&(a=a&&i.lastButtonClicked.formNoValidate!==!0),t!=="get"&&processInputValue(n,o,s,getRelatedForm(e),a),processInputValue(n,r,s,e,a),i.lastButtonClicked||e.tagName==="BUTTON"||e.tagName==="INPUT"&&getRawAttribute(e,"type")==="submit"){let c=i.lastButtonClicked||e,d=getRawAttribute(c,"name");addValueToFormData(d,c.value,o)}let l=findAttributeTargets(e,"hx-include");return forEach(l,function(c){processInputValue(n,r,s,asElement(c),a),matches(c,"form")||forEach(asParentNode(c).querySelectorAll(INPUT_SELECTOR),function(d){processInputValue(n,r,s,d,a)})}),overrideFormData(r,o),{errors:s,formData:r,values:formDataProxy(r)}}function appendParam(e,t,n){e!==""&&(e+="&"),String(n)==="[object Object]"&&(n=JSON.stringify(n));let r=encodeURIComponent(n);return e+=encodeURIComponent(t)+"="+r,e}function urlEncode(e){e=formDataFromObject(e);let t="";return e.forEach(function(n,r){t=appendParam(t,r,n)}),t}function getHeaders(e,t,n){let r={"HX-Request":"true","HX-Trigger":getRawAttribute(e,"id"),"HX-Trigger-Name":getRawAttribute(e,"name"),"HX-Target":getAttributeValue(t,"id"),"HX-Current-URL":location.href};return getValuesForElement(e,"hx-headers",!1,r),n!==void 0&&(r["HX-Prompt"]=n),getInternalData(e).boosted&&(r["HX-Boosted"]="true"),r}function filterValues(e,t){let n=getClosestAttributeValue(t,"hx-params");if(n){if(n==="none")return new FormData;if(n==="*")return e;if(n.indexOf("not ")===0)return forEach(n.slice(4).split(","),function(r){r=r.trim(),e.delete(r)}),e;{let r=new FormData;return forEach(n.split(","),function(o){o=o.trim(),e.has(o)&&e.getAll(o).forEach(function(s){r.append(o,s)})}),r}}else return e}function isAnchorLink(e){return!!getRawAttribute(e,"href")&&getRawAttribute(e,"href").indexOf("#")>=0}function getSwapSpecification(e,t){let n=t||getClosestAttributeValue(e,"hx-swap"),r={swapStyle:getInternalData(e).boosted?"innerHTML":htmx.config.defaultSwapStyle,swapDelay:htmx.config.defaultSwapDelay,settleDelay:htmx.config.defaultSettleDelay};if(htmx.config.scrollIntoViewOnBoost&&getInternalData(e).boosted&&!isAnchorLink(e)&&(r.show="top"),n){let i=splitOnWhitespace(n);if(i.length>0)for(let a=0;a0?o.join(":"):null;r.scroll=d,r.scrollTarget=s}else if(l.indexOf("show:")===0){var o=l.slice(5).split(":");let u=o.pop();var s=o.length>0?o.join(":"):null;r.show=u,r.showTarget=s}else if(l.indexOf("focus-scroll:")===0){let c=l.slice(13);r.focusScroll=c=="true"}else a==0?r.swapStyle=l:logError("Unknown modifier in hx-swap: "+l)}}return r}function usesFormData(e){return getClosestAttributeValue(e,"hx-encoding")==="multipart/form-data"||matches(e,"form")&&getRawAttribute(e,"enctype")==="multipart/form-data"}function encodeParamsForBody(e,t,n){let r=null;return withExtensions(t,function(o){r==null&&(r=o.encodeParameters(e,n,t))}),r??(usesFormData(t)?overrideFormData(new FormData,formDataFromObject(n)):urlEncode(n))}function makeSettleInfo(e){return{tasks:[],elts:[e]}}function updateScrollState(e,t){let n=e[0],r=e[e.length-1];if(t.scroll){var o=null;t.scrollTarget&&(o=asElement(querySelectorExt(n,t.scrollTarget))),t.scroll==="top"&&(n||o)&&(o=o||n,o.scrollTop=0),t.scroll==="bottom"&&(r||o)&&(o=o||r,o.scrollTop=o.scrollHeight),typeof t.scroll=="number"&&getWindow().setTimeout(function(){window.scrollTo(0,t.scroll)},0)}if(t.show){var o=null;if(t.showTarget){let i=t.showTarget;t.showTarget==="window"&&(i="body"),o=asElement(querySelectorExt(n,i))}t.show==="top"&&(n||o)&&(o=o||n,o.scrollIntoView({block:"start",behavior:htmx.config.scrollBehavior})),t.show==="bottom"&&(r||o)&&(o=o||r,o.scrollIntoView({block:"end",behavior:htmx.config.scrollBehavior}))}}function getValuesForElement(e,t,n,r,o){if(r==null&&(r={}),e==null)return r;let s=getAttributeValue(e,t);if(s){let i=s.trim(),a=n;if(i==="unset")return null;i.indexOf("javascript:")===0?(i=i.slice(11),a=!0):i.indexOf("js:")===0&&(i=i.slice(3),a=!0),i.indexOf("{")!==0&&(i="{"+i+"}");let l;a?l=maybeEval(e,function(){return o?Function("event","return ("+i+")").call(e,o):Function("return ("+i+")").call(e)},{}):l=parseJSON(i);for(let c in l)l.hasOwnProperty(c)&&r[c]==null&&(r[c]=l[c])}return getValuesForElement(asElement(parentElt(e)),t,n,r,o)}function maybeEval(e,t,n){return htmx.config.allowEval?t():(triggerErrorEvent(e,"htmx:evalDisallowedError"),n)}function getHXVarsForElement(e,t,n){return getValuesForElement(e,"hx-vars",!0,n,t)}function getHXValsForElement(e,t,n){return getValuesForElement(e,"hx-vals",!1,n,t)}function getExpressionVars(e,t){return mergeObjects(getHXVarsForElement(e,t),getHXValsForElement(e,t))}function safelySetHeaderValue(e,t,n){if(n!==null)try{e.setRequestHeader(t,n)}catch{e.setRequestHeader(t,encodeURIComponent(n)),e.setRequestHeader(t+"-URI-AutoEncoded","true")}}function getPathFromResponse(e){if(e.responseURL)try{let t=new URL(e.responseURL);return t.pathname+t.search}catch{triggerErrorEvent(getDocument().body,"htmx:badResponseUrl",{url:e.responseURL})}}function hasHeader(e,t){return t.test(e.getAllResponseHeaders())}function ajaxHelper(e,t,n){if(e=e.toLowerCase(),n){if(n instanceof Element||typeof n=="string")return issueAjaxRequest(e,t,null,null,{targetOverride:resolveTarget(n)||DUMMY_ELT,returnPromise:!0});{let r=resolveTarget(n.target);return(n.target&&!r||n.source&&!r&&!resolveTarget(n.source))&&(r=DUMMY_ELT),issueAjaxRequest(e,t,resolveTarget(n.source),n.event,{handler:n.handler,headers:n.headers,values:n.values,targetOverride:r,swapOverride:n.swap,select:n.select,returnPromise:!0,push:n.push,replace:n.replace,selectOOB:n.selectOOB})}}else return issueAjaxRequest(e,t,null,null,{returnPromise:!0})}function hierarchyForElt(e){let t=[];for(;e;)t.push(e),e=e.parentElement;return t}function verifyPath(e,t,n){let r=new URL(t,location.protocol!=="about:"?location.href:window.origin),s=(location.protocol!=="about:"?location.origin:window.origin)===r.origin;return htmx.config.selfRequestsOnly&&!s?!1:triggerEvent(e,"htmx:validateUrl",mergeObjects({url:r,sameHost:s},n))}function formDataFromObject(e){if(e instanceof FormData)return e;let t=new FormData;for(let n in e)e.hasOwnProperty(n)&&(e[n]&&typeof e[n].forEach=="function"?e[n].forEach(function(r){t.append(n,r)}):typeof e[n]=="object"&&!(e[n]instanceof Blob)?t.append(n,JSON.stringify(e[n])):t.append(n,e[n]));return t}function formDataArrayProxy(e,t,n){return new Proxy(n,{get:function(r,o){return typeof o=="number"?r[o]:o==="length"?r.length:o==="push"?function(s){r.push(s),e.append(t,s)}:typeof r[o]=="function"?function(){r[o].apply(r,arguments),e.delete(t),r.forEach(function(s){e.append(t,s)})}:r[o]&&r[o].length===1?r[o][0]:r[o]},set:function(r,o,s){return r[o]=s,e.delete(t),r.forEach(function(i){e.append(t,i)}),!0}})}function formDataProxy(e){return new Proxy(e,{get:function(t,n){if(typeof n=="symbol"){let o=Reflect.get(t,n);return typeof o=="function"?function(){return o.apply(e,arguments)}:o}if(n==="toJSON")return()=>Object.fromEntries(e);if(n in t&&typeof t[n]=="function")return function(){return e[n].apply(e,arguments)};let r=e.getAll(n);if(r.length!==0)return r.length===1?r[0]:formDataArrayProxy(t,n,r)},set:function(t,n,r){return typeof n!="string"?!1:(t.delete(n),r&&typeof r.forEach=="function"?r.forEach(function(o){t.append(n,o)}):typeof r=="object"&&!(r instanceof Blob)?t.append(n,JSON.stringify(r)):t.append(n,r),!0)},deleteProperty:function(t,n){return typeof n=="string"&&t.delete(n),!0},ownKeys:function(t){return Reflect.ownKeys(Object.fromEntries(t))},getOwnPropertyDescriptor:function(t,n){return Reflect.getOwnPropertyDescriptor(Object.fromEntries(t),n)}})}function issueAjaxRequest(e,t,n,r,o,s){let i=null,a=null;if(o=o??{},o.returnPromise&&typeof Promise<"u")var l=new Promise(function(m,v){i=m,a=v});n==null&&(n=getDocument().body);let c=o.handler||handleAjaxResponse,d=o.select||null;if(!bodyContains(n))return maybeCall(i),l;let u=o.targetOverride||asElement(getTarget(n));if(u==null||u==DUMMY_ELT)return triggerErrorEvent(n,"htmx:targetError",{target:getClosestAttributeValue(n,"hx-target")}),maybeCall(a),l;let f=getInternalData(n),y=f.lastButtonClicked;if(y){let m=getRawAttribute(y,"formaction");m!=null&&(t=m);let v=getRawAttribute(y,"formmethod");if(v!=null)if(VERBS.includes(v.toLowerCase()))e=v;else return maybeCall(i),l}let h=getClosestAttributeValue(n,"hx-confirm");if(s===void 0&&triggerEvent(n,"htmx:confirm",{target:u,elt:n,path:t,verb:e,triggeringEvent:r,etc:o,issueRequest:function(A){return issueAjaxRequest(e,t,n,r,o,!!A)},question:h})===!1)return maybeCall(i),l;let p=n,g=getClosestAttributeValue(n,"hx-sync"),w=null,C=!1;if(g){let m=g.split(":"),v=m[0].trim();if(v==="this"?p=findThisElement(n,"hx-sync"):p=asElement(querySelectorExt(n,v)),g=(m[1]||"drop").trim(),f=getInternalData(p),g==="drop"&&f.xhr&&f.abortable!==!0)return maybeCall(i),l;if(g==="abort"){if(f.xhr)return maybeCall(i),l;C=!0}else g==="replace"?triggerEvent(p,"htmx:abort"):g.indexOf("queue")===0&&(w=(g.split(" ")[1]||"last").trim())}if(f.xhr)if(f.abortable)triggerEvent(p,"htmx:abort");else{if(w==null){if(r){let m=getInternalData(r);m&&m.triggerSpec&&m.triggerSpec.queue&&(w=m.triggerSpec.queue)}w==null&&(w="last")}return f.queuedRequests==null&&(f.queuedRequests=[]),w==="first"&&f.queuedRequests.length===0?f.queuedRequests.push(function(){issueAjaxRequest(e,t,n,r,o)}):w==="all"?f.queuedRequests.push(function(){issueAjaxRequest(e,t,n,r,o)}):w==="last"&&(f.queuedRequests=[],f.queuedRequests.push(function(){issueAjaxRequest(e,t,n,r,o)})),maybeCall(i),l}let x=new XMLHttpRequest;f.xhr=x,f.abortable=C;let E=function(){f.xhr=null,f.abortable=!1,f.queuedRequests!=null&&f.queuedRequests.length>0&&f.queuedRequests.shift()()},J=getClosestAttributeValue(n,"hx-prompt");if(J){var F=prompt(J);if(F===null||!triggerEvent(n,"htmx:prompt",{prompt:F,target:u}))return maybeCall(i),E(),l}if(h&&!s&&!confirm(h))return maybeCall(i),E(),l;let H=getHeaders(n,u,F);e!=="get"&&!usesFormData(n)&&(H["Content-Type"]="application/x-www-form-urlencoded"),o.headers&&(H=mergeObjects(H,o.headers));let Y=getInputValues(n,e),O=Y.errors,z=Y.formData;o.values&&overrideFormData(z,formDataFromObject(o.values));let ie=formDataFromObject(getExpressionVars(n,r)),q=overrideFormData(z,ie),I=filterValues(q,n);htmx.config.getCacheBusterParam&&e==="get"&&I.set("org.htmx.cache-buster",getRawAttribute(u,"id")||"true"),(t==null||t==="")&&(t=location.href);let k=getValuesForElement(n,"hx-request"),K=getInternalData(n).boosted,L=htmx.config.methodsThatUseUrlParams.indexOf(e)>=0,S={boosted:K,useUrlParams:L,formData:I,parameters:formDataProxy(I),unfilteredFormData:q,unfilteredParameters:formDataProxy(q),headers:H,elt:n,target:u,verb:e,errors:O,withCredentials:o.credentials||k.credentials||htmx.config.withCredentials,timeout:o.timeout||k.timeout||htmx.config.timeout,path:t,triggeringEvent:r};if(!triggerEvent(n,"htmx:configRequest",S))return maybeCall(i),E(),l;if(t=S.path,e=S.verb,H=S.headers,I=formDataFromObject(S.parameters),O=S.errors,L=S.useUrlParams,O&&O.length>0)return triggerEvent(n,"htmx:validation:halted",S),maybeCall(i),E(),l;let G=t.split("#"),ae=G[0],_=G[1],T=t;if(L&&(T=ae,!I.keys().next().done&&(T.indexOf("?")<0?T+="?":T+="&",T+=urlEncode(I),_&&(T+="#"+_))),!verifyPath(n,T,S))return triggerErrorEvent(n,"htmx:invalidPath",S),maybeCall(a),E(),l;if(x.open(e.toUpperCase(),T,!0),x.overrideMimeType("text/html"),x.withCredentials=S.withCredentials,x.timeout=S.timeout,!k.noHeaders){for(let m in H)if(H.hasOwnProperty(m)){let v=H[m];safelySetHeaderValue(x,m,v)}}let b={xhr:x,target:u,requestConfig:S,etc:o,boosted:K,select:d,pathInfo:{requestPath:t,finalRequestPath:T,responsePath:null,anchor:_}};if(x.onload=function(){try{let m=hierarchyForElt(n);if(b.pathInfo.responsePath=getPathFromResponse(x),c(n,b),b.keepIndicators!==!0&&removeRequestIndicators(P,N),triggerEvent(n,"htmx:afterRequest",b),triggerEvent(n,"htmx:afterOnLoad",b),!bodyContains(n)){let v=null;for(;m.length>0&&v==null;){let A=m.shift();bodyContains(A)&&(v=A)}v&&(triggerEvent(v,"htmx:afterRequest",b),triggerEvent(v,"htmx:afterOnLoad",b))}maybeCall(i)}catch(m){throw triggerErrorEvent(n,"htmx:onLoadError",mergeObjects({error:m},b)),m}finally{E()}},x.onerror=function(){removeRequestIndicators(P,N),triggerErrorEvent(n,"htmx:afterRequest",b),triggerErrorEvent(n,"htmx:sendError",b),maybeCall(a),E()},x.onabort=function(){removeRequestIndicators(P,N),triggerErrorEvent(n,"htmx:afterRequest",b),triggerErrorEvent(n,"htmx:sendAbort",b),maybeCall(a),E()},x.ontimeout=function(){removeRequestIndicators(P,N),triggerErrorEvent(n,"htmx:afterRequest",b),triggerErrorEvent(n,"htmx:timeout",b),maybeCall(a),E()},!triggerEvent(n,"htmx:beforeRequest",b))return maybeCall(i),E(),l;var P=addRequestIndicatorClasses(n),N=disableElements(n);forEach(["loadstart","loadend","progress","abort"],function(m){forEach([x,x.upload],function(v){v.addEventListener(m,function(A){triggerEvent(n,"htmx:xhr:"+m,{lengthComputable:A.lengthComputable,loaded:A.loaded,total:A.total})})})}),triggerEvent(n,"htmx:beforeSend",b);let le=L?null:encodeParamsForBody(x,n,I);return x.send(le),l}function determineHistoryUpdates(e,t){let n=t.xhr,r=null,o=null;if(hasHeader(n,/HX-Push:/i)?(r=n.getResponseHeader("HX-Push"),o="push"):hasHeader(n,/HX-Push-Url:/i)?(r=n.getResponseHeader("HX-Push-Url"),o="push"):hasHeader(n,/HX-Replace-Url:/i)&&(r=n.getResponseHeader("HX-Replace-Url"),o="replace"),r)return r==="false"?{}:{type:o,path:r};let s=t.pathInfo.finalRequestPath,i=t.pathInfo.responsePath,a=t.etc.push||getClosestAttributeValue(e,"hx-push-url"),l=t.etc.replace||getClosestAttributeValue(e,"hx-replace-url"),c=getInternalData(e).boosted,d=null,u=null;return a?(d="push",u=a):l?(d="replace",u=l):c&&(d="push",u=i||s),u?u==="false"?{}:(u==="true"&&(u=i||s),t.pathInfo.anchor&&u.indexOf("#")===-1&&(u=u+"#"+t.pathInfo.anchor),{type:d,path:u}):{}}function codeMatches(e,t){var n=new RegExp(e.code);return n.test(t.toString(10))}function resolveResponseHandling(e){for(var t=0;t.${t}{opacity:0;visibility: hidden} .${n} .${t}, .${n}.${t}{opacity:1;visibility: visible;transition: opacity 200ms ease-in}`)}}function getMetaConfig(){let e=getDocument().querySelector('meta[name="htmx-config"]');return e?parseJSON(e.content):null}function mergeMetaConfig(){let e=getMetaConfig();e&&(htmx.config=mergeObjects(htmx.config,e))}return ready(function(){mergeMetaConfig(),insertIndicatorStyles();let e=getDocument().body;processNode(e);let t=getDocument().querySelectorAll("[hx-trigger='restored'],[data-hx-trigger='restored']");e.addEventListener("htmx:abort",function(r){let o=r.detail.elt||r.target,s=getInternalData(o);s&&s.xhr&&s.xhr.abort()});let n=window.onpopstate?window.onpopstate.bind(window):null;window.onpopstate=function(r){r.state&&r.state.htmx?(restoreHistory(),forEach(t,function(o){triggerEvent(o,"htmx:restored",{document:getDocument(),triggerEvent})})):n&&n(r)},getWindow().setTimeout(function(){triggerEvent(e,"htmx:load",{}),e=null},0)}),htmx})(),R=ce;(function(){let e;R.defineExtension("json-enc",{init:function(t){e=t},onEvent:function(t,n){t==="htmx:configRequest"&&(n.detail.headers["Content-Type"]="application/json")},encodeParameters:function(t,n,r){t.overrideMimeType("text/json");let o={};n.forEach(function(i,a){Object.hasOwn(o,a)?(Array.isArray(o[a])||(o[a]=[o[a]]),o[a].push(i)):o[a]=i});let s=e.getExpressionVars(r);return Object.keys(o).forEach(function(i){o[i]=Object.hasOwn(s,i)?s[i]:o[i]}),JSON.stringify(o)}})})();var Q="https://typeahead.waow.tech",ee="https://public.api.bsky.app",ue="/xrpc/app.bsky.actor.searchActorsTypeahead",fe="/xrpc/app.bsky.actor.getProfiles";var de="atcr_recent_handles",te="atcr_recent_profile_cache";var U=class{constructor(t){this.input=t,this.container=t.closest(".sailor-typeahead")||t.parentElement,this.dropdown=null,this.selectedCard=null,this.actors=[],this.currentItems=[],this.mode="hidden",this.focusIndex=-1,this.debounceTimer=null,this.requestSeq=0,this.primaryUnhealthyUntil=0,this.lastPrefetchPrefix="",this.lastPrefetchAt=0,this.createDropdown(),this.bindEvents(),this.input.value.trim().length===0&&this.showRecent()}createDropdown(){this.dropdown=document.createElement("div"),this.dropdown.className="sailor-typeahead-dropdown",this.dropdown.setAttribute("role","listbox"),this.dropdown.style.display="none",this.input.insertAdjacentElement("afterend",this.dropdown)}bindEvents(){this.input.addEventListener("focus",()=>this.handleFocus()),this.input.addEventListener("input",()=>this.handleInput()),this.input.addEventListener("keydown",t=>this.handleKeydown(t)),document.addEventListener("click",t=>{!this.input.contains(t.target)&&!this.dropdown.contains(t.target)&&this.hide()}),document.addEventListener("keydown",t=>{t.key==="Escape"&&this.selectedCard&&this.clearSelection()})}handleFocus(){this.input.value.trim().length===0&&this.showRecent()}handleInput(){let t=this.input.value.trim();if(t.length===0){this.showRecent();return}if(t.length>=2&&t.length<4){this.hide(),this.schedulePrefetch(t);return}if(t.length>=4){this.scheduleSearch(t);return}this.hide()}schedulePrefetch(t){clearTimeout(this.debounceTimer),this.debounceTimer=setTimeout(()=>this.runPrefetch(t),150)}scheduleSearch(t){clearTimeout(this.debounceTimer),this.debounceTimer=setTimeout(()=>this.runSearch(t),150)}async runPrefetch(t){let n=Date.now();if(!(t===this.lastPrefetchPrefix&&n-this.lastPrefetchAt<1e4)&&!(n=this.primaryUnhealthyUntil)try{r=await B(Q,t,1500)}catch{this.primaryUnhealthyUntil=Date.now()+6e4}if(r===null)try{r=await B(ee,t,1500)}catch{r=[]}n===this.requestSeq&&(this.actors=r||[],this.focusIndex=-1,this.renderResults())}renderResults(){if(this.mode="results",this.dropdown.innerHTML="",this.currentItems=[],this.actors.length===0){this.hide();return}this.actors.forEach((t,n)=>{this.currentItems.push(t),this.dropdown.appendChild(this.buildActorRow(t,n))}),this.dropdown.style.display="block"}buildActorRow(t,n){let r=document.createElement("div");r.className="sailor-typeahead-item",r.setAttribute("role","option"),r.dataset.index=String(n),r.dataset.handle=t.handle;let o=document.createElement("div");if(o.className="sailor-typeahead-avatar",t.avatar){let l=document.createElement("img");l.src=t.avatar,l.alt="",l.loading="lazy",o.appendChild(l)}let s=document.createElement("div");s.className="sailor-typeahead-text";let i=t.displayName&&t.displayName!==t.handle;if(i){let l=document.createElement("div");l.className="sailor-typeahead-name",l.textContent=t.displayName,s.appendChild(l)}let a=document.createElement("div");return a.className=i?"sailor-typeahead-handle":"sailor-typeahead-name",a.textContent="@"+t.handle,s.appendChild(a),r.append(o,s),r.addEventListener("mousedown",l=>{l.preventDefault(),this.select(t)}),r}showRecent(){let t=me();if(t.length===0){this.hide();return}this.mode="recent",this.focusIndex=-1,this.renderRecent(t),this.enrichRecent(t)}renderRecent(t){let n=M();this.dropdown.innerHTML="",this.currentItems=[];let r=document.createElement("div");r.className="sailor-typeahead-header",r.textContent="Recent accounts",this.dropdown.appendChild(r),t.forEach((o,s)=>{let i=n[o]?.profile||{handle:o};this.currentItems.push(i),this.dropdown.appendChild(this.buildActorRow(i,s))}),this.dropdown.style.display="block"}async enrichRecent(t){let n=M(),r=Date.now(),o=t.filter(a=>{let l=n[a];return!l||r-l.ts>864e5});if(o.length===0)return;let s=await he(o);if(s.length===0)return;let i=M();s.forEach(a=>{i[a.handle]={ts:r,profile:{handle:a.handle,displayName:a.displayName,avatar:a.avatar}}}),Z(i),this.mode==="recent"&&this.renderRecent(t)}hide(){this.mode="hidden",this.focusIndex=-1,this.dropdown.style.display="none"}select(t){if(typeof t=="string"&&(t={handle:t}),this.input.value=t.handle,this.hide(),this.showSelectedCard(t),t.handle){let n=M();n[t.handle]={ts:Date.now(),profile:{handle:t.handle,displayName:t.displayName,avatar:t.avatar}},Z(n)}}showSelectedCard(t){this.clearSelectedCard();let n=document.createElement("div");n.className="sailor-typeahead-selected";let r=document.createElement("div");if(r.className="sailor-typeahead-avatar",t.avatar){let l=document.createElement("img");l.src=t.avatar,l.alt="",r.appendChild(l)}let o=document.createElement("div");o.className="sailor-typeahead-text";let s=t.displayName&&t.displayName!==t.handle;if(s){let l=document.createElement("div");l.className="sailor-typeahead-name",l.textContent=t.displayName,o.appendChild(l)}let i=document.createElement("div");i.className=s?"sailor-typeahead-handle":"sailor-typeahead-name",i.textContent="@"+t.handle,o.appendChild(i);let a=document.createElement("button");a.type="button",a.className="sailor-typeahead-clear",a.tabIndex=-1,a.setAttribute("aria-label","Change account"),a.innerHTML="×",a.addEventListener("click",()=>this.clearSelection()),n.append(r,o,a),this.input.style.display="none",this.input.insertAdjacentElement("beforebegin",n),this.selectedCard=n}clearSelectedCard(){this.selectedCard&&(this.selectedCard.remove(),this.selectedCard=null)}clearSelection(){this.clearSelectedCard(),this.input.style.display="",this.input.value="",this.input.focus(),this.showRecent()}handleKeydown(t){if(this.mode==="hidden")return;let n=this.dropdown.querySelectorAll(".sailor-typeahead-item");n.length!==0&&(t.key==="ArrowDown"?(t.preventDefault(),this.focusIndex=(this.focusIndex+1)%n.length,this.updateFocus(n)):t.key==="ArrowUp"?(t.preventDefault(),this.focusIndex=this.focusIndex<=0?n.length-1:this.focusIndex-1,this.updateFocus(n)):t.key==="Enter"?this.focusIndex>=0&&this.currentItems[this.focusIndex]&&(t.preventDefault(),this.select(this.currentItems[this.focusIndex])):t.key==="Escape"?this.hide():t.key==="Tab"&&this.focusIndex===-1&&n.length>0&&(t.preventDefault(),this.focusIndex=0,this.updateFocus(n)))}updateFocus(t){t.forEach((n,r)=>{n.classList.toggle("focused",r===this.focusIndex),r===this.focusIndex&&n.scrollIntoView({block:"nearest"})})}};async function B(e,t,n){let r=new URL(ue,e);r.searchParams.set("q",t),r.searchParams.set("limit",String(8));let o=new AbortController,s=setTimeout(()=>o.abort(),n);try{let i=await fetch(r,{signal:o.signal});if(!i.ok)throw new Error("HTTP "+i.status);let a=await i.json();return Array.isArray(a.actors)?a.actors:[]}finally{clearTimeout(s)}}async function he(e){if(e.length===0)return[];let t=new URL(fe,ee);e.forEach(o=>t.searchParams.append("actors",o));let n=new AbortController,r=setTimeout(()=>n.abort(),3e3);try{let o=await fetch(t,{signal:n.signal});if(!o.ok)return[];let s=await o.json();return Array.isArray(s.profiles)?s.profiles:[]}catch{return[]}finally{clearTimeout(r)}}function M(){try{return JSON.parse(localStorage.getItem(te)||"{}")}catch{return{}}}function Z(e){try{localStorage.setItem(te,JSON.stringify(e))}catch{}}function me(){try{let e=localStorage.getItem(de);return e?JSON.parse(e):[]}catch{return[]}}document.addEventListener("DOMContentLoaded",()=>{let e=document.getElementById("handle");e&&new U(e)});function re(){return localStorage.getItem("theme")||"system"}function ge(e){return e==="dark"||e==="light"?e:window.matchMedia("(prefers-color-scheme: dark)").matches?"dark":"light"}function W(){let e=re(),n=ge(e)==="dark";document.documentElement.classList.toggle("dark",n),document.documentElement.setAttribute("data-theme",n?"dark":"light"),pe(e)}function oe(e){localStorage.setItem("theme",e),W(),Ee()}function pe(e){let t={system:"sun-moon",light:"sun",dark:"moon"};document.querySelectorAll("[data-theme-icon] use").forEach(n=>{n.setAttribute("href",`/icons.svg#${t[e]||"sun-moon"}`)}),document.querySelectorAll(".theme-option").forEach(n=>{let r=n.dataset.value===e,o=n.querySelector(".theme-check");o&&(o.style.visibility=r?"visible":"hidden")})}function Ee(){document.querySelectorAll("[data-theme-toggle]").forEach(e=>{let t=e.closest("details");t&&t.removeAttribute("open")})}window.matchMedia("(prefers-color-scheme: dark)").addEventListener("change",()=>{re()==="system"&&W()});function ye(){let e=document.querySelector(".nav-search-wrapper"),t=document.getElementById("nav-search-input");!e||!t||(e.classList.toggle("expanded"),e.classList.contains("expanded")&&t.focus())}function V(){let e=document.querySelector(".nav-search-wrapper");e&&e.classList.remove("expanded")}document.addEventListener("DOMContentLoaded",()=>{let e=document.querySelector(".nav-search-wrapper"),t=document.getElementById("nav-search-input");!e||!t||(document.addEventListener("keydown",n=>{if(n.key==="Escape"&&e.classList.contains("expanded")&&V(),n.key==="/"&&!e.classList.contains("expanded")){let r=n.target.tagName;if(r==="INPUT"||r==="TEXTAREA"||n.target.isContentEditable)return;n.preventDefault(),e.classList.add("expanded"),t.focus()}}),document.addEventListener("click",n=>{e.classList.contains("expanded")&&!e.contains(n.target)&&V()}))});function j(e,t){!t&&typeof event<"u"&&(t=event.target.closest("button")),navigator.clipboard.writeText(e).then(()=>{if(!t)return;let n=t.innerHTML;t.innerHTML=' Copied!',setTimeout(()=>{t.innerHTML=n},2e3)}).catch(n=>{console.error("Failed to copy:",n)})}function xe(e){let t=s=>{let i=(s==null?"":String(s)).replace(/\s+/g," ").trim();return/[",\n\r]/.test(i)?'"'+i.replace(/"/g,'""')+'"':i},n=s=>Array.from(s).map(i=>t(i.textContent)).join(","),r=[],o=e.querySelector("thead tr");return o&&r.push(n(o.querySelectorAll("th,td"))),e.querySelectorAll("tbody tr").forEach(s=>{r.push(n(s.querySelectorAll("td,th")))}),r.join(`
-`)}document.addEventListener("DOMContentLoaded",()=>{document.addEventListener("click",e=>{let t=e.target.closest("button[data-copy-csv]");if(t){let o=t.closest("[data-csv-section]"),s=o&&o.querySelector("table");s&&j(xe(s),t);return}let n=e.target.closest("button[data-cmd]");if(n){j(n.getAttribute("data-cmd"),n);return}if(e.target.closest("a, button, input, .cmd"))return;let r=e.target.closest("[data-href]");r&&(window.location=r.getAttribute("data-href"))})});function ve(e){let t=Math.floor((new Date-new Date(e))/1e3),n={year:31536e3,month:2592e3,week:604800,day:86400,hour:3600,minute:60,second:1};for(let[r,o]of Object.entries(n)){let s=Math.floor(t/o);if(s>=1)return s===1?`1 ${r} ago`:`${s} ${r}s ago`}return"just now"}function X(){document.querySelectorAll("time[datetime]").forEach(e=>{let t=e.getAttribute("datetime");if(t&&!e.dataset.noUpdate){let n=ve(t);e.textContent!==n&&(e.textContent=n)}})}document.addEventListener("DOMContentLoaded",()=>{X(),W(),document.querySelectorAll("[data-theme-menu]").forEach(e=>{e.querySelectorAll(".theme-option").forEach(t=>{t.addEventListener("click",()=>{oe(t.dataset.value)})})}),document.addEventListener("click",e=>{let t=e.target.closest("details.dropdown");document.querySelectorAll("details.dropdown[open]").forEach(n=>{n!==t&&n.removeAttribute("open")})})});document.addEventListener("htmx:afterSwap",X);setInterval(X,6e4);function be(){let e=document.getElementById("show-offline-toggle"),t=document.querySelector(".manifests-list");!e||!t||(localStorage.setItem("showOfflineManifests",e.checked),e.checked?t.classList.add("show-offline"):t.classList.remove("show-offline"))}document.addEventListener("DOMContentLoaded",()=>{let e=document.getElementById("show-offline-toggle");if(!e)return;let t=localStorage.getItem("showOfflineManifests")==="true";e.checked=t;let n=document.querySelector(".manifests-list");n&&(t?n.classList.add("show-offline"):n.classList.remove("show-offline"))});async function we(e,t,n){try{let r=await fetch("/api/manifests",{method:"DELETE",credentials:"include",headers:{"Content-Type":"application/json"},body:JSON.stringify({repo:e,digest:t,confirm:!1})});if(r.status===409){let o=await r.json();Ce(e,t,n,o.tags)}else if(r.ok)se(n);else{let o=await r.text();alert(`Failed to delete manifest: ${o}`)}}catch(r){console.error("Error deleting manifest:",r),alert(`Error deleting manifest: ${r.message}`)}}function Ce(e,t,n,r){let o=document.getElementById("manifest-delete-modal"),s=document.getElementById("manifest-delete-tags"),i=document.getElementById("confirm-manifest-delete-btn");s.innerHTML="",r.forEach(a=>{let l=document.createElement("li");l.textContent=a,s.appendChild(l)}),i.onclick=()=>Se(e,t,n),o.style.display="flex"}function $(){let e=document.getElementById("manifest-delete-modal");e.style.display="none"}async function Se(e,t,n){let r=document.getElementById("confirm-manifest-delete-btn"),o=r.textContent;try{r.disabled=!0,r.textContent="Deleting...";let s=await fetch("/api/manifests",{method:"DELETE",credentials:"include",headers:{"Content-Type":"application/json"},body:JSON.stringify({repo:e,digest:t,confirm:!0})});if(s.ok)$(),se(n),location.reload();else{let i=await s.text();alert(`Failed to delete manifest: ${i}`),r.disabled=!1,r.textContent=o}}catch(s){console.error("Error deleting manifest:",s),alert(`Error deleting manifest: ${s.message}`),r.disabled=!1,r.textContent=o}}async function Te(e){let t=document.getElementById("confirm-untagged-delete-btn"),n=t.textContent;try{t.disabled=!0,t.textContent="Deleting...";let r=await fetch("/api/manifests/untagged",{method:"DELETE",credentials:"include",headers:{"Content-Type":"application/json"},body:JSON.stringify({repo:e})}),o=await r.json();r.ok?(document.getElementById("untagged-delete-modal").close(),D(`Deleted ${o.deleted} untagged manifest(s)`,"success"),o.deleted>0&&location.reload(),t.disabled=!1,t.textContent=n):(alert(`Failed to delete untagged manifests: ${o.error||"Unknown error"}`),t.disabled=!1,t.textContent=n)}catch(r){console.error("Error deleting untagged manifests:",r),alert(`Error: ${r.message}`),t.disabled=!1,t.textContent=n}}function se(e){let t=document.getElementById(`manifest-${e}`);t&&t.remove()}document.addEventListener("DOMContentLoaded",()=>{let e=document.getElementById("manifest-delete-modal");e&&e.addEventListener("click",t=>{t.target===e&&$()})});async function Ae(e,t){let n=document.getElementById("vuln-detail-modal"),r=document.getElementById("vuln-modal-body");if(!(!n||!r)){r.innerHTML='
',n.showModal();try{let o=await fetch(`/api/vuln-details?digest=${encodeURIComponent(e)}&holdEndpoint=${encodeURIComponent(t)}`);r.innerHTML=await o.text()}catch{r.innerHTML='Failed to load vulnerability details
'}}}document.addEventListener("DOMContentLoaded",()=>{let e=document.cookie.split("; ").find(n=>n.startsWith("atcr_login_handle="));if(!e)return;let t=decodeURIComponent(e.split("=")[1]);if(t){try{let n="atcr_recent_handles",r=JSON.parse(localStorage.getItem(n)||"[]");r=r.filter(o=>o!==t),r.unshift(t),r=r.slice(0,5),localStorage.setItem(n,JSON.stringify(r))}catch(n){console.error("Failed to save recent account:",n)}document.cookie="atcr_login_handle=; path=/; max-age=0"}});function ne(){let e=document.getElementById("featured-carousel"),t=document.getElementById("carousel-prev"),n=document.getElementById("carousel-next");if(!e)return;let r=e.querySelectorAll(".carousel-item");if(r.length===0)return;let o=null,s=5e3;function i(){let u=r[0],f=parseFloat(getComputedStyle(e).gap)||24;return u.offsetWidth+f}function a(){let u=e.scrollWidth-e.clientWidth;e.scrollLeft>=u-10?e.scrollTo({left:0,behavior:"smooth"}):e.scrollBy({left:i(),behavior:"smooth"})}function l(){e.scrollLeft<=10?e.scrollTo({left:e.scrollWidth,behavior:"smooth"}):e.scrollBy({left:-i(),behavior:"smooth"})}function c(){o||e.scrollWidth<=e.clientWidth+10||(o=setInterval(a,s))}function d(){o&&(clearInterval(o),o=null)}t&&t.addEventListener("click",()=>{d(),l(),c()}),n&&n.addEventListener("click",()=>{d(),a(),c()}),e.addEventListener("mouseenter",d),e.addEventListener("mouseleave",c),c()}document.addEventListener("DOMContentLoaded",()=>{"requestIdleCallback"in window?requestIdleCallback(ne,{timeout:2e3}):setTimeout(ne,100)});function D(e,t){let n=document.getElementById("toast-container");n||(n=document.createElement("div"),n.id="toast-container",n.className="toast toast-end toast-bottom z-50",document.body.appendChild(n));let r=t==="error"?"alert-error":"alert-success",o=document.createElement("div");o.className=`alert ${r} shadow-lg transition-opacity duration-300`,o.innerHTML=`${e} `,n.appendChild(o),setTimeout(()=>{o.style.opacity="0",setTimeout(()=>o.remove(),300)},3e3)}async function He(e){try{let t=await fetch(`/api/webhooks/${e}/test`,{method:"POST",credentials:"include"}),n=await t.text();n.includes('class="success"')||t.ok&&!n.includes('class="error"')?D("Test webhook delivered successfully!","success"):D("Test delivery failed \u2014 check the webhook URL","error")}catch{D("Failed to reach server","error")}}window.setTheme=oe;window.toggleSearch=ye;window.closeSearch=V;window.copyToClipboard=j;window.toggleOfflineManifests=be;window.deleteManifest=we;window.deleteUntaggedManifests=Te;window.closeManifestDeleteModal=$;window.openVulnDetails=Ae;window.showToast=D;window.testWebhook=He;window.htmx=R;R.config.methodsThatUseUrlParams=["get"];
+var xe=(function(){"use strict";let htmx={onLoad:null,process:null,on:null,off:null,trigger:null,ajax:null,find:null,findAll:null,closest:null,values:function(e,t){return getInputValues(e,t||"post").values},remove:null,addClass:null,removeClass:null,toggleClass:null,takeClass:null,swap:null,defineExtension:null,removeExtension:null,logAll:null,logNone:null,logger:null,config:{historyEnabled:!0,historyCacheSize:10,refreshOnHistoryMiss:!1,defaultSwapStyle:"innerHTML",defaultSwapDelay:0,defaultSettleDelay:20,includeIndicatorStyles:!0,indicatorClass:"htmx-indicator",requestClass:"htmx-request",addedClass:"htmx-added",settlingClass:"htmx-settling",swappingClass:"htmx-swapping",allowEval:!0,allowScriptTags:!0,inlineScriptNonce:"",inlineStyleNonce:"",attributesToSettle:["class","style","width","height"],withCredentials:!1,timeout:0,wsReconnectDelay:"full-jitter",wsBinaryType:"blob",disableSelector:"[hx-disable], [data-hx-disable]",scrollBehavior:"instant",defaultFocusScroll:!1,getCacheBusterParam:!1,globalViewTransitions:!1,methodsThatUseUrlParams:["get","delete"],selfRequestsOnly:!0,ignoreTitle:!1,scrollIntoViewOnBoost:!0,triggerSpecsCache:null,disableInheritance:!1,responseHandling:[{code:"204",swap:!1},{code:"[23]..",swap:!0},{code:"[45]..",swap:!1,error:!0}],allowNestedOobSwaps:!0,historyRestoreAsHxRequest:!0,reportValidityOfForms:!1},parseInterval:null,location,_:null,version:"2.0.8"};htmx.onLoad=onLoadHelper,htmx.process=processNode,htmx.on=addEventListenerImpl,htmx.off=removeEventListenerImpl,htmx.trigger=triggerEvent,htmx.ajax=ajaxHelper,htmx.find=find,htmx.findAll=findAll,htmx.closest=closest,htmx.remove=removeElement,htmx.addClass=addClassToElement,htmx.removeClass=removeClassFromElement,htmx.toggleClass=toggleClassOnElement,htmx.takeClass=takeClassForElement,htmx.swap=swap,htmx.defineExtension=defineExtension,htmx.removeExtension=removeExtension,htmx.logAll=logAll,htmx.logNone=logNone,htmx.parseInterval=parseInterval,htmx._=internalEval;let internalAPI={addTriggerHandler,bodyContains,canAccessLocalStorage,findThisElement,filterValues,swap,hasAttribute,getAttributeValue,getClosestAttributeValue,getClosestMatch,getExpressionVars,getHeaders,getInputValues,getInternalData,getSwapSpecification,getTriggerSpecs,getTarget,makeFragment,mergeObjects,makeSettleInfo,oobSwap,querySelectorExt,settleImmediately,shouldCancel,triggerEvent,triggerErrorEvent,withExtensions},VERBS=["get","post","put","delete","patch"],VERB_SELECTOR=VERBS.map(function(e){return"[hx-"+e+"], [data-hx-"+e+"]"}).join(", ");function parseInterval(e){if(e==null)return;let t=NaN;return e.slice(-2)=="ms"?t=parseFloat(e.slice(0,-2)):e.slice(-1)=="s"?t=parseFloat(e.slice(0,-1))*1e3:e.slice(-1)=="m"?t=parseFloat(e.slice(0,-1))*1e3*60:t=parseFloat(e),isNaN(t)?void 0:t}function getRawAttribute(e,t){return e instanceof Element&&e.getAttribute(t)}function hasAttribute(e,t){return!!e.hasAttribute&&(e.hasAttribute(t)||e.hasAttribute("data-"+t))}function getAttributeValue(e,t){return getRawAttribute(e,t)||getRawAttribute(e,"data-"+t)}function parentElt(e){let t=e.parentElement;return!t&&e.parentNode instanceof ShadowRoot?e.parentNode:t}function getDocument(){return document}function getRootNode(e,t){return e.getRootNode?e.getRootNode({composed:t}):getDocument()}function getClosestMatch(e,t){for(;e&&!t(e);)e=parentElt(e);return e||null}function getAttributeValueWithDisinheritance(e,t,n){let r=getAttributeValue(t,n),o=getAttributeValue(t,"hx-disinherit");var s=getAttributeValue(t,"hx-inherit");if(e!==t){if(htmx.config.disableInheritance)return s&&(s==="*"||s.split(" ").indexOf(n)>=0)?r:null;if(o&&(o==="*"||o.split(" ").indexOf(n)>=0))return"unset"}return r}function getClosestAttributeValue(e,t){let n=null;if(getClosestMatch(e,function(r){return!!(n=getAttributeValueWithDisinheritance(e,asElement(r),t))}),n!=="unset")return n}function matches(e,t){return e instanceof Element&&e.matches(t)}function getStartTag(e){let n=/<([a-z][^\/\0>\x20\t\r\n\f]*)/i.exec(e);return n?n[1].toLowerCase():""}function parseHTML(e){return"parseHTMLUnsafe"in Document?Document.parseHTMLUnsafe(e):new DOMParser().parseFromString(e,"text/html")}function takeChildrenFor(e,t){for(;t.childNodes.length>0;)e.append(t.childNodes[0])}function duplicateScript(e){let t=getDocument().createElement("script");return forEach(e.attributes,function(n){t.setAttribute(n.name,n.value)}),t.textContent=e.textContent,t.async=!1,htmx.config.inlineScriptNonce&&(t.nonce=htmx.config.inlineScriptNonce),t}function isJavaScriptScriptNode(e){return e.matches("script")&&(e.type==="text/javascript"||e.type==="module"||e.type==="")}function normalizeScriptTags(e){Array.from(e.querySelectorAll("script")).forEach(t=>{if(isJavaScriptScriptNode(t)){let n=duplicateScript(t),r=t.parentNode;try{r.insertBefore(n,t)}catch(o){logError(o)}finally{t.remove()}}})}function makeFragment(e){let t=e.replace(/]*)?>[\s\S]*?<\/head>/i,""),n=getStartTag(t),r;if(n==="html"){r=new DocumentFragment;let s=parseHTML(e);takeChildrenFor(r,s.body),r.title=s.title}else if(n==="body"){r=new DocumentFragment;let s=parseHTML(t);takeChildrenFor(r,s.body),r.title=s.title}else{let s=parseHTML(''+t+" ");r=s.querySelector("template").content,r.title=s.title;var o=r.querySelector("title");o&&o.parentNode===r&&(o.remove(),r.title=o.innerText)}return r&&(htmx.config.allowScriptTags?normalizeScriptTags(r):r.querySelectorAll("script").forEach(s=>s.remove())),r}function maybeCall(e){e&&e()}function isType(e,t){return Object.prototype.toString.call(e)==="[object "+t+"]"}function isFunction(e){return typeof e=="function"}function isRawObject(e){return isType(e,"Object")}function getInternalData(e){let t="htmx-internal-data",n=e[t];return n||(n=e[t]={}),n}function toArray(e){let t=[];if(e)for(let n=0;n=0}function bodyContains(e){return e.getRootNode({composed:!0})===document}function splitOnWhitespace(e){return e.trim().split(/\s+/)}function mergeObjects(e,t){for(let n in t)t.hasOwnProperty(n)&&(e[n]=t[n]);return e}function parseJSON(e){try{return JSON.parse(e)}catch(t){return logError(t),null}}function canAccessLocalStorage(){let e="htmx:sessionStorageTest";try{return sessionStorage.setItem(e,e),sessionStorage.removeItem(e),!0}catch{return!1}}function normalizePath(e){let t=new URL(e,"http://x");return t&&(e=t.pathname+t.search),e!="/"&&(e=e.replace(/\/+$/,"")),e}function internalEval(str){return maybeEval(getDocument().body,function(){return eval(str)})}function onLoadHelper(e){return htmx.on("htmx:load",function(n){e(n.detail.elt)})}function logAll(){htmx.logger=function(e,t,n){console&&console.log(t,e,n)}}function logNone(){htmx.logger=null}function find(e,t){return typeof e!="string"?e.querySelector(t):find(getDocument(),e)}function findAll(e,t){return typeof e!="string"?e.querySelectorAll(t):findAll(getDocument(),e)}function getWindow(){return window}function removeElement(e,t){e=resolveTarget(e),t?getWindow().setTimeout(function(){removeElement(e),e=null},t):parentElt(e).removeChild(e)}function asElement(e){return e instanceof Element?e:null}function asHtmlElement(e){return e instanceof HTMLElement?e:null}function asString(e){return typeof e=="string"?e:null}function asParentNode(e){return e instanceof Element||e instanceof Document||e instanceof DocumentFragment?e:null}function addClassToElement(e,t,n){e=asElement(resolveTarget(e)),e&&(n?getWindow().setTimeout(function(){addClassToElement(e,t),e=null},n):e.classList&&e.classList.add(t))}function removeClassFromElement(e,t,n){let r=asElement(resolveTarget(e));r&&(n?getWindow().setTimeout(function(){removeClassFromElement(r,t),r=null},n):r.classList&&(r.classList.remove(t),r.classList.length===0&&r.removeAttribute("class")))}function toggleClassOnElement(e,t){e=resolveTarget(e),e.classList.toggle(t)}function takeClassForElement(e,t){e=resolveTarget(e),forEach(e.parentElement.children,function(n){removeClassFromElement(n,t)}),addClassToElement(asElement(e),t)}function closest(e,t){return e=asElement(resolveTarget(e)),e?e.closest(t):null}function startsWith(e,t){return e.substring(0,t.length)===t}function endsWith(e,t){return e.substring(e.length-t.length)===t}function normalizeSelector(e){let t=e.trim();return startsWith(t,"<")&&endsWith(t,"/>")?t.substring(1,t.length-2):t}function querySelectorAllExt(e,t,n){if(t.indexOf("global ")===0)return querySelectorAllExt(e,t.slice(7),!0);e=resolveTarget(e);let r=[];{let i=0,l=0;for(let a=0;a"&&i--}l0;){let i=normalizeSelector(r.shift()),l;i.indexOf("closest ")===0?l=closest(asElement(e),normalizeSelector(i.slice(8))):i.indexOf("find ")===0?l=find(asParentNode(e),normalizeSelector(i.slice(5))):i==="next"||i==="nextElementSibling"?l=asElement(e).nextElementSibling:i.indexOf("next ")===0?l=scanForwardQuery(e,normalizeSelector(i.slice(5)),!!n):i==="previous"||i==="previousElementSibling"?l=asElement(e).previousElementSibling:i.indexOf("previous ")===0?l=scanBackwardsQuery(e,normalizeSelector(i.slice(9)),!!n):i==="document"?l=document:i==="window"?l=window:i==="body"?l=document.body:i==="root"?l=getRootNode(e,!!n):i==="host"?l=e.getRootNode().host:s.push(i),l&&o.push(l)}if(s.length>0){let i=s.join(","),l=asParentNode(getRootNode(e,!!n));o.push(...toArray(l.querySelectorAll(i)))}return o}var scanForwardQuery=function(e,t,n){let r=asParentNode(getRootNode(e,n)).querySelectorAll(t);for(let o=0;o=0;o--){let s=r[o];if(s.compareDocumentPosition(e)===Node.DOCUMENT_POSITION_FOLLOWING)return s}};function querySelectorExt(e,t){return typeof e!="string"?querySelectorAllExt(e,t)[0]:querySelectorAllExt(getDocument().body,e)[0]}function resolveTarget(e,t){return typeof e=="string"?find(asParentNode(t)||document,e):e}function processEventArgs(e,t,n,r){return isFunction(t)?{target:getDocument().body,event:asString(e),listener:t,options:n}:{target:resolveTarget(e),event:asString(t),listener:n,options:r}}function addEventListenerImpl(e,t,n,r){return ready(function(){let s=processEventArgs(e,t,n,r);s.target.addEventListener(s.event,s.listener,s.options)}),isFunction(t)?t:n}function removeEventListenerImpl(e,t,n){return ready(function(){let r=processEventArgs(e,t,n);r.target.removeEventListener(r.event,r.listener)}),isFunction(t)?t:n}let DUMMY_ELT=getDocument().createElement("output");function findAttributeTargets(e,t){let n=getClosestAttributeValue(e,t);if(n){if(n==="this")return[findThisElement(e,t)];{let r=querySelectorAllExt(e,n);if(/(^|,)(\s*)inherit(\s*)($|,)/.test(n)){let s=asElement(getClosestMatch(e,function(i){return i!==e&&hasAttribute(asElement(i),t)}));s&&r.push(...findAttributeTargets(s,t))}return r.length===0?(logError('The selector "'+n+'" on '+t+" returned no matches!"),[DUMMY_ELT]):r}}}function findThisElement(e,t){return asElement(getClosestMatch(e,function(n){return getAttributeValue(asElement(n),t)!=null}))}function getTarget(e){let t=getClosestAttributeValue(e,"hx-target");return t?t==="this"?findThisElement(e,"hx-target"):querySelectorExt(e,t):getInternalData(e).boosted?getDocument().body:e}function shouldSettleAttribute(e){return htmx.config.attributesToSettle.includes(e)}function cloneAttributes(e,t){forEach(Array.from(e.attributes),function(n){!t.hasAttribute(n.name)&&shouldSettleAttribute(n.name)&&e.removeAttribute(n.name)}),forEach(t.attributes,function(n){shouldSettleAttribute(n.name)&&e.setAttribute(n.name,n.value)})}function isInlineSwap(e,t){let n=getExtensions(t);for(let r=0;r0?(s=e.substring(0,e.indexOf(":")),o=e.substring(e.indexOf(":")+1)):s=e),t.removeAttribute("hx-swap-oob"),t.removeAttribute("data-hx-swap-oob");let i=querySelectorAllExt(r,o,!1);return i.length?(forEach(i,function(l){let a,c=t.cloneNode(!0);a=getDocument().createDocumentFragment(),a.appendChild(c),isInlineSwap(s,l)||(a=asParentNode(c));let d={shouldSwap:!0,target:l,fragment:a};triggerEvent(l,"htmx:oobBeforeSwap",d)&&(l=d.target,d.shouldSwap&&(handlePreservedElements(a),swapWithStyle(s,l,l,a,n),restorePreservedElements()),forEach(n.elts,function(u){triggerEvent(u,"htmx:oobAfterSwap",d)}))}),t.parentNode.removeChild(t)):(t.parentNode.removeChild(t),triggerErrorEvent(getDocument().body,"htmx:oobErrorNoTarget",{content:t})),e}function restorePreservedElements(){let e=find("#--htmx-preserve-pantry--");if(e){for(let t of[...e.children]){let n=find("#"+t.id);n.parentNode.moveBefore(t,n),n.remove()}e.remove()}}function handlePreservedElements(e){forEach(findAll(e,"[hx-preserve], [data-hx-preserve]"),function(t){let n=getAttributeValue(t,"id"),r=getDocument().getElementById(n);if(r!=null)if(t.moveBefore){let o=find("#--htmx-preserve-pantry--");o==null&&(getDocument().body.insertAdjacentHTML("afterend","
"),o=find("#--htmx-preserve-pantry--")),o.moveBefore(r,null)}else t.parentNode.replaceChild(r,t)})}function handleAttributes(e,t,n){forEach(t.querySelectorAll("[id]"),function(r){let o=getRawAttribute(r,"id");if(o&&o.length>0){let s=o.replace("'","\\'"),i=r.tagName.replace(":","\\:"),l=asParentNode(e),a=l&&l.querySelector(i+"[id='"+s+"']");if(a&&a!==l){let c=r.cloneNode();cloneAttributes(r,a),n.tasks.push(function(){cloneAttributes(r,c)})}}})}function makeAjaxLoadTask(e){return function(){removeClassFromElement(e,htmx.config.addedClass),processNode(asElement(e)),processFocus(asParentNode(e)),triggerEvent(e,"htmx:load")}}function processFocus(e){let t="[autofocus]",n=asHtmlElement(matches(e,t)?e:e.querySelector(t));n?.focus()}function insertNodesBefore(e,t,n,r){for(handleAttributes(e,n,r);n.childNodes.length>0;){let o=n.firstChild;addClassToElement(asElement(o),htmx.config.addedClass),e.insertBefore(o,t),o.nodeType!==Node.TEXT_NODE&&o.nodeType!==Node.COMMENT_NODE&&r.tasks.push(makeAjaxLoadTask(o))}}function stringHash(e,t){let n=0;for(;n0}function swap(e,t,n,r){r||(r={});let o=null,s=null,i=function(){maybeCall(r.beforeSwapCallback),e=resolveTarget(e);let c=r.contextElement?getRootNode(r.contextElement,!1):getDocument(),d=document.activeElement,u={};u={elt:d,start:d?d.selectionStart:null,end:d?d.selectionEnd:null};let f=makeSettleInfo(e);if(n.swapStyle==="textContent")e.textContent=t;else{let h=makeFragment(t);if(f.title=r.title||h.title,r.historyRequest&&(h=h.querySelector("[hx-history-elt],[data-hx-history-elt]")||h),r.selectOOB){let y=r.selectOOB.split(",");for(let p=0;p0?getWindow().setTimeout(m,n.settleDelay):m()},l=htmx.config.globalViewTransitions;n.hasOwnProperty("transition")&&(l=n.transition);let a=r.contextElement||getDocument();if(l&&triggerEvent(a,"htmx:beforeTransition",r.eventInfo)&&typeof Promise<"u"&&document.startViewTransition){let c=new Promise(function(u,f){o=u,s=f}),d=i;i=function(){document.startViewTransition(function(){return d(),c})}}try{n?.swapDelay&&n.swapDelay>0?getWindow().setTimeout(i,n.swapDelay):i()}catch(c){throw triggerErrorEvent(a,"htmx:swapError",r.eventInfo),maybeCall(s),c}}function handleTriggerHeader(e,t,n){let r=e.getResponseHeader(t);if(r.indexOf("{")===0){let o=parseJSON(r);for(let s in o)if(o.hasOwnProperty(s)){let i=o[s];isRawObject(i)?n=i.target!==void 0?i.target:n:i={value:i},triggerEvent(n,s,i)}}else{let o=r.split(",");for(let s=0;s0;){let i=t[0];if(i==="]"){if(r--,r===0){s===null&&(o=o+"true"),t.shift(),o+=")})";try{let l=maybeEval(e,function(){return Function(o)()},function(){return!0});return l.source=o,l}catch(l){return triggerErrorEvent(getDocument().body,"htmx:syntax:error",{error:l,source:o}),null}}}else i==="["&&r++;isPossibleRelativeReference(i,s,n)?o+="(("+n+"."+i+") ? ("+n+"."+i+") : (window."+i+"))":o=o+i,s=t.shift()}}}function consumeUntil(e,t){let n="";for(;e.length>0&&!t.test(e[0]);)n+=e.shift();return n}function consumeCSSSelector(e){let t;return e.length>0&&COMBINED_SELECTOR_START.test(e[0])?(e.shift(),t=consumeUntil(e,COMBINED_SELECTOR_END).trim(),e.shift()):t=consumeUntil(e,WHITESPACE_OR_COMMA),t}let INPUT_SELECTOR="input, textarea, select";function parseAndCacheTrigger(e,t,n){let r=[],o=tokenizeString(t);do{consumeUntil(o,NOT_WHITESPACE);let l=o.length,a=consumeUntil(o,/[,\[\s]/);if(a!=="")if(a==="every"){let c={trigger:"every"};consumeUntil(o,NOT_WHITESPACE),c.pollInterval=parseInterval(consumeUntil(o,/[,\[\s]/)),consumeUntil(o,NOT_WHITESPACE);var s=maybeGenerateConditional(e,o,"event");s&&(c.eventFilter=s),r.push(c)}else{let c={trigger:a};var s=maybeGenerateConditional(e,o,"event");for(s&&(c.eventFilter=s),consumeUntil(o,NOT_WHITESPACE);o.length>0&&o[0]!==",";){let u=o.shift();if(u==="changed")c.changed=!0;else if(u==="once")c.once=!0;else if(u==="consume")c.consume=!0;else if(u==="delay"&&o[0]===":")o.shift(),c.delay=parseInterval(consumeUntil(o,WHITESPACE_OR_COMMA));else if(u==="from"&&o[0]===":"){if(o.shift(),COMBINED_SELECTOR_START.test(o[0]))var i=consumeCSSSelector(o);else{var i=consumeUntil(o,WHITESPACE_OR_COMMA);if(i==="closest"||i==="find"||i==="next"||i==="previous"){o.shift();let m=consumeCSSSelector(o);m.length>0&&(i+=" "+m)}}c.from=i}else u==="target"&&o[0]===":"?(o.shift(),c.target=consumeCSSSelector(o)):u==="throttle"&&o[0]===":"?(o.shift(),c.throttle=parseInterval(consumeUntil(o,WHITESPACE_OR_COMMA))):u==="queue"&&o[0]===":"?(o.shift(),c.queue=consumeUntil(o,WHITESPACE_OR_COMMA)):u==="root"&&o[0]===":"?(o.shift(),c[u]=consumeCSSSelector(o)):u==="threshold"&&o[0]===":"?(o.shift(),c[u]=consumeUntil(o,WHITESPACE_OR_COMMA)):triggerErrorEvent(e,"htmx:syntax:error",{token:o.shift()});consumeUntil(o,NOT_WHITESPACE)}r.push(c)}o.length===l&&triggerErrorEvent(e,"htmx:syntax:error",{token:o.shift()}),consumeUntil(o,NOT_WHITESPACE)}while(o[0]===","&&o.shift());return n&&(n[t]=r),r}function getTriggerSpecs(e){let t=getAttributeValue(e,"hx-trigger"),n=[];if(t){let r=htmx.config.triggerSpecsCache;n=r&&r[t]||parseAndCacheTrigger(e,t,r)}return n.length>0?n:matches(e,"form")?[{trigger:"submit"}]:matches(e,'input[type="button"], input[type="submit"]')?[{trigger:"click"}]:matches(e,INPUT_SELECTOR)?[{trigger:"change"}]:[{trigger:"click"}]}function cancelPolling(e){getInternalData(e).cancelled=!0}function processPolling(e,t,n){let r=getInternalData(e);r.timeout=getWindow().setTimeout(function(){bodyContains(e)&&r.cancelled!==!0&&(maybeFilterEvent(n,e,makeEvent("hx:poll:trigger",{triggerSpec:n,target:e}))||t(e),processPolling(e,t,n))},n.pollInterval)}function isLocalLink(e){return location.hostname===e.hostname&&getRawAttribute(e,"href")&&getRawAttribute(e,"href").indexOf("#")!==0}function eltIsDisabled(e){return closest(e,htmx.config.disableSelector)}function boostElement(e,t,n){if(e instanceof HTMLAnchorElement&&isLocalLink(e)&&(e.target===""||e.target==="_self")||e.tagName==="FORM"&&String(getRawAttribute(e,"method")).toLowerCase()!=="dialog"){t.boosted=!0;let r,o;if(e.tagName==="A")r="get",o=getRawAttribute(e,"href");else{let s=getRawAttribute(e,"method");r=s?s.toLowerCase():"get",o=getRawAttribute(e,"action"),(o==null||o==="")&&(o=location.href),r==="get"&&o.includes("?")&&(o=o.replace(/\?[^#]+/,""))}n.forEach(function(s){addEventListener(e,function(i,l){let a=asElement(i);if(eltIsDisabled(a)){cleanUpElement(a);return}issueAjaxRequest(r,o,a,l)},t,s,!0)})}}function shouldCancel(e,t){if(e.type==="submit"&&t.tagName==="FORM")return!0;if(e.type==="click"){let n=t.closest('input[type="submit"], button');if(n&&n.form&&n.type==="submit")return!0;let r=t.closest("a"),o=/^#.+/;if(r&&r.href&&!o.test(r.getAttribute("href")))return!0}return!1}function ignoreBoostedAnchorCtrlClick(e,t){return getInternalData(e).boosted&&e instanceof HTMLAnchorElement&&t.type==="click"&&(t.ctrlKey||t.metaKey)}function maybeFilterEvent(e,t,n){let r=e.eventFilter;if(r)try{return r.call(t,n)!==!0}catch(o){let s=r.source;return triggerErrorEvent(getDocument().body,"htmx:eventFilter:error",{error:o,source:s}),!0}return!1}function addEventListener(e,t,n,r,o){let s=getInternalData(e),i;r.from?i=querySelectorAllExt(e,r.from):i=[e],r.changed&&("lastValue"in s||(s.lastValue=new WeakMap),i.forEach(function(l){s.lastValue.has(r)||s.lastValue.set(r,new WeakMap),s.lastValue.get(r).set(l,l.value)})),forEach(i,function(l){let a=function(c){if(!bodyContains(e)){l.removeEventListener(r.trigger,a);return}if(ignoreBoostedAnchorCtrlClick(e,c)||((o||shouldCancel(c,l))&&c.preventDefault(),maybeFilterEvent(r,e,c)))return;let d=getInternalData(c);if(d.triggerSpec=r,d.handledFor==null&&(d.handledFor=[]),d.handledFor.indexOf(e)<0){if(d.handledFor.push(e),r.consume&&c.stopPropagation(),r.target&&c.target&&!matches(asElement(c.target),r.target))return;if(r.once){if(s.triggeredOnce)return;s.triggeredOnce=!0}if(r.changed){let u=c.target,f=u.value,m=s.lastValue.get(r);if(m.has(u)&&m.get(u)===f)return;m.set(u,f)}if(s.delayed&&clearTimeout(s.delayed),s.throttle)return;r.throttle>0?s.throttle||(triggerEvent(e,"htmx:trigger"),t(e,c),s.throttle=getWindow().setTimeout(function(){s.throttle=null},r.throttle)):r.delay>0?s.delayed=getWindow().setTimeout(function(){triggerEvent(e,"htmx:trigger"),t(e,c)},r.delay):(triggerEvent(e,"htmx:trigger"),t(e,c))}};n.listenerInfos==null&&(n.listenerInfos=[]),n.listenerInfos.push({trigger:r.trigger,listener:a,on:l}),l.addEventListener(r.trigger,a)})}let windowIsScrolling=!1,scrollHandler=null;function initScrollHandler(){scrollHandler||(scrollHandler=function(){windowIsScrolling=!0},window.addEventListener("scroll",scrollHandler),window.addEventListener("resize",scrollHandler),setInterval(function(){windowIsScrolling&&(windowIsScrolling=!1,forEach(getDocument().querySelectorAll("[hx-trigger*='revealed'],[data-hx-trigger*='revealed']"),function(e){maybeReveal(e)}))},200))}function maybeReveal(e){!hasAttribute(e,"data-hx-revealed")&&isScrolledIntoView(e)&&(e.setAttribute("data-hx-revealed","true"),getInternalData(e).initHash?triggerEvent(e,"revealed"):e.addEventListener("htmx:afterProcessNode",function(){triggerEvent(e,"revealed")},{once:!0}))}function loadImmediately(e,t,n,r){let o=function(){n.loaded||(n.loaded=!0,triggerEvent(e,"htmx:trigger"),t(e))};r>0?getWindow().setTimeout(o,r):o()}function processVerbs(e,t,n){let r=!1;return forEach(VERBS,function(o){if(hasAttribute(e,"hx-"+o)){let s=getAttributeValue(e,"hx-"+o);r=!0,t.path=s,t.verb=o,n.forEach(function(i){addTriggerHandler(e,i,t,function(l,a){let c=asElement(l);if(eltIsDisabled(c)){cleanUpElement(c);return}issueAjaxRequest(o,s,c,a)})})}}),r}function addTriggerHandler(e,t,n,r){if(t.trigger==="revealed")initScrollHandler(),addEventListener(e,r,n,t),maybeReveal(asElement(e));else if(t.trigger==="intersect"){let o={};t.root&&(o.root=querySelectorExt(e,t.root)),t.threshold&&(o.threshold=parseFloat(t.threshold)),new IntersectionObserver(function(i){for(let l=0;l0?(n.polling=!0,processPolling(asElement(e),r,t)):addEventListener(e,r,n,t)}function shouldProcessHxOn(e){let t=asElement(e);if(!t)return!1;let n=t.attributes;for(let r=0;r", "+s).join(""))}else return[]}function maybeSetLastButtonClicked(e){let t=getTargetButton(e.target),n=getRelatedFormData(e);n&&(n.lastButtonClicked=t)}function maybeUnsetLastButtonClicked(e){let t=getRelatedFormData(e);t&&(t.lastButtonClicked=null)}function getTargetButton(e){return closest(asElement(e),"button, input[type='submit']")}function getRelatedForm(e){return e.form||closest(e,"form")}function getRelatedFormData(e){let t=getTargetButton(e.target);if(!t)return;let n=getRelatedForm(t);if(n)return getInternalData(n)}function initButtonTracking(e){e.addEventListener("click",maybeSetLastButtonClicked),e.addEventListener("focusin",maybeSetLastButtonClicked),e.addEventListener("focusout",maybeUnsetLastButtonClicked)}function addHxOnEventHandler(e,t,n){let r=getInternalData(e);Array.isArray(r.onHandlers)||(r.onHandlers=[]);let o,s=function(i){maybeEval(e,function(){eltIsDisabled(e)||(o||(o=new Function("event",n)),o.call(e,i))})};e.addEventListener(t,s),r.onHandlers.push({event:t,listener:s})}function processHxOnWildcard(e){deInitOnHandlers(e);for(let t=0;thtmx.config.historyCacheSize;)s.shift();for(;s.length>0;)try{sessionStorage.setItem("htmx-history-cache",JSON.stringify(s));break}catch(l){triggerErrorEvent(getDocument().body,"htmx:historyCacheError",{cause:l,cache:s}),s.shift()}}function getCachedHistory(e){if(!canAccessLocalStorage())return null;e=normalizePath(e);let t=parseJSON(sessionStorage.getItem("htmx-history-cache"))||[];for(let n=0;n=200&&this.status<400?(r.response=this.response,triggerEvent(getDocument().body,"htmx:historyCacheMissLoad",r),swap(r.historyElt,r.response,n,{contextElement:r.historyElt,historyRequest:!0}),setCurrentPathForHistory(r.path),triggerEvent(getDocument().body,"htmx:historyRestore",{path:e,cacheMiss:!0,serverResponse:r.response})):triggerErrorEvent(getDocument().body,"htmx:historyCacheMissLoadError",r)},triggerEvent(getDocument().body,"htmx:historyCacheMiss",r)&&t.send()}function restoreHistory(e){saveCurrentPageToHistory(),e=e||location.pathname+location.search;let t=getCachedHistory(e);if(t){let n={swapStyle:"innerHTML",swapDelay:0,settleDelay:0,scroll:t.scroll},r={path:e,item:t,historyElt:getHistoryElement(),swapSpec:n};triggerEvent(getDocument().body,"htmx:historyCacheHit",r)&&(swap(r.historyElt,t.content,n,{contextElement:r.historyElt,title:t.title}),setCurrentPathForHistory(r.path),triggerEvent(getDocument().body,"htmx:historyRestore",r))}else htmx.config.refreshOnHistoryMiss?htmx.location.reload(!0):loadHistoryFromServer(e)}function addRequestIndicatorClasses(e){let t=findAttributeTargets(e,"hx-indicator");return t==null&&(t=[e]),forEach(t,function(n){let r=getInternalData(n);r.requestCount=(r.requestCount||0)+1,n.classList.add.call(n.classList,htmx.config.requestClass)}),t}function disableElements(e){let t=findAttributeTargets(e,"hx-disabled-elt");return t==null&&(t=[]),forEach(t,function(n){let r=getInternalData(n);r.requestCount=(r.requestCount||0)+1,n.setAttribute("disabled",""),n.setAttribute("data-disabled-by-htmx","")}),t}function removeRequestIndicators(e,t){forEach(e.concat(t),function(n){let r=getInternalData(n);r.requestCount=(r.requestCount||1)-1}),forEach(e,function(n){getInternalData(n).requestCount===0&&n.classList.remove.call(n.classList,htmx.config.requestClass)}),forEach(t,function(n){getInternalData(n).requestCount===0&&(n.removeAttribute("disabled"),n.removeAttribute("data-disabled-by-htmx"))})}function haveSeenNode(e,t){for(let n=0;nt.indexOf(o)<0):r=r.filter(o=>o!==t),n.delete(e),forEach(r,o=>n.append(e,o))}}function getValueFromInput(e){return e instanceof HTMLSelectElement&&e.multiple?toArray(e.querySelectorAll("option:checked")).map(function(t){return t.value}):e instanceof HTMLInputElement&&e.files?toArray(e.files):e.value}function processInputValue(e,t,n,r,o){if(!(r==null||haveSeenNode(e,r))){if(e.push(r),shouldInclude(r)){let s=getRawAttribute(r,"name");addValueToFormData(s,getValueFromInput(r),t),o&&validateElement(r,n)}r instanceof HTMLFormElement&&(forEach(r.elements,function(s){e.indexOf(s)>=0?removeValueFromFormData(s.name,getValueFromInput(s),t):e.push(s),o&&validateElement(s,n)}),new FormData(r).forEach(function(s,i){s instanceof File&&s.name===""||addValueToFormData(i,s,t)}))}}function validateElement(e,t){let n=e;n.willValidate&&(triggerEvent(n,"htmx:validation:validate"),n.checkValidity()||(triggerEvent(n,"htmx:validation:failed",{message:n.validationMessage,validity:n.validity})&&!t.length&&htmx.config.reportValidityOfForms&&n.reportValidity(),t.push({elt:n,message:n.validationMessage,validity:n.validity})))}function overrideFormData(e,t){for(let n of t.keys())e.delete(n);return t.forEach(function(n,r){e.append(r,n)}),e}function getInputValues(e,t){let n=[],r=new FormData,o=new FormData,s=[],i=getInternalData(e);i.lastButtonClicked&&!bodyContains(i.lastButtonClicked)&&(i.lastButtonClicked=null);let l=e instanceof HTMLFormElement&&e.noValidate!==!0||getAttributeValue(e,"hx-validate")==="true";if(i.lastButtonClicked&&(l=l&&i.lastButtonClicked.formNoValidate!==!0),t!=="get"&&processInputValue(n,o,s,getRelatedForm(e),l),processInputValue(n,r,s,e,l),i.lastButtonClicked||e.tagName==="BUTTON"||e.tagName==="INPUT"&&getRawAttribute(e,"type")==="submit"){let c=i.lastButtonClicked||e,d=getRawAttribute(c,"name");addValueToFormData(d,c.value,o)}let a=findAttributeTargets(e,"hx-include");return forEach(a,function(c){processInputValue(n,r,s,asElement(c),l),matches(c,"form")||forEach(asParentNode(c).querySelectorAll(INPUT_SELECTOR),function(d){processInputValue(n,r,s,d,l)})}),overrideFormData(r,o),{errors:s,formData:r,values:formDataProxy(r)}}function appendParam(e,t,n){e!==""&&(e+="&"),String(n)==="[object Object]"&&(n=JSON.stringify(n));let r=encodeURIComponent(n);return e+=encodeURIComponent(t)+"="+r,e}function urlEncode(e){e=formDataFromObject(e);let t="";return e.forEach(function(n,r){t=appendParam(t,r,n)}),t}function getHeaders(e,t,n){let r={"HX-Request":"true","HX-Trigger":getRawAttribute(e,"id"),"HX-Trigger-Name":getRawAttribute(e,"name"),"HX-Target":getAttributeValue(t,"id"),"HX-Current-URL":location.href};return getValuesForElement(e,"hx-headers",!1,r),n!==void 0&&(r["HX-Prompt"]=n),getInternalData(e).boosted&&(r["HX-Boosted"]="true"),r}function filterValues(e,t){let n=getClosestAttributeValue(t,"hx-params");if(n){if(n==="none")return new FormData;if(n==="*")return e;if(n.indexOf("not ")===0)return forEach(n.slice(4).split(","),function(r){r=r.trim(),e.delete(r)}),e;{let r=new FormData;return forEach(n.split(","),function(o){o=o.trim(),e.has(o)&&e.getAll(o).forEach(function(s){r.append(o,s)})}),r}}else return e}function isAnchorLink(e){return!!getRawAttribute(e,"href")&&getRawAttribute(e,"href").indexOf("#")>=0}function getSwapSpecification(e,t){let n=t||getClosestAttributeValue(e,"hx-swap"),r={swapStyle:getInternalData(e).boosted?"innerHTML":htmx.config.defaultSwapStyle,swapDelay:htmx.config.defaultSwapDelay,settleDelay:htmx.config.defaultSettleDelay};if(htmx.config.scrollIntoViewOnBoost&&getInternalData(e).boosted&&!isAnchorLink(e)&&(r.show="top"),n){let i=splitOnWhitespace(n);if(i.length>0)for(let l=0;l0?o.join(":"):null;r.scroll=d,r.scrollTarget=s}else if(a.indexOf("show:")===0){var o=a.slice(5).split(":");let u=o.pop();var s=o.length>0?o.join(":"):null;r.show=u,r.showTarget=s}else if(a.indexOf("focus-scroll:")===0){let c=a.slice(13);r.focusScroll=c=="true"}else l==0?r.swapStyle=a:logError("Unknown modifier in hx-swap: "+a)}}return r}function usesFormData(e){return getClosestAttributeValue(e,"hx-encoding")==="multipart/form-data"||matches(e,"form")&&getRawAttribute(e,"enctype")==="multipart/form-data"}function encodeParamsForBody(e,t,n){let r=null;return withExtensions(t,function(o){r==null&&(r=o.encodeParameters(e,n,t))}),r??(usesFormData(t)?overrideFormData(new FormData,formDataFromObject(n)):urlEncode(n))}function makeSettleInfo(e){return{tasks:[],elts:[e]}}function updateScrollState(e,t){let n=e[0],r=e[e.length-1];if(t.scroll){var o=null;t.scrollTarget&&(o=asElement(querySelectorExt(n,t.scrollTarget))),t.scroll==="top"&&(n||o)&&(o=o||n,o.scrollTop=0),t.scroll==="bottom"&&(r||o)&&(o=o||r,o.scrollTop=o.scrollHeight),typeof t.scroll=="number"&&getWindow().setTimeout(function(){window.scrollTo(0,t.scroll)},0)}if(t.show){var o=null;if(t.showTarget){let i=t.showTarget;t.showTarget==="window"&&(i="body"),o=asElement(querySelectorExt(n,i))}t.show==="top"&&(n||o)&&(o=o||n,o.scrollIntoView({block:"start",behavior:htmx.config.scrollBehavior})),t.show==="bottom"&&(r||o)&&(o=o||r,o.scrollIntoView({block:"end",behavior:htmx.config.scrollBehavior}))}}function getValuesForElement(e,t,n,r,o){if(r==null&&(r={}),e==null)return r;let s=getAttributeValue(e,t);if(s){let i=s.trim(),l=n;if(i==="unset")return null;i.indexOf("javascript:")===0?(i=i.slice(11),l=!0):i.indexOf("js:")===0&&(i=i.slice(3),l=!0),i.indexOf("{")!==0&&(i="{"+i+"}");let a;l?a=maybeEval(e,function(){return o?Function("event","return ("+i+")").call(e,o):Function("return ("+i+")").call(e)},{}):a=parseJSON(i);for(let c in a)a.hasOwnProperty(c)&&r[c]==null&&(r[c]=a[c])}return getValuesForElement(asElement(parentElt(e)),t,n,r,o)}function maybeEval(e,t,n){return htmx.config.allowEval?t():(triggerErrorEvent(e,"htmx:evalDisallowedError"),n)}function getHXVarsForElement(e,t,n){return getValuesForElement(e,"hx-vars",!0,n,t)}function getHXValsForElement(e,t,n){return getValuesForElement(e,"hx-vals",!1,n,t)}function getExpressionVars(e,t){return mergeObjects(getHXVarsForElement(e,t),getHXValsForElement(e,t))}function safelySetHeaderValue(e,t,n){if(n!==null)try{e.setRequestHeader(t,n)}catch{e.setRequestHeader(t,encodeURIComponent(n)),e.setRequestHeader(t+"-URI-AutoEncoded","true")}}function getPathFromResponse(e){if(e.responseURL)try{let t=new URL(e.responseURL);return t.pathname+t.search}catch{triggerErrorEvent(getDocument().body,"htmx:badResponseUrl",{url:e.responseURL})}}function hasHeader(e,t){return t.test(e.getAllResponseHeaders())}function ajaxHelper(e,t,n){if(e=e.toLowerCase(),n){if(n instanceof Element||typeof n=="string")return issueAjaxRequest(e,t,null,null,{targetOverride:resolveTarget(n)||DUMMY_ELT,returnPromise:!0});{let r=resolveTarget(n.target);return(n.target&&!r||n.source&&!r&&!resolveTarget(n.source))&&(r=DUMMY_ELT),issueAjaxRequest(e,t,resolveTarget(n.source),n.event,{handler:n.handler,headers:n.headers,values:n.values,targetOverride:r,swapOverride:n.swap,select:n.select,returnPromise:!0,push:n.push,replace:n.replace,selectOOB:n.selectOOB})}}else return issueAjaxRequest(e,t,null,null,{returnPromise:!0})}function hierarchyForElt(e){let t=[];for(;e;)t.push(e),e=e.parentElement;return t}function verifyPath(e,t,n){let r=new URL(t,location.protocol!=="about:"?location.href:window.origin),s=(location.protocol!=="about:"?location.origin:window.origin)===r.origin;return htmx.config.selfRequestsOnly&&!s?!1:triggerEvent(e,"htmx:validateUrl",mergeObjects({url:r,sameHost:s},n))}function formDataFromObject(e){if(e instanceof FormData)return e;let t=new FormData;for(let n in e)e.hasOwnProperty(n)&&(e[n]&&typeof e[n].forEach=="function"?e[n].forEach(function(r){t.append(n,r)}):typeof e[n]=="object"&&!(e[n]instanceof Blob)?t.append(n,JSON.stringify(e[n])):t.append(n,e[n]));return t}function formDataArrayProxy(e,t,n){return new Proxy(n,{get:function(r,o){return typeof o=="number"?r[o]:o==="length"?r.length:o==="push"?function(s){r.push(s),e.append(t,s)}:typeof r[o]=="function"?function(){r[o].apply(r,arguments),e.delete(t),r.forEach(function(s){e.append(t,s)})}:r[o]&&r[o].length===1?r[o][0]:r[o]},set:function(r,o,s){return r[o]=s,e.delete(t),r.forEach(function(i){e.append(t,i)}),!0}})}function formDataProxy(e){return new Proxy(e,{get:function(t,n){if(typeof n=="symbol"){let o=Reflect.get(t,n);return typeof o=="function"?function(){return o.apply(e,arguments)}:o}if(n==="toJSON")return()=>Object.fromEntries(e);if(n in t&&typeof t[n]=="function")return function(){return e[n].apply(e,arguments)};let r=e.getAll(n);if(r.length!==0)return r.length===1?r[0]:formDataArrayProxy(t,n,r)},set:function(t,n,r){return typeof n!="string"?!1:(t.delete(n),r&&typeof r.forEach=="function"?r.forEach(function(o){t.append(n,o)}):typeof r=="object"&&!(r instanceof Blob)?t.append(n,JSON.stringify(r)):t.append(n,r),!0)},deleteProperty:function(t,n){return typeof n=="string"&&t.delete(n),!0},ownKeys:function(t){return Reflect.ownKeys(Object.fromEntries(t))},getOwnPropertyDescriptor:function(t,n){return Reflect.getOwnPropertyDescriptor(Object.fromEntries(t),n)}})}function issueAjaxRequest(e,t,n,r,o,s){let i=null,l=null;if(o=o??{},o.returnPromise&&typeof Promise<"u")var a=new Promise(function(g,b){i=g,l=b});n==null&&(n=getDocument().body);let c=o.handler||handleAjaxResponse,d=o.select||null;if(!bodyContains(n))return maybeCall(i),a;let u=o.targetOverride||asElement(getTarget(n));if(u==null||u==DUMMY_ELT)return triggerErrorEvent(n,"htmx:targetError",{target:getClosestAttributeValue(n,"hx-target")}),maybeCall(l),a;let f=getInternalData(n),m=f.lastButtonClicked;if(m){let g=getRawAttribute(m,"formaction");g!=null&&(t=g);let b=getRawAttribute(m,"formmethod");if(b!=null)if(VERBS.includes(b.toLowerCase()))e=b;else return maybeCall(i),a}let h=getClosestAttributeValue(n,"hx-confirm");if(s===void 0&&triggerEvent(n,"htmx:confirm",{target:u,elt:n,path:t,verb:e,triggeringEvent:r,etc:o,issueRequest:function(L){return issueAjaxRequest(e,t,n,r,o,!!L)},question:h})===!1)return maybeCall(i),a;let y=n,p=getClosestAttributeValue(n,"hx-sync"),w=null,T=!1;if(p){let g=p.split(":"),b=g[0].trim();if(b==="this"?y=findThisElement(n,"hx-sync"):y=asElement(querySelectorExt(n,b)),p=(g[1]||"drop").trim(),f=getInternalData(y),p==="drop"&&f.xhr&&f.abortable!==!0)return maybeCall(i),a;if(p==="abort"){if(f.xhr)return maybeCall(i),a;T=!0}else p==="replace"?triggerEvent(y,"htmx:abort"):p.indexOf("queue")===0&&(w=(p.split(" ")[1]||"last").trim())}if(f.xhr)if(f.abortable)triggerEvent(y,"htmx:abort");else{if(w==null){if(r){let g=getInternalData(r);g&&g.triggerSpec&&g.triggerSpec.queue&&(w=g.triggerSpec.queue)}w==null&&(w="last")}return f.queuedRequests==null&&(f.queuedRequests=[]),w==="first"&&f.queuedRequests.length===0?f.queuedRequests.push(function(){issueAjaxRequest(e,t,n,r,o)}):w==="all"?f.queuedRequests.push(function(){issueAjaxRequest(e,t,n,r,o)}):w==="last"&&(f.queuedRequests=[],f.queuedRequests.push(function(){issueAjaxRequest(e,t,n,r,o)})),maybeCall(i),a}let v=new XMLHttpRequest;f.xhr=v,f.abortable=T;let E=function(){f.xhr=null,f.abortable=!1,f.queuedRequests!=null&&f.queuedRequests.length>0&&f.queuedRequests.shift()()},Q=getClosestAttributeValue(n,"hx-prompt");if(Q){var U=prompt(Q);if(U===null||!triggerEvent(n,"htmx:prompt",{prompt:U,target:u}))return maybeCall(i),E(),a}if(h&&!s&&!confirm(h))return maybeCall(i),E(),a;let I=getHeaders(n,u,U);e!=="get"&&!usesFormData(n)&&(I["Content-Type"]="application/x-www-form-urlencoded"),o.headers&&(I=mergeObjects(I,o.headers));let Z=getInputValues(n,e),q=Z.errors,ee=Z.formData;o.values&&overrideFormData(ee,formDataFromObject(o.values));let ve=formDataFromObject(getExpressionVars(n,r)),V=overrideFormData(ee,ve),H=filterValues(V,n);htmx.config.getCacheBusterParam&&e==="get"&&H.set("org.htmx.cache-buster",getRawAttribute(u,"id")||"true"),(t==null||t==="")&&(t=location.href);let j=getValuesForElement(n,"hx-request"),te=getInternalData(n).boosted,k=htmx.config.methodsThatUseUrlParams.indexOf(e)>=0,S={boosted:te,useUrlParams:k,formData:H,parameters:formDataProxy(H),unfilteredFormData:V,unfilteredParameters:formDataProxy(V),headers:I,elt:n,target:u,verb:e,errors:q,withCredentials:o.credentials||j.credentials||htmx.config.withCredentials,timeout:o.timeout||j.timeout||htmx.config.timeout,path:t,triggeringEvent:r};if(!triggerEvent(n,"htmx:configRequest",S))return maybeCall(i),E(),a;if(t=S.path,e=S.verb,I=S.headers,H=formDataFromObject(S.parameters),q=S.errors,k=S.useUrlParams,q&&q.length>0)return triggerEvent(n,"htmx:validation:halted",S),maybeCall(i),E(),a;let ne=t.split("#"),be=ne[0],W=ne[1],A=t;if(k&&(A=be,!H.keys().next().done&&(A.indexOf("?")<0?A+="?":A+="&",A+=urlEncode(H),W&&(A+="#"+W))),!verifyPath(n,A,S))return triggerErrorEvent(n,"htmx:invalidPath",S),maybeCall(l),E(),a;if(v.open(e.toUpperCase(),A,!0),v.overrideMimeType("text/html"),v.withCredentials=S.withCredentials,v.timeout=S.timeout,!j.noHeaders){for(let g in I)if(I.hasOwnProperty(g)){let b=I[g];safelySetHeaderValue(v,g,b)}}let x={xhr:v,target:u,requestConfig:S,etc:o,boosted:te,select:d,pathInfo:{requestPath:t,finalRequestPath:A,responsePath:null,anchor:W}};if(v.onload=function(){try{let g=hierarchyForElt(n);if(x.pathInfo.responsePath=getPathFromResponse(v),c(n,x),x.keepIndicators!==!0&&removeRequestIndicators(N,P),triggerEvent(n,"htmx:afterRequest",x),triggerEvent(n,"htmx:afterOnLoad",x),!bodyContains(n)){let b=null;for(;g.length>0&&b==null;){let L=g.shift();bodyContains(L)&&(b=L)}b&&(triggerEvent(b,"htmx:afterRequest",x),triggerEvent(b,"htmx:afterOnLoad",x))}maybeCall(i)}catch(g){throw triggerErrorEvent(n,"htmx:onLoadError",mergeObjects({error:g},x)),g}finally{E()}},v.onerror=function(){removeRequestIndicators(N,P),triggerErrorEvent(n,"htmx:afterRequest",x),triggerErrorEvent(n,"htmx:sendError",x),maybeCall(l),E()},v.onabort=function(){removeRequestIndicators(N,P),triggerErrorEvent(n,"htmx:afterRequest",x),triggerErrorEvent(n,"htmx:sendAbort",x),maybeCall(l),E()},v.ontimeout=function(){removeRequestIndicators(N,P),triggerErrorEvent(n,"htmx:afterRequest",x),triggerErrorEvent(n,"htmx:timeout",x),maybeCall(l),E()},!triggerEvent(n,"htmx:beforeRequest",x))return maybeCall(i),E(),a;var N=addRequestIndicatorClasses(n),P=disableElements(n);forEach(["loadstart","loadend","progress","abort"],function(g){forEach([v,v.upload],function(b){b.addEventListener(g,function(L){triggerEvent(n,"htmx:xhr:"+g,{lengthComputable:L.lengthComputable,loaded:L.loaded,total:L.total})})})}),triggerEvent(n,"htmx:beforeSend",x);let we=k?null:encodeParamsForBody(v,n,H);return v.send(we),a}function determineHistoryUpdates(e,t){let n=t.xhr,r=null,o=null;if(hasHeader(n,/HX-Push:/i)?(r=n.getResponseHeader("HX-Push"),o="push"):hasHeader(n,/HX-Push-Url:/i)?(r=n.getResponseHeader("HX-Push-Url"),o="push"):hasHeader(n,/HX-Replace-Url:/i)&&(r=n.getResponseHeader("HX-Replace-Url"),o="replace"),r)return r==="false"?{}:{type:o,path:r};let s=t.pathInfo.finalRequestPath,i=t.pathInfo.responsePath,l=t.etc.push||getClosestAttributeValue(e,"hx-push-url"),a=t.etc.replace||getClosestAttributeValue(e,"hx-replace-url"),c=getInternalData(e).boosted,d=null,u=null;return l?(d="push",u=l):a?(d="replace",u=a):c&&(d="push",u=i||s),u?u==="false"?{}:(u==="true"&&(u=i||s),t.pathInfo.anchor&&u.indexOf("#")===-1&&(u=u+"#"+t.pathInfo.anchor),{type:d,path:u}):{}}function codeMatches(e,t){var n=new RegExp(e.code);return n.test(t.toString(10))}function resolveResponseHandling(e){for(var t=0;t.${t}{opacity:0;visibility: hidden} .${n} .${t}, .${n}.${t}{opacity:1;visibility: visible;transition: opacity 200ms ease-in}`)}}function getMetaConfig(){let e=getDocument().querySelector('meta[name="htmx-config"]');return e?parseJSON(e.content):null}function mergeMetaConfig(){let e=getMetaConfig();e&&(htmx.config=mergeObjects(htmx.config,e))}return ready(function(){mergeMetaConfig(),insertIndicatorStyles();let e=getDocument().body;processNode(e);let t=getDocument().querySelectorAll("[hx-trigger='restored'],[data-hx-trigger='restored']");e.addEventListener("htmx:abort",function(r){let o=r.detail.elt||r.target,s=getInternalData(o);s&&s.xhr&&s.xhr.abort()});let n=window.onpopstate?window.onpopstate.bind(window):null;window.onpopstate=function(r){r.state&&r.state.htmx?(restoreHistory(),forEach(t,function(o){triggerEvent(o,"htmx:restored",{document:getDocument(),triggerEvent})})):n&&n(r)},getWindow().setTimeout(function(){triggerEvent(e,"htmx:load",{}),e=null},0)}),htmx})(),D=xe;(function(){let e;D.defineExtension("json-enc",{init:function(t){e=t},onEvent:function(t,n){t==="htmx:configRequest"&&(n.detail.headers["Content-Type"]="application/json")},encodeParameters:function(t,n,r){t.overrideMimeType("text/json");let o={};n.forEach(function(i,l){Object.hasOwn(o,l)?(Array.isArray(o[l])||(o[l]=[o[l]]),o[l].push(i)):o[l]=i});let s=e.getExpressionVars(r);return Object.keys(o).forEach(function(i){o[i]=Object.hasOwn(s,i)?s[i]:o[i]}),JSON.stringify(o)}})})();var re="https://typeahead.waow.tech",se="https://public.api.bsky.app",Te="/xrpc/app.bsky.actor.searchActorsTypeahead",Se="/xrpc/app.bsky.actor.getProfiles";var Ce="atcr_recent_handles",ie="atcr_recent_profile_cache";var z=class{constructor(t){this.input=t,this.container=t.closest(".sailor-typeahead")||t.parentElement,this.dropdown=null,this.selectedCard=null,this.actors=[],this.currentItems=[],this.mode="hidden",this.focusIndex=-1,this.debounceTimer=null,this.requestSeq=0,this.primaryUnhealthyUntil=0,this.lastPrefetchPrefix="",this.lastPrefetchAt=0,this.createDropdown(),this.bindEvents(),this.input.value.trim().length===0&&this.showRecent()}createDropdown(){this.dropdown=document.createElement("div"),this.dropdown.className="sailor-typeahead-dropdown",this.dropdown.setAttribute("role","listbox"),this.dropdown.style.display="none",this.input.insertAdjacentElement("afterend",this.dropdown)}bindEvents(){this.input.addEventListener("focus",()=>this.handleFocus()),this.input.addEventListener("input",()=>this.handleInput()),this.input.addEventListener("keydown",t=>this.handleKeydown(t)),document.addEventListener("click",t=>{!this.input.contains(t.target)&&!this.dropdown.contains(t.target)&&this.hide()}),document.addEventListener("keydown",t=>{t.key==="Escape"&&this.selectedCard&&this.clearSelection()})}handleFocus(){this.input.value.trim().length===0&&this.showRecent()}handleInput(){let t=this.input.value.trim();if(t.length===0){this.showRecent();return}if(t.length>=2&&t.length<4){this.hide(),this.schedulePrefetch(t);return}if(t.length>=4){this.scheduleSearch(t);return}this.hide()}schedulePrefetch(t){clearTimeout(this.debounceTimer),this.debounceTimer=setTimeout(()=>this.runPrefetch(t),150)}scheduleSearch(t){clearTimeout(this.debounceTimer),this.debounceTimer=setTimeout(()=>this.runSearch(t),150)}async runPrefetch(t){let n=Date.now();if(!(t===this.lastPrefetchPrefix&&n-this.lastPrefetchAt<1e4)&&!(n=this.primaryUnhealthyUntil)try{r=await X(re,t,1500)}catch{this.primaryUnhealthyUntil=Date.now()+6e4}if(r===null)try{r=await X(se,t,1500)}catch{r=[]}n===this.requestSeq&&(this.actors=r||[],this.focusIndex=-1,this.renderResults())}renderResults(){if(this.mode="results",this.dropdown.innerHTML="",this.currentItems=[],this.actors.length===0){this.hide();return}this.actors.forEach((t,n)=>{this.currentItems.push(t),this.dropdown.appendChild(this.buildActorRow(t,n))}),this.dropdown.style.display="block"}buildActorRow(t,n){let r=document.createElement("div");r.className="sailor-typeahead-item",r.setAttribute("role","option"),r.dataset.index=String(n),r.dataset.handle=t.handle;let o=document.createElement("div");if(o.className="sailor-typeahead-avatar",t.avatar){let a=document.createElement("img");a.src=t.avatar,a.alt="",a.loading="lazy",o.appendChild(a)}let s=document.createElement("div");s.className="sailor-typeahead-text";let i=t.displayName&&t.displayName!==t.handle;if(i){let a=document.createElement("div");a.className="sailor-typeahead-name",a.textContent=t.displayName,s.appendChild(a)}let l=document.createElement("div");return l.className=i?"sailor-typeahead-handle":"sailor-typeahead-name",l.textContent="@"+t.handle,s.appendChild(l),r.append(o,s),r.addEventListener("mousedown",a=>{a.preventDefault(),this.select(t)}),r}showRecent(){let t=Le();if(t.length===0){this.hide();return}this.mode="recent",this.focusIndex=-1,this.renderRecent(t),this.enrichRecent(t)}renderRecent(t){let n=F();this.dropdown.innerHTML="",this.currentItems=[];let r=document.createElement("div");r.className="sailor-typeahead-header",r.textContent="Recent accounts",this.dropdown.appendChild(r),t.forEach((o,s)=>{let i=n[o]?.profile||{handle:o};this.currentItems.push(i),this.dropdown.appendChild(this.buildActorRow(i,s))}),this.dropdown.style.display="block"}async enrichRecent(t){let n=F(),r=Date.now(),o=t.filter(l=>{let a=n[l];return!a||r-a.ts>864e5});if(o.length===0)return;let s=await Ae(o);if(s.length===0)return;let i=F();s.forEach(l=>{i[l.handle]={ts:r,profile:{handle:l.handle,displayName:l.displayName,avatar:l.avatar}}}),oe(i),this.mode==="recent"&&this.renderRecent(t)}hide(){this.mode="hidden",this.focusIndex=-1,this.dropdown.style.display="none"}select(t){if(typeof t=="string"&&(t={handle:t}),this.input.value=t.handle,this.hide(),this.showSelectedCard(t),t.handle){let n=F();n[t.handle]={ts:Date.now(),profile:{handle:t.handle,displayName:t.displayName,avatar:t.avatar}},oe(n)}}showSelectedCard(t){this.clearSelectedCard();let n=document.createElement("div");n.className="sailor-typeahead-selected";let r=document.createElement("div");if(r.className="sailor-typeahead-avatar",t.avatar){let a=document.createElement("img");a.src=t.avatar,a.alt="",r.appendChild(a)}let o=document.createElement("div");o.className="sailor-typeahead-text";let s=t.displayName&&t.displayName!==t.handle;if(s){let a=document.createElement("div");a.className="sailor-typeahead-name",a.textContent=t.displayName,o.appendChild(a)}let i=document.createElement("div");i.className=s?"sailor-typeahead-handle":"sailor-typeahead-name",i.textContent="@"+t.handle,o.appendChild(i);let l=document.createElement("button");l.type="button",l.className="sailor-typeahead-clear",l.tabIndex=-1,l.setAttribute("aria-label","Change account"),l.innerHTML="×",l.addEventListener("click",()=>this.clearSelection()),n.append(r,o,l),this.input.style.display="none",this.input.insertAdjacentElement("beforebegin",n),this.selectedCard=n}clearSelectedCard(){this.selectedCard&&(this.selectedCard.remove(),this.selectedCard=null)}clearSelection(){this.clearSelectedCard(),this.input.style.display="",this.input.value="",this.input.focus(),this.showRecent()}handleKeydown(t){if(this.mode==="hidden")return;let n=this.dropdown.querySelectorAll(".sailor-typeahead-item");n.length!==0&&(t.key==="ArrowDown"?(t.preventDefault(),this.focusIndex=(this.focusIndex+1)%n.length,this.updateFocus(n)):t.key==="ArrowUp"?(t.preventDefault(),this.focusIndex=this.focusIndex<=0?n.length-1:this.focusIndex-1,this.updateFocus(n)):t.key==="Enter"?this.focusIndex>=0&&this.currentItems[this.focusIndex]&&(t.preventDefault(),this.select(this.currentItems[this.focusIndex])):t.key==="Escape"?this.hide():t.key==="Tab"&&this.focusIndex===-1&&n.length>0&&(t.preventDefault(),this.focusIndex=0,this.updateFocus(n)))}updateFocus(t){t.forEach((n,r)=>{n.classList.toggle("focused",r===this.focusIndex),r===this.focusIndex&&n.scrollIntoView({block:"nearest"})})}};async function X(e,t,n){let r=new URL(Te,e);r.searchParams.set("q",t),r.searchParams.set("limit",String(8));let o=new AbortController,s=setTimeout(()=>o.abort(),n);try{let i=await fetch(r,{signal:o.signal});if(!i.ok)throw new Error("HTTP "+i.status);let l=await i.json();return Array.isArray(l.actors)?l.actors:[]}finally{clearTimeout(s)}}async function Ae(e){if(e.length===0)return[];let t=new URL(Se,se);e.forEach(o=>t.searchParams.append("actors",o));let n=new AbortController,r=setTimeout(()=>n.abort(),3e3);try{let o=await fetch(t,{signal:n.signal});if(!o.ok)return[];let s=await o.json();return Array.isArray(s.profiles)?s.profiles:[]}catch{return[]}finally{clearTimeout(r)}}function F(){try{return JSON.parse(localStorage.getItem(ie)||"{}")}catch{return{}}}function oe(e){try{localStorage.setItem(ie,JSON.stringify(e))}catch{}}function Le(){try{let e=localStorage.getItem(Ce);return e?JSON.parse(e):[]}catch{return[]}}document.addEventListener("DOMContentLoaded",()=>{let e=document.getElementById("handle");e&&new z(e)});function ue(){return localStorage.getItem("theme")||"system"}function Ie(e){return e==="dark"||e==="light"?e:window.matchMedia("(prefers-color-scheme: dark)").matches?"dark":"light"}function J(){let e=ue(),n=Ie(e)==="dark";document.documentElement.classList.toggle("dark",n),document.documentElement.setAttribute("data-theme",n?"dark":"light"),He(e)}function de(e){localStorage.setItem("theme",e),J(),De()}function He(e){let t={system:"sun-moon",light:"sun",dark:"moon"};document.querySelectorAll("[data-theme-icon] use").forEach(n=>{n.setAttribute("href",`/icons.svg#${t[e]||"sun-moon"}`)}),document.querySelectorAll(".theme-option").forEach(n=>{let r=n.dataset.value===e;n.setAttribute("aria-checked",r?"true":"false");let o=n.querySelector(".theme-check");o&&(o.style.visibility=r?"visible":"hidden")})}function De(){document.querySelectorAll("[data-theme-toggle]").forEach(e=>{let t=e.closest("details");t&&t.removeAttribute("open")})}window.matchMedia("(prefers-color-scheme: dark)").addEventListener("change",()=>{ue()==="system"&&J()});function fe(e,t){if(!e)return;let n=e.querySelector(".nav-search-form"),r=e.querySelector('button[aria-controls="nav-search-form"]');e.classList.toggle("expanded",t),n&&(t?n.removeAttribute("inert"):n.setAttribute("inert","")),r&&r.setAttribute("aria-expanded",t?"true":"false")}function Re(){let e=document.querySelector(".nav-search-wrapper");if(!e)return;let t=!e.classList.contains("expanded");if(fe(e,t),t){let n=document.getElementById("nav-search-input");n&&n.focus()}}function ae(){fe(document.querySelector(".nav-search-wrapper"),!1)}document.addEventListener("DOMContentLoaded",()=>{let e=document.querySelector(".nav-search-wrapper"),t=document.getElementById("nav-search-input");!e||!t||(document.addEventListener("keydown",n=>{if(n.key==="Escape"&&e.classList.contains("expanded")&&ae(),n.key==="/"&&!e.classList.contains("expanded")){let r=n.target.tagName;if(r==="INPUT"||r==="TEXTAREA"||n.target.isContentEditable)return;n.preventDefault(),e.classList.add("expanded"),t.focus()}}),document.addEventListener("click",n=>{e.classList.contains("expanded")&&!e.contains(n.target)&&ae()}))});function $(e,t){let n=()=>{if(!t)return;let r=t.innerHTML;t.innerHTML=' Copied!',setTimeout(()=>{t.innerHTML=r},2e3)};if(navigator.clipboard&&window.isSecureContext){navigator.clipboard.writeText(e).then(n).catch(r=>{console.error("Clipboard API failed, falling back:",r),le(e)?n():C("Copy failed \u2014 check browser permissions","error")});return}le(e)?n():C("Copy failed \u2014 select the text and copy manually","error")}function le(e){let t=document.createElement("textarea");t.value=e,t.setAttribute("readonly",""),t.setAttribute("aria-hidden","true"),t.style.position="fixed",t.style.top="0",t.style.left="0",t.style.width="1px",t.style.height="1px",t.style.opacity="0",t.style.pointerEvents="none",document.body.appendChild(t);let n=!1;try{t.focus(),t.select(),t.setSelectionRange(0,e.length),n=document.execCommand&&document.execCommand("copy")}catch{n=!1}return document.body.removeChild(t),!!n}function Oe(e){let t=s=>{let i=(s==null?"":String(s)).replace(/\s+/g," ").trim();return/[",\n\r]/.test(i)?'"'+i.replace(/"/g,'""')+'"':i},n=s=>Array.from(s).map(i=>t(i.textContent)).join(","),r=[],o=e.querySelector("thead tr");return o&&r.push(n(o.querySelectorAll("th,td"))),e.querySelectorAll("tbody tr").forEach(s=>{r.push(n(s.querySelectorAll("td,th")))}),r.join(`
+`)}document.addEventListener("DOMContentLoaded",()=>{document.addEventListener("click",e=>{let t=e.target.closest("button[data-copy-csv]");if(t){let r=t.closest("[data-csv-section]"),o=r&&r.querySelector("table");o&&$(Oe(o),t);return}let n=e.target.closest("button[data-cmd]");if(n){$(n.getAttribute("data-cmd"),n);return}})});function Me(e){let t=Math.floor((new Date-new Date(e))/1e3),n={year:31536e3,month:2592e3,week:604800,day:86400,hour:3600,minute:60,second:1};for(let[r,o]of Object.entries(n)){let s=Math.floor(t/o);if(s>=1)return s===1?`1 ${r} ago`:`${s} ${r}s ago`}return"just now"}function B(){document.querySelectorAll("time[datetime]").forEach(e=>{let t=e.getAttribute("datetime");if(t&&!e.dataset.noUpdate){let n=Me(t);e.textContent!==n&&(e.textContent=n)}})}document.addEventListener("DOMContentLoaded",()=>{B(),J(),document.querySelectorAll("[data-theme-menu]").forEach(e=>{e.querySelectorAll(".theme-option").forEach(t=>{t.addEventListener("click",()=>{de(t.dataset.value)})})}),document.addEventListener("click",e=>{let t=e.target.closest("details.dropdown");document.querySelectorAll("details.dropdown[open]").forEach(n=>{n!==t&&n.removeAttribute("open")})})});document.addEventListener("htmx:afterSwap",B);var R=null;function he(){R===null&&(R=setInterval(B,6e4))}function qe(){R!==null&&(clearInterval(R),R=null)}document.addEventListener("visibilitychange",()=>{document.visibilityState==="hidden"?qe():(B(),he())});he();async function ke(e,t,n){try{let r=await fetch("/api/manifests",{method:"DELETE",credentials:"include",headers:{"Content-Type":"application/json"},body:JSON.stringify({repo:e,digest:t,confirm:!1})});if(r.status===409){let o=await r.json();Ne(e,t,n,o.tags)}else if(r.ok)me(n);else{let o=await r.text();C(`Failed to delete manifest: ${o||r.status}`,"error")}}catch(r){console.error("Error deleting manifest:",r),C(`Error deleting manifest: ${r.message}`,"error")}}function Ne(e,t,n,r){let o=document.getElementById("manifest-delete-modal"),s=document.getElementById("manifest-delete-tags"),i=document.getElementById("confirm-manifest-delete-btn");s.innerHTML="",r.forEach(l=>{let a=document.createElement("li");a.textContent=l,s.appendChild(a)}),i.onclick=()=>Pe(e,t,n),K(o)}function Y(){O(document.getElementById("manifest-delete-modal"))}async function Pe(e,t,n){let r=document.getElementById("confirm-manifest-delete-btn"),o=r.textContent;try{r.disabled=!0,r.textContent="Deleting...";let s=await fetch("/api/manifests",{method:"DELETE",credentials:"include",headers:{"Content-Type":"application/json"},body:JSON.stringify({repo:e,digest:t,confirm:!0})});if(s.ok)Y(),me(n),location.reload();else{let i=await s.text();C(`Failed to delete manifest: ${i||s.status}`,"error"),r.disabled=!1,r.textContent=o}}catch(s){console.error("Error deleting manifest:",s),C(`Error deleting manifest: ${s.message}`,"error"),r.disabled=!1,r.textContent=o}}async function Fe(e){let t=document.getElementById("confirm-untagged-delete-btn"),n=t.textContent;try{t.disabled=!0,t.textContent="Deleting...";let r=await fetch("/api/manifests/untagged",{method:"DELETE",credentials:"include",headers:{"Content-Type":"application/json"},body:JSON.stringify({repo:e})}),o=await r.json();r.ok?(O(document.getElementById("untagged-delete-modal")),C(`Deleted ${o.deleted} untagged manifest(s)`,"success"),o.deleted>0&&location.reload(),t.disabled=!1,t.textContent=n):(C(`Failed to delete untagged manifests: ${o.error||"Unknown error"}`,"error"),t.disabled=!1,t.textContent=n)}catch(r){console.error("Error deleting untagged manifests:",r),C(`Error: ${r.message}`,"error"),t.disabled=!1,t.textContent=n}}function me(e){let t=document.getElementById(`manifest-${e}`);t&&t.remove()}document.addEventListener("DOMContentLoaded",()=>{let e=document.getElementById("manifest-delete-modal");e&&e.addEventListener("click",t=>{t.target===e&&Y()})});var M=new WeakMap;function K(e,t){if(e&&(M.set(e,t||document.activeElement),typeof e.showModal=="function")){e.open&&(e.open=!1);try{e.showModal()}catch{}}}function O(e,{remove:t=!1}={}){if(!e)return;let n=M.get(e);if(M.delete(e),typeof e.close=="function"&&e.open)try{e.close()}catch{}t&&e.remove(),ge(n)}function ge(e){e&&typeof e.focus=="function"&&document.contains(e)&&e.focus()}document.addEventListener("close",e=>{let t=e.target;if(!(t instanceof HTMLDialogElement))return;let n=M.get(t);M.delete(t),ge(n)},!0);document.body.addEventListener("htmx:afterSettle",()=>{document.querySelectorAll("dialog.modal-open:not([data-modal-promoted]), dialog[open]:not([data-modal-promoted])").forEach(t=>{t.dataset.modalPromoted="1",K(t)})});document.addEventListener("change",e=>{let t=e.target.closest("select[data-diff-url]");if(!t)return;let n=t.dataset.diffUrl;n&&(window.location.href=n.replace("__VALUE__",encodeURIComponent(t.value)))});document.addEventListener("DOMContentLoaded",()=>{let e=document.getElementById("pull-cmd-container");if(!e)return;let t=e.dataset.registryUrl,n=e.dataset.ownerHandle,r=e.dataset.repoName,o=e.dataset.tag||"latest",s=e.dataset.isLoggedIn==="true";function i(a){let d=(a==="none"?"":a+" pull ")+t+"/"+n+"/"+r+":"+o,u=document.getElementById("pull-cmd-display");if(!u)return;let f=u.querySelector("code");f&&(f.textContent=d);let m=u.querySelector("[data-cmd]");m&&(m.dataset.cmd=d),s&&window.htmx?window.htmx.ajax("POST","/api/profile/oci-client",{values:{oci_client:a},swap:"none"}):s||localStorage.setItem("oci-client",a)}if(!s){let a=localStorage.getItem("oci-client");if(a){let c=document.getElementById("oci-client-switcher");c&&(c.value=a,i(a))}}let l=document.getElementById("oci-client-switcher");l&&l.addEventListener("change",()=>i(l.value))});document.addEventListener("DOMContentLoaded",()=>{let e=document.querySelectorAll(".platform-tab[data-platform]");e.length&&e.forEach(t=>{t.addEventListener("click",()=>{e.forEach(r=>{let o=r===t;r.classList.toggle("btn-primary",o),r.classList.toggle("btn-ghost",!o)}),document.querySelectorAll(".platform-content").forEach(r=>r.classList.add("hidden"));let n=document.getElementById(t.dataset.platform+"-content");n&&n.classList.remove("hidden")})})});document.addEventListener("DOMContentLoaded",()=>{let e=document.getElementById("login-form");e&&e.addEventListener("submit",()=>{let t=e.querySelector('button[type="submit"]');!t||t.disabled||(t.disabled=!0,t.innerHTML=' Navigating…')})});document.addEventListener("DOMContentLoaded",()=>{let e=document.cookie.split("; ").find(n=>n.startsWith("atcr_login_handle="));if(!e)return;let t=decodeURIComponent(e.split("=")[1]);if(t){try{let n="atcr_recent_handles",r=JSON.parse(localStorage.getItem(n)||"[]");r=r.filter(o=>o!==t),r.unshift(t),r=r.slice(0,5),localStorage.setItem(n,JSON.stringify(r))}catch(n){console.error("Failed to save recent account:",n)}document.cookie="atcr_login_handle=; path=/; max-age=0"}});function ce(){let e=document.getElementById("featured-carousel"),t=document.getElementById("carousel-prev"),n=document.getElementById("carousel-next");if(!e)return;let r=e.querySelectorAll(".carousel-item");if(r.length===0)return;let o=null,s=5e3,i=0,l=0;function a(){let m=parseFloat(getComputedStyle(e).gap)||24;i=r[0].offsetWidth+m}a(),window.addEventListener("resize",()=>{cancelAnimationFrame(l),l=requestAnimationFrame(a)}),document.body.addEventListener("htmx:afterSettle",m=>{m.target&&m.target.contains&&m.target.contains(e)&&a()});function c(){let m=e.scrollWidth-e.clientWidth;e.scrollLeft>=m-10?e.scrollTo({left:0,behavior:"smooth"}):e.scrollBy({left:i,behavior:"smooth"})}function d(){e.scrollLeft<=10?e.scrollTo({left:e.scrollWidth,behavior:"smooth"}):e.scrollBy({left:-i,behavior:"smooth"})}function u(){o||document.visibilityState!=="hidden"&&(e.scrollWidth<=e.clientWidth+10||(o=setInterval(c,s)))}function f(){o&&(clearInterval(o),o=null)}t&&t.addEventListener("click",()=>{f(),d(),u()}),n&&n.addEventListener("click",()=>{f(),c(),u()}),e.addEventListener("mouseenter",f),e.addEventListener("mouseleave",u),document.addEventListener("visibilitychange",()=>{document.visibilityState==="hidden"?f():u()}),u()}document.addEventListener("DOMContentLoaded",()=>{"requestIdleCallback"in window?requestIdleCallback(ce,{timeout:2e3}):setTimeout(ce,100)});var Be=4,_e=1500;function C(e,t){let n=document.getElementById("toast-container");n||(n=document.createElement("div"),n.id="toast-container",n.className="toast toast-end toast-bottom z-50",n.setAttribute("aria-live","polite"),n.setAttribute("aria-atomic","false"),document.body.appendChild(n));let r=(t||"info")+"|"+e,o=Date.now(),s=n.querySelector(`[data-toast-key="${Ve(r)}"]`);if(s&&o-Number(s.dataset.toastAt)<_e){Ue(s);return}let i=t==="error",l=i?"alert-error":"alert-success",a=document.createElement("div");a.className=`alert ${l} shadow-lg transition-opacity duration-300`,a.style.willChange="opacity",a.setAttribute("role",i?"alert":"status"),a.dataset.toastKey=r,a.dataset.toastAt=String(o);let c=document.createElement("span");for(c.textContent=e,a.appendChild(c),n.appendChild(a);n.children.length>Be;)n.firstElementChild.remove();pe(a)}function pe(e){e._dismissTimer=setTimeout(()=>{e.style.opacity="0",e._removeTimer=setTimeout(()=>e.remove(),300)},3e3)}function Ue(e){clearTimeout(e._dismissTimer),clearTimeout(e._removeTimer),e.style.opacity="",e.dataset.toastAt=String(Date.now()),pe(e)}function Ve(e){return window.CSS&&CSS.escape?CSS.escape(e):String(e).replace(/[^a-zA-Z0-9_-]/g,t=>"\\"+t)}async function je(e){try{let t=await fetch(`/api/webhooks/${e}/test`,{method:"POST",credentials:"include"}),n=await t.text();n.includes('class="success"')||t.ok&&!n.includes('class="error"')?C("Test webhook delivered successfully!","success"):C("Test delivery failed \u2014 check the webhook URL","error")}catch{C("Failed to reach server","error")}}(function(){let t={"switch-repo-tab":s=>window.switchRepoTab&&window.switchRepoTab(s.dataset.tab),"switch-editor-tab":s=>window.switchEditorTab&&window.switchEditorTab(s.dataset.tab),"insert-md":s=>window.insertMd&&window.insertMd(s.dataset.mdType),"toggle-editor":s=>window.toggleOverviewEditor&&window.toggleOverviewEditor(s.dataset.show==="true"),"show-modal":s=>K(document.getElementById(s.dataset.modalId),s),"close-dialog":s=>O(s.closest("dialog")),"remove-closest-dialog":s=>O(s.closest("dialog"),{remove:!0}),"close-manifest-delete-modal":()=>window.closeManifestDeleteModal&&window.closeManifestDeleteModal(),"save-overview":()=>window.saveOverview&&window.saveOverview(),"delete-manifest":s=>window.deleteManifest&&window.deleteManifest(s.dataset.repo,s.dataset.digest,s.dataset.manifestId||""),"delete-untagged":s=>window.deleteUntaggedManifests&&window.deleteUntaggedManifests(s.dataset.repo),copy:s=>window.copyToClipboard&&window.copyToClipboard(s.dataset.copy,s),"toggle-search":()=>window.toggleSearch&&window.toggleSearch(),"switch-settings-tab":s=>window.switchSettingsTab&&window.switchSettingsTab(s.dataset.tab),"test-webhook":s=>window.testWebhook&&window.testWebhook(s.dataset.webhookId),"diff-to":(s,i)=>window.diffToTag&&window.diffToTag(i,s),"modal-backdrop-close":(s,i)=>{i.target===s&&O(s,{remove:!0})}},n={"sort-tags":s=>window.sortTags&&window.sortTags(s.value),"submit-form":s=>s.form&&s.form.requestSubmit()},r={"filter-tags":s=>window.filterTags&&window.filterTags(s.value)};function o(s,i){let l=i.target.closest("[data-action]");if(!l)return;let a=s[l.dataset.action];a&&a(l,i)}document.addEventListener("click",s=>o(t,s)),document.addEventListener("change",s=>o(n,s)),document.addEventListener("input",s=>o(r,s))})();window.setTheme=de;window.toggleSearch=Re;window.copyToClipboard=$;window.deleteManifest=ke;window.deleteUntaggedManifests=Fe;window.closeManifestDeleteModal=Y;window.showToast=C;window.testWebhook=je;function We(){let e=document.getElementById("md-editor");if(!e)return;let t=e.dataset.ownerDid,n=e.dataset.repository;window.toggleOverviewEditor=function(r){document.getElementById("overview-view").classList.toggle("hidden",r),document.getElementById("overview-edit").classList.toggle("hidden",!r),r&&e.focus()},window.switchEditorTab=function(r){if(document.querySelectorAll(".editor-panel").forEach(o=>o.classList.add("hidden")),document.getElementById(r==="write"?"editor-write":"editor-preview").classList.remove("hidden"),document.querySelectorAll(".editor-tab").forEach(o=>{let s=o.dataset.tab===r;o.classList.toggle("border-primary",s),o.classList.toggle("text-primary",s),o.classList.toggle("border-transparent",!s),o.classList.toggle("text-base-content/60",!s)}),r==="preview"){let o=e.value,s=document.getElementById("preview-content");if(!o.trim()){s.innerHTML='Nothing to preview
';return}s.innerHTML=' Rendering preview…
';let i=new FormData;i.append("markdown",o),fetch("/api/repo-page/preview",{method:"POST",body:i}).then(l=>{if(!l.ok)throw new Error("HTTP "+l.status);return l.text()}).then(l=>{s.innerHTML=l}).catch(()=>{s.innerHTML='Preview failed. Check your connection and try again.
'})}},window.insertMd=function(r){let o=e.selectionStart,s=e.selectionEnd,i=e.value.substring(o,s),l=e.value.substring(0,o),a=e.value.substring(s),c,d,u;switch(r){case"heading":c="## "+(i||"Heading"),d=o+3,u=o+c.length;break;case"bold":c="**"+(i||"bold text")+"**",d=o+2,u=o+c.length-2;break;case"italic":c="_"+(i||"italic text")+"_",d=o+1,u=o+c.length-1;break;case"link":c="["+(i||"link text")+"](url)",d=o+c.length-4,u=o+c.length-1;break;case"image":c="",d=o+c.length-4,u=o+c.length-1;break;case"ul":c="- "+(i||"list item"),d=o+2,u=o+c.length;break;case"ol":c="1. "+(i||"list item"),d=o+3,u=o+c.length;break;case"code":i&&i.indexOf(`
+`)!==-1?(c="```\n"+i+"\n```",d=o+4,u=o+4+i.length):(c="`"+(i||"code")+"`",d=o+1,u=o+c.length-1);break;default:return}e.value=l+c+a,e.focus(),e.selectionStart=d,e.selectionEnd=u},window.saveOverview=function(){let r=document.getElementById("save-overview-btn");r.classList.add("btn-disabled"),r.innerHTML=' Saving...';let o=new FormData;o.append("did",t),o.append("repository",n),o.append("description",e.value),fetch("/api/repo-page",{method:"POST",body:o,headers:{"HX-Request":"true"}}).then(s=>s.ok?s.text():s.text().then(i=>{throw new Error(i)})).then(s=>{document.getElementById("overview-rendered").innerHTML=s,window.toggleOverviewEditor(!1),typeof window.showToast=="function"&&window.showToast("Overview saved","success")}).catch(s=>{typeof window.showToast=="function"&&window.showToast(s.message||"Failed to save","error")}).finally(()=>{r.classList.remove("btn-disabled"),r.innerHTML="Save"})},e.addEventListener("keydown",r=>{(r.ctrlKey||r.metaKey)&&r.key==="s"&&(r.preventDefault(),window.saveOverview())})}window.sortTags=function(e){let t=document.getElementById("tags-list");if(!t)return;let n=Array.from(t.querySelectorAll(".artifact-entry"));n.sort((r,o)=>{switch(e){case"oldest":return parseInt(r.dataset.created)-parseInt(o.dataset.created);case"az":return r.dataset.tag.localeCompare(o.dataset.tag);case"za":return o.dataset.tag.localeCompare(r.dataset.tag);default:return parseInt(o.dataset.created)-parseInt(r.dataset.created)}}),n.forEach(r=>t.appendChild(r))};var _=0;window.filterTags=function(e){_&&cancelAnimationFrame(_),_=requestAnimationFrame(()=>{_=0;let t=e.toLowerCase();document.querySelectorAll("#tags-list .artifact-entry").forEach(n=>{n.style.display=!t||n.dataset.tag.toLowerCase().includes(t)?"":"none"})})};function Xe(){if(!document.getElementById("tag-content"))return;let e=["overview","layers","vulns","sbom","artifacts"],t={};function n(i,l){if(t[i])return;t[i]=!0;let a=document.getElementById(i);if(!a)return;let c=new AbortController,d=setTimeout(()=>c.abort(),1e4);fetch(l,{signal:c.signal}).then(u=>{if(!u.ok)throw new Error("HTTP "+u.status);return u.text()}).then(u=>{a.innerHTML=u,a.querySelectorAll("script").forEach(f=>{let m=document.createElement("script");m.textContent=f.textContent,f.parentNode.replaceChild(m,f)}),typeof window.htmx<"u"&&window.htmx.process(a)}).catch(u=>{t[i]=!1;let m=u&&u.name==="AbortError"?"This section took too long to load.":"Couldn't load this section.";a.innerHTML=''}).finally(()=>clearTimeout(d))}document.body.addEventListener("click",i=>{let l=i.target.closest("[data-retry-section]");if(!l)return;let a=l.getAttribute("data-retry-section"),d={"artifacts-content":o,"layers-content":()=>r("layers"),"vulns-content":()=>r("vulns"),"sbom-content":()=>r("sbom")}[a];if(d){let u=d();u&&n(a,u)}});function r(i){let l=document.getElementById("tag-content");if(!l)return null;let a=l.dataset.digest;return a?"/api/digest-content/"+l.dataset.owner+"/"+l.dataset.repo+"?digest="+encodeURIComponent(a)+"§ion="+i:null}function o(){let i=document.getElementById("tag-content");return i?"/api/repo-tags/"+i.dataset.owner+"/"+i.dataset.repo:null}window.diffToTag=function(i,l){i.preventDefault();let a=l.dataset.diffTo,c=document.getElementById("tag-content"),d=document.getElementById("tag-selector");if(!c||!d||!a)return;let u=c.dataset.digest,f=d.value;!u||a===f||(window.location.href="/diff/"+c.dataset.owner+"/"+c.dataset.repo+"?from="+encodeURIComponent(u)+"&to="+encodeURIComponent(a))},window.switchRepoTab=function(i){window._activeRepoTab=i;let l=document.getElementById("tag-content");if(!l)return;l.querySelectorAll(".repo-panel").forEach(d=>d.classList.add("hidden"));let a=document.getElementById("tab-"+i);a&&a.classList.remove("hidden"),l.querySelectorAll(".repo-tab").forEach(d=>{let u=d.dataset.tab===i;d.classList.toggle("border-primary",u),d.classList.toggle("text-primary",u),d.classList.toggle("border-transparent",!u),d.classList.toggle("text-base-content/60",!u),d.setAttribute("aria-selected",u?"true":"false"),d.setAttribute("tabindex",u?"0":"-1")});let c=new URL(window.location);if(c.hash=i,history.replaceState(null,"",c.toString()),i==="artifacts"){let d=o();d&&n("artifacts-content",d)}if(i==="layers"){let d=r("layers");d&&n("layers-content",d)}if(i==="vulns"){let d=r("vulns");d&&n("vulns-content",d)}if(i==="sbom"){let d=r("sbom");d&&n("sbom-content",d)}};function s(){t={},[["artifacts-tab-btn","artifacts-content",o],["layers-tab-btn","layers-content",()=>r("layers")],["vulns-tab-btn","vulns-content",()=>r("vulns")],["sbom-tab-btn","sbom-content",()=>r("sbom")]].forEach(([c,d,u])=>{let f=document.getElementById(c);f&&f.addEventListener("mouseenter",()=>{let m=u();m&&n(d,m)},{once:!0})});let l=document.querySelector('[role="tablist"][aria-label="Repository sections"]');l&&!l.dataset.keyboardBound&&(l.dataset.keyboardBound="1",l.addEventListener("keydown",c=>{let d=Array.from(l.querySelectorAll(".repo-tab")),u=d.indexOf(document.activeElement);if(u===-1)return;let f=-1;switch(c.key){case"ArrowRight":f=(u+1)%d.length;break;case"ArrowLeft":f=(u-1+d.length)%d.length;break;case"Home":f=0;break;case"End":f=d.length-1;break;case"Enter":case" ":c.preventDefault(),window.switchRepoTab(d[u].dataset.tab);return;default:return}c.preventDefault(),d[f].focus()}));let a=window._activeRepoTab||window.location.hash.replace("#","")||"overview";e.indexOf(a)===-1&&(a="overview"),window.switchRepoTab(a)}s(),document.addEventListener("keydown",i=>{if(i.target.tagName==="INPUT"||i.target.tagName==="TEXTAREA"||i.target.tagName==="SELECT"||i.target.isContentEditable||i.ctrlKey||i.metaKey||i.altKey)return;let a={o:"overview",l:"layers",v:"vulns",s:"sbom",a:"artifacts"}[i.key.toLowerCase()];a&&e.indexOf(a)!==-1&&window.switchRepoTab(a)}),document.body.addEventListener("htmx:afterSettle",i=>{i.detail.target&&i.detail.target.id==="tag-content"&&s()})}document.addEventListener("DOMContentLoaded",()=>{We(),Xe()});function ze(){let e=["user","billing","storage","devices","webhooks","advanced"];if(!document.querySelector(".settings-tab-mobile, .menu li[data-tab]"))return;function t(a){document.querySelectorAll(".settings-panel").forEach(d=>d.classList.add("hidden"));let c=document.getElementById("tab-"+a);c&&c.classList.remove("hidden"),document.querySelectorAll(".menu li[data-tab]").forEach(d=>{let u=d.dataset.tab===a;d.classList.toggle("menu-active",u);let f=d.querySelector('a[role="tab"]');f&&(f.setAttribute("aria-selected",u?"true":"false"),f.setAttribute("tabindex",u?"0":"-1"))}),document.querySelectorAll(".settings-tab-mobile").forEach(d=>{let u=d.dataset.tab===a;d.classList.toggle("btn-ghost",!u),d.classList.toggle("btn-secondary",u),d.setAttribute("aria-selected",u?"true":"false"),d.setAttribute("tabindex",u?"0":"-1")}),history.replaceState(null,"","#"+a),document.body.dispatchEvent(new CustomEvent("tab:"+a))}window.isTabActive=function(a){let c=document.getElementById("tab-"+a);return c&&!c.classList.contains("hidden")},window.switchSettingsTab=t;function n(a,c){let d=c==="vertical"?"ArrowUp":"ArrowLeft",u=c==="vertical"?"ArrowDown":"ArrowRight";return function(f){let m=a.indexOf(f.currentTarget);if(m===-1)return;let h=null;f.key===d?h=a[(m-1+a.length)%a.length]:f.key===u?h=a[(m+1)%a.length]:f.key==="Home"?h=a[0]:f.key==="End"&&(h=a[a.length-1]),h&&(f.preventDefault(),t(h.dataset.tab||h.parentElement.dataset.tab),h.focus())}}let r=Array.from(document.querySelectorAll(".settings-tab-mobile")),o=n(r,"horizontal");r.forEach(a=>{a.addEventListener("click",c=>{c.preventDefault(),t(a.dataset.tab)}),a.addEventListener("keydown",o)});let s=Array.from(document.querySelectorAll('.menu li[data-tab] a[role="tab"]')),i=n(s,"vertical");s.forEach(a=>{a.addEventListener("click",c=>{c.preventDefault(),t(a.parentElement.dataset.tab)}),a.addEventListener("keydown",i)});let l=window.location.hash.replace("#","")||"user";e.indexOf(l)===-1&&(l="user"),t(l),window.addEventListener("hashchange",()=>{let a=window.location.hash.replace("#","")||"user";e.indexOf(a)!==-1&&t(a)})}function $e(){let e=document.getElementById("delete-account-btn");if(!e)return;let t=e.dataset.clientShortName||"this account",r="DELETE "+(e.dataset.profileHandle||"");function o(i){let l=document.createElement("div");return l.textContent=i,l.innerHTML}e.addEventListener("click",s);function s(){let i=document.getElementById("delete-pds-records").checked,l=document.createElement("div");l.className="modal modal-open",l.innerHTML=`
+
+
+
+ Delete ${o(t)} Data
+
+
+
+
+
+ Your ATProto account will NOT be affected.
+
+
+
+ This action cannot be undone . This will permanently delete:
+
+
+
+ Your ${o(t)} account and all settings
+ All authorized devices
+ Your data from all holds you're a member of
+ ${i?"All io.atcr.* records from your ATProto PDS ":""}
+
+
+
+ Type ${o(r)} to confirm:
+
+
+
+
+
+ Cancel
+
+
+ Delete My ${o(t)} Data
+
+
+
+
+ `,document.body.appendChild(l);let a=document.getElementById("confirm-delete-input"),c=document.getElementById("confirm-delete"),d=document.getElementById("cancel-delete");setTimeout(()=>a.focus(),100),a.addEventListener("input",function(){c.disabled=this.value!==r}),a.addEventListener("keydown",function(m){m.key==="Enter"&&this.value===r&&f()}),d.addEventListener("click",()=>l.remove()),document.getElementById("modal-backdrop").addEventListener("click",()=>l.remove());function u(m){m.key==="Escape"&&(l.remove(),document.removeEventListener("keydown",u))}document.addEventListener("keydown",u),c.addEventListener("click",f);async function f(){let m=document.getElementById("delete-pds-records").checked;c.disabled=!0,c.innerHTML=' Deleting...',d.disabled=!0;try{let h=await fetch("/api/account",{method:"DELETE",headers:{"Content-Type":"application/json"},body:JSON.stringify({delete_pds_records:m,confirmation:r})}),y=await h.json();if(h.ok&&y.success)l.querySelector(".modal-box").innerHTML=`
+
+
+ Account Deleted
+
+
+
Your account has been successfully deleted.
+
Redirecting to home page...
+
+ `,setTimeout(()=>{window.location.href="/?deleted=true"},2e3);else{let p=y.errors||["An unknown error occurred"];l.querySelector(".modal-box").innerHTML=`
+
+
+ Deletion Failed
+
+
+
There were errors during account deletion:
+
+ ${p.map(w=>""+o(w)+" ").join("")}
+
+
+
+ Close
+
+ `,l.querySelector("[data-dismiss-modal]").addEventListener("click",()=>l.remove())}}catch(h){console.error("Delete account error:",h),l.querySelector(".modal-box").innerHTML=`
+
+
+ Error
+
+
+
Failed to delete account: ${o(h.message)}
+
+
+ Close
+
+ `,l.querySelector("[data-dismiss-modal]").addEventListener("click",()=>l.remove())}}}}document.addEventListener("DOMContentLoaded",()=>{ze(),$e()});var G="showEmptyLayers";function Je(e,t,n){let r=0;for(let o=t;oLayers '+i+"-"+l+' contain no history ('+s+' layers, click to expand) '+a+" ",c.addEventListener("click",()=>{c.remove();for(let d=o;d{n.style.display=t?"":"none"})}function Ee(e){let t=e||document;(t.querySelectorAll?t.querySelectorAll(".layers-table:not([data-layers-processed])"):[]).forEach(r=>{r.setAttribute("data-layers-processed","1"),Ke(r),ye(r)})}function Ge(e){localStorage.setItem(G,e),document.querySelectorAll(".show-empty-layers-cb").forEach(t=>{t.checked=e}),document.querySelectorAll(".layers-table").forEach(ye)}document.addEventListener("DOMContentLoaded",()=>{let e=localStorage.getItem(G)==="true";document.querySelectorAll(".show-empty-layers-cb").forEach(t=>{t.checked=e}),Ee()});document.addEventListener("change",e=>{e.target.matches("[data-toggle-empty-layers]")&&Ge(e.target.checked)});document.body.addEventListener("htmx:afterSettle",e=>{e.target&&e.target.querySelectorAll&&Ee(e.target)});window.htmx=D;D.config.methodsThatUseUrlParams=["get"];
diff --git a/pkg/appview/src/css/main.css b/pkg/appview/src/css/main.css
index 8e471ba..5bc107b 100644
--- a/pkg/appview/src/css/main.css
+++ b/pkg/appview/src/css/main.css
@@ -99,9 +99,9 @@
default: false;
prefersdark: true;
color-scheme: "dark";
- --color-base-100: oklch(19.5% 0.036 257.7);
- --color-base-200: oklch(23.2% 0.041 253.9);
- --color-base-300: oklch(28% 0.049 252);
+ --color-base-100: oklch(20% 0.05 250);
+ --color-base-200: oklch(25% 0.05 250);
+ --color-base-300: oklch(30% 0.05 250);
--color-base-content: oklch(95.4% 0.022 211);
--color-primary: oklch(60% 0.126 221.723);
--color-primary-content: oklch(10% 0.126 221.723);
@@ -134,12 +134,12 @@
============================================ */
@plugin "daisyui/theme" {
name: "light";
- default: true
+ default: true;
prefersdark: false;
color-scheme: "light";
- --color-base-100: oklch(99.4% 0.004 214.3);
- --color-base-200: oklch(97.3% 0.01 212.5);
- --color-base-300: oklch(93.7% 0.02 212.5);
+ --color-base-100: oklch(98% 0.01 225);
+ --color-base-200: oklch(95% 0.02 225);
+ --color-base-300: oklch(92% 0.03 225);
--color-base-content: oklch(21.1% 0.037 254.4);
--color-primary: oklch(60% 0.126 221.723);
--color-primary-content: oklch(10% 0.126 221.723);
@@ -171,11 +171,23 @@
ADDITIONAL CSS VARIABLES
======================================== */
:root {
- --shadow-card-hover:
- 0 8px 25px oklch(67.1% 0.05 145 / 0.25), 0 4px 12px oklch(0% 0 0 / 0.1);
/* Dedicated star/favorite color — semantically distinct from `warning`
even if values currently coincide. Used by .text-star/.fill-star/etc. */
--color-star: oklch(82% 0.189 84.429);
+
+ /* Vulnerability severity scale. Held constant across themes on purpose:
+ CVE severity is a product-semantic signal that needs to read the same
+ way regardless of surface. Content-pair colors come from the same hue
+ family (lighter for dark surfaces, darker for light surfaces) to avoid
+ gray-on-color contrast problems. */
+ --color-severity-critical: oklch(45% 0.19 25);
+ --color-severity-critical-content: oklch(97% 0.01 25);
+ --color-severity-high: oklch(56% 0.19 50);
+ --color-severity-high-content: oklch(97% 0.01 50);
+ --color-severity-medium: oklch(72% 0.15 70);
+ --color-severity-medium-content: oklch(25% 0.05 70);
+ --color-severity-low: oklch(80% 0.1 85);
+ --color-severity-low-content: oklch(25% 0.05 85);
}
/* ========================================
@@ -209,19 +221,21 @@
font-variant-numeric: tabular-nums;
}
+/* Card elevation. In dark mode, shadows disappear against a dark surface —
+ depth is communicated primarily by the base-100 → base-200 surface ramp
+ plus a white-alpha edge ring (see `.card-interactive` rule below). On
+ hover we add a neutral-black amplified shadow (~4–5× the light-mode
+ alpha). Tinted or glow shadows read as highlights, not elevation. */
[data-theme="dark"] {
--shadow-card-hover:
- 0 8px 25px oklch(67.1% 0.05 145 / 0.2), 0 4px 12px oklch(0% 0 0 / 0.2);
+ 0 2px 4px -1px oklch(0% 0 0 / 0.55),
+ 0 12px 24px -6px oklch(0% 0 0 / 0.45);
}
[data-theme="light"] {
--shadow-card-hover:
- 0 8px 25px oklch(53.1% 0.1 144.8 / 0.25), 0 4px 12px oklch(0% 0 0 / 0.1);
-}
-
-[data-theme="dark"] {
- --shadow-card-hover:
- 0 8px 25px oklch(63.1% 0.07 144.7 / 0.2), 0 4px 12px oklch(0% 0 0 / 0.2);
+ 0 1px 2px oklch(0% 0 0 / 0.06),
+ 0 8px 24px -6px oklch(0% 0 0 / 0.12);
}
/* ========================================
@@ -348,6 +362,19 @@
white-space: nowrap;
border-width: 0;
}
+
+ /* Skip-to-content link. Hidden until keyboard-focused, then anchors at
+ the top-left so the user can press Enter to jump past the nav. */
+ .skip-link {
+ @apply absolute left-2 z-50 px-3 py-2 rounded-md;
+ @apply bg-primary text-primary-content font-medium text-sm;
+ top: -10rem;
+ transition: top 0.15s ease-out;
+ }
+ .skip-link:focus,
+ .skip-link:focus-visible {
+ top: 0.5rem;
+ }
}
/* ========================================
@@ -360,6 +387,112 @@
outline-offset: 2px;
}
+/* ========================================
+ TOUCH TARGET SIZING
+ Small buttons and compact form controls meet the keyboard minimum on
+ desktop but fall below the 44×44 recommended touch target on touch
+ devices (WCAG 2.5.5). Grow them only on coarse-pointer devices so
+ pointer-primary layouts stay dense.
+ ======================================== */
+@media (pointer: coarse) {
+ /* Icon-only buttons grow both axes — daisyUI's circle/square variants
+ are the marker for these. */
+ :is(.btn-circle, .btn-square):is(.btn-xs, .btn-sm) {
+ min-width: 2.75rem;
+ min-height: 2.75rem;
+ }
+
+ /* Text buttons only need vertical clearance — padding handles width. */
+ .btn-xs, .btn-sm {
+ min-height: 2.75rem;
+ }
+
+ /* Small checkbox/radio: expand the clickable region without distorting
+ the control itself — negative margin on the parent would be
+ cleaner but requires markup changes; here we just grow the box. */
+ :is(.checkbox, .radio):is(.checkbox-xs, .radio-xs, .checkbox-sm, .radio-sm) {
+ min-width: 1.5rem;
+ min-height: 1.5rem;
+ }
+
+ /* daisyUI menu items (used in dropdowns, settings sidebar) are small
+ link-like elements. Ensure they meet the tap threshold. */
+ .menu li > a,
+ .menu li > button {
+ min-height: 2.75rem;
+ }
+
+ /* Custom tablist buttons (repo-tab, editor-tab) should match. Padding
+ already puts them near the threshold on desktop; lock in the floor. */
+ .repo-tab,
+ .editor-tab {
+ min-height: 2.75rem;
+ }
+
+ .sailor-typeahead-selected .sailor-typeahead-clear {
+ width: 2.75rem;
+ height: 2.75rem;
+ }
+}
+
+/* ========================================
+ COMMAND BLOCK ON NARROW VIEWPORTS
+ On desktop .cmd uses `truncate` for a tidy inline look. On mobile,
+ truncation hides the very thing the user wants to copy ("atcr.io/…"),
+ so switch to horizontal scrolling — the copy button still copies the
+ full text, but users can also see what they're about to paste.
+ ======================================== */
+@media (max-width: 40rem) {
+ .cmd code {
+ overflow-x: auto;
+ overflow-y: hidden;
+ text-overflow: clip;
+ /* Touch-friendly scroll momentum */
+ -webkit-overflow-scrolling: touch;
+ }
+}
+
+/* ========================================
+ REDUCED MOTION
+ Honor users who opt out of animation. Collapse all durations to a
+ near-instant value rather than removing transitions entirely, so
+ state changes still fire (transitionend listeners, etc.).
+ ======================================== */
+@media (prefers-reduced-motion: reduce) {
+ *,
+ *::before,
+ *::after {
+ animation-duration: 0.01ms !important;
+ animation-iteration-count: 1 !important;
+ transition-duration: 0.01ms !important;
+ scroll-behavior: auto !important;
+ }
+}
+
+/* ========================================
+ FORCED COLORS (Windows High Contrast)
+ The OS strips box-shadow entirely, so any UI that communicates a
+ "separate surface" purely through shadow becomes invisible. Paint
+ explicit borders using system colors so edges survive. Hover/active
+ states use the Highlight system color which the OS also guarantees
+ is perceptually distinct.
+ ======================================== */
+@media (forced-colors: active) {
+ .card-interactive {
+ border: 1px solid CanvasText;
+ }
+ .card-interactive:hover {
+ outline: 2px solid Highlight;
+ outline-offset: 2px;
+ }
+ /* Severity badges lose their distinguishing fill in forced-colors;
+ fall back to a visible border so the severity strip still reads
+ as a series of distinct cells. */
+ .vuln-strip > span {
+ border: 1px solid CanvasText;
+ }
+}
+
/* ========================================
CUSTOM COMPONENTS (Not in DaisyUI)
======================================== */
@@ -368,13 +501,16 @@
COMMAND / CODE DISPLAY
---------------------------------------- */
.cmd {
- @apply flex items-center gap-2 relative w-fit max-w-full overflow-hidden;
- @apply bg-base-200 border border-base-300 rounded-md;
+ @apply flex items-center gap-2 relative w-fit max-w-full;
+ @apply bg-base-300 rounded-md;
@apply px-3 py-2;
}
+ /* `min-w-0` + `flex-1` let the code shrink below its intrinsic width so
+ `truncate` can actually produce an ellipsis inside a flex container.
+ Without them, long commands overflow silently. */
.cmd code {
- @apply font-mono text-sm truncate;
+ @apply font-mono text-sm truncate min-w-0 flex-1;
}
/* ----------------------------------------
@@ -432,9 +568,18 @@
/* ----------------------------------------
CARD EXTENSIONS
---------------------------------------- */
+ /* Resting cards rely on surface lightness for elevation. In dark mode
+ we also paint a 1px inner white-alpha ring so the edge reads against
+ the slightly-lighter card surface — borders do more perceptual work
+ than shadows in dark. Hover then adds a real (neutral-black) shadow. */
.card-interactive {
- @apply cursor-pointer duration-500;
- transition-property: box-shadow, transform;
+ position: relative;
+ transition: transform 250ms cubic-bezier(0.16, 1, 0.3, 1),
+ box-shadow 250ms cubic-bezier(0.16, 1, 0.3, 1);
+ }
+
+ [data-theme="dark"] .card-interactive {
+ box-shadow: inset 0 0 0 1px oklch(100% 0 0 / 0.06);
}
.card-interactive:hover {
@@ -442,6 +587,32 @@
transform: translateY(-2px);
}
+ [data-theme="dark"] .card-interactive:hover {
+ box-shadow:
+ inset 0 0 0 1px oklch(100% 0 0 / 0.1),
+ var(--shadow-card-hover);
+ }
+
+ /* Stretched-link pattern: the whole card is one accessible link.
+ The anchor fills the card via absolute positioning; real interactive
+ descendants (owner/repo links, copy buttons, inline commands) raise
+ themselves above it with z-index so they remain clickable. */
+ .card-stretched-link {
+ position: absolute;
+ inset: 0;
+ z-index: 1;
+ border-radius: inherit;
+ text-decoration: none;
+ }
+ .card-stretched-link:focus-visible {
+ outline: 2px solid var(--color-primary);
+ outline-offset: 2px;
+ }
+ .card-interactive :is(a:not(.card-stretched-link), button, .cmd, [role="button"]) {
+ position: relative;
+ z-index: 2;
+ }
+
/* ----------------------------------------
SAILOR TYPEAHEAD
---------------------------------------- */
@@ -455,6 +626,10 @@
@apply rounded-lg shadow-lg;
@apply max-h-80 overflow-y-auto z-50;
margin-top: 0.25rem;
+ /* Don't escape the viewport on narrow screens — the dropdown is
+ anchored to its input, but if the input sits near a viewport
+ edge the right: 0 anchor can still overflow. */
+ max-width: calc(100vw - 1rem);
}
.sailor-typeahead-header {
@@ -470,7 +645,7 @@
.sailor-typeahead-item:hover,
.sailor-typeahead-item.focused {
- @apply bg-base-200;
+ @apply bg-base-300;
}
.sailor-typeahead-item-compact {
@@ -514,7 +689,7 @@
@apply flex-shrink-0 w-8 h-8 rounded-full;
@apply flex items-center justify-center;
@apply text-xl leading-none text-base-content/60;
- @apply hover:bg-base-200 hover:text-base-content;
+ @apply hover:bg-base-300 hover:text-base-content;
@apply transition-colors cursor-pointer;
}
@@ -557,19 +732,6 @@
@apply block w-full;
}
- /* ----------------------------------------
- OFFLINE MANIFEST FILTERING
- Hide offline manifests by default;
- show when "Show offline images" is checked
- ---------------------------------------- */
- .manifests-list > [data-reachable="false"] {
- display: none;
- }
-
- .manifests-list.show-offline > [data-reachable="false"] {
- display: block;
- }
-
/* ----------------------------------------
RESPONSIVE TABLE — STACK ON MOBILE
Below md, each row becomes a labeled block.
@@ -606,24 +768,50 @@
}
}
+ /* ----------------------------------------
+ MODAL — MOBILE GUTTER
+ DaisyUI's .modal-box is ~512px wide by default with no mobile clamp;
+ on viewports under that it presses against the screen edges. Force
+ a 1rem gutter on each side so the dialog reads as a card. Only
+ applies under the sm breakpoint so desktop max-w-* utilities win.
+ ---------------------------------------- */
+ @media (max-width: 39.999rem) {
+ .modal .modal-box {
+ max-width: calc(100vw - 2rem);
+ }
+ }
+
/* ----------------------------------------
VULNERABILITY SEVERITY BOX STRIP
Docker Hub-style connected severity boxes
---------------------------------------- */
.vuln-strip {
@apply inline-flex items-stretch text-xs font-semibold leading-none;
+ /* Never spill out of a narrow column. The strip's natural width
+ (~115px on mobile) almost always fits; this is a safety net for
+ ultra-cramped table cells and side panels. */
+ max-width: 100%;
}
.vuln-strip > span {
@apply px-1 py-1 min-w-5 text-center cursor-pointer sm:px-2 sm:min-w-7;
}
.vuln-strip > span:first-child { @apply rounded-l-sm; }
.vuln-strip > span:last-child { @apply rounded-r-sm; }
- .vuln-box-critical { background-color: oklch(45% 0.19 25); color: oklch(97% 0.01 25); }
- .vuln-box-high { background-color: oklch(56% 0.19 50); color: oklch(97% 0.01 50); }
- .vuln-box-medium { background-color: oklch(72% 0.15 70); color: oklch(25% 0.05 70); }
- .vuln-box-low { background-color: oklch(80% 0.1 85); color: oklch(25% 0.05 85); }
+ .vuln-box-critical { background-color: var(--color-severity-critical); color: var(--color-severity-critical-content); }
+ .vuln-box-high { background-color: var(--color-severity-high); color: var(--color-severity-high-content); }
+ .vuln-box-medium { background-color: var(--color-severity-medium); color: var(--color-severity-medium-content); }
+ .vuln-box-low { background-color: var(--color-severity-low); color: var(--color-severity-low-content); }
}
+/* ========================================
+ HTMX REQUEST INDICATOR
+ Opt-in: elements with class `htmx-indicator` are hidden except during
+ an in-flight request. Keeps request UX declarative — no JS required.
+ ======================================== */
+.htmx-indicator { display: none; }
+.htmx-request .htmx-indicator,
+.htmx-request.htmx-indicator { display: inline-block; }
+
/* ========================================
TOAST CONTAINER
======================================== */
diff --git a/pkg/appview/src/js/app.js b/pkg/appview/src/js/app.js
index 22db1e8..0c27638 100644
--- a/pkg/appview/src/js/app.js
+++ b/pkg/appview/src/js/app.js
@@ -32,9 +32,10 @@ function updateThemeUI(pref) {
use.setAttribute('href', `/icons.svg#${iconMap[pref] || 'sun-moon'}`);
});
- // Update checkmarks in dropdown
+ // Update checkmarks + ARIA state in dropdown
document.querySelectorAll('.theme-option').forEach(option => {
const isSelected = option.dataset.value === pref;
+ option.setAttribute('aria-checked', isSelected ? 'true' : 'false');
const check = option.querySelector('.theme-check');
if (check) {
check.style.visibility = isSelected ? 'visible' : 'hidden';
@@ -58,24 +59,36 @@ window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', ()
});
// Expandable search
+function setSearchExpanded(wrapper, expanded) {
+ if (!wrapper) return;
+ const form = wrapper.querySelector('.nav-search-form');
+ const toggleBtn = wrapper.querySelector('button[aria-controls="nav-search-form"]');
+ wrapper.classList.toggle('expanded', expanded);
+ if (form) {
+ if (expanded) {
+ form.removeAttribute('inert');
+ } else {
+ form.setAttribute('inert', '');
+ }
+ }
+ if (toggleBtn) {
+ toggleBtn.setAttribute('aria-expanded', expanded ? 'true' : 'false');
+ }
+}
+
function toggleSearch() {
const wrapper = document.querySelector('.nav-search-wrapper');
- const input = document.getElementById('nav-search-input');
-
- if (!wrapper || !input) return;
-
- wrapper.classList.toggle('expanded');
-
- if (wrapper.classList.contains('expanded')) {
- input.focus();
+ if (!wrapper) return;
+ const willExpand = !wrapper.classList.contains('expanded');
+ setSearchExpanded(wrapper, willExpand);
+ if (willExpand) {
+ const input = document.getElementById('nav-search-input');
+ if (input) input.focus();
}
}
function closeSearch() {
- const wrapper = document.querySelector('.nav-search-wrapper');
- if (wrapper) {
- wrapper.classList.remove('expanded');
- }
+ setSearchExpanded(document.querySelector('.nav-search-wrapper'), false);
}
// Close search on Escape key and click outside
@@ -110,24 +123,65 @@ document.addEventListener('DOMContentLoaded', () => {
});
});
-// Copy to clipboard
-// text: the text to copy
-// btn: optional button element for feedback (uses event.target if not provided)
+// Copy to clipboard. Always called with an explicit btn from the delegated
+// dispatcher or direct callers — no implicit global `event` fallback.
function copyToClipboard(text, btn) {
- if (!btn && typeof event !== 'undefined') {
- btn = event.target.closest('button');
- }
- navigator.clipboard.writeText(text).then(() => {
+ const onSuccess = () => {
if (!btn) return;
- // Show success feedback
const originalHTML = btn.innerHTML;
btn.innerHTML = ' Copied!';
- setTimeout(() => {
- btn.innerHTML = originalHTML;
- }, 2000);
- }).catch(err => {
- console.error('Failed to copy:', err);
- });
+ setTimeout(() => { btn.innerHTML = originalHTML; }, 2000);
+ };
+
+ if (navigator.clipboard && window.isSecureContext) {
+ navigator.clipboard.writeText(text).then(onSuccess).catch(err => {
+ console.error('Clipboard API failed, falling back:', err);
+ if (!legacyCopy(text)) {
+ showToast('Copy failed — check browser permissions', 'error');
+ } else {
+ onSuccess();
+ }
+ });
+ return;
+ }
+
+ // Insecure context (http://) or unsupported browser — fall back to the
+ // legacy textarea + execCommand technique. Still works in every browser
+ // released in the last decade.
+ if (legacyCopy(text)) {
+ onSuccess();
+ } else {
+ showToast('Copy failed — select the text and copy manually', 'error');
+ }
+}
+
+// Hidden-textarea fallback for clipboard copy. Returns true on success.
+function legacyCopy(text) {
+ const ta = document.createElement('textarea');
+ ta.value = text;
+ ta.setAttribute('readonly', '');
+ ta.setAttribute('aria-hidden', 'true');
+ // Position off-screen but inside viewport so iOS Safari doesn't reject
+ // the selection. Avoid display:none — the textarea must be focusable.
+ ta.style.position = 'fixed';
+ ta.style.top = '0';
+ ta.style.left = '0';
+ ta.style.width = '1px';
+ ta.style.height = '1px';
+ ta.style.opacity = '0';
+ ta.style.pointerEvents = 'none';
+ document.body.appendChild(ta);
+ let ok = false;
+ try {
+ ta.focus();
+ ta.select();
+ ta.setSelectionRange(0, text.length);
+ ok = document.execCommand && document.execCommand('copy');
+ } catch (_) {
+ ok = false;
+ }
+ document.body.removeChild(ta);
+ return !!ok;
}
// Serialize a (thead + tbody) as CSV (RFC 4180 quoting)
@@ -146,7 +200,7 @@ function tableToCSV(table) {
return lines.join('\n');
}
-// Initialize copy buttons with data-cmd attribute and clickable cards with data-href
+// Initialize copy buttons with data-cmd attribute and CSV copy buttons.
document.addEventListener('DOMContentLoaded', () => {
document.addEventListener('click', (e) => {
// Handle copy-as-CSV buttons (for vulnerability / SBOM tables)
@@ -164,13 +218,6 @@ document.addEventListener('DOMContentLoaded', () => {
copyToClipboard(btn.getAttribute('data-cmd'), btn);
return;
}
-
- // Handle clickable cards (skip if clicking on interactive elements)
- if (e.target.closest('a, button, input, .cmd')) return;
- const card = e.target.closest('[data-href]');
- if (card) {
- window.location = card.getAttribute('data-href');
- }
});
});
@@ -241,46 +288,25 @@ document.addEventListener('DOMContentLoaded', () => {
// Update timestamps after HTMX swaps
document.addEventListener('htmx:afterSwap', updateTimestamps);
-// Update timestamps periodically
-setInterval(updateTimestamps, 60000); // Every minute
-
-// Toggle offline manifests visibility
-function toggleOfflineManifests() {
- const checkbox = document.getElementById('show-offline-toggle');
- const manifestsList = document.querySelector('.manifests-list');
-
- if (!checkbox || !manifestsList) return;
-
- // Store preference in localStorage
- localStorage.setItem('showOfflineManifests', checkbox.checked);
-
- // Toggle visibility of offline manifests
- if (checkbox.checked) {
- manifestsList.classList.add('show-offline');
- } else {
- manifestsList.classList.remove('show-offline');
- }
+// Update timestamps periodically — pause while the tab is hidden so we don't
+// walk the DOM every minute for an audience that isn't looking. On return,
+// refresh immediately so stamps reflect real time elapsed.
+let timestampInterval = null;
+function startTimestampUpdates() {
+ if (timestampInterval === null) timestampInterval = setInterval(updateTimestamps, 60000);
}
-
-// Restore offline manifests toggle state on page load
-document.addEventListener('DOMContentLoaded', () => {
- const checkbox = document.getElementById('show-offline-toggle');
- if (!checkbox) return;
-
- // Restore state from localStorage
- const showOffline = localStorage.getItem('showOfflineManifests') === 'true';
- checkbox.checked = showOffline;
-
- // Apply initial state
- const manifestsList = document.querySelector('.manifests-list');
- if (manifestsList) {
- if (showOffline) {
- manifestsList.classList.add('show-offline');
- } else {
- manifestsList.classList.remove('show-offline');
- }
+function stopTimestampUpdates() {
+ if (timestampInterval !== null) { clearInterval(timestampInterval); timestampInterval = null; }
+}
+document.addEventListener('visibilitychange', () => {
+ if (document.visibilityState === 'hidden') {
+ stopTimestampUpdates();
+ } else {
+ updateTimestamps();
+ startTimestampUpdates();
}
});
+startTimestampUpdates();
// Delete manifest with confirmation for tagged manifests
async function deleteManifest(repository, digest, sanitizedId) {
@@ -303,11 +329,11 @@ async function deleteManifest(repository, digest, sanitizedId) {
} else {
// Other error
const errorText = await response.text();
- alert(`Failed to delete manifest: ${errorText}`);
+ showToast(`Failed to delete manifest: ${errorText || response.status}`, 'error');
}
} catch (err) {
console.error('Error deleting manifest:', err);
- alert(`Error deleting manifest: ${err.message}`);
+ showToast(`Error deleting manifest: ${err.message}`, 'error');
}
}
@@ -328,14 +354,12 @@ function showManifestDeleteModal(repository, digest, sanitizedId, tags) {
// Set up confirm button click handler
confirmBtn.onclick = () => confirmManifestDelete(repository, digest, sanitizedId);
- // Show modal
- modal.style.display = 'flex';
+ openDialog(modal);
}
// Close the manifest delete confirmation modal
function closeManifestDeleteModal() {
- const modal = document.getElementById('manifest-delete-modal');
- modal.style.display = 'none';
+ closeDialog(document.getElementById('manifest-delete-modal'));
}
// Confirm and execute manifest deletion with all tags
@@ -357,21 +381,19 @@ async function confirmManifestDelete(repository, digest, sanitizedId) {
});
if (response.ok) {
- // Successfully deleted
closeManifestDeleteModal();
removeManifestElement(sanitizedId);
- // Also remove any tag elements that were deleted
- location.reload(); // Reload to refresh the tags list
+ location.reload();
} else {
// Error
const errorText = await response.text();
- alert(`Failed to delete manifest: ${errorText}`);
+ showToast(`Failed to delete manifest: ${errorText || response.status}`, 'error');
confirmBtn.disabled = false;
confirmBtn.textContent = originalText;
}
} catch (err) {
console.error('Error deleting manifest:', err);
- alert(`Error deleting manifest: ${err.message}`);
+ showToast(`Error deleting manifest: ${err.message}`, 'error');
confirmBtn.disabled = false;
confirmBtn.textContent = originalText;
}
@@ -396,7 +418,7 @@ async function deleteUntaggedManifests(repository) {
const data = await response.json();
if (response.ok) {
- document.getElementById('untagged-delete-modal').close();
+ closeDialog(document.getElementById('untagged-delete-modal'));
showToast(`Deleted ${data.deleted} untagged manifest(s)`, 'success');
if (data.deleted > 0) {
location.reload();
@@ -404,13 +426,13 @@ async function deleteUntaggedManifests(repository) {
confirmBtn.disabled = false;
confirmBtn.textContent = originalText;
} else {
- alert(`Failed to delete untagged manifests: ${data.error || 'Unknown error'}`);
+ showToast(`Failed to delete untagged manifests: ${data.error || 'Unknown error'}`, 'error');
confirmBtn.disabled = false;
confirmBtn.textContent = originalText;
}
} catch (err) {
console.error('Error deleting untagged manifests:', err);
- alert(`Error: ${err.message}`);
+ showToast(`Error: ${err.message}`, 'error');
confirmBtn.disabled = false;
confirmBtn.textContent = originalText;
}
@@ -424,7 +446,9 @@ function removeManifestElement(sanitizedId) {
}
}
-// Close modal when clicking outside
+// Close manifest-delete-modal on backdrop click. With native showModal()
+// the dialog itself receives clicks that land on its ::backdrop pseudo,
+// so e.target === modal correctly identifies a backdrop click.
document.addEventListener('DOMContentLoaded', () => {
const modal = document.getElementById('manifest-delete-modal');
if (modal) {
@@ -436,24 +460,159 @@ document.addEventListener('DOMContentLoaded', () => {
}
});
-// Vulnerability details modal
-async function openVulnDetails(digest, holdEndpoint) {
- const modal = document.getElementById('vuln-detail-modal');
- const body = document.getElementById('vuln-modal-body');
- if (!modal || !body) return;
+// ----------------------------------------
+// Modal focus management
+// Native .showModal() already traps Tab; we layer on:
+// 1. Restoring focus to the trigger when the dialog closes.
+// 2. Promoting HTMX-injected elements (which arrive
+// without showModal() ever being called) so the focus trap engages.
+// ----------------------------------------
+const _dialogOpeners = new WeakMap();
- // Show modal with loading spinner
- body.innerHTML = '
';
- modal.showModal();
+function openDialog(dialog, opener) {
+ if (!dialog) return;
+ _dialogOpeners.set(dialog, opener || document.activeElement);
+ if (typeof dialog.showModal !== 'function') return;
+ // If the dialog is already in the non-modal open state (e.g. injected
+ // with the [open] attribute), force it back into modal mode so Tab is
+ // trapped. Setting open=false before showModal() avoids firing the
+ // close event (which would steal focus restoration).
+ if (dialog.open) dialog.open = false;
+ try { dialog.showModal(); } catch (_) { /* detached from DOM */ }
+}
- try {
- const resp = await fetch(`/api/vuln-details?digest=${encodeURIComponent(digest)}&holdEndpoint=${encodeURIComponent(holdEndpoint)}`);
- body.innerHTML = await resp.text();
- } catch {
- body.innerHTML = 'Failed to load vulnerability details
';
+function closeDialog(dialog, { remove = false } = {}) {
+ if (!dialog) return;
+ const opener = _dialogOpeners.get(dialog);
+ _dialogOpeners.delete(dialog);
+ if (typeof dialog.close === 'function' && dialog.open) {
+ try { dialog.close(); } catch (_) { /* ignore */ }
+ }
+ if (remove) dialog.remove();
+ restoreFocus(opener);
+}
+
+function restoreFocus(opener) {
+ if (opener && typeof opener.focus === 'function' && document.contains(opener)) {
+ opener.focus();
}
}
+// Native close events fire from Escape and
@@ -219,39 +219,39 @@
- OAuth tokens
- AppView
- Until revoked or logout
+ OAuth tokens
+ AppView
+ Until revoked or logout
- Web UI session tokens
- AppView
- Until logout or expiration
+ Web UI session tokens
+ AppView
+ Until logout or expiration
- Device tokens (credential helper)
- AppView
- Until revoked by user
+ Device tokens (credential helper)
+ AppView
+ Until revoked by user
- Cached PDS data
- AppView
- Refreshed periodically; deleted on account deletion
+ Cached PDS data
+ AppView
+ Refreshed periodically; deleted on account deletion
- Server logs
- AppView
- Currently ephemeral; this policy will be updated if log retention is implemented
+ Server logs
+ AppView
+ Currently ephemeral; this policy will be updated if log retention is implemented
- Layer records
- Hold PDS
- Until you request deletion
+ Layer records
+ Hold PDS
+ Until you request deletion
- OCI blobs
- Hold Storage
- Until no longer referenced (pruned within 30 days)
+ OCI blobs
+ Hold Storage
+ Until no longer referenced (pruned within 30 days)
@@ -276,7 +276,7 @@
{{ .CompanyName }} supports "Bring Your Own Storage" where users can deploy their own hold services to store container image blobs. This section explains how BYOS affects your privacy rights.
{{ .CompanyName }}-Hosted Holds
- Hold services on *.{{ .SiteURL }} domains (e.g., hold01.{{ .SiteURL }}) are operated by us and fully covered by this privacy policy. We can fulfill all data access, export, and deletion requests for these services.
+ Hold services on *.{{ .SiteURL }} domains (e.g., hold01.{{ .SiteURL }}) are operated by us and fully covered by this privacy policy. We can fulfill all data access, export, and deletion requests for these services.
User-Deployed Holds
If you use a hold service not operated by us:
@@ -303,7 +303,7 @@
Most data management can be done directly through your account settings at {{ .SiteURL }}:
Export your data: Use the "Export Data" button in settings to download a copy of all personal data we store about you.
- Delete your data: Use the "Delete Account" button in settings. This will remove your layer records, cached data, and authentication tokens. You may also choose to have us delete io.atcr.* records from your PDS (requires active OAuth session).
+ Delete your data: Use the "Delete Account" button in settings. This will remove your layer records, cached data, and authentication tokens. You may also choose to have us delete io.atcr.* records from your PDS (requires active OAuth session).
Revoke device tokens: Manage and revoke credential helper devices in settings.
Update your data: Corrections happen through normal use of the service.
@@ -334,7 +334,6 @@
-
{{ template "footer" . }}
diff --git a/pkg/appview/templates/pages/repository.html b/pkg/appview/templates/pages/repository.html
index 004ec40..26257c0 100644
--- a/pkg/appview/templates/pages/repository.html
+++ b/pkg/appview/templates/pages/repository.html
@@ -8,10 +8,10 @@
{{ template "nav" . }}
-
+
-
+
{{ template "repo-avatar" (dict "IconURL" .Repository.IconURL "RepositoryName" .Repository.Name "IsOwner" .IsOwner) }}
@@ -37,7 +37,7 @@
{{ end }}
{{ if .Stats.LastPush }}
-
+
Updated {{ timeAgoShort (derefTime .Stats.LastPush) }}
{{ end }}
@@ -101,7 +101,7 @@
{{ range .AllTags }}
- {{ . }}
+ {{ . }}
{{ end }}
@@ -126,7 +126,7 @@
hx-get="/api/attestation-details?digest={{ .SelectedTag.Info.Digest | urlquery }}&did={{ .Owner.DID | urlquery }}&repo={{ .Repository.Name | urlquery }}"
hx-target="#attestation-modal-body"
hx-swap="innerHTML"
- onclick="document.getElementById('attestation-detail-modal').showModal()">
+ data-action="show-modal" data-modal-id="attestation-detail-modal">
{{ icon "shield-check" "size-3" }} Attested
{{ end }}
@@ -138,16 +138,16 @@
{{ if .IsOwner }}
-
+
+ data-tab="write" data-action="switch-editor-tab">
Write
+ data-tab="preview" data-action="switch-editor-tab">
Preview
@@ -157,36 +157,39 @@
-
+
{{ icon "heading" "size-4" }}
-
+
{{ icon "bold" "size-4" }}
-
+
{{ icon "italic" "size-4" }}
-
+
{{ icon "link" "size-4" }}
-
+
{{ icon "image" "size-4" }}
-
+
{{ icon "list" "size-4" }}
-
+
{{ icon "list-ordered" "size-4" }}
-
+
{{ icon "code" "size-4" }}
@@ -199,44 +202,41 @@
- Cancel
- Save
+ Cancel
+ Save
{{ end }}
-
-
-
-
-
-
Confirm Deletion
+
+
+
Confirm Deletion
This manifest has associated tags that will also be deleted:
This action cannot be undone.
- Cancel
+ Cancel
Delete All
-
-
-
Delete Untagged Manifests
+
+
+
Delete Untagged Manifests
This will delete all untagged manifests in this repository, including those not currently visible.
This action cannot be undone.
+ data-action="delete-untagged" data-repo="{{ .Repository.Name }}">
Delete All Untagged
@@ -245,9 +245,9 @@
-
-
-
Attestation Details
+
+
+
Attestation Details
@@ -258,310 +258,6 @@
- {{ if .IsOwner }}
-
- {{ end }}
-
-
-
{{ template "footer" . }}
diff --git a/pkg/appview/templates/pages/search.html b/pkg/appview/templates/pages/search.html
index fdaa9f8..7573da9 100644
--- a/pkg/appview/templates/pages/search.html
+++ b/pkg/appview/templates/pages/search.html
@@ -8,7 +8,7 @@
{{ template "nav" . }}
-
+
{{ if .SearchQuery }}
Search Results for "{{ .SearchQuery }}"
{{ else }}
@@ -27,9 +27,6 @@
-
-
-
{{ template "footer" . }}
diff --git a/pkg/appview/templates/pages/settings.html b/pkg/appview/templates/pages/settings.html
index 1eb4757..0676ac8 100644
--- a/pkg/appview/templates/pages/settings.html
+++ b/pkg/appview/templates/pages/settings.html
@@ -8,11 +8,11 @@
{{ template "nav" . }}
-
+
Settings
-
+
@@ -50,7 +50,7 @@
{{ icon "webhook" "size-4" }} Webhooks
{{ icon "shield-check" "size-4" }} Advanced
-
+
@@ -61,7 +61,7 @@
-
+
Preferences
Customize your experience across the site.
@@ -71,11 +71,14 @@
Preferred client
-
Sets the pull command shown on repository pages. Choose Image reference only to copy just the image ref (useful for Kubernetes manifests or docker-compose).
+
Sets the pull command shown on repository pages. Choose Image reference only to copy without a command prefix.
{{ $oci := .Profile.OciClient }}
+ name="oci_client"
+ hx-post="/api/profile/oci-client"
+ hx-trigger="change"
+ hx-swap="none">
Docker
Podman
Buildah
@@ -104,9 +107,9 @@
{{ else }}
AI Image Advisor
-
Analyze your container images for optimization suggestions using AI.
+
Analyze your container images for optimization suggestions using AI.
- Upgrade your plan to enable this feature.
+ Upgrade your plan to enable this feature.
{{ end }}
@@ -125,7 +128,7 @@
{{ if .ActiveHold }}
{{ template "hold_card" .ActiveHold }}
{{ else }}
-
+
No active hold selected. Choose one above.
{{ end }}
@@ -137,7 +140,7 @@
{{ else }}
-
+
No holds configured. Push an image to get started.
{{ end }}
@@ -169,7 +172,7 @@
-
+
Authorized Devices
Devices authorized via docker-credential-atcr credential helper.
@@ -229,7 +232,7 @@
-
+
Webhooks
Get notified when images are pushed or vulnerability scans complete.
@@ -243,7 +246,7 @@
-
+
Data Privacy
Download a copy of all data we store about you.
@@ -290,7 +293,9 @@
-
+
{{ icon "trash-2" "size-5" }}
Delete My {{ .ClientShortName }} Data
@@ -302,291 +307,6 @@
-
-
{{ template "footer" . }}
diff --git a/pkg/appview/templates/pages/terms.html b/pkg/appview/templates/pages/terms.html
index 7c0de6b..e9e1508 100644
--- a/pkg/appview/templates/pages/terms.html
+++ b/pkg/appview/templates/pages/terms.html
@@ -8,7 +8,7 @@
{{ template "nav" . }}
-
+
Terms of Service - {{ .CompanyName }} ({{ .SiteURL }})
Last updated: January 2025
@@ -104,7 +104,7 @@
The Service operates on the AT Protocol, a distributed network. Data written to your PDS is controlled by you or your PDS hosting provider, not by us.
7.2 Records on Your PDS
- When you use the Service, records are written to your PDS under the io.atcr.* namespace. We can create, update, and delete these records only while you have granted us OAuth access. Revoking access does not automatically delete existing records.
+ When you use the Service, records are written to your PDS under the io.atcr.* namespace. We can create, update, and delete these records only while you have granted us OAuth access. Revoking access does not automatically delete existing records.
7.3 No Control Over Your PDS
We do not control your PDS. If your PDS is offline or your PDS provider terminates your account, we cannot restore your AT Protocol records.
@@ -198,7 +198,6 @@
-
{{ template "footer" . }}
diff --git a/pkg/appview/templates/pages/user.html b/pkg/appview/templates/pages/user.html
index 90a5771..2320a66 100644
--- a/pkg/appview/templates/pages/user.html
+++ b/pkg/appview/templates/pages/user.html
@@ -8,14 +8,14 @@
{{ template "nav" . }}
-
+
{{ if .ViewedUser.Avatar }}
-
+
{{ else if .HasProfile }}
@@ -26,7 +26,7 @@
{{ else }}
-
-
-
{{ template "footer" . }}
diff --git a/pkg/appview/templates/partials/attestation-details.html b/pkg/appview/templates/partials/attestation-details.html
index 633063d..fab5914 100644
--- a/pkg/appview/templates/partials/attestation-details.html
+++ b/pkg/appview/templates/partials/attestation-details.html
@@ -12,9 +12,9 @@
{{ .Digest }}
{{ if .NeedsLogin }}
- Log in to view attestation content
+ Log in to view attestation content
{{ else if .FetchError }}
- {{ .FetchError }}
+ {{ .FetchError }}
{{ else if .RawJSON }}
View content
@@ -23,7 +23,7 @@
{{ else if .Size }}
- Binary content ({{ .Size }} bytes) — cannot display inline
+ Binary content ({{ .Size }} bytes) — cannot display inline
{{ end }}
{{ end }}
diff --git a/pkg/appview/templates/partials/diff-content.html b/pkg/appview/templates/partials/diff-content.html
index d52c0b4..77b6ba8 100644
--- a/pkg/appview/templates/partials/diff-content.html
+++ b/pkg/appview/templates/partials/diff-content.html
@@ -2,7 +2,7 @@
-
+
Layers
{{ if .LayerDiff }}
@@ -29,7 +29,7 @@
{{ if not .Layer.EmptyLayer }}{{ humanizeBytes .Layer.Size }}{{ end }}
{{ if and (eq .Status "rebuilt") .PrevLayer }}
{{ if ne .Layer.Size .PrevLayer.Size }}
- ({{ humanizeByteDelta (sub64 .Layer.Size .PrevLayer.Size) }})
+ ({{ humanizeByteDelta (sub64 .Layer.Size .PrevLayer.Size) }})
{{ end }}
{{ end }}
@@ -44,7 +44,7 @@
-
+
Vulnerabilities
{{ if not .HasVulnData }}
@@ -54,7 +54,7 @@
{{ if .FixedVulns }}
-
+
{{ icon "shield-check" "size-4 text-success" }}
Fixed ({{ len .FixedVulns }})
@@ -94,7 +94,7 @@
{{ if .NewVulns }}
-
+
{{ icon "alert-triangle" "size-4 text-error" }}
New ({{ len .NewVulns }})
@@ -136,7 +136,7 @@
{{ if .UnchangedVulns }}
-
+
Unchanged ({{ len .UnchangedVulns }})
diff --git a/pkg/appview/templates/partials/digest-content.html b/pkg/appview/templates/partials/digest-content.html
index a443442..7101eaa 100644
--- a/pkg/appview/templates/partials/digest-content.html
+++ b/pkg/appview/templates/partials/digest-content.html
@@ -2,11 +2,11 @@
-
+
-
{{ else }}
No layer information available
{{ end }}
-
+
diff --git a/pkg/appview/templates/partials/hold_card.html b/pkg/appview/templates/partials/hold_card.html
index b041e3c..fb63658 100644
--- a/pkg/appview/templates/partials/hold_card.html
+++ b/pkg/appview/templates/partials/hold_card.html
@@ -1,21 +1,18 @@
{{ define "hold_card" }}
-
+
- ★
{{ .DisplayName }}
- Active
+ Active
{{ if eq .Membership "owner" }}Owner
{{ else }}Crew {{ end }}
- {{ if eq .Status "online" }}● Online
- {{ else if eq .Status "offline" }}● Offline
+ {{ if eq .Status "online" }} Online
+ {{ else if eq .Status "offline" }} Offline
{{ end }}
-
{{ .DID }}
-
-
+ {{ .DID }}
@@ -25,7 +22,7 @@
hx-get="/api/storage?hold_did={{ .DID | urlquery }}"
hx-trigger="load, tab:storage from:body once"
hx-swap="innerHTML">
-
{{ icon "loader-2" "size-4 animate-spin" }} Loading storage...
+
{{ icon "loader-2" "size-4 animate-spin" }} Loading storage...
diff --git a/pkg/appview/templates/partials/hold_selector.html b/pkg/appview/templates/partials/hold_selector.html
index badf1fc..a672c9e 100644
--- a/pkg/appview/templates/partials/hold_selector.html
+++ b/pkg/appview/templates/partials/hold_selector.html
@@ -1,9 +1,9 @@
{{ define "hold_selector" }}
-
+
{{ else if .Suggestions }}
-
+
{{ icon "sparkle" "size-4" }}
@@ -66,10 +66,10 @@
-
Generated by Claude Haiku. Suggestions are advisory only.
+
Generated by Claude Haiku. Suggestions are advisory only.
{{ else }}
-
No suggestions generated.
+
No suggestions generated.
{{ end }}
{{ end }}
diff --git a/pkg/appview/templates/partials/layers-section.html b/pkg/appview/templates/partials/layers-section.html
index 948254e..bce1b6a 100644
--- a/pkg/appview/templates/partials/layers-section.html
+++ b/pkg/appview/templates/partials/layers-section.html
@@ -1,9 +1,9 @@
{{ define "layers-section" }}
-
+
-
{{ else }}
-
No layer information available
+
+
No layer history available
+
This image was built without history metadata — common for squashed images or tarballs imported with docker load.
+
{{ end }}
{{ end }}
diff --git a/pkg/appview/templates/partials/other_holds_table.html b/pkg/appview/templates/partials/other_holds_table.html
index 9fe8463..2c6d1f4 100644
--- a/pkg/appview/templates/partials/other_holds_table.html
+++ b/pkg/appview/templates/partials/other_holds_table.html
@@ -1,5 +1,5 @@
{{ define "other_holds_table" }}
-
+
Other Holds
@@ -25,13 +25,13 @@
{{ if eq .Status "online" }}
- ●
+
Online
{{ else if eq .Status "offline" }}
- ●
+
Offline
{{ else }}
- ●
+
Unknown
{{ end }}
diff --git a/pkg/appview/templates/partials/repo-tag-section.html b/pkg/appview/templates/partials/repo-tag-section.html
index 4d5a2bc..8f7f3f7 100644
--- a/pkg/appview/templates/partials/repo-tag-section.html
+++ b/pkg/appview/templates/partials/repo-tag-section.html
@@ -11,44 +11,44 @@
{{ range .NonDefaultHolds }}
{{ displayHoldDID . }}
{{ end }}
-
(different from your default hold)
+
(different from your default hold)
{{ end }}
-
+
- Image Size
- Layers
+ Image Size
+ Layers
{{ humanizeBytes .SelectedTag.CompressedSize }}
{{ .SelectedTag.LayerCount }}
-
+
Pushed {{ timeAgoShort .SelectedTag.Info.CreatedAt }}
-
-
Vulnerabilities
+
+
Vulnerabilities
{{ $firstPlatform := index .SelectedTag.Info.Platforms 0 }}
- Loading...
+ Loading...
-
+
- Pulls
+ Pulls
-
{{ .Stats.PullCount }} total
-
+
{{ .Stats.PullCount }} total
+
{{ if .Stats.LastPull }}Last pull {{ timeAgoShort (derefTime .Stats.LastPull) }}{{ else }}No pulls yet{{ end }}
@@ -80,7 +80,7 @@
aria-selected="false"
aria-controls="tab-overview"
id="overview-tab-btn"
- onclick="switchRepoTab('overview')">
+ data-action="switch-repo-tab">
Overview
{{ if .SelectedTag }}
@@ -90,7 +90,7 @@
aria-selected="false"
aria-controls="tab-layers"
id="layers-tab-btn"
- onclick="switchRepoTab('layers')">
+ data-action="switch-repo-tab">
Layers
+ data-action="switch-repo-tab">
Vulnerabilities
+ data-action="switch-repo-tab">
SBOM
{{ end }}
@@ -118,7 +118,7 @@
aria-selected="false"
aria-controls="tab-artifacts"
id="artifacts-tab-btn"
- onclick="switchRepoTab('artifacts')">
+ data-action="switch-repo-tab">
Artifacts
@@ -126,7 +126,7 @@
-
+
{{ if and .AIAdvisorEnabled .User .IsOwner .SelectedTag }}
-
+
{{ icon "pencil" "size-4" }}
Edit
@@ -160,18 +160,18 @@
{{ else }}
{{ if .IsOwner }}
- {{ icon "file-text" "size-12 text-base-content opacity-40 mx-auto" }}
+ {{ icon "file-text" "size-12 text-base-content/40 mx-auto" }}
No README provided
-
Add a README to help users understand this image.
-
+ Add a README to help users understand this image.
+
{{ icon "pencil" "size-4" }} Add README
{{ else }}
- {{ icon "file-text" "size-12 text-base-content opacity-40 mx-auto" }}
+ {{ icon "file-text" "size-12 text-base-content/40 mx-auto" }}
No README provided
-
Image metadata is shown above.
+
Image metadata is shown above.
{{ end }}
{{ end }}
diff --git a/pkg/appview/templates/partials/repo-tags.html b/pkg/appview/templates/partials/repo-tags.html
index 933c784..fd37115 100644
--- a/pkg/appview/templates/partials/repo-tags.html
+++ b/pkg/appview/templates/partials/repo-tags.html
@@ -14,7 +14,7 @@
hx-get="/api/attestation-details?digest={{ .Entry.Digest | urlquery }}&did={{ .OwnerDID | urlquery }}&repo={{ .RepoName | urlquery }}"
hx-target="#attestation-modal-body"
hx-swap="innerHTML"
- onclick="document.getElementById('attestation-detail-modal').showModal()">
+ data-action="show-modal" data-modal-id="attestation-detail-modal">
{{ icon "shield-check" "size-3" }} Attested
{{ end }}
@@ -38,7 +38,7 @@
{{ else }}
{{ icon "trash-2" "size-4" }}
@@ -86,7 +86,7 @@
@@ -110,7 +110,7 @@
{{ define "load-more-button" }}
{{ if .HasMore }}
-
- {{ .Package }}{{ if .Type }} ({{ .Type }}) {{ end }}
+ {{ .Package }}{{ if .Type }} ({{ .Type }}) {{ end }}
{{ .Version }}
{{ if .FixedIn }}
{{ .FixedIn }}
{{ else }}
- -
+ -
{{ end }}
diff --git a/pkg/appview/templates/partials/vulns-section.html b/pkg/appview/templates/partials/vulns-section.html
index 896f994..d3d5ad4 100644
--- a/pkg/appview/templates/partials/vulns-section.html
+++ b/pkg/appview/templates/partials/vulns-section.html
@@ -1,9 +1,12 @@
{{ define "vulns-section" }}
-
+
{{ if .VulnData }}
{{ template "vuln-details" .VulnData }}
{{ else }}
-
No vulnerability scan data available
+
+
No vulnerability scan available yet
+
Scans run automatically shortly after a push. Check back in a few minutes, or push a new tag to trigger a scan.
+
{{ end }}
{{ end }}
diff --git a/pkg/appview/templates/partials/webhooks_list.html b/pkg/appview/templates/partials/webhooks_list.html
index 0a7e5cd..7358dc4 100644
--- a/pkg/appview/templates/partials/webhooks_list.html
+++ b/pkg/appview/templates/partials/webhooks_list.html
@@ -12,16 +12,17 @@
Webhook URL
+ class="input input-bordered w-full" required aria-required="true">
- Signing Secret (optional)
+ Signing Secret (optional)
- If set, payloads include an X-Webhook-Signature-256 header
+ class="input input-bordered w-full" autocomplete="new-password"
+ aria-describedby="webhook-secret-hint">
+ If set, payloads include an X-Webhook-Signature-256 header
@@ -58,7 +59,7 @@
{{ if .Webhooks }}
{{ range .Webhooks }}
-
+
{{ .URL }}
@@ -82,7 +83,7 @@
Test
@@ -100,7 +101,7 @@
{{ end }}
{{ else }}
-
No webhooks configured yet.
+
No webhooks configured yet.
{{ end }}
{{ end }}
diff --git a/pkg/hold/admin/public/icons.svg b/pkg/hold/admin/public/icons.svg
index ea32d1a..eb4d6b7 100644
--- a/pkg/hold/admin/public/icons.svg
+++ b/pkg/hold/admin/public/icons.svg
@@ -30,7 +30,6 @@
-
diff --git a/themes/seamark/templates/components/hero.html b/themes/seamark/templates/components/hero.html
index 5423b49..5694a15 100644
--- a/themes/seamark/templates/components/hero.html
+++ b/themes/seamark/templates/components/hero.html
@@ -38,21 +38,21 @@
-
+
{{ icon "ship" "size-8" }}
Works with Docker
Use docker push & pull. No new tools to learn.
-
+
{{ icon "anchor" "size-8" }}
Your Data
Join shared holds or captain your own storage.
-
+
{{ icon "compass" "size-8" }}
diff --git a/themes/seamark/theme.css b/themes/seamark/theme.css
index e4dd52a..a97a44f 100644
--- a/themes/seamark/theme.css
+++ b/themes/seamark/theme.css
@@ -1,16 +1,26 @@
/* Seamark color overrides (injected after atcr.io's compiled stylesheet) */
[data-theme="dark"] {
+ --color-primary: oklch(72% 0.17 225);
+ --color-primary-content: oklch(15% 0.05 240);
--color-secondary: oklch(90% 0.182 98.111);
--color-secondary-content: oklch(30% 0.182 98.111);
- --color-accent: oklch(66.6% 0.121 28);
- --color-accent-content: oklch(28% 0.121 28);
+ --color-accent: oklch(70% 0.14 345);
+ --color-accent-content: oklch(98% 0.008 345);
+ --color-base-100: oklch(20% 0.05 250);
+ --color-base-200: oklch(25% 0.05 250);
+ --color-base-300: oklch(30% 0.05 250);
}
[data-theme="light"] {
+ --color-primary: oklch(48% 0.17 250);
+ --color-primary-content: oklch(98% 0.01 250);
--color-secondary: oklch(76% 0.095 76.1);
--color-secondary-content: oklch(27.1% 0.026 76.4);
- --color-accent: oklch(66.6% 0.121 28);
- --color-accent-content: oklch(28% 0.121 28);
+ --color-accent: oklch(56% 0.17 345);
+ --color-accent-content: oklch(98% 0.008 345);
+ --color-base-100: oklch(98% 0.01 225);
+ --color-base-200: oklch(95% 0.02 225);
+ --color-base-300: oklch(92% 0.03 225);
}
@keyframes rock {